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