【问题标题】:Writing correct LL(1) grammars?编写正确的 LL(1) 语法?
【发布时间】:2011-02-18 13:55:45
【问题描述】:

我目前正在尝试为编程语言编写一个(非常)小的解释器/编译器。我已经设置了语言的语法,现在我需要写下语言的语法。我打算使用 LL(1) 解析器,因为经过一番研究,它似乎是最容易使用的。

我是这个领域的新手,但根据我收集到的信息,强烈建议使用 BNF 或 EBNF 形式化语法。然而,似乎并非所有语法都适合使用 LL(1) 解析器来实现。因此,我想知道以 LL(1) 形式编写语法的正确(或推荐)方法是什么。

感谢您的帮助, 查理。

PS:我打算使用 Haskell 的 Parsec 库编写解析器。

编辑:另外,根据 SK 逻辑,Parsec 可以处理无限前瞻(LL(k) ?) - 但我想这个问题仍然代表这种类型的语法。

【问题讨论】:

  • Parsec 能够进行无限前瞻。您无需出于性能以外的原因将自己限制为 LL(1)。
  • 而且不一定是LL(k),可以是上下文相关的。因此,您唯一需要担心的是避免左递归。

标签: parsing grammar recursive-descent ll


【解决方案1】:

我不是这方面的专家,因为我只用 LR(0) 解析器做了一个类似的小项目。我推荐的一般方法:

  1. 让算法工作。通过这种方式,为+, -, /, * 等制定规则和派生,并确保解析器生成一个有效的抽象语法树。在不同的输入上测试和评估树,以确保它正确地执行算术。 一步一步做事。如果遇到任何冲突,请先解决后再继续。

  2. 让更简单的构造像 if-then-elsecase 表达式一样工作。

  3. 进一步取决于您编写语法的语言。

明确地检查其他编程语言语法作为参考(不幸的是,我在 1 分钟内没有找到任何在线语言的完整 LL 语法,但 LR 语法也应该作为参考有用)。例如:

ANSI C grammar

Python grammar

当然还有维基百科中关于 LL 语法 Wikipedia LL Parser 的一些小例子,您可能已经查看过。

我希望这些东西对你有用

【讨论】:

    【解决方案2】:

    有两种算法都可以确定语法是否为 LL(k)。解析器生成器实现它们。如果可能的话,还有将语法转换为 LL(k) 的启发式方法。

    但您不需要将简单语言限制为 LL(1),因为大多数现代解析器生成器(JavaCCANTLRPyparsing 等)都可以处理 LL(k) 中的任何 k .

    更重要的是,您认为最适合您的语言的语法很可能需要k 介于 2 和 4 之间,因为有几种常见的编程结构。

    【讨论】:

    • 您能否详细说明哪些特定结构需要哪些k 以及为什么?我只是好奇。
    • @SasQ 在我的脑海中,if-then-else 带有可选的else 而没有end 需要k2。任何具有可选部分且没有结束标记的构造都需要大于 1 的前瞻。
    • 即使您将if-then 部分分解为公因数规则?之后,匹配该规则将匹配 if-then 部分,这本身就是正确的。然后它可以尝试以else 作为第一个标记来解析可选部分,因此它可以仅通过查看该单个标记来确定它是否存在。对我来说这是 LL(1),还是我错过了什么?
    • @SaasQ 我确实说过“我的头顶”。请参阅 [1],了解为什么不能仅使用 LL(1) 处理“悬空 else”问题。 \ [1] en.wikipedia.org/wiki/Dangling_else
    【解决方案3】:

    所以首先,你不一定希望你的语法是 LL(1)。它使编写解析器更简单,并可能提供更好的性能,但这确实意味着您的语言最终可能会比常用语言(通常不是 LL(1))更冗长。

    如果没问题,你的下一步就是在脑海中逐步完成语法,想象此时可能出现的所有可能性,并检查它们是否可以通过它们的第一个标记来区分。

    制作文法 LL(1) 有两个主要的经验法则

    1. 如果多个选项可以出现在给定点并且它们可以 同一个token开头,前面加一个关键词告诉你哪个 做出了选择。
    2. 如果您有可选的或重复的部分,请制作 确保其后跟一个不能作为可选/重复部分的第一个标记出现的结束标记。
    3. 尽可能避免在生产开始时使用可选部件。它使前两个步骤变得容易得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多