C0编译器的设计与实现实验报告
一、任务分工
经过讨论,我们了解到,词法分析、语法分析、语义分析以及解释执行模块中,词法分析以及解释执行是相对独立的,而语法语义分析是密不可分的,因此将分工划分如下:
李东岳:语法语义分析部分 李瑞婷:词法分析、解释执行
二、各自的分析设计以及问题解答
李东岳:语法语义分析部分
1、起始模块划分设计(在实现过程中发现不足有改动):
1)流程图:
第 1 页 共 25 页
流程图解释:
最开始的架构设计就是,在最主要的处理函数program里只处理int,void语句,因为不管全局变量、自定义函数还是主函数都是以int或void开头,而遇到不同的语句会调用不同的变量定义integer,有返回值函数intproject_d,无返回值函数voidproject_d以及主函数mainproject的相应处理函数。
把{}里的内容都看成是语句,调用语句处理,可分为赋值语句,if语句,while语句,scanf语句,printf语句以及局部变量定义语句,对应不同语句调用不同的函数处理。
语句处理又会调用表达式处理,表达式处理又会用到项处理,项处理又会用到因子处理,用到时调用即可。
2)需要用到的定义 enum object {
integer,intproject,voidproject };
将自定义的标识符分为三类,一类是整形变量integer,一类是有返回值的函数intproject,一类是无返回值的函数voidproject。
struct table1 {
char name[AL]; enum object kind; int val; int level; int adr; int size; };
struct table1 table[TXMAX+1];
符号表,储存自定义标识符的各对应内容,name即名字,kind即类型,val即变量的值,level即标识符所在层,adr对应变量的偏移量函数的入口地址,size即函数的大小。
struct instruction {
enum fct f; int l; int a; };
struct instruction code[CXMAX+1];
将需要保存的栈式指令保存到code数组,以便在解释执行时使用。其中,fa代表栈式指令,l代表层数,a根据不同指令有不同定义。
enum fct {
LIT,LOD,STO,CAL,INT,JMP,JPC,ADD,SUB,MUL,DIV,RED,WRT,RET };
将需要用到的栈式指令定义,以便将相应指令加到目标代码指令数组code。
第 2 页 共 25 页
3)语法语义分析主要任务:一次扫描源程序,将词法分析得到的单词进行分析,并对应相应的类型进行处理,处理过程需要(sym,id/num)二元组对单词类别及内容进行储存。将变量、函数及其各性质加入名字表table。在处理到需要转为指令的单词时,要产生相应指令,并存入code数组。
4)各主要接口的设计 a)program
program函数主要设计的目的是,每次循环只是识别int和void。
int会有两种情况,一种是全局变量的定义,一种是有返回值函数的定义,读到后根据后跟符号是,和;可以判断是全局变量定义则转而执行integer函数;后跟符号是(可以判断是有返回值的函数,调用intproject_d函数。
void也会有两种情况,一种是主函数main,一种是无返回值函数的定义,由于在词法分析时会把main的sym存储为mainsym,而普通的函数存储为ident,因此可以通过sym判断,再调用相应的处理函数voidproject_d和mainproject即可。
b)intproject_d
int定义函数,需要有()以及{},如果没有则报错。把{}之间的内容都视为语句,读到{后调用statement即可。但需要注意的是,int是有返回值的函数,要注意return的处理。
c)voidproject_d
void定义函数,需要有()以及{},如果没有则报错。把{}之间的内容都视为语句,读到{后调用statement即可。
d)mainproject
main定义函数,需要有()以及{},如果没有则报错。把{}之间的内容都视为语句,读到{后调用statement即可。
e)statement
语句大致可分为几种:
局部变量定义,调用定义函数即可;
赋值语句,调用表达式处理expression; if-else语句,调用if_stat; while语句,调用while_stat; scanf语句,调用scanf_stat; printf语句,调用printf_stat; f)expression
读到自定义标识符即转到expression处理,标识符又分为变量和自定义函数,可以根据table表的kind进行区别。expression会调用相应项处理,项处理又会调用相应因子处理。
2、具体实现过程(代码实现,问题发现,改进设计)
1)各模块的简要算法,过程中遇到的问题及解决方案 a)program
问题1、全局变量层到底需不需要像函数层一样有返回值RA和动态连DL? 在与解释执行设计者李瑞婷讨论后,发现全局变量层的RA和DL没有太实际的意义,为更简化栈,选择不开辟空间,因此只是有几个全局变量就开辟几个空
第 3 页 共 25 页