我正在编写一个解析器,其语言如下所示:
L00<<identifier>>
L10<<keyword>>
L250<<identifier>>
<<identifier>>
也就是说,每行可能会也可能不会以Lxxx..
形式的行号开头(&#39; L&#39;后跟一个或多个数字),后跟一个标识符或关键字。标识符为标准[a-zA-Z_][a-zA-Z0-9_]*
,L
后面的位数不固定。行号和后面的identifer / keyword之间的空格是可选的(在大多数情况下不存在)。
我目前的词法分析器如下:
// Parser rules
commands : command*;
command : LINE_NUM? keyword NEWLINE
| LINE_NUM? IDENTIFIER NEWLINE;
keyword : KEYWORD_A | KEYWORD_B | ... ;
// Lexer rules
fragment INT : [0-9]+;
LINE_NUM : 'L' INT;
KEYWORD_A : 'someKeyword';
KEYWORD_B : 'reservedWord';
...
IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_]*
然而,这导致所有以LINE_NUM
标记开头的行被标记为IDENTIFIER
s。
有没有办法使用ANTLR语法正确地标记这个输入?
答案 0 :(得分:1)
您需要向IDENTIFIER
添加语义谓词:
IDENTIFIER
: {_input.getCharPositionInLine() != 0
|| _input.LA(1) != 'L'
|| !Character.isDigit(_input.LA(2))}?
[a-zA-Z_] [a-zA-Z0-9_]*
;
您还可以使用词法模式来避免语义谓词。
//
// Default mode is active at the beginning of a line
//
LINE_NUM
: 'L' [0-9]+ -> pushMode(NotBeginningOfLine)
;
KEYWORD_A : 'someKeyword' -> pushMode(NotBeginningOfLine);
KEYWORD_B : 'reservedWord' -> pushMode(NotBeginningOfLine);
IDENTIFIER
: ( 'L'
| 'L' [a-zA-Z_] [a-zA-Z0-9_]*
| [a-zA-KM-Z_] [a-zA-Z0-9_]*
)
-> pushMode(NotBeginningOfLine)
;
NL : ('\r' '\n'? | '\n');
mode NotBeginningOfLine;
NotBeginningOfLine_NL : ('\r' '\n'? | '\n') -> type(NL), popMode;
NotBeginningOfLine_KEYWORD_A : KEYWORD_A -> type(KEYWORD_A);
NotBeginningOfLine_KEYWORD_B : KEYWORD_B -> type(KEYWORD_B);
NotBeginningOfLine_IDENTIFIER
: [a-zA-Z_] [a-zA-Z0-9_]* -> type(IDENTIFIER)
;