语法:如何添加优先级



因此,假设我为一种简单的计算器语言提供了以下上下文无关语法:

S->TS'
S'->OP1 TE'|e
T->FT'
T'->OP2 FT'|e
F->id|(S)
OP1->+|-
OP2->*|/

可以看出,*和/的优先级高于+和-。但是,如何添加其他级别的优先级?例如指数,^,(例如:3^2=9(或其他什么?请解释一下你是如何到达那里的程序和理由,这样我就可以为其他操作员做这件事了。

这里有一个更可读的语法:

expr: sum
sum : sum add_op term
| term
term: term mul_op factor
| factor
factor: ID
| '(' expr ')'
add_op: '+' | '-'
mul_op: '*' | '/'

这可以使用相同的模式轻松扩展:

expr: bool
bool: bool or_op conj
| conj
conj: conj and_op comp
| comp
/* This one doesn't allow associativity. No a < b < c in this language */ 
comp: sum comp_op sum
sum : sum add_op term
| term
term: term mul_op factor
| factor
/* Here we'll add an even higher precedence operators */
/* Unlike the other operators, though, this one is right associative */
factor: atom exp_op factor
| atom
atom: ID
| '(' expr ')'
/* I left out the operator definitions. I hope they are obvious. If not,
* let me know and I'll put them back in
*/

我希望这种模式或多或少是显而易见的。

这些语法在递归下降解析器中不起作用,因为递归下降解析器会阻塞左递归。您已经通过左递归消除算法运行了语法,您也可以对上面的语法执行此操作。但请注意,消除左递归或多或少会消除左递归和右递归之间的差异,因此,在使用递归下降语法识别解析后,您需要根据您对运算符的关联性的了解来修复它,因为关联性不再是语法中固有的。

对于这些简单的生成,消除左递归非常简单,只需两个步骤。我们从一些非终端开始:

foo: foo foo_op bar
| bar

我们把它翻转过来,使它具有正确的关联性:

foo: bar foo_op foo
| bar

(如果操作符最初是正确关联的,就像上面的求幂一样,那么就不需要这个步骤了。(

然后我们需要保留因子,因为LL解析要求非终端的每个备选方案都有一个唯一的前缀:

foo : bar foo'
foo': foo_op foo
| ε

对上面的每一个递归生成(也就是说,除了exprcompatom之外的所有递归生成(执行此操作将生成一个语法,该语法看起来与您开始使用的语法相似,只是使用了更多的运算符。

顺便强调一下,这里并没有神秘的神奇力量在起作用。当语法说,例如:

term: term mul_op factor
| factor

它所说的是,term(或者乘积,如果你愿意的话(不能是乘法的右边自变量,但它可以是左边自变量。它还说,如果你在一个乘积有效的点上,你实际上不需要带乘法运算符的东西;您可以使用factor。但很明显,您不能使用sum,因为factor不使用sum运算符解析表达式。(它确实解析括号内的任何内容。但这些都是括号内的内容。(

这就是结合性和优先性都隐含在语法中的意义。

最新更新