【问题标题】:When rewriting tree on ANTLR, java.lang.NullPointerException is thrown在 ANTLR 上重写树时,抛出 java.lang.NullPointerException
【发布时间】:2012-06-01 12:10:12
【问题描述】:

我正在尝试为 QuickBasic 创建解析器,这是我获取 cmets 的尝试:

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

【问题讨论】:

    标签: antlr


    【解决方案1】:

    重写规则仅适用于解析器规则,不适用于词法分析器规则。而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)
        ;
    

    【讨论】:

    • 谢谢巴特!这一切背后的真正意图是将用 QuickBasic 编写的程序转换为任何其他语言。这就是 cmets 很重要的原因。
    • 关于 COMMENT 令牌...刚刚删除它。 :)
    猜你喜欢
    • 2012-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-16
    • 2013-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多