2

我对如何创建 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。

我的大问题是如何定义然后逐一比较树上的类型。

任何帮助都会很棒,包括理论。

谢谢。

4

1 回答 1

3

简单的答案是,“遍历树,构建符号表”。

当你沿着树递归时,你会遇到作用域构造;为遇到的每个此类节点构建一个范围,并推送到范围堆栈的顶部。当您访问引入该范围的节点的声明子节点时,将声明的定义插入范围堆栈顶部的范围中。当您从引入范围的节点返回时,弹出您的范围堆栈。瞧:词法范围语言的符号表。所有这些都独立于 JavaCC,并且在编译器书籍中有很好的解释;建议你买一本仔细阅读。

具有名称空间的语言并不那么容易,但可以硬塞进这种结构中。有些语言的范围之间的关系更复杂,这并不容易。

现在,要为 Java 做这件事……类型系统的细节是复杂而神秘的,知道类型的语法意味着什么的复杂性令人惊讶地复杂,尤其是。使用模板类型。没有编译器书籍可以帮助您;如果您构建自己的符号表,则需要解释 Java 参考手册。预计这将非常困难;它适用于其他所有人。

当您遇到包引用时,您会发现其中一个“不那么容易嵌套”的范围问题;要解析包含包引用的模块的名称,您首先必须找到所引用包的源文件或类文件并为其构建符号。这实际上意味着在为一个文件构建符号表的过程中,您可能必须进入文件系统,解析文件 [作为文本或类] 并在继续之前为其构建符号表。

底线:Java 对符号表构建者来说充满了不便的惊喜。

(我构建了程序分析工具。我们只花了几天时间就可以解析所有各种 Java 方言,部分原因是我们有非常好的解析机制;我们花了几个月的时间来构建一个通过 Java 1.7 的适当符号表,我们现在在 Java 1.8 上工作)。

如果您真的想使用 AST 和符号表,最好获取/使用其他人的解析器/名称类型解析器。想到 JDT AST 机器。我的公司也在这个领域提供了一个工具。

于 2014-05-25T16:21:22.247 回答