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