我有一个简单的语法:
grammar sample;
options { output = AST; }
assignment
: IDENT ':=' expr ';'
;
expr
: factor ('*' factor)*
;
factor
: primary ('+' primary)*
;
primary
: NUM
| '(' expr ')'
;
IDENT : ('a'..'z')+ ;
NUM : ('0'..'9')+ ;
WS : (' '|'\n'|'\t'|'\r')+ {$channel=HIDDEN;} ;
现在我想添加一些重写规则来生成AST。根据我在网上和“语言模式”一书中的内容,我应该能够像这样修改语法:
assignment
: IDENT ':=' expr ';' -> ^(':=' IDENT expr)
;
expr
: factor ('*' factor)* -> ^('*' factor+)
;
factor
: primary ('+' primary)* -> ^('+' primary+)
;
primary
: NUM
| '(' expr ')' -> ^(expr)
;
但它不起作用。虽然它编译得很好,但是当我运行解析器时,我得到一个RewriteEmptyStreamException错误。这就是事情变得奇怪的地方。
如果我定义伪令牌ADD和MULT并使用它们而不是树节点文字,它可以正常工作。
tokens { ADD; MULT; }
expr
: factor ('*' factor)* -> ^(MULT factor+)
;
factor
: primary ('+' primary)* -> ^(ADD primary+)
;
或者,如果我使用节点后缀表示法,它似乎也可以正常工作:
expr
: factor ('*'^ factor)*
;
factor
: primary ('+'^ primary)*
;
这种行为差异是一个错误吗?
答案 0 :(得分:10)
不,不是错误,AFAIK。以您的expr
规则为例:
expr
: factor ('*' factor)* -> ^('*' factor+)
;
由于*
可能不存在,因此它也不应该在您的AST重写规则中。所以,以上是不正确的,ANTLR抱怨它是正确。
现在,如果您插入像MULT
这样的虚构标记:
expr
: factor ('*' factor)* -> ^(MULT factor+)
;
一切都没关系,因为你的规则总会生成一个或多个factor
。
你可能想要做的是这样的事情:
expr
: (factor -> factor) ('*' f=factor -> ^('*' $expr $f))*
;
另请参阅The Definitive ANTLR Reference中的第7章:树构造。特别是段落重写规则(第173页)和在重写规则中引用先前规则AST (第174/175页)。
答案 1 :(得分:7)
如果要为'*'运算符生成一个N元树,所有子级都在同一级别,您可以这样做:
expr
: (s=factor -> factor) (('*' factor)+ -> ^('*' $s factor+))?
;
以下是一些将返回的示例:
Tokens: AST
factor: factor
factor '*' factor: ^('*' factor factor)
factor '*' factor '*' factor: ^('*' factor factor factor)
巴顿上面的第三个例子将产生一个嵌套树,因为每个连续迭代的$ expr结果是一个有两个子节点的节点,如下所示:
factor * factor * factor: ^('*' factor ^('*' factor factor))
你可能不需要,因为乘法是可交换的。