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 /** 027 * Count of entries into yyparse error handling (keyword rollback, error 028 * shift/discard, abort) since this parser instance was created. Read by 029 * {@link DynamicSqlProofHarness}: the dynamic-SQL publication proof must 030 * fail when a parse needed ANY recovery, including silently-successful 031 * keyword rollback. Never reset — use a fresh parser per proof. 032 */ 033 int proofRecoveryEvents = 0; 034 035 /** 036 * Subset of {@link #proofRecoveryEvents}: entries that attempted the 037 * deterministic keyword-to-identifier rollback (e.g. {@code select a.wait 038 * from b}). Typed separately so a future audited-rewrite refinement can 039 * treat successful keyword rollback as a bounded rewrite instead of a 040 * disqualifying recovery — today the proof still refuses on it (sound, 041 * conservative; costs recall on the ~72 rollback-only keyword-column 042 * shapes, tracked in the design doc). 043 */ 044 int proofKeywordRollbackEvents = 0; 045 046 /** @see #proofRecoveryEvents */ 047 public int getProofRecoveryEvents() { 048 return proofRecoveryEvents; 049 } 050 051 /** @see #proofKeywordRollbackEvents */ 052 public int getProofKeywordRollbackEvents() { 053 return proofKeywordRollbackEvents; 054 } 055 056 /* ------------------------------------------------------------------ 057 * Proof-mode LR configuration observation (design R4 — the commitment 058 * check for dynamic-SQL edge provenance). 059 * 060 * A dynamic-SQL site is literal text with holes whose runtime value is 061 * unknown. To decide whether a construct is COMMITTED — i.e. no hole 062 * instantiation can still extend it and rebind a name — we need the LR 063 * automaton's own configuration at the point where the literal prefix 064 * ends, because the grammar, not a hand-written table of clause kinds, 065 * is what knows which productions are still open. 066 * 067 * This block only OBSERVES. It never changes an action, a reduction or 068 * a token. When {@link #proofLrCutoffOffset} is negative (the default) 069 * every field here is untouched and the cost is one int comparison per 070 * lookahead fetch. 071 * ------------------------------------------------------------------ */ 072 073 /** Returned by {@link #do_yyparse} when it stopped at the proof cutoff. */ 074 public static final int PROOF_LR_STOPPED_AT_CUTOFF = 10099; 075 076 /** One reduction the automaton performed, recorded before the stack is popped. */ 077 public static final class ProofReduction { 078 /** yacc rule number (positive). */ 079 public final int rule; 080 /** Number of stack entries the rule pops. */ 081 public final int length; 082 /** LHS symbol the rule reduces to, as stored in the generated tables. */ 083 public final int lhsSymbol; 084 /** Stack depth BEFORE the pop — the rule spans depths [depth-length+1, depth]. */ 085 public final int stackDepthBeforePop; 086 /** 087 * Character offset of the lookahead token in hand when the reduction 088 * ran, or -1 when the reduction needed no lookahead (a default 089 * reduction). Only reductions taken with a STABLE lookahead — one that 090 * lies before the first hole — may be used as positive evidence. 091 */ 092 public final long lookaheadOffset; 093 094 ProofReduction(int rule, int length, int lhsSymbol, int stackDepthBeforePop, 095 long lookaheadOffset) { 096 this.rule = rule; 097 this.length = length; 098 this.lhsSymbol = lhsSymbol; 099 this.stackDepthBeforePop = stackDepthBeforePop; 100 this.lookaheadOffset = lookaheadOffset; 101 } 102 103 @Override 104 public String toString() { 105 return "rule=" + rule + " len=" + length + " lhs=" + lhsSymbol 106 + " depth=" + stackDepthBeforePop + " lookahead@" + lookaheadOffset; 107 } 108 } 109 110 /** 111 * The automaton's configuration at the proof cutoff: the state stack as it 112 * stood when the parser first needed a token at or beyond the cutoff, plus 113 * every reduction performed before that point. 114 * 115 * <p>The snapshot is taken while the cutoff token has been READ but not yet 116 * shifted, and before any action is looked up for it. So the stack is 117 * exactly "what the literal prefix committed to", with no influence from 118 * the unstable token — which is the whole point. 119 */ 120 public static final class ProofLrConfiguration { 121 /** The state stack, bottom first — a copy of {@code yys[1..yysp]}. */ 122 public final int[] stateStack; 123 /** Character offset of the token the parser stopped before. */ 124 public final long stoppedBeforeOffset; 125 /** Token code of that token. */ 126 public final int stoppedBeforeTokenCode; 127 /** Reductions performed before the cutoff, in order. */ 128 public final java.util.List<ProofReduction> reductions; 129 130 ProofLrConfiguration(int[] stateStack, long stoppedBeforeOffset, 131 int stoppedBeforeTokenCode, java.util.List<ProofReduction> reductions) { 132 this.stateStack = stateStack; 133 this.stoppedBeforeOffset = stoppedBeforeOffset; 134 this.stoppedBeforeTokenCode = stoppedBeforeTokenCode; 135 this.reductions = java.util.Collections.unmodifiableList(reductions); 136 } 137 138 /** Depth of the state stack. */ 139 public int depth() { 140 return stateStack.length; 141 } 142 143 /** The state on top of the stack — the automaton's current state. */ 144 public int topState() { 145 return stateStack.length == 0 ? 0 : stateStack[stateStack.length - 1]; 146 } 147 148 @Override 149 public String toString() { 150 return "ProofLrConfiguration{depth=" + depth() + " top=" + topState() 151 + " stoppedBefore@" + stoppedBeforeOffset 152 + " token=" + stoppedBeforeTokenCode 153 + " reductions=" + reductions.size() + "}"; 154 } 155 } 156 157 /** 158 * Stop the parse before consuming any token at or beyond this character 159 * offset, and record the configuration. Negative (default) disables all 160 * observation. 161 */ 162 long proofLrCutoffOffset = -1; 163 164 /** Populated only when the cutoff was actually reached; null otherwise. */ 165 ProofLrConfiguration proofLrConfiguration; 166 167 /** Reductions seen so far this parse; allocated only when observing. */ 168 private java.util.List<ProofReduction> proofLrReductions; 169 170 /** 171 * Arm the observer. Must be called before {@code yyparse()}. Observation is 172 * read-only: the parse proceeds exactly as it otherwise would, up to the 173 * cutoff, at which point it stops WITHOUT entering error recovery (recovery 174 * unwinds the very stack we are trying to read). 175 */ 176 public void setProofLrCutoffOffset(long offset) { 177 this.proofLrCutoffOffset = offset; 178 this.proofLrConfiguration = null; 179 this.proofLrReductions = offset < 0 ? null : new java.util.ArrayList<ProofReduction>(); 180 } 181 182 /** The configuration captured at the cutoff, or null if it was never reached. */ 183 public ProofLrConfiguration getProofLrConfiguration() { 184 return proofLrConfiguration; 185 } 186 187 EDbVendor dbvendor; 188 TDatabaseYYSType yylval; 189 TDatabaseYYSType[] yyv; // 1 based array 190 int[] yys; // parser state stack, reused across parse calls for performance 191 TDatabaseYYSType yyval = null; 192 193 // the terminal or non-terminal numbers in the right side of a BNF rule, start from 1. 194 // Take this rule for example: 195 // sqlstmts: stmt ';' 196 // stmt is non-terminal, its number is 1, ';' is terminal, its number is 2. 197 // when sqlstmts rule is reduced, the yysp is 2 which means it points to the ';' token. 198 // and if we need to access the stmt node, we can use yyv[yysp-1] to get it. 199 int yysp; 200 201 boolean isbeginofbatch; //used by mssql 202 TSourceTokenList tmp_sourcetokenlist; 203 int tmp_curtokenpos; 204 205 public TSourceTokenList sourcetokenlist; 206 public TNodeFactory nf; 207 public TParseTreeNode rootNode; 208 final int yymaxdepth = 1048; 209 final int _error = 256; 210 final int yyfnone = 0; 211 final int yyfaccept = 1; 212 final int yyfabort = 2; 213 final int yyferror = 3; 214 final int aopAbort = 0; 215 final int aopContinue = 1; 216 final int tsOriginal = 0; 217 final int tsDeleted = 1; 218 final int tsIgnoreByYacc = 2; 219 final int tsMarkDeletedInPPDoWhiteSpace = 3; 220 final int tsAddedInPP = 4; 221 final int tsDeletedInPP = 5; 222 final int tsAlreadlyAddedToList = 6; 223 final int tsSynataxError = 7; 224 final int tsSynataxErrorProcessed = 8; 225 final int tsAddbyHand = 9; 226 final int tsAddedInTokensInScript = 10; 227 //final int tsNotStartTokenOfSQL, 228 final int tsIgnoredByGetRawStatement = 11; 229 final int tsDummyStatus = 12; 230 231 // Vendor-specific SQL command resolver (injected by TGSqlParser) 232 public gudusoft.gsqlparser.sqlcmds.ISqlCmds sqlcmds; 233 public TCustomLexer lexer; 234 235 TParseTreeNode tmpnode,tmpnode1,tmpnode2,tmpnode3,tmpnode4; 236 237 int yyflag;// yyfnone,yyfaccept,yyfabort ,yyferror 238 int nextstmtstartpos , curtokenpos,stmtendpos; 239 TSourceToken acceptedtoken,currentsourcetoken,recovertoken,errorstmtstarttoken; 240 int currentyystate,currentyysp,currentyyn; 241 int[] retvalue = {0}; // used when need to pass VAR variable to a function, return value by this variable 242 public TCustomSqlStatement sql; 243 244 public TNodeFactory getNf() { 245 return nf; 246 } 247 248 private TCustomParser(){ 249 curtokenpos = 0; 250 yylval = new TDatabaseYYSType(); 251 yyv = new TDatabaseYYSType[yymaxdepth + 1]; //1 based 252 yys = new int[yymaxdepth + 1]; // 1 based, reused across parse calls 253 yyval = null; 254 // sqlcmds will be injected by TGSqlParser based on vendor 255 } 256 257 TCustomParser(EDbVendor pDbVendor){ 258 this(); 259 this.dbvendor = pDbVendor; 260 nf = new TNodeFactory(this.dbvendor); 261 } 262 263 TParseTreeNodeList yacclcons(Object obj, TParseTreeNodeList parseTreeNodeList,boolean IsParse){ 264 return null; 265 } 266 267 TParseTreeNodeList yaccmakeList1(Object x1,boolean IsParse){ 268 return null; 269 } 270 271 TParseTreeNodeList yaccmakeList2(Object x1,Object x2,boolean IsParse){ 272 return null; 273 } 274 275 TParseTreeNodeList yaccnconc(TParseTreeNodeList l1, TParseTreeNodeList l2){ 276 return null; 277 } 278 TParseTreeNodeList yacclappend(TParseTreeNodeList parseTreeNodeList,Object obj,boolean IsParse){ 279 return null; 280 } 281 int yylexwrap(boolean isignore){ 282 int ret = 0; 283 if (sourcetokenlist == null) return ret; 284 TSourceToken ast = getasourcetoken(isignore); 285 if (ast == null ) return ret; 286 if (ast.tokencode == 0) return ret; 287 yylval.yyTSourceToken = ast; 288 289 if ((yylval.yyTSourceToken.tokencode == TBaseType.bind_v) 290 && (dbvendor == EDbVendor.dbvmysql)) 291 { 292 yylval.yyTSourceToken.tokencode = TBaseType.ident; 293 //yylval.yyTSourceToken.nodetype := T_BindV; 294 } 295 if (dbvendor == EDbVendor.dbvoracle){ 296 yylval.yyTSourceToken.tag = 0; 297 } 298 //System.out.println(yylval.yyTSourceToken.toString()); 299 return yylval.yyTSourceToken.tokencode; 300 } 301 302 TSourceToken read_to_next_parentheses(boolean isIncluding){ 303 return read_to_next_parentheses(isIncluding, new TDummy()); 304 } 305 306 TSourceToken read_to_next_parentheses(boolean isIncluding, TParseTreeNode ownerNode){ 307 int nested = 0; 308 int yychar = -1; 309 310 TSourceToken ret = null,prevSt = null; 311 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 (yylval.yyTSourceToken.tokentype == ETokenType.ttleftparenthesis) 319 {nested++;} 320 321 if (yylval.yyTSourceToken.tokentype == ETokenType.ttrightparenthesis) 322 {nested--;} 323 324 if (prevSt == null){ 325 ownerNode.setStartToken(yylval.yyTSourceToken); 326 } 327 328 if (nested < 0) 329 { 330 //curtokenpos--; //rollback ')' 331 if (isIncluding) { 332 stmtendpos = curtokenpos;// - 1; 333 ret = yylval.yyTSourceToken; 334 ownerNode.setEndToken(ret); 335 }else{ 336 curtokenpos--; 337 stmtendpos = curtokenpos;// - 1; 338 ret = prevSt; 339 ownerNode.setEndToken(ret); 340 } 341 break; // end of this node 342 } 343 344 ret = yylval.yyTSourceToken; 345 346 if (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 347 { 348 ownerNode.setEndToken(ret); 349 break; 350 } 351 352 prevSt = yylval.yyTSourceToken; 353 } // while 354 355 return ret; 356 357 } 358 359 TSourceToken read_before_subquery(){ 360 int yychar = -1; 361 TSourceToken ret = null; 362 363 while (true){ 364 yychar = yylexwrap(false);//yyLexer.yylexwrap; 365 if (yychar<0) {yychar = 0;} 366 if (yychar == 0) { return ret;} 367 368 if (yylval.yyTSourceToken.tokencode == TBaseType.rrw_as) 369 { 370 TSourceToken next = yylval.yyTSourceToken.nextSolidToken(); 371 if (next != null){ 372 if ((next.tokencode == TBaseType.rrw_select)||(next.tokencode == TBaseType.rrw_with)){ 373 curtokenpos--; 374 break; 375 } 376 } 377 } 378 379 ret = yylval.yyTSourceToken; 380 if (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 381 { 382 break; 383 } 384 } // while 385 386 return ret; 387 388 } 389 390 TokenAndText read_consume_valid_filename_token(boolean removeTokenBeforeWhitespace) { 391 int yychar = -1; 392 String ret = ""; 393 TSourceToken lastToken = null; 394 395 while (true) { 396 yychar = yylexwrap(false); // yyLexer.yylexwrap; 397 if (yychar < 0) { 398 yychar = 0; 399 } 400 if (yychar == 0) { 401 return new TokenAndText(lastToken, ret); 402 } 403 404 if ((yylval.yyTSourceToken.tokentype == ETokenType.ttwhitespace) 405 || (yylval.yyTSourceToken.tokentype == ETokenType.ttreturn) 406 || (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 407 || (yylval.yyTSourceToken.tokencode == ')') 408 || (yylval.yyTSourceToken.tokencode == '(') 409 ) { 410 curtokenpos--; // rollback to ensure the token is not consumed 411 break; 412 } 413 414 415 ret = ret + yylval.yyTSourceToken.toString(); 416 lastToken = yylval.yyTSourceToken; 417 if (removeTokenBeforeWhitespace) { 418 yylval.yyTSourceToken.tokenstatus = ETokenStatus.tsdeleted; 419 } 420 } 421 return new TokenAndText(lastToken, ret); 422 } 423 424 TSourceToken read_before_this_token(int[] pTokenCodes){ 425 int yychar = -1; 426 TSourceToken ret = null; 427 boolean found = false; 428 429 while (true){ 430 yychar = yylexwrap(false);//yyLexer.yylexwrap; 431 if (yychar<0) {yychar = 0;} 432 if (yychar == 0) { return ret;} 433 434 for(int k=0;k<pTokenCodes.length;k++){ 435 if (yylval.yyTSourceToken.tokencode == pTokenCodes[k]) 436 { 437 found = true; 438 curtokenpos--; 439 break; 440 } 441 } 442 if (found) break; 443 ret = yylval.yyTSourceToken; 444 if (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 445 { 446 break; 447 } 448 } // while 449 450 return ret; 451 } 452 453 TSourceToken read_before_this_token(int pTokenCode){ 454 return read_before_this_token(new int[] {pTokenCode}); 455 } 456 457 TSourceToken read_to_semicolon(){ 458 return read_to_semicolon(new TDummy(),true); 459 } 460 461 TSourceToken read_to_semicolon(boolean includeSemicolon){ 462 return read_to_semicolon(new TDummy(),includeSemicolon); 463 } 464 465 TSourceToken read_to_semicolon(TParseTreeNode ownerNode){ 466 return read_to_semicolon(ownerNode,true); 467 } 468 469 TSourceToken read_to_semicolon(TParseTreeNode ownerNode,boolean includeSemicolon){ 470 471 int yychar = -1; 472 473 TSourceToken ret = null; 474 475 while (true){ 476 yychar = yylexwrap(false);//yyLexer.yylexwrap; 477 if (yychar<0) {yychar = 0;} 478 if (yychar == 0) { return ret;} 479 480 if ((ret == null)&&(ownerNode.getStartToken() == null)){ 481 ownerNode.setStartToken(yylval.yyTSourceToken); 482 } 483 ret = yylval.yyTSourceToken; 484 485 if (yylval.yyTSourceToken.tokentype == ETokenType.ttsemicolon) 486 { 487 break; 488 } 489 } // while 490 if (ret.tokentype == ETokenType.ttsemicolon){ 491 ownerNode.setEndToken(ret.getPrevTokenInChain()); 492 if (!includeSemicolon){ 493 curtokenpos -- ; 494 } 495 }else{ 496 ownerNode.setEndToken(ret); 497 } 498 499 return ret; 500 501 } 502 503 TSourceToken read_a_token( ){ 504 505 int yychar = -1; 506 507 TSourceToken ret = null; 508 yychar = yylexwrap(false); 509 ret = yylval.yyTSourceToken; 510 511 return ret; 512 513 } 514 515 516 TSourceToken read_to_this_token( int tokenCode){ 517 518 int yychar = -1; 519 520 TSourceToken ret = null; 521 522 while (true){ 523 yychar = yylexwrap(false);//yyLexer.yylexwrap; 524 if (yychar<0) {yychar = 0;} 525 if (yychar == 0) { return ret;} 526 527 ret = yylval.yyTSourceToken; 528 529 if (yylval.yyTSourceToken.tokencode == tokenCode) 530 { 531 break; 532 } 533 } // while 534 535 return ret; 536 537 } 538 539 /** 540 * Read tokens until we encounter double closing braces }} 541 * Used for MLE JavaScript code blocks: AS MLE LANGUAGE JAVASCRIPT {{ ... }} 542 */ 543 TSourceToken read_to_double_close_brace(){ 544 int yychar = -1; 545 TSourceToken ret = null; 546 TSourceToken prevToken = null; 547 548 while (true){ 549 yychar = yylexwrap(false); 550 if (yychar < 0) {yychar = 0;} 551 if (yychar == 0) { return ret;} 552 553 ret = yylval.yyTSourceToken; 554 555 // Check if we have }} (two consecutive closing braces) 556 if (prevToken != null && 557 prevToken.tokencode == '}' && 558 ret.tokencode == '}') { 559 break; 560 } 561 562 prevToken = ret; 563 } 564 565 return ret; 566 } 567 568 TSourceToken getasourcetoken(boolean isignore){ 569 TSourceToken newst = null; 570 int j; 571 if (sourcetokenlist == null) return null; 572 573 if (curtokenpos > sourcetokenlist.size() - 1) return null; 574 for (j = curtokenpos; j < sourcetokenlist.size();j++) 575 { 576 newst = sourcetokenlist.get(j); 577 if ((newst.tokencode == TBaseType.lexspace) && isignore) continue; 578 if ((newst.tokencode == TBaseType.lexnewline) && isignore) continue; 579 if ((newst.tokencode == TBaseType.cmtdoublehyphen) && isignore) continue; 580 if ((newst.tokencode == TBaseType.cmtslashstar) && isignore) continue; 581 if ((newst.tokenstatus == ETokenStatus.tsignorebyyacc)) continue; 582 583 if (newst.tokenstatus != ETokenStatus.tsdeleted) break; 584 } 585 if (j == sourcetokenlist.size()) return null; 586 else 587 curtokenpos = curtokenpos + (j-curtokenpos+1); 588 589 // System.out.println("curtokenpos:"+curtokenpos+" "+newst); 590 591// pstr := ''; 592// asqlstatement := TCustomSqlStatement(sqlstatement); 593// 594// //check bind variable 595// // if (newst.TokenType = ttBindVar) and (dbvendor <> dbvmssql) and (newst.TokenStatus <> tsDeleted) then 596// if (newst.TokenType = ttBindVar) and (newst.TokenStatus <> tsDeleted) then 597// begin 598// if assigned(onBindVar) then 599// begin 600// onBindVar(self,copy(newst.SourceCode,2,length(newst.SourceCode)-1),pstr); 601// end; 602// // newst.TokenType := ttIdentifier; 603// if assigned(asqlstatement) then 604// begin 605// lcValue := TLzValue.create(asqlstatement); 606// lcValue.ValueName := copy(newst.SourceCode,2,length(newst.SourceCode)-1); 607// lcValue.ValueStr := pstr; 608// lcValue.SourceToken := newst; 609// asqlstatement.params.add(lcValue); 610// end; 611// if length(pstr) <> 0 then 612// newst.SourceCode := pstr; 613// end; 614 615// //check variable 616// // if (newst.TokenType = ttSqlVar) and (dbvendor <> dbvmssql) and (newst.TokenStatus <> tsDeleted) then 617// if (newst.TokenType = ttSqlVar) and (newst.TokenStatus <> tsDeleted) then 618// begin 619// if assigned(onSqlVar) then 620// begin 621// onSqlVar(self,copy(newst.SourceCode,2,length(newst.SourceCode)-1),pstr); 622// end; 623// if dbvendor <> dbvmssql then 624// newst.TokenType := ttIdentifier; 625// if assigned(asqlstatement) then 626// begin 627// lcValue := TLzValue.create(asqlstatement); 628// lcValue.ValueName := copy(newst.SourceCode,2,length(newst.SourceCode)-1); 629// lcValue.ValueStr := pstr; 630// lcValue.SourceToken := newst; 631// asqlstatement.sqlvars.add(lcValue); 632// end; 633// if length(pstr) <> 0 then 634// newst.SourceCode := pstr; 635// end; 636// 637// pstr := ''; 638// 639// try 640// if assigned(OnParserToken) 641// and (newst.CodeSource = csOriginal) 642// and (newst.TokenStatus <> tsDeleted) 643// and (newst.TokenType <> ttBindVar) 644// then OnParserToken(self,newst,Integer(DbVendor)); 645// except 646// // paot := aotNone; 647// end; 648 649// if (newst.tokenstatus = tsDeleted) then 650// begin 651// if assigned(RecoverToken) then 652// begin 653// newst := RecoverToken; 654// RecoverToken := nil; 655// end 656// else 657// newst := GetASourceToken(IsIgnore); 658// end; 659 660 return newst; 661 } 662 663 int dobefore_yyparse(){ 664 int ret = 10000; 665 for (int i=0; i< sourcetokenlist.size();i++) 666 { // if there are no solid tokentext in list, return -1, don't parse anymore 667 if( (sourcetokenlist.get(i).tokentype == ETokenType.ttwhitespace) 668 || (sourcetokenlist.get(i).tokentype == ETokenType.ttreturn) 669 || (sourcetokenlist.get(i).tokencode == TBaseType.cmtdoublehyphen) 670 || (sourcetokenlist.get(i).tokencode == TBaseType.cmtslashstar) ) 671 {continue;} 672 else 673 { 674 ret = 0; 675 break; 676 } 677 } 678 679 return ret; 680 681 } 682 683 //spFatalError yyparse stack overflow error 1010 ,CurrentSourceToken.lines,CurrentSourceToken.columns 684 void onparseerrorhandle(EErrorType errortype,String pmsg,String token,long xposition,long yposition, int errorno){ 685 if (sql != null){ 686 sql.parseerrormessagehandle( new TSyntaxError(token,xposition,yposition,pmsg,errortype,errorno,null,-1)); 687 }else{ 688 System.out.println(pmsg); 689 } 690 } 691 692 boolean yyact(int state,int sym,int[] act){ 693 return false; 694 } 695 696 boolean yygoto(int state, int sym,int[] nstate){ 697 return false; 698 } 699 700 /** 701 * according to the input state and sym, get the new state from the goto table 702 * return false if no state found (this will cause a parse error), otherwise return true, and the new state is stored in nstate[0] 703 * 704 * if method is called when a reduce action is performed. 705 * 706 * @param state 707 * @param sym 708 * @param nstate 709 * @param p_yygl 710 * @param p_yygh 711 * @param p_yyg_sym 712 * @param p_yyg_act 713 * @return 714 */ 715 boolean yygoto(int state, int sym,int[] nstate, int[] p_yygl, int[] p_yygh, int[] p_yyg_sym, int[] p_yyg_act){ 716 boolean r; 717 int k = p_yygl[state]; 718 while ((k<=p_yygh[state]) && (p_yyg_sym[k] != sym)) {k++;} 719 if (k>p_yygh[state]) 720 r = false; 721 else 722 { 723 nstate[0] = p_yyg_act[k]; 724 r = true; 725 } 726 return r; 727 } 728 729 /** 730 * according to the input state and sym, get the action from the action table 731 * return false if no action found (this will cause a parse error), otherwise return true, and the action is stored in act[0] 732 * if act[0] > 0, it means shift, the value is the new state, can be used in yyact() method 733 * if act[0] < 0, it means reduce, the value is the rule number, used in yyaction(-value) method 734 * if act[0] = 0, it means parse completed successfully. 735 * 736 * @param state 737 * @param sym 738 * @param act 739 * @param p_yyal 740 * @param p_yyah 741 * @param p_yya_sym 742 * @param p_yya_act 743 * @return 744 */ 745 boolean yyact(int state,int sym,int[] act, int[] p_yyal, int[] p_yyah, int[] p_yya_sym, int[] p_yya_act){ 746 boolean r; 747 int k = p_yyal[state]; 748 while ((k <= p_yyah[state]) && (p_yya_sym[k] != sym) ) {k++;} 749 if (k>p_yyah[state]) 750 r = false; 751 else { 752 act[0] = p_yya_act[k]; 753 r = true; 754 } 755 return r; 756 } 757 758 public int do_yyparse(int [] p_yyd, 759 int [] p_yyal, int [] p_yyah, int [] p_yya_sym, int[] p_yya_act, 760 int [] p_yygl, int [] p_yygh, int [] p_yyg_sym, int [] p_yyg_act, 761 int [] p_yyr_len,int [] p_yyr_sym, 762 Map<Integer, int[]> p_rollbackTokens 763 ){ 764 int lcprevyysp,lcyystate,lcyyn,yyn=0; 765 // yys array is now an instance field, reused across parse calls for performance 766 TDatabaseYYSType rollback_token = null; 767 int lcAction; 768 boolean lcrollbackstate ; 769 int lcrollbacktokens; 770 771 curtokenpos = 0; 772 int lcRetries = dobefore_yyparse();//super.yyparse(); 773 if (lcRetries == -1) 774 { // no solid tokentext in tokentext list 775 return 0; 776 } 777 778 int rollback_mode = 0; 779 int yystate = 0, yychar = -1, yynerrs = 0, yyerrflag = 0; 780 yysp = 0; 781 boolean lcIsError = false; 782 boolean lcIsParse = false; 783 boolean lcIsReduce= false; 784 boolean lcIsShift = false; 785 786 int rollback_state = yystate; 787 int rollback_sp = yysp; 788 789 boolean isBeginOfBatch = true; //used in mssql 790 boolean lccanreduce; // used in mssql 791 792 isbeginofbatch = true; 793 794 while (true){ // the main loop for parsing 795 796 // this is the point where parse started: 797 798 yysp++; 799 if (yysp > yymaxdepth) 800 { 801 // yyerror('yyparse stack overflow'); 802 onparseerrorhandle(EErrorType.spfatalerror, "yyparse stack overflow error 1010" , currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10010); 803 //goto abort; 804// if (dbvendor == EDbVendor.dbvmssql){ 805// onparseerrorhandle(EErrorType.spfatalabort,"abort !!! error 1001",currentsourcetoken.astext ,currentsourcetoken.lineNo,currentsourcetoken.columnNo,10011); 806// } 807 808 return 10001; 809 } 810 811 yys[yysp] = yystate; 812 yyv[yysp] = yyval; 813 814 while (true){ 815 // this is the point where NEXT is started: 816 // get next symbol 817 818 if( (p_yyd[yystate] == 0) && (yychar == -1)) 819 //(* get next symbol *) 820 { 821 do{ 822 yychar = yylexwrap(true);//yyLexer.yylexwrap; 823 if (yychar<0) { yychar = 0;} 824 // ignore comments and blanks [ \n\t] 825 //if not( (yychar=_COMMENT) or (yychar=_BLANK) or 826 // (yychar=_TAB) or (yychar=_NEWLINE) ) then break; 827 if (!( (yychar== TBaseType.cmtdoublehyphen)|| (yychar== TBaseType.cmtslashstar) || 828 (yychar== TBaseType.lexspace) || (yychar== TBaseType.lexnewline) || (yychar== TBaseType.sqlpluscmd) )) 829 { 830 if (yychar == 0) 831 { 832 //System.out.println("error tokentext:"+yylval.yyTSourceToken+"c "+currentsourcetoken); 833 if ( ( sourcetokenlist.get(sourcetokenlist.size() - 1)).tokencode != 0) 834 { 835 //System.out.println("yychar is 0, but tokencode is:"+ ( sourcetokenlist.get(sourcetokenlist.size() - 1)).tokencode); 836 yylval.yyTSourceToken = new TSourceToken(" "); 837 // NewSourceToken(yylval.yyTSourceToken,'',ttUnknown,wtNotAWord,eNotAComment,-1,-1); 838 yylval.yyTSourceToken.container = sourcetokenlist; 839 yylval.yyTSourceToken.tokencode = 0; 840 //sourcetokenlist.add(yylval.yyTSourceToken); 841 yylval.yyTSourceToken.posinlist = sourcetokenlist.size() - 1; 842 curtokenpos = sourcetokenlist.size(); 843 //showmessage('end of input'); 844 } 845 else 846 { 847 yylval.yyTSourceToken = sourcetokenlist.get(sourcetokenlist.size() - 1); 848 // showmessage('end of input again'); 849 } 850 } 851 852 currentsourcetoken = yylval.yyTSourceToken; 853 break; 854 } 855 else 856 { 857 //ignore non solid tokentext 858 } 859 860 } while (true); 861 862 // Proof-mode cutoff (design R4 commitment check). The token 863 // has been READ but not shifted, and no action has been 864 // looked up for it yet, so the stack here is exactly what 865 // the literal prefix committed to — uncontaminated by the 866 // unstable token. Stop by RETURNING rather than by falling 867 // into error handling: MSSQL recovery pops the stack looking 868 // for a state that shifts `error`, destroying the snapshot. 869 if (proofLrCutoffOffset >= 0 && proofLrConfiguration == null 870 && currentsourcetoken != null 871 && currentsourcetoken.offset >= proofLrCutoffOffset) 872 { 873 int[] stackCopy = new int[yysp]; 874 for (int i = 1; i <= yysp; i++) 875 { 876 stackCopy[i - 1] = yys[i]; 877 } 878 proofLrConfiguration = new ProofLrConfiguration(stackCopy, 879 currentsourcetoken.offset, yychar, proofLrReductions); 880 return PROOF_LR_STOPPED_AT_CUTOFF; 881 } 882 } //(* get next symbol *) 883 884 if (!lcIsError) 885 { 886 yyn = p_yyd[yystate]; 887 if (yyn != 0) 888 { 889 //goto reduce; (* simple state *) 890 lcIsReduce = true; 891 break; 892 } 893 894 // (* no default action; search parse table *) 895 boolean foundAction = yyact(yystate, yychar, retvalue,p_yyal,p_yyah,p_yya_sym,p_yya_act); 896 if(foundAction) {yyn = retvalue[0];} 897 if (! foundAction) 898 { // no action found, here we do error handling 899 // Proof-mode observability (DynamicSqlProofHarness): every 900 // entry into error handling — keyword rollback included — 901 // is a recovery event. A parse that needed ANY recovery is 902 // not evidence for the dynamic-SQL publication proof, even 903 // when the rollback silently succeeds. 904 proofRecoveryEvents++; 905 // lcRestartPos := curtokenpos; 906 907 lcAction = aopAbort; 908 lcrollbackstate = false; 909 lcrollbacktokens = 0; 910 911 //if parse error occurs due to a keyword, then change this keyword to identifier 912 // and retry again, 913 // for example 914 915 // select a.wait from b 916 // wait is a keyword, can not be field name due to .y file, 917 // but it's a legal in mssql, use this procedure while during parsing, 918 // we can fix such problem which is very common 919 // we don't recover from FROM keyword 920 921 if ((yylval.yyTSourceToken.tokencode >= TBaseType.rrw_select ) 922 && (yylval.yyTSourceToken.tokencode != TBaseType.rrw_from ) 923 && (dbvendor != EDbVendor.dbvmssql?true:(yylval.yyTSourceToken.tokencode != TBaseType.rrw_where )) 924 ) 925 { 926 proofKeywordRollbackEvents++; 927 // 如果一个token有多个侯备的其他token可以尝试,我们逐一尝试,如果没有成功的,将token类型改为ident进行最后尝试,还不成功,则报错。 928 929 int[] rollbackTokens = new int[1]; 930 rollbackTokens[0] = TBaseType.ident; 931 if ((p_rollbackTokens!=null) && (p_rollbackTokens.containsKey(yylval.yyTSourceToken.tokencode))) { 932 rollbackTokens = p_rollbackTokens.get(yylval.yyTSourceToken.tokencode); 933 } 934 935 for(int i=0;i<rollbackTokens.length;i++) 936 { 937 yylval.yyTSourceToken.tokencode = rollbackTokens[i]; 938 if (yyact(yystate, yylval.yyTSourceToken.tokencode, retvalue, p_yyal,p_yyah,p_yya_sym,p_yya_act)) 939 { 940 yyn = retvalue[0]; 941 if (yyn>0) 942 { 943 //goto shift; 944 lcIsShift = true; 945 break; 946 } 947 else if( yyn<0 ) 948 { 949 // goto reduce 950 lcIsReduce = true; 951 break; 952 } 953 else 954 { 955 // goto accept; 956 return 0; 957 } 958 } 959 } 960 961 if (lcIsShift||lcIsReduce) 962 { 963 if (yylval.yyTSourceToken.tokencode == TBaseType.ident){ 964 yylval.yyTSourceToken.tokentype = ETokenType.ttidentifier; 965 } 966 yychar = yylval.yyTSourceToken.tokencode; 967 break; 968 } 969 } 970 971 // end of error recover 972 973 if (lcAction == aopAbort ) 974 { 975 // goto error; 976 lcIsError = true; 977 } 978 } 979 else if (yyn>0) 980 { 981 //goto shift; 982 lcIsShift = true; 983 break; 984 } 985 else if( yyn<0 ) 986 { 987 // goto reduce 988 lcIsReduce = true; 989 break; 990 } 991 else 992 { 993 // goto accept; 994 return 0; 995 } 996 997 } // if not lcIsError 998 999 if (lcIsError) 1000 { 1001 lcIsError = false; 1002 1003 if ((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase)||(dbvendor == EDbVendor.dbvsybasease || dbvendor == EDbVendor.dbvsqlanywhere || dbvendor == EDbVendor.dbvsybaseiq)){ 1004 if (yyerrflag<=2) // (* incomplete recovery; try again *) 1005 { 1006 yyerrflag = 3; 1007 //(* uncover a state with shift action on error tokentext *) 1008 //(* error; start error recovery: *) 1009 1010 1011 lcprevyysp = yysp; 1012 while ((yysp>0) 1013 && !( yyact(yys[yysp], _error, retvalue,p_yyal,p_yyah,p_yya_sym,p_yya_act) 1014 &&( (yyn = retvalue[0]) >0 ) 1015 ) 1016 ) 1017 { 1018 yysp--; 1019 } 1020 1021 if (lcprevyysp != yysp) // if error stmt is just the next state need, then it's a fake error, don't report 1022 geterrormsg(yystate, yychar,10101); 1023 1024 if (yysp==0) 1025 { 1026 //assert(1=2,'Should be an error handle rule in y file, never goes to here!!!'); 1027 onparseerrorhandle(EErrorType.spfatalerror,"error recover failed error", currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10012); 1028 //goto abort; (* parser has fallen from stack; abort *) 1029 1030 onparseerrorhandle(EErrorType.spfatalabort,"abort !!! error 1001", currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10013); 1031 1032 return 10003; 1033 } 1034 1035 1036 errorstmtstarttoken = null; 1037 1038 1039 yystate = yyn; // (* simulate shift on error *) 1040 yychar = -1; 1041 stmtendpos = curtokenpos-1; 1042 1043 //goto parse; 1044 lcIsParse = true; 1045 break; 1046 } 1047 else //(yyerrflag<=2) (* no shift yet; discard symbol *) 1048 { 1049 if (yychar==0) 1050 { 1051 1052 // goto abort; (* end of input; abort *) 1053 onparseerrorhandle(EErrorType.spfatalabort, "abort !!! error 1001", currentsourcetoken.getAstext(),currentsourcetoken.lineNo,currentsourcetoken.columnNo,10013); 1054 1055 return 10004; 1056 } 1057 1058 yychar = -1; 1059 stmtendpos = curtokenpos-1; 1060 sourcetokenlist.get(curtokenpos-1).tokenstatus = ETokenStatus.tssynataxerror; 1061 // showmessage('lookahead:'+inttostr(curtokenpos-1)+'->'+sourcetokenlist[curtokenpos-1].astext+'->yyd[yystate]:'+inttostr(yystate)); 1062 // goto next; (* clear lookahead char and try again *) 1063 continue; 1064 } 1065 1066 }else{ 1067 1068 // Enhanced parser to handle SQL statements that are missing a semicolon at the end. 1069 // 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. 1070 1071 // 如果当前token是0 (end of input),并且可以shift一个分号,则shift一个分号,否则报错 1072 if (yychar == 0 && yyact(yystate, ';', retvalue, p_yyal,p_yyah,p_yya_sym,p_yya_act) && retvalue[0] > 0) { 1073 yyn = retvalue[0]; 1074 lcIsShift = true; 1075 break; 1076 } 1077 geterrormsg(yystate, yychar,10102); 1078 return 10102; 1079 } 1080 1081 }// if lcIsError 1082 1083 } //next 1084 1085 if (lcIsParse) 1086 { 1087 lcIsParse = false; 1088 continue; 1089 } 1090 1091 if (lcIsShift) 1092 { 1093 // this is the point where SHIFT is started: 1094 1095 lcIsShift = false; 1096 //(* go to new state, clear lookahead character: *) 1097 rollback_state = yystate; 1098 rollback_mode = 1; 1099 rollback_sp = yysp; 1100 rollback_token = yyval; 1101 if ((yyerrflag>0) && (yychar != _error ) ) 1102 { 1103 if ((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase)||(dbvendor == EDbVendor.dbvsybasease || dbvendor == EDbVendor.dbvsqlanywhere || dbvendor == EDbVendor.dbvsybaseiq)){ 1104 nextstmtstartpos = curtokenpos - 1; 1105 } 1106 yyerrflag--; 1107 } 1108 yystate = yyn; 1109 yychar = -1; 1110 yyval = new TDatabaseYYSType(); 1111 yyval.copy( yylval); 1112 1113 if (lcRetries > 0) lcRetries--; 1114 1115 if ((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase)||(dbvendor == EDbVendor.dbvsybasease || dbvendor == EDbVendor.dbvsqlanywhere || dbvendor == EDbVendor.dbvsybaseiq)){ 1116 stmtendpos = curtokenpos - 1; // tokentext became part of stmt only after shift 1117 acceptedtoken = currentsourcetoken; 1118 } 1119 1120 // goto parse; 1121 continue; 1122 1123 }//if lcIsShift 1124 1125 if (lcIsReduce) 1126 { 1127 // this is the point where REDUCE is started: 1128 1129 lcIsReduce = false; 1130 1131 //(* execute action, pop rule from stack, and go to next state: *) 1132 // yyval.yyTLz_Parse_Tree_Node := nil; 1133 yyflag = yyfnone; 1134 yyval = new TDatabaseYYSType(); 1135 yyaction(-yyn); 1136 1137 // Proof-mode observation: record the reduction BEFORE the pop, 1138 // so the rule's extent on the stack is still visible. yychar is 1139 // -1 when this is a default reduction, i.e. one the prefix 1140 // determined without any lookahead. 1141 if (proofLrReductions != null && proofLrConfiguration == null) 1142 { 1143 proofLrReductions.add(new ProofReduction(-yyn, p_yyr_len[-yyn], 1144 p_yyr_sym[-yyn], yysp, 1145 (yychar == -1 || currentsourcetoken == null) 1146 ? -1L : currentsourcetoken.offset)); 1147 } 1148 1149 rollback_mode = 2; 1150 yysp = yysp - p_yyr_len[-yyn]; 1151 1152 if (yygoto(yys[yysp], p_yyr_sym[-yyn], retvalue,p_yygl,p_yygh,p_yyg_sym,p_yyg_act)) 1153 { 1154 yyn = retvalue[0]; 1155 yystate = yyn; 1156 } 1157 1158 //(* handle action calls to yyaccept, yyabort and yyerror: *) 1159 // goto parse; 1160 continue; 1161 1162 } //if lcIsReduce 1163 1164 } // parse 1165 1166 } 1167 1168 1169 void geterrormsg(int state, int sym, int errorno){ 1170 if (sql != null){ 1171 String s; 1172 if (sym == 0){ 1173 s = "end of input, state:"+state; 1174 }else{ 1175 s = "syntax error, state:"+state; 1176 } 1177 //System.out.println(currentsourcetoken); 1178// if (currentsourcetoken != null){ 1179// s = s+"toke code:"+currentsourcetoken.tokencode+" ,token type:"+currentsourcetoken.tokentype; 1180// } 1181 1182 sql.parseerrormessagehandle(new TSyntaxError(currentsourcetoken,s, EErrorType.spfatalerror,errorno,null)); 1183 1184 1185 1186 }else 1187 System.out.println("syntax error 10033,state:"+state); 1188 1189 } 1190 1191 1192 1193 void yyaction (int yyruleno){ 1194 1195 } 1196 1197public int yyparse(){ 1198 return -1; 1199} 1200 1201} 1202 1203class TDatabaseYYSType { 1204 String yylzString; 1205 TSourceToken yyTSourceToken; 1206 TParseTreeNodeList yyTParseTreeNodeList; 1207 TParseTreeNode yyTParseTreeNode; 1208 TSourceTokenList yyTSourceTokenList; 1209 ArrayList yyArrayList; 1210 // TStatementList yyTStatementList; 1211 1212 public void copy(TDatabaseYYSType p){ 1213 yyTSourceToken = p.yyTSourceToken; 1214 yyTParseTreeNodeList = p.yyTParseTreeNodeList; 1215 yyTParseTreeNode = p.yyTParseTreeNode; 1216 yyTSourceTokenList = p.yyTSourceTokenList; 1217 yyArrayList = p.yyArrayList; 1218 } 1219} 1220 1221class TokenAndText{ 1222 public TSourceToken lastToken; 1223 public String text; 1224 1225 public TokenAndText(TSourceToken lastToken, String text) { 1226 this.lastToken = lastToken; 1227 this.text = text; 1228 } 1229} 1230