January 1, 0001
因为SysY里的const
完全是编译期计算的(实际上是constexpr
),所以可以在语义分析阶段就把常量全算完存进符号表,后面IR生成就不用管常量语句了;同理,语义分析阶段也不应该为变量赋实值。
用setjmp()
和longjmp()
整了一套异常系统,好玩。
语法分析阶段,我的设计是把三个list直接给flatten掉。理论上没什么问题,但是要注意一点:LR分析器的基本规则是后序遍历,所以不需要、也不能按照如下的前序遍历(LL)思路设置不动点:
ConstDefList
: ConstDef {
/* ... */
this_ConstDefList = NULL;
}
| ConstDef COMMA ConstDefList {
if (!this_ConstDefList)
this_ConstDefList = /* ... */;
/* ... */
}
;
其实完全没这么复杂,只需要在ConstDef
处创建结点,然后在每次规约的时候往里面加child就可以了。
从这里也可以看出来,虽然对树的前序、后序遍历都需要下推自动机,但后序的表达能力是比先序要强一点,主要是后序的平均栈深度要大不少,context也更明确。
实际上,codegen的过程,就是把递归的数据结构扁平(迭代)化的过程,而这个过程我们刚才其实已经做过了,借助的是this_ConstDefList
这一全局变量。
07_var_main.c里头竟然写了个这个东西……
int main() {
int main = 10;
return main;
}
留到Lv5再做算了,这很明显是跟符号定义和作用域有关的。
代码生成时仅仅为alloc
指令分配了栈空间,而其余部分的表达式计算、常量计算等全部都是用寄存器完成。感觉这样如果不call的话还算合理,但是一旦要call,需要保存的寄存器数量应该不少。
prologue和epilogue写得有点混乱了,之后得看看怎么重构。