ANTLR:解析引号字符串中的日期

ANTLR: Parse a date within a quote string

我在弄清楚如何解析语法中的日期时遇到问题。

问题在于它与 String 共享其定义,但根据 Antlr 4 文档,它应该通过查看声明顺序来遵循优先级。

这是我的语法:

grammar formula;


/* entry point */
parse: expr EOF;

expr
    : value                                  # argumentArithmeticExpr
    | l=expr operator=('*'|'/'|'%') r=expr   # multdivArithmeticExpr // TODO: test the % operator
    | l=expr operator=('+'|'-') r=expr       # addsubtArithmeticExpr
    | '-' expr                               # minusArithmeticExpr
    | FUNCTION_NAME '(' (expr ( ','  expr )* ) ? ')'# functionExpr
    | '(' expr ')'                           # parensArithmeticExpr
    ;

value
    : number
    | variable
    | date
    | string
    | bool;

/* Atomes */

bool
    : BOOL
    ;

variable
    : '[' (~(']') | ' ')* ']'
    ;

date
    : DQUOTE date_format DQUOTE
    | QUOTE date_format QUOTE
    ;

date_format
    : year=INT '-' month=INT '-' day=INT (hour=INT ':' minutes=INT ':' seconds=INT)?
    ;

string
    : STRING_LITERAL
    ;


number
    : ('+'|'-')? NUMERIC_LITERAL
    ;


/* lexemes de base */

QUOTE   : '\'';
DQUOTE  : '"';
MINUS   : '-';
COLON   : ':';
DOT     : '.';
PIPE    : '|';
BOOL    : T R U E | F A L S E;

FUNCTION_NAME: IDENTIFIER ;

IDENTIFIER
 : [a-zA-Z_] [a-zA-Z_0-9]* // TODO: do we more chars in this set?
 ;

NUMERIC_LITERAL
 : DIGIT+ ( '.' DIGIT* )? ( E [-+]? DIGIT+ )? // ex: 0.05e3
 | '.' DIGIT+ ( E [-+]? DIGIT+ )? // ex: .05e3
 ;

INT: DIGIT+;

STRING_LITERAL
    :  '\'' ( ~'\'' | '\'\'' )* '\''
    |  '"' ( ~'"' | '""' )* '"'
    ;

WS: [ \t\n]+ -> skip;

UNEXPECTED_CHAR: . ;

fragment DIGIT: [0-9];
fragment A:('a'|'A');
fragment B:('b'|'B');
fragment C:('c'|'C');
fragment D:('d'|'D');
fragment E:('e'|'E');
fragment F:('f'|'F');
fragment G:('g'|'G');
fragment H:('h'|'H');
fragment I:('i'|'I');
fragment J:('j'|'J');
fragment K:('k'|'K');
fragment L:('l'|'L');
fragment M:('m'|'M');
fragment N:('n'|'N');
fragment O:('o'|'O');
fragment P:('p'|'P');
fragment Q:('q'|'Q');
fragment R:('r'|'R');
fragment S:('s'|'S');
fragment T:('t'|'T');
fragment U:('u'|'U');
fragment V:('v'|'V');
fragment W:('w'|'W');
fragment X:('x'|'X');
fragment Y:('y'|'Y');
fragment Z:('z'|'Z');

这里的重要部分是:

value
    : number
    | variable
    | date
    | string
    | bool;

date
    : DQUOTE date_format DQUOTE
    | QUOTE date_format QUOTE
    ;

date_format
    : year=INT '-' month=INT '-' day=INT (hour=INT ':' minutes=INT ':' seconds=INT)?
    ;

我的语法需要这些东西:

我(尝试过?)确保解析器在尝试匹配字符串之前尝试匹配日期value: ...| date | string| ....

但是当我使用 grun 实用程序(和我的单元测试...)时,我可以看到它将日期归类为字符串,就像它从不费心检查日期格式一样。

你能告诉我为什么会这样吗? 我怀疑我声明语法规则的顺序有问题,但我尝试了一些排列但没有得到任何结果。

问题源于未能理解词法分析器在任何解析器规则被有效考虑之前运行完成。

这意味着,STRING_LITERAL 词法分析器规则将使用所有字符串,包括日期,并且仅输出 STRING_LITERAL 个标记。 date 和相关的解析器子规则从未被解析器考虑过。

也许最小的解决方案是将 STRING_LITERAL 词法分析器规则修改为

STRING_LITERAL
    :  { notDateString() }? 
    ( QUOTE  .*? QUOTE
    | DQUOTE .*? DQUOTE
    )
    ;

notDateString 谓词需要本机代码来执行日期格式和其他字符串之间的基本消歧。

另一种选择是将 STRING_LITERAL 规则完全提升到解析器。可行,但有点混乱,具体取决于是否需要在 'real' 个字符串中保留空格。

顺便说一句,您可能希望将 添加到您的标准单元测试系列中。