1 package net.sourceforge.phpeclipse.phpeditor;
3 import java.util.HashMap;
5 import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
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
15 IBM Corporation - Initial implementation
16 Klaus Hartlage - www.eclipseproject.de
17 **********************************************************************/
19 public class PHPParser extends PHPKeywords {
21 private static HashMap keywordMap = null;
29 // row counter for syntax errors:
31 // column counter for syntax errors:
42 final static int TT_EOF = 0;
43 final static int TT_UNDEFINED = 1;
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;
64 final static int TT_SET = 49;
66 final static int TT_FOREACH = 51;
67 final static int TT_ARGOPEN = 128;
68 final static int TT_ARGCLOSE = 129;
69 final static int TT_LISTOPEN = 130;
70 final static int TT_LISTCLOSE = 131;
71 final static int TT_PARTOPEN = 132;
72 final static int TT_PARTCLOSE = 133;
73 final static int TT_COMMA = 134;
74 final static int TT_PERCENT = 135;
75 final static int TT_STRING = 136;
76 final static int TT_IDENTIFIER = 138;
77 final static int TT_DIGIT = 139;
78 final static int TT_SEMICOLON = 140;
79 final static int TT_SLOT = 141;
80 final static int TT_SLOTSEQUENCE = 142;
81 final static int TT_DECREMENT = 144;
82 final static int TT_INCREMENT = 145;
83 final static int TT_ADDTO = 146;
84 final static int TT_DIVIDEBY = 147;
85 final static int TT_SUBTRACTFROM = 148;
86 final static int TT_TIMESBY = 149;
87 final static int TT_VARIABLE = 150;
88 final static int TT_INT_NUMBER = 151;
89 final static int TT_DOUBLE_NUMBER = 152;
90 final static int TT_INTERPOLATED_STRING = 153;
91 final static int TT_STRING_CONSTANT = 154;
92 // final static int TT_AT = 153; // @
97 *@param sess Description of Parameter
100 public PHPParser(String s, int rowCount) {
101 if (keywordMap == null) {
102 keywordMap = new HashMap();
103 for (int i = 0; i < PHP_KEYWORS.length; i++) {
104 keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
110 this.rowCount = rowCount;
111 this.columnCount = 0;
116 private void throwSyntaxError(String error) {
118 if (str.length() < chIndx) {
121 // read until end-of-line
123 while (str.length() > eol) {
124 ch = str.charAt(eol++);
130 throw new SyntaxError(rowCount, chIndx - columnCount, str.substring(columnCount + 1, eol), error);
134 * Method Declaration.
139 if (str.length() > chIndx) {
140 ch = str.charAt(chIndx++);
145 chIndx = str.length() + 1;
151 * gets the next token from input
153 void getNextToken() {
154 while (str.length() > chIndx) {
155 ch = str.charAt(chIndx++);
156 token = TT_UNDEFINED;
159 columnCount = chIndx;
160 continue; // while loop
163 if (!Character.isWhitespace(ch)) {
164 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$') || (ch == '@')) {
168 if (ch >= '0' && ch <= '9') {
173 if (str.length() > chIndx) {
174 if (str.charAt(chIndx) == '/') {
176 // read comment until end of line:
177 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
181 } else if (str.charAt(chIndx) == '*') {
183 // multi line comment:
184 while (str.length() > chIndx) {
185 if (str.charAt(chIndx) == '*' &&
186 (str.length() > (chIndx+1) ) &&
187 str.charAt(chIndx+1) == '/') {
196 } else if (ch == '#') {
197 // read comment until end of line:
198 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
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) {
209 if (str.length() > chIndx) {
213 if (str.charAt(chIndx) == '\n') {
215 columnCount = chIndx;
219 if (str.length() > chIndx) {
222 token = TT_INTERPOLATED_STRING;
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) {
231 if (str.length() > chIndx) {
236 if (str.length() > chIndx) {
239 token = TT_STRING_CONSTANT;
258 token = TT_LISTCLOSE;
266 token = TT_PARTCLOSE;
276 if (str.length() > chIndx) {
277 if (str.charAt(chIndx) == '=') {
279 token = TT_DOTASSIGN;
295 token = TT_SEMICOLON;
305 if (str.length() > chIndx) {
306 if (str.charAt(chIndx) == '=') {
317 if (str.length() > chIndx) {
318 if (str.charAt(chIndx) == '*') {
324 if (str.charAt(chIndx) == '=') {
335 if (str.length() > chIndx) {
336 if (str.charAt(chIndx) == '+') {
338 token = TT_INCREMENT;
342 if (str.charAt(chIndx) == '=') {
352 if (str.length() > chIndx) {
353 if (str.charAt(chIndx) == '-') {
355 token = TT_DECREMENT;
359 if (str.charAt(chIndx) == '=') {
361 token = TT_SUBTRACTFROM;
371 if (str.length() > chIndx) {
372 ch = str.charAt(chIndx);
392 if (str.length() > chIndx) {
393 if (str.charAt(chIndx) == '=') {
405 if (str.length() > chIndx) {
406 if (str.charAt(chIndx) == '=') {
408 token = TT_GREATEREQUAL;
418 if (str.length() > chIndx) {
419 if (str.charAt(chIndx) == '=') {
421 token = TT_LESSEQUAL;
430 if (str.length() > chIndx) {
431 if (str.charAt(chIndx++) == '|') {
440 if (str.length() > chIndx) {
441 if (str.charAt(chIndx++) == '&') {
462 throwSyntaxError("unexpected character: '" + ch + "'");
465 if (token == TT_UNDEFINED) {
466 throwSyntaxError("token not found");
473 chIndx = str.length() + 1;
478 void getIdentifier() {
479 StringBuffer ident = new StringBuffer();
486 token = TT_IDENTIFIER;
489 while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch >= '_')) {
493 identifier = ident.toString();
495 Integer i = (Integer) keywordMap.get(identifier);
497 token = i.intValue();
502 StringBuffer inum = new StringBuffer();
511 // determine number conversions:
512 if (firstCh == '0') {
541 if (numFormat == 16) {
542 while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
547 while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
548 if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
549 if (ch == '.' && dFlag != ' ') {
552 if ((dFlag == 'E') || (dFlag == 'e')) {
558 if ((ch == '-') || (ch == '+')) {
569 // token = TT_INT_NUMBER;
573 doubleNumber = new Double(inum.toString());
574 token = TT_DOUBLE_NUMBER;
577 longNumber = Long.valueOf(inum.toString(), numFormat);
578 token = TT_INT_NUMBER;
582 } catch (Throwable e) {
583 throwSyntaxError("Number format error: " + inum.toString());
587 public void start() throws SyntaxError {
589 if (token != TT_EOF) {
590 if (token == TT_ARGCLOSE) {
591 throwSyntaxError("too many closing ')'; end-of-file not reached");
593 if (token == TT_LISTCLOSE) {
594 throwSyntaxError("too many closing '}'; end-of-file not reached");
596 if (token == TT_PARTCLOSE) {
597 throwSyntaxError("too many closing ']'; end-of-file not reached");
600 throwSyntaxError("end-of-file not reached");
605 public void statementList() {
609 public void statement() {
610 while (token != TT_UNDEFINED) {
611 if (token > TT_KEYWORD) {
612 if (token == TT_case) {
615 if (token == TT_DDOT) {
619 throwSyntaxError("':' character after 'case' constant expected.");
622 } else if (token == TT_default) {
624 if (token == TT_DDOT) {
628 throwSyntaxError("':' character after 'default' expected.");
631 } else if (token == TT_include || token == TT_include_once) {
634 if (token == TT_SEMICOLON) {
637 throwSyntaxError("';' character after 'include' or 'include_once' expected.");
640 } else if (token == TT_require || token == TT_require_once) {
643 if (token == TT_SEMICOLON) {
646 throwSyntaxError("';' character after 'require' or 'require_once' expected.");
649 } else if (token == TT_if) {
651 if (token == TT_ARGOPEN) {
654 throwSyntaxError("'(' expected after 'if' keyword.");
657 if (token == TT_ARGCLOSE) {
660 throwSyntaxError("')' expected after 'if' condition.");
665 } else if (token == TT_switch) {
667 if (token == TT_ARGOPEN) {
670 throwSyntaxError("'(' expected after 'switch' keyword.");
673 if (token == TT_ARGCLOSE) {
676 throwSyntaxError("')' expected after 'switch' condition.");
680 } else if (token == TT_for) {
682 if (token == TT_ARGOPEN) {
685 throwSyntaxError("'(' expected after 'for' keyword.");
687 if (token == TT_SEMICOLON) {
691 if (token == TT_SEMICOLON) {
694 throwSyntaxError("';' character after 'for' expected.");
697 if (token == TT_SEMICOLON) {
701 if (token == TT_SEMICOLON) {
704 throwSyntaxError("';' character after 'for' expected.");
707 if (token == TT_ARGCLOSE) {
711 if (token == TT_ARGCLOSE) {
714 throwSyntaxError("')' expected after 'for' condition.");
719 } else if (token == TT_while) {
721 if (token == TT_ARGOPEN) {
724 throwSyntaxError("'(' expected after 'while' keyword.");
727 if (token == TT_ARGCLOSE) {
730 throwSyntaxError("')' expected after 'while' condition.");
734 } else if (token == TT_foreach) {
736 if (token == TT_ARGOPEN) {
739 throwSyntaxError("'(' expected after 'foreach' keyword.");
742 if (token == TT_as) {
745 throwSyntaxError("'as' expected after 'foreach' exxpression.");
748 if (token == TT_FOREACH) {
752 if (token == TT_ARGCLOSE) {
755 throwSyntaxError("')' expected after 'foreach' expression.");
760 } else if (token == TT_continue || token == TT_break || token == TT_return) {
762 if (token != TT_SEMICOLON) {
765 if (token == TT_SEMICOLON) {
768 throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
772 } else if (token == TT_echo) {
775 if (token == TT_SEMICOLON) {
778 throwSyntaxError("';' expected after 'echo' statement.");
782 } else if (token == TT_print) {
785 if (token == TT_SEMICOLON) {
788 throwSyntaxError("';' expected after 'print' statement.");
792 } else if (token == TT_global || token == TT_static) {
795 if (token == TT_SEMICOLON) {
798 throwSyntaxError("';' expected after 'global' or 'static' statement.");
802 } else if (token == TT_unset) {
804 if (token == TT_ARGOPEN) {
807 throwSyntaxError("'(' expected after 'unset' keyword.");
810 if (token == TT_ARGCLOSE) {
813 throwSyntaxError("')' expected after 'unset' statement.");
815 if (token == TT_SEMICOLON) {
818 throwSyntaxError("';' expected after 'unset' statement.");
822 } else if (token == TT_exit || token == TT_die) {
824 if (token != TT_SEMICOLON) {
827 if (token == TT_SEMICOLON) {
830 throwSyntaxError("';' expected after 'exit' or 'die' statement.");
834 } else if (token == TT_define) {
836 if (token == TT_ARGOPEN) {
839 throwSyntaxError("'(' expected after 'define' keyword.");
842 if (token == TT_COMMA) {
845 throwSyntaxError("',' expected after first 'define' constant.");
848 if (token == TT_ARGCLOSE) {
851 throwSyntaxError("')' expected after 'define' statement.");
853 if (token == TT_SEMICOLON) {
856 throwSyntaxError("';' expected after 'define' statement.");
863 if (token == TT_LISTOPEN) {
866 if (token == TT_LISTCLOSE) {
869 throwSyntaxError("'}' expected.");
874 if (token == TT_SEMICOLON) {
877 throwSyntaxError("';' expected after expression.");
882 public void labeledStatement() {
885 public void expressionStatement() {
888 public void inclusionStatement() {
891 public void compoundStatement() {
894 public void selectionStatement() {
897 public void iterationStatement() {
900 public void jumpStatement() {
903 public void outputStatement() {
906 public void scopeStatement() {
909 public void flowStatement() {
912 public void definitionStatement() {
915 public void ifStatement() {
918 public void switchStatement() {
921 public void forStatement() {
924 public void whileStatement() {
927 public void foreachStatement() {
930 public void exitStatus() {
931 if (token == TT_ARGOPEN) {
934 throwSyntaxError("'(' expected in 'exit-status'.");
936 if (token != TT_ARGCLOSE) {
939 if (token == TT_ARGCLOSE) {
942 throwSyntaxError("')' expected after 'exit-status'.");
946 public void expressionList() {
949 if (token == TT_COMMA) {
957 public void expression() {
958 if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
962 // while (token != TT_SEMICOLON) {
968 public void postfixExpression() {
972 public void variableList() {
975 if (token == TT_COMMA) {
983 public void variable() {
984 if (token == TT_VARIABLE) {
987 throwSyntaxError("$-variable expected in variable-list.");
991 public void constant() {