ANTLR Грамматическая строка 1: 6 несоответствующий ввод '<EOF>' ожидающий '.' - PullRequest
0 голосов
/ 23 января 2019

Я играю с файлами грамматики antlr4, и я хотел написать свою собственную jsonpath грамматику.

Я пришел с этим:

grammar ObjectPath;

objectPath      : dnot;

dnot            : ROOT expr ('.' expr)
                | EOF
                ;

expr            : select #selectExpr
                | ID #idExpr
                ;

select          : ID '[]' #selectAll
                | ID '[' INT ']' #selectIndex
                | ID '[' INT (',' INT)* ']' #selectIndexes
                | ID '[' INT ':' INT ']' #selectRange
                | ID '[' INT ':]' #selectFrom
                | ID '[:' INT ']' #selectUntil
                | ID '[-' INT ':]' #selectLast
                | ID '[?(' query ')]' #selectQuery
                ;

query           : expr (AND|OR) expr # andOr
                | ALL # all
                | QPREF ID # prop
                | QPREF ID GT INT # gt
                | QPREF ID LT INT # lt
                | QPREF ID EQ INT # eq
                | QPREF ID GTE INT # gte
                | QPREF ID LTE INT # lte
                ;

/** Lexer **/
ROOT    : '$.' ;
QPREF   : '@.' ;
ID      : [a-zA-Z][a-zA-Z0-9]* ;
INT     : '0' | [1-9][0-9]* ;
AND     : '&&' ;
OR      : '||' ;
GT      : '>'  ;
LT      : '<'  ;
EQ      : '==' ;
GTE     : '>=' ;
LTE     : '<=' ;
ALL     : '*'  ;

Послевыполняя это на простом выражении:

CharStream input = CharStreams.fromString("$.name");
ObjectPathLexer lexer = new ObjectPathLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);

ObjectPathParser parser = new ObjectPathParser(tokens);
ParseTree parseTree = parser.dnot();
ObjectPathDefaultVisitor visitor = ...
System.out.println(visitor.visit(parseTree));
System.out.println(parseTree.toStringTree(parser));

Вывод в порядке, что означает, что «имя» на самом деле получено из json, но есть предупреждение, которое я не могу объяснить:

line 1:6 mismatched input '<EOF>' expecting '.'

Я прочитал, что мне нужно явно добавить правило EOF к моему начальному (dnot), но это, похоже, не работает.

Есть идеи, что я могу сделать?

1 Ответ

0 голосов
/ 23 января 2019

Ваш ввод $.name не может быть проанализирован по вашему правилу:

dnot            : ROOT expr ('.' expr)
                | EOF
                ;

$.name производит 2 токена:

  1. ROOT
  2. ID

Но ваша первая альтернатива, ROOT expr ('.' expr), ожидает 2 выражения, разделенных .. Возможно, вы хотели сделать второй expr необязательным, например:

dnot            : ROOT expr ('.' expr)*
                | EOF
                ;

И EOF обычно добавляется в конце вашего правила запуска, чтобы заставить анализатор использовать все токены. Как вы и сделали, анализатор успешно проанализировал ROOT expr, но затем не смог выполнить дальнейший анализ и выдает предупреждение, которое вы видели (ожидая '.').

Так как objectPath кажется вашим правилом старта, я думаю, это то, что вы хотите сделать:

objectPath      : dnot EOF;

dnot            : ROOT expr ('.' expr)?
                ;

Кроме того, подобные токены [], '[?(' и т. Д. Выглядят подозрительно. Я не очень знаком с Object Path, но, склеивая эти символы друг с другом, ввод, подобный этому [ ] ([ и ], разделенные пробелом), не будет совпадать с []. Так что, если foo[ ] действительно, я бы написал это так:

select          : ID '[' ']' #selectAll
                | ...

и пропустить пробелы в лексере:

SPACES : [ \t\r\n]+ -> skip;
...