Parsing 在Bison中语法的左因子分解是必要的吗?

Parsing 在Bison中语法的左因子分解是必要的吗?,parsing,grammar,bison,bnf,Parsing,Grammar,Bison,Bnf,我正在用bison做一个解析器。我只是想问一下,在《野牛》中使用语法时,是否仍有必要将其保留下来。我尝试给bison一个非左因子语法,它没有给出任何警告或错误,它也接受了我给解析器的示例语法,但我担心解析器可能不会在每个输入中都准确无误。左因子分解是消除语法中LL冲突的方法。由于Bison使用LALR,因此它在左递归或任何其他LL冲突方面没有问题(事实上,左递归更可取,因为它最小化了堆栈要求),因此左因子分解既不必要也不可取 注意,左因子分解不会破坏任何东西——bison可以处理左因子语法和非左

我正在用bison做一个解析器。我只是想问一下,在《野牛》中使用语法时,是否仍有必要将其保留下来。我尝试给bison一个非左因子语法,它没有给出任何警告或错误,它也接受了我给解析器的示例语法,但我担心解析器可能不会在每个输入中都准确无误。

左因子分解是消除语法中LL冲突的方法。由于Bison使用LALR,因此它在左递归或任何其他LL冲突方面没有问题(事实上,左递归更可取,因为它最小化了堆栈要求),因此左因子分解既不必要也不可取

注意,左因子分解不会破坏任何东西——bison可以处理左因子语法和非左因子语法,但它可能需要更多的资源(内存)来解析左因子语法,所以通常不要这样做

编辑

您似乎对LL和LR解析的工作原理以及语法结构如何影响它们感到困惑

LL解析是自上而下的——您只需要从解析堆栈上的开始符号开始,并且在每一步中,您都将堆栈顶部的非终结符替换为该非终结符的某个规则右侧的符号。当堆栈顶部有一个终端时,它必须与输入的下一个标记相匹配,因此您可以弹出它并使用输入。目标是消耗所有输入,最终得到一个空堆栈

LR解析是自下而上的——您从一个空堆栈开始,在每个步骤中,您要么将一个令牌从输入复制到堆栈(使用它),要么将堆栈顶部对应于某个规则右侧的一系列符号替换为规则左侧的单个符号。目标是消耗所有的输入,只留下堆栈上的开始符号

因此,同一个非终端的不同规则(在右侧以相同符号开头)对于LL解析来说是一个大问题——您可以用任一规则中的符号替换该非终端,并匹配接下来的几个输入标记,因此您需要更多的前瞻性来知道该做什么。但是对于LR解析,没有问题——您只需将标记从输入移到(移动)堆栈,当您到达后面的标记时,您就可以决定它匹配的右侧


LR解析往往会遇到以右侧相同标记结尾的规则问题,而不是以相同标记开头的规则问题。在John Levine书中的示例中,有规则“cart\u animal::=马”和“work\u animal::=马”,因此在移动马符号后,可以将其减少(替换为)“cart\u animal”或“work\u animal”。由于上下文允许“AND”标记后跟其中一个标记,因此当下一个标记为“AND”时,会出现reduce/reduce(LR)冲突。

左因子分解是删除语法中所有冲突的方法。由于Bison使用LALR,因此它在左递归或任何其他LL冲突方面没有问题(事实上,左递归更可取,因为它最小化了堆栈要求),因此左因子分解既不必要也不可取

注意,左因子分解不会破坏任何东西——bison可以处理左因子语法和非左因子语法,但它可能需要更多的资源(内存)来解析左因子语法,所以通常不要这样做

编辑

您似乎对LL和LR解析的工作原理以及语法结构如何影响它们感到困惑

LL解析是自上而下的——您只需要从解析堆栈上的开始符号开始,并且在每一步中,您都将堆栈顶部的非终结符替换为该非终结符的某个规则右侧的符号。当堆栈顶部有一个终端时,它必须与输入的下一个标记相匹配,因此您可以弹出它并使用输入。目标是消耗所有输入,最终得到一个空堆栈

LR解析是自下而上的——您从一个空堆栈开始,在每个步骤中,您要么将一个令牌从输入复制到堆栈(使用它),要么将堆栈顶部对应于某个规则右侧的一系列符号替换为规则左侧的单个符号。目标是消耗所有的输入,只留下堆栈上的开始符号

因此,同一个非终端的不同规则(在右侧以相同符号开头)对于LL解析来说是一个大问题——您可以用任一规则中的符号替换该非终端,并匹配接下来的几个输入标记,因此您需要更多的前瞻性来知道该做什么。但是对于LR解析,没有问题——您只需将标记从输入移到(移动)堆栈,当您到达后面的标记时,您就可以决定它匹配的右侧


LR解析往往会遇到以右侧相同标记结尾的规则问题,而不是以相同标记开头的规则问题。在John Levine书中的示例中,有规则“cart\u animal::=马”和“work\u animal::=马”,因此在移动马符号后,可以将其减少(替换为)“cart\u animal”或“work\u animal”。由于上下文允许“AND”标记后跟其中一个,因此当下一个标记为“AND”时,就会出现reduce/reduce(LR)冲突。

事实上,情况正好相反。LALR(1)解析器生成器生成的解析器不仅支持左递归,事实上,它们在左递归中工作得更好。具有讽刺意味的是,您可能必须从语法中重构正确的递归

右递归工程;但是,它会延迟缩减,导致解析堆栈空间与正在解析的递归构造的大小成比例

例如,构建一个Lisp样式列表,如下所示:

list : item { $$ = cons($1, nil); }
     | item list { $$ = cons($1, $2); }
表示解析器堆栈与列表的长度成比例。在到达最右边的
项之前,不会进行任何减少
list : item        { $$ = cons($1, nil); }
     | list item   { $$ = append($1, cons($2, nil)); }