我正在为一个数学表达式解析器的Bison文件工作。到目前为止,它几乎没问题,但我面临隐式乘法的问题。
你知道,我想支持像2x sin(4x) cos(4x)
这样的表达。它应该像2 * x * sin(4 * x) * cos(4 * x)
一样解析。这里没什么不好的,但请考虑以下规则:
expr
: /* snip */
| '-' expr { /* negate expression */ }
| expr '-' expr { /* subtract expressions */ }
| expr expr { /* multiply expressions */ }
使用隐式乘法规则会在减法规则中产生歧义:x - log(x)
减去log(x)
到x
或x
乘以-log(x)
}?
我已经准备好接受一个简单的解决方案,比如“它是一个乘法,除非它减去”,但我不知道怎么告诉Bison。
答案 0 :(得分:5)
使用隐式乘法规则会在减法规则中产生歧义:是x - log(x)将log(x)减去x还是x乘以-log(x)?
甚至,是x - l * o * g * x
吗?或者只是x - log * x
?
所以不是一个简单的问题。假设您可以通过查看log
它是一个函数来判断。然后你可以在你的词法分析器中消除歧义,并且你留下“如果有疑问,看起来像中缀运算符的运算符是一个中缀运算符”。这是一个快速的解决方案:
term : ID
| NUMBER
| '(' expr ')' { $$ = $2; }
| FUNC '(' expr ')' { $$ = new_expr($1, 'c', $3); }
;
factor : term
| term factor { $$ = new_expr($1, '*', $2); }
;
prefix : factor
| '-' factor { $$ = new_expr(0, '-', $2); }
;
muldiv : prefix
| muldiv '/' prefix { $$ = new_expr($1, '/', $3); }
| muldiv '*' prefix { $$ = new_expr($1, '*', $3); }
;
expr : muldiv
| expr '+' muldiv { $$ = new_expr($1, '+', $3); }
| expr '-' muldiv { $$ = new_expr($1, '-', $3); }
;
这个特殊的语法不允许--x,虽然它对y - x非常满意,这意味着y - ( - x)。如果您想接受--x,则可以将第二个prefix
作品更改为'-' prefix
。
就个人而言,我更愿意输入sin 2x
和log 3n
,但这开始变得有点棘手。 sin 2x cos 2x
是什么意思?据推测,这意味着(sin(2*x))*(cos(2*x))
。但log nlog n
不代表log(n*log(n))
吗?这一切都可以实现;它只需要思考所有可能性。