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

时间:2011-03-19 01:28:43

标签: parsing language-design compiler-construction intermediate-code

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

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

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

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

  • 你会如何处理条件?如果您有if-else甚至只有if,那么当条件为if时,如果您生成代码,如何解析false的分支目标你去)?

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

2 个答案:

答案 0 :(得分:8)

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

在FORTH中,补丁的“列表”保留在控制堆栈上,并在每个控制结构终止时展开。见FORTH Dimensions

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

答案 1 :(得分:1)

Crenshaw tutorial是使用任何类型的AST的 not 的具体示例。它构建了一个有效的编译器(显然包括条件),可立即生成针对m68k汇编的代码。

您可以在下午阅读该文档,这是值得的。