Parsing PCF有LL(k)语法吗?
我们正在编译器设计类中进行自顶向下的解析。示例都是类似java的语言。我决定尝试一种简单的函数式语言来让它变得有趣,所以我选择了PCF()。不过,我似乎无法把它写进LL(1)语法。我认为问题在于函数应用(即两个表达式并置)。关于如何判断这是因为我缺乏技能,还是因为这是一种没有LL(1)语法或LL(k)语法的语言,我没有得到明确的答案。有人能澄清我是否需要更聪明,或者根本不存在这样的语法吗 基本上,我的PCF版本类似于下面的草图(大写是非端子,“/”开始注释)。我说“类似于”是因为我并不完全认同这一点,我已经写了很多变体——只是想要一个合理的PCF变体 请注意,我已经尝试了左因子分解,并考虑了中间非终结符的优先级Parsing PCF有LL(k)语法吗?,parsing,functional-programming,lambda-calculus,Parsing,Functional Programming,Lambda Calculus,我们正在编译器设计类中进行自顶向下的解析。示例都是类似java的语言。我决定尝试一种简单的函数式语言来让它变得有趣,所以我选择了PCF()。不过,我似乎无法把它写进LL(1)语法。我认为问题在于函数应用(即两个表达式并置)。关于如何判断这是因为我缺乏技能,还是因为这是一种没有LL(1)语法或LL(k)语法的语言,我没有得到明确的答案。有人能澄清我是否需要更聪明,或者根本不存在这样的语法吗 基本上,我的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)
问题是,语法是左递归的,这与自顶向下的解析器不匹配,如LL(k)所述 具体来说,尝试解析
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这样的组合解析器库通常具有方便的预打包特性,可以为您完成这项工作
从语言理论的角度来看,这证明了语法所接受的语言与语法分析器基于该语法生成的解析之间的区别……这是标准的左递归消除,请参见示例。基本思想是语法
A->Aα|β
等价于A->βA';A'->ε|αA'
。你必须用更多的β
s来概括这种情况。@Bakuriu我确实尝试过消除左递归,但也许我只对直接左递归这样做。我必须再看一看你关于间接部分的链接。然而,这个链接确实说明了一些关于破坏关联性的事情,这也是我一直在努力解决的问题。如果我不清楚的话,很抱歉。我知道示例语法是直接左递归的,我尝试用一些更大的语法删除左递归(并处理所有运算符的优先级和关联性)。但是,我认为它们仍然不是LL(1)(在应用程序上间接地左递归?)。我想知道我是不是找错了人。我想这也许就是你所说的——放弃LL(1)并用另一种方式去做——但我会在有时间的时候消化你的答案。我的答案推荐了一种坚持LL(1)的方法,并使用自顶向下的解析器可以提供给你的东西。我确实怀疑你找错了方向,但这里要学的是,对于这种情况,左递归消除将破坏你的解析顺序,不管你如何尝试对它进行切片;我的回答给你举了一个例子。但是,您的评论表明,您还希望语法以左关联的方式解析应用程序语法,这对LL(1)或几乎任何一种自顶向下的解析器都不起作用,除非是完全通用的解析器。因此,我推荐的方法(特别是因为您的类正在处理自顶向下的解析章节)是使用LL(1) 识别您的语言的语法(即使它没有按照您想要的顺序解析),然后修复解析顺序。再次感谢您的详细阐述。我将进一步了解这一点。也许我迷路的地方是,讲师似乎将您分离的两个想法混为一谈。我想讲师会说,ll(1)PCF的语法是不正确的,无论它接受哪种语言,如果它导致的解析树/AST不能反映正确/期望的关联性,而没有语法之外的调整。我们没有做过任何事情,比如在自顶向下的解析之后有额外的步骤来进行额外的语法更正。