4

我正在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)在我的计算器中那样编写表达式。

是否有可能使这种语法明确?

4

1 回答 1

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
于 2015-10-18T17:25:04.550 回答