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