【问题标题】:Is There an LL(k) Grammar for PCF?PCF 有 LL(k) 语法吗?
【发布时间】:2016-02-29 17:59:44
【问题描述】:

我们正在编译器设计类中进行自上而下的解析。示例都是类 java 语言。我决定尝试一种简单的函数式语言来让它变得有趣,所以我选择了 PCF (see e.g. here)。不过,我似乎无法将其纳入 LL(1) 语法。我认为问题在于函数应用(即两个表达式的并置)。关于如何确定这是否只是我缺乏技能,或者这是一种没有 LL(1) 语法或 LL(k) 的语言,我没有得到明确的答案。有人可以澄清一下我是需要更聪明还是根本不存在这样的语法?

基本上,我的 PCF 版本类似于下面的草图(大写是非终端,“//”开始注释)。我说“类似”是因为我并不完全赞同这一点,而且我已经写了很多变体——只想要一个合理的 PCF 变体。

请注意,我已经尝试过左分解并考虑中间非终结符的优先级。

Exp -> Const     // integer and boolean literals, normal ops e.g. +
    |  if Exp then Exp else Exp
    |  lambda identifier dot Exp    //lambda (function) abstraction
    |  Exp Exp                      // function application
    |  fix Exp                      // fixpoint operator (recursion)

【问题讨论】:

  • 这是标准的左递归消除,例如见here。基本思想是语法A -> A α | β 等价于A -> β A'; A' -> ε | α A'。你必须用更多的βs 来概括这个案例。
  • @Bakuriu 我确实尝试过消除左递归,但也许我这样做只是为了直接左递归。我将不得不再看看你关于间接部分的链接。然而,这个链接确实说明了一些关于搞乱关联性的问题,我也在努力解决这个问题。

标签: parsing functional-programming lambda-calculus


【解决方案1】:

问题在于您的语法是左递归的,这与 LL(k) 所描述的自上而下的解析器不能很好地配合。

具体来说,尝试解析 Exp 会导致尝试首先解析函数应用程序的第一部分 Exp Exp... 对于自上而下的解析器,这会导致无限循环。

在您的情况下,可能的解决方案是以右递归样式实现任意长度的函数应用程序:

AppExp -> Exp | Exp AppExp

Exp -> Const | (AppExp) | ...

请注意,这种结构消除了语法歧义。不幸的是,它为您的问题解决了错误的方向 - 并且没有很好的方法来解决它;左关联版本:

AppExp  -> Exp | AppExp Exp

将和原来的一样左递归​​。

在自上而下的解析器范围内解决此问题的(不太好的)方法是接受右关联语法,将AppExp 视为一个列表,并在解析后将其反转,以便您的摘要语法树具有您想要的关联性:

 application expression:    f a b c d
   |
   |  LL(1) parse
   v
 right-associative   --->   left-associative
       @             list              @
      / \          reversal           / \
     f   @                           @   d
        / \                         / \
       a   @                       @   c
          / \                     / \
         b   @                   @   b
            / \                 / \
           c   .               .   a
               |               |
               d               f

像 Parsec 这样的组合解析器库通常具有方便的预打包功能,可以为您执行此操作。

在语言理论术语中,这证明了语法接受的语言与基于该语法的解析器产生的解析之间的区别....

【讨论】:

  • 对不起,如果我不清楚。我知道示例语法是直接左递归的,并且我尝试使用一些最终 更大的语法来删除左递归(并处理所有运算符的优先级和关联性)。但是,我认为它们仍然不是 LL(1)(在应用程序上间接留下递归?)。我试图了解我是否只是在吠叫错误的树。我认为也许这就是你的意思——放弃 LL(1) 并以不同的方式去做——但是当我有时间时,我将不得不消化你的答案。跨度>
  • 我的回答推荐了一种坚持使用 LL(1) 并使用自上而下解析器可以为您提供的方法。我确实怀疑你找错了树,但这里要吸取的教训是,对于这种情况,无论你如何尝试切片,左递归消除都会破坏你的解析顺序。
  • 换一种说法:你可以制定一个能够识别你的语言的LL(1)语法;我的回答向您展示了一个例子。但是,您的评论表明您希望您的语法以左关联方式解析您的应用程序语法,这不适用于 LL(1) 或几乎任何类型的 top-向下解析器缺少一个完全通用的解析器。
  • 所以,我推荐的方法(特别是因为你的班级正在研究自上而下的解析章节)是使用识别你的语言的 LL(1) 语法(即使它不按您想要的顺序解析它),并修复解析顺序之后
  • 再次感谢您的详细说明。我会再看看这个。也许我迷路的一个地方是,讲师似乎将您分开的两个想法混为一谈。我认为讲师会说 PCF 的 LL(1) 语法将是不正确,无论它接受什么语言,如果它导致解析树 / AST如果没有语法之外的调整,则不能反映正确/所需的关联性。我们还没有做任何事情,比如在自上而下的解析之后有一个额外的步骤来进行额外的语法更正。
猜你喜欢
  • 2021-01-03
  • 1970-01-01
  • 1970-01-01
  • 2016-08-22
  • 1970-01-01
  • 2017-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多