【问题标题】:ANTLR - Join tokens to outputANTLR - 加入令牌以输出
【发布时间】:2014-07-15 09:15:51
【问题描述】:

使用 ANTLR3,我想解析这样的字符串:

  • 姓名为空且年龄不在 (14, 15)

对于这些情况,我想获得以下 AST:

  n0 [label="QUERY"];
  n1 [label="AND"];
  n1 [label="AND"];
  n2 [label="IS NOT"];
  n2 [label="IS NOT"];
  n3 [label="name"];
  n4 [label="empty"];
  n5 [label="NOT IN"];
  n5 [label="NOT IN"];
  n6 [label="age"];
  n7 [label="14"];
  n8 [label="15"];

  n0 -> n1 // "QUERY" -> "AND"
  n1 -> n2 // "AND" -> "IS NOT"
  n2 -> n3 // "IS NOT" -> "name"
  n2 -> n4 // "IS NOT" -> "empty"
  n1 -> n5 // "AND" -> "NOT IN"
  n5 -> n6 // "NOT IN" -> "age"
  n5 -> n7 // "NOT IN" -> "14"
  n5 -> n8 // "NOT IN" -> "15"

但我的 n2 和 n5 节点 看起来像: n2 [标签="IS"]; n5 [label="NOT"];

即,仅出现第一个单词。如何将两个令牌合并为一个?

我的语法是:

query
    :   expr EOF   ->   ^(QUERY expr)
    ;

expr
    :   logical_expr
    ;

logical_expr
    :   equality_expr (logical_op^ equality_expr)*
    ;

equality_expr
    :   ID equality_op+ atom    -> ^(equality_op ID atom)
    |   '(' expr ')'    ->  ^('(' expr)
    ;

atom
    :   ID
    |   id_list
    |   Int
    |   Number
    |   String
    |   '*'
    ;

id_list
    :   '(' ID (',' ID)+ ')'    ->  ID+
    |   '(' Number (',' Number)* ')' -> Number+
    |   '(' String (',' String)* ')' -> String+
    ;

equality_op
    :   'IN'
    |   'IS'
    |   'NOT'
    |   'in'
    |   'is'
    |   'not'
    ;

logical_op
    :   'AND'
    |   'OR'
    |   'and'
    |   'or'
    ;

Number
    :   Int ('.' Digit*)?
    ;

ID
    :   ('a'..'z' | 'A'..'Z' | '_' | '.' | '-' | '*' | '/' | ':' | Digit)* 
    ;

String
@after {
    setText(getText().substring(1, getText().length()-1).replaceAll("\\\\(.)", "$1"));
    }
    :  '"'  (~('"' | '\\')  | '\\' ('\\' | '"'))* '"' 
    |  '\'' (~('\'' | '\\') | '\\' ('\\' | '\''))* '\''
    ;

Comment
    :  '//' ~('\r' | '\n')* {skip();}
    |  '/*' .* '*/'         {skip();}
    ;

Space
    :  (' ' | '\t' | '\r' | '\n' | '\u000C') {skip();}
    ;

fragment Int
    :  '1'..'9' Digit*
    |  '0'
    ;

fragment Digit 
    :  '0'..'9'
    ;

indexes
    :  ('[' expr ']')+ -> ^(INDEXES expr+)
    ;

【问题讨论】:

    标签: java token grammar antlr3


    【解决方案1】:

    改为这样做(检查我添加的内联 cmets):

    tokens {
      IS_NOT; // added
      NOT_IN; // added
      QUERY;
      INDEXES;
    }
    
    query
        :   expr EOF   ->   ^(QUERY expr)
        ;
    
    expr
        :   logical_expr
        ;
    
    logical_expr
        :   equality_expr (logical_op^ equality_expr)*
        ;
    
    equality_expr
        :   ID equality_op atom    -> ^(equality_op ID atom) // changed equality_op+ to equality_op
        |   '(' expr ')'    ->  ^('(' expr)
        ;
    
    atom
        :   ID
        |   id_list
        |   Int
        |   Number
        |   String
        |   '*'
        ;
    
    id_list
        :   '(' ID (',' ID)+ ')'    ->  ID+
        |   '(' Number (',' Number)* ')' -> Number+
        |   '(' String (',' String)* ')' -> String+
        ;
    
    equality_op
        :   IS NOT -> IS_NOT // added
        |   NOT IN -> NOT_IN // added
        |   IN
        |   IS
        |   NOT
        ;
    
    logical_op
        :   AND
        |   OR
        ;
    
    IS : 'IS' | 'is'; // added
    NOT : 'NOT' | 'not'; // added
    IN : 'IN' | 'in'; // added
    AND : 'AND' | 'and'; // added
    OR : 'OR' | 'or'; // added
    
    Number
        :   Int ('.' Digit*)?
        ;
    
    ID
        :   ('a'..'z' | 'A'..'Z' | '_' | '.' | '-' | '*' | '/' | ':' | Digit)+ 
        ;
    
    String
    @after {
        setText(getText().substring(1, getText().length()-1).replaceAll("\\\\(.)", "$1"));
        }
        :  '"'  (~('"' | '\\')  | '\\' ('\\' | '"'))* '"' 
        |  '\'' (~('\'' | '\\') | '\\' ('\\' | '\''))* '\''
        ;
    
    Comment
        :  '//' ~('\r' | '\n')* {skip();}
        |  '/*' .* '*/'         {skip();}
        ;
    
    Space
        :  (' ' | '\t' | '\r' | '\n' | '\u000C') {skip();}
        ;
    
    fragment Int
        :  '1'..'9' Digit*
        |  '0'
        ;
    
    fragment Digit 
        :  '0'..'9'
        ;
    
    indexes
        :  ('[' expr ']')+ -> ^(INDEXES expr+)
        ;
    

    产生以下 AST:

    此外,词法分析器规则应始终匹配至少 1 个字符(我之前已向您提到过这一点)。您的词法分析器规则 ID 可能匹配 0 个字符。

    【讨论】:

    • 就是这样!非常感谢(再一次)!
    【解决方案2】:

    问题是equalop+只有第一个匹配的值。 我看到了不同的解决方法:创建特定规则,如果它只是为了不在或不在,创建一个子规则,或者像我在这里做的那样连接一个变量:

    equality_expr
        :   ID (full_op+=equality_op) + atom    -> ^(full_op ID atom)
        |   '(' expr ')'    ->  ^('(' expr)
        ;
    

    以下问题有所不同,但给出了我的想法: Antlr AST generating (possible) madness

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-16
      • 1970-01-01
      • 2012-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多