使用Island语法返回默认模式而不使用令牌

时间:2014-02-06 19:22:55

标签: antlr

我仍在尝试使用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;

我的lexer语法在这里:

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退出模式而不消耗令牌,这样当我们返回DEFAULT_MODE时'* /'是下一个令牌。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

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

对于CLOSE_NAME规则,您可以使用谓词而不是匹配的文字来处理评论的结尾:

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

这可以产生零长度令牌并且在ANTLR 4.0中不被允许,但是在ANTLR 4.1中删除了限制(更改为警告),因为我们意识到可以使用零长度令牌来触发模式改变,从而避免无限循环。