1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3
* Copyright (C) 1998-2004 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
package weka.core.parser.JFlex;
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.4.1, $Revision: 1.1 $, $Date: 2008/05/09 09:14:11 $
35
final public class Macros {
37
/** Maps names of macros to their definition */
38
private Hashtable macros;
40
/** Maps names of macros to their "used" flag */
41
private Hashtable used;
45
* Creates a new macro expander.
48
macros = new Hashtable();
49
used = new Hashtable();
54
* Stores a new macro and its definition.
56
* @param name the name of the new macro
57
* @param definition the definition of the new macro
59
* @return <code>true</code>, iff the macro name has not been
62
public boolean insert(String name, RegExp definition) {
65
Out.debug("inserting macro "+name+" with definition :"+Out.NL+definition); //$NON-NLS-1$ //$NON-NLS-2$
67
used.put(name, Boolean.FALSE);
68
return macros.put(name,definition) == null;
73
* Marks a makro as used.
75
* @return <code>true</code>, iff the macro name has been
78
public boolean markUsed(String name) {
79
return used.put(name, Boolean.TRUE) != null;
84
* Tests if a macro has been used.
86
* @return <code>true</code>, iff the macro has been used in
87
* a regular expression.
89
public boolean isUsed(String name) {
90
return ((Boolean)used.get(name)).booleanValue();
95
* Returns all unused macros.
97
* @return the enumeration of macro names that have not been used.
99
public Enumeration unused() {
101
Vector unUsed = new Vector();
103
Enumeration names = used.keys();
104
while ( names.hasMoreElements() ) {
105
String name = (String) names.nextElement();
106
Boolean isUsed = (Boolean) used.get( name );
107
if ( !isUsed.booleanValue() ) unUsed.addElement(name);
110
return unUsed.elements();
115
* Fetches the definition of the macro with the specified name,
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).
121
* @param name the name of the macro
123
* @return the definition of the macro, <code>null</code> if
124
* no macro with the specified name has been stored.
126
* @see JFlex.Macros#expand
128
public RegExp getDefinition(String name) {
129
return (RegExp) macros.get(name);
134
* Expands all stored macros, so that getDefinition always returns
135
* a defintion that doesn't contain any macro usages.
137
* @throws MacroException if there is a cycle in the macro usage graph.
139
public void expand() throws MacroException {
143
names = macros.keys();
145
while ( names.hasMoreElements() ) {
146
String name = (String) names.nextElement();
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
157
* Expands the specified macro by replacing each macro usage
158
* with the stored definition.
160
* @param name the name of the macro to expand (for detecting cycles)
161
* @param definition the definition of the macro to expand
163
* @return the expanded definition of the macro.
165
* @throws MacroException when an error (such as a cyclic definition)
166
* occurs during expansion
168
private RegExp expandMacro(String name, RegExp definition) throws MacroException {
170
// Out.print("checking macro "+name);
171
// Out.print("definition is "+definition);
173
switch ( definition.type ) {
176
RegExp2 binary = (RegExp2) definition;
177
binary.r1 = expandMacro(name, binary.r1);
178
binary.r2 = expandMacro(name, binary.r2);
186
RegExp1 unary = (RegExp1) definition;
187
unary.content = expandMacro(name, (RegExp) unary.content);
191
String usename = (String) ((RegExp1) definition).content;
193
if ( name.equals(usename) )
194
throw new MacroException(ErrorMessages.get(ErrorMessages.MACRO_CYCLE, name));
196
RegExp usedef = getDefinition(usename);
198
if ( usedef == null )
199
throw new MacroException(ErrorMessages.get(ErrorMessages.MACRO_DEF_MISSING, usename, name));
203
return expandMacro(name, usedef);
214
throw new MacroException("unknown expression type "+definition.type+" in macro expansion"); //$NON-NLS-1$ //$NON-NLS-2$