代码之家  ›  专栏  ›  技术社区  ›  Barry Brown

antlr ast规则失败,出现rewriteEmptyStream异常

  •  8
  • Barry Brown  · 技术社区  · 14 年前

    我有一个简单的语法:

    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)*
        ;
    

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

    2 回复  |  直到 14 年前
        1
  •  10
  •   Bart Kiers    14 年前

    不,不是虫子,阿飞。带上你的 expr 规则例如:

    expr    
        : factor ('*' factor)* -> ^('*' factor+)
        ;
    

    自从 * 可能不存在,也不应在AST重写规则中。所以,上面的说法是不正确的 对的。

    现在如果你插入一个想象中的标记 MULT 而是:

    expr    
        : factor ('*' factor)* -> ^(MULT factor+)
        ;
    

    一切都好,因为你的规则总是会产生一个或多个 factor s。

    你可能想这样做:

    expr    
        :  (factor -> factor) ('*' f=factor -> ^('*' $expr $f))*
        ;
    

    也看到 第七章:树木建设 The Definitive ANTLR Reference . 尤其是段落 重写子规则中的规则 (第173页)和 在重写规则中引用以前的规则ast (第174/175页)。

        2
  •  7
  •   JoelPM    14 年前

    如果要为“*”运算符生成一个n元树,所有子级都在同一级别,可以执行以下操作:

    expr
        : (s=factor -> factor) (('*' factor)+ -> ^('*' $s factor+))?
        ;
    

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

    Tokens: AST
    factor: factor
    factor '*' factor: ^('*' factor factor)
    factor '*' factor '*' factor: ^('*' factor factor factor)
    

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

    factor * factor * factor: ^('*' factor ^('*' factor factor))
    

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