为什么编译器这么难写?
0 410
1
该提问暂无详细描述
收藏
2021-01-16 13:58 更新 anna •  5042
共 1 个回答
高赞 时间
0

这里有一些我想到的实际问题。

1.你需要了解很多知识。一方面是解析器,另一方面是目标计算机的详细信息,以及如何从A转换为B。当然,语言语义也非常复杂。

2.人们期望你的结果是非常非常理想的。他们会将你的与他们知道的最快的编译器进行比较。他们将与手工编码的程序集进行比较。他们会假设(通常是错误地)他们会比一个好的编译器更好地手工编码。

除了相当简单的事情之外,优化可能非常困难。而且,你必须确保你的优化确实可以在实际代码中提高目标体系结构的性能。这样的循环展开功能可以消除分支开销吗?可能会导致缓存冲突,并使代码运行速度变慢,而不是超过一定大小而变快?

3.管理目标计算机的资源可能很复杂。寄存器机器往往比堆栈计算机要复杂一些,至少在你完全有效利用寄存器的情况下!基本问题是,“鉴于这些基本块,将变量分配给寄存器的最佳方法是什么?”

4.人们期望你的编译器能够快速编译。因此,寻找最佳优化的算法并非起步,甚至看似简单和快速的事情也可以轻松地与其他优化交互,并真正使编译器进行爬网。

5.解析器中好的错误处理异常困难。比编写用于中途语言语法的解析器更难。你需要提出对人类有意义的错误消息,然后你需要确定源中人类需要修复的实际问题所在的部分,通常是在你发现问题之前就将其修复。

6.更糟糕的是,人们希望你在输入无效后继续解析,并产生所有问题,而不仅仅是第一个。因此,你必须找出一种方法在哪里进行备份,以便从那里生成合理的错误。

这既很难设计-如何同步备份-也很难编码-如何使解析器进入适当的状态,就像先前的代码是有效的一样。有多种方法可以执行此操作,但请参阅#1。

7.平交路口可以使你的电线交叉。编译器基本上是一系列保留语义的转换。假设你有一个寄存器分配阶段,一个生成阶段,然后是一个对生成的二进制进行操作的优化阶段,从而消除了不需要的指令或替换了某些指令序列。

进一步说,某些允许的优化需要知道某个特定点是否正在使用寄存器。因此,为此,你的分配阶段需要将两个级别的信息传达到指令优化阶段。如果计划的话,也不太难-但请参阅上面的#1。

8.即使是经过良好测试的编译器,也可能会存在许多年未发现的错误,例如,适当的情况组合会导致优化误入歧途,例如破坏一些仍在使用的寄存器,或对语言规范的细微误解,以至于没有人会偶然发现,但是有人会自动生成代码并成功解决问题。

每个大型程序都有错误-但是编译器错误特别痛苦。它们破坏了使用该编译器构建的每个程序的可靠性,而且跟踪起来非常昂贵。特别是因为人们认为问题不是编译器。这些年来,我在生产编译器中发现了许多错误。

9.编译器不断发展。语言功能已添加。需要新的优化。也许甚至需要新的目标体系结构。你必须进行设计以支持变更,并着眼于持续测试。你绝对需要一个完善的开发过程。

10.尽管你有免责声明,但某人可能将你的编译器用于至关重要的用途。

如前所述,编译器本质上是一串保留语义的转换。如果你坚持使用一种简单的语言,一种针对目标的简单执行模型,并避免每个阶段的复杂性,那么基本的编译器实际上并没有那么难(无论如何,在最初的几个之后)。

我可以设计一种语言,为其编译器,并在一天内轻松实现它。但这通常不是现实世界中的任务。通常,每个步骤都有更大的复杂性或性能要求。

收藏
2021-01-16 15:05 更新 karry •  4540