From 239b00c26cc3f24b7d9e334de8ac1bee849e05b1 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 8 Aug 2023 15:08:14 +0200 Subject: Drop PCPP, GlueGen exclusively uses JCPP; Adopt test case Test{P->J}CPP --- doc/manual/index.html | 79 +- make/scripts/runtest-secmgr.sh | 2 +- make/scripts/runtest.sh | 4 +- .../jogamp/gluegen/pcpp/ConcatenatingReader.java | 181 --- src/java/com/jogamp/gluegen/pcpp/PCPP.java | 1200 -------------------- .../gluegen/test/junit/generation/TestJCPP.java | 132 +++ .../gluegen/test/junit/generation/TestPCPP.java | 151 --- .../test/junit/generation/cpptest-included.h | 2 + .../jogamp/gluegen/test/junit/generation/cpptest.h | 138 +++ .../test/junit/generation/pcpptest-included.h | 2 - .../gluegen/test/junit/generation/pcpptest.h | 138 --- 11 files changed, 291 insertions(+), 1738 deletions(-) delete mode 100644 src/java/com/jogamp/gluegen/pcpp/ConcatenatingReader.java delete mode 100644 src/java/com/jogamp/gluegen/pcpp/PCPP.java create mode 100644 src/junit/com/jogamp/gluegen/test/junit/generation/TestJCPP.java delete mode 100644 src/junit/com/jogamp/gluegen/test/junit/generation/TestPCPP.java create mode 100644 src/junit/com/jogamp/gluegen/test/junit/generation/cpptest-included.h create mode 100644 src/junit/com/jogamp/gluegen/test/junit/generation/cpptest.h delete mode 100644 src/junit/com/jogamp/gluegen/test/junit/generation/pcpptest-included.h delete mode 100644 src/junit/com/jogamp/gluegen/test/junit/generation/pcpptest.h diff --git a/doc/manual/index.html b/doc/manual/index.html index 2ab020b..8d3d2fd 100755 --- a/doc/manual/index.html +++ b/doc/manual/index.html @@ -29,7 +29,7 @@

GlueGen Manual

- Disclaimer: This documented is slightly outdated and may require an update. + Disclaimer: This documented shall be synchronized with source code, especially the confifuration options.

Please also consider reading GlueGen Native Data & Function Mapping for details on native data and function mappings.

@@ -53,7 +53,7 @@
  • Basic Operation
  • Running GlueGen as an Ant Task
  • -
  • PCPP
  • +
  • JCPP
  • Error Reporting
  • Stub Headers
  • 32- and 64-bit Considerations
  • @@ -462,74 +462,27 @@ concrete, though non-trivial, examples of how to invoke GlueGen via Ant. -

    PCPP

    +

    JCPP

    - GlueGen contains and uses a minimal C preprocessor called the "Pseudo - C Pre-Processor", or PCPP. A slightly specialized C preprocessor is - required for correct glue code generation with most libraries. + GlueGen contains and uses the C preprocessor JCPP, + see original homepage. +

    +

    Constant values intended for use by end users are defined in many C libraries' headers using #defines rather than constant - int declarations, and if the header is processed by a full C - preprocessor then the #define statements will be stripped become + int declarations. If the header would be processed by a full C + preprocessor, the #define statement's macro name become unavailable for processing by the glue code generator. - + Using JCPP allows us to utilize the #define macro names and values.

    - - PCPP is largely an invisible part of the glue code generation process; - however, it has certain limitations which make it difficult to parse - certain header files. First, it does not support macro evaluation in - any form, so if a header relies on macro evaluation in order to - generate code, PCPP will fail. It is possible that PCPP may fail - silently in this situation, causing GlueGen to simply not produce code - for the associated constructs. If GlueGen's output is not as expected - and there is heavy use of the C preprocessor in the header, run PCPP - against the header directly (PCPP takes simply the -I and filename + JCPP is largely an invisible part of the glue code generation process. + If GlueGen's output is not as expected + and there is heavy use of the C preprocessor in the header, run JCPP + against the header directly (JCPP takes simply the -I and filename arguments accepted by GlueGen) and examine the output. - -

    -

    - - Second, PCPP contains only limited support for #if - clauses. Generally speaking, its handling of #if defined(foo) || - defined(bar) constructs is limited to approximately what is - required to handle the OpenGL header files. If the header being parsed - relies on moderately complicated expressions being evaluated by the C - preprocessor, check the output from PCPP and ensure it is as expected. - -

    -

    - - Contributions to PCPP would be especially welcome. It would be very - desirable to turn it into a full-blown C preprocessor with simply the - option of passing through #define statements unchanged. - -

    - -

    Error Reporting

    - -

    - - Error reporting by GlueGen's parser is currently less than ideal. - Because PCPP makes #include directives disappear - completely with respect to the C parser (it appears that the - #line directives it emits are not being consumed properly - -- an area which needs more investigation), the line numbers reported - in parse failures are incorrect in all but the simplest cases. This - makes it difficult to determine in exactly what header file and on - exactly what construct the C parser failed. - -

    -

    - - Fortunately, there is a relatively simple workaround. PCPP can be run - with all of the same -I arguments passed to GlueGen and the result - piped to a new .c file. GlueGen can then be invoked on that .c file - (now containing no #include directives) and the line - numbers on any parse failures will be correct. -

    Stub Headers

    @@ -612,7 +565,7 @@ undesirable to try to parse the real windows.h just to pick up these typedefs; not only does this header contain thousands of unneeded APIs, but it also uses certain macro constructs not supported - by GlueGen's minimal C preprocessor. To avoid + by GlueGen's contained C preprocessor. To avoid these problems, a "stub" windows.h header is placed in GlueGen's include path containing only the necessary typedefs:

    @@ -1550,7 +1503,7 @@ well as the function pointer typedef. Some headers, in particular the OpenAL headers, have their #ifdefs structured in such a way that either the declaration or the typedef is visible, but not - both simultaneously. Because the PCPP C + both simultaneously. Because the JCPP C preprocessor GlueGen uses obeys #ifdefs, it is in a situation like this that the headers would have to be modified to allow GlueGen to see both declarations. diff --git a/make/scripts/runtest-secmgr.sh b/make/scripts/runtest-secmgr.sh index 24f1b58..b174d36 100755 --- a/make/scripts/runtest-secmgr.sh +++ b/make/scripts/runtest-secmgr.sh @@ -99,7 +99,7 @@ function onetest() { #onetest com.jogamp.common.util.IntObjectHashMapTest 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.LongIntHashMapTest 2>&1 | tee -a $LOG #onetest com.jogamp.common.nio.TestBuffersFloatDoubleConversion 2>&1 | tee -a $LOG -#onetest com.jogamp.gluegen.PCPPTest 2>&1 | tee -a $LOG +#onetest com.jogamp.gluegen.JCPPTest 2>&1 | tee -a $LOG #onetest com.jogamp.common.nio.TestPointerBufferEndian 2>&1 | tee -a $LOG #onetest com.jogamp.common.nio.TestStructAccessorEndian 2>&1 | tee -a $LOG #onetest com.jogamp.common.os.TestElfReader01 2>&1 | tee -a $LOG diff --git a/make/scripts/runtest.sh b/make/scripts/runtest.sh index d692747..cb480f4 100755 --- a/make/scripts/runtest.sh +++ b/make/scripts/runtest.sh @@ -150,7 +150,7 @@ function onetest() { #onetest com.jogamp.common.os.TestElfReader01 $* 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.test.junit.internals.TestType 2>&1 | tee -a $LOG -#onetest com.jogamp.gluegen.test.junit.generation.TestPCPP 2>&1 | tee -a $LOG +onetest com.jogamp.gluegen.test.junit.generation.TestJCPP 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.CppReaderTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.ErrorTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.IncludeAbsoluteTest 2>&1 | tee -a $LOG @@ -158,7 +158,7 @@ function onetest() { #onetest com.jogamp.gluegen.jcpp.JoinReaderTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.LexerSourceTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.NumericValueTest 2>&1 | tee -a $LOG -onetest com.jogamp.gluegen.jcpp.PragmaTest 2>&1 | tee -a $LOG +#onetest com.jogamp.gluegen.jcpp.PragmaTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.PreprocessorTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.RegressionTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.TokenPastingWhitespaceTest 2>&1 | tee -a $LOG diff --git a/src/java/com/jogamp/gluegen/pcpp/ConcatenatingReader.java b/src/java/com/jogamp/gluegen/pcpp/ConcatenatingReader.java deleted file mode 100644 index 7583d50..0000000 --- a/src/java/com/jogamp/gluegen/pcpp/ConcatenatingReader.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2006 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.jogamp.gluegen.pcpp; - -import java.io.*; - -/** A Reader implementation which finds lines ending in the backslash - character ('\') and concatenates them with the next line. */ - -public class ConcatenatingReader extends FilterReader { - // Any leftover characters go here - private char[] curBuf; - private int curPos; - private final BufferedReader reader; - private static String newline = System.getProperty("line.separator"); - - /** This class requires that the input reader be a BufferedReader so - it can do line-oriented operations. */ - public ConcatenatingReader(final BufferedReader in) { - super(in); - this.reader = in; - } - - @Override - public int read() throws IOException { - final char[] tmp = new char[1]; - final int num = read(tmp, 0, 1); - if (num < 0) - return -1; - return tmp[0]; - } - - // It's easier not to support mark/reset since we don't need it - @Override - public boolean markSupported() { - return false; - } - - @Override - public void mark(final int readAheadLimit) throws IOException { - throw new IOException("mark/reset not supported"); - } - - @Override - public void reset() throws IOException { - throw new IOException("mark/reset not supported"); - } - - @Override - public boolean ready() throws IOException { - if (curBuf != null || reader.ready()) - return true; - return false; - } - - @Override - public int read(final char[] cbuf, int off, int len) throws IOException { - if (curBuf == null) { - nextLine(); - } - - if (curBuf == null) { - return -1; - } - - int numRead = 0; - - while ((len > 0) && (curBuf != null) && (curPos < curBuf.length)) { - cbuf[off] = curBuf[curPos]; - ++curPos; - ++off; - --len; - ++numRead; - if (curPos == curBuf.length) { - nextLine(); - } - } - - return numRead; - } - - @Override - public long skip(long n) throws IOException { - long numSkipped = 0; - - while (n > 0) { - final int intN = (int) n; - final char[] tmp = new char[intN]; - final int numRead = read(tmp, 0, intN); - n -= numRead; - numSkipped += numRead; - if (numRead < intN) - break; - } - return numSkipped; - } - - private void nextLine() throws IOException { - final String cur = reader.readLine(); - if (cur == null) { - curBuf = null; - return; - } - // The trailing newline was trimmed by the readLine() method. See - // whether we have to put it back or not, depending on whether the - // last character of the line is the concatenation character. - int numChars = cur.length(); - boolean needNewline = true; - if ((numChars > 0) && - (cur.charAt(cur.length() - 1) == '\\')) { - --numChars; - needNewline = false; - } - final char[] buf = new char[numChars + (needNewline ? newline.length() : 0)]; - cur.getChars(0, numChars, buf, 0); - if (needNewline) { - newline.getChars(0, newline.length(), buf, numChars); - } - curBuf = buf; - curPos = 0; - } - - // Test harness - /* - public static void main(String[] args) throws IOException { - if (args.length != 1) { - System.out.println("Usage: java ConcatenatingReader [file name]"); - System.exit(1); - } - - ConcatenatingReader reader = new ConcatenatingReader(new BufferedReader(new FileReader(args[0]))); - OutputStreamWriter writer = new OutputStreamWriter(System.out); - char[] buf = new char[8192]; - boolean done = false; - while (!done && reader.ready()) { - int numRead = reader.read(buf, 0, buf.length); - writer.write(buf, 0, numRead); - if (numRead < buf.length) - done = true; - } - writer.flush(); - } - */ -} diff --git a/src/java/com/jogamp/gluegen/pcpp/PCPP.java b/src/java/com/jogamp/gluegen/pcpp/PCPP.java deleted file mode 100644 index c4af374..0000000 --- a/src/java/com/jogamp/gluegen/pcpp/PCPP.java +++ /dev/null @@ -1,1200 +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.jogamp.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.Level; - -import com.jogamp.gluegen.ASTLocusTag; -import com.jogamp.gluegen.ConstantDefinition; -import com.jogamp.gluegen.GenericCPP; -import com.jogamp.gluegen.GlueGenException; -import com.jogamp.gluegen.Logging; -import com.jogamp.gluegen.Logging.LoggerIf; - -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 implements GenericCPP { - - private final LoggerIf LOG; - - /** 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 final Map defineMap = new HashMap(128); - private final Map macroMap = new HashMap(128); - private final Set nonConstantDefines = new HashSet(128); - - /** List containing the #include paths as Strings */ - private final List includePaths; - private final List alreadyIncludedFiles = new ArrayList(); - - private ParseState state; - - private final boolean enableDebugPrint; - private final boolean enableCopyOutput2Stderr; - private final boolean enablePragmaOnce; - - public PCPP(final List includePaths, final boolean debug, final boolean copyOutput2Stderr, final boolean pragmaOnce) { - LOG = Logging.getLogger(PCPP.class.getPackage().getName(), PCPP.class.getSimpleName()); - this.includePaths = includePaths; - setOut(System.out); - enableDebugPrint = debug; - enableCopyOutput2Stderr = copyOutput2Stderr; - enablePragmaOnce = pragmaOnce; - } - - @Override - public void run(final Reader reader, final String filename) throws GlueGenException { - 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); - - final ParseState curState = new ParseState(tok, filename); - final ParseState oldState = state; - state = curState; - lineDirective(); - try { - parse(); - } catch (final Exception e) { - final StringBuilder buf = new StringBuilder("Preprocessor failed"); - LOG.log(Level.SEVERE, buf.toString(), e); - if( e instanceof GlueGenException ) { - throw (GlueGenException)e; - } else { - throw new GlueGenException("Preprocessor failed", - new ASTLocusTag(filename(), lineNumber(), -1, null), e); - } - } - state = oldState; - if (state != null) { - lineDirective(); - } - } - - @Override - public List getConstantDefinitions() throws GlueGenException { - return new ArrayList(); // NOP - } - - private void initTokenizer(final 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); - } - - @Override - public String findFile(final String filename) { - final String sep = File.separator; - for (final String inclPath : includePaths) { - final String fullPath = inclPath + sep + filename; - final File file = new File(fullPath); - if (file.exists()) { - return fullPath; - } - } - return null; - } - - @Override - public OutputStream out() { - return out; - } - - @Override - public void setOut(final OutputStream out) { - this.out = out; - writer = new PrintWriter(out); - } - - // State - static class ParseState { - - private final StreamTokenizer tok; - private final String filename; - private boolean startOfLine; - private boolean startOfFile; - - ParseState(final StreamTokenizer tok, final 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(final boolean val) { - startOfLine = val; - } - - boolean startOfFile() { - return startOfFile; - } - - void setStartOfFile(final boolean val) { - startOfFile = val; - } - - } - - private static class Macro { - - private final List values; - private final List params; - - Macro(final List params, final List 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(final boolean returnEOLs) throws IOException { - final 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(final int requiredToken) throws IOException { - final int nextTok = nextToken(); - if (nextTok != requiredToken) { - String msg = "Expected token '" + requiredToken + "' but got "; - switch (nextTok) { - case StreamTokenizer.TT_EOF: msg += ""; break; - case StreamTokenizer.TT_EOL: msg += ""; break; - default: msg += "'" + curTokenAsString() + "'"; break; - } - msg += " at file " + filename() + ", line " + lineNumber(); - throw new IOException(msg); - } - } - - - private String curTokenAsString() { - final 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 at file " + filename() + ", line " + lineNumber()); - } - final char c = (char) t; - if (c == '"' || c == '\'') { - final 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 { - final 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 (null != state) ? state.filename() : null; - } - - private int lineNumber() { - return (null != state) ? state.lineNumber() : -1; - } - - ///////////// - // 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(" "); - } - final String s = curTokenAsString(); - String newS = defineMap.get(s); - if (newS == null) { - newS = s; - } - - final Macro macro = macroMap.get(newS); - if(macro != null) { - newS = ""; - final List args = new ArrayList(); - while (nextToken() != StreamTokenizer.TT_EOL) { - final 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++) { - final String param = macro.params.get(j); - if(param.equals(value)) { - value = args.get(j); - break; - } - } - - if(ConstantDefinition.isIdentifier(value)) { - newS +=" "; - } - - newS += value; - - } - - } - - print(newS); - } - } - flush(); - } - - private void preprocessorDirective() throws IOException { - final 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 if (w.equals("pragma")){ - handlePragma(); - shouldPrint = false; - } else { - int line = -1; - try { - // try '# ""' case - line = Integer.parseInt(w); - final String filename = nextWordOrString(); - print("# " + line + " " + filename); - println(); - shouldPrint = false; - } catch (final NumberFormatException nfe) { - // 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 - final String name = nextWord(); - - debugPrint(true, "UNDEF " + name); - - // there shouldn't be any extra symbols after the name, but just in case... - final List values = new ArrayList(); - while (nextToken(true) != StreamTokenizer.TT_EOL) { - values.add(curTokenAsString()); - } - - if (enabled()) { - final String oldDef = defineMap.remove(name); - if (oldDef == null) { - LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, name), - "ignoring redundant \"#undef {0}\" - was not previously defined", - name); - } else { - // System.err.println("UNDEFINED: '" + name + "' (line " + lineNumber() + " file " + filename() + ")"); - } - nonConstantDefines.remove(name); - } else { - LOG.log(INFO, new ASTLocusTag(filename(), lineNumber(), -1, name), - "DISABLED UNDEFINE: ''{0}''", name); - } - } - - private void handleWarning() throws IOException { - final String msg = nextWordOrString(); - if (enabled()) { - LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null), msg); - } - } - - private void handleError() throws IOException, GlueGenException { - final String msg = nextWordOrString(); - if (enabled()) { - throw new GlueGenException(msg, new ASTLocusTag(filename(), lineNumber(), -1, null)); - } - } - - 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(); - - final 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) - final List values = new ArrayList(); - - if(macroDefinition) { - final int index = name.indexOf('('); - final 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()); - } - addDefine(name, macroDefinition, values); - } - - @Override - public void addDefine(final String name, final String value) { - final List values = new ArrayList(); - values.add(value); - addDefine(name, false, values); - } - - private void addDefine(final String name, final boolean nameIsMacro, List values) { - // 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 - final int sz = values.size(); - if (sz == 0) { - // definition to nothing, like "#define FOO" - final String value = ""; - final String oldDef = defineMap.put(name, value); - if (oldDef != null && !oldDef.equals(value)) { - LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null), - "\"{0}\" redefined from \"{1}\" to \"\"", 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.err.println("//---DEFINED: " + name + "to \"\""); - } else if (sz == 1) { - // See whether the value is a constant - final String value = values.get(0); - - if (ConstantDefinition.isNumber(value)) { - // Value is numeric constant like "#define FOO 5". - // Put it in the #define map - final String oldDef = defineMap.put(name, value); - if (oldDef != null && !oldDef.equals(value)) { - LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null), - "\"{0}\" redefined from \"{1}\" to \"{2}\"", name, oldDef, value); - } - debugPrint(true, "DEFINE " + name + " ["+oldDef+" ] -> "+value + " CONST"); - //System.err.println("//---DEFINED: " + name + " to \"" + value + "\""); - } else { - // Value is a symbolic constant like "#define FOO BAR". - // Try to look up the symbol's value - final String newValue = resolveDefine(value, true); - debugPrint(true, "DEFINE " + name + " -> "+value + " -> <" + newValue + "> SYMB"); - 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 - final boolean valueIsMacro = newValue.contains("("); - if(valueIsMacro) { - // parser can't dig this currently - emitDefine = false; - } else { - values.set(0, newValue); - } - } else { - // Still perform textual replacement - defineMap.put(name, value); - nonConstantDefines.add(name); - emitDefine = false; - } - } - - } else if (nameIsMacro) { - // list parameters - final List params = new ArrayList(); - for (int i = 1; i < values.size(); i++) { - final 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); - } - } - - final Macro macro = new Macro(params, values); - final Macro oldDef = macroMap.put(name, macro); - if (oldDef != null) { - LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null), - "\"{0}\" redefined from \"{1}\" to \"{2}\"", 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 (final String value : values) { - if(ConstantDefinition.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; - final 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() + "\"" + - " at file \"" + filename() + ", line " + lineNumber() ); - } - defineMap.put(name, val.toString()); - nonConstantDefines.add(name); - - }else{ // constant expression -> pass through - - final StringBuilder sb = new StringBuilder(); - for (final String v : values) { - sb.append(v); - } - final String value = sb.toString(); - - final String oldDef = defineMap.put(name, value); - if (oldDef != null && !oldDef.equals(value)) { - LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null), - "\"{0}\" redefined from \"{1}\" to \"{2}\"", name, oldDef, value); - } - debugPrint(true, "DEFINE " + name + " ["+oldDef+" ] -> "+value + " CONST"); -// System.err.println("#define " + name +" "+value + " CONST EXPRESSION"); - } - - } - - if (emitDefine) { - // Print name and value - print("# define "); - print(name); - print(" "); - for (final String v : values) { - print(v); - } - println(); - } - - } // end if (enabled()) - - //System.err.println("OUT HANDLE_DEFINE: " + name); - } - - private String resolveDefine(final String word, final 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 - * - * condition - the actual if-elif condition - * whole-block - the whole if-else-endif block - * inside-block - the inner block between if-elif-else-endif - * - * Outside - reflects the state at entering the whole-block - * Condition - reflects the state of the condition - * Inside - reflects the state within the inside-block - */ - - /** - * @param isIfdef if true, we're processing #ifdef; if false, we're - * processing #ifndef. - */ - private void handleIfdef(final boolean isIfdef) throws IOException { - // Next token is the name of the #ifdef - final String symbolName = nextWord(); - - final boolean enabledOutside = enabled(); - final boolean symbolIsDefined = defineMap.get(symbolName) != null; - - debugPrint(false, (isIfdef ? "IFDEF " : "IFNDEF ") + symbolName + ", enabledOutside " + enabledOutside + ", isDefined " + symbolIsDefined + ", file \"" + filename() + " line " + lineNumber()); - - final boolean enabledNow = enabled() && symbolIsDefined == isIfdef ; - pushEnableBit( enabledNow ) ; // StateCondition - pushEnableBit( enabledNow ) ; // StateInside - } - - /** Handles #else directives */ - private void handleElse() throws IOException { - popEnableBit(); // Inside - final boolean enabledCondition = enabled(); - popEnableBit(); // Condition - final boolean enabledOutside = enabled(); - - debugPrint(false, "ELSE, enabledOutside " + enabledOutside + ", file \"" + filename() + " line " + lineNumber()); - pushEnableBit(enabledOutside && !enabledCondition); // Condition - don't care - pushEnableBit(enabledOutside && !enabledCondition); // Inside - } - - private void handleEndif() { - popEnableBit(); // Inside - popEnableBit(); // Condition - final boolean enabledOutside = enabled(); - - // print the endif if we were enabled prior to popEnableBit() (sending - // false to debugPrint means "print regardless of current enabled() state). - debugPrint(false, "ENDIF, enabledOutside " + enabledOutside); - } - - /** - * @param isIf if true, we're processing #if; if false, we're - * processing #elif. - */ - private void handleIf(final boolean isIf) throws IOException { - boolean enabledCondition = false; - boolean enabledOutside; - - if (!isIf) { - popEnableBit(); // Inside - enabledCondition = enabled(); - popEnableBit(); // Condition - } - enabledOutside = enabled(); - - final boolean defineEvaluatedToTrue = handleIfRecursive(true); - - debugPrint(false, (isIf ? "IF" : "ELIF") + ", enabledOutside " + enabledOutside + ", eval " + defineEvaluatedToTrue + ", file \"" + filename() + " line " + lineNumber()); - - boolean enabledNow; - - if(isIf) { - enabledNow = enabledOutside && defineEvaluatedToTrue ; - pushEnableBit( enabledNow ) ; // Condition - pushEnableBit( enabledNow ) ; // Inside - } else { - enabledNow = enabledOutside && !enabledCondition && defineEvaluatedToTrue ; - pushEnableBit( enabledCondition || enabledNow ) ; // Condition - pushEnableBit( enabledNow ) ; // Inside - } - } - - //static int tmp = -1; - - /** - * This method is called recursively to process nested sub-expressions such as: - *
    -     *   #if !defined(OPENSTEP) && !(defined(NeXT) || !defined(NeXT_PDO))
    -     *
    - * - * @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(final boolean greedy) throws IOException { - //System.err.println("IN HANDLE_IF_RECURSIVE (" + ++tmp + ", greedy = " + greedy + ")"); System.err.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.err.println("-- READ: [" + (tok == StreamTokenizer.TT_EOL ? "" :curTokenAsString()) + "]"); - switch (tok) { - case '(': - ++openParens; - //System.err.println("OPEN PARENS = " + openParens); - ifValue = ifValue && handleIfRecursive(true); - break; - case ')': - --openParens; - //System.err.println("OPEN PARENS = " + openParens); - break; - case '!': - { - //System.err.println("HANDLE_IF_RECURSIVE HANDLING !"); - final boolean rhs = handleIfRecursive(false); - ifValue = !rhs; - //System.err.println("HANDLE_IF_RECURSIVE HANDLED OUT !, RHS = " + rhs); - } - break; - case '&': - { - nextRequiredToken('&'); - //System.err.println("HANDLE_IF_RECURSIVE HANDLING &&, LHS = " + ifValue); - final boolean rhs = handleIfRecursive(true); - //System.err.println("HANDLE_IF_RECURSIVE HANDLED &&, RHS = " + rhs); - ifValue = ifValue && rhs; - } - break; - case '|': - { - nextRequiredToken('|'); - //System.err.println("HANDLE_IF_RECURSIVE HANDLING ||, LHS = " + ifValue); - final boolean rhs = handleIfRecursive(true); - //System.err.println("HANDLE_IF_RECURSIVE HANDLED ||, RHS = " + rhs); - ifValue = ifValue || rhs; - } - break; - case '>': - { - // NOTE: we don't handle expressions like this properly - final boolean rhs = handleIfRecursive(true); - ifValue = false; - } - break; - case '<': - { - // NOTE: we don't handle expressions like this properly - final boolean rhs = handleIfRecursive(true); - ifValue = false; - } - break; - case '*': - { - // NOTE: we don't handle expressions like this properly - final boolean rhs = handleIfRecursive(false); - ifValue = false; - } - break; - case '+': - { - // NOTE: we don't handle expressions like this properly - final boolean rhs = handleIfRecursive(false); - ifValue = false; - } - break; - case '-': - { - // NOTE: we don't handle expressions like this properly - final boolean rhs = handleIfRecursive(false); - ifValue = false; - } - break; - case '=': - { - // NOTE: we don't handle expressions like this properly - final boolean rhs = handleIfRecursive(true); - ifValue = false; - } - break; - case StreamTokenizer.TT_WORD: - { - final String word = curTokenAsString(); - if (word.equals("defined")) { - // Handle things like #if defined(SOMESYMBOL) - nextRequiredToken('('); - final String symbol = nextWord(); - final boolean isDefined = defineMap.get(symbol) != null; - //System.err.println("HANDLE_IF_RECURSIVE HANDLING defined(" + symbol + ") = " + isDefined); - ifValue = ifValue && isDefined; - nextRequiredToken(')'); - } else { - // Handle things like #if SOME_SYMBOL. - final 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 (final NumberFormatException nfe1) { - try { - // ok, it's not a valid decimal value, try hex/octal value - return Long.parseLong(word) != 0; - } catch (final NumberFormatException nfe2) { - // ok, it's not a valid hex/octal value, try boolean last - return Boolean.valueOf(word).booleanValue(); - } - } - } - } - } // end case TT_WORD - break; - case StreamTokenizer.TT_EOL: - //System.err.println("HANDLE_IF_RECURSIVE HIT !"); - 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.err.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.err.println("OUT HANDLE_IF_RECURSIVE (" + tmp-- + ", returning " + ifValue + ")"); - //System.err.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 - final StringBuilder buf = new StringBuilder(); - while ((t = nextToken()) != '>' && (t != StreamTokenizer.TT_EOF)) { - buf.append(curTokenAsString()); - } - if (t == StreamTokenizer.TT_EOF) { - LOG.warning(new ASTLocusTag(filename(), lineNumber(), -1, null), - "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 - final String fullname = findFile(filename); - //System.err.println("ACTIVE BLOCK, LOADING " + filename); - if (fullname == null) { - throw new RuntimeException("Can't find #include file \"" + filename + "\" at file " + filename() + ", line " + lineNumber()); - } - if ((!enablePragmaOnce || !alreadyIncludedFiles.contains(fullname))) { - // Process this file in-line - final Reader reader = new BufferedReader(new FileReader(fullname)); - run(reader, fullname); - } else { - //System.err.println("INACTIVE BLOCK, SKIPPING " + filename); - } - } else { - //System.err.println("INACTIVE BLOCK, SKIPPING " + filename); - } - } - - ///////////////////////////////////// - // Handling of #pragma directives // - ///////////////////////////////////// - - private void handlePragma() throws IOException { - final String msg = nextWordOrString(); - if (enablePragmaOnce && msg.equals("once")) { - alreadyIncludedFiles.add(filename()); - } - } - - //////////// - // Output // - //////////// - - private OutputStream out; - private PrintWriter writer; - private final List enabledBits = new ArrayList(); - - private static int debugPrintIndentLevel = 0; - - private void debugPrint(final boolean onlyPrintIfEnabled, final String msg) { - if (!enableDebugPrint) { - return; - } - - if (!onlyPrintIfEnabled || (onlyPrintIfEnabled && enabled())) { - for (int i = debugPrintIndentLevel; --i > 0;) { - System.err.print(" "); - } - System.err.println("STATE: " + msg + " (line " + lineNumber() + " file " + filename() + ")"); - System.err.flush(); - } - } - - private void pushEnableBit(final boolean enabled) { - enabledBits.add(enabled); - ++debugPrintIndentLevel; - debugPrint(false, "PUSH_ENABLED, NOW: " + enabled()); - } - - private void popEnableBit() { - if (enabledBits.isEmpty()) { - throw new RuntimeException("mismatched #ifdef/endif pairs at file " + filename() + ", line " + lineNumber()); - } - 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(final String s) { - if (enabled()) { - writer.print(s); - if (enableCopyOutput2Stderr) { - System.err.print(s); - System.err.flush(); - return; - } - } - } - - private void print(final char c) { - if (enabled()) { - writer.print(c); - if (enableCopyOutput2Stderr) { - System.err.print(c); - System.err.flush(); - return; - } - } - } - - private void println() { - if (enabled()) { - writer.println(); - if (enableCopyOutput2Stderr) { - System.err.println(); - System.err.flush(); - return; - } - } - } - - private void printToken() { - print(curTokenAsString()); - } - - private void flush() { - if (enabled()) { - writer.flush(); - if (enableCopyOutput2Stderr) { - System.err.flush(); - return; - } - } - } - - private void lineDirective() { - print("# " + lineNumber() + " \"" + filename() + "\""); - println(); - } - - private static void usage() { - System.err.println("Usage: java PCPP [filename | -]"); - System.err.println("Minimal pseudo-C-preprocessor."); - System.err.println("Output goes to standard output. Standard input can be used as input"); - System.err.println("by passing '-' as the argument."); - System.err.println(" --debug enables debug mode"); - System.err.println(" --enablePragmaOnce enables pragma once management"); - System.exit(1); - } - - public static void main(final String[] args) throws IOException { - Reader reader = null; - String filename = null; - boolean debug = false; - boolean enablePragmaOnce = false; - - if (args.length == 0) { - usage(); - } - - final List includePaths = new ArrayList(); - for (int i = 0; i < args.length; i++) { - if (i < args.length - 1) { - final String arg = args[i]; - if (arg.startsWith("-I")) { - final 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 if (arg.equals("--enablePragmaOnce")) { - enablePragmaOnce = true; - } else { - usage(); - } - } else { - final 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, debug, enablePragmaOnce).run(reader, filename); - } - -} diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/TestJCPP.java b/src/junit/com/jogamp/gluegen/test/junit/generation/TestJCPP.java new file mode 100644 index 0000000..61cb01a --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/TestJCPP.java @@ -0,0 +1,132 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.gluegen.test.junit.generation; + +import com.jogamp.common.os.AndroidVersion; +import com.jogamp.gluegen.jcpp.JCPP; +import com.jogamp.junit.util.SingletonJunitCase; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.Collections; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * serves mainly as entry point for debugging purposes. + * @author Sven Gothel, Michael Bien + */ +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestJCPP extends SingletonJunitCase { + + @BeforeClass + public static void init() { + if(AndroidVersion.isAvailable) { + // JCPP is n/a on Android - GlueGen Runtime only + setTestSupported(false); + } + } + + @Test + public void pcppMacroDefinitionTestWithoutPragmaOnce() throws FileNotFoundException, IOException { + pcppMacroDefinitionTest(false); + } + + @Test + public void pcppMacroDefinitionTestWithPragmaOnce() throws FileNotFoundException, IOException { + pcppMacroDefinitionTest(true); + } + + public void pcppMacroDefinitionTest(final boolean pragmaOnce) throws FileNotFoundException, IOException { + final String folderpath = BuildEnvironment.gluegenRoot + "/src/junit/com/jogamp/gluegen/test/junit/generation"; + final JCPP pp = new JCPP(Collections.singletonList(folderpath), false, false, pragmaOnce); + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + pp.setOut(output); + + final String filename = "cpptest.h"; + final String filepath = folderpath + "/" + filename ; + pp.run(new BufferedReader(new FileReader(filepath)), filename); + + final String expected = "#line 1 \"cpptest.h\" 1"+ + ""+ + "cl_char GOOD_A;"+ + "int GOOD_B;"+ + "int GOOD_C;"+ + ""+ + " int TEST_D_GOOD;"+ + ""+ + "/***"+ + " ** STD API file .."+ + " */"+ + ""+ + "int GOOD_F_1;"+ + "int GOOD_F_2;"+ + ""+ + "int GOOD_G;"+ + "#line 1\""+folderpath+"/cpptest-included.h\" 1"+ + "" + ; + + + output.flush(); + final String result = output.toString(); + output.close(); + + System.err.println("Expected: "); + System.err.println("-------------------------------"); + System.err.println(killWhitespace(expected)); + System.err.println("-------------------------------"); + System.err.println(); + System.err.println("Result: "); + System.err.println("-------------------------------"); + System.err.println(killWhitespace(result)); + System.err.println("-------------------------------"); + System.err.println(); + + assertEquals(killWhitespace(expected), killWhitespace(result)); + + } + + private String killWhitespace(final String a) { + return a.replaceAll("\\p{javaWhitespace}+", ""); + } + + public static void main(final String args[]) throws IOException { + final String tstname = TestJCPP.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } +} diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/TestPCPP.java b/src/junit/com/jogamp/gluegen/test/junit/generation/TestPCPP.java deleted file mode 100644 index d2209e4..0000000 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/TestPCPP.java +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Copyright 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions 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. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.gluegen.test.junit.generation; - -import com.jogamp.common.os.AndroidVersion; -import com.jogamp.gluegen.pcpp.PCPP; -import com.jogamp.junit.util.SingletonJunitCase; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.Collections; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * serves mainly as entry point for debugging purposes. - * @author Sven Gothel, Michael Bien - */ -import org.junit.FixMethodOrder; -import org.junit.runners.MethodSorters; - -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestPCPP extends SingletonJunitCase { - - @BeforeClass - public static void init() { - if(AndroidVersion.isAvailable) { - // PCPP is n/a on Android - GlueGen Runtime only - setTestSupported(false); - } - } - - @Test - public void pcppMacroDefinitionTestWithoutPragmaOnce() throws FileNotFoundException, IOException { - pcppMacroDefinitionTest(false); - } - - @Test - public void pcppMacroDefinitionTestWithPragmaOnce() throws FileNotFoundException, IOException { - pcppMacroDefinitionTest(true); - } - - public void pcppMacroDefinitionTest(final boolean pragmaOnce) throws FileNotFoundException, IOException { - final String folderpath = BuildEnvironment.gluegenRoot + "/src/junit/com/jogamp/gluegen/test/junit/generation"; - final PCPP pp = new PCPP(Collections.singletonList(folderpath), false, false, pragmaOnce); - final ByteArrayOutputStream output = new ByteArrayOutputStream(); - pp.setOut(output); - - final String filename = "pcpptest.h"; - final String filepath = folderpath + "/" + filename ; - pp.run(new BufferedReader(new FileReader(filepath)), filename); - - final String expected = "# 1 \"pcpptest.h\""+ - "# define CL_SCHAR_MIN (-127-1)"+ - "# define __YES__ 1"+ - "# 16 \"pcpptest.h\""+ - "# 26 \"pcpptest.h\""+ - "# 36 \"pcpptest.h\""+ - " cl_char GOOD_A;"+ - " int GOOD_B;"+ - " int GOOD_C;"+ - "# 40 \"pcpptest.h\""+ - "#54\"pcpptest.h\""+ - " int TEST_D_GOOD;"+ - "#60\"pcpptest.h\""+ - "#70\"pcpptest.h\""+ - "#77\"pcpptest.h\""+ - "#105\"pcpptest.h\""+ - "#123\"pcpptest.h\""+ - " int GOOD_F_1;"+ - " int GOOD_F_2;"+ - "#126\"pcpptest.h\""+ - " int GOOD_G;"+ - "#128\"pcpptest.h\""+ - "#130\"pcpptest.h\""+ - "#134\"pcpptest.h\""+ - "#1\""+folderpath+"/pcpptest-included.h\""+ - "# define EXAMPLE 42"+ - "#134\"pcpptest.h\""+ - (!pragmaOnce ? - ( - "#1\""+folderpath+"/pcpptest-included.h\""+ - "# define EXAMPLE 42"+ - "#135\"pcpptest.h\"" - ): - "" - )+ - "#137\"pcpptest.h\""+ - "#139\"pcpptest.h\"" - ; - - - output.flush(); - final String result = output.toString(); - output.close(); - - System.err.println("Expected: "); - System.err.println("-------------------------------"); - System.err.println(killWhitespace(expected)); - System.err.println("-------------------------------"); - System.err.println(); - System.err.println("Result: "); - System.err.println("-------------------------------"); - System.err.println(killWhitespace(result)); - System.err.println("-------------------------------"); - System.err.println(); - - assertEquals(killWhitespace(expected), killWhitespace(result)); - - } - - private String killWhitespace(final String a) { - return a.replaceAll("\\p{javaWhitespace}+", ""); - } - - public static void main(final String args[]) throws IOException { - final String tstname = TestPCPP.class.getName(); - org.junit.runner.JUnitCore.main(tstname); - } -} diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/cpptest-included.h b/src/junit/com/jogamp/gluegen/test/junit/generation/cpptest-included.h new file mode 100644 index 0000000..8dbe022 --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/cpptest-included.h @@ -0,0 +1,2 @@ +#pragma once +#define EXAMPLE 42 \ No newline at end of file diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/cpptest.h b/src/junit/com/jogamp/gluegen/test/junit/generation/cpptest.h new file mode 100644 index 0000000..5cda9a5 --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/cpptest.h @@ -0,0 +1,138 @@ + +#define CL_SCHAR_MIN (-127-1) + +#define __YES__ 1 + +#if defined( __YES__ ) + #define TEST_A(_x) GOOD_A +#elif defined( _WIN32) && (_MSC_VER) + #define TEST_A(_x) ERR_A_1 +#elif defined( __unix__) || ( __sun__ ) + #define TEST_A(_x) ERR_A_2 +#else + #define TEST_A(_x) ERR_A_3 +#endif + +#if defined( __NO__ ) + #define TEST_B ERR_B_1 +#elif defined( __YES__) + #define TEST_B GOOD_B +#elif defined( __unix__) || ( __sun__ ) + #define TEST_B ERR_B_2 +#else + #define TEST_B ERR_B_3 +#endif + +#if defined( __NO__ ) + #define TEST_C ERR_C_1 +#elif defined( __NO__ ) + #define TEST_C ERR_C_2 +#elif defined( __unix__) || ( __sun__ ) + #define TEST_C ERR_C_3 +#else + #define TEST_C GOOD_C +#endif + +cl_char TEST_A(2); +int TEST_B; +int TEST_C; + +#ifndef __NO__ + #ifdef __YES__ + #ifdef CGDLL_EXPORTS + #define ERR_D_1 + #elif defined (CG_LIB) + #define ERR_D_2 + #else + #define GOOD_D + #endif + #else + #define ERR_D_3 + #endif +#endif + +#ifdef GOOD_D + int TEST_D_GOOD; +#elif + int TEST_D_ERROR; +#endif + +#if (defined(__NO__) && defined(__NOPE__)) + #define TEST_E_VAL ((long) 0x7FFFFFFFFFFFFFFFLL) +#else + #define TEST_E_VAL ((long) 0x7FFFFFFFFFFFFFFFLL) +#endif + +/*** + ** STD API file .. + */ + +#ifndef __test_h_ +#define __test_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined( __NANA__ ) + #if defined( __MINGW64__ ) + #include + #elif defined( __NONO__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) + #include + #else + #include + #endif +#else + #if defined( __MINGW64__ ) + #include + #elif defined( __NONO__) + #include + #else + #define TEST_F_VAL1 GOOD_F_1 + #endif + #if defined( __GNUC__ ) + #include + #else + #define TEST_F_VAL2 GOOD_F_2 + #endif +#endif + +#if defined( __YES__ ) + #if defined( __NONO__) + #include + #elif defined( __YES__) + #define TEST_G_VAL GOOD_G + #else + #include + #endif +#else + #if defined( __MINGW64__ ) + #include + #elif defined( __NONO__) + #include + #else + #include + #endif +#endif + +int TEST_F_VAL1; +int TEST_F_VAL2; + +int TEST_G_VAL; + +#warning "Test warning with quotes - they must have quotes" + +#ifdef __cplusplus +} +#endif + +#include +#include + +#endif /* __test_h_ */ + diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/pcpptest-included.h b/src/junit/com/jogamp/gluegen/test/junit/generation/pcpptest-included.h deleted file mode 100644 index 8dbe022..0000000 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/pcpptest-included.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#define EXAMPLE 42 \ No newline at end of file diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/pcpptest.h b/src/junit/com/jogamp/gluegen/test/junit/generation/pcpptest.h deleted file mode 100644 index 31b80c3..0000000 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/pcpptest.h +++ /dev/null @@ -1,138 +0,0 @@ - -#define CL_SCHAR_MIN (-127-1) - -#define __YES__ 1 - -#if defined( __YES__ ) - #define TEST_A(_x) GOOD_A -#elif defined( _WIN32) && (_MSC_VER) - #define TEST_A(_x) ERR_A_1 -#elif defined( __unix__) || ( __sun__ ) - #define TEST_A(_x) ERR_A_2 -#else - #define TEST_A(_x) ERR_A_3 -#endif - -#if defined( __NO__ ) - #define TEST_B ERR_B_1 -#elif defined( __YES__) - #define TEST_B GOOD_B -#elif defined( __unix__) || ( __sun__ ) - #define TEST_B ERR_B_2 -#else - #define TEST_B ERR_B_3 -#endif - -#if defined( __NO__ ) - #define TEST_C ERR_C_1 -#elif defined( __NO__ ) - #define TEST_C ERR_C_2 -#elif defined( __unix__) || ( __sun__ ) - #define TEST_C ERR_C_3 -#else - #define TEST_C GOOD_C -#endif - -cl_char TEST_A(2); -int TEST_B; -int TEST_C; - -#ifndef __NO__ - #ifdef __YES__ - #ifdef CGDLL_EXPORTS - #define ERR_D_1 - #elif defined (CG_LIB) - #define ERR_D_2 - #else - #define GOOD_D - #endif - #else - #define ERR_D_3 - #endif -#endif - -#ifdef GOOD_D - int TEST_D_GOOD; -#elif - int TEST_D_ERROR; -#endif - -#if (defined(__NO__) && defined(__NOPE__)) - #define TEST_E_VAL ((long) 0x7FFFFFFFFFFFFFFFLL) -#else - #define TEST_E_VAL ((long) 0x7FFFFFFFFFFFFFFFLL) -#endif - -/*** - ** STD API file .. - */ - -#ifndef __test_h_ -#define __test_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined( __NANA__ ) - #if defined( __MINGW64__ ) - #include - #elif defined( __NONO__ ) - #include - #else - #include - #endif - #if defined( __GNUC__ ) - #include - #else - #include - #endif -#else - #if defined( __MINGW64__ ) - #include - #elif defined( __NONO__) - #include - #else - #define TEST_F_VAL1 GOOD_F_1 - #endif - #if defined( __GNUC__ ) - #include - #else - #define TEST_F_VAL2 GOOD_F_2 - #endif -#endif - -#if defined( __YES__ ) - #if defined( __NONO__) - #include - #elif defined( __YES__) - #define TEST_G_VAL GOOD_G - #else - #include - #endif -#else - #if defined( __MINGW64__ ) - #include - #elif defined( __NONO__) - #include - #else - #include - #endif -#endif - -int TEST_F_VAL1; -int TEST_F_VAL2; - -int TEST_G_VAL; - -#warning "Test warning with quotes - they must have quotes" - -#ifdef __cplusplus -} -#endif - -#include -#include - -#endif /* __test_h_ */ - -- cgit v1.2.3