如果你打算写规则明确地说,对于每个“优先级”级别使用不同的非终端,那么根本不需要声明优先级,而且您也不应该这样做。
柠檬和所有yacc衍生物一样,使用优先声明来消除模糊语法中的歧义。特定的模糊语法是这样的:
expression: expression '+' expression
| expression '*' expression
| '&' expression
| ... etc, etc.
在这种情况下,每一个替代方案都会导致转换减少冲突。如果您的解析器发电机没有优先规则,或者你想成为精确,你必须写,作为一个明确的语法(这是你做了什么):
term: ID | NUMBER | '(' expression ')' ;
postfix_expr: term | term '[' expression '] | ... ;
unary_expr: postfix_expr | '&' unary_expr | '*' unary_expr | ... ;
multiplicative_expr: unary_expr | multiplicative_expr '*' postfix_expr | ... ;
additive_expr: multiplicative_expr | additive_expr '+' multiplicative_expr | ... ;
...
assignment_expr: conditional_expr | unary_expr '=' assignment_expr | ...;
expression: assignment_expr ;
[1]
注意,明确语法甚至显示了左结合(上面的乘法和加法)和右结合(赋值,尽管有点奇怪,见下文)。所以确实没有含糊之处。
现在,优先声明(%left
,%right
等)是只有用于消除歧义。如果没有歧义,则声明忽略。解析器生成器甚至不检查它们是否反映语法。 (实际上,许多语法不能表示为这种优先关系。)
因此,如果语法是明确的,那么包含优先声明是一个非常糟糕的主意。他们可能是完全错误的,并误导任何读过语法的人。改变它们不会影响语言解析的方式,这可能会误导任何想编辑语法的人。
至少有一些问题,最好是使用具有优先规则的模糊语法,还是使用明确的语法。在类似于C
的语言中,其语法不能用简单的优先级列表表示,因此使用明确的语法可能会更好。然而,明确的语法有更多的状态,并且可能会使语法分析稍微慢一些,除非语法分析器生成器能够优化单位减少量(上述语法中的所有第一个替代方法,其中每个表达式类型可能只是前一个表达式类型,但不影响AST;这些生产中的每一个都需要减少,尽管它大部分是空操作,并且许多解析器生成器会插入一些代码。)
原因C
不能简单地表示为优先关系恰好是赋值运算符。试想一下:
a = 4 + b = c + 4;
这并不是因为assignment-expression
分析,赋值运算符可以在左侧仅适用于unary-expression
。这并不反映+
和=
之间可能的数字优先顺序。 [2]
如果+
较高优先级的比=
,表达式将作为解析:
a = ((4 + b) = (c + 4));
并且如果+
较低优先级,这将解析为
(a = 4) + (b = (c + 4));
[1]我刚刚意识到我遗漏了cast_expression,但我不能投入重演;你明白了)
[2]描述固定。
+1为了补偿疼痛,因为你必须亲手写这个。 – 2012-12-28 21:40:47
我不确定从哪里开始。我应该尝试在语法树级别解析它,还是应该尝试在解析器中检测它(例如,通过窥视最近的令牌流)。 – doug65536
在解析器中。 AST必须是明确的。解析器是什么数学和逻辑。 – 2012-12-28 21:57:09