java – ANTLR:在引号字符串中解析日期

我有一个问题,想弄清楚如何解析我的语法中的日期.

问题在于它与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)?
    ;

我的语法期望这些东西:

>“引用字符串” – >给出一个字符串
>“2015-03 TOTOTo” – >给出一个字符串,因为日期格式不匹配.
>“2015-03-15” – >给出一个日期,因为它匹配DQUOTE INT’ – ‘INT’ – ‘INT DQUOTE

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

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

《java – ANTLR:在引号字符串中解析日期》

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

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

这意味着,STRING_LITERAL词法分析器规则将使用所有字符串,包括日期,并仅输出STRING_LITERAL标记.解析器甚至从不考虑日期和相关的解析器子规则.

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

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

notDateString谓词要求本机代码在日期格式和其他字符串之间执行必要的消歧.

另一种方法是将STRING_LITERAL规则完全提升到解析器.可行,但有点混乱取决于是否需要在“真实”字符串中保留空格.

顺便说一下,您可能希望在标准系列的单元测试中添加token stream dump.

点赞