如何在PHP解析器中处理赋值运算符的优先级?

时间:2012-06-28 13:24:37

标签: antlr antlr3

我在ANTLR 3.4中编写了一个PHP5解析器,它已经准备就绪,但我无法处理PHP的一个棘手功能。我的问题在于赋值运算符的优先级。作为PHP手册says,赋值的优先级几乎位于列表的末尾。列表中只有andxoror,在其后面。

但是有一个关于这个手册页的说明:

  

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

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

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

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

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

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

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

运营商的构建方式与ANTLR书籍建议的方式相同:第一步有基本的出版物,每个级别的运营商都是相互追随的。

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

1 个答案:

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

enter image description here