Antlr 在不使用令牌的情况下使用孤岛语法返回默认模式

Antlr 在不使用令牌的情况下使用孤岛语法返回默认模式,antlr,Antlr,我仍在尝试使用ANTLR解析一个简单的Javadoc样式的格式。基本上,格式如下所示: /** * Description * * @name someId */ 我的语法分析器如下: query_doc : BEGIN_QDOC description name NOMANSLAND* END_QDOC; description : (DESCRIPTION_TEXT | NOMANSLAND)*; name : OPEN_N

我仍在尝试使用ANTLR解析一个简单的Javadoc样式的格式。基本上,格式如下所示:

/**
 * Description
 *
 * @name someId
 */
我的语法分析器如下:

query_doc       :   BEGIN_QDOC description name NOMANSLAND* END_QDOC;

description     :   (DESCRIPTION_TEXT | NOMANSLAND)*;

name            :   OPEN_NAME INNER_WS NAMEID INNER_WS* CLOSE_NAME;
BEGIN_QDOC          :   '/**';


END_QDOC            :   ('*/');


NOMANSLAND          :   '\r'? '\n' (' ' | '\t')* '*' (' ' | '\t')*;


DESCRIPTION_TEXT    :   ~('\n');


OPEN_NAME                   :   '@name' -> mode(NAME);

mode NAME;


INNER_WS                    :   (' ' | '\t')+;


NAMEID                      :   ('a'..'z' | 'A'..'Z' | '0'..'9' | '-' | '_' | '?')+;

CLOSE_NAME                  :   (('\r'? '\n') | '*/')  -> mode(DEFAULT_MODE);
我的lexer语法如下:

query_doc       :   BEGIN_QDOC description name NOMANSLAND* END_QDOC;

description     :   (DESCRIPTION_TEXT | NOMANSLAND)*;

name            :   OPEN_NAME INNER_WS NAMEID INNER_WS* CLOSE_NAME;
BEGIN_QDOC          :   '/**';


END_QDOC            :   ('*/');


NOMANSLAND          :   '\r'? '\n' (' ' | '\t')* '*' (' ' | '\t')*;


DESCRIPTION_TEXT    :   ~('\n');


OPEN_NAME                   :   '@name' -> mode(NAME);

mode NAME;


INNER_WS                    :   (' ' | '\t')+;


NAMEID                      :   ('a'..'z' | 'A'..'Z' | '0'..'9' | '-' | '_' | '?')+;

CLOSE_NAME                  :   (('\r'? '\n') | '*/')  -> mode(DEFAULT_MODE);
除了在以下情况下关闭@name定义外,这似乎在大多数情况下都可以正常工作:

/**
 * @name someId*/
上述观点应该是完全正确的。在注释以“*/”结尾之前,我们不需要新行。我遇到的问题是“*/”成功终止了名称定义,但它使用了令牌,并且只返回到默认模式,因此我需要:

/**
 * @name someId*/*/
如果我真的想让它结束评论。我希望它返回到默认模式,然后意识到这个标记应该结束注释(即,它应该匹配end_QDOC)。如何在ANTLR中实现这一点?我尝试修复它,使CLOSE_NAME与ID相反:

CLOSE_NAME : ~('a'..'z' | 'A'..'Z' | '0'..'9' | '-' | '_' | '?');

但ANTLR仍然使用*在剩余的“/”上留下无法识别的令牌错误。我真正想做的是让ANTLR退出模式而不使用令牌,这样当我们返回到默认的_模式时,“*/”就是下一个令牌。有什么想法吗?

首先,您可能不想使用
模式
命令,而是想使用
->pushMode(NAME)
->popMode
返回默认模式

对于
CLOSE\u NAME
规则,可以使用谓词而不是匹配的文本来处理注释的结尾:

CLOSE_NAME
  : ( '\r'? '\n'
    | {_input.LA(1) == '*' && _input.LA(2) == '/'}?
    )
    -> popMode
  ;

这可能会产生一个零长度标记,在ANTLR 4.0中是不允许的,但在ANTLR 4.1中取消了该限制(更改为警告),因为我们意识到零长度标记可以用来触发模式更改,从而避免无限循环。

我肯定遗漏了一些东西,因为这不起作用。现在代币消失了。它没有显示为CLOSE_名称的一部分,但我仍然得到不匹配的输入“”,期望CLOSE_名称IntStream.LA是否实际使用该字符?这在文件中并不清楚。如果LA代表前瞻,那么这就是我想要的,但它似乎不能正常工作。