用于 C 风格注释的 ANTLR 词法分析器

ANTLR lexer for C-style comment

我目前正在研究支持 C 风格注释的 ANTLR 词法分析器规则。对于这样的目标,有一个广泛推荐的规则:

C_COMMENT
:
'/*' (options {greedy=false;}: .)* '*/'
{ $channel=HIDDEN; }
;

然而我想要的是另一种选择:“+”不允许成为评论正文的第一个非 space 字符,例如/* +blablabla*/ 不是有效的注释。 然后我尝试了这样的事情:

C_COMMENT
:
'/*' (' '|'\r'|'\t'|'\n')* ~(' '|'\r'|'\t'|'\n'|'+') (options {greedy=false;}: .)* '*/'
{ $channel=HIDDEN; }
;

它几乎成功了,除了空注释 /* */。所以我尝试了这样的事情:

C_COMMENT
:
'/*' (' '|'\r'|'\t'|'\n')*
(
'*/'
|
(~(' '|'\r'|'\t'|'\n'|'+') (options {greedy=false;}: .)* '*/')
)
{ $channel=HIDDEN; }
;

它和我没有列出的一堆类似的东西从来没有用过。 /* */ 中的 * / 总是属于 ~(' '|'\r'|'\t'|'\n'|'+') 部分。

最后我得到了这样的东西:

C_COMMENT
:
'/*' (' '|'\r'|'\t'|'\n')* '*/'
{ $channel=HIDDEN; }
|
'/*' (' '|'\r'|'\t'|'\n')*
(
'*/'
|
(~(' '|'\r'|'\t'|'\n'|'+') (options {greedy=false;}: .)* '*/')
)
{ $channel=HIDDEN; }
;

尽管 ANTLR 警告像 /* */ 这样的模式可以匹配两种选择。

谁能帮我理解这一切?我的意思是,为什么最后一个以上的都不起作用。

提前致谢。

为什么不这样做:

grammar T;

parse
 : ( c_comment
   | plus_comment
   )* 
   EOF
 ;

c_comment
 : C_COMMENT
 ;

plus_comment
 : PLUS_COMMENT
 ;

PLUS_COMMENT
 : '/*' S* '+' .* '*/'
 ;

C_COMMENT
 : '/*' .* '*/'
 ;

SPACES
 : S+ {skip();}
 ;

fragment S
 : ' ' | '\t' | '\r' | '\n'
 ;

它将解析输入:

/**/
/*       + as*/
/*  sdcdcds      sdcds */

如下:

这里的技巧是在C_COMMENT之前定义PLUS_COMMENT。这样,如果词法分析器遇到 "/* s",它会从 PLUS_COMMENT 回落到 C_COMMENT,因为它无法匹配 +.