我目前正在学习语言处理器,而且经常出现的主题是语法中的元素被消耗的方向。从左到右或从右到左。 我理解这个概念,但似乎有很多方法来编写这些规则,我不确定它们是否完全相同。到目前为止我所看到的是:
右/左递归, 右/左最推导, 右/左减少,优先,相关等。
这些都意味着同样的事情吗?
答案 0 :(得分:9)
不,它们都有不同的含义。
右递增和左递归是指生产规则中的递归。如果非终端的生产可以导出包含该非终端的序列,则该生产是递归的。如果非终端可以出现在派生序列的开始(左边缘),则它是左递归的,如果它可以出现在末尾(右边缘),则是右递归。生产可以递归,而不是左递归或右递归,甚至可以是左递归和右递归。
例如:
term: term '*' factor { /* left-recursive */ }
assignment: lval '=' assignment { /* right-recursive */ }
以上例子都是直接递归;非终端直接导出包含非终端的序列。递归也可以是间接的;它仍然是递归。
所有常见的解析算法从左到右处理,这是LL和LR中的第一个L.自上而下(LL)解析找到最左边的推导(第二个L),而自下而上(LR)解析找到最右边的推导(R)。
实际上,两种类型的解析器都以单个非终端(起始符号)和"猜测"基于当前序列中的一些非终端的派生,直到导出输入文本。在最左边的派生中,它总是最左边的非终端被扩展。在最右边的派生中,它始终是最右边的非终端。
因此,自上而下的解析器总是猜测哪个生产用于第一个非终端,之后它需要再次处理现在的第一个非终端。 ("猜猜"这里是非正式的。它可以查看要匹配的输入 - 或至少输入的下一个 k 标记 - 以确定要生成的输入使用。)这称为自上而下处理,因为它从上到下构建解析树。
更容易(至少对我来说)反向自由地显示自下而上解析器的动作;它通过反复读取足够的输入来构建解析树,以找到一些生成,这将是派生链中的最后一个派生。所以它确实产生了最右边的推导,但它会从前到后输出它。
在运算符语言的LR语法中(粗略地说,语言类似于算术表达式的语法),左右相关性分别使用左递归语法规则和右递归语法规则建模。 "结合性"是语法的非正式描述,"优先"。
优先级是通过使用一系列语法规则建模的,每个规则都引用下一个规则(并且通常最终会产生用于处理括号的递归生成 - '(' expr ')'
- 这既不是左边也不是右递归)。
有一种较旧的自下而上解析方式,称为"运算符优先解析",其中优先级明确是语言描述的一部分。一种常见的运算符优先算法是所谓的Shunting Yard算法。但是如果你有一个LALR(1)解析器生成器,比如bison,你也可以使用它,因为它更通用,更精确。
答案 1 :(得分:1)
(我不是解析器和编译器理论方面的专家。我碰巧学习了一些相关的东西。而且我想分享我到目前为止所发现的东西。)
我强烈建议您查看此awesome article。
它解释了插图 LL和LR算法。你可以清楚地看到为什么LL被称为自上而下,LR被称为自下而上。
一些引用:
LL和LR解析器如何运作的主要区别在于 LL解析器输出解析树和LR的预订序遍历 解析器输出一个后序遍历。
...
我们正在聚合一个非常简单的LL和LR解析器模型 操作。两者都读取输入令牌流并输出相同的令牌 流,在适当的地方插入规则来实现 解析树的预订(LL)或后订购(LR)遍历。
...
当您看到LL(1),LR(0)等名称中的数字时 括号是前瞻标记的数量。
至于首字母缩略词:(source)
LR 和 LL 中的第一个 L 表示:解析器读取输入 一个方向上的文字,无需备份 ;那个方向通常是 在每条线内从左到右,从上到下穿过线 完整的输入文件。
剩余的 R 和 L 分别表示:最右侧和最左侧的派生。< / p>
这是两种不同的解析策略。解析策略确定要重写的下一个非终端。 (source)