It's like Porth, which itself is like Forth, but in C. This project came in my brain when I discovered Tsoding and it's Porth videos. I have to practice C for school purposes, so why not doing so while creating (rather copying) a programming language ? At least, I can work with files, error handling, debugging, assembly code, etc ... In addition, it will help me to understand how a programming language does work. I share this project to you the same way Tsoding did for me.
Corth is planned to be :
- Compiled
- Native
- Stack based (just like Porth and Forth)
- Turing-complete (Rule 110)
- Statically typed
- Self-hosted
- Fix the lexer about handling
\r\n
(Win) AND\n
(Unix) - Fix the compiler about printing negative numbers. (Ex :
-10
->/0
)
Simulation simply interprets the program.
$ cat program.corth
34 35 + .
$ ./corth sim program.corth
69
Compilation generates assembly code which can be compiled using NASM and linked with ld. So make sure you have them installed.
$ cat program.corth
34 35 + .
$ ./corth com program.corth
$ nasm -felf64 output.asm -o output.o
$ ld output.o -o output
$ ./output
69
This is what the language supports so far. Since the language is a work in progress, some operations are subject to change.
<integer>
: pushes the integer onto the stack. Right now, it's the only kind of thing that can be parsed by the lexer as number.
push(stack, <integer>)
"<string>"
: pushes the string's length and then the string's address onto the stack.
push(stack, strlen(<string>))
push(stack, &<string>)
pop
: pops the element at the top of the stack. (Not returned yet)
pop(stack)
dup
: duplicates an element on the top of the stack.
a = pop(stack)
push(stack, a)
push(stack, a)
dump
: pops the element at the top of the stack to print it to the stdout.
a = pop(stack)
print(a)
Arithmetics (Example file)
+
: sums up two elements at the top of the stack.
a = pop(stack)
b = pop(stack)
push(stack, a + b)
-
: substracts two elements at the top of the stack.
a = pop(stack)
b = pop(stack)
push(stack, b - a)
Bitwise (Example file)
shr
shifter = pop(stack)
shifted = pop(stack)
push(shifter >> shifted)
shl
shifter = pop(stack)
shifted = pop(stack)
push(shifted << shifter)
orb
a = pop(stack)
b = pop(stack)
push(a | b)
andb
a = pop(stack)
b = pop(stack)
push(a & b)
!=
,=
,<
,<=
,>=
and>
: pops two elements from the top of the stack, compares them, and pushes either0
if the condition is not fulfilled or1
if it is.
if <then-branch> else <else-branch> end
: pops the element at the top of the stack and check if it's value is not0
to execute the<then-branch>
, otherwise it runs the<else-branch>
. (Example file)while <condition> do <body> end
: keeps executing both<condition>
and<body>
until<condition>
produces0
at the top of the stack. To check the result of the<condition>
, the last element of the stack is poped. (Example file)halt
:pops the elements at the top of the stack as an exit status, then quits the program.Replaced by thesyscallN
feature. See### System
.
Memory (Example file)
mem
: pushes the address of the beginning of the readable/writable memory onto the stack.over
: duplicates the element just before the one at the top of the stack.
a = pop(stack)
b = pop(stack)
push(stack, b)
push(stack, a)
push(stack, b)
swap
: swaps the two elements at the top of the stack.
a = pop(stack)
b = pop(stack)
push(stack, a)
push(stack, b)
push(mem_address)
store
: stores a given byte to the givenmem
address.
byte = pop(stack)
address = pop(stack)
store(address, byte)
load
: loads a byte from a givenmem
address.
address = pop(stack)
byte = laod(address)
push(stack, byte)
syscallN
: perform a syscall (according to this convention) which requiresN
arguments such as0 <= N <= 6
.
rax = pop(stack) # The syscall ID, must be here anyway.
rdi = pop(stack) # if N is enough high.
rsi = pop(stack) # if N is enough high.
rdx = pop(stack) # if N is enough high.
r10 = pop(stack) # if N is enough high.
r8 = pop(stack) # if N is enough high.
r9 = pop(stack) # if N is enough high.
syscall
Example : show the 3 first character of the mem
into the stdout.
3 // rdx
mem // rsi
1 // rdi
1 // rax
syscall3 // This syscall has 3 arguments.