improved php parser (if-statement); but a lot of things don't work yet
[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_NOT = 31;
46   final static int TT_DOT = 32;
47   final static int TT_POW = 33;
48   final static int TT_DIVIDE = 34;
49   final static int TT_MULTIPLY = 35;
50   final static int TT_SUBTRACT = 36;
51   final static int TT_ADD = 37;
52   final static int TT_EQUAL = 38;
53   final static int TT_UNEQUAL = 39;
54   final static int TT_GREATER = 40;
55   final static int TT_GREATEREQUAL = 41;
56   final static int TT_LESS = 42;
57   final static int TT_LESSEQUAL = 43;
58   final static int TT_AND = 44;
59   final static int TT_OR = 45;
60   final static int TT_HASH = 46;
61   final static int TT_DDOT = 47;
62   final static int TT_DOTASSIGN = 48;
63
64   final static int TT_SET = 49;
65   final static int TT_REF = 50;
66   final static int TT_FOREACH = 51;
67   final static int TT_AMPERSAND = 52;
68   final static int TT_DOLLARLISTOPEN = 53;
69   final static int TT_ARGOPEN = 128;
70   final static int TT_ARGCLOSE = 129;
71   final static int TT_LISTOPEN = 130;
72   final static int TT_LISTCLOSE = 131;
73   final static int TT_PARTOPEN = 132;
74   final static int TT_PARTCLOSE = 133;
75   final static int TT_COMMA = 134;
76   final static int TT_PERCENT = 135;
77   final static int TT_STRING = 136;
78   final static int TT_IDENTIFIER = 138;
79   final static int TT_DIGIT = 139;
80   final static int TT_SEMICOLON = 140;
81   final static int TT_SLOT = 141;
82   final static int TT_SLOTSEQUENCE = 142;
83   final static int TT_DECREMENT = 144;
84   final static int TT_INCREMENT = 145;
85   final static int TT_ADDTO = 146;
86   final static int TT_DIVIDEBY = 147;
87   final static int TT_SUBTRACTFROM = 148;
88   final static int TT_TIMESBY = 149;
89   final static int TT_VARIABLE = 150;
90   final static int TT_INT_NUMBER = 151;
91   final static int TT_DOUBLE_NUMBER = 152;
92   final static int TT_INTERPOLATED_STRING = 153;
93   final static int TT_STRING_CONSTANT = 154;
94   //  final static int TT_AT = 153; // @
95   /**
96    *  Class Constructor.
97    *
98    *@param  s
99    *@param  sess  Description of Parameter
100    *@see
101    */
102   public PHPParser() {
103     if (keywordMap == null) {
104       keywordMap = new HashMap();
105       for (int i = 0; i < PHP_KEYWORS.length; i++) {
106         keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
107       }
108     }
109     this.str = "";
110     this.token = TT_EOF;
111     this.chIndx = 0;
112     this.rowCount = 1;
113     this.columnCount = 0;
114
115     getNextToken();
116   }
117
118   private void throwSyntaxError(String error) {
119
120     if (str.length() < chIndx) {
121       chIndx--;
122     }
123     // read until end-of-line
124     int eol = chIndx;
125     while (str.length() > eol) {
126       ch = str.charAt(eol++);
127       if (ch == '\n') {
128         eol--;
129         break;
130       }
131     }
132     throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
133   }
134
135   /**
136    *  Method Declaration.
137    *
138    *@see
139    */
140   void getChar() {
141     if (str.length() > chIndx) {
142       ch = str.charAt(chIndx++);
143
144       return;
145     }
146
147     chIndx = str.length() + 1;
148     ch = ' ';
149     token = TT_EOF;
150   }
151
152   /**
153    * gets the next token from input
154    */
155   void getNextToken() {
156     while (str.length() > chIndx) {
157       ch = str.charAt(chIndx++);
158       token = TT_UNDEFINED;
159       if (ch == '\n') {
160         rowCount++;
161         columnCount = chIndx;
162         continue; // while loop
163       }
164
165       if (!Character.isWhitespace(ch)) {
166         if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$') || (ch == '@')) {
167           getIdentifier();
168           return;
169         }
170         if (ch >= '0' && ch <= '9') {
171           getNumber();
172           return;
173         }
174         if (ch == '/') {
175           if (str.length() > chIndx) {
176             if (str.charAt(chIndx) == '/') {
177               chIndx++;
178               // read comment until end of line:
179               while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
180                 chIndx++;
181               }
182               continue;
183             } else if (str.charAt(chIndx) == '*') {
184               chIndx++;
185               // multi line comment:
186               while (str.length() > chIndx) {
187                 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
188                   chIndx += 2;
189                   break;
190                 }
191                 chIndx++;
192               }
193               continue;
194             }
195           }
196         } else if (ch == '#') {
197           // read comment until end of line:
198           while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
199             chIndx++;
200           }
201           continue;
202         } else if (ch == '"') {
203           // read string until end
204           while ((str.length() > chIndx) && (str.charAt(chIndx++) != '"')) {
205             if (str.charAt(chIndx) == '\\') {
206               if (str.length() > chIndx) {
207                 chIndx++;
208               }
209               if (str.length() > chIndx) {
210                 chIndx++;
211               }
212             } else {
213               if (str.charAt(chIndx) == '\n') {
214                 rowCount++;
215                 columnCount = chIndx;
216               }
217             }
218           }
219           //          if (str.length() > chIndx) {
220           //            chIndx++;
221           //          }
222           token = TT_INTERPOLATED_STRING;
223           return;
224         } else if (ch == '\'') {
225           // read string until end
226           while ((str.length() > chIndx) && (str.charAt(chIndx++) != '\'')) {
227             if (str.charAt(chIndx) == '\\') {
228               if (str.length() > chIndx) {
229                 chIndx++;
230               }
231               if (str.length() > chIndx) {
232                 chIndx++;
233               }
234             }
235           }
236           //          if (str.length() > chIndx) {
237           //            chIndx++;
238           //          }
239           token = TT_STRING_CONSTANT;
240           return;
241         }
242
243         switch (ch) {
244
245           case '(' :
246             token = TT_ARGOPEN;
247
248             break;
249           case ')' :
250             token = TT_ARGCLOSE;
251
252             break;
253           case '{' :
254             token = TT_LISTOPEN;
255
256             break;
257           case '}' :
258             token = TT_LISTCLOSE;
259
260             break;
261           case '[' :
262             token = TT_PARTOPEN;
263
264             break;
265           case ']' :
266             token = TT_PARTCLOSE;
267
268             break;
269           case ',' :
270             token = TT_COMMA;
271
272             break;
273
274           case '.' :
275             token = TT_DOT;
276             if (str.length() > chIndx) {
277               if (str.charAt(chIndx) == '=') {
278                 chIndx++;
279                 token = TT_DOTASSIGN;
280
281                 break;
282               }
283             }
284
285             break;
286           case '"' :
287             token = TT_STRING;
288
289             break;
290           case '%' :
291             token = TT_PERCENT;
292
293             break;
294           case ';' :
295             token = TT_SEMICOLON;
296
297             break;
298           case '^' :
299             token = TT_POW;
300
301             break;
302           case '/' :
303             token = TT_DIVIDE;
304
305             if (str.length() > chIndx) {
306               if (str.charAt(chIndx) == '=') {
307                 chIndx++;
308                 token = TT_DIVIDEBY;
309
310                 break;
311               }
312             }
313
314             break;
315           case '*' :
316             token = TT_MULTIPLY;
317             if (str.length() > chIndx) {
318               if (str.charAt(chIndx) == '*') {
319                 chIndx++;
320                 token = TT_POW;
321
322                 break;
323               }
324               if (str.charAt(chIndx) == '=') {
325                 chIndx++;
326                 token = TT_TIMESBY;
327
328                 break;
329               }
330             }
331
332             break;
333           case '+' :
334             token = TT_ADD;
335             if (str.length() > chIndx) {
336               if (str.charAt(chIndx) == '+') {
337                 chIndx++;
338                 token = TT_INCREMENT;
339
340                 break;
341               }
342               if (str.charAt(chIndx) == '=') {
343                 chIndx++;
344                 token = TT_ADDTO;
345
346                 break;
347               }
348             }
349             break;
350           case '-' :
351             token = TT_SUBTRACT;
352             if (str.length() > chIndx) {
353               if (str.charAt(chIndx) == '-') {
354                 chIndx++;
355                 token = TT_DECREMENT;
356
357                 break;
358               }
359               if (str.charAt(chIndx) == '=') {
360                 chIndx++;
361                 token = TT_SUBTRACTFROM;
362
363                 break;
364               }
365               if (str.charAt(chIndx) == '>') {
366                 chIndx++;
367                 token = TT_REF;
368
369                 break;
370               }
371             }
372
373             break;
374           case '=' :
375             token = TT_SET;
376
377             if (str.length() > chIndx) {
378               ch = str.charAt(chIndx);
379
380               if (ch == '=') {
381                 chIndx++;
382                 token = TT_EQUAL;
383
384                 break;
385               }
386               if (ch == '>') {
387                 chIndx++;
388                 token = TT_FOREACH;
389
390                 break;
391               }
392             }
393
394             break;
395           case '!' :
396             token = TT_NOT;
397
398             if (str.length() > chIndx) {
399               if (str.charAt(chIndx) == '=') {
400                 chIndx++;
401                 token = TT_UNEQUAL;
402
403                 break;
404               }
405             }
406
407             break;
408           case '>' :
409             token = TT_GREATER;
410
411             if (str.length() > chIndx) {
412               if (str.charAt(chIndx) == '=') {
413                 chIndx++;
414                 token = TT_GREATEREQUAL;
415
416                 break;
417               }
418             }
419
420             break;
421           case '<' :
422             token = TT_LESS;
423
424             if (str.length() > chIndx) {
425               if (str.charAt(chIndx) == '=') {
426                 chIndx++;
427                 token = TT_LESSEQUAL;
428
429                 break;
430               }
431             }
432
433             break;
434
435           case '|' :
436             if (str.length() > chIndx) {
437               if (str.charAt(chIndx) == '|') {
438                 chIndx++;
439                 token = TT_OR;
440
441                 break;
442               }
443             }
444
445             break;
446           case '&' :
447             if (str.length() > chIndx) {
448               if (str.charAt(chIndx) == '&') {
449                 chIndx++;
450                 token = TT_AND;
451
452                 break;
453               } else {
454                 token = TT_AMPERSAND;
455
456                 break;
457               }
458             }
459
460             break;
461           case ':' :
462             token = TT_DDOT;
463
464             break;
465           case '#' :
466             token = TT_HASH;
467
468             break;
469             //          case '@' :
470             //            token = TT_AT;
471             //
472             //            break;
473           default :
474             throwSyntaxError("unexpected character: '" + ch + "'");
475         }
476
477         if (token == TT_UNDEFINED) {
478           throwSyntaxError("token not found");
479         }
480
481         return;
482       }
483     }
484
485     chIndx = str.length() + 1;
486     ch = ' ';
487     token = TT_EOF;
488   }
489
490   void getIdentifier() {
491     StringBuffer ident = new StringBuffer();
492
493     ident.append(ch);
494     if (ch == '$') {
495       token = TT_VARIABLE;
496     } else {
497       token = TT_IDENTIFIER;
498     }
499     getChar();
500     while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch >= '_')) {
501       ident.append(ch);
502       getChar();
503     }
504     identifier = ident.toString();
505     chIndx--;
506
507     Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
508     if (i != null) {
509       token = i.intValue();
510     }
511   }
512
513   void getNumber() {
514     StringBuffer inum = new StringBuffer();
515     char dFlag = ' ';
516     int numFormat = 10;
517
518     // save first digit
519     char firstCh = ch;
520     inum.append(ch);
521
522     getChar();
523     // determine number conversions:
524     if (firstCh == '0') {
525       switch (ch) {
526         case 'b' :
527           numFormat = 2;
528           getChar();
529           break;
530         case 'B' :
531           numFormat = 2;
532           getChar();
533           break;
534         case 'o' :
535           numFormat = 8;
536           getChar();
537           break;
538         case 'O' :
539           numFormat = 8;
540           getChar();
541           break;
542         case 'x' :
543           numFormat = 16;
544           getChar();
545           break;
546         case 'X' :
547           numFormat = 16;
548           getChar();
549           break;
550       }
551     }
552
553     if (numFormat == 16) {
554       while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
555         inum.append(ch);
556         getChar();
557       }
558     } else {
559       while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
560         if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
561           if (ch == '.' && dFlag != ' ') {
562             break;
563           }
564           if ((dFlag == 'E') || (dFlag == 'e')) {
565             break;
566           }
567           dFlag = ch;
568           inum.append(ch);
569           getChar();
570           if ((ch == '-') || (ch == '+')) {
571             inum.append(ch);
572             getChar();
573           }
574         } else {
575           inum.append(ch);
576           getChar();
577         }
578       }
579     }
580     chIndx--;
581
582     try {
583       if (dFlag != ' ') {
584         doubleNumber = new Double(inum.toString());
585         token = TT_DOUBLE_NUMBER;
586         return;
587       } else {
588         longNumber = Long.valueOf(inum.toString(), numFormat);
589         token = TT_INT_NUMBER;
590         return;
591       }
592
593     } catch (Throwable e) {
594       throwSyntaxError("Number format error: " + inum.toString());
595     }
596   }
597
598   public void start(String s, int rowCount) throws SyntaxError {
599     // start up
600     this.str = s;
601     this.token = TT_EOF;
602     this.chIndx = 0;
603     this.rowCount = rowCount;
604     this.columnCount = 0;
605     getNextToken();
606
607     statementList();
608     if (token != TT_EOF) {
609       if (token == TT_ARGCLOSE) {
610         throwSyntaxError("too many closing ')'; end-of-file not reached");
611       }
612       if (token == TT_LISTCLOSE) {
613         throwSyntaxError("too many closing '}'; end-of-file not reached");
614       }
615       if (token == TT_PARTCLOSE) {
616         throwSyntaxError("too many closing ']'; end-of-file not reached");
617       }
618
619       if (token == TT_ARGOPEN) {
620         throwSyntaxError("read character '('; end-of-file not reached");
621       }
622       if (token == TT_LISTOPEN) {
623         throwSyntaxError("read character '{';  end-of-file not reached");
624       }
625       if (token == TT_PARTOPEN) {
626         throwSyntaxError("read character '[';  end-of-file not reached");
627       }
628
629       throwSyntaxError("end-of-file not reached");
630     }
631
632   }
633
634   public void statementList() {
635     do {
636       statement();
637       if ((token == TT_LISTCLOSE)
638         || (token == TT_elseif)
639         || (token == TT_endif)
640         || (token == TT_endfor)
641         || (token == TT_endforeach)
642         || (token == TT_endwhile)
643         || (token == TT_endswitch)
644         || (token == TT_EOF)) {
645         return;
646       }
647     } while (true);
648   }
649
650   public void statement() {
651     while (token != TT_UNDEFINED && token != TT_EOF) {
652       if (token > TT_KEYWORD) {
653         if (token == TT_case) {
654           getNextToken();
655           constant();
656           if (token == TT_DDOT) {
657             getNextToken();
658             statement();
659           } else {
660             throwSyntaxError("':' character after 'case' constant expected.");
661           }
662           return;
663         } else if (token == TT_default) {
664           getNextToken();
665           if (token == TT_DDOT) {
666             getNextToken();
667             statement();
668           } else {
669             throwSyntaxError("':' character after 'default' expected.");
670           }
671           return;
672         } else if (token == TT_include || token == TT_include_once) {
673           getNextToken();
674           expression();
675           if (token == TT_SEMICOLON) {
676             getNextToken();
677           } else {
678             throwSyntaxError("';' character after 'include' or 'include_once' expected.");
679           }
680           return;
681         } else if (token == TT_require || token == TT_require_once) {
682           getNextToken();
683           //constant();
684           expression();
685           if (token == TT_SEMICOLON) {
686             getNextToken();
687           } else {
688             throwSyntaxError("';' character after 'require' or 'require_once' expected.");
689           }
690           return;
691         } else if (token == TT_if) {
692           getNextToken();
693           if (token == TT_ARGOPEN) {
694             getNextToken();
695           } else {
696             throwSyntaxError("'(' expected after 'if' keyword.");
697           }
698           expression();
699           if (token == TT_ARGCLOSE) {
700             getNextToken();
701           } else {
702             throwSyntaxError("')' expected after 'if' condition.");
703           }
704           ifStatement();
705           return;
706
707         } else if (token == TT_switch) {
708           getNextToken();
709           if (token == TT_ARGOPEN) {
710             getNextToken();
711           } else {
712             throwSyntaxError("'(' expected after 'switch' keyword.");
713           }
714           expression();
715           if (token == TT_ARGCLOSE) {
716             getNextToken();
717           } else {
718             throwSyntaxError("')' expected after 'switch' condition.");
719           }
720           switchStatement();
721           return;
722         } else if (token == TT_for) {
723           getNextToken();
724           if (token == TT_ARGOPEN) {
725             getNextToken();
726           } else {
727             throwSyntaxError("'(' expected after 'for' keyword.");
728           }
729           if (token == TT_SEMICOLON) {
730             getNextToken();
731           } else {
732             expression();
733             if (token == TT_SEMICOLON) {
734               getNextToken();
735             } else {
736               throwSyntaxError("';' character after 'for' expected.");
737             }
738           }
739           if (token == TT_SEMICOLON) {
740             getNextToken();
741           } else {
742             expression();
743             if (token == TT_SEMICOLON) {
744               getNextToken();
745             } else {
746               throwSyntaxError("';' character after 'for' expected.");
747             }
748           }
749           if (token == TT_ARGCLOSE) {
750             getNextToken();
751           } else {
752             expression();
753             if (token == TT_ARGCLOSE) {
754               getNextToken();
755             } else {
756               throwSyntaxError("')' expected after 'for' condition.");
757             }
758           }
759           forStatement();
760           return;
761         } else if (token == TT_while) {
762           getNextToken();
763           if (token == TT_ARGOPEN) {
764             getNextToken();
765           } else {
766             throwSyntaxError("'(' expected after 'while' keyword.");
767           }
768           expression();
769           if (token == TT_ARGCLOSE) {
770             getNextToken();
771           } else {
772             throwSyntaxError("')' expected after 'while' condition.");
773           }
774           whileStatement();
775           return;
776         } else if (token == TT_foreach) {
777           getNextToken();
778           if (token == TT_ARGOPEN) {
779             getNextToken();
780           } else {
781             throwSyntaxError("'(' expected after 'foreach' keyword.");
782           }
783           expression();
784           if (token == TT_as) {
785             getNextToken();
786           } else {
787             throwSyntaxError("'as' expected after 'foreach' exxpression.");
788           }
789           variable();
790           if (token == TT_FOREACH) {
791             getNextToken();
792             variable();
793           }
794           if (token == TT_ARGCLOSE) {
795             getNextToken();
796           } else {
797             throwSyntaxError("')' expected after 'foreach' expression.");
798           }
799           foreachStatement();
800           return;
801
802         } else if (token == TT_continue || token == TT_break || token == TT_return) {
803           getNextToken();
804           if (token != TT_SEMICOLON) {
805             expression();
806           }
807           if (token == TT_SEMICOLON) {
808             getNextToken();
809           } else {
810             throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
811           }
812           return;
813
814         } else if (token == TT_echo) {
815           getNextToken();
816           expressionList();
817           if (token == TT_SEMICOLON) {
818             getNextToken();
819           } else {
820             throwSyntaxError("';' expected after 'echo' statement.");
821           }
822           return;
823
824         } else if (token == TT_print) {
825           getNextToken();
826           expression();
827           if (token == TT_SEMICOLON) {
828             getNextToken();
829           } else {
830             throwSyntaxError("';' expected after 'print' statement.");
831           }
832           return;
833
834         } else if (token == TT_global || token == TT_static) {
835           getNextToken();
836           variableList();
837           if (token == TT_SEMICOLON) {
838             getNextToken();
839           } else {
840             throwSyntaxError("';' expected after 'global' or 'static' statement.");
841           }
842           return;
843
844         } else if (token == TT_unset) {
845           getNextToken();
846           if (token == TT_ARGOPEN) {
847             getNextToken();
848           } else {
849             throwSyntaxError("'(' expected after 'unset' keyword.");
850           }
851           variableList();
852           if (token == TT_ARGCLOSE) {
853             getNextToken();
854           } else {
855             throwSyntaxError("')' expected after 'unset' statement.");
856           }
857           if (token == TT_SEMICOLON) {
858             getNextToken();
859           } else {
860             throwSyntaxError("';' expected after 'unset' statement.");
861           }
862           return;
863
864         } else if (token == TT_exit || token == TT_die) {
865           getNextToken();
866           if (token != TT_SEMICOLON) {
867             exitStatus();
868           }
869           if (token == TT_SEMICOLON) {
870             getNextToken();
871           } else {
872             throwSyntaxError("';' expected after 'exit' or 'die' statement.");
873           }
874           return;
875
876         } else if (token == TT_define) {
877           getNextToken();
878           if (token == TT_ARGOPEN) {
879             getNextToken();
880           } else {
881             throwSyntaxError("'(' expected after 'define' keyword.");
882           }
883           constant();
884           if (token == TT_COMMA) {
885             getNextToken();
886           } else {
887             throwSyntaxError("',' expected after first 'define' constant.");
888           }
889           constant();
890           if (token == TT_ARGCLOSE) {
891             getNextToken();
892           } else {
893             throwSyntaxError("')' expected after 'define' statement.");
894           }
895           if (token == TT_SEMICOLON) {
896             getNextToken();
897           } else {
898             throwSyntaxError("';' expected after 'define' statement.");
899           }
900           return;
901
902         }
903
904       } else if (token == TT_LISTOPEN) {
905         // compundStatement
906         getNextToken();
907         if (token != TT_LISTCLOSE) {
908           statementList();
909         }
910         if (token == TT_LISTCLOSE) {
911           getNextToken();
912         } else {
913           throwSyntaxError("'}' expected.");
914         }
915       } else {
916         if (token != TT_SEMICOLON) {
917           expression();
918         }
919         if (token == TT_SEMICOLON) {
920           getNextToken();
921         } else {
922           throwSyntaxError("';' expected after expression.");
923         }
924       }
925     }
926   }
927
928   public void labeledStatement() {
929   }
930
931   public void expressionStatement() {
932   }
933
934   public void inclusionStatement() {
935   }
936
937   //  public void compoundStatement() {
938   //  }
939
940   public void selectionStatement() {
941   }
942
943   public void iterationStatement() {
944   }
945
946   public void jumpStatement() {
947   }
948
949   public void outputStatement() {
950   }
951
952   public void scopeStatement() {
953   }
954
955   public void flowStatement() {
956   }
957
958   public void definitionStatement() {
959   }
960
961   public void ifStatement() {
962     // statement [else-statement]
963     statement();
964     if (token == TT_else) {
965       getNextToken();
966       statement();
967     }
968   }
969
970   public void switchStatement() {
971   }
972
973   public void forStatement() {
974   }
975
976   public void whileStatement() {
977   }
978
979   public void foreachStatement() {
980   }
981
982   public void exitStatus() {
983     if (token == TT_ARGOPEN) {
984       getNextToken();
985     } else {
986       throwSyntaxError("'(' expected in 'exit-status'.");
987     }
988     if (token != TT_ARGCLOSE) {
989       expression();
990     }
991     if (token == TT_ARGCLOSE) {
992       getNextToken();
993     } else {
994       throwSyntaxError("')' expected after 'exit-status'.");
995     }
996   }
997
998   public void expressionList() {
999     do {
1000       expression();
1001       if (token == TT_COMMA) {
1002         getNextToken();
1003       } else {
1004         break;
1005       }
1006     } while (true);
1007   }
1008
1009   public void expression() {
1010     if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
1011       getNextToken();
1012     } else {
1013       postfixExpression();
1014       //      while (token != TT_SEMICOLON) {
1015       //        getNextToken();
1016       //      }
1017     }
1018   }
1019
1020   public void postfixExpression() {
1021     switch (token) {
1022       case TT_ARGOPEN :
1023         getNextToken();
1024         expression();
1025         if (token != TT_ARGCLOSE) {
1026           throwSyntaxError(") expected in postfix-expression.");
1027         }
1028         getNextToken();
1029         break;
1030       case TT_DOUBLE_NUMBER :
1031         getNextToken();
1032         break;
1033       case TT_INT_NUMBER :
1034         getNextToken();
1035         break;
1036       case TT_VARIABLE :
1037         getNextToken();
1038         break;
1039       case TT_IDENTIFIER :
1040         getNextToken();
1041         if (token == TT_ARGOPEN) {
1042           getNextToken();
1043           if (token != TT_ARGCLOSE) {
1044             expressionList();
1045             if (token != TT_ARGCLOSE) {
1046               throwSyntaxError(") expected after identifier in postfix-expression.");
1047             }
1048           }
1049           getNextToken();
1050         }
1051         break;
1052
1053     }
1054     boolean while_flag = true;
1055     do {
1056       switch (token) {
1057         case TT_PARTOPEN :
1058           getNextToken();
1059           expression();
1060           if (token != TT_PARTCLOSE) {
1061             throwSyntaxError("] expected in postfix-expression.");
1062           }
1063           getNextToken();
1064           break;
1065         case TT_REF :
1066           switch (token) {
1067             case TT_VARIABLE :
1068               getNextToken();
1069               break;
1070             case TT_IDENTIFIER :
1071               getNextToken();
1072               break;
1073             case TT_LISTOPEN :
1074               getNextToken();
1075               expression();
1076               if (token != TT_LISTCLOSE) {
1077                 throwSyntaxError("] expected in postfix-expression.");
1078               }
1079               getNextToken();
1080               break;
1081             default :
1082               throwSyntaxError("Syntax error after '->' token.");
1083           }
1084         case TT_INCREMENT :
1085           getNextToken();
1086           break;
1087         case TT_DECREMENT :
1088           getNextToken();
1089           break;
1090         default :
1091           while_flag = false;
1092       }
1093     } while (while_flag);
1094   }
1095
1096   public void variableList() {
1097     do {
1098       variable();
1099       if (token == TT_COMMA) {
1100         getNextToken();
1101       } else {
1102         break;
1103       }
1104     } while (true);
1105   }
1106
1107   public void variable() {
1108     if (token == TT_VARIABLE) {
1109       getNextToken();
1110     } else {
1111       throwSyntaxError("$-variable expected in variable-list.");
1112     }
1113   }
1114
1115   public void constant() {
1116
1117   }
1118
1119 }