summaryrefslogtreecommitdiffstats
path: root/src/net/java/games/gluegen
diff options
context:
space:
mode:
authordjp <[email protected]>2003-06-08 19:27:01 +0000
committerdjp <[email protected]>2003-06-08 19:27:01 +0000
commitd49fd968963909f181423eae46c613189468fac3 (patch)
treeb231329e6b65fd54aa24b3bcc0a3ecc623daec61 /src/net/java/games/gluegen
parent9c8fb046dee5d832bea3f36dcbd43285054f49a0 (diff)
Initial revision
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@3 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/net/java/games/gluegen')
-rw-r--r--src/net/java/games/gluegen/ArrayTypes.java107
-rw-r--r--src/net/java/games/gluegen/CMethodBindingEmitter.java1141
-rw-r--r--src/net/java/games/gluegen/CMethodBindingImplEmitter.java99
-rw-r--r--src/net/java/games/gluegen/CodeGenUtils.java148
-rw-r--r--src/net/java/games/gluegen/CommentEmitter.java52
-rw-r--r--src/net/java/games/gluegen/DebugEmitter.java102
-rw-r--r--src/net/java/games/gluegen/FunctionEmitter.java199
-rw-r--r--src/net/java/games/gluegen/GlueEmitter.java99
-rw-r--r--src/net/java/games/gluegen/GlueEmitterControls.java49
-rw-r--r--src/net/java/games/gluegen/GlueGen.java299
-rw-r--r--src/net/java/games/gluegen/JavaConfiguration.java1051
-rw-r--r--src/net/java/games/gluegen/JavaEmitter.java1246
-rw-r--r--src/net/java/games/gluegen/JavaMethodBindingEmitter.java260
-rw-r--r--src/net/java/games/gluegen/JavaMethodBindingImplEmitter.java220
-rw-r--r--src/net/java/games/gluegen/JavaType.java277
-rw-r--r--src/net/java/games/gluegen/MethodBinding.java340
-rw-r--r--src/net/java/games/gluegen/ReferencedStructs.java61
-rw-r--r--src/net/java/games/gluegen/StructLayout.java138
-rw-r--r--src/net/java/games/gluegen/TypeInfo.java61
-rw-r--r--src/net/java/games/gluegen/cgram/CSymbolTable.java132
-rw-r--r--src/net/java/games/gluegen/cgram/CToken.java32
-rw-r--r--src/net/java/games/gluegen/cgram/Define.java56
-rw-r--r--src/net/java/games/gluegen/cgram/GnuCEmitter.g1145
-rw-r--r--src/net/java/games/gluegen/cgram/GnuCParser.g864
-rw-r--r--src/net/java/games/gluegen/cgram/GnuCTreeParser.g852
-rw-r--r--src/net/java/games/gluegen/cgram/HeaderParser.g715
-rw-r--r--src/net/java/games/gluegen/cgram/LineObject.java126
-rw-r--r--src/net/java/games/gluegen/cgram/PreprocessorInfoChannel.java73
-rw-r--r--src/net/java/games/gluegen/cgram/StdCParser.g1375
-rw-r--r--src/net/java/games/gluegen/cgram/TNode.java433
-rw-r--r--src/net/java/games/gluegen/cgram/TNodeFactory.java33
-rw-r--r--src/net/java/games/gluegen/cgram/types/ArrayType.java131
-rw-r--r--src/net/java/games/gluegen/cgram/types/BitType.java87
-rw-r--r--src/net/java/games/gluegen/cgram/types/CVAttributes.java48
-rw-r--r--src/net/java/games/gluegen/cgram/types/CompoundType.java205
-rw-r--r--src/net/java/games/gluegen/cgram/types/CompoundTypeKind.java50
-rw-r--r--src/net/java/games/gluegen/cgram/types/DoubleType.java64
-rw-r--r--src/net/java/games/gluegen/cgram/types/EnumType.java147
-rw-r--r--src/net/java/games/gluegen/cgram/types/Field.java96
-rw-r--r--src/net/java/games/gluegen/cgram/types/FloatType.java64
-rw-r--r--src/net/java/games/gluegen/cgram/types/FunctionSymbol.java112
-rw-r--r--src/net/java/games/gluegen/cgram/types/FunctionType.java159
-rw-r--r--src/net/java/games/gluegen/cgram/types/IntType.java82
-rw-r--r--src/net/java/games/gluegen/cgram/types/MachineDescription.java78
-rw-r--r--src/net/java/games/gluegen/cgram/types/MachineDescription32Bit.java46
-rw-r--r--src/net/java/games/gluegen/cgram/types/PointerType.java136
-rw-r--r--src/net/java/games/gluegen/cgram/types/PrimitiveType.java50
-rw-r--r--src/net/java/games/gluegen/cgram/types/Type.java242
-rw-r--r--src/net/java/games/gluegen/cgram/types/TypeDictionary.java169
-rw-r--r--src/net/java/games/gluegen/cgram/types/TypeVisitor.java44
-rw-r--r--src/net/java/games/gluegen/cgram/types/VoidType.java56
-rw-r--r--src/net/java/games/gluegen/opengl/BuildComposablePipeline.java498
-rw-r--r--src/net/java/games/gluegen/opengl/BuildStaticGLInfo.java258
-rw-r--r--src/net/java/games/gluegen/opengl/CGLPAWrapperEmitter.java201
-rw-r--r--src/net/java/games/gluegen/opengl/ConvertFromGL4Java.java91
-rw-r--r--src/net/java/games/gluegen/opengl/GLEmitter.java330
-rw-r--r--src/net/java/games/gluegen/opengl/JavaGLPAWrapperEmitter.java178
-rw-r--r--src/net/java/games/gluegen/pcpp/PCPP.java824
-rw-r--r--src/net/java/games/gluegen/runtime/BufferFactory.java50
-rw-r--r--src/net/java/games/gluegen/runtime/StructAccessor.java191
60 files changed, 16472 insertions, 0 deletions
diff --git a/src/net/java/games/gluegen/ArrayTypes.java b/src/net/java/games/gluegen/ArrayTypes.java
new file mode 100644
index 000000000..86867866a
--- /dev/null
+++ b/src/net/java/games/gluegen/ArrayTypes.java
@@ -0,0 +1,107 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+/**
+ * Convenience class containing the Class objects corresponding to arrays of
+ * various types (e.g., {@link #booleanArrayClass} is the Class of Java type
+ * "boolean[]").
+ */
+public class ArrayTypes {
+ /** Class for Java type string[] */
+ public static final Class stringArrayClass;
+ /** Class for Java type boolean[] */
+ public static final Class booleanArrayClass;
+ /** Class for Java type byte[] */
+ public static final Class byteArrayClass;
+ /** Class for Java type char[] */
+ public static final Class charArrayClass;
+ /** Class for Java type short[] */
+ public static final Class shortArrayClass;
+ /** Class for Java type int[] */
+ public static final Class intArrayClass;
+ /** Class for Java type long[] */
+ public static final Class longArrayClass;
+ /** Class for Java type float[] */
+ public static final Class floatArrayClass;
+ /** Class for Java type double[] */
+ public static final Class doubleArrayClass;
+
+ /** Class for Java type string[][] */
+ public static final Class stringArrayArrayClass;
+ /** Class for Java type boolean[][] */
+ public static final Class booleanArrayArrayClass;
+ /** Class for Java type byte[][] */
+ public static final Class byteArrayArrayClass;
+ /** Class for Java type char[][] */
+ public static final Class charArrayArrayClass;
+ /** Class for Java type short[][] */
+ public static final Class shortArrayArrayClass;
+ /** Class for Java type int[][] */
+ public static final Class intArrayArrayClass;
+ /** Class for Java type long[][] */
+ public static final Class longArrayArrayClass;
+ /** Class for Java type float[][] */
+ public static final Class floatArrayArrayClass;
+ /** Class for Java type double[][] */
+ public static final Class doubleArrayArrayClass;
+
+ static {
+ stringArrayClass = new String [0].getClass();
+ booleanArrayClass = new boolean[0].getClass();
+ byteArrayClass = new byte [0].getClass();
+ charArrayClass = new char [0].getClass();
+ shortArrayClass = new short [0].getClass();
+ intArrayClass = new int [0].getClass();
+ longArrayClass = new long [0].getClass();
+ floatArrayClass = new float [0].getClass();
+ doubleArrayClass = new double [0].getClass();
+
+ stringArrayArrayClass = new String [0][0].getClass();
+ booleanArrayArrayClass = new boolean[0][0].getClass();
+ byteArrayArrayClass = new byte [0][0].getClass();
+ charArrayArrayClass = new char [0][0].getClass();
+ shortArrayArrayClass = new short [0][0].getClass();
+ intArrayArrayClass = new int [0][0].getClass();
+ longArrayArrayClass = new long [0][0].getClass();
+ floatArrayArrayClass = new float [0][0].getClass();
+ doubleArrayArrayClass = new double [0][0].getClass();
+ }
+}
diff --git a/src/net/java/games/gluegen/CMethodBindingEmitter.java b/src/net/java/games/gluegen/CMethodBindingEmitter.java
new file mode 100644
index 000000000..45035f640
--- /dev/null
+++ b/src/net/java/games/gluegen/CMethodBindingEmitter.java
@@ -0,0 +1,1141 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.util.*;
+import java.io.*;
+import java.text.MessageFormat;
+
+import net.java.games.gluegen.cgram.types.*;
+
+/** Emits the C-side component of the Java<->C JNI binding. */
+public class CMethodBindingEmitter extends FunctionEmitter
+{
+ protected static final CommentEmitter defaultCommentEmitter =
+ new DefaultCommentEmitter();
+
+ private MethodBinding binding;
+
+ /** Name of the package in which the corresponding Java method resides.*/
+ private String packageName;
+
+ /** Name of the class in which the corresponding Java method resides.*/
+ private String className;
+
+ /**
+ * Whether or not the Java<->C JNI binding for this emitter's MethodBinding
+ * is overloaded.
+ */
+ private boolean isOverloadedBinding;
+
+ /**
+ * Whether or not the Java-side of the Java<->C JNI binding for this
+ * emitter's MethodBinding is static.
+ */
+ private boolean isJavaMethodStatic;
+
+ /**
+ * Optional List of Strings containing temporary C variables to declare.
+ */
+ private List/*<String>*/ temporaryCVariableDeclarations;
+
+ /**
+ * Optional List of Strings containing assignments to temporary C variables
+ * to make after the call is completed.
+ */
+ private List/*<String>*/ temporaryCVariableAssignments;
+
+ /**
+ * Capacity of the return value in the event that it is encapsulated in a
+ * java.nio.Buffer. Is ignored if binding.getJavaReturnType().isNIOBuffer()
+ * == false;
+ */
+ private MessageFormat returnValueCapacityExpression = null;
+
+ // Note: the VC++ 6.0 compiler emits hundreds of warnings when the
+ // (necessary) null-checking code is enabled. This appears to just
+ // be a compiler bug, but would be good to track down exactly why it
+ // is happening. When the null checking is enabled for just the
+ // GetPrimitiveArrayCritical calls, there are five warnings
+ // generated for several thousand new if tests added to the code.
+ // Which ones are the ones at fault? The line numbers for the
+ // warnings are incorrect.
+ private static final boolean EMIT_NULL_CHECKS = true;
+
+ /**
+ * Constructs an emitter for the specified binding, and sets a default
+ * comment emitter that will emit the signature of the C function that is
+ * being bound.
+ */
+ public CMethodBindingEmitter(MethodBinding binding,
+ boolean isOverloadedBinding,
+ String javaPackageName,
+ String javaClassName,
+ boolean isJavaMethodStatic,
+ PrintWriter output)
+ {
+ super(output);
+
+ assert(binding != null);
+ assert(javaClassName != null);
+ assert(javaPackageName != null);
+
+ this.binding = binding;
+ this.packageName = javaPackageName;
+ this.className = javaClassName;
+ this.isOverloadedBinding = isOverloadedBinding;
+ this.isJavaMethodStatic = isJavaMethodStatic;
+ setCommentEmitter(defaultCommentEmitter);
+ }
+
+ public final MethodBinding getBinding() { return binding; }
+
+ public String getName() {
+ return binding.getName();
+ }
+
+ /**
+ * Get the expression for the capacity of the returned java.nio.Buffer.
+ */
+ public final MessageFormat getReturnValueCapacityExpression()
+ {
+ return returnValueCapacityExpression;
+ }
+
+ /**
+ * If this function returns a void* encapsulated in a
+ * java.nio.Buffer, sets the expression for the capacity of the
+ * returned Buffer.
+ *
+ * @param expression a MessageFormat which, when applied to an array
+ * of type String[] that contains each of the arguments names of the
+ * Java-side binding, returns an expression that will (when compiled
+ * by a C compiler) evaluate to an integer-valued expression. The
+ * value of this expression is the capacity of the java.nio.Buffer
+ * returned from this method.
+ *
+ * @throws IllegalArgumentException if the <code>
+ * binding.getJavaReturnType().isNIOBuffer() == false
+ * </code>
+ */
+ public final void setReturnValueCapacityExpression(MessageFormat expression)
+ {
+ returnValueCapacityExpression = expression;
+
+ if (!binding.getJavaReturnType().isNIOBuffer())
+ {
+ throw new IllegalArgumentException(
+ "Cannot specify return value capacity for a method that does not " +
+ "return java.nio.Buffer: \"" + binding + "\"");
+ }
+ }
+
+ /**
+ * Sets up a List of Strings containing declarations for temporary C
+ * variables to be assigned to after the underlying function call. A
+ * null argument indicates that no manual declarations are to be made.
+ */
+ public final void setTemporaryCVariableDeclarations(List/*<String>*/ arg) {
+ temporaryCVariableDeclarations = arg;
+ }
+
+ /**
+ * Sets up a List of Strings containing assignments for temporary C
+ * variables which are made after the underlying function call. A
+ * null argument indicates that no manual assignments are to be made.
+ */
+ public final void setTemporaryCVariableAssignments(List/*<String>*/ arg) {
+ temporaryCVariableAssignments = arg;
+ }
+
+ /**
+ * Get the name of the class in which the corresponding Java method
+ * resides.
+ */
+ public String getJavaPackageName() { return packageName; }
+
+ /**
+ * Get the name of the package in which the corresponding Java method
+ * resides.
+ */
+ public String getJavaClassName() { return className; }
+
+ /**
+ * Is the Java<->C JNI binding for this emitter's MethodBinding one of
+ * several overloaded methods with the same name?
+ */
+ public final boolean getIsOverloadedBinding() { return isOverloadedBinding; }
+
+ /**
+ * Is the Java side of the Java<->C JNI binding for this emitter's
+ * MethodBinding a static method?.
+ */
+ public final boolean getIsJavaMethodStatic() { return isJavaMethodStatic; }
+
+ protected void emitReturnType(PrintWriter writer)
+ {
+ writer.print("JNIEXPORT ");
+ writer.print(binding.getJavaReturnType().jniTypeName());
+ writer.print(" JNICALL");
+ }
+
+ protected void emitName(PrintWriter writer)
+ {
+ writer.println(); // start name on new line
+ writer.print("Java_");
+ writer.print(jniMangle(getJavaPackageName()));
+ writer.print("_");
+ writer.print(jniMangle(getJavaClassName()));
+ writer.print("_");
+ if (isOverloadedBinding)
+ {
+ writer.print(jniMangle(binding));
+ //System.err.println("OVERLOADED MANGLING FOR " + binding.getName() +
+ // " = " + jniMangle(binding));
+ }
+ else
+ {
+ writer.print(jniMangle(binding.getName()));
+ //System.err.println(" NORMAL MANGLING FOR " + binding.getName() +
+ // " = " + jniMangle(binding.getName()));
+ }
+ }
+
+ protected int emitArguments(PrintWriter writer)
+ {
+ writer.print("JNIEnv *env, ");
+ int numEmitted = 1; // initially just the JNIEnv
+ if (isJavaMethodStatic && !binding.hasContainingType())
+ {
+ writer.print("jclass");
+ }
+ else
+ {
+ writer.print("jobject");
+ }
+ writer.print(" _unused");
+ ++numEmitted;
+
+ if (binding.hasContainingType())
+ {
+ // "this" argument always comes down in argument 0 as direct buffer
+ writer.print(", jobject " + JavaMethodBindingEmitter.javaThisArgumentName());
+ }
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType javaArgType = binding.getJavaArgumentType(i);
+ // Handle case where only param is void
+ if (javaArgType.isVoid()) {
+ // Make sure this is the only param to the method; if it isn't,
+ // there's something wrong with our parsing of the headers.
+ assert(binding.getNumArguments() == 1);
+ continue;
+ }
+ if (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+ continue;
+ }
+ writer.print(", ");
+ writer.print(javaArgType.jniTypeName());
+ writer.print(" ");
+ writer.print(binding.getArgumentName(i));
+ ++numEmitted;
+ }
+
+ return numEmitted;
+ }
+
+
+ protected void emitBody(PrintWriter writer)
+ {
+ writer.println(" {");
+ emitBodyVariableDeclarations(writer);
+ emitBodyUserVariableDeclarations(writer);
+ emitBodyVariablePreCallSetup(writer);
+ emitBodyCallCFunction(writer);
+ emitBodyUserVariableAssignments(writer);
+ emitBodyVariablePostCallCleanup(writer);
+ emitBodyReturnResult(writer);
+ writer.println("}");
+ writer.println();
+ }
+
+ protected void emitBodyVariableDeclarations(PrintWriter writer)
+ {
+ // Emit declarations for all pointer and String conversion variables
+ if (binding.hasContainingType()) {
+ emitPointerDeclaration(writer,
+ binding.getContainingType(),
+ binding.getContainingCType(),
+ CMethodBindingEmitter.cThisArgumentName());
+ }
+
+ boolean emittedDataCopyTemps = false;
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+ continue;
+ }
+
+ if (type.isArray() || type.isNIOBuffer()) {
+ String convName = pointerConversionArgumentName(i);
+ // handle array/buffer argument types
+ boolean needsDataCopy =
+ emitPointerDeclaration(writer,
+ binding.getJavaArgumentType(i),
+ binding.getCArgumentType(i),
+ convName);
+ if (needsDataCopy && !emittedDataCopyTemps) {
+ // emit loop counter and array length variables used during data
+ // copy
+ writer.println(" jobject _tmpObj;");
+ writer.println(" int _copyIndex;");
+ writer.println(" jsize _arrayLen"+convName+";");
+ emittedDataCopyTemps = true;
+ }
+ } else if (type.isString()) {
+ writer.print(" const char* _UTF8");
+ writer.print(binding.getArgumentName(i));
+ writer.println(" = NULL;");
+ }
+
+ }
+
+ // Emit declaration for return value if necessary
+ Type cReturnType = binding.getCReturnType();
+
+ JavaType javaReturnType = binding.getJavaReturnType();
+ String arrayResLength = "_array_res_length";
+ String arrayRes = "_array_res";
+ String capitalizedComponentType = null;
+ if (!cReturnType.isVoid()) {
+ writer.print(" ");
+ // Note we must respect const/volatile for return argument
+ writer.print(binding.getCSymbol().getReturnType().getName(true));
+ writer.println(" _res;");
+ if (javaReturnType.isArray()) {
+ writer.print(" int ");
+ writer.print(arrayResLength);
+ writer.println(";");
+
+ Class componentType = javaReturnType.getJavaClass().getComponentType();
+ if (componentType.isArray()) {
+ throw new RuntimeException("Multi-dimensional arrays not supported yet");
+ }
+
+ String javaTypeName = componentType.getName();
+ capitalizedComponentType =
+ "" + Character.toUpperCase(javaTypeName.charAt(0)) + javaTypeName.substring(1);
+ String javaArrayTypeName = "j" + javaTypeName + "Array";
+ writer.print(" ");
+ writer.print(javaArrayTypeName);
+ writer.print(" ");
+ writer.print(arrayRes);
+ writer.println(";");
+ }
+ }
+ }
+
+ /** Emits the user-defined C variable declarations from the
+ TemporaryCVariableDeclarations directive in the .cfg file. */
+ protected void emitBodyUserVariableDeclarations(PrintWriter writer) {
+ if (temporaryCVariableDeclarations != null) {
+ for (Iterator iter = temporaryCVariableDeclarations.iterator(); iter.hasNext(); ) {
+ String val = (String) iter.next();
+ writer.print(" ");
+ writer.println(val);
+ }
+ }
+ }
+
+ /**
+ * Code to init the variables that were declared in
+ * emitBodyVariableDeclarations(), PRIOR TO calling the actual C
+ * function.
+ */
+ protected void emitBodyVariablePreCallSetup(PrintWriter writer)
+ {
+ // Convert all Buffers to pointers first so we don't have to
+ // call ReleasePrimitiveArrayCritical for any arrays if any
+ // incoming buffers aren't direct
+ if (binding.hasContainingType()) {
+ emitPointerConversion(writer, binding,
+ binding.getContainingType(),
+ binding.getContainingCType(),
+ JavaMethodBindingEmitter.javaThisArgumentName(),
+ CMethodBindingEmitter.cThisArgumentName());
+ }
+
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+ continue;
+ }
+ if (type.isNIOBuffer()) {
+ emitPointerConversion(writer, binding, type,
+ binding.getCArgumentType(i),
+ binding.getArgumentName(i),
+ pointerConversionArgumentName(i));
+ }
+ }
+
+ // Convert all arrays to pointers, and get UTF-8 versions of jstring args
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType javaArgType = binding.getJavaArgumentType(i);
+
+ if (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+ continue;
+ }
+
+ if (javaArgType.isArray()) {
+
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(binding.getArgumentName(i));
+ writer.println(" != NULL) {");
+ }
+
+ writer.print(" ");
+ String convName = pointerConversionArgumentName(i);
+ writer.print(convName);
+ writer.print(" = (");
+ Type cArgType = binding.getCArgumentType(i);
+ String cArgTypeName = cArgType.getName();
+ if (javaArgType.isArray() &&
+ javaArgType.getJavaClass().getComponentType() == java.lang.String.class) {
+ // java-side type is String[]
+ cArgTypeName = "jstring *";
+ }
+ writer.print(cArgTypeName);
+ writer.print(") (*env)->GetPrimitiveArrayCritical(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.println(", NULL);");
+
+ // Handle the case where the array elements are of a type that needs a
+ // data copy operation to convert from the java memory model to the C
+ // memory model (e.g., int[][], String[], etc)
+ //
+ // FIXME: should factor out this whole block of code into a separate
+ // method for clarity and maintenance purposes
+ Class subArrayElementJavaType = javaArgType.getJavaClass().getComponentType();
+ boolean needsDataCopy =
+ subArrayElementJavaType.isArray() ||
+ subArrayElementJavaType == java.lang.String.class;
+ if (needsDataCopy)
+ {
+ if (cArgType.toString().indexOf("const") == -1) {
+ // FIXME: if the arg type is non-const, the sematics might be that
+ // the function modifies the argument -- we don't yet support
+ // this.
+ //
+ // Note: the check for "const" in the CVAttributes string isn't
+ // truly checking the constness of the target types at both
+ // pointer depths. However, it's a quick approximation, and quite
+ // often C code doesn't get the constness right anyhow.
+ throw new RuntimeException(
+ "Cannot copy data for ptr-to-ptr arg type \"" + cArgType +
+ "\": support for non-const ptr-to-ptr types not implemented.");
+ }
+
+ writer.println();
+ writer.println(" /* Copy contents of " + convName +
+ " into " + convName + "_copy */");
+
+ // get length of array being copied
+ String arrayLenName = "_arrayLen"+convName;
+ writer.print(" ");
+ writer.print(arrayLenName);
+ writer.print(" = (*env)->GetArrayLength(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.println(");");
+
+ // allocate an array to hold each element
+ if (cArgType.pointerDepth() != 2) {
+ throw new RuntimeException(
+ "Could not copy data for type \"" + cArgType +
+ "\"; copying only supported for types of the form " +
+ "ptr-to-ptr-to-primitive.");
+ }
+ PointerType cArgPtrType = cArgType.asPointer();
+ if (cArgPtrType == null) {
+ throw new RuntimeException(
+ "Could not copy data for type \"" + cArgType +
+ "\"; currently only pointer types supported.");
+ }
+ PointerType cArgElementType = cArgPtrType.getTargetType().asPointer();
+ emitMalloc(
+ writer,
+ convName+"_copy",
+ cArgElementType.getName(),
+ arrayLenName,
+ "Could not allocate buffer for copying data in argument \\\""+binding.getArgumentName(i)+"\\\"");
+
+ // process each element in the array
+ writer.println(" for (_copyIndex = 0; _copyIndex < "+arrayLenName+"; ++_copyIndex) {");
+
+ // get each array element
+ writer.println(" /* get each element of the array argument \"" + binding.getArgumentName(i) + "\" */");
+ String subArrayElementJNITypeString = jniType(subArrayElementJavaType);
+ writer.print(" _tmpObj = (");
+ writer.print(subArrayElementJNITypeString);
+ writer.print(") (*env)->GetObjectArrayElement(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.println(", _copyIndex);");
+
+ if (subArrayElementJNITypeString == "jstring")
+ {
+ writer.print(" ");
+ emitGetStringUTFChars(writer,
+ "(jstring) _tmpObj",
+ "(const char*)"+convName+"_copy[_copyIndex]");
+ }
+ else
+ {
+ // Question: do we always need to copy the sub-arrays, or just
+ // GetPrimitiveArrayCritical on each jobjectarray element and
+ // assign it to the appropriate elements at pointer depth 1?
+ // Probably depends on const-ness of the argument.
+ // Malloc enough space to hold a copy of each sub-array
+ writer.print(" ");
+ emitMalloc(
+ writer,
+ convName+"_copy[_copyIndex]",
+ cArgElementType.getTargetType().getName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !!
+ "(*env)->GetArrayLength(env, _tmpObj)",
+ "Could not allocate buffer during copying of data in argument \\\""+binding.getArgumentName(i)+"\\\"");
+ // FIXME: copy the data (use Get<type>ArrayRegion() calls)
+ if (true) throw new RuntimeException(
+ "Cannot yet handle type \"" + cArgType.getName() +
+ "\"; need to add support for copying ptr-to-ptr-to-primitiveType subarrays");
+
+
+ }
+ writer.println(" }");
+
+ writer.println();
+ } // end of data copy
+
+ if (EMIT_NULL_CHECKS) {
+ writer.println(" }");
+ }
+
+ } else if (javaArgType.isString()) {
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(binding.getArgumentName(i));
+ writer.println(" != NULL) {");
+ }
+
+ emitGetStringUTFChars(writer,
+ binding.getArgumentName(i),
+ "_UTF8" + binding.getArgumentName(i));
+
+ if (EMIT_NULL_CHECKS) {
+ writer.println(" }");
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Code to clean up any variables that were declared in
+ * emitBodyVariableDeclarations(), AFTER calling the actual C function.
+ */
+ protected void emitBodyVariablePostCallCleanup(PrintWriter writer)
+ {
+ // Release primitive arrays and temporary UTF8 strings if necessary
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType javaArgType = binding.getJavaArgumentType(i);
+ if (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+ continue;
+ }
+ if (javaArgType.isArray()) {
+ String convName = pointerConversionArgumentName(i);
+
+ // Release array
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(binding.getArgumentName(i));
+ writer.println(" != NULL) {");
+ }
+
+ // clean up the case where the array elements are of a type that needed
+ // a data copy operation to convert from the java memory model to the
+ // C memory model (e.g., int[][], String[], etc)
+ //
+ // FIXME: should factor out this whole block of code into a separate
+ // method for clarity and maintenance purposes
+ Class subArrayElementJavaType = javaArgType.getJavaClass().getComponentType();
+ boolean needsDataCopy =
+ subArrayElementJavaType.isArray() ||
+ subArrayElementJavaType == java.lang.String.class;
+ if (needsDataCopy)
+ {
+ Type cArgType = binding.getCArgumentType(i);
+ String cArgTypeName = cArgType.getName();
+
+ if (cArgType.toString().indexOf("const") == -1) {
+ // FIXME: handle any cleanup from treatment of non-const args,
+ // assuming they were treated differently in
+ // emitBodyVariablePreCallSetup() (see the similar section in that
+ // method for details).
+ throw new RuntimeException(
+ "Cannot clean up copied data for ptr-to-ptr arg type \"" + cArgType +
+ "\": support for cleaning up non-const ptr-to-ptr types not implemented.");
+ }
+
+ writer.println(" /* Clean up " + convName + "_copy */");
+ String arrayLenName = "_arrayLen" + convName;
+
+ // free each element
+ PointerType cArgPtrType = cArgType.asPointer();
+ if (cArgPtrType == null) {
+ throw new RuntimeException(
+ "Could not copy data for type \"" + cArgType +
+ "\"; currently only pointer types supported.");
+ }
+ PointerType cArgElementType = cArgPtrType.getTargetType().asPointer();
+
+ // process each element in the array
+ writer.println(" for (_copyIndex = 0; _copyIndex < " + arrayLenName +"; ++_copyIndex) {");
+
+ // get each array element
+ writer.println(" /* free each element of " +convName +"_copy */");
+ String subArrayElementJNITypeString = jniType(subArrayElementJavaType);
+ writer.print(" _tmpObj = (");
+ writer.print(subArrayElementJNITypeString);
+ writer.print(") (*env)->GetObjectArrayElement(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.println(", _copyIndex);");
+
+ if (subArrayElementJNITypeString == "jstring")
+ {
+ writer.print(" (*env)->ReleaseStringUTFChars(env, ");
+ writer.print("(jstring) _tmpObj");
+ writer.print(", ");
+ writer.print(convName+"_copy[_copyIndex]");
+ writer.println(");");
+ }
+ else
+ {
+ // FIXME: free up stuff here
+ if (true) throw new RuntimeException(
+ "Cannot yet handle type \"" + cArgType.getName() +
+ "\"; need to add support for cleaning up copied ptr-to-ptr-to-primitiveType subarrays");
+ }
+
+ writer.println(" }");
+ // free the main array
+ writer.print(" free(");
+ writer.print(convName+"_copy");
+ writer.println(");");
+
+
+ writer.println();
+ } // end of cleaning up copied data
+
+ writer.print(" (*env)->ReleasePrimitiveArrayCritical(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.print(", ");
+ writer.print(convName);
+ writer.println(", JNI_ABORT);");
+
+
+ if (EMIT_NULL_CHECKS) {
+ writer.println(" }");
+ }
+ } else if (javaArgType.isString()) {
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(binding.getArgumentName(i));
+ writer.println(" != NULL) {");
+ }
+
+ writer.print(" (*env)->ReleaseStringUTFChars(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.print(", _UTF8");
+ writer.print(binding.getArgumentName(i));
+ writer.println(");");
+
+ if (EMIT_NULL_CHECKS) {
+ writer.println(" }");
+ }
+ }
+ }
+ }
+
+ protected void emitBodyCallCFunction(PrintWriter writer)
+ {
+ // Make the call to the actual C function
+ writer.print(" ");
+
+ // WARNING: this code assumes that the return type has already been
+ // typedef-resolved.
+ Type cReturnType = binding.getCReturnType();
+
+ if (!cReturnType.isVoid()) {
+ writer.print("_res = ");
+ }
+ if (binding.hasContainingType()) {
+ // Call through function pointer
+ writer.print(CMethodBindingEmitter.cThisArgumentName() + "->");
+ }
+ writer.print(binding.getCSymbol().getName());
+ writer.print("(");
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ if (i != 0) {
+ writer.print(", ");
+ }
+ JavaType javaArgType = binding.getJavaArgumentType(i);
+ // Handle case where only param is void.
+ if (javaArgType.isVoid()) {
+ // Make sure this is the only param to the method; if it isn't,
+ // there's something wrong with our parsing of the headers.
+ assert(binding.getNumArguments() == 1);
+ continue;
+ }
+
+ if (javaArgType.isJNIEnv()) {
+ writer.print("env");
+ } else if (binding.isArgumentThisPointer(i)) {
+ writer.print(CMethodBindingEmitter.cThisArgumentName());
+ } else {
+ writer.print("(");
+ Type cArgType = binding.getCSymbol().getArgumentType(i);
+ writer.print(cArgType.getName());
+ writer.print(") ");
+ if (binding.getCArgumentType(i).isPointer() && binding.getJavaArgumentType(i).isPrimitive()) {
+ writer.print("(intptr_t) ");
+ }
+ if (javaArgType.isArray() || javaArgType.isNIOBuffer()) {
+ writer.print(pointerConversionArgumentName(i));
+ } else {
+ if (javaArgType.isString()) { writer.print("_UTF8"); }
+ writer.print(binding.getArgumentName(i));
+ }
+ }
+ }
+ writer.println(");");
+ }
+
+ /** Emits the user-defined C variable assignments from the
+ TemporaryCVariableAssignments directive in the .cfg file. */
+ protected void emitBodyUserVariableAssignments(PrintWriter writer) {
+ if (temporaryCVariableAssignments != null) {
+ for (Iterator iter = temporaryCVariableAssignments.iterator(); iter.hasNext(); ) {
+ String val = (String) iter.next();
+ writer.print(" ");
+ writer.println(val);
+ }
+ }
+ }
+
+ // FIXME: refactor this so that subclasses (in particular,
+ // net.java.games.gluegen.opengl.CGLPAWrapperEmitter) don't have to copy the whole
+ // method
+ protected void emitBodyReturnResult(PrintWriter writer)
+ {
+ // WARNING: this code assumes that the return type has already been
+ // typedef-resolved.
+ Type cReturnType = binding.getCReturnType();
+
+ // Return result if necessary
+ if (!cReturnType.isVoid()) {
+ JavaType javaReturnType = binding.getJavaReturnType();
+ if (javaReturnType.isPrimitive()) {
+ writer.print(" return ");
+ if (cReturnType.isPointer()) {
+ // Pointer being converted to int or long: cast this result
+ // (through intptr_t to avoid compiler warnings with gcc)
+ writer.print("(" + javaReturnType.jniTypeName() + ") (intptr_t) ");
+ }
+ writer.println("_res;");
+ } else if (javaReturnType.isNIOBuffer()) {
+ writer.println(" if (_res == NULL) return NULL;");
+ writer.print(" return (*env)->NewDirectByteBuffer(env, _res, ");
+ // See whether capacity has been specified
+ if (returnValueCapacityExpression != null) {
+ String[] argumentNames = new String[binding.getNumArguments()];
+ for (int i = 0; i < binding.getNumArguments(); i++)
+ {
+ argumentNames[i] = binding.getArgumentName(i);
+ }
+ writer.print(
+ returnValueCapacityExpression.format(argumentNames));
+ } else {
+ int sz = 0;
+ if (cReturnType.isPointer() &&
+ cReturnType.asPointer().getTargetType().isCompound()) {
+ sz = cReturnType.asPointer().getTargetType().getSize();
+ if (sz == -1) {
+ throw new InternalError(
+ "Error emitting code for compound return type "+
+ "for function \"" + binding + "\": " +
+ "Structs to be emitted should have been laid out by this point " +
+ "(type " + cReturnType.asPointer().getTargetType().getName() + " / " +
+ cReturnType.asPointer().getTargetType() + " was not)"
+ );
+ }
+ } else {
+ sz = cReturnType.getSize();
+ }
+ writer.print(sz);
+ System.err.println(
+ "WARNING: No capacity specified for java.nio.Buffer return " +
+ "value for function \"" + binding + "\";" +
+ " assuming size of equivalent C return type (" + sz + " bytes): " + binding);
+ }
+ writer.println(");");
+ } else if (javaReturnType.isString()) {
+ writer.print(" if (_res == NULL) return NULL;");
+ writer.println(" return (*env)->NewStringUTF(env, _res);");
+ } else if (javaReturnType.isArray()) {
+ // FIXME: must have user provide length of array in .cfg file
+ // by providing a constant value, input parameter, or
+ // expression which computes the array size (already present
+ // as ReturnValueCapacity, not yet implemented / tested here)
+
+ throw new RuntimeException(
+ "Could not emit native code for function \"" + binding +
+ "\": array return values for non-char types not implemented yet");
+
+ // FIXME: This is approximately what will be required here
+ //
+ //writer.print(" ");
+ //writer.print(arrayRes);
+ //writer.print(" = (*env)->New");
+ //writer.print(capitalizedComponentType);
+ //writer.print("Array(env, ");
+ //writer.print(arrayResLength);
+ //writer.println(");");
+ //writer.print(" (*env)->Set");
+ //writer.print(capitalizedComponentType);
+ //writer.print("ArrayRegion(env, ");
+ //writer.print(arrayRes);
+ //writer.print(", 0, ");
+ //writer.print(arrayResLength);
+ //writer.println(", _res);");
+ //writer.print(" return ");
+ //writer.print(arrayRes);
+ //writer.println(";");
+
+ }
+ }
+ }
+
+ protected static String cThisArgumentName() {
+ return "this0";
+ }
+
+ // Mangle a class, package or function name
+ protected String jniMangle(String name) {
+ return name.replaceAll("_", "_1").replace('.', '_');
+ }
+
+ protected String jniMangle(MethodBinding binding) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(jniMangle(binding.getName()));
+ buf.append("__");
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ Class c = type.getJavaClass();
+ if (c != null) {
+ jniMangle(c, buf);
+ } else {
+ // FIXME: add support for char* -> String conversion
+ throw new RuntimeException("Unknown kind of JavaType: name="+type.getName());
+ }
+ }
+ return buf.toString();
+ }
+
+ protected void jniMangle(Class c, StringBuffer res) {
+ if (c.isArray()) {
+ res.append("_3");
+ jniMangle(c.getComponentType(), res);
+ } else if (c.isPrimitive()) {
+ if (c == Boolean.TYPE) res.append("Z");
+ else if (c == Byte.TYPE) res.append("B");
+ else if (c == Character.TYPE) res.append("C");
+ else if (c == Short.TYPE) res.append("S");
+ else if (c == Integer.TYPE) res.append("I");
+ else if (c == Long.TYPE) res.append("J");
+ else if (c == Float.TYPE) res.append("F");
+ else if (c == Double.TYPE) res.append("D");
+ else throw new InternalError("Illegal primitive type");
+ } else {
+ res.append("L");
+ res.append(c.getName().replace('.', '_'));
+ res.append("_2");
+ }
+ }
+
+ private String jniType(Class javaType)
+ {
+ if (javaType.isPrimitive()) {
+ return "j" + javaType.getName();
+ } else if (javaType == java.lang.String.class) {
+ return "jstring";
+ } else {
+ throw new RuntimeException(
+ "Could not determine JNI type for Java class \"" +
+ javaType.getName() + "\"; was not String or primitive");
+ }
+ }
+
+ private void emitOutOfMemoryCheck(PrintWriter writer, String varName,
+ String errorMessage)
+ {
+ writer.print(" if (");
+ writer.print(varName);
+ writer.println(" == NULL) {");
+ writer.println(" (*env)->ThrowNew(env, (*env)->FindClass(env, \"java/lang/OutOfMemoryException\"),");
+ writer.print(" \"" + errorMessage);
+ writer.print(" in native dispatcher for \\\"");
+ writer.print(binding.getName());
+ writer.println("\\\"\");");
+ writer.print(" return");
+ if (!binding.getJavaReturnType().isVoid()) {
+ writer.print(" 0");
+ }
+ writer.println(";");
+ writer.println(" }");
+ }
+
+ private void emitMalloc(PrintWriter writer,
+ String targetVarName,
+ String elementTypeString,
+ String numElementsExpression,
+ String mallocFailureErrorString)
+ {
+ writer.print(" ");
+ writer.print(targetVarName);
+ writer.print(" = (");
+ writer.print(elementTypeString);
+ writer.print(" *) malloc(");
+ writer.print(numElementsExpression);
+ writer.print(" * sizeof(");
+ writer.print(elementTypeString);
+ writer.println("));");
+ // Catch memory allocation failure
+ if (EMIT_NULL_CHECKS) {
+ emitOutOfMemoryCheck(
+ writer, targetVarName,
+ mallocFailureErrorString);
+ }
+ }
+
+ private void emitGetStringUTFChars(PrintWriter writer,
+ String sourceVarName,
+ String receivingVarName)
+ {
+ writer.print(" ");
+ writer.print(receivingVarName);
+ writer.print(" = (*env)->GetStringUTFChars(env, ");
+ writer.print(sourceVarName);
+ writer.println(", (jboolean*)NULL);");
+ // Catch memory allocation failure in the event that the VM didn't pin
+ // the String and failed to allocate a copy
+ if (EMIT_NULL_CHECKS) {
+ emitOutOfMemoryCheck(
+ writer, receivingVarName,
+ "Failed to get UTF-8 chars for argument \\\""+sourceVarName+"\\\"");
+ }
+ }
+
+ // Note: if the data in the Type needs to be converted from the Java memory
+ // model to the C memory model prior to calling any C-side functions, then
+ // an extra variable named XXX_copy (where XXX is the value of the
+ // cVariableName argument) will be emitted and TRUE will be returned.
+ private boolean emitPointerDeclaration(PrintWriter writer,
+ JavaType javaType,
+ Type cType,
+ String cVariableName) {
+ String ptrTypeString = null;
+ boolean needsDataCopy = false;
+
+ // Emit declaration for the pointer variable.
+ //
+ // Note that we don't need to obey const/volatile for outgoing arguments
+ //
+ if (javaType.isNIOBuffer())
+ {
+ ptrTypeString = cType.getName();
+ }
+ else if (javaType.isArray()) {
+ // It's an array; get the type of the elements in the array
+ Class elementType = javaType.getJavaClass().getComponentType();
+ if (elementType.isPrimitive())
+ {
+ ptrTypeString = cType.getName();
+ }
+ else if (elementType == java.lang.String.class)
+ {
+ ptrTypeString = "jstring *";
+ needsDataCopy = true;
+ }
+ else if (elementType.isArray())
+ {
+ needsDataCopy = true;
+
+ Class subElementType = elementType.getComponentType();
+ if (subElementType.isPrimitive())
+ {
+ // type is pointer to pointer to primitive
+ ptrTypeString = cType.getName();
+ }
+ else
+ {
+ // type is pointer to pointer of some type we don't support (maybe
+ // it's an array of pointers to structs?)
+ throw new RuntimeException("Unsupported pointer type: \"" + cType.getName() + "\"");
+ }
+
+ }
+ else
+ {
+ // Type is pointer to something we can't/don't handle
+ throw new RuntimeException("Unsupported pointer type: \"" + cType.getName() + "\"");
+ }
+ }
+ else
+ {
+ ptrTypeString = cType.getName();
+ }
+
+ // declare the pointer variable
+ writer.print(" ");
+ writer.print(ptrTypeString);
+ writer.print(" ");
+ writer.print(cVariableName);
+ writer.println(" = NULL;");
+
+ if (needsDataCopy)
+ {
+ // Declare a variable to hold a copy of the argument data in which the
+ // incoming data has been properly laid out in memory to match the C
+ // memory model
+ //writer.print(" const ");
+ Class elementType = javaType.getJavaClass().getComponentType();
+ if (javaType.isArray() &&
+ javaType.getJavaClass().getComponentType() == java.lang.String.class) {
+ writer.print(" char **");
+ } else {
+ writer.print(ptrTypeString);
+ }
+ writer.print(" ");
+ writer.print(cVariableName);
+ writer.print("_copy = NULL; /* copy of data in ");
+ writer.print(cVariableName);
+ writer.println(", laid out according to C memory model */");
+ }
+
+ return needsDataCopy;
+ }
+
+ private void emitPointerConversion(PrintWriter writer,
+ MethodBinding binding,
+ JavaType type,
+ Type cType,
+ String incomingArgumentName,
+ String cVariableName) {
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(incomingArgumentName);
+ writer.println(" != NULL) {");
+ }
+
+ writer.print(" ");
+ writer.print(cVariableName);
+ writer.print(" = (");
+ writer.print(cType.getName());
+ writer.print(") (*env)->GetDirectBufferAddress(env, ");
+ writer.print(incomingArgumentName);
+ writer.println(");");
+
+ writer.print(" if (");
+ writer.print(cVariableName);
+ writer.println(" == NULL) {");
+ writer.println(" (*env)->ThrowNew(env, (*env)->FindClass(env, \"java/lang/RuntimeException\"),");
+ writer.print (" \"Argument \\\"");
+ writer.print(incomingArgumentName);
+ writer.println("\\\" was not a direct buffer\");");
+ writer.print (" return");
+ if (!binding.getJavaReturnType().isVoid()) {
+ writer.print(" 0");
+ }
+ writer.println(";");
+ writer.println(" }");
+
+ if (EMIT_NULL_CHECKS) {
+ writer.println(" }");
+ }
+ }
+
+ protected String pointerConversionArgumentName(int i) {
+ return "_ptr" + i;
+ }
+
+ /**
+ * Class that emits a generic comment for CMethodBindingEmitters; the comment
+ * includes the C signature of the native method that is being bound by the
+ * emitter java method.
+ */
+ protected static class DefaultCommentEmitter implements CommentEmitter {
+ public void emit(FunctionEmitter emitter, PrintWriter writer) {
+ emitBeginning((CMethodBindingEmitter)emitter, writer);
+ emitEnding((CMethodBindingEmitter)emitter, writer);
+ }
+ protected void emitBeginning(CMethodBindingEmitter emitter, PrintWriter writer) {
+ writer.println(" Java->C glue code:");
+ writer.print(" * Java package: ");
+ writer.print(emitter.getJavaPackageName());
+ writer.print(".");
+ writer.println(emitter.getJavaClassName());
+ writer.print(" * Java method: ");
+ MethodBinding binding = emitter.getBinding();
+ writer.println(binding);
+ writer.println(" * C function: " + binding.getCSymbol());
+ }
+ protected void emitEnding(CMethodBindingEmitter emitter, PrintWriter writer) {
+ }
+ }
+
+}
+
diff --git a/src/net/java/games/gluegen/CMethodBindingImplEmitter.java b/src/net/java/games/gluegen/CMethodBindingImplEmitter.java
new file mode 100644
index 000000000..95f04d235
--- /dev/null
+++ b/src/net/java/games/gluegen/CMethodBindingImplEmitter.java
@@ -0,0 +1,99 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.util.*;
+import java.io.*;
+import java.text.MessageFormat;
+
+public class CMethodBindingImplEmitter extends CMethodBindingEmitter
+{
+ protected static final CommentEmitter defaultCImplCommentEmitter =
+ new CImplCommentEmitter();
+
+ public CMethodBindingImplEmitter(MethodBinding binding,
+ boolean isOverloadedBinding,
+ String javaPackageName,
+ String javaClassName,
+ boolean isJavaMethodStatic,
+ PrintWriter output)
+ {
+ super(binding, isOverloadedBinding,
+ javaPackageName, javaClassName,
+ isJavaMethodStatic, output);
+ setCommentEmitter(defaultCImplCommentEmitter);
+ }
+
+ protected void emitName(PrintWriter writer)
+ {
+ super.emitName(writer);
+ if (!getIsOverloadedBinding()) {
+ writer.print("0");
+ }
+ }
+
+ /**
+ * Gets the mangled name for the binding, but assumes that this is an Impl
+ * routine
+ */
+ protected String jniMangle(MethodBinding binding) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(jniMangle(binding.getName()));
+ buf.append("0");
+ buf.append("__");
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ Class c = type.getJavaClass();
+ if (c != null) {
+ jniMangle(c, buf);
+ } else {
+ // FIXME: add support for char* -> String conversion
+ throw new RuntimeException("Unknown kind of JavaType: name="+type.getName());
+ }
+ }
+ return buf.toString();
+ }
+
+ protected static class CImplCommentEmitter extends CMethodBindingEmitter.DefaultCommentEmitter {
+ protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) {
+ writer.print(" -- FIXME: PUT A COMMENT HERE -- ");
+ }
+ }
+}
diff --git a/src/net/java/games/gluegen/CodeGenUtils.java b/src/net/java/games/gluegen/CodeGenUtils.java
new file mode 100644
index 000000000..313896d13
--- /dev/null
+++ b/src/net/java/games/gluegen/CodeGenUtils.java
@@ -0,0 +1,148 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.io.*;
+import java.util.*;
+
+public class CodeGenUtils
+{
+ /**
+ * Given a java package name (e.g., "java.lang"), return the package as a
+ * directory path (i.e., "java/lang").
+ */
+ public static String packageAsPath(String packageName) {
+ String path = packageName.replace('.', File.separatorChar);
+ //System.out.println("Converted package [" + packageName + "] to path [" + path +"]");
+ return path;
+ }
+
+ /**
+ * @param generator the object that is emitting the autogenerated code. If
+ * null, the generator will not be mentioned in the warning message.
+ */
+ public static void emitAutogeneratedWarning(PrintWriter w, Object generator) {
+ w.print("/* !---- DO NOT EDIT: This file autogenerated ");
+ if (generator != null)
+ {
+ w.print("by ");
+ w.print(packageAsPath(generator.getClass().getName()));
+ w.print(".java ");
+ }
+ w.print("on ");
+ w.print((new Date()).toString());
+ w.println(" ----! */");
+ w.println();
+ }
+
+ /**
+ * Emit the opening headers for one java class/interface file.
+ */
+ public static void emitJavaHeaders(
+ PrintWriter w,
+ String packageName,
+ String className,
+ boolean isClassNotInterface,
+ String[] imports,
+ String[] accessModifiers,
+ String[] interfaces,
+ String classExtended,
+ EmissionCallback classDocComment) throws IOException
+ {
+ w.println("package " + packageName + ";");
+ w.println();
+
+ for (int i = 0; imports != null && i < imports.length; ++i) {
+ w.print("import ");
+ w.print(imports[i]);
+ w.println(';');
+ }
+
+ w.println();
+
+ if (classDocComment != null)
+ {
+ classDocComment.emit(w);
+ }
+
+ for (int i = 0; accessModifiers != null && i < accessModifiers.length; ++i) {
+ w.print(accessModifiers[i]);
+ w.print(' ');
+ }
+
+ if (isClassNotInterface) {
+ w.print("class ");
+ w.print(className);
+ w.print(' ');
+ if (classExtended != null) {
+ w.print("extends ");
+ w.print(classExtended);
+ }
+ }
+ else {
+ if (classExtended != null) {
+ throw new IllegalArgumentException(
+ "Autogenerated interface class " + className +
+ " cannot extend class " + classExtended);
+ }
+ w.print("interface ");
+ w.print(className);
+ w.print(' ');
+ }
+
+ for (int i = 0; interfaces != null && i < interfaces.length; ++i) {
+ if (i == 0) { w.print(isClassNotInterface ? "implements " : "extends "); }
+ w.print(interfaces[i]);
+ if (i < interfaces.length-1) { w.print(", "); }
+ }
+
+ w.println();
+ w.println('{');
+ }
+
+ //-----------------------------------------
+
+ /** A class that emits source code of some time when activated. */
+ public interface EmissionCallback
+ {
+ /** Emit appropriate source code through the given writer. */
+ public void emit(PrintWriter output);
+ }
+}
diff --git a/src/net/java/games/gluegen/CommentEmitter.java b/src/net/java/games/gluegen/CommentEmitter.java
new file mode 100644
index 000000000..337161ce0
--- /dev/null
+++ b/src/net/java/games/gluegen/CommentEmitter.java
@@ -0,0 +1,52 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.io.*;
+
+public interface CommentEmitter
+{
+ /**
+ * Emit the body of a comment for the specified function; do NOT emit the
+ * open (e.g., comment "/*") or close (e.g., "*\/") characters.
+ */
+ public void emit(FunctionEmitter funcEmitter, PrintWriter output);
+}
+
diff --git a/src/net/java/games/gluegen/DebugEmitter.java b/src/net/java/games/gluegen/DebugEmitter.java
new file mode 100644
index 000000000..677c3e7e6
--- /dev/null
+++ b/src/net/java/games/gluegen/DebugEmitter.java
@@ -0,0 +1,102 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.util.*;
+
+import net.java.games.gluegen.cgram.types.*;
+
+/** Debug emitter which prints the parsing results to standard output. */
+
+public class DebugEmitter implements GlueEmitter {
+ public void readConfigurationFile(String filename) {}
+
+ public void setMachineDescription(MachineDescription md) {}
+
+ public void beginEmission(GlueEmitterControls controls) {
+ System.out.println("----- BEGIN EMISSION OF GLUE CODE -----");
+ }
+ public void endEmission() {
+ System.out.println("----- END EMISSION OF GLUE CODE -----");
+ }
+ public void beginDefines() {}
+ public void emitDefine(String name, String value, String optionalComment) {
+ System.out.println("#define " + name + " " + value +
+ (optionalComment != null ? ("// " + optionalComment) : ""));
+ }
+ public void endDefines() {}
+
+ public void beginFunctions(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) {
+ Set keys = typedefDictionary.keySet();
+ for (Iterator iter = keys.iterator(); iter.hasNext(); ) {
+ String key = (String) iter.next();
+ Type value = typedefDictionary.get(key);
+ System.out.println("typedef " + value + " " + key + ";");
+ }
+ }
+ public Iterator emitFunctions(List/*<FunctionSymbol>*/ originalCFunctions)
+ throws Exception {
+ for (Iterator iter = originalCFunctions.iterator(); iter.hasNext(); ) {
+ FunctionSymbol sym = (FunctionSymbol) iter.next();
+ emitSingleFunction(sym);
+ }
+ return originalCFunctions.iterator();
+ }
+ public void emitSingleFunction(FunctionSymbol sym) {
+ System.out.println(sym);
+ System.out.println(" -> " + sym.toString());
+ }
+ public void endFunctions() {}
+
+ public void beginStructLayout() throws Exception {}
+ public void layoutStruct(CompoundType t) throws Exception {}
+ public void endStructLayout() throws Exception {}
+
+ public void beginStructs(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) {
+ }
+ public void emitStruct(CompoundType t) {
+ System.out.println("Referenced type \"" + t.getName() + "\"");
+ }
+ public void endStructs() {}
+}
diff --git a/src/net/java/games/gluegen/FunctionEmitter.java b/src/net/java/games/gluegen/FunctionEmitter.java
new file mode 100644
index 000000000..cb5ef4159
--- /dev/null
+++ b/src/net/java/games/gluegen/FunctionEmitter.java
@@ -0,0 +1,199 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.util.*;
+import java.io.*;
+
+public abstract class FunctionEmitter
+{
+ public static final EmissionModifier STATIC = new EmissionModifier("static");
+
+ private HashSet modifiers = new HashSet(4);
+ private CommentEmitter commentEmitter = null;
+ private PrintWriter defaultOutput;
+
+ /**
+ * Constructs the FunctionEmitter with a CommentEmitter that emits nothing.
+ */
+ public FunctionEmitter(PrintWriter defaultOutput)
+ {
+ assert(defaultOutput != null);
+ this.defaultOutput = defaultOutput;
+ }
+
+ public PrintWriter getDefaultOutput() { return defaultOutput; }
+
+ public void addModifiers(Iterator/*<EmissionModifier>*/ mi)
+ {
+ while (mi.hasNext())
+ {
+ modifiers.add((EmissionModifier) mi.next());
+ }
+ }
+ public void addModifier(EmissionModifier m) { modifiers.add(m); }
+
+ public boolean removeModifier(EmissionModifier m) { return modifiers.remove(m); }
+
+ public void clearModifiers() { modifiers.clear(); }
+
+ public boolean hasModifier(EmissionModifier m) { return modifiers.contains(m); }
+
+ public Iterator getModifiers() { return modifiers.iterator(); }
+
+ public abstract String getName();
+
+ /**
+ * Emit the function to the specified output (instead of the default
+ * output).
+ */
+ public void emit(PrintWriter output)
+ {
+ emitDocComment(output);
+ //output.println(" // Emitter: " + getClass().getName());
+ emitSignature(output);
+ emitBody(output);
+ }
+
+ /**
+ * Emit the function to the default output (the output that was passed to
+ * the constructor)
+ */
+ public final void emit()
+ {
+ emit(getDefaultOutput());
+ }
+
+ /** Returns, as a String, whatever {@link emit()} would output. */
+ public String toString()
+ {
+ StringWriter sw = new StringWriter(500);
+ PrintWriter w = new PrintWriter(sw);
+ emit(w);
+ return sw.toString();
+ }
+
+ /**
+ * Set the object that will emit the comment for this function. If the
+ * parameter is null, no comment will be emitted.
+ */
+ public void setCommentEmitter(CommentEmitter cEmitter)
+ {
+ commentEmitter = cEmitter;
+ }
+
+ /**
+ * Get the comment emitter for this FunctionEmitter. The return value may be
+ * null, in which case no comment emitter has been set.
+ */
+ public CommentEmitter getCommentEmitter() { return commentEmitter; }
+
+ protected void emitDocComment(PrintWriter writer)
+ {
+ if (commentEmitter != null)
+ {
+ writer.print(getBaseIndentString()); //indent
+
+ writer.print(getCommentStartString());
+
+ commentEmitter.emit(this, writer);
+
+ writer.print(getBaseIndentString()); //indent
+
+ writer.println(getCommentEndString());
+ }
+ }
+
+ protected void emitSignature(PrintWriter writer)
+ {
+ writer.print(getBaseIndentString()); // indent method
+
+ int numEmitted = emitModifiers(writer);
+ if (numEmitted > 0)
+ {
+ writer.print(" ");
+ }
+
+ emitReturnType(writer);
+ writer.print(" ");
+
+ emitName(writer);
+ writer.print("(");
+
+ emitArguments(writer);
+ writer.print(")");
+ }
+
+ protected int emitModifiers(PrintWriter writer)
+ {
+ PrintWriter w = getDefaultOutput();
+ int numEmitted = 0;
+ for (Iterator it = getModifiers(); it.hasNext(); )
+ {
+ writer.print(it.next());
+ ++numEmitted;
+ if (it.hasNext())
+ {
+ writer.print(" ");
+ }
+ }
+ return numEmitted;
+ }
+
+ protected String getBaseIndentString() { return ""; }
+
+ protected String getCommentStartString() { return "/* "; }
+ protected String getCommentEndString() { return " */"; }
+
+ protected abstract void emitReturnType(PrintWriter writer);
+ protected abstract void emitName(PrintWriter writer);
+ /** Returns the number of arguments emitted. */
+ protected abstract int emitArguments(PrintWriter writer);
+ protected abstract void emitBody(PrintWriter writer);
+
+ public static class EmissionModifier
+ {
+ public final String toString() { return emittedForm; }
+
+ private String emittedForm;
+ protected EmissionModifier(String emittedForm) { this.emittedForm = emittedForm; }
+ }
+}
+
diff --git a/src/net/java/games/gluegen/GlueEmitter.java b/src/net/java/games/gluegen/GlueEmitter.java
new file mode 100644
index 000000000..3d55474e0
--- /dev/null
+++ b/src/net/java/games/gluegen/GlueEmitter.java
@@ -0,0 +1,99 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.util.*;
+import net.java.games.gluegen.cgram.types.*;
+
+/** Specifies the interface by which GlueGen requests glue code to be
+ generated. Can be replaced to generate glue code for other
+ languages and foreign function interfaces. */
+
+public interface GlueEmitter {
+
+ public void readConfigurationFile(String filename) throws Exception;
+
+ /** Set the description of the underlying hardware. */
+ public void setMachineDescription(MachineDescription md);
+
+ /**
+ * Begin the emission of glue code. This might include opening files,
+ * emitting class headers, etc.
+ */
+ public void beginEmission(GlueEmitterControls controls) throws Exception;
+
+ /**
+ * Finish the emission of glue code. This might include closing files,
+ * closing open class definitions, etc.
+ */
+ public void endEmission() throws Exception;
+
+ public void beginDefines() throws Exception;
+ /**
+ * @param optionalComment If optionalComment is non-null, the emitter can
+ * emit that string as a comment providing extra information about the
+ * define.
+ */
+ public void emitDefine(String name, String value, String optionalComment) throws Exception;
+ public void endDefines() throws Exception;
+
+ public void beginFunctions(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) throws Exception;
+
+ /** Emit glue code for the list of FunctionSymbols. */
+ public Iterator emitFunctions(java.util.List/*<FunctionSymbol>*/ cFunctions) throws Exception;
+ public void endFunctions() throws Exception;
+
+ /** Begins the process of computing field offsets and type sizes for
+ the structs to be emitted. */
+ public void beginStructLayout() throws Exception;
+ /** Lays out one struct which will be emitted later. */
+ public void layoutStruct(CompoundType t) throws Exception;
+ /** Finishes the struct layout process. */
+ public void endStructLayout() throws Exception;
+
+ public void beginStructs(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) throws Exception;
+ /** Emit glue code for the given CompoundType. */
+ public void emitStruct(CompoundType t) throws Exception;
+ public void endStructs() throws Exception;
+}
diff --git a/src/net/java/games/gluegen/GlueEmitterControls.java b/src/net/java/games/gluegen/GlueEmitterControls.java
new file mode 100644
index 000000000..f4f48a399
--- /dev/null
+++ b/src/net/java/games/gluegen/GlueEmitterControls.java
@@ -0,0 +1,49 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+/** Specifies the interface by which a GlueEmitter can request
+ additional information from the glue generator. */
+
+public interface GlueEmitterControls {
+ /** Requests emission of an accessor for a struct that will not be
+ referenced by any functions or other structs. */
+ public void forceStructEmission(String typedefName);
+}
diff --git a/src/net/java/games/gluegen/GlueGen.java b/src/net/java/games/gluegen/GlueGen.java
new file mode 100644
index 000000000..374611c81
--- /dev/null
+++ b/src/net/java/games/gluegen/GlueGen.java
@@ -0,0 +1,299 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.io.*;
+import java.util.*;
+
+import antlr.*;
+import antlr.collections.*;
+import net.java.games.gluegen.cgram.*;
+import net.java.games.gluegen.cgram.types.*;
+import net.java.games.gluegen.pcpp.*;
+
+/** Glue code generator for C functions and data structures. */
+
+public class GlueGen implements GlueEmitterControls {
+ private java.util.List forcedStructNames = new ArrayList();
+
+ public void forceStructEmission(String typedefName) {
+ forcedStructNames.add(typedefName);
+ }
+
+ public void run(String[] args) {
+ try {
+ Reader reader = null;
+ String filename = null;
+ String emitterClass = null;
+ java.util.List cfgFiles = new ArrayList();
+
+ if (args.length == 0) {
+ usage();
+ }
+
+ java.util.List includePaths = new ArrayList();
+ 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.startsWith("-E")) {
+ emitterClass = arg.substring(2);
+ } else if (arg.startsWith("-C")) {
+ cfgFiles.add(arg.substring(2));
+ } 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));
+ }
+ }
+ }
+
+ final PCPP preprocessor = new PCPP(includePaths);
+ PipedInputStream ppIn = new PipedInputStream();
+ final PipedOutputStream ppOut = new PipedOutputStream(ppIn);
+ preprocessor.setOut(ppOut);
+ final Reader rdr = reader;
+ final String fn = filename;
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ preprocessor.run(rdr, fn);
+ ppOut.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }).start();
+
+ DataInputStream dis = new DataInputStream(ppIn);
+ GnuCLexer lexer = new GnuCLexer(dis);
+ lexer.setTokenObjectClass(CToken.class.getName());
+ lexer.initialize();
+ // Parse the input expression.
+ GnuCParser parser = new GnuCParser(lexer);
+
+ // set AST node type to TNode or get nasty cast class errors
+ parser.setASTNodeType(TNode.class.getName());
+ TNode.setTokenVocabulary(GNUCTokenTypes.class.getName());
+
+ // invoke parser
+ try {
+ parser.translationUnit();
+ }
+ catch (RecognitionException e) {
+ System.err.println("Fatal IO error:\n"+e);
+ System.exit(1);
+ }
+ catch (TokenStreamException e) {
+ System.err.println("Fatal IO error:\n"+e);
+ System.exit(1);
+ }
+
+ HeaderParser headerParser = new HeaderParser();
+ MachineDescription machDesc = new MachineDescription32Bit();
+ headerParser.setMachineDescription(machDesc);
+ TypeDictionary td = new TypeDictionary();
+ headerParser.setTypedefDictionary(td);
+ TypeDictionary sd = new TypeDictionary();
+ headerParser.setStructDictionary(sd);
+ // set AST node type to TNode or get nasty cast class errors
+ headerParser.setASTNodeType(TNode.class.getName());
+ // walk that tree
+ headerParser.translationUnit( parser.getAST() );
+
+ // For debugging: Dump type dictionary and struct dictionary to System.err
+ //td.dumpDictionary(System.err, "All Types");
+ //sd.dumpDictionary(System.err, "All Structs");
+
+ // At this point we have all of the pieces we need in order to
+ // generate glue code: the #defines to constants, the set of
+ // typedefs, and the set of functions.
+
+ GlueEmitter emit = null;
+ if (emitterClass == null) {
+ emit = new JavaEmitter();
+ } else {
+ try {
+ emit = (GlueEmitter) Class.forName(emitterClass).newInstance();
+ } catch (Exception e) {
+ System.err.println("Exception occurred while instantiating emitter class. Exiting.");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ for (Iterator iter = cfgFiles.iterator(); iter.hasNext(); ) {
+ emit.readConfigurationFile((String) iter.next());
+ }
+
+ // provide MachineDescription to emitter if it needs it
+ emit.setMachineDescription(machDesc);
+
+ // begin emission of glue code
+ emit.beginEmission(this);
+
+ emit.beginDefines();
+ Set emittedDefines = new HashSet(100);
+ // emit java equivalent of enum { ... } statements
+ for (Iterator iter = headerParser.getEnums().iterator(); iter.hasNext(); ) {
+ EnumType enumeration = (EnumType)iter.next();
+ // iterate over all values in the enumeration
+ for (int i = 0; i < enumeration.getNumEnumerates(); ++i) {
+ String enumElementName = enumeration.getEnumName(i);
+ if (emittedDefines.contains(enumElementName) == false) {
+ emittedDefines.add(enumElementName);
+ String comment = null;
+ if (! enumeration.getName().equals("<anonymous>")) {
+ comment = "Defined as part of enum type \"" +
+ enumeration.getName() + "\"";
+ }
+ emit.emitDefine(
+ enumElementName,
+ String.valueOf(enumeration.getEnumValue(i)),
+ comment);
+ }
+ }
+ }
+ // emit java equivalent of #define statements
+ for (Iterator iter = lexer.getDefines().iterator(); iter.hasNext(); ) {
+ Define def = (Define) iter.next();
+ if (emittedDefines.contains(def.getName()) == false) {
+ emittedDefines.add(def.getName());
+ emit.emitDefine(def.getName(), def.getValue(), null);
+ }
+ }
+ emit.endDefines();
+
+ java.util.List functions = headerParser.getParsedFunctions();
+
+ // Iterate through the functions finding structs that are referenced in
+ // the function signatures; these will be remembered for later emission
+ ReferencedStructs referencedStructs = new ReferencedStructs();
+ for (Iterator iter = functions.iterator(); iter.hasNext(); ) {
+ FunctionSymbol sym = (FunctionSymbol) iter.next();
+ // FIXME: this doesn't take into account the possibility that some of
+ // the functions we send to emitMethodBindings() might not actually be
+ // emitted (e.g., if an Ignore directive in the JavaEmitter causes it
+ // to be skipped).
+ sym.getType().visit(referencedStructs);
+ }
+
+ // Normally only referenced types will be emitted. The user can force a
+ // type to be emitted via a .cfg file directive. Those directives are
+ // processed here.
+ for (Iterator iter = forcedStructNames.iterator(); iter.hasNext(); ) {
+ String name = (String) iter.next();
+ Type type = td.get(name);
+ if (type == null) {
+ System.err.println("WARNING: during forced struct emission: struct \"" + name + "\" not found");
+ } else if (!type.isCompound()) {
+ System.err.println("WARNING: during forced struct emission: type \"" + name + "\" was not a struct");
+ } else {
+ type.visit(referencedStructs);
+ }
+ }
+
+ // Lay out structs
+ emit.beginStructLayout();
+ for (Iterator iter = referencedStructs.results(); iter.hasNext(); ) {
+ emit.layoutStruct((CompoundType) iter.next());
+ }
+ emit.endStructLayout();
+
+ // Emit structs
+ emit.beginStructs(td, sd, headerParser.getCanonMap());
+ for (Iterator iter = referencedStructs.results(); iter.hasNext(); ) {
+ emit.emitStruct((CompoundType) iter.next());
+ }
+ emit.endStructs();
+
+ // emit java and C code to interface with the native functions
+ emit.beginFunctions(td, sd, headerParser.getCanonMap());
+ emit.emitFunctions(functions);
+ emit.endFunctions();
+
+ // end emission of glue code
+ emit.endEmission();
+
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ System.err.println("Exception occurred while generating glue code. Exiting.");
+ System.exit(1);
+ }
+ }
+
+ public static void main(String[] args) {
+ new GlueGen().run(args);
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private static void usage() {
+ System.out.println("Usage: java GlueGen [-I...] [-Eemitter_class_name] [-Ccfg_file_name...] <filename | ->");
+ System.out.println();
+ System.out.println("Runs C header parser on input file or standard input, first");
+ System.out.println("passing input through minimal pseudo-C-preprocessor. Use -I");
+ System.out.println("command-line arguments to specify the search path for #includes.");
+ System.out.println("Emitter class name can be specified with -E option: i.e.,");
+ System.out.println("-Enet.java.games.gluegen.JavaEmitter (the default). Use");
+ System.out.println("-Enet.java.games.gluegen.DebugEmitter to print recognized entities");
+ System.out.println("(#define directives to constant numbers, typedefs, and function");
+ System.out.println("declarations) to standard output. Emitter-specific configuration");
+ System.out.println("file or files can be specified with -C option; e.g,");
+ System.out.println("-Cjava-emitter.cfg.");
+ System.exit(1);
+ }
+}
diff --git a/src/net/java/games/gluegen/JavaConfiguration.java b/src/net/java/games/gluegen/JavaConfiguration.java
new file mode 100644
index 000000000..ecd953480
--- /dev/null
+++ b/src/net/java/games/gluegen/JavaConfiguration.java
@@ -0,0 +1,1051 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import net.java.games.gluegen.cgram.types.*;
+
+/** Parses and provides access to the contents of .cfg files for the
+ JavaEmitter. */
+
+public class JavaConfiguration {
+ private int nestedReads;
+ private String packageName;
+ private String implPackageName;
+ private String className;
+ private String implClassName;
+ /**
+ * Root directory for the hierarchy of generated java classes. Default is
+ * working directory.
+ */
+ private String javaOutputDir = ".";
+ /**
+ * Directory into which generated native JNI code will be written. Default
+ * is current working directory.
+ */
+ private String nativeOutputDir = ".";
+ /**
+ * If true, then each native *.c and *.h file will be generated in the
+ * directory nativeOutputDir/packageAsPath(packageName). Default is false.
+ */
+ private boolean nativeOutputUsesJavaHierarchy;
+ /**
+ * Style of code emission. Can emit everything into one class
+ * (AllStatic), separate interface and implementing classes
+ * (InterfaceAndImpl), only the interface (InterfaceOnly), or only
+ * the implementation (ImplOnly).
+ */
+ private int emissionStyle = JavaEmitter.ALL_STATIC;
+ /**
+ * List of imports to emit at the head of the output files.
+ */
+ private List/*<String>*/ imports = new ArrayList();
+ /**
+ * The kind of exception raised by the generated code if run-time
+ * checks fail. Defaults to RuntimeException.
+ */
+ private String runtimeExceptionType = "RuntimeException";
+ private Map/*<String,TypeInfo>*/ typeInfoMap = new HashMap();
+ private Set/*<String>*/ returnsString = new HashSet();
+ private Map/*<String, String>*/ returnedArrayLengths = new HashMap();
+ /**
+ * Key is function that has some byte[] arguments that should be
+ * converted to String args; value is List of Integer argument indices
+ */
+ private Map/*<String,List<Integer>>*/ argumentsAreString = new HashMap();
+ private Set/*<Pattern>*/ ignores = new HashSet();
+ private Set/*<Pattern>*/ ignoreNots = new HashSet();
+ private Set/*<Pattern>*/ unimplemented = new HashSet();
+ private Set/*<String>*/ nioOnly = new HashSet();
+ private Set/*<String>*/ manuallyImplement = new HashSet();
+ private Map/*<String,List<String>>*/ customJavaCode = new HashMap();
+ private Map/*<String,List<String>>*/ classJavadoc = new HashMap();
+ private Map/*<String,String>*/ structPackages = new HashMap();
+ private List/*<String>*/ customCCode = new ArrayList();
+ private List/*<String>*/ forcedStructs = new ArrayList();
+ private Map/*<String,List<Integer>>*/ mirroredArgs = new HashMap();
+ private Map/*<String, String>*/ returnValueCapacities = new HashMap();
+ private Map/*<String, List<String>>*/ temporaryCVariableDeclarations = new HashMap();
+ private Map/*<String, List<String>>*/ temporaryCVariableAssignments = new HashMap();
+ private Map/*<String,List<String>>*/ extendedInterfaces = new HashMap();
+ private Map/*<String,String>*/ javaTypeRenames = new HashMap();
+
+ /** Reads the configuration file.
+ @param path to file that should be read
+ */
+ public final void read(String filename) throws IOException {
+ read(filename, null);
+ }
+
+ /** Reads the specified file, treating each line as if it started with the
+ specified string.
+ @param path to file that should be read
+ @param linePrefix if not null, treat each line read as if it were
+ prefixed with the specified string.
+ */
+ protected final void read(String filename, String linePrefix) throws IOException {
+ File file = new File(filename);
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ }
+ catch (FileNotFoundException fnfe) {
+ throw new RuntimeException("Could not read file \"" + file + "\"", fnfe);
+ }
+ int lineNo = 0;
+ String line = null;
+ boolean hasPrefix = linePrefix != null && linePrefix.length() > 0;
+ try {
+ ++nestedReads;
+ while ((line = reader.readLine()) != null) {
+ ++lineNo;
+ if (hasPrefix)
+ {
+ line = linePrefix + " " + line;
+ }
+
+ if (line.trim().startsWith("#"))
+ {
+ // comment line
+ continue;
+ }
+
+ StringTokenizer tok = new StringTokenizer(line);
+ if (tok.hasMoreTokens())
+ {
+ // always reset delimiters in case of CustomJavaCode, etc.
+ String cmd = tok.nextToken(" \t\n\r\f");
+
+ dispatch(cmd, tok, file, filename, lineNo);
+ }
+ }
+ reader.close();
+ } finally {
+ --nestedReads;
+ }
+
+ if (nestedReads == 0) {
+ if (allStatic() && implClassName != null) {
+ throw new IllegalStateException(
+ "Error in configuration file \"" + filename + "\": Cannot use " +
+ "directive \"ImplJavaClass\" in conjunction with " +
+ "\"Style AllStatic\"");
+ }
+
+ if (className == null) {
+ throw new RuntimeException("Output class name was not specified in configuration file");
+ }
+ if (packageName == null) {
+ throw new RuntimeException("Output package name was not specified in configuration file");
+ }
+
+ if (allStatic()) {
+ implClassName = className;
+ // If we're using the "Style AllStatic" directive, then the
+ // implPackageName is the same as the regular package name
+ implPackageName = packageName;
+ } else {
+ if (implClassName == null) {
+ // implClassName defaults to "<className>Impl" if ImplJavaClass
+ // directive is not used
+ implClassName = className + "Impl";
+ }
+ if (implPackageName == null) {
+ // implPackageName defaults to "<packageName>.impl" if ImplPackage
+ // directive is not used
+ implPackageName = packageName + ".impl";
+ }
+ }
+ }
+ }
+
+ /** Returns the package name parsed from the configuration file. */
+ public String packageName() { return packageName; }
+ /** Returns the implementation package name parsed from the configuration file. */
+ public String implPackageName() { return implPackageName; }
+ /** Returns the class name parsed from the configuration file. */
+ public String className() { return className; }
+ /** Returns the implementation class name parsed from the configuration file. */
+ public String implClassName() { return implClassName; }
+ /** Returns the Java code output directory parsed from the configuration file. */
+ public String javaOutputDir() { return javaOutputDir; }
+ /** Returns the native code output directory parsed from the configuration file. */
+ public String nativeOutputDir() { return nativeOutputDir; }
+ /** Returns whether the native code directory structure mirrors the Java hierarchy. */
+ public boolean nativeOutputUsesJavaHierarchy() { return nativeOutputUsesJavaHierarchy; }
+ /** Returns the code emission style (constants in JavaEmitter) parsed from the configuration file. */
+ public int emissionStyle() { return emissionStyle; }
+ /** Returns the kind of exception to raise if run-time checks fail in the generated code. */
+ public String runtimeExceptionType() { return runtimeExceptionType; }
+ /** Returns the list of imports that should be emitted at the top of each .java file. */
+ public List/*<String>*/ imports() { return imports; }
+
+ /** If this type should be considered opaque, returns the TypeInfo
+ describing the replacement type. Returns null if this type
+ should not be considered opaque. */
+ public TypeInfo typeInfo(Type type, TypeDictionary typedefDictionary) {
+ // Because typedefs of pointer types can show up at any point,
+ // walk the pointer chain looking for a typedef name that is in
+ // the TypeInfo map.
+ int pointerDepth = type.pointerDepth();
+ for (int i = 0; i <= pointerDepth; i++) {
+ String name = type.getName();
+ if (name != null) {
+ TypeInfo info = (TypeInfo) typeInfoMap.get(name);
+ while (info != null) {
+ if (info.name().equals(name) && info.pointerDepth() == i) {
+ return info;
+ }
+ info = info.next();
+ }
+ }
+
+ if (type.isCompound()) {
+ // Try struct name as well
+ name = type.asCompound().getStructName();
+ if (name != null) {
+ TypeInfo info = (TypeInfo) typeInfoMap.get(name);
+ while (info != null) {
+ if (info.name().equals(name) && info.pointerDepth() == i) {
+ return info;
+ }
+ info = info.next();
+ }
+ }
+ }
+
+ // Try all typedef names that map to this type
+ Set entrySet = typedefDictionary.entrySet();
+ for (Iterator iter = entrySet.iterator(); iter.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ // "eq" equality is OK to use here since all types have been canonicalized
+ if (entry.getValue() == type) {
+ name = (String) entry.getKey();
+ TypeInfo info = (TypeInfo) typeInfoMap.get(name);
+ while (info != null) {
+ if (info.name().equals(name) && info.pointerDepth() == i) {
+ return info;
+ }
+ info = info.next();
+ }
+ }
+ }
+
+ if (type.isPointer()) {
+ type = type.asPointer().getTargetType();
+ }
+ }
+
+ return null;
+ }
+
+ /** Indicates whether the given function (which returns a
+ <code>char*</code> in C) should be translated as returning a
+ <code>java.lang.String</code>. */
+ public boolean returnsString(String functionName) {
+ return returnsString.contains(functionName);
+ }
+
+ /** Provides a Java MessageFormat expression indicating the number
+ of elements in the returned array from the specified function
+ name as defined by the ReturnsArray directive. */
+ public String returnedArrayLength(String functionName) {
+ return (String) returnedArrayLengths.get(functionName);
+ }
+
+ /** Returns a list of <code>Integer</code>s which are the indices of <code>const char*</code>
+ arguments that should be converted to <code>String</code>s. Returns null if there are no
+ such hints for the given function name. */
+
+ public List/*<Integer>*/ stringArguments(String functionName) {
+ return (List) argumentsAreString.get(functionName);
+ }
+
+ /** Returns true if the given function should only create a java.nio
+ variant, and no array variants, for <code>void*</code>
+ pointers. */
+ public boolean nioOnly(String functionName) {
+ return nioOnly.contains(functionName);
+ }
+
+ /** Returns true if the glue code for the given function will be
+ manually implemented by the end user. */
+ public boolean manuallyImplement(String functionName) {
+ return manuallyImplement.contains(functionName);
+ }
+
+ /** Returns a list of Strings containing user-implemented code for
+ the given Java type name (not fully-qualified, only the class
+ name); returns either null or an empty list if there is no
+ custom code for the class. */
+ public List customJavaCodeForClass(String className) {
+ List res = (List) customJavaCode.get(className);
+ if (res == null) {
+ res = new ArrayList();
+ customJavaCode.put(className, res);
+ }
+ return res;
+ }
+
+ /** Returns a list of Strings containing Javadoc documentation for
+ the given Java type name (not fully-qualified, only the class
+ name); returns either null or an empty list if there is no
+ Javadoc documentation for the class. */
+ public List javadocForClass(String className) {
+ List res = (List) classJavadoc.get(className);
+ if (res == null) {
+ res = new ArrayList();
+ classJavadoc.put(className, res);
+ }
+ return res;
+ }
+
+ /** Returns the package into which to place the glue code for
+ accessing the specified struct. Defaults to emitting into the
+ regular package (i.e., the result of {@link getPackage}}. */
+ public String packageForStruct(String structName) {
+ String res = (String) structPackages.get(structName);
+ if (res == null) {
+ res = packageName;
+ }
+ return res;
+ }
+
+ /** Returns, as a List of Strings, the custom C code to be emitted
+ along with the glue code for the main class. */
+ public List/*<String>*/ customCCode() {
+ return customCCode;
+ }
+
+ /** Returns, as a List of Strings, the structs for which glue code
+ emission should be forced. */
+ public List/*<String>*/ forcedStructs() {
+ return forcedStructs;
+ }
+
+ /** Returns a List of Integers indicating the indices of arguments
+ in this function that should be expanded to the same type when
+ binding functions with multiple void* arguments. Returns null if
+ no such indices were specified. */
+ public List/*<Integer>*/ mirroredArgs(String functionName) {
+ return (List) mirroredArgs.get(functionName);
+ }
+
+ /** Returns a MessageFormat string of the C expression calculating
+ the capacity of the java.nio.ByteBuffer being returned from a
+ native method, or null if no expression has been specified. */
+ public String returnValueCapacity(String functionName) {
+ return (String) returnValueCapacities.get(functionName);
+ }
+
+ /** Returns a List of Strings of expressions declaring temporary C
+ variables in the glue code for the specified function. */
+ public List/*<String>*/ temporaryCVariableDeclarations(String functionName) {
+ return (List) temporaryCVariableDeclarations.get(functionName);
+ }
+
+ /** Returns a List of Strings of expressions containing assignments
+ to temporary C variables in the glue code for the specified
+ function. */
+ public List/*<String>*/ temporaryCVariableAssignments(String functionName) {
+ return (List) temporaryCVariableAssignments.get(functionName);
+ }
+
+ /** Returns a List of Strings indicating the interfaces the passed
+ interface should declare it extends. May return null or a list
+ of zero length if there are none. */
+ public List/*<String>*/ extendedInterfaces(String interfaceName) {
+ List res = (List) extendedInterfaces.get(interfaceName);
+ if (res == null) {
+ res = new ArrayList();
+ extendedInterfaces.put(interfaceName, res);
+ }
+ return res;
+ }
+
+ /** Returns true if this #define, function, struct, or field within
+ a struct should be ignored during glue code generation. */
+ public boolean shouldIgnore(String symbol) {
+
+ //System.err.println("CHECKING IGNORE: " + symbol);
+
+ // Simple case; the entire symbol is in the ignore table.
+ if (ignores.contains(symbol)) {
+ return true;
+ }
+
+ // Ok, the slow case. We need to check the entire table, in case the table
+ // contains an regular expression that matches the symbol.
+ for (Iterator iter = ignores.iterator(); iter.hasNext(); ) {
+ Pattern regexp = (Pattern)iter.next();
+ Matcher matcher = regexp.matcher(symbol);
+ if (matcher.matches()) {
+ return true;
+ }
+ }
+
+ // Check negated ignore table if not empty
+ if (ignoreNots.size() > 0) {
+ // Ok, the slow case. We need to check the entire table, in case the table
+ // contains an regular expression that matches the symbol.
+ for (Iterator iter = ignoreNots.iterator(); iter.hasNext(); ) {
+ Pattern regexp = (Pattern)iter.next();
+ Matcher matcher = regexp.matcher(symbol);
+ if (!matcher.matches()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /** Returns true if this function should be given a body which
+ throws a run-time exception with an "unimplemented" message
+ during glue code generation. */
+ public boolean isUnimplemented(String symbol) {
+
+ // Simple case; the entire symbol is in the ignore table.
+ if (unimplemented.contains(symbol)) {
+ return true;
+ }
+
+ // Ok, the slow case. We need to check the entire table, in case the table
+ // contains an regular expression that matches the symbol.
+ for (Iterator iter = unimplemented.iterator(); iter.hasNext(); ) {
+ Pattern regexp = (Pattern)iter.next();
+ Matcher matcher = regexp.matcher(symbol);
+ if (matcher.matches()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /** Returns a replacement name for this type, which should be the
+ name of a Java wrapper class for a C struct, or the name
+ unchanged if no RenameJavaType directive was specified for this
+ type. */
+ public String renameJavaType(String javaTypeName) {
+ String rename = (String) javaTypeRenames.get(javaTypeName);
+ if (rename != null) {
+ return rename;
+ }
+ return javaTypeName;
+ }
+
+ /** Returns true if the emission style is AllStatic. */
+ public boolean allStatic() {
+ return (emissionStyle == JavaEmitter.ALL_STATIC);
+ }
+
+ /** Returns true if an interface should be emitted during glue code generation. */
+ public boolean emitInterface() {
+ return (emissionStyle() == JavaEmitter.INTERFACE_AND_IMPL ||
+ emissionStyle() == JavaEmitter.INTERFACE_ONLY);
+ }
+
+ /** Returns true if an implementing class should be emitted during glue code generation. */
+ public boolean emitImpl() {
+ return (emissionStyle() == JavaEmitter.ALL_STATIC ||
+ emissionStyle() == JavaEmitter.INTERFACE_AND_IMPL ||
+ emissionStyle() == JavaEmitter.IMPL_ONLY);
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ protected void dispatch(String cmd, StringTokenizer tok, File file, String filename, int lineNo) throws IOException {
+ //System.err.println("read cmd = [" + cmd + "]");
+ if (cmd.equalsIgnoreCase("Package")) {
+ packageName = readString("package", tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("ImplPackage")) {
+ implPackageName = readString("ImplPackage", tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("JavaClass")) {
+ className = readString("JavaClass", tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("ImplJavaClass")) {
+ implClassName = readString("ImplJavaClass", tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("JavaOutputDir")) {
+ javaOutputDir = readString("JavaOutputDir", tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("NativeOutputDir")) {
+ nativeOutputDir = readString("NativeOutputDir", tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("HierarchicalNativeOutput")) {
+ String tmp = readString("HierarchicalNativeOutput", tok, filename, lineNo);
+ nativeOutputUsesJavaHierarchy = Boolean.valueOf(tmp).booleanValue();
+ } else if (cmd.equalsIgnoreCase("Style")) {
+ String style = readString("Style", tok, filename, lineNo);
+ if (style.equalsIgnoreCase("AllStatic")) {
+ emissionStyle = JavaEmitter.ALL_STATIC;
+ } else if (style.equalsIgnoreCase("InterfaceAndImpl")) {
+ emissionStyle = JavaEmitter.INTERFACE_AND_IMPL;
+ } else if (style.equalsIgnoreCase("InterfaceOnly")) {
+ emissionStyle = JavaEmitter.INTERFACE_ONLY;
+ } else if (style.equalsIgnoreCase("ImplOnly")) {
+ emissionStyle = JavaEmitter.IMPL_ONLY;
+ } else {
+ System.err.println("WARNING: Error parsing \"style\" command at line " + lineNo +
+ " in file \"" + filename + "\"");
+ }
+ } else if (cmd.equalsIgnoreCase("Import")) {
+ imports.add(readString("Import", tok, filename, lineNo));
+ } else if (cmd.equalsIgnoreCase("Opaque")) {
+ readOpaque(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("ReturnsString")) {
+ readReturnsString(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("ReturnedArrayLength")) {
+ readReturnedArrayLength(tok, filename, lineNo);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because ReturnedArrayLength changes them.
+ } else if (cmd.equalsIgnoreCase("ArgumentIsString")) {
+ readArgumentIsString(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("Ignore")) {
+ readIgnore(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("IgnoreNot")) {
+ readIgnoreNot(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("Unimplemented")) {
+ readUnimplemented(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("IgnoreField")) {
+ readIgnoreField(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("ManuallyImplement")) {
+ readManuallyImplement(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("CustomJavaCode")) {
+ readCustomJavaCode(tok, filename, lineNo);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because readCustomJavaCode changes them.
+ } else if (cmd.equalsIgnoreCase("CustomCCode")) {
+ readCustomCCode(tok, filename, lineNo);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because readCustomCCode changes them.
+ } else if (cmd.equalsIgnoreCase("ClassJavadoc")) {
+ readClassJavadoc(tok, filename, lineNo);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because readClassJavadoc changes them.
+ } else if (cmd.equalsIgnoreCase("NioOnly")) {
+ nioOnly.add(readString("NioOnly", tok, filename, lineNo));
+ } else if (cmd.equalsIgnoreCase("EmitStruct")) {
+ forcedStructs.add(readString("EmitStruct", tok, filename, lineNo));
+ } else if (cmd.equalsIgnoreCase("MirrorExpandedBindingArgs")) {
+ readMirrorExpandedBindingArgs(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("StructPackage")) {
+ readStructPackage(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("TemporaryCVariableDeclaration")) {
+ readTemporaryCVariableDeclaration(tok, filename, lineNo);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because TemporaryCVariableDeclaration changes them.
+ } else if (cmd.equalsIgnoreCase("TemporaryCVariableAssignment")) {
+ readTemporaryCVariableAssignment(tok, filename, lineNo);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because TemporaryCVariableAssignment changes them.
+ } else if (cmd.equalsIgnoreCase("ReturnValueCapacity")) {
+ readReturnValueCapacity(tok, filename, lineNo);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because ReturnValueCapacity changes them.
+ } else if (cmd.equalsIgnoreCase("Include")) {
+ doInclude(tok, file, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("IncludeAs")) {
+ doIncludeAs(tok, file, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("Extends")) {
+ readExtend(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("RenameJavaType")) {
+ readRenameJavaType(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("RuntimeExceptionType")) {
+ runtimeExceptionType = readString("RuntimeExceptionType", tok, filename, lineNo);
+ } else {
+ throw new RuntimeException("Unknown command \"" + cmd +
+ "\" in command file " + filename +
+ " at line number " + lineNo);
+ }
+ }
+
+ protected String readString(String cmd, StringTokenizer tok, String filename, int lineNo) {
+ try {
+ return tok.nextToken();
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"" + cmd + "\" command at line " + lineNo +
+ " in file \"" + filename + "\": missing expected parameter", e);
+ }
+ }
+
+ protected Boolean readBoolean(String cmd, StringTokenizer tok, String filename, int lineNo) {
+ try {
+ return Boolean.valueOf(tok.nextToken());
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"" + cmd + "\" command at line " + lineNo +
+ " in file \"" + filename + "\": missing expected boolean value", e);
+ }
+ }
+
+ protected Class stringToPrimitiveType(String type) throws ClassNotFoundException {
+ if (type.equals("boolean")) return Boolean.TYPE;
+ if (type.equals("byte")) return Integer.TYPE;
+ if (type.equals("char")) return Character.TYPE;
+ if (type.equals("short")) return Short.TYPE;
+ if (type.equals("int")) return Integer.TYPE;
+ if (type.equals("long")) return Long.TYPE;
+ if (type.equals("float")) return Float.TYPE;
+ if (type.equals("double")) return Double.TYPE;
+ throw new RuntimeException("Only primitive types are supported here");
+ }
+
+ protected void readOpaque(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ JavaType javaType = JavaType.createForClass(stringToPrimitiveType(tok.nextToken()));
+ String cType = null;
+ while (tok.hasMoreTokens()) {
+ if (cType == null) {
+ cType = tok.nextToken();
+ } else {
+ cType = cType + " " + tok.nextToken();
+ }
+ }
+ if (cType == null) {
+ throw new RuntimeException("No C type for \"Opaque\" command at line " + lineNo +
+ " in file \"" + filename + "\"");
+ }
+ TypeInfo info = parseTypeInfo(cType, javaType);
+ addTypeInfo(info);
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing \"Opaque\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readReturnsString(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String name = tok.nextToken();
+ returnsString.add(name);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"ReturnsString\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readReturnedArrayLength(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String functionName = tok.nextToken();
+ String restOfLine = tok.nextToken("\n\r\f");
+ restOfLine = restOfLine.trim();
+ returnedArrayLengths.put(functionName, restOfLine);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"ReturnedArrayLength\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readIgnore(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String regex = tok.nextToken();
+ ignores.add(Pattern.compile(regex));
+ //System.err.println("IGNORING " + regex + " / " + ignores.get(regex));
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"Ignore\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readIgnoreNot(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String regex = tok.nextToken();
+ ignoreNots.add(Pattern.compile(regex));
+ //System.err.println("IGNORING NEGATION OF " + regex + " / " + ignores.get(regex));
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"IgnoreNot\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readUnimplemented(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String regex = tok.nextToken();
+ unimplemented.add(Pattern.compile(regex));
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"Unimplemented\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readIgnoreField(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String containingStruct = tok.nextToken();
+ String name = tok.nextToken();
+ ignores.add(Pattern.compile(containingStruct + " " + name));
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"IgnoreField\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readManuallyImplement(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String name = tok.nextToken();
+ manuallyImplement.add(name);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"ManuallyImplement\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readCustomJavaCode(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String className = tok.nextToken();
+ String restOfLine = tok.nextToken("\n\r\f");
+ addCustomJavaCode(className, restOfLine);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"CustomJavaCode\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void addCustomJavaCode(String className, String code) {
+ List codeList = customJavaCodeForClass(className);
+ codeList.add(code);
+ }
+
+ protected void readCustomCCode(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String restOfLine = tok.nextToken("\n\r\f");
+ customCCode.add(restOfLine);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"CustomCCode\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readClassJavadoc(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String className = tok.nextToken();
+ String restOfLine = tok.nextToken("\n\r\f");
+ addClassJavadoc(className, restOfLine);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"ClassJavadoc\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void addClassJavadoc(String className, String code) {
+ List codeList = javadocForClass(className);
+ codeList.add(code);
+ }
+
+ /**
+ * When void* arguments in the C function prototypes are encountered, the
+ * emitter will try to expand the binding and create Java entry points for
+ * all possible array types. If there are 2 or more void* arguments in the C
+ * prototype, this directive lets you specify which of those arguments
+ * should always be expanded to the same type. <p>
+ *
+ * For example, given the C prototype:
+ * <pre>
+ * void FuncName(void *foo, void *bar);
+ * </pre>
+ *
+ * The emitter will normally emit multiple Java entry points:
+ * <pre>
+ * public abstract void FuncName(boolean[] foo, java.nio.Buffer bar);
+ * public abstract void FuncName(boolean[] foo, boolean[] bar);
+ * public abstract void FuncName(boolean[] foo, byte[] bar);
+ * public abstract void FuncName(boolean[] foo, char[] bar);
+ * public abstract void FuncName(boolean[] foo, short[] bar);
+ * public abstract void FuncName(boolean[] foo, int[] bar);
+ * public abstract void FuncName(boolean[] foo, long[] bar);
+ * public abstract void FuncName(boolean[] foo, float[] bar);
+ * public abstract void FuncName(boolean[] foo, double[] bar);
+ *
+ * public abstract void FuncName(byte[] foo, java.nio.Buffer bar);
+ * public abstract void FuncName(byte[] foo, boolean[] bar);
+ * public abstract void FuncName(byte[] foo, byte[] bar);
+ * <...etc for all variants on the second parameter...>
+ *
+ * public abstract void FuncName(char[] foo, java.nio.Buffer bar);
+ * public abstract void FuncName(char[] foo, boolean[] bar);
+ * public abstract void FuncName(char[] foo, byte[] bar);
+ * <...etc for all variants on the second parameter...>
+ * <...and so on for all remaining variants on the first parameter...>
+ * </pre>
+ *
+ * This directive lets you specify that arguments at a particular index
+ * should always be expanded to the same type. For example, the directive:
+ * <pre>
+ * MirrorExpandedBindingArgs FuncName 0 1
+ * </pre>
+ * will force the first and second arguments in function FuncName to be
+ * expanded identically. This would result in the emission of the following
+ * entry points only:
+ * <pre>
+ * public abstract void FuncName(java.nio.Buffer[] foo, java.nio.Buffer bar);
+ * public abstract void FuncName(boolean[] foo, boolean[] bar);
+ * public abstract void FuncName(byte[] foo, byte[] bar);
+ * public abstract void FuncName(char[] foo, char[] bar);
+ * public abstract void FuncName(short[] foo, short[] bar);
+ * public abstract void FuncName(int[] foo, int[] bar);
+ * public abstract void FuncName(long[] foo, long[] bar);
+ * public abstract void FuncName(float[] foo, float[] bar);
+ * public abstract void FuncName(double[] foo, double[] bar);
+ * </pre>
+ */
+ protected void readMirrorExpandedBindingArgs(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String methodName = tok.nextToken();
+ ArrayList argIndices = new ArrayList(2);
+ while (tok.hasMoreTokens())
+ {
+ Integer idx = Integer.valueOf(tok.nextToken());
+ argIndices.add(idx);
+ }
+
+ if(argIndices.size() > 1)
+ {
+ mirroredArgs.put(methodName, argIndices);
+ }
+ else
+ {
+ throw new RuntimeException("ERROR: Error parsing \"MirrorExpandedBindingArgs\" command at line " + lineNo +
+ " in file \"" + filename + "\": directive requires at least 2 argument indices");
+ }
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException(
+ "Error parsing \"MirrorExpandedBindingArgs\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ /**
+ * When const char* arguments in the C function prototypes are encountered,
+ * the emitter will normally convert them to <code>byte[]</code>
+ * arguments. This directive lets you specify which of those arguments
+ * should be converted to <code>String</code> arguments instead of <code>
+ * byte[] </code>. <p>
+ *
+ * For example, given the C prototype:
+ * <pre>
+ * void FuncName(const char* ugh, int bar, const char *foo, const char* goop);
+ * </pre>
+ *
+ * The emitter will normally emit:
+ * <pre>
+ * public abstract void FuncName(byte[] ugh, int bar, byte[] foo, byte[] goop);
+ * </pre>
+ *
+ * However, if you supplied the following directive:
+ *
+ * <pre>
+ * ArgumentIsString FuncName 0 2
+ * </pre>
+ *
+ * The emitter will instead emit:
+ * <pre>
+ * public abstract void FuncName(String ugh, int bar, String foo, byte[] goop);
+ * </pre>
+ *
+ */
+ protected void readArgumentIsString(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String methodName = tok.nextToken();
+ ArrayList argIndices = new ArrayList(2);
+ while (tok.hasMoreTokens()) {
+ Integer idx = Integer.valueOf(tok.nextToken());
+ argIndices.add(idx);
+ }
+
+ if(argIndices.size() > 0) {
+ argumentsAreString.put(methodName, argIndices);
+ }
+ else {
+ throw new RuntimeException("ERROR: Error parsing \"ArgumentIsString\" command at line " + lineNo +
+ " in file \"" + filename + "\": directive requires specification of at least 1 index");
+ }
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException(
+ "Error parsing \"ArgumentIsString\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readStructPackage(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String struct = tok.nextToken();
+ String pkg = tok.nextToken();
+ structPackages.put(struct, pkg);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"StructPackage\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readReturnValueCapacity(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String functionName = tok.nextToken();
+ String restOfLine = tok.nextToken("\n\r\f");
+ restOfLine = restOfLine.trim();
+ returnValueCapacities.put(functionName, restOfLine);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"ReturnValueCapacity\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readTemporaryCVariableDeclaration(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String functionName = tok.nextToken();
+ String restOfLine = tok.nextToken("\n\r\f");
+ restOfLine = restOfLine.trim();
+ List list = (List) temporaryCVariableDeclarations.get(functionName);
+ if (list == null) {
+ list = new ArrayList/*<String>*/();
+ temporaryCVariableDeclarations.put(functionName, list);
+ }
+ list.add(restOfLine);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"TemporaryCVariableDeclaration\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readTemporaryCVariableAssignment(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String functionName = tok.nextToken();
+ String restOfLine = tok.nextToken("\n\r\f");
+ restOfLine = restOfLine.trim();
+ List list = (List) temporaryCVariableAssignments.get(functionName);
+ if (list == null) {
+ list = new ArrayList/*<String>*/();
+ temporaryCVariableAssignments.put(functionName, list);
+ }
+ list.add(restOfLine);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"TemporaryCVariableAssignment\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void doInclude(StringTokenizer tok, File file, String filename, int lineNo) throws IOException {
+ try {
+ String includedFilename = tok.nextToken();
+ File includedFile = new File(includedFilename);
+ if (!includedFile.isAbsolute()) {
+ includedFile = new File(file.getParentFile(), includedFilename);
+ }
+ read(includedFile.getAbsolutePath());
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"Include\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void doIncludeAs(StringTokenizer tok, File file, String filename, int lineNo) throws IOException {
+ try {
+ StringBuffer linePrefix = new StringBuffer(128);
+ while (tok.countTokens() > 1)
+ {
+ linePrefix.append(tok.nextToken());
+ linePrefix.append(" ");
+ }
+ // last token is filename
+ String includedFilename = tok.nextToken();
+ File includedFile = new File(includedFilename);
+ if (!includedFile.isAbsolute()) {
+ includedFile = new File(file.getParentFile(), includedFilename);
+ }
+ read(includedFile.getAbsolutePath(), linePrefix.toString());
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"IncludeAs\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readExtend(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String interfaceName = tok.nextToken();
+ List intfs = extendedInterfaces(interfaceName);
+ intfs.add(tok.nextToken());
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"Extends\" command at line " + lineNo +
+ " in file \"" + filename + "\": missing expected parameter", e);
+ }
+ }
+
+ protected void readRenameJavaType(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String fromName = tok.nextToken();
+ String toName = tok.nextToken();
+ javaTypeRenames.put(fromName, toName);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"RenameJavaType\" command at line " + lineNo +
+ " in file \"" + filename + "\": missing expected parameter", e);
+ }
+ }
+
+ protected static TypeInfo parseTypeInfo(String cType, JavaType javaType) {
+ String typeName = null;
+ int pointerDepth = 0;
+ int idx = 0;
+ while (idx < cType.length() &&
+ (cType.charAt(idx) != ' ') &&
+ (cType.charAt(idx) != '*')) {
+ ++idx;
+ }
+ typeName = cType.substring(0, idx);
+ // Count pointer depth
+ while (idx < cType.length()) {
+ if (cType.charAt(idx) == '*') {
+ ++pointerDepth;
+ }
+ ++idx;
+ }
+ return new TypeInfo(typeName, pointerDepth, javaType);
+ }
+
+ protected void addTypeInfo(TypeInfo info) {
+ TypeInfo tmp = (TypeInfo) typeInfoMap.get(info.name());
+ if (tmp == null) {
+ typeInfoMap.put(info.name(), info);
+ return;
+ }
+ while (tmp.next() != null) {
+ tmp = tmp.next();
+ }
+ tmp.setNext(info);
+ }
+}
diff --git a/src/net/java/games/gluegen/JavaEmitter.java b/src/net/java/games/gluegen/JavaEmitter.java
new file mode 100644
index 000000000..228b5aff2
--- /dev/null
+++ b/src/net/java/games/gluegen/JavaEmitter.java
@@ -0,0 +1,1246 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.io.*;
+import java.util.*;
+import java.text.MessageFormat;
+
+import net.java.games.gluegen.cgram.types.*;
+
+// PROBLEMS:
+// - what if something returns 'const int *'? Could we
+// return an IntBuffer that has read-only behavior? Or do we copy the array
+// (but we don't know its size!). What do we do if it returns a non-const
+// int*? Should the user be allowed to write back to the returned pointer?
+//
+// - Non-const array types must be properly released with JNI_COMMIT
+// in order to see side effects if the array was copied.
+
+
+public class JavaEmitter implements GlueEmitter {
+ private StructLayout layout;
+ private TypeDictionary typedefDictionary;
+ private TypeDictionary structDictionary;
+ private Map canonMap;
+ private JavaConfiguration cfg;
+
+ /**
+ * Style of code emission. Can emit everything into one class
+ * (AllStatic), separate interface and implementing classes
+ * (InterfaceAndImpl), only the interface (InterfaceOnly), or only
+ * the implementation (ImplOnly).
+ */
+ static final int ALL_STATIC = 1;
+ static final int INTERFACE_AND_IMPL = 2;
+ static final int INTERFACE_ONLY = 3;
+ static final int IMPL_ONLY = 4;
+
+ private PrintWriter javaWriter; // Emits either interface or, in AllStatic mode, everything
+ private PrintWriter javaImplWriter; // Only used in non-AllStatic modes for impl class
+ private PrintWriter cWriter;
+ private MachineDescription machDesc;
+
+ public void readConfigurationFile(String filename) throws Exception {
+ cfg = createConfig();
+ cfg.read(filename);
+ }
+
+ public void setMachineDescription(MachineDescription md) {
+ machDesc = md;
+ }
+
+ public void beginEmission(GlueEmitterControls controls) throws IOException
+ {
+ try
+ {
+ openWriters();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(
+ "Unable to open files for writing", e);
+ }
+
+ emitAllFileHeaders();
+
+ // Request emission of any structs requested
+ for (Iterator iter = cfg.forcedStructs().iterator(); iter.hasNext(); ) {
+ controls.forceStructEmission((String) iter.next());
+ }
+ }
+
+ public void endEmission()
+ {
+ emitAllFileFooters();
+
+ try
+ {
+ closeWriters();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(
+ "Unable to close open files", e);
+ }
+ }
+
+ public void beginDefines() throws Exception
+ {
+ if (cfg.allStatic() || cfg.emitInterface()) {
+ javaWriter().println();
+ }
+ }
+
+ public void emitDefine(String name, String value, String optionalComment) throws Exception
+ {
+ if (cfg.allStatic() || cfg.emitInterface()) {
+ // TODO: Some defines (e.g., GL_DOUBLE_EXT in gl.h) are defined in terms
+ // of other defines -- should we emit them as references to the original
+ // define (not even sure if the lexer supports this)? Right now they're
+ // emitted as the numeric value of the original definition. If we decide
+ // emit them as references we'll also have to emit them in the correct
+ // order. It's probably not an issue right now because the emitter
+ // currently only emits only numeric defines -- if it handled #define'd
+ // objects it would make a bigger difference.
+
+ if (!cfg.shouldIgnore(name)) {
+ String type = null;
+
+ // FIXME: need to handle when type specifier is in last char (e.g.,
+ // "1.0d or 2759L", because parseXXX() methods don't allow the type
+ // specifier character in the string.
+ //
+ //char lastChar = value.charAt(value.length()-1);
+
+ try {
+ // see if it's a long or int
+ int radix;
+ String parseValue;
+ // FIXME: are you allowed to specify hex/octal constants with
+ // negation, e.g. "-0xFF" or "-056"? If so, need to modify the
+ // following "if(..)" checks and parseValue computation
+ if (value.startsWith("0x") || value.startsWith("0X")) {
+ radix = 16;
+ parseValue = value.substring(2);
+ }
+ else if (value.startsWith("0") && value.length() > 1) {
+ // TODO: is "0" the prefix in C to indicate octal???
+ radix = 8;
+ parseValue = value.substring(1);
+ }
+ else {
+ radix = 10;
+ parseValue = value;
+ }
+ //System.err.println("parsing " + value + " as long w/ radix " + radix);
+ long longVal = Long.parseLong(parseValue, radix);
+ type = "long";
+ // if constant is small enough, store it as an int instead of a long
+ if (longVal > Integer.MIN_VALUE && longVal < Integer.MAX_VALUE) {
+ type = "int";
+ }
+
+ } catch (NumberFormatException e) {
+ try {
+ // see if it's a double or float
+ double dVal = Double.parseDouble(value);
+ type = "double";
+ // if constant is small enough, store it as a float instead of a double
+ if (dVal > Float.MIN_VALUE && dVal < Float.MAX_VALUE) {
+ type = "float";
+ }
+
+ } catch (NumberFormatException e2) {
+ throw new RuntimeException(
+ "Cannot emit define \""+name+"\": value \""+value+
+ "\" cannot be assigned to a int, long, float, or double", e2);
+ }
+ }
+
+ if (type == null) {
+ throw new RuntimeException(
+ "Cannot emit define (2) \""+name+"\": value \""+value+
+ "\" cannot be assigned to a int, long, float, or double");
+ }
+ if (optionalComment != null && optionalComment.length() != 0) {
+ javaWriter().println(" /** " + optionalComment + " */");
+ }
+ javaWriter().println(" public static final " + type + " " + name + " = " + value + ";");
+ }
+ }
+ }
+
+ public void endDefines() throws Exception
+ {
+ }
+
+ public void beginFunctions(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) throws Exception {
+ this.typedefDictionary = typedefDictionary;
+ this.structDictionary = structDictionary;
+ this.canonMap = canonMap;
+ if (cfg.allStatic() || cfg.emitInterface()) {
+ javaWriter().println();
+ }
+ }
+
+ public Iterator emitFunctions(List/*<FunctionSymbol>*/ originalCFunctions)
+ throws Exception {
+ // Sometimes headers will have the same function prototype twice, once
+ // with the argument names and once without. We'll remember the signatures
+ // we've already processed we don't generate duplicate bindings.
+ //
+ // Note: this code assumes that on the equals() method in FunctionSymbol
+ // only considers function name and argument types (i.e., it does not
+ // consider argument *names*) when comparing FunctionSymbols for equality
+ Set funcsToBindSet = new HashSet(100);
+ for (Iterator cIter = originalCFunctions.iterator(); cIter.hasNext(); ) {
+ FunctionSymbol cFunc = (FunctionSymbol) cIter.next();
+ if (!funcsToBindSet.contains(cFunc)) {
+ funcsToBindSet.add(cFunc);
+ }
+ }
+
+ ArrayList funcsToBind = new ArrayList(funcsToBindSet.size());
+ funcsToBind.addAll(funcsToBindSet);
+ // sort functions to make them easier to find in native code
+ Collections.sort(
+ funcsToBind,
+ new Comparator() {
+ public int compare(Object o1, Object o2) {
+ return ((FunctionSymbol)o1).getName().compareTo(
+ ((FunctionSymbol)o2).getName());
+ }
+ public boolean equals(Object obj) {
+ return obj.getClass() == this.getClass();
+ }
+ });
+
+ // Bind all the C funcs to Java methods
+ ArrayList/*<FunctionEmitter>*/ methodBindingEmitters = new ArrayList(2*funcsToBind.size());
+ for (Iterator iter = funcsToBind.iterator(); iter.hasNext(); ) {
+ FunctionSymbol cFunc = (FunctionSymbol) iter.next();
+ // Check to see whether this function should be ignored
+ if (cfg.shouldIgnore(cFunc.getName())) {
+ continue; // don't generate bindings for this symbol
+ }
+
+ Iterator allBindings = generateMethodBindingEmitters(cFunc);
+ while (allBindings.hasNext()) {
+ methodBindingEmitters.add(allBindings.next());
+ }
+ }
+
+ // Emit all the methods
+ for (int i = 0; i < methodBindingEmitters.size(); ++i) {
+ FunctionEmitter emitter = (FunctionEmitter)methodBindingEmitters.get(i);
+ try {
+ emitter.emit();
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Error while emitting binding for \"" + emitter.getName() + "\"", e);
+ }
+ emitter.getDefaultOutput().println(); // put newline after method body
+ }
+
+ // Return the list of FunctionSymbols that we generated gluecode for
+ return funcsToBind.iterator();
+ }
+
+ /**
+ * Create the object that will read and store configuration information for
+ * this JavaEmitter.
+ */
+ protected JavaConfiguration createConfig() {
+ return new JavaConfiguration();
+ }
+
+ /**
+ * Get the configuration information for this JavaEmitter.
+ */
+ protected JavaConfiguration getConfig() {
+ return cfg;
+ }
+
+ /**
+ * Generate all appropriate Java bindings for the specified C function
+ * symbols.
+ */
+ protected Iterator generateMethodBindingEmitters(FunctionSymbol sym) throws Exception {
+
+ ArrayList/*<FunctionEmitter>*/ allEmitters = new ArrayList(1);
+
+ try {
+ // Get Java binding for the function
+ MethodBinding mb = bindFunction(sym, null, null);
+
+ // Expand all void* arguments
+ List bindings = expandMethodBinding(mb);
+ boolean overloaded = (bindings.size() > 1);
+ if (overloaded) {
+ // resize ahead of time for speed
+ allEmitters.ensureCapacity(bindings.size());
+ }
+
+ // List of the indices of the arguments in this function that should be
+ // expanded to the same type when binding functions with multiple void*
+ // arguments
+ List mirrorIdxs = cfg.mirroredArgs(sym.getName());
+
+ for (Iterator iter = bindings.iterator(); iter.hasNext(); ) {
+ MethodBinding binding = (MethodBinding) iter.next();
+
+ // Honor the MirrorExpandedBindingArgs directive in .cfg files
+ if (mirrorIdxs != null) {
+ assert(mirrorIdxs.size() >= 2); // sanity check.
+ boolean typesMatch = true;
+ int argIndex = ((Integer)mirrorIdxs.get(0)).intValue();
+ JavaType leftArgType = binding.getJavaArgumentType(argIndex);
+ for (int i = 1; i < mirrorIdxs.size(); ++i) {
+ argIndex = ((Integer)mirrorIdxs.get(i)).intValue();
+ JavaType rightArgType = binding.getJavaArgumentType(argIndex);
+ if (!(leftArgType.equals(rightArgType))) {
+ typesMatch = false;
+ break;
+ }
+ leftArgType = rightArgType;
+ }
+ // Don't emit the binding if the specified args aren't the same type
+ if (!typesMatch) { continue; } // skip this binding
+ }
+
+ // Try to create an NIOBuffer variant for this expanded binding. If
+ // it's the same as the original binding, then we'll be able to emit
+ // the binding like any normal binding because no special binding
+ // generation (wrapper methods, etc) will be necessary.
+ MethodBinding specialBinding = binding.createNIOBufferVariant();
+
+ if (cfg.allStatic() && binding.hasContainingType()) {
+ // This should not currently happen since structs are emitted using a different mechanism
+ throw new IllegalArgumentException("Cannot create binding in AllStatic mode because method has containing type: \"" +
+ binding + "\"");
+ }
+
+ boolean isUnimplemented = cfg.isUnimplemented(binding.getName());
+
+ if (cfg.emitImpl()) {
+ // Generate the emitter for the method which may do conversion
+ // from type wrappers to NIO Buffers or which may call the
+ // underlying function directly
+ JavaMethodBindingImplEmitter entryPoint =
+ new JavaMethodBindingImplEmitter(binding,
+ (cfg.allStatic() ? javaWriter() : javaImplWriter()),
+ cfg.runtimeExceptionType(),
+ isUnimplemented);
+ entryPoint.addModifier(JavaMethodBindingEmitter.PUBLIC);
+ if (cfg.allStatic()) {
+ entryPoint.addModifier(JavaMethodBindingEmitter.STATIC);
+ }
+ if (!isUnimplemented && !binding.needsBody()) {
+ entryPoint.addModifier(JavaMethodBindingEmitter.NATIVE);
+ }
+ entryPoint.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName()));
+ allEmitters.add(entryPoint);
+ }
+
+ if (cfg.emitInterface()) {
+ // Generate an emitter that will emit just the interface to the function
+ JavaMethodBindingEmitter entryPointInterface =
+ new JavaMethodBindingEmitter(binding, javaWriter(), cfg.runtimeExceptionType());
+ entryPointInterface.addModifier(JavaMethodBindingEmitter.PUBLIC);
+ entryPointInterface.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName()));
+ allEmitters.add(entryPointInterface);
+ }
+
+ if (cfg.emitImpl() && binding.needsBody() && !isUnimplemented) {
+ // Generate the method which calls the underlying function
+ // after unboxing has occurred
+ PrintWriter output = cfg.allStatic() ? javaWriter() : javaImplWriter();
+ JavaMethodBindingEmitter wrappedEntryPoint =
+ new JavaMethodBindingEmitter(specialBinding, output, cfg.runtimeExceptionType(), true);
+ wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.PRIVATE);
+ wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.STATIC); // Doesn't really matter
+ wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.NATIVE);
+ allEmitters.add(wrappedEntryPoint);
+ }
+
+ // If the user has stated that the function will be
+ // manually implemented, then don't auto-generate a function body.
+ if (cfg.emitImpl()) {
+ if (!cfg.manuallyImplement(sym.getName()) && !isUnimplemented)
+ {
+ CMethodBindingEmitter cEmitter =
+ makeCEmitter(specialBinding,
+ overloaded,
+ (binding != specialBinding),
+ cfg.implPackageName(), cfg.implClassName(),
+ cWriter());
+ allEmitters.add(cEmitter);
+ }
+ }
+ } // end iteration over expanded bindings
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Error while generating bindings for \"" + sym + "\"", e);
+ }
+
+ return allEmitters.iterator();
+ }
+
+
+ public void endFunctions() throws Exception
+ {
+ if (cfg.allStatic() || cfg.emitInterface()) {
+ emitCustomJavaCode(javaWriter(), cfg.className());
+ }
+ if (!cfg.allStatic() && cfg.emitImpl()) {
+ emitCustomJavaCode(javaImplWriter(), cfg.implClassName());
+ }
+ }
+
+ public void beginStructLayout() throws Exception {}
+ public void layoutStruct(CompoundType t) throws Exception {
+ getLayout().layout(t);
+ }
+ public void endStructLayout() throws Exception {}
+
+ public void beginStructs(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) throws Exception {
+ this.typedefDictionary = typedefDictionary;
+ this.structDictionary = structDictionary;
+ this.canonMap = canonMap;
+ }
+
+ public void emitStruct(CompoundType structType) throws Exception {
+ if (structType.getName() == null) {
+ System.err.println("WARNING: skipping emission of unnamed struct \"" + structType + "\"");
+ return;
+ }
+
+ if (cfg.shouldIgnore(structType.getName())) {
+ return;
+ }
+
+ Type containingCType = canonicalize(new PointerType(machDesc.pointerSizeInBytes(), structType, 0));
+ JavaType containingType = typeToJavaType(containingCType, false);
+ String containingTypeName = containingType.getName();
+
+ boolean needsNativeCode = false;
+ for (int i = 0; i < structType.getNumFields(); i++) {
+ if (structType.getField(i).getType().isFunctionPointer()) {
+ needsNativeCode = true;
+ break;
+ }
+ }
+
+ String structClassPkg = cfg.packageForStruct(structType.getName());
+ PrintWriter writer = null;
+ PrintWriter cWriter = null;
+ try
+ {
+ writer = openFile(
+ cfg.javaOutputDir() + File.separator +
+ CodeGenUtils.packageAsPath(structClassPkg) +
+ File.separator + containingTypeName + ".java");
+ CodeGenUtils.emitAutogeneratedWarning(writer, this);
+ if (needsNativeCode) {
+ String nRoot = cfg.nativeOutputDir();
+ if (cfg.nativeOutputUsesJavaHierarchy()) {
+ nRoot +=
+ File.separator +
+ CodeGenUtils.packageAsPath(cfg.packageName());
+ }
+ cWriter = openFile(nRoot + File.separator + containingTypeName + "_JNI.c");
+ CodeGenUtils.emitAutogeneratedWarning(cWriter, this);
+ emitCHeader(cWriter, containingTypeName);
+ }
+ }
+ catch(Exception e)
+ {
+ throw new RuntimeException(
+ "Unable to open files for emission of struct class", e);
+ }
+
+ writer.println();
+ writer.println("package " + structClassPkg + ";");
+ writer.println();
+ writer.println("import java.nio.*;");
+ writer.println();
+ writer.println("import net.java.games.gluegen.runtime.*;");
+ writer.println();
+ List/*<String>*/ javadoc = cfg.javadocForClass(containingTypeName);
+ for (Iterator iter = javadoc.iterator(); iter.hasNext(); ) {
+ writer.println((String) iter.next());
+ }
+ writer.println();
+ writer.println("public class " + containingTypeName + " {");
+ writer.println(" private StructAccessor accessor;");
+ writer.println();
+ writer.println(" public static int size() {");
+ writer.println(" return " + structType.getSize() + ";");
+ writer.println(" }");
+ writer.println();
+ writer.println(" public " + containingTypeName + "() {");
+ writer.println(" this(BufferFactory.newDirectByteBuffer(size()));");
+ writer.println(" }");
+ writer.println();
+ writer.println(" public " + containingTypeName + "(ByteBuffer buf) {");
+ writer.println(" accessor = new StructAccessor(buf);");
+ writer.println(" }");
+ writer.println();
+ writer.println(" public ByteBuffer getBuffer() {");
+ writer.println(" return accessor.getBuffer();");
+ writer.println(" }");
+ for (int i = 0; i < structType.getNumFields(); i++) {
+ Field field = structType.getField(i);
+ Type fieldType = field.getType();
+ if (!cfg.shouldIgnore(structType.getName() + " " + field.getName())) {
+ if (fieldType.isFunctionPointer()) {
+ try {
+ // Emit method call and associated native code
+ FunctionType funcType = fieldType.asPointer().getTargetType().asFunction();
+ FunctionSymbol funcSym = new FunctionSymbol(field.getName(), funcType);
+ MethodBinding binding = bindFunction(funcSym, containingType, containingCType);
+ binding.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis
+ MethodBinding specialBinding = binding.createNIOBufferVariant();
+ writer.println();
+
+ JavaMethodBindingEmitter entryPoint = new JavaMethodBindingImplEmitter(binding, writer, cfg.runtimeExceptionType());
+ entryPoint.addModifier(JavaMethodBindingEmitter.PUBLIC);
+ if (!binding.needsBody() && !binding.hasContainingType()) {
+ entryPoint.addModifier(JavaMethodBindingEmitter.NATIVE);
+ }
+ entryPoint.emit();
+
+ JavaMethodBindingEmitter wrappedEntryPoint = new JavaMethodBindingEmitter(specialBinding, writer, cfg.runtimeExceptionType(), true);
+ wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.PRIVATE);
+ wrappedEntryPoint.addModifier(JavaMethodBindingEmitter.NATIVE);
+ wrappedEntryPoint.emit();
+
+ CMethodBindingEmitter cEmitter =
+ makeCEmitter(specialBinding,
+ false, // overloaded
+ true, // doing impl routine?
+ structClassPkg,
+ containingTypeName,
+ cWriter);
+ cEmitter.emit();
+ } catch (Exception e) {
+ System.err.println("While processing field " + field + " of type " + structType.getName() + ":");
+ throw(e);
+ }
+ } else if (fieldType.isCompound()) {
+ // FIXME: will need to support this at least in order to
+ // handle the union in jawt_Win32DrawingSurfaceInfo (fabricate
+ // a name?)
+ if (fieldType.getName() == null) {
+ throw new RuntimeException("Anonymous structs as fields not supported yet (field \"" +
+ field + "\" in type \"" + structType.getName() + "\")");
+ }
+
+ writer.println();
+ writer.println(" public " + fieldType.getName() + " " + field.getName() + "() {");
+ writer.println(" return new " + fieldType.getName() + "(accessor.slice(" +
+ field.getOffset() + ", " + fieldType.getSize() + "));");
+ writer.println(" }");
+
+ // FIXME: add setter by autogenerating "copyTo" for all compound type wrappers
+ } else if (fieldType.isArray()) {
+ System.err.println("WARNING: Array fields (field \"" + field + "\" of type \"" + structType.getName() +
+ "\") not implemented yet");
+ } else {
+ JavaType javaType = null;
+ try {
+ javaType = typeToJavaType(fieldType, false);
+ } catch (Exception e) {
+ System.err.println("Error occurred while creating accessor for field \"" +
+ field.getName() + "\" in type \"" + structType.getName() + "\"");
+ e.printStackTrace();
+ throw(e);
+ }
+ if (javaType.isPrimitive()) {
+ // Primitive type
+ String externalJavaTypeName = javaType.getName();
+ String internalJavaTypeName = externalJavaTypeName;
+ if (isOpaque(fieldType)) {
+ internalJavaTypeName = compatiblePrimitiveJavaTypeName(fieldType, javaType);
+ }
+ String capitalized =
+ "" + Character.toUpperCase(internalJavaTypeName.charAt(0)) + internalJavaTypeName.substring(1);
+ int slot = slot(fieldType, (int) field.getOffset());
+ // Setter
+ writer.println();
+ writer.println(" public " + containingTypeName + " " + field.getName() + "(" + externalJavaTypeName + " val) {");
+ writer.print (" accessor.set" + capitalized + "At(" + slot + ", ");
+ if (!externalJavaTypeName.equals(internalJavaTypeName)) {
+ writer.print("(" + internalJavaTypeName + ") ");
+ }
+ writer.println("val);");
+ writer.println(" return this;");
+ writer.println(" }");
+ // Getter
+ writer.println();
+ writer.println(" public " + externalJavaTypeName + " " + field.getName() + "() {");
+ writer.print (" return ");
+ if (!externalJavaTypeName.equals(internalJavaTypeName)) {
+ writer.print("(" + externalJavaTypeName + ") ");
+ }
+ writer.println("accessor.get" + capitalized + "At(" + slot + ");");
+ writer.println(" }");
+ } else {
+ // FIXME
+ String name = structType.getName();
+ if (name == null) {
+ name = structType.toString();
+ }
+ System.err.println("WARNING: Complicated fields (field \"" + field + "\" of type \"" + name +
+ "\") not implemented yet");
+ // throw new RuntimeException("Complicated fields (field \"" + field + "\" of type \"" + t +
+ // "\") not implemented yet");
+ }
+ }
+ }
+ }
+ emitCustomJavaCode(writer, containingTypeName);
+ writer.println("}");
+ writer.flush();
+ writer.close();
+ if (needsNativeCode) {
+ cWriter.flush();
+ cWriter.close();
+ }
+ }
+ public void endStructs() throws Exception {}
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private CMethodBindingEmitter makeCEmitter(MethodBinding binding,
+ boolean overloaded,
+ boolean doingImplRoutine,
+ String bindingJavaPackageName,
+ String bindingJavaClassName,
+ PrintWriter output) {
+ MessageFormat returnValueCapacityFormat = null;
+ JavaType javaReturnType = binding.getJavaReturnType();
+ if (javaReturnType.isNIOBuffer()) {
+ // See whether capacity has been specified
+ String capacity = cfg.returnValueCapacity(binding.getName());
+ if (capacity != null) {
+ returnValueCapacityFormat = new MessageFormat(capacity);
+ }
+ }
+ CMethodBindingEmitter cEmitter;
+ if (doingImplRoutine) {
+ cEmitter = new CMethodBindingImplEmitter(binding, overloaded,
+ bindingJavaPackageName,
+ bindingJavaClassName,
+ cfg.allStatic(), output);
+ } else {
+ cEmitter = new CMethodBindingEmitter(binding, overloaded,
+ bindingJavaPackageName,
+ bindingJavaClassName,
+ cfg.allStatic(), output);
+ }
+ if (returnValueCapacityFormat != null) {
+ cEmitter.setReturnValueCapacityExpression(returnValueCapacityFormat);
+ }
+ cEmitter.setTemporaryCVariableDeclarations(cfg.temporaryCVariableDeclarations(binding.getName()));
+ cEmitter.setTemporaryCVariableAssignments(cfg.temporaryCVariableAssignments(binding.getName()));
+ return cEmitter;
+ }
+
+ private JavaType typeToJavaType(Type cType, boolean outgoingArgument) {
+ // Recognize JNIEnv* case up front
+ PointerType opt = cType.asPointer();
+ if ((opt != null) &&
+ (opt.getTargetType().getName() != null) &&
+ (opt.getTargetType().getName().equals("JNIEnv"))) {
+ return JavaType.createForJNIEnv();
+ }
+
+ // Opaque specifications override automatic conversions
+ TypeInfo info = cfg.typeInfo(cType, typedefDictionary);
+ if (info != null) {
+ return info.javaType();
+ }
+ Type t = cType;
+ if (t.isInt() || t.isEnum()) {
+ switch (t.getSize()) {
+ case 1: return javaType(Byte.TYPE);
+ case 2: return javaType(Short.TYPE);
+ case 4: return javaType(Integer.TYPE);
+ case 8: return javaType(Long.TYPE);
+ default: throw new RuntimeException("Unknown integer type of size " +
+ t.getSize() + " and name " + t.getName());
+ }
+ } else if (t.isFloat()) {
+ return javaType(Float.TYPE);
+ } else if (t.isDouble()) {
+ return javaType(Double.TYPE);
+ } else if (t.isVoid()) {
+ return javaType(Void.TYPE);
+ } else {
+ if (t.pointerDepth() > 0 || arrayDimension(t) > 0) {
+ // FIXME: add option to disable generation of typed pointer ->
+ // array conversions so that these will be handled with direct
+ // buffers (Should this be done later? in expandMethodBinding?)
+ Type targetType; // target type
+ if (t.isPointer()) {
+ // t is <type>*, we need to get <type>
+ targetType = t.asPointer().getTargetType();
+ } else {
+ // t is <type>[], we need to get <type>
+ targetType = t.asArray().getElementType();
+ }
+
+ // Handle Types of form pointer-to-type or array-of-type, like char*
+ // or int[]
+ if (t.pointerDepth() == 1 || arrayDimension(t) == 1) {
+ if (targetType.isVoid()) {
+ return JavaType.createForVoidPointer();
+ } else if (targetType.isInt()) {
+ switch (targetType.getSize()) {
+ case 1: return javaType(ArrayTypes.byteArrayClass);
+ case 2: return javaType(ArrayTypes.shortArrayClass);
+ case 4: return javaType(ArrayTypes.intArrayClass);
+ case 8: return javaType(ArrayTypes.longArrayClass);
+ default: throw new RuntimeException("Unknown integer array type of size " +
+ t.getSize() + " and name " + t.getName());
+ }
+ } else if (targetType.isFloat()) {
+ return javaType(ArrayTypes.floatArrayClass);
+ } else if (targetType.isDouble()) {
+ return javaType(ArrayTypes.doubleArrayClass);
+ } else if (targetType.isCompound()) {
+ if (t.isArray()) {
+ throw new RuntimeException("Arrays of compound types not handled yet");
+ }
+ // Special cases for known JNI types (in particular for converting jawt.h)
+ if (cType.getName() != null &&
+ cType.getName().equals("jobject")) {
+ return javaType(java.lang.Object.class);
+ }
+
+ return JavaType.createForCStruct(cfg.renameJavaType(targetType.getName()));
+ } else {
+ throw new RuntimeException("Don't know how to convert pointer/array type \"" +
+ t + "\"");
+ }
+ }
+ // Handle Types of form pointer-to-pointer-to-type or
+ // array-of-arrays-of-type, like char** or int[][]
+ else if (t.pointerDepth() == 2 || arrayDimension(t) == 2) {
+ // Get the target type of the target type (targetType was computer earlier
+ // as to be a pointer to the target type, so now we need to get its
+ // target type)
+ if (targetType.isPointer()) {
+ // t is<type>**, targetType is <type>*, we need to get <type>
+ targetType = targetType.asPointer().getTargetType();
+ } else {
+ // t is<type>[][], targetType is <type>[], we need to get <type>
+ targetType = targetType.asArray().getElementType();
+ }
+ if (targetType.isInt()) {
+ switch (targetType.getSize())
+ {
+ case 1: return javaType(ArrayTypes.byteArrayArrayClass);
+ // FIXME: handle 2,4,8-byte int types here
+ default:
+ throw new RuntimeException(
+ "Could not convert C type \"" + t + "\" to appropriate " +
+ "Java type; Currently, the only supported depth=2 " +
+ "pointer/array integer types are \"char**\" and \"char[][]\"");
+ }
+ } else {
+ throw new RuntimeException(
+ "Could not convert C type \"" + t + "\" " +
+ "to appropriate Java type; need to add support for " +
+ "depth=2 pointer/array types with non-integral target " +
+ "types [debug info: targetType=\"" + targetType + "\"]");
+ }
+
+ } else {
+ // can't handle this type of pointer/array argument
+ throw new RuntimeException(
+ "Could not convert C pointer/array \"" + t + "\" to " +
+ "appropriate Java type; types with pointer/array depth " +
+ "greater than 2 are not yet supported [debug info: " +
+ "pointerDepth=" + t.pointerDepth() + " arrayDimension=" +
+ arrayDimension(t) + " targetType=\"" + targetType + "\"]");
+ }
+
+ } else {
+ throw new RuntimeException(
+ "Could not convert C type \"" + t + "\" to appropriate Java type; ");
+ }
+ }
+ }
+
+ private static boolean isIntegerType(Class c) {
+ return ((c == Byte.TYPE) ||
+ (c == Short.TYPE) ||
+ (c == Character.TYPE) ||
+ (c == Integer.TYPE) ||
+ (c == Long.TYPE));
+ }
+
+ private int slot(Type t, int byteOffset) {
+ if (t.isInt()) {
+ switch (t.getSize()) {
+ case 1:
+ case 2:
+ case 4:
+ case 8: return byteOffset / t.getSize();
+ default: throw new RuntimeException("Illegal type");
+ }
+ } else if (t.isFloat()) {
+ return byteOffset / 4;
+ } else if (t.isDouble()) {
+ return byteOffset / 8;
+ } else if (t.isPointer()) {
+ return byteOffset / machDesc.pointerSizeInBytes();
+ } else {
+ throw new RuntimeException("Illegal type " + t);
+ }
+ }
+
+ private StructLayout getLayout() {
+ if (layout == null) {
+ layout = StructLayout.createForCurrentPlatform();
+ }
+ return layout;
+ }
+
+ protected PrintWriter openFile(String filename) throws IOException {
+ //System.out.println("Trying to open: " + filename);
+ File file = new File(filename);
+ String parentDir = file.getParent();
+ if (parentDir != null)
+ {
+ File pDirFile = new File(parentDir);
+ pDirFile.mkdirs();
+ }
+ return new PrintWriter(new BufferedWriter(new FileWriter(file)));
+ }
+
+ private int arrayDimension(Type type) {
+ ArrayType arrayType = type.asArray();
+ if (arrayType == null) {
+ return 0;
+ }
+ return 1 + arrayDimension(arrayType.getElementType());
+ }
+
+ private boolean isOpaque(Type type) {
+ return (cfg.typeInfo(type, typedefDictionary) != null);
+ }
+
+ private String compatiblePrimitiveJavaTypeName(Type fieldType,
+ JavaType javaType) {
+ Class c = javaType.getJavaClass();
+ if (!isIntegerType(c)) {
+ // FIXME
+ throw new RuntimeException("Can't yet handle opaque definitions of structs' fields to non-integer types (byte, short, int, long, etc.)");
+ }
+ switch (fieldType.getSize()) {
+ case 1: return "byte";
+ case 2: return "short";
+ case 4: return "int";
+ case 8: return "long";
+ default: throw new RuntimeException("Can't handle opaque definitions if the starting type isn't compatible with integral types");
+ }
+ }
+
+ private void openWriters() throws IOException {
+ String jRoot =
+ cfg.javaOutputDir() + File.separator +
+ CodeGenUtils.packageAsPath(cfg.packageName());
+ String jImplRoot = null;
+ if (!cfg.allStatic()) {
+ jImplRoot =
+ cfg.javaOutputDir() + File.separator +
+ CodeGenUtils.packageAsPath(cfg.implPackageName());
+ }
+ String nRoot = cfg.nativeOutputDir();
+ if (cfg.nativeOutputUsesJavaHierarchy())
+ {
+ nRoot +=
+ File.separator + CodeGenUtils.packageAsPath(cfg.packageName());
+ }
+
+ if (cfg.allStatic() || cfg.emitInterface()) {
+ javaWriter = openFile(jRoot + File.separator + cfg.className() + ".java");
+ }
+ if (!cfg.allStatic() && cfg.emitImpl()) {
+ javaImplWriter = openFile(jImplRoot + File.separator + cfg.implClassName() + ".java");
+ }
+ if (cfg.emitImpl()) {
+ cWriter = openFile(nRoot + File.separator + cfg.implClassName() + "_JNI.c");
+ }
+
+ if (javaWriter != null) {
+ CodeGenUtils.emitAutogeneratedWarning(javaWriter, this);
+ }
+ if (javaImplWriter != null) {
+ CodeGenUtils.emitAutogeneratedWarning(javaImplWriter, this);
+ }
+ if (cWriter != null) {
+ CodeGenUtils.emitAutogeneratedWarning(cWriter, this);
+ }
+ }
+
+ protected PrintWriter javaWriter() {
+ if (!cfg.allStatic() && !cfg.emitInterface()) {
+ throw new InternalError("Should not call this");
+ }
+ return javaWriter;
+ }
+
+ protected PrintWriter javaImplWriter() {
+ if (cfg.allStatic() || !cfg.emitImpl()) {
+ throw new InternalError("Should not call this");
+ }
+ return javaImplWriter;
+ }
+
+ protected PrintWriter cWriter() {
+ if (!cfg.emitImpl()) {
+ throw new InternalError("Should not call this");
+ }
+ return cWriter;
+ }
+
+ private void closeWriter(PrintWriter writer) throws IOException {
+ writer.flush();
+ writer.close();
+ }
+
+ private void closeWriters() throws IOException {
+ if (javaWriter != null) {
+ closeWriter(javaWriter);
+ }
+ if (javaImplWriter != null) {
+ closeWriter(javaImplWriter);
+ }
+ if (cWriter != null) {
+ closeWriter(cWriter);
+ }
+ javaWriter = null;
+ javaImplWriter = null;
+ cWriter = null;
+ }
+
+ /**
+ * Returns the value that was specified by the configuration directive
+ * "JavaOutputDir", or the default if none was specified.
+ */
+ protected String getJavaOutputDir() {
+ return cfg.javaOutputDir();
+ }
+
+ /**
+ * Returns the value that was specified by the configuration directive
+ * "Package", or the default if none was specified.
+ */
+ protected String getJavaPackageName() {
+ return cfg.packageName();
+ }
+
+ /**
+ * Returns the value that was specified by the configuration directive
+ * "ImplPackage", or the default if none was specified.
+ */
+ protected String getImplPackageName() {
+ return cfg.implPackageName();
+ }
+
+ /**
+ * Emit all the strings specified in the "CustomJavaCode" parameters of
+ * the configuration file.
+ */
+ protected void emitCustomJavaCode(PrintWriter writer, String className) throws Exception
+ {
+ List code = cfg.customJavaCodeForClass(className);
+ if (code.size() == 0)
+ return;
+
+ writer.println();
+ writer.println(" // --- Begin CustomJavaCode .cfg declarations");
+ for (Iterator iter = code.iterator(); iter.hasNext(); ) {
+ writer.println((String) iter.next());
+ }
+ writer.println(" // ---- End CustomJavaCode .cfg declarations");
+ }
+
+ /**
+ * Write out any header information for the output files (class declaration
+ * and opening brace, import statements, etc).
+ */
+ protected void emitAllFileHeaders() throws IOException {
+ try {
+ if (cfg.allStatic() || cfg.emitInterface()) {
+ String[] interfaces;
+ if (cfg.emitInterface()) {
+ List userSpecifiedInterfaces = cfg.extendedInterfaces(cfg.className());
+ interfaces = new String[userSpecifiedInterfaces.size()];
+ userSpecifiedInterfaces.toArray(interfaces);
+ } else {
+ interfaces = null;
+ }
+
+ final List/*<String>*/ intfDocs = cfg.javadocForClass(cfg.className());
+ CodeGenUtils.EmissionCallback docEmitter =
+ new CodeGenUtils.EmissionCallback() {
+ public void emit(PrintWriter w) {
+ for (Iterator iter = intfDocs.iterator(); iter.hasNext(); ) {
+ w.println((String) iter.next());
+ }
+ }
+ };
+
+ CodeGenUtils.emitJavaHeaders(
+ javaWriter,
+ cfg.packageName(),
+ cfg.className(),
+ cfg.allStatic() ? true : false,
+ (String[]) cfg.imports().toArray(new String[] {}),
+ new String[] { "public" },
+ interfaces,
+ null,
+ docEmitter);
+ }
+
+ if (!cfg.allStatic() && cfg.emitImpl()) {
+ final List/*<String>*/ implDocs = cfg.javadocForClass(cfg.className());
+ CodeGenUtils.EmissionCallback docEmitter =
+ new CodeGenUtils.EmissionCallback() {
+ public void emit(PrintWriter w) {
+ for (Iterator iter = implDocs.iterator(); iter.hasNext(); ) {
+ w.println((String) iter.next());
+ }
+ }
+ };
+
+ CodeGenUtils.emitJavaHeaders(
+ javaImplWriter,
+ cfg.implPackageName(),
+ cfg.implClassName(),
+ true,
+ new String[] { "java.nio.*", cfg.packageName() + ".*" },
+ new String[] { "public" },
+ new String[] { cfg.className() },
+ null,
+ docEmitter);
+ }
+
+ if (cfg.emitImpl()) {
+ PrintWriter cWriter = cWriter();
+ emitCHeader(cWriter, cfg.implClassName());
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Error emitting all file headers: cfg.allStatic()=" + cfg.allStatic() +
+ " cfg.emitImpl()=" + cfg.emitImpl() + " cfg.emitInterface()=" + cfg.emitInterface(),
+ e);
+ }
+
+ }
+
+ protected void emitCHeader(PrintWriter cWriter, String className) {
+ cWriter.println("#include <jni.h>");
+ cWriter.println();
+ for (Iterator iter = cfg.customCCode().iterator(); iter.hasNext(); ) {
+ cWriter.println((String) iter.next());
+ }
+ cWriter.println();
+ }
+
+ /**
+ * Write out any footer information for the output files (closing brace of
+ * class definition, etc).
+ */
+ protected void emitAllFileFooters(){
+ if (cfg.allStatic() || cfg.emitInterface()) {
+ javaWriter().println();
+ javaWriter().println("} // end of class " + cfg.className());
+ }
+ if (!cfg.allStatic() && cfg.emitImpl())
+ {
+ javaImplWriter().println();
+ javaImplWriter().println("} // end of class " + cfg.implClassName());
+ }
+ }
+
+ private JavaType javaType(Class c) {
+ return JavaType.createForClass(c);
+ }
+
+ private MethodBinding bindFunction(FunctionSymbol sym,
+ JavaType containingType,
+ Type containingCType) {
+
+ MethodBinding binding = new MethodBinding(sym, containingType, containingCType);
+
+ if (cfg.returnsString(binding.getName())) {
+ PointerType prt = sym.getReturnType().asPointer();
+ if (prt == null ||
+ prt.getTargetType().asInt() == null ||
+ prt.getTargetType().getSize() != 1) {
+ throw new RuntimeException(
+ "Cannot apply ReturnsString configuration directive to \"" + sym +
+ "\". ReturnsString requires native method to have return type \"char *\"");
+ }
+ binding.setJavaReturnType(JavaType.createForClass(java.lang.String.class));
+ } else {
+ binding.setJavaReturnType(typeToJavaType(sym.getReturnType(), false));
+ }
+
+ // List of the indices of the arguments in this function that should be
+ // converted from byte[] to String
+ List stringArgIndices = cfg.stringArguments(binding.getName());
+
+ for (int i = 0; i < sym.getNumArguments(); i++) {
+ Type cArgType = sym.getArgumentType(i);
+ JavaType mappedType = typeToJavaType(cArgType, true);
+ //System.out.println("C arg type -> \"" + cArgType + "\"" );
+ //System.out.println(" Java -> \"" + mappedType + "\"" );
+
+ // Take into account any ArgumentIsString configuration directives that apply
+ if (stringArgIndices != null && stringArgIndices.contains(new Integer(i))) {
+ //System.out.println("Forcing conversion of " + binding.getName() + " arg #" + i + " from byte[] to String ");
+ if ((mappedType.isArray() &&
+ (mappedType.getJavaClass() == ArrayTypes.byteArrayClass ||
+ mappedType.getJavaClass() == ArrayTypes.byteArrayArrayClass)) ||
+ (mappedType.isVoidPointerType())) {
+ // convert mapped type from void* and byte[] to String, or byte[][] to String[]
+ if (mappedType.getJavaClass() == ArrayTypes.byteArrayArrayClass) {
+ mappedType = javaType(ArrayTypes.stringArrayClass);
+ } else {
+ mappedType = javaType(String.class);
+ }
+ }
+ else {
+ throw new RuntimeException(
+ "Cannot apply ArgumentIsString configuration directive to " +
+ "argument " + i + " of \"" + sym + "\": argument type is not " +
+ "a \"void*\", \"char *\", or \"char**\" equivalent");
+ }
+ }
+ binding.addJavaArgumentType(mappedType);
+ //System.out.println("During binding of [" + sym + "], added mapping from C type: " + cArgType + " to Java type: " + mappedType);
+ }
+
+ //System.err.println("---> " + binding);
+ //System.err.println(" ---> " + binding.getCSymbol());
+ return binding;
+ }
+
+ // Expands a MethodBinding containing void pointer types into
+ // multiple variants taking double arrays and NIO buffers, subject
+ // to the per-function "NIO only" rule in the configuration file
+ private List/*<MethodBinding>*/ expandMethodBinding(MethodBinding binding) {
+ List result = new ArrayList();
+ result.add(binding);
+ int i = 0;
+ while (i < result.size()) {
+ MethodBinding mb = (MethodBinding) result.get(i);
+ boolean shouldRemoveCurrent = false;
+ for (int j = 0; j < mb.getNumArguments(); j++) {
+ JavaType t = mb.getJavaArgumentType(j);
+ if (t.isVoidPointerType()) {
+ // Create variants
+ MethodBinding variant = null;
+ if (!cfg.nioOnly(mb.getCSymbol().getName())) {
+ variant = mb.createVoidPointerVariant(j, javaType(ArrayTypes.booleanArrayClass));
+ if (! result.contains(variant)) result.add(variant);
+ variant = mb.createVoidPointerVariant(j, javaType(ArrayTypes.byteArrayClass));
+ if (! result.contains(variant)) result.add(variant);
+ variant = mb.createVoidPointerVariant(j, javaType(ArrayTypes.charArrayClass));
+ if (! result.contains(variant)) result.add(variant);
+ variant = mb.createVoidPointerVariant(j, javaType(ArrayTypes.shortArrayClass));
+ if (! result.contains(variant)) result.add(variant);
+ variant = mb.createVoidPointerVariant(j, javaType(ArrayTypes.intArrayClass));
+ if (! result.contains(variant)) result.add(variant);
+ variant = mb.createVoidPointerVariant(j, javaType(ArrayTypes.longArrayClass));
+ if (! result.contains(variant)) result.add(variant);
+ variant = mb.createVoidPointerVariant(j, javaType(ArrayTypes.floatArrayClass));
+ if (! result.contains(variant)) result.add(variant);
+ variant = mb.createVoidPointerVariant(j, javaType(ArrayTypes.doubleArrayClass));
+ if (! result.contains(variant)) result.add(variant);
+ }
+ variant = mb.createVoidPointerVariant(j, JavaType.forNIOBufferClass());
+ if (! result.contains(variant)) result.add(variant);
+
+ // Remove original from list
+ shouldRemoveCurrent = true;
+ }
+ }
+ if (mb.getJavaReturnType().isVoidPointerType()) {
+ MethodBinding variant = mb.createVoidPointerVariant(-1, JavaType.forNIOByteBufferClass());
+ if (! result.contains(variant)) result.add(variant);
+ shouldRemoveCurrent = true;
+ }
+ if (shouldRemoveCurrent) {
+ result.remove(i);
+ --i;
+ }
+ ++i;
+ }
+ return result;
+ }
+
+ private String resultName() {
+ return "_res";
+ }
+
+ private Type canonicalize(Type t) {
+ Type res = (Type) canonMap.get(t);
+ if (res != null) {
+ return res;
+ }
+ canonMap.put(t, t);
+ return t;
+ }
+}
diff --git a/src/net/java/games/gluegen/JavaMethodBindingEmitter.java b/src/net/java/games/gluegen/JavaMethodBindingEmitter.java
new file mode 100644
index 000000000..003ea8643
--- /dev/null
+++ b/src/net/java/games/gluegen/JavaMethodBindingEmitter.java
@@ -0,0 +1,260 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.util.*;
+import java.io.*;
+
+import net.java.games.gluegen.cgram.types.*;
+import net.java.games.gluegen.cgram.*;
+
+/**
+ * An emitter that emits only the interface for a Java<->C JNI binding.
+ */
+public class JavaMethodBindingEmitter extends FunctionEmitter
+{
+ public static final EmissionModifier PUBLIC = new EmissionModifier("public");
+ public static final EmissionModifier PROTECTED = new EmissionModifier("protected");
+ public static final EmissionModifier PRIVATE = new EmissionModifier("private");
+ public static final EmissionModifier ABSTRACT = new EmissionModifier("abstract");
+ public static final EmissionModifier FINAL = new EmissionModifier("final");
+ public static final EmissionModifier NATIVE = new EmissionModifier("native");
+ public static final EmissionModifier SYNCHRONIZED = new EmissionModifier("synchronized");
+
+ protected static final CommentEmitter defaultJavaCommentEmitter = new DefaultCommentEmitter();
+ protected static final CommentEmitter defaultInterfaceCommentEmitter =
+ new InterfaceCommentEmitter();
+
+ // Exception type raised in the generated code if runtime checks fail
+ private String runtimeExceptionType;
+
+ private MethodBinding binding;
+ private boolean forNIOBufferBaseRoutine;
+
+ // A non-null value indicates that rather than returning a compound
+ // type accessor we are returning an array of such accessors; this
+ // expression is a MessageFormat string taking the names of the
+ // incoming Java arguments as parameters and computing as an int the
+ // number of elements of the returned array.
+ private String returnedArrayLengthExpression;
+
+ public JavaMethodBindingEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType)
+ {
+ this(binding, output, runtimeExceptionType, false);
+ }
+
+ public JavaMethodBindingEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType, boolean forNIOBufferBaseRoutine)
+ {
+ super(output);
+ this.binding = binding;
+ this.forNIOBufferBaseRoutine = forNIOBufferBaseRoutine;
+ this.runtimeExceptionType = runtimeExceptionType;
+ setCommentEmitter(defaultInterfaceCommentEmitter);
+ }
+
+ public final MethodBinding getBinding() { return binding; }
+
+ public final boolean isForNIOBufferBaseRoutine() { return forNIOBufferBaseRoutine; }
+
+ public String getName() {
+ return binding.getName();
+ }
+
+
+ /** The type of exception (must subclass
+ <code>java.lang.RuntimeException</code>) raised if runtime
+ checks fail in the generated code. */
+ public String getRuntimeExceptionType() {
+ return runtimeExceptionType;
+ }
+
+ /** If the underlying function returns an array (currently only
+ arrays of compound types are supported) as opposed to a pointer
+ to an object, this method should be called to provide a
+ MessageFormat string containing an expression that computes the
+ number of elements of the returned array. The parameters to the
+ MessageFormat expression are the names of the incoming Java
+ arguments. */
+ public void setReturnedArrayLengthExpression(String expr) {
+ returnedArrayLengthExpression = expr;
+ }
+
+ protected void emitReturnType(PrintWriter writer)
+ {
+ writer.print(getReturnTypeString(false));
+ }
+
+ protected String getReturnTypeString(boolean skipArray) {
+ if (skipArray || getReturnedArrayLengthExpression() == null) {
+ return binding.getJavaReturnType().getName();
+ }
+ return binding.getJavaReturnType().getName() + "[]";
+ }
+
+ protected void emitName(PrintWriter writer)
+ {
+ writer.print(binding.getName());
+ if (forNIOBufferBaseRoutine) {
+ writer.print("0");
+ }
+ }
+
+ protected int emitArguments(PrintWriter writer)
+ {
+ boolean needComma = false;
+ int numEmitted = 0;
+
+ if (forNIOBufferBaseRoutine && binding.hasContainingType()) {
+ // Always emit outgoing "this" argument
+ writer.print("java.nio.Buffer ");
+ writer.print(javaThisArgumentName());
+ ++numEmitted;
+ needComma = true;
+ }
+
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ if (type.isVoid()) {
+ // Make sure this is the only param to the method; if it isn't,
+ // there's something wrong with our parsing of the headers.
+ if (binding.getNumArguments() != 1) {
+ throw new InternalError(
+ "\"void\" argument type found in " +
+ "multi-argument function \"" + binding + "\"");
+ }
+ continue;
+ }
+
+ if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+ // Don't need to expose these at the Java level
+ continue;
+ }
+
+ if (needComma) {
+ writer.print(", ");
+ }
+
+ writer.print(type.getName());
+ writer.print(" ");
+ writer.print(binding.getArgumentName(i));
+ ++numEmitted;
+ needComma = true;
+ }
+ return numEmitted;
+ }
+
+ protected String getImplMethodName()
+ {
+ return binding.getName() + "0";
+ }
+
+ protected void emitBody(PrintWriter writer)
+ {
+ writer.println(';');
+ }
+
+ protected static String javaThisArgumentName() {
+ return "jthis0";
+ }
+
+ protected String getCommentStartString() { return "/** "; }
+
+ protected String getBaseIndentString() { return " "; }
+
+ protected String getReturnedArrayLengthExpression() {
+ return returnedArrayLengthExpression;
+ }
+
+ /**
+ * Class that emits a generic comment for JavaMethodBindingEmitters; the comment
+ * includes the C signature of the native method that is being bound by the
+ * emitter java method.
+ */
+ protected static class DefaultCommentEmitter implements CommentEmitter {
+ public void emit(FunctionEmitter emitter, PrintWriter writer) {
+ emitBeginning(emitter, writer);
+ emitBindingCSignature(((JavaMethodBindingEmitter)emitter).getBinding(), writer);
+ emitEnding(emitter, writer);
+ }
+ protected void emitBeginning(FunctionEmitter emitter, PrintWriter writer) {
+ writer.print("Entry point to C language function: <br> ");
+ }
+ protected void emitBindingCSignature(MethodBinding binding, PrintWriter writer) {
+ writer.print("<code> ");
+ writer.print(binding.getCSymbol());
+ writer.print(" </code> ");
+ }
+ protected void emitEnding(FunctionEmitter emitter, PrintWriter writer) {
+ // If argument type is a named enum, then emit a comment detailing the
+ // acceptable values of that enum.
+ MethodBinding binding = ((JavaMethodBindingEmitter)emitter).getBinding();
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ Type type = binding.getCArgumentType(i);
+ // don't emit param comments for anonymous enums, since we can't
+ // distinguish between the values found within multiple anonymous
+ // enums in the same C translation unit.
+ if (type.isEnum() && type.getName() != HeaderParser.ANONYMOUS_ENUM_NAME) {
+ EnumType enum = (EnumType)type;
+ writer.println();
+ writer.print(emitter.getBaseIndentString());
+ writer.print(" ");
+ writer.print("@param ");
+ writer.print(binding.getArgumentName(i));
+ writer.print(" valid values are: <code>");
+ for (int j = 0; j < enum.getNumEnumerates(); ++j) {
+ if (j>0) writer.print(", ");
+ writer.print(enum.getEnumName(j));
+ }
+ writer.println("</code>");
+ }
+ }
+ }
+ }
+
+ protected static class InterfaceCommentEmitter
+ extends JavaMethodBindingEmitter.DefaultCommentEmitter
+ {
+ protected void emitBeginning(FunctionEmitter emitter,
+ PrintWriter writer) {
+ writer.print("Interface to C language function: <br> ");
+ }
+ }
+}
+
diff --git a/src/net/java/games/gluegen/JavaMethodBindingImplEmitter.java b/src/net/java/games/gluegen/JavaMethodBindingImplEmitter.java
new file mode 100644
index 000000000..2357e7c38
--- /dev/null
+++ b/src/net/java/games/gluegen/JavaMethodBindingImplEmitter.java
@@ -0,0 +1,220 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.io.*;
+import java.util.*;
+import java.text.MessageFormat;
+
+import net.java.games.gluegen.cgram.types.*;
+
+/** Emits the Java-side component of the Java<->C JNI binding. */
+public class JavaMethodBindingImplEmitter extends JavaMethodBindingEmitter
+{
+ private boolean isUnimplemented;
+
+ public JavaMethodBindingImplEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType)
+ {
+ this(binding, output, runtimeExceptionType, false);
+ }
+
+ public JavaMethodBindingImplEmitter(MethodBinding binding,
+ PrintWriter output,
+ String runtimeExceptionType,
+ boolean isUnimplemented)
+ {
+ super(binding, output, runtimeExceptionType);
+ setCommentEmitter(defaultJavaCommentEmitter);
+ this.isUnimplemented = isUnimplemented;
+ }
+
+ protected void emitBody(PrintWriter writer)
+ {
+ MethodBinding binding = getBinding();
+ if (needsBody()) {
+ writer.println();
+ writer.println(" {");
+ if (isUnimplemented) {
+ writer.println(" throw new " + getRuntimeExceptionType() + "(\"Unimplemented\");");
+ } else {
+ emitPreCallSetup(binding, writer);
+ emitReturnVariableSetup(binding, writer);
+ emitCall(binding, writer);
+ }
+ writer.println(" }");
+ } else {
+ writer.println(";");
+ }
+ }
+
+ protected boolean needsBody() {
+ return isUnimplemented || getBinding().needsBody() || getBinding().hasContainingType();
+ }
+
+ protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) {
+ emitArrayLengthChecks(binding, writer);
+ }
+
+ protected void emitArrayLengthChecks(MethodBinding binding, PrintWriter writer) {
+ // Check lengths of any incoming arrays if necessary
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ Type type = binding.getCArgumentType(i);
+ if (type.isArray()) {
+ ArrayType arrayType = type.asArray();
+ writer.println(" if (" + binding.getArgumentName(i) + ".length < " + arrayType.getLength() + ")");
+ writer.println(" throw new " + getRuntimeExceptionType() + "(\"Length of array \\\"" + binding.getArgumentName(i) +
+ "\\\" was less than the required " + arrayType.getLength() + "\");");
+ }
+ }
+ }
+
+ protected void emitReturnVariableSetup(MethodBinding binding, PrintWriter writer) {
+ writer.print(" ");
+ JavaType returnType = binding.getJavaReturnType();
+ if (!returnType.isVoid()) {
+ if (returnType.isCompoundTypeWrapper() ||
+ returnType.isNIOByteBuffer()) {
+ writer.println("ByteBuffer _res;");
+ writer.print(" _res = ");
+ } else {
+ writer.print("return ");
+ }
+ }
+ }
+
+ protected void emitCall(MethodBinding binding, PrintWriter writer) {
+ writer.print(getImplMethodName());
+ writer.print("(");
+ emitCallArguments(binding, writer);
+ writer.print(")");
+ emitCallResultReturn(binding, writer);
+ }
+
+ protected int emitCallArguments(MethodBinding binding, PrintWriter writer) {
+ boolean needComma = false;
+ int numArgsEmitted = 0;
+ if (binding.hasContainingType()) {
+ // Emit this pointer
+ assert(binding.getContainingType().isCompoundTypeWrapper());
+ writer.print("getBuffer()");
+ needComma = true;
+ ++numArgsEmitted;
+ }
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+ // Don't need to expose these at the Java level
+ continue;
+ }
+
+ if (type.isVoid()) {
+ // Make sure this is the only param to the method; if it isn't,
+ // there's something wrong with our parsing of the headers.
+ assert(binding.getNumArguments() == 1);
+ continue;
+ }
+
+ if (needComma) {
+ writer.print(", ");
+ }
+
+ if (type.isCompoundTypeWrapper()) {
+ writer.print("((");
+ }
+ writer.print(binding.getArgumentName(i));
+ if (type.isCompoundTypeWrapper()) {
+ writer.print(" == null) ? null : ");
+ writer.print(binding.getArgumentName(i));
+ writer.print(".getBuffer())");
+ }
+ needComma = true;
+ ++numArgsEmitted;
+ }
+ return numArgsEmitted;
+ }
+
+ protected void emitCallResultReturn(MethodBinding binding, PrintWriter writer) {
+ JavaType returnType = binding.getJavaReturnType();
+ if (returnType.isCompoundTypeWrapper()) {
+ writer.println(";");
+ String fmt = getReturnedArrayLengthExpression();
+ writer.println(" if (_res == null) return null;");
+ if (fmt == null) {
+ writer.print(" return new " + returnType.getName() + "(_res.order(ByteOrder.nativeOrder()))");
+ } else {
+ writer.println(" _res.order(ByteOrder.nativeOrder());");
+ String[] argumentNames = new String[binding.getNumArguments()];
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ argumentNames[i] = binding.getArgumentName(i);
+ }
+ String expr = new MessageFormat(fmt).format(argumentNames);
+ PointerType cReturnTypePointer = binding.getCReturnType().asPointer();
+ CompoundType cReturnType = null;
+ if (cReturnTypePointer != null) {
+ cReturnType = cReturnTypePointer.getTargetType().asCompound();
+ }
+ if (cReturnType == null) {
+ throw new RuntimeException("ReturnedArrayLength directive currently only supported for pointers to compound types " +
+ "(error occurred while generating Java glue code for " + binding.getName() + ")");
+ }
+ writer.println(" " + getReturnTypeString(false) + " _retarray = new " + getReturnTypeString(true) + "[" + expr + "];");
+ writer.println(" for (int _count = 0; _count < " + expr + "; _count++) {");
+ // Create temporary ByteBuffer slice
+ // FIXME: probably need Type.getAlignedSize() for arrays of
+ // compound types (rounding up to machine-dependent alignment)
+ writer.println(" _res.position(_count * " + cReturnType.getSize() + ");");
+ writer.println(" _res.limit ((1 + _count) * " + cReturnType.getSize() + ");");
+ writer.println(" ByteBuffer _tmp = _res.slice();");
+ writer.println(" _tmp.order(ByteOrder.nativeOrder());");
+ writer.println(" _res.position(0);");
+ writer.println(" _res.limit(_res.capacity());");
+ writer.println(" _retarray[_count] = new " + returnType.getName() + "(_tmp);");
+ writer.println(" }");
+ writer.print (" return _retarray");
+ }
+ } else if (returnType.isNIOBuffer()) {
+ writer.println(";");
+ writer.println(" if (_res == null) return null;");
+ writer.print(" return _res.order(ByteOrder.nativeOrder())");
+ }
+ writer.println(";");
+ }
+}
+
diff --git a/src/net/java/games/gluegen/JavaType.java b/src/net/java/games/gluegen/JavaType.java
new file mode 100644
index 000000000..ac42aa0f1
--- /dev/null
+++ b/src/net/java/games/gluegen/JavaType.java
@@ -0,0 +1,277 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+/**
+ * Describes a java-side representation of a type that is used to represent
+ * the same data on both the Java-side and C-side during a JNI operation. Also
+ * contains some utility methods for creating common types.
+ */
+public class JavaType {
+ private Class clazz; // Primitive types and other types representable as Class objects
+ private String name; // Types we're generating glue code for (i.e., C structs)
+ private static JavaType nioBufferType;
+ private static JavaType nioByteBufferType;
+
+ public boolean equals(Object arg) {
+ if ((arg == null) || (!(arg instanceof JavaType))) {
+ return false;
+ }
+ JavaType t = (JavaType) arg;
+ return (t.clazz == clazz &&
+ ((t.name == name) ||
+ ((name != null) && (t.name != null) && (t.name.equals(name)))));
+ }
+
+ public int hashCode() {
+ if (clazz == null) {
+ if (name == null) {
+ return 0;
+ }
+ return name.hashCode();
+ }
+ return clazz.hashCode();
+ }
+
+ public static JavaType createForClass(Class clazz) {
+ return new JavaType(clazz);
+ }
+
+ public static JavaType createForCStruct(String name) {
+ return new JavaType(name);
+ }
+
+ public static JavaType createForVoidPointer() {
+ return new JavaType();
+ }
+
+ public static JavaType createForJNIEnv() {
+ return createForCStruct("JNIEnv");
+ }
+
+ public static JavaType forNIOBufferClass() {
+ if (nioBufferType == null) {
+ nioBufferType = createForClass(java.nio.Buffer.class);
+ }
+ return nioBufferType;
+ }
+
+ public static JavaType forNIOByteBufferClass() {
+ if (nioByteBufferType == null) {
+ nioByteBufferType = createForClass(java.nio.ByteBuffer.class);
+ }
+ return nioByteBufferType;
+ }
+
+ /**
+ * Returns the Java Class corresponding to this type. Returns null if this
+ * object corresponds to a C "void*" type.
+ */
+ public Class getJavaClass() {
+ return clazz;
+ }
+
+ /**
+ * Returns the name corresponding to this type. Returns null when this
+ * object does not represent a C-language "struct" type.
+ */
+ public String getName() {
+ if (clazz != null) {
+ if (clazz.isArray()) {
+ return arrayName(clazz);
+ }
+ return clazz.getName();
+ }
+ return name;
+ }
+
+ /** Returns the String corresponding to the JNI type for this type,
+ or NULL if it can't be represented (i.e., it's a boxing class
+ that we need to call getBuffer() on.) */
+ public String jniTypeName() {
+ if (clazz == null) {
+ return null;
+ }
+
+ if (isVoid()) {
+ return "void";
+ }
+
+ if (clazz.isPrimitive()) {
+ return "j" + clazz.getName();
+ }
+
+ if (clazz.isArray()) {
+ Class elementType = clazz.getComponentType();
+ if (elementType.isPrimitive())
+ {
+ // Type is array-of-primitive
+ return "j" + elementType.getName() + "Array";
+ }
+ else if (elementType == java.lang.String.class)
+ {
+ // Type is array-of-string
+ return "jobjectArray /*elements are String*/";
+ //return "jobjectArray";
+ }
+ else if (elementType.isArray())
+ {
+ // Type is array-of-arrays-of-something
+
+ if (elementType.getComponentType().isPrimitive())
+ {
+ // Type is an array-of-arrays-of-primitive
+ return "jobjectArray /* elements are " + elementType.getComponentType() + "[]*/";
+ //return "jobjectArray";
+ }
+ else
+ {
+ throw new RuntimeException("Multi-dimensional arrays of types that are not primitives or Strings are not supported.");
+ }
+ }
+ else
+ {
+ // Some unusual type that we don't handle
+ throw new RuntimeException("Unexpected and unsupported type: \"" + this + "\"");
+ }
+ } // end array type case
+
+ if (isString()) {
+ return "jstring";
+ }
+
+ return "jobject";
+ }
+
+ public boolean isNIOBuffer() {
+ return (clazz == java.nio.Buffer.class ||
+ clazz == java.nio.ByteBuffer.class);
+ }
+
+ public boolean isNIOByteBuffer() {
+ return (clazz == java.nio.ByteBuffer.class);
+ }
+
+ public boolean isString() {
+ return (clazz == java.lang.String.class);
+ }
+
+ public boolean isArray() {
+ return ((clazz != null) && clazz.isArray());
+ }
+
+ public boolean isPrimitive() {
+ return ((clazz != null) && !isArray() && clazz.isPrimitive() && (clazz != Void.TYPE));
+ }
+
+ public boolean isVoid() {
+ return (clazz == Void.TYPE);
+ }
+
+ public boolean isObjectType() {
+ // FIXME: what about char* -> String conversion?
+ return (isNIOBuffer() || isArray());
+ }
+
+ public boolean isCompoundTypeWrapper() {
+ return (clazz == null && name != null && !isJNIEnv());
+ }
+
+ public boolean isVoidPointerType() {
+ return (clazz == null && name == null);
+ }
+
+ public boolean isJNIEnv() {
+ return clazz == null && name == "JNIEnv";
+ }
+
+ public Object clone() {
+ JavaType clone = new JavaType();
+
+ clone.clazz = this.clazz;
+ clone.name = this.name;
+
+ return clone;
+ }
+
+ public String toString() {
+ return getName();
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ /**
+ * Constructs a representation for a type corresponding to the given Class
+ * argument.
+ */
+ private JavaType(Class clazz) {
+ this.clazz = clazz;
+ }
+
+ /** Constructs a type representing a named C struct. */
+ private JavaType(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Default constructor; the type is initialized to the equivalent of a
+ * C-language "void *".
+ */
+ private JavaType() {
+
+ }
+
+ private String arrayName(Class clazz) {
+ StringBuffer buf = new StringBuffer();
+ int arrayCount = 0;
+ while (clazz.isArray()) {
+ ++arrayCount;
+ clazz = clazz.getComponentType();
+ }
+ buf.append(clazz.getName());
+ while (--arrayCount >= 0) {
+ buf.append("[]");
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/src/net/java/games/gluegen/MethodBinding.java b/src/net/java/games/gluegen/MethodBinding.java
new file mode 100644
index 000000000..9cdcd4b0b
--- /dev/null
+++ b/src/net/java/games/gluegen/MethodBinding.java
@@ -0,0 +1,340 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.util.*;
+
+import net.java.games.gluegen.cgram.types.*;
+
+/** Represents the binding of a C function to a Java method. Also used
+ to represent calls through function pointers contained in
+ structs. */
+
+public class MethodBinding {
+
+ private FunctionSymbol sym;
+ private JavaType javaReturnType;
+ private List javaArgumentTypes;
+ private boolean computedNeedsBody;
+ private boolean needsBody;
+ private JavaType containingType;
+ private Type containingCType;
+ private int thisPointerIndex = -1;
+
+ /**
+ * Constructs a new MethodBinding that is an exact clone of the
+ * argument, including the java return type and java argument
+ * types. It's safe to modify this binding after construction.
+ */
+ public MethodBinding(MethodBinding bindingToCopy) {
+ this.sym = bindingToCopy.sym;
+
+ this.containingType = bindingToCopy.containingType;
+ this.containingCType = bindingToCopy.containingCType;
+ this.javaReturnType = bindingToCopy.javaReturnType;
+ this.javaArgumentTypes = (List)((ArrayList)bindingToCopy.javaArgumentTypes).clone();
+ this.computedNeedsBody = bindingToCopy.computedNeedsBody;
+ this.needsBody = bindingToCopy.needsBody;
+ this.thisPointerIndex = bindingToCopy.thisPointerIndex;
+ }
+
+ /** Constructor for calling a C function. */
+ public MethodBinding(FunctionSymbol sym) {
+ this.sym = sym;
+ }
+
+ /** Constructor for calling a function pointer contained in a
+ struct. */
+ public MethodBinding(FunctionSymbol sym, JavaType containingType, Type containingCType) {
+ this.sym = sym;
+ this.containingType = containingType;
+ this.containingCType = containingCType;
+ }
+
+ public void setJavaReturnType(JavaType type) {
+ javaReturnType = type;
+ computedNeedsBody = false;
+ }
+
+ public void addJavaArgumentType(JavaType type) {
+ if (javaArgumentTypes == null) {
+ javaArgumentTypes = new ArrayList();
+ }
+ javaArgumentTypes.add(type);
+ computedNeedsBody = false;
+ }
+
+ public JavaType getJavaReturnType() {
+ return javaReturnType;
+ }
+
+ public int getNumArguments() {
+ return sym.getNumArguments();
+ }
+
+ public JavaType getJavaArgumentType(int i) {
+ return (JavaType) javaArgumentTypes.get(i);
+ }
+
+ public Type getCReturnType() {
+ return sym.getReturnType();
+ }
+
+ public Type getCArgumentType(int i) {
+ return sym.getArgumentType(i);
+ }
+
+ public FunctionSymbol getCSymbol() {
+ return sym;
+ }
+
+ /** Returns either the argument name specified by the underlying
+ FunctionSymbol or a fabricated argument name based on the
+ position. Note that it is currently not guaranteed that there
+ are no namespace clashes with these fabricated argument
+ names. */
+ public String getArgumentName(int i) {
+ String ret = sym.getArgumentName(i);
+ if (ret != null) {
+ return ret;
+ }
+ return "arg" + i;
+ }
+
+ public String getName() {
+ return sym.getName();
+ }
+
+ /** Replaces the void* argument at slot <i>argumentNumber</i>
+ (0..getNumArguments() - 1) with the specified type. If
+ argumentNumber is less than 0 then replaces the return type. */
+ public MethodBinding createVoidPointerVariant(int argumentNumber,
+ JavaType newArgType) {
+ MethodBinding binding = new MethodBinding(sym);
+ if (argumentNumber < 0) {
+ binding.setJavaReturnType(newArgType);
+ } else {
+ binding.setJavaReturnType(javaReturnType);
+ }
+ for (int i = 0; i < getNumArguments(); i++) {
+ JavaType type = getJavaArgumentType(i);
+ if (i == argumentNumber) {
+ type = newArgType;
+ }
+ binding.addJavaArgumentType(type);
+ }
+ return binding;
+ }
+ /**
+ * Returns true if this method needs a special implementation to wrap and/or
+ * set the byte order of its arguments or return type (i.e., needs special
+ * pre-processing of the data passed to the native function, or
+ * post-processing of the data returned from the native function). <P>
+ *
+ * Returns false if this binding can be implemented via a one-to-one
+ * correspondence between a Java method and its native implementation.
+ */
+ public boolean needsBody() {
+ if (!computedNeedsBody) {
+ if (javaReturnType.isCompoundTypeWrapper() ||
+ javaReturnType.isNIOByteBuffer()) {
+ // Needs wrapping and/or setting of byte order (neither of
+ // which can be done easily from native code)
+ needsBody = true;
+ } else {
+ for (int i = 0; i < getNumArguments(); i++) {
+ JavaType javaArgType = getJavaArgumentType(i);
+ Type cArgType = getCArgumentType(i);
+ if (javaArgType.isCompoundTypeWrapper() ||
+ cArgType.isArray()) {
+ // Needs unwrapping of accessors or checking of array lengths
+ needsBody = true;
+ break;
+ }
+ }
+ }
+ computedNeedsBody = true;
+ }
+
+ return needsBody;
+ }
+
+ public MethodBinding createNIOBufferVariant() {
+ if (!needsBody()) {
+ return this;
+ }
+ MethodBinding binding = new MethodBinding(sym, containingType, containingCType);
+ binding.thisPointerIndex = thisPointerIndex;
+ if (javaReturnType.isCompoundTypeWrapper()) {
+ binding.setJavaReturnType(JavaType.forNIOByteBufferClass());
+ } else {
+ binding.setJavaReturnType(javaReturnType);
+ }
+ for (int i = 0; i < getNumArguments(); i++) {
+ JavaType type = getJavaArgumentType(i);
+ if (type.isCompoundTypeWrapper()) {
+ type = JavaType.forNIOBufferClass();
+ }
+ binding.addJavaArgumentType(type);
+ }
+ return binding;
+ }
+
+ /** Indicates whether this MethodBinding is for a function pointer
+ contained in a struct. */
+ public boolean hasContainingType() {
+ return (getContainingType() != null);
+ }
+
+ /** Retrieves the containing type of this MethodBinding if it is for
+ a function pointer contained in a struct. */
+ public JavaType getContainingType() {
+ return containingType;
+ }
+
+ /** Retrieves the containing C type of this MethodBinding if it is for
+ a function pointer contained in a struct. */
+ public Type getContainingCType() {
+ return containingCType;
+ }
+
+ /** Find the leftmost argument matching the type of the containing
+ type (for function pointer MethodBindings) and record that as a
+ "this" pointer, meaning that it does not need to be explicitly
+ passed at the Java level. */
+ public void findThisPointer() {
+ clearThisPointer();
+ for (int i = 0; i < getNumArguments(); i++) {
+ JavaType arg = getJavaArgumentType(i);
+ if (arg.equals(containingType)) {
+ thisPointerIndex = i;
+ break;
+ }
+
+ if (!arg.isJNIEnv()) {
+ break; // this pointer must be leftmost argument excluding JNIEnvs
+ }
+ }
+ }
+
+ /** Clears any record of a this pointer for this MethodBinding. */
+ public void clearThisPointer() {
+ thisPointerIndex = -1;
+ }
+
+ /** Indicates whether the <i>i</i>th argument to this MethodBinding
+ is actually a "this" pointer. */
+ public boolean isArgumentThisPointer(int i) {
+ return (thisPointerIndex == i);
+ }
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj == null || ! (obj instanceof MethodBinding)) {
+ return false;
+ }
+
+ MethodBinding other = (MethodBinding)obj;
+ if (!(sym.equals(other.sym))) { return false; }
+ if (!(javaReturnType.equals(other.getJavaReturnType()))) { return false; }
+ if (containingType != null &&
+ other.getContainingCType() != null &&
+ (!(containingCType.equals(other.getContainingCType())))) {
+ return false;
+ }
+ if (javaArgumentTypes.size() != other.javaArgumentTypes.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < javaArgumentTypes.size(); ++i) {
+ Object typeThis = javaArgumentTypes.get(i);
+ Object typeOther = other.getJavaArgumentType(i);
+ if (!(typeThis.equals(typeOther))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // FIXME!! Implement hashCode() to match equals(Object)
+
+ /** Returns the signature of this binding. */
+ public String toString() {
+ StringBuffer buf = new StringBuffer(200);
+ buf.append(getJavaReturnType().getName());
+ buf.append(" ");
+ buf.append(getName());
+ buf.append("(");
+ boolean needComma = false;
+ for (int i = 0; i < getNumArguments(); i++) {
+ JavaType type = getJavaArgumentType(i);
+ if (type.isVoid()) {
+ // Make sure this is the only param to the method; if it isn't,
+ // there's something wrong with our parsing of the headers.
+ assert(getNumArguments() == 1);
+ continue;
+ }
+ if (type.isJNIEnv() || isArgumentThisPointer(i)) {
+ // Don't need to expose these at the Java level
+ continue;
+ }
+
+ if (needComma) {
+ buf.append(", ");
+ }
+
+ buf.append(type.getName());
+ buf.append(" ");
+ buf.append(getArgumentName(i));
+ needComma = true;
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+ public final Object clone() {
+ return new MethodBinding(this);
+ }
+
+}
+
diff --git a/src/net/java/games/gluegen/ReferencedStructs.java b/src/net/java/games/gluegen/ReferencedStructs.java
new file mode 100644
index 000000000..1b3b75198
--- /dev/null
+++ b/src/net/java/games/gluegen/ReferencedStructs.java
@@ -0,0 +1,61 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import java.util.*;
+import net.java.games.gluegen.cgram.types.*;
+
+public class ReferencedStructs implements TypeVisitor {
+ private Set results = new HashSet();
+
+ public void clear() {
+ results.clear();
+ }
+
+ public Iterator results() {
+ return results.iterator();
+ }
+
+ public void visitType(Type t) {
+ if (t.isCompound()) {
+ results.add(t);
+ }
+ }
+}
diff --git a/src/net/java/games/gluegen/StructLayout.java b/src/net/java/games/gluegen/StructLayout.java
new file mode 100644
index 000000000..2a500ceae
--- /dev/null
+++ b/src/net/java/games/gluegen/StructLayout.java
@@ -0,0 +1,138 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+import net.java.games.gluegen.cgram.types.*;
+
+public class StructLayout {
+ private int baseOffset;
+ private int structAlignment;
+
+ protected StructLayout(int baseOffset,
+ int structAlignment) {
+ this.baseOffset = baseOffset;
+ this.structAlignment = structAlignment;
+ }
+
+ public void layout(CompoundType t) {
+ int n = t.getNumFields();
+ int curOffset = baseOffset;
+ int maxSize = 0;
+ for (int i = 0; i < n; i++) {
+ Field f = t.getField(i);
+ Type ft = f.getType();
+ if (ft.isInt() || ft.isFloat() || ft.isDouble() || ft.isPointer()) {
+ int sz = ft.getSize();
+ if ((curOffset % sz) != 0) {
+ curOffset += sz - (curOffset % sz);
+ }
+ f.setOffset(curOffset);
+ if (t.isUnion()) {
+ maxSize = Math.max(maxSize, sz);
+ } else {
+ curOffset += sz;
+ }
+ } else if (ft.isCompound()) {
+ new StructLayout(0, structAlignment).layout(ft.asCompound());
+ if ((curOffset % structAlignment) != 0) {
+ curOffset += structAlignment - (curOffset % structAlignment);
+ }
+ f.setOffset(curOffset);
+ if (t.isUnion()) {
+ maxSize = Math.max(maxSize, ft.getSize());
+ } else {
+ curOffset += ft.getSize();
+ }
+ } else if (ft.isArray()) {
+ ArrayType arrayType = ft.asArray();
+ CompoundType compoundElementType = arrayType.getBaseElementType().asCompound();
+ if (compoundElementType != null) {
+ new StructLayout(0, structAlignment).layout(compoundElementType);
+ arrayType.recomputeSize();
+ }
+ // Note: not sure how this rounding is done
+ if ((curOffset % structAlignment) != 0) {
+ curOffset += structAlignment - (curOffset % structAlignment);
+ }
+ f.setOffset(curOffset);
+ curOffset += ft.getSize();
+ } else {
+ // FIXME
+ String name = t.getName();
+ if (name == null) {
+ name = t.toString();
+ }
+ throw new RuntimeException("Complicated field types (" + ft +
+ " " + f.getName() +
+ " in type " + name +
+ ") not implemented yet");
+ }
+ }
+ // FIXME: I think the below is wrong; better check with some examples
+ // if ((curOffset % structAlignment) != 0) {
+ // curOffset += structAlignment - (curOffset % structAlignment);
+ // }
+ if (t.isUnion()) {
+ t.setSize(maxSize);
+ } else {
+ t.setSize(curOffset);
+ }
+ }
+
+
+
+ public static StructLayout createForCurrentPlatform() {
+ String os = System.getProperty("os.name").toLowerCase();
+ String cpu = System.getProperty("os.arch").toLowerCase();
+ if ((os.startsWith("windows") && cpu.equals("x86")) ||
+ (os.startsWith("linux") && cpu.equals("i386")) ||
+ (os.startsWith("sunos") && cpu.equals("sparc")) ||
+ (os.startsWith("sunos") && cpu.equals("i386"))||
+ (os.startsWith("mac os") && cpu.equals("ppc"))
+ ) {
+ // FIXME: make struct alignment configurable? May need to change
+ // packing rules on a per-type basis?
+ return new StructLayout(0, 8);
+ } else {
+ // FIXME: add more ports
+ throw new RuntimeException("Please port StructLayout to your OS (" + os + ") and CPU (" + cpu + ")");
+ }
+ }
+}
diff --git a/src/net/java/games/gluegen/TypeInfo.java b/src/net/java/games/gluegen/TypeInfo.java
new file mode 100644
index 000000000..5df72e411
--- /dev/null
+++ b/src/net/java/games/gluegen/TypeInfo.java
@@ -0,0 +1,61 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen;
+
+/** Utility class for handling Opaque directives for JavaEmitter. */
+
+public class TypeInfo {
+ private String name;
+ private int pointerDepth;
+ private JavaType javaType;
+ private TypeInfo next;
+
+ public TypeInfo(String name, int pointerDepth, JavaType javaType) {
+ this.name = name;
+ this.pointerDepth = pointerDepth;
+ this.javaType = javaType;
+ }
+
+ public String name() { return name; }
+ public int pointerDepth() { return pointerDepth; }
+ public JavaType javaType() { return javaType; }
+ public void setNext(TypeInfo info) { this.next = info; }
+ public TypeInfo next() { return next; }
+}
diff --git a/src/net/java/games/gluegen/cgram/CSymbolTable.java b/src/net/java/games/gluegen/cgram/CSymbolTable.java
new file mode 100644
index 000000000..e22274b90
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/CSymbolTable.java
@@ -0,0 +1,132 @@
+package net.java.games.gluegen.cgram;
+
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+
+
+public class CSymbolTable {
+
+ /** holds list of scopes */
+ private Vector scopeStack;
+
+ /** table where all defined names are mapped to TNode tree nodes */
+ private Hashtable symTable;
+
+ public CSymbolTable() {
+ scopeStack = new Vector(10);
+ symTable = new Hashtable(533);
+ }
+
+
+ /** push a new scope onto the scope stack.
+ */
+ public void pushScope(String s) {
+ //System.out.println("push scope:" + s);
+ scopeStack.addElement(s);
+ }
+
+ /** pop the last scope off the scope stack.
+ */
+ public void popScope() {
+ //System.out.println("pop scope");
+ int size = scopeStack.size();
+ if(size > 0)
+ scopeStack.removeElementAt(size - 1);
+ }
+
+ /** return the current scope as a string
+ */
+ public String currentScopeAsString() {
+ StringBuffer buf = new StringBuffer(100);
+ boolean first = true;
+ Enumeration e = scopeStack.elements();
+ while(e.hasMoreElements()) {
+ if(first)
+ first = false;
+ else
+ buf.append("::");
+ buf.append(e.nextElement().toString());
+ }
+ return buf.toString();
+ }
+
+ /** given a name for a type, append it with the
+ current scope.
+ */
+ public String addCurrentScopeToName(String name) {
+ String currScope = currentScopeAsString();
+ return addScopeToName(currScope, name);
+ }
+
+ /** given a name for a type, append it with the
+ given scope. MBZ
+ */
+ public String addScopeToName(String scope, String name) {
+ if(scope == null || scope.length() > 0)
+ return scope + "::" + name;
+ else
+ return name;
+ }
+
+ /** remove one level of scope from name MBZ*/
+ public String removeOneLevelScope(String scopeName) {
+ int index = scopeName.lastIndexOf("::");
+ if (index > 0) {
+ return scopeName.substring(0,index);
+ }
+ if (scopeName.length() > 0) {
+ return "";
+ }
+ return null;
+ }
+
+ /** add a node to the table with it's key as
+ the current scope and the name */
+ public TNode add(String name, TNode node) {
+ return (TNode)symTable.put(addCurrentScopeToName(name),node);
+ }
+
+
+ /** lookup a fully scoped name in the symbol table */
+ public TNode lookupScopedName(String scopedName) {
+ return (TNode)symTable.get(scopedName);
+ }
+
+ /** lookup an unscoped name in the table by prepending
+ the current scope.
+ MBZ -- if not found, pop scopes and look again
+ */
+ public TNode lookupNameInCurrentScope(String name) {
+ String scope = currentScopeAsString();
+ String scopedName;
+ TNode tnode = null;
+
+ //System.out.println( "\n"+ this.toString() );
+
+ while (tnode == null && scope != null) {
+ scopedName = addScopeToName(scope, name);
+ //System.out.println("lookup trying " + scopedName);
+ tnode = (TNode)symTable.get(scopedName);
+ scope = removeOneLevelScope(scope);
+ }
+ return tnode;
+ }
+
+ /** convert this table to a string */
+ public String toString() {
+ StringBuffer buff = new StringBuffer(300);
+ buff.append("CSymbolTable { \nCurrentScope: " + currentScopeAsString() +
+ "\nDefinedSymbols:\n");
+ Enumeration ke = symTable.keys();
+ Enumeration ve = symTable.elements();
+ while(ke.hasMoreElements()) {
+ buff.append(ke.nextElement().toString() + " (" +
+ TNode.getNameForType(((TNode)ve.nextElement()).getType()) + ")\n");
+ }
+ buff.append("}\n");
+ return buff.toString();
+ }
+
+};
diff --git a/src/net/java/games/gluegen/cgram/CToken.java b/src/net/java/games/gluegen/cgram/CToken.java
new file mode 100644
index 000000000..facd95a08
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/CToken.java
@@ -0,0 +1,32 @@
+package net.java.games.gluegen.cgram;
+
+import antlr.CommonToken;
+
+public class CToken extends antlr.CommonToken {
+ String source = "";
+ int tokenNumber;
+
+ public String getSource()
+ {
+ return source;
+ }
+
+ public void setSource(String src)
+ {
+ source = src;
+ }
+
+ public int getTokenNumber()
+ {
+ return tokenNumber;
+ }
+
+ public void setTokenNumber(int i)
+ {
+ tokenNumber = i;
+ }
+
+ public String toString() {
+ return "CToken:" +"(" + hashCode() + ")" + "[" + getType() + "] "+ getText() + " line:" + getLine() + " source:" + source ;
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/Define.java b/src/net/java/games/gluegen/cgram/Define.java
new file mode 100644
index 000000000..3ab7c9063
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/Define.java
@@ -0,0 +1,56 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram;
+
+/** Represents a #define of a literal to a value (a number represented
+ in string form.) */
+
+public class Define {
+ private String name;
+ private String value;
+
+ public Define(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getName() { return name; }
+ public String getValue() { return value; }
+}
diff --git a/src/net/java/games/gluegen/cgram/GnuCEmitter.g b/src/net/java/games/gluegen/cgram/GnuCEmitter.g
new file mode 100644
index 000000000..87294fc53
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/GnuCEmitter.g
@@ -0,0 +1,1145 @@
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Copyright (c) Non, Inc. 1998 -- All Rights Reserved
+
+PROJECT: C Compiler
+MODULE: GnuCEmitter
+FILE: GnuCEmitter.g
+
+AUTHOR: Monty Zukowski ([email protected]) April 28, 1998
+
+DESCRIPTION:
+
+ This tree grammar is for a Gnu C AST.
+ It turns the tree back into source code.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+header {
+ package net.java.games.gluegen.cgram;
+
+ import java.io.*;
+ import java.util.*;
+
+ import antlr.CommonAST;
+ import antlr.DumpASTVisitor;
+}
+
+
+class GnuCEmitter extends GnuCTreeParser;
+
+options
+ {
+ importVocab = GNUC;
+ buildAST = false;
+ ASTLabelType = "TNode";
+
+ // Copied following options from java grammar.
+ codeGenMakeSwitchThreshold = 2;
+ codeGenBitsetTestThreshold = 3;
+ }
+
+
+{
+
+
+int tabs = 0;
+PrintStream currentOutput = System.out;
+int lineNum = 1;
+String currentSource = "";
+LineObject trueSourceFile;
+final int lineDirectiveThreshold = Integer.MAX_VALUE;
+PreprocessorInfoChannel preprocessorInfoChannel = null;
+Stack sourceFiles = new Stack();
+
+public GnuCEmitter( PreprocessorInfoChannel preprocChannel )
+{
+ preprocessorInfoChannel = preprocChannel;
+}
+
+void initializePrinting()
+{
+ Vector preprocs = preprocessorInfoChannel.extractLinesPrecedingTokenNumber( new Integer(1) );
+ printPreprocs(preprocs);
+/* if ( currentSource.equals("") ) {
+ trueSourceFile = new LineObject(currentSource);
+ currentOutput.println("# 1 \"" + currentSource + "\"\n");
+ sourceFiles.push(trueSourceFile);
+ }
+*/
+}
+
+void finalizePrinting() {
+ // flush any leftover preprocessing instructions to the stream
+
+ printPreprocs(
+ preprocessorInfoChannel.extractLinesPrecedingTokenNumber(
+ new Integer( preprocessorInfoChannel.getMaxTokenNumber() + 1 ) ));
+ //print a newline so file ends at a new line
+ currentOutput.println();
+}
+
+void printPreprocs( Vector preprocs )
+{
+ // if there was a preprocessingDirective previous to this token then
+ // print a newline and the directive, line numbers handled later
+ if ( preprocs.size() > 0 ) {
+ if ( trueSourceFile != null ) {
+ currentOutput.println(); //make sure we're starting a new line unless this is the first line directive
+ }
+ lineNum++;
+ Enumeration e = preprocs.elements();
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+ if ( o.getClass().getName().equals("LineObject") ) {
+ LineObject l = (LineObject) o;
+
+ // we always return to the trueSourceFile, we never enter it from another file
+ // force it to be returning if in fact we aren't currently in trueSourceFile
+ if (( trueSourceFile != null ) //trueSource exists
+ && ( !currentSource.equals(trueSourceFile.getSource()) ) //currently not in trueSource
+ && ( trueSourceFile.getSource().equals(l.getSource()) ) ) { //returning to trueSource
+ l.setEnteringFile( false );
+ l.setReturningToFile( true );
+ }
+
+
+ // print the line directive
+ currentOutput.println(l);
+ lineNum = l.getLine();
+ currentSource = l.getSource();
+
+
+ // the very first line directive always represents the true sourcefile
+ if ( trueSourceFile == null ) {
+ trueSourceFile = new LineObject(currentSource);
+ sourceFiles.push(trueSourceFile);
+ }
+
+ // keep our own stack of files entered
+ if ( l.getEnteringFile() ) {
+ sourceFiles.push(l);
+ }
+
+ // if returning to a file, pop the exited files off the stack
+ if ( l.getReturningToFile() ) {
+ LineObject top = (LineObject) sourceFiles.peek();
+ while (( top != trueSourceFile ) && (! l.getSource().equals(top.getSource()) )) {
+ sourceFiles.pop();
+ top = (LineObject) sourceFiles.peek();
+ }
+ }
+ }
+ else { // it was a #pragma or such
+ currentOutput.println(o);
+ lineNum++;
+ }
+ }
+ }
+
+}
+
+void print( TNode t ) {
+ int tLineNum = t.getLocalLineNum();
+ if ( tLineNum == 0 ) tLineNum = lineNum;
+
+ Vector preprocs = preprocessorInfoChannel.extractLinesPrecedingTokenNumber((Integer)t.getAttribute("tokenNumber"));
+ printPreprocs(preprocs);
+
+ if ( (lineNum != tLineNum) ) {
+ // we know we'll be newlines or a line directive or it probably
+ // is just the case that this token is on the next line
+ // either way start a new line and indent it
+ currentOutput.println();
+ lineNum++;
+ printTabs();
+ }
+
+ if ( lineNum == tLineNum ){
+ // do nothing special, we're at the right place
+ }
+ else {
+ int diff = tLineNum - lineNum;
+ if ( lineNum < tLineNum ) {
+ // print out the blank lines to bring us up to right line number
+ for ( ; lineNum < tLineNum ; lineNum++ ) {
+ currentOutput.println();
+ }
+ printTabs();
+ }
+ else { // just reset lineNum
+ lineNum = tLineNum;
+ }
+ }
+ currentOutput.print( t.getText() + " " );
+}
+
+
+/* This was my attempt at being smart about line numbers
+ It didn't work quite right but I don't know why, I didn't
+ have enough test cases. Worked ok compiling rcs and ghostscript
+*/
+void printAddingLineDirectives( TNode t ) {
+ int tLineNum = t.getLocalLineNum();
+ String tSource = (String) t.getAttribute("source");
+
+ if ( tSource == null ) tSource = currentSource;
+ if ( tLineNum == 0 ) tLineNum = lineNum;
+
+ Vector preprocs = preprocessorInfoChannel.extractLinesPrecedingTokenNumber((Integer)t.getAttribute("tokenNumber"));
+ printPreprocs(preprocs);
+
+ if ( (lineNum != tLineNum) || !currentSource.equals(tSource) ) {
+ // we know we'll be newlines or a line directive or it probably
+ // is just the case that this token is on the next line
+ // either way start a new line and indent it
+ currentOutput.println();
+ lineNum++;
+ printTabs();
+ }
+
+ if ( ( lineNum == tLineNum ) && ( currentSource.equals(tSource) ) ){
+ // do nothing special, we're at the right place
+ }
+ else if ( currentSource.equals(tSource) ) {
+ int diff = tLineNum - lineNum;
+ if (diff > 0 && diff < lineDirectiveThreshold) {
+ // print out the blank lines to bring us up to right line number
+ for ( ; lineNum < tLineNum ; lineNum++ ) {
+ currentOutput.println();
+ }
+ }
+ else { // print line directive to get us to right line number
+ // preserve flags 3 and 4 if present in current file
+ if ( ! sourceFiles.empty() ) {
+ LineObject l = (LineObject) sourceFiles.peek();
+ StringBuffer tFlags = new StringBuffer("");
+ if (l.getSystemHeader()) {
+ tFlags.append(" 3");
+ }
+ if (l.getTreatAsC()) {
+ tFlags.append(" 4");
+ }
+ currentOutput.println("# " + tLineNum + " \"" + tSource + "\"" + tFlags.toString());
+ lineNum = tLineNum;
+ }
+ }
+
+ printTabs();
+ }
+ else { // different source
+ Enumeration sources = sourceFiles.elements();
+ // see if we're returning to a file we entered earlier
+ boolean returningToEarlierFile = false;
+ while (sources.hasMoreElements()) {
+ LineObject l = (LineObject) sources.nextElement();
+ if (l.getSource().equals(tSource)) {
+ returningToEarlierFile = true;
+ break;
+ }
+ }
+ if (returningToEarlierFile) {
+ // pop off the files we're exiting, but never pop the trueSourceFile
+ LineObject l = (LineObject) sourceFiles.peek();
+ while ( ( l != trueSourceFile ) &&(! l.getSource().equals(tSource) ) ) {
+ sourceFiles.pop();
+ l = (LineObject) sourceFiles.peek();
+ }
+
+ // put in the return flag, plus others as needed
+ StringBuffer tFlags = new StringBuffer(" 2");
+ if (l.getSystemHeader()) {
+ tFlags.append(" 3");
+ }
+ if (l.getTreatAsC()) {
+ tFlags.append(" 4");
+ }
+
+ currentOutput.println("# " + tLineNum + " \"" + tSource + "\"" + tFlags);
+ lineNum = tLineNum;
+ currentSource = tSource;
+ printTabs();
+ }
+ else { // entering a file that wasn't in the original source
+ // pretend we're entering it from top of stack
+ currentOutput.println("# " + tLineNum + " \"" + tSource + "\"" + " 1");
+ lineNum = tLineNum;
+ currentSource = tSource;
+ printTabs();
+ }
+ }
+ currentOutput.print( t.getText() + " " );
+}
+
+/** It is not ok to print newlines from the String passed in as
+it will screw up the line number handling **/
+void print( String s ) {
+ currentOutput.print( s + " " );
+}
+
+void printTabs() {
+ for ( int i = 0; i< tabs; i++ ) {
+ currentOutput.print( "\t" );
+ }
+}
+
+void commaSep( TNode t ) {
+ print( t );
+ if ( t.getNextSibling() != null ) {
+ print( "," );
+ }
+}
+
+ int traceDepth = 0;
+ public void reportError(RecognitionException ex) {
+ if ( ex != null) {
+ System.err.println("ANTLR Tree Parsing RecognitionException Error: " + ex.getClass().getName() + " " + ex );
+ ex.printStackTrace(System.err);
+ }
+ }
+ public void reportError(NoViableAltException ex) {
+ System.err.println("ANTLR Tree Parsing NoViableAltException Error: " + ex.toString());
+ TNode.printTree( ex.node );
+ ex.printStackTrace(System.err);
+ }
+ public void reportError(MismatchedTokenException ex) {
+ if ( ex != null) {
+ TNode.printTree( ex.node );
+ System.err.println("ANTLR Tree Parsing MismatchedTokenException Error: " + ex );
+ ex.printStackTrace(System.err);
+ }
+ }
+ public void reportError(String s) {
+ System.err.println("ANTLR Error from String: " + s);
+ }
+ public void reportWarning(String s) {
+ System.err.println("ANTLR Warning from String: " + s);
+ }
+ protected void match(AST t, int ttype) throws MismatchedTokenException {
+ //System.out.println("match("+ttype+"); cursor is "+t);
+ super.match(t, ttype);
+ }
+ public void match(AST t, BitSet b) throws MismatchedTokenException {
+ //System.out.println("match("+b+"); cursor is "+t);
+ super.match(t, b);
+ }
+ protected void matchNot(AST t, int ttype) throws MismatchedTokenException {
+ //System.out.println("matchNot("+ttype+"); cursor is "+t);
+ super.matchNot(t, ttype);
+ }
+ public void traceIn(String rname, AST t) {
+ traceDepth += 1;
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ super.traceIn(rname, t);
+ }
+ public void traceOut(String rname, AST t) {
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ super.traceOut(rname, t);
+ traceDepth -= 1;
+ }
+
+
+
+}
+
+
+translationUnit options {
+ defaultErrorHandler=false;
+}
+ :
+ { initializePrinting(); }
+ ( externalList )?
+ { finalizePrinting(); }
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+externalList
+ : ( externalDef )+
+ ;
+
+
+externalDef
+ : declaration
+ | functionDef
+ | asm_expr
+ | typelessDeclaration
+ | s:SEMI { print( s ); }
+ ;
+
+typelessDeclaration
+ : #(NTypeMissing initDeclList s: SEMI) { print( s ); }
+ ;
+
+
+
+asm_expr
+ : #( a:"asm" { print( a ); }
+ ( v:"volatile" { print( v ); }
+ )?
+ lc:LCURLY { print( lc ); tabs++; }
+ expr
+ rc:RCURLY { tabs--; print( rc ); }
+ s:SEMI { print( s ); }
+ )
+ ;
+
+
+declaration
+ : #( NDeclaration
+ declSpecifiers
+ (
+ initDeclList
+ )?
+ ( s:SEMI { print( s ); } )+
+ )
+ ;
+
+
+declSpecifiers
+ : ( storageClassSpecifier
+ | typeQualifier
+ | typeSpecifier
+ )+
+ ;
+
+storageClassSpecifier
+ : a:"auto" { print( a ); }
+ | b:"register" { print( b ); }
+ | c:"typedef" { print( c ); }
+ | functionStorageClassSpecifier
+ ;
+
+
+functionStorageClassSpecifier
+ : a:"extern" { print( a ); }
+ | b:"static" { print( b ); }
+ | c:"inline" { print( c ); }
+ ;
+
+
+typeQualifier
+ : a:"const" { print( a ); }
+ | b:"volatile" { print( b ); }
+ ;
+
+
+typeSpecifier
+ : a:"void" { print( a ); }
+ | b:"char" { print( b ); }
+ | c:"short" { print( c ); }
+ | d:"int" { print( d ); }
+ | e:"long" { print( e ); }
+ | f:"float" { print( f ); }
+ | g:"double" { print( g ); }
+ | h:"signed" { print( h ); }
+ | i:"unsigned" { print( i ); }
+ | structSpecifier ( attributeDecl )*
+ | unionSpecifier ( attributeDecl )*
+ | enumSpecifier
+ | typedefName
+ | #(n:"typeof" lp:LPAREN { print( n ); print( lp ); }
+ ( (typeName )=> typeName
+ | expr
+ )
+ rp:RPAREN { print( rp ); }
+ )
+ | p:"__complex" { print( p ); }
+ ;
+
+
+typedefName
+ : #(NTypedefName i:ID { print( i ); } )
+ ;
+
+
+structSpecifier
+ : #( a:"struct" { print( a ); }
+ structOrUnionBody
+ )
+ ;
+
+unionSpecifier
+ : #( a:"union" { print( a ); }
+ structOrUnionBody
+ )
+ ;
+
+structOrUnionBody
+ : ( (ID LCURLY) => i1:ID lc1:LCURLY { print( i1 ); print ( "{" ); tabs++; }
+ ( structDeclarationList )?
+ rc1:RCURLY { tabs--; print( rc1 ); }
+ | lc2:LCURLY { print( lc2 ); tabs++; }
+ ( structDeclarationList )?
+ rc2:RCURLY { tabs--; print( rc2 ); }
+ | i2:ID { print( i2 ); }
+ )
+ ;
+
+structDeclarationList
+ : ( structDeclaration { print( ";" ); }
+ )+
+ ;
+
+
+structDeclaration
+ : specifierQualifierList structDeclaratorList
+ ;
+
+
+specifierQualifierList
+ : (
+ typeSpecifier
+ | typeQualifier
+ )+
+ ;
+
+
+structDeclaratorList
+ : structDeclarator
+ ( { print(","); } structDeclarator )*
+ ;
+
+
+structDeclarator
+ :
+ #( NStructDeclarator
+ ( declarator )?
+ ( c:COLON { print( c ); } expr )?
+ ( attributeDecl )*
+ )
+ ;
+
+
+enumSpecifier
+ : #( a:"enum" { print( a ); }
+ ( i:ID { print( i ); } )?
+ ( lc:LCURLY { print( lc ); tabs++; }
+ enumList
+ rc:RCURLY { tabs--; print( rc ); }
+ )?
+ )
+ ;
+
+
+enumList
+ :
+ enumerator ( {print(",");} enumerator)*
+ ;
+
+
+enumerator
+ : i:ID { print( i ); }
+ ( b:ASSIGN { print( b ); }
+ expr
+ )?
+ ;
+
+
+attributeDecl:
+ #( a:"__attribute" { print( a ); }
+ (b:. { print( b ); } )*
+ )
+ | #( n:NAsmAttribute { print( n ); }
+ lp:LPAREN { print( lp ); }
+ expr { print( ")" ); }
+ rp:RPAREN { print( rp ); }
+ )
+ ;
+
+initDeclList
+ : initDecl
+ ( { print( "," ); } initDecl )*
+ ;
+
+
+initDecl
+ { String declName = ""; }
+ : #(NInitDecl
+ declarator
+ ( attributeDecl )*
+ ( a:ASSIGN { print( a ); }
+ initializer
+ | b:COLON { print( b ); }
+ expr
+ )?
+ )
+ ;
+
+
+pointerGroup
+ : #( NPointerGroup
+ ( a:STAR { print( a ); }
+ ( typeQualifier )*
+ )+
+ )
+ ;
+
+
+
+idList
+ : i:ID { print( i ); }
+ ( c:COMMA { print( c ); }
+ id:ID { print( id ); }
+ )*
+ ;
+
+
+
+initializer
+ : #( NInitializer (initializerElementLabel)? expr )
+ | lcurlyInitializer
+ ;
+
+initializerElementLabel
+ : #( NInitializerElementLabel
+ (
+ ( l:LBRACKET { print( l ); }
+ expr
+ r:RBRACKET { print( r ); }
+ (a1:ASSIGN { print( a1 ); } )?
+ )
+ | i1:ID c:COLON { print( i1 ); print( c ); }
+ | d:DOT i2:ID a2:ASSIGN { print( d ); print( i2 ); print( a2 ); }
+ )
+ )
+ ;
+
+lcurlyInitializer
+ : #(n:NLcurlyInitializer { print( n ); tabs++; }
+ initializerList
+ rc:RCURLY { tabs--; print( rc ); }
+ )
+ ;
+
+initializerList
+ : ( i:initializer { commaSep( i ); }
+ )*
+ ;
+
+
+declarator
+ : #( NDeclarator
+ ( pointerGroup )?
+
+ ( id:ID { print( id ); }
+ | lp:LPAREN { print( lp ); } declarator rp:RPAREN { print( rp ); }
+ )
+
+ ( #( n:NParameterTypeList { print( n ); }
+ (
+ parameterTypeList
+ | (idList)?
+ )
+ r:RPAREN { print( r ); }
+ )
+ | lb:LBRACKET { print( lb );} ( expr )? rb:RBRACKET { print( rb ); }
+ )*
+ )
+ ;
+
+
+
+parameterTypeList
+ : ( parameterDeclaration
+ ( c:COMMA { print( c ); }
+ | s:SEMI { print( s ); }
+ )?
+ )+
+ ( v:VARARGS { print( v ); } )?
+ ;
+
+
+
+parameterDeclaration
+ : #( NParameterDeclaration
+ declSpecifiers
+ (declarator | nonemptyAbstractDeclarator)?
+ )
+ ;
+
+
+functionDef
+ : #( NFunctionDef
+ ( functionDeclSpecifiers)?
+ declarator
+ (declaration
+ | v:VARARGS { print( v ); }
+ )*
+ compoundStatement
+ )
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+functionDeclSpecifiers
+ :
+ ( functionStorageClassSpecifier
+ | typeQualifier
+ | typeSpecifier
+ )+
+ ;
+
+declarationList
+ :
+ ( //ANTLR doesn't know that declarationList properly eats all the declarations
+ //so it warns about the ambiguity
+ options {
+ warnWhenFollowAmbig = false;
+ } :
+ localLabelDecl
+ | declaration
+ )+
+ ;
+
+localLabelDecl
+ : #(a:"__label__" { print( a ); }
+ ( i:ID { commaSep( i ); }
+ )+
+ { print( ";" ); }
+ )
+ ;
+
+
+
+compoundStatement
+ : #( cs:NCompoundStatement { print( cs ); tabs++; }
+ ( declarationList
+ | functionDef
+ )*
+ ( statementList )?
+ rc:RCURLY { tabs--; print( rc ); }
+ )
+
+ ;
+
+statementList
+ : ( statement )+
+ ;
+
+statement
+ : statementBody
+ ;
+
+statementBody
+ : s:SEMI { print( s ); }
+
+ | compoundStatement // Group of statements
+
+ | #(NStatementExpr
+ expr { print( ";" ); }
+ ) // Expressions
+
+// Iteration statements:
+
+ | #( w:"while" { print( w ); print( "(" ); }
+ expr { print( ")" ); }
+ statement )
+
+ | #( d:"do" { print( d ); }
+ statement
+ { print( " while ( " ); }
+ expr
+ { print( " );" ); }
+ )
+
+ | #( f:"for" { print( f ); print( "(" ); }
+ expr { print( ";" ); }
+ expr { print( ";" ); }
+ expr { print( ")" ); }
+ statement
+ )
+
+
+// Jump statements:
+
+ | #( g:"goto" { print( g );}
+ expr { print( ";" ); }
+ )
+ | c:"continue" { print( c ); print( ";" );}
+ | b:"break" { print( b ); print( ";" );}
+ | #( r:"return" { print( r ); }
+ ( expr )?
+ { print( ";" ); }
+ )
+
+
+// Labeled statements:
+ | #( NLabel
+ ni:ID { print( ni ); print( ":" ); }
+ ( statement )?
+ )
+
+ | #(
+ ca:"case" { print( ca ); }
+ expr { print( ":" ); }
+ (statement)?
+ )
+
+ | #(
+ de:"default" { print( de ); print( ":" ); }
+ (statement)?
+ )
+
+
+
+// Selection statements:
+
+ | #( i:"if" { print( i ); print( "(" ); }
+ expr { print( ")" ); }
+ statement
+ ( e:"else" { print( e ); }
+ statement
+ )?
+ )
+ | #( sw:"switch" { print( sw ); print( "(" ); }
+ expr { print( ")" ); }
+ statement
+ )
+
+
+
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+
+
+
+
+expr
+ :
+ binaryExpr
+ | conditionalExpr
+ | castExpr
+ | unaryExpr
+ | postfixExpr
+ | primaryExpr
+ | emptyExpr
+ | compoundStatementExpr
+ | initializer
+ | rangeExpr
+ | gnuAsmExpr
+ ;
+
+emptyExpr
+ : NEmptyExpression
+ ;
+
+compoundStatementExpr
+ : #(l:LPAREN { print( l ); }
+ compoundStatement
+ r:RPAREN { print( r ); }
+ )
+ ;
+
+rangeExpr
+ : #(NRangeExpr expr v:VARARGS{ print( v ); } expr)
+ ;
+
+gnuAsmExpr
+ : #(n:NGnuAsmExpr { print( n ); }
+ (v:"volatile" { print( v ); } )?
+ lp:LPAREN { print( lp ); }
+ stringConst
+ ( options { warnWhenFollowAmbig = false; }:
+ c1:COLON { print( c1 );}
+ (strOptExprPair
+ ( c2:COMMA { print( c2 ); } strOptExprPair)*
+ )?
+ ( options { warnWhenFollowAmbig = false; }:
+ c3:COLON { print( c3 ); }
+ (strOptExprPair
+ ( c4:COMMA { print( c4 ); } strOptExprPair)*
+ )?
+ )?
+ )?
+ ( c5:COLON { print( c5 ); }
+ stringConst
+ ( c6:COMMA { print( c6 ); }
+ stringConst
+ )*
+ )?
+ rp:RPAREN { print( rp ); }
+ )
+ ;
+
+strOptExprPair
+ : stringConst
+ (
+ l:LPAREN { print( l ); }
+ expr
+ r:RPAREN { print( r ); }
+ )?
+ ;
+
+binaryOperator
+ : ASSIGN
+ | DIV_ASSIGN
+ | PLUS_ASSIGN
+ | MINUS_ASSIGN
+ | STAR_ASSIGN
+ | MOD_ASSIGN
+ | RSHIFT_ASSIGN
+ | LSHIFT_ASSIGN
+ | BAND_ASSIGN
+ | BOR_ASSIGN
+ | BXOR_ASSIGN
+ | LOR
+ | LAND
+ | BOR
+ | BXOR
+ | BAND
+ | EQUAL
+ | NOT_EQUAL
+ | LT
+ | LTE
+ | GT
+ | GTE
+ | LSHIFT
+ | RSHIFT
+ | PLUS
+ | MINUS
+ | STAR
+ | DIV
+ | MOD
+ | NCommaExpr
+ ;
+
+binaryExpr
+ : b:binaryOperator
+ // no rules allowed as roots, so here I manually get
+ // the first and second children of the binary operator
+ // and then print them out in the right order
+ { TNode e1, e2;
+ e1 = (TNode) b.getFirstChild();
+ e2 = (TNode) e1.getNextSibling();
+ expr( e1 );
+ print( b );
+ expr( e2 );
+ }
+
+ ;
+
+
+conditionalExpr
+ : #( q:QUESTION
+ expr { print( q ); }
+ ( expr )?
+ c:COLON { print( c ); }
+ expr
+ )
+ ;
+
+
+castExpr
+ : #(
+ c:NCast { print( c ); }
+ typeName
+ rp:RPAREN { print( rp ); }
+ expr
+ )
+ ;
+
+
+typeName
+ : specifierQualifierList (nonemptyAbstractDeclarator)?
+ ;
+
+nonemptyAbstractDeclarator
+ : #( NNonemptyAbstractDeclarator
+ ( pointerGroup
+ ( (lp1:LPAREN { print( lp1 ); }
+ ( nonemptyAbstractDeclarator
+ | parameterTypeList
+ )?
+ rp1:RPAREN { print( rp1 ); }
+ )
+ | (
+ lb1:LBRACKET { print( lb1 ); }
+ (expr)?
+ rb1:RBRACKET { print( rb1 ); }
+ )
+ )*
+
+ | ( (lp2:LPAREN { print( lp2 ); }
+ ( nonemptyAbstractDeclarator
+ | parameterTypeList
+ )?
+ rp2:RPAREN { print( rp2 ); }
+ )
+ | (
+ lb2:LBRACKET { print( lb2 ); }
+ (expr)?
+ rb2:RBRACKET { print( rb2 ); }
+ )
+ )+
+ )
+ )
+ ;
+
+
+
+unaryExpr
+ : #( i:INC { print( i ); } expr )
+ | #( d:DEC { print( d ); } expr )
+ | #( NUnaryExpr u:unaryOperator { print( u ); } expr)
+ | #( s:"sizeof" { print( s ); }
+ ( ( LPAREN typeName )=>
+ lps:LPAREN { print( lps ); }
+ typeName
+ rps:RPAREN { print( rps ); }
+ | expr
+ )
+ )
+ | #( a:"__alignof" { print( a ); }
+ ( ( LPAREN typeName )=>
+ lpa:LPAREN { print( lpa ); }
+ typeName
+ rpa:RPAREN { print( rpa ); }
+ | expr
+ )
+ )
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+ unaryOperator
+ : BAND
+ | STAR
+ | PLUS
+ | MINUS
+ | BNOT
+ | LNOT
+ | LAND
+ | "__real"
+ | "__imag"
+ ;
+
+
+postfixExpr
+ : #( NPostfixExpr
+ primaryExpr
+ ( a:PTR b:ID { print( a ); print( b ); }
+ | c:DOT d:ID { print( c ); print( d ); }
+ | #( n:NFunctionCallArgs { print( n ); }
+ (argExprList)?
+ rp:RPAREN { print( rp ); }
+ )
+ | lb:LBRACKET { print( lb ); }
+ expr
+ rb:RBRACKET { print( rb ); }
+ | f:INC { print( f ); }
+ | g:DEC { print( g ); }
+ )+
+ )
+ ;
+
+
+
+primaryExpr
+ : i:ID { print( i ); }
+ | n:Number { print( n ); }
+ | charConst
+ | stringConst
+
+// JTC:
+// ID should catch the enumerator
+// leaving it in gives ambiguous err
+// | enumerator
+
+ | #( eg:NExpressionGroup { print( eg ); }
+ expr { print( ")" ); }
+ )
+ ;
+
+
+
+argExprList
+ : expr ( {print( "," );} expr )*
+ ;
+
+
+
+protected
+charConst
+ : c:CharLiteral { print( c ); }
+ ;
+
+
+protected
+stringConst
+ : #( NStringSeq
+ (
+ s:StringLiteral { print( s ); }
+ )+
+ )
+ ;
+
+
+protected
+intConst
+ : IntOctalConst
+ | LongOctalConst
+ | UnsignedOctalConst
+ | IntIntConst
+ | LongIntConst
+ | UnsignedIntConst
+ | IntHexConst
+ | LongHexConst
+ | UnsignedHexConst
+ ;
+
+
+protected
+floatConst
+ : FloatDoubleConst
+ | DoubleDoubleConst
+ | LongDoubleConst
+ ;
+
+
+
+
+
+
+
+
+
+
diff --git a/src/net/java/games/gluegen/cgram/GnuCParser.g b/src/net/java/games/gluegen/cgram/GnuCParser.g
new file mode 100644
index 000000000..feed4518e
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/GnuCParser.g
@@ -0,0 +1,864 @@
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Copyright (c) Non, Inc. 1998 -- All Rights Reserved
+
+PROJECT: C Compiler
+MODULE: GnuCParser
+FILE: GnuCParser.g
+
+AUTHOR: Monty Zukowski ([email protected]) April 28, 1998
+
+DESCRIPTION:
+ This is a grammar for the GNU C compiler. It is a
+ grammar subclass of StdCParser, overriding only those
+ rules which are different from Standard C.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+header {
+ package net.java.games.gluegen.cgram;
+
+ import java.io.*;
+
+ import antlr.CommonAST;
+ import antlr.DumpASTVisitor;
+}
+
+
+class GnuCParser extends StdCParser;
+
+options
+ {
+ k = 2;
+ exportVocab = GNUC;
+ buildAST = true;
+ ASTLabelType = "TNode";
+
+ // Copied following options from java grammar.
+ codeGenMakeSwitchThreshold = 2;
+ codeGenBitsetTestThreshold = 3;
+ }
+
+
+{
+ // Suppport C++-style single-line comments?
+ public static boolean CPPComments = true;
+
+ // access to symbol table
+ public CSymbolTable symbolTable = new CSymbolTable();
+
+ // source for names to unnamed scopes
+ protected int unnamedScopeCounter = 0;
+
+ public boolean isTypedefName(String name) {
+ boolean returnValue = false;
+ TNode node = symbolTable.lookupNameInCurrentScope(name);
+ for (; node != null; node = (TNode) node.getNextSibling() ) {
+ if(node.getType() == LITERAL_typedef) {
+ returnValue = true;
+ break;
+ }
+ }
+ return returnValue;
+ }
+
+
+ public String getAScopeName() {
+ return "" + (unnamedScopeCounter++);
+ }
+
+ public void pushScope(String scopeName) {
+ symbolTable.pushScope(scopeName);
+ }
+
+ public void popScope() {
+ symbolTable.popScope();
+ }
+
+ int traceDepth = 0;
+ public void reportError(RecognitionException ex) {
+ try {
+ System.err.println("ANTLR Parsing Error: "+ex + " token name:" + tokenNames[LA(1)]);
+ ex.printStackTrace(System.err);
+ }
+ catch (TokenStreamException e) {
+ System.err.println("ANTLR Parsing Error: "+ex);
+ ex.printStackTrace(System.err);
+ }
+ }
+ public void reportError(String s) {
+ System.err.println("ANTLR Parsing Error from String: " + s);
+ }
+ public void reportWarning(String s) {
+ System.err.println("ANTLR Parsing Warning from String: " + s);
+ }
+ public void match(int t) throws MismatchedTokenException {
+ boolean debugging = false;
+
+ if ( debugging ) {
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ try {
+ System.out.println("Match("+tokenNames[t]+") with LA(1)="+
+ tokenNames[LA(1)] + ((inputState.guessing>0)?" [inputState.guessing "+ inputState.guessing + "]":""));
+ }
+ catch (TokenStreamException e) {
+ System.out.println("Match("+tokenNames[t]+") " + ((inputState.guessing>0)?" [inputState.guessing "+ inputState.guessing + "]":""));
+
+ }
+
+ }
+ try {
+ if ( LA(1)!=t ) {
+ if ( debugging ){
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ System.out.println("token mismatch: "+tokenNames[LA(1)]
+ + "!="+tokenNames[t]);
+ }
+ throw new MismatchedTokenException(tokenNames, LT(1), t, false, getFilename());
+
+ } else {
+ // mark token as consumed -- fetch next token deferred until LA/LT
+ consume();
+ }
+ }
+ catch (TokenStreamException e) {
+ }
+
+ }
+ public void traceIn(String rname) {
+ traceDepth += 1;
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ try {
+ System.out.println("> "+rname+"; LA(1)==("+ tokenNames[LT(1).getType()]
+ + ") " + LT(1).getText() + " [inputState.guessing "+ inputState.guessing + "]");
+ }
+ catch (TokenStreamException e) {
+ }
+ }
+ public void traceOut(String rname) {
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ try {
+ System.out.println("< "+rname+"; LA(1)==("+ tokenNames[LT(1).getType()]
+ + ") "+LT(1).getText() + " [inputState.guessing "+ inputState.guessing + "]");
+ }
+ catch (TokenStreamException e) {
+ }
+ traceDepth -= 1;
+ }
+
+}
+
+
+translationUnit
+ : ( externalList )? /* Empty source files are allowed. */
+ ;
+asm_expr
+ : "asm"^
+ ("volatile")? LCURLY expr RCURLY ( SEMI )+
+ ;
+
+idList
+ : ID ( options{warnWhenFollowAmbig=false;}: COMMA ID )*
+ ;
+
+externalDef
+ : ( "typedef" | declaration )=> declaration
+ | ( functionPrefix )=> functionDef
+ | typelessDeclaration
+ | asm_expr
+ | SEMI
+ ;
+
+/* these two are here because GCC allows "cat = 13;" as a valid program! */
+functionPrefix
+ { String declName; }
+ : ( (functionDeclSpecifiers)=> ds:functionDeclSpecifiers
+ | //epsilon
+ )
+ declName = d:declarator[true]
+ ( declaration )* (VARARGS)? ( SEMI )*
+ LCURLY
+ ;
+
+typelessDeclaration
+ { AST typeMissing = #[NTypeMissing]; }
+ : initDeclList[typeMissing] SEMI { ## = #( #[NTypeMissing], ##); }
+ ;
+
+initializer
+ : ( ( ( (initializerElementLabel)=> initializerElementLabel )?
+ ( assignExpr | lcurlyInitializer ) { ## = #( #[NInitializer], ## ); }
+ )
+ | lcurlyInitializer
+ )
+ ;
+
+// GCC allows more specific initializers
+initializerElementLabel
+ : ( ( LBRACKET ((constExpr VARARGS)=> rangeExpr | constExpr) RBRACKET (ASSIGN)? )
+ | ID COLON
+ | DOT ID ASSIGN
+ )
+ { ## = #( #[NInitializerElementLabel], ##) ; }
+ ;
+
+// GCC allows empty initializer lists
+lcurlyInitializer
+ :
+ LCURLY^ (initializerList ( COMMA! )? )? RCURLY
+ { ##.setType( NLcurlyInitializer ); }
+ ;
+
+initializerList
+ : initializer ( options{warnWhenFollowAmbig=false;}:COMMA! initializer )*
+ ;
+
+
+declarator[boolean isFunctionDefinition] returns [String declName]
+ { declName = ""; }
+ :
+ ( pointerGroup )?
+
+ ( id:ID { declName = id.getText(); }
+ | LPAREN declName = declarator[false] RPAREN
+ )
+
+ ( declaratorParamaterList[isFunctionDefinition, declName]
+ | LBRACKET ( expr )? RBRACKET
+ )*
+ { ## = #( #[NDeclarator], ## ); }
+ ;
+
+declaratorParamaterList[boolean isFunctionDefinition, String declName]
+ :
+ LPAREN^
+ {
+ if (isFunctionDefinition) {
+ pushScope(declName);
+ }
+ else {
+ pushScope("!"+declName);
+ }
+ }
+ (
+ (declSpecifiers)=> parameterTypeList
+ | (idList)?
+ )
+ {
+ popScope();
+ }
+ ( COMMA! )?
+ RPAREN
+ { ##.setType(NParameterTypeList); }
+ ;
+
+parameterTypeList
+ : parameterDeclaration
+ ( options {
+ warnWhenFollowAmbig = false;
+ } :
+ ( COMMA | SEMI )
+ parameterDeclaration
+ )*
+ ( ( COMMA | SEMI )
+ VARARGS
+ )?
+ ;
+
+
+declarationList
+ : ( options { // this loop properly aborts when
+ // it finds a non-typedefName ID MBZ
+ warnWhenFollowAmbig = false;
+ } :
+
+ localLabelDeclaration
+ | ( declarationPredictor )=> declaration
+ )+
+ ;
+localLabelDeclaration
+ : ( //GNU note: any __label__ declarations must come before regular declarations.
+ "__label__"^ ID (options{warnWhenFollowAmbig=false;}: COMMA! ID)* ( COMMA! )? ( SEMI! )+
+ )
+ ;
+
+
+declaration
+ { AST ds1 = null; }
+ : ds:declSpecifiers { ds1 = astFactory.dupList(#ds); }
+ (
+ initDeclList[ds1]
+ )?
+ ( SEMI )+
+ { ## = #( #[NDeclaration], ##); }
+
+ ;
+
+functionStorageClassSpecifier
+ : "extern"
+ | "static"
+ | "inline"
+ ;
+
+typeSpecifier [int specCount] returns [int retSpecCount]
+ { retSpecCount = specCount + 1; }
+ :
+ ( "void"
+ | "char"
+ | "short"
+ | "int"
+ | "__int64"
+ | "long"
+ | "float"
+ | "double"
+ | "signed"
+ | "unsigned"
+ | structOrUnionSpecifier ( options{warnWhenFollowAmbig=false;}: attributeDecl )*
+ | enumSpecifier
+ | { specCount==0 }? typedefName
+ | "typeof"^ LPAREN
+ ( ( typeName )=> typeName
+ | expr
+ )
+ RPAREN
+ | "__complex"
+ )
+ ;
+
+
+structOrUnionSpecifier
+ { String scopeName; }
+ : sou:structOrUnion!
+ ( ( ID LCURLY )=> i:ID l:LCURLY
+ {
+ scopeName = #sou.getText() + " " + #i.getText();
+ #l.setText(scopeName);
+ pushScope(scopeName);
+ }
+ ( structDeclarationList )?
+ { popScope();}
+ RCURLY
+ | l1:LCURLY
+ {
+ scopeName = getAScopeName();
+ #l1.setText(scopeName);
+ pushScope(scopeName);
+ }
+ ( structDeclarationList )?
+ { popScope(); }
+ RCURLY
+ | ID
+ )
+ {
+ ## = #( #sou, ## );
+ }
+ ;
+
+
+structDeclaration
+ : specifierQualifierList structDeclaratorList ( COMMA! )? ( SEMI! )+
+ ;
+
+structDeclaratorList
+ : structDeclarator ( options{warnWhenFollowAmbig=false;}: COMMA! structDeclarator )*
+ ;
+
+structDeclarator
+ : ( declarator[false] )?
+ ( COLON constExpr )?
+ ( attributeDecl )*
+ { ## = #( #[NStructDeclarator], ##); }
+ ;
+
+
+
+enumSpecifier
+ : "enum"^
+ ( ( ID LCURLY )=> i:ID LCURLY enumList[i.getText()] RCURLY
+ | LCURLY enumList["anonymous"] RCURLY
+ | ID
+ )
+ ;
+enumList[String enumName]
+ : enumerator[enumName] ( options{warnWhenFollowAmbig=false;}: COMMA! enumerator[enumName] )* ( COMMA! )?
+ ;
+
+
+initDeclList[AST declarationSpecifiers]
+ : initDecl[declarationSpecifiers]
+ ( options{warnWhenFollowAmbig=false;}: COMMA! initDecl[declarationSpecifiers] )*
+ ( COMMA! )?
+ ;
+
+initDecl[AST declarationSpecifiers]
+ { String declName = ""; }
+ : declName = d:declarator[false]
+ { AST ds1, d1;
+ ds1 = astFactory.dupList(declarationSpecifiers);
+ d1 = astFactory.dupList(#d);
+ symbolTable.add(declName, #(null, ds1, d1) );
+ }
+ ( attributeDecl )*
+ ( ASSIGN initializer
+ | COLON expr
+ )?
+ { ## = #( #[NInitDecl], ## ); }
+ ;
+
+attributeDecl
+ : "__attribute"^ LPAREN LPAREN attributeList RPAREN RPAREN
+ | "asm"^ LPAREN stringConst RPAREN { ##.setType( NAsmAttribute ); }
+ ;
+
+attributeList
+ : attribute ( options{warnWhenFollowAmbig=false;}: COMMA attribute)* ( COMMA )?
+ ;
+
+attribute
+ : ( ~(LPAREN | RPAREN | COMMA)
+ | LPAREN attributeList RPAREN
+ )*
+ ;
+compoundStatement[String scopeName]
+ : LCURLY^
+
+ {
+ pushScope(scopeName);
+ }
+ ( //this ambiguity is ok, declarationList and nestedFunctionDef end properly
+ options {
+ warnWhenFollowAmbig = false;
+ } :
+ ( "typedef" | "__label__" | declaration )=> declarationList
+ | (nestedFunctionDef)=> nestedFunctionDef
+ )*
+ ( statementList )?
+ { popScope(); }
+ RCURLY
+ { ##.setType( NCompoundStatement ); ##.setAttribute( "scopeName", scopeName ); }
+ ;
+
+nestedFunctionDef
+ { String declName; }
+ : ( "auto" )? //only for nested functions
+ ( (functionDeclSpecifiers)=> ds:functionDeclSpecifiers
+ )?
+ declName = d:declarator[false]
+ {
+ AST d2, ds2;
+ d2 = astFactory.dupList(#d);
+ ds2 = astFactory.dupList(#ds);
+ symbolTable.add(declName, #(null, ds2, d2));
+ pushScope(declName);
+ }
+ ( declaration )*
+ { popScope(); }
+ compoundStatement[declName]
+ { ## = #( #[NFunctionDef], ## );}
+ ;
+
+statement
+ : SEMI // Empty statements
+
+ | compoundStatement[getAScopeName()] // Group of statements
+
+ | expr SEMI! { ## = #( #[NStatementExpr], ## );} // Expressions
+
+// Iteration statements:
+
+ | "while"^ LPAREN! expr RPAREN! statement
+ | "do"^ statement "while"! LPAREN! expr RPAREN! SEMI!
+ |! "for"
+ LPAREN ( e1:expr )? SEMI ( e2:expr )? SEMI ( e3:expr )? RPAREN
+ s:statement
+ {
+ if ( #e1 == null) { #e1 = (TNode) #[ NEmptyExpression ]; }
+ if ( #e2 == null) { #e2 = (TNode) #[ NEmptyExpression ]; }
+ if ( #e3 == null) { #e3 = (TNode) #[ NEmptyExpression ]; }
+ ## = #( #[LITERAL_for, "for"], #e1, #e2, #e3, #s );
+ }
+
+
+// Jump statements:
+
+ | "goto"^ expr SEMI!
+ | "continue" SEMI!
+ | "break" SEMI!
+ | "return"^ ( expr )? SEMI!
+
+
+ | ID COLON! (options {warnWhenFollowAmbig=false;}: statement)? { ## = #( #[NLabel], ## ); }
+// GNU allows range expressions in case statements
+ | "case"^ ((constExpr VARARGS)=> rangeExpr | constExpr) COLON! ( options{warnWhenFollowAmbig=false;}:statement )?
+ | "default"^ COLON! ( options{warnWhenFollowAmbig=false;}: statement )?
+
+// Selection statements:
+
+ | "if"^
+ LPAREN! expr RPAREN! statement
+ ( //standard if-else ambiguity
+ options {
+ warnWhenFollowAmbig = false;
+ } :
+ "else" statement )?
+ | "switch"^ LPAREN! expr RPAREN! statement
+ ;
+
+
+
+conditionalExpr
+ : logicalOrExpr
+ ( QUESTION^ (expr)? COLON conditionalExpr )?
+ ;
+
+rangeExpr //used in initializers only
+ : constExpr VARARGS constExpr
+ { ## = #(#[NRangeExpr], ##); }
+ ;
+
+castExpr
+ : ( LPAREN typeName RPAREN )=>
+ LPAREN^ typeName RPAREN ( castExpr | lcurlyInitializer )
+ { ##.setType(NCast); }
+
+ | unaryExpr
+ ;
+nonemptyAbstractDeclarator
+ : (
+ pointerGroup
+ ( (LPAREN
+ ( nonemptyAbstractDeclarator
+ | parameterTypeList
+ )?
+ ( COMMA! )?
+ RPAREN)
+ | (LBRACKET (expr)? RBRACKET)
+ )*
+
+ | ( (LPAREN
+ ( nonemptyAbstractDeclarator
+ | parameterTypeList
+ )?
+ ( COMMA! )?
+ RPAREN)
+ | (LBRACKET (expr)? RBRACKET)
+ )+
+ )
+ { ## = #( #[NNonemptyAbstractDeclarator], ## ); }
+
+ ;
+
+
+
+unaryExpr
+ : postfixExpr
+ | INC^ castExpr
+ | DEC^ castExpr
+ | u:unaryOperator castExpr { ## = #( #[NUnaryExpr], ## ); }
+
+ | "sizeof"^
+ ( ( LPAREN typeName )=> LPAREN typeName RPAREN
+ | unaryExpr
+ )
+ | "__alignof"^
+ ( ( LPAREN typeName )=> LPAREN typeName RPAREN
+ | unaryExpr
+ )
+ | gnuAsmExpr
+ ;
+
+unaryOperator
+ : BAND
+ | STAR
+ | PLUS
+ | MINUS
+ | BNOT //also stands for complex conjugation
+ | LNOT
+ | LAND //for label dereference (&&label)
+ | "__real"
+ | "__imag"
+ ;
+
+gnuAsmExpr
+ : "asm"^ ("volatile")?
+ LPAREN stringConst
+ ( options { warnWhenFollowAmbig = false; }:
+ COLON (strOptExprPair ( COMMA strOptExprPair)* )?
+ ( options { warnWhenFollowAmbig = false; }:
+ COLON (strOptExprPair ( COMMA strOptExprPair)* )?
+ )?
+ )?
+ ( COLON stringConst ( COMMA stringConst)* )?
+ RPAREN
+ { ##.setType(NGnuAsmExpr); }
+ ;
+
+//GCC requires the PARENs
+strOptExprPair
+ : stringConst ( LPAREN expr RPAREN )?
+ ;
+
+
+primaryExpr
+ : ID
+ | Number
+ | charConst
+ | stringConst
+// JTC:
+// ID should catch the enumerator
+// leaving it in gives ambiguous err
+// | enumerator
+ | (LPAREN LCURLY) => LPAREN^ compoundStatement[getAScopeName()] RPAREN
+ | LPAREN^ expr RPAREN { ##.setType(NExpressionGroup); }
+ ;
+
+
+{
+ import java.io.*;
+ import java.util.*;
+ import antlr.*;
+}
+
+class GnuCLexer extends StdCLexer;
+options
+ {
+ k = 3;
+ importVocab = GNUC;
+ testLiterals = false;
+ }
+tokens {
+ LITERAL___extension__ = "__extension__";
+}
+
+{
+ public void initialize(String src)
+ {
+ setOriginalSource(src);
+ initialize();
+ }
+
+ public void initialize()
+ {
+ literals.put(new ANTLRHashString("__alignof__", this), new Integer(LITERAL___alignof));
+ literals.put(new ANTLRHashString("__asm", this), new Integer(LITERAL_asm));
+ literals.put(new ANTLRHashString("__asm__", this), new Integer(LITERAL_asm));
+ literals.put(new ANTLRHashString("__attribute__", this), new Integer(LITERAL___attribute));
+ literals.put(new ANTLRHashString("__complex__", this), new Integer(LITERAL___complex));
+ literals.put(new ANTLRHashString("__const", this), new Integer(LITERAL_const));
+ literals.put(new ANTLRHashString("__const__", this), new Integer(LITERAL_const));
+ literals.put(new ANTLRHashString("__imag__", this), new Integer(LITERAL___imag));
+ literals.put(new ANTLRHashString("__inline", this), new Integer(LITERAL_inline));
+ literals.put(new ANTLRHashString("__inline__", this), new Integer(LITERAL_inline));
+ literals.put(new ANTLRHashString("__real__", this), new Integer(LITERAL___real));
+ literals.put(new ANTLRHashString("__signed", this), new Integer(LITERAL_signed));
+ literals.put(new ANTLRHashString("__signed__", this), new Integer(LITERAL_signed));
+ literals.put(new ANTLRHashString("__typeof", this), new Integer(LITERAL_typeof));
+ literals.put(new ANTLRHashString("__typeof__", this), new Integer(LITERAL_typeof));
+ literals.put(new ANTLRHashString("__volatile", this), new Integer(LITERAL_volatile));
+ literals.put(new ANTLRHashString("__volatile__", this), new Integer(LITERAL_volatile));
+ }
+
+
+ LineObject lineObject = new LineObject();
+ String originalSource = "";
+ PreprocessorInfoChannel preprocessorInfoChannel = new PreprocessorInfoChannel();
+ int tokenNumber = 0;
+ boolean countingTokens = true;
+ int deferredLineCount = 0;
+ List defines = new ArrayList();
+
+ public void setCountingTokens(boolean ct)
+ {
+ countingTokens = ct;
+ if ( countingTokens ) {
+ tokenNumber = 0;
+ }
+ else {
+ tokenNumber = 1;
+ }
+ }
+
+ public void setOriginalSource(String src)
+ {
+ originalSource = src;
+ lineObject.setSource(src);
+ }
+ public void setSource(String src)
+ {
+ lineObject.setSource(src);
+ }
+
+ public PreprocessorInfoChannel getPreprocessorInfoChannel()
+ {
+ return preprocessorInfoChannel;
+ }
+
+ public void setPreprocessingDirective(String pre)
+ {
+ preprocessorInfoChannel.addLineForTokenNumber( pre, new Integer(tokenNumber) );
+ }
+
+ public void addDefine(String name, String value)
+ {
+ defines.add(new Define(name, value));
+ }
+
+ /** Returns a list of Define objects corresponding to the
+ preprocessor definitions seen during parsing. */
+ public List getDefines() {
+ return defines;
+ }
+
+ protected Token makeToken(int t)
+ {
+ if ( t != Token.SKIP && countingTokens) {
+ tokenNumber++;
+ }
+ CToken tok = (CToken) super.makeToken(t);
+ tok.setLine(lineObject.line);
+ tok.setSource(lineObject.source);
+ tok.setTokenNumber(tokenNumber);
+
+ lineObject.line += deferredLineCount;
+ deferredLineCount = 0;
+ return tok;
+ }
+
+ public void deferredNewline() {
+ deferredLineCount++;
+ }
+
+ public void newline() {
+ lineObject.newline();
+ }
+
+
+
+
+
+
+}
+Whitespace
+ : ( ( ' ' | '\t' | '\014')
+ | "\r\n" { newline(); }
+ | ( '\n' | '\r' ) { newline(); }
+ ) { _ttype = Token.SKIP; }
+ ;
+
+
+protected
+Escape
+ : '\\'
+ ( options{warnWhenFollowAmbig=false;}:
+ ~('0'..'7' | 'x')
+ | ('0'..'3') ( options{warnWhenFollowAmbig=false;}: Digit )*
+ | ('4'..'7') ( options{warnWhenFollowAmbig=false;}: Digit )*
+ | 'x' ( options{warnWhenFollowAmbig=false;}: Digit | 'a'..'f' | 'A'..'F' )+
+ )
+ ;
+
+protected IntSuffix
+ : 'L'
+ | 'l'
+ | 'U'
+ | 'u'
+ | 'I'
+ | 'i'
+ | 'J'
+ | 'j'
+ ;
+protected NumberSuffix
+ :
+ IntSuffix
+ | 'F'
+ | 'f'
+ ;
+
+Number
+ : ( ( Digit )+ ( '.' | 'e' | 'E' ) )=> ( Digit )+
+ ( '.' ( Digit )* ( Exponent )?
+ | Exponent
+ )
+ ( NumberSuffix
+ )*
+
+ | ( "..." )=> "..." { _ttype = VARARGS; }
+
+ | '.' { _ttype = DOT; }
+ ( ( Digit )+ ( Exponent )?
+ { _ttype = Number; }
+ ( NumberSuffix
+ )*
+ )?
+
+ | '0' ( '0'..'7' )*
+ ( NumberSuffix
+ )*
+
+ | '1'..'9' ( Digit )*
+ ( NumberSuffix
+ )*
+
+ | '0' ( 'x' | 'X' ) ( 'a'..'f' | 'A'..'F' | Digit )+
+ ( IntSuffix
+ )*
+ ;
+
+IDMEAT
+ :
+ i:ID {
+
+ if ( i.getType() == LITERAL___extension__ ) {
+ $setType(Token.SKIP);
+ }
+ else {
+ $setType(i.getType());
+ }
+
+ }
+ ;
+
+protected ID
+ options
+ {
+ testLiterals = true;
+ }
+ : ( 'a'..'z' | 'A'..'Z' | '_' | '$')
+ ( 'a'..'z' | 'A'..'Z' | '_' | '$' | '0'..'9' )*
+ ;
+
+WideCharLiteral
+ :
+ 'L' CharLiteral
+ { $setType(CharLiteral); }
+ ;
+
+
+
+WideStringLiteral
+ :
+ 'L' StringLiteral
+ { $setType(StringLiteral); }
+ ;
+
+StringLiteral
+ :
+ '"'
+ ( ('\\' ~('\n'))=> Escape
+ | ( '\r' { newline(); }
+ | '\n' {
+ newline();
+ }
+ | '\\' '\n' {
+ newline();
+ }
+ )
+ | ~( '"' | '\r' | '\n' | '\\' )
+ )*
+ '"'
+ ;
+
+
+
+
diff --git a/src/net/java/games/gluegen/cgram/GnuCTreeParser.g b/src/net/java/games/gluegen/cgram/GnuCTreeParser.g
new file mode 100644
index 000000000..8400e3e59
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/GnuCTreeParser.g
@@ -0,0 +1,852 @@
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Copyright (c) Non, Inc. 1998 -- All Rights Reserved
+
+PROJECT: C Compiler
+MODULE: GnuCTreeParser
+FILE: GnuCTreeParser.g
+
+AUTHOR: Monty Zukowski ([email protected]) April 28, 1998
+
+DESCRIPTION:
+
+ This tree grammar is for a Gnu C AST. No actions in it,
+ subclass to do something useful.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+header {
+ package net.java.games.gluegen.cgram;
+
+ import java.io.*;
+
+ import antlr.CommonAST;
+ import antlr.DumpASTVisitor;
+}
+
+
+class GnuCTreeParser extends TreeParser;
+
+options
+ {
+ importVocab = GNUC;
+ buildAST = false;
+ ASTLabelType = "TNode";
+
+ // Copied following options from java grammar.
+ codeGenMakeSwitchThreshold = 2;
+ codeGenBitsetTestThreshold = 3;
+ }
+
+
+{
+ int traceDepth = 0;
+ public void reportError(RecognitionException ex) {
+ if ( ex != null) {
+ System.err.println("ANTLR Tree Parsing RecognitionException Error: " + ex.getClass().getName() + " " + ex );
+ ex.printStackTrace(System.err);
+ }
+ }
+ public void reportError(NoViableAltException ex) {
+ System.err.println("ANTLR Tree Parsing NoViableAltException Error: " + ex.toString());
+ TNode.printTree( ex.node );
+ ex.printStackTrace(System.err);
+ }
+ public void reportError(MismatchedTokenException ex) {
+ if ( ex != null) {
+ TNode.printTree( ex.node );
+ System.err.println("ANTLR Tree Parsing MismatchedTokenException Error: " + ex );
+ ex.printStackTrace(System.err);
+ }
+ }
+ public void reportError(String s) {
+ System.err.println("ANTLR Error from String: " + s);
+ }
+ public void reportWarning(String s) {
+ System.err.println("ANTLR Warning from String: " + s);
+ }
+ protected void match(AST t, int ttype) throws MismatchedTokenException {
+ //System.out.println("match("+ttype+"); cursor is "+t);
+ super.match(t, ttype);
+ }
+ public void match(AST t, BitSet b) throws MismatchedTokenException {
+ //System.out.println("match("+b+"); cursor is "+t);
+ super.match(t, b);
+ }
+ protected void matchNot(AST t, int ttype) throws MismatchedTokenException {
+ //System.out.println("matchNot("+ttype+"); cursor is "+t);
+ super.matchNot(t, ttype);
+ }
+ public void traceIn(String rname, AST t) {
+ traceDepth += 1;
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ super.traceIn(rname, t);
+ }
+ public void traceOut(String rname, AST t) {
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ super.traceOut(rname, t);
+ traceDepth -= 1;
+ }
+
+
+}
+
+translationUnit options {
+ defaultErrorHandler=false;
+}
+ : ( externalList )?
+ ;
+
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+externalList
+ : ( externalDef )+
+ ;
+
+
+externalDef
+ : declaration
+ | functionDef
+ | asm_expr
+ | SEMI
+ | typelessDeclaration
+ ;
+
+typelessDeclaration
+ : #(NTypeMissing initDeclList SEMI)
+ ;
+
+
+
+asm_expr
+ : #( "asm" ( "volatile" )? LCURLY expr RCURLY ( SEMI )+ )
+ ;
+
+
+declaration
+ : #( NDeclaration
+ declSpecifiers
+ (
+ initDeclList
+ )?
+ ( SEMI )+
+ )
+ ;
+
+
+declSpecifiers
+ : ( storageClassSpecifier
+ | typeQualifier
+ | typeSpecifier
+ )+
+ ;
+
+storageClassSpecifier
+ : "auto"
+ | "register"
+ | "typedef"
+ | functionStorageClassSpecifier
+ ;
+
+
+functionStorageClassSpecifier
+ : "extern"
+ | "static"
+ | "inline"
+ ;
+
+
+typeQualifier
+ : "const"
+ | "volatile"
+ ;
+
+
+typeSpecifier
+ : "void"
+ | "char"
+ | "short"
+ | "int"
+ | "long"
+ | "float"
+ | "double"
+ | "signed"
+ | "unsigned"
+ | structSpecifier ( attributeDecl )*
+ | unionSpecifier ( attributeDecl )*
+ | enumSpecifier
+ | typedefName
+ | #("typeof" LPAREN
+ ( (typeName )=> typeName
+ | expr
+ )
+ RPAREN
+ )
+ | "__complex"
+ ;
+
+
+typedefName
+ : #(NTypedefName ID)
+ ;
+
+
+structSpecifier
+ : #( "struct" structOrUnionBody )
+ ;
+
+unionSpecifier
+ : #( "union" structOrUnionBody )
+ ;
+
+structOrUnionBody
+ : ( (ID LCURLY) => ID LCURLY
+ ( structDeclarationList )?
+ RCURLY
+ | LCURLY
+ ( structDeclarationList )?
+ RCURLY
+ | ID
+ )
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+structDeclarationList
+ : ( structDeclaration )+
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+
+structDeclaration
+ : specifierQualifierList structDeclaratorList
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+
+specifierQualifierList
+ : (
+ typeSpecifier
+ | typeQualifier
+ )+
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+
+structDeclaratorList
+ : ( structDeclarator )+
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+
+structDeclarator
+ :
+ #( NStructDeclarator
+ ( declarator )?
+ ( COLON expr )?
+ ( attributeDecl )*
+ )
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+
+
+enumSpecifier
+ : #( "enum"
+ ( ID )?
+ ( LCURLY enumList RCURLY )?
+ )
+ ;
+
+
+enumList
+ : ( enumerator )+
+ ;
+
+
+enumerator
+ : ID ( ASSIGN expr )?
+ ;
+
+
+
+attributeDecl:
+ #( "__attribute" (.)* )
+ | #( NAsmAttribute LPAREN expr RPAREN )
+ ;
+
+initDeclList
+ : ( initDecl )+
+ ;
+
+
+initDecl
+ { String declName = ""; }
+ : #( NInitDecl
+ declarator
+ ( attributeDecl )*
+ ( ASSIGN initializer
+ | COLON expr
+ )?
+ )
+ ;
+
+
+pointerGroup
+ : #( NPointerGroup ( STAR ( typeQualifier )* )+ )
+ ;
+
+
+
+idList
+ : ID ( COMMA ID )*
+ ;
+
+
+
+initializer
+ : #( NInitializer (initializerElementLabel)? expr )
+ | lcurlyInitializer
+ ;
+
+initializerElementLabel
+ : #( NInitializerElementLabel
+ (
+ ( LBRACKET expr RBRACKET (ASSIGN)? )
+ | ID COLON
+ | DOT ID ASSIGN
+ )
+ )
+ ;
+
+lcurlyInitializer
+ : #( NLcurlyInitializer
+ initializerList
+ RCURLY
+ )
+ ;
+
+initializerList
+ : ( initializer )*
+ ;
+
+
+declarator
+ : #( NDeclarator
+ ( pointerGroup )?
+
+ ( id:ID
+ | LPAREN declarator RPAREN
+ )
+
+ ( #( NParameterTypeList
+ (
+ parameterTypeList
+ | (idList)?
+ )
+ RPAREN
+ )
+ | LBRACKET ( expr )? RBRACKET
+ )*
+ )
+ ;
+
+
+
+parameterTypeList
+ : ( parameterDeclaration ( COMMA | SEMI )? )+ ( VARARGS )?
+ ;
+
+
+
+parameterDeclaration
+ : #( NParameterDeclaration
+ declSpecifiers
+ (declarator | nonemptyAbstractDeclarator)?
+ )
+ ;
+
+
+functionDef
+ : #( NFunctionDef
+ ( functionDeclSpecifiers)?
+ declarator
+ (declaration | VARARGS)*
+ compoundStatement
+ )
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+functionDeclSpecifiers
+ :
+ ( functionStorageClassSpecifier
+ | typeQualifier
+ | typeSpecifier
+ )+
+ ;
+
+declarationList
+ :
+ ( //ANTLR doesn't know that declarationList properly eats all the declarations
+ //so it warns about the ambiguity
+ options {
+ warnWhenFollowAmbig = false;
+ } :
+ localLabelDecl
+ | declaration
+ )+
+ ;
+
+localLabelDecl
+ : #("__label__" (ID)+ )
+ ;
+
+
+
+compoundStatement
+ : #( NCompoundStatement
+ ( declarationList
+ | functionDef
+ )*
+ ( statementList )?
+ RCURLY
+ )
+ ;
+
+statementList
+ : ( statement )+
+ ;
+
+statement
+ : statementBody
+ ;
+
+statementBody
+ : SEMI // Empty statements
+
+ | compoundStatement // Group of statements
+
+ | #(NStatementExpr expr) // Expressions
+
+// Iteration statements:
+
+ | #( "while" expr statement )
+ | #( "do" statement expr )
+ | #( "for"
+ expr expr expr
+ statement
+ )
+
+
+// Jump statements:
+
+ | #( "goto" expr )
+ | "continue"
+ | "break"
+ | #( "return" ( expr )? )
+
+
+// Labeled statements:
+ | #( NLabel ID (statement)? )
+ | #( "case" expr (statement)? )
+ | #( "default" (statement)? )
+
+
+
+// Selection statements:
+
+ | #( "if"
+ expr statement
+ ( "else" statement )?
+ )
+ | #( "switch" expr statement )
+
+
+
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+
+
+
+
+
+expr
+ : assignExpr
+ | conditionalExpr
+ | logicalOrExpr
+ | logicalAndExpr
+ | inclusiveOrExpr
+ | exclusiveOrExpr
+ | bitAndExpr
+ | equalityExpr
+ | relationalExpr
+ | shiftExpr
+ | additiveExpr
+ | multExpr
+ | castExpr
+ | unaryExpr
+ | postfixExpr
+ | primaryExpr
+ | commaExpr
+ | emptyExpr
+ | compoundStatementExpr
+ | initializer
+ | rangeExpr
+ | gnuAsmExpr
+ ;
+
+commaExpr
+ : #(NCommaExpr expr expr)
+ ;
+
+emptyExpr
+ : NEmptyExpression
+ ;
+
+compoundStatementExpr
+ : #(LPAREN compoundStatement RPAREN)
+ ;
+
+rangeExpr
+ : #(NRangeExpr expr VARARGS expr)
+ ;
+
+gnuAsmExpr
+ : #(NGnuAsmExpr
+ ("volatile")?
+ LPAREN stringConst
+ ( options { warnWhenFollowAmbig = false; }:
+ COLON (strOptExprPair ( COMMA strOptExprPair)* )?
+ ( options { warnWhenFollowAmbig = false; }:
+ COLON (strOptExprPair ( COMMA strOptExprPair)* )?
+ )?
+ )?
+ ( COLON stringConst ( COMMA stringConst)* )?
+ RPAREN
+ )
+ ;
+
+strOptExprPair
+ : stringConst ( LPAREN expr RPAREN )?
+ ;
+
+assignExpr
+ : #( ASSIGN expr expr)
+ | #( DIV_ASSIGN expr expr)
+ | #( PLUS_ASSIGN expr expr)
+ | #( MINUS_ASSIGN expr expr)
+ | #( STAR_ASSIGN expr expr)
+ | #( MOD_ASSIGN expr expr)
+ | #( RSHIFT_ASSIGN expr expr)
+ | #( LSHIFT_ASSIGN expr expr)
+ | #( BAND_ASSIGN expr expr)
+ | #( BOR_ASSIGN expr expr)
+ | #( BXOR_ASSIGN expr expr)
+ ;
+
+
+conditionalExpr
+ : #( QUESTION expr (expr)? COLON expr )
+ ;
+
+
+logicalOrExpr
+ : #( LOR expr expr)
+ ;
+
+
+logicalAndExpr
+ : #( LAND expr expr )
+ ;
+
+
+inclusiveOrExpr
+ : #( BOR expr expr )
+ ;
+
+
+exclusiveOrExpr
+ : #( BXOR expr expr )
+ ;
+
+
+bitAndExpr
+ : #( BAND expr expr )
+ ;
+
+
+
+equalityExpr
+ : #( EQUAL expr expr)
+ | #( NOT_EQUAL expr expr)
+ ;
+
+
+relationalExpr
+ : #( LT expr expr)
+ | #( LTE expr expr)
+ | #( GT expr expr)
+ | #( GTE expr expr)
+ ;
+
+
+
+shiftExpr
+ : #( LSHIFT expr expr)
+ | #( RSHIFT expr expr)
+ ;
+
+
+additiveExpr
+ : #( PLUS expr expr)
+ | #( MINUS expr expr)
+ ;
+
+
+multExpr
+ : #( STAR expr expr)
+ | #( DIV expr expr)
+ | #( MOD expr expr)
+ ;
+
+
+
+castExpr
+ : #( NCast typeName RPAREN expr)
+ ;
+
+
+typeName
+ : specifierQualifierList (nonemptyAbstractDeclarator)?
+ ;
+
+nonemptyAbstractDeclarator
+ : #( NNonemptyAbstractDeclarator
+ ( pointerGroup
+ ( (LPAREN
+ ( nonemptyAbstractDeclarator
+ | parameterTypeList
+ )?
+ RPAREN)
+ | (LBRACKET (expr)? RBRACKET)
+ )*
+
+ | ( (LPAREN
+ ( nonemptyAbstractDeclarator
+ | parameterTypeList
+ )?
+ RPAREN)
+ | (LBRACKET (expr)? RBRACKET)
+ )+
+ )
+ )
+ ;
+
+
+
+unaryExpr
+ : #( INC expr )
+ | #( DEC expr )
+ | #( NUnaryExpr unaryOperator expr)
+ | #( "sizeof"
+ ( ( LPAREN typeName )=> LPAREN typeName RPAREN
+ | expr
+ )
+ )
+ | #( "__alignof"
+ ( ( LPAREN typeName )=> LPAREN typeName RPAREN
+ | expr
+ )
+ )
+ ;
+/*
+exception
+catch [RecognitionException ex]
+ {
+ reportError(ex);
+ System.out.println("PROBLEM TREE:\n"
+ + _t.toStringList());
+ if (_t!=null) {_t = _t.getNextSibling();}
+ }
+*/
+
+ unaryOperator
+ : BAND
+ | STAR
+ | PLUS
+ | MINUS
+ | BNOT
+ | LNOT
+ | LAND
+ | "__real"
+ | "__imag"
+ ;
+
+
+postfixExpr
+ : #( NPostfixExpr
+ primaryExpr
+ ( PTR ID
+ | DOT ID
+ | #( NFunctionCallArgs (argExprList)? RPAREN )
+ | LBRACKET expr RBRACKET
+ | INC
+ | DEC
+ )+
+ )
+ ;
+
+
+
+primaryExpr
+ : ID
+ | Number
+ | charConst
+ | stringConst
+
+// JTC:
+// ID should catch the enumerator
+// leaving it in gives ambiguous err
+// | enumerator
+
+ | #( NExpressionGroup expr )
+ ;
+
+
+
+argExprList
+ : ( expr )+
+ ;
+
+
+
+protected
+charConst
+ : CharLiteral
+ ;
+
+
+protected
+stringConst
+ : #(NStringSeq (StringLiteral)+)
+ ;
+
+
+protected
+intConst
+ : IntOctalConst
+ | LongOctalConst
+ | UnsignedOctalConst
+ | IntIntConst
+ | LongIntConst
+ | UnsignedIntConst
+ | IntHexConst
+ | LongHexConst
+ | UnsignedHexConst
+ ;
+
+
+protected
+floatConst
+ : FloatDoubleConst
+ | DoubleDoubleConst
+ | LongDoubleConst
+ ;
+
+
+
+
+
+
+
+
+
diff --git a/src/net/java/games/gluegen/cgram/HeaderParser.g b/src/net/java/games/gluegen/cgram/HeaderParser.g
new file mode 100644
index 000000000..1263c30b8
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/HeaderParser.g
@@ -0,0 +1,715 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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.
+ */
+
+header {
+ package net.java.games.gluegen.cgram;
+
+ import java.io.*;
+ import java.util.*;
+
+ import antlr.CommonAST;
+ import net.java.games.gluegen.cgram.types.*;
+}
+
+class HeaderParser extends GnuCTreeParser;
+options {
+ k = 1;
+}
+
+{
+ /** Name assigned to a anonymous EnumType (e.g., "enum { ... }"). */
+ public static final String ANONYMOUS_ENUM_NAME = "<anonymous>";
+
+ /** Set the machine description for this HeaderParser. Must be
+ done before parsing. */
+ public void setMachineDescription(MachineDescription machDesc) {
+ this.machDesc = machDesc;
+ }
+
+ /** Returns the MachineDescription this HeaderParser uses. */
+ public MachineDescription machineDescription() {
+ return machDesc;
+ }
+
+ /** Set the dictionary mapping typedef names to types for this
+ HeaderParser. Must be done before parsing. */
+ public void setTypedefDictionary(TypeDictionary dict) {
+ this.typedefDictionary = dict;
+ }
+
+ /** Returns the typedef dictionary this HeaderParser uses. */
+ public TypeDictionary getTypedefDictionary() {
+ return typedefDictionary;
+ }
+
+ /** Set the dictionary mapping struct names (i.e., the "foo" in
+ "struct foo { ... };") to types for this HeaderParser. Must be done
+ before parsing. */
+ public void setStructDictionary(TypeDictionary dict) {
+ this.structDictionary = dict;
+ }
+
+ /** Returns the struct name dictionary this HeaderParser uses. */
+ public TypeDictionary getStructDictionary() {
+ return structDictionary;
+ }
+
+ /** Get the canonicalization map, which is a regular HashMap
+ mapping Type to Type and which is used for looking up the unique
+ instances of e.g. pointer-to-structure types that have been typedefed
+ and therefore have names. */
+ public Map getCanonMap() {
+ return canonMap;
+ }
+
+ /** Pre-define the list of EnumTypes for this HeaderParser. Must be
+ done before parsing. */
+ public void setEnums(List/*<EnumType>*/ enumTypes) {
+ // FIXME: Need to take the input set of EnumTypes, extract all
+ // the enumerates from each EnumType, and fill in the enumHash
+ // so that each enumerate maps to the enumType to which it
+ // belongs.
+ throw new RuntimeException("setEnums is Unimplemented!");
+ }
+
+ /** Returns the EnumTypes this HeaderParser processed. */
+ public List/*<EnumType>*/ getEnums() {
+ return new ArrayList(enumHash.values());
+ }
+
+ /** Clears the list of functions this HeaderParser has parsed.
+ Useful when reusing the same HeaderParser for more than one
+ header file. */
+ public void clearParsedFunctions() {
+ functions.clear();
+ }
+
+ /** Returns the list of FunctionSymbols this HeaderParser has parsed. */
+ public List getParsedFunctions() {
+ return functions;
+ }
+
+ private CompoundType lookupInStructDictionary(String typeName,
+ CompoundTypeKind kind,
+ int cvAttrs) {
+ CompoundType t = (CompoundType) structDictionary.get(typeName);
+ if (t == null) {
+ t = new CompoundType(null, -1, kind, cvAttrs);
+ t.setStructName(typeName);
+ structDictionary.put(typeName, t);
+ }
+ return t;
+ }
+
+ private Type lookupInTypedefDictionary(String typeName) {
+ Type t = typedefDictionary.get(typeName);
+ if (t == null) {
+ throw new RuntimeException("Undefined reference to typedef name " + typeName);
+ }
+ return t;
+ }
+
+ static class ParameterDeclaration {
+ private String id;
+ private Type type;
+
+ ParameterDeclaration(String id, Type type) {
+ this.id = id;
+ this.type = type;
+ }
+ String id() { return id; }
+ Type type() { return type; }
+ }
+
+ // A box for a Type. Allows type to be passed down to be modified by recursive rules.
+ static class TypeBox {
+ private Type origType;
+ private Type type;
+ private boolean isTypedef;
+
+ TypeBox(Type type) {
+ this(type, false);
+ }
+
+ TypeBox(Type type, boolean isTypedef) {
+ this.origType = type;
+ this.isTypedef = isTypedef;
+ }
+
+ Type type() {
+ if (type == null) {
+ return origType;
+ }
+ return type;
+ }
+ void setType(Type type) {
+ this.type = type;
+ }
+ void reset() {
+ type = null;
+ }
+
+ boolean isTypedef() { return isTypedef; }
+
+ // for easier debugging
+ public String toString() {
+ String tStr = "Type=NULL_REF";
+ if (type == origType) {
+ tStr = "Type=ORIG_TYPE";
+ } else if (type != null) {
+ tStr = "Type: name=\"" + type.getCVAttributesString() + " " +
+ type.getName() + "\"; signature=\"" + type + "\"; class " +
+ type.getClass().getName();
+ }
+ String oStr = "OrigType=NULL_REF";
+ if (origType != null) {
+ oStr = "OrigType: name=\"" + origType.getCVAttributesString() + " " +
+ origType.getName() + "\"; signature=\"" + origType + "\"; class " +
+ origType.getClass().getName();
+ }
+ return "<["+tStr + "] [" + oStr + "] " + " isTypedef=" + isTypedef+">";
+ }
+ }
+
+ private MachineDescription machDesc;
+ private boolean doDeclaration; // Used to only process function typedefs
+ private String declId;
+ private List parameters;
+ private TypeDictionary typedefDictionary;
+ private TypeDictionary structDictionary;
+ private List/*<FunctionSymbol>*/ functions = new ArrayList();
+ // hash from name of an enumerated value to the EnumType to which it belongs
+ private HashMap/*<String,EnumType>*/ enumHash = new HashMap();
+
+ // Storage class specifiers
+ private static final int AUTO = 1 << 0;
+ private static final int REGISTER = 1 << 1;
+ private static final int TYPEDEF = 1 << 2;
+ // Function storage class specifiers
+ private static final int EXTERN = 1 << 3;
+ private static final int STATIC = 1 << 4;
+ private static final int INLINE = 1 << 5;
+ // Type qualifiers
+ private static final int CONST = 1 << 6;
+ private static final int VOLATILE = 1 << 7;
+ private static final int SIGNED = 1 << 8;
+ private static final int UNSIGNED = 1 << 9;
+
+ private void initDeclaration() {
+ doDeclaration = false;
+ declId = null;
+ }
+
+ private void doDeclaration() {
+ doDeclaration = true;
+ }
+
+ private void processDeclaration(Type returnType) {
+ if (doDeclaration) {
+ FunctionSymbol sym = new FunctionSymbol(declId, new FunctionType(null, -1, returnType, 0));
+ if (parameters != null) { // handle funcs w/ empty parameter lists (e.g., "foo()")
+ for (Iterator iter = parameters.iterator(); iter.hasNext(); ) {
+ ParameterDeclaration pd = (ParameterDeclaration) iter.next();
+ sym.addArgument(pd.type(), pd.id());
+ }
+ }
+ functions.add(sym);
+ }
+ }
+
+ private int attrs2CVAttrs(int attrs) {
+ int cvAttrs = 0;
+ if ((attrs & CONST) != 0) {
+ cvAttrs |= CVAttributes.CONST;
+ }
+ if ((attrs & VOLATILE) != 0) {
+ cvAttrs |= CVAttributes.VOLATILE;
+ }
+ return cvAttrs;
+ }
+
+ /** Helper routine which handles creating a pointer or array type
+ for [] expressions */
+ private void handleArrayExpr(TypeBox tb, AST t) {
+ if (t != null) {
+ try {
+ // FIXME: this doesn't take into account struct alignment, which may be necessary
+ // See also FIXMEs in ArrayType.java
+ int len = parseIntConstExpr(t);
+ tb.setType(canonicalize(new ArrayType(tb.type(), len * tb.type().getSize(), len, 0)));
+ return;
+ } catch (RecognitionException e) {
+ // Fall through
+ }
+ }
+ tb.setType(canonicalize(new PointerType(machDesc.pointerSizeInBytes(),
+ tb.type(),
+ 0)));
+ }
+
+ private int parseIntConstExpr(AST t) throws RecognitionException {
+ return intConstExpr(t);
+ }
+
+ /** Utility function: creates a new EnumType with the given name, or
+ returns an existing one if it has already been created. */
+ private EnumType getEnumType(String enumTypeName) {
+ EnumType enumType = null;
+ Iterator it = enumHash.values().iterator();
+ while (it.hasNext()) {
+ EnumType potentialMatch = (EnumType)it.next();
+ if (potentialMatch.getName().equals(enumTypeName)) {
+ enumType = potentialMatch;
+ break;
+ }
+ }
+
+ if (enumType == null) {
+ enumType = new EnumType(enumTypeName, machDesc.longSizeInBytes());
+ }
+
+ return enumType;
+ }
+
+ // Map used to canonicalize types. For example, we may typedef
+ // struct foo { ... } *pfoo; subsequent references to struct foo* should
+ // point to the same PointerType object that had its name set to "pfoo".
+ private Map canonMap = new HashMap();
+ private Type canonicalize(Type t) {
+ Type res = (Type) canonMap.get(t);
+ if (res != null) {
+ return res;
+ }
+ canonMap.put(t, t);
+ return t;
+ }
+}
+
+declarator[TypeBox tb] returns [String s] {
+ initDeclaration();
+ s = null;
+ List params = null;
+ String funcPointerName = null;
+ TypeBox dummyTypeBox = null;
+}
+ : #( NDeclarator
+ ( pointerGroup[tb] )?
+
+ ( id:ID { s = id.getText(); }
+ | LPAREN funcPointerName = declarator[dummyTypeBox] RPAREN
+ )
+
+ ( #( NParameterTypeList
+ (
+ params = parameterTypeList
+ | (idList)?
+ )
+ RPAREN
+ ) {
+ if (id != null) {
+ declId = id.getText();
+ parameters = params; // FIXME: Ken, why are we setting this class member here?
+ doDeclaration();
+ } else if ( funcPointerName != null ) {
+ /* TypeBox becomes function pointer in this case */
+ FunctionType ft = new FunctionType(null, -1, tb.type(), 0);
+ if (params == null) {
+ // If the function pointer has no declared parameters, it's a
+ // void function. I'm not sure if the parameter name is
+ // ever referenced anywhere when the type is VoidType, so
+ // just in case I'll set it to a comment string so it will
+ // still compile if written out to code anywhere.
+ ft.addArgument(new VoidType(0), "/*unnamed-void*/");
+ } else {
+ for (Iterator iter = params.iterator(); iter.hasNext(); ) {
+ ParameterDeclaration pd = (ParameterDeclaration) iter.next();
+ ft.addArgument(pd.type(), pd.id());
+ }
+ }
+ tb.setType(canonicalize(new PointerType(machDesc.pointerSizeInBytes(),
+ ft,
+ 0)));
+ s = funcPointerName;
+ }
+ }
+ | LBRACKET ( e:expr )? RBRACKET { handleArrayExpr(tb, e); }
+ )*
+ )
+ ;
+
+typelessDeclaration {
+ TypeBox tb = null;
+}
+ : #(NTypeMissing initDeclList[tb] SEMI)
+ ;
+
+declaration {
+ TypeBox tb = null;
+}
+ : #( NDeclaration
+ tb = declSpecifiers
+ (
+ initDeclList[tb]
+ )?
+ ( SEMI )+
+ ) { processDeclaration(tb.type()); }
+ ;
+
+parameterTypeList returns [List l] { l = new ArrayList(); ParameterDeclaration decl = null; }
+ : ( decl = parameterDeclaration { if (decl != null) l.add(decl); } ( COMMA | SEMI )? )+ ( VARARGS )?
+ ;
+
+parameterDeclaration returns [ParameterDeclaration pd] {
+ Type t = null;
+ String decl = null;
+ pd = null;
+ TypeBox tb = null;
+}
+ : #( NParameterDeclaration
+ tb = declSpecifiers
+ (decl = declarator[tb] | nonemptyAbstractDeclarator[tb])?
+ ) { pd = new ParameterDeclaration(decl, tb.type()); }
+ ;
+
+functionDef {
+ TypeBox tb = null;
+}
+ : #( NFunctionDef
+ ( functionDeclSpecifiers)?
+ declarator[tb]
+ (declaration | VARARGS)*
+ compoundStatement
+ )
+ ;
+
+declSpecifiers returns [TypeBox tb] {
+ tb = null;
+ Type t = null;
+ int x = 0;
+ int y = 0;
+}
+ : ( y = storageClassSpecifier { x |= y; }
+ | y = typeQualifier { x |= y; }
+ | t = typeSpecifier[x]
+ )+
+{
+ if (t == null &&
+ (x & (SIGNED | UNSIGNED)) != 0) {
+ t = new IntType("int", machDesc.intSizeInBytes(), ((x & UNSIGNED) != 0), attrs2CVAttrs(x));
+ }
+ tb = new TypeBox(t, ((x & TYPEDEF) != 0));
+}
+ ;
+
+storageClassSpecifier returns [int x] { x = 0; }
+ : "auto" { x |= AUTO; }
+ | "register" { x |= REGISTER; }
+ | "typedef" { x |= TYPEDEF; }
+ | x = functionStorageClassSpecifier
+ ;
+
+
+functionStorageClassSpecifier returns [int x] { x = 0; }
+ : "extern" { x |= EXTERN; }
+ | "static" { x |= STATIC; }
+ | "inline" { x |= INLINE; }
+ ;
+
+
+typeQualifier returns [int x] { x = 0; }
+ : "const" { x |= CONST; }
+ | "volatile" { x |= VOLATILE; }
+ | "signed" { x |= SIGNED; }
+ | "unsigned" { x |= UNSIGNED; }
+ ;
+
+typeSpecifier[int attributes] returns [Type t] {
+ t = null;
+ int cvAttrs = attrs2CVAttrs(attributes);
+ boolean unsigned = ((attributes & UNSIGNED) != 0);
+}
+ : "void" { t = new VoidType(cvAttrs); }
+ | "char" { t = new IntType("char" , machDesc.charSizeInBytes(), unsigned, cvAttrs); }
+ | "short" { t = new IntType("short", machDesc.shortSizeInBytes(), unsigned, cvAttrs); }
+ | "int" { t = new IntType("int" , machDesc.intSizeInBytes(), unsigned, cvAttrs); }
+ | "long" { t = new IntType("long" , machDesc.longSizeInBytes(), unsigned, cvAttrs); }
+ | "__int64" { t = new IntType("__int64", machDesc.int64SizeInBytes(), unsigned, cvAttrs); }
+ | "float" { t = new FloatType("float", machDesc.floatSizeInBytes(), cvAttrs); }
+ | "double" { t = new DoubleType("double", machDesc.doubleSizeInBytes(), cvAttrs); }
+ | t = structSpecifier[cvAttrs] ( attributeDecl )*
+ | t = unionSpecifier [cvAttrs] ( attributeDecl )*
+ | t = enumSpecifier [cvAttrs]
+ | t = typedefName [cvAttrs]
+ | #("typeof" LPAREN
+ ( (typeName )=> typeName
+ | expr
+ )
+ RPAREN
+ )
+ | "__complex"
+ ;
+
+typedefName[int cvAttrs] returns [Type t] { t = null; }
+ : #(NTypedefName id : ID)
+ {
+ t = canonicalize(lookupInTypedefDictionary(id.getText()).getCVVariant(cvAttrs));
+ }
+ ;
+
+structSpecifier[int cvAttrs] returns [Type t] { t = null; }
+ : #( "struct" t = structOrUnionBody[CompoundTypeKind.STRUCT, cvAttrs] )
+ ;
+
+unionSpecifier[int cvAttrs] returns [Type t] { t = null; }
+ : #( "union" t = structOrUnionBody[CompoundTypeKind.UNION, cvAttrs] )
+ ;
+
+structOrUnionBody[CompoundTypeKind kind, int cvAttrs] returns [CompoundType t] {
+ t = null;
+}
+ : ( (ID LCURLY) => id:ID LCURLY {
+ t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs));
+ } ( structDeclarationList[t] )?
+ RCURLY { t.setBodyParsed(); }
+ | LCURLY { t = new CompoundType(null, -1, kind, cvAttrs); }
+ ( structDeclarationList[t] )?
+ RCURLY { t.setBodyParsed(); }
+ | id2:ID { t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs)); }
+ )
+ ;
+
+structDeclarationList[CompoundType t]
+ : ( structDeclaration[t] )+
+ ;
+
+structDeclaration[CompoundType containingType] {
+ Type t = null;
+ boolean addedAny = false;
+}
+ : t = specifierQualifierList addedAny = structDeclaratorList[containingType, t] {
+ if (!addedAny) {
+ if (t != null) {
+ CompoundType ct = t.asCompound();
+ if (ct.isUnion()) {
+ // Anonymous union
+ containingType.addField(new Field(null, t, -1));
+ }
+ }
+ }
+ }
+ ;
+
+specifierQualifierList returns [Type t] {
+ t = null; int x = 0; int y = 0;
+}
+ : (
+ t = typeSpecifier[x]
+ | y = typeQualifier { x |= y; }
+ )+ {
+ if (t == null &&
+ (x & (SIGNED | UNSIGNED)) != 0) {
+ t = new IntType("int", machDesc.intSizeInBytes(), ((x & UNSIGNED) != 0), attrs2CVAttrs(x));
+ }
+}
+ ;
+
+structDeclaratorList[CompoundType containingType, Type t] returns [boolean addedAny] {
+ addedAny = false;
+ boolean y = false;
+}
+ : ( y = structDeclarator[containingType, t] { addedAny = y; })+
+ ;
+
+structDeclarator[CompoundType containingType, Type t] returns [boolean addedAny] {
+ addedAny = false;
+ String s = null;
+ TypeBox tb = new TypeBox(t);
+}
+ :
+ #( NStructDeclarator
+ ( s = declarator[tb] { containingType.addField(new Field(s, tb.type(), -1)); addedAny = true; } )?
+ ( COLON expr { /* FIXME: bit types not handled yet */ } ) ?
+ ( attributeDecl )*
+ )
+ ;
+
+// FIXME: this will not correctly set the name of the enumeration when
+// encountering a declaration like this:
+//
+// typedef enum { } enumName;
+//
+// In this case calling getName() on the EnumType return value will
+// incorrectly return HeaderParser.ANONYMOUS_ENUM_NAME instead of
+// "enumName"
+//
+// I haven't implemented it yet because I'm not sure how to get the
+// "enumName" *before* executing the enumList rule.
+enumSpecifier [int cvAttrs] returns [Type t] {
+ t = null;
+}
+ : #( "enum"
+ ( ( ID LCURLY )=> i:ID LCURLY enumList[(EnumType)(t = getEnumType(i.getText()))] RCURLY
+ | LCURLY enumList[(EnumType)(t = getEnumType(ANONYMOUS_ENUM_NAME))] RCURLY
+ | ID { t = getEnumType(i.getText()); }
+ )
+ )
+ ;
+
+enumList[EnumType enumeration] {
+ long defaultEnumerantValue = 0;
+}
+ : ( defaultEnumerantValue = enumerator[enumeration, defaultEnumerantValue] )+
+ ;
+
+enumerator[EnumType enumeration, long defaultValue] returns [long newDefaultValue] {
+ newDefaultValue = defaultValue;
+}
+ : eName:ID ( ASSIGN eVal:expr )? {
+ // FIXME! Integer.parseInt() will throw if its argument is in octal or hex format.
+ long value = (eVal == null) ? defaultValue : Long.parseLong(eVal.getText());
+ newDefaultValue = value+1;
+ String eTxt = eName.getText();
+ if (enumHash.containsKey(eTxt)) {
+ EnumType oldEnumType = ((EnumType)enumHash.get(eTxt));
+ long oldValue = oldEnumType.getEnumValue(eTxt);
+ System.err.println("WARNING: redefinition of enumerated value '" + eTxt + "';" +
+ " existing definition is in enumeration '" + oldEnumType.getName() +
+ "' with value " + oldValue + " and new definition is in enumeration '" +
+ enumeration.getName() + "' with value " + value);
+ // remove old definition
+ oldEnumType.removeEnumerate(eTxt);
+ }
+ // insert new definition
+ enumeration.addEnum(eTxt, value);
+ enumHash.put(eTxt, enumeration);
+ //System.err.println("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + enumeration.getEnumValue(eTxt) +
+ // " (new default = " + newDefaultValue + ")");
+ }
+ ;
+
+initDeclList[TypeBox tb]
+ : ( initDecl[tb] )+
+ ;
+
+initDecl[TypeBox tb] {
+ String declName = null;
+}
+ : #( NInitDecl
+ declName = declarator[tb] {
+ //System.err.println("GOT declName: " + declName + " TB=" + tb);
+ }
+ ( attributeDecl )*
+ ( ASSIGN initializer
+ | COLON expr
+ )?
+ )
+{
+ if ((declName != null) && (tb != null) && tb.isTypedef()) {
+ Type t = tb.type();
+ //System.err.println("Adding typedef mapping: [" + declName + "] -> [" + t + "]");
+ if (!t.hasTypedefName()) {
+ t.setName(declName);
+ }
+ t = canonicalize(t);
+ typedefDictionary.put(declName, t);
+ // Clear out PointerGroup effects in case another typedef variant follows
+ tb.reset();
+ }
+}
+ ;
+
+pointerGroup[TypeBox tb] { int x = 0; int y = 0; }
+ : #( NPointerGroup ( STAR { x = 0; y = 0; } ( y = typeQualifier { x |= y; } )*
+ {
+ //System.err.println("IN PTR GROUP: TB=" + tb);
+ if (tb != null) {
+ tb.setType(canonicalize(new PointerType(machDesc.pointerSizeInBytes(),
+ tb.type(),
+ attrs2CVAttrs(x))));
+ }
+ }
+ )+ )
+ ;
+
+
+functionDeclSpecifiers
+ :
+ ( functionStorageClassSpecifier
+ | typeQualifier
+ | typeSpecifier[0]
+ )+
+ ;
+
+typeName {
+ TypeBox tb = null;
+}
+ : specifierQualifierList (nonemptyAbstractDeclarator[tb])?
+ ;
+
+
+/* FIXME: the handling of types in this rule has not been well thought
+ out and is known to be incomplete. Currently it is only used to handle
+ pointerGroups for unnamed parameters. */
+nonemptyAbstractDeclarator[TypeBox tb]
+ : #( NNonemptyAbstractDeclarator
+ ( pointerGroup[tb]
+ ( (LPAREN
+ ( nonemptyAbstractDeclarator[tb]
+ | parameterTypeList
+ )?
+ RPAREN)
+ | (LBRACKET (e1:expr)? RBRACKET) { handleArrayExpr(tb, e1); }
+ )*
+
+ | ( (LPAREN
+ ( nonemptyAbstractDeclarator[tb]
+ | parameterTypeList
+ )?
+ RPAREN)
+ | (LBRACKET (e2:expr)? RBRACKET) { handleArrayExpr(tb, e2); }
+ )+
+ )
+ )
+ ;
+
+/* Helper routine for parsing expressions which evaluate to integer
+ constants. Can be made more complicated as necessary. */
+intConstExpr returns [int i] { i = -1; }
+ : n:Number { return Integer.parseInt(n.getText()); }
+ ;
diff --git a/src/net/java/games/gluegen/cgram/LineObject.java b/src/net/java/games/gluegen/cgram/LineObject.java
new file mode 100644
index 000000000..578e14194
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/LineObject.java
@@ -0,0 +1,126 @@
+package net.java.games.gluegen.cgram;
+
+class LineObject {
+ LineObject parent = null;
+ String source = "";
+ int line = 1;
+ boolean enteringFile = false;
+ boolean returningToFile = false;
+ boolean systemHeader = false;
+ boolean treatAsC = false;
+
+ public LineObject()
+ {
+ super();
+ }
+
+ public LineObject( LineObject lobj )
+ {
+ parent = lobj.getParent();
+ source = lobj.getSource();
+ line = lobj.getLine();
+ enteringFile = lobj.getEnteringFile();
+ returningToFile = lobj.getReturningToFile();
+ systemHeader = lobj.getSystemHeader();
+ treatAsC = lobj.getTreatAsC();
+ }
+
+ public LineObject( String src)
+ {
+ source = src;
+ }
+
+ public void setSource(String src)
+ {
+ source = src;
+ }
+
+ public String getSource()
+ {
+ return source;
+ }
+
+ public void setParent(LineObject par)
+ {
+ parent = par;
+ }
+
+ public LineObject getParent()
+ {
+ return parent;
+ }
+
+ public void setLine(int l)
+ {
+ line = l;
+ }
+
+ public int getLine()
+ {
+ return line;
+ }
+
+ public void newline()
+ {
+ line++;
+ }
+
+ public void setEnteringFile(boolean v)
+ {
+ enteringFile = v;
+ }
+
+ public boolean getEnteringFile()
+ {
+ return enteringFile;
+ }
+
+ public void setReturningToFile(boolean v)
+ {
+ returningToFile = v;
+ }
+
+ public boolean getReturningToFile()
+ {
+ return returningToFile;
+ }
+
+ public void setSystemHeader(boolean v)
+ {
+ systemHeader = v;
+ }
+
+ public boolean getSystemHeader()
+ {
+ return systemHeader;
+ }
+
+ public void setTreatAsC(boolean v)
+ {
+ treatAsC = v;
+ }
+
+ public boolean getTreatAsC()
+ {
+ return treatAsC;
+ }
+
+ public String toString() {
+ StringBuffer ret;
+ ret = new StringBuffer("# " + line + " \"" + source + "\"");
+ if (enteringFile) {
+ ret.append(" 1");
+ }
+ if (returningToFile) {
+ ret.append(" 2");
+ }
+ if (systemHeader) {
+ ret.append(" 3");
+ }
+ if (treatAsC) {
+ ret.append(" 4");
+ }
+ return ret.toString();
+ }
+}
+
diff --git a/src/net/java/games/gluegen/cgram/PreprocessorInfoChannel.java b/src/net/java/games/gluegen/cgram/PreprocessorInfoChannel.java
new file mode 100644
index 000000000..f2de592c7
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/PreprocessorInfoChannel.java
@@ -0,0 +1,73 @@
+package net.java.games.gluegen.cgram;
+
+import java.util.*;
+
+public class PreprocessorInfoChannel
+{
+ Hashtable lineLists = new Hashtable(); // indexed by Token number
+ int firstValidTokenNumber = 0;
+ int maxTokenNumber = 0;
+
+ public void addLineForTokenNumber( Object line, Integer toknum )
+ {
+ if ( lineLists.containsKey( toknum ) ) {
+ Vector lines = (Vector) lineLists.get( toknum );
+ lines.addElement(line);
+ }
+ else {
+ Vector lines = new Vector();
+ lines.addElement(line);
+ lineLists.put(toknum, lines);
+ if ( maxTokenNumber < toknum.intValue() ) {
+ maxTokenNumber = toknum.intValue();
+ }
+ }
+ }
+
+ public int getMaxTokenNumber()
+ {
+ return maxTokenNumber;
+ }
+
+ public Vector extractLinesPrecedingTokenNumber( Integer toknum )
+ {
+ Vector lines = new Vector();
+ if (toknum == null) return lines;
+ for (int i = firstValidTokenNumber; i < toknum.intValue(); i++){
+ Integer inti = new Integer(i);
+ if ( lineLists.containsKey( inti ) ) {
+ Vector tokenLineVector = (Vector) lineLists.get( inti );
+ if ( tokenLineVector != null) {
+ Enumeration tokenLines = tokenLineVector.elements();
+ while ( tokenLines.hasMoreElements() ) {
+ lines.addElement( tokenLines.nextElement() );
+ }
+ lineLists.remove(inti);
+ }
+ }
+ }
+ firstValidTokenNumber = toknum.intValue();
+ return lines;
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer("PreprocessorInfoChannel:\n");
+ for (int i = 0; i <= maxTokenNumber + 1; i++){
+ Integer inti = new Integer(i);
+ if ( lineLists.containsKey( inti ) ) {
+ Vector tokenLineVector = (Vector) lineLists.get( inti );
+ if ( tokenLineVector != null) {
+ Enumeration tokenLines = tokenLineVector.elements();
+ while ( tokenLines.hasMoreElements() ) {
+ sb.append(inti + ":" + tokenLines.nextElement() + '\n');
+ }
+ }
+ }
+ }
+ return sb.toString();
+ }
+}
+
+
+
diff --git a/src/net/java/games/gluegen/cgram/StdCParser.g b/src/net/java/games/gluegen/cgram/StdCParser.g
new file mode 100644
index 000000000..65f7468bf
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/StdCParser.g
@@ -0,0 +1,1375 @@
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Copyright (c) Non, Inc. 1997 -- All Rights Reserved
+
+PROJECT: C Compiler
+MODULE: Parser
+FILE: stdc.g
+
+AUTHOR: John D. Mitchell ([email protected]), Jul 12, 1997
+
+REVISION HISTORY:
+
+ Name Date Description
+ ---- ---- -----------
+ JDM 97.07.12 Initial version.
+ JTC 97.11.18 Declaration vs declarator & misc. hacking.
+ JDM 97.11.20 Fixed: declaration vs funcDef,
+ parenthesized expressions,
+ declarator iteration,
+ varargs recognition,
+ empty source file recognition,
+ and some typos.
+
+
+DESCRIPTION:
+
+ This grammar supports the Standard C language.
+
+ Note clearly that this grammar does *NOT* deal with
+ preprocessor functionality (including things like trigraphs)
+ Nor does this grammar deal with multi-byte characters nor strings
+ containing multi-byte characters [these constructs are "exercises
+ for the reader" as it were :-)].
+
+ Please refer to the ISO/ANSI C Language Standard if you believe
+ this grammar to be in error. Please cite chapter and verse in any
+ correspondence to the author to back up your claim.
+
+TODO:
+
+ - typedefName is commented out, needs a symbol table to resolve
+ ambiguity.
+
+ - trees
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+header {
+ package net.java.games.gluegen.cgram;
+
+ import java.io.*;
+
+ import antlr.CommonAST;
+ import antlr.DumpASTVisitor;
+}
+
+
+class StdCParser extends Parser;
+
+options
+ {
+ k = 2;
+ exportVocab = STDC;
+ buildAST = true;
+ ASTLabelType = "TNode";
+
+ // Copied following options from java grammar.
+ codeGenMakeSwitchThreshold = 2;
+ codeGenBitsetTestThreshold = 3;
+ }
+
+
+{
+ // Suppport C++-style single-line comments?
+ public static boolean CPPComments = true;
+
+ // access to symbol table
+ public CSymbolTable symbolTable = new CSymbolTable();
+
+ // source for names to unnamed scopes
+ protected int unnamedScopeCounter = 0;
+
+ public boolean isTypedefName(String name) {
+ boolean returnValue = false;
+ TNode node = symbolTable.lookupNameInCurrentScope(name);
+ for (; node != null; node = (TNode) node.getNextSibling() ) {
+ if(node.getType() == LITERAL_typedef) {
+ returnValue = true;
+ break;
+ }
+ }
+ return returnValue;
+ }
+
+
+ public String getAScopeName() {
+ return "" + (unnamedScopeCounter++);
+ }
+
+ public void pushScope(String scopeName) {
+ symbolTable.pushScope(scopeName);
+ }
+
+ public void popScope() {
+ symbolTable.popScope();
+ }
+
+ int traceDepth = 0;
+ public void reportError(RecognitionException ex) {
+ try {
+ System.err.println("ANTLR Parsing Error: "+ex + " token name:" + tokenNames[LA(1)]);
+ ex.printStackTrace(System.err);
+ }
+ catch (TokenStreamException e) {
+ System.err.println("ANTLR Parsing Error: "+ex);
+ ex.printStackTrace(System.err);
+ }
+ }
+ public void reportError(String s) {
+ System.err.println("ANTLR Parsing Error from String: " + s);
+ }
+ public void reportWarning(String s) {
+ System.err.println("ANTLR Parsing Warning from String: " + s);
+ }
+ public void match(int t) throws MismatchedTokenException {
+ boolean debugging = false;
+
+ if ( debugging ) {
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ try {
+ System.out.println("Match("+tokenNames[t]+") with LA(1)="+
+ tokenNames[LA(1)] + ((inputState.guessing>0)?" [inputState.guessing "+ inputState.guessing + "]":""));
+ }
+ catch (TokenStreamException e) {
+ System.out.println("Match("+tokenNames[t]+") " + ((inputState.guessing>0)?" [inputState.guessing "+ inputState.guessing + "]":""));
+
+ }
+
+ }
+ try {
+ if ( LA(1)!=t ) {
+ if ( debugging ){
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ System.out.println("token mismatch: "+tokenNames[LA(1)]
+ + "!="+tokenNames[t]);
+ }
+ throw new MismatchedTokenException(tokenNames, LT(1), t, false, getFilename());
+
+ } else {
+ // mark token as consumed -- fetch next token deferred until LA/LT
+ consume();
+ }
+ }
+ catch (TokenStreamException e) {
+ }
+
+ }
+ public void traceIn(String rname) {
+ traceDepth += 1;
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ try {
+ System.out.println("> "+rname+"; LA(1)==("+ tokenNames[LT(1).getType()]
+ + ") " + LT(1).getText() + " [inputState.guessing "+ inputState.guessing + "]");
+ }
+ catch (TokenStreamException e) {
+ }
+ }
+ public void traceOut(String rname) {
+ for (int x=0; x<traceDepth; x++) System.out.print(" ");
+ try {
+ System.out.println("< "+rname+"; LA(1)==("+ tokenNames[LT(1).getType()]
+ + ") "+LT(1).getText() + " [inputState.guessing "+ inputState.guessing + "]");
+ }
+ catch (TokenStreamException e) {
+ }
+ traceDepth -= 1;
+ }
+
+}
+
+
+
+translationUnit
+ : externalList
+
+ | /* Empty source files are *not* allowed. */
+ {
+ System.err.println ( "Empty source file!" );
+ }
+ ;
+
+
+externalList
+ : ( externalDef )+
+ ;
+
+
+externalDef
+ : ( "typedef" | declaration )=> declaration
+ | functionDef
+ | asm_expr
+ ;
+
+
+asm_expr
+ : "asm"^
+ ("volatile")? LCURLY! expr RCURLY! SEMI!
+ ;
+
+
+declaration
+ { AST ds1 = null; }
+ : ds:declSpecifiers { ds1 = astFactory.dupList(#ds); }
+ (
+ initDeclList[ds1]
+ )?
+ SEMI!
+ { ## = #( #[NDeclaration], ##); }
+
+ ;
+
+
+declSpecifiers
+ { int specCount=0; }
+ : ( options { // this loop properly aborts when
+ // it finds a non-typedefName ID MBZ
+ warnWhenFollowAmbig = false;
+ } :
+ s:storageClassSpecifier
+ | typeQualifier
+ | ( "struct" | "union" | "enum" | typeSpecifier[specCount] )=>
+ specCount = typeSpecifier[specCount]
+ )+
+ ;
+
+storageClassSpecifier
+ : "auto"
+ | "register"
+ | "typedef"
+ | functionStorageClassSpecifier
+ ;
+
+
+functionStorageClassSpecifier
+ : "extern"
+ | "static"
+ ;
+
+
+typeQualifier
+ : "const"
+ | "volatile"
+ ;
+
+typeSpecifier [int specCount] returns [int retSpecCount]
+ { retSpecCount = specCount + 1; }
+ :
+ ( "void"
+ | "char"
+ | "short"
+ | "int"
+ | "long"
+ | "float"
+ | "double"
+ | "signed"
+ | "unsigned"
+ | structOrUnionSpecifier
+ | enumSpecifier
+ | { specCount == 0 }? typedefName
+ )
+ ;
+
+
+typedefName
+ : { isTypedefName ( LT(1).getText() ) }?
+ i:ID { ## = #(#[NTypedefName], #i); }
+ ;
+
+structOrUnionSpecifier
+ { String scopeName; }
+ : sou:structOrUnion!
+ ( ( ID LCURLY )=> i:ID l:LCURLY
+ {
+ scopeName = #sou.getText() + " " + #i.getText();
+ #l.setText(scopeName);
+ pushScope(scopeName);
+ }
+ structDeclarationList
+ { popScope();}
+ RCURLY!
+ | l1:LCURLY
+ {
+ scopeName = getAScopeName();
+ #l1.setText(scopeName);
+ pushScope(scopeName);
+ }
+ structDeclarationList
+ { popScope(); }
+ RCURLY!
+ | ID
+ )
+ {
+ ## = #( #sou, ## );
+ }
+ ;
+
+
+structOrUnion
+ : "struct"
+ | "union"
+ ;
+
+
+structDeclarationList
+ : ( structDeclaration )+
+ ;
+
+
+structDeclaration
+ : specifierQualifierList structDeclaratorList ( SEMI! )+
+ ;
+
+
+specifierQualifierList
+ { int specCount = 0; }
+ : ( options { // this loop properly aborts when
+ // it finds a non-typedefName ID MBZ
+ warnWhenFollowAmbig = false;
+ } :
+ ( "struct" | "union" | "enum" | typeSpecifier[specCount] )=>
+ specCount = typeSpecifier[specCount]
+ | typeQualifier
+ )+
+ ;
+
+
+structDeclaratorList
+ : structDeclarator ( COMMA! structDeclarator )*
+ ;
+
+
+structDeclarator
+ :
+ ( COLON constExpr
+ | declarator[false] ( COLON constExpr )?
+ )
+ { ## = #( #[NStructDeclarator], ##); }
+ ;
+
+
+enumSpecifier
+ : "enum"^
+ ( ( ID LCURLY )=> i:ID LCURLY enumList[i.getText()] RCURLY!
+ | LCURLY enumList["anonymous"] RCURLY!
+ | ID
+ )
+ ;
+
+
+enumList[String enumName]
+ : enumerator[enumName] ( COMMA! enumerator[enumName] )*
+ ;
+
+enumerator[String enumName]
+ : i:ID { symbolTable.add( i.getText(),
+ #( null,
+ #[LITERAL_enum, "enum"],
+ #[ ID, enumName]
+ )
+ );
+ }
+ (ASSIGN constExpr)?
+ ;
+
+
+initDeclList[AST declarationSpecifiers]
+ : initDecl[declarationSpecifiers]
+ ( COMMA! initDecl[declarationSpecifiers] )*
+ ;
+
+
+initDecl[AST declarationSpecifiers]
+ { String declName = ""; }
+ : declName = d:declarator[false]
+ { AST ds1, d1;
+ ds1 = astFactory.dupList(declarationSpecifiers);
+ d1 = astFactory.dupList(#d);
+ symbolTable.add(declName, #(null, ds1, d1) );
+ }
+ ( ASSIGN initializer
+ | COLON expr
+ )?
+ { ## = #( #[NInitDecl], ## ); }
+
+ ;
+
+pointerGroup
+ : ( STAR ( typeQualifier )* )+ { ## = #( #[NPointerGroup], ##); }
+ ;
+
+
+
+idList
+ : ID ( COMMA! ID )*
+ ;
+
+
+initializer
+ : ( assignExpr
+ | LCURLY initializerList ( COMMA! )? RCURLY!
+ )
+ { ## = #( #[NInitializer], ## ); }
+ ;
+
+
+initializerList
+ : initializer ( COMMA! initializer )*
+ ;
+
+
+declarator[boolean isFunctionDefinition] returns [String declName]
+ { declName = ""; }
+ :
+ ( pointerGroup )?
+
+ ( id:ID { declName = id.getText(); }
+ | LPAREN declName = declarator[false] RPAREN
+ )
+
+ ( ! LPAREN
+ {
+ if (isFunctionDefinition) {
+ pushScope(declName);
+ }
+ else {
+ pushScope("!"+declName);
+ }
+ }
+ (
+ (declSpecifiers)=> p:parameterTypeList
+ {
+ ## = #( null, ##, #( #[NParameterTypeList], #p ) );
+ }
+
+ | (i:idList)?
+ {
+ ## = #( null, ##, #( #[NParameterTypeList], #i ) );
+ }
+ )
+ {
+ popScope();
+ }
+ RPAREN
+ | LBRACKET ( constExpr )? RBRACKET
+ )*
+ { ## = #( #[NDeclarator], ## ); }
+ ;
+
+parameterTypeList
+ : parameterDeclaration
+ ( options {
+ warnWhenFollowAmbig = false;
+ } :
+ COMMA!
+ parameterDeclaration
+ )*
+ ( COMMA!
+ VARARGS
+ )?
+ ;
+
+
+parameterDeclaration
+ { String declName; }
+ : ds:declSpecifiers
+ ( ( declarator[false] )=> declName = d:declarator[false]
+ {
+ AST d2, ds2;
+ d2 = astFactory.dupList(#d);
+ ds2 = astFactory.dupList(#ds);
+ symbolTable.add(declName, #(null, ds2, d2));
+ }
+ | nonemptyAbstractDeclarator
+ )?
+ {
+ ## = #( #[NParameterDeclaration], ## );
+ }
+ ;
+
+/* JTC:
+ * This handles both new and old style functions.
+ * see declarator rule to see differences in parameters
+ * and here (declaration SEMI)* is the param type decls for the
+ * old style. may want to do some checking to check for illegal
+ * combinations (but I assume all parsed code will be legal?)
+ */
+
+functionDef
+ { String declName; }
+ : ( (functionDeclSpecifiers)=> ds:functionDeclSpecifiers
+ | //epsilon
+ )
+ declName = d:declarator[true]
+ {
+ AST d2, ds2;
+ d2 = astFactory.dupList(#d);
+ ds2 = astFactory.dupList(#ds);
+ symbolTable.add(declName, #(null, ds2, d2));
+ pushScope(declName);
+ }
+ ( declaration )* (VARARGS)? ( SEMI! )*
+ { popScope(); }
+ compoundStatement[declName]
+ { ## = #( #[NFunctionDef], ## );}
+ ;
+
+functionDeclSpecifiers
+ { int specCount = 0; }
+ : ( options { // this loop properly aborts when
+ // it finds a non-typedefName ID MBZ
+ warnWhenFollowAmbig = false;
+ } :
+ functionStorageClassSpecifier
+ | typeQualifier
+ | ( "struct" | "union" | "enum" | typeSpecifier[specCount] )=>
+ specCount = typeSpecifier[specCount]
+ )+
+ ;
+
+declarationList
+ : ( options { // this loop properly aborts when
+ // it finds a non-typedefName ID MBZ
+ warnWhenFollowAmbig = false;
+ } :
+ ( declarationPredictor )=> declaration
+ )+
+ ;
+
+declarationPredictor
+ : (options { //only want to look at declaration if I don't see typedef
+ warnWhenFollowAmbig = false;
+ }:
+ "typedef"
+ | declaration
+ )
+ ;
+
+
+compoundStatement[String scopeName]
+ : LCURLY!
+ {
+ pushScope(scopeName);
+ }
+ ( ( declarationPredictor)=> declarationList )?
+ ( statementList )?
+ { popScope(); }
+ RCURLY!
+ { ## = #( #[NCompoundStatement, scopeName], ##); }
+ ;
+
+
+statementList
+ : ( statement )+
+ ;
+statement
+ : SEMI // Empty statements
+
+ | compoundStatement[getAScopeName()] // Group of statements
+
+ | expr SEMI! { ## = #( #[NStatementExpr], ## ); } // Expressions
+
+// Iteration statements:
+
+ | "while"^ LPAREN! expr RPAREN! statement
+ | "do"^ statement "while"! LPAREN! expr RPAREN! SEMI!
+ |! "for"
+ LPAREN ( e1:expr )? SEMI ( e2:expr )? SEMI ( e3:expr )? RPAREN
+ s:statement
+ {
+ if ( #e1 == null) { #e1 = (TNode) #[ NEmptyExpression ]; }
+ if ( #e2 == null) { #e2 = (TNode) #[ NEmptyExpression ]; }
+ if ( #e3 == null) { #e3 = (TNode) #[ NEmptyExpression ]; }
+ ## = #( #[LITERAL_for, "for"], #e1, #e2, #e3, #s );
+ }
+
+
+// Jump statements:
+
+ | "goto"^ ID SEMI!
+ | "continue" SEMI!
+ | "break" SEMI!
+ | "return"^ ( expr )? SEMI!
+
+
+// Labeled statements:
+ | ID COLON! (options {warnWhenFollowAmbig=false;}:statement)? { ## = #( #[NLabel], ## ); }
+ | "case"^ constExpr COLON! statement
+ | "default"^ COLON! statement
+
+
+
+// Selection statements:
+
+ | "if"^
+ LPAREN! expr RPAREN! statement
+ ( //standard if-else ambiguity
+ options {
+ warnWhenFollowAmbig = false;
+ } :
+ "else" statement )?
+ | "switch"^ LPAREN! expr RPAREN! statement
+ ;
+
+
+
+
+
+
+expr
+ : assignExpr (options {
+ /* MBZ:
+ COMMA is ambiguous between comma expressions and
+ argument lists. argExprList should get priority,
+ and it does by being deeper in the expr rule tree
+ and using (COMMA assignExpr)*
+ */
+ warnWhenFollowAmbig = false;
+ } :
+ c:COMMA^ { #c.setType(NCommaExpr); } assignExpr
+ )*
+ ;
+
+
+assignExpr
+ : conditionalExpr ( a:assignOperator! assignExpr { ## = #( #a, ## );} )?
+ ;
+
+assignOperator
+ : ASSIGN
+ | DIV_ASSIGN
+ | PLUS_ASSIGN
+ | MINUS_ASSIGN
+ | STAR_ASSIGN
+ | MOD_ASSIGN
+ | RSHIFT_ASSIGN
+ | LSHIFT_ASSIGN
+ | BAND_ASSIGN
+ | BOR_ASSIGN
+ | BXOR_ASSIGN
+ ;
+
+
+conditionalExpr
+ : logicalOrExpr
+ ( QUESTION^ expr COLON! conditionalExpr )?
+ ;
+
+
+constExpr
+ : conditionalExpr
+ ;
+
+logicalOrExpr
+ : logicalAndExpr ( LOR^ logicalAndExpr )*
+ ;
+
+
+logicalAndExpr
+ : inclusiveOrExpr ( LAND^ inclusiveOrExpr )*
+ ;
+
+inclusiveOrExpr
+ : exclusiveOrExpr ( BOR^ exclusiveOrExpr )*
+ ;
+
+
+exclusiveOrExpr
+ : bitAndExpr ( BXOR^ bitAndExpr )*
+ ;
+
+
+bitAndExpr
+ : equalityExpr ( BAND^ equalityExpr )*
+ ;
+
+
+
+equalityExpr
+ : relationalExpr
+ ( ( EQUAL^ | NOT_EQUAL^ ) relationalExpr )*
+ ;
+
+
+relationalExpr
+ : shiftExpr
+ ( ( LT^ | LTE^ | GT^ | GTE^ ) shiftExpr )*
+ ;
+
+
+
+shiftExpr
+ : additiveExpr
+ ( ( LSHIFT^ | RSHIFT^ ) additiveExpr )*
+ ;
+
+
+additiveExpr
+ : multExpr
+ ( ( PLUS^ | MINUS^ ) multExpr )*
+ ;
+
+
+multExpr
+ : castExpr
+ ( ( STAR^ | DIV^ | MOD^ ) castExpr )*
+ ;
+
+
+castExpr
+ : ( LPAREN typeName RPAREN )=>
+ LPAREN! typeName RPAREN! ( castExpr )
+ { ## = #( #[NCast, "("], ## ); }
+
+ | unaryExpr
+ ;
+
+
+typeName
+ : specifierQualifierList (nonemptyAbstractDeclarator)?
+ ;
+
+nonemptyAbstractDeclarator
+ : (
+ pointerGroup
+ ( (LPAREN
+ ( nonemptyAbstractDeclarator
+ | parameterTypeList
+ )?
+ RPAREN)
+ | (LBRACKET (expr)? RBRACKET)
+ )*
+
+ | ( (LPAREN
+ ( nonemptyAbstractDeclarator
+ | parameterTypeList
+ )?
+ RPAREN)
+ | (LBRACKET (expr)? RBRACKET)
+ )+
+ )
+ { ## = #( #[NNonemptyAbstractDeclarator], ## ); }
+
+ ;
+
+/* JTC:
+
+LR rules:
+
+abstractDeclarator
+ : nonemptyAbstractDeclarator
+ | // null
+ ;
+
+nonemptyAbstractDeclarator
+ : LPAREN nonemptyAbstractDeclarator RPAREN
+ | abstractDeclarator LPAREN RPAREN
+ | abstractDeclarator (LBRACKET (expr)? RBRACKET)
+ | STAR abstractDeclarator
+ ;
+*/
+
+unaryExpr
+ : postfixExpr
+ | INC^ unaryExpr
+ | DEC^ unaryExpr
+ | u:unaryOperator castExpr { ## = #( #[NUnaryExpr], ## ); }
+
+ | "sizeof"^
+ ( ( LPAREN typeName )=> LPAREN typeName RPAREN
+ | unaryExpr
+ )
+ ;
+
+
+unaryOperator
+ : BAND
+ | STAR
+ | PLUS
+ | MINUS
+ | BNOT
+ | LNOT
+ ;
+
+postfixExpr
+ : primaryExpr
+ (
+ postfixSuffix {## = #( #[NPostfixExpr], ## );}
+ )?
+ ;
+postfixSuffix
+ :
+ ( PTR ID
+ | DOT ID
+ | functionCall
+ | LBRACKET expr RBRACKET
+ | INC
+ | DEC
+ )+
+ ;
+
+functionCall
+ :
+ LPAREN^ (a:argExprList)? RPAREN
+ {
+ ##.setType( NFunctionCallArgs );
+ }
+ ;
+
+
+primaryExpr
+ : ID
+ | charConst
+ | intConst
+ | floatConst
+ | stringConst
+
+// JTC:
+// ID should catch the enumerator
+// leaving it in gives ambiguous err
+// | enumerator
+ | LPAREN! expr RPAREN! { ## = #( #[NExpressionGroup, "("], ## ); }
+ ;
+
+argExprList
+ : assignExpr ( COMMA! assignExpr )*
+ ;
+
+
+
+protected
+charConst
+ : CharLiteral
+ ;
+
+
+protected
+stringConst
+ : (StringLiteral)+ { ## = #(#[NStringSeq], ##); }
+ ;
+
+
+protected
+intConst
+ : IntOctalConst
+ | LongOctalConst
+ | UnsignedOctalConst
+ | IntIntConst
+ | LongIntConst
+ | UnsignedIntConst
+ | IntHexConst
+ | LongHexConst
+ | UnsignedHexConst
+ ;
+
+
+protected
+floatConst
+ : FloatDoubleConst
+ | DoubleDoubleConst
+ | LongDoubleConst
+ ;
+
+
+
+
+
+
+dummy
+ : NTypedefName
+ | NInitDecl
+ | NDeclarator
+ | NStructDeclarator
+ | NDeclaration
+ | NCast
+ | NPointerGroup
+ | NExpressionGroup
+ | NFunctionCallArgs
+ | NNonemptyAbstractDeclarator
+ | NInitializer
+ | NStatementExpr
+ | NEmptyExpression
+ | NParameterTypeList
+ | NFunctionDef
+ | NCompoundStatement
+ | NParameterDeclaration
+ | NCommaExpr
+ | NUnaryExpr
+ | NLabel
+ | NPostfixExpr
+ | NRangeExpr
+ | NStringSeq
+ | NInitializerElementLabel
+ | NLcurlyInitializer
+ | NAsmAttribute
+ | NGnuAsmExpr
+ | NTypeMissing
+ ;
+
+
+
+
+
+
+{
+ import java.io.*;
+ import antlr.*;
+}
+
+class StdCLexer extends Lexer;
+
+options
+ {
+ k = 3;
+ exportVocab = STDC;
+ testLiterals = false;
+ }
+
+{
+ LineObject lineObject = new LineObject();
+ String originalSource = "";
+ PreprocessorInfoChannel preprocessorInfoChannel = new PreprocessorInfoChannel();
+ int tokenNumber = 0;
+ boolean countingTokens = true;
+ int deferredLineCount = 0;
+
+ public void setCountingTokens(boolean ct)
+ {
+ countingTokens = ct;
+ if ( countingTokens ) {
+ tokenNumber = 0;
+ }
+ else {
+ tokenNumber = 1;
+ }
+ }
+
+ public void setOriginalSource(String src)
+ {
+ originalSource = src;
+ lineObject.setSource(src);
+ }
+ public void setSource(String src)
+ {
+ lineObject.setSource(src);
+ }
+
+ public PreprocessorInfoChannel getPreprocessorInfoChannel()
+ {
+ return preprocessorInfoChannel;
+ }
+
+ public void setPreprocessingDirective(String pre)
+ {
+ preprocessorInfoChannel.addLineForTokenNumber( pre, new Integer(tokenNumber) );
+ }
+
+ public void addDefine(String name, String value)
+ {
+ }
+
+ protected Token makeToken(int t)
+ {
+ if ( t != Token.SKIP && countingTokens) {
+ tokenNumber++;
+ }
+ CToken tok = (CToken) super.makeToken(t);
+ tok.setLine(lineObject.line);
+ tok.setSource(lineObject.source);
+ tok.setTokenNumber(tokenNumber);
+
+ lineObject.line += deferredLineCount;
+ deferredLineCount = 0;
+ return tok;
+ }
+
+ public void deferredNewline() {
+ deferredLineCount++;
+ }
+
+ public void newline() {
+ lineObject.newline();
+ }
+
+
+
+
+
+
+}
+
+protected
+Vocabulary
+ : '\3'..'\377'
+ ;
+
+
+/* Operators: */
+
+ASSIGN : '=' ;
+COLON : ':' ;
+COMMA : ',' ;
+QUESTION : '?' ;
+SEMI : ';' ;
+PTR : "->" ;
+
+
+// DOT & VARARGS are commented out since they are generated as part of
+// the Number rule below due to some bizarre lexical ambiguity shme.
+
+// DOT : '.' ;
+protected
+DOT:;
+
+// VARARGS : "..." ;
+protected
+VARARGS:;
+
+
+LPAREN : '(' ;
+RPAREN : ')' ;
+LBRACKET : '[' ;
+RBRACKET : ']' ;
+LCURLY : '{' ;
+RCURLY : '}' ;
+
+EQUAL : "==" ;
+NOT_EQUAL : "!=" ;
+LTE : "<=" ;
+LT : "<" ;
+GTE : ">=" ;
+GT : ">" ;
+
+DIV : '/' ;
+DIV_ASSIGN : "/=" ;
+PLUS : '+' ;
+PLUS_ASSIGN : "+=" ;
+INC : "++" ;
+MINUS : '-' ;
+MINUS_ASSIGN : "-=" ;
+DEC : "--" ;
+STAR : '*' ;
+STAR_ASSIGN : "*=" ;
+MOD : '%' ;
+MOD_ASSIGN : "%=" ;
+RSHIFT : ">>" ;
+RSHIFT_ASSIGN : ">>=" ;
+LSHIFT : "<<" ;
+LSHIFT_ASSIGN : "<<=" ;
+
+LAND : "&&" ;
+LNOT : '!' ;
+LOR : "||" ;
+
+BAND : '&' ;
+BAND_ASSIGN : "&=" ;
+BNOT : '~' ;
+BOR : '|' ;
+BOR_ASSIGN : "|=" ;
+BXOR : '^' ;
+BXOR_ASSIGN : "^=" ;
+
+
+Whitespace
+ : ( ( '\003'..'\010' | '\t' | '\013' | '\f' | '\016'.. '\037' | '\177'..'\377' | ' ' )
+ | "\r\n" { newline(); }
+ | ( '\n' | '\r' ) { newline(); }
+ ) { _ttype = Token.SKIP; }
+ ;
+
+
+Comment
+ : "/*"
+ ( { LA(2) != '/' }? '*'
+ | "\r\n" { deferredNewline(); }
+ | ( '\r' | '\n' ) { deferredNewline(); }
+ | ~( '*'| '\r' | '\n' )
+ )*
+ "*/" { _ttype = Token.SKIP;
+ }
+ ;
+
+
+CPPComment
+ :
+ "//" ( ~('\n') )*
+ {
+ _ttype = Token.SKIP;
+ }
+ ;
+
+protected NonWhitespace
+ : (~('\r' | '\n'))*
+ ;
+
+
+PREPROC_DIRECTIVE
+options {
+ paraphrase = "a line directive";
+}
+
+ :
+ '#'
+ ( ( "line" || (( ' ' | '\t' | '\014')+ '0'..'9')) => LineDirective
+ | ( (Space)* "define" (Space)* i:ID (Space)* (n:Number)?
+ nw:NonWhitespace
+ ("\r\n" | "\r" | "\n") ) { if (n != null) {
+ addDefine(i.getText(), n.getText());
+ } else {
+ setPreprocessingDirective("#define " + i.getText() + " " +
+ nw.getText());
+ }
+ }
+ | (~'\n')* { setPreprocessingDirective(getText()); }
+ )
+ {
+ _ttype = Token.SKIP;
+ }
+ ;
+
+protected Space:
+ ( ' ' | '\t' | '\014')
+ ;
+
+protected LineDirective
+{
+ boolean oldCountingTokens = countingTokens;
+ countingTokens = false;
+}
+:
+ {
+ lineObject = new LineObject();
+ deferredLineCount = 0;
+ }
+ ("line")? //this would be for if the directive started "#line", but not there for GNU directives
+ (Space)+
+ n:Number { lineObject.setLine(Integer.parseInt(n.getText())); }
+ (Space)+
+ ( fn:StringLiteral { try {
+ lineObject.setSource(fn.getText().substring(1,fn.getText().length()-1));
+ }
+ catch (StringIndexOutOfBoundsException e) { /*not possible*/ }
+ }
+ | fi:ID { lineObject.setSource(fi.getText()); }
+ )?
+ (Space)*
+ ("1" { lineObject.setEnteringFile(true); } )?
+ (Space)*
+ ("2" { lineObject.setReturningToFile(true); } )?
+ (Space)*
+ ("3" { lineObject.setSystemHeader(true); } )?
+ (Space)*
+ ("4" { lineObject.setTreatAsC(true); } )?
+ (~('\r' | '\n'))*
+ ("\r\n" | "\r" | "\n")
+ {
+ preprocessorInfoChannel.addLineForTokenNumber(new LineObject(lineObject), new Integer(tokenNumber));
+ countingTokens = oldCountingTokens;
+ }
+ ;
+
+
+
+/* Literals: */
+
+/*
+ * Note that we do NOT handle tri-graphs nor multi-byte sequences.
+ */
+
+
+/*
+ * Note that we can't have empty character constants (even though we
+ * can have empty strings :-).
+ */
+CharLiteral
+ : '\'' ( Escape | ~( '\'' ) ) '\''
+ ;
+
+
+/*
+ * Can't have raw imbedded newlines in string constants. Strict reading of
+ * the standard gives odd dichotomy between newlines & carriage returns.
+ * Go figure.
+ */
+StringLiteral
+ : '"'
+ ( Escape
+ | (
+ '\r' { deferredNewline(); }
+ | '\n' {
+ deferredNewline();
+ _ttype = BadStringLiteral;
+ }
+ | '\\' '\n' {
+ deferredNewline();
+ }
+ )
+ | ~( '"' | '\r' | '\n' | '\\' )
+ )*
+ '"'
+ ;
+
+
+protected BadStringLiteral
+ : // Imaginary token.
+ ;
+
+
+/*
+ * Handle the various escape sequences.
+ *
+ * Note carefully that these numeric escape *sequences* are *not* of the
+ * same form as the C language numeric *constants*.
+ *
+ * There is no such thing as a binary numeric escape sequence.
+ *
+ * Octal escape sequences are either 1, 2, or 3 octal digits exactly.
+ *
+ * There is no such thing as a decimal escape sequence.
+ *
+ * Hexadecimal escape sequences are begun with a leading \x and continue
+ * until a non-hexadecimal character is found.
+ *
+ * No real handling of tri-graph sequences, yet.
+ */
+
+protected
+Escape
+ : '\\'
+ ( options{warnWhenFollowAmbig=false;}:
+ 'a'
+ | 'b'
+ | 'f'
+ | 'n'
+ | 'r'
+ | 't'
+ | 'v'
+ | '"'
+ | '\''
+ | '\\'
+ | '?'
+ | ('0'..'3') ( options{warnWhenFollowAmbig=false;}: Digit ( options{warnWhenFollowAmbig=false;}: Digit )? )?
+ | ('4'..'7') ( options{warnWhenFollowAmbig=false;}: Digit )?
+ | 'x' ( options{warnWhenFollowAmbig=false;}: Digit | 'a'..'f' | 'A'..'F' )+
+ )
+ ;
+
+
+/* Numeric Constants: */
+
+protected
+Digit
+ : '0'..'9'
+ ;
+
+protected
+LongSuffix
+ : 'l'
+ | 'L'
+ ;
+
+protected
+UnsignedSuffix
+ : 'u'
+ | 'U'
+ ;
+
+protected
+FloatSuffix
+ : 'f'
+ | 'F'
+ ;
+
+protected
+Exponent
+ : ( 'e' | 'E' ) ( '+' | '-' )? ( Digit )+
+ ;
+
+
+protected
+DoubleDoubleConst:;
+
+protected
+FloatDoubleConst:;
+
+protected
+LongDoubleConst:;
+
+protected
+IntOctalConst:;
+
+protected
+LongOctalConst:;
+
+protected
+UnsignedOctalConst:;
+
+protected
+IntIntConst:;
+
+protected
+LongIntConst:;
+
+protected
+UnsignedIntConst:;
+
+protected
+IntHexConst:;
+
+protected
+LongHexConst:;
+
+protected
+UnsignedHexConst:;
+
+
+
+
+Number
+ : ( ( Digit )+ ( '.' | 'e' | 'E' ) )=> ( Digit )+
+ ( '.' ( Digit )* ( Exponent )?
+ | Exponent
+ ) { _ttype = DoubleDoubleConst; }
+ ( FloatSuffix { _ttype = FloatDoubleConst; }
+ | LongSuffix { _ttype = LongDoubleConst; }
+ )?
+
+ | ( "..." )=> "..." { _ttype = VARARGS; }
+
+ | '.' { _ttype = DOT; }
+ ( ( Digit )+ ( Exponent )?
+ { _ttype = DoubleDoubleConst; }
+ ( FloatSuffix { _ttype = FloatDoubleConst; }
+ | LongSuffix { _ttype = LongDoubleConst; }
+ )?
+ )?
+
+ | '0' ( '0'..'7' )* { _ttype = IntOctalConst; }
+ ( LongSuffix { _ttype = LongOctalConst; }
+ | UnsignedSuffix { _ttype = UnsignedOctalConst; }
+ )?
+
+ | '1'..'9' ( Digit )* { _ttype = IntIntConst; }
+ ( LongSuffix { _ttype = LongIntConst; }
+ | UnsignedSuffix { _ttype = UnsignedIntConst; }
+ )?
+
+ | '0' ( 'x' | 'X' ) ( 'a'..'f' | 'A'..'F' | Digit )+
+ { _ttype = IntHexConst; }
+ ( LongSuffix { _ttype = LongHexConst; }
+ | UnsignedSuffix { _ttype = UnsignedHexConst; }
+ )?
+ ;
+
+
+ID
+ options
+ {
+ testLiterals = true;
+ }
+ : ( 'a'..'z' | 'A'..'Z' | '_' )
+ ( 'a'..'z' | 'A'..'Z' | '_' | '0'..'9' )*
+ ;
+
+
diff --git a/src/net/java/games/gluegen/cgram/TNode.java b/src/net/java/games/gluegen/cgram/TNode.java
new file mode 100644
index 000000000..2a93b939c
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/TNode.java
@@ -0,0 +1,433 @@
+package net.java.games.gluegen.cgram;
+
+import antlr.collections.AST;
+import antlr.CommonAST;
+import antlr.Token;
+import java.lang.reflect.*;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+/**
+ Class TNode is an implementation of the AST interface
+ and adds many useful features:
+
+ It is double-linked for reverse searching.
+ (this is currently incomplete, in that method doubleLink() must
+ be called after any changes to the tree to maintain the
+ reverse links).
+
+ It can store a definition node (defNode), so that nodes such
+ as scoped names can refer to the node that defines the name.
+
+ It stores line numbers for nodes.
+
+ Searches for parents and children of a tree can be done
+ based on their type.
+
+ The tree can be printed to System.out using a lisp-style syntax.
+
+
+
+ */
+public class TNode extends CommonAST {
+ protected int ttype;
+ protected String text;
+ protected int lineNum = 0;
+ protected TNode defNode;
+ protected TNode up;
+ protected TNode left;
+ protected boolean marker = false;
+ protected Hashtable attributes = null;
+ static String tokenVocabulary;
+
+
+
+
+ /** Set the token vocabulary to a tokentypes class
+ generated by antlr.
+ */
+ public static void setTokenVocabulary(String s) {
+ tokenVocabulary = s;
+ }
+
+
+public void initialize(Token token) {
+ CToken tok = (CToken) token;
+ setText(tok.getText());
+ setType(tok.getType());
+ setLineNum(tok.getLine());
+ setAttribute("source", tok.getSource());
+ setAttribute("tokenNumber", new Integer(tok.getTokenNumber()));
+}
+public void initialize(AST tr) {
+ TNode t = (TNode) tr;
+ setText(t.getText());
+ setType(t.getType());
+ setLineNum(t.getLineNum());
+ setDefNode(t.getDefNode());
+ this.attributes = t.getAttributesTable();
+}
+
+
+ /** Get the token type for this node */
+ public int getType() { return ttype; }
+
+ /** Set the token type for this node */
+ public void setType(int ttype_) {
+ ttype = ttype_;
+ }
+
+ /** Get the marker value for this node.
+ This member is a general-use marker.
+ */
+ public boolean getMarker() { return marker; }
+
+ /** Set the marker value for this node.
+ This property is a general-use boolean marker.
+ */
+ public void setMarker(boolean marker_) {
+ marker = marker_;
+ }
+
+ /** get the hashtable that holds attribute values.
+ */
+ public Hashtable getAttributesTable() {
+ if(attributes == null)
+ attributes = new Hashtable(7);
+ return attributes;
+ }
+
+ /** set an attribute in the attribute table.
+ */
+ public void setAttribute(String attrName, Object value) {
+ if(attributes == null)
+ attributes = new Hashtable(7);
+ attributes.put(attrName,value);
+ }
+
+ /** lookup the attribute name in the attribute table.
+ If the value does not exist, it returns null.
+ */
+ public Object getAttribute(String attrName) {
+ if(attributes == null)
+ return null;
+ else
+ return attributes.get(attrName);
+ }
+
+ /** Get the line number for this node.
+ If the line number is 0, search for a non-zero line num among children */
+ public int getLineNum() {
+ if(lineNum != 0)
+ return lineNum;
+ else
+ if(down == null)
+ return lineNum;
+ else
+ return ((TNode)down).getLocalLineNum();
+ }
+
+ public int getLocalLineNum() {
+ if(lineNum != 0)
+ return lineNum;
+ else
+ if(down == null)
+ if(right == null)
+ return lineNum;
+ else
+ return ((TNode)right).getLocalLineNum();
+ else
+ return ((TNode)down).getLocalLineNum();
+ }
+
+ /** Set the line number for this node */
+ public void setLineNum(int lineNum_) {
+ lineNum = lineNum_;
+ }
+
+ /** Get the token text for this node */
+ public String getText() { return text; }
+
+ /** Set the token text for this node */
+ public void setText(String text_) {
+ text = text_;
+ }
+
+ /** return the last child of this node, or null if there is none */
+ public TNode getLastChild() {
+ TNode down = (TNode)getFirstChild();
+ if(down != null)
+ return down.getLastSibling();
+ else
+ return null;
+ }
+
+ /** return the last sibling of this node, which is
+ this if the next sibling is null */
+ public TNode getLastSibling() {
+ TNode next = (TNode)getNextSibling();
+ if(next != null)
+ return next.getLastSibling();
+ else
+ return this;
+ }
+
+ /** return the first sibling of this node, which is
+ this if the prev sibling is null */
+ public TNode getFirstSibling() {
+ TNode prev = (TNode)left;
+ if(prev != null)
+ return prev.getFirstSibling();
+ else
+ return this;
+ }
+
+
+ /** return the parent node of this node */
+ public TNode getParent() {
+ return (TNode)getFirstSibling().up;
+ }
+
+
+ /** add the new node as a new sibling, inserting it ahead of any
+ existing next sibling. This method maintains double-linking.
+ if node is null, nothing happens. If the node has siblings,
+ then they are added in as well.
+ */
+ public void addSibling(AST node) {
+ if(node == null) return;
+ TNode next = (TNode)right;
+ right = (TNode)node;
+ ((TNode)node).left = this;
+ TNode nodeLastSib = ((TNode)node).getLastSibling();
+ nodeLastSib.right = next;
+ if(next != null)
+ next.left = nodeLastSib;
+ }
+
+
+ /** return the number of children of this node */
+ public int numberOfChildren() {
+ int count = 0;
+ AST child = getFirstChild();
+ while(child != null) {
+ count++;
+ child = child.getNextSibling();
+ }
+ return count;
+ }
+
+
+ /** remove this node from the tree, resetting sibling and parent
+ pointers as necessary. This method maintains double-linking */
+ public void removeSelf() {
+ TNode parent = (TNode)up;
+ TNode prev = (TNode)left;
+ TNode next = (TNode)right;
+
+ if(parent != null) {
+ parent.down = next;
+ if(next != null) {
+ next.up = parent;
+ next.left = prev; // which should be null
+ }
+ }
+ else {
+ if(prev != null)
+ prev.right = next;
+ if(next != null)
+ next.left = prev;
+ }
+ }
+
+
+ /** return the def node for this node */
+ public TNode getDefNode() {
+ return defNode;
+ }
+
+ /** set the def node for this node */
+ public void setDefNode(TNode n) {
+ defNode = n;
+ }
+
+
+ /** return a deep copy of this node, and all sub nodes.
+ New tree is doubleLinked, with no parent or siblings.
+ Marker value is not copied!
+ */
+ public TNode deepCopy() {
+ TNode copy = new TNode();
+ copy.ttype = ttype;
+ copy.text = text;
+ copy.lineNum = lineNum;
+ copy.defNode = defNode;
+ if(attributes != null)
+ copy.attributes = (Hashtable)attributes.clone();
+ if(down != null)
+ copy.down = ((TNode)down).deepCopyWithRightSiblings();
+ copy.doubleLink();
+ return copy;
+ }
+
+
+ /** return a deep copy of this node, all sub nodes,
+ and right siblings.
+ New tree is doubleLinked, with no parent or left siblings.
+ defNode is not copied */
+ public TNode deepCopyWithRightSiblings() {
+ TNode copy = new TNode();
+ copy.ttype = ttype;
+ copy.text = text;
+ copy.lineNum = lineNum;
+ copy.defNode = defNode;
+ if(attributes != null)
+ copy.attributes = (Hashtable)attributes.clone();
+ if(down != null)
+ copy.down = ((TNode)down).deepCopyWithRightSiblings();
+ if(right != null)
+ copy.right = ((TNode)right).deepCopyWithRightSiblings();
+ copy.doubleLink();
+ return copy;
+ }
+
+
+ /** return a short string representation of the node */
+ public String toString() {
+ StringBuffer str = new StringBuffer( getNameForType(getType()) +
+ "[" + getText() + ", " + "]");
+
+ if(this.getLineNum() != 0)
+ str.append(" line:" + (this.getLineNum() ) );
+
+ Enumeration keys = (this.getAttributesTable().keys());
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ str.append(" " + key + ":" + (this.getAttribute(key)));
+ }
+
+ return str.toString();
+ }
+
+
+ /** print given tree to System.out */
+ public static void printTree(AST t) {
+ if (t == null) return;
+ printASTNode(t,0);
+ System.out.print("\n");
+ }
+
+
+ /** protected method that does the work of printing */
+ protected static void printASTNode(AST t, int indent) {
+ AST child1, next;
+ child1 = t.getFirstChild();
+
+ System.out.print("\n");
+ for(int i = 0; i < indent; i++)
+ System.out.print(" ");
+
+ if(child1 != null)
+ System.out.print("(");
+
+ String s = t.getText();
+ if(s != null && s.length() > 0) {
+ System.out.print(getNameForType(t.getType()));
+ System.out.print(": \"" + s + "\"");
+ }
+ else
+ System.out.print(getNameForType(t.getType()));
+ if(((TNode)t).getLineNum() != 0)
+ System.out.print(" line:" + ((TNode)t).getLineNum() );
+
+ Enumeration keys = ((TNode)t).getAttributesTable().keys();
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ System.out.print(" " + key + ":" + ((TNode)t).getAttribute(key));
+ }
+ TNode def = ((TNode)t).getDefNode();
+ if(def != null)
+ System.out.print("[" + getNameForType(def.getType()) + "]");
+
+
+ if(child1 != null) {
+ printASTNode(child1,indent + 1);
+
+ System.out.print("\n");
+ for(int i = 0; i < indent; i++)
+ System.out.print(" ");
+ System.out.print(")");
+ }
+
+ next = t.getNextSibling();
+ if(next != null) {
+ printASTNode(next,indent);
+ }
+ }
+
+ /** converts an int tree token type to a name.
+ Does this by reflecting on nsdidl.IDLTreeTokenTypes,
+ and is dependent on how ANTLR 2.00 outputs that class. */
+ public static String getNameForType(int t) {
+ try{
+ Class c = Class.forName(tokenVocabulary);
+ Field[] fields = c.getDeclaredFields();
+ if(t-2 < fields.length)
+ return fields[t-2].getName();
+ } catch (Exception e) { System.out.println(e); }
+ return "unfoundtype: " + t;
+ }
+
+
+ /** set up reverse links between this node and its first
+ child and its first sibling, and link those as well */
+ public void doubleLink() {
+ TNode right = (TNode)getNextSibling();
+ if(right != null) {
+ right.left = this;
+ right.doubleLink();
+ }
+ TNode down = (TNode)getFirstChild();
+ if(down != null) {
+ down.up = this;
+ down.doubleLink();
+ }
+ }
+
+ /** find first parent of the given type,
+ return null on failure */
+ public TNode parentOfType(int type) {
+ if(up == null) {
+ if(left == null)
+ return null;
+ else
+ return left.parentOfType(type);
+ }
+ if(up.getType() == type)
+ return up;
+ return up.parentOfType(type);
+ }
+
+ /** find the first child of the node
+ of the given type, return null on failure */
+ public TNode firstChildOfType(int type) {
+ TNode down = (TNode)getFirstChild();
+ if(down == null)
+ return null;
+ if(down.getType() == type)
+ return down;
+ return down.firstSiblingOfType(type);
+ }
+
+ /** find the first sibling of the node
+ of the given type, return null on failure */
+ public TNode firstSiblingOfType(int type) {
+ TNode right = (TNode)getNextSibling();
+ if(right == null)
+ return null;
+ if(right.getType() == type)
+ return right;
+ return right.firstSiblingOfType(type);
+ }
+
+}
diff --git a/src/net/java/games/gluegen/cgram/TNodeFactory.java b/src/net/java/games/gluegen/cgram/TNodeFactory.java
new file mode 100644
index 000000000..8cda2cfa9
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/TNodeFactory.java
@@ -0,0 +1,33 @@
+package net.java.games.gluegen.cgram;
+
+import antlr.Token;
+import antlr.ASTFactory;
+import antlr.collections.AST;
+
+/** This class extends ASTFactory to build instances
+ of class TNode */
+public class TNodeFactory extends ASTFactory {
+
+ /** Create a new ampty AST node */
+ public AST create() {
+ return new TNode();
+ }
+
+ /** Create a new AST node from type and text */
+ public AST create(int ttype, String text) {
+ AST ast = new TNode();
+ ast.setType(ttype);
+ ast.setText(text);
+ return ast;
+ }
+
+ /** Create a new AST node from an existing AST node */
+ public AST create(AST ast) {
+ AST newast = new TNode();
+ newast.setType(ast.getType());
+ newast.setText(ast.getText());
+ return newast;
+ }
+
+
+}
diff --git a/src/net/java/games/gluegen/cgram/types/ArrayType.java b/src/net/java/games/gluegen/cgram/types/ArrayType.java
new file mode 100644
index 000000000..6394a39cb
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/ArrayType.java
@@ -0,0 +1,131 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+/** Represents an array type. This differs from a pointer type in C
+ syntax by the use of "[]" rather than "*". The length may or may
+ not be known; if the length is unknown then a negative number
+ should be passed in to the constructor. */
+
+public class ArrayType extends Type {
+ private Type elementType;
+ private int length;
+ private String computedName;
+
+ public ArrayType(Type elementType, int sizeInBytes, int length, int cvAttributes) {
+ super(elementType.getName() + " *", sizeInBytes, cvAttributes);
+ this.elementType = elementType;
+ this.length = length;
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) return true;
+ if (arg == null || (!(arg instanceof ArrayType))) {
+ return false;
+ }
+ ArrayType t = (ArrayType) arg;
+ return (super.equals(arg) && elementType.equals(t.elementType) && (length == t.length));
+ }
+
+ public String getName(boolean includeCVAttrs) {
+ // Lazy computation of name due to lazy setting of compound type
+ // names during parsing
+ // Note: don't think cvAttributes can be set for array types (unlike pointer types)
+ if (computedName == null) {
+ computedName = elementType.getName() + " *";
+ computedName = computedName.intern();
+ }
+ return computedName;
+ }
+
+ public ArrayType asArray() { return this; }
+
+ public Type getElementType() { return elementType; }
+ public int getLength() { return length; }
+ public boolean hasLength() { return length >= 0; }
+
+ /** Return the bottommost element type if this is a multidimensional
+ array. */
+ public Type getBaseElementType() {
+ ArrayType t = this;
+ while (t.getElementType().isArray()) {
+ t = t.getElementType().asArray();
+ }
+ return t.getElementType();
+ }
+
+ /** Recompute the size of this array if necessary. This needs to be
+ done when the base element type is a compound type. */
+ public void recomputeSize() {
+ ArrayType arrayElementType = getElementType().asArray();
+ if (arrayElementType != null) {
+ arrayElementType.recomputeSize();
+ }
+ // FIXME: this doesn't take into account struct alignment, which may be necessary
+ // See also FIXME below and in HeaderParser.g
+ super.setSize(getLength() * elementType.getSize());
+ }
+
+ public String toString() {
+ return toString(null);
+ }
+
+ public String toString(String variableName) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(elementType.getName());
+ if (variableName != null) {
+ buf.append(" ");
+ buf.append(variableName);
+ }
+ buf.append("[");
+ buf.append(length);
+ buf.append("]");
+ return buf.toString();
+ }
+
+ public void visit(TypeVisitor arg) {
+ super.visit(arg);
+ elementType.visit(arg);
+ }
+
+ Type newCVVariant(int cvAttributes) {
+ return new ArrayType(elementType, getSize(), length, cvAttributes);
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/BitType.java b/src/net/java/games/gluegen/cgram/types/BitType.java
new file mode 100644
index 000000000..48d81e933
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/BitType.java
@@ -0,0 +1,87 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+/** Represents a bitfield in a struct. */
+
+public class BitType extends IntType {
+ private IntType underlyingType;
+ private int sizeInBits;
+ private int offset;
+
+ public BitType(IntType underlyingType, int sizeInBits, int lsbOffset, int cvAttributes) {
+ super(underlyingType.getName(), underlyingType.getSize(), underlyingType.isUnsigned(), cvAttributes);
+ this.underlyingType = underlyingType;
+ this.sizeInBits = sizeInBits;
+ this.offset = lsbOffset;
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) return true;
+ if (arg == null || (!(arg instanceof BitType))) {
+ return false;
+ }
+ BitType t = (BitType) arg;
+ return (super.equals(arg) && underlyingType.equals(t.underlyingType) &&
+ (sizeInBits == t.sizeInBits) && (offset == t.offset));
+ }
+
+ public BitType asBit() { return this; }
+
+ /** Size in bits of this type. */
+ public int getSizeInBits() {
+ return sizeInBits;
+ }
+
+ /** Offset from the least-significant bit (LSB) of the LSB of this
+ type */
+ public int getOffset() {
+ return offset;
+ }
+
+ public void visit(TypeVisitor arg) {
+ super.visit(arg);
+ underlyingType.visit(arg);
+ }
+
+ Type newCVVariant(int cvAttributes) {
+ return new BitType(underlyingType, sizeInBits, offset, cvAttributes);
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/CVAttributes.java b/src/net/java/games/gluegen/cgram/types/CVAttributes.java
new file mode 100644
index 000000000..e93d38cc5
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/CVAttributes.java
@@ -0,0 +1,48 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+/** Enumeration for const/volatile attributes. These are passed in to
+ the constructor of the type. */
+
+public interface CVAttributes {
+ public static final int CONST = 0x01;
+ public static final int VOLATILE = 0x02;
+}
diff --git a/src/net/java/games/gluegen/cgram/types/CompoundType.java b/src/net/java/games/gluegen/cgram/types/CompoundType.java
new file mode 100644
index 000000000..a08193a13
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/CompoundType.java
@@ -0,0 +1,205 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+import java.util.*;
+
+/** Models all compound types, i.e., those containing fields: structs
+ and unions. The boolean type accessors indicate how the type is
+ really defined. */
+
+public class CompoundType extends Type {
+ private CompoundTypeKind kind;
+ // The name "foo" in the construct "struct foo { ... }";
+ private String structName;
+ private ArrayList fields;
+ private boolean visiting;
+ private boolean bodyParsed;
+ private boolean computedHashcode;
+ private int hashcode;
+
+ public CompoundType(String name, int size, CompoundTypeKind kind, int cvAttributes) {
+ this(name, size, kind, cvAttributes, null);
+ }
+
+ private CompoundType(String name, int size, CompoundTypeKind kind, int cvAttributes, String structName) {
+ super(name, size, cvAttributes);
+ assert kind != null;
+ this.kind = kind;
+ this.structName = structName;
+ }
+
+ public int hashCode() {
+ if (computedHashcode) {
+ return hashcode;
+ }
+
+ if (structName != null) {
+ hashcode = structName.hashCode();
+ } else if (getName() != null) {
+ hashcode = getName().hashCode();
+ } else {
+ hashcode = System.identityHashCode(this);
+ }
+
+ computedHashcode = true;
+ return hashcode;
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) return true;
+ if (arg == null || (!(arg instanceof CompoundType))) {
+ return false;
+ }
+ CompoundType t = (CompoundType) arg;
+ return (super.equals(arg) &&
+ kind == t.kind &&
+ listsEqual(fields, t.fields));
+ }
+
+ /** Returns the struct name of this CompoundType, i.e. the "foo" in
+ the construct "struct foo { ... };". */
+ public String getStructName() {
+ return structName;
+ }
+
+ /** Sets the struct name of this CompoundType, i.e. the "foo" in the
+ construct "struct foo { ... };". */
+ public void setStructName(String structName) {
+ this.structName = structName;
+ }
+
+ public void setSize(int size) {
+ super.setSize(size);
+ }
+
+ public CompoundType asCompound() { return this; }
+
+ /** Returns the number of fields in this type. */
+ public int getNumFields() {
+ return ((fields == null) ? 0 : fields.size());
+ }
+
+ /** Returns the <i>i</i>th field of this type. */
+ public Field getField(int i) {
+ return (Field) fields.get(i);
+ }
+
+ /** Adds a field to this type. */
+ public void addField(Field f) {
+ if (bodyParsed) {
+ throw new RuntimeException("Body of this CompoundType has already been parsed; should not be adding more fields");
+ }
+ if (fields == null) {
+ fields = new ArrayList();
+ }
+ fields.add(f);
+ }
+
+ /** Indicates to this CompoundType that its body has been parsed and
+ that no more {@link addField} operations will be made. */
+ public void setBodyParsed() {
+ bodyParsed = true;
+ }
+
+ /** Indicates whether this type was declared as a struct. */
+ public boolean isStruct() { return (kind == CompoundTypeKind.STRUCT); }
+ /** Indicates whether this type was declared as a union. */
+ public boolean isUnion() { return (kind == CompoundTypeKind.UNION); }
+
+ public String toString() {
+ String cvAttributesString = getCVAttributesString();
+ if (getName() != null) {
+ return cvAttributesString + getName();
+ } else if (getStructName() != null) {
+ return cvAttributesString + "struct " + getStructName();
+ } else {
+ return cvAttributesString + getStructString();
+ }
+ }
+
+ public void visit(TypeVisitor arg) {
+ if (visiting) {
+ return;
+ }
+ try {
+ visiting = true;
+ super.visit(arg);
+ int n = getNumFields();
+ for (int i = 0; i < n; i++) {
+ Field f = getField(i);
+ f.getType().visit(arg);
+ }
+ } finally {
+ visiting = false;
+ }
+ }
+
+ public String getStructString() {
+ if (visiting) {
+ if (getName() != null) {
+ return getName();
+ }
+ return "struct {/*Recursive type reference*/}";
+ }
+
+ try {
+ visiting = true;
+ String kind = (isStruct() ? "struct {" : "union {");
+ StringBuffer res = new StringBuffer();
+ res.append(kind);
+ int n = getNumFields();
+ for (int i = 0; i < n; i++) {
+ res.append(" ");
+ res.append(getField(i));
+ }
+ res.append(" }");
+ return res.toString();
+ } finally {
+ visiting = false;
+ }
+ }
+
+ Type newCVVariant(int cvAttributes) {
+ CompoundType t = new CompoundType(getName(), getSize(), kind, cvAttributes, structName);
+ t.fields = fields;
+ return t;
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/CompoundTypeKind.java b/src/net/java/games/gluegen/cgram/types/CompoundTypeKind.java
new file mode 100644
index 000000000..9a1475d70
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/CompoundTypeKind.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+/** Type-safe enum for discriminating between structs and unions,
+ which are both represented as compound types. */
+
+public class CompoundTypeKind {
+ public static final CompoundTypeKind STRUCT = new CompoundTypeKind();
+ public static final CompoundTypeKind UNION = new CompoundTypeKind();
+
+ private CompoundTypeKind() {}
+}
diff --git a/src/net/java/games/gluegen/cgram/types/DoubleType.java b/src/net/java/games/gluegen/cgram/types/DoubleType.java
new file mode 100644
index 000000000..3c2869e58
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/DoubleType.java
@@ -0,0 +1,64 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+/** Represents a double-word floating-point type (C type "double".) */
+
+public class DoubleType extends PrimitiveType {
+ public DoubleType(String name, int size, int cvAttributes) {
+ super(name, size, cvAttributes);
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) {
+ return true;
+ }
+ if (arg == null || (!(arg instanceof DoubleType))) {
+ return false;
+ }
+ return super.equals(arg);
+ }
+
+ public DoubleType asDouble() { return this; }
+
+ Type newCVVariant(int cvAttributes) {
+ return new DoubleType(getName(), getSize(), cvAttributes);
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/EnumType.java b/src/net/java/games/gluegen/cgram/types/EnumType.java
new file mode 100644
index 000000000..f85f64e23
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/EnumType.java
@@ -0,0 +1,147 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+import java.util.*;
+
+/** Describes enumerated types. Enumerations are like ints except that
+ they have a set of named values. */
+
+public class EnumType extends IntType {
+ private IntType underlyingType;
+
+ private static class Enum {
+ String name;
+ long value;
+ Enum(String name, long value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ String getName() { return name; }
+ long getValue() { return value; }
+ }
+ private List/*<Enum>*/ enums;
+
+ private static final int longSizeBytes = 8;
+
+ public EnumType(String name) {
+ super(name, longSizeBytes, false, CVAttributes.CONST );
+ this.underlyingType = new IntType(name, longSizeBytes, false, CVAttributes.CONST);
+ }
+
+ public EnumType(String name, int enumSizeBytes) {
+ super(name, enumSizeBytes, false, CVAttributes.CONST );
+ this.underlyingType = new IntType(name, enumSizeBytes, false, CVAttributes.CONST);
+ }
+
+ protected EnumType(String name, IntType underlyingType, int cvAttributes) {
+ super(name, underlyingType.getSize(), underlyingType.isUnsigned(), cvAttributes);
+ this.underlyingType = underlyingType;
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) return true;
+ if (arg == null || (!(arg instanceof EnumType))) {
+ return false;
+ }
+ EnumType t = (EnumType) arg;
+ return (super.equals(arg) &&
+ underlyingType.equals(t.underlyingType) &&
+ listsEqual(enums, t.enums));
+ }
+
+ public EnumType asEnum() { return this; }
+
+ public void addEnum(String name, long val) {
+ if (enums == null) {
+ enums = new ArrayList();
+ }
+ enums.add(new Enum(name, val));
+ }
+
+ /** Number of enumerates defined in this enum. */
+ public int getNumEnumerates() { return enums.size(); }
+ /** Fetch <i>i</i>th (0..getNumEnumerates() - 1) name */
+ public String getEnumName(int i) { return ((Enum) enums.get(i)).getName(); }
+ /** Fetch <i>i</i>th (0..getNumEnumerates() - 1) value */
+ public long getEnumValue(int i) { return ((Enum) enums.get(i)).getValue(); }
+ /** Fetch the value of the enumerate with the given name. */
+ public long getEnumValue(String name) {
+ for (int i = 0; i < enums.size(); ++i) {
+ Enum n = ((Enum)enums.get(i));
+ if (n.getName().equals(name)) { return n.getValue(); }
+ }
+ throw new NoSuchElementException(
+ "No enumerate named \"" + name + "\" in EnumType \"" +
+ getName() + "\"");
+ }
+ /** Does this enum type contain an enumerate with the given name? */
+ public boolean containsEnumerate(String name) {
+ for (int i = 0; i < enums.size(); ++i) {
+ if (((Enum)enums.get(i)).getName().equals(name)) { return true; }
+ }
+ return false;
+ }
+ /** Remove the enumerate with the given name. Returns true if it was found
+ * and removed; false if it was not found.
+ */
+ public boolean removeEnumerate(String name) {
+ for (int i = 0; i < enums.size(); ++i) {
+ Enum e = (Enum)enums.get(i);
+ if (e.getName().equals(name)) {
+ enums.remove(e);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void visit(TypeVisitor arg) {
+ super.visit(arg);
+ underlyingType.visit(arg);
+ }
+
+ Type newCVVariant(int cvAttributes) {
+ EnumType t = new EnumType(getName(), underlyingType, cvAttributes);
+ t.enums = enums;
+ return t;
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/Field.java b/src/net/java/games/gluegen/cgram/types/Field.java
new file mode 100644
index 000000000..1c6f6f8a0
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/Field.java
@@ -0,0 +1,96 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+/** Represents a field in a struct or union. */
+
+public class Field {
+ private String name;
+ private Type type;
+ private long offset;
+
+ public Field(String name, Type type, long offset) {
+ this.name = name;
+ this.type = type;
+ this.offset = offset;
+ }
+
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == null || (!(arg instanceof Field))) {
+ return false;
+ }
+
+ Field f = (Field) arg;
+ return (((name != null && name.equals(f.name)) ||
+ (name == null && f.name == null)) &&
+ type.equals(f.type) &&
+ offset == f.offset);
+ }
+
+ /** Name of this field in the containing data structure. */
+ public String getName() { return name; }
+
+ /** Type of this field. */
+ public Type getType() { return type; }
+
+ /** Offset, in bytes, of this field in the containing data structure. */
+ public long getOffset() { return offset; }
+
+ /** Sets the offset of this field in the containing data structure. */
+ public void setOffset(long offset) { this.offset = offset; }
+
+ public String toString() {
+ if (!getType().isFunctionPointer()) {
+ if (getName() == null &&
+ getType().asCompound() != null &&
+ getType().asCompound().isUnion()) {
+ return "" + getType() + ";";
+ }
+ return "" + getType() + " " + getName() + ";";
+ } else {
+ FunctionType ft = getType().asPointer().getTargetType().asFunction();
+ return ft.toString(getName(), true) + ";";
+ }
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/FloatType.java b/src/net/java/games/gluegen/cgram/types/FloatType.java
new file mode 100644
index 000000000..1ad28f1ba
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/FloatType.java
@@ -0,0 +1,64 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+/** Represents a single-word floating-point type (C type "float".) */
+
+public class FloatType extends PrimitiveType {
+ public FloatType(String name, int size, int cvAttributes) {
+ super(name, size, cvAttributes);
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) {
+ return true;
+ }
+ if (arg == null || (!(arg instanceof FloatType))) {
+ return false;
+ }
+ return super.equals(arg);
+ }
+
+ public FloatType asFloat() { return this; }
+
+ Type newCVVariant(int cvAttributes) {
+ return new FloatType(getName(), getSize(), cvAttributes);
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/FunctionSymbol.java b/src/net/java/games/gluegen/cgram/types/FunctionSymbol.java
new file mode 100644
index 000000000..491961c5b
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/FunctionSymbol.java
@@ -0,0 +1,112 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+import java.util.*;
+
+/** Describes a function symbol, which includes the name and
+ type. Since we are currently only concerned with processing
+ functions this is the only symbol type, though plausibly more
+ types should be added and a true symbol table constructed during
+ parsing. */
+
+public class FunctionSymbol {
+ private String name;
+ private FunctionType type;
+
+ public FunctionSymbol(String name, FunctionType type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName() { return name; }
+
+ /** Returns the type of this function. Do not add arguments to it
+ directly; use addArgument instead. */
+ public FunctionType getType() { return type; }
+
+ /** Returns the return type of this function. */
+ public Type getReturnType() { return type.getReturnType(); }
+
+ public int getNumArguments() { return type.getNumArguments(); }
+
+ /** Returns the name of the <i>i</i>th argument. May return null if
+ no argument names were available during parsing. */
+ public String getArgumentName(int i) {
+ return type.getArgumentName(i);
+ }
+
+ /** Returns the type of the <i>i</i>th argument. */
+ public Type getArgumentType(int i) {
+ return type.getArgumentType(i);
+ }
+
+ /** Add an argument's name and type. Use null for unknown argument
+ names. */
+ public void addArgument(Type argumentType, String argumentName) {
+ type.addArgument(argumentType, argumentName);
+ }
+
+ public String toString() {
+ return getType().toString(getName());
+ }
+
+ public int hashCode() {
+ if (name == null) {
+ return 0;
+ }
+ return name.hashCode();
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) {
+ return true;
+ }
+
+ if (arg == null || (!(arg instanceof FunctionSymbol))) {
+ return false;
+ }
+
+ FunctionSymbol other = (FunctionSymbol) arg;
+ return (
+ (getName() == other.getName() || getName().equals(other.getName()))
+ && type.equals(other.type));
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/FunctionType.java b/src/net/java/games/gluegen/cgram/types/FunctionType.java
new file mode 100644
index 000000000..f864b4d2c
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/FunctionType.java
@@ -0,0 +1,159 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+import java.util.*;
+
+/** Describes a function type, used to model both function
+ declarations and (via PointerType) function pointers. */
+
+public class FunctionType extends Type {
+ private Type returnType;
+ private ArrayList argumentTypes;
+ private ArrayList argumentNames;
+
+ public FunctionType(String name, int size, Type returnType, int cvAttributes) {
+ super(name, size, cvAttributes);
+ this.returnType = returnType;
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) return true;
+ if (arg == null || (!(arg instanceof FunctionType))) {
+ return false;
+ }
+ FunctionType t = (FunctionType) arg;
+ return (super.equals(arg) &&
+ returnType.equals(t.returnType) &&
+ listsEqual(argumentTypes, t.argumentTypes));
+ }
+
+ public FunctionType asFunction() { return this; }
+
+ /** Returns the return type of this function. */
+ public Type getReturnType() { return returnType; }
+
+ public int getNumArguments() { return ((argumentTypes == null) ? 0 : argumentTypes.size()); }
+
+ /** Returns the name of the <i>i</i>th argument. May return null if
+ no argument names were available during parsing. */
+ public String getArgumentName(int i) {
+ return (String) argumentNames.get(i);
+ }
+
+ /** Returns the type of the <i>i</i>th argument. */
+ public Type getArgumentType(int i) {
+ return (Type) argumentTypes.get(i);
+ }
+
+ /** Add an argument's name and type. Use null for unknown argument
+ names. */
+ public void addArgument(Type argumentType, String argumentName) {
+ if (argumentTypes == null) {
+ argumentTypes = new ArrayList();
+ argumentNames = new ArrayList();
+ }
+ argumentTypes.add(argumentType);
+ argumentNames.add(argumentName);
+ }
+
+ public String toString() {
+ return toString(null);
+ }
+
+ public String toString(String functionName) {
+ return toString(functionName, false);
+ }
+
+ String toString(String functionName, boolean isPointer) {
+ StringBuffer res = new StringBuffer();
+ res.append(getReturnType());
+ res.append(" ");
+ if (isPointer) {
+ res.append("(*");
+ }
+ if (functionName != null) {
+ res.append(functionName);
+ }
+ if (isPointer) {
+ res.append(")");
+ }
+ res.append("(");
+ int n = getNumArguments();
+ for (int i = 0; i < n; i++) {
+ Type t = getArgumentType(i);
+ if (t.isFunctionPointer()) {
+ FunctionType ft = t.asPointer().getTargetType().asFunction();
+ res.append(ft.toString(getArgumentName(i), true));
+ } else if (t.isArray()) {
+ res.append(t.asArray().toString(getArgumentName(i)));
+ } else {
+ res.append(t);
+ String argumentName = getArgumentName(i);
+ if (argumentName != null) {
+ res.append(" ");
+ res.append(argumentName);
+ }
+ }
+ if (i < n - 1) {
+ res.append(", ");
+ }
+ }
+ res.append(")");
+ if (!isPointer) {
+ res.append(";");
+ }
+ return res.toString();
+ }
+
+ public void visit(TypeVisitor arg) {
+ super.visit(arg);
+ returnType.visit(arg);
+ int n = getNumArguments();
+ for (int i = 0; i < n; i++) {
+ getArgumentType(i).visit(arg);
+ }
+ }
+
+ Type newCVVariant(int cvAttributes) {
+ // Functions don't have const/volatile attributes
+ return this;
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/IntType.java b/src/net/java/games/gluegen/cgram/types/IntType.java
new file mode 100644
index 000000000..84f9b4c13
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/IntType.java
@@ -0,0 +1,82 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+public class IntType extends PrimitiveType {
+ private boolean unsigned;
+ private boolean typedefedUnsigned;
+
+ public IntType(String name, int size, boolean unsigned, int cvAttributes) {
+ this(name, size, unsigned, cvAttributes, false);
+ }
+
+ private IntType(String name, int size, boolean unsigned, int cvAttributes, boolean typedefedUnsigned) {
+ super(name, size, cvAttributes);
+ this.unsigned = unsigned;
+ this.typedefedUnsigned = typedefedUnsigned;
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) return true;
+ if (arg == null || (!(arg instanceof IntType))) {
+ return false;
+ }
+ IntType t = (IntType) arg;
+ return (super.equals(arg) && (unsigned == t.unsigned));
+ }
+
+ public void setName(String name) {
+ super.setName(name);
+ typedefedUnsigned = unsigned;
+ }
+
+ public IntType asInt() { return this; }
+
+ /** Indicates whether this type is unsigned */
+ public boolean isUnsigned() { return unsigned; }
+
+ public String toString() {
+ return getCVAttributesString() + ((isUnsigned() & (!typedefedUnsigned)) ? "unsigned " : "") + getName();
+ }
+
+ Type newCVVariant(int cvAttributes) {
+ return new IntType(getName(), getSize(), isUnsigned(), cvAttributes, typedefedUnsigned);
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/MachineDescription.java b/src/net/java/games/gluegen/cgram/types/MachineDescription.java
new file mode 100644
index 000000000..3db50d554
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/MachineDescription.java
@@ -0,0 +1,78 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+public class MachineDescription {
+ private int charSizeInBytes;
+ private int shortSizeInBytes;
+ private int intSizeInBytes;
+ private int longSizeInBytes;
+ private int int64SizeInBytes;
+ private int floatSizeInBytes;
+ private int doubleSizeInBytes;
+ private int pointerSizeInBytes;
+
+ public MachineDescription(int charSizeInBytes,
+ int shortSizeInBytes,
+ int intSizeInBytes,
+ int longSizeInBytes,
+ int int64SizeInBytes,
+ int floatSizeInBytes,
+ int doubleSizeInBytes,
+ int pointerSizeInBytes) {
+ this.charSizeInBytes = charSizeInBytes;
+ this.shortSizeInBytes = shortSizeInBytes;
+ this.intSizeInBytes = intSizeInBytes;
+ this.longSizeInBytes = longSizeInBytes;
+ this.int64SizeInBytes = int64SizeInBytes;
+ this.floatSizeInBytes = floatSizeInBytes;
+ this.doubleSizeInBytes = doubleSizeInBytes;
+ this.pointerSizeInBytes = pointerSizeInBytes;
+ }
+
+ public int charSizeInBytes() { return charSizeInBytes; }
+ public int shortSizeInBytes() { return shortSizeInBytes; }
+ public int intSizeInBytes() { return intSizeInBytes; }
+ public int longSizeInBytes() { return longSizeInBytes; }
+ public int int64SizeInBytes() { return int64SizeInBytes; }
+ public int floatSizeInBytes() { return floatSizeInBytes; }
+ public int doubleSizeInBytes() { return doubleSizeInBytes; }
+ public int pointerSizeInBytes() { return pointerSizeInBytes; }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/MachineDescription32Bit.java b/src/net/java/games/gluegen/cgram/types/MachineDescription32Bit.java
new file mode 100644
index 000000000..337747047
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/MachineDescription32Bit.java
@@ -0,0 +1,46 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+public class MachineDescription32Bit extends MachineDescription {
+ public MachineDescription32Bit() {
+ super(1, 2, 4, 4, 8, 4, 8, 4);
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/PointerType.java b/src/net/java/games/gluegen/cgram/types/PointerType.java
new file mode 100644
index 000000000..62bfe9c1a
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/PointerType.java
@@ -0,0 +1,136 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+public class PointerType extends Type {
+ private Type targetType;
+ private String computedName;
+ private boolean hasTypedefedName;
+
+ public PointerType(int size, Type targetType, int cvAttributes) {
+ // can pass null for the final name parameter because the PointerType's getName()
+ // completely replaces superclass behavior
+ this(size, targetType, cvAttributes, false, null);
+ }
+
+ private PointerType(int size, Type targetType, int cvAttributes, boolean hasTypedefedName, String typedefedName) {
+ super(targetType.getName() + " *", size, cvAttributes);
+ this.hasTypedefedName = false;
+ this.targetType = targetType;
+ if (hasTypedefedName) {
+ setName(typedefedName);
+ }
+ }
+
+ public int hashCode() {
+ return targetType.hashCode();
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == this) return true;
+ if (arg == null || (!(arg instanceof PointerType))) {
+ return false;
+ }
+ PointerType t = (PointerType) arg;
+ // Note we ignore the name of this type (which might be a typedef
+ // name) for comparison purposes because this is what allows
+ // e.g. a newly-fabricated type "PIXELFORMATDESCRIPTOR *" to be
+ // canonicalized to e.g. "LPPIXELFORMATDESCRIPTOR"
+ return ((getSize() == t.getSize()) &&
+ (getCVAttributes() == t.getCVAttributes()) &&
+ targetType.equals(t.targetType));
+ }
+
+ public void setName(String name) {
+ super.setName(name);
+ hasTypedefedName = true;
+ }
+
+ public String getName(boolean includeCVAttrs) {
+ if (hasTypedefedName) {
+ return super.getName(includeCVAttrs);
+ } else {
+ // Lazy computation of name due to lazy setting of compound type
+ // names during parsing
+ if (computedName == null) {
+ computedName = targetType.getName(includeCVAttrs) + " *";
+ computedName = computedName.intern();
+ }
+ if (!includeCVAttrs) {
+ return computedName;
+ }
+ return targetType.getName(includeCVAttrs) + " * " + getCVAttributesString();
+ }
+ }
+
+ public PointerType asPointer() { return this; }
+
+ public Type getTargetType() { return targetType; }
+
+ public boolean isFunctionPointer() { return targetType.isFunction(); }
+
+ public String toString() {
+ if (hasTypedefedName) {
+ return super.getName(true);
+ } else {
+ if (!targetType.isFunction()) {
+ return targetType.toString() + " * " + getCVAttributesString();
+ }
+ return toString(null); // this is a pointer to an unnamed function
+ }
+ }
+
+ /** For use only when printing function pointers */
+ public String toString(String functionName) {
+ if (!targetType.isFunction()) {
+ throw new RuntimeException("<Internal error or misuse> This method is only for use when printing function pointers");
+ }
+ return ((FunctionType) targetType).toString(functionName, true);
+ }
+
+ public void visit(TypeVisitor arg) {
+ super.visit(arg);
+ targetType.visit(arg);
+ }
+
+ Type newCVVariant(int cvAttributes) {
+ return new PointerType(getSize(), targetType, cvAttributes, hasTypedefedName, (hasTypedefedName ? getName() : null));
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/PrimitiveType.java b/src/net/java/games/gluegen/cgram/types/PrimitiveType.java
new file mode 100644
index 000000000..7b41510df
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/PrimitiveType.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+public abstract class PrimitiveType extends Type {
+ protected PrimitiveType(String name, int size, int cvAttributes) {
+ super(name, size, cvAttributes);
+ }
+
+ public boolean isPrimitive() {
+ return true;
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/Type.java b/src/net/java/games/gluegen/cgram/types/Type.java
new file mode 100644
index 000000000..531393aa5
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/Type.java
@@ -0,0 +1,242 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+import java.util.List;
+
+/** Models a C type. Primitive types include int, float, and
+ double. All types have an associated name. Structs and unions are
+ modeled as "compound" types -- composed of fields of primitive or
+ other types. */
+
+public abstract class Type {
+ private String name;
+ private int size;
+ private int cvAttributes;
+ private int typedefedCVAttributes;
+ private boolean hasTypedefName;
+
+ protected Type(String name, int size, int cvAttributes) {
+ setName(name);
+ this.size = size;
+ this.cvAttributes = cvAttributes;
+ hasTypedefName = false;
+ }
+
+ /** Returns the name of this type. The returned string is suitable
+ for use as a type specifier. Does not include any const/volatile
+ attributes. */
+ public String getName() { return getName(false); }
+
+ /** Returns the name of this type, optionally including
+ const/volatile attributes. The returned string is suitable for
+ use as a type specifier. */
+ public String getName(boolean includeCVAttrs) {
+ if (!includeCVAttrs) {
+ return name;
+ }
+ return getCVAttributesString() + name;
+ }
+
+ /** Set the name of this type; used for handling typedefs. */
+ public void setName(String name) {
+ if (name == null) {
+ this.name = name;
+ } else {
+ this.name = name.intern();
+ }
+ // Capture the const/volatile attributes at the time of typedef so
+ // we don't redundantly repeat them in the CV attributes string
+ typedefedCVAttributes = cvAttributes;
+ hasTypedefName = true;
+ }
+
+ /** Size of this type in bytes. */
+ public int getSize() { return size; }
+ /** Set the size of this type; only available for CompoundTypes. */
+ void setSize(int size) { this.size = size; }
+
+ /** Casts this to a BitType or returns null if not a BitType. */
+ public BitType asBit() { return null; }
+ /** Casts this to an IntType or returns null if not an IntType. */
+ public IntType asInt() { return null; }
+ /** Casts this to an EnumType or returns null if not an EnumType. */
+ public EnumType asEnum() { return null; }
+ /** Casts this to a FloatType or returns null if not a FloatType. */
+ public FloatType asFloat() { return null; }
+ /** Casts this to a DoubleType or returns null if not a DoubleType. */
+ public DoubleType asDouble() { return null; }
+ /** Casts this to a PointerType or returns null if not a PointerType. */
+ public PointerType asPointer() { return null; }
+ /** Casts this to an ArrayType or returns null if not an ArrayType. */
+ public ArrayType asArray() { return null; }
+ /** Casts this to a CompoundType or returns null if not a CompoundType. */
+ public CompoundType asCompound() { return null; }
+ /** Casts this to a FunctionType or returns null if not a FunctionType. */
+ public FunctionType asFunction() { return null; }
+ /** Casts this to a VoidType or returns null if not a VoidType. */
+ public VoidType asVoid() { return null; }
+
+ /** Indicates whether this is a BitType. */
+ public boolean isBit() { return (asBit() != null); }
+ /** Indicates whether this is an IntType. */
+ public boolean isInt() { return (asInt() != null); }
+ /** Indicates whether this is an EnumType. */
+ public boolean isEnum() { return (asEnum() != null); }
+ /** Indicates whether this is a FloatType. */
+ public boolean isFloat() { return (asFloat() != null); }
+ /** Indicates whether this is a DoubleType. */
+ public boolean isDouble() { return (asDouble() != null); }
+ /** Indicates whether this is a PointerType. */
+ public boolean isPointer() { return (asPointer() != null); }
+ /** Indicates whether this is an ArrayType. */
+ public boolean isArray() { return (asArray() != null); }
+ /** Indicates whether this is a CompoundType. */
+ public boolean isCompound() { return (asCompound() != null); }
+ /** Indicates whether this is a FunctionType. */
+ public boolean isFunction() { return (asFunction() != null); }
+ /** Indicates whether this is a VoidType. */
+ public boolean isVoid() { return (asVoid() != null); }
+
+ /** Indicates whether this type is const. */
+ public boolean isConst() { return (((cvAttributes & ~typedefedCVAttributes) & CVAttributes.CONST) != 0); }
+ /** Indicates whether this type is volatile. */
+ public boolean isVolatile() { return (((cvAttributes & ~typedefedCVAttributes) & CVAttributes.VOLATILE) != 0); }
+
+ /** Indicates whether this type is a primitive type. */
+ public boolean isPrimitive(){ return false; }
+
+ /** Convenience routine indicating whether this Type is a pointer to
+ a function. */
+ public boolean isFunctionPointer() {
+ return (isPointer() && asPointer().getTargetType().isFunction());
+ }
+
+ /** Hashcode for Types. */
+ public int hashCode() {
+ if (name == null) {
+ return 0;
+ }
+
+ if (cvAttributes != 0)
+ {
+ String nameWithAttribs = name + cvAttributes;
+ return nameWithAttribs.hashCode();
+ }
+ return name.hashCode();
+ }
+
+ /**
+ * Equality test for Types.
+ */
+ public boolean equals(Object arg) {
+ if (arg == this) {
+ return true;
+ }
+ if (arg == null || (!(arg instanceof Type))) {
+ return false;
+ }
+ Type t = (Type) arg;
+ return ((name == t.name || (name != null && name.equals(name))) &&
+ (size == t.size) &&
+ (cvAttributes == t.cvAttributes));
+ }
+
+ /** Returns a string representation of this type. This string is not
+ necessarily suitable for use as a type specifier; for example,
+ it will contain an expanded description of structs/unions. */
+ public String toString() {
+ return getName(true);
+ }
+
+ /** Visit this type and all of the component types of this one; for
+ example, the return type and argument types of a FunctionType. */
+ public void visit(TypeVisitor visitor) {
+ visitor.visitType(this);
+ }
+
+ public final int getCVAttributes() {
+ return cvAttributes;
+ }
+
+ /** Returns a string indicating the const/volatile attributes of
+ this type. */
+ public final String getCVAttributesString() {
+ if (isConst() && isVolatile()) return "const volatile ";
+ if (isConst()) return "const ";
+ if (isVolatile()) return "volatile ";
+ return "";
+ }
+
+ /** Return a variant of this type matching the given const/volatile
+ attributes. May return this object if the attributes match. */
+ public final Type getCVVariant(int cvAttributes) {
+ if (this.cvAttributes == cvAttributes) {
+ return this;
+ }
+ return newCVVariant(cvAttributes);
+ }
+
+ /** Create a new variant of this type matching the given
+ const/volatile attributes. */
+ abstract Type newCVVariant(int cvAttributes);
+
+ /** Indicates whether setName() has been called on this type,
+ indicating that it already has a typedef name. */
+ public boolean hasTypedefName() {
+ return hasTypedefName;
+ }
+
+ /** Helper method for determining how many pointer indirections this
+ type represents (i.e., "void **" returns 2). */
+ public int pointerDepth() {
+ PointerType pt = asPointer();
+ if (pt == null) {
+ return 0;
+ }
+ return 1 + pt.getTargetType().pointerDepth();
+ }
+
+ /** Helper routine for list equality comparison */
+ static boolean listsEqual(List a, List b) {
+ return ((a == null && b == null) ||
+ (a != null && b != null && a.equals(b)));
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/TypeDictionary.java b/src/net/java/games/gluegen/cgram/types/TypeDictionary.java
new file mode 100644
index 000000000..bbf69b3c9
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/TypeDictionary.java
@@ -0,0 +1,169 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+import java.util.*;
+
+/** Utility class for recording names of typedefs and structs. */
+
+public class TypeDictionary {
+ /** Mapping from type name to type.*/
+ private HashMap/*<String, Type>*/ map = new HashMap/*<String, Type>*/();
+
+ /** Reverse mapping; created lazily from the regular map */
+ private HashMap/*<Set<Type>, String>*/ reverseMap = new HashMap/*<Set<Type>, String>*/();
+
+ /** Has a type been added/removed since the last time the reverse map was
+ * calculated? */
+ private boolean reverseMapOutOfDate = false;
+
+ /**
+ * Create a mapping from a type to its name.
+ * @param name the name to which the type is defined
+ * @param type the type that can be referred to by the specified name.
+ */
+ public Type put(String name, Type type) {
+ reverseMapOutOfDate = true;
+ return (Type) map.put(name, type);
+ }
+
+ /** Get the type corresponding to the given name. Returns null if no type
+ * was found corresponding to the given name. */
+ public Type get(String name) {
+ return (Type) map.get(name);
+ }
+
+ /**
+ * Get the names that correspond to the given type. There will be more than
+ * one name in the returned list if the type has been defined to multiple
+ * names. Returns null if no names were found for given type.
+ */
+ public Set/*<String>*/ get(Type type) {
+ if (reverseMapOutOfDate) {
+ rebuildReverseMap();
+ reverseMapOutOfDate = false;
+ }
+ // Don't let callers muck with the set.
+ return Collections.unmodifiableSet((Set)reverseMap.get(type));
+ }
+
+ /** Remove the mapping from the specified name to its associated type.*/
+ public Type remove(String name) {
+ reverseMapOutOfDate = true;
+ return (Type) map.remove(name);
+ }
+
+ /** Get all the names that map to Types.
+ * @returns a Set of Strings that are the typedef names that map to Types in the dictionary.
+ */
+ public Set keySet() {
+ return map.keySet();
+ }
+
+ public Set entrySet() {
+ return map.entrySet();
+ }
+
+ public boolean containsKey(String key) {
+ return map.containsKey(key);
+ }
+
+ public boolean containsValue(Type value) {
+ return map.containsValue(value);
+ }
+
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /** Returns a collection of all the Types in the dictionary that are mapped via typedefs names. */
+ public Collection values() {
+ return map.values();
+ }
+
+ /** Build the mapping of from each Type to all the names by which is may be
+ * referenced. Warning: this is a slow operation!
+ */
+ private void rebuildReverseMap() {
+ reverseMap.clear();
+ for (Iterator/*<String>*/ it = map.keySet().iterator(); it.hasNext(); ) {
+ String name = (String)it.next();
+ Type type = (Type)map.get(name);
+ if (type == null) {
+ throw new IllegalStateException("Internal error; TypedefDictionary contains null Type for name \"" + name + "\"");
+ }
+ HashSet allNamesForType = (HashSet)reverseMap.get(type);
+ if (allNamesForType == null) {
+ allNamesForType = new HashSet/*<String>*/();
+ reverseMap.put(type, allNamesForType);
+ }
+ allNamesForType.add(name);
+ }
+ }
+
+ /**
+ * Dumps the dictionary contents to the specified output stream, annotated
+ * with the specified description. Useful for debugging.
+ */
+ public void dumpDictionary(java.io.PrintStream out, String description) {
+ out.println("------------------------------------------------------------------------------");
+ out.println("TypeDictionary: " + (description == null ? "" : description));
+ out.println("------------------------------------------------------------------------------");
+ out.println("Forward mapping: ");
+ for (Iterator names = keySet().iterator(); names.hasNext(); ) {
+ String typeName = (String)names.next();
+ out.println(" [" + typeName + "]\t--> [" + get(typeName) + "]");
+ }
+ out.println("Reverse mapping: ");
+
+ // because the reverse mapping is built lazily upon query, we must force it to
+ // be built if it has not yet been built.
+ if (reverseMapOutOfDate) {
+ rebuildReverseMap();
+ reverseMapOutOfDate = false;
+ }
+ for (Iterator types = reverseMap.keySet().iterator(); types.hasNext(); ) {
+ Type type = (Type)types.next();
+ Set names = get(type);
+ out.println(" [" + type + "]\t--> " + names + "");
+ }
+ out.println("------------------------------------------------------------------------------");
+ }
+}
diff --git a/src/net/java/games/gluegen/cgram/types/TypeVisitor.java b/src/net/java/games/gluegen/cgram/types/TypeVisitor.java
new file mode 100644
index 000000000..e0bc57ed4
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/TypeVisitor.java
@@ -0,0 +1,44 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+public interface TypeVisitor {
+ public void visitType(Type t);
+}
diff --git a/src/net/java/games/gluegen/cgram/types/VoidType.java b/src/net/java/games/gluegen/cgram/types/VoidType.java
new file mode 100644
index 000000000..948c156c0
--- /dev/null
+++ b/src/net/java/games/gluegen/cgram/types/VoidType.java
@@ -0,0 +1,56 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.cgram.types;
+
+public class VoidType extends Type {
+ public VoidType(int cvAttributes) {
+ this("void", cvAttributes);
+ }
+
+ private VoidType(String name, int cvAttributes) {
+ super(name, 0, cvAttributes);
+ }
+
+ public VoidType asVoid() { return this; }
+
+ Type newCVVariant(int cvAttributes) {
+ return new VoidType(getName(), cvAttributes);
+ }
+}
diff --git a/src/net/java/games/gluegen/opengl/BuildComposablePipeline.java b/src/net/java/games/gluegen/opengl/BuildComposablePipeline.java
new file mode 100644
index 000000000..90ec97113
--- /dev/null
+++ b/src/net/java/games/gluegen/opengl/BuildComposablePipeline.java
@@ -0,0 +1,498 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.opengl;
+
+import net.java.games.gluegen.*;
+
+import java.lang.reflect.*;
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+public class BuildComposablePipeline
+{
+ private String outputDirectory;
+ private Class classToComposeAround;
+
+ public static void main(String[] args)
+ {
+ String nameOfClassToComposeAround = args[0];
+ Class classToComposeAround;
+ try {
+ classToComposeAround = Class.forName(nameOfClassToComposeAround);
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Could not find class \"" + nameOfClassToComposeAround + "\"", e);
+ }
+
+ String outputDir = args[1];
+
+ BuildComposablePipeline composer =
+ new BuildComposablePipeline(classToComposeAround, outputDir);
+
+ try
+ {
+ composer.emit();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(
+ "Error generating composable pipeline source files", e);
+ }
+ }
+
+ protected BuildComposablePipeline(Class classToComposeAround, String outputDirectory)
+ {
+ this.outputDirectory = outputDirectory;
+ this.classToComposeAround = classToComposeAround;
+
+ if (! classToComposeAround.isInterface())
+ {
+ throw new IllegalArgumentException(
+ classToComposeAround.getName() + " is not an interface class");
+ }
+ }
+
+ /**
+ * Emit the java source code for the classes that comprise the composable
+ * pipeline.
+ */
+ public void emit() throws IOException
+ {
+ String pDir = outputDirectory;
+ String pInterface = classToComposeAround.getName();
+ List/*<Method>*/ publicMethods = Arrays.asList(classToComposeAround.getMethods());
+
+ (new DebugPipeline(pDir, pInterface)).emit(publicMethods);
+ (new TracePipeline(pDir, pInterface)).emit(publicMethods);
+ }
+
+ //-------------------------------------------------------
+
+ /**
+ * Emits a Java source file that represents one element of the composable
+ * pipeline.
+ */
+ protected static abstract class PipelineEmitter
+ {
+ private File file;
+ private String basePackage;
+ private String baseName; // does not include package!
+ private String outputDir;
+
+ /**
+ * @param outputDir the directory into which the pipeline classes will be
+ * generated.
+ * @param baseInterfaceClassName the full class name (including package,
+ * e.g. "java.lang.String") of the interface that the pipeline wraps
+ * @exception IllegalArgumentException if classToComposeAround is not an
+ * interface.
+ */
+ public PipelineEmitter(String outputDir, String baseInterfaceClassName)
+ {
+ int lastDot = baseInterfaceClassName.lastIndexOf('.');
+ if (lastDot == -1)
+ {
+ // no package, class is at root level
+ this.baseName = baseInterfaceClassName;
+ this.basePackage = null;
+ }
+ else
+ {
+ this.baseName = baseInterfaceClassName.substring(lastDot+1);
+ this.basePackage = baseInterfaceClassName.substring(0, lastDot);
+ }
+
+ this.outputDir = outputDir;
+ }
+
+ public void emit(List/*<Method>*/ methodsToWrap) throws IOException
+ {
+ String pipelineClassName = getPipelineName();
+ this.file = new File(outputDir + File.separatorChar + pipelineClassName + ".java");
+ String parentDir = file.getParent();
+ if (parentDir != null)
+ {
+ File pDirFile = new File(parentDir);
+ pDirFile.mkdirs();
+ }
+
+ PrintWriter output = new PrintWriter(new BufferedWriter(new FileWriter(file)));
+
+ CodeGenUtils.emitJavaHeaders(output,
+ basePackage,
+ pipelineClassName,
+ true,
+ new String[] { "java.io.*" },
+ new String[] { "public" },
+ new String[] { baseName },
+ null,
+ new CodeGenUtils.EmissionCallback() {
+ public void emit(PrintWriter w) { emitClassDocComment(w); }
+ }
+ );
+
+ preMethodEmissionHook(output);
+
+ constructorHook(output);
+
+ for (int i = 0; i < methodsToWrap.size(); ++i)
+ {
+ Method m = (Method)methodsToWrap.get(i);
+ emitMethodDocComment(output, m);
+ emitSignature(output, m);
+ emitBody(output, m);
+ }
+
+ postMethodEmissionHook(output);
+
+ output.println();
+ output.print(" private " + baseName + " " + getDownstreamObjectName() + ";");
+
+ // end the class
+ output.println();
+ output.print("} // end class ");
+ output.println(pipelineClassName);
+
+ output.flush();
+ output.close();
+ }
+
+ /** Get the name of the object through which API calls should be routed. */
+ protected String getDownstreamObjectName()
+ {
+ return "downstream" + baseName;
+ }
+
+ protected void emitMethodDocComment(PrintWriter output, Method m)
+ {
+ }
+
+ protected void emitSignature(PrintWriter output, Method m)
+ {
+ output.print(" public ");
+ output.print(' ');
+ output.print(m.getReturnType().getName());
+ output.print(' ');
+ output.print(m.getName());
+ output.print('(');
+ output.print(getArgListAsString(m, true, true));
+ output.println(")");
+ }
+
+ protected void emitBody(PrintWriter output, Method m)
+ {
+ output.println(" {");
+ output.print(" ");
+ Class retType = m.getReturnType();
+
+ preDownstreamCallHook(output, m);
+
+ if (retType != Void.TYPE)
+ {
+ output.print(JavaType.createForClass(retType).getName());
+ output.print(" _res = ");
+ }
+ output.print(getDownstreamObjectName());
+ output.print('.');
+ output.print(m.getName());
+ output.print('(');
+ output.print(getArgListAsString(m, false, true));
+ output.println(");");
+
+ postDownstreamCallHook(output, m);
+
+ if (retType != Void.TYPE)
+ {
+ output.println(" return _res;");
+ }
+ output.println(" }");
+
+ }
+
+ private String getArgListAsString(Method m, boolean includeArgTypes, boolean includeArgNames)
+ {
+ StringBuffer buf = new StringBuffer(256);
+ if (!includeArgNames && !includeArgTypes)
+ {
+ throw new IllegalArgumentException(
+ "Cannot generate arglist without both arg types and arg names");
+ }
+
+ Class[] argTypes = m.getParameterTypes();
+ for (int i = 0; i < argTypes.length; ++i)
+ {
+ if (includeArgTypes)
+ {
+ buf.append(JavaType.createForClass(argTypes[i]).getName());
+ buf.append(' ');
+ }
+
+ if (includeArgNames)
+ {
+ buf.append("arg");
+ buf.append(i);
+ }
+ if (i < argTypes.length-1) { buf.append(','); }
+ }
+
+ return buf.toString();
+ }
+
+ /** The name of the class around which this pipeline is being
+ * composed. E.g., if this pipeline was constructed with
+ * "java.util.Set" as the baseInterfaceClassName, then this method will
+ * return "Set".
+ */
+ protected String getBaseInterfaceName()
+ {
+ return baseName;
+ }
+
+ /** Get the name for this pipeline class. */
+ protected abstract String getPipelineName();
+
+ /**
+ * Called after the class headers have been generated, but before any
+ * method wrappers have been generated.
+ */
+ protected abstract void preMethodEmissionHook(PrintWriter output);
+
+ /**
+ * Emits the constructor for the pipeline; called after the preMethodEmissionHook.
+ */
+ protected void constructorHook(PrintWriter output) {
+ output.print( " public " + getPipelineName() + "(" + baseName + " ");
+ output.println(getDownstreamObjectName() + ")");
+ output.println(" {");
+ output.print( " this." + getDownstreamObjectName());
+ output.println(" = " + getDownstreamObjectName() + ";");
+ output.println(" }");
+ output.println();
+ }
+
+ /**
+ * Called after the method wrappers have been generated, but before the
+ * closing parenthesis of the class is emitted.
+ */
+ protected abstract void postMethodEmissionHook(PrintWriter output);
+
+ /**
+ * Called before the pipeline routes the call to the downstream object.
+ */
+ protected abstract void preDownstreamCallHook(PrintWriter output, Method m);
+
+ /**
+ * Called after the pipeline has routed the call to the downstream object,
+ * but before the calling function exits or returns a value.
+ */
+ protected abstract void postDownstreamCallHook(PrintWriter output, Method m);
+
+ /** Emit a Javadoc comment for this pipeline class. */
+ protected abstract void emitClassDocComment(PrintWriter output);
+
+ } // end class PipelineEmitter
+
+ //-------------------------------------------------------
+
+ protected class DebugPipeline extends PipelineEmitter
+ {
+ String className;
+ String baseInterfaceClassName;
+ public DebugPipeline(String outputDir, String baseInterfaceClassName)
+ {
+ super(outputDir, baseInterfaceClassName);
+ className = "Debug" + getBaseInterfaceName();
+ }
+
+ protected String getPipelineName()
+ {
+ return className;
+ }
+
+ protected void preMethodEmissionHook(PrintWriter output)
+ {
+ }
+
+ protected void postMethodEmissionHook(PrintWriter output)
+ {
+ output.println(" private void checkGLGetError(String caller)");
+ output.println(" {");
+ output.println(" // Debug code to make sure the pipeline is working; leave commented out unless testing this class");
+ output.println(" //System.err.println(\"Checking for GL errors " +
+ "after call to \" + caller + \"()\");");
+ output.println();
+ output.println(" int err = " +
+ getDownstreamObjectName() +
+ ".glGetError();");
+ output.println(" if (err == GL_NO_ERROR) { return; }");
+ output.println();
+ output.println(" StringBuffer buf = new StringBuffer(");
+ output.println(" \"glGetError() returned the following error codes " +
+ "after a call to \" + caller + \"(): \");");
+ output.println();
+ output.println(" // Loop repeatedly to allow for distributed GL implementations,");
+ output.println(" // as detailed in the glGetError() specification");
+ output.println(" do {");
+ output.println(" switch (err) {");
+ output.println(" case GL_INVALID_ENUM: buf.append(\"GL_INVALID_ENUM \"); break;");
+ output.println(" case GL_INVALID_VALUE: buf.append(\"GL_INVALID_VALUE \"); break;");
+ output.println(" case GL_INVALID_OPERATION: buf.append(\"GL_INVALID_OPERATION \"); break;");
+ output.println(" case GL_STACK_OVERFLOW: buf.append(\"GL_STACK_OVERFLOW \"); break;");
+ output.println(" case GL_STACK_UNDERFLOW: buf.append(\"GL_STACK_UNDERFLOW \"); break;");
+ output.println(" case GL_OUT_OF_MEMORY: buf.append(\"GL_OUT_OF_MEMORY \"); break;");
+ output.println(" case GL_NO_ERROR: throw new InternalError(\"Should not be treating GL_NO_ERROR as error\");");
+ output.println(" default: throw new InternalError(\"Unknown glGetError() return value: \" + err);");
+ output.println(" }");
+ output.println( " } while ((err = " +
+ getDownstreamObjectName() +
+ ".glGetError()) != GL_NO_ERROR);");
+ output.println(" throw new GLException(buf.toString());");
+ output.println(" }");
+
+ output.println(" /** True if the pipeline is inside a glBegin/glEnd pair.*/");
+ output.println(" private boolean insideBeginEndPair = false;");
+ output.println();
+
+ }
+ protected void emitClassDocComment(PrintWriter output)
+ {
+ output.println("/** <P> Composable pipline which wraps an underlying {@link GL} implementation,");
+ output.println(" providing error checking after each OpenGL method call. If an error occurs,");
+ output.println(" causes a {@link GLException} to be thrown at exactly the point of failure.");
+ output.println(" Sample code which installs this pipeline: </P>");
+ output.println();
+ output.println("<PRE>");
+ output.println(" drawable.setGL(new DebugGL(drawable.getGL()));");
+ output.println("</PRE>");
+ output.println("*/");
+ }
+
+ protected void preDownstreamCallHook(PrintWriter output, Method m)
+ {
+ }
+
+ protected void postDownstreamCallHook(PrintWriter output, Method m)
+ {
+ if (m.getName().equals("glBegin"))
+ {
+ output.println(" insideBeginEndPair = true;");
+ output.println(" // NOTE: can't check glGetError(); it's not allowed inside glBegin/glEnd pair");
+ }
+ else
+ {
+ if (m.getName().equals("glEnd"))
+ {
+ output.println(" insideBeginEndPair = false;");
+ }
+
+ // calls to glGetError() are only allowed outside of glBegin/glEnd pairs
+ output.println(" checkGLGetError(\"" + m.getName() + "\");");
+ }
+ }
+
+ } // end class DebugPipeline
+
+ //-------------------------------------------------------
+
+ protected class TracePipeline extends PipelineEmitter
+ {
+ String className;
+ String baseInterfaceClassName;
+ public TracePipeline(String outputDir, String baseInterfaceClassName)
+ {
+ super(outputDir, baseInterfaceClassName);
+ className = "Trace" + getBaseInterfaceName();
+ }
+
+ protected String getPipelineName()
+ {
+ return className;
+ }
+
+ protected void preMethodEmissionHook(PrintWriter output)
+ {
+ }
+
+ protected void constructorHook(PrintWriter output) {
+ output.print( " public " + getPipelineName() + "(" + getBaseInterfaceName() + " ");
+ output.println(getDownstreamObjectName() + ", PrintStream " + getOutputStreamName() + ")");
+ output.println(" {");
+ output.print( " this." + getDownstreamObjectName());
+ output.println(" = " + getDownstreamObjectName() + ";");
+ output.print( " this." + getOutputStreamName());
+ output.println(" = " + getOutputStreamName() + ";");
+ output.println(" }");
+ output.println();
+ }
+
+ protected void postMethodEmissionHook(PrintWriter output)
+ {
+ output.println("private PrintStream " + getOutputStreamName() + ";");
+ }
+ protected void emitClassDocComment(PrintWriter output)
+ {
+ output.println("/** <P> Composable pipline which wraps an underlying {@link GL} implementation,");
+ output.println(" providing tracing information to a user-specified {@link java.io.PrintStream}");
+ output.println(" before after each OpenGL method call. Sample code which installs this pipeline: </P>");
+ output.println();
+ output.println("<PRE>");
+ output.println(" drawable.setGL(new TraceGL(drawable.getGL(), System.err));");
+ output.println("</PRE>");
+ output.println("*/");
+ }
+
+ protected void preDownstreamCallHook(PrintWriter output, Method m)
+ {
+ output.println(getOutputStreamName() + ".println(\"Entered " + m.getName() + "\");");
+ output.print(" ");
+ }
+
+ protected void postDownstreamCallHook(PrintWriter output, Method m)
+ {
+ output.println(" " + getOutputStreamName() + ".println(\"Exited " + m.getName() + "\");");
+ }
+
+ private String getOutputStreamName() {
+ return "stream";
+ }
+
+ } // end class TracePipeline
+}
diff --git a/src/net/java/games/gluegen/opengl/BuildStaticGLInfo.java b/src/net/java/games/gluegen/opengl/BuildStaticGLInfo.java
new file mode 100644
index 000000000..ed0c83445
--- /dev/null
+++ b/src/net/java/games/gluegen/opengl/BuildStaticGLInfo.java
@@ -0,0 +1,258 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.opengl;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+ /**
+ * Builds the StaticGLInfo class from the OpenGL header files (i.e., gl.h
+ * and glext.h) whose paths were passed as arguments to {@link
+ * #main(String[])}.
+ *
+ * It relies upon the assumption that a function's membership is scoped by
+ * preprocessor blocks in the header files that match the following pattern:
+ * <br>
+ *
+ * <pre>
+ *
+ * #ifndef GL_XXXX
+ * GLAPI <returnType> <APIENTRY|GLAPIENTRY> glFuncName(<params>)
+ * #endif GL_XXXX
+ *
+ * </pre>
+ *
+ * For example, if it parses the following data:
+ *
+ * <pre>
+ *
+ * #ifndef GL_VERSION_1_3
+ * GLAPI void APIENTRY glActiveTexture (GLenum);
+ * GLAPI void APIENTRY glMultiTexCoord1dv (GLenum, const GLdouble *);
+ * GLAPI void <APIENTRY|GLAPIENTRY> glFuncName(<params>)
+ * #endif GL_VERSION_1_3
+ *
+ * #ifndef GL_ARB_texture_compression
+ * GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+ * GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+ * #endif
+ *
+ * </pre>
+ *
+ * It will associate
+ * <code> glActiveTexture </code> and
+ * <code> glMultiTexCoord1dv </code>
+ * with the symbol
+ * <code> GL_VERSION_1_3 </code>,
+ * and associate
+ * <code> glCompressedTexImage2DARB </code> and
+ * <code> glCompressedTexImage3DARB </code>
+ * with the symbol
+ * <code> GL_ARB_texture_compression </code>.
+ * */
+public class BuildStaticGLInfo
+{
+ protected static Pattern funcPattern =
+ Pattern.compile("^(GLAPI|extern)?(\\s*)(\\w+)(\\*)?(\\s+)(APIENTRY|WINAPI)?(\\s*)([w]?gl\\w+)\\s?(\\(.*)");
+ protected static Pattern associationPattern =
+ Pattern.compile("\\#ifndef ([W]?GL[X]?_[A-Za-z0-9_]+)");
+
+ /**
+ * The first argument is the package to which the StaticGLInfo class
+ * belongs, the second is the path to the directory in which that package's
+ * classes reside, and the remaining arguments are paths to the C header
+ * files that should be parsed
+ */
+ public static void main(String[] args)
+ {
+ String packageName = args[0];
+ String packageDir = args[1];
+
+ String[] cHeaderFilePaths = new String[args.length-2];
+ System.arraycopy(args, 2, cHeaderFilePaths, 0, cHeaderFilePaths.length);
+
+ BuildStaticGLInfo builder = new BuildStaticGLInfo();
+ try
+ {
+ File file = new File(packageDir + File.separatorChar + "StaticGLInfo.java");
+ String parentDir = file.getParent();
+ if (parentDir != null)
+ {
+ File pDirFile = new File(parentDir);
+ pDirFile.mkdirs();
+ }
+
+ PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(file)));
+ builder.build(writer, packageName, cHeaderFilePaths);
+
+ writer.flush();
+ writer.close();
+ }
+ catch (Exception e)
+ {
+ StringBuffer buf = new StringBuffer("{ ");
+ for (int i = 0; i < cHeaderFilePaths.length; ++i)
+ {
+ buf.append(cHeaderFilePaths[i]);
+ buf.append(" ");
+ }
+ buf.append('}');
+ throw new RuntimeException(
+ "Error building StaticGLInfo.java from " + buf.toString(), e);
+ }
+ }
+
+ protected void build(PrintWriter output, String packageName, String[] cHeaderFilePaths) throws IOException
+ {
+ HashMap groupToFuncHash = new HashMap(50);
+ for (int i = 0; i < cHeaderFilePaths.length; ++i)
+ {
+ process(groupToFuncHash, new FileReader(cHeaderFilePaths[i]));
+ }
+
+ emitJavaCode(output, packageName, groupToFuncHash);
+ }
+
+ protected void process(HashMap groupToFuncHash, FileReader headerFile) throws IOException
+ {
+ BufferedReader reader = new BufferedReader(headerFile);
+ String line, activeAssociation = null;
+ Matcher m;
+ while ((line = reader.readLine()) != null)
+ {
+ // see if we're inside a #ifndef GL_XXX block and matching a function
+ if (activeAssociation != null && (m = funcPattern.matcher(line)).matches())
+ {
+ // We found a new function associated with the last #ifndef block we
+ // were associated with
+
+ String funcName = m.group(8);
+ HashSet funcsForGroup = (HashSet)groupToFuncHash.get(activeAssociation);
+ if (funcsForGroup == null)
+ {
+ funcsForGroup = new HashSet(8);
+ groupToFuncHash.put(activeAssociation, funcsForGroup);
+ }
+ funcsForGroup.add(funcName);
+
+ //System.err.println("FOUND ASSOCIATION FOR " + activeAssociation + ": " + funcName);
+ }
+ else if ((m = associationPattern.matcher(line)).matches())
+ {
+ // found a new #ifndef GL_XXX block
+ activeAssociation = m.group(1);
+
+ //System.err.println("FOUND NEW ASSOCIATION BLOCK: " + activeAssociation);
+ }
+ }
+ }
+
+ protected void emitJavaCode(PrintWriter output, String packageName, HashMap groupToFuncHash)
+ {
+ output.println("package " + packageName + ";");
+ output.println();
+ output.println("import java.util.*;");
+ output.println();
+ output.println("public final class StaticGLInfo");
+ output.println("{");
+
+ output.println(" // maps function names to the extension string or OpenGL");
+ output.println(" // specification version string to which they correspond.");
+ output.println(" private static HashMap funcToAssocMap = null;");
+ output.println();
+
+ output.println(" /**");
+ output.println(" * Returns the OpenGL extension string or GL_VERSION string with which the");
+ output.println(" * given function is associated. <P>");
+ output.println(" *");
+ output.println(" * If the");
+ output.println(" * function is part of the OpenGL core, the returned value will be");
+ output.println(" * GL_VERSION_XXX where XXX represents the OpenGL version of which the");
+ output.println(" * function is a member (XXX will be of the form \"A\" or \"A_B\" or \"A_B_C\";");
+ output.println(" * e.g., GL_VERSION_1_2_1 for OpenGL version 1.2.1).");
+ output.println(" *");
+ output.println(" * If the function is an extension function, the returned value will the");
+ output.println(" * OpenGL extension string for the extension to which the function");
+ output.println(" * corresponds. For example, if glLoadTransposeMatrixfARB is the argument,");
+ output.println(" * GL_ARB_transpose_matrix will be the value returned.");
+ output.println(" * Please see http://oss.sgi.com/projects/ogl-sample/registry/index.html for");
+ output.println(" * a list of extension names and the functions they expose.");
+ output.println(" *");
+ output.println(" * If the function specified is not part of any known OpenGL core version or");
+ output.println(" * extension, then NULL will be returned.");
+ output.println(" */");
+ output.println(" public static String getFunctionAssociation(String glFunctionName)");
+ output.println(" {");
+ output.println(" if (funcToAssocMap == null) { init(); }");
+ output.println(" return (String)funcToAssocMap.get(glFunctionName);");
+ output.println(" }");
+ output.println();
+
+ output.println(" private static void init()");
+ output.println(" {");
+ output.println(" funcToAssocMap = new HashMap(1536); // approximate max capacity");
+ output.println(" String group;");
+ ArrayList sets = new ArrayList(groupToFuncHash.keySet());
+ Collections.sort(sets);
+ for (int i = 0; i < sets.size(); ++i)
+ {
+ String groupName = (String) sets.get(i);
+ //System.err.println(groupName); // debug
+ output.println();
+ output.println(" //----------------------------------------------------------------");
+ output.println(" // " + groupName);
+ output.println(" //----------------------------------------------------------------");
+ output.println(" group = \"" + groupName + "\";");
+ HashSet funcs = (HashSet)groupToFuncHash.get(groupName);
+ Iterator funcIter = funcs.iterator();
+ while (funcIter.hasNext())
+ {
+ String funcName = (String)funcIter.next();
+ //System.err.println(" " + funcName); // debug
+ output.println(" funcToAssocMap.put(\"" + funcName + "\", group);");
+ }
+ }
+ output.println(" }");
+
+ output.println("} // end class StaticGLInfo");
+ }
+
+}
diff --git a/src/net/java/games/gluegen/opengl/CGLPAWrapperEmitter.java b/src/net/java/games/gluegen/opengl/CGLPAWrapperEmitter.java
new file mode 100644
index 000000000..cd0554dc3
--- /dev/null
+++ b/src/net/java/games/gluegen/opengl/CGLPAWrapperEmitter.java
@@ -0,0 +1,201 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.opengl;
+
+import java.io.*;
+import java.util.*;
+import net.java.games.gluegen.*;
+import net.java.games.gluegen.cgram.types.*;
+
+public class CGLPAWrapperEmitter extends CMethodBindingEmitter
+{
+ private static final CommentEmitter defaultCommentEmitter =
+ new CGLPAWrapperCommentEmitter();
+
+ private CMethodBindingEmitter emitterBeingWrapped;
+ private String glFuncPtrTypedefValue;
+ private static String procAddressJavaTypeName =
+ JavaType.createForClass(Long.TYPE).jniTypeName();
+
+ public CGLPAWrapperEmitter(CMethodBindingEmitter methodToWrap)
+ {
+ super(
+ new MethodBinding(methodToWrap.getBinding()) {
+ public String getName() {
+ return GLEmitter.WRAP_PREFIX + super.getName();
+ }
+ },
+ methodToWrap.getIsOverloadedBinding(),
+ methodToWrap.getJavaPackageName(),
+ methodToWrap.getJavaClassName(),
+ methodToWrap.getIsJavaMethodStatic(),
+ methodToWrap.getDefaultOutput()
+ );
+
+ setCommentEmitter(defaultCommentEmitter);
+ }
+
+ protected int emitArguments(PrintWriter writer)
+ {
+ int numEmitted = super.emitArguments(writer);
+ if (numEmitted > 0)
+ {
+ writer.print(", ");
+ }
+ //writer.print("long glProcAddress");
+ writer.print(procAddressJavaTypeName);
+ writer.print(" glProcAddress");
+ ++numEmitted;
+
+ return numEmitted;
+ }
+
+ protected void emitBodyVariableDeclarations(PrintWriter writer)
+ {
+ // create variable for the function pointer with the right type, and set
+ // it to the value of the passed-in glProcAddress
+ FunctionSymbol cSym = getBinding().getCSymbol();
+ String funcPointerTypedefName =
+ GLEmitter.getGLFunctionPointerTypedefName(cSym);
+
+ writer.print(" ");
+ writer.print(funcPointerTypedefName);
+ writer.print(" ptr_");
+ writer.print(cSym.getName());
+ writer.println(";");
+
+ super.emitBodyVariableDeclarations(writer);
+ }
+
+ protected void emitBodyVariablePreCallSetup(PrintWriter writer)
+ {
+ super.emitBodyVariablePreCallSetup(writer);
+
+ // set the function pointer to the value of the passed-in glProcAddress
+ FunctionSymbol cSym = getBinding().getCSymbol();
+ String funcPointerTypedefName =
+ GLEmitter.getGLFunctionPointerTypedefName(cSym);
+
+ String ptrVarName = "ptr_" + cSym.getName();
+
+ writer.print(" ");
+ writer.print(ptrVarName);
+ writer.print(" = (");
+ writer.print(funcPointerTypedefName);
+ writer.println(") (intptr_t) glProcAddress;");
+
+ writer.println(" assert(" + ptrVarName + " != NULL);");
+ }
+
+ // FIXME: refactor this and the superclass version so we don't have to copy
+ // the whole function
+ protected void emitBodyCallCFunction(PrintWriter writer)
+ {
+ // Make the call to the actual C function
+ writer.print(" ");
+
+ // WARNING: this code assumes that the return type has already been
+ // typedef-resolved.
+ Type cReturnType = getBinding().getCReturnType();
+
+ if (!cReturnType.isVoid()) {
+ writer.print("_res = ");
+ }
+
+ // !!!!!!!!! BEGIN CHANGES FROM SUPERCLASS METHOD
+
+ MethodBinding binding = getBinding();
+ if (binding.hasContainingType()) {
+ // Cannot call GL func through function pointer
+ throw new IllegalStateException(
+ "Cannot call GL func through function pointer: " + binding);
+ }
+
+ // call throught the run-time function pointer
+ writer.print("(* ptr_");
+ writer.print(binding.getCSymbol().getName());
+ writer.print(") ");
+
+ // !!!!!!!!! END CHANGES FROM SUPERCLASS METHOD
+
+
+ writer.print("(");
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ if (i != 0) {
+ writer.print(", ");
+ }
+ JavaType javaType = binding.getJavaArgumentType(i);
+ // Handle case where only param is void.
+ if (javaType.isVoid()) {
+ // Make sure this is the only param to the method; if it isn't,
+ // there's something wrong with our parsing of the headers.
+ assert(binding.getNumArguments() == 1);
+ continue;
+ }
+
+ if (javaType.isJNIEnv()) {
+ writer.print("env");
+ } else if (binding.isArgumentThisPointer(i)) {
+ writer.print(CMethodBindingEmitter.cThisArgumentName());
+ } else {
+ writer.print("(");
+ writer.print(binding.getCSymbol().getArgumentType(i).getName());
+ writer.print(") ");
+ if (binding.getCArgumentType(i).isPointer() && binding.getJavaArgumentType(i).isPrimitive()) {
+ writer.print("(intptr_t) ");
+ }
+ if (javaType.isArray() || javaType.isNIOBuffer()) {
+ writer.print(pointerConversionArgumentName(i));
+ } else {
+ if (javaType.isString()) { writer.print("_UTF8"); }
+ writer.print(binding.getArgumentName(i));
+ }
+ }
+ }
+ writer.println(");");
+ }
+
+ /** This class emits the comment for the wrapper method */
+ private static class CGLPAWrapperCommentEmitter extends CMethodBindingEmitter.DefaultCommentEmitter {
+ protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) {
+ writer.print(" -- FIXME: IMPLEMENT COMMENT FOR CGLPAWrapperCommentEmitter -- ");
+ }
+ }
+} // end class CGLPAWrapperEmitter
diff --git a/src/net/java/games/gluegen/opengl/ConvertFromGL4Java.java b/src/net/java/games/gluegen/opengl/ConvertFromGL4Java.java
new file mode 100644
index 000000000..c026dbd50
--- /dev/null
+++ b/src/net/java/games/gluegen/opengl/ConvertFromGL4Java.java
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.opengl;
+
+import java.io.*;
+
+public class ConvertFromGL4Java {
+ public static void main(String[] args) throws IOException {
+ for (int i = 0; i < args.length; i++) {
+ convert(new File(args[i]));
+ }
+ }
+
+ private static void convert(File src) throws IOException {
+ File orig = new File(src.getAbsolutePath() + ".orig");
+ if (!src.renameTo(orig)) {
+ throw new IOException("Error renaming original file to " + orig);
+ }
+ File dest = src;
+ BufferedReader reader = new BufferedReader(new FileReader(orig));
+ BufferedWriter writer = new BufferedWriter(new FileWriter(dest));
+ boolean handledImports = false;
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ String trimmed = line.trim();
+ boolean isImport = false;
+ if (trimmed.startsWith("import gl4java")) {
+ line = "import net.java.games.jogl.*;";
+ isImport = true;
+ }
+ if (!isImport ||
+ (isImport && !handledImports)) {
+ line = line.replaceAll("GLFunc14", "GL");
+ line = line.replaceAll("GLUFunc14", "GLU");
+ line = line.replaceAll("GLFunc", "GL");
+ line = line.replaceAll("GLUFunc", "GLU");
+ line = line.replaceAll("implements GLEnum,", "implements ");
+ line = line.replaceAll(", GLEnum\\s", " ");
+ line = line.replaceAll("GLEnum,", "");
+ line = line.replaceAll("GLEnum.", "");
+ line = line.replaceAll("GLEnum", "");
+ line = line.replaceAll("GL_", "GL.GL_");
+ writer.write(line);
+ writer.newLine();
+ if (isImport) {
+ handledImports = true;
+ }
+ }
+ }
+ writer.flush();
+ reader.close();
+ writer.close();
+ }
+}
diff --git a/src/net/java/games/gluegen/opengl/GLEmitter.java b/src/net/java/games/gluegen/opengl/GLEmitter.java
new file mode 100644
index 000000000..27cc07e2c
--- /dev/null
+++ b/src/net/java/games/gluegen/opengl/GLEmitter.java
@@ -0,0 +1,330 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.opengl;
+
+import java.io.*;
+import java.text.MessageFormat;
+import java.util.*;
+import net.java.games.gluegen.*;
+import net.java.games.gluegen.cgram.types.*;
+
+/**
+ * A subclass of JavaEmitter that modifies the normal emission of C and Java
+ * code in order to allow a high-performance, cross-platform binding of Java
+ * to OpenGL.
+ */
+public class GLEmitter extends JavaEmitter
+{
+ public static final String PROCADDRESS_VAR_PREFIX = "_addressof_";
+ protected static final String WRAP_PREFIX = "dispatch_";
+ private TypeDictionary typedefDictionary;
+ private PrintWriter tableWriter;
+ private String tableClassName = "ProcAddressTable";
+ private int numProcAddressEntries;
+
+ public void beginFunctions(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) throws Exception
+ {
+ this.typedefDictionary = typedefDictionary;
+
+ if (getConfig().emitImpl()) {
+ cWriter().println("#include <assert.h> /* this include emitted by GLEmitter.java */");
+ cWriter().println();
+ }
+
+ if (((GLConfiguration)getConfig()).emitProcAddressTable())
+ {
+ beginGLProcAddressTable();
+ }
+ super.beginFunctions(typedefDictionary, structDictionary, canonMap);
+ }
+
+ public void endFunctions() throws Exception
+ {
+ if (((GLConfiguration)getConfig()).emitProcAddressTable())
+ {
+ endGLProcAddressTable();
+ }
+ super.endFunctions();
+ }
+
+ public void beginStructs(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) throws Exception {
+ super.beginStructs(typedefDictionary, structDictionary, canonMap);
+ }
+
+ protected JavaConfiguration createConfig() {
+ return new GLConfiguration();
+ }
+
+ protected Iterator generateMethodBindingEmitters(FunctionSymbol sym) throws Exception
+ {
+ Iterator defaultEmitters = super.generateMethodBindingEmitters(sym);
+
+ // if the superclass didn't generate any bindings for the symbol, let's
+ // honor that (for example, the superclass might have caught an Ignore
+ // direction that matched the symbol's name).
+ if (!defaultEmitters.hasNext())
+ {
+ return defaultEmitters;
+ }
+
+ // Don't do anything special if this symbol doesn't require passing of
+ // Opengl procedure addresses in order to function correctly.
+ if (!needsProcAddressWrapper(sym) || getConfig().isUnimplemented(sym.getName()))
+ {
+ return defaultEmitters;
+ }
+
+ // 9 is default # expanded bindings for void*
+ ArrayList modifiedEmitters = new ArrayList(9);
+
+ if (((GLConfiguration)getConfig()).emitProcAddressTable())
+ {
+ // emit an entry in the GL proc address table for this method.
+ emitGLProcAddressTableEntryForSymbol(sym);
+ }
+
+ while (defaultEmitters.hasNext())
+ {
+ FunctionEmitter emitter = (FunctionEmitter)defaultEmitters.next();
+ if (emitter instanceof JavaMethodBindingEmitter)
+ {
+ JavaMethodBindingEmitter newEmitter =
+ generateModifiedEmitter((JavaMethodBindingEmitter)emitter);
+ if (newEmitter != null) {
+ modifiedEmitters.add(newEmitter);
+ }
+ }
+ else if (emitter instanceof CMethodBindingEmitter)
+ {
+ modifiedEmitters.add(
+ generateModifiedEmitter((CMethodBindingEmitter)emitter));
+ }
+ else
+ {
+ throw new RuntimeException("Unexpected emitter type: " +
+ emitter.getClass().getName());
+ }
+ }
+
+ return modifiedEmitters.iterator();
+ }
+
+ /**
+ * Returns the name of the typedef for a pointer to the GL function
+ * represented by the argument. For example, if the argument is the function
+ * "glFuncName", the value returned will be "PFNGLFUNCNAMEPROC". This
+ * returns a valid string regardless of whether or not the typedef is
+ * actually defined.
+ */
+ static String getGLFunctionPointerTypedefName(FunctionSymbol sym)
+ {
+ String symName = sym.getName();
+ StringBuffer buf = new StringBuffer(symName.length() + 8);
+ buf.append("PFN");
+ buf.append(symName.toUpperCase());
+ buf.append("PROC");
+ return buf.toString();
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private JavaMethodBindingEmitter generateModifiedEmitter(JavaMethodBindingEmitter baseJavaEmitter)
+ {
+ if (!(baseJavaEmitter instanceof JavaMethodBindingImplEmitter)) {
+ // We only want to wrap the native entry point in the implementation
+ // class, not the public interface in the interface class.
+ //
+ // If the superclass has generated a "0" emitter for this routine because
+ // it needs argument conversion or similar, filter that out since we will
+ // be providing such an emitter ourselves. Otherwise return the emitter
+ // unmodified.
+ if (baseJavaEmitter.isForNIOBufferBaseRoutine())
+ return null;
+ return baseJavaEmitter;
+ }
+ return new JavaGLPAWrapperEmitter(baseJavaEmitter);
+ }
+
+ private CMethodBindingEmitter generateModifiedEmitter(CMethodBindingEmitter baseCEmitter)
+ {
+ // The C-side JNI binding for this particular function will have an
+ // extra final argument, which is the address (the OpenGL procedure
+ // address) of the function it needs to call
+ CGLPAWrapperEmitter res = new CGLPAWrapperEmitter(baseCEmitter);
+ MessageFormat exp = baseCEmitter.getReturnValueCapacityExpression();
+ if (exp != null) {
+ res.setReturnValueCapacityExpression(exp);
+ }
+ return res;
+ }
+
+ private boolean needsProcAddressWrapper(FunctionSymbol sym)
+ {
+ String symName = sym.getName();
+
+ // We should only wrap the GL symbol if its function pointer typedef has
+ // been defined (most likely in glext.h).
+ String funcPointerTypedefName = getGLFunctionPointerTypedefName(sym);
+ boolean shouldWrap = typedefDictionary.containsKey(funcPointerTypedefName);
+ //System.err.println(funcPointerTypedefName + " defined: " + shouldWrap);
+
+ if (!shouldWrap)
+ {
+ //System.err.println("WARNING (GL): *not* run-time linking: " + sym +
+ // "(" + funcPointerTypedefName + " undefined)");
+ }
+ return shouldWrap;
+ }
+
+ private void beginGLProcAddressTable() throws Exception
+ {
+ String implPackageName = getImplPackageName();
+ String jImplRoot =
+ getJavaOutputDir() + File.separator +
+ CodeGenUtils.packageAsPath(implPackageName);
+
+ // HACK: until we have a way to make the impl dir different from the
+ // WindowsGLImpl dir and the interface dir
+ //tableWriter = openFile(jImplRoot + File.separator + tableClassName + ".java");
+ File tmpFile = new File(jImplRoot);
+ tmpFile = tmpFile.getParentFile();
+ tmpFile = new File(tmpFile, tableClassName + ".java");
+ tableWriter = openFile(tmpFile.getPath());
+ // tableWriter = openFile(jImplRoot + File.separator + ".." + File.separator + tableClassName + ".java");
+
+ CodeGenUtils.emitAutogeneratedWarning(tableWriter, this);
+
+ // HACK: until we have a way to make the impl dir different from the
+ // WindowsGLImpl dir and the interface dir
+ //tableWriter.println("package " + implPackageName + ";");
+ tableWriter.println("package " + getJavaPackageName() + ".impl;");
+ tableWriter.println();
+ tableWriter.println("/**");
+ tableWriter.println(" * This table is a cache of the native pointers to OpenGL extension");
+ tableWriter.println(" * functions, to be used for run-time linking of these extensions. ");
+ tableWriter.println(" * These pointers are obtained by the OpenGL context via a ");
+ tableWriter.println(" * platform-specific function (e.g., wglGetProcAddress() on Win32,");
+ tableWriter.println(" * glXGetProcAddress() on X11, etc). If the member variable ");
+ tableWriter.println(" * " + PROCADDRESS_VAR_PREFIX + "glFuncName is non-zero then function");
+ tableWriter.println(" * \"glFuncName\" can be called through the associated GLContext; ");
+ tableWriter.println(" * if it is 0, then the extension is not available and cannot be called.");
+ tableWriter.println(" */");
+ tableWriter.println("public class " + tableClassName);
+ tableWriter.println("{");
+ numProcAddressEntries = 0;
+ }
+
+ private void endGLProcAddressTable() throws Exception
+ {
+ PrintWriter w = tableWriter;
+ w.print(" protected static long __PROCADDRESSINDEX__LASTINDEX = ");
+ w.print(numProcAddressEntries-1);
+ w.println(';');
+
+ w.println();
+ w.println(" /**");
+ w.println(" * This is a convenience method to get (by name) the native function ");
+ w.println(" * pointer for a given extension function. It lets you avoid ");
+ w.println(" * having to manually compute the " + PROCADDRESS_VAR_PREFIX + "<glFunctionName>");
+ w.println(" * member variable name and look it up via reflection; it also");
+ w.println(" * will throw an exception if you try to get the address of an");
+ w.println(" * unknown GL extension, or one that is statically linked ");
+ w.println(" * and therefore does not have a valid GL procedure address. ");
+ w.println(" */");
+ w.println(" public long getAddressFor(String glFunctionName) {");
+ w.println(" String addressFieldName = net.java.games.gluegen.opengl.GLEmitter.PROCADDRESS_VAR_PREFIX + glFunctionName;");
+ w.println(" try { ");
+ w.println(" java.lang.reflect.Field addressField = this.getClass().getField(addressFieldName);");
+ w.println(" return addressField.getLong(this);");
+ w.println(" } catch (Exception e) {");
+ w.println(" // The user is calling a bogus function or one which is not runtime");
+ w.println(" // linked (extensions and core post-OpenGL 1.1 functions are runtime linked)");
+ w.println(" if (!FunctionAvailabilityCache.isPartOfGLCore(\"1.1\", glFunctionName)) ");
+ w.println(" {");
+ w.println(" throw new RuntimeException(" );
+ w.println(" \"WARNING: Address query failed for \\\"\" + glFunctionName +");
+ w.println(" \"\\\"; either it's not runtime linked or it is not a known \" +");
+ w.println(" \"OpenGL function\", e);");
+ w.println(" }");
+ w.println(" } ");
+ w.println(" assert(false); // should never get this far");
+ w.println(" return 0;");
+ w.println(" }");
+
+ w.println("} // end of class " + tableClassName);
+ w.flush();
+ w.close();
+ }
+
+ private void emitGLProcAddressTableEntryForSymbol(FunctionSymbol cFunc)
+ {
+ tableWriter.print(" public static long ");
+ tableWriter.print(PROCADDRESS_VAR_PREFIX);
+ tableWriter.print(cFunc.getName());
+ tableWriter.println(";");
+ ++numProcAddressEntries;
+ }
+
+ protected static class GLConfiguration extends JavaConfiguration
+ {
+ private boolean emitProcAddressTable = false;
+
+ protected void dispatch(String cmd, StringTokenizer tok, File file, String filename, int lineNo) throws IOException {
+ if (cmd.equalsIgnoreCase("EmitProcAddressTable"))
+ {
+ emitProcAddressTable =
+ readBoolean("EmitProcAddressTable", tok, filename, lineNo).booleanValue();
+ }
+ else
+ {
+ super.dispatch(cmd,tok,file,filename,lineNo);
+ }
+ }
+
+ public boolean emitProcAddressTable() { return emitProcAddressTable; }
+ } // end class GLConfiguration
+}
+
diff --git a/src/net/java/games/gluegen/opengl/JavaGLPAWrapperEmitter.java b/src/net/java/games/gluegen/opengl/JavaGLPAWrapperEmitter.java
new file mode 100644
index 000000000..e0a098f2a
--- /dev/null
+++ b/src/net/java/games/gluegen/opengl/JavaGLPAWrapperEmitter.java
@@ -0,0 +1,178 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.opengl;
+
+import java.io.*;
+import java.util.*;
+import net.java.games.gluegen.*;
+import net.java.games.gluegen.cgram.types.*;
+
+public class JavaGLPAWrapperEmitter extends JavaMethodBindingImplEmitter
+{
+ private static final CommentEmitter commentEmitterForWrappedMethod =
+ new WrappedMethodCommentEmitter();
+
+ private JavaMethodBindingEmitter emitterBeingWrapped;
+
+ public JavaGLPAWrapperEmitter(JavaMethodBindingEmitter methodToWrap)
+ {
+ super(methodToWrap.getBinding(), methodToWrap.getDefaultOutput(), methodToWrap.getRuntimeExceptionType());
+
+ if (methodToWrap.getBinding().hasContainingType())
+ {
+ throw new IllegalArgumentException(
+ "Cannot create OpenGL proc. address wrapper; method has containing type: \"" +
+ methodToWrap.getBinding() + "\"");
+ }
+
+ // make a new emitter that will emit the original method's binding, but
+ // with WRAP_PREFIX before its name. If a body is needed (for array
+ // length checking, unwrapping of wrapper objects to java.nio.Buffers,
+ // etc.) then it will be generated; therefore the emitter being wrapped
+ // should be an "NIO buffer variant" (i.e., after all unpacking has
+ // occurred).
+ emitterBeingWrapped =
+ new JavaMethodBindingEmitter(methodToWrap.getBinding().createNIOBufferVariant(),
+ methodToWrap.getDefaultOutput(),
+ methodToWrap.getRuntimeExceptionType())
+ {
+ protected void emitName(PrintWriter writer)
+ {
+ writer.print(GLEmitter.WRAP_PREFIX);
+ super.emitName(writer);
+ }
+ protected int emitArguments(PrintWriter writer)
+ {
+ int numEmitted = super.emitArguments(writer);
+ if (numEmitted > 0)
+ {
+ writer.print(", ");
+ }
+ writer.print("long glProcAddress");
+ ++numEmitted;
+
+ return numEmitted;
+ }
+ };
+
+ // copy the modifiers from the original emitter
+ emitterBeingWrapped.addModifiers(methodToWrap.getModifiers());
+
+ // Change the access of the method we're wrapping to PRIVATE
+ EmissionModifier origAccess = null; // null is equivalent if package access
+ if (emitterBeingWrapped.hasModifier(PUBLIC))
+ {
+ origAccess = PUBLIC;
+ }
+ else if (emitterBeingWrapped.hasModifier(PROTECTED))
+ {
+ origAccess = PROTECTED;
+ }
+ else if (emitterBeingWrapped.hasModifier(PRIVATE))
+ {
+ origAccess = PRIVATE;
+ }
+
+ if (origAccess != null)
+ {
+ emitterBeingWrapped.removeModifier(origAccess);
+ }
+ emitterBeingWrapped.addModifier(PRIVATE);
+ emitterBeingWrapped.addModifier(NATIVE);
+
+ // Now make our binding use the original access of the wrapped method
+ this.addModifier(origAccess);
+ }
+
+ protected boolean needsBody() {
+ return true;
+ }
+
+ protected String getImplMethodName() {
+ return GLEmitter.WRAP_PREFIX + getBinding().getName();
+ }
+
+ public void emit(PrintWriter writer)
+ {
+ // Emit a wrapper that will call the method we want to wrap
+ //writer.println(" // Emitter being wrapped = " + emitterBeingWrapped.getClass().getName());
+ super.emit(writer);
+ writer.println();
+
+ // emit the wrapped method
+ CommentEmitter origComment = emitterBeingWrapped.getCommentEmitter();
+ emitterBeingWrapped.setCommentEmitter(commentEmitterForWrappedMethod);
+ emitterBeingWrapped.emit(writer);
+ emitterBeingWrapped.setCommentEmitter(origComment);
+ writer.println();
+ }
+
+ protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) {
+ super.emitPreCallSetup(binding, writer);
+ JavaType returnType = binding.getJavaReturnType();
+
+ MethodBinding wrappedBinding = emitterBeingWrapped.getBinding();
+ String procAddressVariable =
+ GLEmitter.PROCADDRESS_VAR_PREFIX + wrappedBinding.getName();
+
+ writer.print(" final long addr = context.getGLProcAddressTable().");
+ writer.print(procAddressVariable);
+ writer.println(';');
+ writer.println(" if (addr == 0) {");
+ writer.println(" throw new GLException(\"Method \\\"" + binding.getName() + "\\\" not available\");");
+ writer.println(" }");
+ }
+
+ protected int emitCallArguments(MethodBinding binding, PrintWriter writer) {
+ int numEmitted = super.emitCallArguments(binding, writer);
+ if (numEmitted > 0) {
+ writer.print(", ");
+ }
+ writer.print("addr");
+ return 1 + numEmitted;
+ }
+
+ /** This class emits the comment for the wrapper method */
+ private static class WrappedMethodCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter {
+ protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) {
+ writer.print("Encapsulates function pointer for OpenGL function <br>: ");
+ }
+ }
+} // end class JavaGLPAWrapperEmitter
diff --git a/src/net/java/games/gluegen/pcpp/PCPP.java b/src/net/java/games/gluegen/pcpp/PCPP.java
new file mode 100644
index 000000000..4bddc976f
--- /dev/null
+++ b/src/net/java/games/gluegen/pcpp/PCPP.java
@@ -0,0 +1,824 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.pcpp;
+
+import java.io.*;
+import java.util.*;
+
+/** 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 boolean disableDebugPrint = true;
+
+ public PCPP(List/*<String>*/ includePaths) {
+ this.includePaths = includePaths;
+ setOut(System.out);
+ }
+
+ public OutputStream out() { return out; }
+ public void setOut(OutputStream out) { this.out = out; writer = new PrintWriter(out); }
+
+ public void run(Reader reader, String filename) throws IOException {
+ StreamTokenizer tok = new StreamTokenizer(reader);
+ tok.resetSyntax();
+ tok.wordChars('a', 'z');
+ tok.wordChars('A', 'Z');
+ tok.wordChars('0', '9');
+ tok.wordChars('_', '_');
+ tok.wordChars('.', '.');
+ tok.wordChars(128 + 32, 255);
+ tok.whitespaceChars(0, ' ');
+ tok.quoteChar('"');
+ tok.quoteChar('\'');
+ tok.eolIsSignificant(true);
+ tok.slashSlashComments(true);
+ tok.slashStarComments(true);
+ ParseState curState = new ParseState(tok, filename);
+ ParseState oldState = state;
+ state = curState;
+ lineDirective();
+ parse();
+ state = oldState;
+ if (state != null) {
+ lineDirective();
+ }
+ }
+
+ public static void main(String[] args) {
+ try {
+ Reader reader = null;
+ String filename = null;
+
+ if (args.length == 0) {
+ usage();
+ }
+
+ List includePaths = new ArrayList();
+ 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 {
+ 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).run(reader, filename);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ 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.exit(1);
+ }
+
+ /** 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();
+
+ /** List containing the #include paths as Strings */
+ private List/*<String>*/ includePaths;
+
+ // State
+ static class ParseState {
+ private StreamTokenizer tok;
+ private String filename;
+ private int lineNumber;
+ private boolean startOfLine;
+ private boolean startOfFile;
+
+ ParseState(StreamTokenizer tok, String filename) {
+ this.tok = tok;
+ this.filename = filename;
+ lineNumber = 1;
+ startOfLine = true;
+ startOfFile = true;
+ }
+
+ StreamTokenizer tok() { return tok; }
+ 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 ParseState state;
+
+ // Accessors
+
+ private void pushBackToken() throws IOException {
+ state.tok().pushBack();
+ }
+
+ /** 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 (curToken() == StreamTokenizer.TT_EOL) {
+ state.setStartOfLine(true);
+ } else if (!state.startOfFile()) {
+ state.setStartOfLine(false);
+ }
+ state.setStartOfFile(false);
+ int val = state.tok().nextToken();
+ if (!returnEOLs) {
+ if (val == StreamTokenizer.TT_EOL) {
+ do {
+ // Consume and return next token, setting state appropriately
+ val = state.tok().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 int curToken() {
+ return state.tok().ttype;
+ }
+
+ private String curTokenAsString() {
+ int t = curToken();
+ if (t == StreamTokenizer.TT_WORD) {
+ return curWord();
+ }
+ if (t == StreamTokenizer.TT_EOL) {
+ throw new RuntimeException("Should not be converting EOL characters to strings");
+ }
+ char c = (char) t;
+ if (c == '"' || c == '\'') {
+ StringBuffer buf = new StringBuffer();
+ buf.append(c);
+ buf.append(state.tok().sval);
+ buf.append(c);
+ return buf.toString();
+ }
+ return new String(new char[] { c });
+ }
+
+ private String nextWord() throws IOException {
+ int val = nextToken();
+ if (val != StreamTokenizer.TT_WORD) {
+ throw new RuntimeException("Expected word at file " + filename() +
+ ", line " + lineNumber());
+ }
+ return curWord();
+ }
+
+ private String curWord() {
+ return state.tok().sval;
+ }
+
+ 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)
+ print(" ");
+ String s = curTokenAsString();
+ String newS = (String) defineMap.get(s);
+ if (newS == null) {
+ newS = s;
+ }
+ print(newS);
+ }
+ }
+ flush();
+ }
+
+ private void preprocessorDirective() throws IOException {
+ String w = nextWord();
+ boolean shouldPrint = true;
+ 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 values = new ArrayList();
+ while (nextToken(true) != StreamTokenizer.TT_EOL) {
+ values.add(curTokenAsString());
+ }
+
+ if (enabled()) {
+ String oldDef = (String)defineMap.remove(name);
+ if (oldDef == null) {
+ System.err.println("WARNING: ignoring redundant \"#undef " +
+ name + "\", at \"" + filename() + "\" line " + lineNumber() +
+ ": \"" + name + "\" was not previously defined");
+ } else {
+ // System.err.println("UNDEFINED: '" + name + "' (line " + lineNumber() + " file " + filename() + ")");
+ }
+ }
+ else System.err.println("FAILED TO UNDEFINE: '" + name + "' (line " + lineNumber() + " file " + filename() + ")");
+
+ }
+
+ private void handleDefine() throws IOException {
+ // Next token is the name of the #define
+ String name = nextWord();
+ //System.err.println("IN HANDLE_DEFINE: '" + name + "' (line " + lineNumber() + " file " + filename() + ")");
+ // (Note that this is not actually proper handling for multi-line #defines)
+ List values = new ArrayList();
+ 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 oldDef = (String)defineMap.put(name, "");
+ if (oldDef != null) {
+ System.err.println("WARNING: \"" + name + "\" redefined from \"" +
+ oldDef + "\" to \"\"");
+ }
+ // 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 = (String) values.get(0);
+ if (isConstant(value)) {
+ // Value is numeric constant like "#define FOO 5".
+ // Put it in the #define map
+ String oldDef = (String)defineMap.put(name, value);
+ if (oldDef != null) {
+ System.err.println("WARNING: \"" + name + "\" redefined from \"" +
+ oldDef + "\" to \"" + value + "\"");
+ }
+ //System.out.println("//---DEFINED: " + name + " to \"" + value + "\"");
+ } else {
+ // Value is a symbolic constant like "#define FOO BAR".
+ // Try to look up the symbol's value
+ String newValue = (String) defineMap.get(value);
+ 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);
+ emitDefine = false;
+ }
+ }
+ }
+ else
+ {
+ // can't handle definitions that aren't constants or empty
+ emitDefine = false;
+ StringBuffer buf = new StringBuffer("#define ");
+ buf.append(name);
+ for (int i = 0; i < sz; ++i) {
+ buf.append(" ");
+ buf.append(values.get(i));
+ }
+ System.err.println("WARNING: Ignoring \"" + buf.toString() +
+ "\" at \"" + filename() + "\" line " + lineNumber() +
+ ": Unable to handle definition to non-constant");
+ 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 \"" + buf.toString() + "\"");
+ }
+ }
+
+ if (emitDefine)
+ {
+ // Print name and value
+ print("# define ");
+ print(name);
+ for (Iterator iter = values.iterator(); iter.hasNext(); ) {
+ print(" ");
+ print((String) iter.next());
+ }
+ println();
+ }
+
+ } // end if (enabled())
+
+ //System.err.println("OUT HANDLE_DEFINE: " + name);
+ }
+
+ private boolean isConstant(String s) {
+ if (s.startsWith("0x") || s.startsWith("0X")) {
+ return checkHex(s);
+ } else {
+ return checkDecimal(s);
+ }
+ }
+
+ private boolean checkHex(String s) {
+ for (int i = 2; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (!((c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'F'))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean checkDecimal(String s) {
+ try {
+ Float.valueOf(s);
+ }
+ catch (NumberFormatException e) {
+ // not parsable as a number
+ return false;
+ }
+ return true;
+ }
+
+ ////////////////////////////////////////////////
+ // 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, "HANDLE_IFDEF: ifdef(" + symbolName + ") = " + 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(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 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 = (String)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.
+ return true;
+ } 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>!");
+ 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 = curWord();
+ } else if (t == '<') {
+ // Components of path name are coming in as separate tokens;
+ // concatenate them
+ StringBuffer buf = new StringBuffer();
+ while ((t = nextToken()) != '>' && (t != StreamTokenizer.TT_EOF)) {
+ buf.append(curTokenAsString());
+ }
+ if (t == StreamTokenizer.TT_EOF) {
+ System.err.println("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) {
+ System.err.println("WARNING: unable to find #include file \"" + 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);
+ }
+ }
+
+ private String findFile(String filename) {
+ String sep = System.getProperty("file.separator");
+ for (Iterator iter = includePaths.iterator(); iter.hasNext(); ) {
+ String inclPath = (String) iter.next();
+ String fullPath = inclPath + sep + filename;
+ File file = new File(fullPath);
+ if (file.exists()) {
+ return fullPath;
+ }
+ }
+ return null;
+ }
+
+ ////////////
+ // Output //
+ ////////////
+
+ private OutputStream out;
+ private PrintWriter writer;
+ private ArrayList enabledBits = new ArrayList();
+
+ private static int debugPrintIndentLevel = 0;
+ private void debugPrint(boolean onlyPrintIfEnabled, String msg)
+ {
+ if (disableDebugPrint) {
+ 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(new Boolean(enabled));
+ ++debugPrintIndentLevel;
+ //debugPrint(false, "PUSH_ENABLED, NOW: " + enabled());
+ }
+
+ private void popEnableBit() {
+ if (enabledBits.size() == 0) {
+ System.err.println("WARNING: mismatched #ifdef/endif pairs");
+ return;
+ }
+ enabledBits.remove(enabledBits.size() - 1);
+ --debugPrintIndentLevel;
+ //debugPrint(false, "POP_ENABLED, NOW: " + enabled());
+ }
+
+ private boolean enabled() {
+ return (enabledBits.size() == 0 ||
+ ((Boolean) enabledBits.get(enabledBits.size() - 1)).booleanValue());
+ }
+
+ 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("#line " + lineNumber() + " \"" + filename() + "\"");
+ println();
+ }
+}
diff --git a/src/net/java/games/gluegen/runtime/BufferFactory.java b/src/net/java/games/gluegen/runtime/BufferFactory.java
new file mode 100644
index 000000000..2efb78ca6
--- /dev/null
+++ b/src/net/java/games/gluegen/runtime/BufferFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.runtime;
+
+import java.nio.*;
+
+public class BufferFactory {
+ public static ByteBuffer newDirectByteBuffer(int size) {
+ ByteBuffer buf = ByteBuffer.allocateDirect(size);
+ buf.order(ByteOrder.nativeOrder());
+ return buf;
+ }
+}
diff --git a/src/net/java/games/gluegen/runtime/StructAccessor.java b/src/net/java/games/gluegen/runtime/StructAccessor.java
new file mode 100644
index 000000000..a5d1d1717
--- /dev/null
+++ b/src/net/java/games/gluegen/runtime/StructAccessor.java
@@ -0,0 +1,191 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.gluegen.runtime;
+
+import java.nio.*;
+
+public class StructAccessor {
+ private ByteBuffer bb;
+ private CharBuffer cb;
+ private DoubleBuffer db;
+ private FloatBuffer fb;
+ private IntBuffer ib;
+ private LongBuffer lb;
+ private ShortBuffer sb;
+
+ public StructAccessor(ByteBuffer bb) {
+ // Setting of byte order is concession to native code which needs
+ // to instantiate these
+ this.bb = bb.order(ByteOrder.nativeOrder());
+ }
+
+ public ByteBuffer getBuffer() {
+ return bb;
+ }
+
+ /** Return a slice of the current ByteBuffer starting at the
+ specified byte offset and extending the specified number of
+ bytes. Note that this method is not thread-safe with respect to
+ the other methods in this class. */
+ public ByteBuffer slice(int byteOffset, int byteLength) {
+ bb.position(byteOffset);
+ bb.limit(byteOffset + byteLength);
+ ByteBuffer newBuf = bb.slice();
+ bb.position(0);
+ bb.limit(bb.capacity());
+ return newBuf;
+ }
+
+ /** Retrieves the byte at the specified slot (byte offset). */
+ public byte getByteAt(int slot) {
+ return bb.get(slot);
+ }
+
+ /** Puts a byte at the specified slot (byte offset). */
+ public void setByteAt(int slot, byte v) {
+ bb.put(slot, v);
+ }
+
+ /** Retrieves the char at the specified slot (2-byte offset). */
+ public char getCharAt(int slot) {
+ return charBuffer().get(slot);
+ }
+
+ /** Puts a char at the specified slot (2-byte offset). */
+ public void setCharAt(int slot, char v) {
+ charBuffer().put(slot, v);
+ }
+
+ /** Retrieves the double at the specified slot (8-byte offset). */
+ public double getDoubleAt(int slot) {
+ return doubleBuffer().get(slot);
+ }
+
+ /** Puts a double at the specified slot (8-byte offset). */
+ public void setDoubleAt(int slot, double v) {
+ doubleBuffer().put(slot, v);
+ }
+
+ /** Retrieves the float at the specified slot (4-byte offset). */
+ public float getFloatAt(int slot) {
+ return floatBuffer().get(slot);
+ }
+
+ /** Puts a float at the specified slot (4-byte offset). */
+ public void setFloatAt(int slot, float v) {
+ floatBuffer().put(slot, v);
+ }
+
+ /** Retrieves the int at the specified slot (4-byte offset). */
+ public int getIntAt(int slot) {
+ return intBuffer().get(slot);
+ }
+
+ /** Puts a int at the specified slot (4-byte offset). */
+ public void setIntAt(int slot, int v) {
+ intBuffer().put(slot, v);
+ }
+
+ /** Retrieves the long at the specified slot (8-byte offset). */
+ public long getLongAt(int slot) {
+ return longBuffer().get(slot);
+ }
+
+ /** Puts a long at the specified slot (8-byte offset). */
+ public void setLongAt(int slot, long v) {
+ longBuffer().put(slot, v);
+ }
+
+ /** Retrieves the short at the specified slot (2-byte offset). */
+ public short getShortAt(int slot) {
+ return shortBuffer().get(slot);
+ }
+
+ /** Puts a short at the specified slot (2-byte offset). */
+ public void setShortAt(int slot, short v) {
+ shortBuffer().put(slot, v);
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private CharBuffer charBuffer() {
+ if (cb == null) {
+ cb = bb.asCharBuffer();
+ }
+ return cb;
+ }
+
+ private DoubleBuffer doubleBuffer() {
+ if (db == null) {
+ db = bb.asDoubleBuffer();
+ }
+ return db;
+ }
+
+ private FloatBuffer floatBuffer() {
+ if (fb == null) {
+ fb = bb.asFloatBuffer();
+ }
+ return fb;
+ }
+
+ private IntBuffer intBuffer() {
+ if (ib == null) {
+ ib = bb.asIntBuffer();
+ }
+ return ib;
+ }
+
+ private LongBuffer longBuffer() {
+ if (lb == null) {
+ lb = bb.asLongBuffer();
+ }
+ return lb;
+ }
+
+ private ShortBuffer shortBuffer() {
+ if (sb == null) {
+ sb = bb.asShortBuffer();
+ }
+ return sb;
+ }
+}