Skip to content

dougy147/k7

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

k7

k7 is a programming language.

  • stack-based
  • self-hosted (k7 source code is written in k7)
  • compiles down to assembly (x86_64)
  • concatenative
  • inspired by Porth
  • experimental++
  • unfinished and never will
  • pronounced /kas.εt/
  • statically typed
  • not for the faint of heart
  • Linux only
  • Turing-complete

Example

func add ( x int , y int )
    x y +
end

var result int in

@result 2 2 add :=

if result 5 = then
    "Hello, dystopian World!\n" print
end

Quick start

Install fasm to automatically compile the assembly code k7 generates, or to bootstrap the k7 compiler. fasm executable must be located here /usr/bin/fasm.

Binary

$ ./k7 -run ./examples/hello.k7
Hello, World!

Compile from assembly

Bootstrap the compiler with fasm, then give the compiler its own source code to get... the exact same compiler!

$ fasm -m 324017 ./src/k7.asm
$ ./src/k7 -v ./src/k7.k7 -o ./k7

Overview

Documentation below is brief and non-exhaustive. I'd recommend checking ./examples/ programs to get a grasp on how to write k7.

Comments

# this is a comment

Stack-operations

k7 is stack-based. You push stuff and operate on a stack.

10 20 + 

We just pushed two integers (10 and 20) and one operator (+) on the stack. What happened:

10 # push 10      (stack = 10)
20 # push 20      (stack = 10 20)
+  # act on stack (stack = 30)

We have a plethora of operators. Most of them are self-explanatory.

+ - * / mod    # arithmetic
>> <<          # bitwise
= != > >= < <= # comparison
and or not     # logic

The following are "stolen" from Forth. Check out their webpage for a better explanation:

dup   # duplicate last value on the stack
2dup  # duplicate last pair
swap  # swap last two values
2swap # swap last two pairs
lob   # duplicate penultimate value ("over" in Forth)
2lob  # duplicate penultimate pair  ("2over" in Forth)
rot   # move antepenultimate value to last position
drop  # remove last value

Print

  • Keywords: print , put

Use print to print strings

Use put to print numeric values

"Hello world\n" print

10 20 + put # prints 30

print requires two values on the stack: length and address (that's what strings are in k7). put requires one numeric value on the stack.

Strings

  • Structure: "anything between non-escaped double-quotes"

Strings push two things on the stack: their length and address

Strings can be multiline

"Foo"   # push 3 (length) and string address on stack
"Bar\n" # push 4 and address on stack

"here
is a
multiline
string"

Chars

  • Structure: '_'

Characters litterals push their ASCII code on the stack

'a'  put # prints 97
'\n' put # prints 10

Booleans

  • Keywords: true, false

False = 0

True = 1

Conditionals

  • Keywords: if, elif, else, end
  • Structure: if <condition> then <instructions> [elif <condition> then <instructions> [else <instructions>]] end
if weather sunny = then
    "sunglasses" print
elif weather rain = then
    "umbrella" print
elif weather hail = then
    "helmet" print
end

Loops

  • Keywords: for, while, do, done
  • Structure:
    • for loop: <iterations> for <instructions> 1 - done
    • while loop: while <condition> do <instructions> done

For loops push the iterator on the stack and stop when it is equal to zero

While loops continue until their condition is false

# print from 10 to 1 (descending)
10 for
    dup # duplicate iterator
    put # and prints it
    1 - # decrease iterator by 1
done
drop # remove iterator from stack

# print from 1 to 10
1 while dup 10 <= do
    dup put
    1 +
done drop

Loops control flow

  • Keywords: continue, break

Types

Built-in types and their respective sizes (in bytes):

  • u8 (1)
  • u16 (2)
  • u32 (4)
  • u64 (8)
  • int (8)
  • ptr (8)
  • char (1)
  • bool (1)

Macros

  • Keywords: def, end
  • Structure: def <identifier> <instructions> end

Literally rewrite every occurrence of <identifier> to <instructions> at compile time.

Macros are scoped (i.e. they are either global, either local when declared inside functions).

def N 3 end
N N * # will be rewritten as 3 3 *

Functions

  • Keywords: func, end
  • Structure: func <identifier> [ parameters ] <body> end
  • Parameters: ( <var0_identifier> <var0_type> [, <var1_identifier> <var1_type> , ...] )

Parameters are optional.

Functions are scoped.

Functions can be nested.

func fib ( n int )
    if n 2 < then
        1 return
    end
    n 1 - fib n 2 - fib +
end

10 fib # call fib with n = 10
put    # outputs => 89

Variables

  • Keywords: var, in
  • Structure:
    • declare variable: var <identifier> <type> in
    • assign to variable: @<identifier> <value> :=
    • reverse assign: <value> @<identifier> =:
var age u8 in
@age 36 :=  # assign 36 to variable "age"

var name char ptr in
"Luc" swap drop @name =: # assign (reverse) string address to "name"

To refer to the value of a variable, simply call it with its identifier. If you want to refer to the address of a variable (when assigning to it, or passing it as a pointer) prepend a @ to its identifier.

User-defined types

  • Keywords: type, end
  • Structure: type <identifier> <type> end
type age u8 end
type input char ptr end

Structs

  • Keywords: struct, field, end
  • Structure: struct <identifier> [field <field_id> <field_type> end]+ end
struct person
    field name char ptr end
    field age        u8 end
end

var john person in
@john.name "John" swap drop :=
@john.age 99 :=

We mimick C struct memory alignment, thus receiving structured data from kernel is easy (check ./lib/ctypes.k7).

Structs are syntactic sugar, in the background they are just variables (and allocations for padding). If structs are passed by reference to a function, there is no easy way to access fields other than using memory load/store operators manually.

Allocations

  • Keywords: alloc, end
  • Structure: alloc <identifier> <size> end

Allocate a chunk of size bytes.

Allocations are scoped.

Size can be simple arithmetic operations on types

alloc my_str char 256 * end # allocate a chunk of 256 bytes

255 for
    dup my_str + lob >(8) # store byte X at index X of my_str
done drop

Imports

  • Keyword: import
  • Structure: import "file_path"

Import other k7 programs into the current one. If no absolute path given, will look in the relative ./lib directory.

import "./lib/maths.k7" # or simply
import "maths"          # same as above

Check ./lib for available libraries.

Memory operations

# loading operators
    m>    # load as a 64-bits object
    (64)> # load as a 64-bits object
    (32)> # load as a 32-bits object
    (16)> # load as a 16-bits object
    (8)>  # load as a  8-bits object
# storing operators
    >m    # store as a 64-bits object
    >(64) # store as a 64-bits object
    >(32) # store as a 32-bits object
    >(16) # store as a 16-bits object
    >(8)  # store as a  8-bits object
var x int in @x 100 :=
var p int ptr in @p @x :=

p m> put # prints 100
p 50 >m  # stores 50 in @x as 64-bits integer
x put    # prints 50

Linux syscalls

  • Keywords: sys0,sys1,sys2,sys3,sys4,sys5,sys6
  • Structure: [parameters] syscall
60 1 sys1 # exit 1 syscall

Enumerations

enum
    BLACK  # 0
    BLUE   # 1
    GREEN  # 2
    YELLOW # 3
end

Not implemented

  • useful logs/error messages (worst feature to lack..)
  • floats
  • negative litterals
  • compiler optimization
  • variables direct value assignement
  • string interpolation
  • everything else

Unfinished

  • type checker (too flexible for now)
  • structs (no easy fields access when passed by reference)
  • dereferencing
  • everything else

Syntax highlighting

Sorry non-Vim users, I only came up with k7.vim.

$ cp ./syntax/k7.vim ~/.config/vim/syntax/k7.vim
$ echo 'autocmd BufNewFile,BufRead *.k7 set filetype=k7 syntax=k7' >> ~/.vimrc

About

k7 is the result of a two-months limit experiment. Experiment motivated by the idea of generating assembly code from own higher lever instructions. Idea instilled by Porth developer in their video series.

Not only being the first programming language I've written, k7 is also the first stack-based programming language I've ever used. Just for the records. It was a fun project.

[o=o]

About

Programming Language that compiles to Assembly

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages