随想录(开源编译器ucc)

xiaoxiao2021-02-28  41

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com

 

    要说开源编译器,一般大家想到的都是gcc。但是现在gcc的代码量太大了,不太适合学习。代码量比较适合学习的编译器,如果google一下,基本上就剩下lcc和ucc这两个项目。其中,lcc支持多个cpu,而ucc目前只支持x86、且很长时间没有人维护了。但是从代码的可阅读性来说,我还是建议阅读ucc。ucc代码量一般,我统计了一下,大约15000行左右,结构也比较清晰。编译器当然可以用lex&bison来生成,但是看看ucc纯手工打造的软件,也是不错的学习体验。

 

注1(另一个简洁的编译器,和lua差不多):

https://github.com/rswier/c4/blob/master/c4.c

这是一个简单的c编译器,完成的词法分析、语法分析、代码编译、代码执行全部动作,关键是整个文件也就527行

编译的时候请编译成32位代码,即gcc -m32 c4.c -o c4

 

还有一个不错的c编译器,包含有c预处理功能

https://github.com/rui314/8cc

https://github.com/rui314/9cc

 

目前ucc只支持32位os,所以最好用32位ubuntu进行测试,比如32位的ubuntu 1604 os。

 

注2:

bnf范式是理解计算机最好的方式,编译原理也是区别于计算机和其他学科最重要的内容。如果大家阅读过形式化验证的方法,就会发现,验证的本质其实判断状态和逻辑的完整性,从某种意义上来说,这几乎已经是数学的范畴了。而所有的逻辑推理和归纳中,递归的思想最为重要。

 

1、代码可以从github进行阅读或者下载

https://github.com/sheisc/ucc162.3/tree/master/ucc

编译ucc的方法就是在顶层目录输入 make,

shell> make make -C driver make[1]: Entering directory '/home/fxx/Desktop/ucc-master/driver' gcc -o ucc -g ucc.c linux.c make[1]: Leaving directory '/home/fxx/Desktop/ucc-master/driver' make -C ucl make[1]: Entering directory '/home/fxx/Desktop/ucc-master/ucl' gcc -g -D_UCC -c -o alloc.o alloc.c gcc -g -D_UCC -c -o ast.o ast.c gcc -g -D_UCC -c -o decl.o decl.c gcc -g -D_UCC -c -o declchk.o declchk.c gcc -g -D_UCC -c -o dumpast.o dumpast.c gcc -g -D_UCC -c -o dom.o dom.c gcc -g -D_UCC -c -o emit.o emit.c gcc -g -D_UCC -c -o error.o error.c gcc -g -D_UCC -c -o expr.o expr.c gcc -g -D_UCC -c -o exprchk.o exprchk.c gcc -g -D_UCC -c -o flow.o flow.c gcc -g -D_UCC -c -o fold.o fold.c gcc -g -D_UCC -c -o gen.o gen.c gcc -g -D_UCC -c -o input.o input.c gcc -g -D_UCC -c -o lex.o lex.c gcc -g -D_UCC -c -o output.o output.c gcc -g -D_UCC -c -o reg.o reg.c gcc -g -D_UCC -c -o simp.o simp.c gcc -g -D_UCC -c -o stmt.o stmt.c gcc -g -D_UCC -c -o stmtchk.o stmtchk.c gcc -g -D_UCC -c -o str.o str.c gcc -g -D_UCC -c -o symbol.o symbol.c gcc -g -D_UCC -c -o tranexpr.o tranexpr.c gcc -g -D_UCC -c -o transtmt.o transtmt.c gcc -g -D_UCC -c -o type.o type.c gcc -g -D_UCC -c -o ucl.o ucl.c gcc -g -D_UCC -c -o uildasm.o uildasm.c gcc -g -D_UCC -c -o vector.o vector.c gcc -g -D_UCC -c -o x86.o x86.c gcc -g -D_UCC -c -o x86linux.o x86linux.c gcc -g -D_UCC -c -o assert.o assert.c gcc -o ucl -g -D_UCC alloc.o ast.o decl.o declchk.o dumpast.o dom.o emit.o error.o expr.o exprchk.o flow.o fold.o gen.o input.o lex.o output.o reg.o simp.o stmt.o stmtchk.o str.o symbol.o tranexpr.o transtmt.o type.o ucl.o uildasm.o vector.o x86.o x86linux.o make[1]: Leaving directory '/home/fxx/Desktop/ucc-master/ucl'

接着执行./ucl --dump-ast --dump-IR hello.c,这个时候会生成hello.s、hello.ast、hello.uil

其中hello.s表示汇编文件,hello.ast表示生成的语法树,hello.uil表示生成的中间代码文件

 

如果在使用中遇到32位程序的问题,可以尝试利用这篇博客提供的方法来解决。

 

ucc和lcc相比较,缺少一个c预处理程序。其实喜欢ucc的朋友可以直接将lcc的预处理程序copy过来,因为lcc的cpp本来就是一个独立执行的文件。

 

a,假设有一个iterate.c的文件,那么现在尝试用./ucl --dump-ast --dump-IR iterate.c进行编译

1 int 2 iterate(int data){ 3 4 if(1 == data) 5 return 1; 6 else 7 return iterate(data-1) + data; 8 }

b,生成的语法树为iterate.ast,

1 function iterate 2 { 3 (if (== 1 4 data) 5 (then 6 (ret 1) 7 end-then) 8 (else 9 (ret (+ (call iterate 10 (- data 11 1)) 12 data)) 13 end-else) 14 end-if) 15 } 16 ~

c,中间代码文件为iterate.uil,

1 function iterate 2 if (1 != data) goto BB0; 3 return 1; 4 goto BB1; 5 goto BB1; 6 BB0: 7 t0 = data + -1; 8 t1 = iterate(t0); 9 t2 = t1 + data; 10 return t2; 11 BB1: 12 ret 13 14

d,当然,少不了最后的iterate.s汇编文件,

1 # Code auto-generated by UCC 2 3 .data 4 5 6 7 8 .text 9 10 .globl iterate 11 12 iterate: 13 pushl
转载请注明原文地址: https://www.6miu.com/read-2612991.html

最新回复(0)