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