📄 preprocessor.java
字号:
/**
* Reads the next input line and advances the internal line counter. If we are currently in multi
* line comment mode then skip comment lines until we find a comment end.
*
* @return The read line.
* @throws IOException
*/
protected String readLine() throws IOException
{
String line = null;
do
{
line = input.readLine();
if (traceProcessing)
System.out.println(" : " + line);
if (line == null)
{
// If the input string empty then there is no more input available in this file.
// Return to previous input state in this case.
reportIncludeFile("<<< " + inputState.getFilename());
inputState.popState();
break;
}
if (skip != SKIP_NONE)
break;
// First check if we are still waiting for a multi line comment to end.
if (inMultilineComment)
{
int commentEndIndex = line.indexOf("*/");
// If the comment does not end on this line then start over with the next one.
if (commentEndIndex == -1)
continue;
// The multi line comment ends here. Remove the remaining comment part and continue processing.
inMultilineComment = false;
line = line.substring(commentEndIndex + 2, line.length());
break;
}
}
while (inMultilineComment);
if (line == null)
return null;
else
if (skip != SKIP_NONE)
return line.trim();
else
return removeComments(line);
}
//------------------------------------------------------------------------------------------------
/**
* Reads and processes all input until a non-preprocessor line is found. This line is appended
* to the current content of the currentLine string buffer that is used to feed the lexer.
*
* @throws IOException Thrown when something goes wrong with reading file data.
*/
protected void readNextLine() throws IOException
{
currentLine.delete(0, currentPosition);
currentPosition = 0;
String result = processUnconditionalInput();
if (result != null)
currentLine.append(result);
currentLine.append('\n');
}
//------------------------------------------------------------------------------------------------
/**
* Adds the given search path for include files to the internal list.
* Note that this preprocessor does nothing know about predefined pathes as used in MSVC (e.g.
* as in <tchar.h>). So you must explicitely give these pathes too.
*
* @param name The new search path to add.
*/
public void addIncludePath(String name)
{
includePaths.add(name);
}
//------------------------------------------------------------------------------------------------
/**
* Adds the given macro to the internal macro table.
* Note: The definition must not contain the <b>#define</b> part.
*
* @param macro The macro definition string.
*/
public void addMacro(String macro)
{
macroTable.defineMacro(macro);
}
//------------------------------------------------------------------------------------------------
public void addPreprocessorEventListener(IParseEventListener listener)
{
listeners.add(listener);
}
//------------------------------------------------------------------------------------------------
/* (non-Javadoc)
* @see java.io.Reader#close()
*/
public void close() throws IOException
{
// Nothing to do here.
}
//------------------------------------------------------------------------------------------------
/**
* Returns the internal table of collected macro definitions.
*
* @return Returns the macro table.
*/
public MacroTable getMacroTable()
{
return macroTable;
}
//------------------------------------------------------------------------------------------------
public boolean hadErrors()
{
return hadErrors;
}
//------------------------------------------------------------------------------------------------
public boolean hadWarnings()
{
return hadWarnings;
}
//------------------------------------------------------------------------------------------------
/* (non-Javadoc)
* @see net.softgems.resourceparser.main.IParseEventListener#handleEvent(int, java.lang.String)
*/
public void handleEvent(int event, String message)
{
// This method is called here only during an expression evaluation and is used to forward
// the incoming events to the owner of this preprocessor.
doEvent(event, message, false);
}
//------------------------------------------------------------------------------------------------
/**
* Sets a new input state up so following read attempts by the lexer are directed to the new
* preprocessor.
*
* @param filename The file to include.
* @return <b>true</b> if a new preprocessor was set up, otherwise <b>false</b>.
* @throws IOException
* @throws FileNotFoundException
*/
public boolean includeFile(String filename) throws IOException, FileNotFoundException
{
boolean result = false;
// The map processedIncludes contains files, which were marked with the "#pragma once" directive
// and hence should automatically not be included more than once.
if (!processedIncludes.containsKey(filename))
{
// To make relative includes from the included file possible switch to the resulting
// directory of this include file. Restore the value after return.
File canonicalFile = null;
// Try to locate the include file without include path first (relative to application root)
File file = new File(filename);
// Convert eventual further subfolders in the file to one canonical file,
// so we have resolved links and no special folders like "." or ".." etc. anymore.
canonicalFile = file.getCanonicalFile();
if (!file.isAbsolute())
{
// If the file is relative then first try to access it as if it is using the current
// user dir as base folder.
if (!canonicalFile.canRead())
{
// We have a relative file, which is not accessible from the current user directory.
// Try each include path until we have access.
for (Iterator iterator = includePaths.iterator(); iterator.hasNext();)
{
String path = (String) iterator.next();
if (!path.endsWith(File.separator))
path += File.separator;
File testFile = new File(path + filename);
if (testFile.exists())
{
canonicalFile = testFile.getCanonicalFile();
break;
}
}
}
}
if (canonicalFile.canRead())
{
reportIncludeFile(">>> " + filename);
// If we can read the file then set up a new preprocessor instance. The sub preprocessor
// uses the same input state, include pathes and defined symbols as this one.
InputConverter input = new InputConverter(inputState, new FileInputStream(canonicalFile),
DEFAULT_CHARSET);
Preprocessor preprocessor = new Preprocessor(input, this, inputState, traceProcessing);
inputState.pushState(preprocessor, canonicalFile.getName(), canonicalFile.getParent());
preprocessor.addPreprocessorEventListener(
new IParseEventListener()
{
public void handleEvent(int event, String message)
{
doEvent(event, message, false);
};
}
);
preprocessor.init();
result = true;
}
else
reportWarning("Cannot access include file \"" + filename + "\"");
}
return result;
}
//------------------------------------------------------------------------------------------------
public void init()
{
// Microsoft's resource compiler handles *.c and *.h files in a special way. Everything except
// preprocessor lines is automatically skipped in such files.
// See also: "Using #include Directive with Windows Resource Compiler", KB Q80945.
String filename = inputState.getFilename();
skipNonPPLines = filename.toLowerCase().endsWith(".c") || filename.toLowerCase().endsWith(".h");
}
//------------------------------------------------------------------------------------------------
/**
* This method is executed by the preprocessor internally when it detected an illegal
* state that cannot be recovered from.
*/
public void panic(String s)
{
doEvent(IParseEventListener.PANIC, "RC lexer panic: " + s, true);
}
//------------------------------------------------------------------------------------------------
/* (non-Javadoc)
* @see java.io.Reader#read()
*/
public int read() throws IOException
{
if (currentLine.length() < (currentPosition + 1))
readNextLine();
if (currentLine.length() == 0)
return -1;
else
return currentLine.charAt(currentPosition++);
}
//------------------------------------------------------------------------------------------------
/* (non-Javadoc)
* @see java.io.Reader#read(char[], int, int)
*/
public int read(char[] cbuf, int off, int len) throws IOException
{
if (currentLine.length() < (currentPosition + len))
readNextLine();
if (currentLine.length() == 0)
return -1;
else
{
int actualLength = Math.min(currentLine.length() - currentPosition, len);
currentLine.getChars(currentPosition, actualLength, cbuf, off);
currentPosition += actualLength;
return actualLength;
}
}
//------------------------------------------------------------------------------------------------
/**
* Removes the given listener from the internal list. If the listerner is not in this list
* then the method does nothing.
*
* @param listener The listener to be removed.
*/
public void removePreprocessorEventListener(IParseEventListener listener)
{
listeners.remove(listener);
}
//------------------------------------------------------------------------------------------------
/**
* Removes the symbol with the given name from the internal symbol table. If the symbol does not
* exist then nothing happens.
*
* @param name The name of the symbol to be removed.
*/
public void removeSymbol(String name)
{
macroTable.undefineMacro(name);
}
//------------------------------------------------------------------------------------------------
/**
* Reports an error to the calling application.
*
* @param s Error message to report.
*/
public void reportError(String s)
{
doEvent(IParseEventListener.ERROR, s, inputState.getFullFilename() != null);
}
//------------------------------------------------------------------------------------------------
/**
* Reports the names of all files, which are included during the preprocessing step.
*
* @param filen The name of the file that is about to be processed.
*/
public void reportIncludeFile(String file)
{
doEvent(IParseEventListener.INCLUDE_FILE, file, inputState.getFullFilename() != null);
}
//------------------------------------------------------------------------------------------------
/**
* Reports general information to the calling application.
*
* @param s Information message to report.
*/
public void reportInfo(String s)
{
doEvent(IParseEventListener.INFORMATION, s, inputState.getFullFilename() != null);
}
//------------------------------------------------------------------------------------------------
/**
* Reports a warning to the calling application.
*
* @param s Warning message to report.
*/
public void reportWarning(String s)
{
doEvent(IParseEventListener.WARNING, s, inputState.getFullFilename() != null);
}
//------------------------------------------------------------------------------------------------
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -