在编译器中生成中间代码.在处理条件时,是否始终需要AST或解析树?

Viv*_*ath 8 compiler-construction parsing language-design intermediate-code

我正在使用编译器设计类,我们必须实现自己的编译器(使用flex和bison).我曾在解析(写入EBNF的和递归下降解析器)的经验,但是这是我第一次写的编译器.

语言设计非常开放(教授把它留给了我们).在课堂上,教授过去生成中间代码.他说,这是没有必要为我们构建一个抽象语法树或在解析解析树,而且因为我们去,我们可以生成中间代码.

我发现这令人困惑有两个原因:

  • 如果定义函数之前调用函数怎么办?你如何解决分支目标?我想你必须制定一个规则,你必须在使用之前定义函数,或者可能预先定义它们(比如C吗?)

  • 你会如何处理条件?如果你有一个if-else甚至只是一个if,你怎么能解决分支目标为if在条件false(如果你是因为你去生成代码)?

我计划生成AST然后在创建它之后走树,以解析函数和分支目标的地址.这是正确的还是我错过了什么?

Dou*_*rie 8

解决这两个问题的一般方法是保留需要"修补"的地址列表.您生成代码并为丢失的地址或偏移留下漏洞.在编译单元的末尾,您将浏览孔列表并将其填入.

在FORTH中,补丁的"列表"保留在控制堆栈上,并在每个控制结构终止时展开.请参阅FORTH尺寸

轶事:一个早期的Lisp编译器(我相信它是Lisp)生成了一个符号格式的机器代码指令列表,带有对条件的每个分支的机器代码列表的前向引用.然后它生成了向后走的列表的二进制代码.这样,当需要发出分支指令时,所有前向分支的代码位置都是已知的.