Parsing 现代编译器使用哪些解析器?

Parsing 现代编译器使用哪些解析器?,parsing,compiler-construction,abstract-syntax-tree,Parsing,Compiler Construction,Abstract Syntax Tree,我找不到关于一些现代编译器的解析器的任何信息,特别是: 打字稿 C# 生锈 他们使用的是LL(k)、LR(k)、混合物还是其他东西?是否有任何网站列出了关于多语言编译器/解析器的类似信息?由于这些编译器通常被认为是“现代的”,我对它们的解析技术非常感兴趣。它们三个都使用特殊的、手工构建的解析器,松散地基于预测(自顶向下)解析,在自顶向下解析不确定的情况下,使用任何看起来必要的乱七八糟的东西 我当然不推荐将此作为如何构建解析器的模型,如果您希望这样做的话。使用解析器生成器构建解析器要容易得多;

我找不到关于一些现代编译器的解析器的任何信息,特别是:

  • 打字稿
  • C#
  • 生锈

他们使用的是LL(k)、LR(k)、混合物还是其他东西?是否有任何网站列出了关于多语言编译器/解析器的类似信息?由于这些编译器通常被认为是“现代的”,我对它们的解析技术非常感兴趣。

它们三个都使用特殊的、手工构建的解析器,松散地基于预测(自顶向下)解析,在自顶向下解析不确定的情况下,使用任何看起来必要的乱七八糟的东西

我当然不推荐将此作为如何构建解析器的模型,如果您希望这样做的话。使用解析器生成器构建解析器要容易得多;生成的解析器将更短、更易于阅读,如果您做得正确,它将是自文档化的,因为用于生成解析器的语法正是您希望放在文档中的语法

在这种情况下,您可能有理由想知道为什么很少有“现代”语言使用解析器生成器。除了与编程心理学相关的解释之外,我没有一个好的答案。手工编写解析器需要大量的工作和巨大的痛苦,但这远远不是编写编译器的最大任务——好的优化是一个更复杂的问题,而且没有简单的生成器工具来解决这个问题——因此,这项工作可能不像人们想象的那样具有抑制作用。显然,用几千LoC解析大多数语言是可能的,而且这似乎比学习解析器生成器的细节要省力得多

一种常见的解释是,使用自顶向下的解析器显然更容易生成好的编译器错误消息,而好的错误消息对于语言的采用非常重要。(例如,C++模板中的小错误导致的无法理解的错误消息显然是C++采用的一个障碍,即使在今天,模板编译错误消息也很难读取,但它们已经变得更好了。)这并不是说用自下而上的语法编写好的编译器错误消息处理程序是不可能的,但如何做到这一点并不总是显而易见的

另一种解释是,大多数人似乎想用自己的语言编写解析器(和编译器)。通常的策略是用另一种令人讨厌的语言构建一个快速而肮脏的小型编译器,并用它来引导一个用正在开发的语言构建的华丽优雅的编译器。(这种心态导致了一个奇怪的事实,即大多数语言都是首先针对编译器编写进行优化的,尽管很可能每种语言只编写一个编译器。)

bootstrap策略使得使用解析器生成器变得很困难,因为首先必须重写解析器生成器本身,以生成新语言中的代码。在一个完美的世界中,将一种新语言的代码生成改造成一个现有的解析器生成器是很容易的,但实际情况却大不相同。(如果你想继续这个项目,我强烈建议你使用Lemon解析器作为基础,而不是yacc或bison的任何实现。这不会很简单,但至少你不需要学习如何在M4中施放法术。)


如中所述,手工构建的解析器的主要缺点是没有简单的方法来验证它们是否能够识别已发布语法记录的语言。Rust源代码树现在包括一个Bison/Flex解析器,该解析器生成AST,尽管Rust编译器没有使用它(它是用Rust编写的,见上文)。尽管存在缺陷,但它比产品解析器更接近已发布的语法。但是它没有试图产生任何形式的语法错误信息(或者,实际上是生成代码)。

我发现了这些信息:@nikeee:Anders Hjelsberg的视频很有趣,尽管采访格式有限制。(ycombinator评论线程主要是情感观点的随机集合,尽管也有一些好的评论。当然,这种评价可能是我的情感观点:))。我认为他关于编译器作为API的评论非常重要,它基本上是Clang的设计模型,Clang已经开发了很长一段时间,尽管它不像Roslyn那样面向IDE。继续讨论很快就会超出SO的范围,所以我只想补充一点……从很多方面来说,这反映了两种编程风格之间的经典对峙:“让它工作并交付用户想要的”与“编写你知道会工作的代码”。这两个极端都是不合理的,我们都需要“从双方”学习技巧。语法分析器不能揭示语言真正语法的语言是一个问题,但是IDE也有一个问题,它不能快速传递好的错误消息。从这个意义上说,安德斯的方法鼓励了我,它试图将函数式编程与实用设计结合起来。