C Bison移位/减少编程语言语法的冲突
我正在编写一个编程语言解析器,我陷入了这种转换/减少冲突中 下面是parser.output文件中的冲突状态,该文件是通过使用-v运行bison获得的C Bison移位/减少编程语言语法的冲突,c,parsing,bison,yacc,compiler-compiler,C,Parsing,Bison,Yacc,Compiler Compiler,我正在编写一个编程语言解析器,我陷入了这种转换/减少冲突中 下面是parser.output文件中的冲突状态,该文件是通过使用-v运行bison获得的 State 1 24 ident: TIDENT . 26 call: TIDENT . TLPAREN args TRPAREN TLPAREN shift, and go to state 24 TLPAREN [reduce using rule 24 (ident)] $default r
State 1
24 ident: TIDENT .
26 call: TIDENT . TLPAREN args TRPAREN
TLPAREN shift, and go to state 24
TLPAREN [reduce using rule 24 (ident)]
$default reduce using rule 24 (ident)
冲突发生在我尝试实现调用规则时,它似乎与正常的ident规则冲突
这里是语法的一些部分,(为了简单起见,删除了一些动作,但不需要它们。另外,我不确定规则的定义顺序是否重要,如果我错了,请纠正我)
(大写字母是代币)
ident规则很简单
ident: TIDENT
;
Args,由call使用
args: /* empty */
|
expr
|
args TCOMMA expr
;
调用函数的调用
call:
TIDENT TLPAREN args TRPAREN
;
表达式的表达式
expr:
number
|
ternary
|
bool
|
string
|
ident
|
call
|
TLPAREN expr TRPAREN
|
expr TPLUS expr
|
expr TMINUS expr
|
expr TSLASH expr
|
expr TSTAR expr
|
expr TGT expr
|
expr TGE expr
|
expr TLT expr
|
expr TLE expr
;
问题是:为什么语法有移位/减少冲突,你如何解决它?我见过类似样式的解析器,它们没有冲突,这真的很奇怪
如果您需要查看复制的完整语法,这里有一个hastebin
如果您需要有关其他任何内容的更多详细信息,请在注释中告诉我,我将相应地编辑问题。问题是,当解析器移动了一个TIDENT标记并向前看一个
TLPAREN
标记时,语法允许两种选择:
TIDENT
减少为ident
,或TLPAREN
移动调用的规则来解决冲突
生产:
call:
ident TLPAREN args TRPAREN
;
根据该规则,如果不先将TIDENT
减少为ident
,则将TLPAREN
切换为
可选地,您可以考虑完全删除<代码> IDON/CONT>非终结符,而直接使用<代码> TeTunt,直接在您现在使用“代码> IDN/CODE >的地方。也许还有其他选择。哪种方法最适合你可能取决于你试图用你的语义动作做什么。我无法对此做出更具体的评论,因为您选择了不考虑语义操作。
问题是,当解析器移动了一个TIDENT标记并向前看一个TLPAREN
标记时,语法允许两种选择:
将TIDENT
减少为ident
,或
将TLPAREN
移动
Bison通常会通过选择轮班来解决轮班/减少冲突,如果在这种情况下这是您想要的,那么您可以忽略警告
但是,在这种特殊情况下,您应该能够通过更改调用的规则来解决冲突
生产:
call:
ident TLPAREN args TRPAREN
;
根据该规则,如果不先将TIDENT
减少为ident
,则将TLPAREN
切换为
可选地,您可以考虑完全删除<代码> IDON/CONT>非终结符,而直接使用<代码> TeTunt,直接在您现在使用“代码> IDN/CODE >的地方。也许还有其他选择。哪种方法最适合你可能取决于你试图用你的语义动作做什么。我无法对此做出更具体的评论,因为您选择了不考虑语义操作。
Bison默认生成一个LR解析器,它是一个自底向上的解析器,可以决定是否移动或减少标记的每个状态
冲突非常简单,输出本身也能很好地解释(我不知道还有什么不清楚),它告诉你:
如果我找到了一个标识符
,我应该通过规则24将其减少为标识符
非终端,还是应该像调用
规则那样移动它
这是因为一旦减少了,你就不能转移,反之亦然,这确实造成了冲突
要解决冲突,您需要在解析器的相同状态下移动该选择,以便它能够根据上下文进行决定
由于ident
只有一个终端ident
规则,同样适用于呼叫,因此您可以轻松地将所有内容移动到同一级别,使其始终移动:
expr:
IDENT |
IDENT LPAREN args RPAREN |
...
或者对call
和expr
本身使用相同的ident
非终端,这样它将始终减少它。Bison默认生成一个LR解析器,它是一个自底向上的解析器,可以决定是否移动令牌或减少令牌
冲突非常简单,输出本身也能很好地解释(我不知道还有什么不清楚),它告诉你:
如果我找到了一个标识符
,我应该通过规则24将其减少为标识符
非终端,还是应该像调用
规则那样移动它
这是因为一旦减少了,你就不能转移,反之亦然,这确实造成了冲突
要解决冲突,您需要在解析器的相同状态下移动该选择,以便它能够根据上下文进行决定
由于ident
只有一个终端ident
规则,同样适用于呼叫,因此您可以轻松地将所有内容移动到同一级别,使其始终移动:
expr:
IDENT |
IDENT LPAREN args RPAREN |
...
或者对call
和expr
本身使用相同的ident
非终结符,以便始终减少它。这里的基本问题是语法不明确,因为语句不需要终止(stmts:stmts stmt
),并且语句可以是表达式。因此,两个表达式可以在没有任何标点的情况下一个接一个地出现。这意味着f(3)
可以是一个表达式(函数调用)或两个表达式(f
和(3)
)
如果您很高兴解析器总是将其解释为函数调用(这是它的默认行为,因为它更喜欢移位),那么您可以只添加两个优先级d