ANTLR 3上的ASN.1/SMI注释语法

ANTLR 3上的ASN.1/SMI注释语法,antlr,antlr3,Antlr,Antlr3,在ANTLR 2上,注释语法如下所示 // Single-line comments SL_COMMENT : (options {warnWhenFollowAmbig=false;} : '--'( { LA(2)!='-' }? '-' | ~('-'|'\n'|'\r'))* ( (('\r')? '\n') { newline(); }| '--') ) {$setType(Token.SKIP); } ; 但是,当将其移植到

在ANTLR 2上,注释语法如下所示

// Single-line comments
SL_COMMENT
    : (options {warnWhenFollowAmbig=false;} 
    : '--'(  { LA(2)!='-' }? '-'    |   ~('-'|'\n'|'\r'))*  ( (('\r')? '\n') { newline(); }| '--') )
        {$setType(Token.SKIP);  }
    ;
但是,当将其移植到ANTLR 3时

SL_COMMENT
    : (
    : '--'(  { input.LA(2)!='-' }? '-'  |   ~('-'|'\n'|'\r'))*  ( (('\r')? '\n') | '--') )
        {$channel = HIDDEN;}
    ;
由于没有更多选项{warnWhenFollowAmbig=false;},因此无法正确分析以下注释

-- some comment -- some not comment

那么,为ANTLR 3定义此SL_注释规则的可能方式是什么?

我终于找到了一个解决方案

SL_评论 :注释({input.LA(2)!='-'}?'-')=>'-'| ~('-'|'\n'|'\r'))*((('\r')?'\n')|注释) {$channel=HIDDEN;}
;

就我个人而言,我喜欢让语法规则尽可能“空”。在本例中,我将创建一个lexer方法,如果输入中的下两个字符是
“--”
,则该方法将返回
true
。只要不是这种情况,请匹配除
\r
\n
以外的任何字符,并重复零次或多次,直到遇到可选的
“-”
。请注意,我没有在末尾添加新行,因为末尾不一定有新行(也可能是
EOF
)。此外,
\r
\n
很可能会与
空间
规则相匹配,该规则放在
隐藏
频道上:因此按照我的建议这样做没有害处

演示:

...

@lexer::members {
  private boolean endCommentAhead() {
    return input.LA(1) == '-' && input.LA(2) == '-';
  }
}

...

SL_COMMENT 
 : '--' ({!endCommentAhead()}?=> ~('\r' | '\n'))* '--'?
 ;

...
如果您不喜欢lexer members块,只需执行以下操作:

SL_COMMENT 
 : '--' ({!(input.LA(1) == '-' && input.LA(2) == '-')}?=> ~('\r' | '\n'))* '--'?
 ;
编辑 一个完整的小演示:

grammar T;

@parser::members {
  public static void main(String[] args) throws Exception {
    String source = "12 - 34 -- foo - bar -- 42 \n - - 5678 -- more comments 666\n--\n--";
    TLexer lexer = new TLexer(new ANTLRStringStream(source));
    TParser parser = new TParser(new CommonTokenStream(lexer));
    parser.parse();
  }
}

@lexer::members {
  private boolean endCommentAhead() {
    return input.LA(1) == '-' && input.LA(2) == '-';
  }
}

parse
 : (t=. {System.out.printf("\%-15s\%s\n", tokenNames[$t.type], $t.text);})* EOF
 ;

SL_COMMENT 
 : '--' ({!endCommentAhead()}?=> ~('\r' | '\n'))* '--'?
 ;

MINUS
 : '-'
 ;

INT
 : '0'..'9'+
 ;

SPACE
 : (' ' | '\t' | '\r' | '\n') {skip();}
 ;
在解析输入之后:

12 - 34 -- foo - bar -- 42 - - 5678 -- more comments 666 12-34--foo-bar--42 --5678--更多评论666 将打印:

INT 12 MINUS - INT 34 SL_COMMENT -- foo - bar -- INT 42 MINUS - MINUS - INT 5678 SL_COMMENT -- more comments 666 SL_COMMENT -- SL_COMMENT -- INT 12 减去- INT 34 SL_注释——foo-bar-- INT 42 减去- 减去- 国际电话5678 SL_评论——更多评论666 SL_评论--
SL_注释——我将检查这是否通过了我很快创建的所有测试用例。不幸的是,这条规则没有通过所有测试用例。例如,如果此行仅包含“---”,则此规则不会将其视为注释。因此,仍然需要使用(((“\r”)?“\n”)|注释)作为结尾。@LexLi,呃,不,这是不正确的。只有
“--”
后跟换行符或
EOF
都将标记为
SL\u COMMENT
。我编辑了我的答案来展示这个。嗨,巴特,谢谢你再次访问它。我仍然感到奇怪的是,在我的测试中,这个失败了。完整的语法在这里。如果您将SL_注释更改为您的版本,然后使用此文本“bytesAvailAlert TRAP-TYPE\n ENTERPRISE alerts\n--\n::=1”进行测试,并根据“assignment”规则进行测试,“--”部分将阻止此完整规则按预期工作。好吧,我所能说的是,我的建议是正确的,你可以通过运行我发布的演示来验证你自己。您的语法看起来很奇怪:它包含一些额外的冒号(在
WS
规则中,以及其他一些规则中),并且您使用了v2关键字
protected
,而不是v3
片段。不确定这对您的解析器有多大影响。。。