如何处理用于柠檬解析器两件事的相同符号

时间:2012-12-28 21:35:33

标签: c parsing lemon

我正在开发一种特定于域的语言。部分语言与C表达式解析语义完全相同,例如预测和符号。

我正在使用Lemon解析器。我遇到了一个用于两个不同事物的相同标记的问题,我无法区分词法分析器。 &符号(&)符号用于“按位”和“地址”。

起初我认为这是一个微不足道的问题,直到我意识到他们没有相同的关联性。

如何为两个不同的关联性提供相同的标记?我应该只使用AMP(如&符号)并使地址和按位和规则使用AMP,或者我应该使用不同的令牌(如ADDRESSOF和BITWISE_AND)。如果我使用单独的符号,我怎么知道lexer中的哪一个(如果不是解析器本身就无法知道!)。

2 个答案:

答案 0 :(得分:3)

如果您要明确地编写规则,对每个“优先级”级别使用不同的非终端,那么您根本不需要声明优先级,并且您不应该这样做。

与所有yacc衍生物一样,Lemon使用优先级声明来消除模糊语法中的歧义。提到的特殊模糊语法就是这个:

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 :(得分:0)

后来我意识到我在取消引用( * )和乘法之间也有同样的歧义,也是(*)。

Lemon提供了一种为规则分配预先确定的方法,使用在句点之后的方括号中的关联性声明(%left / right / nonassoc)中使用的名称。

我还没有确认这是否正常,但我认为你可以做到这一点(注意末尾附近的方括号内的东西):

.
.
.

%left COMMA.
%right QUESTION ASSIGN
    ADD_ASSIGN SUB_ASSIGN MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN
    LSH_ASSIGN RSH_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN.
%left LOGICAL_OR.
%left LOGICAL_AND.
%left BITWISE_OR.
%left BITWISE_XOR.
%left BITWISE_AND.
%left EQ NE.
%left LT LE GT GE.
%left LSHIFT RSHIFT.
%left PLUS MINUS.
%left TIMES DIVIDE MOD.
//%left MEMBER_INDIRECT ->* .*
%right INCREMENT DECREMENT CALL INDEX DOT INDIRECT ADDRESSOF DEREFERENCE.

.
.
.

multiplicative_expr ::= cast_expr.
multiplicative_expr(A) ::= multiplicative_expr(B) STAR cast_expr(C). [TIMES]
    { A = Node_2_Op(Op_Mul, B, C); }
.
.
.
unary_expr(A) ::= STAR unary_expr(B). [DEREFERENCE]
    { A = Node_1_Op(Op_Dereference, B); }