在ANTLR上重写树时,抛出java.lang.NullPointerException

时间:2012-06-01 12:10:13

标签: antlr

我正在尝试为QuickBasic创建一个解析器,这是我尝试获取注释:

grammar QuickBasic;

options 
{
    language = 'CSharp2';
    output = AST;
}

tokens
{
    COMMENT;
}

parse
    :    .* EOF
    ;

// DOESN'T WORK
Comment
    :    R E M t=~('\n')* { Text = $t; } -> ^(COMMENT $t)
    |    Quote t=~('\n')* { Text = $t; } -> ^(COMMENT $t)
    ;

Space  
    :    (' ' | '\t' | '\r' | '\n' | '\u000C') { Skip(); }  
    ;

fragment Quote : '\'';    
fragment E     : 'E' | 'e';
fragment M     : 'M' | 'm';
fragment R     : 'R' | 'r';

即使我只使用令牌COMMENT重写,仅此而且我仍然会遇到同样的错误。

// It DOESN'T WORK EITHER
Comment
    :    (R E M | Quote) ~('\n')* -> ^(COMMENT)
    ;

如果我放弃重写,它就有效:

// THIS WORKS
Comment
    :    (R E M | Quote) ~('\n')*
    ;

1 个答案:

答案 0 :(得分:3)

重写规则仅适用于解析器规则,而不适用于词法分析器规则。并且t=~('\n')*只会将最后一个非换行符存储在t - 标签中,因此无论如何都不会有效。

但为什么不一起跳过这些Comment令牌。如果您将它们留在令牌流中,则需要在所有解析器规则中考虑Comment令牌(其中Comment令牌有效):不是您想要的,对吧?

要跳过,只需在规则末尾调用Skip()

Comment
    :    R E M ~('\r' | '\n')* { Skip(); }
    |    Quote ~('\r' | '\n')* { Skip(); }
    ;

或更简洁:

Comment
    :    (Quote | R E M) ~('\r' | '\n')* { Skip(); }
    ;

但是,如果您真的热衷于在流中留下Comment令牌并删除"rem"或评论中的引文,请执行以下操作:

Comment
    :    (Quote | R E M) t=NonLineBreaks { Text = $t.text; }
    ;

fragment NonLineBreaks : ~('\r' | '\n')+;

然后,您还可以创建一个解析器规则,以COMMENT为根创建AST(虽然我没有看到仅仅使用Comment的好处):

comment
    :    Comment -> ^(COMMENT Comment)
    ;