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    import javafe.util.Location;
009    
010    /**
011     * Base class for Java parser; provides some basic parsing utilities.
012     *
013     * @see javafe.ast.ASTNode
014     * @see javafe.parser.ParseType
015     * @see javafe.parser.Parse
016     */
017    
018    public class ParseUtil
019    {
020        public ParseUtil() {
021            //@ set seqModifierPragma.elementType = \type(ModifierPragma);
022            //@ set seqModifierPragma.owner = this;
023        }
024    
025    
026        //----------------------- Misc Helper Functions ----------------------------
027    
028        /** Raises a <TT>RuntimeException</TT> with the argument string. */
029    
030        // @ ensures false;
031        // UNUSED private static void fail(String m) { ErrorSet.fatal(m); }
032    
033        /** Raises a <TT>RuntimeException</TT> with the argument string
034            including a textual representation of the given source location. */
035        //@ requires loc != Location.NULL;
036        //@ ensures false;
037        public static void fail(int loc, String m) { ErrorSet.fatal(loc, m); }
038    
039        //@ requires loc != Location.NULL;
040        public static void error(int loc, String m) { ErrorSet.error(loc, m); }
041    
042        /** 
043         Takes an expected token from the input stream, 
044         calls <TT>fail</TT> on error.
045         */
046        //@ requires l != null && l.m_in != null;
047        //@ modifies l.ttype, l.auxVal, l.identifierVal;
048        //@ ensures \old(l.ttype)==expected;
049        public void expect(Lex l, int expected) {
050            if( l.ttype != expected ) 
051                fail(l.startingLoc,
052                     "Unexpected token '" + PrettyPrint.inst.toString(l.ttype) +
053                     "', expected '" + PrettyPrint.inst.toString(expected)+"'");
054            l.getNextToken();
055        }
056    
057        /**
058    
059         Converts operator tokens to corresponding AST tag.
060         Tokens INC and DEC get mapped to PREFIXINC and PREFIXDEC
061    
062         */
063    
064        int operatorTokenToTag(int token) {
065            // Right now we have the identity mapping.
066            return token;
067        }
068    
069    
070        /*------------------------ Modifiers -------------------------------*/
071    
072        //* Internal working storage for parse*Modifier* functions
073        //@ invariant seqModifierPragma.elementType == \type(ModifierPragma);
074        //@ invariant seqModifierPragma.owner == this;
075        protected final StackVector seqModifierPragma = new StackVector();
076    
077        /**
078         * Keyword at index i in this array corresponds to bit i in
079         * modifier bitset.  Thus PRIVATE is at index 1, ACC_PRIVATE =
080         * 1<<1.
081         * These are in the same bit order as the values in 
082         * java.lang.reflect.Modifier, and should remain that way, though
083         * I don't know if any code uses that fact (it might come in handy
084         * in reading class files, for example).
085         */
086        public static final int modifierKeywords[] = {
087            TagConstants.PUBLIC, TagConstants.PRIVATE, TagConstants.PROTECTED, 
088            TagConstants.STATIC, TagConstants.FINAL, 
089            TagConstants.SYNCHRONIZED, TagConstants.VOLATILE,
090            TagConstants.TRANSIENT, TagConstants.NATIVE, 
091            -1, // Don't consider 'interface' to be a modifier
092            TagConstants.ABSTRACT, TagConstants.STRICT
093        };
094    
095    
096        /**
097         * Parse a list of modifier pragmas.  Returns <code>null</code> if
098         * <code>l</code> does not point to a modifier pragma.  Otherwise,
099         * reads <code>l</code> until there are no more modifier pragmas and
100         * returns the resulting list.
101         */
102        //@ requires l.m_in != null;
103        public ModifierPragmaVec parseModifierPragmas(/*@ non_null @*/ Lex l) {
104            if (l.ttype != TagConstants.MODIFIERPRAGMA)
105                return null;
106    
107            seqModifierPragma.push();
108            do {
109                seqModifierPragma.addElement(l.auxVal);
110                l.getNextToken();
111            } while (l.ttype == TagConstants.MODIFIERPRAGMA);
112            return ModifierPragmaVec.popFromStackVector(seqModifierPragma);
113        }
114    
115        /**
116         * Parse a list of modifier pragmas and adds them to an existing
117         * <code>ModifierPragmaVec</code>.  If the existing
118         * <code>ModifierPragmaVec</code> was <code>null</code>, then it
119         * either returns <code>null</code> (if <code>l</code> does not point
120         * to a modifier pragma), or returns a new
121         * <code>ModifierPragmaVec</code>.
122         */
123        //@ requires l.m_in != null;
124        public ModifierPragmaVec parseMoreModifierPragmas(/*@ non_null @*/ Lex l, 
125                                                          ModifierPragmaVec orig)
126        {
127            ModifierPragmaVec modifierPragmas = parseModifierPragmas( l );
128            if (modifierPragmas == null)
129                return orig;
130            else if (orig == null)
131                return modifierPragmas;
132            else {
133                orig.append( modifierPragmas );
134                return orig;
135            }
136        }
137    
138        /** As a side effect, <code>parseModifiers</code> mutates this
139         value. */
140        public ModifierPragmaVec modifierPragmas;
141    
142    
143        /**
144         * Parse a list of modifiers.  Ensures no duplicate Java modifiers
145         * and only one of the access modifiers public, protected,
146         * private.  Return integer encoding the Java modifiers.
147         *
148         * <p> In addition to parsing Java modifiers, also handles modifier
149         * pragmas (anything with a ttype of TagConstants.MODIFIERPRAGMA).
150         * If no modifier pragmas are seen, sets
151         * <c>modifierPragmas</c> to <c>null</c>.  Otherwise, sets it to
152         * be the list of modifier pragmas seen in the course of parsing any
153         * Java modifiers.
154         *
155         * @see javafe.ast.Modifiers
156         */
157        //@ requires l.m_in != null;
158        //@ modifies modifierPragmas;
159        public int parseModifiers(/*@ non_null @*/ Lex l) {
160            boolean seenPragma = false;
161            int modifiers = Modifiers.NONE;
162    
163            getModifierLoop:
164            for(;;) {
165                if (l.ttype == TagConstants.MODIFIERPRAGMA) {
166                    if (! seenPragma) { 
167                            seqModifierPragma.push(); 
168                            seenPragma = true; 
169                    }
170                    seqModifierPragma.addElement(l.auxVal);
171                    l.getNextToken();
172                    continue getModifierLoop;
173                } else {
174                    int i = getJavaModifier(l,modifiers);
175                    if (i != 0) {
176                        modifiers |= i;
177                        continue getModifierLoop;
178                    }
179                }
180                // Next token is not a modifier
181                if (! seenPragma)
182                    modifierPragmas = null;
183                else
184                    modifierPragmas
185                        = ModifierPragmaVec.popFromStackVector(seqModifierPragma);
186                return modifiers;
187            }
188        }
189    
190        /** Checks if the next token is a Java modifier.  Returns 0
191            if it is not; returns an int with the modifier bit turned on
192            if it is.  Also issues an error if the modifier is already 
193            present in the modifiers argument (use 0 for this argument
194            to turn off these errors).
195            Note that the bit that is found is not ORed into the modifiers
196            int; you have to do that outside this call.
197            The Lex is advanced if a modifier is found.
198        */
199        public int getJavaModifier(Lex l, int modifiers) {
200            for( int i=0; i<modifierKeywords.length; i++ ) {
201                if( l.ttype == modifierKeywords[i] ) {
202                    // Token is modifier keyword 
203                    int modifierBit = 1<<i;
204                    if( (modifiers & modifierBit) != 0 ) {
205                        ErrorSet.caution(l.startingLoc, 
206                            "Duplicate occurrence of modifier '"
207                             +PrettyPrint.inst.toString(l.ttype)+"'");
208                    } else if( (modifiers & Modifiers.ACCESS_MODIFIERS) != 0 &&
209                        (modifierBit & Modifiers.ACCESS_MODIFIERS) != 0 ) {
210                        ErrorSet.error(l.startingLoc, 
211                             "Cannot have more than one of the access modifiers "+
212                             "public, protected, private");
213                    }
214                    l.getNextToken();
215                    return modifierBit;
216                }
217            }
218            return 0;
219        }
220    
221        public boolean isJavaModifier(int ttype) {
222            for( int i=0; i<modifierKeywords.length; i++ ) {
223                if( ttype == modifierKeywords[i] ) return true;
224            }
225            return false;
226        }
227    
228        static public String arrayToString(Object[] a, String sep) {
229            if (a==null || a.length == 0) return "";
230            else {
231                    StringBuffer sb = new StringBuffer();
232                    sb.append(a[0].toString());
233                    for (int i=1; i<a.length; ++i) {
234                        sb.append(sep);
235                        sb.append(a[i].toString());
236                    }
237                    return sb.toString();
238            }
239        }
240    }