yacc移位/减少冲突:函数调用与函数定义
我有以下法律定义:yacc移位/减少冲突:函数调用与函数定义,yacc,shift-reduce-conflict,Yacc,Shift Reduce Conflict,我有以下法律定义: [a-zA-Z][a-zA-Z0-9_]* return NAME; \, return COMMA; \: return COLON; \; return SEMICOLON; \( return OPAREN; \) return CPAREN; \+ return PLUS; 以及以下yacc生成规则
[a-zA-Z][a-zA-Z0-9_]* return NAME;
\, return COMMA;
\: return COLON;
\; return SEMICOLON;
\( return OPAREN;
\) return CPAREN;
\+ return PLUS;
以及以下yacc生成规则:
program:
| program statement;
arglist:
OPAREN CPAREN
| OPAREN expressionlist CPAREN;
trailed:
NAME
| trailed arglist;
expression:
trailed
| expression PLUS trailed;
expressionlist:
expression
| expressionlist COMMA expression;
statement:
expression SEMICOLON
|NAME arglist COLON expression SEMICOLON;
如果我把最后一条规则注释掉,一切都会顺利进行。与上一条规则发生冲突:
yacc: 1 shift/reduce conflict.
所以我猜,yacc无法决定是将下一个符号移到堆栈上,还是使用给定的规则减少堆栈
arglist:
OPAREN CPAREN
| OPAREN expressionlist CPAREN;
expressionlist:
expression
| expressionlist COMMA expression;
到
正如我所建议的那样没有帮助。当
语句的第二条规则处于活动状态时,仍然会出现冲突,一旦对该规则进行注释,就不会出现冲突。如果要调试shift/reduce错误,请将--report=all--report file=pars.report添加到bison命令行,生成的pars.report文件会让您明白
简化语法文件
%token OPAREN CPAREN NAME PLUS COMMA SEMICOLON COLON
%%
program:
| program statement;
arglist:
OPAREN CPAREN
| OPAREN expressionlist CPAREN;
trailed:
NAME
| trailed arglist;
expression:
trailed
| expression PLUS trailed;
expressionlist:
expression
| expressionlist COMMA expression;
statement:
expression SEMICOLON
|NAME arglist COLON expression SEMICOLON;
%标记OPAREN CPAREN名称加逗号分号冒号
%%
节目:
|程序语句;
arglist:
OPAREN CPAREN
|OPAREN表达列表;
跟踪:
名称
|跟踪arglist;
表达方式:
跟踪
|表情加拖尾;
表达列表:
表情
|表达式列表逗号表达式;
声明:
表达式分号
|名称arglist冒号表达式分号;
提供以下报告:
State 3 conflicts: 1 shift/reduce
....
state 3
3 arglist: . OPAREN CPAREN
4 | . OPAREN expressionlist CPAREN
5 trailed: NAME . [OPAREN, PLUS, SEMICOLON]
12 statement: NAME . arglist COLON expression SEMICOLON
OPAREN shift, and go to state 7
OPAREN [reduce using rule 5 (trailed)]
$default reduce using rule 5 (trailed)
arglist go to state 8
状态3冲突:1转移/减少
....
国家3
3 arglist:。OPAREN CPAREN
4 | . OPAREN表达式列表CPAREN
5:姓名。[蛋白石,加号,分号]
12声明:姓名。arglist冒号表达式分号
OPAREN移位,进入状态7
OPAREN[使用规则5(trailed)减少]
$default使用规则5减少(拖尾)
arglist转到状态8
在报告的开头,有导致错误的解析器状态,随后您可以看到解析状态的详细信息。这个文件也很有趣,因为它实际上解释了解析器在每个步骤中所做的事情
冲突在于
statement : NAME arglist COLON expression SEMICOLON;
语句:名称arglist冒号表达式分号;
及
陈述:表达;
表达方式:拖尾;
trailed:NAME | tailed arglist;
给定源语法:
%token COLON COMMA CPAREN NAME OPAREN PLUS SEMICOLON
%%
program:
| program statement
;
arglist:
OPAREN CPAREN
| OPAREN expressionlist CPAREN
;
trailed:
NAME
| trailed arglist
;
expression:
trailed
| expression PLUS trailed
;
expressionlist:
expression
| expressionlist COMMA expression
;
statement:
expression SEMICOLON
| NAME arglist COLON expression SEMICOLON
;
我从bison-v xyz.y
中得到的报告给出了xyz.y:conflicts:1 shift/reduce
,但是xyz.output
中的描述与his中的报告有些不同
这意味着,当语法读取了一个名称并获取了一个OPAREN时,它无法推断该名称是在后面紧跟着arglist
的语句中,还是在语句中紧跟着arglist
的语句中。在到达冒号之前,它无法确定差异,冒号太远了,一个前瞻标记无法确定
这使得普通Yacc无法解析语法,因为Yacc只能向前看一个标记。(我不确定这是否会使它变得模棱两可或其他什么——“在Yacc中不起作用”涵盖了这种情况。Bison提供了GLR语法,这可能会有所帮助。)正如其他人所指出的,问题是,要区分函数定义和函数调用,需要不止一个前瞻标记。所编写的语法的问题在于,当向前看是OPAREN
时,它需要在看到NAME
后决定是减少规则trailed:NAME
还是移位以匹配规则语句:NAME arglist冒号表达式分号
。但是,在看到arglist之后,它才能决定它后面是否有冒号(这是区分这两种情况的原因)
要解决这个问题,您需要重构语法,这样在到达冒号之前,就不需要减少只出现在一个选项上的任何内容。使用此语法,您可以通过重构trailed
规则,使其始终至少需要一个arglist,并将不包含arglist
的NAME
作为一个单独的表达式
规则:
trailed:
NAME arglist
| trailed arglist;
expression:
NAME
| trailed
| expression PLUS NAME
| expression PLUS trailed;
现在,当您获得一个输入时,NAME OPAREN…
还没有必要减少任何内容——您只需切换到匹配arglist
的规则,在匹配arglist
之后,您就可以看到下一个标记,并决定这是函数调用还是函数定义。谢谢。那么,当我删除规则语句:NAME arglist冒号表达式分号时,为什么arglist不产生冲突呢。如果我在第二条语句规则前面引入另一个标记(例如DEF
),为什么冲突会被删除。我刚刚尝试了您的尝试。如果我答对了,请查看我问题的编辑。冲突仍然取决于语句的定义。冲突发生在trailed:NAME
的减少和移位之间。所以这个问题与两个arglist规则无关,根本不是一个模糊问题——它需要一个以上的前瞻标记。不模糊——它只需要一个以上的前瞻标记。谢谢,我担心这是由于前瞻。我会重构我的语法,看看会发生什么。太好了。我确信这与未来的展望有关。我一到电脑前就要试试。是的,这就成功了。我必须重写很多,但我可以从这里开始工作。再次感谢。
%token COLON COMMA CPAREN NAME OPAREN PLUS SEMICOLON
%%
program:
| program statement
;
arglist:
OPAREN CPAREN
| OPAREN expressionlist CPAREN
;
trailed:
NAME
| trailed arglist
;
expression:
trailed
| expression PLUS trailed
;
expressionlist:
expression
| expressionlist COMMA expression
;
statement:
expression SEMICOLON
| NAME arglist COLON expression SEMICOLON
;
State 3 conflicts: 1 shift/reduce
…
state 3
5 trailed: NAME .
12 statement: NAME . arglist COLON expression SEMICOLON
OPAREN shift, and go to state 7
OPAREN [reduce using rule 5 (trailed)]
$default reduce using rule 5 (trailed)
arglist go to state 8
trailed:
NAME arglist
| trailed arglist;
expression:
NAME
| trailed
| expression PLUS NAME
| expression PLUS trailed;