|
1 /* |
|
2 * Copyright 1994-2004 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package sun.tools.java; |
|
27 |
|
28 import sun.tools.tree.*; |
|
29 import java.io.IOException; |
|
30 import java.io.InputStream; |
|
31 import java.util.Enumeration; |
|
32 import java.util.Vector; |
|
33 |
|
34 /** |
|
35 * This class is used to parse Java statements and expressions. |
|
36 * The result is a parse tree.<p> |
|
37 * |
|
38 * This class implements an operator precedence parser. Errors are |
|
39 * reported to the Environment object, if the error can't be |
|
40 * resolved immediately, a SyntaxError exception is thrown.<p> |
|
41 * |
|
42 * Error recovery is implemented by catching SyntaxError exceptions |
|
43 * and discarding input tokens until an input token is reached that |
|
44 * is possibly a legal continuation.<p> |
|
45 * |
|
46 * The parse tree that is constructed represents the input |
|
47 * exactly (no rewrites to simpler forms). This is important |
|
48 * if the resulting tree is to be used for code formatting in |
|
49 * a programming environment. Currently only documentation comments |
|
50 * are retained.<p> |
|
51 * |
|
52 * The parsing algorithm does NOT use any type information. Changes |
|
53 * in the type system do not affect the structure of the parse tree. |
|
54 * This restriction does introduce an ambiguity an expression of the |
|
55 * form: (e1) e2 is assumed to be a cast if e2 does not start with |
|
56 * an operator. That means that (a) - b is interpreted as subtract |
|
57 * b from a and not cast negative b to type a. However, if a is a |
|
58 * simple type (byte, int, ...) then it is assumed to be a cast.<p> |
|
59 * |
|
60 * WARNING: The contents of this source file are not part of any |
|
61 * supported API. Code that depends on them does so at its own risk: |
|
62 * they are subject to change or removal without notice. |
|
63 * |
|
64 * @author Arthur van Hoff |
|
65 */ |
|
66 |
|
67 public |
|
68 class Parser extends Scanner implements ParserActions, Constants { |
|
69 /** |
|
70 * Create a parser |
|
71 */ |
|
72 protected Parser(Environment env, InputStream in) throws IOException { |
|
73 super(env, in); |
|
74 this.scanner = this; |
|
75 this.actions = this; |
|
76 } |
|
77 |
|
78 /** |
|
79 * Create a parser, given a scanner. |
|
80 */ |
|
81 protected Parser(Scanner scanner) throws IOException { |
|
82 super(scanner.env); |
|
83 this.scanner = scanner; |
|
84 ((Scanner)this).env = scanner.env; |
|
85 ((Scanner)this).token = scanner.token; |
|
86 ((Scanner)this).pos = scanner.pos; |
|
87 this.actions = this; |
|
88 } |
|
89 |
|
90 /** |
|
91 * Create a parser, given a scanner and the semantic callback. |
|
92 */ |
|
93 public Parser(Scanner scanner, ParserActions actions) throws IOException { |
|
94 this(scanner); |
|
95 this.actions = actions; |
|
96 } |
|
97 |
|
98 /** |
|
99 * Usually <code>this.actions == (ParserActions)this</code>. |
|
100 * However, a delegate scanner can produce tokens for this parser, |
|
101 * in which case <code>(Scanner)this</code> is unused, |
|
102 * except for <code>this.token</code> and <code>this.pos</code> |
|
103 * instance variables which are filled from the real scanner |
|
104 * by <code>this.scan()</code> and the constructor. |
|
105 */ |
|
106 ParserActions actions; |
|
107 |
|
108 // Note: The duplication of methods allows pre-1.1 classes to |
|
109 // be binary compatible with the new version of the parser, |
|
110 // which now passes IdentifierTokens to the semantics phase, |
|
111 // rather than just Identifiers. This change is necessary, |
|
112 // since the parser is no longer responsible for managing the |
|
113 // resolution of type names. (That caused the "Vector" bug.) |
|
114 // |
|
115 // In a future release, the old "plain-Identifier" methods will |
|
116 // go away, and the corresponding "IdentifierToken" methods |
|
117 // may become abstract. |
|
118 |
|
119 /** |
|
120 * package declaration |
|
121 * @deprecated |
|
122 */ |
|
123 @Deprecated |
|
124 public void packageDeclaration(long off, IdentifierToken nm) { |
|
125 // By default, call the deprecated version. |
|
126 // Any application must override one of the packageDeclaration methods. |
|
127 packageDeclaration(off, nm.id); |
|
128 } |
|
129 /** |
|
130 * @deprecated |
|
131 */ |
|
132 @Deprecated |
|
133 protected void packageDeclaration(long off, Identifier nm) { |
|
134 throw new RuntimeException("beginClass method is abstract"); |
|
135 } |
|
136 |
|
137 /** |
|
138 * import class |
|
139 * @deprecated |
|
140 */ |
|
141 @Deprecated |
|
142 public void importClass(long off, IdentifierToken nm) { |
|
143 // By default, call the deprecated version. |
|
144 // Any application must override one of the packageDeclaration methods. |
|
145 importClass(off, nm.id); |
|
146 } |
|
147 /** |
|
148 * @deprecated Use the version with the IdentifierToken arguments. |
|
149 */ |
|
150 @Deprecated |
|
151 protected void importClass(long off, Identifier nm) { |
|
152 throw new RuntimeException("importClass method is abstract"); |
|
153 } |
|
154 |
|
155 /** |
|
156 * import package |
|
157 * @deprecated |
|
158 */ |
|
159 @Deprecated |
|
160 public void importPackage(long off, IdentifierToken nm) { |
|
161 // By default, call the deprecated version. |
|
162 // Any application must override one of the importPackage methods. |
|
163 importPackage(off, nm.id); |
|
164 } |
|
165 /** |
|
166 * @deprecated Use the version with the IdentifierToken arguments. |
|
167 */ |
|
168 @Deprecated |
|
169 protected void importPackage(long off, Identifier nm) { |
|
170 throw new RuntimeException("importPackage method is abstract"); |
|
171 } |
|
172 |
|
173 /** |
|
174 * Define class |
|
175 * @deprecated |
|
176 */ |
|
177 @Deprecated |
|
178 public ClassDefinition beginClass(long off, String doc, |
|
179 int mod, IdentifierToken nm, |
|
180 IdentifierToken sup, |
|
181 IdentifierToken impl[]) { |
|
182 // By default, call the deprecated version. |
|
183 // Any application must override one of the beginClass methods. |
|
184 Identifier supId = (sup == null) ? null : sup.id; |
|
185 Identifier implIds[] = null; |
|
186 if (impl != null) { |
|
187 implIds = new Identifier[impl.length]; |
|
188 for (int i = 0; i < impl.length; i++) { |
|
189 implIds[i] = impl[i].id; |
|
190 } |
|
191 } |
|
192 beginClass(off, doc, mod, nm.id, supId, implIds); |
|
193 return getCurrentClass(); |
|
194 } |
|
195 /** |
|
196 * @deprecated Use the version with the IdentifierToken arguments. |
|
197 */ |
|
198 @Deprecated |
|
199 protected void beginClass(long off, String doc, int mod, Identifier nm, |
|
200 Identifier sup, Identifier impl[]) { |
|
201 throw new RuntimeException("beginClass method is abstract"); |
|
202 } |
|
203 |
|
204 /** |
|
205 * Report the current class under construction. |
|
206 * By default, it's a no-op which returns null. |
|
207 * It may only be called before the corresponding endClass(). |
|
208 */ |
|
209 protected ClassDefinition getCurrentClass() { |
|
210 return null; |
|
211 } |
|
212 |
|
213 /** |
|
214 * End class |
|
215 * @deprecated |
|
216 */ |
|
217 @Deprecated |
|
218 public void endClass(long off, ClassDefinition c) { |
|
219 // By default, call the deprecated version. |
|
220 // Any application must override one of the beginClass methods. |
|
221 endClass(off, c.getName().getFlatName().getName()); |
|
222 } |
|
223 /** |
|
224 * @deprecated Use the version with the IdentifierToken arguments. |
|
225 */ |
|
226 @Deprecated |
|
227 protected void endClass(long off, Identifier nm) { |
|
228 throw new RuntimeException("endClass method is abstract"); |
|
229 } |
|
230 |
|
231 /** |
|
232 * Define a field |
|
233 * @deprecated |
|
234 */ |
|
235 @Deprecated |
|
236 public void defineField(long where, ClassDefinition c, |
|
237 String doc, int mod, Type t, |
|
238 IdentifierToken nm, IdentifierToken args[], |
|
239 IdentifierToken exp[], Node val) { |
|
240 // By default, call the deprecated version. |
|
241 // Any application must override one of the defineField methods. |
|
242 Identifier argIds[] = null; |
|
243 Identifier expIds[] = null; |
|
244 if (args != null) { |
|
245 argIds = new Identifier[args.length]; |
|
246 for (int i = 0; i < args.length; i++) { |
|
247 argIds[i] = args[i].id; |
|
248 } |
|
249 } |
|
250 if (exp != null) { |
|
251 expIds = new Identifier[exp.length]; |
|
252 for (int i = 0; i < exp.length; i++) { |
|
253 expIds[i] = exp[i].id; |
|
254 } |
|
255 } |
|
256 defineField(where, doc, mod, t, nm.id, argIds, expIds, val); |
|
257 } |
|
258 |
|
259 /** |
|
260 * @deprecated Use the version with the IdentifierToken arguments. |
|
261 */ |
|
262 @Deprecated |
|
263 protected void defineField(long where, String doc, int mod, Type t, |
|
264 Identifier nm, Identifier args[], |
|
265 Identifier exp[], Node val) { |
|
266 throw new RuntimeException("defineField method is abstract"); |
|
267 } |
|
268 |
|
269 /* |
|
270 * A growable array of nodes. It is used as a growable |
|
271 * buffer to hold argument lists and expression lists. |
|
272 * I'm not using Vector to make it more efficient. |
|
273 */ |
|
274 private Node args[] = new Node[32]; |
|
275 protected int argIndex = 0; |
|
276 |
|
277 protected final void addArgument(Node n) { |
|
278 if (argIndex == args.length) { |
|
279 Node newArgs[] = new Node[args.length * 2]; |
|
280 System.arraycopy(args, 0, newArgs, 0, args.length); |
|
281 args = newArgs; |
|
282 } |
|
283 args[argIndex++] = n; |
|
284 } |
|
285 protected final Expression exprArgs(int index)[] { |
|
286 Expression e[] = new Expression[argIndex - index]; |
|
287 System.arraycopy(args, index, e, 0, argIndex - index); |
|
288 argIndex = index; |
|
289 return e; |
|
290 } |
|
291 protected final Statement statArgs(int index)[] { |
|
292 Statement s[] = new Statement[argIndex - index]; |
|
293 System.arraycopy(args, index, s, 0, argIndex - index); |
|
294 argIndex = index; |
|
295 return s; |
|
296 } |
|
297 |
|
298 /** |
|
299 * Expect a token, return its value, scan the next token or |
|
300 * throw an exception. |
|
301 */ |
|
302 protected void expect(int t) throws SyntaxError, IOException { |
|
303 if (token != t) { |
|
304 switch (t) { |
|
305 case IDENT: |
|
306 env.error(scanner.prevPos, "identifier.expected"); |
|
307 break; |
|
308 default: |
|
309 env.error(scanner.prevPos, "token.expected", opNames[t]); |
|
310 break; |
|
311 } |
|
312 throw new SyntaxError(); |
|
313 } |
|
314 scan(); |
|
315 } |
|
316 |
|
317 /** |
|
318 * Parse a type expression. Does not parse the []'s. |
|
319 */ |
|
320 protected Expression parseTypeExpression() throws SyntaxError, IOException { |
|
321 switch (token) { |
|
322 case VOID: |
|
323 return new TypeExpression(scan(), Type.tVoid); |
|
324 case BOOLEAN: |
|
325 return new TypeExpression(scan(), Type.tBoolean); |
|
326 case BYTE: |
|
327 return new TypeExpression(scan(), Type.tByte); |
|
328 case CHAR: |
|
329 return new TypeExpression(scan(), Type.tChar); |
|
330 case SHORT: |
|
331 return new TypeExpression(scan(), Type.tShort); |
|
332 case INT: |
|
333 return new TypeExpression(scan(), Type.tInt); |
|
334 case LONG: |
|
335 return new TypeExpression(scan(), Type.tLong); |
|
336 case FLOAT: |
|
337 return new TypeExpression(scan(), Type.tFloat); |
|
338 case DOUBLE: |
|
339 return new TypeExpression(scan(), Type.tDouble); |
|
340 case IDENT: |
|
341 Expression e = new IdentifierExpression(pos, scanner.idValue); |
|
342 scan(); |
|
343 while (token == FIELD) { |
|
344 e = new FieldExpression(scan(), e, scanner.idValue); |
|
345 expect(IDENT); |
|
346 } |
|
347 return e; |
|
348 } |
|
349 |
|
350 env.error(pos, "type.expected"); |
|
351 throw new SyntaxError(); |
|
352 } |
|
353 |
|
354 /** |
|
355 * Parse a method invocation. Should be called when the current |
|
356 * then is the '(' of the argument list. |
|
357 */ |
|
358 protected Expression parseMethodExpression(Expression e, Identifier id) throws SyntaxError, IOException { |
|
359 long p = scan(); |
|
360 int i = argIndex; |
|
361 if (token != RPAREN) { |
|
362 addArgument(parseExpression()); |
|
363 while (token == COMMA) { |
|
364 scan(); |
|
365 addArgument(parseExpression()); |
|
366 } |
|
367 } |
|
368 expect(RPAREN); |
|
369 return new MethodExpression(p, e, id, exprArgs(i)); |
|
370 } |
|
371 |
|
372 /** |
|
373 * Parse a new instance expression. Should be called when the current |
|
374 * token is the '(' of the argument list. |
|
375 */ |
|
376 protected Expression parseNewInstanceExpression(long p, Expression outerArg, Expression type) throws SyntaxError, IOException { |
|
377 int i = argIndex; |
|
378 expect(LPAREN); |
|
379 if (token != RPAREN) { |
|
380 addArgument(parseExpression()); |
|
381 while (token == COMMA) { |
|
382 scan(); |
|
383 addArgument(parseExpression()); |
|
384 } |
|
385 } |
|
386 expect(RPAREN); |
|
387 ClassDefinition body = null; |
|
388 if (token == LBRACE && !(type instanceof TypeExpression)) { |
|
389 long tp = pos; |
|
390 // x = new Type(arg) { subclass body ... } |
|
391 Identifier superName = FieldExpression.toIdentifier(type); |
|
392 if (superName == null) { |
|
393 env.error(type.getWhere(), "type.expected"); |
|
394 } |
|
395 Vector ext = new Vector(1); |
|
396 Vector impl = new Vector(0); |
|
397 ext.addElement(new IdentifierToken(idNull)); |
|
398 if (token == IMPLEMENTS || token == EXTENDS) { |
|
399 env.error(pos, "anonymous.extends"); |
|
400 parseInheritance(ext, impl); // error recovery |
|
401 } |
|
402 body = parseClassBody(new IdentifierToken(tp, idNull), |
|
403 M_ANONYMOUS | M_LOCAL, EXPR, null, |
|
404 ext, impl, type.getWhere()); |
|
405 } |
|
406 if (outerArg == null && body == null) { |
|
407 return new NewInstanceExpression(p, type, exprArgs(i)); |
|
408 } |
|
409 return new NewInstanceExpression(p, type, exprArgs(i), outerArg, body); |
|
410 } |
|
411 |
|
412 /** |
|
413 * Parse a primary expression. |
|
414 */ |
|
415 protected Expression parseTerm() throws SyntaxError, IOException { |
|
416 switch (token) { |
|
417 case CHARVAL: { |
|
418 char v = scanner.charValue; |
|
419 return new CharExpression(scan(), v); |
|
420 } |
|
421 case INTVAL: { |
|
422 int v = scanner.intValue; |
|
423 long q = scan(); |
|
424 if (v < 0 && radix == 10) env.error(q, "overflow.int.dec"); |
|
425 return new IntExpression(q, v); |
|
426 } |
|
427 case LONGVAL: { |
|
428 long v = scanner.longValue; |
|
429 long q = scan(); |
|
430 if (v < 0 && radix == 10) env.error(q, "overflow.long.dec"); |
|
431 return new LongExpression(q, v); |
|
432 } |
|
433 case FLOATVAL: { |
|
434 float v = scanner.floatValue; |
|
435 return new FloatExpression(scan(), v); |
|
436 } |
|
437 case DOUBLEVAL: { |
|
438 double v = scanner.doubleValue; |
|
439 return new DoubleExpression(scan(), v); |
|
440 } |
|
441 case STRINGVAL: { |
|
442 String v = scanner.stringValue; |
|
443 return new StringExpression(scan(), v); |
|
444 } |
|
445 case IDENT: { |
|
446 Identifier v = scanner.idValue; |
|
447 long p = scan(); |
|
448 return (token == LPAREN) ? |
|
449 parseMethodExpression(null, v) : new IdentifierExpression(p, v); |
|
450 } |
|
451 |
|
452 case TRUE: |
|
453 return new BooleanExpression(scan(), true); |
|
454 case FALSE: |
|
455 return new BooleanExpression(scan(), false); |
|
456 case NULL: |
|
457 return new NullExpression(scan()); |
|
458 |
|
459 case THIS: { |
|
460 Expression e = new ThisExpression(scan()); |
|
461 return (token == LPAREN) ? parseMethodExpression(e, idInit) : e; |
|
462 } |
|
463 case SUPER: { |
|
464 Expression e = new SuperExpression(scan()); |
|
465 return (token == LPAREN) ? parseMethodExpression(e, idInit) : e; |
|
466 } |
|
467 |
|
468 case VOID: |
|
469 case BOOLEAN: |
|
470 case BYTE: |
|
471 case CHAR: |
|
472 case SHORT: |
|
473 case INT: |
|
474 case LONG: |
|
475 case FLOAT: |
|
476 case DOUBLE: |
|
477 return parseTypeExpression(); |
|
478 |
|
479 case ADD: { |
|
480 long p = scan(); |
|
481 switch (token) { |
|
482 case INTVAL: { |
|
483 int v = scanner.intValue; |
|
484 long q = scan(); |
|
485 if (v < 0 && radix == 10) env.error(q, "overflow.int.dec"); |
|
486 return new IntExpression(q, v); |
|
487 } |
|
488 case LONGVAL: { |
|
489 long v = scanner.longValue; |
|
490 long q = scan(); |
|
491 if (v < 0 && radix == 10) env.error(q, "overflow.long.dec"); |
|
492 return new LongExpression(q, v); |
|
493 } |
|
494 case FLOATVAL: { |
|
495 float v = scanner.floatValue; |
|
496 return new FloatExpression(scan(), v); |
|
497 } |
|
498 case DOUBLEVAL: { |
|
499 double v = scanner.doubleValue; |
|
500 return new DoubleExpression(scan(), v); |
|
501 } |
|
502 } |
|
503 return new PositiveExpression(p, parseTerm()); |
|
504 } |
|
505 case SUB: { |
|
506 long p = scan(); |
|
507 switch (token) { |
|
508 case INTVAL: { |
|
509 int v = -scanner.intValue; |
|
510 return new IntExpression(scan(), v); |
|
511 } |
|
512 case LONGVAL: { |
|
513 long v = -scanner.longValue; |
|
514 return new LongExpression(scan(), v); |
|
515 } |
|
516 case FLOATVAL: { |
|
517 float v = -scanner.floatValue; |
|
518 return new FloatExpression(scan(), v); |
|
519 } |
|
520 case DOUBLEVAL: { |
|
521 double v = -scanner.doubleValue; |
|
522 return new DoubleExpression(scan(), v); |
|
523 } |
|
524 } |
|
525 return new NegativeExpression(p, parseTerm()); |
|
526 } |
|
527 case NOT: |
|
528 return new NotExpression(scan(), parseTerm()); |
|
529 case BITNOT: |
|
530 return new BitNotExpression(scan(), parseTerm()); |
|
531 case INC: |
|
532 return new PreIncExpression(scan(), parseTerm()); |
|
533 case DEC: |
|
534 return new PreDecExpression(scan(), parseTerm()); |
|
535 |
|
536 case LPAREN: { |
|
537 // bracketed-expr: (expr) |
|
538 long p = scan(); |
|
539 Expression e = parseExpression(); |
|
540 expect(RPAREN); |
|
541 |
|
542 if (e.getOp() == TYPE) { |
|
543 // cast-expr: (simple-type) expr |
|
544 return new CastExpression(p, e, parseTerm()); |
|
545 } |
|
546 |
|
547 switch (token) { |
|
548 |
|
549 // We handle INC and DEC specially. |
|
550 // See the discussion in JLS section 15.14.1. |
|
551 // (Part of fix for 4044502.) |
|
552 |
|
553 case INC: |
|
554 // We know this must be a postfix increment. |
|
555 return new PostIncExpression(scan(), e); |
|
556 |
|
557 case DEC: |
|
558 // We know this must be a postfix decrement. |
|
559 return new PostDecExpression(scan(), e); |
|
560 |
|
561 case LPAREN: |
|
562 case CHARVAL: |
|
563 case INTVAL: |
|
564 case LONGVAL: |
|
565 case FLOATVAL: |
|
566 case DOUBLEVAL: |
|
567 case STRINGVAL: |
|
568 case IDENT: |
|
569 case TRUE: |
|
570 case FALSE: |
|
571 case NOT: |
|
572 case BITNOT: |
|
573 case THIS: |
|
574 case SUPER: |
|
575 case NULL: |
|
576 case NEW: |
|
577 // cast-expr: (expr) expr |
|
578 return new CastExpression(p, e, parseTerm()); |
|
579 } |
|
580 return new ExprExpression(p, e); |
|
581 } |
|
582 |
|
583 case LBRACE: { |
|
584 // array initializer: {expr1, expr2, ... exprn} |
|
585 long p = scan(); |
|
586 int i = argIndex; |
|
587 if (token != RBRACE) { |
|
588 addArgument(parseExpression()); |
|
589 while (token == COMMA) { |
|
590 scan(); |
|
591 if (token == RBRACE) { |
|
592 break; |
|
593 } |
|
594 addArgument(parseExpression()); |
|
595 } |
|
596 } |
|
597 expect(RBRACE); |
|
598 return new ArrayExpression(p, exprArgs(i)); |
|
599 } |
|
600 |
|
601 case NEW: { |
|
602 long p = scan(); |
|
603 int i = argIndex; |
|
604 |
|
605 if (token == LPAREN) { |
|
606 scan(); |
|
607 Expression e = parseExpression(); |
|
608 expect(RPAREN); |
|
609 env.error(p, "not.supported", "new(...)"); |
|
610 return new NullExpression(p); |
|
611 } |
|
612 |
|
613 Expression e = parseTypeExpression(); |
|
614 |
|
615 if (token == LSQBRACKET) { |
|
616 while (token == LSQBRACKET) { |
|
617 scan(); |
|
618 addArgument((token != RSQBRACKET) ? parseExpression() : null); |
|
619 expect(RSQBRACKET); |
|
620 } |
|
621 Expression[] dims = exprArgs(i); |
|
622 if (token == LBRACE) { |
|
623 return new NewArrayExpression(p, e, dims, parseTerm()); |
|
624 } |
|
625 return new NewArrayExpression(p, e, dims); |
|
626 } else { |
|
627 return parseNewInstanceExpression(p, null, e); |
|
628 } |
|
629 } |
|
630 } |
|
631 |
|
632 // System.err.println("NEAR: " + opNames[token]); |
|
633 env.error(scanner.prevPos, "missing.term"); |
|
634 return new IntExpression(pos, 0); |
|
635 } |
|
636 |
|
637 /** |
|
638 * Parse an expression. |
|
639 */ |
|
640 protected Expression parseExpression() throws SyntaxError, IOException { |
|
641 for (Expression e = parseTerm() ; e != null ; e = e.order()) { |
|
642 Expression more = parseBinaryExpression(e); |
|
643 if (more == null) |
|
644 return e; |
|
645 e = more; |
|
646 } |
|
647 // this return is bogus |
|
648 return null; |
|
649 } |
|
650 |
|
651 /** |
|
652 * Given a left-hand term, parse an operator and right-hand term. |
|
653 */ |
|
654 protected Expression parseBinaryExpression(Expression e) throws SyntaxError, IOException { |
|
655 if (e != null) { |
|
656 switch (token) { |
|
657 case LSQBRACKET: { |
|
658 // index: expr1[expr2] |
|
659 long p = scan(); |
|
660 Expression index = (token != RSQBRACKET) ? parseExpression() : null; |
|
661 expect(RSQBRACKET); |
|
662 e = new ArrayAccessExpression(p, e, index); |
|
663 break; |
|
664 } |
|
665 |
|
666 case INC: |
|
667 e = new PostIncExpression(scan(), e); |
|
668 break; |
|
669 case DEC: |
|
670 e = new PostDecExpression(scan(), e); |
|
671 break; |
|
672 case FIELD: { |
|
673 long p = scan(); |
|
674 if (token == THIS) { |
|
675 // class C { class N { ... C.this ... } } |
|
676 // class C { class N { N(C c){ ... c.this() ... } } } |
|
677 long q = scan(); |
|
678 if (token == LPAREN) { |
|
679 e = new ThisExpression(q, e); |
|
680 e = parseMethodExpression(e, idInit); |
|
681 } else { |
|
682 e = new FieldExpression(p, e, idThis); |
|
683 } |
|
684 break; |
|
685 } |
|
686 if (token == SUPER) { |
|
687 // class D extends C.N { D(C.N n) { n.super(); } } |
|
688 // Also, 'C.super', as in: |
|
689 // class C extends CS { class N { ... C.super.foo ... } } |
|
690 // class C extends CS { class N { ... C.super.foo() ... } } |
|
691 long q = scan(); |
|
692 if (token == LPAREN) { |
|
693 e = new SuperExpression(q, e); |
|
694 e = parseMethodExpression(e, idInit); |
|
695 } else { |
|
696 // We must check elsewhere that this expression |
|
697 // does not stand alone, but qualifies a member name. |
|
698 e = new FieldExpression(p, e, idSuper); |
|
699 } |
|
700 break; |
|
701 } |
|
702 if (token == NEW) { |
|
703 // new C().new N() |
|
704 scan(); |
|
705 if (token != IDENT) |
|
706 expect(IDENT); |
|
707 e = parseNewInstanceExpression(p, e, parseTypeExpression()); |
|
708 break; |
|
709 } |
|
710 if (token == CLASS) { |
|
711 // just class literals, really |
|
712 // Class c = C.class; |
|
713 scan(); |
|
714 e = new FieldExpression(p, e, idClass); |
|
715 break; |
|
716 } |
|
717 Identifier id = scanner.idValue; |
|
718 expect(IDENT); |
|
719 if (token == LPAREN) { |
|
720 e = parseMethodExpression(e, id); |
|
721 } else { |
|
722 e = new FieldExpression(p, e, id); |
|
723 } |
|
724 break; |
|
725 } |
|
726 case INSTANCEOF: |
|
727 e = new InstanceOfExpression(scan(), e, parseTerm()); |
|
728 break; |
|
729 case ADD: |
|
730 e = new AddExpression(scan(), e, parseTerm()); |
|
731 break; |
|
732 case SUB: |
|
733 e = new SubtractExpression(scan(), e, parseTerm()); |
|
734 break; |
|
735 case MUL: |
|
736 e = new MultiplyExpression(scan(), e, parseTerm()); |
|
737 break; |
|
738 case DIV: |
|
739 e = new DivideExpression(scan(), e, parseTerm()); |
|
740 break; |
|
741 case REM: |
|
742 e = new RemainderExpression(scan(), e, parseTerm()); |
|
743 break; |
|
744 case LSHIFT: |
|
745 e = new ShiftLeftExpression(scan(), e, parseTerm()); |
|
746 break; |
|
747 case RSHIFT: |
|
748 e = new ShiftRightExpression(scan(), e, parseTerm()); |
|
749 break; |
|
750 case URSHIFT: |
|
751 e = new UnsignedShiftRightExpression(scan(), e, parseTerm()); |
|
752 break; |
|
753 case LT: |
|
754 e = new LessExpression(scan(), e, parseTerm()); |
|
755 break; |
|
756 case LE: |
|
757 e = new LessOrEqualExpression(scan(), e, parseTerm()); |
|
758 break; |
|
759 case GT: |
|
760 e = new GreaterExpression(scan(), e, parseTerm()); |
|
761 break; |
|
762 case GE: |
|
763 e = new GreaterOrEqualExpression(scan(), e, parseTerm()); |
|
764 break; |
|
765 case EQ: |
|
766 e = new EqualExpression(scan(), e, parseTerm()); |
|
767 break; |
|
768 case NE: |
|
769 e = new NotEqualExpression(scan(), e, parseTerm()); |
|
770 break; |
|
771 case BITAND: |
|
772 e = new BitAndExpression(scan(), e, parseTerm()); |
|
773 break; |
|
774 case BITXOR: |
|
775 e = new BitXorExpression(scan(), e, parseTerm()); |
|
776 break; |
|
777 case BITOR: |
|
778 e = new BitOrExpression(scan(), e, parseTerm()); |
|
779 break; |
|
780 case AND: |
|
781 e = new AndExpression(scan(), e, parseTerm()); |
|
782 break; |
|
783 case OR: |
|
784 e = new OrExpression(scan(), e, parseTerm()); |
|
785 break; |
|
786 case ASSIGN: |
|
787 e = new AssignExpression(scan(), e, parseTerm()); |
|
788 break; |
|
789 case ASGMUL: |
|
790 e = new AssignMultiplyExpression(scan(), e, parseTerm()); |
|
791 break; |
|
792 case ASGDIV: |
|
793 e = new AssignDivideExpression(scan(), e, parseTerm()); |
|
794 break; |
|
795 case ASGREM: |
|
796 e = new AssignRemainderExpression(scan(), e, parseTerm()); |
|
797 break; |
|
798 case ASGADD: |
|
799 e = new AssignAddExpression(scan(), e, parseTerm()); |
|
800 break; |
|
801 case ASGSUB: |
|
802 e = new AssignSubtractExpression(scan(), e, parseTerm()); |
|
803 break; |
|
804 case ASGLSHIFT: |
|
805 e = new AssignShiftLeftExpression(scan(), e, parseTerm()); |
|
806 break; |
|
807 case ASGRSHIFT: |
|
808 e = new AssignShiftRightExpression(scan(), e, parseTerm()); |
|
809 break; |
|
810 case ASGURSHIFT: |
|
811 e = new AssignUnsignedShiftRightExpression(scan(), e, parseTerm()); |
|
812 break; |
|
813 case ASGBITAND: |
|
814 e = new AssignBitAndExpression(scan(), e, parseTerm()); |
|
815 break; |
|
816 case ASGBITOR: |
|
817 e = new AssignBitOrExpression(scan(), e, parseTerm()); |
|
818 break; |
|
819 case ASGBITXOR: |
|
820 e = new AssignBitXorExpression(scan(), e, parseTerm()); |
|
821 break; |
|
822 case QUESTIONMARK: { |
|
823 long p = scan(); |
|
824 Expression second = parseExpression(); |
|
825 expect(COLON); |
|
826 Expression third = parseExpression(); |
|
827 |
|
828 // The grammar in the JLS does not allow assignment |
|
829 // expressions as the third part of a ?: expression. |
|
830 // Even though javac has no trouble parsing this, |
|
831 // check for this case and signal an error. |
|
832 // (fix for bug 4092958) |
|
833 if (third instanceof AssignExpression |
|
834 || third instanceof AssignOpExpression) { |
|
835 env.error(third.getWhere(), "assign.in.conditionalexpr"); |
|
836 } |
|
837 |
|
838 e = new ConditionalExpression(p, e, second, third); |
|
839 break; |
|
840 } |
|
841 |
|
842 default: |
|
843 return null; // mark end of binary expressions |
|
844 } |
|
845 } |
|
846 return e; // return more binary expression stuff |
|
847 } |
|
848 |
|
849 /** |
|
850 * Recover after a syntax error in a statement. This involves |
|
851 * discarding tokens until EOF or a possible continuation is |
|
852 * encountered. |
|
853 */ |
|
854 protected boolean recoverStatement() throws SyntaxError, IOException { |
|
855 while (true) { |
|
856 switch (token) { |
|
857 case EOF: |
|
858 case RBRACE: |
|
859 case LBRACE: |
|
860 case IF: |
|
861 case FOR: |
|
862 case WHILE: |
|
863 case DO: |
|
864 case TRY: |
|
865 case CATCH: |
|
866 case FINALLY: |
|
867 case BREAK: |
|
868 case CONTINUE: |
|
869 case RETURN: |
|
870 // begin of a statement, return |
|
871 return true; |
|
872 |
|
873 case VOID: |
|
874 case STATIC: |
|
875 case PUBLIC: |
|
876 case PRIVATE: |
|
877 case SYNCHRONIZED: |
|
878 case INTERFACE: |
|
879 case CLASS: |
|
880 case TRANSIENT: |
|
881 // begin of something outside a statement, panic some more |
|
882 expect(RBRACE); |
|
883 return false; |
|
884 |
|
885 case LPAREN: |
|
886 match(LPAREN, RPAREN); |
|
887 scan(); |
|
888 break; |
|
889 |
|
890 case LSQBRACKET: |
|
891 match(LSQBRACKET, RSQBRACKET); |
|
892 scan(); |
|
893 break; |
|
894 |
|
895 default: |
|
896 // don't know what to do, skip |
|
897 scan(); |
|
898 break; |
|
899 } |
|
900 } |
|
901 } |
|
902 |
|
903 /** |
|
904 * Parse declaration, called after the type expression |
|
905 * has been parsed and the current token is IDENT. |
|
906 */ |
|
907 protected Statement parseDeclaration(long p, int mod, Expression type) throws SyntaxError, IOException { |
|
908 int i = argIndex; |
|
909 if (token == IDENT) { |
|
910 addArgument(new VarDeclarationStatement(pos, parseExpression())); |
|
911 while (token == COMMA) { |
|
912 scan(); |
|
913 addArgument(new VarDeclarationStatement(pos, parseExpression())); |
|
914 } |
|
915 } |
|
916 return new DeclarationStatement(p, mod, type, statArgs(i)); |
|
917 } |
|
918 |
|
919 /** |
|
920 * Check if an expression is a legal toplevel expression. |
|
921 * Only method, inc, dec, and new expression are allowed. |
|
922 */ |
|
923 protected void topLevelExpression(Expression e) { |
|
924 switch (e.getOp()) { |
|
925 case ASSIGN: |
|
926 case ASGMUL: |
|
927 case ASGDIV: |
|
928 case ASGREM: |
|
929 case ASGADD: |
|
930 case ASGSUB: |
|
931 case ASGLSHIFT: |
|
932 case ASGRSHIFT: |
|
933 case ASGURSHIFT: |
|
934 case ASGBITAND: |
|
935 case ASGBITOR: |
|
936 case ASGBITXOR: |
|
937 case PREINC: |
|
938 case PREDEC: |
|
939 case POSTINC: |
|
940 case POSTDEC: |
|
941 case METHOD: |
|
942 case NEWINSTANCE: |
|
943 return; |
|
944 } |
|
945 env.error(e.getWhere(), "invalid.expr"); |
|
946 } |
|
947 |
|
948 /** |
|
949 * Parse a statement. |
|
950 */ |
|
951 protected Statement parseStatement() throws SyntaxError, IOException { |
|
952 switch (token) { |
|
953 case SEMICOLON: |
|
954 return new CompoundStatement(scan(), new Statement[0]); |
|
955 |
|
956 case LBRACE: |
|
957 return parseBlockStatement(); |
|
958 |
|
959 case IF: { |
|
960 // if-statement: if (expr) stat |
|
961 // if-statement: if (expr) stat else stat |
|
962 long p = scan(); |
|
963 |
|
964 expect(LPAREN); |
|
965 Expression c = parseExpression(); |
|
966 expect(RPAREN); |
|
967 Statement t = parseStatement(); |
|
968 if (token == ELSE) { |
|
969 scan(); |
|
970 return new IfStatement(p, c, t, parseStatement()); |
|
971 } else { |
|
972 return new IfStatement(p, c, t, null); |
|
973 } |
|
974 } |
|
975 |
|
976 case ELSE: { |
|
977 // else-statement: else stat |
|
978 env.error(scan(), "else.without.if"); |
|
979 return parseStatement(); |
|
980 } |
|
981 |
|
982 case FOR: { |
|
983 // for-statement: for (decl-expr? ; expr? ; expr?) stat |
|
984 long p = scan(); |
|
985 Statement init = null; |
|
986 Expression cond = null, inc = null; |
|
987 |
|
988 expect(LPAREN); |
|
989 if (token != SEMICOLON) { |
|
990 long p2 = pos; |
|
991 int mod = parseModifiers(M_FINAL); |
|
992 Expression e = parseExpression(); |
|
993 |
|
994 if (token == IDENT) { |
|
995 init = parseDeclaration(p2, mod, e); |
|
996 } else { |
|
997 if (mod != 0) { |
|
998 expect(IDENT); // should have been a declaration |
|
999 } |
|
1000 topLevelExpression(e); |
|
1001 while (token == COMMA) { |
|
1002 long p3 = scan(); |
|
1003 Expression e2 = parseExpression(); |
|
1004 topLevelExpression(e2); |
|
1005 e = new CommaExpression(p3, e, e2); |
|
1006 } |
|
1007 init = new ExpressionStatement(p2, e); |
|
1008 } |
|
1009 } |
|
1010 expect(SEMICOLON); |
|
1011 if (token != SEMICOLON) { |
|
1012 cond = parseExpression(); |
|
1013 } |
|
1014 expect(SEMICOLON); |
|
1015 if (token != RPAREN) { |
|
1016 inc = parseExpression(); |
|
1017 topLevelExpression(inc); |
|
1018 while (token == COMMA) { |
|
1019 long p2 = scan(); |
|
1020 Expression e2 = parseExpression(); |
|
1021 topLevelExpression(e2); |
|
1022 inc = new CommaExpression(p2, inc, e2); |
|
1023 } |
|
1024 } |
|
1025 expect(RPAREN); |
|
1026 return new ForStatement(p, init, cond, inc, parseStatement()); |
|
1027 } |
|
1028 |
|
1029 case WHILE: { |
|
1030 // while-statement: while (expr) stat |
|
1031 long p = scan(); |
|
1032 |
|
1033 expect(LPAREN); |
|
1034 Expression cond = parseExpression(); |
|
1035 expect(RPAREN); |
|
1036 return new WhileStatement(p, cond, parseStatement()); |
|
1037 } |
|
1038 |
|
1039 case DO: { |
|
1040 // do-statement: do stat while (expr) |
|
1041 long p = scan(); |
|
1042 |
|
1043 Statement body = parseStatement(); |
|
1044 expect(WHILE); |
|
1045 expect(LPAREN); |
|
1046 Expression cond = parseExpression(); |
|
1047 expect(RPAREN); |
|
1048 expect(SEMICOLON); |
|
1049 return new DoStatement(p, body, cond); |
|
1050 } |
|
1051 |
|
1052 case BREAK: { |
|
1053 // break-statement: break ; |
|
1054 long p = scan(); |
|
1055 Identifier label = null; |
|
1056 |
|
1057 if (token == IDENT) { |
|
1058 label = scanner.idValue; |
|
1059 scan(); |
|
1060 } |
|
1061 expect(SEMICOLON); |
|
1062 return new BreakStatement(p, label); |
|
1063 } |
|
1064 |
|
1065 case CONTINUE: { |
|
1066 // continue-statement: continue ; |
|
1067 long p = scan(); |
|
1068 Identifier label = null; |
|
1069 |
|
1070 if (token == IDENT) { |
|
1071 label = scanner.idValue; |
|
1072 scan(); |
|
1073 } |
|
1074 expect(SEMICOLON); |
|
1075 return new ContinueStatement(p, label); |
|
1076 } |
|
1077 |
|
1078 case RETURN: { |
|
1079 // return-statement: return ; |
|
1080 // return-statement: return expr ; |
|
1081 long p = scan(); |
|
1082 Expression e = null; |
|
1083 |
|
1084 if (token != SEMICOLON) { |
|
1085 e = parseExpression(); |
|
1086 } |
|
1087 expect(SEMICOLON); |
|
1088 return new ReturnStatement(p, e); |
|
1089 } |
|
1090 |
|
1091 case SWITCH: { |
|
1092 // switch statement: switch ( expr ) stat |
|
1093 long p = scan(); |
|
1094 int i = argIndex; |
|
1095 |
|
1096 expect(LPAREN); |
|
1097 Expression e = parseExpression(); |
|
1098 expect(RPAREN); |
|
1099 expect(LBRACE); |
|
1100 |
|
1101 while ((token != EOF) && (token != RBRACE)) { |
|
1102 int j = argIndex; |
|
1103 try { |
|
1104 switch (token) { |
|
1105 case CASE: |
|
1106 // case-statement: case expr: |
|
1107 addArgument(new CaseStatement(scan(), parseExpression())); |
|
1108 expect(COLON); |
|
1109 break; |
|
1110 |
|
1111 case DEFAULT: |
|
1112 // default-statement: default: |
|
1113 addArgument(new CaseStatement(scan(), null)); |
|
1114 expect(COLON); |
|
1115 break; |
|
1116 |
|
1117 default: |
|
1118 addArgument(parseStatement()); |
|
1119 break; |
|
1120 } |
|
1121 } catch (SyntaxError ee) { |
|
1122 argIndex = j; |
|
1123 if (!recoverStatement()) { |
|
1124 throw ee; |
|
1125 } |
|
1126 } |
|
1127 } |
|
1128 expect(RBRACE); |
|
1129 return new SwitchStatement(p, e, statArgs(i)); |
|
1130 } |
|
1131 |
|
1132 case CASE: { |
|
1133 // case-statement: case expr : stat |
|
1134 env.error(pos, "case.without.switch"); |
|
1135 while (token == CASE) { |
|
1136 scan(); |
|
1137 parseExpression(); |
|
1138 expect(COLON); |
|
1139 } |
|
1140 return parseStatement(); |
|
1141 } |
|
1142 |
|
1143 case DEFAULT: { |
|
1144 // default-statement: default : stat |
|
1145 env.error(pos, "default.without.switch"); |
|
1146 scan(); |
|
1147 expect(COLON); |
|
1148 return parseStatement(); |
|
1149 } |
|
1150 |
|
1151 case TRY: { |
|
1152 // try-statement: try stat catch (type-expr ident) stat finally stat |
|
1153 long p = scan(); |
|
1154 Statement init = null; // try-object specification |
|
1155 int i = argIndex; |
|
1156 boolean catches = false; |
|
1157 |
|
1158 if (false && token == LPAREN) { |
|
1159 expect(LPAREN); |
|
1160 long p2 = pos; |
|
1161 int mod = parseModifiers(M_FINAL); |
|
1162 Expression e = parseExpression(); |
|
1163 |
|
1164 if (token == IDENT) { |
|
1165 init = parseDeclaration(p2, mod, e); |
|
1166 // leave check for try (T x, y) for semantic phase |
|
1167 } else { |
|
1168 if (mod != 0) { |
|
1169 expect(IDENT); // should have been a declaration |
|
1170 } |
|
1171 init = new ExpressionStatement(p2, e); |
|
1172 } |
|
1173 expect(RPAREN); |
|
1174 } |
|
1175 |
|
1176 Statement s = parseBlockStatement(); |
|
1177 |
|
1178 if (init != null) { |
|
1179 // s = new FinallyStatement(p, init, s, 0); |
|
1180 } |
|
1181 |
|
1182 while (token == CATCH) { |
|
1183 long pp = pos; |
|
1184 expect(CATCH); |
|
1185 expect(LPAREN); |
|
1186 int mod = parseModifiers(M_FINAL); |
|
1187 Expression t = parseExpression(); |
|
1188 IdentifierToken id = scanner.getIdToken(); |
|
1189 expect(IDENT); |
|
1190 id.modifiers = mod; |
|
1191 // We only catch Throwable's, so this is no longer required |
|
1192 // while (token == LSQBRACKET) { |
|
1193 // t = new ArrayAccessExpression(scan(), t, null); |
|
1194 // expect(RSQBRACKET); |
|
1195 // } |
|
1196 expect(RPAREN); |
|
1197 addArgument(new CatchStatement(pp, t, id, parseBlockStatement())); |
|
1198 catches = true; |
|
1199 } |
|
1200 |
|
1201 if (catches) |
|
1202 s = new TryStatement(p, s, statArgs(i)); |
|
1203 |
|
1204 if (token == FINALLY) { |
|
1205 scan(); |
|
1206 return new FinallyStatement(p, s, parseBlockStatement()); |
|
1207 } else if (catches || init != null) { |
|
1208 return s; |
|
1209 } else { |
|
1210 env.error(pos, "try.without.catch.finally"); |
|
1211 return new TryStatement(p, s, null); |
|
1212 } |
|
1213 } |
|
1214 |
|
1215 case CATCH: { |
|
1216 // catch-statement: catch (expr ident) stat finally stat |
|
1217 env.error(pos, "catch.without.try"); |
|
1218 |
|
1219 Statement s; |
|
1220 do { |
|
1221 scan(); |
|
1222 expect(LPAREN); |
|
1223 parseModifiers(M_FINAL); |
|
1224 parseExpression(); |
|
1225 expect(IDENT); |
|
1226 expect(RPAREN); |
|
1227 s = parseBlockStatement(); |
|
1228 } while (token == CATCH); |
|
1229 |
|
1230 if (token == FINALLY) { |
|
1231 scan(); |
|
1232 s = parseBlockStatement(); |
|
1233 } |
|
1234 return s; |
|
1235 } |
|
1236 |
|
1237 case FINALLY: { |
|
1238 // finally-statement: finally stat |
|
1239 env.error(pos, "finally.without.try"); |
|
1240 scan(); |
|
1241 return parseBlockStatement(); |
|
1242 } |
|
1243 |
|
1244 case THROW: { |
|
1245 // throw-statement: throw expr; |
|
1246 long p = scan(); |
|
1247 Expression e = parseExpression(); |
|
1248 expect(SEMICOLON); |
|
1249 return new ThrowStatement(p, e); |
|
1250 } |
|
1251 |
|
1252 case GOTO: { |
|
1253 long p = scan(); |
|
1254 expect(IDENT); |
|
1255 expect(SEMICOLON); |
|
1256 env.error(p, "not.supported", "goto"); |
|
1257 return new CompoundStatement(p, new Statement[0]); |
|
1258 } |
|
1259 |
|
1260 case SYNCHRONIZED: { |
|
1261 // synchronized-statement: synchronized (expr) stat |
|
1262 long p = scan(); |
|
1263 expect(LPAREN); |
|
1264 Expression e = parseExpression(); |
|
1265 expect(RPAREN); |
|
1266 return new SynchronizedStatement(p, e, parseBlockStatement()); |
|
1267 } |
|
1268 |
|
1269 case INTERFACE: |
|
1270 case CLASS: |
|
1271 // Inner class. |
|
1272 return parseLocalClass(0); |
|
1273 |
|
1274 case CONST: |
|
1275 case ABSTRACT: |
|
1276 case FINAL: |
|
1277 case STRICTFP: { |
|
1278 // a declaration of some sort |
|
1279 long p = pos; |
|
1280 |
|
1281 // A class which is local to a block is not a member, and so |
|
1282 // cannot be public, private, protected, or static. It is in |
|
1283 // effect private to the block, since it cannot be used outside |
|
1284 // its scope. |
|
1285 // |
|
1286 // However, any class (if it has a name) can be declared final, |
|
1287 // abstract, or strictfp. |
|
1288 int mod = parseModifiers(M_FINAL | M_ABSTRACT |
|
1289 | M_STRICTFP ); |
|
1290 |
|
1291 switch (token) { |
|
1292 case INTERFACE: |
|
1293 case CLASS: |
|
1294 return parseLocalClass(mod); |
|
1295 |
|
1296 case BOOLEAN: |
|
1297 case BYTE: |
|
1298 case CHAR: |
|
1299 case SHORT: |
|
1300 case INT: |
|
1301 case LONG: |
|
1302 case FLOAT: |
|
1303 case DOUBLE: |
|
1304 case IDENT: { |
|
1305 if ((mod & (M_ABSTRACT | M_STRICTFP )) != 0) { |
|
1306 mod &= ~ (M_ABSTRACT | M_STRICTFP ); |
|
1307 expect(CLASS); |
|
1308 } |
|
1309 Expression e = parseExpression(); |
|
1310 if (token != IDENT) { |
|
1311 expect(IDENT); |
|
1312 } |
|
1313 // declaration: final expr expr |
|
1314 Statement s = parseDeclaration(p, mod, e); |
|
1315 expect(SEMICOLON); |
|
1316 return s; |
|
1317 } |
|
1318 |
|
1319 default: |
|
1320 env.error(pos, "type.expected"); |
|
1321 throw new SyntaxError(); |
|
1322 } |
|
1323 } |
|
1324 |
|
1325 case VOID: |
|
1326 case STATIC: |
|
1327 case PUBLIC: |
|
1328 case PRIVATE: |
|
1329 case TRANSIENT: |
|
1330 // This is the start of something outside a statement |
|
1331 env.error(pos, "statement.expected"); |
|
1332 throw new SyntaxError(); |
|
1333 } |
|
1334 |
|
1335 long p = pos; |
|
1336 Expression e = parseExpression(); |
|
1337 |
|
1338 if (token == IDENT) { |
|
1339 // declaration: expr expr |
|
1340 Statement s = parseDeclaration(p, 0, e); |
|
1341 expect(SEMICOLON); |
|
1342 return s; |
|
1343 } |
|
1344 if (token == COLON) { |
|
1345 // label: id: stat |
|
1346 scan(); |
|
1347 Statement s = parseStatement(); |
|
1348 s.setLabel(env, e); |
|
1349 return s; |
|
1350 } |
|
1351 |
|
1352 // it was just an expression... |
|
1353 topLevelExpression(e); |
|
1354 expect(SEMICOLON); |
|
1355 return new ExpressionStatement(p, e); |
|
1356 } |
|
1357 |
|
1358 protected Statement parseBlockStatement() throws SyntaxError, IOException { |
|
1359 // compound statement: { stat1 stat2 ... statn } |
|
1360 if (token != LBRACE) { |
|
1361 // We're expecting a block statement. But we'll probably do the |
|
1362 // least damage if we try to parse a normal statement instead. |
|
1363 env.error(scanner.prevPos, "token.expected", opNames[LBRACE]); |
|
1364 return parseStatement(); |
|
1365 } |
|
1366 long p = scan(); |
|
1367 int i = argIndex; |
|
1368 while ((token != EOF) && (token != RBRACE)) { |
|
1369 int j = argIndex; |
|
1370 try { |
|
1371 addArgument(parseStatement()); |
|
1372 } catch (SyntaxError e) { |
|
1373 argIndex = j; |
|
1374 if (!recoverStatement()) { |
|
1375 throw e; |
|
1376 } |
|
1377 } |
|
1378 } |
|
1379 |
|
1380 expect(RBRACE); |
|
1381 return new CompoundStatement(p, statArgs(i)); |
|
1382 } |
|
1383 |
|
1384 |
|
1385 /** |
|
1386 * Parse an identifier. ie: a.b.c returns "a.b.c" |
|
1387 * If star is true then "a.b.*" is allowed. |
|
1388 * The return value encodes both the identifier and its location. |
|
1389 */ |
|
1390 protected IdentifierToken parseName(boolean star) throws SyntaxError, IOException { |
|
1391 IdentifierToken res = scanner.getIdToken(); |
|
1392 expect(IDENT); |
|
1393 |
|
1394 if (token != FIELD) { |
|
1395 return res; |
|
1396 } |
|
1397 |
|
1398 StringBuffer buf = new StringBuffer(res.id.toString()); |
|
1399 |
|
1400 while (token == FIELD) { |
|
1401 scan(); |
|
1402 if ((token == MUL) && star) { |
|
1403 scan(); |
|
1404 buf.append(".*"); |
|
1405 break; |
|
1406 } |
|
1407 |
|
1408 buf.append('.'); |
|
1409 if (token == IDENT) { |
|
1410 buf.append(scanner.idValue); |
|
1411 } |
|
1412 expect(IDENT); |
|
1413 } |
|
1414 |
|
1415 res.id = Identifier.lookup(buf.toString()); |
|
1416 return res; |
|
1417 } |
|
1418 /** |
|
1419 * @deprecated |
|
1420 * @see #parseName |
|
1421 */ |
|
1422 @Deprecated |
|
1423 protected Identifier parseIdentifier(boolean star) throws SyntaxError, IOException { |
|
1424 return parseName(star).id; |
|
1425 } |
|
1426 |
|
1427 /** |
|
1428 * Parse a type expression, this results in a Type. |
|
1429 * The parse includes trailing array brackets. |
|
1430 */ |
|
1431 protected Type parseType() throws SyntaxError, IOException { |
|
1432 Type t; |
|
1433 |
|
1434 switch (token) { |
|
1435 case IDENT: |
|
1436 t = Type.tClass(parseName(false).id); |
|
1437 break; |
|
1438 case VOID: |
|
1439 scan(); |
|
1440 t = Type.tVoid; |
|
1441 break; |
|
1442 case BOOLEAN: |
|
1443 scan(); |
|
1444 t = Type.tBoolean; |
|
1445 break; |
|
1446 case BYTE: |
|
1447 scan(); |
|
1448 t = Type.tByte; |
|
1449 break; |
|
1450 case CHAR: |
|
1451 scan(); |
|
1452 t = Type.tChar; |
|
1453 break; |
|
1454 case SHORT: |
|
1455 scan(); |
|
1456 t = Type.tShort; |
|
1457 break; |
|
1458 case INT: |
|
1459 scan(); |
|
1460 t = Type.tInt; |
|
1461 break; |
|
1462 case FLOAT: |
|
1463 scan(); |
|
1464 t = Type.tFloat; |
|
1465 break; |
|
1466 case LONG: |
|
1467 scan(); |
|
1468 t = Type.tLong; |
|
1469 break; |
|
1470 case DOUBLE: |
|
1471 scan(); |
|
1472 t = Type.tDouble; |
|
1473 break; |
|
1474 default: |
|
1475 env.error(pos, "type.expected"); |
|
1476 throw new SyntaxError(); |
|
1477 } |
|
1478 return parseArrayBrackets(t); |
|
1479 } |
|
1480 |
|
1481 /** |
|
1482 * Parse the tail of a type expression, which might be array brackets. |
|
1483 * Return the given type, as possibly modified by the suffix. |
|
1484 */ |
|
1485 protected Type parseArrayBrackets(Type t) throws SyntaxError, IOException { |
|
1486 |
|
1487 // Parse []'s |
|
1488 while (token == LSQBRACKET) { |
|
1489 scan(); |
|
1490 if (token != RSQBRACKET) { |
|
1491 env.error(pos, "array.dim.in.decl"); |
|
1492 parseExpression(); |
|
1493 } |
|
1494 expect(RSQBRACKET); |
|
1495 t = Type.tArray(t); |
|
1496 } |
|
1497 return t; |
|
1498 } |
|
1499 |
|
1500 /* |
|
1501 * Dealing with argument lists, I'm not using |
|
1502 * Vector for efficiency. |
|
1503 */ |
|
1504 |
|
1505 private int aCount = 0; |
|
1506 private Type aTypes[] = new Type[8]; |
|
1507 private IdentifierToken aNames[] = new IdentifierToken[aTypes.length]; |
|
1508 |
|
1509 private void addArgument(int mod, Type t, IdentifierToken nm) { |
|
1510 nm.modifiers = mod; |
|
1511 if (aCount >= aTypes.length) { |
|
1512 Type newATypes[] = new Type[aCount * 2]; |
|
1513 System.arraycopy(aTypes, 0, newATypes, 0, aCount); |
|
1514 aTypes = newATypes; |
|
1515 IdentifierToken newANames[] = new IdentifierToken[aCount * 2]; |
|
1516 System.arraycopy(aNames, 0, newANames, 0, aCount); |
|
1517 aNames = newANames; |
|
1518 } |
|
1519 aTypes[aCount] = t; |
|
1520 aNames[aCount++] = nm; |
|
1521 } |
|
1522 |
|
1523 /** |
|
1524 * Parse a possibly-empty sequence of modifier keywords. |
|
1525 * Return the resulting bitmask. |
|
1526 * Diagnose repeated modifiers, but make no other checks. |
|
1527 * Only modifiers mentioned in the given bitmask are scanned; |
|
1528 * an unmatched modifier must be handled by the caller. |
|
1529 */ |
|
1530 protected int parseModifiers(int mask) throws IOException { |
|
1531 int mod = 0; |
|
1532 while (true) { |
|
1533 if (token==CONST) { |
|
1534 // const isn't in java, but handle a common C++ usage gently |
|
1535 env.error(pos, "not.supported", "const"); |
|
1536 scan(); |
|
1537 } |
|
1538 int nextmod = 0; |
|
1539 switch (token) { |
|
1540 case PRIVATE: nextmod = M_PRIVATE; break; |
|
1541 case PUBLIC: nextmod = M_PUBLIC; break; |
|
1542 case PROTECTED: nextmod = M_PROTECTED; break; |
|
1543 case STATIC: nextmod = M_STATIC; break; |
|
1544 case TRANSIENT: nextmod = M_TRANSIENT; break; |
|
1545 case FINAL: nextmod = M_FINAL; break; |
|
1546 case ABSTRACT: nextmod = M_ABSTRACT; break; |
|
1547 case NATIVE: nextmod = M_NATIVE; break; |
|
1548 case VOLATILE: nextmod = M_VOLATILE; break; |
|
1549 case SYNCHRONIZED: nextmod = M_SYNCHRONIZED; break; |
|
1550 case STRICTFP: nextmod = M_STRICTFP; break; |
|
1551 } |
|
1552 if ((nextmod & mask) == 0) { |
|
1553 break; |
|
1554 } |
|
1555 if ((nextmod & mod) != 0) { |
|
1556 env.error(pos, "repeated.modifier"); |
|
1557 } |
|
1558 mod |= nextmod; |
|
1559 scan(); |
|
1560 } |
|
1561 return mod; |
|
1562 } |
|
1563 |
|
1564 private ClassDefinition curClass; |
|
1565 |
|
1566 /** |
|
1567 * Parse a field. |
|
1568 */ |
|
1569 protected void parseField() throws SyntaxError, IOException { |
|
1570 |
|
1571 // Empty fields are not allowed by the JLS but are accepted by |
|
1572 // the compiler, and much code has come to rely on this. It has |
|
1573 // been decided that the language will be extended to legitimize them. |
|
1574 if (token == SEMICOLON) { |
|
1575 // empty field |
|
1576 scan(); |
|
1577 return; |
|
1578 } |
|
1579 |
|
1580 // Optional doc comment |
|
1581 String doc = scanner.docComment; |
|
1582 |
|
1583 // The start of the field |
|
1584 long p = pos; |
|
1585 |
|
1586 // Parse the modifiers |
|
1587 int mod = parseModifiers(MM_FIELD | MM_METHOD); |
|
1588 |
|
1589 // Check for static initializer |
|
1590 // ie: static { ... } |
|
1591 // or an instance initializer (w/o the static). |
|
1592 if ((mod == (mod & M_STATIC)) && (token == LBRACE)) { |
|
1593 // static initializer |
|
1594 actions.defineField(p, curClass, doc, mod, |
|
1595 Type.tMethod(Type.tVoid), |
|
1596 new IdentifierToken(idClassInit), null, null, |
|
1597 parseStatement()); |
|
1598 return; |
|
1599 } |
|
1600 |
|
1601 // Check for inner class |
|
1602 if (token == CLASS || token == INTERFACE) { |
|
1603 parseNamedClass(mod, CLASS, doc); |
|
1604 return; |
|
1605 } |
|
1606 |
|
1607 // Parse the type |
|
1608 p = pos; |
|
1609 Type t = parseType(); |
|
1610 IdentifierToken id = null; |
|
1611 |
|
1612 // Check that the type is followed by an Identifier |
|
1613 // (the name of the method or the first variable), |
|
1614 // otherwise it is a constructor. |
|
1615 switch (token) { |
|
1616 case IDENT: |
|
1617 id = scanner.getIdToken(); |
|
1618 p = scan(); |
|
1619 break; |
|
1620 |
|
1621 case LPAREN: |
|
1622 // It is a constructor |
|
1623 id = new IdentifierToken(idInit); |
|
1624 if ((mod & M_STRICTFP) != 0) |
|
1625 env.error(pos, "bad.constructor.modifier"); |
|
1626 break; |
|
1627 |
|
1628 default: |
|
1629 expect(IDENT); |
|
1630 } |
|
1631 |
|
1632 // If the next token is a left-bracket then we |
|
1633 // are dealing with a method or constructor, otherwise it is |
|
1634 // a list of variables |
|
1635 if (token == LPAREN) { |
|
1636 // It is a method or constructor declaration |
|
1637 scan(); |
|
1638 aCount = 0; |
|
1639 |
|
1640 if (token != RPAREN) { |
|
1641 // Parse argument type and identifier |
|
1642 // (arguments (like locals) are allowed to be final) |
|
1643 int am = parseModifiers(M_FINAL); |
|
1644 Type at = parseType(); |
|
1645 IdentifierToken an = scanner.getIdToken(); |
|
1646 expect(IDENT); |
|
1647 |
|
1648 // Parse optional array specifier, ie: a[][] |
|
1649 at = parseArrayBrackets(at); |
|
1650 addArgument(am, at, an); |
|
1651 |
|
1652 // If the next token is a comma then there are |
|
1653 // more arguments |
|
1654 while (token == COMMA) { |
|
1655 // Parse argument type and identifier |
|
1656 scan(); |
|
1657 am = parseModifiers(M_FINAL); |
|
1658 at = parseType(); |
|
1659 an = scanner.getIdToken(); |
|
1660 expect(IDENT); |
|
1661 |
|
1662 // Parse optional array specifier, ie: a[][] |
|
1663 at = parseArrayBrackets(at); |
|
1664 addArgument(am, at, an); |
|
1665 } |
|
1666 } |
|
1667 expect(RPAREN); |
|
1668 |
|
1669 // Parse optional array sepecifier, ie: foo()[][] |
|
1670 t = parseArrayBrackets(t); |
|
1671 |
|
1672 // copy arguments |
|
1673 Type atypes[] = new Type[aCount]; |
|
1674 System.arraycopy(aTypes, 0, atypes, 0, aCount); |
|
1675 |
|
1676 IdentifierToken anames[] = new IdentifierToken[aCount]; |
|
1677 System.arraycopy(aNames, 0, anames, 0, aCount); |
|
1678 |
|
1679 // Construct the type signature |
|
1680 t = Type.tMethod(t, atypes); |
|
1681 |
|
1682 // Parse and ignore throws clause |
|
1683 IdentifierToken exp[] = null; |
|
1684 if (token == THROWS) { |
|
1685 Vector v = new Vector(); |
|
1686 scan(); |
|
1687 v.addElement(parseName(false)); |
|
1688 while (token == COMMA) { |
|
1689 scan(); |
|
1690 v.addElement(parseName(false)); |
|
1691 } |
|
1692 |
|
1693 exp = new IdentifierToken[v.size()]; |
|
1694 v.copyInto(exp); |
|
1695 } |
|
1696 |
|
1697 // Check if it is a method definition or a method declaration |
|
1698 // ie: foo() {...} or foo(); |
|
1699 switch (token) { |
|
1700 case LBRACE: // It's a method definition |
|
1701 |
|
1702 // Set the state of FP strictness for the body of the method |
|
1703 int oldFPstate = FPstate; |
|
1704 if ((mod & M_STRICTFP)!=0) { |
|
1705 FPstate = M_STRICTFP; |
|
1706 } else { |
|
1707 mod |= FPstate & M_STRICTFP; |
|
1708 } |
|
1709 |
|
1710 actions.defineField(p, curClass, doc, mod, t, id, |
|
1711 anames, exp, parseStatement()); |
|
1712 |
|
1713 FPstate = oldFPstate; |
|
1714 |
|
1715 break; |
|
1716 |
|
1717 case SEMICOLON: |
|
1718 scan(); |
|
1719 actions.defineField(p, curClass, doc, mod, t, id, |
|
1720 anames, exp, null); |
|
1721 break; |
|
1722 |
|
1723 default: |
|
1724 // really expected a statement body here |
|
1725 if ((mod & (M_NATIVE | M_ABSTRACT)) == 0) { |
|
1726 expect(LBRACE); |
|
1727 } else { |
|
1728 expect(SEMICOLON); |
|
1729 } |
|
1730 } |
|
1731 return; |
|
1732 } |
|
1733 |
|
1734 // It is a list of instance variables |
|
1735 while (true) { |
|
1736 p = pos; // get the current position |
|
1737 // parse the array brackets (if any) |
|
1738 // ie: var[][][] |
|
1739 Type vt = parseArrayBrackets(t); |
|
1740 |
|
1741 // Parse the optional initializer |
|
1742 Node init = null; |
|
1743 if (token == ASSIGN) { |
|
1744 scan(); |
|
1745 init = parseExpression(); |
|
1746 } |
|
1747 |
|
1748 // Define the variable |
|
1749 actions.defineField(p, curClass, doc, mod, vt, id, |
|
1750 null, null, init); |
|
1751 |
|
1752 // If the next token is a comma, then there is more |
|
1753 if (token != COMMA) { |
|
1754 expect(SEMICOLON); |
|
1755 return; |
|
1756 } |
|
1757 scan(); |
|
1758 |
|
1759 // The next token must be an identifier |
|
1760 id = scanner.getIdToken(); |
|
1761 expect(IDENT); |
|
1762 } |
|
1763 } |
|
1764 |
|
1765 /** |
|
1766 * Recover after a syntax error in a field. This involves |
|
1767 * discarding tokens until an EOF or a possible legal |
|
1768 * continuation is encountered. |
|
1769 */ |
|
1770 protected void recoverField(ClassDefinition newClass) throws SyntaxError, IOException { |
|
1771 while (true) { |
|
1772 switch (token) { |
|
1773 case EOF: |
|
1774 case STATIC: |
|
1775 case FINAL: |
|
1776 case PUBLIC: |
|
1777 case PRIVATE: |
|
1778 case SYNCHRONIZED: |
|
1779 case TRANSIENT: |
|
1780 |
|
1781 case VOID: |
|
1782 case BOOLEAN: |
|
1783 case BYTE: |
|
1784 case CHAR: |
|
1785 case SHORT: |
|
1786 case INT: |
|
1787 case FLOAT: |
|
1788 case LONG: |
|
1789 case DOUBLE: |
|
1790 // possible begin of a field, continue |
|
1791 return; |
|
1792 |
|
1793 case LBRACE: |
|
1794 match(LBRACE, RBRACE); |
|
1795 scan(); |
|
1796 break; |
|
1797 |
|
1798 case LPAREN: |
|
1799 match(LPAREN, RPAREN); |
|
1800 scan(); |
|
1801 break; |
|
1802 |
|
1803 case LSQBRACKET: |
|
1804 match(LSQBRACKET, RSQBRACKET); |
|
1805 scan(); |
|
1806 break; |
|
1807 |
|
1808 case RBRACE: |
|
1809 case INTERFACE: |
|
1810 case CLASS: |
|
1811 case IMPORT: |
|
1812 case PACKAGE: |
|
1813 // begin of something outside a class, panic more |
|
1814 actions.endClass(pos, newClass); |
|
1815 throw new SyntaxError(); |
|
1816 |
|
1817 default: |
|
1818 // don't know what to do, skip |
|
1819 scan(); |
|
1820 break; |
|
1821 } |
|
1822 } |
|
1823 } |
|
1824 |
|
1825 /** |
|
1826 * Parse a top-level class or interface declaration. |
|
1827 */ |
|
1828 protected void parseClass() throws SyntaxError, IOException { |
|
1829 String doc = scanner.docComment; |
|
1830 |
|
1831 // Parse the modifiers. |
|
1832 int mod = parseModifiers(MM_CLASS | MM_MEMBER); |
|
1833 |
|
1834 parseNamedClass(mod, PACKAGE, doc); |
|
1835 } |
|
1836 |
|
1837 // Current strict/default state of floating point. This is |
|
1838 // set and reset with a stack discipline around methods and named |
|
1839 // classes. Only M_STRICTFP may be set in this word. try... |
|
1840 // finally is not needed to protect setting and resetting because |
|
1841 // there are no error messages based on FPstate. |
|
1842 private int FPstate = 0; |
|
1843 |
|
1844 /** |
|
1845 * Parse a block-local class or interface declaration. |
|
1846 */ |
|
1847 protected Statement parseLocalClass(int mod) throws SyntaxError, IOException { |
|
1848 long p = pos; |
|
1849 ClassDefinition body = parseNamedClass(M_LOCAL | mod, STAT, null); |
|
1850 Statement ds[] = { |
|
1851 new VarDeclarationStatement(p, new LocalMember(body), null) |
|
1852 }; |
|
1853 Expression type = new TypeExpression(p, body.getType()); |
|
1854 return new DeclarationStatement(p, 0, type, ds); |
|
1855 } |
|
1856 |
|
1857 /** |
|
1858 * Parse a named class or interface declaration, |
|
1859 * starting at "class" or "interface". |
|
1860 * @arg ctx Syntactic context of the class, one of {PACKAGE CLASS STAT EXPR}. |
|
1861 */ |
|
1862 protected ClassDefinition parseNamedClass(int mod, int ctx, String doc) throws SyntaxError, IOException { |
|
1863 // Parse class/interface |
|
1864 switch (token) { |
|
1865 case INTERFACE: |
|
1866 scan(); |
|
1867 mod |= M_INTERFACE; |
|
1868 break; |
|
1869 |
|
1870 case CLASS: |
|
1871 scan(); |
|
1872 break; |
|
1873 |
|
1874 default: |
|
1875 env.error(pos, "class.expected"); |
|
1876 break; |
|
1877 } |
|
1878 |
|
1879 int oldFPstate = FPstate; |
|
1880 if ((mod & M_STRICTFP)!=0) { |
|
1881 FPstate = M_STRICTFP; |
|
1882 } else { |
|
1883 // The & (...) isn't really necessary here because we do maintain |
|
1884 // the invariant that FPstate has no extra bits set. |
|
1885 mod |= FPstate & M_STRICTFP; |
|
1886 } |
|
1887 |
|
1888 // Parse the class name |
|
1889 IdentifierToken nm = scanner.getIdToken(); |
|
1890 long p = pos; |
|
1891 expect(IDENT); |
|
1892 |
|
1893 Vector ext = new Vector(); |
|
1894 Vector impl = new Vector(); |
|
1895 parseInheritance(ext, impl); |
|
1896 |
|
1897 ClassDefinition tmp = parseClassBody(nm, mod, ctx, doc, ext, impl, p); |
|
1898 |
|
1899 FPstate = oldFPstate; |
|
1900 |
|
1901 return tmp; |
|
1902 } |
|
1903 |
|
1904 protected void parseInheritance(Vector ext, Vector impl) throws SyntaxError, IOException { |
|
1905 // Parse extends clause |
|
1906 if (token == EXTENDS) { |
|
1907 scan(); |
|
1908 ext.addElement(parseName(false)); |
|
1909 while (token == COMMA) { |
|
1910 scan(); |
|
1911 ext.addElement(parseName(false)); |
|
1912 } |
|
1913 } |
|
1914 |
|
1915 // Parse implements clause |
|
1916 if (token == IMPLEMENTS) { |
|
1917 scan(); |
|
1918 impl.addElement(parseName(false)); |
|
1919 while (token == COMMA) { |
|
1920 scan(); |
|
1921 impl.addElement(parseName(false)); |
|
1922 } |
|
1923 } |
|
1924 } |
|
1925 |
|
1926 /** |
|
1927 * Parse the body of a class or interface declaration, |
|
1928 * starting at the left brace. |
|
1929 */ |
|
1930 protected ClassDefinition parseClassBody(IdentifierToken nm, int mod, |
|
1931 int ctx, String doc, |
|
1932 Vector ext, Vector impl, long p |
|
1933 ) throws SyntaxError, IOException { |
|
1934 // Decide which is the super class |
|
1935 IdentifierToken sup = null; |
|
1936 if ((mod & M_INTERFACE) != 0) { |
|
1937 if (impl.size() > 0) { |
|
1938 env.error(((IdentifierToken)impl.elementAt(0)).getWhere(), |
|
1939 "intf.impl.intf"); |
|
1940 } |
|
1941 impl = ext; |
|
1942 } else { |
|
1943 if (ext.size() > 0) { |
|
1944 if (ext.size() > 1) { |
|
1945 env.error(((IdentifierToken)ext.elementAt(1)).getWhere(), |
|
1946 "multiple.inherit"); |
|
1947 } |
|
1948 sup = (IdentifierToken)ext.elementAt(0); |
|
1949 } |
|
1950 } |
|
1951 |
|
1952 ClassDefinition oldClass = curClass; |
|
1953 |
|
1954 // Begin a new class |
|
1955 IdentifierToken implids[] = new IdentifierToken[impl.size()]; |
|
1956 impl.copyInto(implids); |
|
1957 ClassDefinition newClass = |
|
1958 actions.beginClass(p, doc, mod, nm, sup, implids); |
|
1959 |
|
1960 // Parse fields |
|
1961 expect(LBRACE); |
|
1962 while ((token != EOF) && (token != RBRACE)) { |
|
1963 try { |
|
1964 curClass = newClass; |
|
1965 parseField(); |
|
1966 } catch (SyntaxError e) { |
|
1967 recoverField(newClass); |
|
1968 } finally { |
|
1969 curClass = oldClass; |
|
1970 } |
|
1971 } |
|
1972 expect(RBRACE); |
|
1973 |
|
1974 // End the class |
|
1975 actions.endClass(scanner.prevPos, newClass); |
|
1976 return newClass; |
|
1977 } |
|
1978 |
|
1979 /** |
|
1980 * Recover after a syntax error in the file. |
|
1981 * This involves discarding tokens until an EOF |
|
1982 * or a possible legal continuation is encountered. |
|
1983 */ |
|
1984 protected void recoverFile() throws IOException { |
|
1985 while (true) { |
|
1986 switch (token) { |
|
1987 case CLASS: |
|
1988 case INTERFACE: |
|
1989 // Start of a new source file statement, continue |
|
1990 return; |
|
1991 |
|
1992 case LBRACE: |
|
1993 match(LBRACE, RBRACE); |
|
1994 scan(); |
|
1995 break; |
|
1996 |
|
1997 case LPAREN: |
|
1998 match(LPAREN, RPAREN); |
|
1999 scan(); |
|
2000 break; |
|
2001 |
|
2002 case LSQBRACKET: |
|
2003 match(LSQBRACKET, RSQBRACKET); |
|
2004 scan(); |
|
2005 break; |
|
2006 |
|
2007 case EOF: |
|
2008 return; |
|
2009 |
|
2010 default: |
|
2011 // Don't know what to do, skip |
|
2012 scan(); |
|
2013 break; |
|
2014 } |
|
2015 } |
|
2016 } |
|
2017 |
|
2018 /** |
|
2019 * Parse an Java file. |
|
2020 */ |
|
2021 public void parseFile() { |
|
2022 try { |
|
2023 try { |
|
2024 if (token == PACKAGE) { |
|
2025 // Package statement |
|
2026 long p = scan(); |
|
2027 IdentifierToken id = parseName(false); |
|
2028 expect(SEMICOLON); |
|
2029 actions.packageDeclaration(p, id); |
|
2030 } |
|
2031 } catch (SyntaxError e) { |
|
2032 recoverFile(); |
|
2033 } |
|
2034 while (token == IMPORT) { |
|
2035 try{ |
|
2036 // Import statement |
|
2037 long p = scan(); |
|
2038 IdentifierToken id = parseName(true); |
|
2039 expect(SEMICOLON); |
|
2040 if (id.id.getName().equals(idStar)) { |
|
2041 id.id = id.id.getQualifier(); |
|
2042 actions.importPackage(p, id); |
|
2043 } else { |
|
2044 actions.importClass(p, id); |
|
2045 } |
|
2046 } catch (SyntaxError e) { |
|
2047 recoverFile(); |
|
2048 } |
|
2049 } |
|
2050 |
|
2051 while (token != EOF) { |
|
2052 try { |
|
2053 switch (token) { |
|
2054 case FINAL: |
|
2055 case PUBLIC: |
|
2056 case PRIVATE: |
|
2057 case ABSTRACT: |
|
2058 case CLASS: |
|
2059 case INTERFACE: |
|
2060 case STRICTFP: |
|
2061 // Start of a class |
|
2062 parseClass(); |
|
2063 break; |
|
2064 |
|
2065 case SEMICOLON: |
|
2066 // Bogus semicolon. |
|
2067 // According to the JLS (7.6,19.6), a TypeDeclaration |
|
2068 // may consist of a single semicolon, however, this |
|
2069 // usage is discouraged (JLS 7.6). In contrast, |
|
2070 // a FieldDeclaration may not be empty, and is flagged |
|
2071 // as an error. See parseField above. |
|
2072 scan(); |
|
2073 break; |
|
2074 |
|
2075 case EOF: |
|
2076 // The end |
|
2077 return; |
|
2078 |
|
2079 default: |
|
2080 // Oops |
|
2081 env.error(pos, "toplevel.expected"); |
|
2082 throw new SyntaxError(); |
|
2083 } |
|
2084 } catch (SyntaxError e) { |
|
2085 recoverFile(); |
|
2086 } |
|
2087 } |
|
2088 } catch (IOException e) { |
|
2089 env.error(pos, "io.exception", env.getSource()); |
|
2090 return; |
|
2091 } |
|
2092 } |
|
2093 |
|
2094 /** |
|
2095 * Usually <code>this.scanner == (Scanner)this</code>. |
|
2096 * However, a delegate scanner can produce tokens for this parser, |
|
2097 * in which case <code>(Scanner)this</code> is unused, |
|
2098 * except for <code>this.token</code> and <code>this.pos</code> |
|
2099 * instance variables which are filled from the real scanner |
|
2100 * by <code>this.scan()</code> and the constructor. |
|
2101 */ |
|
2102 protected Scanner scanner; |
|
2103 |
|
2104 // Design Note: We ought to disinherit Parser from Scanner. |
|
2105 // We also should split out the interface ParserActions from |
|
2106 // Parser, and make BatchParser implement ParserActions, |
|
2107 // not extend Parser. This would split scanning, parsing, |
|
2108 // and class building into distinct responsibility areas. |
|
2109 // (Perhaps tree building could be virtualized too.) |
|
2110 |
|
2111 public long scan() throws IOException { |
|
2112 if (scanner != this && scanner != null) { |
|
2113 long result = scanner.scan(); |
|
2114 ((Scanner)this).token = scanner.token; |
|
2115 ((Scanner)this).pos = scanner.pos; |
|
2116 return result; |
|
2117 } |
|
2118 return super.scan(); |
|
2119 } |
|
2120 |
|
2121 public void match(int open, int close) throws IOException { |
|
2122 if (scanner != this) { |
|
2123 scanner.match(open, close); |
|
2124 ((Scanner)this).token = scanner.token; |
|
2125 ((Scanner)this).pos = scanner.pos; |
|
2126 return; |
|
2127 } |
|
2128 super.match(open, close); |
|
2129 } |
|
2130 } |