KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > JFlex > Macros


1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * JFlex 1.4.1 *
3  * Copyright (C) 1998-2004 Gerwin Klein <lsf@jflex.de> *
4  * All rights reserved. *
5  * *
6  * This program is free software; you can redistribute it and/or modify *
7  * it under the terms of the GNU General Public License. See the file *
8  * COPYRIGHT for more information. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License along *
16  * with this program; if not, write to the Free Software Foundation, Inc., *
17  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
18  * *
19  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

20
21 package JFlex;
22
23 import java.util.*;
24
25
26 /**
27  * Symbol table and expander for macros.
28  *
29  * Maps macros to their (expanded) definitions, detects cycles and
30  * unused macros.
31  *
32  * @author Gerwin Klein
33  * @version JFlex 1.4.1, $Revision: 2.4 $, $Date: 2004/11/06 23:03:32 $
34  */

35 final public class Macros {
36
37   /** Maps names of macros to their definition */
38   private Hashtable macros;
39
40   /** Maps names of macros to their "used" flag */
41   private Hashtable used;
42
43
44   /**
45    * Creates a new macro expander.
46    */

47   public Macros() {
48     macros = new Hashtable();
49     used = new Hashtable();
50   }
51
52
53   /**
54    * Stores a new macro and its definition.
55    *
56    * @param name the name of the new macro
57    * @param definition the definition of the new macro
58    *
59    * @return <code>true</code>, iff the macro name has not been
60    * stored before.
61    */

62   public boolean insert(String JavaDoc name, RegExp definition) {
63     
64     if (Options.DEBUG)
65       Out.debug("inserting macro "+name+" with definition :"+Out.NL+definition); //$NON-NLS-1$ //$NON-NLS-2$
66

67     used.put(name, Boolean.FALSE);
68     return macros.put(name,definition) == null;
69   }
70
71
72   /**
73    * Marks a makro as used.
74    *
75    * @return <code>true</code>, iff the macro name has been
76    * stored before.
77    */

78   public boolean markUsed(String JavaDoc name) {
79     return used.put(name, Boolean.TRUE) != null;
80   }
81
82
83   /**
84    * Tests if a macro has been used.
85    *
86    * @return <code>true</code>, iff the macro has been used in
87    * a regular expression.
88    */

89   public boolean isUsed(String JavaDoc name) {
90     return ((Boolean JavaDoc)used.get(name)).booleanValue();
91   }
92
93
94   /**
95    * Returns all unused macros.
96    *
97    * @return the enumeration of macro names that have not been used.
98    */

99   public Enumeration unused() {
100     
101     Vector unUsed = new Vector();
102
103     Enumeration names = used.keys();
104     while ( names.hasMoreElements() ) {
105       String JavaDoc name = (String JavaDoc) names.nextElement();
106       Boolean JavaDoc isUsed = (Boolean JavaDoc) used.get( name );
107       if ( !isUsed.booleanValue() ) unUsed.addElement(name);
108     }
109     
110     return unUsed.elements();
111   }
112
113
114   /**
115    * Fetches the definition of the macro with the specified name,
116    * <p>
117    * The definition will either be the same as stored (expand() not
118    * called), or an equivalent one, that doesn't contain any macro
119    * usages (expand() called before).
120    *
121    * @param name the name of the macro
122    *
123    * @return the definition of the macro, <code>null</code> if
124    * no macro with the specified name has been stored.
125    *
126    * @see JFlex.Macros#expand
127    */

128   public RegExp getDefinition(String JavaDoc name) {
129     return (RegExp) macros.get(name);
130   }
131
132
133   /**
134    * Expands all stored macros, so that getDefinition always returns
135    * a defintion that doesn't contain any macro usages.
136    *
137    * @throws MacroException if there is a cycle in the macro usage graph.
138    */

139    public void expand() throws MacroException {
140     
141     Enumeration names;
142
143     names = macros.keys();
144     
145     while ( names.hasMoreElements() ) {
146       String JavaDoc name = (String JavaDoc) names.nextElement();
147       if ( isUsed(name) )
148         macros.put(name, expandMacro(name, getDefinition(name)));
149       // this put doesn't get a new key, so only a new value
150
// is set for the key "name" (without changing the enumeration
151
// "names"!)
152
}
153   }
154
155
156   /**
157    * Expands the specified macro by replacing each macro usage
158    * with the stored definition.
159    *
160    * @param name the name of the macro to expand (for detecting cycles)
161    * @param definition the definition of the macro to expand
162    *
163    * @return the expanded definition of the macro.
164    *
165    * @throws MacroException when an error (such as a cyclic definition)
166    * occurs during expansion
167    */

168   private RegExp expandMacro(String JavaDoc name, RegExp definition) throws MacroException {
169
170     // Out.print("checking macro "+name);
171
// Out.print("definition is "+definition);
172

173     switch ( definition.type ) {
174     case sym.BAR:
175     case sym.CONCAT:
176       RegExp2 binary = (RegExp2) definition;
177       binary.r1 = expandMacro(name, binary.r1);
178       binary.r2 = expandMacro(name, binary.r2);
179       return definition;
180       
181     case sym.STAR:
182     case sym.PLUS:
183     case sym.QUESTION:
184     case sym.BANG:
185     case sym.TILDE:
186       RegExp1 unary = (RegExp1) definition;
187       unary.content = expandMacro(name, (RegExp) unary.content);
188       return definition;
189       
190     case sym.MACROUSE:
191       String JavaDoc usename = (String JavaDoc) ((RegExp1) definition).content;
192       
193       if ( name.equals(usename) )
194         throw new MacroException(ErrorMessages.get(ErrorMessages.MACRO_CYCLE, name));
195           
196       RegExp usedef = getDefinition(usename);
197       
198       if ( usedef == null )
199         throw new MacroException(ErrorMessages.get(ErrorMessages.MACRO_DEF_MISSING, usename, name));
200       
201       markUsed(usename);
202       
203       return expandMacro(name, usedef);
204
205     case sym.STRING:
206     case sym.STRING_I:
207     case sym.CHAR:
208     case sym.CHAR_I:
209     case sym.CCLASS:
210     case sym.CCLASSNOT:
211       return definition;
212
213     default:
214       throw new MacroException("unknown expression type "+definition.type+" in macro expansion"); //$NON-NLS-1$ //$NON-NLS-2$
215
}
216   }
217 }
218
Popular Tags