ANTLR AST规则因RewriteEmptyStreamException而失败

Bar*_*own 8 parsing antlr

我有一个简单的语法:

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;} ;
Run Code Online (Sandbox Code Playgroud)

现在我想添加一些重写规则来生成AST.从我在网上阅读的语言模式书中,我应该能够像这样修改语法:

assignment
    : IDENT ':=' expr ';'   -> ^(':=' IDENT expr)
    ;
expr    
    : factor ('*' factor)* -> ^('*' factor+)
    ;
factor  
    : primary ('+' primary)* -> ^('+' primary+)
    ;
primary
    : NUM
    | '(' expr ')' -> ^(expr)
    ;
Run Code Online (Sandbox Code Playgroud)

但它不起作用.虽然它编译得很好,但是当我运行解析器时,我得到一个RewriteEmptyStreamException错误.事情变得奇怪了.

如果我定义伪令牌ADD和MULT并使用它们而不是树节点文字,它可以正常工作.

tokens { ADD; MULT; }

expr    
    : factor ('*' factor)* -> ^(MULT factor+)
    ;
factor  
    : primary ('+' primary)* -> ^(ADD primary+)
    ;
Run Code Online (Sandbox Code Playgroud)

或者,如果我使用节点后缀表示法,它似乎也可以正常工作:

expr    
    : factor ('*'^ factor)*
    ;
factor  
    : primary ('+'^ primary)*
    ;
Run Code Online (Sandbox Code Playgroud)

这种行为差异是一个错误吗?

Bar*_*ers 10

不,不是一个错误,AFAIK.以你的expr规则为例:

expr    
    : factor ('*' factor)* -> ^('*' factor+)
    ;
Run Code Online (Sandbox Code Playgroud)

由于*可能不存在,它也应该不在您的AST重写规则中.所以,以上是不正确的,ANTLR抱怨它正确的.

现在,如果您插入一个虚构的令牌,MULT而不是:

expr    
    : factor ('*' factor)* -> ^(MULT factor+)
    ;
Run Code Online (Sandbox Code Playgroud)

一切都没关系,因为你的规则总会产生一个或多个factor.

你可能想要做的是这样的:

expr    
    :  (factor -> factor) ('*' f=factor -> ^('*' $expr $f))*
    ;
Run Code Online (Sandbox Code Playgroud)

另请参见第7章:树的建立权威ANTLR参考.特别是"在子规则中重写规则"(第173页)和"在重写规则中引用先前规则AST"(第174/175页)中的段落.


Joe*_*lPM 7

如果要为'*'运算符生成N元树,并且所有子级都在同一级别,则可以执行以下操作:

expr
    : (s=factor -> factor) (('*' factor)+ -> ^('*' $s factor+))?
    ;
Run Code Online (Sandbox Code Playgroud)

以下是一些将返回的示例:

Tokens: AST
factor: factor
factor '*' factor: ^('*' factor factor)
factor '*' factor '*' factor: ^('*' factor factor factor)
Run Code Online (Sandbox Code Playgroud)

Bart上面的第三个例子将生成一个嵌套树,因为每个连续迭代的$ expr结果是一个有两个子节点的节点,如下所示:

factor * factor * factor: ^('*' factor ^('*' factor factor))
Run Code Online (Sandbox Code Playgroud)

你可能不需要,因为乘法是可交换的.