1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3
* Copyright (C) 1998-2001 Gerwin Klein <lsf@jflex.de> *
4
* All rights reserved. *
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. *
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. *
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 *
19
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
27
* Symbol table and expander for macros.
29
* Maps macros to their (expanded) definitions, detects cycles and
32
* @author Gerwin Klein
33
* @version JFlex 1.3.5, $Revision: 1.14 $, $Date: 2001/10/08 10:08:02 $
35
final public class Macros {
38
* Maps names of macros to their definition
40
private Hashtable macros;
42
private Hashtable used;
46
* Creates a new macro expander.
49
macros = new Hashtable();
50
used = new Hashtable();
55
* Stores a new macro and its definition.
57
* @param name the name of the new macro
58
* @param definition the definition of the new macro
60
* @return <code>true</code>, iff the macro name has not been
63
public boolean insert(String name, RegExp definition) {
66
Out.debug("inserting macro "+name+" with definition :"+Out.NL+definition);
68
used.put(name, new Boolean(false));
69
return macros.put(name,definition) == null;
74
* Marks a makro as used.
76
* @return <code>true</code>, iff the macro name has been
79
public boolean markUsed(String name) {
80
return used.put(name, new Boolean(true)) != null;
85
* Tests if a macro has been used.
87
* @return <code>true</code>, iff the macro has been used in
88
* a regular expression.
90
public boolean isUsed(String name) {
91
return ((Boolean)used.get(name)).booleanValue();
96
* Returns all unused macros.
98
* @return the enumeration of macro-names that have not been used.
100
public Enumeration unused() {
102
Vector unUsed = new Vector();
104
Enumeration names = used.keys();
105
while ( names.hasMoreElements() ) {
106
String name = (String) names.nextElement();
107
Boolean isUsed = (Boolean) used.get( name );
108
if ( !isUsed.booleanValue() ) unUsed.addElement(name);
111
return unUsed.elements();
116
* Fetches the definition of the macro with the specified name,
118
* The definition will either be the same as stored (expand() not
119
* called), or an equivalent one, that doesn't contain any macro
120
* usages (expand() called before).
122
* @param name the name of the macro
124
* @return the definition of the macro, <code>null</code> if
125
* no macro with the specified name has been stored.
127
* @see JFlex.Macros#expand
129
public RegExp getDefinition(String name) {
130
return (RegExp) macros.get(name);
135
* Expands all stored macros, so that getDefinition always returns
136
* a defintion that doesn't contain any macro usages.
138
* @throws MacroException if there is a cycle in the macro usage graph.
140
public void expand() throws MacroException {
144
names = macros.keys();
146
while ( names.hasMoreElements() ) {
147
String name = (String) names.nextElement();
149
macros.put(name, expandMacro(name, getDefinition(name)));
150
// this put doesn't get a new key, so only the a new value
151
// is set for the key "name" (without changing the enumeration
160
* Expands the specified macro by replacing each macro usage
161
* with the stored definition.
163
* @param name the name of the macro to expand (for detecting cycles)
164
* @param definition the definition of the macro to expand
166
* @return the expanded definition of the macro.
168
* @throws MacroException when an error (such as a cyclic definition)
169
* occurs during expansion
171
private RegExp expandMacro(String name, RegExp definition) throws MacroException {
173
// Out.print("checking macro "+name);
174
// Out.print("definition is "+definition);
176
switch ( definition.type ) {
179
RegExp2 binary = (RegExp2) definition;
180
binary.r1 = expandMacro(name, binary.r1);
181
binary.r2 = expandMacro(name, binary.r2);
187
RegExp1 unary = (RegExp1) definition;
188
unary.content = expandMacro(name, (RegExp) unary.content);
192
String usename = (String) ((RegExp1) definition).content;
194
if ( name.equals(usename) )
195
throw new MacroException("Macro "+name+" contains a cycle");
197
RegExp usedef = getDefinition(usename);
199
if ( usedef == null )
200
throw new MacroException("Found no definition for {"+usename+"} while expanding {"+name+"}");
204
return expandMacro(name, usedef);