我对如何创建 javacc 解释器感到非常困惑,特别是如何从之前生成的 AST 树构建符号表。
类似这样的东西,来自这个 AST:
> Program
> Id
> Id
> Id
> VarDecl
> Type
> Id
> Stl
> Id
> NewInt
> IntLit
> Sta
> Id
> IntLit
> ParseArgs
> Id
> IntLit
> Sta
> Id
> IntLit
> ParseArgs
> Id
> IntLit
(…)
到此表
=== Symbol table ===
Name Type Init Values
---- ---- ---- ------
args args[] true 2 12 8
x int[] true 2 4 0
以此输入为例
class gcd {
public static void main(String[] args) {
int[] x;
x = new int[2];
x[0] = Integer.parseInt(args[0]);
x[1] = Integer.parseInt(args[1]);
if (x[0] == 0)
System.out.println(x[1]);
else
while (x[1] > 0) {
if (x[0] > x[1])
x[0] = x[0] - x[1];
else
x[1] = x[1] - x[0];
}
System.out.println(x[0]);
}
}
我现在所拥有的,仅创建 AST。
我的大问题是如何定义然后一一比较树上的类型。
任何帮助都会很棒,包括理论。
谢谢。
最佳答案
简单的答案是“遍历树,构建符号表”。
当您沿着树向下递归时,您将遇到作用域构造;为遇到的每个此类节点构建一个作用域,并将其插入作用域堆栈的顶部。当您访问引入该作用域的节点的声明子级时,将声明的定义插入作用域堆栈顶部的作用域中。当您从引入作用域的节点返回时,弹出作用域堆栈。瞧:词法范围语言的符号表。所有这些都独立于 JavaCC,并且在编译器书籍中得到了很好的解释;建议你买一本并仔细阅读。
具有命名空间的语言并不那么容易,但可以硬塞到这个结构中。有些语言的作用域之间的关系更为复杂,而这并不那么容易。
现在,要为 Java 执行此操作...类型系统的细节既复杂又神秘,并且了解类型语法含义的复杂性出人意料地复杂,尤其是。与模板化类型。没有任何编译器书籍可以在这方面为您提供帮助;如果您构建自己的符号表,则需要解释 Java 引用手册。预计这会相当困难;这是为了其他人。
当您遇到包引用时,您会发现其中一个“不太容易嵌套”的范围问题;要解析包含包引用的模块的名称,您首先必须找到引用的包的源文件或类文件,并为其构建符号表。这实际上意味着在为一个文件构建符号表的过程中,您可能必须进入文件系统,解析文件[作为文本或类]并为其构建符号表,然后再继续。
底线:对于符号表构建者来说,Java 充满了令人不便的意外。
(我构建程序分析工具。我们只花了几天时间就可以解析所有各种 Java 方言,部分原因是我们拥有非常好的解析机制;我们花了几个月的时间来构建一个适当的符号表一直到 Java 1.7,我们正在开发 Java 1.8)。
如果您确实想使用 AST 和符号表,那么最好获取/使用其他人的解析器/名称类型解析器。我想到了 JDT AST 机械。我的公司也在这个领域提供了一个工具。
关于compiler-construction - JavaCC 解释器(AST 到符号表),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23857356/