我正在使用野牛制作解析器。我只是想问一下,当在野牛中使用时,是否还需要将语法留下来。我尝试给bison一个非左派的语法,它没有给出任何警告或错误,它也接受了我给解析器的示例语法,但是我担心解析器可能不是每个输入都准确无误。
答案 0 :(得分:4)
左分解是指如何删除语法中的LL冲突。由于Bison使用LALR,因此左递归或任何其他LL冲突都没有问题(事实上,左递归是最好的,因为它最小化了堆栈要求),因此左分解既不必要也不可取。
请注意,左分解不会破坏任何东西 - bison可以处理左分解语法以及非左分解语法,但可能需要更多资源(内存)来解析左分解语法,所以一般来说,不要。
修改强>
你似乎对LL-vs-LR解析工作的方式以及语法结构如何影响每个人感到困惑。
LL解析是自上而下的 - 你从解析堆栈上的起始符号开始,并在每一步,用一些规则右侧的符号替换堆栈顶部的非终端非末端。当堆栈顶部有一个终端时,它必须匹配下一个输入令牌,因此你弹出它并消耗输入。目标是消耗所有输入并最终得到一个空堆栈。
LR解析是自下而上的 - 你从一个空堆栈开始,在每一步你要么将一个令牌从输入复制到堆栈(使用它),要么替换堆栈顶部的一系列符号对应于某些规则的右侧,带有来自规则左侧的单个符号。目标是消耗所有输入,只留下堆栈中的起始符号。
因此,对于同一个非终端的不同规则,以右侧相同的符号开头是LL解析的一个大问题 - 您可以用任一规则中的符号替换该非终端并匹配接下来的几个令牌输入,所以你需要更多的前瞻来知道该做什么。但是对于LR解析,没有问题 - 你只是将令牌从输入移动(移动)到堆栈,当你到达后面的令牌时,你决定它匹配哪个右侧。
LR解析往往会出现与右侧相同标记 end 的规则有关的问题,而不是以相同标记开头的规则。在John Levine的书的例子中,有规则“cart_animal :: = HORSE”和“work_animal :: = HORSE”,因此在移动HORSE符号后,它可以减少(替换为)“cart_animal”或“work_animal” 。由于上下文允许后跟“AND”标记,因此当下一个标记为“AND”时,最终会出现减少/减少(LR)冲突。
答案 1 :(得分:0)
正确的递归工作;但是,它会延迟减少,从而导致解析堆栈空间与正在解析的递归构造的大小成比例。
例如,构建一个像这样的Lisp样式列表:
list : item { $$ = cons($1, nil); }
| item list { $$ = cons($1, $2); }
表示解析器堆栈与列表的长度成比例。在到达最右边的item
之前不会进行缩减,然后会发生一连串的缩减,通过一系列cons
调用从右到左构建列表。
在开始解析数据而不是代码之前,您可能不会遇到此问题,并且数据会变大。
如果你为左递归修改它,你可以在一个恒定数量的解析器堆栈中构建一个列表,因为该动作将“随你减少”:
list : item { $$ = cons($1, nil); }
| list item { $$ = append($1, cons($2, nil)); }
(现在append
搜索列表的尾部存在性能问题;有各种解决方案,与解析无关。)