ANTLR 条件词法分析器
ANTLR conditional Lexer
我有以下ANTLR语法
relation
: IDENTIFIER EQUAL relative_date
;
relative_date
: K_NOW (PLUS | MINUS) NUMERIC_LITERAL TIME_UNIT
;
IDENTIFIER
: //'"' (~'"' | '""')* '"'
'`' (~'`' | '``')* '`'
| '[' ~']'* ']'
| [a-zA-Z_] [a-zA-Z_.0-9]*
;
TIME_UNIT
: ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
;
PLUS : '+';
MINUS : '-';
EQUAL: '=';
K_NOW : N O W;
NUMERIC_LITERAL
: [0-9]+ ;
如果我把 TIME_UNIT
放在 IDENTIFIER
解析器之前
something = now - 5d
有效
d = now - 5d
不工作,起初失败 d
并说 IDENTIFIER
需要
如果我把 TIME_UNIT
放在 IDENTIFIER
解析器之后
something = now - 5d
在第二个 d
失败并说 TIME_UNIT 需要
d = now - 5d
在第二个 d
处失败并表示 TIME_UNIT 需要
有人可以帮助我如何更改语法以在两种情况下都有效吗?就像当它是相对日期时使用 TIME_UNIT
lexer 否则 IDENTIFIER
lexer
您可以将 NUMERIC_LITERAL TIME_UNIT
更改为一个词法分析器规则 DURATION
并自行解析持续时间
relative_date
: K_NOW (PLUS | MINUS) DURATION
;
DURATION
: [0-9]+ SPACE* ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
;
SPACE
: [ \u000B\t\r\n]
;
ANTLR 的词法分析器尝试匹配尽可能多的字符。当 2 个或多个词法分析器规则匹配相同数量的字符时,首先定义的规则“获胜”。
所以,输入d
同时匹配TIME_UNIT
和IDENTIFIER
,但是因为IDENTIFIER
先被定义,所以它获胜。换句话说:规则 TIME_UNIT
将永远不会被匹配。
解决办法,把TIME_UNIT
放在IDENTIFIER
之前:
TIME_UNIT
: ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
;
K_NOW
: N O W
;
IDENTIFIER
: //'"' (~'"' | '""')* '"'
'`' (~'`' | '``')* '`'
| '[' ~']'* ']'
| [a-zA-Z_] [a-zA-Z_.0-9]*
;
(注意K_NOW
也需要放在IDENTIFIER
之前!)
但是,现在输入 d
、h
、m
等永远不会变成 IDENTIFIER
,因为它们现在总是会变成 TIME_UNIT
.你不能改变它,这就是 ANTLR 的词法分析器的工作方式。您可以像这样在解析器中处理它:
identifier
: IDENTIFIER
| TIME_UNIT
;
TIME_UNIT
: ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
;
IDENTIFIER
: //'"' (~'"' | '""')* '"'
'`' (~'`' | '``')* '`'
| '[' ~']'* ']'
| [a-zA-Z_] [a-zA-Z_.0-9]*
;
然后在解析器规则中使用规则 identifier
而不是 IDENTIFIER
:
relation
: identifier EQUAL relative_date
;
我有以下ANTLR语法
relation
: IDENTIFIER EQUAL relative_date
;
relative_date
: K_NOW (PLUS | MINUS) NUMERIC_LITERAL TIME_UNIT
;
IDENTIFIER
: //'"' (~'"' | '""')* '"'
'`' (~'`' | '``')* '`'
| '[' ~']'* ']'
| [a-zA-Z_] [a-zA-Z_.0-9]*
;
TIME_UNIT
: ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
;
PLUS : '+';
MINUS : '-';
EQUAL: '=';
K_NOW : N O W;
NUMERIC_LITERAL
: [0-9]+ ;
如果我把 TIME_UNIT
放在 IDENTIFIER
解析器之前
something = now - 5d
有效d = now - 5d
不工作,起初失败d
并说IDENTIFIER
需要
如果我把 TIME_UNIT
放在 IDENTIFIER
解析器之后
something = now - 5d
在第二个d
失败并说 TIME_UNIT 需要d = now - 5d
在第二个d
处失败并表示 TIME_UNIT 需要
有人可以帮助我如何更改语法以在两种情况下都有效吗?就像当它是相对日期时使用 TIME_UNIT
lexer 否则 IDENTIFIER
lexer
您可以将 NUMERIC_LITERAL TIME_UNIT
更改为一个词法分析器规则 DURATION
并自行解析持续时间
relative_date
: K_NOW (PLUS | MINUS) DURATION
;
DURATION
: [0-9]+ SPACE* ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
;
SPACE
: [ \u000B\t\r\n]
;
ANTLR 的词法分析器尝试匹配尽可能多的字符。当 2 个或多个词法分析器规则匹配相同数量的字符时,首先定义的规则“获胜”。
所以,输入d
同时匹配TIME_UNIT
和IDENTIFIER
,但是因为IDENTIFIER
先被定义,所以它获胜。换句话说:规则 TIME_UNIT
将永远不会被匹配。
解决办法,把TIME_UNIT
放在IDENTIFIER
之前:
TIME_UNIT
: ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
;
K_NOW
: N O W
;
IDENTIFIER
: //'"' (~'"' | '""')* '"'
'`' (~'`' | '``')* '`'
| '[' ~']'* ']'
| [a-zA-Z_] [a-zA-Z_.0-9]*
;
(注意K_NOW
也需要放在IDENTIFIER
之前!)
但是,现在输入 d
、h
、m
等永远不会变成 IDENTIFIER
,因为它们现在总是会变成 TIME_UNIT
.你不能改变它,这就是 ANTLR 的词法分析器的工作方式。您可以像这样在解析器中处理它:
identifier
: IDENTIFIER
| TIME_UNIT
;
TIME_UNIT
: ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
;
IDENTIFIER
: //'"' (~'"' | '""')* '"'
'`' (~'`' | '``')* '`'
| '[' ~']'* ']'
| [a-zA-Z_] [a-zA-Z_.0-9]*
;
然后在解析器规则中使用规则 identifier
而不是 IDENTIFIER
:
relation
: identifier EQUAL relative_date
;