Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Optimization 为一种具有前瞻性和多个文件的语言编写编译器?_Optimization_Compiler Construction_Build Process_Compiler Theory_Compiler Optimization - Fatal编程技术网

Optimization 为一种具有前瞻性和多个文件的语言编写编译器?

Optimization 为一种具有前瞻性和多个文件的语言编写编译器?,optimization,compiler-construction,build-process,compiler-theory,compiler-optimization,Optimization,Compiler Construction,Build Process,Compiler Theory,Compiler Optimization,在我的语言中,当定义出现在方法下面时,我可以在方法中使用类变量。它还可以调用我的方法下面的方法等。没有“头”。以这个C#为例 我应该如何编译它?我想的是: 过程1:将所有内容转换为AST pass2:遍历所有类并构建定义类/变量/等的列表 pass3:检查代码并检查是否有任何错误,如未定义的变量、错误的使用等,然后创建我的输出 但是为了让它工作,我必须在做pass3之前对所有文件做pass1和pass2。此外,在我发现语法错误之前,感觉还有很多工作要做(除了在解析时可以完成的明显错误,例如忘

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

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

  • 过程1:将所有内容转换为AST
  • pass2:遍历所有类并构建定义类/变量/等的列表
  • pass3:检查代码并检查是否有任何错误,如未定义的变量、错误的使用等,然后创建我的输出
但是为了让它工作,我必须在做pass3之前对所有文件做pass1和pass2。此外,在我发现语法错误之前,感觉还有很多工作要做(除了在解析时可以完成的明显错误,例如忘记关闭大括号或写入0xLETTERS而不是十六进制值)。我的直觉告诉我还有别的办法


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

我将在第1步中完成并收集所有类/方法/字段名和类型,忽略方法体。然后在第二遍中只检查方法体。

我对处理前向引用的语言的理解是,它们通常只使用第一遍来构建有效名称列表。类似于将一个条目放入表中(而不填写定义),这样在以后生成定义的实际过程中,您就可以指向某些内容


如果您试图在运行过程中实际构建完整的定义,那么最终将不得不重新扫描repatedly,每次都将对未定义内容的任何引用保存到下一个过程。如果存在循环引用,即使这样也会失败。

我不知道除了遍历源代码中的所有文件之外,还有什么其他方法

我认为您可以将其归结为两个过程——在第一个过程中,构建AST,并且每当您找到一个变量名时,将其添加到包含该块符号的列表中(将该列表添加到树中的相应范围可能会很有用)。第二步是线性遍历树,确保使用的每个符号都引用该范围内的符号或其上方的范围


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

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

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

然后,当你遇到
B
和方法时,你可以清除你的未知。由于您对它们有一点了解,您可以说它们的行为是否应该如此,或者第一次使用是否是语法错误

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

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


最后,如果你写了一种新的语言,你不应该再使用bison和flex了。现在有了更好的工具,例如,您可以生成一个可以在发生错误后恢复的解析器,因此您仍然可以解析整个文件。或者查看更多选项。

例如?在阅读了一本关于Bison的书之后,它看起来非常有趣,而且是一个不错的工具。在我的答案中添加了几个链接。Bison解析器也可以在出错后恢复,使用特殊的
error
nonterminal。@Edmund:ANTLR解析器会自动执行此操作,该工具会提供更好的错误消息,它在单个文件中处理标记和语法,语法的语法更好一些。最后,它可以生成多种语言的语法,而Bison仅限于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"); }
}