1

我在 ANTLR 3.4 中编写了一个 PHP5 解析器,它几乎准备好了,但我无法处理 PHP 的一个棘手功能。我的问题是赋值运算符的优先级。正如 PHP 手册所说,赋值的优先级几乎在列表的末尾。只有and, xor,or,在列表中。

但是手册页上有一条注释,上面写着:

尽管=优先级低于大多数其他运算符,但 PHP 仍然允许类似于以下的表达式:if (!$a = foo()),在这种情况下, 的返回值foo()被放入$a

注释中的小示例对我的解析器来说不是问题,我可以将其作为分配规则中的特殊情况处理。

但是还有更复杂的代码,例如:

if ($a && $b = func()) {}

我的解析器在这里失败,因为它首先识别$a && $b并且无法处理其余的条件。这是因为 的&&优先级高于=。如果我将括号放在右侧&&

if ($a && ($b = func())) {}

通过这种方式,解析器可以很好地识别结构。

算子是按照 ANTLR 书推荐的方式构建的:第一步有基本表达式,每个级别的算子都接踵而至。

有没有办法处理这种优先级跳跃?

4

1 回答 1

0

不要把它看成一个赋值,而是把它命名为赋值表达式。将此赋值表达式放在一元表达式“下方”(因此它们的优先级高于一元表达式):

grammar T;

options {
  output=AST;
}

tokens {
  BLOCK;
  FUNC_CALL;
  EXPR_LIST;
}

parse
 : stat* EOF!
 ;

stat
 : assignment ';'!
 | if_stat
 ;

assignment
 : Var '='^ expr
 ;

if_stat
 : If '(' expr ')' block -> ^(If expr block)
 ;

block
 : '{' stat* '}' -> ^(BLOCK stat*)
 ;

expr
 : or_expr
 ;

or_expr
 : and_expr ('||'^ and_expr)*
 ;

and_expr
 : unary_expr ('&&'^ unary_expr)*
 ;

unary_expr
 : '!'^ assign_expr
 | '-'^ assign_expr
 | assign_expr
 ;

assign_expr
 : Var ('='^ atom)*
 | atom
 ;

atom
 : Num
 | func_call
 ;

func_call
 : Id '(' expr_list ')' -> ^(FUNC_CALL Id expr_list)
 ;

expr_list
 : (expr (',' expr)*)? -> ^(EXPR_LIST expr*)
 ;

If    : 'if';
Num   : '0'..'9'+;
Var   : '$' Id;
Id    : ('a'..'z')+;
Space : (' ' | '\t' | '\r' | '\n')+ {skip();};

如果您现在解析源:

if (!$a = foo()) { $a = 1 && 2; }
if ($a && $b = func()) { $b = 2 && 3; }
if ($a = baz() && $b) { $c = 3 && 4; }

将构建以下 AST:

在此处输入图像描述

于 2012-06-28T14:19:22.317 回答