planckforth/README.md

90 lines
3.6 KiB
Markdown
Raw Normal View History

2021-01-04 14:17:05 +01:00
# PlanckForth: Bootstrapping Forth from Handwritten Binary
2020-12-28 14:11:20 +01:00
2021-01-02 05:07:29 +01:00
This project aims to bootstrap a Forth interpreter from hand-written tiny ELF binary.
2021-01-02 05:01:31 +01:00
## How to build
You can create a binary for x86 linux environment by following steps.
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-04 14:16:12 +01:00
There are implementations in C and Python 3 as a reference in `others`.
Try `make c` or `make python`
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 09:29:32 +01:00
$ ./planck < bootstrap.fs --i386-linux
Ready.
2021-01-02 05:01:31 +01:00
." Hello World!" cr
2021-01-03 10:40:30 +01:00
```
2021-01-09 09:29:32 +01:00
The option `--i386-linux` is to specify OS and hardware for dynamic
code generation by `bootstrap.fs`.
It is not necessay in case of implementations by other languages.
`bootstrap.fs` also takes a file as an input 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 09:29:32 +01:00
38 fib . cr
$ ./planck < bootstrap.fs --i386-linux example/fib.fs
39088169
2020-12-29 06:51:27 +01:00
```
2020-12-28 18:16:46 +01:00
# Builtin Words
2021-01-03 01:36:41 +01:00
| code | name | stack effect | semantics |
|:----:|:----------|:----------------|:-----------------------------|
| Q | quit | ( -- ) | 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 |
| $ | 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 interpreter function |
| e | exit | ( -- ) | Exit current function |
| L | lit | ( -- n ) | Load immediate |
| S | litstring | ( -- c-addr ) | Load string literal |
2021-01-03 01:36:41 +01:00
| + | add | ( a b -- c ) | c = (a + b) |
| - | sub | ( a b -- c ) | c = (a - b) |
| * | mul | ( a b -- c ) | c = (a * b) |
| / | div | ( a b -- c ) | c = (a / b) |
| % | mod | ( a b -- c ) | c = (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) |
| = | equal | ( a b -- c ) | c = (a == b) |
2021-01-09 15:40:41 +01:00
| v | argv | ( -- a-addr u ) | argv and argc |
2021-01-09 16:00:18 +01:00
| V | impl | ( -- c-addr ) | Implementation String |