我有以下 lex 定义:
[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 无法决定是将下一个符号移到堆栈上还是使用给定规则减少堆栈。
我的语法有歧义吗?
规则“trailed: trailed arglist”和“statement: NAME arglist COLON expression SEMICOLON”之间的决定不应该没有冲突,因为前者从来没有冒号,而后者总是有?
这与前瞻缓冲区的大小有关吗?
如何修复此语法以解析“a (b) ();” 和“a (b, c): b + c;” 作为有效的陈述?
如何以更详细的方式回溯冲突?
- - 编辑
关于迈克尔莫泽的回答:
改变
arglist:
OPAREN CPAREN
| OPAREN expressionlist CPAREN;
expressionlist:
expression
| expressionlist COMMA expression;
至
arglist: OPAREN expressionlist CPAREN;
expressionlist:
| expressionlist COMMA expression; //this now allows for expression lists like ,a,b but NVM
正如建议的那样没有帮助。与 active的第二条规则仍然存在冲突statement
,并且一旦注释掉该规则,就不会给出任何冲突。