5848e7d13e1932065d67eade1efc736eff5ef273
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPParser.java
1 package net.sourceforge.phpeclipse.phpeditor;
2
3 import java.util.HashMap;
4
5 import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
6
7 /**********************************************************************
8 Copyright (c) 2000, 2002 IBM Corp. and others.
9 All rights reserved. This program and the accompanying materials
10 are made available under the terms of the Common Public License v1.0
11 which accompanies this distribution, and is available at
12 http://www.eclipse.org/legal/cpl-v10.html
13
14 Contributors:
15     IBM Corporation - Initial implementation
16     Klaus Hartlage - www.eclipseproject.de
17 **********************************************************************/
18
19 public class PHPParser extends PHPKeywords {
20
21   private static HashMap keywordMap = null;
22   private String str;
23
24   // current character
25   char ch;
26   // current token
27   int token;
28
29   // row counter for syntax errors:
30   int rowCount;
31   // column counter for syntax errors:
32   int columnCount;
33
34   int chIndx;
35
36   // current identifier
37   String identifier;
38
39   Long longNumber;
40   Double doubleNumber;
41
42   final static int TT_EOF = 0;
43   final static int TT_UNDEFINED = 1;
44
45   final static int TT_MOD = 30;
46   final static int TT_NOT = 31;
47   final static int TT_DOT = 32;
48   final static int TT_POW = 33;
49   final static int TT_DIV = 34;
50   final static int TT_MULTIPLY = 35;
51   final static int TT_SUBTRACT = 36;
52   final static int TT_ADD = 37;
53   final static int TT_EQUAL = 38;
54   final static int TT_UNEQUAL = 39;
55   final static int TT_GREATER = 40;
56   final static int TT_GREATEREQUAL = 41;
57   final static int TT_LESS = 42;
58   final static int TT_LESSEQUAL = 43;
59   final static int TT_AND = 44;
60   final static int TT_OR = 45;
61   final static int TT_HASH = 46;
62   final static int TT_DDOT = 47;
63   final static int TT_DOTASSIGN = 48;
64
65   final static int TT_SET = 49;
66   final static int TT_REF = 50;
67   final static int TT_FOREACH = 51;
68   final static int TT_AMPERSAND = 52;
69   final static int TT_DOLLARLISTOPEN = 53;
70   final static int TT_TILDE = 54;
71
72   final static int TT_ARGOPEN = 128;
73   final static int TT_ARGCLOSE = 129;
74   final static int TT_LISTOPEN = 130;
75   final static int TT_LISTCLOSE = 131;
76   final static int TT_PARTOPEN = 132;
77   final static int TT_PARTCLOSE = 133;
78   final static int TT_COMMA = 134;
79
80   final static int TT_STRING = 136;
81   final static int TT_IDENTIFIER = 138;
82   final static int TT_DIGIT = 139;
83   final static int TT_SEMICOLON = 140;
84   final static int TT_SLOT = 141;
85   final static int TT_SLOTSEQUENCE = 142;
86   final static int TT_DECREMENT = 144;
87   final static int TT_INCREMENT = 145;
88   final static int TT_ADDTO = 146;
89   final static int TT_DIVIDEBY = 147;
90   final static int TT_SUBTRACTFROM = 148;
91   final static int TT_TIMESBY = 149;
92   final static int TT_VARIABLE = 150;
93   final static int TT_INT_NUMBER = 151;
94   final static int TT_DOUBLE_NUMBER = 152;
95   final static int TT_INTERPOLATED_STRING = 153;
96   final static int TT_STRING_CONSTANT = 154;
97
98   final static int TT_LSHIFT = 155;
99   final static int TT_RSHIFT = 156;
100   final static int TT_EX_EQUAL = 157;
101   final static int TT_EX_UNEQUAL = 158;
102   final static int TT_LINE = 159;
103   //  final static int TT_AT = 153; // @
104   /**
105    *  Class Constructor.
106    *
107    *@param  s
108    *@param  sess  Description of Parameter
109    *@see
110    */
111   public PHPParser() {
112     if (keywordMap == null) {
113       keywordMap = new HashMap();
114       for (int i = 0; i < PHP_KEYWORS.length; i++) {
115         keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
116       }
117     }
118     this.str = "";
119     this.token = TT_EOF;
120     this.chIndx = 0;
121     this.rowCount = 1;
122     this.columnCount = 0;
123
124     getNextToken();
125   }
126
127   private void throwSyntaxError(String error) {
128
129     if (str.length() < chIndx) {
130       chIndx--;
131     }
132     // read until end-of-line
133     int eol = chIndx;
134     while (str.length() > eol) {
135       ch = str.charAt(eol++);
136       if (ch == '\n') {
137         eol--;
138         break;
139       }
140     }
141     throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
142   }
143
144   /**
145    *  Method Declaration.
146    *
147    *@see
148    */
149   void getChar() {
150     if (str.length() > chIndx) {
151       ch = str.charAt(chIndx++);
152
153       return;
154     }
155
156     chIndx = str.length() + 1;
157     ch = ' ';
158     token = TT_EOF;
159   }
160
161   /**
162    * gets the next token from input
163    */
164   void getNextToken() {
165     while (str.length() > chIndx) {
166       ch = str.charAt(chIndx++);
167       token = TT_UNDEFINED;
168       if (ch == '\n') {
169         rowCount++;
170         columnCount = chIndx;
171         continue; // while loop
172       }
173
174       if (!Character.isWhitespace(ch)) {
175         if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$') || (ch == '@')) {
176           getIdentifier();
177           return;
178         }
179         if (ch >= '0' && ch <= '9') {
180           getNumber();
181           return;
182         }
183         if (ch == '/') {
184           if (str.length() > chIndx) {
185             if (str.charAt(chIndx) == '/') {
186               chIndx++;
187               // read comment until end of line:
188               while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
189                 chIndx++;
190               }
191               continue;
192             } else if (str.charAt(chIndx) == '*') {
193               chIndx++;
194               // multi line comment:
195               while (str.length() > chIndx) {
196                 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
197                   chIndx += 2;
198                   break;
199                 }
200                 chIndx++;
201               }
202               continue;
203             }
204           }
205         } else if (ch == '#') {
206           // read comment until end of line:
207           while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
208             chIndx++;
209           }
210           continue;
211         } else if (ch == '"') {
212           // read string until end
213           boolean openString = true;
214           while (str.length() > chIndx) {
215             ch = str.charAt(chIndx++);
216             if (ch == '\\') {
217               if (str.length() > chIndx) {
218                 ch = str.charAt(chIndx++);
219               }
220             } else if (ch == '"') {
221               openString = false;
222               break;
223             } else {
224               if (ch == '\n') {
225                 rowCount++;
226                 columnCount = chIndx;
227               }
228             }
229           }
230           if (openString) {
231             throwSyntaxError("Open string character '\"' at end of file.");
232           }
233           token = TT_INTERPOLATED_STRING;
234           return;
235         } else if (ch == '\'') {
236           // read string until end
237           boolean openString = true;
238           while (str.length() > chIndx) {
239             ch = str.charAt(chIndx++);
240             if (ch == '\\') {
241               if (str.length() > chIndx) {
242                 ch = str.charAt(chIndx++);
243               }
244             } else if (ch == '\'') {
245               openString = false;
246               break;
247             } else {
248               if (ch == '\n') {
249                 rowCount++;
250                 columnCount = chIndx;
251               }
252             }
253           }
254           if (openString) {
255             throwSyntaxError("Open string character \"'\" at end of file.");
256           }
257           token = TT_STRING_CONSTANT;
258           return;
259         }
260
261         switch (ch) {
262
263           case '(' :
264             token = TT_ARGOPEN;
265
266             break;
267           case ')' :
268             token = TT_ARGCLOSE;
269
270             break;
271           case '{' :
272             token = TT_LISTOPEN;
273
274             break;
275           case '}' :
276             token = TT_LISTCLOSE;
277
278             break;
279           case '[' :
280             token = TT_PARTOPEN;
281
282             break;
283           case ']' :
284             token = TT_PARTCLOSE;
285
286             break;
287           case ',' :
288             token = TT_COMMA;
289
290             break;
291           case '~' :
292             token = TT_TILDE;
293
294             break;
295           case '.' :
296             token = TT_DOT;
297             if (str.length() > chIndx) {
298               if (str.charAt(chIndx) == '=') {
299                 chIndx++;
300                 token = TT_DOTASSIGN;
301
302                 break;
303               }
304             }
305
306             break;
307           case '"' :
308             token = TT_STRING;
309
310             break;
311           case '%' :
312             token = TT_MOD;
313
314             break;
315           case ';' :
316             token = TT_SEMICOLON;
317
318             break;
319           case '^' :
320             token = TT_POW;
321
322             break;
323           case '/' :
324             token = TT_DIV;
325
326             if (str.length() > chIndx) {
327               if (str.charAt(chIndx) == '=') {
328                 chIndx++;
329                 token = TT_DIVIDEBY;
330
331                 break;
332               }
333             }
334
335             break;
336           case '*' :
337             token = TT_MULTIPLY;
338             if (str.length() > chIndx) {
339               if (str.charAt(chIndx) == '*') {
340                 chIndx++;
341                 token = TT_POW;
342
343                 break;
344               }
345               if (str.charAt(chIndx) == '=') {
346                 chIndx++;
347                 token = TT_TIMESBY;
348
349                 break;
350               }
351             }
352
353             break;
354           case '+' :
355             token = TT_ADD;
356             if (str.length() > chIndx) {
357               if (str.charAt(chIndx) == '+') {
358                 chIndx++;
359                 token = TT_INCREMENT;
360
361                 break;
362               }
363               if (str.charAt(chIndx) == '=') {
364                 chIndx++;
365                 token = TT_ADDTO;
366
367                 break;
368               }
369             }
370             break;
371           case '-' :
372             token = TT_SUBTRACT;
373             if (str.length() > chIndx) {
374               if (str.charAt(chIndx) == '-') {
375                 chIndx++;
376                 token = TT_DECREMENT;
377
378                 break;
379               }
380               if (str.charAt(chIndx) == '=') {
381                 chIndx++;
382                 token = TT_SUBTRACTFROM;
383
384                 break;
385               }
386               if (str.charAt(chIndx) == '>') {
387                 chIndx++;
388                 token = TT_REF;
389
390                 break;
391               }
392             }
393
394             break;
395           case '=' :
396             token = TT_SET;
397
398             if (str.length() > chIndx) {
399               ch = str.charAt(chIndx);
400
401               if (ch == '=') {
402                 chIndx++;
403                 token = TT_EQUAL;
404                 if (str.length() > chIndx) {
405                   ch = str.charAt(chIndx);
406
407                   if (ch == '=') {
408                     chIndx++;
409                     token = TT_EX_EQUAL;
410                   }
411                 }
412                 break;
413               }
414               if (ch == '>') {
415                 chIndx++;
416                 token = TT_FOREACH;
417
418                 break;
419               }
420             }
421
422             break;
423           case '!' :
424             token = TT_NOT;
425
426             if (str.length() > chIndx) {
427               if (str.charAt(chIndx) == '=') {
428                 chIndx++;
429                 token = TT_UNEQUAL;
430                 if (str.length() > chIndx) {
431                   ch = str.charAt(chIndx);
432
433                   if (ch == '=') {
434                     chIndx++;
435                     token = TT_EX_UNEQUAL;
436                   }
437                 }
438                 break;
439               }
440             }
441
442             break;
443           case '>' :
444             token = TT_GREATER;
445
446             if (str.length() > chIndx) {
447               if (str.charAt(chIndx) == '=') {
448                 chIndx++;
449                 token = TT_GREATEREQUAL;
450
451                 break;
452               }
453               if (str.charAt(chIndx) == '>') {
454                 chIndx++;
455                 token = TT_RSHIFT;
456
457                 break;
458               }
459             }
460
461             break;
462           case '<' :
463             token = TT_LESS;
464
465             if (str.length() > chIndx) {
466               if (str.charAt(chIndx) == '=') {
467                 chIndx++;
468                 token = TT_LESSEQUAL;
469
470                 break;
471               }
472               if (str.charAt(chIndx) == '<') {
473                 chIndx++;
474                 token = TT_LSHIFT;
475
476                 break;
477               }
478             }
479
480             break;
481
482           case '|' :
483             token = TT_LINE;
484
485             if (str.length() > chIndx) {
486               if (str.charAt(chIndx) == '|') {
487                 chIndx++;
488                 token = TT_OR;
489
490                 break;
491               }
492             }
493
494             break;
495           case '&' :
496             if (str.length() > chIndx) {
497               if (str.charAt(chIndx) == '&') {
498                 chIndx++;
499                 token = TT_AND;
500
501                 break;
502               } else {
503                 token = TT_AMPERSAND;
504
505                 break;
506               }
507             }
508
509             break;
510           case ':' :
511             token = TT_DDOT;
512
513             break;
514           case '#' :
515             token = TT_HASH;
516
517             break;
518             //          case '@' :
519             //            token = TT_AT;
520             //
521             //            break;
522           default :
523             throwSyntaxError("unexpected character: '" + ch + "'");
524         }
525
526         if (token == TT_UNDEFINED) {
527           throwSyntaxError("token not found");
528         }
529
530         return;
531       }
532     }
533
534     chIndx = str.length() + 1;
535     ch = ' ';
536     token = TT_EOF;
537   }
538
539   void getIdentifier() {
540     StringBuffer ident = new StringBuffer();
541
542     ident.append(ch);
543     if (ch == '$') {
544       token = TT_VARIABLE;
545     } else {
546       token = TT_IDENTIFIER;
547     }
548     getChar();
549     while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
550       ident.append(ch);
551       getChar();
552     }
553     identifier = ident.toString();
554     chIndx--;
555
556     Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
557     if (i != null) {
558       token = i.intValue();
559     }
560   }
561
562   void getNumber() {
563     StringBuffer inum = new StringBuffer();
564     char dFlag = ' ';
565     int numFormat = 10;
566
567     // save first digit
568     char firstCh = ch;
569     inum.append(ch);
570
571     getChar();
572     // determine number conversions:
573     if (firstCh == '0') {
574       switch (ch) {
575         case 'b' :
576           numFormat = 2;
577           getChar();
578           break;
579         case 'B' :
580           numFormat = 2;
581           getChar();
582           break;
583         case 'o' :
584           numFormat = 8;
585           getChar();
586           break;
587         case 'O' :
588           numFormat = 8;
589           getChar();
590           break;
591         case 'x' :
592           numFormat = 16;
593           getChar();
594           break;
595         case 'X' :
596           numFormat = 16;
597           getChar();
598           break;
599       }
600     }
601
602     if (numFormat == 16) {
603       while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
604         inum.append(ch);
605         getChar();
606       }
607     } else {
608       while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
609         if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
610           if (ch == '.' && dFlag != ' ') {
611             break;
612           }
613           if ((dFlag == 'E') || (dFlag == 'e')) {
614             break;
615           }
616           dFlag = ch;
617           inum.append(ch);
618           getChar();
619           if ((ch == '-') || (ch == '+')) {
620             inum.append(ch);
621             getChar();
622           }
623         } else {
624           inum.append(ch);
625           getChar();
626         }
627       }
628     }
629     chIndx--;
630
631     try {
632       if (dFlag != ' ') {
633         doubleNumber = new Double(inum.toString());
634         token = TT_DOUBLE_NUMBER;
635         return;
636       } else {
637         longNumber = Long.valueOf(inum.toString(), numFormat);
638         token = TT_INT_NUMBER;
639         return;
640       }
641
642     } catch (Throwable e) {
643       throwSyntaxError("Number format error: " + inum.toString());
644     }
645   }
646
647   public void start(String s, int rowCount) throws SyntaxError {
648     // start up
649     this.str = s;
650     this.token = TT_EOF;
651     this.chIndx = 0;
652     this.rowCount = rowCount;
653     this.columnCount = 0;
654     getNextToken();
655
656     statementList();
657     if (token != TT_EOF) {
658       if (token == TT_ARGCLOSE) {
659         throwSyntaxError("too many closing ')'; end-of-file not reached");
660       }
661       if (token == TT_LISTCLOSE) {
662         throwSyntaxError("too many closing '}'; end-of-file not reached");
663       }
664       if (token == TT_PARTCLOSE) {
665         throwSyntaxError("too many closing ']'; end-of-file not reached");
666       }
667
668       if (token == TT_ARGOPEN) {
669         throwSyntaxError("read character '('; end-of-file not reached");
670       }
671       if (token == TT_LISTOPEN) {
672         throwSyntaxError("read character '{';  end-of-file not reached");
673       }
674       if (token == TT_PARTOPEN) {
675         throwSyntaxError("read character '[';  end-of-file not reached");
676       }
677
678       throwSyntaxError("end-of-file not reached");
679     }
680
681   }
682
683   public void statementList() {
684     do {
685       statement();
686       if ((token == TT_LISTCLOSE)
687         || (token == TT_case)
688         || (token == TT_default)
689         || (token == TT_elseif)
690         || (token == TT_endif)
691         || (token == TT_endfor)
692         || (token == TT_endforeach)
693         || (token == TT_endwhile)
694         || (token == TT_endswitch)
695         || (token == TT_EOF)) {
696         return;
697       }
698     } while (true);
699   }
700
701   public void compoundStatement() {
702     // '{' [statement-list] '}'
703     if (token == TT_LISTOPEN) {
704       getNextToken();
705     } else {
706       throwSyntaxError("'{' expected in compound-statement.");
707     }
708     if (token != TT_LISTCLOSE) {
709       statementList();
710     }
711     if (token == TT_LISTCLOSE) {
712       getNextToken();
713     } else {
714       throwSyntaxError("'}' expected in compound-statement.");
715     }
716   }
717
718   public void statement() {
719     if (token > TT_KEYWORD && token != TT_list) {
720       String keyword = identifier;
721       if (token == TT_include || token == TT_include_once) {
722         getNextToken();
723         expression();
724         if (token == TT_SEMICOLON) {
725           getNextToken();
726         } else {
727           throwSyntaxError("';' character after 'include' or 'include_once' expected.");
728         }
729         return;
730       } else if (token == TT_require || token == TT_require_once) {
731         getNextToken();
732         //constant();
733         expression();
734         if (token == TT_SEMICOLON) {
735           getNextToken();
736         } else {
737           throwSyntaxError("';' character after 'require' or 'require_once' expected.");
738         }
739         return;
740       } else if (token == TT_if) {
741         getNextToken();
742         if (token == TT_ARGOPEN) {
743           getNextToken();
744         } else {
745           throwSyntaxError("'(' expected after 'if' keyword.");
746         }
747         expression();
748         if (token == TT_ARGCLOSE) {
749           getNextToken();
750         } else {
751           throwSyntaxError("')' expected after 'if' condition.");
752         }
753         ifStatement();
754         return;
755
756       } else if (token == TT_switch) {
757         getNextToken();
758         if (token == TT_ARGOPEN) {
759           getNextToken();
760         } else {
761           throwSyntaxError("'(' expected after 'switch' keyword.");
762         }
763         expression();
764         if (token == TT_ARGCLOSE) {
765           getNextToken();
766         } else {
767           throwSyntaxError("')' expected after 'switch' condition.");
768         }
769         switchStatement();
770         return;
771       } else if (token == TT_for) {
772         getNextToken();
773         if (token == TT_ARGOPEN) {
774           getNextToken();
775         } else {
776           throwSyntaxError("'(' expected after 'for' keyword.");
777         }
778         if (token == TT_SEMICOLON) {
779           getNextToken();
780         } else {
781           expression();
782           if (token == TT_SEMICOLON) {
783             getNextToken();
784           } else {
785             throwSyntaxError("';' character after 'for' expected.");
786           }
787         }
788         if (token == TT_SEMICOLON) {
789           getNextToken();
790         } else {
791           expression();
792           if (token == TT_SEMICOLON) {
793             getNextToken();
794           } else {
795             throwSyntaxError("';' character after 'for' expected.");
796           }
797         }
798         if (token == TT_ARGCLOSE) {
799           getNextToken();
800         } else {
801           expression();
802           if (token == TT_ARGCLOSE) {
803             getNextToken();
804           } else {
805             throwSyntaxError("')' expected after 'for' condition.");
806           }
807         }
808         forStatement();
809         return;
810       } else if (token == TT_while) {
811         getNextToken();
812         if (token == TT_ARGOPEN) {
813           getNextToken();
814         } else {
815           throwSyntaxError("'(' expected after 'while' keyword.");
816         }
817         expression();
818         if (token == TT_ARGCLOSE) {
819           getNextToken();
820         } else {
821           throwSyntaxError("')' expected after 'while' condition.");
822         }
823         whileStatement();
824         return;
825       } else if (token == TT_foreach) {
826         getNextToken();
827         if (token == TT_ARGOPEN) {
828           getNextToken();
829         } else {
830           throwSyntaxError("'(' expected after 'foreach' keyword.");
831         }
832         expression();
833         if (token == TT_as) {
834           getNextToken();
835         } else {
836           throwSyntaxError("'as' expected after 'foreach' exxpression.");
837         }
838         variable();
839         if (token == TT_FOREACH) {
840           getNextToken();
841           variable();
842         }
843         if (token == TT_ARGCLOSE) {
844           getNextToken();
845         } else {
846           throwSyntaxError("')' expected after 'foreach' expression.");
847         }
848         foreachStatement();
849         return;
850
851       } else if (token == TT_continue || token == TT_break || token == TT_return) {
852         getNextToken();
853         if (token != TT_SEMICOLON) {
854           expression();
855         }
856         if (token == TT_SEMICOLON) {
857           getNextToken();
858         } else {
859           throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
860         }
861         return;
862
863       } else if (token == TT_echo) {
864         getNextToken();
865         expressionList();
866         if (token == TT_SEMICOLON) {
867           getNextToken();
868         } else {
869           throwSyntaxError("';' expected after 'echo' statement.");
870         }
871         return;
872
873       } else if (token == TT_print) {
874         getNextToken();
875         expression();
876         if (token == TT_SEMICOLON) {
877           getNextToken();
878         } else {
879           throwSyntaxError("';' expected after 'print' statement.");
880         }
881         return;
882
883       } else if (token == TT_global || token == TT_static) {
884         getNextToken();
885         variableList();
886         if (token == TT_SEMICOLON) {
887           getNextToken();
888         } else {
889           throwSyntaxError("';' expected after 'global' or 'static' statement.");
890         }
891         return;
892
893       } else if (token == TT_unset) {
894         getNextToken();
895         if (token == TT_ARGOPEN) {
896           getNextToken();
897         } else {
898           throwSyntaxError("'(' expected after 'unset' keyword.");
899         }
900         variableList();
901         if (token == TT_ARGCLOSE) {
902           getNextToken();
903         } else {
904           throwSyntaxError("')' expected after 'unset' statement.");
905         }
906         if (token == TT_SEMICOLON) {
907           getNextToken();
908         } else {
909           throwSyntaxError("';' expected after 'unset' statement.");
910         }
911         return;
912
913       } else if (token == TT_exit || token == TT_die) {
914         getNextToken();
915         if (token != TT_SEMICOLON) {
916           exitStatus();
917         }
918         if (token == TT_SEMICOLON) {
919           getNextToken();
920         } else {
921           throwSyntaxError("';' expected after 'exit' or 'die' statement.");
922         }
923         return;
924
925       } else if (token == TT_define) {
926         getNextToken();
927         if (token == TT_ARGOPEN) {
928           getNextToken();
929         } else {
930           throwSyntaxError("'(' expected after 'define' keyword.");
931         }
932         constant();
933         if (token == TT_COMMA) {
934           getNextToken();
935         } else {
936           throwSyntaxError("',' expected after first 'define' constant.");
937         }
938         constant();
939         if (token == TT_ARGCLOSE) {
940           getNextToken();
941         } else {
942           throwSyntaxError("')' expected after 'define' statement.");
943         }
944         if (token == TT_SEMICOLON) {
945           getNextToken();
946         } else {
947           throwSyntaxError("';' expected after 'define' statement.");
948         }
949         return;
950       } else if (token == TT_function) {
951         getNextToken();
952         functionDefinition();
953         return;
954       } else {
955         throwSyntaxError("Unexpected keyword '" + keyword + "'");
956       }
957
958     } else if (token == TT_LISTOPEN) {
959       // compundStatement
960       getNextToken();
961       if (token != TT_LISTCLOSE) {
962         statementList();
963       }
964       if (token == TT_LISTCLOSE) {
965         getNextToken();
966         return;
967       } else {
968         throwSyntaxError("'}' expected.");
969       }
970     } else {
971       if (token != TT_SEMICOLON) {
972         expression();
973       }
974       if (token == TT_SEMICOLON) {
975         getNextToken();
976         return;
977       } else {
978         throwSyntaxError("';' expected after expression.");
979       }
980     }
981
982   }
983
984   public void functionDefinition() {
985     functionDeclarator();
986     compoundStatement();
987   }
988
989   public void functionDeclarator() {
990     //identifier '(' [parameter-list] ')'
991     if (token == TT_IDENTIFIER) {
992       getNextToken();
993       if (token == TT_ARGOPEN) {
994         getNextToken();
995       } else {
996         throwSyntaxError("'(' expected in function declaration.");
997       }
998       if (token != TT_ARGCLOSE) {
999         parameterList();
1000       }
1001       if (token != TT_ARGCLOSE) {
1002         throwSyntaxError("')' expected in function declaration.");
1003       } else {
1004         getNextToken();
1005       }
1006     }
1007   }
1008   //
1009   public void parameterList() {
1010     //parameter-declaration
1011     //parameter-list ',' parameter-declaration
1012     do {
1013       parameterDeclaration();
1014       if (token != TT_COMMA) {
1015         break;
1016       }
1017       getNextToken();
1018     } while (true);
1019   }
1020
1021   public void parameterDeclaration() {
1022     //variable
1023     //variable-reference
1024     //variable '=' constant
1025     if (token == TT_VARIABLE) {
1026       getNextToken();
1027       if (token == TT_SET) {
1028         getNextToken();
1029         constant();
1030       }
1031       return;
1032     }
1033   }
1034
1035   public void labeledStatementList() {
1036     if (token != TT_case && token != TT_default) {
1037       throwSyntaxError("'case' or 'default' expected.");
1038     }
1039     do {
1040       if (token == TT_case) {
1041         getNextToken();
1042         constant();
1043         if (token == TT_DDOT) {
1044           getNextToken();
1045           statementList();
1046         } else {
1047           throwSyntaxError("':' character after 'case' constant expected.");
1048         }
1049       } else { // TT_default 
1050         getNextToken();
1051         if (token == TT_DDOT) {
1052           getNextToken();
1053           statementList();
1054         } else {
1055           throwSyntaxError("':' character after 'default' expected.");
1056         }
1057       }
1058     } while (token == TT_case || token == TT_default);
1059   }
1060
1061   //  public void labeledStatement() {
1062   //    if (token == TT_case) {
1063   //      getNextToken();
1064   //      constant();
1065   //      if (token == TT_DDOT) {
1066   //        getNextToken();
1067   //        statement();
1068   //      } else {
1069   //        throwSyntaxError("':' character after 'case' constant expected.");
1070   //      }
1071   //      return;
1072   //    } else if (token == TT_default) {
1073   //      getNextToken();
1074   //      if (token == TT_DDOT) {
1075   //        getNextToken();
1076   //        statement();
1077   //      } else {
1078   //        throwSyntaxError("':' character after 'default' expected.");
1079   //      }
1080   //      return;
1081   //    }
1082   //  }
1083
1084   public void expressionStatement() {
1085   }
1086
1087   public void inclusionStatement() {
1088   }
1089
1090   //  public void compoundStatement() {
1091   //  }
1092
1093   //  public void selectionStatement() {
1094   //  }
1095   //
1096   //  public void iterationStatement() {
1097   //  }
1098   //
1099   //  public void jumpStatement() {
1100   //  }
1101   //
1102   //  public void outputStatement() {
1103   //  }
1104   //
1105   //  public void scopeStatement() {
1106   //  }
1107   //
1108   //  public void flowStatement() {
1109   //  }
1110   //
1111   //  public void definitionStatement() {
1112   //  }
1113
1114   public void ifStatement() {
1115     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
1116     if (token == TT_DDOT) {
1117       getNextToken();
1118       statementList();
1119       switch (token) {
1120         case TT_else :
1121           getNextToken();
1122           if (token == TT_DDOT) {
1123             getNextToken();
1124             statementList();
1125           } else {
1126             if (token == TT_if) { //'else if'
1127               getNextToken();
1128               elseifStatementList();
1129             } else {
1130               throwSyntaxError("':' expected after 'else'.");
1131             }
1132           }
1133           break;
1134         case TT_elseif :
1135           getNextToken();
1136           elseifStatementList();
1137           break;
1138       }
1139
1140       if (token != TT_endif) {
1141         throwSyntaxError("'endif' expected.");
1142       }
1143       getNextToken();
1144       if (token != TT_SEMICOLON) {
1145         throwSyntaxError("';' expected after if-statement.");
1146       }
1147       getNextToken();
1148     } else {
1149       // statement [else-statement]
1150       statement();
1151       if (token == TT_elseif) {
1152         getNextToken();
1153         if (token == TT_ARGOPEN) {
1154           getNextToken();
1155         } else {
1156           throwSyntaxError("'(' expected after 'elseif' keyword.");
1157         }
1158         expression();
1159         if (token == TT_ARGCLOSE) {
1160           getNextToken();
1161         } else {
1162           throwSyntaxError("')' expected after 'elseif' condition.");
1163         }
1164         ifStatement();
1165       } else if (token == TT_else) {
1166         getNextToken();
1167         statement();
1168       }
1169     }
1170   }
1171   public void elseifStatementList() {
1172     do {
1173       elseifStatement();
1174       switch (token) {
1175         case TT_else :
1176           getNextToken();
1177           if (token == TT_DDOT) {
1178             getNextToken();
1179             statementList();
1180             return;
1181           } else {
1182             if (token == TT_if) { //'else if'
1183               getNextToken();
1184             } else {
1185               throwSyntaxError("':' expected after 'else'.");
1186             }
1187           }
1188           break;
1189         case TT_elseif :
1190           getNextToken();
1191           break;
1192         default :
1193           return;
1194       }
1195     } while (true);
1196   }
1197
1198   public void elseifStatement() {
1199     if (token == TT_ARGOPEN) {
1200       getNextToken();
1201       expression();
1202       if (token != TT_ARGOPEN) {
1203         throwSyntaxError("')' expected in else-if-statement.");
1204       }
1205       getNextToken();
1206       if (token != TT_DDOT) {
1207         throwSyntaxError("':' expected in else-if-statement.");
1208       }
1209       getNextToken();
1210       statementList();
1211     }
1212   }
1213
1214   public void switchStatement() {
1215     if (token == TT_DDOT) {
1216       // ':' [labeled-statement-list] 'endswitch' ';'
1217       getNextToken();
1218       labeledStatementList();
1219       if (token != TT_endswitch) {
1220         throwSyntaxError("'endswitch' expected.");
1221       }
1222       getNextToken();
1223       if (token != TT_SEMICOLON) {
1224         throwSyntaxError("';' expected after switch-statement.");
1225       }
1226       getNextToken();
1227     } else {
1228       // '{' [labeled-statement-list] '}'
1229       if (token != TT_LISTOPEN) {
1230         throwSyntaxError("'{' expected in switch statement.");
1231       }
1232       getNextToken();
1233       if (token != TT_LISTCLOSE) {
1234         labeledStatementList();
1235       }
1236       if (token != TT_LISTCLOSE) {
1237         throwSyntaxError("'}' expected in switch statement.");
1238       }
1239       getNextToken();
1240
1241     }
1242   }
1243
1244   public void forStatement() {
1245     if (token == TT_DDOT) {
1246       getNextToken();
1247       statementList();
1248       if (token != TT_endfor) {
1249         throwSyntaxError("'endfor' expected.");
1250       }
1251       getNextToken();
1252       if (token != TT_SEMICOLON) {
1253         throwSyntaxError("';' expected after for-statement.");
1254       }
1255       getNextToken();
1256     } else {
1257       statement();
1258     }
1259   }
1260
1261   public void whileStatement() {
1262     // ':' statement-list 'endwhile' ';'
1263     if (token == TT_DDOT) {
1264       getNextToken();
1265       statementList();
1266       if (token != TT_endwhile) {
1267         throwSyntaxError("'endwhile' expected.");
1268       }
1269       getNextToken();
1270       if (token != TT_SEMICOLON) {
1271         throwSyntaxError("';' expected after while-statement.");
1272       }
1273       getNextToken();
1274     } else {
1275       statement();
1276     }
1277   }
1278
1279   public void foreachStatement() {
1280     if (token == TT_DDOT) {
1281       getNextToken();
1282       statementList();
1283       if (token != TT_endforeach) {
1284         throwSyntaxError("'endforeach' expected.");
1285       }
1286       getNextToken();
1287       if (token != TT_SEMICOLON) {
1288         throwSyntaxError("';' expected after foreach-statement.");
1289       }
1290       getNextToken();
1291     } else {
1292       statement();
1293     }
1294   }
1295
1296   public void exitStatus() {
1297     if (token == TT_ARGOPEN) {
1298       getNextToken();
1299     } else {
1300       throwSyntaxError("'(' expected in 'exit-status'.");
1301     }
1302     if (token != TT_ARGCLOSE) {
1303       expression();
1304     }
1305     if (token == TT_ARGCLOSE) {
1306       getNextToken();
1307     } else {
1308       throwSyntaxError("')' expected after 'exit-status'.");
1309     }
1310   }
1311
1312   public void expressionList() {
1313     do {
1314       expression();
1315       if (token == TT_COMMA) {
1316         getNextToken();
1317       } else {
1318         break;
1319       }
1320     } while (true);
1321   }
1322
1323   public void expression() {
1324     //    if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
1325     //      getNextToken();
1326     //    } else {
1327     logicalinclusiveorExpression();
1328     //      while (token != TT_SEMICOLON) {
1329     //        getNextToken();
1330     //      //      }
1331     //    }
1332   }
1333
1334   public void postfixExpression() {
1335     String ident;
1336     boolean castFlag = false;
1337     switch (token) {
1338       case TT_STRING_CONSTANT :
1339         getNextToken();
1340         break;
1341       case TT_INTERPOLATED_STRING :
1342         getNextToken();
1343         break;
1344       case TT_ARGOPEN :
1345         getNextToken();
1346         if (token == TT_IDENTIFIER) {
1347           // check if identifier is a type:
1348           ident = identifier;
1349           String str = identifier.toLowerCase();
1350           for (int i = 0; i < PHP_TYPES.length; i++) {
1351             if (PHP_TYPES[i].equals(str)) {
1352               castFlag = true;
1353               break;
1354             }
1355           }
1356           if (castFlag) {
1357             getNextToken();
1358             if (token != TT_ARGCLOSE) {
1359               throwSyntaxError(") expected after cast-type '" + ident + "'.");
1360             }
1361             getNextToken();
1362             expression();
1363             break;
1364           }
1365         }
1366         if (!castFlag) {
1367           expression();
1368         }
1369         if (token != TT_ARGCLOSE) {
1370           throwSyntaxError(") expected in postfix-expression.");
1371         }
1372         getNextToken();
1373         break;
1374       case TT_DOUBLE_NUMBER :
1375         getNextToken();
1376         break;
1377       case TT_INT_NUMBER :
1378         getNextToken();
1379         break;
1380       case TT_VARIABLE :
1381         ident = identifier;
1382         getNextToken();
1383         if (token == TT_LISTOPEN) {
1384           getNextToken();
1385           expression();
1386           if (token != TT_LISTCLOSE) {
1387             throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
1388           }
1389           getNextToken();
1390         }
1391         break;
1392       case TT_IDENTIFIER :
1393         ident = identifier;
1394         getNextToken();
1395         if (token == TT_ARGOPEN) {
1396           getNextToken();
1397           if (token != TT_ARGCLOSE) {
1398             expressionList();
1399             if (token != TT_ARGCLOSE) {
1400               throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
1401             }
1402           }
1403           getNextToken();
1404         }
1405         break;
1406       case TT_list :
1407         getNextToken();
1408         if (token == TT_ARGOPEN) {
1409           getNextToken();
1410           if (token == TT_COMMA) {
1411             getNextToken();
1412           }
1413           expressionList();
1414           if (token != TT_ARGCLOSE) {
1415             throwSyntaxError("')' expected after 'list' keyword.");
1416           }
1417           getNextToken();
1418           //          if (token == TT_SET) {
1419           //            getNextToken();
1420           //            logicalinclusiveorExpression();
1421           //          }
1422         } else {
1423           throwSyntaxError("'(' expected after 'list' keyword.");
1424         }
1425         break;
1426         //      case TT_array :
1427         //        getNextToken();
1428         //        if (token == TT_ARGOPEN) {
1429         //          getNextToken();
1430         //          if (token == TT_COMMA) {
1431         //            getNextToken();
1432         //          }
1433         //          expressionList();
1434         //          if (token != TT_ARGCLOSE) {
1435         //            throwSyntaxError("')' expected after 'list' keyword.");
1436         //          }
1437         //          getNextToken();
1438         //          if (token == TT_SET) {
1439         //            getNextToken();
1440         //            logicalinclusiveorExpression();
1441         //          }
1442         //        } else {
1443         //          throwSyntaxError("'(' expected after 'list' keyword.");
1444         //        }
1445         //        break;
1446     }
1447     boolean while_flag = true;
1448     do {
1449       switch (token) {
1450         case TT_PARTOPEN :
1451           getNextToken();
1452           expression();
1453           if (token != TT_PARTCLOSE) {
1454             throwSyntaxError("] expected in postfix-expression.");
1455           }
1456           getNextToken();
1457           break;
1458         case TT_REF : // ->
1459           switch (token) {
1460             case TT_VARIABLE :
1461               getNextToken();
1462               break;
1463             case TT_IDENTIFIER :
1464               getNextToken();
1465               break;
1466             case TT_LISTOPEN :
1467               getNextToken();
1468               expression();
1469               if (token != TT_LISTCLOSE) {
1470                 throwSyntaxError("} expected in postfix-expression.");
1471               }
1472               getNextToken();
1473               break;
1474             default :
1475               throwSyntaxError("Syntax error after '->' token.");
1476           }
1477         case TT_INCREMENT :
1478           getNextToken();
1479           break;
1480         case TT_DECREMENT :
1481           getNextToken();
1482           break;
1483         default :
1484           while_flag = false;
1485       }
1486     } while (while_flag);
1487   }
1488
1489   public void unaryExpression() {
1490     switch (token) {
1491       case TT_INCREMENT :
1492         getNextToken();
1493         unaryExpression();
1494         break;
1495       case TT_DECREMENT :
1496         getNextToken();
1497         unaryExpression();
1498         break;
1499         //'&' '*' '+' '-' '~' '!' 
1500       case TT_AMPERSAND :
1501         getNextToken();
1502         castExpression();
1503         break;
1504       case TT_MULTIPLY :
1505         getNextToken();
1506         castExpression();
1507         break;
1508       case TT_ADD :
1509         getNextToken();
1510         castExpression();
1511         break;
1512       case TT_SUBTRACT :
1513         getNextToken();
1514         castExpression();
1515         break;
1516       case TT_TILDE :
1517         getNextToken();
1518         castExpression();
1519         break;
1520       case TT_NOT :
1521         getNextToken();
1522         castExpression();
1523         break;
1524       default :
1525         postfixExpression();
1526     }
1527   }
1528
1529   public void castExpression() {
1530     //    if (token == TT_ARGOPEN) {
1531     //      getNextToken();
1532     //      typeName();
1533     //      if (token != TT_ARGCLOSE) {
1534     //        throwSyntaxError(") expected after cast-expression.");
1535     //      }
1536     //      getNextToken();
1537     //    }
1538     unaryExpression();
1539   }
1540
1541   public void typeName() {
1542     //'string' 'unset' 'array' 'object'
1543     //'bool' 'boolean'
1544     //'real' 'double' 'float'
1545     //'int' 'integer'
1546     String ident = "";
1547     if (token == TT_IDENTIFIER) {
1548       ident = identifier;
1549       String str = identifier.toLowerCase();
1550       getNextToken();
1551       for (int i = 0; i < PHP_TYPES.length; i++) {
1552         if (PHP_TYPES[i].equals(str)) {
1553           return;
1554         }
1555       }
1556     }
1557     throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
1558   }
1559
1560   public void assignExpression() {
1561     castExpression();
1562     if (token == TT_SET) { // =
1563       getNextToken();
1564       logicalinclusiveorExpression();
1565     } else if (token == TT_DOTASSIGN) { // .=
1566       getNextToken();
1567       logicalinclusiveorExpression();
1568     } else if (token == TT_FOREACH) { // =>
1569       getNextToken();
1570       logicalinclusiveorExpression();
1571     }
1572   }
1573
1574   public void multiplicativeExpression() {
1575     do {
1576       assignExpression();
1577       if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
1578         return;
1579       }
1580       getNextToken();
1581     } while (true);
1582   }
1583
1584   public void concatenationExpression() {
1585     do {
1586       multiplicativeExpression();
1587       if (token != TT_DOT) {
1588         return;
1589       }
1590       getNextToken();
1591     } while (true);
1592   }
1593
1594   public void additiveExpression() {
1595     do {
1596       concatenationExpression();
1597       if (token != TT_ADD && token != TT_SUBTRACT) {
1598         return;
1599       }
1600       getNextToken();
1601     } while (true);
1602   }
1603
1604   public void shiftExpression() {
1605     do {
1606       additiveExpression();
1607       if (token != TT_LSHIFT && token != TT_RSHIFT) {
1608         return;
1609       }
1610       getNextToken();
1611     } while (true);
1612   }
1613
1614   public void relationalExpression() {
1615     do {
1616       shiftExpression();
1617       if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
1618         return;
1619       }
1620       getNextToken();
1621     } while (true);
1622   }
1623
1624   public void identicalExpression() {
1625     do {
1626       relationalExpression();
1627       if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
1628         return;
1629       }
1630       getNextToken();
1631     } while (true);
1632   }
1633
1634   public void equalityExpression() {
1635     do {
1636       identicalExpression();
1637       if (token != TT_EQUAL && token != TT_UNEQUAL) {
1638         return;
1639       }
1640       getNextToken();
1641     } while (true);
1642   }
1643
1644   public void andExpression() {
1645     do {
1646       equalityExpression();
1647       if (token != TT_AMPERSAND) {
1648         return;
1649       }
1650       getNextToken();
1651     } while (true);
1652   }
1653
1654   public void exclusiveorExpression() {
1655     do {
1656       andExpression();
1657       if (token != TT_POW) {
1658         return;
1659       }
1660       getNextToken();
1661     } while (true);
1662   }
1663
1664   public void inclusiveorExpression() {
1665     do {
1666       exclusiveorExpression();
1667       if (token != TT_LINE) {
1668         return;
1669       }
1670       getNextToken();
1671     } while (true);
1672   }
1673
1674   public void booleanandExpression() {
1675     do {
1676       inclusiveorExpression();
1677       if (token != TT_AND) {
1678         return;
1679       }
1680       getNextToken();
1681     } while (true);
1682   }
1683
1684   public void booleanorExpression() {
1685     do {
1686       booleanandExpression();
1687       if (token != TT_OR) {
1688         return;
1689       }
1690       getNextToken();
1691     } while (true);
1692   }
1693
1694   public void logicalandExpression() {
1695     do {
1696       booleanorExpression();
1697       if (token != TT_and) {
1698         return;
1699       }
1700       getNextToken();
1701     } while (true);
1702   }
1703
1704   public void logicalexclusiveorExpression() {
1705     do {
1706       logicalandExpression();
1707       if (token != TT_xor) {
1708         return;
1709       }
1710       getNextToken();
1711     } while (true);
1712   }
1713
1714   public void logicalinclusiveorExpression() {
1715     do {
1716       logicalexclusiveorExpression();
1717       if (token != TT_or) {
1718         return;
1719       }
1720       getNextToken();
1721     } while (true);
1722   }
1723
1724   //  public void assignmentExpression() {
1725   //    if (token == TT_VARIABLE) {
1726   //      getNextToken();
1727   //      if (token == TT_SET) {
1728   //        getNextToken();
1729   //        logicalinclusiveorExpression();
1730   //      }
1731   //    } else {
1732   //      logicalinclusiveorExpression();
1733   //    }
1734   //  }
1735
1736   public void variableList() {
1737     do {
1738       variable();
1739       if (token == TT_COMMA) {
1740         getNextToken();
1741       } else {
1742         break;
1743       }
1744     } while (true);
1745   }
1746
1747   public void variable() {
1748     if (token == TT_VARIABLE) {
1749       getNextToken();
1750     } else {
1751       throwSyntaxError("$-variable expected in variable-list.");
1752     }
1753   }
1754
1755   public void constant() {
1756     switch (token) {
1757       case TT_STRING_CONSTANT :
1758         getNextToken();
1759         break;
1760       case TT_INTERPOLATED_STRING :
1761         getNextToken();
1762         break;
1763       case TT_DOUBLE_NUMBER :
1764         getNextToken();
1765         break;
1766       case TT_INT_NUMBER :
1767         getNextToken();
1768         break;
1769       default :
1770         throwSyntaxError("Constant expected.");
1771     }
1772   }
1773
1774 }