问题描述
我有一个基于sql Antlr4的词法分析器,它也可以从sql注释中解析特定的标签:
OPEN_COMMENT: '/*' -> mode(COMMENT);
mode COMMENT;
NAME_TAG : '@name';
CLOSE_COMMENT: '*/' -> mode(DEFAULT_MODE);
此词法分析器能够读取以下内容:
/* @name GetAllUsers */
但是,我也希望能够阅读行注释:
-- @name @GetAllUsers
我不能使用相同的模式,因为CLOSE_COMMENT的工作方式有所不同:块注释应为*/
,行注释应为\n
。但是,无论是行注释还是块注释,我都希望解析器获得相同的标记。
我该如何实现?还是使用词法分析器模式根本不是正确的方法?
(出于这个问题的目的,我将代码仅修整为必要的部分,因此更易于阅读和推理。您可以找到有问题的here中的整个代码。)
解决方法
您必须将某些内容复制到2种不同的模式中。您可以定义通用令牌,例如语法NAME
块内的tokens { ... }
令牌,以便可以在展位模式下共享它。
快速演示:
lexer grammar TestLexer;
tokens {
NAME
}
ID
: [a-zA-Z_] [a-zA-Z_0-9]*
;
LINE_COMMENT_START
: '--' -> skip,mode(LINE_COMMENT_MODE)
;
BLOCK_COMMENT_START
: '/*' -> skip,mode(BLOCK_COMMENT_MODE)
;
mode LINE_COMMENT_MODE;
LINE_COMMENT_MODE_ID
: ID -> type(ID)
;
LINE_COMMENT_NAME
: '@name' -> type(NAME)
;
LINE_COMMENT_END
: [\r\n]+ -> skip,mode(DEFAULT_MODE)
;
LINE_COMMENT_OTHER
: . -> skip
;
mode BLOCK_COMMENT_MODE;
BLOCK_COMMENT_MODE_ID
: ID -> type(ID)
;
BLOCK_COMMENT_NAME
: '@name' -> type(NAME)
;
BLOCK_COMMENT_END
: '*/' -> skip,mode(DEFAULT_MODE)
;
BLOCK_COMMENT_OTHER
: . -> skip
;
如果将输入标记化:
-- @name GetAllUsers
/* @name GetAllUsers */
您将获得以下令牌:
NAME `@name`
ID `GetAllUsers`
NAME `@name`
ID `GetAllUsers`