Parsing 条件词法分析器

Parsing 条件词法分析器,parsing,antlr,antlr4,grammar,lexer,Parsing,Antlr,Antlr4,Grammar,Lexer,我有以下ANTLR语法 relation : IDENTIFIER EQUAL relative_date ; relative_date : K_NOW (PLUS | MINUS) NUMERIC_LITERAL TIME_UNIT ; IDENTIFIER : //'"' (~'"' | '""')* '"' '`' (~'`' | '``')* '`' | '[' ~']'* ']' | [a-zA-Z_] [a-zA

我有以下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]+ ;
如果我将
时间单位
放在
标识符
解析器之前

  • something=now-5d
    有效
  • d=now-5d
    不起作用,开始出现故障
    d
    ,并表示需要
    标识符
如果我将
时间单位
放在
标识符
解析器之后

  • something=now-5d
    在第二个
    d
    时失败,并表示需要时间单位
  • d=now-5d
    在第二次
    d
    时失败,并表示需要时间单位

有人能帮我改变语法,使之在两种情况下都适用吗?例如,当它是相对日期时,使用
时间单位
lexer,否则
标识符
lexer

您可以将
数字时间单位
更改为一个lexer规则
持续时间
,并自己解析持续时间

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的lexer试图匹配尽可能多的字符。当两个或多个lexer规则匹配相同数量的字符时,第一个定义的规则“获胜”

因此,输入的
d
既匹配
时间单位
又匹配
标识符
,但由于首先定义了
标识符
,因此它获胜。换句话说:规则
时间单位
永远不会匹配

解决方案,将
时间单位
置于
标识符
之前:

TIME_UNIT
 : ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
 ;

K_NOW
 : N O W
 ;

IDENTIFIER 
 : //'"' (~'"' | '""')* '"'
   '`' (~'`' | '``')* '`'
 | '[' ~']'* ']'
 | [a-zA-Z_] [a-zA-Z_.0-9]* 
 ;
relation
 : identifier EQUAL relative_date
 ;
(请注意,
K_NOW
还需要放在
标识符之前
!)

但是,现在输入的
d
h
m
等将永远不会成为
标识符,因为它们现在将始终成为
时间单位
。你不能改变这一点,这就是ANTLR的lexer的工作原理。您可以在解析器中这样处理:

identifier
 : IDENTIFIER
 | TIME_UNIT
 ;

TIME_UNIT
 : ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
 ;

IDENTIFIER 
 : //'"' (~'"' | '""')* '"'
   '`' (~'`' | '``')* '`'
 | '[' ~']'* ']'
 | [a-zA-Z_] [a-zA-Z_.0-9]* 
 ;
然后在解析器规则中使用规则
标识符
,而不是
标识符

TIME_UNIT
 : ('h'|'m'|'s'|'d'|'w'|'M'|'y'|'q')
 ;

K_NOW
 : N O W
 ;

IDENTIFIER 
 : //'"' (~'"' | '""')* '"'
   '`' (~'`' | '``')* '`'
 | '[' ~']'* ']'
 | [a-zA-Z_] [a-zA-Z_.0-9]* 
 ;
relation
 : identifier EQUAL relative_date
 ;

这将导致
123456789 hi
标记为
123456789 h
(持续时间)和
i
(标识符)。很可能不是Richa想要的…@BartKiers事实上不,这对我来说很有效。我在
I
处得到了一个错误节点,看起来很正常。我有什么事吗missing@Richa您可能还没有重新生成lexer和解析器。就如我刚才解释的那样。检查此代码:否则会有更多您尚未显示的冲突规则。无论如何,我不会同意这里描述的建议。是的@BartKiers你是对的。我没有将整个语法文件粘贴到这里,只是为了避免问题中的噪音,我正在努力解决的部分。@Richa我对
K\u NOW
标记做了一个小编辑。非常感谢。我将尝试在我的代码中实现这一点