?? macrotable.java
字號:
for (int i = 0; i < listeners.size(); i++)
{
IParseEventListener listener = (IParseEventListener)listeners.get(i);
listener.handleEvent(event, message);
}
}
//------------------------------------------------------------------------------------------------
/**
* Substitutes the given macro definition (which might simply be an identifier without any
* associated value) and returns the substitution string for it.
* The method does not raise an exception or show an error otherwise. The caller is responsible
* to take the appropriate action when null is returned.
*
* @param macroName A macro call or simple identifier to be replaced.
* @param parameters A list of parameters, if <b>macro</b> refers to a macro call (can be null).
* @return A string containing the textual replacement for the input or null if
* there is no replacement.
*/
protected String getMacroSubstitution(String macroName, String[] parameters)
{
String result = null;
Macro macro = (Macro) macros.get(macroName);
if (macro != null)
result = macro.getSubstition(parameters);
return result;
}
//------------------------------------------------------------------------------------------------
/**
* Adds the given event listener to the internal listener list.
*
* @param listener The listener to add.
*/
public void addMacroEventListener(IParseEventListener listener)
{
listeners.add(listener);
}
//----------------------------------------------------------------------------------------------
/**
* Adds the given macro definition to the table. Such a definition must consist solely of
* an identifier and an optional replacement text separated by one or more white spaces (space, tab).
* Additionally, as with C/C++, the macro identifier might be followed by a parameter list
* enclosed in parenthesis, similar to a function call.
*
* @param definition The macro definition to parse.
* @throws A runtime exception is thrown if the definition contains errors.
*/
public void defineMacro(String definition)
{
if (definition.trim().length() != 0)
{
// Split the definition into the main parts.
// Note: If the macro contains parentheses then there must be no white space between the
// macro identifier and the parameter list. This is necessary to distinct between a
// function macro and a symbolic constant enclosed in parentheses.
String[] parts = null;
Macro macro = null;
MacroTokenizer tokenizer = new MacroTokenizer(definition, false);
// Skip to the first identifier.
int token;
do
{
token = tokenizer.nextToken();
}
while (token != StreamTokenizer.TT_WORD);
String macroName = tokenizer.getStringValue();
token = tokenizer.nextToken();
if (token == '(')
{
// Found a macro call.
String parameters = tokenizer.getInnerText();
String[] parameterList = parameters.split(",");
for (int i = 0; i < parameterList.length; i++)
parameterList[i] = parameterList[i].trim();
String substitution = tokenizer.getRawInput(Integer.MAX_VALUE);
// Check if the macro is already defined with another value.
macro = (Macro) macros.get(macroName);
if (macro != null)
{
if (!macro.substitution.equals(substitution))
reportWarning("Macro " + macroName + " is being redefined.");
}
else
macro = new Macro(macroName, parameterList, substitution.trim());
}
else
{
// We are dealing with a simple macro definition (a.k.a macro object).
parts = definition.trim().split(" |\t", 2);
String substitution = null;
if (parts.length == 0)
reportError("Empty macro definition found.");
else
if (parts.length > 1)
substitution = parts[1].trim();
macroName = parts[0].trim();
// Check if the macro is already defined with another value.
macro = (Macro) macros.get(macroName);
if (macro != null)
{
if ((macro.substitution == null) != (substitution == null))
reportWarning("Macro " + macroName + " is being redefined.");
else
if (macro.substitution != null && !macro.substitution.equals(substitution))
reportWarning("Macro " + macroName + " is being redefined.");
}
else
macro = new Macro(macroName, null, substitution);
}
macros.put(macroName, macro);
}
}
//------------------------------------------------------------------------------------------------
/**
* Takes the input string and scans it for macro identifiers. Each occurence is recursively expanded.
*/
public String expandMacros(String input)
{
if (input == null)
return null;
else
{
String expandedString = "";
if (input.length() > 0)
{
StringBuffer buffer = new StringBuffer();
MacroTokenizer tokenizer = new MacroTokenizer(input, false);
boolean endReached = false;
while (!endReached)
{
int token = tokenizer.nextToken();
switch (token)
{
case StreamTokenizer.TT_EOF:
{
endReached = true;
break;
}
case StreamTokenizer.TT_WORD:
{
String symbol = tokenizer.getStringValue();
// Identifier found, which means that's something we have to expand or it is a
// preprocessor directive. Could well be a normal identifier, though.
if (!symbol.equals("defined") && (!isDefined(symbol) || evaluationList.contains(symbol)))
{
// If there is no known macro definition then keep the name without scanning
// further. If the symbol is already being expanded then we found an endless
// recursion. In this case the symbol also can be added to the output as it
// will then be catched by the evaluator as an undefined symbol.
// This is the same behavior like that of MSVC.
buffer.append(symbol);
}
else
{
// Make sure we do not get into an endless definition loop.
evaluationList.add(symbol);
// Note: The tokenizer is prepared so that number signs (#) belong to identifiers.
// In valid rc and header files number signs can only appear as part of a
// preprocessor directive, which is never macro-expanded.
if (symbol.charAt(0) == '#')
{
buffer.append(symbol);
break;
}
// Check if the identifier is followed by a parenthesis as this is
// then a list of parameters and separates a macro symbol from a macro call.
// Note: We are now going to directly manipulate the underlying reader of our tokenizer,
// so everything we consume here is never seen by the tokenizer.
int localToken = tokenizer.nextToken();
// Skip any whitespace but note if there were some and output a single space for them.
boolean outputWhiteSpace = false;
while (localToken == ' ' || localToken == '\t')
{
outputWhiteSpace = true;
localToken = tokenizer.nextToken();
}
if (localToken == '(')
{
if (symbol.equals("defined"))
{
// Special case: "defined(symbol)".
localToken = tokenizer.nextToken();
if (localToken != StreamTokenizer.TT_WORD)
reportError("Invalid macro definition");
symbol = tokenizer.getStringValue();
localToken = tokenizer.nextToken();
if (localToken != ')')
reportError("Invalid macro definition");
if (isDefined(symbol))
buffer.append("true");
else
buffer.append("false");
break;
}
String[] parameters = null;
// Collect all actual parameters into a list of strings and use this to
// resolve the macro call.
String paramList = tokenizer.getInnerText();
if (paramList == null)
parameters = null;
else
parameters = paramList.split(",");
// Recurse here for nested macro definitions.
String substitution = expandMacros(getMacroSubstitution(symbol, parameters));
if (substitution != null)
buffer.append(substitution);
}
else
{
tokenizer.pushBack();
// Just a simple macro symbol.
String substitution = expandMacros(getMacroSubstitution(symbol, null));
if (substitution != null)
buffer.append(substitution);
if (outputWhiteSpace)
buffer.append(" ");
}
evaluationList.remove(symbol);
}
break;
}
case '"':
{
buffer.append('"');
buffer.append(tokenizer.getStringValue());
buffer.append('"');
break;
}
case '\'':
{
buffer.append('\'');
buffer.append(tokenizer.getStringValue());
buffer.append('\'');
break;
}
default:
{
buffer.append((char)token);
break;
}
}
}
expandedString = buffer.toString();
}
return expandedString;
}
}
//------------------------------------------------------------------------------------------------
/**
* Determines if the given identifier is defined in the table.
*
* @param identifier The name of the potential macro.
* @return <b>true</b> if the identifier is defined, otherwise <b>false</b>.
*/
public boolean isDefined(String identifier)
{
return macros.containsKey(identifier);
}
//------------------------------------------------------------------------------------------------
/**
* Determines if the given identifier is defined in the table and has a non-empty expansion text.
*
* @param identifier The name of the potential macro.
* @return <b>true</b> if the identifier is defined and non-empty, otherwise <b>false</b>.
*/
public boolean isDefinedNonEmpty(String identifier)
{
Macro macro = (Macro) macros.get(identifier);
if (macro != null && !macro.isEmpty())
return true;
else
return false;
}
//------------------------------------------------------------------------------------------------
/**
* Reports an error to the calling application.
*
* @param s Error message to report.
*/
public void reportError(String s)
{
doEvent(IParseEventListener.ERROR, s);
}
//------------------------------------------------------------------------------------------------
/**
* Reports general information to the calling application.
*
* @param s Information message to report.
*/
public void reportInfo(String s)
{
doEvent(IParseEventListener.INFORMATION, s);
}
//------------------------------------------------------------------------------------------------
/**
* Reports a warning to the calling application.
*
* @param s Warning message to report.
*/
public void reportWarning(String s)
{
doEvent(IParseEventListener.WARNING, s);
}
//------------------------------------------------------------------------------------------------
/**
* Removes the macro definition with the given name from the definition list.
* If the macro does not exist then nothing happens.
*/
public void undefineMacro(String identifier)
{
macros.remove(identifier);
}
//------------------------------------------------------------------------------------------------
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -