问题描述
我有以下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
解析器之前
如果我将TIME_UNIT
放在IDENTIFIER
解析器之后
有人可以帮助我如何更改两种情况下的语法吗?就像是相对日期一样,请使用TIME_UNIT
词法分析器,否则使用IDENTIFIER
词法分析器
解决方法
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
;
,
您的IDENTIFIER
与TIME_UNIT
冲突。 d
都可以作为IDENTIFIER
的一部分,并且 是有效的TIME_UNIT
。
这使解析器感到困惑。因此,在以d
开头时,您必须使用更长的标识符,或者从允许的1个字母的IDENTIFIER
中排除它。
第二个选项将要求对语法进行以下更改:
IDENTIFIER
: //'"' (~'"' | '""')* '"'
'`' (~'`' | '``')* '`'
| '[' ~']'* ']'
| [a-ce-zA-Z_] [a-zA-Z_.0-9]*
请注意从[a-zA-Z_]
更改为[a-ce-zA-Z_]
。
您可以将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]
;