LAMBDA-8CC เป็นคอมไพเลอร์ x86 C ที่เขียนเป็นคำศัพท์แคลคูลัส Lambda ปิดเสาหิน
เมื่อพิมพ์ลงบนกระดาษขนาดตัวอักษรมันจะกลายเป็น 18,506 หน้าบน PDF 22 MB โดยไม่มีตัวเลขใด ๆ PDF สามารถเห็นได้ในหน้า GitHub ของฉันที่นี่ แหล่งกำเนิดน้ำยางคือ 448 MB และไฟล์บันทึกการรวบรวม LaTex main.log คือ 284 MB ฉันไม่อยากจะเชื่อเลยว่า Latex สามารถทำเช่นนั้นได้
คำศัพท์แคลลัสแลมบ์ดาขนาดมหึมานี้เป็นคอมไพเลอร์ C นี่คือ ROT13.C โปรแกรมที่รวบรวมบน GCC โดยไม่มีข้อผิดพลาด โปรแกรมเดียวกันนี้สามารถรวบรวมได้โดยใช้ Lambda-8cc ที่ผลิต X86 ROT13.bin ที่ทำงานได้ X86, Runnable บน X86/X86-64 Linux: Linux:
$ echo ' Hello, world! ' | ./rot13.bin
Uryyb, jbeyq !
$ echo ' Uryyb, jbeyq! ' | ./rot13.bin
Hello, world !แม้จะมีขนาดใหญ่ แต่การรวบรวม ROT13.C เสร็จสิ้นใน 8 นาทีบนเครื่องของฉันโดยใช้ล่ามแลมบ์ดาแคลคูลัส คุณสามารถลองใช้พีซีของคุณเองโดยการโคลน repo นี้ สถิติเวลาทำงานสรุปได้ในส่วนเวลาทำงานและการใช้หน่วยความจำ โปรดทราบว่าแม้ว่าการรวบรวมจะใช้เวลา แต่ไบนารีที่รวบรวมได้จะทำงานทันที
ในฐานะที่เป็นคุณสมบัติเพิ่มเติมไม่เพียง แต่ Lambda-8cc Compile C ถึง X86 เท่านั้น แต่ยังสามารถรวบรวม C ถึง Calculus Calculus ได้ซึ่งสร้างบางอย่างเช่น ROT13.LAM คำศัพท์แลมบ์ดาที่คอมไพล์ทำงานบนล่ามแลมบ์ดาแคลคูลัสเดียวกันที่ใช้ในการเรียกใช้ Lambda-8cc เอง
ด้วยการใช้ตัวเลือกการรวบรวม Lambda-8cc สามารถรวบรวม C เป็น 5 รูปแบบที่แตกต่างกัน นี่คือรายการคุณสมบัติทั้งหมด:
ในรายการคือ Lazy K ซึ่งเป็นภาษาที่ใช้งานได้อย่างหมดจดโดยมีผู้ให้บริการในตัวเพียง 4 คนคล้ายกับภาษา BF ที่จำเป็นน้อยที่สุดซึ่งมีเพียง 8 คำแนะนำ ฉันได้กล่าวถึงเรื่องนี้เล็กน้อยในโพสต์บล็อกของฉันเช่นกัน
Lambda-8cc ขึ้นอยู่กับ 3 โครงการต่อไปนี้: โครงการแรกคือ Lambdavm ที่เขียนโดยผู้เขียน REPO Hikaru Ikuta นี้ซึ่งเป็นซีพียูเสมือนจริงที่ตั้งโปรแกรมได้ซึ่งเขียนเป็นคำ Lambda Calculus นี่คือการรวมกับ 8cc โดย Rui Ueyama และ ELVM รุ่นดัดแปลงโดย Shinichiro Hamaji
หน้าแรกของ PDF มีลักษณะเช่นนี้ สังเกตจำนวนหน้าจำนวนด้านบนซ้าย:

ตอนจบที่ยิ่งใหญ่ของมันคือรอบของเสียงปรบมือโดยหน้าเต็มไปด้วยวงเล็บขวา:

Lambda-8cc เขียนเป็นคำศัพท์แคลลัสแลมบ์ดาที่ยังไม่ได้ปิดเครื่อง
ที่นี่แม้แต่สตริงก็ถูกเข้ารหัสเป็นเงื่อนไขแลมบ์ดา อักขระและไบต์ถูกเข้ารหัสเป็นรายการบิตด้วย
ดังนั้น ทุกอย่าง ในกระบวนการคำนวณรวมถึงจำนวนเต็มถูกปิดในโลกของคำศัพท์ลัมบ์ดาบริสุทธิ์โดยไม่จำเป็นต้องแนะนำวัตถุประเภทที่ไม่ใช่แลมบ์ดาใด ๆ มันไม่ได้ใช้ประเภทดั้งเดิมใด ๆ นอกเหนือจากแลมบ์ดา Lambda-8cc ทำให้เบต้าลดความต้องการเพียงอย่างเดียวสำหรับการรวบรวม C เป็น x86 โปรดทราบว่ากระบวนการไม่ได้ขึ้นอยู่กับตัวเลือกของชื่อตัวแปรเช่นกัน แทนที่จะเข้ารหัสอักขระ A เป็นตัวแปรที่มีชื่อ A ถูกเข้ารหัสเป็นรายการบิตของการเข้ารหัส ASCII 01000001
กระบวนการเข้ารหัสนั้นยุ่งยากเล็กน้อยที่จะพูดอย่างน้อยก็ต้องทำด้วยมือ สิ่งนี้สามารถแก้ไขได้โดยใช้ล่ามแลมบ์ดาแคลคูลัส ล่ามแลมบ์ดาแคลคูลัสต่าง ๆ จัดการรูปแบบ I/O นี้โดยอัตโนมัติเพื่อให้มันทำงานบนเทอร์มินัล - อินพุตมาตรฐานถูกเข้ารหัสเป็นคำแลมบ์ดาและคำสั่งเอาท์พุทแลมบ์ดาถูกถอดรหัสและแสดงบนเทอร์มินัล การใช้ล่ามเหล่านี้ Lambda-8cc สามารถทำงานบนเทอร์มินัลเพื่อรวบรวมโปรแกรม C เช่นเดียวกับ GCC
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการจัดการ I/O และวิธีการเขียนโปรแกรมใน Lambda Calculus โปรดดูรายละเอียดการใช้งานของโครงการ Lambdalisp อื่น ๆ ของฉันซึ่งเป็นล่าม LISP ที่เขียนขึ้นเป็นคำแลมบูลัสแลมบูลัส
นอกจาก X86 Lambda-8cc ยังสามารถรวบรวม C เป็น Lambda Calculus ได้เช่นกัน โปรแกรมเอาท์พุททำงานบนล่ามแลมบ์ดาแคลคูลัสเดียวกันที่ใช้ในการเรียกใช้แลมบ์ดา-8cc คำศัพท์แลมบ์ดาที่คอมไพล์ยังทำงานบนล่ามน้อยที่สุดเช่น 521-byte lambda calculus calculus sectorlambda ที่เขียนโดย Justine Tunney และล่าม IOCCC 2012 "การทำงานมากที่สุด" ที่เขียนโดย John Tromp สิ่งนี้ทำให้ Lambda-8cc อยู่ในตัวเองในขอบเขตของ Lambda Calculus
มันเป็นที่รู้จักกันมานานในวิทยาศาสตร์คอมพิวเตอร์ว่าแคลลัสแลมบ์ดาเป็นทัวริงที่สมบูรณ์ Lambda-8cc แสดงให้เห็นถึงสิ่งนี้ในวิธีที่ค่อนข้างตรงไปตรงมาโดยแสดงให้เห็นว่าโปรแกรม C สามารถรวบรวมโดยตรงในเงื่อนไขแคลคูลัสแลมบ์ดา
สิ่งที่ดีเกี่ยวกับแคลลัสแลมบ์ดาคือรายละเอียดภาษานั้นง่ายมาก ด้วย Lambda-8cc เรากำลังรักษาความรู้เกี่ยวกับวิธีการรวบรวม C ในวิธีการที่ไม่มีกาลเวลา แม้ว่ามนุษยชาติจะสูญเสียความรู้เกี่ยวกับชุดคำสั่ง x86 ตราบใดที่เราจำกฎสำหรับแคลลัสแลมบ์ดาและมีคำแลมบ์ดาสำหรับแลมบ์ดา-8cc เรายังสามารถใช้ภาษา C ทั้งหมดผ่าน Lambda-8cc และสร้างทุกอย่างบนมันอีกครั้ง
นี่คือโปรแกรม ROT13.C ที่เข้ารหัส/ถอดรหัสอินพุตมาตรฐานไปยัง/จาก Cipher 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 Zhanglam2bin : ยูทิลิตี้ที่เขียนโดย Justine Tunney (มีอยู่ที่ https://justine.lol/lambda/) ที่แปลงสัญลักษณ์แคลคูลัส Lambda Plaintext เช่น xx เป็นสัญลักษณ์แคลคูลัส Lambda Binary ซึ่งเป็นรูปแบบที่ยอมรับโดย Uni ++asc2bin : ยูทิลิตี้ที่บรรจุ 0/1 ASCII Bitstream ถึงไบต์เครื่องมือจะสร้างผ่านชุดพัฒนาแคลคูลัสแลมบ์ดา
การแปลงจาก 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 คุณสามารถใช้ไฟล์ swap กับ mkswap และ swapon เพื่อขยายการแลกเปลี่ยนโดยไม่ต้องกำหนดค่าการตั้งค่าพาร์ติชัน นอกจากนี้โดยการรวบรวมแอสเซมบลีและ X86 แยกกันได้แยกกันคุณสามารถลดการใช้ RAM ได้ครึ่งหนึ่งเป็น 65 GB ดังที่แสดงในส่วนการใช้งานโดยละเอียด โปรแกรมขนาดเล็กเช่น Putchar.c ใช้หน่วยความจำประมาณ 40 GB ฉันสงสัยว่าการใช้ RAM สามารถลดลงได้โดยการแนะนำ GC แบบทำเครื่องหมายและกวาดให้กับล่ามแม้ว่าฉันจะยังไม่ได้ยืนยันก็ตาม
สถิติเวลาทำงานมากขึ้นมีอยู่ในส่วนเวลาทำงานและการใช้หน่วยความจำ ตัวอย่างเพิ่มเติมโปรแกรม C ที่รวบรวมโดย Lambda-8cc สามารถพบได้ภายใต้ ./examples
ตัวเลือกการรวบรวมอื่น ๆ อธิบายไว้ในส่วนการใช้งานโดยละเอียด
การเขียนในแคลลัสแลมบ์ดาโดยธรรมชาติตัวเลือกการรวบรวมของแลมบ์ดา-8cc จะแสดงเป็นเงื่อนไขแคลคูลัสแลมบ์ดาเช่นกัน ตัวเลือกเหล่านี้สามารถใช้เพื่อปลดล็อกคุณสมบัติทั้งหมดของ Lambda-8cc
ตัวเลือกการรวบรวมถูกใช้โดยการใช้คำเสริมเป็น (lambda-8cc option) ล่วงหน้าของอินพุต สิ่งนี้เปลี่ยนพฤติกรรมของ Lambda Term lambda-8cc เพื่อให้ยอมรับ/สร้างรูปแบบอินพุต/เอาต์พุตที่แตกต่างกัน
นี่คือตัวเลือกการรวบรวมทั้งหมดของ Lambda-8cc:
| ป้อนข้อมูล | เอาท์พุท | ตัวเลือกการรวบรวม |
|---|---|---|
| C | x86 ปฏิบัติการได้ | |
| C | คำศัพท์แคลคูลัส Lambda Plaintext | |
| C | สัญลักษณ์แคลคูลัสไบนารีแลมบ์ดา (โปรแกรม BLC) | |
| C | สกี Combinator Calculus (โปรแกรม Lazy K) | |
| C | แอสเซมบลี ELVM | |
| แอสเซมบลี ELVM | x86 ปฏิบัติการได้ | |
| แอสเซมบลี ELVM | คำศัพท์แคลคูลัส Lambda Plaintext | |
| แอสเซมบลี ELVM | สัญลักษณ์แคลคูลัสไบนารีแลมบ์ดา (โปรแกรม BLC) | |
| แอสเซมบลี ELVM | สกี Combinator Calculus (โปรแกรม Lazy K) |
แต่ละตัวเลือกอยู่ในรูปแบบของ 3-tuple
ตัวเลือกการรวบรวมที่แสดงก่อนสามารถใช้ในเทอร์มินัลดังนี้
เพื่อรวบรวม 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 เพื่อรวบรวมรายการแอสเซมบลี ELVM as x86 ที่เรียกใช้งานได้ a.out :
( ( 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
| โปรแกรม | เวลารวบรวม | สูงสุด การใช้งาน 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/จาก rot13 |
| fizzbuzz.c | 49.7 นาที | 240 GB | 5,512 ไบต์ | พิมพ์ Fizzbuzz ลำดับสูงสุด 30 |
| primes.c | 53.0 นาที | 241 GB | 5,500 ไบต์ | พิมพ์ช่วงเวลาสูงถึง 100 |
ตอนนี้เป็นความทรงจำมากมาย! ในการรวบรวมโปรแกรมที่ต้องใช้ RAM ขนาดใหญ่คุณสามารถขยายพื้นที่แลกเปลี่ยนของคุณได้โดยไม่ต้องเปลี่ยนการตั้งค่าพาร์ติชันโดยใช้ไฟล์ SWAP หากคุณเรียกใช้ Linux และมีที่เก็บข้อมูลฟรีหรือไดรฟ์ USB คุณสามารถใช้ที่เก็บข้อมูลนั้นเพื่อขยายพื้นที่แลกเปลี่ยนของคุณอย่างง่ายดายและแบบไดนามิกโดยใช้ mkswap และ swapon สถิติในตารางนี้ทำงานด้วยพื้นที่แลกเปลี่ยนเพิ่มเติมด้วยวิธีนี้ คำแนะนำมีการอธิบายในเธรด Askubuntu นี้ ฉันสงสัยว่าการใช้ RAM สามารถลดลงได้โดยการแนะนำ GC แบบทำเครื่องหมายและกวาดให้กับล่ามแม้ว่าฉันจะยังไม่ได้ยืนยันก็ตาม
โปรดทราบว่าสิ่งเหล่านี้เป็นเวลาในการรวบรวม - เวลาทำงานของไบนารี x86 ที่คอมไพล์นั้นทันที สิ่งนี้ยังคงมีอยู่เมื่อรวบรวมเงื่อนไข C Lambda Calculus คำศัพท์แลมบ์ดาที่คอมไพล์ยังทำงานได้ทันทีและใช้หน่วยความจำเพียงไม่กี่กิกะไบต์เมื่อทำงานบนล่ามแลมบ์ดาแคลคูลัส
การรวบรวมสถิติเหล่านี้ทำงานบนเครื่อง Ubuntu 22.04.1 ที่มี RAM 48 GB, การแลกเปลี่ยน SSD 16GB (พาร์ติชันเริ่มต้น) และ 274GB (256GIB) การแลกเปลี่ยน HDD (เพิ่มแบบไดนามิกด้วย mkswap และ swapon ) เวลาทำงานที่แสดงที่นี่คือเวลาทำงานของนาฬิกาแขวนรวมถึงการทำงานของหน่วยความจำ สำหรับโปรแกรมแลกเปลี่ยนหนักเวลาทำงานอาจลดลงได้โดยใช้อุปกรณ์ที่มีความเร็ว I/O ที่เร็วขึ้น
สถิติถูกวัดโดยการวิ่ง
cp examples/[program].c ./input.c
make ซึ่งรวบรวม as และ a.out สำหรับ input.c แยกต่างหากเพื่อบันทึกการใช้หน่วยความจำทั้งหมด ตารางรายละเอียดเพิ่มเติมของสถิติสำหรับแต่ละบัตรจะแสดงในรายละเอียด md
โปรดดูรายละเอียด
สำหรับรายละเอียดเกี่ยวกับการสร้างจากแหล่งที่มาโปรดดูรายละเอียด MD
Lambda-8cc เป็นการรวมกันของ 3 โครงการ Lambdavm, ELVM และ 8CC Lambdavm เขียนโดย Hikaru Ikuta ผู้เขียนที่เก็บนี้ (Lambda-8cc) สถาปัตยกรรม ELVM เขียนโดย Shinichiro Hamaji 8cc เขียนโดย Rui Ueyama เวอร์ชัน 8cc ที่ใช้ใน Lambda-8cc เป็นรุ่น 8CC ที่แก้ไขแล้วรวมเป็นส่วนหนึ่งของ ELVM ดัดแปลงโดย Shinichiro Hamaji และอื่น ๆ Lambda-8cc ยังรวมถึง ELC ซึ่งเป็นส่วนหนึ่งของ ELVM ที่เขียนโดย Shinichiro Hamaji ดัดแปลงโดย Hikaru Ikuta เพื่อให้สามารถรวบรวม Assembly ELVM ไปยัง Lambda Calculus แบ็กเอนด์แลมบ์ดาแคลคูลัสสำหรับ ELVM เขียนโดย Hikaru Ikuta โดยรวม Lambdavm เข้ากับ ELVM สถิติการใช้งานเวลาและหน่วยความจำถูกวัดโดยใช้ล่ามแลมบ์ดาแคลคูลัสเขียนโดยเมลวินจาง Lam2bin เขียนโดย Justine Tunney