2016-04-08 4 views
3

У меня возникла проблема в том, как разобрать дату в моей грамматике.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)? 
    ; 

Моя грамматика ожидает, что эти вещи:

  • "a quoted string" -> дает string
  • "2015-03 TOTOTo" -> дает string, потому что формат даты не совпадает.
  • "2015-03-15" -> дает date, потому что он соответствует DQUOTE INT '-' INT '-' INT DQUOTE

И я, чтобы убедиться, что анализатор пытается сопоставить дату перед тем пытается соответствовать строке: value: ...| date | string| ... (пробовал?).

Но когда я использую утилиту grun (и мои юнит-тесты ...), я вижу, что она классифицирует дату как строку, например, если она никогда не беспокоилась о проверке формата даты.

the ast

Можете ли вы сказать мне, почему это так? Я подозреваю, что есть улов с порядком, в котором я объявляю свои правила грамматики, но я попробовал некоторые перестановки и ничего не получил.

ответ

1

Проблема связана с непониманием того, что лексер работает до завершения до. Эффективное рассмотрение любого из правил парсера.

Это означает, что правило lexer STRING_LITERAL будет потреблять все строки, включая даты и выводить только токеты STRING_LITERAL. date и связанные с ним подпрограммы анализатора даже не рассматриваются анализатором.

Возможно минимальное решение изменить правила STRING_LITERAL лексических анализатора для

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

notDateString предиката требует нативный кода для выполнения существенного устранения неоднозначности между форматами даты и другими строками.

Другой альтернативой является продвижение правила STRING_LITERAL полностью к парсеру. Doable, но немного беспорядочно в зависимости от того, нужно ли сохранять пробелы в «реальных» строках.

Кстати, вы можете добавить token stream dump в стандартную серию модульных испытаний.

+0

Я реализовал другое решение, которое должно анализировать дату в правиле * string *. Но я приму решение в качестве альтернативы. – Gui13