基础信息
本代码是在以下项目的基础上进行完善:
之前已经完成:词法分析,语法分析,语义分析
词法分析没有改变,语法分析有细微的变动
另外写了一个 makefile 文件:
1 | OBJS=main.o tool1.o tool2.o |
语法分析
添加了一个规则用于表示数组列表:
1 | ArrayList: LB Exp RB ArrayList {$$=mknode(ARRAY_LIST,$2,$4,NULL,yylineno);} |
- PS:其实这里根本没有用到第一条路径,后面会进行说明
对于数组来说,需要用到 ArrayList 的地方只有两处:
- 数组定义
1 | VarDec: ID {$$=mknode(ID,NULL,NULL,NULL,yylineno);strcpy($$->type_id,$1);} |
- 数组使用(可以把数组看做一种表达式)
1 | Exp: Exp ASSIGNOP Exp {$$=mknode(ASSIGNOP,$1,$3,NULL,yylineno);strcpy($$->type_id,"ASSIGNOP");} |
这里有一处细节需要说明:案例 arr[4][5][6]
- 分解后的结构如下:
1 | arr => ID(arr) |
- 在实际构造 AST 时,程序会从下往上进行遍历分析
- 发现 ArrayList 永远是
LB Exp RB
,不会走第一条路径(刚开始设计时害怕程序识别不了多个LB Exp RB
于是就写了一个递归的规则)
语义分析
语义分析部分主要是对多级数组进行处理
首先对符号表结构进行了修改,添加了一个条目用于存储数组各级的大小
1 | struct symbol |
对全局数组定义的处理:
1 | void ext_var_list(struct node *T,int is_arr) /* EXT_DEC_LIST */ |
- 核心点其实就是一个递归调用,不断调用
ext_var_list
直到 T->kind 为 ID - 然后进行回溯,同时向
symbolTable.symbols[place].array
中填入各级数组的值
对局部数组定义的处理:
1 | void var_def(struct node *T) /* TYPE || DEC_LIST */ |
- 这里就没有采用递归的做法(因为要处理变量初始化,很难实现递归),而是直接遍历链表
- 这样做会导致顺序问题,因为之前是在递归函数回溯时填写符号表的,相当于一个逆序操作,而遍历则是一个顺序操作
- 为了这两者的顺序统一,就写了一个
arr[32]
来暂时存放各级数组的数值,然后逆序取出
对数组使用的处理:
1 | void array_exp(struct node *T,struct node **Tr,int *sum,int key) |
- 传入的参数 key 用于表示 左边/右边 为数组,Tr 和 sum 是需要外传的参数
- 使用公式把多维数组转化为一维数组
- 数组通常在赋值语句中发挥作用,于是就有3种情况发生:
- 赋值语句左边为数组,右边不是
- 赋值语句右边为数组,左边不是
- 赋值语句左右两边都是数组
在赋值语句中添加对数组的处理:
1 | void assignop_exp(struct node *T) |
- 按照常规的逻辑进行处理就好
另外此版本的编译器还修改了一些“函数参数处理”中的 BUG:
1 | int match_param(int i, struct node *T) /* PARAM_DEC,PARAM_LIST || PARAM_DEC */ |
- 添加了报错处理
生成 IR 中间语言
最后修改了一下打印函数:
1 | void DisplaySymbolTable(struct node *T) |
- 打开
inter.txt
文件,并把中间代码写入其中
1 | void print_IR(struct codenode *head) |
- 在生成的中间代码中会标识数组的类型
- 全局变量也会被添加到中间代码中
下个版本打算添加对 “结构体” 和 “指针” 的处理