001package gudusoft.gsqlparser; 002 003 004import gudusoft.gsqlparser.nodes.TDummy; 005import gudusoft.gsqlparser.nodes.TParseTreeNode; 006import gudusoft.gsqlparser.nodes.TParseTreeNodeList; 007import gudusoft.gsqlparser.nodes.TNodeFactory; 008 009 010import java.util.ArrayList; 011import java.util.Map; 012 013 014/** 015 * Base parser of all databases. 016 */ 017public class TCustomParser { 018 019 // Make the map static and initialize it directly 020// static final Map<Integer, int[]> postgresRollbackTokens = new HashMap<Integer, int[]>() {{ 021// // TBaseType.ident must be the last element in each array 022// put(TBaseType.rrw_postgresql_insert_values, new int[]{TBaseType.rrw_values,TBaseType.ident}); 023// }}; 024 025 026 EDbVendor dbvendor; 027 TDatabaseYYSType yylval; 028 TDatabaseYYSType[] yyv; // 1 based array 029 int[] yys; // parser state stack, reused across parse calls for performance 030 TDatabaseYYSType yyval = null; 031 032 // the terminal or non-terminal numbers in the right side of a BNF rule, start from 1. 033 // Take this rule for example: 034 // sqlstmts: stmt ';' 035 // stmt is non-terminal, its number is 1, ';' is terminal, its number is 2. 036 // when sqlstmts rule is reduced, the yysp is 2 which means it points to the ';' token. 037 // and if we need to access the stmt node, we can use yyv[yysp-1] to get it. 038 int yysp; 039 040 boolean isbeginofbatch; //used by mssql 041 TSourceTokenList tmp_sourcetokenlist; 042 int tmp_curtokenpos; 043 044 public TSourceTokenList sourcetokenlist; 045 public TNodeFactory nf; 046 public TParseTreeNode rootNode; 047 final int yymaxdepth = 1048; 048 final int _error = 256; 049 final int yyfnone = 0; 050 final int yyfaccept = 1; 051 final int yyfabort = 2; 052 final int yyferror = 3; 053 final int aopAbort = 0; 054 final int aopContinue = 1; 055 final int tsOriginal = 0; 056 final int tsDeleted = 1; 057 final int tsIgnoreByYacc = 2; 058 final int tsMarkDeletedInPPDoWhiteSpace = 3; 059 final int tsAddedInPP = 4; 060 final int tsDeletedInPP = 5; 061 final int tsAlreadlyAddedToList = 6; 062 final int tsSynataxError = 7; 063 final int tsSynataxErrorProcessed = 8; 064 final int tsAddbyHand = 9; 065 final int tsAddedInTokensInScript = 10; 066 //final int tsNotStartTokenOfSQL, 067 final int tsIgnoredByGetRawStatement = 11; 068 final int tsDummyStatus = 12; 069 070 // Vendor-specific SQL command resolver (injected by TGSqlParser) 071 public gudusoft.gsqlparser.sqlcmds.ISqlCmds sqlcmds; 072 public TCustomLexer lexer; 073 074 TParseTreeNode tmpnode,tmpnode1,tmpnode2,tmpnode3,tmpnode4; 075 076 int yyflag;// yyfnone,yyfaccept,yyfabort ,yyferror 077 int nextstmtstartpos , curtokenpos,stmtendpos; 078 TSourceToken acceptedtoken,currentsourcetoken,recovertoken,errorstmtstarttoken; 079 int currentyystate,currentyysp,currentyyn; 080 int[] retvalue = {0}; // used when need to pass VAR variable to a function, return value by this variable 081 public TCustomSqlStatement sql; 082 083 public TNodeFactory getNf() { 084 return nf; 085 } 086 087 private TCustomParser(){ 088 curtokenpos = 0; 089 yylval = new TDatabaseYYSType(); 090 yyv = new TDatabaseYYSType[yymaxdepth + 1]; //1 based 091 yys = new int[yymaxdepth + 1]; // 1 based, reused across parse calls 092 yyval = null; 093 // sqlcmds will be injected by TGSqlParser based on vendor 094 } 095 096 TCustomParser(EDbVendor pDbVendor){ 097 this(); 098 this.dbvendor = pDbVendor; 099 nf = new TNodeFactory(this.dbvendor); 100 } 101 102 TParseTreeNodeList yacclcons(Object obj, TParseTreeNodeList parseTreeNodeList,boolean IsParse){ 103 return null; 104 } 105 106 TParseTreeNodeList yaccmakeList1(Object x1,boolean IsParse){ 107 return null; 108 } 109 110 TParseTreeNodeList yaccmakeList2(Object x1,Object x2,boolean IsParse){ 111 return null; 112 } 113 114 TParseTreeNodeList yaccnconc(TParseTreeNodeList l1, TParseTreeNodeList l2){ 115 return null; 116 } 117 TParseTreeNodeList yacclappend(TParseTreeNodeList parseTreeNodeList,Object obj,boolean IsParse){ 118 return null; 119 } 120 int yylexwrap(boolean isignore){ 121 int ret = 0; 122 if (sourcetokenlist == null) return ret; 123 TSourceToken ast = getasourcetoken(isignore); 124 if (ast == null ) return ret; 125 if (ast.tokencode == 0) return ret; 126 yylval.yyTSourceToken = ast; 127 128 if ((yylval.yyTSourceToken.tokencode == TBaseType.bind_v) 129 && (dbvendor == EDbVendor.dbvmysql)) 130 { 131 yylval.yyTSourceToken.tokencode = TBaseType.ident; 132 //yylval.yyTSourceToken.nodetype := T_BindV; 133 } 134 if (dbvendor == EDbVendor.dbvoracle){ 135 yylval.yyTSourceToken.tag = 0; 136 } 137 //System.out.println(yylval.yyTSourceToken.toString()); 138 return yylval.yyTSourceToken.tokencode; 139 } 140 141 TSourceToken read_to_next_parentheses(boolean isIncluding){ 142 return read_to_next_parentheses(isIncluding, new TDummy()); 143 } 144 145 TSourceToken read_to_next_parentheses(boolean isIncluding, TParseTreeNode ownerNode){ 146 int nested = 0; 147 int yychar = -1; 148 149 TSourceToken ret = null,prevSt = null; 150 151 152 while (true){ 153 yychar = yylexwrap(false);//yyLexer.yylexwrap; 154 if (yychar<0) {yychar = 0;} 155 if (yychar == 0) { return ret;} 156 157 if (yylval.yyTSourceToken.tokentype == ETokenType.ttleftparenthesis) 158 {nested++;} 159 160 if (yylval.yyTSourceToken.tokentype == ETokenType.ttrightparenthesis) 161 {nested--;} 162 163 if (prevSt == null){ 164 ownerNode.setStartToken(yylval.yyTSourceToken); 165 } 166 167 if (nested < 0) 168 { 169 //curtokenpos--; //rollback ')' 170 if (isIncluding) { 171 stmtendpos = curtokenpos;// - 1; 172 ret = yylval.yyTSourceToken; 173 ownerNode.setEndToken(ret); 174 }else{ 175 curtokenpos--; 176 stmtendpos = curtokenpos;// - 1; 177 ret = prevSt; 178 ownerNode.setEndToken(ret); 179 } 180 break; // end of this node 181 } 182 183 ret = yylval.yyTSourceToken; 184 185 if (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 186 { 187 ownerNode.setEndToken(ret); 188 break; 189 } 190 191 prevSt = yylval.yyTSourceToken; 192 } // while 193 194 return ret; 195 196 } 197 198 TSourceToken read_before_subquery(){ 199 int yychar = -1; 200 TSourceToken ret = null; 201 202 while (true){ 203 yychar = yylexwrap(false);//yyLexer.yylexwrap; 204 if (yychar<0) {yychar = 0;} 205 if (yychar == 0) { return ret;} 206 207 if (yylval.yyTSourceToken.tokencode == TBaseType.rrw_as) 208 { 209 TSourceToken next = yylval.yyTSourceToken.nextSolidToken(); 210 if (next != null){ 211 if ((next.tokencode == TBaseType.rrw_select)||(next.tokencode == TBaseType.rrw_with)){ 212 curtokenpos--; 213 break; 214 } 215 } 216 } 217 218 ret = yylval.yyTSourceToken; 219 if (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 220 { 221 break; 222 } 223 } // while 224 225 return ret; 226 227 } 228 229 TokenAndText read_consume_valid_filename_token(boolean removeTokenBeforeWhitespace) { 230 int yychar = -1; 231 String ret = ""; 232 TSourceToken lastToken = null; 233 234 while (true) { 235 yychar = yylexwrap(false); // yyLexer.yylexwrap; 236 if (yychar < 0) { 237 yychar = 0; 238 } 239 if (yychar == 0) { 240 return new TokenAndText(lastToken, ret); 241 } 242 243 if ((yylval.yyTSourceToken.tokentype == ETokenType.ttwhitespace) 244 || (yylval.yyTSourceToken.tokentype == ETokenType.ttreturn) 245 || (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 246 || (yylval.yyTSourceToken.tokencode == ')') 247 || (yylval.yyTSourceToken.tokencode == '(') 248 ) { 249 curtokenpos--; // rollback to ensure the token is not consumed 250 break; 251 } 252 253 254 ret = ret + yylval.yyTSourceToken.toString(); 255 lastToken = yylval.yyTSourceToken; 256 if (removeTokenBeforeWhitespace) { 257 yylval.yyTSourceToken.tokenstatus = ETokenStatus.tsdeleted; 258 } 259 } 260 return new TokenAndText(lastToken, ret); 261 } 262 263 TSourceToken read_before_this_token(int[] pTokenCodes){ 264 int yychar = -1; 265 TSourceToken ret = null; 266 boolean found = false; 267 268 while (true){ 269 yychar = yylexwrap(false);//yyLexer.yylexwrap; 270 if (yychar<0) {yychar = 0;} 271 if (yychar == 0) { return ret;} 272 273 for(int k=0;k<pTokenCodes.length;k++){ 274 if (yylval.yyTSourceToken.tokencode == pTokenCodes[k]) 275 { 276 found = true; 277 curtokenpos--; 278 break; 279 } 280 } 281 if (found) break; 282 ret = yylval.yyTSourceToken; 283 if (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 284 { 285 break; 286 } 287 } // while 288 289 return ret; 290 } 291 292 TSourceToken read_before_this_token(int pTokenCode){ 293 return read_before_this_token(new int[] {pTokenCode}); 294 } 295 296 TSourceToken read_to_semicolon(){ 297 return read_to_semicolon(new TDummy(),true); 298 } 299 300 TSourceToken read_to_semicolon(boolean includeSemicolon){ 301 return read_to_semicolon(new TDummy(),includeSemicolon); 302 } 303 304 TSourceToken read_to_semicolon(TParseTreeNode ownerNode){ 305 return read_to_semicolon(ownerNode,true); 306 } 307 308 TSourceToken read_to_semicolon(TParseTreeNode ownerNode,boolean includeSemicolon){ 309 310 int yychar = -1; 311 312 TSourceToken ret = null; 313 314 while (true){ 315 yychar = yylexwrap(false);//yyLexer.yylexwrap; 316 if (yychar<0) {yychar = 0;} 317 if (yychar == 0) { return ret;} 318 319 if ((ret == null)&&(ownerNode.getStartToken() == null)){ 320 ownerNode.setStartToken(yylval.yyTSourceToken); 321 } 322 ret = yylval.yyTSourceToken; 323 324 if (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 325 { 326 break; 327 } 328 } // while 329 if (ret.tokentype == ETokenType.ttsemicolon){ 330 ownerNode.setEndToken(ret.getPrevTokenInChain()); 331 if (!includeSemicolon){ 332 curtokenpos -- ; 333 } 334 }else{ 335 ownerNode.setEndToken(ret); 336 } 337 338 return ret; 339 340 } 341 342 TSourceToken read_a_token( ){ 343 344 int yychar = -1; 345 346 TSourceToken ret = null; 347 yychar = yylexwrap(false); 348 ret = yylval.yyTSourceToken; 349 350 return ret; 351 352 } 353 354 355 TSourceToken read_to_this_token( int tokenCode){ 356 357 int yychar = -1; 358 359 TSourceToken ret = null; 360 361 while (true){ 362 yychar = yylexwrap(false);//yyLexer.yylexwrap; 363 if (yychar<0) {yychar = 0;} 364 if (yychar == 0) { return ret;} 365 366 ret = yylval.yyTSourceToken; 367 368 if (yylval.yyTSourceToken.tokencode == tokenCode) 369 { 370 break; 371 } 372 } // while 373 374 return ret; 375 376 } 377 378 /** 379 * Read tokens until we encounter double closing braces }} 380 * Used for MLE JavaScript code blocks: AS MLE LANGUAGE JAVASCRIPT {{ ... }} 381 */ 382 TSourceToken read_to_double_close_brace(){ 383 int yychar = -1; 384 TSourceToken ret = null; 385 TSourceToken prevToken = null; 386 387 while (true){ 388 yychar = yylexwrap(false); 389 if (yychar < 0) {yychar = 0;} 390 if (yychar == 0) { return ret;} 391 392 ret = yylval.yyTSourceToken; 393 394 // Check if we have }} (two consecutive closing braces) 395 if (prevToken != null && 396 prevToken.tokencode == '}' && 397 ret.tokencode == '}') { 398 break; 399 } 400 401 prevToken = ret; 402 } 403 404 return ret; 405 } 406 407 TSourceToken getasourcetoken(boolean isignore){ 408 TSourceToken newst = null; 409 int j; 410 if (sourcetokenlist == null) return null; 411 412 if (curtokenpos > sourcetokenlist.size() - 1) return null; 413 for (j = curtokenpos; j < sourcetokenlist.size();j++) 414 { 415 newst = sourcetokenlist.get(j); 416 if ((newst.tokencode == TBaseType.lexspace) && isignore) continue; 417 if ((newst.tokencode == TBaseType.lexnewline) && isignore) continue; 418 if ((newst.tokencode == TBaseType.cmtdoublehyphen) && isignore) continue; 419 if ((newst.tokencode == TBaseType.cmtslashstar) && isignore) continue; 420 if ((newst.tokenstatus == ETokenStatus.tsignorebyyacc)) continue; 421 422 if (newst.tokenstatus != ETokenStatus.tsdeleted) break; 423 } 424 if (j == sourcetokenlist.size()) return null; 425 else 426 curtokenpos = curtokenpos + (j-curtokenpos+1); 427 428 // System.out.println("curtokenpos:"+curtokenpos+" "+newst); 429 430// pstr := ''; 431// asqlstatement := TCustomSqlStatement(sqlstatement); 432// 433// //check bind variable 434// // if (newst.TokenType = ttBindVar) and (dbvendor <> dbvmssql) and (newst.TokenStatus <> tsDeleted) then 435// if (newst.TokenType = ttBindVar) and (newst.TokenStatus <> tsDeleted) then 436// begin 437// if assigned(onBindVar) then 438// begin 439// onBindVar(self,copy(newst.SourceCode,2,length(newst.SourceCode)-1),pstr); 440// end; 441// // newst.TokenType := ttIdentifier; 442// if assigned(asqlstatement) then 443// begin 444// lcValue := TLzValue.create(asqlstatement); 445// lcValue.ValueName := copy(newst.SourceCode,2,length(newst.SourceCode)-1); 446// lcValue.ValueStr := pstr; 447// lcValue.SourceToken := newst; 448// asqlstatement.params.add(lcValue); 449// end; 450// if length(pstr) <> 0 then 451// newst.SourceCode := pstr; 452// end; 453 454// //check variable 455// // if (newst.TokenType = ttSqlVar) and (dbvendor <> dbvmssql) and (newst.TokenStatus <> tsDeleted) then 456// if (newst.TokenType = ttSqlVar) and (newst.TokenStatus <> tsDeleted) then 457// begin 458// if assigned(onSqlVar) then 459// begin 460// onSqlVar(self,copy(newst.SourceCode,2,length(newst.SourceCode)-1),pstr); 461// end; 462// if dbvendor <> dbvmssql then 463// newst.TokenType := ttIdentifier; 464// if assigned(asqlstatement) then 465// begin 466// lcValue := TLzValue.create(asqlstatement); 467// lcValue.ValueName := copy(newst.SourceCode,2,length(newst.SourceCode)-1); 468// lcValue.ValueStr := pstr; 469// lcValue.SourceToken := newst; 470// asqlstatement.sqlvars.add(lcValue); 471// end; 472// if length(pstr) <> 0 then 473// newst.SourceCode := pstr; 474// end; 475// 476// pstr := ''; 477// 478// try 479// if assigned(OnParserToken) 480// and (newst.CodeSource = csOriginal) 481// and (newst.TokenStatus <> tsDeleted) 482// and (newst.TokenType <> ttBindVar) 483// then OnParserToken(self,newst,Integer(DbVendor)); 484// except 485// // paot := aotNone; 486// end; 487 488// if (newst.tokenstatus = tsDeleted) then 489// begin 490// if assigned(RecoverToken) then 491// begin 492// newst := RecoverToken; 493// RecoverToken := nil; 494// end 495// else 496// newst := GetASourceToken(IsIgnore); 497// end; 498 499 return newst; 500 } 501 502 int dobefore_yyparse(){ 503 int ret = 10000; 504 for (int i=0; i< sourcetokenlist.size();i++) 505 { // if there are no solid tokentext in list, return -1, don't parse anymore 506 if( (sourcetokenlist.get(i).tokentype == ETokenType.ttwhitespace) 507 || (sourcetokenlist.get(i).tokentype == ETokenType.ttreturn) 508 || (sourcetokenlist.get(i).tokencode == TBaseType.cmtdoublehyphen) 509 || (sourcetokenlist.get(i).tokencode == TBaseType.cmtslashstar) ) 510 {continue;} 511 else 512 { 513 ret = 0; 514 break; 515 } 516 } 517 518 return ret; 519 520 } 521 522 //spFatalError yyparse stack overflow error 1010 ,CurrentSourceToken.lines,CurrentSourceToken.columns 523 void onparseerrorhandle(EErrorType errortype,String pmsg,String token,long xposition,long yposition, int errorno){ 524 if (sql != null){ 525 sql.parseerrormessagehandle( new TSyntaxError(token,xposition,yposition,pmsg,errortype,errorno,null,-1)); 526 }else{ 527 System.out.println(pmsg); 528 } 529 } 530 531 boolean yyact(int state,int sym,int[] act){ 532 return false; 533 } 534 535 boolean yygoto(int state, int sym,int[] nstate){ 536 return false; 537 } 538 539 /** 540 * according to the input state and sym, get the new state from the goto table 541 * return false if no state found (this will cause a parse error), otherwise return true, and the new state is stored in nstate[0] 542 * 543 * if method is called when a reduce action is performed. 544 * 545 * @param state 546 * @param sym 547 * @param nstate 548 * @param p_yygl 549 * @param p_yygh 550 * @param p_yyg_sym 551 * @param p_yyg_act 552 * @return 553 */ 554 boolean yygoto(int state, int sym,int[] nstate, int[] p_yygl, int[] p_yygh, int[] p_yyg_sym, int[] p_yyg_act){ 555 boolean r; 556 int k = p_yygl[state]; 557 while ((k<=p_yygh[state]) && (p_yyg_sym[k] != sym)) {k++;} 558 if (k>p_yygh[state]) 559 r = false; 560 else 561 { 562 nstate[0] = p_yyg_act[k]; 563 r = true; 564 } 565 return r; 566 } 567 568 /** 569 * according to the input state and sym, get the action from the action table 570 * return false if no action found (this will cause a parse error), otherwise return true, and the action is stored in act[0] 571 * if act[0] > 0, it means shift, the value is the new state, can be used in yyact() method 572 * if act[0] < 0, it means reduce, the value is the rule number, used in yyaction(-value) method 573 * if act[0] = 0, it means parse completed successfully. 574 * 575 * @param state 576 * @param sym 577 * @param act 578 * @param p_yyal 579 * @param p_yyah 580 * @param p_yya_sym 581 * @param p_yya_act 582 * @return 583 */ 584 boolean yyact(int state,int sym,int[] act, int[] p_yyal, int[] p_yyah, int[] p_yya_sym, int[] p_yya_act){ 585 boolean r; 586 int k = p_yyal[state]; 587 while ((k <= p_yyah[state]) && (p_yya_sym[k] != sym) ) {k++;} 588 if (k>p_yyah[state]) 589 r = false; 590 else { 591 act[0] = p_yya_act[k]; 592 r = true; 593 } 594 return r; 595 } 596 597 public int do_yyparse(int [] p_yyd, 598 int [] p_yyal, int [] p_yyah, int [] p_yya_sym, int[] p_yya_act, 599 int [] p_yygl, int [] p_yygh, int [] p_yyg_sym, int [] p_yyg_act, 600 int [] p_yyr_len,int [] p_yyr_sym, 601 Map<Integer, int[]> p_rollbackTokens 602 ){ 603 int lcprevyysp,lcyystate,lcyyn,yyn=0; 604 // yys array is now an instance field, reused across parse calls for performance 605 TDatabaseYYSType rollback_token = null; 606 int lcAction; 607 boolean lcrollbackstate ; 608 int lcrollbacktokens; 609 610 curtokenpos = 0; 611 int lcRetries = dobefore_yyparse();//super.yyparse(); 612 if (lcRetries == -1) 613 { // no solid tokentext in tokentext list 614 return 0; 615 } 616 617 int rollback_mode = 0; 618 int yystate = 0, yychar = -1, yynerrs = 0, yyerrflag = 0; 619 yysp = 0; 620 boolean lcIsError = false; 621 boolean lcIsParse = false; 622 boolean lcIsReduce= false; 623 boolean lcIsShift = false; 624 625 int rollback_state = yystate; 626 int rollback_sp = yysp; 627 628 boolean isBeginOfBatch = true; //used in mssql 629 boolean lccanreduce; // used in mssql 630 631 isbeginofbatch = true; 632 633 while (true){ // the main loop for parsing 634 635 // this is the point where parse started: 636 637 yysp++; 638 if (yysp > yymaxdepth) 639 { 640 // yyerror('yyparse stack overflow'); 641 onparseerrorhandle(EErrorType.spfatalerror, "yyparse stack overflow error 1010" , currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10010); 642 //goto abort; 643// if (dbvendor == EDbVendor.dbvmssql){ 644// onparseerrorhandle(EErrorType.spfatalabort,"abort !!! error 1001",currentsourcetoken.astext ,currentsourcetoken.lineNo,currentsourcetoken.columnNo,10011); 645// } 646 647 return 10001; 648 } 649 650 yys[yysp] = yystate; 651 yyv[yysp] = yyval; 652 653 while (true){ 654 // this is the point where NEXT is started: 655 // get next symbol 656 657 if( (p_yyd[yystate] == 0) && (yychar == -1)) 658 //(* get next symbol *) 659 { 660 do{ 661 yychar = yylexwrap(true);//yyLexer.yylexwrap; 662 if (yychar<0) { yychar = 0;} 663 // ignore comments and blanks [ \n\t] 664 //if not( (yychar=_COMMENT) or (yychar=_BLANK) or 665 // (yychar=_TAB) or (yychar=_NEWLINE) ) then break; 666 if (!( (yychar== TBaseType.cmtdoublehyphen)|| (yychar== TBaseType.cmtslashstar) || 667 (yychar== TBaseType.lexspace) || (yychar== TBaseType.lexnewline) || (yychar== TBaseType.sqlpluscmd) )) 668 { 669 if (yychar == 0) 670 { 671 //System.out.println("error tokentext:"+yylval.yyTSourceToken+"c "+currentsourcetoken); 672 if ( ( sourcetokenlist.get(sourcetokenlist.size() - 1)).tokencode != 0) 673 { 674 //System.out.println("yychar is 0, but tokencode is:"+ ( sourcetokenlist.get(sourcetokenlist.size() - 1)).tokencode); 675 yylval.yyTSourceToken = new TSourceToken(" "); 676 // NewSourceToken(yylval.yyTSourceToken,'',ttUnknown,wtNotAWord,eNotAComment,-1,-1); 677 yylval.yyTSourceToken.container = sourcetokenlist; 678 yylval.yyTSourceToken.tokencode = 0; 679 //sourcetokenlist.add(yylval.yyTSourceToken); 680 yylval.yyTSourceToken.posinlist = sourcetokenlist.size() - 1; 681 curtokenpos = sourcetokenlist.size(); 682 //showmessage('end of input'); 683 } 684 else 685 { 686 yylval.yyTSourceToken = sourcetokenlist.get(sourcetokenlist.size() - 1); 687 // showmessage('end of input again'); 688 } 689 } 690 691 currentsourcetoken = yylval.yyTSourceToken; 692 break; 693 } 694 else 695 { 696 //ignore non solid tokentext 697 } 698 699 } while (true); 700 } //(* get next symbol *) 701 702 if (!lcIsError) 703 { 704 yyn = p_yyd[yystate]; 705 if (yyn != 0) 706 { 707 //goto reduce; (* simple state *) 708 lcIsReduce = true; 709 break; 710 } 711 712 // (* no default action; search parse table *) 713 boolean foundAction = yyact(yystate, yychar, retvalue,p_yyal,p_yyah,p_yya_sym,p_yya_act); 714 if(foundAction) {yyn = retvalue[0];} 715 if (! foundAction) 716 { // no action found, here we do error handling 717 // lcRestartPos := curtokenpos; 718 719 lcAction = aopAbort; 720 lcrollbackstate = false; 721 lcrollbacktokens = 0; 722 723 //if parse error occurs due to a keyword, then change this keyword to identifier 724 // and retry again, 725 // for example 726 727 // select a.wait from b 728 // wait is a keyword, can not be field name due to .y file, 729 // but it's a legal in mssql, use this procedure while during parsing, 730 // we can fix such problem which is very common 731 // we don't recover from FROM keyword 732 733 if ((yylval.yyTSourceToken.tokencode >= TBaseType.rrw_select ) 734 && (yylval.yyTSourceToken.tokencode != TBaseType.rrw_from ) 735 && (dbvendor != EDbVendor.dbvmssql?true:(yylval.yyTSourceToken.tokencode != TBaseType.rrw_where )) 736 ) 737 { 738 // 如果一个token有多个侯备的其他token可以尝试,我们逐一尝试,如果没有成功的,将token类型改为ident进行最后尝试,还不成功,则报错。 739 740 int[] rollbackTokens = new int[1]; 741 rollbackTokens[0] = TBaseType.ident; 742 if ((p_rollbackTokens!=null) && (p_rollbackTokens.containsKey(yylval.yyTSourceToken.tokencode))) { 743 rollbackTokens = p_rollbackTokens.get(yylval.yyTSourceToken.tokencode); 744 } 745 746 for(int i=0;i<rollbackTokens.length;i++) 747 { 748 yylval.yyTSourceToken.tokencode = rollbackTokens[i]; 749 if (yyact(yystate, yylval.yyTSourceToken.tokencode, retvalue, p_yyal,p_yyah,p_yya_sym,p_yya_act)) 750 { 751 yyn = retvalue[0]; 752 if (yyn>0) 753 { 754 //goto shift; 755 lcIsShift = true; 756 break; 757 } 758 else if( yyn<0 ) 759 { 760 // goto reduce 761 lcIsReduce = true; 762 break; 763 } 764 else 765 { 766 // goto accept; 767 return 0; 768 } 769 } 770 } 771 772 if (lcIsShift||lcIsReduce) 773 { 774 if (yylval.yyTSourceToken.tokencode == TBaseType.ident){ 775 yylval.yyTSourceToken.tokentype = ETokenType.ttidentifier; 776 } 777 yychar = yylval.yyTSourceToken.tokencode; 778 break; 779 } 780 } 781 782 // end of error recover 783 784 if (lcAction == aopAbort ) 785 { 786 // goto error; 787 lcIsError = true; 788 } 789 } 790 else if (yyn>0) 791 { 792 //goto shift; 793 lcIsShift = true; 794 break; 795 } 796 else if( yyn<0 ) 797 { 798 // goto reduce 799 lcIsReduce = true; 800 break; 801 } 802 else 803 { 804 // goto accept; 805 return 0; 806 } 807 808 } // if not lcIsError 809 810 if (lcIsError) 811 { 812 lcIsError = false; 813 814 if ((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase)){ 815 if (yyerrflag<=2) // (* incomplete recovery; try again *) 816 { 817 yyerrflag = 3; 818 //(* uncover a state with shift action on error tokentext *) 819 //(* error; start error recovery: *) 820 821 822 lcprevyysp = yysp; 823 while ((yysp>0) 824 && !( yyact(yys[yysp], _error, retvalue,p_yyal,p_yyah,p_yya_sym,p_yya_act) 825 &&( (yyn = retvalue[0]) >0 ) 826 ) 827 ) 828 { 829 yysp--; 830 } 831 832 if (lcprevyysp != yysp) // if error stmt is just the next state need, then it's a fake error, don't report 833 geterrormsg(yystate, yychar,10101); 834 835 if (yysp==0) 836 { 837 //assert(1=2,'Should be an error handle rule in y file, never goes to here!!!'); 838 onparseerrorhandle(EErrorType.spfatalerror,"error recover failed error", currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10012); 839 //goto abort; (* parser has fallen from stack; abort *) 840 841 onparseerrorhandle(EErrorType.spfatalabort,"abort !!! error 1001", currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10013); 842 843 return 10003; 844 } 845 846 847 errorstmtstarttoken = null; 848 849 850 yystate = yyn; // (* simulate shift on error *) 851 yychar = -1; 852 stmtendpos = curtokenpos-1; 853 854 //goto parse; 855 lcIsParse = true; 856 break; 857 } 858 else //(yyerrflag<=2) (* no shift yet; discard symbol *) 859 { 860 if (yychar==0) 861 { 862 863 // goto abort; (* end of input; abort *) 864 onparseerrorhandle(EErrorType.spfatalabort, "abort !!! error 1001", currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10013); 865 866 return 10004; 867 } 868 869 yychar = -1; 870 stmtendpos = curtokenpos-1; 871 sourcetokenlist.get(curtokenpos-1).tokenstatus = ETokenStatus.tssynataxerror; 872 // showmessage('lookahead:'+inttostr(curtokenpos-1)+'->'+sourcetokenlist[curtokenpos-1].astext+'->yyd[yystate]:'+inttostr(yystate)); 873 // goto next; (* clear lookahead char and try again *) 874 continue; 875 } 876 877 }else{ 878 879 // Enhanced parser to handle SQL statements that are missing a semicolon at the end. 880 // When a statement without a semicolon is encountered, the parser will attempt to add a virtual semicolon and continue parsing rather than throwing an error. This improves parsing robustness for incomplete statements. 881 882 // 如果当前token是0 (end of input),并且可以shift一个分号,则shift一个分号,否则报错 883 if (yychar == 0 && yyact(yystate, ';', retvalue, p_yyal,p_yyah,p_yya_sym,p_yya_act) && retvalue[0] > 0) { 884 yyn = retvalue[0]; 885 lcIsShift = true; 886 break; 887 } 888 geterrormsg(yystate, yychar,10102); 889 return 10102; 890 } 891 892 }// if lcIsError 893 894 } //next 895 896 if (lcIsParse) 897 { 898 lcIsParse = false; 899 continue; 900 } 901 902 if (lcIsShift) 903 { 904 // this is the point where SHIFT is started: 905 906 lcIsShift = false; 907 //(* go to new state, clear lookahead character: *) 908 rollback_state = yystate; 909 rollback_mode = 1; 910 rollback_sp = yysp; 911 rollback_token = yyval; 912 if ((yyerrflag>0) && (yychar != _error ) ) 913 { 914 if ((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase)){ 915 nextstmtstartpos = curtokenpos - 1; 916 } 917 yyerrflag--; 918 } 919 yystate = yyn; 920 yychar = -1; 921 yyval = new TDatabaseYYSType(); 922 yyval.copy( yylval); 923 924 if (lcRetries > 0) lcRetries--; 925 926 if ((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase)){ 927 stmtendpos = curtokenpos - 1; // tokentext became part of stmt only after shift 928 acceptedtoken = currentsourcetoken; 929 } 930 931 // goto parse; 932 continue; 933 934 }//if lcIsShift 935 936 if (lcIsReduce) 937 { 938 // this is the point where REDUCE is started: 939 940 lcIsReduce = false; 941 942 //(* execute action, pop rule from stack, and go to next state: *) 943 // yyval.yyTLz_Parse_Tree_Node := nil; 944 yyflag = yyfnone; 945 yyval = new TDatabaseYYSType(); 946 yyaction(-yyn); 947 948 rollback_mode = 2; 949 yysp = yysp - p_yyr_len[-yyn]; 950 951 if (yygoto(yys[yysp], p_yyr_sym[-yyn], retvalue,p_yygl,p_yygh,p_yyg_sym,p_yyg_act)) 952 { 953 yyn = retvalue[0]; 954 yystate = yyn; 955 } 956 957 //(* handle action calls to yyaccept, yyabort and yyerror: *) 958 // goto parse; 959 continue; 960 961 } //if lcIsReduce 962 963 } // parse 964 965 } 966 967 968 void geterrormsg(int state, int sym, int errorno){ 969 if (sql != null){ 970 String s; 971 if (sym == 0){ 972 s = "end of input, state:"+state; 973 }else{ 974 s = "syntax error, state:"+state; 975 } 976 //System.out.println(currentsourcetoken); 977// if (currentsourcetoken != null){ 978// s = s+"toke code:"+currentsourcetoken.tokencode+" ,token type:"+currentsourcetoken.tokentype; 979// } 980 981 sql.parseerrormessagehandle(new TSyntaxError(currentsourcetoken,s, EErrorType.spfatalerror,errorno,null)); 982 983 984 985 }else 986 System.out.println("syntax error 10033,state:"+state); 987 988 } 989 990 991 992 void yyaction (int yyruleno){ 993 994 } 995 996public int yyparse(){ 997 return -1; 998} 999 1000} 1001 1002class TDatabaseYYSType { 1003 String yylzString; 1004 TSourceToken yyTSourceToken; 1005 TParseTreeNodeList yyTParseTreeNodeList; 1006 TParseTreeNode yyTParseTreeNode; 1007 TSourceTokenList yyTSourceTokenList; 1008 ArrayList yyArrayList; 1009 // TStatementList yyTStatementList; 1010 1011 public void copy(TDatabaseYYSType p){ 1012 yyTSourceToken = p.yyTSourceToken; 1013 yyTParseTreeNodeList = p.yyTParseTreeNodeList; 1014 yyTParseTreeNode = p.yyTParseTreeNode; 1015 yyTSourceTokenList = p.yyTSourceTokenList; 1016 yyArrayList = p.yyArrayList; 1017 } 1018} 1019 1020class TokenAndText{ 1021 public TSourceToken lastToken; 1022 public String text; 1023 1024 public TokenAndText(TSourceToken lastToken, String text) { 1025 this.lastToken = lastToken; 1026 this.text = text; 1027 } 1028} 1029