ANTLR语法第1:6行的输入'<eof>'不匹配,期望为'。'

时间:2019-01-23 18:40:38

标签: java antlr grammar antlr4

我正在使用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 :(得分:4)

您的输入$.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)?
                ;

此外,像这样的标记[]'[?('等看起来也是可疑的。我对对象路径不是很熟悉,但是通过将这些字符相互粘合,像这样的输入[ ][]用空格隔开)将不会与{ {1}}。因此,如果[]有效,我可以这样写:

foo[ ]

并跳过词法分析器中的空格:

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