Antlr4 如何在antlr lexer中处理嵌套注释

Antlr4 如何在antlr lexer中处理嵌套注释,antlr4,Antlr4,如何处理antlr4 lexer中的嵌套注释?ie我需要计算此令牌中“/*”的数量,并仅在收到相同数量的“*/”后关闭。例如,D语言具有“/+…++/”等嵌套注释 例如,以下行应视为一组注释: /* comment 1 comment 2 /* comment 3 comment 4 */ // comment 5 comment 6 */ COMMENT : '/*' (COMMENT|.)*? '*/' -> channel(HIDDEN)

如何处理antlr4 lexer中的嵌套注释?ie我需要计算此令牌中“/*”的数量,并仅在收到相同数量的“*/”后关闭。例如,D语言具有“/+…++/”等嵌套注释

例如,以下行应视为一组注释:

/* comment 1
   comment 2
   /* comment 3
      comment 4
   */
   // comment 5
   comment 6
*/
COMMENT : '/*' (COMMENT|.)*? '*/' -> channel(HIDDEN) ;
LINE_COMMENT  : '//' .*? '\n' -> channel(HIDDEN) ;
我的当前代码如下所示,它不适用于上述嵌套注释:

COMMENT : '/*' .*? '*/' -> channel(HIDDEN)
        ;
LINE_COMMENT : '//' ~('\n'|'\r')* '\r'? '\n'  -> channel(HIDDEN)
        ;

我可以为您提供一个ANTLR3解决方案,您可以调整该解决方案以在ANTLR4中工作:

我认为可以使用递归规则调用。为/*…*/创建非贪婪注释规则这就叫它自己。这应该允许无限嵌套,而不必计算开始和结束注释标记:

COMMENT option { greedy = false; }:
    ('/*' ({LA(1) == '/' && LA(2) == '*'} => COMMENT | .) .* '*/') -> channel(HIDDEN)
;
甚至可能:

COMMENT option { greedy = false; }:
    ('/*' .* COMMENT? .* '*/') -> channel(HIDDEN)
;

我不确定ANTLR是否根据任何字符或注释介绍人正确选择了正确的路径。试试看。

特伦斯·帕尔(Terence Parr)在他的词典中有两行词法分析器,用于对嵌套注释进行词法分析:

/* comment 1
   comment 2
   /* comment 3
      comment 4
   */
   // comment 5
   comment 6
*/
COMMENT : '/*' (COMMENT|.)*? '*/' -> channel(HIDDEN) ;
LINE_COMMENT  : '//' .*? '\n' -> channel(HIDDEN) ;
我正在使用:

COMMENT: '/*' ('/'*? COMMENT | ('/'* | '*'*) ~[/*])*? '*'*? '*/' -> skip;
这将强制注释中的任何
/*
成为嵌套注释的开头,类似地,注释中的
*/
也是如此。换句话说,除了在规则注释的开头和结尾之外,无法识别
/*
*/

这样,像
/*/*/**/a*/
这样的东西将不会被完全识别为(坏的)注释(不匹配的
/*
s和
*/
s),就像使用
注释:'/*'(注释|?'*/'->跳过,但作为
/
,后跟
*
,后跟正确的嵌套注释
/*/**/a*/

适用于Antlr3

允许在注释中嵌套注释和“*”

fragment
F_MultiLineCommentTerm
:
(   {LA(1) == '*' && LA(2) != '/'}? => '*'
|   {LA(1) == '/' && LA(2) == '*'}? => F_MultiLineComment
|   ~('*') 
)*
;   

fragment
F_MultiLineComment
:
'/*' 
F_MultiLineCommentTerm
'*/'
;   

H_MultiLineComment
:   r=  F_MultiLineComment
    {   $channel=HIDDEN;
        printf(stder,"F_MultiLineComment[\%s]",$r->getText($r)->chars); 
    }
;
  • 这将处理:“/*/*/”和“/*…/*/”,其中注释正文分别为“/”和“…/”
  • 多行注释不会嵌套在单行注释内,因此不能在单行注释内启动或开始多行注释。
    • 这不是有效的注释:'/*/*/'
    • 您需要一个换行符来结束单行注释,然后才能使用“*/”来结束多行注释
    • 这是有效的注释:'/*/*/\n/*/'
    • 注释正文为:'/*/\n/'。如您所见,完整的单行注释包含在多行注释的主体中
  • 虽然如果前面的字符为“*”,则“/*/”可以结束多行注释,但注释将在第一个“/”处结束,其余的“*/”将需要结束嵌套注释,否则将出现错误。最短路径获胜,这是非贪婪!
    • 这不是有效的注释/***//
    • 这是一条有效的注释/*/****/,注释正文为/****,它本身就是一条嵌套注释
  • 前缀和后缀在多行注释正文中永远不会匹配
  • 如果要为“D”语言实现此功能,请将“*”更改为“+”
  • COMMENT\u NEST
    : '/*'
    ((“/”|“*”+)?~[*/]|注释|注释| INL)*?
    ('/'|'*'+?)?
    '*/'
    ;

    COMMENT\u INL
    :“/”(注释| ~[\n\r])*
    
    ;

    谢谢。我首先在ANTLR3本身中尝试了您的解决方案,然后转到ANTLR4,但它不起作用。我刚刚用您的规则替换了我的注释规则,然后ANTLR3报告了错误,如:error(100):X.g:语法错误:antlr:MissingTokenException(在选项处插入[@-1,0:0=”,1927:8]记住Antlr3生成的lexer只有1个字符的前瞻性,除非你像上面的例子那样使用谓词。有没有办法也为未完成的块注释制定规则,从而引发自定义错误?