1

私はSQLパーサーに取り組んでおり、プログラマーがmysqlのようなクエリを作成できるようにしています。これは、必要に応じて、mssqlまたはmysqlクエリに自動的に変換されます。これにより、mysqlデータベースとmssqlデータベース間の柔軟な移行が可能になります。

私は現在、1つの問題があることを除いて、作成しようとしているものを持っています。

このようなクエリを実行すると、次のようになります。

SELECT * FROM `x`.`y` WHERE `y`.`b` = 'hello'

文字列は識別子lloとして表示されます

これは私の文法です

grammar Query;

query
    : (select_stmt|update_stmt|delete_stmt|insert_stmt|upsert_stmt) ';'? EOF
    ;

select_stmt
    : select 'FROM' select_table_exp where? groupby? orderby? limit?
    ;

update_stmt
    : 'UPDATE' table_exp set where?
    ;

delete_stmt
    : 'DELETE FROM ' table_exp where    
    ;

insert_stmt
    : 'INSERT INTO' table_exp fields values
    ;

upsert_stmt
    : 'UPSERT' table_exp set ?  
    ;

values
    : 'VALUES (' valuelist ')'
    ;

valuelist
    : value (',' valuelist)?where
    ;

fields
    : '(' groupbylist ')'
    ;

set
    : 'SET' (setlist)
    ;

setlist
    : setters (',' setlist)?
    ;

select
    : 'SELECT' fieldlist
    ;

where
    : 'WHERE' where_stmt 
    ;

limit
    : 'LIMIT' (INT|param) (',' (INT|param))?
    ;

groupby
    : 'GROUP BY' groupbylist    
    ;

orderby
    : 'ORDER BY' orderbylist
    ;

select_table_exp
    : table_exp (join_stmt)?    
    | '(' select_stmt ')' as
    ;

table_exp
    : identifier as?
    ;

fieldlist
    : 
      (
          function as
        | (identifier as?)
        | identifier_prefix? '*' // solve the problem of the `ID`.* problem
        | '(' select_stmt ')' as
      ) (',' fieldlist)?
    ;

function
    : 'COUNT(' (identifier|'*') ')' 
    | 'MAX(' identifier ')'
    | 'MIN(' identifier ')'
    | 'AVERAGE(' identifier ')'
    | 'CONCAT(' groupbylist ')'
    | 'CONCAT_WS(' CHAR ',' groupbylist ')' 
    ;

orderbylist
    : identifier ('ASC'|'DESC')? (',' orderbylist)? 
    ;

groupbylist
    : identifier (',' groupbylist)? 
    ;

as
    : 'AS' (ID | '`' ID '`')    
    ;

join_stmt
    : leftjoin (join_stmt)?
    | rightjoin (join_stmt)?
    | join (join_stmt)?
    ;

leftjoin
    : 'LEFT JOIN' (table_exp|('(' select_stmt ')' as)) on_stmt
    ;

rightjoin
    : 'RIGHT JOIN' (table_exp|('(' select_stmt ')' as)) on_stmt
    ;

join
    : 'JOIN' (table_exp|('(' select_stmt ')' as)) on_stmt
    ;

on_stmt
    : 'ON' where_stmt
    ;

where_stmt
    : where_exp ((BOOLEANAND|BOOLEANOR) where_stmt)?
    ;

where_exp
    : where_exp_identifier
    | value (WHEREOPERATORS|EQUALITYOPERATOR) identifier
    | '(' select_stmt ')' (WHEREOPERATORS|EQUALITYOPERATOR) identifier
    ;

where_exp_identifier
    : identifier (WHEREOPERATORS|EQUALITYOPERATOR) where_exp_identifier_operator_right
    | identifier 'BETWEEN' (numeric_value BOOLEANAND numeric_value)
    | identifier 'LIKE' string_value
    ;

where_exp_identifier_operator_right
    : value
    | identifier
    | '(' select_stmt ')'
    ;

setters
    : identifier EQUALITYOPERATOR value
    | value EQUALITYOPERATOR identifier
    | identifier EQUALITYOPERATOR '(' select_stmt ')'
    | '(' select_stmt ')' EQUALITYOPERATOR identifier
    ;

identifier_value
    : value
    | identifier
    ;

value
    : string_value
    | numeric_value
    | param
    ;

string_value
    : STRING
    | CHAR
    ;

numeric_value
    : INT
    | FLOAT
    ;

identifier_prefix
    : ID '.'
    | '`' ID '`.'   
    ;

identifier
    : identifier_prefix? ID 
    | identifier_prefix? '`' ID '`'
    ;

param
    : '@' ID
    ;

BOOLEANAND
    : 'AND'
    ;

BOOLEANOR
    : 'OR'
    ;

EQUALITYOPERATOR
    : '='
    ;

WHEREOPERATORS
    : ('!='|'<>'|'<'|'>'|'<='|'>=')
    ;

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

INT :   '0'..'9'+
    ;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;

COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

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

STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;

CHAR:  '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
    ;

fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;

私はANTLRの専門家からはほど遠いので、文法を3時間いじって、その位置で正しい文字列を文法に受け入れさせようとした後、皆さんに助けを求めることにしました。たぶん、ここのいくつかのantlrの第一人者は私がこれを整理するのを助けることができます。

どうもありがとう

4

1 に答える 1

0

'hello'二重引用符で囲むように文字列を定義したため、入力は文字列としてトークン化されていません。Acharは、文法で一重引用符で囲まれています。

STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;

CHAR:  '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
    ;

それがエラーの原因です。

于 2012-08-11T19:53:25.193 に答える