要学习如何编写和解析上下文无关语法,我想选择一个工具。对于 Haskell,有两个大选项:Happy,它从语法描述生成解析器和 *Parsec,它允许您直接在 Haskell 中编写解析器。
两种方法的(缺点)优点是什么?
要学习如何编写和解析上下文无关语法,我想选择一个工具。对于 Haskell,有两个大选项:Happy,它从语法描述生成解析器和 *Parsec,它允许您直接在 Haskell 中编写解析器。
两种方法的(缺点)优点是什么?
外部与内部 DSL
Happy 的解析器规范格式是外部 DSL,而使用 Parsec,您可以在定义解析器时使用 Haskell 的全部功能。这意味着您可以编写函数来生成解析器,使用 Template Haskell 等等。
优先规则
使用 Happy,您可以使用优先级来简化语法,而使用 Parsec,您必须自己正确嵌套语法规则。因此,在 Parsec 中更改运算符的优先级要繁琐得多。
静态检查
Happy 会在编译时警告您语法中的歧义。(虽然它不能很好地告诉您它们在哪里。)使用 Parsec,您不会收到任何警告,直到您的解析器在运行时失败。
这是传统的决定:我是使用 lex/yacc(快乐)还是我自己编写(主要是递归下降)解析器,只是 parsec 库就像一个 DSL 来做正确的事。
如果有使用 yacc/lex 方法的经验,那么使用 happy 将是一个更小的学习曲线。
在我看来,Parsec 隐藏了大部分令人讨厌的语法细节,让您更直观地编写解析器。如果您想首先学习这些东西,请使用像 Happy 这样的解析器生成器(或者甚至尝试自己实现一个)。
我习惯了乌得勒支大学的解析器组合库uu-parsinglib。一个人可以免费进行纠错和排列,还有 parsec 拥有的东西。我也喜欢它,因为我实现的语法看起来像 EBNF 语法,没有那么多单子的东西,而且很容易阅读。
天真的解析器组合器不允许语法规则中的左递归,我还没有找到一个库。
Happy 确实允许语言规范中的完整 BNF,以及一些有用的人员,例如优先级规则。因此,对于复杂的情况,Happy 和解析器生成器通常要好得多。但是,对于具有 LL(k) 可解析语法的简单、愚蠢的语言,我会使用解析器组合器库,因为它对维护者更友好。