A stack-based programming language which compiles to assembly.
All examples are located in examples/
Clone this repo and run:
make
There should be an executeable called ach
which you can run.
USAGE: ./ach <FILENAME> <OPTIONS>
OPTIONS:
-h, --help show help
-f, --fasm use fasm to compile program
-n, --nasm use nasm to compile program
-u, --unsafe compile without type checking program
Each program has an entry point through the main
function
def main in
# code here
end
Comments are like in python and ruby
# this is a comment
def main in
# another comment
end
Declaring numbers pushes one value on the stack, an integer.
# stack [34, 35]
def main in
34 35
end
Pushing a string onto the stack pushes 2 values:
- the length of the string (integer)
- a pointer to the string
# stack [5, "Hello"]
def main in
"Hello"
end
To push a null-terminated string, or a C-style string:
# stack ["Hello\0"]
def main in
"Hello"c
end
name | function | stack |
---|---|---|
dup | duplicate top value on the stack | [a] -> [a, a] |
swp | swap top two values on the stack | [a, b] -> [b, a] |
rot | rotate the top three to the left | [a, b, c] -> [b, c, a] |
over | copy second value on stack over | [a, b] -> [a, b a] |
pop | pop top value from the stack | [a, b] -> [a] |
dump | dump top value on the stack into stdout | [a, b] -> [a] |
def main in
# dup
12 # stack [12]
dup # stack [12, 12]
pop pop
# swp
12 13 # stack [12, 13]
swp # stack [13, 12]
pop pop
# rot
12 13 14 # stack [12, 13, 14]
rot # stack [13, 14, 12]
pop pop pop
# over
12 13 # stack [12, 13]
over # stack [12, 13, 12]
pop pop pop
# pop
12 # stack [12]
pop # stack []
# print 13 for debugging
13 dump
end
ach uses reverse polish notation for all expressions and function calls. the following operations are supported:
If the stack is currently [a, b]
+
- add a and b (a + b)-
- subtract b from a (a - b)*
- multiply a and b (a * b)/
- divide a and b (a / b). pushes the quotient and remainder on the stack=
- compare a and b. pushes 1 if equal, 0 if not>
- compare a and b. pushes 1 if a is greater, 0 if not<
- compare a and b. pushes 1 if a is less, 0 if not>=
- compare a and b. pushes 1 if a is greater or equal, 0 if not<=
- compare a and b. pushes 1 if a is less or equal, 0 if not!=
- compare a and b. pushes 1 if not equal, 0 if notor
- compare a and b. pushes 1 if either a or b is not equal to 0, 0 if notand
- compare a and b. pushes 1 if both a or b is not equal to 0, 0 if notnot
- if b is equal to 0, push 1, else push 0>>
- shift a by b bytes to the right<<
- shift a by b bytes to the left
def main in
# 12 + 13 -> 25
12 13 + dump
# 14 - 12 -> 2
14 12 - dump
# 7 * 3 -> 21
7 3 * dump
# 9 / 2 -> 4, 1
9 2 / dump dump
# 1 == 2 -> 0
1 2 = dump
# 2 == 2 -> 1
2 2 = dump
# 3 > 2 -> 1
3 2 > dump
# 3 > 4 -> 0
3 4 > dump
# 2 < 3 -> 1
2 3 < dump
# 3 < 2 -> 0
3 2 < dump
# 12 >= 12 -> 1
12 12 >= dump
# 11 >= 12 -> 0
11 12 >= dump
# 13 >= 12 -> 1
13 12 >= dump
# 12 <= 12 -> 1
12 12 <= dump
# 11 <= 12 -> 1
11 12 <= dump
# 13 <= 12 -> 0
13 12 <= dump
# 1 != 0 -> 1
1 0 != dump
# 1 != 1 -> 0
1 1 != dump
# 4 or 0 -> 1
4 0 or dump
# 3 or 4 -> 1
3 4 or dump
# 0 or 0 -> 0
0 0 or dump
# 4 and 0 -> 0
4 0 and dump
# 3 and 4 -> 1
3 4 and dump
# 0 and 0 -> 0
0 0 and dump
# not 1 -> 0
1 not dump
# not 0 -> 1
0 not dump
# 12 >> 1 -> 6
12 1 >> dump
# 12 << 1 -> 24
12 1 << dump
end
Based off https://gitlab.com/tsoding/porth/-/tree/master.
include "std/core.ach"
struct Struct
num int
string str
end
# fairly useless function
def cstrlen2 str str -> int int in
let str_a str_b in
str_a cstrlen
str_b cstrlen
end
end
def main in
Struct set my_struct end
my_struct "Hello"c !Struct.string
my_struct 69 !Struct.num
my_struct @Struct.String cstr-to-str puts
my_struct @Struct.Num putu "\n" puts
"Hello"c "World!"c cstrlen2
putu "\n" puts
putu "\n" puts
end