26

在编写解析器时,我应该遵循哪些最佳实践?

4

7 回答 7

19

公认的智慧是使用解析器生成器+语法,这似乎是个好建议,因为您使用的是严格的工具,并且可能会减少这样做的工作量和潜在的错误。

要使用解析器生成器,语法必须是上下文无关的。如果您正在设计要解析的语言,那么您可以控制它。如果您不确定,那么如果您从语法路线开始,可能会花费您很多精力。即使在实践中它是上下文无关的,除非语法非常庞大,否则手动编写一个像样的递归解析器会更简单。

上下文无关不仅使解析器生成器成为可能,而且还使手动编码的解析器变得更加简单。你最终得到的是每个短语一个(或两个)功能。也就是说,如果您干净地组织和命名代码并不比语法更难看到(如果您的 IDE 可以显示调用层次结构,那么您几乎可以看到语法是什么)。

优点:-

  • 更简单的构建
  • 更好的性能
  • 更好地控制输出
  • 可以处理小的偏差,例如使用不是 100% 上下文无关的语法

我并不是说语法总是不合适的,但通常好处是微乎其微的,而且往往被成本和风险所抵消。

(我相信他们的论点似是而非地吸引人,并且普遍存在对他们的偏见,因为这是一种表明人们更具有计算机科学素养的方式。)

于 2009-02-20T17:16:27.553 回答
10

几点建议:

  • 了解你的语法 - 以合适的形式写下来
  • 选择正确的工具。使用 Spirit2x 在 C++ 中执行此操作,或选择外部解析器工具,如 antlr、yacc 或任何适合您的工具
  • 你需要解析器吗?也许正则表达式就足够了?或者也许破解一个 perl 脚本来解决这个问题?编写复杂的解析器需要时间。
于 2009-02-20T16:11:58.487 回答
7

不要过度使用正则表达式——虽然它们有自己的位置,但它们根本没有能力处理任何类型的真正解析。你可以推动它们,但你最终会碰壁或陷入无法维护的混乱局面。您最好找到一个可以处理更大语言集的解析器生成器。如果您真的不想使用工具,可以查看递归下降解析器 - 这是一种非常简单的手写小解析器模式。它们不像大型解析器生成器那样灵活或强大,但它们的学习曲线要​​短得多。

除非您有非常严格的性能要求,否则请尝试将您的层分开 - 词法分析器读取单个标记,解析器将它们排列成树,然后语义分析检查所有内容并链接引用,然后在最后阶段输出任何内容正在生产。保持逻辑的不同部分分开将使以后的维护更容易。

于 2009-02-20T16:44:57.940 回答
7

首先阅读大部分龙书

如果您知道如何构建解析器,它们并不复杂,但是如果您投入足够的时间,它们并不是那种类型的东西,您最终会到达那里。建立在现有知识库上会更好。(否则期望写它并把它扔掉几十次)。

于 2009-02-20T17:18:37.517 回答
5

是的。尝试生成它,而不是编写。考虑使用 yacc、ANTLR、Flex/Bison、Coco/R、GOLD 解析器生成器等。仅当现有解析器生成器都不符合您的需求时,才使用手动编写解析器。

于 2009-02-20T16:13:34.273 回答
3
  • 选择正确的解析器类型,有时递归后代就足够了,有时您应该使用 LR 解析器(还有很多类型的 LR 解析器)。
  • 如果您有复杂的语法,请构建抽象语法树。
  • 尝试很好地识别词法分析器中的内容,语法的一部分以及语义的问题。
  • 尽量使解析器与词法分析器实现的耦合最小。
  • 为用户提供一个好的接口,这样他就可以不知道解析器的实现。
于 2009-02-20T16:57:06.617 回答
2

首先,不要尝试将相同的技术应用于解析所有内容。有许多可能的用例,从 IP 地址(一些临时代码)到 C++ 程序(需要工业强度的解析器和符号表的反馈),以及用户输入(需要非常快速)到编译器(通常可以花一点时间解析)。如果您想要有用的答案,您可能需要指定您正在做什么。

其次,要记住一个语法来解析。越复杂,规范就越需要正式。尽量避免过于正式。

第三,嗯,这取决于你在做什么。

于 2009-02-20T17:17:45.570 回答