blob: 10322c13348dfeb71e722c31b7b6cd56ff2c59bc [file] [log] [blame]
options{
STATIC=false;
}
PARSER_BEGIN(QuickSQLParser)
package org.eclipse.datatools.enablement.sybase.parser;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.HashMap;
import java.io.StringReader;
import org.eclipse.datatools.enablement.sybase.Activator;
public class QuickSQLParser extends AbstractQuickSQLParser
{
private static QuickSQLParser _instance = new QuickSQLParser(new StringReader(""));
private boolean _debug = false;
private String _input = "";
private boolean canUseDelimiter = false;
private static final int[] STMT_START = new int[]{ALTER, BEGIN, BREAK, CHECKPOINT, CLOSE, COMMIT, CONNECT,
CONTINUE, CREATE, DEALLOCATE, DECLARE, DELETE, DISK, DROP, DUMP, EXECUTE, EXEC,
FETCH, GOTO, GRANT, IF, INSERT, KILL, LOAD, LOCK, ONLINE, OPEN, PREPARE, //MOUNT,
PRINT, QUIESCE, RAISERROR, READTEXT, RECONFIGURE, REMOVE, REORG, RETURN, REVOKE,
ROLLBACK, SAVE, SELECT, SET, SETUSER, SHUTDOWN, TRUNCATE, UPDATE, USE,//UNMOUNT,
WAITFOR, WHILE, WRITETEXT
};
public static final String[] STMT_START_STRING = new String[]{"ALTER","BEGIN","BREAK","CHECKPOINT","CLOSE","COMMIT","CONNECT",
"CONTINUE","CREATE","DEALLOCATE","DECLARE","DELETE","DISK","DROP","DUMP","EXECUTE","EXEC",
"FETCH","GOTO","GRANT","IF","INSERT","KILL","LOAD","LOCK","ONLINE","OPEN","PREPARE",
"PRINT","QUIESCE","RAISERROR","READTEXT","RECONFIGURE","REMOVE","REORG","RETURN","REVOKE",
"ROLLBACK","SAVE","SELECT","SET","SETUSER","SHUTDOWN","TRUNCATE","UPDATE","USE",
"WAITFOR","WHILE","WRITETEXT"
};
private static final int[] DEFINED_STMT_START = new int[]{ALTER, BEGIN, CREATE, DECLARE, DELETE, EXECUTE, EXEC, FETCH, IF, INSERT, PRINT, RETURN, SELECT, UPDATE, USE };
private static final int[] TERMINATORS = new int[]{GO, SEMICOLON};
private static final String[] TERMINATORS_STRING = new String[]{"GO", ";"};
private static final String[] WATCOM_POST_PARAM= new String[]
{"BEGIN","RETURNS", "RESULT","AT","WITH", "AS","EXTERNAL","ON","DYNAMIC"};
/**
* Returns the statement terminator array. Different vendors will have their
* own terminators defined, so we just leave this method as abstract here.
*
* @return statement terminator array
*/
public String[] getStatementTerminators()
{
return TERMINATORS_STRING;
}
public static QuickSQLParser getInstance(){
return _instance;
}
public QuickSQLParser()
{
this(new StringReader(""));
}
final private void logDebug(String message)
{
if (_debug)
{
Activator.getDefault().debug(message);
}
}
final private void logError(String message)
{
Activator.getDefault().log(message);
}
protected synchronized void initParser(String text)
{
_input = text;
java.io.StringReader sr = new java.io.StringReader( text );
java.io.Reader r = new java.io.BufferedReader( sr );
//ReInit will be generated by JavaCC
ReInit(r);
}
public String getInput()
{
return _input;
}
public boolean match(String input, int pattern)
{
try{
initParser(input);
switch (pattern)
{
case CREATE_PROC_HEADER_PATTERN:
create_proc_header();
return true;
case CREATE_FUNC_HEADER_PATTERN:
create_func_header();
return true;
case CREATE_TRIGGER_HEADER_PATTERN:
create_trigger_header();
return true;
case CREATE_EVENT_HEADER_PATTERN:
create_event_header();
return true;
default:
}
}catch(Throwable e)
{
logDebug(e.getMessage());
return false;
}
return false;
}
public int[] find(String input, String[][] tokens)
{
Token[] ts = getTokens(input, tokens);
if (ts == null)
{
return new int[]{-1, -1};
}
//calculate index
int[] index = new int[2];
index[0] = getStartIndex(ts[0]);
index[1] = getEndIndex(ts[1]);
return index;
}
public Token[] getTokens(String input, String[][] tokens)
{
initParser(input);
boolean found = true;
try{
getNextToken();
do
{
error_skiptobefore1(tokens[0], new String[]{}, false);
int i = 0;
for (; i< tokens.length; i++)
{
boolean tokenMatch = false;
for (int j=0; j< tokens[i].length; j++)
{
if (tokens[i][j].equalsIgnoreCase(getToken(i).image))
{
tokenMatch = true;
break;
}
}
if (! tokenMatch)
{
found = false;
getNextToken();
break;
}
else
{
found = true;
continue;
}
}
if (token.kind == EOF)
{
found = false;
break;
}
}while(!found);
}catch(Throwable e)
{
logDebug(e.getMessage());
return null;
}
if (! found)
{
return null;
}
//calculate index
Token[] ts = new Token[2];
ts[0] = getToken(0);
ts[1] = getToken(tokens.length - 1);
return ts;
}
public String[][] getParameters(String input)
{
initParser(input);
try
{
return routine_parameters();
}catch(Throwable e)
{
logDebug(e.getMessage());
return null;
}
}
public String[] getDatatypeInfo(String input)
{
initParser(input);
try
{
return datatype_info();
}catch(Throwable e)
{
logDebug(e.getMessage());
return null;
}
}
}
PARSER_END(QuickSQLParser)
/***********************************************************************
* Token definitions
***********************************************************************/
SKIP:
{
" "
| "\n"
| "\r"
| "\t"
}
/* COMMENTS */
MORE :
{
"--" : IN_SINGLE_LINE_COMMENT
}
<IN_SINGLE_LINE_COMMENT>
SPECIAL_TOKEN :
{
<SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" > : DEFAULT
}
<IN_SINGLE_LINE_COMMENT>
MORE :
{
< ~[] >
}
/*
SPECIAL_TOKEN :
{
< SINGLE_LINE_COMMENT: "--"(~["\n","\r"])* ("\n"|"\r"|"\r\n")? >
}
*/
TOKEN_MGR_DECLS : {
int commentNestingDepth = 0 ;
}
MORE : { "/*" { commentNestingDepth = 1 ; } : IN_MULTI_LINE_COMMENT }
< IN_MULTI_LINE_COMMENT > MORE : { "/*" { commentNestingDepth += 1 ; } }
< IN_MULTI_LINE_COMMENT > SPECIAL_TOKEN : { "*/" {
commentNestingDepth -= 1;
SwitchTo( commentNestingDepth==0 ? DEFAULT : IN_MULTI_LINE_COMMENT ); } }
< IN_MULTI_LINE_COMMENT > MORE : { <COMMENT_CONTENT: ~[]> {} }
<IGNORE_STATE>
SKIP :
{
< ~[] >
}
TOKEN:
{
< INVALID_TOKEN: "!%^&" > //Using token will always causes exception
| < ADD: "add" >
| < ALTER: "alter" >
| < AND: "and" >
| < ANY: "any" >
| < AS: "as" >
| < ASC: "asc" >
| < AT: "at" >
| < AUTHORIZATION: "authorization" >
| < AVG: "avg" >
| < BEGIN: "begin" >
| < BETWEEN: "between" >
| < BREAK: "break" >
| < BROWSE: "browse" >
| < BULK: "bulk" >
| < BY: "by" >
| < CASCADE: "cascade" >
| < CASE: "case" >
| < CHECK: "check" >
| < CHECKPOINT: "checkpoint" >
| < CLOSE: "close" >
| < CLUSTERED: "clustered" >
| < COALESCE: "coalesce" >
| < COMMIT: "commit" >
| < COMPUTE: "compute" >
| < CONFIRM: "confirm" >
| < CONNECT: "connect" >
| < CONSTRAINT: "constraint" >
| < CONTINUE: "continue" >
| < CONTROLROW: "controlrow" >
| < CONVERT: "convert" >
| < COUNT: "count" >
| < CREATE: "create" >
| < CURRENT: "current" >
| < CURSOR: "cursor" >
| < DATABASE: "database" >
| < DBCC: "dbcc" >
| < DEALLOCATE: "deallocate" >
| < DECLARE: "declare" >
| < DEFAULT_VAL: "default" >
| < DELETE: "delete" >
| < DESC: "desc" >
| < DETERMINISTIC: "deterministic" >
| < DISK: "disk" >
| < DISTINCT: "distinct" >
| < DROP: "drop" >
| < DUMMY: "dummy" >
| < DUMP: "dump" >
| < ELSE: "else" >
| < END: "end" >
| < ENDTRAN: "endtran" >
| < ESCAPE: "escape" >
| < EXCEPT: "except" >
| < EXCLUSIVE: "exclusive" >
| < EXEC: "exec" >
| < EXECUTE: "execute" >
| < EXISTS: "exists" >
| < EXIT: "exit" >
| < EXTERNAL: "external" >
| < EVENT: "event" >
| < FETCH: "fetch" >
| < FILLFACTOR: "fillfactor" >
| < FOR: "for" >
| < FOREIGN: "foreign" >
| < FROM: "from" >
| < FUNC: "func" >
| < FUNCTION: "function" >
| < GO: "go" > //terminator
| < GOTO: "goto" >
| < GRANT: "grant" >
| < GROUP: "group" >
| < HAVING: "having" >
| < HOLDLOCK: "holdlock" >
| < IDENTITY: "identity" >
| < IF: "if" >
| < IN: "in" >
| < INDEX: "index" >
| < INOUT: "inout" >
| < INSERT: "insert" >
| < INSTALL: "install" >
| < INTERSECT: "intersect" >
| < INTO: "into" >
| < IS: "is" >
| < ISOLATION: "isolation" >
| < JAR: "jar" >
| < JOIN: "join" >
| < KEY: "key" >
| < KILL: "kill" >
| < LEVEL: "level" >
| < LIKE: "like" >
| < LOAD: "load" >
| < LOCK: "lock" >
| < MAX: "max" >
| < MIN: "min" >
| < MODIFY: "modify" >
| < NOHOLDLOCK: "noholdlock" >
| < NONCLUSTERED: "nonclustered" >
| < NOT: "not" >
| < NULL: "null" >
| < NULLIF: "nullif" >
| < OF: "of" >
| < OFF: "off" >
| < OFFSETS: "offsets" >
| < ON: "on" >
| < ONCE: "once" >
| < ONLINE: "online" >
| < ONLY: "only" >
| < OPEN: "open" >
| < OPTION: "option" >
| < OR: "or" >
| < ORDER: "order" >
| < OUT: "out" >
| < OUTPUT: "output" >
| < OVER: "over" >
| < PARTITION: "partition" >
| < PERM: "perm" >
| < PERMANENT: "permanent" >
| < PLAN: "plan" >
| < PREPARE: "prepare" >
| < PRIMARY: "primary" >
| < PRINT: "print" >
| < PRIVILEGES: "privileges" >
| < PROC: "proc" >
| < PROCEDURE: "procedure" >
| < PROCESSEXIT: "processexit" >
| < PROXY_TABLE: "proxy_table" >
| < PUBLIC: "public" >
| < QUIESCE: "quiesce" >
| < RAISERROR: "raiserror" >
| < READ: "read" >
| < READPAST: "readpast" >
| < READTEXT: "readtext" >
| < RECONFIGURE: "reconfigure" >
| < REFERENCES: "references" >
| < REMOVE: "remove" >
| < REORG: "reorg" >
| < REPLACE: "replace" >
| < REPLICATION: "replication" >
| < RETURN: "return" >
| < RETURNS: "returns" >
| < REVOKE: "revoke" >
| < ROLE: "role" >
| < ROLLBACK: "rollback" >
| < ROWCOUNT: "rowcount" >
| < ROWS: "rows" >
| < RULE: "rule" >
| < SAVE: "save" >
| < SCHEMA: "schema" >
| < SELECT: "select" >
| < SET: "set" >
| < SETUSER: "setuser" >
| < SHARED: "shared" >
| < SHUTDOWN: "shutdown" >
| < SOME: "some" >
| < STATISTICS: "statistics" >
| < STRINGSIZE: "stringsize" >
| < STRIPE: "stripe" >
| < SUM: "sum" >
| < TABLE: "table" >
| < TEMP: "temp" >
| < TEMPORARY: "temporary" >
| < TEXTSIZE: "textsize" >
| < TO: "to" >
| < TRAN: "tran" >
| < TRANSACTION: "transaction" >
| < TRIGGER: "trigger" >
| < TRUNCATE: "truncate" >
| < UNION: "union" >
| < UNIQUE: "unique" >
| < UNPARTITION: "unpartition" >
| < UPDATE: "update" >
| < USE: "use" >
| < USER: "user" >
| < USING: "using" >
| < VALUES: "values" >
| < VIEW: "view" >
| < WAITFOR: "waitfor" >
| < WHEN: "when" >
| < WHERE: "where" >
| < WHILE: "while" >
| < WITH: "with" >
| < WORK: "work" >
| < WRITETEXT: "writetext" >
//ASA
| < SQLCODE: "SQLCODE">
| < SQLSTATE: "SQLSTATE">
}
<DESCRIPTION_START_STATE> TOKEN:
{
< OPENDESCRIPTION: "\r\n" > : DESCRIPTION_STATE
}
<DESCRIPTION_STATE> TOKEN: /* Line */
{
< CLOSEDESCRIPTION: "~" > : DEFAULT
| < DESCRIPTION: (~["~"])* "~" > : DEFAULT
}
TOKEN: /* Literals */
{
< INTEGER_LITERAL: (["0"-"9"])+ >
| < FLOATING_POINT_LITERAL:
(["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)?
| "." (["0"-"9"])+ (<EXPONENT>)?
| (["0"-"9"])+ (<EXPONENT>)?
>
| < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
| < SINGLE_STRING_LITERAL: "'" (~["'"])* ( "''" (~["'"])* )* "'" >
| < DOUBLE_STRING_LITERAL: "\"" (~["\""])* ( "\"\"" (~["\""])* )* "\"" >
| < BINARY_LITERAL: "0" ("x" | "X" ) ( <HEXDIGIT> )+ >
| < #HEXDIGIT: ["A"-"F", "a"-"f", "0"-"9"] >
| < MONEY_LITERAL: ("$" | "\u00a5" | "\u00a3" )? <FLOATING_POINT_LITERAL> >
}
Token string_literal() : {Token t;}
{
( t = <SINGLE_STRING_LITERAL> | t = <DOUBLE_STRING_LITERAL> )
{return t;}
}
TOKEN: /* Identifiers */
{
< ID: ( <LETTER> | "_" )+ ( <SYMBOL> | <DIGIT> | <LETTER> | "#" | "@" )* >
| < SQUARE_BRACKET_ID: ("[" <ID> "]")>
| < #VAR_NAME_BODY: ( <SYMBOL> | <DIGIT> | <LETTER> | "#" )+ ( <SYMBOL> | <DIGIT> | <LETTER> | "#" | "@" )* >
| < VAR_NAME: "@"<VAR_NAME_BODY> >
| < LABEL: <ID>":" >
| < GLOBAL_VAR_NAME: "@@"<VAR_NAME_BODY> >
| < TEMP_TABLE_NAME: "#" ( <SYMBOL> | <DIGIT> | <LETTER> | "#" | "@" )+ >
/*FIXME: Unicode code point ranges from 0000 to 10ffff, but JavaCC seems only recognize four digits following "u". Not sure what the consequence will be for now.*/
| < #LETTER: ["A"-"Z", "a"-"z", "\u0080"-"\uffff"] >
| < #DIGIT: ["0"-"9"] >
| < #SYMBOL: ["$" , "\u00a5" , "\u00a3" , "_" ] >
}
TOKEN: /* Separators and operators */
{
< CONCAT: "||" >
| < COMMA: "," >
| < SEMICOLON: ";" >
| < DOT: "." >
| < ROWTYPE: "%rowtype" >
| < TILDE: "~" >
| < LESS: "<" >
| < LESSEQUAL: "<=" >
| < GREATER: ">" >
| < GREATEREQUAL: ">=" >
| < EQUAL: "=" >
| < NOTEQUAL: "!=" >
| < JOINPLUS: "(+)" >
| < OPENPAREN: "(" >
| < CLOSEPAREN: ")" >
| < ASTERISK: "*" >
| < SLASH: "/" >
| < PLUS: "+" >
| < MINUS: "-" >
| < QUESTIONMARK: "?" >
| < LEQJOIN: "*="> //FIXME:
| < REQJOIN: "=*">
| < JAVA_REF: ">>">
}
/*******************************************************************
* The SQL grammar starts here
*******************************************************************/
/***** ROOT SYNTAXS *****/
void any_stmt_token():{}
{
{
error_skiptobefore(new int[]{END, SEMICOLON, GO}, STMT_START);
}
}
Token id() : {Token t = null;}
{
(t = idplus()
| t = variable()
)
{return t;}
}
void string() : {}
{
string_literal()
| variable()
}
Token id_string() : {Token t = null;}
{
( t = idplus()
| t = <DOUBLE_STRING_LITERAL>
| t = variable()
)
{return t;}
}
Token id_or_string() : {Token t;}
{
(LOOKAHEAD(1) t = idplus()
| t = string_literal()
)
{return t;}
}
String prefix() : {Token t = null;}
{
( "."
| (t = id_or_string() ) "."
)
{return t == null?".":t.image + ".";}
}
String prefix_list() : {String retval = "", pre = ""; }
{
( LOOKAHEAD([id_or_string() ] ".") pre = prefix() {retval += pre;} )+
{return retval;}
}
//database object such as: table, procedure, view, cursor...
String object() : {String retval = ""; Token t;}
{
([ LOOKAHEAD([id_or_string()] ".") retval = prefix_list() ] t = id_or_string())
{return retval + t.image;}
}
//Special case: "NEW" can be used as id
Token idplus() : {Token t;}
{
( t = <ID>
| t = <TEMP_TABLE_NAME> //TEMP_TABLE_NAME can also be used as column name
| t = <SQUARE_BRACKET_ID>
)
{return t;}
}
//variable reference
Token variable() : {Token t;}
{
( t = <VAR_NAME>
| t = dyn_question_mark()
| t = <GLOBAL_VAR_NAME>
)
{return t;}
}
Token dyn_question_mark() : {Token t;}
{
t = <QUESTIONMARK>
{return t;}
}
int number() : {int retval = 0;}
{
( "-" <INTEGER_LITERAL> {try {retval = Integer.parseInt("-" + getToken(0).image);}catch(Exception e){}}
| [ "+" ] <INTEGER_LITERAL> {try {retval = Integer.parseInt(getToken(0).image);}catch(Exception e){}}
)
{return retval;}
}
void constant() : {}
{
signed_const()
| unsigned_const()
}
Token signed_const() : {Token t;}
{
( t = <INTEGER_LITERAL>
| t = <FLOATING_POINT_LITERAL>
| t = <MONEY_LITERAL>
)
{return t;}
}
Token unsigned_const() : {Token t;}
{
( t = <BINARY_LITERAL>
| t = string_literal()
| t = null_stmt()
| t = variable()
)
{return t;}
}
String literal() : {Token t; boolean negative = false;}
{
( [ "+" | "-" { negative = true;} ] t = signed_const()
| t = unsigned_const()
| t = idplus()
| t = <PRIMARY>
| t = <FOREIGN>
)
{return negative?"-"+t.image:t.image;}
}
Token null_stmt() : {Token t;}
{
t = <NULL>
{return t;}
}
String length_spec() : {String retval = ""; int n = 0;}
{
[ LOOKAHEAD(2) "(" n = number() {retval = "(" + n;} [ "," n = number() {retval += "," + n;} ] ")" {retval += ")";} ]
{return retval;}
}
String datatype():{String retval = ""; Token t; String l="";}
{
((t = <ID> {if (retval.equals("")) retval += t.image; else retval += " " + t.image;})+ | t = <SQUARE_BRACKET_ID> {retval += t.image;} | t = <DOUBLE_STRING_LITERAL> {retval += t.image;}) l = length_spec() {retval += l;}
{return retval;}
}
String[] datatype_info():{String name = null; Token t; String precision= null; String scale = null; int n = 0;}
{
((t = <ID> {if (name == null) name = t.image; else name += " " + t.image;})+ | t = <SQUARE_BRACKET_ID> {name = t.image;} | t = <DOUBLE_STRING_LITERAL> { name = t.image;})
[ LOOKAHEAD(2) "(" n = number() {precision = "" + n;} [ "," n = number() {scale = "" + n;} ] ")" ]
{
if (scale != null)
{
return new String[]{name, precision, scale};
}
else if (precision != null)
{
return new String[]{name, precision};
}
else
{
return new String[]{name};
}
}
}
/**
* @return name: defaultValue
*/
String[] parameter(): {Token name=null; String defaultValue=null; String type=null; int direction = 0;}
{
try{
//As long as the param name starts with @, we regard it as a tsql parameter
LOOKAHEAD(1) ( name = <VAR_NAME>
type = datatype()
[ "=" defaultValue = procparmdefault()]
direction = param_options()
)|(
({direction = 0;} [<IN> | {direction = 1;} <OUT> | {direction = 2;} <INOUT> ] )
name = id_string()
type = datatype()
[<DEFAULT_VAL> defaultValue = procparmdefault()]
)
| (name = <SQLSTATE> )
|( name = <SQLCODE> )
}catch(ParseException e){
error_skiptobefore(new int[]{}, new int[]{COMMA, CLOSEPAREN, WITH, AS, BEGIN});
}
{
String[] param = new String[2];
param[0] = name.toString();
param[1] = defaultValue;
return param;
}
}
String optional_param_default() : {String t = null;}
{
[ "=" t = literal()]
{return t;}
}
int param_options() : {int direction = 0;}
{
[ <IN>
| out_option() {direction = 1;}]
{return direction;}
}
void out_option() : {}
{
<OUT>
| <OUTPUT>
}
void any_chars():{}
{
{token_source.SwitchTo(IGNORE_STATE);}
}
void create_proc_header():{}
{
<CREATE> (<PROC> | <PROCEDURE> ) any_chars()
}
void create_func_header():{}
{
<CREATE> (<FUNC> | <FUNCTION> ) any_chars()
}
void create_trigger_header():{}
{
<CREATE> <TRIGGER> any_chars()
}
void create_event_header():{}
{
<CREATE> <EVENT> any_chars()
}
String[][] parameters():{ArrayList params = new ArrayList(); String[] param = new String[2];}
{
[ ["("] param = parameter() {params.add(param);} ( <COMMA> param = parameter() {params.add(param);} )* [")"]]
{return (String[][])params.toArray(new String[params.size()][2]);}
}
String[][] routine_parameters():{String[][] params = null;}
{
( <CREATE> | <ALTER> ) (<PROC> | <PROCEDURE> | <FUNC> | <FUNCTION> ) object() params = parameters() any_chars()
{return params;}
}
//might contain expressions
String procparmdefault() : {}
{
{
Token start = getToken(1);//next token
int startIndex = getStartIndex(start);
boolean match = false;
do{
int balance = 0;//open parenthesis minus close parenthesis
error_skiptobefore(new int[]{OPENPAREN}, new int[]{COMMA, CLOSEPAREN, OUTPUT, OUT, IN, WITH, AS});
if (getToken(0).kind == OPENPAREN )
{
balance ++;
}
if (getToken(1).kind == CLOSEPAREN )
{
balance --;
}
Token end = getToken(1);
Token next = getToken(2);
if (end == null || next == null)
{
match = true;
break;
}
else if (end.kind == EOF || end.kind == COMMA)
{
match = true;
break;
}
else if (end.kind == COMMA && balance == 0)
{
match = true;
break;
}
else if (end.kind == WITH && balance == 0)
{
match = true;
break;
}
else if (end.kind == AS && balance == 0)//TSQL
{
match = true;
break;
}
else if (end.kind == OUTPUT || end.kind == OUT || end.kind == IN )//TSQL: IN/OUT follows the default value
{
match = true;
break;
}
else if (end.kind == CLOSEPAREN && balance < 0)
{
for (int i=0;i<WATCOM_POST_PARAM.length; i++)
{
if (WATCOM_POST_PARAM[i].equalsIgnoreCase(next.image))
{
match = true;
break;
}
}
}
}while (!match);
int endIndex = getEndIndex(getToken(0));
if (endIndex > startIndex)
{
return _input.substring(startIndex, endIndex);
}
else
{
return null;
}
}
}
JAVACODE
void error_skiptobefore(int[] tokinds, int[] beforekinds) {
boolean match = false;
Token t1 = getToken(0);
// The following loop consumes tokens all the way up to a token of
// "kind". We use a do-while loop rather than a while because the
// current token is the one immediately before the erroneous token
// (in our case the token immediately before what should have been
// "if"/"while".
do {
match = token.kind == 0 || getToken(1).kind == 0 ; // 0 means the <EOF>
if (match) {break;}
for (int i=0; i< tokinds.length; i++){
match = match || token.kind == tokinds[i];
if (match) {break;}
}
if (match) {break;}
for (int i=0; i< beforekinds.length; i++){
match = match || getToken(1).kind == beforekinds[i];
if (match) {break;}
}
if (!match){
logDebug("current token:" + token.image);
getNextToken();
}
} while (!match);
Token t2 = getToken(0);
if (t1 == t2 ){
//force get next token
logDebug("current token:" + token.image);
//System.out.println("current token:" + token.image);
getNextToken();
}
}
//overloaded with String[] parameters
JAVACODE
void error_skiptobefore1(String[] tokinds, String[] beforekinds, boolean force) {
boolean match = false;
Token t1 = getToken(0);
// The following loop consumes tokens all the way up to a token of
// "kind". We use a do-while loop rather than a while because the
// current token is the one immediately before the erroneous token
// (in our case the token immediately before what should have been
// "if"/"while".
do {
match = token.kind == 0 || getToken(1).kind == 0 ; // 0 means the <EOF>
if (match) {break;}
for (int i=0; i< tokinds.length; i++){
match = match || tokinds[i].equalsIgnoreCase(token.image);
if (match) {break;}
}
if (match) {break;}
for (int i=0; i< beforekinds.length; i++){
match = match || beforekinds[i].equalsIgnoreCase(getToken(1).image);
if (match) {break;}
}
if (!match){
logDebug("current token:" + token.image);
getNextToken();
}
} while (!match);
Token t2 = getToken(0);
if (t1 == t2 && force ){
//force get next token
logDebug("current token:" + token.image);
//System.out.println("current token:" + token.image);
getNextToken();
}
}
/*TODO:
<ID> need to be refined
Multi-word tokens should be defined seperatedly
Highlight udt? Need to change types definition in ISQLSyntax referenced by SourceViewerConfiguration
setScope must be placed early enough because Lookahead > 1 will prevent it from executing,
We can only set scope to the last element. e.g. in case of db.owner.table, we'll set scope to table
error_skiptobefore has potential possibility of deadloop
Higher lookahead should proceed lower lookahead
When scope is current_table, we need to store current table name in some place.
can't show popup when user has input part of the <ID>, need to
*/