【问题标题】:LLVM JIT Parser writing with Bison / Antlr / Packrat / Elkhound /使用 Bison / Antlr / Packrat / Elkhound / 编写 LLVM JIT Parser
【发布时间】:2013-01-22 01:43:17
【问题描述】:

LLVM tutorials 中有说明如何编写简单的JIT 编译器。不幸的是,本教程中的词法分析器和解析器是手动编写的。我在想,这样的解决方案有利于学习,但不适合编写复杂的、生产就绪的编译器。不过,GCC 和其他一些“大型编译器”似乎是手写的。但我认为,在编写自己的编译器时,所有这些解析器生成器都会大大提升(尤其是当你独自完成,没有团队的时候)。

是否可以将任何现有的解析器生成器(如 Bison / Antlr / Packrat / Elkhound 等)与 LLVM 一起使用来创建 JIT 编译器?我希望能够不断地(不是一开始就)向解析器“提供”表达式并在运行时编译它们。

另外我发现了很多关于“最好的、现代的”解析器生成器的问题(比如这个:https://stackoverflow.com/questions/428892/what-parser-generator-do-you-recommend)。如果可以使用这些工具来创建 LLVM JIT 编译器,我将感谢任何额外的提示和建议,在这种特殊情况下,哪种工具在性能和灵活性方面最好。

【问题讨论】:

  • “这样的解决方案有利于学习,但不适合编写复杂的、生产就绪的编译器” - 嗯。我一直认为 GCC 是一个复杂且可用于生产的编译器。随便...
  • 如果有的话,我想说的恰恰相反:yacc、Bison 等适用于学习目的等,但对于严肃的生产工作,手写解析器可能是唯一的满足要求的方法。
  • @danilo2:我并不是说 Bison(等)不能用于任何大型或复杂的事情。我是说进展不是“如果可能,手写解析器,如果工作太大或复杂,则使用解析器生成器”,而是相反——如果可能,解析器生成器,如果不能满足则手写您的要求。
  • 至于这些要求是什么:可能是语法类别、增量解析、上下文标记、速度、内存使用或几乎任何数量的其他要求。
  • 可以使用解析器生成器(我们使用 GLR)构建非常复杂的解析器,并具有非常高的生产力和可维护性(包括著名的难以解析的 C++;在我们的例子中,完整的 C++11 ANSI/MS/GCC)。我怀疑可以通过使用错误处理生成显式扩展此类解析器生成器来生成非常好的错误消息(参见 Visser 在 TOPLAS 上的最新论文)。用手写的解析器做不到的是构建语法分析工具、增量编辑器、语法导向的模式匹配器和转换工具等。这似乎是一个巨大的损失。

标签: c++ parsing compiler-construction llvm bison


【解决方案1】:

使用像 bison 或 antlr 这样的解析器生成器有很多优势,尤其是在您开发语言时。毫无疑问,您最终会在进行过程中对语法进行更改,并且您最终会希望获得最终语法的文档。从文档中自动生成语法的工具非常有用。它们还可以帮助您确信该语言的语法是 (a) 您认为的那样,并且 (b) 没有歧义。

如果您的语言(与 C++ 不同)实际上是 LALR(1),甚至更好的是 LL(1),并且您正在使用 LLVM 工具来构建 AST 和 IR,那么您不太可能需要做很多事情不仅仅是写下语法并提供一些简单的操作来构建 AST。这会让你坚持一段时间。

人们最终选择构建自己的解析器的通常原因,除了“真正的程序员不使用解析器生成器”的偏见之外,是不容易为语法错误提供良好的诊断,尤其是使用 LR(1)解析。如果这是您的目标之一,您应该尝试使您的语法 LL(k) 可解析(使用 LL(k) 提供良好的诊断仍然不容易,但似乎更容易一些)并使用 LL(k)像 Antlr 这样的框架。

还有另一种策略,即首先使用比 LL(1) 更灵活的 LALR(1) 解析器以最简单的方式解析程序文本,甚至无需尝试提供诊断。如果解析失败,您可以使用较慢的甚至可能回溯的解析器再次解析它,该解析器不知道如何生成 AST,但会跟踪源位置并尝试从语法错误中恢复。在不使 AST 失效的情况下从语法错误中恢复比仅仅继续解析更加困难,因此不尝试有很多话要说。此外,跟踪源位置真的很慢,如果您不必生成诊断信息(除非您需要它来添加调试注释),它就不是很有用,因此您可以通过不打扰来加快解析速度位置跟踪。

就我个人而言,我对 Packrat 解析有偏见,因为不清楚 PEG 解析的实际语言是什么。其他人对此并不介意,还有YMMV。

【讨论】:

  • 为什么“不清楚”实际语言是什么? PEG 是明确定义的,即使有 Packrat 允许做的所有很酷的 hack(高阶解析等)。
  • @SK-logic:定义明确不等于明确。用 C++ 编写的手工解析器是定义良好的。图灵机是明确定义的。是的,PEG 是明确定义的。但对于他们所有人来说,查看给定字符串是否在语言中的唯一方法是执行代码。 (在这三个替代方案中,PEG 是最不坏的,imo。但我仍然更喜欢正式的上下文无关语法。但是,正如我所说,其他人喜欢 PEG,任何适合你的东西对我来说都很酷。)
  • 从我的实践经验来看,PEG 是最清晰易读的语法。我可以将语言规范直接翻译成 PEG,只需要很少的修改。当然,可以混淆它,但我还没有看到一个非常糟糕的语法。然而,Yacc 语法有许多难以理解的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-03
  • 2010-10-04
  • 2015-05-05
  • 2014-05-21
  • 1970-01-01
  • 1970-01-01
  • 2011-03-31
相关资源
最近更新 更多