c4c语言编译器,c4编译器源码剖析

c4_source

1. 概述

c4是500行代码实现一个c语言编译器

简单暴力,适合了解基础的编译器原理

1

2

3

2. 主流程

1.建立系统符号表

2.读取源代码

3.一次遍历源代码,同时进行词法分析,语法分析和中间代码生成。

4.执行中间代码

1

2

3

4

5

3. 中间代码

3.1. 基础

中间代码

操作

意义

LEA 2

将栈往上的2个位置变量加载到寄存器

加载本地变量

IMM

将代码区位置指定的代码加载到寄存器

加载到全局变量

JMP 2

将代码区跳转到2这个位置

跳转

JSR 2

将下一个代码区位置保存到栈顶,并将代码区跳转到2这个位置

跳转到子程序

BZ 2

如果全局变量为a,则跳转到下一个代码区域,否则跳转到2这个位置

零跳转

BNZ 2

如果全局变量不为a,则跳转到下一个代码区域,否则跳转到2这个位置

非零跳转

ENT 2

保存前一个程序的栈顶到当前栈上,并设置新栈顶,和局部变量区

开辟一个新的子程序

ADJ 2

栈调整,往前2个位置

栈跳转

LEV

栈回滚到当前程序的栈顶,然后恢复上一个程序的栈顶,再恢复上一个程序的代码区,最后恢复上一个程序的栈

子程序退出

LI

将寄存器的整数变量加载出来

加载整数

LC

将寄存器的字符变量加载出来

加载字符

SI

将栈顶指定位置的地址保存整数

保存整数

SC

将栈顶指定位置的地址保存字符

保存字符

PSH

将寄存器变量保存到栈上

保存栈

EXIT

将栈顶变量打印出来,作为返回值,并退出来

退出整个程序

3.2. 运算

OR,XOR,AND,EQ,NE,LT,GT,LE,GE,SHL,SHR,ADD,SUB,MUL,DIV,MOD

都是二元操作符,都是将栈顶变量取出来,然后与寄存器运算,再存回到寄存器

1

2

3

3.3. 系统调用

OPEN,READ,CLOS,PRTF,MALC,MSET,MCMP,

都是系统调用,将栈顶变量作为参数,逐一打印出来

1

2

3

3.4. 范例

3.4.1. 函数调用

函数调用前,先将参数逐个放入栈中

IMM 3,

PSH,

IMM 4,

PSH

然后执行JSR跳转到子程序

JSR -145211380

上述代码相当于调用函数

xxxx(4,3)

这时候栈的内容为:

[3,4,下一行代码的pc位置]

子程序执行完毕后,栈的内容为

[3,4]

重置堆栈位置,去掉参数

ADJ 2

这时栈的内容为

[]

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

3.4.2. 函数执行

ENT 0

开始执行函数,函数的局部变量为0个,所以为ENT 0,这是栈的内容为

[3,4,下一行代码的pc位置,上一个程序的栈底]

LEA 3

LI

PSH

[3,4,下一行代码的pc位置,上一个程序的栈底,3]

LEA 2

LI

ADD

[3,4,下一行代码的pc位置,上一个程序的栈底,7]

将栈顶存入的两个参数运算放入到寄存器中

LEV

离开函数,恢复上一个程序的pc位置,以及栈底

[3,4]

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

3.5 总结

c4的中间代码是一个基于寄存器的vm。

其只有一个寄存器变量,为a

有一个栈存储区,当前栈顶位置为sp,每个函数有自己的栈底bp,存储区域为stack area

有一个代码区,当前执行代码位置为pc,存储区域为text area

有一个数据区,存储区域为data area

1

2

3

4

5

6

4. 符号表

4.1. 符号类型

enum {

Num = 128, Fun, Sys, Glo, Loc, Id,

Char, Else, Enum, If, Int, Return, Sizeof, While,

};

1

2

3

4

5

4.2. 符号表存放

int *sym, // symbol table (simple list of identifiers)

enum { Tk, Hash, Name, Class, Type, Val, HClass, HType, HVal, Idsz };

符号表是一个长数组,每个数组的元素为符号描述,元素长度为Idsz

每个符号元素包括的信息为:

Tk 符号类型,id类型,用来区分是否为关键字的

Hash 符号哈希

Name 符号名字

Class 变量类型,Num = 128(常数)Fun(函数)Sys(系统调用) Glo(全局变量) Loc(本地变量) Id

Type 变量数值类型,char,int,ptr,还是*char,*int,*ptr,还是**char,**int,**ptr

Val 变量的值,对应不同的数据类型有不同的值

1

2

3

4

5

6

7

8

9

10

11

4.3. 关键字符号表

Char, Else, Enum, If, Int, Return, Sizeof, While

以上Id在符号表上都是有特殊的Tk值

1

2

3

4.4. 系统调用符号表

open read close printf malloc memset memcmp exit

以上Id在符号表上的Class为Sys,Type为Int,Val为特殊值

1

2

3

4.5. 特殊符号表

void 的符号设置为和Char一样

main 的符号位置被记录

1

2

3

5.流程

5.1. 配置文件

识别配置文件中的-s -d参数

1

2

5.2. 配置vm环境

建立源代码区域

建立符号表区域

建立text area

建立data area

建立stack area

1

2

3

4

5

6

7

5.3. 初始化符号表

初始化关键字符号表,系统调用符号表,和特殊符号表

1

2

5.4. 读取源代码

将源代码文件整个写入到源代码区域。

1

2

5.5. 词法分析,语法分析与中间代码生成

c4的代码很简洁,一次遍历源代码,同时执行词法分析,语法分析,和中间代码生成

1

2

5.5.1. 词法分析

词法分析,在next()函数中实现。

每解析一个词语,就将

结果类型写入到tk变量,

变量值写入到ival变量

id类的变量还会顺道写入到符号表中

1

2

3

4

5

6

5.5.2. 语法分析

语法分析,在main,stmt,expr中都有实现。

其中main负责主流程的语法分析,包括全局变量定义,枚举体定义,函数定义

stmt负责分支循环语句的语法分析,包括if,while,return

expr负责运算符语句的语法分析,包括加减乘除赋值等等

1

2

3

4

5

5.5.3. 中间代码生成

c4是在语法分析的过程中生成中间代码的。

main中,碰到枚举体定义时,更新符号表。碰到全局变量定义时,加入data area和符号表。碰到函数定义时,生成ENT和LEV的中间代码

stmt中,碰到if,while,return,生成对应的BZ,BNZ,JMP的中间代码

expr中,根据不同的预算符,将变量计算,并将结果均写入到寄存器中。

1

2

3

4

5

5.6. 执行中间代码

在符号表中确定main函数的位置。

初始化退出代码,PSH和EXIT

根据text area,执行中间代码,不断更新stack area与data area

1

2

3

4

6.总结

c4的代码简洁,但较难懂,好多变量都是缩写。

功能齐全,满足编译器开发的,词法分析,语法分析,目标代码生成的三个基本步骤。

并实现了自举,可以自己编译自己。

./c4 c4.c c4.c hello.c。

转自:http://blog.csdn.net/fishmei/article/details/50777998

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值