转变减少冲突
我在理解我知道没有歧义的语法的移位/归约冲突时遇到了问题。 这种情况是 if else 类型之一,但它不是“悬空 else”问题,因为我有强制 END 子句来分隔代码块。
这是 gppg 的语法(它是像 Bison 一样的编译器编译器......而且不是回显):
%output=program.cs
%start program
%token FOR
%token END
%token THINGS
%token WHILE
%token SET
%token IF
%token ELSEIF
%token ELSE
%%
program : statements
;
statements : /*empty */
| statements stmt
;
stmt : flow
| THINGS
;
flow : '#' IF '(' ')' statements else
;
else : '#' END
| '#' ELSE statements '#' END
| elseifs
;
elseifs : elseifs '#' ELSEIF statements else
| '#' ELSEIF statements else
;
这是冲突输出:
// Parser Conflict Information for grammar file "program.y"
Shift/Reduce conflict on symbol "'#'", parser will shift
Reduce 10: else -> elseifs
Shift "'#'": State-22 -> State-23
Items for From-state State 22
10 else: elseifs .
-lookahead: '#', THINGS, EOF
11 elseifs: elseifs . '#' ELSEIF statements else
Items for Next-state State 23
11 elseifs: elseifs '#' . ELSEIF statements else
// End conflict information for parser
我已经切换了所有内容,并且我确实知道如何解决它,但该解决方案涉及给出将左递归放在“elseif”上以实现右递归。
我已经浏览了在互联网上找到的有关此问题的所有稀缺文档(我在最后发布了一些链接),但仍然没有找到一个优雅的解决方案。 我了解 ANTLR,但现在不想考虑它。 请将您的解决方案限制为 Yacc/Bison 解析器。
我很欣赏优雅的解决方案,我设法通过消除 /* 空 */ 规则并复制需要空列表的所有内容来做到这一点,但在我正在研究的更大语法中,它最终就像“意大利面条语法综合症”。
以下是一些链接:
http://nitsan.org/~maratb/cs164/bison.html< /a>
I'm having a problem understanding the shift/reduce confict for a grammar that I know has no ambiguity. The case is one of the if else type but it's not the 'dangling else' problem since I have mandatory END clauses delimiting code blocks.
Here is the grammar for gppg (Its a Bison like compiler compiler ... and that was not an echo):
%output=program.cs
%start program
%token FOR
%token END
%token THINGS
%token WHILE
%token SET
%token IF
%token ELSEIF
%token ELSE
%%
program : statements
;
statements : /*empty */
| statements stmt
;
stmt : flow
| THINGS
;
flow : '#' IF '(' ')' statements else
;
else : '#' END
| '#' ELSE statements '#' END
| elseifs
;
elseifs : elseifs '#' ELSEIF statements else
| '#' ELSEIF statements else
;
Here is the conflict output:
// Parser Conflict Information for grammar file "program.y"
Shift/Reduce conflict on symbol "'#'", parser will shift
Reduce 10: else -> elseifs
Shift "'#'": State-22 -> State-23
Items for From-state State 22
10 else: elseifs .
-lookahead: '#', THINGS, EOF
11 elseifs: elseifs . '#' ELSEIF statements else
Items for Next-state State 23
11 elseifs: elseifs '#' . ELSEIF statements else
// End conflict information for parser
I already switched arround everything, and I do know how to resolve it, but that solution involves giving up the left recursion on 'elseif' for a right recursion.
Ive been through all the scarse documentation I have found on the internet regarding this issue (I post some links at the end) and still have not found an elegant solution. I know about ANTLR and I don't want to consider it right now. Please limit your solution to Yacc/Bison parsers.
I would appreciate elegant solutions, I managed to do It by eleminating the /* empty */ rules and duplication everything that needed an empty list but in the larger grammar Im working on It just ends up like 'sparghetti grammar syndrome'.
Here are some links:
http://nitsan.org/~maratb/cs164/bison.html
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您修改后的 ELSEIF 规则没有条件标记——名义上应该添加“(”和“)”。
更严重的是,你现在有一个规则,
并且
不需要“什么”; 它由“elsebody”隐式处理,而无需“elseifs”。
我非常倾向于使用规则“opt_elseifs”、“opt_else”和“end”:
我没有通过解析器生成器运行它,但我发现这相对容易理解。
Your revised ELSEIF rule has no markers for a condition -- it should nominally have '(' and ')' added.
More seriously, you now have a rule for
and
The 'nothing' is not needed; it is implicitly taken care of by the 'elsebody' without the 'elseifs'.
I would be very inclined to use rules 'opt_elseifs', 'opt_else', and 'end':
I've not run this through a parser generator, but I find this relatively easy to understand.
我认为问题出在 elseifs 子句中。
我认为第一个版本不是必需的,因为 else 子句无论如何都会引用 elseifs:
如果更改 elseifs 会发生什么?:
I think the problem is in the elseifs clause.
I think the first version is not required, since the else clause refers back to elseifs anyway:
What happens if you change elseifs?:
上面乔纳森的答案似乎是最好的,但由于它不适合你,我有一些建议你可以尝试,这将帮助你调试错误。
首先,您是否考虑过将哈希/锐利符号作为标记本身的一部分(即#END、#IF 等)? 这样它们就会被词法分析器取出,这意味着它们不必包含在解析器中。
其次,我敦促您重写规则而不重复任何令牌流。 (“不要重复自己”原则的一部分。)因此,规则“'#'ELSEIF statements else”应该只存在于该文件中的一个位置(而不是像上面那样存在两个位置)。
最后,我建议您研究 IF/ELSEIF/ELSE 标记的优先级和关联性。 我知道您应该能够编写一个不需要这个的解析器,但在这种情况下它可能是您需要的。
The answer from Jonathan above seems like it would be the best, but since its not working for you I have a few suggestions you could try that will help you in debugging the error.
Firstly have you considered making the hash/sharp symbol a part of the tokens themselves (i.e. #END, #IF, etc)? So that they get taken out by the lexer, meaning they don't have to be included in the parser.
Secondly I would urge you to rewrite the rules without duplicating any token streams. (Part of the Don't Repeat Yourself principle.) So the rule " '#' ELSEIF statements else " should only exist in one place in that file (not two as you have above).
Lastly I suggest that you look into precedence and associativity of the IF/ELSEIF/ELSE tokens. I know that you should be able to write a parser that doesn't require this but it might be the thing that you need in this case.
我仍在切换事物,我原来的问题有一些错误,因为 elseifs 序列末尾总是有一个 else ,这是错误的。 这是对这个问题的另一种看法,这次我得到了两个转变/归约冲突:
现在的冲突是:
空规则只会加剧我担心的 gppg。 但它们使用起来似乎很自然,我一直在尝试它们。
我已经知道正确的递归可以解决问题,正如 1800 INFORMATION 所说。 但我正在寻找在 elseifs 子句上使用左递归的解决方案。
I'm still switching thing arround, and my original question had some errors since the elseifs sequence had an else allways at the end which was wrong. Here is another take at the question, this time I get two shift/reduce conflicts:
The conflicts now are:
Empty rules just aggravate the gppg i'm affraid. But they seem so natural to use I keep trying them.
I already know right recursion solves the problem as 1800 INFORMATION has said. But I'm looking for a solution with left recursion on the elseifs clause.
我认为这应该留下递归并始终终止。
I think this should left recurse and always terminate.
好的 - 这是 if 块的语法(不是最小的)。 我从我拥有的一些代码中挖掘出它(称为 adhoc,基于 Kernighan 和 Plauger 的“UNIX 编程环境”中的 hoc)。 这个大纲语法用 Yacc 编译没有冲突。
我使用“NUMBER”作为虚拟元素,而不是 THINGS,并且使用 ELIF 而不是 ELSEIF。 它包括一个 THEN,但这是可选的。 “开始”和“结束”操作用于获取生成程序中的程序计数器 - 因此应该可以从中删除而不影响它。
我认为我需要使用右递归而不是正常的左递归是有原因的 - 但我认为这与我正在使用的代码生成策略有关,而不是其他任何东西。 评论中的问号是原文的; 我记得我对此并不高兴。 该计划作为一个整体确实有效 - 这是一个在过去十年左右的时间里一直处于次要地位的项目(嗯......我在 2004 年底和 2005 年初做了一些工作;在此之前,是 1992 年和 1993)。
我没有花时间弄清楚为什么它可以无冲突编译,而我之前概述的却不能。 我希望它有帮助。
OK - here is a grammar (not minimal) for if blocks. I dug it out of some code I have (called adhoc, based on hoc from Kernighan & Plauger's "The UNIX Programming Environment"). This outline grammar compiles with Yacc with no conflicts.
I used 'NUMBER' as the dummy element, instead of THINGS, and I used ELIF instead of ELSEIF. It includes a THEN, but that is optional. The 'begin' and 'end' operations were used to grab the program counter in the generated program - and therefore should be removable from this without affecting it.
There was a reason I thought I needed to use right recursion instead of the normal left recursion - but I think it was to do with the code generation strategy I was using, rather than anything else. The question mark in the comment was in the original; I remember not being happy with it. The program as a whole does work - it is a project that's been on the back burner for the last decade or so (hmmm...I did some work at the end of 2004 and beginning of 2005; prior to that, it was 1992 and 1993).
I've not spent the time working out why this compiles conflict-free and what I outlined earlier does not. I hope it helps.