001    /* Copyright 2000, 2001, Compaq Computer Corporation */
002    
003    package javafe.parser;
004    
005    import javafe.ast.*;
006    import javafe.util.StackVector;
007    import javafe.util.Location;
008    import javafe.util.ErrorSet;
009    import javafe.Tool;
010    
011    /**
012     * <code>Parse</code> objects parse Java statements, creating AST
013     * structures for the parsed input using the static
014     * <code>make*()</code> methods of the classes in the
015     * <code>javafe.ast</code> package.
016     *
017     * <p> The concrete grammar for statements is as follows:
018     * <pre>
019     * Statement:
020     * ';'
021     * | (Modifier | ModifierPragma)* ClassDeclaration
022     * | (Modifier | ModifierPragma)* Type { Idn [ '=' InitExpr ] },+ ';'
023     * | Idn ':' Stmt
024     * | Expr ';'
025     * | '{' BlockStmt* '}'
026     * // In an assert, BoolExpr must be of type boolean, NonVoidExpr must 
027     * // not be of type void
028     * | 'assert' BoolExpr [ ':' NonVoidExpr ] ';'
029     * | 'break' [ Idn ] ';'
030     * | 'continue' [ Idn ] ';'
031     * | 'return' [ Expr ] ';'
032     * | 'throw' Expr ';'
033     * | 'if' '(' Expr ')' Stmt [ 'else' Stmt ]
034     * | 'do' Stmt 'while' '(' Expr ')' ';'
035     * | 'while' '(' Expr ')' Stmt
036     * | 'for' '(' [ VDeclInit | StmtExpr,* ] ';' Expr ';' StmtExpr,* ')' Stmt
037     * | 'switch' '(' Expr ')'
038     *     '{' { {'case' Expr ':' | 'default:'}* BlockStmt* }* '}'
039     * | 'synchronized' '(' Expr ')' '{' BlockStmt* '}'
040     * | 'try' '{' BlockStmt* '}' { 'catch' '(' VDecl,* ')' '{' BlockStmt* '}' }*
041     *     [ 'finally' '{' BlockStmt* '}' ]
042     * | StmtPragma
043     * </pre>
044     * 
045     * <p> Currently, there is no error recovery.  Upon detection of a
046     * syntax error, all methods in this class throw a {@link
047     * RuntimeException} with a (weak) error message.
048     * 
049     * <p> Although the class as a whole is thread-safe, that is,
050     * different threads can be calling methods of different instances of
051     * <code>ParseStmt</code> at the same time, individual instances are
052     * not.
053     * 
054     * @see javafe.ast.ASTNode
055     */
056    
057    public abstract class ParseStmt extends ParseExpr
058    {
059        public ParseStmt() {
060            //@ set seqStmt.elementType = \type(Stmt);
061            //@ set seqStmt.owner = this;
062    
063            //@ set seqCatchClause.elementType = \type(CatchClause);
064            //@ set seqCatchClause.owner = this;
065        }
066    
067        /**
068         * Internal working storage for many <code>ParseStmt</code>
069         * functions.
070         */
071        //@ invariant seqStmt.elementType == \type(Stmt);
072        //@ invariant seqStmt.owner == this;
073        protected final /*@ non_null @*/ StackVector seqStmt
074                = new StackVector();
075    
076        //* Internal working storage for parseCatches function.
077        //@ invariant seqCatchClause.elementType == \type(CatchClause);
078        //@ invariant seqCatchClause.owner == this;
079        protected final /*@ non_null @*/ StackVector seqCatchClause
080                = new StackVector();
081    
082        /**
083         * Parse a type declaration stating at the class/interface
084         * keyword.  A declaration of this method is needed because class
085         * declarations can be in statements.  However, the body (and more
086         * documentation) lives in Parse.java.
087         */
088        //@ requires l != null && l.m_in != null;
089        //@ requires loc != Location.NULL;
090        //@ modifies l.ttype;
091        //@ ensures \result != null;
092        //@ ensures \old(l.ttype)==TagConstants.CLASS ==> \result instanceof ClassDecl;
093        abstract TypeDecl parseTypeDeclTail(Lex l, boolean specOnly, int loc, 
094                                            int modifiers,
095                                            ModifierPragmaVec modifierPragmas);
096      
097        /**
098         * Method for parsing a <code>Stmt</code>.
099         *
100         * <p> Effects: Parses a single <code>Stmt</code> according to the
101         * grammar at the top of this file, <em>except</em> that it does
102         * not accept variable-declaration statements.  If no syntax
103         * errors are encountered, it adds one or more <code>Stmt</code>
104         * to <code>seqStmt</code>, leaving <code>l</code> at the token
105         * just after the trailing <code>}</code> of the statement.  More
106         * than one statement is added only in the case of variable
107         * declarations that declare more than one variable.
108         */
109        //@ requires l != null && l.m_in != null;
110        //@ ensures \result != null;
111        public Stmt parseStatement(Lex l) {
112            if (l.ttype == TagConstants.LBRACE) // As an optimization, handle specially
113                return parseBlock(l, false);
114            else {
115                seqStmt.push();
116                int loc = l.startingLoc;
117                addStmt(l);
118                Stmt result = (Stmt)seqStmt.elementAt(0);
119                if (seqStmt.size() != 1 || result instanceof VarDeclStmt) {
120                    fail(loc,
121                         "Variable declarations are not legal in this context.");
122                }
123                if (result instanceof StmtPragma) {
124                    fail(loc,
125                         "Statement pragmas are not legal in this context.");
126                }
127    
128                seqStmt.pop();
129                return result;
130            }
131        }
132    
133        /**
134         * Internal method for parsing a <code>Stmt</code>.
135         *
136         * <p> Effects: Parses a single <code>Stmt</code> according to the
137         * grammar at the top of this file.  If no syntax errors are
138         * encountered, it adds one or more <code>Stmt</code> to
139         * <code>seqStmt</code>, leaving <code>l</code> at the token just
140         * after the trailing <code>}</code> of the statement.  More than
141         * one statement is added only in the case of variable
142         * declarations that declare more than one variable.
143         */
144        //@ requires l != null && l.m_in != null;
145        //-@ modifies seqStmt.elementCount, seqStmt.currentStackBottom;
146        /*@ ensures (seqStmt.elementCount - seqStmt.currentStackBottom) >
147         (\old(seqStmt.elementCount) - \old(seqStmt.currentStackBottom)); @*/
148        protected void addStmt(Lex l) {
149            int ttype = l.ttype;
150    
151            // Stmt ::= ';'
152            if (ttype == TagConstants.SEMICOLON) {
153                int loc = l.startingLoc;
154                l.getNextToken(); // Discard ';'
155                seqStmt.addElement( SkipStmt.make(loc) );
156                return;
157            }
158    
159            // Stmt ::= Idn ':' Stmt
160            //          | Idn { '[' ']' }* { Idn ['=' InitExpr] },+
161            //          | Expr ';'
162            if (ttype == TagConstants.IDENT) {
163                //  FIXME @ assert !l.toString().equals("assert");
164                Expr e = parseExpression(l);
165                if (e.getTag() == TagConstants.AMBIGUOUSVARIABLEACCESS) {
166                    Name n = ((AmbiguousVariableAccess)e).name;
167    
168                    // Check to see if we have a labeled expr...
169                    if (l.ttype == TagConstants.COLON) {
170                        l.getNextToken(); // Discard ':'
171                        if (n.size() != 1)
172                            fail(l.startingLoc, "Can't have qualified name in this context");
173                        Identifier id = n.identifierAt(0);
174                        int locId = n.locIdAt(0);
175                        seqStmt.addElement( LabelStmt.make(id, parseStatement(l), locId) );
176                        return;
177                    }
178    
179                    // Assume we have a variable declaration
180                    // first, look for modifiers on type name
181                    TypeModifierPragmaVec tmodifiers = null;
182                    tmodifiers = parseTypeModifierPragmas(l);
183                    Type basetype = TypeName.make(tmodifiers, n);
184    
185                    basetype = parseBracketPairs(l, basetype);
186                    addVarDeclStmts(l, Modifiers.NONE, null, basetype);
187                    expect(l, TagConstants.SEMICOLON);
188                    return;
189                } else {
190                    expect(l, TagConstants.SEMICOLON);
191                    // TODO: make sure e is a statement expr
192                    seqStmt.addElement( EvalStmt.make(e) );
193                    return;
194                }
195            }
196    
197            // Stmt ::= '{' ... '}'  (that is, a Block)
198            if (ttype == TagConstants.LBRACE) {
199                seqStmt.addElement( parseBlock(l, false) );
200                return;
201            }
202         
203            // Stmt ::= <keyword> ...
204            int keywordloc = l.startingLoc;
205            switch (ttype) {
206                case TagConstants.ASSERT: { // 'assert' BoolExpr [ ':' NonVoidExpr ] ';'
207                    
208                    int loc = l.startingLoc;
209                    l.getNextToken(); // Discard the keyword
210                    Expr predicate = parseExpression(l);
211                    Expr label = null;
212                    if (l.ttype == TagConstants.COLON) {
213                        l.getNextToken();
214                        label = parseExpression(l);
215                    }
216                    expect(l, TagConstants.SEMICOLON);
217                    // Only process if assert *is* a keyword.
218                    if (Tool.options != null && !Tool.options.assertIsKeyword) {
219                        ErrorSet.error(loc, "Java keyword \"assert\" is only supported if the" +
220                             " -source 1.4 option is provided.");
221                    } else
222                        seqStmt.addElement(AssertStmt.make(predicate, label, keywordloc));
223                    return;
224                }
225          
226                case TagConstants.BREAK: // 'break' [ Idn ] ';'
227                case TagConstants.CONTINUE: { // 'continue' [ Idn ] ';'
228                    l.getNextToken(); // Discard the keyword
229                    Identifier label = null;
230                    if (l.ttype == TagConstants.IDENT) {
231                        label = l.identifierVal;
232                        l.getNextToken(); // Discard IDENT
233                    }
234                    expect(l, TagConstants.SEMICOLON);
235                    seqStmt.addElement(ttype == TagConstants.BREAK ?
236                                       (Stmt)BreakStmt.make(label, keywordloc)
237                                       : (Stmt)ContinueStmt.make(label, keywordloc));
238                    return;
239                }
240                                    
241                case TagConstants.RETURN: // 'return' Expr ';'
242                    l.getNextToken(); // Discard the keyword
243                    if (l.ttype == TagConstants.SEMICOLON) {
244                        l.getNextToken(); // Discard ';'
245                        seqStmt.addElement( ReturnStmt.make(null, keywordloc) );
246                    } else {
247                        Expr expr = parseExpression(l);
248                        expect(l, TagConstants.SEMICOLON);
249                        seqStmt.addElement(ReturnStmt.make(expr, keywordloc));
250                    }
251                    return;
252                                    
253                case TagConstants.THROW: { // 'throw' Expr ';'
254                    l.getNextToken(); // Discard the keyword
255                    Expr expr = parseExpression(l);
256                    expect(l, TagConstants.SEMICOLON);
257                    seqStmt.addElement(ThrowStmt.make(expr, keywordloc));
258                    return;
259                }
260    
261                case TagConstants.IF: { // 'if' '(' Expr ')' Stmt [ 'else' Stmt ]
262                    l.getNextToken(); // Discard the keyword
263                    expect(l, TagConstants.LPAREN);
264                    Expr test = parseExpression(l);
265                    expect(l, TagConstants.RPAREN);
266                    Stmt consequence = parseStatement(l);
267                    Stmt alternative;
268                    if (l.ttype == TagConstants.ELSE) {
269                        l.getNextToken(); // Discard 'else'
270                        alternative = parseStatement(l);
271                    } else
272                        // set the location of the implicit Skip to be that of the If
273                        alternative = SkipStmt.make(keywordloc);
274                    seqStmt.addElement(IfStmt.make(test, consequence, alternative,
275                                                   keywordloc));
276                    return;
277                }
278    
279                case TagConstants.DO: { // 'do' Stmt 'while' '(' Expr ')' ';'
280                    l.getNextToken(); // Discard the keyword
281                    Stmt body = parseStatement(l);
282                    expect(l, TagConstants.WHILE);
283                    expect(l, TagConstants.LPAREN);
284                    Expr test = parseExpression(l);
285                    expect(l, TagConstants.RPAREN);
286                    expect(l, TagConstants.SEMICOLON);
287                    seqStmt.addElement( DoStmt.make(test, body, keywordloc) );
288                    return;
289                }
290    
291                case TagConstants.WHILE: { // 'while' '(' Expr ')' Stmt
292                    l.getNextToken(); // Discard the keyword
293                    int locGuardOpenParen = l.startingLoc;
294                    expect(l, TagConstants.LPAREN);
295                    Expr test = parseExpression(l);
296                    expect(l, TagConstants.RPAREN);
297                    Stmt body = parseStatement(l);
298                    seqStmt.addElement( WhileStmt.make(test, body, keywordloc,
299                                                       locGuardOpenParen) );
300                    return;
301                }
302                     
303                case TagConstants.FOR: {
304                    l.getNextToken(); // Discard the keyword
305                    seqStmt.addElement( parseForStmt(l, keywordloc) );
306                    return;
307                }
308    
309                case TagConstants.SWITCH: {
310                    l.getNextToken(); // Discard the keyword
311                    seqStmt.addElement( parseSwitchStmt(l, keywordloc) );
312                    return;
313                }
314    
315                case TagConstants.SYNCHRONIZED: { // 'synchronized' '(' Expr ')' '{' BlockStmt* '}'
316                    l.getNextToken(); // Discard the keyword
317                    int locOpenParen = l.startingLoc;
318                    expect(l, TagConstants.LPAREN);
319                    Expr value = parseExpression(l);
320                    expect(l, TagConstants.RPAREN);
321                    BlockStmt body = parseBlock(l, false);
322                    seqStmt.addElement( SynchronizeStmt.make(value, body, keywordloc,
323                                                             locOpenParen));
324                    return;
325                }
326          
327                case TagConstants.TRY: { //'try' '{' BlockStmt* '}' Catches ['finally' '{'BlockStmt*'}']
328                    l.getNextToken(); // Discard the keyword
329                    int openloc = l.startingLoc;
330                    Stmt body = parseBlock(l, false);
331    
332                    CatchClauseVec catches = parseCatches(l);
333    
334                    if (l.ttype == TagConstants.FINALLY) {
335                        int finloc = l.startingLoc;
336                        l.getNextToken(); // Discard 'finally'
337                        Stmt fbody = parseBlock(l, false);
338                        if (catches != null) {
339                            Stmt s = TryCatchStmt.make(body, catches, keywordloc);
340                            seqStmt.addElement( TryFinallyStmt.make(s, fbody, keywordloc,
341                                                                    finloc) );
342                        } else seqStmt.addElement( TryFinallyStmt.make(body, fbody,
343                                                                       keywordloc, finloc) );
344                        return;
345                    } else {
346                        if (catches == null) 
347                            fail(l.startingLoc, "Missing handlers in try statement");
348                        seqStmt.addElement( TryCatchStmt.make(body, catches, keywordloc) );
349                        return;
350                    }
351                }
352            }
353    
354            // Stmt ::= ClassDecl | VarDeclInit   (Except those starting with IDENT)
355            {
356                int modifiers = parseModifiers(l);
357                ModifierPragmaVec pmodifiers = this.modifierPragmas;
358    
359                // This is rather a hack, because some pragmas that are allowed
360                // are not statement pragmas (because they are indistinguishable
361                // from other pragmas).
362                if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA) {
363                    do {
364                        TypeDeclElemPragma tdp = (TypeDeclElemPragma)l.auxVal;
365                        tdp.decorate(pmodifiers);
366                        FieldDecl fd = l.pragmaParser.isPragmaDecl(l);
367                        if (modifiers != Modifiers.NONE) {
368                            ErrorSet.caution(tdp.getStartLoc(),
369                                "Misplaced Java modifiers prior to this point");
370                        }
371                        if (fd != null) {
372                            LocalVarDecl d
373                                = LocalVarDecl.make(fd.modifiers, fd.pmodifiers, 
374                                        fd.id, fd.type, fd.locId, fd.init, fd.locAssignOp);
375                            seqStmt.addElement( VarDeclStmt.make(d) );
376                            l.getNextToken();
377                            // There might be more than one variable declared in
378                            // the one declaration.  We could simply let the 
379                            // parser handle it by returning here, but then we
380                            // lose the pmodifiers information up above.
381                            if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA)
382                                    continue;
383                            break;
384                        } else {
385                            l.getNextToken();
386                            break;
387                        }
388                    } while(true);
389                    return;
390                } else if (l.ttype == TagConstants.CLASS) {
391                    ClassDecl cd = (ClassDecl)parseTypeDeclTail(l, false, keywordloc,
392                                                                modifiers, pmodifiers);
393                    seqStmt.addElement(ClassDeclStmt.make(cd));
394                    return;
395                } else if (modifiers != Modifiers.NONE || pmodifiers != null ||
396                           isPrimitiveKeywordTag(ttype)) {
397                    addVarDeclStmts(l, modifiers, pmodifiers, parseType(l));
398                    expect(l, TagConstants.SEMICOLON);
399                    return;
400                }
401            }
402    
403            // Check for StmtPragma
404            if( ttype == TagConstants.STMTPRAGMA ) {
405                StmtPragma pragma = (StmtPragma)l.auxVal;
406                seqStmt.addElement( (Stmt)pragma );
407                l.getNextToken();
408                return;
409            }
410    
411            // Assume it's a statement expression...
412            Expr e = parseExpression(l);
413            if (! isStatementExpression(e)) 
414                fail(l.startingLoc, "Statement expression expected");
415            seqStmt.addElement( EvalStmt.make(e) );
416            expect(l, TagConstants.SEMICOLON);
417            return;
418        }
419    
420        /**
421         * Method for parsing a <code>ConstructorBody</code>.
422         *
423         * <p> Effects: Parses the following grammar:
424         * <pre>
425         * Block ::=
426         * '{' [ { 'this' | 'super' ] '(' ArgumentList ')' ] { VarDeclInit | Stmt }* '}'
427         * </pre>
428         *
429         * <p> If no syntax errors are encountered, it returns a parse
430         * tree for the parsed input, leaving <code>l</code> at the token
431         * just after the trailing <code>}</code> of the statement.
432         */
433        //@ requires l != null && l.m_in != null;
434        //@ ensures \result != null;
435        public BlockStmt parseConstructorBody(Lex l) {
436            int openloc = l.startingLoc;
437            expect(l, TagConstants.LBRACE);
438            seqStmt.push();
439    
440            // Handle leading constructor invocation; 
441            // make one up if missing and the class being declared in not object
442    
443            if (((l.ttype == TagConstants.THIS || l.ttype == TagConstants.SUPER)
444                 && l.lookahead(1) == TagConstants.LPAREN)) {
445                boolean superCall = (l.ttype == TagConstants.SUPER);
446                int loc = l.startingLoc;
447                l.getNextToken();
448                // Next, parse the argument list, which should start with an open
449                // parenthesis.  As a check that "parseArgumentList" doesn't accept
450                // any other first token than an open parenthesis, the tag of the next
451                // token is stored in "tagShouldBeLParen", and it is assert that
452                // *if* "parseArgumentList" returns normally, then the tag recorded
453                // is indeed an open parenthesis.
454                int locOpenParen = l.startingLoc;
455                int tagShouldBeLParen = l.ttype;
456                ExprVec args = parseArgumentList(l);
457                expect( l, TagConstants.SEMICOLON );
458                seqStmt.addElement( ConstructorInvocation.make( superCall,
459                                                                null, Location.NULL,
460                                                                loc, locOpenParen,
461                                                                args ) );
462            } else {
463                // Look for Primary '.' 'super' '(' ArgumentList ')' ';'
464                boolean foundDotSuper = false;
465                for (int i = 0; ; i++) {
466                    switch (l.lookahead(i)) {
467                        case TagConstants.EOF:
468                            break;
469                        case TagConstants.LBRACE:
470                            for(int braceDepth = 1; 0 < braceDepth; i++) {
471                                if (l.lookahead(i) == TagConstants.RBRACE) braceDepth--;
472                            }
473                            continue;
474                        case TagConstants.SEMICOLON:
475                        case TagConstants.RBRACE:
476                            break;
477                        case TagConstants.FIELD:
478                            if (l.lookahead(i+1) == TagConstants.SUPER) {
479                                foundDotSuper = true;
480                                break;
481                            } else continue;
482                        default: continue;
483                    }
484                    break;
485                }
486                if (foundDotSuper) {
487                    int loc = l.startingLoc;
488                    Expr e = parsePrimaryExpression(l);
489                    int locDot = l.startingLoc;
490                    expect(l, TagConstants.FIELD);
491                    expect(l, TagConstants.SUPER);
492                    int locOpenParen = l.startingLoc;
493                    ExprVec args = parseArgumentList(l);
494                    expect(l, TagConstants.SEMICOLON);
495                    seqStmt.addElement(ConstructorInvocation.make(true, e, locDot,
496                                                                  loc, locOpenParen,
497                                                                  args));
498                }
499            }
500    
501            // No explicit constructor invocation.  We do not know if this
502            // class is java.lang.Object, so we cannot add a constructor
503            // invocation here; we will do it in type checking.
504          
505            // Handle rest of body
506            {
507                int ttype = l.ttype;
508                while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) {
509                    addStmt(l);
510                    ttype = l.ttype;
511                }
512                if (ttype == TagConstants.EOF) 
513                    fail(l.startingLoc, "End of input in block");
514            }
515            StmtVec body = StmtVec.popFromStackVector(seqStmt);
516            int closeloc = l.startingLoc;
517            l.getNextToken(); // Discard '}'
518            return BlockStmt.make(body, openloc, closeloc);
519        }
520    
521        /**
522         * Method for parsing a <code>Block</code>.
523         *
524         * <p> Effects: Parses the following grammar:
525         * <pre>
526         * Block ::=
527         * '{' { VarDeclInit | Stmt }* '}'
528         * </pre>
529         *
530         * <p> If no syntax errors are encountered, it returns a parse
531         * tree for the parsed input, leaving <code>l</code> at the token
532         * just after the trailing <code>}</code> of the statement.
533         */
534        //@ requires l != null && l.m_in != null;
535        //@ ensures \result != null;
536        public BlockStmt parseBlock(Lex l, boolean specOnly) {
537            int openloc = l.startingLoc;
538            expect(l, TagConstants.LBRACE);
539            seqStmt.push();
540            {
541                int ttype = l.ttype;
542                while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) {
543                    if (!specOnly)
544                        addStmt(l);
545                    else {
546                        if (ttype==TagConstants.LBRACE)
547                            parseBlock(l, true);
548                        else
549                            l.getNextToken();
550                    }
551                    ttype = l.ttype;
552                }
553                if (ttype == TagConstants.EOF) 
554                    fail(l.startingLoc, "End of input in block");
555            }
556            StmtVec body = StmtVec.popFromStackVector(seqStmt);
557            int closeloc = l.startingLoc;
558            l.getNextToken(); // Discard '}'
559            return specOnly ? null : BlockStmt.make(body, openloc, closeloc);
560        }
561    
562        /**
563         * Internal method for parsing a switch statement.
564         *
565         * <p> Effects: Parses the following grammar:
566         * <pre>
567         * ForStmtRemainder ::=
568         * '(' [VDeclInit | StmtExpr,* ] ';' Expr ';' StmtExpr,* ')' Stmt
569         * </pre>
570         *
571         * <p> Note that it assumes the leading <code>for</code> has
572         * already been parsed; <code>keywordloc</code> is the location
573         * assumed for the <code>for</code> token.
574         *
575         * <p> If no syntax errors are encountered, it returns a parse
576         * tree for the parsed input, leaving <code>l</code> at the token
577         * just after the trailing <code>}</code> of the statement.
578         */
579        //@ requires l != null && l.m_in != null;
580        //@ requires keywordloc != Location.NULL;
581        //@ ensures \result != null;
582        private ForStmt parseForStmt(Lex l, int keywordloc) {
583            int parenloc = l.startingLoc;
584            expect(l, TagConstants.LPAREN);
585    
586            // Parse ForInit ::= [VDeclInit | StmtExpr,* ] ';'
587            StmtVec forInit;
588            int locFirstSemi;
589            { // Parse ForInit part
590                seqStmt.push();
591    
592                Type basetype = null;
593                int modifiers = Modifiers.NONE;
594                ModifierPragmaVec pmodifiers = null;
595                switch (l.ttype) {
596                    case TagConstants.SEMICOLON:
597                        break;
598    
599                    default:
600                        modifiers = parseModifiers(l);
601                        pmodifiers = this.modifierPragmas;
602    
603                        if (modifiers != Modifiers.NONE || pmodifiers != null ||
604                            isPrimitiveKeywordTag(l.ttype)) {
605                            basetype = parseType(l);
606                            break;
607                        }
608    
609                        Expr e = parseExpression(l);
610                        if (e.getTag() == TagConstants.AMBIGUOUSVARIABLEACCESS) {
611                            // Assume a var declaration
612                            // look for type modifier pragmas
613                            TypeModifierPragmaVec tmodifiers = null;
614                            tmodifiers = parseTypeModifierPragmas(l);
615                            basetype = TypeName.make(tmodifiers, ((AmbiguousVariableAccess)e).name);
616            
617                            break;
618                        } else {
619                            for(;;) {
620                                if (! isStatementExpression(e)) 
621                                    fail(l.startingLoc, "Statement expression expected");
622                                seqStmt.addElement( EvalStmt.make(e) );
623                                if (l.ttype != TagConstants.COMMA) break;
624                                l.getNextToken(); // Discard the COMMA
625                                e = parseExpression(l);
626                            }
627                        }
628                }
629    
630                if (basetype != null) {
631                    basetype = parseBracketPairs(l, basetype);
632                    addVarDeclStmts(l, modifiers, pmodifiers, basetype);
633                }
634    
635                locFirstSemi = l.startingLoc;
636                expect(l, TagConstants.SEMICOLON);
637                forInit = StmtVec.popFromStackVector(seqStmt);
638            }
639    
640            // Parse <pre> Test ::= [ Expr ] ';' </pre>
641            Expr test;
642            if (l.ttype != TagConstants.SEMICOLON)
643                test = parseExpression(l);
644            else test = LiteralExpr.make(TagConstants.BOOLEANLIT, 
645                                         Boolean.TRUE, 
646                                         l.startingLoc );
647            expect(l, TagConstants.SEMICOLON);
648    
649            // Parse <pre> ForUpdate ::= StmtExpr,* ')' </pre>
650            ExprVec forUpdate;
651            {
652                seqExpr.push();
653    
654                if (l.ttype != TagConstants.RPAREN) {
655                    for(;;) {
656                        Expr e = parseExpression(l);
657                        if (! isStatementExpression(e))
658                            fail(l.startingLoc, "Statement expression expected.");
659                        seqExpr.addElement(e);
660                        if (l.ttype != TagConstants.COMMA) break;
661                        l.getNextToken(); // Discard COMMA
662                    }
663                }
664                expect(l, TagConstants.RPAREN);
665                forUpdate = ExprVec.popFromStackVector(seqExpr);
666            }
667    
668            Stmt body = parseStatement(l);
669            return ForStmt.make(forInit, test, forUpdate, body, keywordloc,
670                                locFirstSemi);
671        }
672    
673        /**
674         * Internal method for parsing a switch statement.
675         *
676         * <p> Effects: Parses the following grammar:
677         * <pre>
678         * SwitchStmtRemainder ::=
679         * '(' Expr ')' '{' { 'case' Expr ':' | 'default ':' | Stmt }* '}'
680         * </pre>
681         *
682         * <p> Note that it assumes the trailing <code>switch</code> has
683         * already been parsed; <code>keywordLoc</code> is the location
684         * assumed for the <code>switch</code> token.
685         *
686         * <p> If no syntax errors are encountered, it returns a parse
687         * tree for the parsed input, leaving <code>l</code> at the token
688         * just after the trailing <code>}</code> of the statement.
689         */
690        //@ requires l != null && l.m_in != null;
691        //@ requires keywordloc != Location.NULL;
692        //@ ensures \result != null;
693        private SwitchStmt parseSwitchStmt(Lex l, int keywordloc) {
694            // Read value to be tested
695            expect(l, TagConstants.LPAREN);
696            Expr value = parseExpression(l);
697            expect(l, TagConstants.RPAREN);
698    
699            // Read body
700            int openloc = l.startingLoc;
701            expect(l, TagConstants.LBRACE);
702            boolean atStart=true;
703            boolean hasDefault = false;
704            seqStmt.push();
705            while (l.ttype != TagConstants.RBRACE && l.ttype != TagConstants.EOF) {
706                if (l.ttype == TagConstants.CASE || l.ttype == TagConstants.DEFAULT) {
707                    if (l.ttype == TagConstants.DEFAULT) {
708                        hasDefault = true;
709                    }
710                    int loc = l.startingLoc;
711                    int ttype = l.ttype;
712                    l.getNextToken(); // Discard CASE TagConstants.or DEFAULT
713                    Expr e = (ttype == TagConstants.CASE ? parseExpression(l) : null);
714                    expect(l, TagConstants.COLON);
715                    seqStmt.addElement( SwitchLabel.make(e, loc) );
716                } 
717                else {
718                    if (atStart) fail(l.startingLoc,"Switch body must start with a label");
719                    addStmt(l);
720                }
721                atStart = false;
722            }
723            if (l.ttype == TagConstants.EOF) 
724                fail(l.startingLoc, "End of input in switch body");
725            int closeloc = l.startingLoc;
726            l.getNextToken(); // Discard '}'
727    
728            if (!hasDefault) {
729                seqStmt.addElement(SwitchLabel.make(null, closeloc));
730                seqStmt.addElement(BreakStmt.make(null, closeloc));
731            }
732            StmtVec body = StmtVec.popFromStackVector(seqStmt);
733            return SwitchStmt.make(body, openloc, closeloc, value, keywordloc);
734        }
735    
736        /**
737         * Internal routine for parsing zero or more catch clauses.
738         *
739         * <p> Effects: Parses the following grammar:
740         * <pre> Catches ::= { 'catch' '(' [Modifiers] Type Idn ')' Block }* </pre>
741         *
742         * At the start of each iteration (including the first), if the
743         * first token is not <code>catch</code>, it stops trying to
744         * parse, returning the (possibly empty) sequence of catch clauses
745         * parsed already and leaving the token at the first token
746         * following the last catch clause parsed.  If the first token is
747         * <code>catch</code>, then it tries to parse a catch clause,
748         * throwing an exception if a syntax error is found.
749         */
750        //@ requires l != null && l.m_in != null;
751        private CatchClauseVec parseCatches(Lex l) {
752            if (l.ttype != TagConstants.CATCH) return null;
753            seqCatchClause.push();
754    
755            do {
756                int loc = l.startingLoc;
757                l.getNextToken(); // Discard CATCH
758                expect(l, TagConstants.LPAREN);
759                FormalParaDecl arg = parseFormalParaDecl(l);
760                expect(l, TagConstants.RPAREN);
761                seqCatchClause.addElement( CatchClause.make(arg, parseBlock(l,false),
762                                                            loc) );
763            } while (l.ttype == TagConstants.CATCH);
764            return CatchClauseVec.popFromStackVector(seqCatchClause);
765        }
766    
767        /**
768         * Internal routine for parsing variable declarations
769         * <em>after</em> the leading type has been parsed.
770         * 
771         * <p>Effects: Parses the following grammar:
772         * <pre>
773         * VarDeclRemainder ::=
774         * { Idn { '[' ']' }* [ '=' VariableInitializer ] },*
775         * </pre>
776         * 
777         * <p> Each <code>VarDeclRemainder</code> found is combined with
778         * <code>basetype</code> to create a <code>VarDeclStmt</code>
779         * which is added to the end of <code>seqStmt</code>.
780         * 
781         * <p> On entry, it assumes at least one
782         * <code>VarDeclRemainder</code> is available, and throws an
783         * exception if one isn't.  At the end of each iteration, it stops
784         * trying to parse if the comma is not present, leaving the token
785         * at the first token following the last
786         * <code>VarDeclRemainder</code> parsed.  If a comma is found,
787         * then it tries to parse the next <code>VarDeclRemainder</code>,
788         * throwing an exception if a syntax error is found.
789         */
790        //@ requires l != null && basetype != null && l.m_in != null;
791        //@ requires basetype.syntax;
792        private void addVarDeclStmts(Lex l, int modifiers, 
793                                     ModifierPragmaVec modifierPragmas,
794                                     Type basetype)
795        {
796            // make modifierPragmas non-null, so can retroactively extend
797            if( modifierPragmas == null )
798                modifierPragmas = ModifierPragmaVec.make();
799    
800            for(;;) {
801                // Get identifier and any [] pairs trailing it
802                Identifier id = l.identifierVal;
803                int locId = l.startingLoc;
804                expect(l, TagConstants.IDENT);
805                Type vartype = parseBracketPairs(l, basetype);
806    
807                // Get initializer if there is one
808                VarInit init = null;
809                int locAssignOp = Location.NULL;
810                if (l.ttype == TagConstants.ASSIGN) {
811                    locAssignOp = l.startingLoc;
812                    l.getNextToken();
813                    init = parseVariableInitializer(l, false);
814                }
815    
816                LocalVarDecl d
817                    = LocalVarDecl.make(modifiers, modifierPragmas, 
818                                        id, vartype, locId, init, locAssignOp);
819                seqStmt.addElement( VarDeclStmt.make(d) );
820    
821                // check if end of declaration
822    
823                if(l.ttype == TagConstants.MODIFIERPRAGMA ) {
824                    // if modifier pragma, retroactively add to modifierPragmas
825                    parseMoreModifierPragmas( l, modifierPragmas );
826                    return;
827                } else if(l.ttype != TagConstants.COMMA ) {
828                    // all done - do not swallow following semicolon
829                    return;
830                }
831    
832                expect( l, TagConstants.COMMA );
833                /* And go around loop again */
834            }
835        }
836    
837    
838        /**
839         * Routine for parsing a single formal parameter declarations.
840         * 
841         * <p> Effects: Parses the following grammar:
842         * <pre> FormalParaDecl ::= { [Modifiers] Type Idn ModifierPragma* } </pre>
843         * returning an ASTNode representing the result.  Leaves
844         * <code>l</code> pointing to the token just after the
845         * <code>FormalParaDecl</code>.
846         */
847        //@ requires l != null && l.m_in != null;
848        //@ ensures \result != null;
849        public FormalParaDecl parseFormalParaDecl(Lex l) {
850            int modifiers = parseModifiers(l);
851            ModifierPragmaVec modifierPragmas = this.modifierPragmas;
852            Type paratype = parseType(l);
853            Identifier idn = l.identifierVal;
854            int locId = l.startingLoc;
855            expect(l, TagConstants.IDENT);
856          
857            // allow more modifier pragmas
858            modifierPragmas = parseMoreModifierPragmas( l, modifierPragmas );
859    
860            return FormalParaDecl.make(modifiers, modifierPragmas, 
861                                       idn, paratype, locId);
862        }
863    
864        /**
865         * @return true iff <code>e</code> is a Java
866         * <code>StatementExpression</code> as defined in the grammar
867         * given in the language spec.
868         */
869        //@ requires e != null;
870        public static boolean isStatementExpression(Expr e) {
871            switch (e.getTag()) {
872                case TagConstants.ASSIGN: 
873                case TagConstants.ASGMUL: case TagConstants.ASGDIV: 
874                case TagConstants.ASGREM: 
875                case TagConstants.ASGADD: case TagConstants.ASGSUB:
876                case TagConstants.ASGLSHIFT: case TagConstants.ASGRSHIFT: 
877                case TagConstants.ASGURSHIFT: 
878                case TagConstants.ASGBITAND:
879                case TagConstants.ASGBITOR: case TagConstants.ASGBITXOR:
880                case TagConstants.INC: case TagConstants.DEC: 
881                case TagConstants.POSTFIXINC: case TagConstants.POSTFIXDEC:
882                case TagConstants.METHODINVOCATION:
883                case TagConstants.NEWINSTANCEEXPR:
884                    return true;
885                default:
886                    return true; // TODO return false;
887            }
888        }
889    }