【问题标题】:Write a compiler for a language that looks ahead and multiple files?为一种向前看的语言和多个文件编写编译器?
【发布时间】:2009-10-16 15:32:57
【问题描述】:

在我的语言中,当定义出现在方法下方时,我可以在方法中使用类变量。它还可以调用我的方法等下面的方法。没有“标题”。以这个 C# 为例。

class A
{
    public void callMethods() { print(); B b; b.notYetSeen();
    public void print() { Console.Write("v = {0}", v); }
    int v=9;
}

class B
{
    public void notYetSeen() { Console.Write("notYetSeen()\n"); }
}

我应该如何编译它?我的想法是:

  • pass1:将所有内容都转换为 AST
  • pass2:遍历所有类并构建定义类/变量/等的列表
  • pass3:检查代码并检查是否存在未定义变量、错误使用等错误并创建我的输出

但似乎要让它工作,我必须在做 pass3 之前为所有文件做 pass 1 和 2。在我发现语法错误之前感觉还有很多工作要做(除了可以在解析时完成的明显操作,例如忘记关闭大括号或写入 0xLETTERS 而不是十六进制值)。我的直觉告诉我还有其他方法。

注意:我正在使用 bison/flex 来生成我的编译器。

【问题讨论】:

    标签: optimization compiler-construction build-process compiler-theory compiler-optimization


    【解决方案1】:

    我对处理前向引用的语言的理解是,它们通常只使用第一遍来构建有效名称列表。类似于将条目放入表中(不填写定义)这样的东西,以便稍后在您进行真正的传递以生成定义时指向一些东西。

    如果您尝试实际构建完整的定义,您最终将不得不重新扫描,每次都保存对未定义事物的任何引用,直到下一次通过。如果有循环引用,即使这样也会失败。

    【讨论】:

      【解决方案2】:

      我将通过第一遍并收集您所有的类/方法/字段名称和类型,忽略方法主体。然后通过两个检查方法体。

      【讨论】:

        【解决方案3】:

        我不知道除了遍历源中的所有文件还有其他方法。

        我认为你可以把它减少到两遍——在第一遍时,构建 AST,每当你找到一个变量名时,将它添加到包含该块符号的列表中(添加该列表到树中的相应范围)。第二步是线性遍历树,并确保使用的每个符号都引用了该范围内的符号或其上方的范围。

        我的描述过于简单,但基本答案是——前瞻至少需要两次。

        【讨论】:

          【解决方案4】:

          通常的方法是将B 保存为“未知”。它可能是某种类型(因为你遇到它的地方)。所以即使你不知道它到底是什么,你也可以为它保留内存(一个指针)。

          对于方法调用,你无能为力。在动态语言中,您只需将方法的名称保存在某处并在运行时检查它是否存在。在静态语言中,您可以将其与未知类型 B 一起保存在编译器某处的“未知方法”下。由于方法调用最终会转换为内存地址,因此您可以再次保留内存。

          然后,当你遇到B 和方法时,你可以清除你的未知数。由于您对它们有所了解,因此您可以说出它们的行为是否符合预期,或者现在第一次使用是否是语法错误。

          因此您不必将所有文件都读取两次,但这确实使事情变得更简单。

          或者,您可以在遇到源代码时生成这些头文件,并将它们保存在可以再次找到它们的地方。这样,您可以加快编译速度(因为您不必在下次编译运行时考虑未更改的文件)。

          最后,如果您编写一门新语言,则不应再使用 bison 和 flex。现在有更好的工具。例如,ANTLR 可以生成一个可以在出错后恢复的解析器,因此您仍然可以解析整个文件。或查看this Wikipedia article 了解更多选项。

          【讨论】:

          • 比如?读完一本关于 bision 的书后,它似乎很有趣,而且根本不是一个坏工具。
          • 在我的答案中添加了几个链接。
          • Bison 解析器也可以在错误后恢复,使用特殊的 error 非终端。
          • @Edmund:ANTLR 解析器自动执行此操作,该工具提供了更好的错误消息,它在单个文件中处理标记和语法,并且语法的语法更好一些。最后,它可以生成多种语言的语法,而 Bison 仅限于 C。
          猜你喜欢
          • 2011-03-01
          • 1970-01-01
          • 2010-11-16
          • 2015-02-15
          • 1970-01-01
          • 2011-07-16
          • 1970-01-01
          • 1970-01-01
          • 2011-05-15
          相关资源
          最近更新 更多