Skip to content

Ximaz/corth

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Corth

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.

Roadmap

Corth is planned to be :

  • Compiled
  • Native
  • Stack based (just like Porth and Forth)
  • Turing-complete (Rule 110)
  • Statically typed
  • Self-hosted

TODO

  • Fix the lexer about handling \r\n (Win) AND \n (Unix)
  • Fix the compiler about printing negative numbers. (Ex : -10 -> /0)

Quick Start

Simulation

Simulation simply interprets the program.

$ cat program.corth
34 35 + .
$ ./corth sim program.corth
69

Compilation

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

Language Reference

This is what the language supports so far. Since the language is a work in progress, some operations are subject to change.

Stack manipulation

  • <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)

Comparisons

  • !=, =, <, <=, >= and > : pops two elements from the top of the stack, compares them, and pushes either 0 if the condition is not fulfilled or 1 if it is.

Control Flow

  • if <then-branch> else <else-branch> end : pops the element at the top of the stack and check if it's value is not 0 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> produces 0 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 the syscallN 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 given mem address.
byte = pop(stack)
address = pop(stack)
store(address, byte)
  • load : loads a byte from a given mem address.
address = pop(stack)
byte = laod(address)
push(stack, byte)

System

  • syscallN : perform a syscall (according to this convention) which requires N arguments such as 0 <= 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.