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 TSourceToken getasourcetoken(boolean isignore){ 379 TSourceToken newst = null; 380 int j; 381 if (sourcetokenlist == null) return null; 382 383 if (curtokenpos > sourcetokenlist.size() - 1) return null; 384 for (j = curtokenpos; j < sourcetokenlist.size();j++) 385 { 386 newst = sourcetokenlist.get(j); 387 if ((newst.tokencode == TBaseType.lexspace) && isignore) continue; 388 if ((newst.tokencode == TBaseType.lexnewline) && isignore) continue; 389 if ((newst.tokencode == TBaseType.cmtdoublehyphen) && isignore) continue; 390 if ((newst.tokencode == TBaseType.cmtslashstar) && isignore) continue; 391 if ((newst.tokenstatus == ETokenStatus.tsignorebyyacc)) continue; 392 393 if (newst.tokenstatus != ETokenStatus.tsdeleted) break; 394 } 395 if (j == sourcetokenlist.size()) return null; 396 else 397 curtokenpos = curtokenpos + (j-curtokenpos+1); 398 399 // System.out.println("curtokenpos:"+curtokenpos+" "+newst); 400 401// pstr := ''; 402// asqlstatement := TCustomSqlStatement(sqlstatement); 403// 404// //check bind variable 405// // if (newst.TokenType = ttBindVar) and (dbvendor <> dbvmssql) and (newst.TokenStatus <> tsDeleted) then 406// if (newst.TokenType = ttBindVar) and (newst.TokenStatus <> tsDeleted) then 407// begin 408// if assigned(onBindVar) then 409// begin 410// onBindVar(self,copy(newst.SourceCode,2,length(newst.SourceCode)-1),pstr); 411// end; 412// // newst.TokenType := ttIdentifier; 413// if assigned(asqlstatement) then 414// begin 415// lcValue := TLzValue.create(asqlstatement); 416// lcValue.ValueName := copy(newst.SourceCode,2,length(newst.SourceCode)-1); 417// lcValue.ValueStr := pstr; 418// lcValue.SourceToken := newst; 419// asqlstatement.params.add(lcValue); 420// end; 421// if length(pstr) <> 0 then 422// newst.SourceCode := pstr; 423// end; 424 425// //check variable 426// // if (newst.TokenType = ttSqlVar) and (dbvendor <> dbvmssql) and (newst.TokenStatus <> tsDeleted) then 427// if (newst.TokenType = ttSqlVar) and (newst.TokenStatus <> tsDeleted) then 428// begin 429// if assigned(onSqlVar) then 430// begin 431// onSqlVar(self,copy(newst.SourceCode,2,length(newst.SourceCode)-1),pstr); 432// end; 433// if dbvendor <> dbvmssql then 434// newst.TokenType := ttIdentifier; 435// if assigned(asqlstatement) then 436// begin 437// lcValue := TLzValue.create(asqlstatement); 438// lcValue.ValueName := copy(newst.SourceCode,2,length(newst.SourceCode)-1); 439// lcValue.ValueStr := pstr; 440// lcValue.SourceToken := newst; 441// asqlstatement.sqlvars.add(lcValue); 442// end; 443// if length(pstr) <> 0 then 444// newst.SourceCode := pstr; 445// end; 446// 447// pstr := ''; 448// 449// try 450// if assigned(OnParserToken) 451// and (newst.CodeSource = csOriginal) 452// and (newst.TokenStatus <> tsDeleted) 453// and (newst.TokenType <> ttBindVar) 454// then OnParserToken(self,newst,Integer(DbVendor)); 455// except 456// // paot := aotNone; 457// end; 458 459// if (newst.tokenstatus = tsDeleted) then 460// begin 461// if assigned(RecoverToken) then 462// begin 463// newst := RecoverToken; 464// RecoverToken := nil; 465// end 466// else 467// newst := GetASourceToken(IsIgnore); 468// end; 469 470 return newst; 471 } 472 473 int dobefore_yyparse(){ 474 int ret = 10000; 475 for (int i=0; i< sourcetokenlist.size();i++) 476 { // if there are no solid tokentext in list, return -1, don't parse anymore 477 if( (sourcetokenlist.get(i).tokentype == ETokenType.ttwhitespace) 478 || (sourcetokenlist.get(i).tokentype == ETokenType.ttreturn) 479 || (sourcetokenlist.get(i).tokencode == TBaseType.cmtdoublehyphen) 480 || (sourcetokenlist.get(i).tokencode == TBaseType.cmtslashstar) ) 481 {continue;} 482 else 483 { 484 ret = 0; 485 break; 486 } 487 } 488 489 return ret; 490 491 } 492 493 //spFatalError yyparse stack overflow error 1010 ,CurrentSourceToken.lines,CurrentSourceToken.columns 494 void onparseerrorhandle(EErrorType errortype,String pmsg,String token,long xposition,long yposition, int errorno){ 495 if (sql != null){ 496 sql.parseerrormessagehandle( new TSyntaxError(token,xposition,yposition,pmsg,errortype,errorno,null,-1)); 497 }else{ 498 System.out.println(pmsg); 499 } 500 } 501 502 boolean yyact(int state,int sym,int[] act){ 503 return false; 504 } 505 506 boolean yygoto(int state, int sym,int[] nstate){ 507 return false; 508 } 509 510 /** 511 * according to the input state and sym, get the new state from the goto table 512 * return false if no state found (this will cause a parse error), otherwise return true, and the new state is stored in nstate[0] 513 * 514 * if method is called when a reduce action is performed. 515 * 516 * @param state 517 * @param sym 518 * @param nstate 519 * @param p_yygl 520 * @param p_yygh 521 * @param p_yyg_sym 522 * @param p_yyg_act 523 * @return 524 */ 525 boolean yygoto(int state, int sym,int[] nstate, int[] p_yygl, int[] p_yygh, int[] p_yyg_sym, int[] p_yyg_act){ 526 boolean r; 527 int k = p_yygl[state]; 528 while ((k<=p_yygh[state]) && (p_yyg_sym[k] != sym)) {k++;} 529 if (k>p_yygh[state]) 530 r = false; 531 else 532 { 533 nstate[0] = p_yyg_act[k]; 534 r = true; 535 } 536 return r; 537 } 538 539 /** 540 * according to the input state and sym, get the action from the action table 541 * return false if no action found (this will cause a parse error), otherwise return true, and the action is stored in act[0] 542 * if act[0] > 0, it means shift, the value is the new state, can be used in yyact() method 543 * if act[0] < 0, it means reduce, the value is the rule number, used in yyaction(-value) method 544 * if act[0] = 0, it means parse completed successfully. 545 * 546 * @param state 547 * @param sym 548 * @param act 549 * @param p_yyal 550 * @param p_yyah 551 * @param p_yya_sym 552 * @param p_yya_act 553 * @return 554 */ 555 boolean yyact(int state,int sym,int[] act, int[] p_yyal, int[] p_yyah, int[] p_yya_sym, int[] p_yya_act){ 556 boolean r; 557 int k = p_yyal[state]; 558 while ((k <= p_yyah[state]) && (p_yya_sym[k] != sym) ) {k++;} 559 if (k>p_yyah[state]) 560 r = false; 561 else { 562 act[0] = p_yya_act[k]; 563 r = true; 564 } 565 return r; 566 } 567 568 public int do_yyparse(int [] p_yyd, 569 int [] p_yyal, int [] p_yyah, int [] p_yya_sym, int[] p_yya_act, 570 int [] p_yygl, int [] p_yygh, int [] p_yyg_sym, int [] p_yyg_act, 571 int [] p_yyr_len,int [] p_yyr_sym, 572 Map<Integer, int[]> p_rollbackTokens 573 ){ 574 int lcprevyysp,lcyystate,lcyyn,yyn=0; 575 // yys array is now an instance field, reused across parse calls for performance 576 TDatabaseYYSType rollback_token = null; 577 int lcAction; 578 boolean lcrollbackstate ; 579 int lcrollbacktokens; 580 581 curtokenpos = 0; 582 int lcRetries = dobefore_yyparse();//super.yyparse(); 583 if (lcRetries == -1) 584 { // no solid tokentext in tokentext list 585 return 0; 586 } 587 588 int rollback_mode = 0; 589 int yystate = 0, yychar = -1, yynerrs = 0, yyerrflag = 0; 590 yysp = 0; 591 boolean lcIsError = false; 592 boolean lcIsParse = false; 593 boolean lcIsReduce= false; 594 boolean lcIsShift = false; 595 596 int rollback_state = yystate; 597 int rollback_sp = yysp; 598 599 boolean isBeginOfBatch = true; //used in mssql 600 boolean lccanreduce; // used in mssql 601 602 isbeginofbatch = true; 603 604 while (true){ // the main loop for parsing 605 606 // this is the point where parse started: 607 608 yysp++; 609 if (yysp > yymaxdepth) 610 { 611 // yyerror('yyparse stack overflow'); 612 onparseerrorhandle(EErrorType.spfatalerror, "yyparse stack overflow error 1010" , currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10010); 613 //goto abort; 614// if (dbvendor == EDbVendor.dbvmssql){ 615// onparseerrorhandle(EErrorType.spfatalabort,"abort !!! error 1001",currentsourcetoken.astext ,currentsourcetoken.lineNo,currentsourcetoken.columnNo,10011); 616// } 617 618 return 10001; 619 } 620 621 yys[yysp] = yystate; 622 yyv[yysp] = yyval; 623 624 while (true){ 625 // this is the point where NEXT is started: 626 // get next symbol 627 628 if( (p_yyd[yystate] == 0) && (yychar == -1)) 629 //(* get next symbol *) 630 { 631 do{ 632 yychar = yylexwrap(true);//yyLexer.yylexwrap; 633 if (yychar<0) { yychar = 0;} 634 // ignore comments and blanks [ \n\t] 635 //if not( (yychar=_COMMENT) or (yychar=_BLANK) or 636 // (yychar=_TAB) or (yychar=_NEWLINE) ) then break; 637 if (!( (yychar== TBaseType.cmtdoublehyphen)|| (yychar== TBaseType.cmtslashstar) || 638 (yychar== TBaseType.lexspace) || (yychar== TBaseType.lexnewline) || (yychar== TBaseType.sqlpluscmd) )) 639 { 640 if (yychar == 0) 641 { 642 //System.out.println("error tokentext:"+yylval.yyTSourceToken+"c "+currentsourcetoken); 643 if ( ( sourcetokenlist.get(sourcetokenlist.size() - 1)).tokencode != 0) 644 { 645 //System.out.println("yychar is 0, but tokencode is:"+ ( sourcetokenlist.get(sourcetokenlist.size() - 1)).tokencode); 646 yylval.yyTSourceToken = new TSourceToken(" "); 647 // NewSourceToken(yylval.yyTSourceToken,'',ttUnknown,wtNotAWord,eNotAComment,-1,-1); 648 yylval.yyTSourceToken.container = sourcetokenlist; 649 yylval.yyTSourceToken.tokencode = 0; 650 //sourcetokenlist.add(yylval.yyTSourceToken); 651 yylval.yyTSourceToken.posinlist = sourcetokenlist.size() - 1; 652 curtokenpos = sourcetokenlist.size(); 653 //showmessage('end of input'); 654 } 655 else 656 { 657 yylval.yyTSourceToken = sourcetokenlist.get(sourcetokenlist.size() - 1); 658 // showmessage('end of input again'); 659 } 660 } 661 662 currentsourcetoken = yylval.yyTSourceToken; 663 // System.out.println(currentsourcetoken); 664 break; 665 } 666 else 667 { 668 //ignore non solid tokentext 669 } 670 671 } while (true); 672 } //(* get next symbol *) 673 674 if (!lcIsError) 675 { 676 yyn = p_yyd[yystate]; 677 if (yyn != 0) 678 { 679 //goto reduce; (* simple state *) 680 lcIsReduce = true; 681 break; 682 } 683 684 // (* no default action; search parse table *) 685 boolean foundAction = yyact(yystate, yychar, retvalue,p_yyal,p_yyah,p_yya_sym,p_yya_act); 686 if(foundAction) {yyn = retvalue[0];} 687 if (! foundAction) 688 { // no action found, here we do error handling 689 690 // lcRestartPos := curtokenpos; 691 692 lcAction = aopAbort; 693 lcrollbackstate = false; 694 lcrollbacktokens = 0; 695 696 //if parse error occurs due to a keyword, then change this keyword to identifier 697 // and retry again, 698 // for example 699 700 // select a.wait from b 701 // wait is a keyword, can not be field name due to .y file, 702 // but it's a legal in mssql, use this procedure while during parsing, 703 // we can fix such problem which is very common 704 // we don't recover from FROM keyword 705 706 if ((yylval.yyTSourceToken.tokencode >= TBaseType.rrw_select ) 707 && (yylval.yyTSourceToken.tokencode != TBaseType.rrw_from ) 708 && (dbvendor != EDbVendor.dbvmssql?true:(yylval.yyTSourceToken.tokencode != TBaseType.rrw_where )) 709 ) 710 { 711 // 如果一个token有多个侯备的其他token可以尝试,我们逐一尝试,如果没有成功的,将token类型改为ident进行最后尝试,还不成功,则报错。 712 713 int[] rollbackTokens = new int[1]; 714 rollbackTokens[0] = TBaseType.ident; 715 if ((p_rollbackTokens!=null) && (p_rollbackTokens.containsKey(yylval.yyTSourceToken.tokencode))) { 716 rollbackTokens = p_rollbackTokens.get(yylval.yyTSourceToken.tokencode); 717 } 718 719 for(int i=0;i<rollbackTokens.length;i++) 720 { 721 yylval.yyTSourceToken.tokencode = rollbackTokens[i]; 722 if (yyact(yystate, yylval.yyTSourceToken.tokencode, retvalue, p_yyal,p_yyah,p_yya_sym,p_yya_act)) 723 { 724 yyn = retvalue[0]; 725 if (yyn>0) 726 { 727 //goto shift; 728 lcIsShift = true; 729 break; 730 } 731 else if( yyn<0 ) 732 { 733 // goto reduce 734 lcIsReduce = true; 735 break; 736 } 737 else 738 { 739 // goto accept; 740 return 0; 741 } 742 } 743 } 744 745 if (lcIsShift||lcIsReduce) 746 { 747 if (yylval.yyTSourceToken.tokencode == TBaseType.ident){ 748 yylval.yyTSourceToken.tokentype = ETokenType.ttidentifier; 749 } 750 yychar = yylval.yyTSourceToken.tokencode; 751 break; 752 } 753 } 754 755 // end of error recover 756 757 if (lcAction == aopAbort ) 758 { 759 // goto error; 760 lcIsError = true; 761 } 762 } 763 else if (yyn>0) 764 { 765 //goto shift; 766 lcIsShift = true; 767 break; 768 } 769 else if( yyn<0 ) 770 { 771 // goto reduce 772 lcIsReduce = true; 773 break; 774 } 775 else 776 { 777 // goto accept; 778 return 0; 779 } 780 781 } // if not lcIsError 782 783 if (lcIsError) 784 { 785 lcIsError = false; 786 787 if ((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase)){ 788 if (yyerrflag<=2) // (* incomplete recovery; try again *) 789 { 790 yyerrflag = 3; 791 //(* uncover a state with shift action on error tokentext *) 792 //(* error; start error recovery: *) 793 794 795 lcprevyysp = yysp; 796 while ((yysp>0) 797 && !( yyact(yys[yysp], _error, retvalue,p_yyal,p_yyah,p_yya_sym,p_yya_act) 798 &&( (yyn = retvalue[0]) >0 ) 799 ) 800 ) 801 { 802 yysp--; 803 } 804 805 if (lcprevyysp != yysp) // if error stmt is just the next state need, then it's a fake error, don't report 806 geterrormsg(yystate, yychar,10101); 807 808 if (yysp==0) 809 { 810 //assert(1=2,'Should be an error handle rule in y file, never goes to here!!!'); 811 onparseerrorhandle(EErrorType.spfatalerror,"error recover failed error", currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10012); 812 //goto abort; (* parser has fallen from stack; abort *) 813 814 onparseerrorhandle(EErrorType.spfatalabort,"abort !!! error 1001", currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10013); 815 816 return 10003; 817 } 818 819 820 errorstmtstarttoken = null; 821 822 823 yystate = yyn; // (* simulate shift on error *) 824 yychar = -1; 825 stmtendpos = curtokenpos-1; 826 827 //goto parse; 828 lcIsParse = true; 829 break; 830 } 831 else //(yyerrflag<=2) (* no shift yet; discard symbol *) 832 { 833 if (yychar==0) 834 { 835 836 // goto abort; (* end of input; abort *) 837 onparseerrorhandle(EErrorType.spfatalabort, "abort !!! error 1001", currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10013); 838 839 return 10004; 840 } 841 842 yychar = -1; 843 stmtendpos = curtokenpos-1; 844 sourcetokenlist.get(curtokenpos-1).tokenstatus = ETokenStatus.tssynataxerror; 845 // showmessage('lookahead:'+inttostr(curtokenpos-1)+'->'+sourcetokenlist[curtokenpos-1].astext+'->yyd[yystate]:'+inttostr(yystate)); 846 // goto next; (* clear lookahead char and try again *) 847 continue; 848 } 849 850 }else{ 851 852 // Enhanced parser to handle SQL statements that are missing a semicolon at the end. 853 // 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. 854 855 // 如果当前token是0 (end of input),并且可以shift一个分号,则shift一个分号,否则报错 856 if (yychar == 0 && yyact(yystate, ';', retvalue, p_yyal,p_yyah,p_yya_sym,p_yya_act) && retvalue[0] > 0) { 857 yyn = retvalue[0]; 858 lcIsShift = true; 859 break; 860 } 861 geterrormsg(yystate, yychar,10102); 862 return 10102; 863 } 864 865 }// if lcIsError 866 867 } //next 868 869 if (lcIsParse) 870 { 871 lcIsParse = false; 872 continue; 873 } 874 875 if (lcIsShift) 876 { 877 // this is the point where SHIFT is started: 878 879 lcIsShift = false; 880 //(* go to new state, clear lookahead character: *) 881 rollback_state = yystate; 882 rollback_mode = 1; 883 rollback_sp = yysp; 884 rollback_token = yyval; 885 if ((yyerrflag>0) && (yychar != _error ) ) 886 { 887 if ((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase)){ 888 nextstmtstartpos = curtokenpos - 1; 889 } 890 yyerrflag--; 891 } 892 yystate = yyn; 893 yychar = -1; 894 yyval = new TDatabaseYYSType(); 895 yyval.copy( yylval); 896 897 if (lcRetries > 0) lcRetries--; 898 899 if ((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase)){ 900 stmtendpos = curtokenpos - 1; // tokentext became part of stmt only after shift 901 acceptedtoken = currentsourcetoken; 902 } 903 904 // goto parse; 905 continue; 906 907 }//if lcIsShift 908 909 if (lcIsReduce) 910 { 911 // this is the point where REDUCE is started: 912 913 lcIsReduce = false; 914 915 //(* execute action, pop rule from stack, and go to next state: *) 916 // yyval.yyTLz_Parse_Tree_Node := nil; 917 yyflag = yyfnone; 918 yyval = new TDatabaseYYSType(); 919 yyaction(-yyn); 920 921 rollback_mode = 2; 922 yysp = yysp - p_yyr_len[-yyn]; 923 924 if (yygoto(yys[yysp], p_yyr_sym[-yyn], retvalue,p_yygl,p_yygh,p_yyg_sym,p_yyg_act)) 925 { 926 yyn = retvalue[0]; 927 yystate = yyn; 928 } 929 930 //(* handle action calls to yyaccept, yyabort and yyerror: *) 931 // goto parse; 932 continue; 933 934 } //if lcIsReduce 935 936 } // parse 937 938 } 939 940 941 void geterrormsg(int state, int sym, int errorno){ 942 if (sql != null){ 943 String s; 944 if (sym == 0){ 945 s = "end of input, state:"+state; 946 }else{ 947 s = "syntax error, state:"+state; 948 } 949 //System.out.println(currentsourcetoken); 950// if (currentsourcetoken != null){ 951// s = s+"toke code:"+currentsourcetoken.tokencode+" ,token type:"+currentsourcetoken.tokentype; 952// } 953 954 sql.parseerrormessagehandle(new TSyntaxError(currentsourcetoken,s, EErrorType.spfatalerror,errorno,null)); 955 956 957 958 }else 959 System.out.println("syntax error 10033,state:"+state); 960 961 } 962 963 964 965 void yyaction (int yyruleno){ 966 967 } 968 969public int yyparse(){ 970 return -1; 971} 972 973} 974 975class TDatabaseYYSType { 976 String yylzString; 977 TSourceToken yyTSourceToken; 978 TParseTreeNodeList yyTParseTreeNodeList; 979 TParseTreeNode yyTParseTreeNode; 980 TSourceTokenList yyTSourceTokenList; 981 ArrayList yyArrayList; 982 // TStatementList yyTStatementList; 983 984 public void copy(TDatabaseYYSType p){ 985 yyTSourceToken = p.yyTSourceToken; 986 yyTParseTreeNodeList = p.yyTParseTreeNodeList; 987 yyTParseTreeNode = p.yyTParseTreeNode; 988 yyTSourceTokenList = p.yyTSourceTokenList; 989 yyArrayList = p.yyArrayList; 990 } 991} 992 993class TokenAndText{ 994 public TSourceToken lastToken; 995 public String text; 996 997 public TokenAndText(TSourceToken lastToken, String text) { 998 this.lastToken = lastToken; 999 this.text = text; 1000 } 1001} 1002