java - 输入时没有可行的替代方案

标签 java parsing antlr

我有一个关于我语法的小问题。 我想解析字符串,如下所示:

 "(ICOM LIKE '%bridge%' or ICOM LIKE '%Munich%')"

我最终得到了以下语法(比我所知道的要复杂一点):

//旨在解析一个完整的BQS格式的Query

grammar Logic;

options {
    output=AST;
}

tokens {
  NOT_LIKE;
}

/*------------------------------------------------------------------
 * PARSER RULES
 *------------------------------------------------------------------*/
 // precedence order is (low to high): or, and, not, [comp_op, geo_op, rel_geo_op, like, not like, exists], ()
 parse  
    : expression EOF -> expression
    ; // ommit the EOF token

 expression
    : query
    ;       

 query  
    : term (OR^ term)*    // make `or` the root
    ;

 term   
    : factor (AND^ factor)*
    ;

 factor
  :  (notexp -> notexp) ( NOT LIKE e=notexp  -> ^(NOT_LIKE $factor $e))?
  ;

 notexp
  :  NOT^ like
  |  like
  ;

 like // this one has to be completed (a lot)
    : atom (LIKE^ atom)*
    ;


 atom   
    : ID 
    | | '(' expression ')' -> expression
    ;

/*------------------------------------------------------------------
 * LEXER RULES
 *------------------------------------------------------------------*/
// GENERAL OPERATORS: 
//NOTLIKE   :   'notlike' | 'NOTLIKE'; // whitespaces have been removed
LIKE    :   'like' | 'LIKE';

OR          :   'or' | 'OR';
AND         :   'and' | 'AND';
NOT         :   'not' | 'NOT';

//ELEMENTS 
CONSTANT_EXPRESSION : DATE | NUMBER | QUOTED_STRING;    
ID          :   (CHARACTER|DIGIT)+; 

WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+    { $channel = HIDDEN; } ;

fragment DATE       :   '\'' YEAR '/' MONTH '/' DAY (' ' HOUR ':' MINUTE ':' SECOND)? '\'';

fragment QUOTED_STRING :    '\'' (CHARACTER)+ '\'' ; 

//UNITS
fragment CHARACTER :    ('a'..'z' | 'A'..'Z'|'.'|'\''|'%'); // FIXME: Careful, should be all ASCII
fragment DIGIT  :   '0'..'9' ;
fragment DIGIT_SEQ  :(DIGIT)+;
fragment DEL    :   SPACE ',' SPACE ; //Delimiter + may be space behind
fragment NUMBER :   (SIGN)? DIGIT_SEQ ('.' (DIGIT_SEQ)?)?; // should be given in decimal degrees, North is 0 and direction is clockwise, range is 0 to 360
fragment SIGN   :   '+' | '-';
fragment YEAR   :   DIGIT DIGIT DIGIT DIGIT;
fragment MONTH  :   DIGIT DIGIT;
fragment DAY    :   DIGIT DIGIT;
fragment HOUR   :   DIGIT DIGIT;
fragment MINUTE :   DIGIT DIGIT;
fragment SECOND :   DIGIT (DIGIT)? ('.' (DIGIT)+)?;

fragment SPACE : (' ')?;// used to increase compatibility

事情是,我在创建 AST 时收到此消息:

line 1:11 no viable alternative at input ''%bridge%''
line 1:35 no viable alternative at input ''%Munich%''

虽然生成的树是正确的(至少就我而言是这样):

antlr viable ast tree

那么,有人能给我一些提示,告诉我那里出了什么问题吗?我认为字符包含正确解析此表达式所需的所有额外字符。 . .

谢谢!

像往常一样,一些Java代码来快速测试语法:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
  public static void main(String[] args) throws Exception {

    // the expression
    String src = "(ICOM LIKE '%bridge%' or ICOM LIKE '%Munich%')";

    // create a lexer & parser
    //LogicLexer lexer = new LogicLexer(new ANTLRStringStream(src));
    //LogicParser parser = new LogicParser(new CommonTokenStream(lexer));

    LogicLexer lexer = new LogicLexer(new ANTLRStringStream(src));
    LogicParser parser = new LogicParser(new CommonTokenStream(lexer));

    // invoke the entry point of the parser (the parse() method) and get the AST
    CommonTree tree = (CommonTree)parser.parse().getTree();

    // print the DOT representation of the AST 
    DOTTreeGenerator gen = new DOTTreeGenerator();
    StringTemplate st = gen.toDOT(tree);
    System.out.println(st);
  }
}

最佳答案

我看到 3 个问题:

1

您的 atom 规则匹配 epsilon(无):

atom   
 : ID 
 | | '(' expression ')' -> expression
 ;

(注意 | | 中的“虚无”)

导致你的语法有歧义。我想应该是:

atom   
 : ID 
 | '(' expression ')' -> expression
 ;

2

您的 fragment CHARACTER 匹配一个单引号,而这个单引号也表示 fragment QUOTED_STRING 的结尾。

我想 CHARACTER 应该是这样的:

fragment CHARACTER : ('a'..'z' | 'A'..'Z' | '.' | '%'); 

3

在您的解析器规则中没有任何地方与标记 CONSTANT_EXPRESSION 匹配,因此您发布的 AST 永远不可能由根据您发布的语法生成的解析器创建。我假设您希望像这样在 atom 规则中匹配它:

atom   
 : ID 
 | CONSTANT_EXPRESSION
 | '(' expression ')' -> expression
 ;

通过上面概述的更改,我得到了以下 AST,没有任何错误被打印到控制台:

enter image description here

关于java - 输入时没有可行的替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10614659/

相关文章:

compiler-construction - ANTLR if-else 歧义错误

java - 自定义键盘抛出异常

PHP 简单 HTML DOM 解析器死掉

php - 在 PHP 中解析多字节字符串

php - 从所有先前的消息和元数据中提取电子邮件本身(Sendgrid Parse API/PHP)?

parsing - 如何更正 token ,然后从ANTLR中的失败谓词中恢复?

antlr - "skip"更改解析器行为

java - log4j 不压缩日志文件

java - 子类抛出 UnsupportedOperationException 与忽略输入参数

Java:非法参数异常