diff options
author | Sven Gothel <[email protected]> | 2010-11-06 23:13:39 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-11-06 23:13:39 +0100 |
commit | 6f2d046c8d532db94f6af5003e341104d5bf4aff (patch) | |
tree | 723c31b8f9c1097ae48486acbf68e4e06fab2517 /src/java/com/sun/gluegen/pcpp/PCPP.java | |
parent | ec6d61f4597af32c22319c4bda3c9dd9ab80bf25 (diff) |
Renamed com.sun.gluegen -> com.jogamp.gluegen
Diffstat (limited to 'src/java/com/sun/gluegen/pcpp/PCPP.java')
-rw-r--r-- | src/java/com/sun/gluegen/pcpp/PCPP.java | 1107 |
1 files changed, 0 insertions, 1107 deletions
diff --git a/src/java/com/sun/gluegen/pcpp/PCPP.java b/src/java/com/sun/gluegen/pcpp/PCPP.java deleted file mode 100644 index cced7a6..0000000 --- a/src/java/com/sun/gluegen/pcpp/PCPP.java +++ /dev/null @@ -1,1107 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ - -package com.sun.gluegen.pcpp; - - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StreamTokenizer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Logger; -import static java.util.logging.Level.*; - -/** A minimal pseudo-C-preprocessor designed in particular to preserve - #define statements defining constants so they can be observed by a - glue code generator. */ - -public class PCPP { - - private static final Logger LOG = Logger.getLogger(PCPP.class.getPackage().getName()); - - /** Map containing the results of #define statements. We must - evaluate certain very simple definitions (to properly handle - OpenGL's gl.h) but preserve the text of definitions evaluating - to constants. Macros and multi-line defines (which typically - contain either macro definitions or expressions) are currently - not handled. */ - private Map<String, String> defineMap = new HashMap<String, String>(128); - private Map<String, Macro> macroMap = new HashMap<String, Macro>(128); - private Set<String> nonConstantDefines = new HashSet<String>(128); - - /** List containing the #include paths as Strings */ - private List<String> includePaths; - - private ParseState state; - - private boolean enableDebugPrint; - - public PCPP(List<String> includePaths, boolean debug) { - this.includePaths = includePaths; - setOut(System.out); - enableDebugPrint = debug; - } - - public void run(Reader reader, String filename) throws IOException { - StreamTokenizer tok = null; - BufferedReader bufReader = null; - if (reader instanceof BufferedReader) { - bufReader = (BufferedReader) reader; - } else { - bufReader = new BufferedReader(reader); - } - - tok = new StreamTokenizer(new ConcatenatingReader(bufReader)); - initTokenizer(tok); - - ParseState curState = new ParseState(tok, filename); - ParseState oldState = state; - state = curState; - lineDirective(); - parse(); - state = oldState; - if (state != null) { - lineDirective(); - } - } - - private void initTokenizer(StreamTokenizer tok) { - tok.resetSyntax(); - tok.wordChars('a', 'z'); - tok.wordChars('A', 'Z'); - tok.wordChars('0', '9'); - tok.wordChars('_', '_'); - tok.wordChars('-', '.'); - tok.wordChars(128, 255); - tok.whitespaceChars(0, ' '); - tok.quoteChar('"'); - tok.quoteChar('\''); - tok.eolIsSignificant(true); - tok.slashSlashComments(true); - tok.slashStarComments(true); - } - - public String findFile(String filename) { - String sep = File.separator; - for (String inclPath : includePaths) { - String fullPath = inclPath + sep + filename; - File file = new File(fullPath); - if (file.exists()) { - return fullPath; - } - } - return null; - } - - public OutputStream out() { - return out; - } - - public void setOut(OutputStream out) { - this.out = out; - writer = new PrintWriter(out); - } - - // State - static class ParseState { - - private StreamTokenizer tok; - private String filename; - private boolean startOfLine; - private boolean startOfFile; - - ParseState(StreamTokenizer tok, String filename) { - this.tok = tok; - this.filename = filename; - startOfLine = true; - startOfFile = true; - } - - void pushBackToken() throws IOException { - tok.pushBack(); - } - - int curToken() { - return tok.ttype; - } - - int nextToken() throws IOException { - return tok.nextToken(); - } - - String curWord() { - return tok.sval; - } - - String filename() { - return filename; - } - - int lineNumber() { - return tok.lineno(); - } - - boolean startOfLine() { - return startOfLine; - } - - void setStartOfLine(boolean val) { - startOfLine = val; - } - - boolean startOfFile() { - return startOfFile; - } - - void setStartOfFile(boolean val) { - startOfFile = val; - } - - } - - private static class Macro { - - private final List<String> values; - private final List<String> params; - - Macro(List<String> params, List<String> values) { - this.values = values; - this.params = params; - } - - @Override - public String toString() { - return "params: "+params+" values: "+values; - } - - } - - // Accessors - - /** Equivalent to nextToken(false) */ - private int nextToken() throws IOException { - return nextToken(false); - } - - private int nextToken(boolean returnEOLs) throws IOException { - int lineno = lineNumber(); - // Check to see whether the previous call to nextToken() left an - // EOL on the stream - if (state.curToken() == StreamTokenizer.TT_EOL) { - state.setStartOfLine(true); - } else if (!state.startOfFile()) { - state.setStartOfLine(false); - } - state.setStartOfFile(false); - int val = state.nextToken(); - if (!returnEOLs) { - if (val == StreamTokenizer.TT_EOL) { - do { - // Consume and return next token, setting state appropriately - val = state.nextToken(); - state.setStartOfLine(true); - println(); - } while (val == StreamTokenizer.TT_EOL); - } - } - if (lineNumber() > lineno + 1) { - // This is a little noisier than it needs to be, but does handle - // the case of multi-line comments properly - lineDirective(); - } - return val; - } - - /** - * Reads the next token and throws an IOException if it is not the specified - * token character. - */ - private void nextRequiredToken(int requiredToken) throws IOException { - int nextTok = nextToken(); - if (nextTok != requiredToken) { - String msg = "Expected token '" + requiredToken + "' but got "; - switch (nextTok) { - case StreamTokenizer.TT_EOF: msg += "<EOF>"; break; - case StreamTokenizer.TT_EOL: msg += "<EOL>"; break; - default: msg += "'" + curTokenAsString() + "'"; break; - } - msg += " at file " + filename() + ", line " + lineNumber(); - throw new IOException(msg); - } - } - - - private String curTokenAsString() { - int t = state.curToken(); - if (t == StreamTokenizer.TT_WORD) { - return state.curWord(); - } - if (t == StreamTokenizer.TT_EOL) { - throw new RuntimeException("Should not be converting EOL characters to strings"); - } - char c = (char) t; - if (c == '"' || c == '\'') { - StringBuilder sb = new StringBuilder(); - sb.append(c); - sb.append(state.curWord()); - sb.append(c); - return sb.toString(); - } - return new String(new char[] { c }); - } - - private String nextWordOrString() throws IOException { - nextToken(); - return curTokenAsString(); - } - - private String nextWord() throws IOException { - int val = nextToken(); - if (val != StreamTokenizer.TT_WORD) { - throw new RuntimeException("Expected word at file " + filename() + - ", line " + lineNumber()); - } - return state.curWord(); - } - - private boolean startOfLine() { - return state.startOfLine(); - } - - private String filename() { - return state.filename(); - } - - private int lineNumber() { - return state.lineNumber(); - } - - ///////////// - // Parsing // - ///////////// - - private void parse() throws IOException { - int tok = 0; - while ((tok = nextToken()) != StreamTokenizer.TT_EOF) { - // A '#' at the beginning of a line is a preprocessor directive - if (startOfLine() && (tok == '#')) { - preprocessorDirective(); - } else { - // Output white space plus current token, handling #defines - // (though not properly -- only handling #defines to constants and the empty string) - - // !!HACK!! - print space only for word tokens. This way multicharacter - // operators such as ==, != etc. are property printed. - if (tok == StreamTokenizer.TT_WORD) { - print(" "); - } - String s = curTokenAsString(); - String newS = defineMap.get(s); - if (newS == null) { - newS = s; - } - - Macro macro = macroMap.get(newS); - if(macro != null) { - newS = ""; - List<String> args = new ArrayList<String>(); - while (nextToken() != StreamTokenizer.TT_EOL) { - String token = curTokenAsString(); - if(")".equals(token)) { - break; - }else if(!",".equals(token) && !"(".equals(token)) { - args.add(token); - } - } - - for (int i = 0; i < macro.values.size(); i++) { - String value = macro.values.get(i); - - for (int j = 0; j < macro.params.size(); j++) { - String param = macro.params.get(j); - if(param.equals(value)) { - value = args.get(j); - break; - } - } - - if(isIdentifier(value)) { - newS +=" "; - } - - newS += value; - - } - - } - - print(newS); - } - } - flush(); - } - - private void preprocessorDirective() throws IOException { - String w = nextWord(); - boolean shouldPrint = true; - if (w.equals("warning")) { - handleWarning(); - shouldPrint = false; - } else if (w.equals("error")) { - handleError(); - shouldPrint = false; - } else if (w.equals("define")) { - handleDefine(); - shouldPrint = false; - } else if (w.equals("undef")) { - handleUndefine(); - shouldPrint = false; - } else if (w.equals("if") || w.equals("elif")) { - handleIf(w.equals("if")); - shouldPrint = false; - } else if (w.equals("ifdef") || w.equals("ifndef")) { - handleIfdef(w.equals("ifdef")); - shouldPrint = false; - } else if (w.equals("else")) { - handleElse(); - shouldPrint = false; - } else if (w.equals("endif")) { - handleEndif(); - shouldPrint = false; - } else if (w.equals("include")) { - handleInclude(); - shouldPrint = false; - } else { - // Unknown preprocessor directive (#pragma?) -- ignore - } - if (shouldPrint) { - print("# "); - printToken(); - } - } - - //////////////////////////////////// - // Handling of #define directives // - //////////////////////////////////// - - private void handleUndefine() throws IOException { - // Next token is the name of the #undef - String name = nextWord(); - - debugPrint(true, "#undef " + name); - - // there shouldn't be any extra symbols after the name, but just in case... - List<String> values = new ArrayList<String>(); - while (nextToken(true) != StreamTokenizer.TT_EOL) { - values.add(curTokenAsString()); - } - - if (enabled()) { - String oldDef = defineMap.remove(name); - if (oldDef == null) { - LOG.log(WARNING, "ignoring redundant \"#undef {0}\", at \"{1}\" line {2}: \"{3}\" was not previously defined", - new Object[]{name, filename(), lineNumber(), name}); - } else { - // System.err.println("UNDEFINED: '" + name + "' (line " + lineNumber() + " file " + filename() + ")"); - } - nonConstantDefines.remove(name); - } else { - LOG.log(WARNING, "FAILED TO UNDEFINE: ''{0}'' (line {1} file {2})", new Object[]{name, lineNumber(), filename()}); - } - } - - private void handleWarning() throws IOException { - String msg = nextWordOrString(); - if (enabled()) { - LOG.log(WARNING, "#warning {0} at \"{1}\" line \"{2}\"", new Object[]{msg, filename(), lineNumber()}); - } - } - - private void handleError() throws IOException { - String msg = nextWordOrString(); - if (enabled()) { - LOG.log(WARNING, "#error {0} at \"{1}\" line \"{2}\"", new Object[]{msg, filename(), lineNumber()}); - } - } - - private void handleDefine() throws IOException { - - // (workaround for not having a lookahead) - // macro functions have no space between identifier and '(' - // since whitespace is our delimiter we can't determine wether we are dealing with - // macros or normal defines starting with a brace. - // this will glue the brace to the token if there is no whitespace between both - state.tok.wordChars('(', '('); - - // Next token is the name of the #define - String name = nextWord(); - - boolean macroDefinition = name.contains("("); - - //System.err.println("IN HANDLE_DEFINE: '" + name + "' (line " + lineNumber() + " file " + filename() + ")"); - // (Note that this is not actually proper handling for multi-line #defines) - List<String> values = new ArrayList<String>(); - - if(macroDefinition) { - int index = name.indexOf('('); - String var = name.substring(index+1); - name = name.substring(0, index); - - values.add("("); - values.add(var); - } - - // restore normal syntax - state.tok.ordinaryChar('('); - - while (nextToken(true) != StreamTokenizer.TT_EOL) { - values.add(curTokenAsString()); - } - // if we're not within an active block of code (like inside an "#ifdef - // FOO" where FOO isn't defined), then don't actually alter the definition - // map. - debugPrint(true, "#define " + name); - if (enabled()) { - boolean emitDefine = true; - - // Handle #definitions to nothing or to a constant value - int sz = values.size(); - if (sz == 0) { - // definition to nothing, like "#define FOO" - String value = ""; - String oldDef = defineMap.put(name, value); - if (oldDef != null && !oldDef.equals(value)) { - LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"\"", new Object[]{name, oldDef}); - } - // We don't want to emit the define, because it would serve no purpose - // and cause GlueGen errors (confuse the GnuCParser) - emitDefine = false; - //System.out.println("//---DEFINED: " + name + "to \"\""); - } else if (sz == 1) { - // See whether the value is a constant - String value = values.get(0); - - if (isConstant(value)) { - // Value is numeric constant like "#define FOO 5". - // Put it in the #define map - String oldDef = defineMap.put(name, value); - if (oldDef != null && !oldDef.equals(value)) { - LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"{2}\"", new Object[]{name, oldDef, value}); - } - debugPrint(true, "#define " + name + " ["+oldDef+" ] -> "+value + " CONST"); - //System.out.println("//---DEFINED: " + name + " to \"" + value + "\""); - } else { - debugPrint(true, "#define " + name + " -> "+value + " SYMB"); - // Value is a symbolic constant like "#define FOO BAR". - // Try to look up the symbol's value - String newValue = resolveDefine(value, true); - if (newValue != null) { - // Set the value to the value of the symbol. - // - // TO DO: Is this correct? Why not output the symbol unchanged? - // I think that it's a good thing to see that some symbols are - // defined in terms of others. -chris - values.set(0, newValue); - } else { - // Still perform textual replacement - defineMap.put(name, value); - nonConstantDefines.add(name); - emitDefine = false; - } - } - - } else if (macroDefinition) { - - // list parameters - List<String> params = new ArrayList<String>(); - for (int i = 1; i < values.size(); i++) { - String v = values.get(i); - if(")".equals(v)) { // end of params - if(i != values.size()-1) { - values = values.subList(i+1, values.size()); - }else{ - values = Collections.emptyList(); - } - break; - }else if(!",".equals(v)) { - params.add(v); - } - } - - Macro macro = new Macro(params, values); - Macro oldDef = macroMap.put(name, macro); - if (oldDef != null) { - LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"{2}\"", new Object[]{name, oldDef, macro}); - } - emitDefine = false; - - }else{ - - // find constant expressions like (1 << 3) - // if found just pass them through, they will most likely work in java too - // expressions containing identifiers are currently ignored (casts too) - - boolean containsIdentifier = false; - for (String value : values) { - if(isIdentifier(value)) { - containsIdentifier = true; - break; - } - } - - //TODO more work here e.g casts are currently not handled - if(containsIdentifier) { //skip - - // Non-constant define; try to do reasonable textual substitution anyway - // (FIXME: should identify some of these, like (-1), as constants) - emitDefine = false; - StringBuilder val = new StringBuilder(); - for (int i = 0; i < sz; i++) { - if (i != 0) { - val.append(" "); - } - val.append(resolveDefine(values.get(i), false)); - } - if (defineMap.get(name) != null) { - // This is probably something the user should investigate. - throw new RuntimeException("Cannot redefine symbol \"" + name + - " from \"" + defineMap.get(name) + "\" to non-constant " + - " definition \"" + val.toString() + "\""); - } - defineMap.put(name, val.toString()); - nonConstantDefines.add(name); - - }else{ // constant expression -> pass through - - StringBuilder sb = new StringBuilder(); - for (String v : values) { - sb.append(v); - } - String value = sb.toString(); - - String oldDef = defineMap.put(name, value); - if (oldDef != null && !oldDef.equals(value)) { - LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"{2}\"", new Object[]{name, oldDef, value}); - } - debugPrint(true, "#define " + name + " ["+oldDef+" ] -> "+value + " CONST"); -// System.out.println("#define " + name +" "+value + " CONST EXPRESSION"); - } - - } - - if (emitDefine) { - // Print name and value - print("# define "); - print(name); - print(" "); - for (String v : values) { - print(v); - } - println(); - } - - } // end if (enabled()) - - //System.err.println("OUT HANDLE_DEFINE: " + name); - } - - private boolean isIdentifier(String value) { - - boolean identifier = false; - - char[] chars = value.toCharArray(); - - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; - if (i == 0) { - if (Character.isJavaIdentifierStart(c)) { - identifier = true; - } - } else { - if (!Character.isJavaIdentifierPart(c)) { - identifier = false; - break; - } - } - } - return identifier; - } - - private boolean isConstant(String s) { - if (s.startsWith("0x") || s.startsWith("0X")) { - return checkHex(s); - } else { - return checkDecimal(s); - } - } - - private boolean checkHex(String s) { - char c='\0'; - int i; - for (i = 2; i < s.length(); i++) { - c = s.charAt(i); - if (!((c >= '0' && c <= '9') || - (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F'))) { - break; - } - } - if(i==s.length()) { - return true; - } else if(i==s.length()-1) { - // Const qualifier .. - return c == 'l' || c == 'L' || - c == 'f' || c == 'F' || - c == 'u' || c == 'U' ; - } - return false; - } - - private boolean checkDecimal(String s) { - try { - Float.valueOf(s); - } catch (NumberFormatException e) { - // not parsable as a number - return false; - } - return true; - } - - private String resolveDefine(String word, boolean returnNullIfNotFound) { - String lastWord = defineMap.get(word); - if (lastWord == null) { - if (returnNullIfNotFound) { - return null; - } - return word; - } - String nextWord = null; - do { - nextWord = defineMap.get(lastWord); - if (nextWord != null) { - lastWord = nextWord; - } - } while (nextWord != null); - return lastWord; - } - - //////////////////////////////////////////////// - // Handling of #if/#ifdef/ifndef/endif directives // - //////////////////////////////////////////////// - - /** - * @param isIfdef if true, we're processing #ifdef; if false, we're - * processing #ifndef. - */ - private void handleIfdef(boolean isIfdef) throws IOException { - // Next token is the name of the #ifdef - String symbolName = nextWord(); - debugPrint(true, (isIfdef ? "#ifdef " : "#ifndef ") + symbolName); - boolean symbolIsDefined = defineMap.get(symbolName) != null; - debugPrint(true, (isIfdef ? "#ifdef " : "#ifndef ") + symbolName + "(defined: "+symbolIsDefined+")"); - pushEnableBit(enabled() && symbolIsDefined == isIfdef); - } - - /** Handles #else directives */ - private void handleElse() throws IOException { - boolean enabledStatusBeforeElse = enabled(); - popEnableBit(); - pushEnableBit(enabled() && !enabledStatusBeforeElse); - debugPrint(true, "#else "); - } - - private void handleEndif() { - boolean enabledBeforePopping = enabled(); - popEnableBit(); - - // print the endif if we were enabled prior to popEnableBit() (sending - // false to debugPrint means "print regardless of current enabled() state). - debugPrint(!enabledBeforePopping, "#endif/end-else"); - } - - /** - * @param isIf if true, we're processing #if; if false, we're - * processing #elif. - */ - private void handleIf(boolean isIf) throws IOException { - //System.out.println("IN HANDLE_" + (isIf ? "IF" : "ELIF") + " file \"" + filename() + " line " + lineNumber()); - debugPrint(true, (isIf ? "#if" : "#elif")); - boolean defineEvaluatedToTrue = handleIfRecursive(true); - if (!isIf) { - popEnableBit(); - } - pushEnableBit(enabled() && defineEvaluatedToTrue); - //System.out.println("OUT HANDLE_" + (isIf ? "IF" : "ELIF") +" (evaluated to " + defineEvaluatedToTrue + ")"); - } - - //static int tmp = -1; - - /** - * This method is called recursively to process nested sub-expressions such as: - * <pre> - * #if !defined(OPENSTEP) && !(defined(NeXT) || !defined(NeXT_PDO)) - *</pre> - * - * @param greedy if true, continue evaluating sub-expressions until EOL is - * reached. If false, return as soon as the first sub-expression is - * processed. - * @return the value of the sub-expression or (if greedy==true) - * series of sub-expressions. - */ - private boolean handleIfRecursive(boolean greedy) throws IOException { - //System.out.println("IN HANDLE_IF_RECURSIVE (" + ++tmp + ", greedy = " + greedy + ")"); System.out.flush(); - - // ifValue keeps track of the current value of the potentially nested - // "defined()" expressions as we process them. - boolean ifValue = true; - int openParens = 0; - int tok; - do { - tok = nextToken(true); - //System.out.println("-- READ: [" + (tok == StreamTokenizer.TT_EOL ? "<EOL>" :curTokenAsString()) + "]"); - switch (tok) { - case '(': - ++openParens; - //System.out.println("OPEN PARENS = " + openParens); - ifValue = ifValue && handleIfRecursive(true); - break; - case ')': - --openParens; - //System.out.println("OPEN PARENS = " + openParens); - break; - case '!': - { - //System.out.println("HANDLE_IF_RECURSIVE HANDLING !"); - boolean rhs = handleIfRecursive(false); - ifValue = !rhs; - //System.out.println("HANDLE_IF_RECURSIVE HANDLED OUT !, RHS = " + rhs); - } - break; - case '&': - { - nextRequiredToken('&'); - //System.out.println("HANDLE_IF_RECURSIVE HANDLING &&, LHS = " + ifValue); - boolean rhs = handleIfRecursive(true); - //System.out.println("HANDLE_IF_RECURSIVE HANDLED &&, RHS = " + rhs); - ifValue = ifValue && rhs; - } - break; - case '|': - { - nextRequiredToken('|'); - //System.out.println("HANDLE_IF_RECURSIVE HANDLING ||, LHS = " + ifValue); - boolean rhs = handleIfRecursive(true); - //System.out.println("HANDLE_IF_RECURSIVE HANDLED ||, RHS = " + rhs); - ifValue = ifValue || rhs; - } - break; - case '>': - { - // NOTE: we don't handle expressions like this properly - boolean rhs = handleIfRecursive(true); - ifValue = false; - } - break; - case '<': - { - // NOTE: we don't handle expressions like this properly - boolean rhs = handleIfRecursive(true); - ifValue = false; - } - break; - case '=': - { - // NOTE: we don't handle expressions like this properly - boolean rhs = handleIfRecursive(true); - ifValue = false; - } - break; - case StreamTokenizer.TT_WORD: - { - String word = curTokenAsString(); - if (word.equals("defined")) { - // Handle things like #if defined(SOMESYMBOL) - nextRequiredToken('('); - String symbol = nextWord(); - boolean isDefined = defineMap.get(symbol) != null; - //System.out.println("HANDLE_IF_RECURSIVE HANDLING defined(" + symbol + ") = " + isDefined); - ifValue = ifValue && isDefined; - nextRequiredToken(')'); - } else { - // Handle things like #if SOME_SYMBOL. - String symbolValue = defineMap.get(word); - - // See if the statement is "true"; i.e., a non-zero expression - if (symbolValue != null) { - // The statement is true if the symbol is defined and is a constant expression - return (!nonConstantDefines.contains(word)); - } else { - // The statement is true if the symbol evaluates to a non-zero value - // - // NOTE: This doesn't yet handle evaluable expressions like "#if - // SOME_SYMBOL > 5" or "#if SOME_SYMBOL == 0", both of which are - // valid syntax. It only handles numeric symbols like "#if 1" - - try { - // see if it's in decimal form - return Double.parseDouble(word) != 0; - } catch (NumberFormatException nfe1) { - try { - // ok, it's not a valid decimal value, try hex/octal value - return Long.parseLong(word) != 0; - } catch (NumberFormatException nfe2) { - try { - // ok, it's not a valid hex/octal value, try boolean - return Boolean.valueOf(word) == Boolean.TRUE; - } catch (NumberFormatException nfe3) { - // give up; the symbol isn't a numeric or boolean value - return false; - } - } - } - } - } - } // end case TT_WORD - break; - case StreamTokenizer.TT_EOL: - //System.out.println("HANDLE_IF_RECURSIVE HIT <EOL>!"); - state.pushBackToken(); // so caller hits EOL as well if we're recursing - break; - case StreamTokenizer.TT_EOF: - throw new RuntimeException("Unexpected end of file while parsing " + - "#if statement at file " + filename() + ", line " + lineNumber()); - - default: - throw new RuntimeException("Unexpected token (" + curTokenAsString() + - ") while parsing " + "#if statement at file " + filename() + - ", line " + lineNumber()); - } - //System.out.println("END OF WHILE: greedy = " + greedy + " parens = " +openParens + " not EOL = " + (tok != StreamTokenizer.TT_EOL) + " --> " + ((greedy && openParens >= 0) && tok != StreamTokenizer.TT_EOL)); - } while ((greedy && openParens >= 0) && tok != StreamTokenizer.TT_EOL); - //System.out.println("OUT HANDLE_IF_RECURSIVE (" + tmp-- + ", returning " + ifValue + ")"); - //System.out.flush(); - return ifValue; - } - - ///////////////////////////////////// - // Handling of #include directives // - ///////////////////////////////////// - - private void handleInclude() throws IOException { - // Two kinds of #includes: one with quoted string for argument, - // one with angle brackets surrounding argument - int t = nextToken(); - String filename = null; - if (t == '"') { - filename = state.curWord(); - } else if (t == '<') { - // Components of path name are coming in as separate tokens; - // concatenate them - StringBuilder buf = new StringBuilder(); - while ((t = nextToken()) != '>' && (t != StreamTokenizer.TT_EOF)) { - buf.append(curTokenAsString()); - } - if (t == StreamTokenizer.TT_EOF) { - LOG.warning("unexpected EOF while processing #include directive"); - } - filename = buf.toString(); - } - // if we're not within an active block of code (like inside an "#ifdef - // FOO" where FOO isn't defined), then don't actually process the - // #included file. - debugPrint(true, "#include [" + filename + "]"); - if (enabled()) { - // Look up file in known #include path - String fullname = findFile(filename); - //System.out.println("ACTIVE BLOCK, LOADING " + filename); - if (fullname == null) { - LOG.log(WARNING, "unable to find #include file \"{0}\"", filename); - return; - } - // Process this file in-line - Reader reader = new BufferedReader(new FileReader(fullname)); - run(reader, fullname); - } else { - //System.out.println("INACTIVE BLOCK, SKIPPING " + filename); - } - } - - //////////// - // Output // - //////////// - - private OutputStream out; - private PrintWriter writer; - private List<Boolean> enabledBits = new ArrayList<Boolean>(); - - private static int debugPrintIndentLevel = 0; - - private void debugPrint(boolean onlyPrintIfEnabled, String msg) { - if (!enableDebugPrint) { - return; - } - - if (!onlyPrintIfEnabled || (onlyPrintIfEnabled && enabled())) { - for (int i = debugPrintIndentLevel; --i > 0;) { - System.out.print(" "); - } - System.out.println(msg + " (line " + lineNumber() + " file " + filename() + ")"); - } - } - - private void pushEnableBit(boolean enabled) { - enabledBits.add(enabled); - ++debugPrintIndentLevel; - debugPrint(false, "PUSH_ENABLED, NOW: " + enabled()); - } - - private void popEnableBit() { - if (enabledBits.isEmpty()) { - LOG.warning("mismatched #ifdef/endif pairs"); - return; - } - enabledBits.remove(enabledBits.size() - 1); - --debugPrintIndentLevel; - debugPrint(false, "POP_ENABLED, NOW: " + enabled()); - } - - private boolean enabled() { - return (enabledBits.isEmpty() || enabledBits.get(enabledBits.size() - 1)); - } - - private void print(String s) { - if (enabled()) { - writer.print(s); - //System.out.print(s);//debug - } - } - - private void print(char c) { - if (enabled()) { - writer.print(c); - //System.err.print(c); //debug - } - } - - private void println() { - if (enabled()) { - writer.println(); - //System.err.println();//debug - } - } - - private void printToken() { - print(curTokenAsString()); - } - - private void flush() { - if (enabled()) { - writer.flush(); - //System.err.flush(); //debug - } - } - - private void lineDirective() { - print("# " + lineNumber() + " \"" + filename() + "\""); - println(); - } - - private static void usage() { - System.out.println("Usage: java PCPP [filename | -]"); - System.out.println("Minimal pseudo-C-preprocessor."); - System.out.println("Output goes to standard output. Standard input can be used as input"); - System.out.println("by passing '-' as the argument."); - System.out.println(" --debug enables debug mode"); - System.exit(1); - } - - public static void main(String[] args) throws IOException { - Reader reader = null; - String filename = null; - boolean debug = false; - - if (args.length == 0) { - usage(); - } - - List<String> includePaths = new ArrayList<String>(); - for (int i = 0; i < args.length; i++) { - if (i < args.length - 1) { - String arg = args[i]; - if (arg.startsWith("-I")) { - String[] paths = arg.substring(2).split(System.getProperty("path.separator")); - for (int j = 0; j < paths.length; j++) { - includePaths.add(paths[j]); - } - } else if (arg.equals("--debug")) { - debug = true; - } else { - usage(); - } - } else { - String arg = args[i]; - if (arg.equals("-")) { - reader = new InputStreamReader(System.in); - filename = "standard input"; - } else { - if (arg.startsWith("-")) { - usage(); - } - filename = arg; - reader = new BufferedReader(new FileReader(filename)); - } - } - } - - new PCPP(includePaths, debug).run(reader, filename); - } - -} |