如何解决ANTLR条件词法分析器
我有以下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
词法分析器,否则使用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]
;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。