Lambda-8cc是X86 C编译器,编写为单片封闭的未型Lambda微积分术语。
当在字母大小的纸上打印时,它将在没有任何数字的22 MB PDF上长达18,506页。可以在我的github页面上看到PDF。乳胶源为448 MB,而乳胶编译日志文件main.log为284 MB。我简直不敢相信乳胶能够做到这一点。
这个巨大的lambda演算术语是C编译器。这是rot13.c,该程序在没有错误的情况下在GCC上编译。可以使用lambda-8cc来编译相同的程序,该lambda-8cc生产x86可执行rot13.bin,可在x86/x86-64 linux上运行:
$ echo ' Hello, world! ' | ./rot13.bin
Uryyb, jbeyq !
$ echo ' Uryyb, jbeyq! ' | ./rot13.bin
Hello, world !尽管尺寸较大,但使用Lambda微积分解释器在8分钟内汇编Rot13.c在8分钟内完成。您可以通过克隆此存储库来在自己的PC上尝试一下。运行时间统计数据在运行时间和内存使用部分中总结。请注意,尽管编译需要时间,但二进制二进制运行瞬间运行。
作为一个附加功能,不仅可以将lambda-8cc编译为x86,而且还可以将c编译为lambda conculus术语,从而产生像rot13.lam之类的东西。编译的lambda术语运行在用于运行lambda-8cc本身的同一lambda演算解释器上。
使用其汇编选项,Lambda-8cc可以将C汇编为5种不同格式。这是其功能的完整列表:
列表中有懒惰K,这是一种最小的纯粹功能性语言,只有4个内置操作员,类似于最少的命令性BF,只有8个说明。我也在博客文章中介绍了一些内容。
lambda-8cc基于以下3个项目:第一个项目是由此repo hikaru ikuta的作者撰写的lambdavm,这是一个可编程的虚拟CPU,写为无类似的lambda colculus术语。这与Rui Ueyama的8CC结合在一起,以及Shinichiro Hamaji的ELVM修改版。
PDF的第一页看起来像这样。注意左上方的页面计数:

它的大结局是一个充满正确括号的页面的掌声:

lambda-8cc写为封闭的未型lambda微积分术语
在这里,即使字符串也被编码为lambda术语。字符和字节被编码为与
因此,计算过程中的所有内容,甚至包括整数在内,都在纯lambda术语的世界中封闭,而无需引入任何非lambda类型对象。它不使用Lambdas以外的任何原始类型。 Lambda-8cc使Beta减少了将C到X86的唯一要求。请注意,该过程也不取决于变量名称的选择。而不是编码字符A作为变量,名称A编码为其ASCII编码01000001的位列表。
编码过程至少要说的是有点麻烦。这可以通过使用lambda conculus解释器来解决。各种Lambda微积分解释器会自动处理此I/O格式,以便在终端上运行 - 标准输入被编码为lambda项,并且输出lambda项已解码并显示在终端上。使用这些解释器,Lambda-8cc可以在终端上运行以像GCC一样编译C程序。
有关如何处理I/O的更多详细信息以及如何用lambda cyculus编写程序,请参阅我的其他项目lambdalisp的实现详细信息,这是LISP解释器,这是一本编写为未型Lambda calculus术语的lisp解释器。
除x86外,lambda-8cc还可以将C汇编为lambda演算。输出程序运行在用于运行lambda-8cc本身的同一lambda微积分解释器上。编译的Lambda术语还以最小的口译员(例如Justine Tunney撰写的521个字节Lambda colculus解释器Sectorlambda)和IOCCC 2012年的“最具功能性的”解释器(其源为λ的形状)。这使得lambda-8cc在lambda演算的领域中独立。
长期以来,在计算机科学中已知Lambda微积分已经完成。 Lambda-8cc以一种相当简单的方式证明了C程序可以直接编译为Lambda conculus项,以相当简单的方式进行了证明。
关于lambda演算的好处是,语言规格非常简单。使用Lambda-8cc,我们正在保留有关如何以永恒方法编译C的知识。即使人类失去有关X86指令集的知识,只要我们记得Lambda演算的规则并拥有Lambda-8cc的lambda术语,我们仍然可以通过Lambda-8cc使用整个C语言,并再次构建所有内容。
这是一个程序rot13.c,该程序对rot13密码的标准输入编码/解码。它使用GCC汇编而没有错误:
// rot13.c: Encodes/decodes standard input to/from the ROT13 cipher
#define EOF -1
int putchar ( int c );
char getchar ( void );
char c ;
int offset ;
int main ( void ) {
for (;;) {
c = getchar ();
if ( c == EOF ) {
break ;
}
offset = 0 ;
if (( 'a' <= c && c < 'n' ) || ( 'A' <= c && c < 'N' )) {
offset = 13 ;
} else if (( 'n' <= c && c <= 'z' ) || ( 'N' <= c && c <= 'Z' )) {
offset = -13 ;
}
putchar ( c + offset );
}
return 0 ;
}相同的程序可以由LAMBDA-8CC从开箱即用的开箱即用。
首先构建工具并准备Lambda-8cc:
$ make tools # Build the interpreter uni++ and the tools lam2bin, asc2bin
$ unzip bin/lambda-8cc.lam.zip
$ cat lambda-8cc.lam | bin/lam2bin | bin/asc2bin > lambda-8cc.Blc # Prepare format for uni++要求是:
clang++建造uni++gcc或cc建造lam2bin和asc2bin这里构建的工具是:
uni++ :Melvin Zhang撰写的非常快速的Lambda演算解释器。lam2bin :Justine Tunney撰写的实用程序(可在https://justine.lol/lambda/上获得),可将诸如xx之类的明文lambda colkulus符号转换为二进制lambda colculus note,该格式是uni ++接受的格式。asc2bin :将0/1 ASCII BITSTREAM包装到字节的实用程序。这些工具是通过lambda conculus开发套件构建的。
从lambda-8cc.lam到lambda-8cc.blc的转换只是解释器Uni ++所接受的格式的符号的转换。详细描述详细信息。
然后rot13.c可以被编译为:
$ cat lambda-8cc.Blc examples/rot13.c | bin/uni++ -o > a.out
$ chmod 755 a.out
$ echo ' Hello, world! ' | ./a.out
Uryyb, jbeyq !
$ echo ' Uryyb, jbeyq! ' | ./a.out
Hello, world !这在我的机器上大约8分钟内运行。但是要小心 - 运行它需要145 GB的内存!如果您有免费的存储空间或USB驱动器,则可以使用带有mkswap和swapon的交换文件扩展交换而无需配置分区设置。另外,通过单独编译组件和X86可执行文件,您可以将RAM使用分为65 GB,如详细使用部分所示。小程序(例如putchar.c)仅需大约40 GB的内存。我怀疑通过将标记和清扫的GC引入口译员可以减少RAM使用情况,尽管我尚未确认。
在运行时间和内存使用部分中,可以使用更多的运行时间统计数据。可以在./ exemples下找到可以通过lambda-8cc编译的更多示例C程序。
其他汇编选项在详细的用法部分中进行了描述。
Lambda-8cc的汇编选项自然而然地用lambda conculus写成,也表示为lambda conculus项。这些选项可用于解锁lambda-8cc的全部功能。
通过将可选术语(lambda-8cc option)提前应用于输入,使用了汇编选项。这会改变lambda术语lambda-8cc的行为,以便接受/产生不同的输入/输出格式。
这是Lambda-8cc的所有汇编选项:
| 输入 | 输出 | 汇编选项 |
|---|---|---|
| c | x86可执行 | |
| c | 明文lambda演算术语 | |
| c | 二进制Lambda微积分符号(BLC程序) | |
| c | 滑雪组合器演算(懒惰K程序) | |
| c | ELVM组装 | |
| ELVM组装 | x86可执行 | |
| ELVM组装 | 明文lambda演算术语 | |
| ELVM组装 | 二进制Lambda微积分符号(BLC程序) | |
| ELVM组装 | 滑雪组合器演算(懒惰K程序) |
每个选项都是3键的格式
如下所示的汇编选项可以在终端中使用。
将C汇编为ELVM组件列表as :
( ( cat lambda-8cc.lam ; printf ' (\f.(f (\x.\y.x) (\x.\y.\z.\a.\b.b) (\x.x))) ' )
| bin/lam2bin | bin/asc2bin ; cat input.c ) | bin/uni++ -o > a.s要编译as x86可执行a.out的ELVM组件列表:
( ( cat lambda-8cc.lam ; printf ' (\f.(f (\x.\y.y) (\x.\y.\z.\a.\b.x) (\x.x))) ' )
| bin/lam2bin | bin/asc2bin ; cat a.s ) | bin/uni++ -o > a.out
chmod 755 a.out如前所述,通过将这些命令分别编译为as和a.out ,可以将最大RAM用法切成两半,因为每个过程完成时释放了内存。
通过运行lambda-8cc而无需任何输入或选项,您可以看到一条用法消息,显示完整的选项:
$ cat lambda-8cc.lam | bin/lam2bin | bin/asc2bin | bin/uni++ -o
lambda-8cc v1.0.0
Usage:
apply lambda-8cc.lam [input-file]
apply lambda-8cc.lam [option] [input-file]
Options:
(f.(f [input] [output] (x.x)))
(f.(f (x.y.x) (x.y.z.a.b.x) (x.x))) : C to x86 (defualt)
(f.(f (x.y.x) (x.y.z.a.b.y) (x.x))) : C to *.lam (plaintext lambda calculus program)
(f.(f (x.y.x) (x.y.z.a.b.z) (x.x))) : C to *.blc (binary lambda calculus program)
(f.(f (x.y.x) (x.y.z.a.b.a) (x.x))) : C to *.lazy (SKI combinator calculus, as a Lazy K program)
(f.(f (x.y.x) (x.y.z.a.b.b) (x.x))) : C to ELVM assembly
(f.(f (x.y.y) (x.y.z.a.b.x) (x.x))) : ELVM assembly to x86
(f.(f (x.y.y) (x.y.z.a.b.y) (x.x))) : ELVM assembly to *.lam
(f.(f (x.y.y) (x.y.z.a.b.z) (x.x))) : ELVM assembly to *.blc
(f.(f (x.y.y) (x.y.z.a.b.a) (x.x))) : ELVM assembly to *.lazy
lambda-8cc includes the following projects. All of the following projects
are released under the MIT license. See the LICENSE in each location for details.
8cc: By Rui Ueyama - https://github.com/rui314/8cc
ELVM: By Shinichiro Hamaji - https://github.com/shinh/elvm
LambdaVM: By Hikaru Ikuta - https://github.com/woodrush/lambdavm
lambda-8cc: By Hikaru Ikuta - https://github.com/woodrush/lambda-8cc
下表显示了Melvin Zhang的Lambda cyculus解释器上的汇编时间和内存使用量。
| 程序 | 汇编时间 | 最大限度。汇编时使用RAM | x86二进制尺寸 | 描述 |
|---|---|---|---|---|
| Putchar.C | 1.8分钟 | 31 GB | 342字节 | 打印A |
| 你好 | 2.4分钟 | 42 GB | 802字节 | 打印Hello, world! |
| echo.c | 2.5分钟 | 46 GB | 663字节 | 回声标准输入 |
| rot13.c | 7.7分钟 | 84 GB | 2,118个字节 | 编码/解码stdin to/from rot13 |
| Fizzbuzz.C | 49.7分钟 | 240 GB | 5,512字节 | 打印最高30的FizzBuzz序列 |
| Primes.C | 53.0分钟 | 241 GB | 5,500字节 | 打印高达100的素数 |
现在,这是很多记忆!要编译需要大型RAM的程序,您可以通过使用交换文件更改分区设置而扩展交换区域。如果您运行Linux并具有任何免费存储或USB驱动器,则可以使用该存储使用mkswap和swapon轻松且动态地扩展您的交换区域。该表上的统计数据以这种方式运行,并以扩展的交换区域运行。在此Askubuntu线程中说明了说明。我怀疑通过将标记和清扫的GC引入口译员可以减少RAM使用情况,尽管我尚未确认。
请注意,这些是汇编时间 - 编译X86二进制的运行时间是瞬时的。当将C汇编为lambda演算术语时,这甚至存在。编译的lambda术语也即时运行,并且在lambda cyculus解释器上运行时仅使用几千兆内的内存。
这些统计数据的汇编是在带有48 GB RAM,16GB SSD交换(默认分区)和274GB( swapon )HDD交换mkswap Ubuntu 22.04.1机器上运行的。此处显示的运行时间是壁时钟运行时间,包括内存操作。对于互换量增加的程序,可以使用更快的I/O速度使用设备来减少运行时间。
统计数据是通过运行来衡量的
cp examples/[program].c ./input.c
make comply.c as and a.out as input.c单独保存总内存使用情况。每个通过的统计表更详细,详细显示了MD。
请参阅详细信息。
有关从源头构建的详细信息,请参见详细信息。
Lambda-8cc是3个项目,Lambdavm,Elvm和8cc的组合。 Lambdavm是由该存储库(Lambda-8cc)的作者Hikaru Ikuta撰写的。 ELVM建筑由Shinichiro Hamaji撰写。 8cc由Rui Ueyama撰写。 Lambda-8cc中使用的8CC版本是8cc的修改版本,包括ELVM的一部分,由Shinichiro Hamaji修改。 Lambda-8cc还包括ELC,这是由Hikaru Ikuta修改的Shinichiro Hamaji撰写的ELVM的一部分,以便它可以将ELVM组装汇编为Lambda cyculus。 ELVM的Lambda微积分后端是由Hikaru Ikuta撰写的,它通过将Lambdavm集成到ELVM中。使用Melvin Zhang撰写的Lambda微积分解释器测量运行时间和内存使用统计信息。 Lam2bin由Justine Tunney撰写。