【问题标题】:Antlr identifier with AND does not match与 AND 不匹配的 Antlr 标识符
【发布时间】:2013-02-06 22:05:24
【问题描述】:

使用 Antlr 3.5 规则:

ID
 : ':'? ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '0'..'9' | '_')*
 ;

不匹配:标准

谁能解释一下原因?

以下是完整的语法。您可以使用规则 colname 来测试“标准”。

grammar Sql;

options {
  language = Java;
  output = AST;
}

@rulecatch {catch (RecognitionException e) { throw e;}}

@header {
  package com.something.antlr.sql;
  import java.util.ArrayList;
}

@lexer::header {
  package com.something.antlr.sql;
}

@members {
 private List<Table> tables = new ArrayList<Table>();
 private List<Column> columns = new ArrayList<Column>();

 private StringBuilder joinClauses = new StringBuilder();

 private String withClauseAsString;
 private String tablesAsString;
 private String columnsAsString;
 private String aggregate;
 private String whereClauseAsString;
 private String orderByAsString;
 private String groupByAsString;
 private String limitAsString;

 public List<Table> getTables() {
  return tables;
 }

 public String getColumnsAsString() {
    return columnsAsString;
 }

 public List<Column> getColumns() {
    return columns;
 }

 public String getTablesAsString() {
    return tablesAsString;
 }

 public String getJoinClauseAsString() {
    return joinClauses.toString();
 }

 public String getWhereClauseAsString() {
    return whereClauseAsString;
 }

 public String getOrderByAsString() {
    return orderByAsString;
 }

 public String getAggregate() {
    return aggregate;
 }

 public String getGroupByAsString() {
    return groupByAsString;
 }

 public String getWithClauseAsString() {
    return withClauseAsString;
 }

 public String getLimitAsString() {
    return limitAsString;
 }


}


sql_statement
  : sql EOF;
   catch [RecognitionException e]{ throw e;}

sql
:
  (WITH with_clause)?
    {withClauseAsString = $with_clause.text;}
  SELECT DISTINCT? (TOP LPAREN? t=number_or_param RPAREN?)? columns?
      {
        StringBuilder sb = new StringBuilder();

        if ($DISTINCT.text != null) {
          sb.append(" distinct ");
        }

        if ($TOP.text != null) {
          sb.append(" top ");
        }

        if ($t.text != null) {
          sb.append(" ");
          if ($LPAREN.text != null) {
            sb.append("(");
          }
          sb.append($t.text);
          if ($RPAREN.text != null) {
            sb.append(")");
          }
          sb.append(" ");
        }

        sb.append($columns.text);
        columnsAsString = sb.toString();
      }
      (
      FROM tables*
           {tablesAsString = $tables.text;}

    (join_type? JOIN join_clause)*
     {
       String joinClauseAsString = "";

       if ($join_type.text != null) {
         joinClauseAsString = $join_type.text + " ";
       }

       if ($join_clause.text != null) {
        joinClauseAsString += $join_clause.text;
       }

       if (joinClauseAsString.length() > 0) {
          joinClauses.append("\n ");
          joinClauses.append(joinClauseAsString);
       }

     }

    (WHERE where_clause)?
          {whereClauseAsString = $where_clause.text;}

    (ORDER_BY order_by_clause)?
          {orderByAsString = $order_by_clause.text;}

    (GROUP_BY group_by_clause)?
          {groupByAsString = $group_by_clause.text;}
    (LIMIT t2=number_or_param)?
          {
            if ($t2.text != null) {
              limitAsString = " limit " + $t2.text;
            }
          }

    (UNION ALL? alt_sql)?
    )?
  ;


with_ident
:
  ID
;

with_clause
:
  with_ident (LPAREN columns RPAREN)? AS alt_sql
;


alt_sql
:
  LPAREN?
  (
  SELECT DISTINCT? (TOP number_or_param)? columns?
    FROM tables*
    (join_type? JOIN join_clause)*
    (WHERE where_clause)?
    (ORDER_BY order_by_clause)?
    (GROUP_BY group_by_clause)?
    (LIMIT NUMBER)?
    (UNION ALL? alt_sql)?
  )
  RPAREN?
;

exists_select
:
  SELECT NUMBER FROM tables (WHERE where_clause)?
;

in_select
:
  SELECT colname FROM tables (WHERE where_clause)?
;

colname_or_operand
:
 colname | LPAREN ID RPAREN | RANGE | CONSTANT |  TICK '*' TICK | alt_sql
;

case_test
:
  (ID '.')? function (CALC function)* operator (ID | NUMBER)
;

colname
:
  //CASE WHEN case_test ( (AND | OR) case_test)* THEN (NUMBER | ID) ELSE (NUMBER | ID) END alias
  CASE (WHEN where_logical THEN (ID | NUMBER | LITERAL))+ ELSE (ID | NUMBER | LITERAL) END alias
  |
  col = ID alias?
    {
    Column c = new Column($col.text, "");
    columns.add(c);
    }
  |
  tbl=ID '.' col=ID ('::' ID)? alias?
    {
    Column c = new Column($tbl.text + "." + $col.text, $alias.text);
    columns.add(c);
    }
  |
  (ID '.')? '*'
  |
  (ID '.')? func_name = function alias?
    {
    Column c = new Column($func_name.text, $alias.text);
    columns.add(c);
    }
  |
  col = (ID '::' ID)
    {
    Column c = new Column($col.text, "");
    columns.add(c);
    }
  |
  ('?' | NUMBER | LITERAL) (('::' | AS) ID)?
    {
    Column c = new Column("?", "");
    columns.add(c);
  }
;

columns
:
  (colname (CONCAT colname)* | alt_sql alias?) (',' (colname (CONCAT colname)* | alt_sql alias?))*
;

tablename
:
  ID alias?
    {
    Table tbl = new Table($ID.text, $alias.text);
    tables.add(tbl);
    }
  |
  (ID '.')? function alias?
  |
  t = TABLE LPAREN func = ID LPAREN arguments RPAREN RPAREN alias?
    {
    Table tbl = new Table($t.text + "(" + $func.text + "(" + $arguments.text + ")" + ")", $alias.text);
    tables.add(tbl);
    }
;

arguments
:
  argument (',' argument)*
;

argument
:
  colname
;

tables
  : tablename (',' tablename)*;


join_sql
:
  LPAREN
  SELECT DISTINCT? columns
  FROM tables*
  (WHERE where_clause) RPAREN alias
  ON where_expression
;


join_type
:
  ('left' 'outer'? | 'LEFT' 'OUTER'? | 'Left' 'Outer'?) | ('right' 'outer'? | 'RIGHT' 'OUTER'?  | 'Right' 'Outer'?)
;

join_clause
  :  (alt_sql alias | tablename alias? | colname) ON where_clause
  ;

alias
:
  AS? ID
;


exists_clause
:
  EXISTS LPAREN exists_select RPAREN
;

in_clause
:
  LPAREN (LPAREN in_select RPAREN alias? | in_values) (',' (LPAREN in_select RPAREN alias? | in_values))* RPAREN
;

in_values
:
  (NUMBER | LITERAL) (',' (NUMBER | LITERAL))*
;

where_expression
:
  LPAREN* ((colname operator (colname_or_operand | in_clause)) | exists_clause?) RPAREN*
;

where_logical
:
  LPAREN* where_expression ((AND | OR) where_expression)* RPAREN*
;

where_clause
:
  where_logical ((AND | OR) where_logical)*
;

number_or_param
:
  NUMBER | '?'
;

order_by
:
  (ID | NUMBER) (ASC | DESC)?
;

order_by_clause
  : order_by (',' order_by)*;

group_by_clause
:
  ID ('.' ID)? (',' ID ('.' ID)?)*
;

BETWEEN
:
 'between' | 'BETWEEN' | 'Between'
;


operator
  : '=' | '<' | '>' | '<=' | '>=' | '<>' | 'is' | 'Is' | 'IS' | BETWEEN |  IN |  'like' | '&lt;=' | '&gt;=' | '&lt;&gt;';

CALC
:
  '+' | '-' | '/'
;

function
:
  ID LPAREN DISTINCT? arguments? RPAREN ('::' ID)?
;

CONSTANT
:
  TICK ID TICK
;

LITERAL
:
  TICK .* TICK
;

TABLE : ('t' | 'T') ('a' | 'A') ('b' | 'B') ('l' | 'L') ('e' | 'E');
WITH : 'with' | 'WITH' | 'With';
SELECT : 'select' | 'SELECT' | 'Select';
DISTINCT : ('d' | 'D') ('i' | 'I') ('s' | 'S') ('t' | 'T') ('i' | 'I') ('n' | 'N') ('c' | 'C') ('t' | 'T');
TOP : 'top' | 'TOP' | 'Top';
CASE : ('case' | 'Case' | 'CASE');
WHEN: ('when' | 'When' | 'WHEN');
THEN : 'then' | 'Then' | 'THEN';
ELSE : 'else' | 'Else' | 'ELSE';
END : 'end' | 'END' | 'End';
FROM : 'from' | 'FROM' | 'From';
EXISTS : 'exists' | 'EXISTS' | 'Exists';
WHERE : 'where' | 'WHERE'| 'Where';
JOIN : ('left' | 'LEFT' | 'Left' | 'right' | 'RIGHT' | 'Right')? 'join' | 'Join' | 'JOIN';
ON : 'on' | 'ON' | 'On';
AND : ('a' | 'A') ('n' | 'N') ('d' | 'D');
AS : ('a' | 'A') ('s' | 'S');
OR : ('o' | 'O') ('r' | 'R');
IN : 'in' | 'IN' | 'In';
ORDER_BY : ('o' | 'O') ('r' | 'R') ('d' | 'D') ('e' | 'E') ('r' | 'R') ' ' ('b' | 'B') ('y' | 'Y');
ASC : ('a' | 'A') ('s' | 'S') ('c' | 'C');
DESC : ('d' | 'D') ('e' | 'E') ('s' | 'S') ('c' | 'C');
GROUP_BY : 'group by';
UNION : ('u' | 'U') ('n' | 'N') ('i' | 'I') ('o' | 'O') ('n' | 'N');
ALL :  ('a' | 'A') ('l' | 'L') ('l' | 'L');
LIMIT : 'limit' | 'LIMIT' | 'Limit';
CONCAT : '||';
TICK: '\u0027';

LPAREN
: '('
;

RPAREN
: ')'
;

RANGE
:
  (ID | '?') AND (ID | '?')
;

NUMBER
  : ('0'..'9')+;

ID
 : ':'?('a'..'z' | 'A'..'Z' | '_')('a'..'z' | 'A'..'Z' | '0'..'9' | '_')*;

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

【问题讨论】:

  • 确实匹配它,但你语法中的其他一些规则也可能匹配它。
  • 这里的问题是规则:like_id : ID ;当我在 ANTLRWorks 1.5 Interpreter 中单独使用此规则运行它时,它与“标准”不匹配。在这种情况下如何匹配另一个规则?
  • 抱歉,我无法评论我看不到的内容。你能添加你的语法吗?如果您不愿意发布整个内容,请务必发布足够多的内容,以便我或其他人能够真正复制它。
  • 巴特,感谢您的帮助!但是,我刚刚意识到 ANTLRWorks Interpreter 不能单独运行,即它不能在不考虑整个语法的情况下检查单个规则。
  • 解释器不能,但调试器可以解析您指定的任何规则(无论是解析器规则还是词法分析器规则)。但是,如果您在调试器中尝试like_id : ID ; 并失败,则意味着在ID 可以匹配之前,还有另一个词法分析器规则匹配"standard"。这是因为词法分析器独立于解析器运行。解析器尝试匹配ID 并不重要,词法分析器将按照自己的方式创建标记。见:stackoverflow.com/questions/9251048/…

标签: antlr antlr3


【解决方案1】:

词法分析器与"standard" 存在问题,因为您还定义了RANGE 规则:

RANGE
 : (ID | '?') AND (ID | '?')
 ;

可以将"standard" 标记为:

  • ID ("st")
  • AND ("and")
  • ID ("ard")

请注意,这样的规则不应该是词法分析器规则,因为它不要求在这些标记之间有任何空格。这是一个解析器规则:

range
 : (ID | '?') AND (ID | '?')
 ;

进行该更改后,我确信"standard" 将被标记为ID 标记。

【讨论】:

  • 这很好用,谢谢!我希望 Antlr 提供一条可以详细描述它的消息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-01
相关资源
最近更新 更多