我在ANTLR 3.4中编写了一个PHP5解析器,它已经准备就绪,但我无法处理PHP的一个棘手功能。我的问题在于赋值运算符的优先级。作为PHP手册says,赋值的优先级几乎位于列表的末尾。列表中只有and
,xor
,or
和,
在其后面。
但是有一个关于这个手册页的说明:
虽然
=
的优先级低于大多数其他运算符,但PHP会 仍允许使用类似于以下内容的表达式:if (!$a = foo())
,in 在哪种情况下,foo()
的返回值会被放入$a
。
笔记中的小例子对我的解析器来说不是问题,我可以将其作为分配规则中的特殊情况处理。
但是有更复杂的代码,例如:
if ($a && $b = func()) {}
我的解析器在这里失败,因为它首先识别$a && $b
并且无法处理其余的条件。这是因为&&
的优先级高于=
。
如果我在&&
的右侧放置括号:
if ($a && ($b = func())) {}
通过这种方式,解析器可以很好地识别结构。
运营商的构建方式与ANTLR书籍建议的方式相同:第一步有基本的出版物,每个级别的运营商都是相互追随的。
有没有办法处理这种优先跳跃?
答案 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: