Algorithm LL和LR解析之间的区别是什么?
有谁能给我举一个LL解析和LR解析的简单例子吗?在较高的层次上,LL解析和LR解析之间的区别在于,LL解析器从起始符号开始,并尝试应用结果来到达目标字符串,而LR解析器从目标字符串开始,并尝试返回起始符号 LL解析是从左到右、最左的派生。也就是说,我们考虑从左到右的输入符号,并试图构造最左边的推导。这是通过从开始符号开始并重复展开最左边的非终结符直到到达目标字符串来完成的。LR解析是从左到右、最右边的派生,这意味着我们从左到右扫描并尝试构造最右边的派生。解析器不断地拾取输入的子字符串,并尝试将其反转回非终结符 在LL解析过程中,解析器连续在两个操作之间进行选择:Algorithm LL和LR解析之间的区别是什么?,algorithm,parsing,ll,lr,Algorithm,Parsing,Ll,Lr,有谁能给我举一个LL解析和LR解析的简单例子吗?在较高的层次上,LL解析和LR解析之间的区别在于,LL解析器从起始符号开始,并尝试应用结果来到达目标字符串,而LR解析器从目标字符串开始,并尝试返回起始符号 LL解析是从左到右、最左的派生。也就是说,我们考虑从左到右的输入符号,并试图构造最左边的推导。这是通过从开始符号开始并重复展开最左边的非终结符直到到达目标字符串来完成的。LR解析是从左到右、最右边的派生,这意味着我们从左到右扫描并尝试构造最右边的派生。解析器不断地拾取输入的子字符串,并尝试将其
- → E
- E→ T+E
- E→ T
- T→ <代码>整数
int+int+int
,LL(2)解析器(使用两个lookahead标记)将按如下方式解析该字符串:
Production Input Action
---------------------------------------------------------
S int + int + int Predict S -> E
E int + int + int Predict E -> T + E
T + E int + int + int Predict T -> int
int + E int + int + int Match int
+ E + int + int Match +
E int + int Predict E -> T + E
T + E int + int Predict T -> int
int + E int + int Match int
+ E + int Match +
E int Predict E -> T
T int Predict T -> int
int int Match int
Accept
Workspace Input Action
---------------------------------------------------------
int + int + int Shift
int + int + int Reduce T -> int
T + int + int Shift
T + int + int Shift
T + int + int Reduce T -> int
T + T + int Shift
T + T + int Shift
T + T + int Reduce T -> int
T + T + T Reduce E -> T
T + T + E Reduce E -> T + E
T + E Reduce E -> T + E
E Reduce S -> E
S Accept
请注意,在每个步骤中,我们都会看到产品中最左边的符号。如果它是一个终端,我们匹配它,如果它是一个非终端,我们通过选择一个规则来预测它将是什么
在LR解析器中,有两个操作:
Production Input Action
---------------------------------------------------------
S int + int + int Predict S -> E
E int + int + int Predict E -> T + E
T + E int + int + int Predict T -> int
int + E int + int + int Match int
+ E + int + int Match +
E int + int Predict E -> T + E
T + E int + int Predict T -> int
int + E int + int Match int
+ E + int Match +
E int Predict E -> T
T int Predict T -> int
int int Match int
Accept
Workspace Input Action
---------------------------------------------------------
int + int + int Shift
int + int + int Reduce T -> int
T + int + int Shift
T + int + int Shift
T + int + int Reduce T -> int
T + T + int Shift
T + T + int Shift
T + T + int Reduce T -> int
T + T + T Reduce E -> T
T + T + E Reduce E -> T + E
T + E Reduce E -> T + E
E Reduce S -> E
S Accept
您提到的两种解析算法(LL和LR)具有不同的特性。LL解析器往往更易于手工编写,但它们的功能不如LR解析器,并且接受的语法集比LR解析器小得多。LR解析器有多种风格(LR(0)、SLR(1)、LALR(1)、LR(1)、IELR(1)、GLR(0)等),它们的功能要强大得多。它们也往往更复杂,几乎总是由yacc
或bison
等工具生成。LL解析器也有多种风格(包括工具使用的LL(*),尽管在实践中LL(1)是使用最广泛的
作为一个无耻的插件,如果你想了解更多关于LL和LR解析的知识,我刚刚教完一门编译器课程,并在课程网站上发布了。如果您认为它们中的任何一个有用的话,我很乐意详细说明。Josh Haberman在他的文章中声称LL解析直接对应于,而LR对应于。PN和RPN之间的差异是遍历方程二叉树的顺序:
+ 1 * 2 3 // Polish (prefix) expression; pre-order traversal.
1 2 3 * + // Reverse Polish (postfix) expression; post-order traversal.
根据哈伯曼的说法,这说明了LL和LR解析器之间的主要区别:
LL和LR解析器操作方式的主要区别在于,LL解析器输出解析树的前序遍历,LR解析器输出后序遍历
要获得深入的解释、示例和结论,请查看哈伯曼的。LL使用自上而下的方法,而LR使用自下而上的方法。 如果分析编程语言:
- LL会看到一个源代码,其中包含函数,其中包含表达式
- LR看到表达式,它属于函数,结果是完整的源代码
Goal -> (FunctionDef | FunctionDecl)* <eof>
FunctionDef -> TypeSpec FuncName '(' [Arg/','+] ')' '{' '}'
FunctionDecl -> TypeSpec FuncName '(' [Arg/','+] ')' ';'
TypeSpec -> int
-> char '*' '*'
-> long
-> short
FuncName -> IDENTIFIER
Arg -> TypeSpec ArgName
ArgName -> IDENTIFIER
LR解析器可以解析
int main (int na, char** arg)
在遇到一个“;”之前,不关心被认可的规则是什么或者一个“{”
LL解析器在“int”处挂起,因为它需要知道
规则正在被识别。因此它必须提前查找“;”或
“{”
LL解析器的另一个噩梦是语法中的左递归。左递归在语法中是正常的,对于LR来说没有问题
解析器生成器,但将无法处理它
因此,你必须用LL以不自然的方式编写语法。最左边的派生示例: 上下文无关的语法G具有生成式 z→ xXY(规则:1) X→ Ybx(规则:2) Y→ (第3条规则) Y→ c(规则:4) 计算具有最左侧派生的字符串w='xcbxbc' z⇒ xXY(规则:1) ⇒ xYbxY(规则:2) ⇒ xcbxY(规则:4) ⇒ xcbxbY(规则:3) ⇒ xcbxbc(规则:4)
最右边的派生示例: K→ aKK(规则:1) A.→ b(规则:2) 计算具有最右边派生的字符串w='aababbb' K⇒ aKK(规则:1) ⇒ aKb(规则:2) ⇒ aaKKb(规则:1) ⇒ AAKKB(规则:1) ⇒ aaKaKbb(规则:2) ⇒ AAKABB(规则:2)
⇒ AABABB(规则:2)你的演讲幻灯片非常精彩,很容易成为我见过的最有趣的解释:)这是一种真正能激发兴趣的东西。我也必须对幻灯片进行评论!现在浏览所有幻灯片。非常有帮助!谢谢!非常喜欢这些幻灯片。我想你不可能发布非Windows版本的项目文件(还有scanner.l文件,用于pp2)?:)我能为Matt出色的总结答案做出贡献的一件事是,任何可以被解析的语法都是b