是否有可能使这个YACC语法明确无误? expr:... | expr expr

时间:2015-10-18 10:20:55

标签: grammar bison yacc ambiguity ambiguous-grammar

我正在 yacc / bison 中编写一个简单的计算器。

表达式的语法看起来像这样:

expr
: NUM
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr { $$ = $1 / $3; }
| '+' expr %prec '*' { $$ = $1; }
| '-' expr %prec '*' { $$ = $1; }
| '(' expr ')' { $$ = $2; }
| expr expr { $$ = $1 '*' $2; }
;

我已经宣布了这样的运营商的优先权。

%left '+' '-'
%left '*' '/'
%nonassoc '('

问题在于最后一条规则:

expr expr { $$ = $1 $2; }

我想要这个规则,因为我希望能够在我的计算器中编写像5(3+4)(3-24)这样的表达式。

是否有可能使这个语法明确无误?

1 个答案:

答案 0 :(得分:3)

由于允许一元运算符(- expr)这一事实导致歧义,因此2 - 2可以解析为简单减法(产生0)或隐式产品(2和 - ) 2,屈服-4)。

很明显,减法是有意的(否则无法表示减法)所以如果右侧的第二个expr: expr expr是一元操作,则必须禁止生成expr

使用优先级声明无法完成(或者至少不能以明显的方式完成),因此最好的解决方案是明确写出语法,而不依赖于优先级来消除歧义。

您还必须准确确定隐式乘法的优先级:与显式乘法/除法相同,或更强。这会影响ab/cd的解析方式。我所知道的并没有达成共识,所以它或多或少取决于你。

在下文中,我假设隐式乘法更紧密地绑定。我还确保将-ab解析为(-a)b,尽管-(ab)具有相同的最终结果(直到您开始处理非算术类型和自动转换等事情)。所以请以此为例。

term: NUM
    | '(' expr ')'
unop: term
    | '-' unop
    | '+' unop
conc: unop
    | conc term
prod: conc
    | prod '*' conc
    | prod '/' conc
expr: prod
    | expr '+' prod
    | expr '-' prod