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                    //alx: dw need to reset universeArray because in this case, 
187                    //     parseModifiers wasn't called (which would have reseted 
188                    //     universeArray)
189                    universeArray[0]=0;
190                    universeArray[1]=0;
191                    //alx-end
192    
193                    addVarDeclStmts(l, Modifiers.NONE, null, basetype);
194                    expect(l, TagConstants.SEMICOLON);
195                    return;
196                } else {
197                    expect(l, TagConstants.SEMICOLON);
198                    // TODO: make sure e is a statement expr
199                    seqStmt.addElement( EvalStmt.make(e) );
200                    return;
201                }
202            }
203    
204            // Stmt ::= '{' ... '}'  (that is, a Block)
205            if (ttype == TagConstants.LBRACE) {
206                seqStmt.addElement( parseBlock(l, false) );
207                return;
208            }
209         
210            // Stmt ::= <keyword> ...
211            int keywordloc = l.startingLoc;
212            switch (ttype) {
213                case TagConstants.ASSERT: { // 'assert' BoolExpr [ ':' NonVoidExpr ] ';'
214                    
215                    int loc = l.startingLoc;
216                    l.getNextToken(); // Discard the keyword
217                    Expr predicate = parseExpression(l);
218                    Expr label = null;
219                    if (l.ttype == TagConstants.COLON) {
220                        l.getNextToken();
221                        label = parseExpression(l);
222                    }
223                    expect(l, TagConstants.SEMICOLON);
224                    // Only process if assert *is* a keyword.
225                    if (Tool.options != null && !Tool.options.assertIsKeyword) {
226                        ErrorSet.error(loc, "Java keyword \"assert\" is only supported if the" +
227                             " -source 1.4 option is provided.");
228                    } else
229                        seqStmt.addElement(AssertStmt.make(predicate, label, keywordloc));
230                    return;
231                }
232          
233                case TagConstants.BREAK: // 'break' [ Idn ] ';'
234                case TagConstants.CONTINUE: { // 'continue' [ Idn ] ';'
235                    l.getNextToken(); // Discard the keyword
236                    Identifier label = null;
237                    if (l.ttype == TagConstants.IDENT) {
238                        label = l.identifierVal;
239                        l.getNextToken(); // Discard IDENT
240                    }
241                    expect(l, TagConstants.SEMICOLON);
242                    seqStmt.addElement(ttype == TagConstants.BREAK ?
243                                       (Stmt)BreakStmt.make(label, keywordloc)
244                                       : (Stmt)ContinueStmt.make(label, keywordloc));
245                    return;
246                }
247                                    
248                case TagConstants.RETURN: // 'return' Expr ';'
249                    l.getNextToken(); // Discard the keyword
250                    if (l.ttype == TagConstants.SEMICOLON) {
251                        l.getNextToken(); // Discard ';'
252                        seqStmt.addElement( ReturnStmt.make(null, keywordloc) );
253                    } else {
254                        Expr expr = parseExpression(l);
255                        expect(l, TagConstants.SEMICOLON);
256                        seqStmt.addElement(ReturnStmt.make(expr, keywordloc));
257                    }
258                    return;
259                                    
260                case TagConstants.THROW: { // 'throw' Expr ';'
261                    l.getNextToken(); // Discard the keyword
262                    Expr expr = parseExpression(l);
263                    expect(l, TagConstants.SEMICOLON);
264                    seqStmt.addElement(ThrowStmt.make(expr, keywordloc));
265                    return;
266                }
267    
268                case TagConstants.IF: { // 'if' '(' Expr ')' Stmt [ 'else' Stmt ]
269                    l.getNextToken(); // Discard the keyword
270                    expect(l, TagConstants.LPAREN);
271                    Expr test = parseExpression(l);
272                    expect(l, TagConstants.RPAREN);
273                    Stmt consequence = parseStatement(l);
274                    Stmt alternative;
275                    if (l.ttype == TagConstants.ELSE) {
276                        l.getNextToken(); // Discard 'else'
277                        alternative = parseStatement(l);
278                    } else
279                        // set the location of the implicit Skip to be that of the If
280                        alternative = SkipStmt.make(keywordloc);
281                    seqStmt.addElement(IfStmt.make(test, consequence, alternative,
282                                                   keywordloc));
283                    return;
284                }
285    
286                case TagConstants.DO: { // 'do' Stmt 'while' '(' Expr ')' ';'
287                    l.getNextToken(); // Discard the keyword
288                    Stmt body = parseStatement(l);
289                    expect(l, TagConstants.WHILE);
290                    expect(l, TagConstants.LPAREN);
291                    Expr test = parseExpression(l);
292                    expect(l, TagConstants.RPAREN);
293                    expect(l, TagConstants.SEMICOLON);
294                    seqStmt.addElement( DoStmt.make(test, body, keywordloc) );
295                    return;
296                }
297    
298                case TagConstants.WHILE: { // 'while' '(' Expr ')' Stmt
299                    l.getNextToken(); // Discard the keyword
300                    int locGuardOpenParen = l.startingLoc;
301                    expect(l, TagConstants.LPAREN);
302                    Expr test = parseExpression(l);
303                    expect(l, TagConstants.RPAREN);
304                    Stmt body = parseStatement(l);
305                    seqStmt.addElement( WhileStmt.make(test, body, keywordloc,
306                                                       locGuardOpenParen) );
307                    return;
308                }
309                     
310                case TagConstants.FOR: {
311                    l.getNextToken(); // Discard the keyword
312                    seqStmt.addElement( parseForStmt(l, keywordloc) );
313                    return;
314                }
315    
316                case TagConstants.SWITCH: {
317                    l.getNextToken(); // Discard the keyword
318                    seqStmt.addElement( parseSwitchStmt(l, keywordloc) );
319                    return;
320                }
321    
322                case TagConstants.SYNCHRONIZED: { // 'synchronized' '(' Expr ')' '{' BlockStmt* '}'
323                    l.getNextToken(); // Discard the keyword
324                    int locOpenParen = l.startingLoc;
325                    expect(l, TagConstants.LPAREN);
326                    Expr value = parseExpression(l);
327                    expect(l, TagConstants.RPAREN);
328                    BlockStmt body = parseBlock(l, false);
329                    seqStmt.addElement( SynchronizeStmt.make(value, body, keywordloc,
330                                                             locOpenParen));
331                    return;
332                }
333          
334                case TagConstants.TRY: { //'try' '{' BlockStmt* '}' Catches ['finally' '{'BlockStmt*'}']
335                    l.getNextToken(); // Discard the keyword
336                    int openloc = l.startingLoc;
337                    Stmt body = parseBlock(l, false);
338    
339                    CatchClauseVec catches = parseCatches(l);
340    
341                    if (l.ttype == TagConstants.FINALLY) {
342                        int finloc = l.startingLoc;
343                        l.getNextToken(); // Discard 'finally'
344                        Stmt fbody = parseBlock(l, false);
345                        if (catches != null) {
346                            Stmt s = TryCatchStmt.make(body, catches, keywordloc);
347                            seqStmt.addElement( TryFinallyStmt.make(s, fbody, keywordloc,
348                                                                    finloc) );
349                        } else seqStmt.addElement( TryFinallyStmt.make(body, fbody,
350                                                                       keywordloc, finloc) );
351                        return;
352                    } else {
353                        if (catches == null) 
354                            fail(l.startingLoc, "Missing handlers in try statement");
355                        seqStmt.addElement( TryCatchStmt.make(body, catches, keywordloc) );
356                        return;
357                    }
358                }
359            }
360    
361            // Stmt ::= ClassDecl | VarDeclInit   (Except those starting with IDENT)
362            {
363                int modifiers = parseModifiers(l);
364                ModifierPragmaVec pmodifiers = this.modifierPragmas;
365                //alx: dw handle universes
366                int[] localUniverseArray = (int[]) this.universeArray.clone();
367                //alx-end
368    
369                // This is rather a hack, because some pragmas that are allowed
370                // are not statement pragmas (because they are indistinguishable
371                // from other pragmas).
372                if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA) {
373                    do {
374                        TypeDeclElemPragma tdp = (TypeDeclElemPragma)l.auxVal;
375                        tdp.decorate(pmodifiers);
376                        FieldDecl fd = l.pragmaParser.isPragmaDecl(l);
377                        if (modifiers != Modifiers.NONE) {
378                            ErrorSet.caution(tdp.getStartLoc(),
379                                "Misplaced Java modifiers prior to this point");
380                        }
381                        if (fd != null) {
382                            LocalVarDecl d
383                                = LocalVarDecl.make(fd.modifiers, fd.pmodifiers, 
384                                        fd.id, fd.type, fd.locId, fd.init, fd.locAssignOp);
385                            seqStmt.addElement( VarDeclStmt.make(d) );
386                            l.getNextToken();
387                            // There might be more than one variable declared in
388                            // the one declaration.  We could simply let the 
389                            // parser handle it by returning here, but then we
390                            // lose the pmodifiers information up above.
391                            if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA)
392                                    continue;
393                            break;
394                        } else {
395                            l.getNextToken();
396                            break;
397                        }
398                    } while(true);
399                    return;
400                } else if (l.ttype == TagConstants.CLASS) {
401                    ClassDecl cd = (ClassDecl)parseTypeDeclTail(l, false, keywordloc,
402                                                                modifiers, pmodifiers);
403                    seqStmt.addElement(ClassDeclStmt.make(cd));
404                    return;
405                } else if (modifiers != Modifiers.NONE || pmodifiers != null ||
406                           //alx: dw universe modifiers are also in this case
407                           localUniverseArray[0]!=0 ||
408                           //alx-end
409                           isPrimitiveKeywordTag(ttype)) {
410                    //alx: dw save universes to our field, addVarDeclStmts expects 
411                    //   it there
412                    universeArray=localUniverseArray;
413                    //alx-end
414    
415                    addVarDeclStmts(l, modifiers, pmodifiers, parseType(l));
416                    expect(l, TagConstants.SEMICOLON);
417                    return;
418                }
419            }
420    
421            // Check for StmtPragma
422            if( ttype == TagConstants.STMTPRAGMA ) {
423                StmtPragma pragma = (StmtPragma)l.auxVal;
424                seqStmt.addElement( (Stmt)pragma );
425                l.getNextToken();
426                return;
427            }
428    
429            // Assume it's a statement expression...
430            Expr e = parseExpression(l);
431            if (! isStatementExpression(e)) 
432                fail(l.startingLoc, "Statement expression expected");
433            seqStmt.addElement( EvalStmt.make(e) );
434            expect(l, TagConstants.SEMICOLON);
435            return;
436        }
437    
438        /**
439         * Method for parsing a <code>ConstructorBody</code>.
440         *
441         * <p> Effects: Parses the following grammar:
442         * <pre>
443         * Block ::=
444         * '{' [ { 'this' | 'super' ] '(' ArgumentList ')' ] { VarDeclInit | Stmt }* '}'
445         * </pre>
446         *
447         * <p> If no syntax errors are encountered, it returns a parse
448         * tree for the parsed input, leaving <code>l</code> at the token
449         * just after the trailing <code>}</code> of the statement.
450         */
451        //@ requires l != null && l.m_in != null;
452        //@ ensures \result != null;
453        public BlockStmt parseConstructorBody(Lex l) {
454            int openloc = l.startingLoc;
455            expect(l, TagConstants.LBRACE);
456            seqStmt.push();
457    
458            // Handle leading constructor invocation; 
459            // make one up if missing and the class being declared in not object
460    
461            if (((l.ttype == TagConstants.THIS || l.ttype == TagConstants.SUPER)
462                 && l.lookahead(1) == TagConstants.LPAREN)) {
463                boolean superCall = (l.ttype == TagConstants.SUPER);
464                int loc = l.startingLoc;
465                l.getNextToken();
466                // Next, parse the argument list, which should start with an open
467                // parenthesis.  As a check that "parseArgumentList" doesn't accept
468                // any other first token than an open parenthesis, the tag of the next
469                // token is stored in "tagShouldBeLParen", and it is assert that
470                // *if* "parseArgumentList" returns normally, then the tag recorded
471                // is indeed an open parenthesis.
472                int locOpenParen = l.startingLoc;
473                int tagShouldBeLParen = l.ttype;
474                ExprVec args = parseArgumentList(l);
475                expect( l, TagConstants.SEMICOLON );
476                seqStmt.addElement( ConstructorInvocation.make( superCall,
477                                                                null, Location.NULL,
478                                                                loc, locOpenParen,
479                                                                args ) );
480            } else {
481                // Look for Primary '.' 'super' '(' ArgumentList ')' ';'
482                boolean foundDotSuper = false;
483                for (int i = 0; ; i++) {
484                    switch (l.lookahead(i)) {
485                        case TagConstants.EOF:
486                            break;
487                        case TagConstants.LBRACE:
488                            for(int braceDepth = 1; 0 < braceDepth; i++) {
489                                if (l.lookahead(i) == TagConstants.RBRACE) braceDepth--;
490                            }
491                            continue;
492                        case TagConstants.SEMICOLON:
493                        case TagConstants.RBRACE:
494                            break;
495                        case TagConstants.FIELD:
496                            if (l.lookahead(i+1) == TagConstants.SUPER) {
497                                foundDotSuper = true;
498                                break;
499                            } else continue;
500                        default: continue;
501                    }
502                    break;
503                }
504                if (foundDotSuper) {
505                    int loc = l.startingLoc;
506                    Expr e = parsePrimaryExpression(l);
507                    int locDot = l.startingLoc;
508                    expect(l, TagConstants.FIELD);
509                    expect(l, TagConstants.SUPER);
510                    int locOpenParen = l.startingLoc;
511                    ExprVec args = parseArgumentList(l);
512                    expect(l, TagConstants.SEMICOLON);
513                    seqStmt.addElement(ConstructorInvocation.make(true, e, locDot,
514                                                                  loc, locOpenParen,
515                                                                  args));
516                }
517            }
518    
519            // No explicit constructor invocation.  We do not know if this
520            // class is java.lang.Object, so we cannot add a constructor
521            // invocation here; we will do it in type checking.
522          
523            // Handle rest of body
524            {
525                int ttype = l.ttype;
526                while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) {
527                    addStmt(l);
528                    ttype = l.ttype;
529                }
530                if (ttype == TagConstants.EOF) 
531                    fail(l.startingLoc, "End of input in block");
532            }
533            StmtVec body = StmtVec.popFromStackVector(seqStmt);
534            int closeloc = l.startingLoc;
535            l.getNextToken(); // Discard '}'
536            return BlockStmt.make(body, openloc, closeloc);
537        }
538    
539        /**
540         * Method for parsing a <code>Block</code>.
541         *
542         * <p> Effects: Parses the following grammar:
543         * <pre>
544         * Block ::=
545         * '{' { VarDeclInit | Stmt }* '}'
546         * </pre>
547         *
548         * <p> If no syntax errors are encountered, it returns a parse
549         * tree for the parsed input, leaving <code>l</code> at the token
550         * just after the trailing <code>}</code> of the statement.
551         */
552        //@ requires l != null && l.m_in != null;
553        //@ ensures \result != null;
554        public BlockStmt parseBlock(Lex l, boolean specOnly) {
555            int openloc = l.startingLoc;
556            expect(l, TagConstants.LBRACE);
557            seqStmt.push();
558            {
559                int ttype = l.ttype;
560                while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) {
561                    if (!specOnly)
562                        addStmt(l);
563                    else {
564                        if (ttype==TagConstants.LBRACE)
565                            parseBlock(l, true);
566                        else
567                            l.getNextToken();
568                    }
569                    ttype = l.ttype;
570                }
571                if (ttype == TagConstants.EOF) 
572                    fail(l.startingLoc, "End of input in block");
573            }
574            StmtVec body = StmtVec.popFromStackVector(seqStmt);
575            int closeloc = l.startingLoc;
576            l.getNextToken(); // Discard '}'
577            return specOnly ? null : BlockStmt.make(body, openloc, closeloc);
578        }
579    
580        /**
581         * Internal method for parsing a switch statement.
582         *
583         * <p> Effects: Parses the following grammar:
584         * <pre>
585         * ForStmtRemainder ::=
586         * '(' [VDeclInit | StmtExpr,* ] ';' Expr ';' StmtExpr,* ')' Stmt
587         * </pre>
588         *
589         * <p> Note that it assumes the leading <code>for</code> has
590         * already been parsed; <code>keywordloc</code> is the location
591         * assumed for the <code>for</code> token.
592         *
593         * <p> If no syntax errors are encountered, it returns a parse
594         * tree for the parsed input, leaving <code>l</code> at the token
595         * just after the trailing <code>}</code> of the statement.
596         */
597        //@ requires l != null && l.m_in != null;
598        //@ requires keywordloc != Location.NULL;
599        //@ ensures \result != null;
600        private ForStmt parseForStmt(Lex l, int keywordloc) {
601            int parenloc = l.startingLoc;
602            expect(l, TagConstants.LPAREN);
603    
604            // Parse ForInit ::= [VDeclInit | StmtExpr,* ] ';'
605            StmtVec forInit;
606            int locFirstSemi;
607            { // Parse ForInit part
608                seqStmt.push();
609    
610                Type basetype = null;
611                int modifiers = Modifiers.NONE;
612                ModifierPragmaVec pmodifiers = null;
613                switch (l.ttype) {
614                    case TagConstants.SEMICOLON:
615                        break;
616    
617                    default:
618                        modifiers = parseModifiers(l);
619                        pmodifiers = this.modifierPragmas;
620    
621                        if (modifiers != Modifiers.NONE || pmodifiers != null ||
622                            isPrimitiveKeywordTag(l.ttype)) {
623                            basetype = parseType(l);
624                            break;
625                        }
626    
627                        Expr e = parseExpression(l);
628                        if (e.getTag() == TagConstants.AMBIGUOUSVARIABLEACCESS) {
629                            // Assume a var declaration
630                            // look for type modifier pragmas
631                            TypeModifierPragmaVec tmodifiers = null;
632                            tmodifiers = parseTypeModifierPragmas(l);
633                            basetype = TypeName.make(tmodifiers, ((AmbiguousVariableAccess)e).name);
634            
635                            break;
636                        } else {
637                            for(;;) {
638                                if (! isStatementExpression(e)) 
639                                    fail(l.startingLoc, "Statement expression expected");
640                                seqStmt.addElement( EvalStmt.make(e) );
641                                if (l.ttype != TagConstants.COMMA) break;
642                                l.getNextToken(); // Discard the COMMA
643                                e = parseExpression(l);
644                            }
645                        }
646                }
647    
648                if (basetype != null) {
649                    basetype = parseBracketPairs(l, basetype);
650                    addVarDeclStmts(l, modifiers, pmodifiers, basetype);
651                }
652    
653                locFirstSemi = l.startingLoc;
654                expect(l, TagConstants.SEMICOLON);
655                forInit = StmtVec.popFromStackVector(seqStmt);
656            }
657    
658            // Parse <pre> Test ::= [ Expr ] ';' </pre>
659            Expr test;
660            if (l.ttype != TagConstants.SEMICOLON)
661                test = parseExpression(l);
662            else test = LiteralExpr.make(TagConstants.BOOLEANLIT, 
663                                         Boolean.TRUE, 
664                                         l.startingLoc );
665            expect(l, TagConstants.SEMICOLON);
666    
667            // Parse <pre> ForUpdate ::= StmtExpr,* ')' </pre>
668            ExprVec forUpdate;
669            {
670                seqExpr.push();
671    
672                if (l.ttype != TagConstants.RPAREN) {
673                    for(;;) {
674                        Expr e = parseExpression(l);
675                        if (! isStatementExpression(e))
676                            fail(l.startingLoc, "Statement expression expected.");
677                        seqExpr.addElement(e);
678                        if (l.ttype != TagConstants.COMMA) break;
679                        l.getNextToken(); // Discard COMMA
680                    }
681                }
682                expect(l, TagConstants.RPAREN);
683                forUpdate = ExprVec.popFromStackVector(seqExpr);
684            }
685    
686            Stmt body = parseStatement(l);
687            return ForStmt.make(forInit, test, forUpdate, body, keywordloc,
688                                locFirstSemi);
689        }
690    
691        /**
692         * Internal method for parsing a switch statement.
693         *
694         * <p> Effects: Parses the following grammar:
695         * <pre>
696         * SwitchStmtRemainder ::=
697         * '(' Expr ')' '{' { 'case' Expr ':' | 'default ':' | Stmt }* '}'
698         * </pre>
699         *
700         * <p> Note that it assumes the trailing <code>switch</code> has
701         * already been parsed; <code>keywordLoc</code> is the location
702         * assumed for the <code>switch</code> token.
703         *
704         * <p> If no syntax errors are encountered, it returns a parse
705         * tree for the parsed input, leaving <code>l</code> at the token
706         * just after the trailing <code>}</code> of the statement.
707         */
708        //@ requires l != null && l.m_in != null;
709        //@ requires keywordloc != Location.NULL;
710        //@ ensures \result != null;
711        private SwitchStmt parseSwitchStmt(Lex l, int keywordloc) {
712            // Read value to be tested
713            expect(l, TagConstants.LPAREN);
714            Expr value = parseExpression(l);
715            expect(l, TagConstants.RPAREN);
716    
717            // Read body
718            int openloc = l.startingLoc;
719            expect(l, TagConstants.LBRACE);
720            boolean atStart=true;
721            boolean hasDefault = false;
722            seqStmt.push();
723            while (l.ttype != TagConstants.RBRACE && l.ttype != TagConstants.EOF) {
724                if (l.ttype == TagConstants.CASE || l.ttype == TagConstants.DEFAULT) {
725                    if (l.ttype == TagConstants.DEFAULT) {
726                        hasDefault = true;
727                    }
728                    int loc = l.startingLoc;
729                    int ttype = l.ttype;
730                    l.getNextToken(); // Discard CASE TagConstants.or DEFAULT
731                    Expr e = (ttype == TagConstants.CASE ? parseExpression(l) : null);
732                    expect(l, TagConstants.COLON);
733                    seqStmt.addElement( SwitchLabel.make(e, loc) );
734                } 
735                else {
736                    if (atStart) fail(l.startingLoc,"Switch body must start with a label");
737                    addStmt(l);
738                }
739                atStart = false;
740            }
741            if (l.ttype == TagConstants.EOF) 
742                fail(l.startingLoc, "End of input in switch body");
743            int closeloc = l.startingLoc;
744            l.getNextToken(); // Discard '}'
745    
746            if (!hasDefault) {
747                seqStmt.addElement(SwitchLabel.make(null, closeloc));
748                seqStmt.addElement(BreakStmt.make(null, closeloc));
749            }
750            StmtVec body = StmtVec.popFromStackVector(seqStmt);
751            return SwitchStmt.make(body, openloc, closeloc, value, keywordloc);
752        }
753    
754        /**
755         * Internal routine for parsing zero or more catch clauses.
756         *
757         * <p> Effects: Parses the following grammar:
758         * <pre> Catches ::= { 'catch' '(' [Modifiers] Type Idn ')' Block }* </pre>
759         *
760         * At the start of each iteration (including the first), if the
761         * first token is not <code>catch</code>, it stops trying to
762         * parse, returning the (possibly empty) sequence of catch clauses
763         * parsed already and leaving the token at the first token
764         * following the last catch clause parsed.  If the first token is
765         * <code>catch</code>, then it tries to parse a catch clause,
766         * throwing an exception if a syntax error is found.
767         */
768        //@ requires l != null && l.m_in != null;
769        private CatchClauseVec parseCatches(Lex l) {
770            if (l.ttype != TagConstants.CATCH) return null;
771            seqCatchClause.push();
772    
773            do {
774                int loc = l.startingLoc;
775                l.getNextToken(); // Discard CATCH
776                expect(l, TagConstants.LPAREN);
777                FormalParaDecl arg = parseFormalParaDecl(l);
778                //alx: dw in catchclauses the default is readonly
779                if (useUniverses && getUniverse(arg)==TagConstants.IMPL_PEER)
780                    setUniverse(arg,TagConstants.READONLY);
781                else if (useUniverses && getUniverse(arg)!=TagConstants.READONLY) {
782                    setUniverse(arg,TagConstants.READONLY);
783                    if (universeLevel%5!=0)
784                        ErrorSet.error(arg.getStartLoc(),
785                                       "only readonly allowed for catch clauses");
786                }
787                //alx-end
788                
789                expect(l, TagConstants.RPAREN);
790                seqCatchClause.addElement( CatchClause.make(arg, parseBlock(l,false),
791                                                            loc) );
792            } while (l.ttype == TagConstants.CATCH);
793            return CatchClauseVec.popFromStackVector(seqCatchClause);
794        }
795    
796        /**
797         * Internal routine for parsing variable declarations
798         * <em>after</em> the leading type has been parsed.
799         * 
800         * <p>Effects: Parses the following grammar:
801         * <pre>
802         * VarDeclRemainder ::=
803         * { Idn { '[' ']' }* [ '=' VariableInitializer ] },*
804         * </pre>
805         * 
806         * <p> Each <code>VarDeclRemainder</code> found is combined with
807         * <code>basetype</code> to create a <code>VarDeclStmt</code>
808         * which is added to the end of <code>seqStmt</code>.
809         * 
810         * <p> On entry, it assumes at least one
811         * <code>VarDeclRemainder</code> is available, and throws an
812         * exception if one isn't.  At the end of each iteration, it stops
813         * trying to parse if the comma is not present, leaving the token
814         * at the first token following the last
815         * <code>VarDeclRemainder</code> parsed.  If a comma is found,
816         * then it tries to parse the next <code>VarDeclRemainder</code>,
817         * throwing an exception if a syntax error is found.
818         */
819        //@ requires l != null && basetype != null && l.m_in != null;
820        //@ requires basetype.syntax;
821        private void addVarDeclStmts(Lex l, int modifiers, 
822                                     ModifierPragmaVec modifierPragmas,
823                                     Type basetype)
824        {
825            // make modifierPragmas non-null, so can retroactively extend
826            if( modifierPragmas == null )
827                modifierPragmas = ModifierPragmaVec.make();
828    
829            //alx: dw needed because init can have more modifiers!
830            int[] localUniverseArray=null;
831            if (useUniverses)
832                    localUniverseArray = (int[]) universeArray.clone();
833            //alx-end
834    
835            for(;;) {
836                // Get identifier and any [] pairs trailing it
837                Identifier id = l.identifierVal;
838                int locId = l.startingLoc;
839                expect(l, TagConstants.IDENT);
840                Type vartype = parseBracketPairs(l, basetype);
841    
842                // Get initializer if there is one
843                VarInit init = null;
844                int locAssignOp = Location.NULL;
845                if (l.ttype == TagConstants.ASSIGN) {
846                    locAssignOp = l.startingLoc;
847                    l.getNextToken();
848                    init = parseVariableInitializer(l, false);
849                }
850    
851                LocalVarDecl d
852                    = LocalVarDecl.make(modifiers, modifierPragmas, 
853                                        id, vartype, locId, init, locAssignOp);
854                //alx: dw set universe modifiers
855                if (useUniverses)
856                    setUniverse(d,localUniverseArray);
857                //alx-end
858                seqStmt.addElement( VarDeclStmt.make(d) );
859    
860                // check if end of declaration
861    
862                if(l.ttype == TagConstants.MODIFIERPRAGMA ) {
863                    // if modifier pragma, retroactively add to modifierPragmas
864                    parseMoreModifierPragmas( l, modifierPragmas );
865                    return;
866                } else if(l.ttype != TagConstants.COMMA ) {
867                    // all done - do not swallow following semicolon
868                    return;
869                }
870    
871                expect( l, TagConstants.COMMA );
872                /* And go around loop again */
873            }
874        }
875    
876    
877        /**
878         * Routine for parsing a single formal parameter declarations.
879         * 
880         * <p> Effects: Parses the following grammar:
881         * <pre> FormalParaDecl ::= { [Modifiers] Type Idn ModifierPragma* } </pre>
882         * returning an ASTNode representing the result.  Leaves
883         * <code>l</code> pointing to the token just after the
884         * <code>FormalParaDecl</code>.
885         */
886        //@ requires l != null && l.m_in != null;
887        //@ ensures \result != null;
888        public FormalParaDecl parseFormalParaDecl(Lex l) {
889            int modifiers = parseModifiers(l);
890            //alx: dw save the universe modifiers
891            int[] localUniverseArray=null;
892            if (useUniverses)
893                    localUniverseArray = (int[]) this.universeArray.clone();
894            //alx-end
895            ModifierPragmaVec modifierPragmas = this.modifierPragmas;
896            Type paratype = parseType(l);
897            Identifier idn = l.identifierVal;
898            int locId = l.startingLoc;
899            expect(l, TagConstants.IDENT);
900          
901            // allow more modifier pragmas
902            modifierPragmas = parseMoreModifierPragmas( l, modifierPragmas );
903    
904            FormalParaDecl fpd = FormalParaDecl.make(modifiers, modifierPragmas, 
905                  idn, paratype, locId);
906            //alx: dw attatch universe modifiers to the formal parameter
907            if (useUniverses)
908                    setUniverse(fpd,localUniverseArray);
909            //alx-end
910            return fpd;
911        }
912    
913        /**
914         * @return true iff <code>e</code> is a Java
915         * <code>StatementExpression</code> as defined in the grammar
916         * given in the language spec.
917         */
918        //@ requires e != null;
919        public static boolean isStatementExpression(Expr e) {
920            switch (e.getTag()) {
921                case TagConstants.ASSIGN: 
922                case TagConstants.ASGMUL: case TagConstants.ASGDIV: 
923                case TagConstants.ASGREM: 
924                case TagConstants.ASGADD: case TagConstants.ASGSUB:
925                case TagConstants.ASGLSHIFT: case TagConstants.ASGRSHIFT: 
926                case TagConstants.ASGURSHIFT: 
927                case TagConstants.ASGBITAND:
928                case TagConstants.ASGBITOR: case TagConstants.ASGBITXOR:
929                case TagConstants.INC: case TagConstants.DEC: 
930                case TagConstants.POSTFIXINC: case TagConstants.POSTFIXDEC:
931                case TagConstants.METHODINVOCATION:
932                case TagConstants.NEWINSTANCEEXPR:
933                    return true;
934                default:
935                    return true; // TODO return false;
936            }
937        }
938    }