代码之家  ›  专栏  ›  技术社区  ›  Andrei Ciobanu

antlr语法行1:6输入不匹配'<eof>'应为''。

  •  1
  • Andrei Ciobanu  · 技术社区  · 7 年前

    我在玩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 回复  |  直到 7 年前
        1
  •  4
  •   Bart Kiers    7 年前

    你的输入 $.name 无法按规则分析:

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

    名字 生成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)?
                    ;
    

    另外,像这样的代币 [] , '[?(' 等等,看起来可疑。我不太熟悉对象路径,但是通过将这些字符粘在一起,像这样输入 [ ] ( [ ] 以空格分隔)将不匹配 [] . 所以如果 foo[ ] 有效,我改为这样写:

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

    并跳过lexer中的空格:

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