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.ErrorSet;
008    
009    import javafe.util.CorrelatedReader;    // For test harness only
010    import javafe.util.Location;
011    
012    import java.util.List;
013    import java.util.LinkedList;
014    import java.util.Iterator;
015    
016    /**
017     * Parses java source.
018     * 
019     * <p> Uses the static <code>make*()</code> methods of the classes of
020     * the <code>javafe.ast</code> package to create AST nodes.
021     * 
022     * <p> The main entry point is the method
023     * {@link #parseStream(CorrelatedReader, boolean)}.
024     * 
025     * <P>Each parsing method for a particular syntactic unit is
026     * documented with appropriate grammar production rules for that
027     * syntactic unit.  These grammar rules follow the conventions
028     * described in "The Java Language Specification", with the addition
029     * of the symbols '(', ')', '[', ']', '*', '+', and '|', which have
030     * their usual meaning. When necessary, we denote the corresponding
031     * concrete tokens using LPAREN, RPAREN, LSQBRACKET, RSQBRACKET, STAR,
032     * PLUS and BITOR.
033     * 
034     * @see javafe.ast.ASTNode
035     * @see javafe.parser.ParseStmt
036     */
037    
038    public class Parse extends ParseStmt
039    {
040        public Parse() {
041            //@ set seqTypeName.elementType = \type(TypeName);
042            //@ set seqTypeName.owner = this;
043    
044            //@ set seqFormalParaDecl.elementType = \type(FormalParaDecl);
045            //@ set seqFormalParaDecl.owner = this;
046    
047            //@ set seqImportDecl.elementType = \type(ImportDecl);
048            //@ set seqImportDecl.owner = this;
049    
050            //@ set seqTypeDecl.elementType = \type(TypeDecl);
051            //@ set seqTypeDecl.owner = this;
052        }
053    
054        /**
055         * Internal working storage for many Parse functions.
056         */
057        //@ invariant seqTypeName.elementType == \type(TypeName);
058        //@ invariant seqTypeName.owner == this;
059        protected final /*@ non_null @*/ StackVector seqTypeName
060            = new StackVector();
061    
062        /**
063         * Internal working storage for many Parse functions.
064         */
065        //@ invariant seqFormalParaDecl.elementType == \type(FormalParaDecl);
066        //@ invariant seqFormalParaDecl.owner == this;
067        protected final /*@ non_null @*/ StackVector seqFormalParaDecl
068            = new StackVector();
069    
070        /**
071         * Internal working storage for many Parse functions.
072         */
073        //@ invariant seqImportDecl.elementType == \type(ImportDecl);
074        //@ invariant seqImportDecl.owner == this;
075        protected final /*@ non_null @*/ StackVector seqImportDecl
076            = new StackVector();
077    
078        /**
079         * Internal working storage for many Parse functions.
080         */
081        //@ invariant seqTypeDecl.elementType == \type(TypeDecl);
082        //@ invariant seqTypeDecl.owner == this;
083        protected final /*@ non_null @*/ StackVector seqTypeDecl
084            = new StackVector();
085    
086    
087      /** Parse a <TT>CompilationUnit</TT> from an input stream.
088    
089        <P> Requires: prefix of <TT>in</TT> contains text from which the
090        <TT>CompilationUnit</TT> non-terminal can be derrived.
091    
092        <P> Ensures: parses a <TT>CompilationUnit</TT> from the input
093        stream, generating a syntax tree for it.  All errors are treated
094        as fatal errors and are reporting through <code>ErrorSet</code>.
095    
096        @see javafe.util.ErrorSet
097        */
098    
099      //@ requires in != null;
100      public CompilationUnit parseStream(CorrelatedReader in, boolean specOnly) {
101        if (parseStreamLexer == null) parseStreamLexer = new Lex(null, true);
102        parseStreamLexer.restart(in);
103        return parseCompilationUnit(parseStreamLexer, specOnly);
104      }
105    
106    
107      private Lex parseStreamLexer;
108    
109      /** Parse a <TT>CompilationUnit</TT>.
110          <PRE>
111          CompilationUnit:
112             [Package name ;] ImportDeclaration* TypeDeclaration*
113          </PRE>
114          To handle pragmas, call this method directly 
115          with an appropriate <TT>Lex</TT> object.
116        */
117      // specOnly means parse without keeping the bodies of methods/constructors/..
118    
119      //@ requires l != null && l.m_in != null;
120      //@ ensures \result != null;
121      public CompilationUnit parseCompilationUnit(Lex l, boolean specOnly) {
122        Name pkgName = null;
123        int loc = l.startingLoc;
124    
125    
126        /* Optional PackageDeclaration: package name ; */
127        if( l.ttype == TagConstants.PACKAGE ) {
128          l.getNextToken();
129          pkgName = parseName(l);
130          expect( l, TagConstants.SEMICOLON );
131        } 
132    
133        /* Import Declarations */
134        seqImportDecl.push();
135        while( l.ttype == TagConstants.IMPORT ) { 
136          seqImportDecl.addElement( parseImportDeclaration( l ) );
137        }
138        ImportDeclVec imports = ImportDeclVec.popFromStackVector(seqImportDecl);
139    
140        /* Type Declarations */
141        seqTypeDeclElem.push();
142        seqTypeDecl.push();
143        while( l.ttype != TagConstants.EOF ) {
144          if( l.ttype == TagConstants.SEMICOLON )
145            l.getNextToken();
146          else {
147            int locstart = l.startingLoc;
148            int modifiers = parseModifiers(l);
149            ModifierPragmaVec modifierPragmas = this.modifierPragmas;
150    
151              if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA) {
152                TypeDeclElemPragma pragma = (TypeDeclElemPragma)l.auxVal;
153                pragma.decorate(modifierPragmas);
154                    // FIXME - what about modifiers ?
155                seqTypeDeclElem.addElement( pragma );
156                l.getNextToken();
157              } else {
158                TypeDecl td = parseTypeDeclaration(l, specOnly,modifiers,modifierPragmas,locstart);
159                if (td != null) seqTypeDecl.addElement( td );
160              }
161          }
162        }
163        TypeDeclVec elems = TypeDeclVec.popFromStackVector( seqTypeDecl );
164        TypeDeclElemVec extras = TypeDeclElemVec.popFromStackVector( seqTypeDeclElem);
165    
166        LexicalPragmaVec lexicalPragmas = l.getLexicalPragmas();
167    
168        return CompilationUnit.make(pkgName, lexicalPragmas, 
169                                    imports, elems, loc, extras );
170      }
171    
172      /** Parse an <TT>ImportDeclaration</TT>.
173        <PRE>
174        ImportDeclaration:
175          import Name ; 
176          import Name . STAR ;
177        </PRE>
178       */
179            
180      //@ requires l != null && l.m_in != null;
181      //@ ensures \result != null;
182      protected ImportDecl parseImportDeclaration(Lex l) {
183        int loc = l.startingLoc;
184        l.getNextToken();                // swallow import keyword
185        Name name = parseName(l);
186        if( l.ttype == TagConstants.SEMICOLON ) {
187          l.getNextToken();              // swallow semicolon
188          TypeName typename = TypeName.make( name );
189          return SingleTypeImportDecl.make( loc, typename );
190        } else {
191          expect( l, TagConstants.FIELD );
192          expect( l, TagConstants.STAR );
193          expect( l, TagConstants.SEMICOLON );
194          return OnDemandImportDecl.make( loc, name );
195        }
196      }
197    
198    
199      /**********************************************************************
200        Parse a <TT>TypeDeclaration</TT> (ie a class or interface declaration).
201        <PRE>
202          TypeDeclaration:
203            ClassDeclaration
204            InterfaceDeclaration  
205            ;
206    
207          ClassDeclaration:
208            TypeDeclElemPragma* Modifiers class Identifier [extends TypeName] [implements TypeNameList]
209              { TypeDeclElem* }
210            TypeDeclElemPragma* Modifiers interface Identifier [extends TypeNameList]
211              { TypeDeclElem* }
212         </PRE>
213       */
214    
215      //@ requires l != null && l.m_in != null;
216      //@ ensures \result != null;
217      protected TypeDecl parseTypeDeclaration(Lex l, boolean specOnly) {
218        int locstart = l.startingLoc;
219        int modifiers = parseModifiers(l);
220        ModifierPragmaVec modifierPragmas = this.modifierPragmas;
221        return parseTypeDeclaration(l,specOnly,modifiers,modifierPragmas,
222                                            locstart);
223      }
224      protected TypeDecl parseTypeDeclaration(Lex l, boolean specOnly,
225                            int modifiers, ModifierPragmaVec modifierPragmas,
226                            int loc) {
227        TypeDecl result =
228            parseTypeDeclTail(l, specOnly, loc, modifiers, modifierPragmas);
229        return result;
230      }
231    
232      /**********************************************************************
233        Parse a <TT>TypeDeclTail</TT> (ie a class or interface declaration
234        starting at the keyword 'class' or 'interface').
235        <PRE>
236          TypeDeclTail:
237            class Identifier [TypeModifierPragma]* [extends TypeName] [implements TypeNameList]
238              { TypeDeclElem* }
239            interface Identifier [TypeModifierPragma]* [extends TypeNameList] { TypeDeclElem* }
240         </PRE> */
241    
242      protected
243      TypeDecl parseTypeDeclTail(Lex l, boolean specOnly, int loc, 
244                                 int modifiers, ModifierPragmaVec modifierPragmas){
245        int keyword = l.ttype;
246       
247        if( keyword != TagConstants.CLASS && keyword != TagConstants.INTERFACE ) {
248          if (keyword == TagConstants.EOF) return null;
249          fail(l.startingLoc, "expected 'class' or 'interface' instead of "
250                    + TagConstants.toString(keyword));
251        }
252    
253        l.getNextToken();              // swallow keyword
254    
255        int locId = l.startingLoc;
256        Identifier id = parseIdentifier(l);
257        TypeModifierPragmaVec tmodifiers = parseTypeModifierPragmas(l);
258        
259        /* Parse superclass, if any */
260        TypeName superClass = null;
261        if( keyword == TagConstants.CLASS && l.ttype == TagConstants.EXTENDS ) {
262          l.getNextToken();            // swallow "extends" keyword
263          superClass = parseTypeName(l);
264        }
265    
266        /* Parse super interfaces, if any */
267        TypeNameVec superInterfaces =
268          parseTypeNames( l, (keyword == TagConstants.CLASS ? 
269                              TagConstants.IMPLEMENTS : TagConstants.EXTENDS ) );
270    
271        /* Now parse class body */
272        int locOpenBrace = l.startingLoc;
273        expect( l, TagConstants.LBRACE );
274        
275        /* Build up Vec of TypeDeclElems in class or interface */
276        seqTypeDeclElem.push();
277        while( l.ttype != TagConstants.RBRACE ) {
278          parseTypeDeclElemIntoSeqTDE( l, keyword, id, specOnly );
279        }
280        TypeDeclElemVec elems =
281            TypeDeclElemVec.popFromStackVector( seqTypeDeclElem );
282    
283        int locCloseBrace = l.startingLoc;
284        expect( l, TagConstants.RBRACE );
285    
286        TypeDecl result;
287        if (keyword == TagConstants.CLASS) {
288          addDefaultConstructor(elems, locOpenBrace, specOnly);
289          result = ClassDecl.make(modifiers, modifierPragmas, id, 
290                                  superInterfaces, tmodifiers, elems,
291                                  loc, locId, locOpenBrace, locCloseBrace,
292                                  superClass);
293        } else {
294          result = InterfaceDecl.make(modifiers, modifierPragmas, id,
295                                      superInterfaces, tmodifiers, elems,
296                                      loc, locId, 
297                                      locOpenBrace, locCloseBrace );
298        }
299        result.specOnly = specOnly;
300        return result;
301      }
302        
303    
304      /** checks for           X TypeModifierPragma* (
305          in the input stream. 
306          Use this to match the beginning of a constructor or method declration
307          versus the beginning of a field declaration.
308      */
309        //@ requires l != null && l.m_in != null;
310        private boolean atStartOfConstructorOrMethod(Lex l) {
311            int i = 1;
312            while ((l.lookahead(i) == TagConstants.TYPEMODIFIERPRAGMA)) {
313                i++;
314            }
315            return l.lookahead(i) == TagConstants.LPAREN;
316        }
317    
318    
319    
320    
321      /** If no constructors are found in "elems", adds a default one to it.
322        If a default constructor is created, the "loc" and "locId" fields of
323        the default constructor will be set to "loc". */
324      void addDefaultConstructor(TypeDeclElemVec elems, int loc, boolean specOnly) {
325          // Return if a constructor is already present:
326          for (int i=0; i<elems.size(); i++) {
327              if (elems.elementAt(i) instanceof ConstructorDecl)
328                  return;
329          }
330    
331          /*
332           * No constructor found, add one:
333           *  name() { super(); }
334           *
335           * Don't put super constructor invocation in --  it is added by
336           * the type checker.
337           */
338          BlockStmt blk = specOnly ? null :BlockStmt.make(StmtVec.make(), loc, loc);
339          TypeNameVec raises = TypeNameVec.make();
340          FormalParaDeclVec formals = FormalParaDeclVec.make();
341          ConstructorDecl cd
342              = ConstructorDecl.make(Modifiers.ACC_PUBLIC, null, null, 
343                                     formals, raises, blk, loc, loc, loc,
344                                     Location.NULL );
345          cd.implicit = true;
346          elems.addElement(cd);
347      }
348    
349      /** Parse a keyword, 
350          followed by a comma-separated list of <TT>TypeName</TT>s.
351    
352          Used to parse throws clauses, and super-interface clauses.
353          <PRE>
354          TypeNames:
355             keyword TypeNameList
356             empty
357    
358          TypeNameList:
359            TypeName ( , TypeName )*
360          </PRE>
361       */
362    
363      //@ requires l != null && l.m_in != null;
364      //@ ensures \result != null;
365      protected TypeNameVec parseTypeNames(Lex l, int keyword)
366      {
367        if( l.ttype != keyword ) 
368          return TypeNameVec.make();
369    
370        /* Have type names */
371        seqTypeName.push();
372        do {
373          // Skip keyword or ',' .
374          l.getNextToken();
375          seqTypeName.addElement( parseTypeName(l) );
376        } while( l.ttype == TagConstants.COMMA );
377        return TypeNameVec.popFromStackVector( seqTypeName );
378      }
379      
380    /************************************************************************ 
381    
382    Parse a <TT>TypeDeclElem</TT>, which is either a field, method, or
383    constructor declaration, a static block, or a TypeDecl [1.1].  
384    
385    <p> A field declaration may define many fields.  Since returning
386    multiple declared entities is cumbersome, this method simply adds all
387    the declared entities onto the StackVector seqTypeDeclElem.  The
388    <TT>keyword</TT> argument is either CLASS or INTERFACE.  The argument
389    containerId is the name of the enclosing class, which is necessary for
390    checking constructor declarations.
391    
392    <PRE>
393    TypeDeclElem: 
394       FieldDeclaration 
395       MethodDeclaration
396       ConstructorDeclaration 
397       InitBlock
398       TypeDeclElemPragma
399       TypeDeclaration              [1.1]
400       ;
401    
402    FieldDeclaration:
403       Modifiers Type VariableDeclarator (, VariableDeclarator)* ;
404    
405    MethodDeclaration:
406       Modifiers Type Identifier FormalParameterList BracketPair*
407          [throws TypeNameList]
408          ( ; | Block )
409    
410    ConstructorDeclaration:
411       Modifiers Identifier FormalParameterList Block
412    
413    InitBlock:
414       Modifiers Block
415    
416    VariableDeclarator:
417       Identifier BRACKET_PAIR* [ = VariableInitializer ]
418    
419    </PRE>
420    
421    @see javafe.parser.TagConstants
422    
423    */
424    
425      protected TypeDeclElem
426      parseTypeDeclElemIntoSeqTDE(Lex l, int keyword, Identifier containerId,
427                                       boolean specOnly)                    
428      {
429        int loc = l.startingLoc;
430        int modifiers = parseModifiers(l);
431        ModifierPragmaVec modifierPragmas = this.modifierPragmas;
432        TypeDeclElem result = null;
433    
434        if( l.ttype == TagConstants.SEMICOLON 
435           && modifiers == Modifiers.NONE
436           && modifierPragmas == null ) {
437          // Semicolons are not in JLS, 
438          // but accepted by javac and in many java progs
439          // so allow them and do nothing
440          l.getNextToken();
441          return null;
442        } 
443        else if( l.ttype == TagConstants.CLASS 
444              || l.ttype == TagConstants.INTERFACE) {
445          /* Nested class/interface */
446          TypeDecl nested = parseTypeDeclaration(l, specOnly);
447          nested.modifiers = modifiers;
448          nested.pmodifiers = modifierPragmas;
449          seqTypeDeclElem.addElement(nested);
450          return nested;
451        } 
452        else if( l.ttype == TagConstants.LBRACE ) {
453          /* Initialization block */
454          if( keyword == TagConstants.INTERFACE ) 
455            fail(l.startingLoc, 
456                 "Cannot have initializer blocks in an interface");
457          if (specOnly)
458            parseBlock(l, true);
459          else {
460            seqTypeDeclElem.addElement( result = InitBlock.make( modifiers, modifierPragmas,
461                                                        parseBlock(l,false) ) );
462          }
463          return result;
464        } 
465        else if( atStartOfConstructorOrMethod(l) ) {
466          // Constructor declaration 
467          if( keyword == TagConstants.INTERFACE ) 
468            fail(l.startingLoc, "Cannot declare constructors in an interface");
469          int locId = l.startingLoc;
470          Identifier id = parseIdentifier(l);
471          TypeModifierPragmaVec tmodifiers = parseTypeModifierPragmas(l);
472          if (id != containerId) {
473              if (containerId.toString().startsWith("$anon_"))
474                  fail(l.startingLoc,
475                       "Anonymous classes may not have constructors");
476              else
477                  fail(l.startingLoc, 
478                       "Invalid name '"+id+"' for constructor;"
479                       +" expected '"+containerId+"'");
480          }
481    
482          FormalParaDeclVec args = parseFormalParameterList(l);
483          int locThrowsKeyword;
484          if (l.ttype == TagConstants.THROWS) {
485            locThrowsKeyword = l.startingLoc;
486          } else {
487            locThrowsKeyword = Location.NULL;
488          }
489          TypeNameVec raises = parseTypeNames( l, TagConstants.THROWS );
490    
491          // allow more modifier pragmas
492          modifierPragmas = parseMoreModifierPragmas( l, modifierPragmas );
493          BlockStmt body = null;
494          int locOpenBrace = Location.NULL;
495          if ( l.ttype == TagConstants.SEMICOLON ) {
496              l.getNextToken();   // swallow semicolon
497          } else {
498              locOpenBrace = l.startingLoc;
499              // specOnly means do not keep any bodies of methods/constructors/etc.
500              body = specOnly ? parseBlock(l, true)
501                                        : parseConstructorBody(l);
502    
503          }
504          seqTypeDeclElem.addElement( result = ConstructorDecl.make( modifiers,
505                                                            modifierPragmas,
506                                                            tmodifiers,
507                                                            args, 
508                                                            raises, body,
509                                                            locOpenBrace,
510                                                            loc, locId, 
511                                                            locThrowsKeyword ) );
512          return result;
513        } 
514        else if( l.ttype == TagConstants.TYPEDECLELEMPRAGMA ) {
515          // TypeDeclElemPragma
516          if( modifiers != Modifiers.NONE)
517            ErrorSet.error(l.startingLoc, 
518                 "Cannot have modifiers outside of the annotation on a TypeDeclElem pragma");
519          TypeDeclElemPragma pragma = (TypeDeclElemPragma)l.auxVal;
520          pragma.decorate(modifierPragmas);
521          seqTypeDeclElem.addElement( pragma );
522          l.getNextToken();
523        }
524        else if (l.ttype == TagConstants.POSTMODIFIERPRAGMA) {
525            ErrorSet.error(l.startingLoc,
526                "Ignoring a modifier pragma that presumably follows a field declaration but is not in the same annotation comment"); // FIXME - can this be fixed?
527          l.getNextToken();
528        }
529        else {
530          /* Is field or method declaration */
531          int locType = l.startingLoc;
532          Type type = parseType(l);
533          if(  atStartOfConstructorOrMethod(l) ) {
534            // Method declaration 
535            
536            int locId              = l.startingLoc;
537            Identifier id          = parseIdentifier(l);
538            TypeModifierPragmaVec tmodifiers = parseTypeModifierPragmas(l);
539            FormalParaDeclVec args = parseFormalParameterList(l);
540            type = parseBracketPairs( l, type );
541            int locThrowsKeyword;
542            if (l.ttype == TagConstants.THROWS) {
543              locThrowsKeyword = l.startingLoc;
544            } else {
545              locThrowsKeyword = Location.NULL;
546            }
547            TypeNameVec raises     = parseTypeNames(l, TagConstants.THROWS );
548            int locOpenBrace;
549            BlockStmt body;
550    
551            // Allow some more modifier pragmas here
552            modifierPragmas = parseMoreModifierPragmas( l, modifierPragmas );
553    
554            if ( l.ttype == TagConstants.SEMICOLON ) {
555              l.getNextToken();   // swallow semicolon
556              locOpenBrace = Location.NULL;
557              body = null;
558    // FIXME - check that this is specOnly for no body ?
559            } else {
560              if( keyword == TagConstants.INTERFACE ) 
561                fail(l.startingLoc, 
562                     "Cannot define a method body inside an interface");
563              locOpenBrace = l.startingLoc;
564              body = parseBlock(l, specOnly);
565            }
566            MethodDecl md = MethodDecl.make(modifiers, modifierPragmas, tmodifiers,
567                                            args, 
568                                            raises, body, locOpenBrace,
569                                            loc, locId, locThrowsKeyword,
570                                            id, type, locType);
571            seqTypeDeclElem.addElement( md );
572            return md;
573    
574          } else {
575    
576            // Field declaration. 
577            
578            // Have modifiers and type. 
579            // May need to loop over many VariableDeclarators 
580    
581            // make modifierPragmas non-null, so can retroactively extend
582            if( modifierPragmas == null )
583              modifierPragmas = ModifierPragmaVec.make();
584    
585            List fds = new LinkedList(); // a list of all the fds produced here
586            for(;;) {
587              int locId     = l.startingLoc;
588              Identifier id = parseIdentifier(l);
589              Type vartype = parseBracketPairs(l, type);
590    
591              VarInit init = null;
592              int locAssignOp = Location.NULL;
593              if( l.ttype == TagConstants.ASSIGN ) {
594                locAssignOp = l.startingLoc;
595                l.getNextToken();
596                init = parseVariableInitializer(l, specOnly);
597              }
598              FieldDecl fielddecl
599                = FieldDecl.make(modifiers, modifierPragmas.copy(), 
600                                 id, vartype, locId, init, locAssignOp );
601              seqTypeDeclElem.addElement( fielddecl );
602              fds.add(fielddecl);
603    
604              if(l.ttype == TagConstants.MODIFIERPRAGMA
605                        || l.ttype == TagConstants.SEMICOLON ) 
606              {
607                // if modifier pragma, retroactively add to modifierPragmas
608                parseMoreModifierPragmas( l, fielddecl.pmodifiers );
609    
610                // End of Declaration 
611    
612                // JML added some clauses that can follow type declarations.
613                // This bit of hackery is to check if there are any such
614                // and associate them with the correct declaration.  All other
615                // modifiers precede the declaration with which they are 
616                // associated (or at least precede the terminating semicolon).
617                l.getNextToken();
618                while (l.ttype == TagConstants.POSTMODIFIERPRAGMA) {
619                    Identifier idd = ((javafe.ast.IdPragma)l.auxVal).id();
620                    Iterator i = fds.iterator();
621                    while (i.hasNext()) {
622                        FieldDecl fd = (FieldDecl)i.next();
623                        if (idd == null || idd == fd.id)
624                            fd.pmodifiers.addElement((ModifierPragma)l.auxVal);
625                    }
626                    l.getNextToken();
627                }
628    
629                return fielddecl;
630              } else {
631                expect( l, TagConstants.COMMA );
632                /* And go around loop again */
633              }
634            } /* loop thru field declarations */
635          } /* is field declarations */
636        } /* field or method declarations */
637        return null;
638      } /* parseTypeDeclElemIntoSeqTDE */
639    
640      /**********************************************************************
641        Parse a <TT>FormalParameterList</TT>, which includes enclosing parens.
642        Note: this definition differs from JLS, where it does not include the
643        parens
644    
645        <PRE>
646          FormalParameterList:
647            LPAREN FormalParameter (, FormalParameter)* RPAREN
648    
649          FormalParameter:
650            [Modifiers] Type Identifier BracketPair* ModifierPragma*     [1.1]
651        <PRE>       
652       */
653    
654      //@ requires l != null && l.m_in != null;
655      //@ ensures \result != null;
656      public FormalParaDeclVec parseFormalParameterList(Lex l) 
657      {
658        /* Should be on LPAREN */
659        if( l.ttype != TagConstants.LPAREN ) 
660          fail(l.startingLoc, "Expected open paren");
661        if( l.lookahead(1) == TagConstants.RPAREN ) {
662          // Empty parameter list
663          expect( l, TagConstants.LPAREN );
664          expect( l, TagConstants.RPAREN );
665          return FormalParaDeclVec.make();
666        } else {
667          seqFormalParaDecl.push();
668          while( l.ttype != TagConstants.RPAREN ) {
669            l.getNextToken();                // swallow open paren or comma
670            int modifiers = parseModifiers(l);
671            ModifierPragmaVec modifierPragmas = this.modifierPragmas;
672            Type type = parseType(l);
673            int locId = l.startingLoc;
674            Identifier id = parseIdentifier(l);
675            type = parseBracketPairs(l, type);
676            modifierPragmas = parseMoreModifierPragmas(l, modifierPragmas);
677            seqFormalParaDecl.addElement( FormalParaDecl.make(modifiers,
678                                                              modifierPragmas, 
679                                                              id, type, locId ) );
680            if( l.ttype != TagConstants.RPAREN && l.ttype != TagConstants.COMMA )
681              fail(l.startingLoc, "Expected comma or close paren");
682          }
683          expect( l, TagConstants.RPAREN );
684          return FormalParaDeclVec.popFromStackVector( seqFormalParaDecl );
685        }
686      }
687    }