从手工编写的微型 ELF 二进制文件启动一个 Forth 解释器
planckforth: Bootstrapping a Forth interpreter from hand-written tiny ELF binary

原始链接: https://github.com/nineties/planckforth

## PlanckForth:一个极简的Forth解释器 PlanckForth是一个有趣的项目,旨在从一个1KB的ELF二进制文件创建一个自举的Forth解释器。该项目仅使用`xxd`构建,展示了一个功能性的Forth系统如何从极其有限的起点出现。 最初,解释器直接从编译后的二进制文件运行,执行特定的字节序列。然后,它使用一个小的Forth源代码文件(`bootstrap.fs`)进行自举,从而实现更传统的Forth编程。 该项目包含示例代码,例如斐波那契数列计算器,展示了如何定义和执行词(Forth函数)。提供了一组核心的原始词,用于处理堆栈操作、算术运算、控制流和内存访问。这些原始词能够在Forth环境中定义更复杂的功能。 PlanckForth纯粹是一个自举的演示,并非用于实际用途,但它突出了Forth语言的力量和优雅。

黑客新闻 新的 | 过去的 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 planckforth: 从手写的微型 ELF 二进制文件引导一个 Forth 解释器 (github.com/nineties) 18 分,由 tosh 发表于 4 小时前 | 隐藏 | 过去的 | 收藏 | 讨论 帮助 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

This project aims to bootstrap a Forth interpreter from hand-written tiny (1KB) ELF binary. This is just for fun. No practical use.

Only xxd is needed to build PlanckForth.

$ git clone https://github.com/nineties/planckforth.git
$ cd planckforth
$ make
xxd -r -c 8 planck.xxd > planck
chmod +x planck

Implementations in other languages are in others.

The hello world program at the beginning looks like this.

$ ./planck
kHtketkltkltkotk tkWtkotkrtkltkdtk!tk:k0-tk0k0-Q

After bootstrapping by bootstrap.fs, it looks like this.

$ ./planck < bootstrap.fs
." Hello World!" cr

bootstrap.fs can also take a file as an input program like this.

$ cat example/fib.fs
: fib dup 2 < unless 1- dup recurse swap 1- recurse + then ;
20 fib . cr
$ ./planck < bootstrap.fs example/fib.fs
6765
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

binary layout

See Wiki/Benchmarks

联系我们 contact @ memedata.com