1

我正在尝试为 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')*
    ;
4

1 回答 1

3

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

但是为什么不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)
    ;
于 2012-06-01T12:26:43.617 回答