2021-01-13 12:28:27 +01:00
|
|
|
# PlanckForth: Bootstrapping an Interpreter from Handwritten 1KB Binary
|
2020-12-28 14:11:20 +01:00
|
|
|
|
2021-01-13 12:26:37 +01:00
|
|
|
This project aims to bootstrap a Forth interpreter from hand-written tiny (1KB) ELF binary.
|
2021-01-12 04:07:12 +01:00
|
|
|
This is just for fun. No practical use.
|
2021-01-02 05:01:31 +01:00
|
|
|
|
|
|
|
## How to build
|
|
|
|
|
|
|
|
Only `xxd` is needed to build PlanckForth.
|
|
|
|
|
2020-12-28 14:11:20 +01:00
|
|
|
```
|
2020-12-30 11:41:21 +01:00
|
|
|
$ git clone https://github.com/nineties/planckforth.git
|
|
|
|
$ cd planckforth
|
2020-12-28 14:11:20 +01:00
|
|
|
$ make
|
2021-01-02 05:01:31 +01:00
|
|
|
xxd -r -c 8 planck.xxd > planck
|
|
|
|
chmod +x planck
|
|
|
|
```
|
|
|
|
|
2021-01-11 05:35:10 +01:00
|
|
|
Implementations in other languages are in `others`.
|
2021-01-11 05:33:15 +01:00
|
|
|
|
2021-01-02 05:01:31 +01:00
|
|
|
## Hello World
|
|
|
|
|
|
|
|
The hello world program at the beginning looks like this.
|
|
|
|
|
|
|
|
```
|
2021-01-02 05:15:42 +01:00
|
|
|
$ ./planck
|
2021-01-02 05:01:31 +01:00
|
|
|
kHtketkltkltkotk tkWtkotkrtkltkdtk!tk:k0-tQ
|
|
|
|
```
|
2021-01-02 05:06:35 +01:00
|
|
|
After bootstrapping by `bootstrap.fs`, it looks like this.
|
2021-01-02 05:01:31 +01:00
|
|
|
|
|
|
|
```
|
2021-01-09 17:14:42 +01:00
|
|
|
$ ./planck < bootstrap.fs
|
2021-01-02 05:01:31 +01:00
|
|
|
." Hello World!" cr
|
2021-01-03 10:40:30 +01:00
|
|
|
```
|
|
|
|
|
2021-01-09 17:14:42 +01:00
|
|
|
`bootstrap.fs` can also takes a file as an input program like this.
|
2021-01-03 10:40:30 +01:00
|
|
|
|
|
|
|
```
|
2021-01-09 09:29:32 +01:00
|
|
|
$ cat example/fib.fs
|
2021-01-03 10:40:30 +01:00
|
|
|
: fib dup 2 < unless 1- dup recurse swap 1- recurse + then ;
|
2021-01-09 17:14:42 +01:00
|
|
|
20 fib . cr
|
|
|
|
$ ./planck < bootstrap.fs example/fib.fs
|
|
|
|
6765
|
2020-12-29 06:51:27 +01:00
|
|
|
```
|
|
|
|
|
2021-01-11 05:32:08 +01:00
|
|
|
# Running Tests
|
|
|
|
|
|
|
|
```
|
|
|
|
$ ./planck < bootstrap.fs runtests.fs
|
|
|
|
```
|
|
|
|
|
2020-12-28 18:16:46 +01:00
|
|
|
# Builtin Words
|
|
|
|
|
2021-01-12 04:07:12 +01:00
|
|
|
| code | name | stack effect | semantics |
|
|
|
|
|:----:|:----------|:----------------|:----------------------------------------|
|
|
|
|
| Q | quit | ( n -- ) | Exit the process |
|
|
|
|
| C | cell | ( -- n ) | The size of Cells |
|
|
|
|
| h | &here | ( -- a-addr ) | The address of 'here' cell |
|
|
|
|
| l | &latest | ( -- a-addr ) | The address of 'latest' cell |
|
|
|
|
| k | key | ( -- c ) | Read character |
|
|
|
|
| t | type | ( c -- ) | Print character |
|
|
|
|
| j | jump | ( -- ) | Unconditional branch |
|
|
|
|
| J | 0jump | ( n -- ) | Jump if a == 0 |
|
|
|
|
| f | find | ( c -- xt ) | Get execution token of c |
|
|
|
|
| x | execute | ( xt -- ... ) | Run the execution token |
|
|
|
|
| @ | fetch | ( a-addr -- w ) | Load value from addr |
|
|
|
|
| ! | store | ( w a-addr -- ) | Store value to addr |
|
|
|
|
| ? | cfetch | ( c-addr -- c ) | Load byte from addr with sign extension |
|
|
|
|
| $ | cstore | ( c c-addr -- ) | Store byte to addr |
|
|
|
|
| d | dfetch | ( -- a-addr ) | Get data stack pointer |
|
|
|
|
| D | dstore | ( a-addr -- ) | Set data stack pointer |
|
|
|
|
| r | rfetch | ( -- a-addr ) | Get return stack pointer |
|
|
|
|
| R | rstore | ( a-addr -- ) | Set return stack pointer |
|
|
|
|
| i | docol | ( -- a-addr ) | Get the code pointer of interpreter |
|
|
|
|
| e | exit | ( -- ) | Exit current function |
|
|
|
|
| L | lit | ( -- n ) | Load immediate |
|
|
|
|
| S | litstring | ( -- c-addr ) | Load string literal |
|
|
|
|
| + | add | ( a b -- c ) | c = (a + b) |
|
|
|
|
| - | sub | ( a b -- c ) | c = (a - b) |
|
|
|
|
| * | mul | ( a b -- c ) | c = (a * b) |
|
|
|
|
| / | divmod | ( a b -- c d ) | c = (a mod b), d = (a / b) |
|
|
|
|
| & | and | ( a b -- c ) | c = (a & b) |
|
|
|
|
| \| | or | ( a b -- c ) | c = (a \| b) |
|
|
|
|
| ^ | xor | ( a b -- c ) | c = (a ^ b) |
|
|
|
|
| < | less | ( a b -- c ) | c = (a < b) |
|
|
|
|
| u | uless | ( a b -- c ) | c = (a unsigned< b) |
|
|
|
|
| = | equal | ( a b -- c ) | c = (a == b) |
|
|
|
|
| { | shl | ( a b -- c ) | c = a << b (logical) |
|
|
|
|
| } | shr | ( a b -- c ) | c = a >> b (logical) |
|
|
|
|
| ) | sar | ( a b -- c ) | c = a >> b (arithmetic) |
|
|
|
|
| v | argv | ( -- a-addr u ) | argv and argc |
|
|
|
|
| V | version | ( -- c-addr ) | Runtime infomation string |
|
2021-01-11 06:49:01 +01:00
|
|
|
|
2021-01-15 01:49:01 +01:00
|
|
|
# Binary Layout
|
|
|
|
|
|
|
|
![binary layout](https://user-images.githubusercontent.com/172570/104666244-c0c58800-5716-11eb-9798-847ea2fe76b8.jpeg)
|
|
|
|
|
2021-01-11 06:49:01 +01:00
|
|
|
# Implementations
|
|
|
|
|
|
|
|
| Implementation of runtime | build | test status |
|
|
|
|
|:----------------------------------|:------------------|:------------|
|
2021-01-12 03:46:58 +01:00
|
|
|
| Handwritten ELF binary for i386-linux | `make` | [![i386-linux-handwritten](https://github.com/nineties/planckforth/workflows/i386-linux-handwritten/badge.svg)](https://github.com/nineties/planckforth/actions?query=workflow:i386-linux-handwritten) |
|
2021-01-11 06:57:17 +01:00
|
|
|
| C | `make c` | [![C](https://github.com/nineties/planckforth/workflows/C/badge.svg)](https://github.com/nineties/planckforth/actions?query=workflow:C) |
|
|
|
|
| Python 3.x | `make python` | [![python](https://github.com/nineties/planckforth/workflows/python/badge.svg)](https://github.com/nineties/planckforth/actions?query=workflow:python) |
|
2021-01-11 09:32:38 +01:00
|
|
|
|
|
|
|
# Benchmarks
|
|
|
|
|
2021-01-11 11:29:03 +01:00
|
|
|
See [Wiki/Benchmarks](https://github.com/nineties/planckforth/wiki/Benchmarks)
|