summaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java')
-rw-r--r--src/java/com/sun/gluegen/ArrayTypes.java125
-rw-r--r--src/java/com/sun/gluegen/CMethodBindingEmitter.java1568
-rw-r--r--src/java/com/sun/gluegen/CodeGenUtils.java150
-rw-r--r--src/java/com/sun/gluegen/CommentEmitter.java52
-rw-r--r--src/java/com/sun/gluegen/ConstantDefinition.java91
-rw-r--r--src/java/com/sun/gluegen/DebugEmitter.java108
-rw-r--r--src/java/com/sun/gluegen/FunctionEmitter.java227
-rw-r--r--src/java/com/sun/gluegen/GlueEmitter.java120
-rw-r--r--src/java/com/sun/gluegen/GlueEmitterControls.java61
-rw-r--r--src/java/com/sun/gluegen/GlueGen.java370
-rw-r--r--src/java/com/sun/gluegen/JavaConfiguration.java1565
-rw-r--r--src/java/com/sun/gluegen/JavaEmitter.java1836
-rw-r--r--src/java/com/sun/gluegen/JavaMethodBindingEmitter.java873
-rw-r--r--src/java/com/sun/gluegen/JavaType.java559
-rw-r--r--src/java/com/sun/gluegen/MethodBinding.java594
-rw-r--r--src/java/com/sun/gluegen/ReferencedStructs.java72
-rw-r--r--src/java/com/sun/gluegen/StructLayout.java153
-rw-r--r--src/java/com/sun/gluegen/SymbolFilter.java64
-rw-r--r--src/java/com/sun/gluegen/TypeInfo.java70
-rw-r--r--src/java/com/sun/gluegen/ant/GlueGenTask.java520
-rw-r--r--src/java/com/sun/gluegen/ant/StaticGLGenTask.java304
-rw-r--r--src/java/com/sun/gluegen/cgram/CSymbolTable.java132
-rw-r--r--src/java/com/sun/gluegen/cgram/CToken.java32
-rw-r--r--src/java/com/sun/gluegen/cgram/Define.java56
-rw-r--r--src/java/com/sun/gluegen/cgram/GnuCEmitter.g1145
-rw-r--r--src/java/com/sun/gluegen/cgram/GnuCParser.g865
-rw-r--r--src/java/com/sun/gluegen/cgram/GnuCTreeParser.g852
-rw-r--r--src/java/com/sun/gluegen/cgram/HeaderParser.g725
-rw-r--r--src/java/com/sun/gluegen/cgram/LineObject.java126
-rw-r--r--src/java/com/sun/gluegen/cgram/PreprocessorInfoChannel.java73
-rw-r--r--src/java/com/sun/gluegen/cgram/StdCParser.g1375
-rw-r--r--src/java/com/sun/gluegen/cgram/TNode.java443
-rw-r--r--src/java/com/sun/gluegen/cgram/TNodeFactory.java33
-rw-r--r--src/java/com/sun/gluegen/cgram/types/ArrayType.java131
-rw-r--r--src/java/com/sun/gluegen/cgram/types/BitType.java87
-rw-r--r--src/java/com/sun/gluegen/cgram/types/CVAttributes.java48
-rw-r--r--src/java/com/sun/gluegen/cgram/types/CompoundType.java206
-rw-r--r--src/java/com/sun/gluegen/cgram/types/CompoundTypeKind.java50
-rw-r--r--src/java/com/sun/gluegen/cgram/types/DoubleType.java64
-rw-r--r--src/java/com/sun/gluegen/cgram/types/EnumType.java145
-rw-r--r--src/java/com/sun/gluegen/cgram/types/Field.java102
-rw-r--r--src/java/com/sun/gluegen/cgram/types/FloatType.java64
-rw-r--r--src/java/com/sun/gluegen/cgram/types/FunctionSymbol.java122
-rw-r--r--src/java/com/sun/gluegen/cgram/types/FunctionType.java179
-rw-r--r--src/java/com/sun/gluegen/cgram/types/IntType.java82
-rw-r--r--src/java/com/sun/gluegen/cgram/types/MachineDescription.java82
-rw-r--r--src/java/com/sun/gluegen/cgram/types/MachineDescription32Bit.java46
-rw-r--r--src/java/com/sun/gluegen/cgram/types/MachineDescription64Bit.java46
-rw-r--r--src/java/com/sun/gluegen/cgram/types/PointerType.java142
-rw-r--r--src/java/com/sun/gluegen/cgram/types/PrimitiveType.java50
-rwxr-xr-xsrc/java/com/sun/gluegen/cgram/types/SizeThunk.java171
-rw-r--r--src/java/com/sun/gluegen/cgram/types/Type.java262
-rw-r--r--src/java/com/sun/gluegen/cgram/types/TypeDictionary.java169
-rw-r--r--src/java/com/sun/gluegen/cgram/types/TypeVisitor.java44
-rw-r--r--src/java/com/sun/gluegen/cgram/types/VoidType.java56
-rw-r--r--src/java/com/sun/gluegen/jgram/JavaParser.g1315
-rw-r--r--src/java/com/sun/gluegen/jgram/Test.java132
-rwxr-xr-xsrc/java/com/sun/gluegen/nativesig/NativeSignatureEmitter.java188
-rwxr-xr-xsrc/java/com/sun/gluegen/nativesig/NativeSignatureJavaMethodBindingEmitter.java486
-rw-r--r--src/java/com/sun/gluegen/opengl/BuildComposablePipeline.java1104
-rw-r--r--src/java/com/sun/gluegen/opengl/BuildStaticGLInfo.java333
-rw-r--r--src/java/com/sun/gluegen/opengl/ConvertFromGL4Java.java91
-rwxr-xr-xsrc/java/com/sun/gluegen/opengl/GLConfiguration.java297
-rw-r--r--src/java/com/sun/gluegen/opengl/GLEmitter.java407
-rwxr-xr-xsrc/java/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java103
-rwxr-xr-xsrc/java/com/sun/gluegen/pcpp/ConcatenatingReader.java174
-rw-r--r--src/java/com/sun/gluegen/pcpp/PCPP.java865
-rwxr-xr-xsrc/java/com/sun/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java215
-rwxr-xr-xsrc/java/com/sun/gluegen/procaddress/ProcAddressConfiguration.java306
-rwxr-xr-xsrc/java/com/sun/gluegen/procaddress/ProcAddressEmitter.java402
-rwxr-xr-xsrc/java/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java153
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/BufferFactory.java.javame_cdc_fp230
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/BufferFactory.java.javase299
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/BufferFactoryInternal.java115
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/CPU.java85
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/DynamicLinker.java50
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/DynamicLookupHelper.java53
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/MacOSXDynamicLinkerImpl.java60
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/NativeLibLoader.java105
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/NativeLibrary.java425
-rw-r--r--src/java/com/sun/gluegen/runtime/ProcAddressHelper.java125
-rw-r--r--src/java/com/sun/gluegen/runtime/ProcAddressTable.java41
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/StructAccessor.java.javame_cdc_fp135
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/StructAccessor.java.javase191
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/UnixDynamicLinkerImpl.java66
-rwxr-xr-xsrc/java/com/sun/gluegen/runtime/WindowsDynamicLinkerImpl.java49
-rw-r--r--src/java/com/sun/gluegen/runtime/opengl/GLExtensionNames.java187
-rw-r--r--src/java/com/sun/gluegen/runtime/opengl/GLProcAddressHelper.java110
-rwxr-xr-xsrc/java/net/highteq/nativetaglet/NativeTaglet.java227
89 files changed, 26811 insertions, 0 deletions
diff --git a/src/java/com/sun/gluegen/ArrayTypes.java b/src/java/com/sun/gluegen/ArrayTypes.java
new file mode 100644
index 0000000..7e5dd95
--- /dev/null
+++ b/src/java/com/sun/gluegen/ArrayTypes.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.nio.*;
+
+/**
+ * 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 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 stringArrayClass;
+
+ // Classes for two-dimensional arrays.
+ //
+ // GlueGen converts C types like int** into Java arrays of direct
+ // buffers of the appropriate type (like IntBuffer[]). If the tool
+ // supported conversions like byte[][] -> char**, it would
+ // effectively be necessary to copy all of the data from the Java
+ // heap to the C heap during each call. The reason for this is that
+ // if we wanted to use GetPrimitiveArrayCritical to lock down the
+ // storage for each individual array element, we would need to fetch
+ // each element of the two-dimensional Java array into temporary
+ // storage before making the first GetPrimitiveArrayCritical call,
+ // since one can not call GetObjectArrayElement inside a Get /
+ // ReleasePrimitiveArrayCritical pair. This means that we would need
+ // two top-level pieces of temporary storage for the two-dimensional
+ // array as well as two loops to set up the contents, which would be
+ // too complicated.
+ //
+ // The one concession we make is converting String[] -> char**. The
+ // JVM takes care of the C heap allocation for GetStringUTFChars and
+ // ReleaseStringUTFChars, and this conversion is important for
+ // certain OpenGL operations.
+
+ /** Class for Java type Buffer[] */
+ public static final Class bufferArrayClass;
+ /** Class for Java type ByteBuffer[] */
+ public static final Class byteBufferArrayClass;
+ /** Class for Java type ShortBuffer[] */
+ public static final Class shortBufferArrayClass;
+ /** Class for Java type IntBuffer[] */
+ public static final Class intBufferArrayClass;
+ /** Class for Java type LongBuffer[] */
+ public static final Class longBufferArrayClass;
+ /** Class for Java type FloatBuffer[] */
+ public static final Class floatBufferArrayClass;
+ /** Class for Java type DoubleBuffer[] */
+ public static final Class doubleBufferArrayClass;
+
+ static {
+ 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();
+ stringArrayClass = new String [0].getClass();
+
+ bufferArrayClass = new Buffer [0].getClass();
+ byteBufferArrayClass = new ByteBuffer [0].getClass();
+ shortBufferArrayClass = new ShortBuffer [0].getClass();
+ intBufferArrayClass = new IntBuffer [0].getClass();
+ longBufferArrayClass = new LongBuffer [0].getClass();
+ floatBufferArrayClass = new FloatBuffer [0].getClass();
+ doubleBufferArrayClass = new DoubleBuffer[0].getClass();
+ }
+}
diff --git a/src/java/com/sun/gluegen/CMethodBindingEmitter.java b/src/java/com/sun/gluegen/CMethodBindingEmitter.java
new file mode 100644
index 0000000..2085477
--- /dev/null
+++ b/src/java/com/sun/gluegen/CMethodBindingEmitter.java
@@ -0,0 +1,1568 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.util.*;
+import java.io.*;
+import java.text.MessageFormat;
+
+import com.sun.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();
+
+ protected static final String arrayResLength = "_array_res_length";
+ protected static final String arrayRes = "_array_res";
+ protected static final String arrayIdx = "_array_idx";
+
+ protected 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;
+
+ // Flags which change various aspects of glue code generation
+ protected boolean forImplementingMethodCall;
+ protected boolean forIndirectBufferAndArrayImplementation;
+
+ /**
+ * 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;
+
+ /**
+ * Length of the returned array. Is ignored if
+ * binding.getJavaReturnType().isArray() is false.
+ */
+ private MessageFormat returnValueLengthExpression = 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;
+
+ protected static final String STRING_CHARS_PREFIX = "_strchars_";
+
+ // We need this in order to compute sizes of certain types
+ protected MachineDescription machDesc;
+
+ /**
+ * 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,
+ PrintWriter output,
+ String javaPackageName,
+ String javaClassName,
+ boolean isOverloadedBinding,
+ boolean isJavaMethodStatic,
+ boolean forImplementingMethodCall,
+ boolean forIndirectBufferAndArrayImplementation,
+ MachineDescription machDesc)
+ {
+ super(output, false);
+
+ assert(binding != null);
+ assert(javaClassName != null);
+ assert(javaPackageName != null);
+
+ this.binding = binding;
+ this.packageName = javaPackageName;
+ this.className = javaClassName;
+ this.isOverloadedBinding = isOverloadedBinding;
+ this.isJavaMethodStatic = isJavaMethodStatic;
+
+ this.forImplementingMethodCall = forImplementingMethodCall;
+ this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation;
+ this.machDesc = machDesc;
+
+ setCommentEmitter(defaultCommentEmitter);
+ }
+
+ public final MethodBinding getBinding() { return binding; }
+
+ public String getName() {
+ return binding.getRenamedMethodName();
+ }
+
+ /**
+ * 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 (or compound type wrapper), 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 and
+ * binding.getJavaReturnType().isCompoundTypeWrapper() == false
+ * </code>
+ */
+ public final void setReturnValueCapacityExpression(MessageFormat expression)
+ {
+ returnValueCapacityExpression = expression;
+
+ if (!binding.getJavaReturnType().isNIOBuffer() &&
+ !binding.getJavaReturnType().isCompoundTypeWrapper())
+ {
+ throw new IllegalArgumentException(
+ "Cannot specify return value capacity for a method that does not " +
+ "return java.nio.Buffer or a compound type wrapper: \"" + binding + "\"");
+ }
+ }
+
+ /**
+ * Get the expression for the length of the returned array
+ */
+ public final MessageFormat getReturnValueLengthExpression()
+ {
+ return returnValueLengthExpression;
+ }
+
+ /**
+ * If this function returns an array, sets the expression for the
+ * length of the returned array.
+ *
+ * @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 length of the array returned from
+ * this method.
+ *
+ * @throws IllegalArgumentException if the <code>
+ * binding.getJavaReturnType().isNIOBuffer() == false
+ * </code>
+ */
+ public final void setReturnValueLengthExpression(MessageFormat expression)
+ {
+ returnValueLengthExpression = expression;
+
+ if (!binding.getJavaReturnType().isArray() &&
+ !binding.getJavaReturnType().isArrayOfCompoundTypeWrappers())
+ {
+ throw new IllegalArgumentException(
+ "Cannot specify return value length for a method that does not " +
+ "return an array: \"" + binding + "\"");
+ }
+ }
+
+ /**
+ * Returns the List of Strings containing declarations for temporary
+ * C variables to be assigned to after the underlying function call.
+ */
+ public final List/*<String>*/ getTemporaryCVariableDeclarations() {
+ return temporaryCVariableDeclarations;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Returns the 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 List/*<String>*/ getTemporaryCVariableAssignments() {
+ return temporaryCVariableAssignments;
+ }
+
+ /**
+ * 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; }
+
+ /**
+ * Is this CMethodBindingEmitter implementing the case of an
+ * indirect buffer or array being passed down to C code?
+ */
+ public final boolean forIndirectBufferAndArrayImplementation() { return forIndirectBufferAndArrayImplementation; }
+
+ /**
+ * Used for certain internal type size computations
+ */
+ public final MachineDescription getMachineDescription() { return machDesc; }
+
+
+ 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 " + getName() +
+ // " = " + jniMangle(binding));
+ }
+ else
+ {
+ writer.print(jniMangle(getName()));
+ //System.err.println(" NORMAL MANGLING FOR " + binding.getName() +
+ // " = " + jniMangle(getName()));
+ }
+ }
+
+ protected String getImplSuffix() {
+ if (forImplementingMethodCall) {
+ if (forIndirectBufferAndArrayImplementation) {
+ return "1";
+ } else {
+ return "0";
+ }
+ }
+ return "";
+ }
+
+ 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;
+
+ if (javaArgType.isPrimitiveArray() ||
+ javaArgType.isNIOBuffer()) {
+ writer.print(", jint " + byteOffsetArgName(i));
+ } else if (javaArgType.isNIOBufferArray()) {
+ writer.print(", jintArray " +
+ byteOffsetArrayArgName(i));
+ }
+ }
+ return numEmitted;
+ }
+
+
+ protected void emitBody(PrintWriter writer)
+ {
+ writer.println(" {");
+ emitBodyVariableDeclarations(writer);
+ emitBodyUserVariableDeclarations(writer);
+ emitBodyVariablePreCallSetup(writer, false);
+ emitBodyVariablePreCallSetup(writer, true);
+ emitBodyCallCFunction(writer);
+ emitBodyUserVariableAssignments(writer);
+ emitBodyVariablePostCallCleanup(writer, true);
+ emitBodyVariablePostCallCleanup(writer, false);
+ 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(),
+ null);
+ }
+
+ 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() || type.isCompoundTypeWrapper() || type.isArrayOfCompoundTypeWrappers()) {
+ String convName = pointerConversionArgumentName(i);
+ // handle array/buffer argument types
+ boolean needsDataCopy =
+ emitPointerDeclaration(writer,
+ binding.getJavaArgumentType(i),
+ binding.getCArgumentType(i),
+ convName,
+ binding.getArgumentName(i));
+ 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 _tmpArrayLen;");
+
+ // Pointer to the data in the Buffer, taking the offset into account
+ writer.println(" int * _offsetHandle = NULL;");
+
+ emittedDataCopyTemps = true;
+ }
+ } else if (type.isString()) {
+ Type cType = binding.getCArgumentType(i);
+ if (isUTF8Type(cType)) {
+ writer.print(" const char* ");
+ } else {
+ writer.print(" jchar* ");
+ }
+ writer.print(STRING_CHARS_PREFIX);
+ writer.print(binding.getArgumentName(i));
+ writer.println(" = NULL;");
+ }
+
+ }
+
+ // Emit declaration for return value if necessary
+ Type cReturnType = binding.getCReturnType();
+
+ JavaType javaReturnType = binding.getJavaReturnType();
+ 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.isNIOByteBufferArray() ||
+ javaReturnType.isArrayOfCompoundTypeWrappers()) {
+ writer.print(" int ");
+ writer.print(arrayResLength);
+ writer.println(";");
+ writer.print(" int ");
+ writer.print(arrayIdx);
+ writer.println(";");
+ writer.print(" jobjectArray ");
+ writer.print(arrayRes);
+ writer.println(";");
+ } else 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);
+ }
+ }
+ }
+
+ /** Checks a type to see whether it is for a UTF-8 pointer type
+ (i.e., "const char *", "const char **"). False implies that this
+ type is for a Unicode pointer type ("jchar *", "jchar **"). */
+ protected boolean isUTF8Type(Type type) {
+ int i = 0;
+ // Try to dereference the type at most two levels
+ while (!type.isInt() && !type.isVoid() && (i < 2)) {
+ PointerType pt = type.asPointer();
+ if (pt != null) {
+ type = pt.getTargetType();
+ } else {
+ ArrayType arrt = type.asArray();
+ if (arrt == null) {
+ throw new IllegalArgumentException("Type " + type + " should have been a pointer or array type");
+ }
+ type = arrt.getElementType();
+ }
+ }
+ if (type.isVoid()) {
+ // Assume UTF-8 since UTF-16 is rare
+ return true;
+ }
+ if (!type.isInt()) {
+ throw new IllegalArgumentException("Type " + type + " should have been a one- or two-dimensional integer pointer or array type");
+ }
+ if (type.getSize(machDesc) != 1 && type.getSize(machDesc) != 2) {
+ throw new IllegalArgumentException("Type " + type + " should have been a one- or two-dimensional pointer to char or short");
+ }
+ return (type.getSize(machDesc) == 1);
+ }
+
+ /** Checks a type (expected to be pointer-to-pointer) for const-ness */
+ protected boolean isConstPtrPtr(Type type) {
+ if (type.pointerDepth() != 2) {
+ return false;
+ }
+ if (type.asPointer().getTargetType().asPointer().getTargetType().isConst()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Code to init the variables that were declared in
+ * emitBodyVariableDeclarations(), PRIOR TO calling the actual C
+ * function.
+ */
+ protected void emitBodyVariablePreCallSetup(PrintWriter writer,
+ boolean emittingPrimitiveArrayCritical)
+ {
+ if (!emittingPrimitiveArrayCritical) {
+ // 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(),
+ null);
+ }
+
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
+ continue;
+ }
+
+ if (type.isCompoundTypeWrapper() ||
+ (type.isNIOBuffer() && !forIndirectBufferAndArrayImplementation)) {
+ emitPointerConversion(writer, binding, type,
+ binding.getCArgumentType(i),
+ binding.getArgumentName(i),
+ pointerConversionArgumentName(i),
+ byteOffsetArgName(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() ||
+ (javaArgType.isNIOBuffer() && forIndirectBufferAndArrayImplementation) ||
+ javaArgType.isArrayOfCompoundTypeWrappers()) {
+ boolean needsDataCopy = javaArgTypeNeedsDataCopy(javaArgType);
+
+ // We only defer the emission of GetPrimitiveArrayCritical
+ // calls that won't be matched up until after the function
+ // we're calling
+ if ((!needsDataCopy && !emittingPrimitiveArrayCritical) ||
+ (needsDataCopy && emittingPrimitiveArrayCritical)) {
+ continue;
+ }
+
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(binding.getArgumentName(i));
+ writer.println(" != NULL) {");
+ }
+
+ Type cArgType = binding.getCArgumentType(i);
+ String cArgTypeName = cArgType.getName();
+
+ String convName = pointerConversionArgumentName(i);
+
+ if (!needsDataCopy) {
+ writer.print(" ");
+ writer.print(convName);
+ writer.print(" = (");
+ if (javaArgType.isStringArray()) {
+ // java-side type is String[]
+ cArgTypeName = "jstring *";
+ }
+ writer.print(cArgTypeName);
+ writer.print(") (((char*) (*env)->GetPrimitiveArrayCritical(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.println(", NULL)) + " + byteOffsetArgName(i) + ");");
+//if(cargtypename is void*)
+// _ptrX = ((char*)convName + index1*sizeof(thisArgsJavaType));
+
+ } else {
+ // 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
+ //
+ // Note that we properly handle only the case of an array of
+ // compound type wrappers in emitBodyVariablePostCallCleanup below
+ if (!isConstPtrPtr(cArgType) &&
+ !javaArgType.isArrayOfCompoundTypeWrappers()) {
+ // FIXME: if the arg type is non-const, the sematics might be that
+ // the function modifies the argument -- we don't yet support
+ // this.
+ 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 " + binding.getArgumentName(i) +
+ " into " + convName + "_copy */");
+
+ // get length of array being copied
+ String arrayLenName = "_tmpArrayLen";
+ 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-type.");
+ }
+ 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)+"\\\"");
+
+ // Get the handle for the byte offset array sent down for Buffers
+ // FIXME: not 100% sure this is correct with respect to the
+ // JNI spec because it may be illegal to call
+ // GetObjectArrayElement while in a critical section. May
+ // need to do another loop and add in the offsets.
+ if (javaArgType.isNIOBufferArray()) {
+ writer.println
+ (" _offsetHandle = (int *) (*env)->GetPrimitiveArrayCritical(env, " +
+ byteOffsetArrayArgName(i) +
+ ", NULL);");
+ }
+
+ // 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) + "\" */");
+ writer.print(" _tmpObj = (*env)->GetObjectArrayElement(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.println(", _copyIndex);");
+
+ if (javaArgType.isStringArray()) {
+ writer.print(" ");
+ emitGetStringChars(writer,
+ "(jstring) _tmpObj",
+ convName+"_copy[_copyIndex]",
+ isUTF8Type(cArgType),
+ true);
+ } else if (javaArgType.isNIOBufferArray()) {
+ /* We always assume an integer "byte offset" argument follows any Buffer
+ in the method binding. */
+ emitGetDirectBufferAddress(writer,
+ "_tmpObj",
+ cArgElementType.getName(),
+ convName + "_copy[_copyIndex]",
+ "_offsetHandle[_copyIndex]",
+ true);
+ } else if (javaArgType.isArrayOfCompoundTypeWrappers()) {
+ // These come down in similar fashion to an array of NIO
+ // Buffers only we do not pass down any integer byte
+ // offset argument
+ emitGetDirectBufferAddress(writer,
+ "_tmpObj",
+ cArgElementType.getName(),
+ convName + "_copy[_copyIndex]",
+ null,
+ true);
+ } 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 matched Get/ReleasePrimitiveArrayCritical() 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(" }");
+
+ if (javaArgType.isNIOBufferArray()) {
+ writer.println
+ (" (*env)->ReleasePrimitiveArrayCritical(env, " +
+ byteOffsetArrayArgName(i) +
+ ", _offsetHandle, JNI_ABORT);");
+ }
+
+ writer.println();
+ } // end of data copy
+
+ if (EMIT_NULL_CHECKS) {
+ writer.println(" }");
+ }
+ } else if (javaArgType.isString()) {
+ if (!emittingPrimitiveArrayCritical) {
+ continue;
+ }
+
+ emitGetStringChars(writer,
+ binding.getArgumentName(i),
+ STRING_CHARS_PREFIX + binding.getArgumentName(i),
+ isUTF8Type(binding.getCArgumentType(i)),
+ false);
+ }
+ }
+ }
+
+
+ /**
+ * Code to clean up any variables that were declared in
+ * emitBodyVariableDeclarations(), AFTER calling the actual C function.
+ */
+ protected void emitBodyVariablePostCallCleanup(PrintWriter writer,
+ boolean emittingPrimitiveArrayCritical)
+ {
+ // 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;
+ }
+ Type cArgType = binding.getCArgumentType(i);
+
+ if (javaArgType.isArray() ||
+ (javaArgType.isNIOBuffer() && forIndirectBufferAndArrayImplementation) ||
+ javaArgType.isArrayOfCompoundTypeWrappers()) {
+ boolean needsDataCopy = javaArgTypeNeedsDataCopy(javaArgType);
+
+ if ((!needsDataCopy && !emittingPrimitiveArrayCritical) ||
+ (needsDataCopy && emittingPrimitiveArrayCritical)) {
+ continue;
+ }
+
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(binding.getArgumentName(i));
+ writer.println(" != NULL) {");
+ }
+
+ String convName = pointerConversionArgumentName(i);
+
+ if (!needsDataCopy) {
+ // Release array
+ writer.print(" (*env)->ReleasePrimitiveArrayCritical(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.print(", ");
+ writer.print(convName);
+ writer.println(", 0);");
+ } else {
+ // 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
+ if (!isConstPtrPtr(cArgType)) {
+ // 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).
+ if (javaArgType.isArrayOfCompoundTypeWrappers()) {
+ // This is the only form of cleanup we handle right now
+ String argName = binding.getArgumentName(i);
+ writer.println(" _tmpArrayLen = (*env)->GetArrayLength(env, " + argName + ");");
+ writer.println(" for (_copyIndex = 0; _copyIndex < _tmpArrayLen; ++_copyIndex) {");
+ writer.println(" _tmpObj = (*env)->GetObjectArrayElement(env, " + argName + ", _copyIndex);");
+ // We only skip the copy back in limited situations
+ String copyName = pointerConversionArgumentName(i) + "_copy";
+ writer.println(" if ((" + copyName + "[_copyIndex] == NULL && _tmpObj == NULL) ||");
+ writer.println(" (" + copyName + "[_copyIndex] != NULL && _tmpObj != NULL &&");
+ writer.println(" (*env)->GetDirectBufferAddress(env, _tmpObj) == " + copyName + "[_copyIndex])) {");
+ writer.println(" /* No copy back needed */");
+ writer.println(" } else {");
+ writer.println(" if (" + copyName + "[_copyIndex] == NULL) {");
+ writer.println(" (*env)->SetObjectArrayElement(env, " + argName + ", _copyIndex, NULL);");
+ writer.println(" } else {");
+ writer.println(" _tmpObj = (*env)->NewDirectByteBuffer(env, " + copyName + "[_copyIndex], sizeof(" + cArgType.getName() + "));");
+ writer.println(" (*env)->SetObjectArrayElement(env, " + argName + ", _copyIndex, _tmpObj);");
+ writer.println(" }");
+ writer.println(" }");
+ writer.println(" }");
+ } else {
+ throw new RuntimeException(
+ "Cannot clean up copied data for ptr-to-ptr arg type \"" + cArgType +
+ "\": support for cleaning up most non-const ptr-to-ptr types not implemented.");
+ }
+ }
+
+ writer.println(" /* Clean up " + convName + "_copy */");
+
+ // Only need to perform cleanup for individual array
+ // elements if they are not direct buffers
+ if (!javaArgType.isNIOBufferArray() &&
+ !javaArgType.isArrayOfCompoundTypeWrappers()) {
+ // Re-fetch length of array that was copied
+ String arrayLenName = "_tmpArrayLen";
+ writer.print(" ");
+ writer.print(arrayLenName);
+ writer.print(" = (*env)->GetArrayLength(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.println(");");
+
+ // 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 */");
+ writer.print(" _tmpObj = (*env)->GetObjectArrayElement(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.println(", _copyIndex);");
+
+ if (javaArgType.isStringArray()) {
+ writer.print(" (*env)->ReleaseStringUTFChars(env, ");
+ writer.print("(jstring) _tmpObj");
+ writer.print(", ");
+ writer.print(convName+"_copy[_copyIndex]");
+ writer.println(");");
+ } else {
+ 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((void*) ");
+ writer.print(convName+"_copy");
+ writer.println(");");
+ } // end of cleaning up copied data
+
+ if (EMIT_NULL_CHECKS) {
+ writer.println(" }");
+ }
+ } else if (javaArgType.isString()) {
+ if (emittingPrimitiveArrayCritical) {
+ continue;
+ }
+
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(binding.getArgumentName(i));
+ writer.println(" != NULL) {");
+ }
+
+ if (isUTF8Type(cArgType)) {
+ writer.print(" (*env)->ReleaseStringUTFChars(env, ");
+ writer.print(binding.getArgumentName(i));
+ writer.print(", " + STRING_CHARS_PREFIX);
+ writer.print(binding.getArgumentName(i));
+ writer.println(");");
+ } else {
+ writer.println(" free((void*) " + STRING_CHARS_PREFIX + binding.getArgumentName(i) + ");");
+ }
+
+ if (EMIT_NULL_CHECKS) {
+ writer.println(" }");
+ }
+ }
+ }
+ }
+
+ /** Returns the number of arguments passed so calling code knows
+ whether to print a comma */
+ protected int emitBodyPassCArguments(PrintWriter writer) {
+ 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() ||
+ javaArgType.isCompoundTypeWrapper() || javaArgType.isArrayOfCompoundTypeWrappers()) {
+ writer.print(pointerConversionArgumentName(i));
+ if (javaArgTypeNeedsDataCopy(javaArgType)) {
+ writer.print("_copy");
+ }
+ } else {
+ if (javaArgType.isString()) { writer.print(STRING_CHARS_PREFIX); }
+ writer.print(binding.getArgumentName(i));
+ }
+ }
+ }
+ return binding.getNumArguments();
+ }
+
+ 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("(");
+ emitBodyPassCArguments(writer);
+ 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);
+ }
+ }
+ }
+
+ 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() ||
+ javaReturnType.isCompoundTypeWrapper()) {
+ writer.println(" if (_res == NULL) return NULL;");
+ writer.print(" return (*env)->NewDirectByteBuffer(env, _res, ");
+ // See whether capacity has been specified
+ if (returnValueCapacityExpression != null) {
+ writer.print(
+ returnValueCapacityExpression.format(argumentNameArray()));
+ } else {
+ if (cReturnType.isPointer() &&
+ cReturnType.asPointer().getTargetType().isCompound()) {
+ if (cReturnType.asPointer().getTargetType().getSize() == null) {
+ throw new RuntimeException(
+ "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)"
+ );
+ }
+ }
+ writer.print("sizeof(" + cReturnType.getName() + ")");
+ System.err.println(
+ "WARNING: No capacity specified for java.nio.Buffer return " +
+ "value for function \"" + binding + "\";" +
+ " assuming size of equivalent C return type (sizeof(" + cReturnType.getName() + ")): " + binding);
+ }
+ writer.println(");");
+ } else if (javaReturnType.isString()) {
+ writer.print(" if (_res == NULL) return NULL;");
+ writer.println(" return (*env)->NewStringUTF(env, _res);");
+ } else if (javaReturnType.isArrayOfCompoundTypeWrappers() ||
+ (javaReturnType.isArray() && javaReturnType.isNIOByteBufferArray())) {
+ writer.println(" if (_res == NULL) return NULL;");
+ if (returnValueLengthExpression == null) {
+ throw new RuntimeException("Error while generating C code: no length specified for array returned from function " +
+ binding);
+ }
+ writer.println(" " + arrayResLength + " = " + returnValueLengthExpression.format(argumentNameArray()) + ";");
+ writer.println(" " + arrayRes + " = (*env)->NewObjectArray(env, " + arrayResLength + ", (*env)->FindClass(env, \"java/nio/ByteBuffer\"), NULL);");
+ writer.println(" for (" + arrayIdx + " = 0; " + arrayIdx + " < " + arrayResLength + "; " + arrayIdx + "++) {");
+ Type retType = binding.getCSymbol().getReturnType();
+ Type pointerType;
+ if (retType.isPointer()) {
+ pointerType = retType.asPointer().getTargetType();
+ } else {
+ pointerType = retType.asArray().getElementType();
+ }
+ Type baseType = pointerType.asPointer().getTargetType();
+ writer.println(" (*env)->SetObjectArrayElement(env, " + arrayRes + ", " + arrayIdx +
+ ", (*env)->NewDirectByteBuffer(env, _res[" + arrayIdx + "], sizeof(" + pointerType.getName() + ")));");
+ writer.println(" }");
+ writer.println(" return " + arrayRes + ";");
+ } 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(";");
+ } else {
+ System.err.print("Unhandled return type: ");
+ javaReturnType.dump();
+ throw new RuntimeException("Unhandled return type");
+ }
+ }
+ }
+
+ 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(getName()));
+ buf.append(getImplSuffix());
+ buf.append("__");
+ if (binding.hasContainingType()) {
+ // "this" argument always comes down in argument 0 as direct buffer
+ jniMangle(java.nio.ByteBuffer.class, buf, true);
+ }
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ if (binding.isArgumentThisPointer(i)) {
+ continue;
+ }
+ JavaType type = binding.getJavaArgumentType(i);
+ if (type.isVoid()) {
+ // We should only see "void" as the first argument of a 1-argument function
+ // FIXME: should normalize this in the parser
+ if ((i != 0) || (binding.getNumArguments() > 1)) {
+ throw new RuntimeException("Saw illegal \"void\" argument while emitting \"" + getName() + "\"");
+ }
+ } else {
+ Class c = type.getJavaClass();
+ if (c != null) {
+ jniMangle(c, buf, false);
+ // If Buffer offset arguments were added, we need to mangle the JNI for the
+ // extra arguments
+ if (type.isNIOBuffer()) {
+ jniMangle(Integer.TYPE, buf, false);
+ } else if (type.isNIOBufferArray()) {
+ int[] intArrayType = new int[0];
+ c = intArrayType.getClass();
+ jniMangle(c , buf, true);
+ }
+ if (type.isPrimitiveArray()) {
+ jniMangle(Integer.TYPE, buf, false);
+ }
+ } else if (type.isCompoundTypeWrapper()) {
+ // Mangle wrappers for C structs as ByteBuffer
+ jniMangle(java.nio.ByteBuffer.class, buf, true);
+ } else if (type.isArrayOfCompoundTypeWrappers()) {
+ // Mangle arrays of C structs as ByteBuffer[]
+ java.nio.ByteBuffer[] tmp = new java.nio.ByteBuffer[0];
+ jniMangle(tmp.getClass(), buf, true);
+ } else if (type.isJNIEnv()) {
+ // These are not exposed at the Java level
+ } 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, boolean syntheticArgument) {
+ 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 RuntimeException("Illegal primitive type \"" + c.getName() + "\"");
+ } else {
+ // Arrays and NIO Buffers are always passed down as java.lang.Object.
+ // The only arrays that show up as true arrays in the signature
+ // are the synthetic byte offset arrays created when passing
+ // down arrays of direct Buffers. Compound type wrappers are
+ // passed down as ByteBuffers (no good reason, just to avoid
+ // accidental conflation) so we mangle them differently.
+ if (syntheticArgument) {
+ if (c.isArray()) {
+ res.append("_3");
+ Class componentType = c.getComponentType();
+ // Handle arrays of compound type wrappers differently for
+ // convenience of the Java-level glue code generation
+ jniMangle(componentType, res,
+ (componentType == java.nio.ByteBuffer.class));
+ } else {
+ res.append("L");
+ res.append(c.getName().replace('.', '_'));
+ res.append("_2");
+ }
+ } else {
+ if (c.isArray()) {
+ res.append("_3");
+ jniMangle(c.getComponentType(), res, false);
+ } else if (c == java.lang.String.class) {
+ res.append("L");
+ res.append(c.getName().replace('.', '_'));
+ res.append("_2");
+ } else {
+ res.append("L");
+ res.append("java_lang_Object");
+ res.append("_2");
+ }
+ }
+ }
+ }
+
+ 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/OutOfMemoryError\"),");
+ writer.print(" \"" + errorMessage);
+ writer.print(" in native dispatcher for \\\"");
+ writer.print(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 emitCalloc(PrintWriter writer,
+ String targetVarName,
+ String elementTypeString,
+ String numElementsExpression,
+ String mallocFailureErrorString)
+ {
+ writer.print(" ");
+ writer.print(targetVarName);
+ writer.print(" = (");
+ writer.print(elementTypeString);
+ writer.print(" *) calloc(");
+ 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 emitGetStringChars(PrintWriter writer,
+ String sourceVarName,
+ String receivingVarName,
+ boolean isUTF8,
+ boolean emitElseClause)
+ {
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(sourceVarName);
+ writer.println(" != NULL) {");
+ }
+ if (isUTF8) {
+ 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+"\\\"");
+ }
+ } else {
+ // The UTF-16 case is basically Windows specific. Unix platforms
+ // tend to use only the UTF-8 encoding. On Windows the problem
+ // is that wide character strings are expected to be null
+ // terminated, but the JNI GetStringChars doesn't return a
+ // null-terminated Unicode string. For this reason we explicitly
+ // calloc our buffer, including the null terminator, and use
+ // GetStringRegion to fetch the string's characters.
+ emitCalloc(writer,
+ receivingVarName,
+ "jchar",
+ "(*env)->GetStringLength(env, " + sourceVarName + ") + 1",
+ "Could not allocate temporary buffer for copying string argument \\\""+sourceVarName+"\\\"");
+ writer.println(" (*env)->GetStringRegion(env, " + sourceVarName + ", 0, (*env)->GetStringLength(env, " + sourceVarName + "), " + receivingVarName + ");");
+ }
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" }");
+ if (emitElseClause) {
+ writer.print(" else {");
+ writer.print(" ");
+ writer.print(receivingVarName);
+ writer.println(" = NULL;");
+ writer.println(" }");
+ } else {
+ writer.println();
+ }
+ }
+ }
+
+ private void emitGetDirectBufferAddress(PrintWriter writer,
+ String sourceVarName,
+ String receivingVarTypeString,
+ String receivingVarName,
+ String byteOffsetVarName,
+ boolean emitElseClause) {
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" if (");
+ writer.print(sourceVarName);
+ writer.println(" != NULL) {");
+ writer.print(" ");
+ }
+
+ writer.print(" ");
+ writer.print(receivingVarName);
+ writer.print(" = (");
+ writer.print(receivingVarTypeString);
+
+ writer.print(") (((char*) (*env)->GetDirectBufferAddress(env, ");
+ writer.print(sourceVarName);
+ writer.println(")) + " + ((byteOffsetVarName != null) ? byteOffsetVarName : "0") + ");");
+
+ if (EMIT_NULL_CHECKS) {
+ writer.print(" }");
+ if (emitElseClause) {
+ writer.println(" else {");
+ writer.print(" ");
+ writer.print(receivingVarName);
+ writer.println(" = NULL;");
+ writer.println(" }");
+ } else {
+ writer.println();
+ }
+ }
+ }
+
+ // 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 javaArgumentName) {
+ 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() || javaType.isArrayOfCompoundTypeWrappers()) {
+ needsDataCopy = javaArgTypeNeedsDataCopy(javaType);
+ if (javaType.isPrimitiveArray() ||
+ javaType.isNIOBufferArray() ||
+ javaType.isArrayOfCompoundTypeWrappers()) {
+ ptrTypeString = cType.getName();
+ } else if (!javaType.isStringArray()) {
+ Class elementType = javaType.getJavaClass().getComponentType();
+ if (elementType.isArray()) {
+ 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 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 {
+ ptrTypeString = cType.getName();
+ }
+
+ if (!needsDataCopy) {
+ // declare the pointer variable
+ writer.print(" ");
+ writer.print(ptrTypeString);
+ writer.print(" ");
+ writer.print(cVariableName);
+ writer.println(" = NULL;");
+ } else {
+ // 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
+ if (javaType.isStringArray()) {
+ writer.print(" const char **");
+ } else {
+ writer.print(" " + ptrTypeString);
+ }
+ writer.print(" ");
+ writer.print(cVariableName);
+ writer.print("_copy = NULL; /* copy of data in ");
+ writer.print(javaArgumentName);
+ 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,
+ String byteOffsetVarName) {
+ // Compound type wrappers do not get byte offsets added on
+ if (type.isCompoundTypeWrapper()) {
+ byteOffsetVarName = null;
+ }
+
+ emitGetDirectBufferAddress(writer,
+ incomingArgumentName,
+ cType.getName(),
+ cVariableName,
+ byteOffsetVarName,
+ false);
+ }
+
+ protected String byteOffsetArgName(int i) {
+ return byteOffsetArgName(binding.getArgumentName(i));
+ }
+
+ protected String byteOffsetArgName(String s) {
+ return s + "_byte_offset";
+ }
+
+ protected String byteOffsetArrayArgName(int i) {
+ return binding.getArgumentName(i) + "_byte_offset_array";
+ }
+
+ protected String[] argumentNameArray() {
+ String[] argumentNames = new String[binding.getNumArguments()];
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ argumentNames[i] = binding.getArgumentName(i);
+ if (binding.getJavaArgumentType(i).isPrimitiveArray()) {
+ // Add on _offset argument in comma-separated expression
+ argumentNames[i] = argumentNames[i] + ", " + byteOffsetArgName(i);
+ }
+ }
+ return argumentNames;
+ }
+
+ 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) {
+ }
+ }
+
+ protected boolean javaArgTypeNeedsDataCopy(JavaType javaArgType) {
+ if (javaArgType.isArray()) {
+ return (javaArgType.isNIOBufferArray() ||
+ javaArgType.isStringArray() ||
+ javaArgType.getJavaClass().getComponentType().isArray());
+ }
+ if (javaArgType.isArrayOfCompoundTypeWrappers()) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/java/com/sun/gluegen/CodeGenUtils.java b/src/java/com/sun/gluegen/CodeGenUtils.java
new file mode 100644
index 0000000..ab81bec
--- /dev/null
+++ b/src/java/com/sun/gluegen/CodeGenUtils.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+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,
+ String gluegenRuntimePackage,
+ 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("import " + gluegenRuntimePackage + ".*;");
+
+ 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/java/com/sun/gluegen/CommentEmitter.java b/src/java/com/sun/gluegen/CommentEmitter.java
new file mode 100644
index 0000000..30004f8
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+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/java/com/sun/gluegen/ConstantDefinition.java b/src/java/com/sun/gluegen/ConstantDefinition.java
new file mode 100644
index 0000000..e06903b
--- /dev/null
+++ b/src/java/com/sun/gluegen/ConstantDefinition.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+
+package com.sun.gluegen;
+
+import java.util.*;
+
+/** Represents the definition of a constant which was provided either
+ via a #define statement or through an enum definition. */
+public class ConstantDefinition {
+ private String name;
+ private String value;
+ private String enumName;
+ private Set/*<String>*/ aliases;
+
+ public ConstantDefinition(String name,
+ String value,
+ String enumName) {
+ this.name = name;
+ this.value = value;
+ this.enumName = enumName;
+ }
+
+ public boolean equals(ConstantDefinition other) {
+ return (equals(name, other.name) &&
+ equals(value, other.value) &&
+ equals(enumName, other.enumName));
+ }
+
+ private boolean equals(String s1, String s2) {
+ if (s1 == null || s2 == null) {
+ if (s1 == null && s2 == null) {
+ return true;
+ }
+ return false;
+ }
+
+ return s1.equals(s2);
+ }
+
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ public String getName() { return name; }
+ public String getValue() { return value; }
+ /** Returns null if this definition was not part of an
+ enumeration, or if the enum was anonymous. */
+ public String getEnumName() { return enumName; }
+
+ public Set/*<String>*/ getAliases() {
+ return aliases;
+ }
+
+ public void addAlias(String alias) {
+ if (aliases == null) {
+ aliases = new LinkedHashSet/*<String>*/();
+ }
+ aliases.add(alias);
+ }
+}
diff --git a/src/java/com/sun/gluegen/DebugEmitter.java b/src/java/com/sun/gluegen/DebugEmitter.java
new file mode 100644
index 0000000..40d6c2d
--- /dev/null
+++ b/src/java/com/sun/gluegen/DebugEmitter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.util.*;
+
+import com.sun.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 md32,
+ MachineDescription md64) {}
+
+ 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, String alternateName) {
+ String name = t.getName();
+ if (name == null && alternateName != null) {
+ name = alternateName;
+ }
+
+ System.out.println("Referenced type \"" + name + "\"");
+ }
+ public void endStructs() {}
+}
diff --git a/src/java/com/sun/gluegen/FunctionEmitter.java b/src/java/com/sun/gluegen/FunctionEmitter.java
new file mode 100644
index 0000000..32ac071
--- /dev/null
+++ b/src/java/com/sun/gluegen/FunctionEmitter.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.util.*;
+import java.io.*;
+import com.sun.gluegen.cgram.types.MachineDescription;
+
+public abstract class FunctionEmitter
+{
+ public static final EmissionModifier STATIC = new EmissionModifier("static");
+
+ private boolean isInterfaceVal;
+ private ArrayList modifiers = new ArrayList();
+ private CommentEmitter commentEmitter = null;
+ private PrintWriter defaultOutput;
+
+ /**
+ * Constructs the FunctionEmitter with a CommentEmitter that emits nothing.
+ */
+ public FunctionEmitter(PrintWriter defaultOutput, boolean isInterface)
+ {
+ assert(defaultOutput != null);
+ this.defaultOutput = defaultOutput;
+ this.isInterfaceVal = isInterface;
+ }
+
+ /**
+ * Makes this FunctionEmitter a copy of the passed one.
+ */
+ public FunctionEmitter(FunctionEmitter arg) {
+ modifiers = (ArrayList) arg.modifiers.clone();
+ commentEmitter = arg.commentEmitter;
+ defaultOutput = arg.defaultOutput;
+ isInterfaceVal = arg.isInterfaceVal;
+ }
+
+ public boolean isInterface() { return isInterfaceVal; }
+
+ 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;
+
+ public int hashCode() {
+ return emittedForm.hashCode();
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == null || (!(arg instanceof EmissionModifier))) {
+ return false;
+ }
+
+ return emittedForm.equals(((EmissionModifier) arg).emittedForm);
+ }
+
+ protected EmissionModifier(String emittedForm) { this.emittedForm = emittedForm; }
+ }
+}
+
diff --git a/src/java/com/sun/gluegen/GlueEmitter.java b/src/java/com/sun/gluegen/GlueEmitter.java
new file mode 100644
index 0000000..e21bc87
--- /dev/null
+++ b/src/java/com/sun/gluegen/GlueEmitter.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.util.*;
+import com.sun.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;
+
+ /** Sets the description of the underlying hardware. "md32"
+ specifies the description of a 32-bit version of the underlying
+ CPU architecture. "md64" specifies the description of a 64-bit
+ version of the underlying CPU architecture. At least one must be
+ specified. When both are specified, the bulk of the glue code is
+ generated using the 32-bit machine description, but structs are
+ laid out twice and the base class delegates between the 32-bit
+ and 64-bit implementation at run time. This allows Java code
+ which can access both 32-bit and 64-bit versions of the data
+ structures to be included in the same jar file. <P>
+
+ It is up to the end user to provide the appropriate opaque
+ definitions to ensure that types of varying size (longs and
+ pointers in particular) are exposed to Java in such a way that
+ changing the machine description does not cause different shared
+ glue code to be generated for the 32- and 64-bit ports.
+ */
+ public void setMachineDescription(MachineDescription md32,
+ MachineDescription md64);
+
+ /**
+ * 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. alternateName is
+ provided when the CompoundType (e.g. "struct foo_t") has not
+ been typedefed to anything but the type of "pointer to struct
+ foo_t" has (e.g. "typedef struct foo_t {} *Foo"); in this case
+ alternateName would be set to Foo. */
+ public void emitStruct(CompoundType t, String alternateName) throws Exception;
+ public void endStructs() throws Exception;
+}
diff --git a/src/java/com/sun/gluegen/GlueEmitterControls.java b/src/java/com/sun/gluegen/GlueEmitterControls.java
new file mode 100644
index 0000000..659a4ee
--- /dev/null
+++ b/src/java/com/sun/gluegen/GlueEmitterControls.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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+/** 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);
+
+ /** Finds the full path name of the specified header file based on
+ the include directories specified on the command line. */
+ public String findHeaderFile(String headerFileName);
+
+ /** Runs the given filter on the #defines, enum definitions and
+ function symbols that this controller has parsed. It is valid to
+ call this method as soon as {@link GlueEmitter#beginEmission}
+ has been called on the GlueEmitter, and it is recommended to
+ call it from that method call. Calling it during glue code
+ emission may cause problems. */
+ public void runSymbolFilter(SymbolFilter filter);
+}
diff --git a/src/java/com/sun/gluegen/GlueGen.java b/src/java/com/sun/gluegen/GlueGen.java
new file mode 100644
index 0000000..5d61fdb
--- /dev/null
+++ b/src/java/com/sun/gluegen/GlueGen.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.io.*;
+import java.util.*;
+
+import antlr.*;
+import antlr.collections.*;
+import com.sun.gluegen.cgram.*;
+import com.sun.gluegen.cgram.types.*;
+import com.sun.gluegen.pcpp.*;
+
+/** Glue code generator for C functions and data structures. */
+
+public class GlueGen implements GlueEmitterControls {
+ private java.util.List forcedStructNames = new ArrayList();
+ private PCPP preprocessor;
+
+ // State for SymbolFilters
+ private java.util.List/*<ConstantDefinition>*/ constants;
+ private java.util.List/*<FunctionSymbol>*/ functions;
+
+ public void forceStructEmission(String typedefName) {
+ forcedStructNames.add(typedefName);
+ }
+
+ public String findHeaderFile(String headerFileName) {
+ return preprocessor.findFile(headerFileName);
+ }
+
+ public void runSymbolFilter(SymbolFilter filter) {
+ filter.filterSymbols(constants, functions);
+ java.util.List/*<ConstantDefinition>*/ newConstants = filter.getConstants();
+ java.util.List/*<FunctionSymbol>*/ newFunctions = filter.getFunctions();
+ if (newConstants != null) {
+ constants = newConstants;
+ }
+ if (newFunctions != null) {
+ functions = newFunctions;
+ }
+ }
+
+ public void run(String[] args) {
+ try {
+ Reader reader = null;
+ String filename = null;
+ String emitterClass = null;
+ String outputRootDir = 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("-O")) {
+ outputRootDir = arg.substring(2);
+ } 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));
+ }
+ }
+ }
+
+ 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();
+ 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());
+ }
+
+ if(null!=outputRootDir && outputRootDir.trim().length()>0) {
+ if(emit instanceof JavaEmitter) {
+ // FIXME: hack to interfere with the *Configuration setting via commandlines
+ JavaEmitter jemit = (JavaEmitter)emit;
+ if(null!=jemit.getConfig()) {
+ jemit.getConfig().setOutputRootDir(outputRootDir);
+ }
+ }
+ }
+
+ // Provide MachineDescriptions to emitter
+ MachineDescription md32 = new MachineDescription32Bit();
+ MachineDescription md64 = new MachineDescription64Bit();
+ emit.setMachineDescription(md32, md64);
+
+ // Repackage the enum and #define statements from the parser into a common format
+ // so that SymbolFilters can operate upon both identically
+ constants = new ArrayList/*<ConstantDefinition>*/();
+ for (Iterator iter = headerParser.getEnums().iterator(); iter.hasNext(); ) {
+ EnumType enumeration = (EnumType)iter.next();
+ String enumName = enumeration.getName();
+ if (enumName.equals("<anonymous>")) {
+ enumName = null;
+ }
+ // iterate over all values in the enumeration
+ for (int i = 0; i < enumeration.getNumEnumerates(); ++i) {
+ String enumElementName = enumeration.getEnumName(i);
+ String value = String.valueOf(enumeration.getEnumValue(i));
+ constants.add(new ConstantDefinition(enumElementName, value, enumName));
+ }
+ }
+ for (Iterator iter = lexer.getDefines().iterator(); iter.hasNext(); ) {
+ Define def = (Define) iter.next();
+ constants.add(new ConstantDefinition(def.getName(), def.getValue(), null));
+ }
+
+ functions = headerParser.getParsedFunctions();
+
+ // begin emission of glue code
+ emit.beginEmission(this);
+
+ emit.beginDefines();
+ Set emittedDefines = new HashSet(100);
+ // emit java equivalent of enum { ... } statements
+ for (Iterator iter = constants.iterator(); iter.hasNext(); ) {
+ ConstantDefinition def = (ConstantDefinition) iter.next();
+ if (!emittedDefines.contains(def.getName())) {
+ emittedDefines.add(def.getName());
+ String comment = null;
+ Set/*<String>*/ aliases = def.getAliases();
+ if (aliases != null) {
+ comment = "Alias for: <code>";
+ for (Iterator i2 = aliases.iterator(); i2.hasNext(); ) {
+ String alias = (String) i2.next();
+ comment += " " + alias;
+ }
+ comment += "</code>";
+ }
+ if (def.getEnumName() != null) {
+ String enumName = "Defined as part of enum type \"" +
+ def.getEnumName() + "\"";
+ if (comment == null) {
+ comment = enumName;
+ } else {
+ comment += "<br>\n" + enumName;
+ }
+ }
+ emit.emitDefine(def.getName(),
+ def.getValue(),
+ comment);
+ }
+ }
+ emit.endDefines();
+
+ // 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(); ) {
+ Type t = (Type) iter.next();
+ if (t.isCompound()) {
+ emit.layoutStruct(t.asCompound());
+ } else if (t.isPointer()) {
+ PointerType p = t.asPointer();
+ CompoundType c = p.getTargetType().asCompound();
+ emit.layoutStruct(c);
+ }
+ }
+ emit.endStructLayout();
+
+ // Emit structs
+ emit.beginStructs(td, sd, headerParser.getCanonMap());
+ for (Iterator iter = referencedStructs.results(); iter.hasNext(); ) {
+ Type t = (Type) iter.next();
+ if (t.isCompound()) {
+ emit.emitStruct(t.asCompound(), null);
+ } else if (t.isPointer()) {
+ PointerType p = t.asPointer();
+ CompoundType c = p.getTargetType().asCompound();
+ assert p.hasTypedefedName() && c.getName() == null : "ReferencedStructs incorrectly recorded pointer type " + p;
+ emit.emitStruct(c, p.getName());
+ }
+ }
+ 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("-Ecom.sun.gluegen.JavaEmitter (the default). Use");
+ System.out.println("-Ecom.sun.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/java/com/sun/gluegen/JavaConfiguration.java b/src/java/com/sun/gluegen/JavaConfiguration.java
new file mode 100644
index 0000000..5693150
--- /dev/null
+++ b/src/java/com/sun/gluegen/JavaConfiguration.java
@@ -0,0 +1,1565 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.io.*;
+import java.lang.reflect.Array;
+import java.util.*;
+import java.util.regex.*;
+
+import com.sun.gluegen.jgram.*;
+import com.sun.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 = ".";
+
+ /**
+ * Top output root directory for all generated files. Default is null, ie not to use it.
+ */
+ private String outputRootDir = null;
+
+ /**
+ * 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;
+ /**
+ * If true, then the comment of a native method binding will include a @native tag
+ * to allow taglets to augment the javadoc with additional information regarding
+ * the mapped C function. Defaults to false.
+ */
+ private boolean tagNativeBinding;
+ /**
+ * 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 package in which the generated glue code expects to find its
+ * run-time helper classes (BufferFactory, CPU,
+ * StructAccessor). Defaults to "com.sun.gluegen.runtime".
+ */
+ private String gluegenRuntimePackage = "com.sun.gluegen.runtime";
+
+ /**
+ * The kind of exception raised by the generated code if run-time
+ * checks fail. Defaults to RuntimeException.
+ */
+ private String runtimeExceptionType = "RuntimeException";
+ private String unsupportedExceptionType = "UnsupportedOperationException";
+ private Map/*<String,Integer>*/ accessControl = new HashMap();
+ 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[] or short[] 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/*<String>*/ extendedIntfSymbols = new HashSet();
+ private boolean extendedIntfSymbolsOnly=false;
+ private Set/*<Pattern>*/ ignores = new HashSet();
+ private Map/*<String,Pattern>*/ ignoreMap = new HashMap();
+ private Set/*<Pattern>*/ ignoreNots = new HashSet();
+ private Set/*<Pattern>*/ unignores = new HashSet();
+ private Set/*<Pattern>*/ unimplemented = new HashSet();
+ private boolean forceNioOnly4All=false;
+ private Set/*<String>*/ nioOnly = new HashSet();
+ private boolean forceNioDirectOnly4All=false;
+ private Set/*<String>*/ nioDirectOnly = 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, String>*/ returnValueCapacities = new HashMap();
+ private Map/*<String, String>*/ returnValueLengths = 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,List<String>>*/ implementedInterfaces = new HashMap();
+ private Map/*<String,String>*/ parentClass = new HashMap();
+ private Map/*<String,String>*/ javaTypeRenames = new HashMap();
+ private Map/*<String,String>*/ javaSymbolRenames = new HashMap();
+ private Map/*<String,List<String>>*/ javaPrologues = new HashMap();
+ private Map/*<String,List<String>>*/ javaEpilogues = new HashMap();
+
+ /** Reads the configuration file.
+ @param filename 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 filename 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 && (emissionStyle() != JavaEmitter.IMPL_ONLY)) {
+ throw new RuntimeException("Output class name was not specified in configuration file \"" + filename + "\"");
+ }
+ if (packageName == null && (emissionStyle() != JavaEmitter.IMPL_ONLY)) {
+ throw new RuntimeException("Output package name was not specified in configuration file \"" + filename + "\"");
+ }
+
+ 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
+ if (className == null) {
+ throw new RuntimeException("If ImplJavaClass is not specified, must specify JavaClass");
+ }
+ implClassName = className + "Impl";
+ }
+ if (implPackageName == null) {
+ // implPackageName defaults to "<packageName>.impl" if ImplPackage
+ // directive is not used
+ if (packageName == null) {
+ throw new RuntimeException("If ImplPackageName is not specified, must specify PackageName");
+ }
+ implPackageName = packageName + ".impl";
+ }
+ }
+ }
+ }
+
+ public void setOutputRootDir(String s) { outputRootDir=s; }
+
+ /** 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 (null!=outputRootDir)?(outputRootDir + "/" + javaOutputDir):javaOutputDir; }
+ /** Returns the native code output directory parsed from the configuration file. */
+ public String nativeOutputDir() { return (null!=outputRootDir)?(outputRootDir + "/" + nativeOutputDir):nativeOutputDir; }
+ /** Returns whether the native code directory structure mirrors the Java hierarchy. */
+ public boolean nativeOutputUsesJavaHierarchy() { return nativeOutputUsesJavaHierarchy; }
+ /** Returns whether the comment of a native method binding should include a @native tag. */
+ public boolean tagNativeBinding() { return tagNativeBinding; }
+ /** Returns the code emission style (constants in JavaEmitter) parsed from the configuration file. */
+ public int emissionStyle() { return emissionStyle; }
+ /** Returns the access control for the emitted Java method. Returns one of JavaEmitter.ACC_PUBLIC, JavaEmitter.ACC_PROTECTED, JavaEmitter.ACC_PRIVATE, or JavaEmitter.ACC_PACKAGE_PRIVATE. */
+ public int accessControl(String methodName) {
+ Integer ret = (Integer) accessControl.get(methodName);
+ if (ret != null) {
+ return ret.intValue();
+ }
+ // Default access control is public
+ return JavaEmitter.ACC_PUBLIC;
+ }
+
+ /** Returns the package in which the generated glue code expects to
+ find its run-time helper classes (BufferFactory, CPU,
+ StructAccessor). Defaults to "com.sun.gluegen.runtime". */
+ public String gluegenRuntimePackage() { return gluegenRuntimePackage; }
+ /** Returns the kind of exception to raise if run-time checks fail in the generated code. */
+ public String runtimeExceptionType() { return runtimeExceptionType; }
+ /** Returns the kind of exception to raise if run-time checks fail in the generated code. */
+ public String unsupportedExceptionType() { return unsupportedExceptionType; }
+ /** Returns the list of imports that should be emitted at the top of each .java file. */
+ public List/*<String>*/ imports() { return imports; }
+
+ private static final boolean DEBUG_TYPE_INFO = false;
+ /** 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.
+ if (DEBUG_TYPE_INFO)
+ System.err.println("Incoming type = " + type);
+ int pointerDepth = type.pointerDepth();
+ for (int i = 0; i <= pointerDepth; i++) {
+ String name = type.getName();
+ if (DEBUG_TYPE_INFO) {
+ System.err.println(" Type = " + type);
+ System.err.println(" Name = " + name);
+ }
+ if (name != null) {
+ TypeInfo info = closestTypeInfo(name, i + type.pointerDepth());
+ if (info != null) {
+ if (DEBUG_TYPE_INFO) {
+ System.err.println(" info.name=" + info.name() + ", name=" + name +
+ ", info.pointerDepth=" + info.pointerDepth() +
+ ", type.pointerDepth=" + type.pointerDepth());
+ }
+ return promoteTypeInfo(info, i);
+ }
+ }
+
+ if (type.isCompound()) {
+ // Try struct name as well
+ name = type.asCompound().getStructName();
+ if (name != null) {
+ TypeInfo info = closestTypeInfo(name, i + type.pointerDepth());
+ if (info != null) {
+ if (DEBUG_TYPE_INFO) {
+ System.err.println(" info.name=" + info.name() + ", name=" + name +
+ ", info.pointerDepth=" + info.pointerDepth() +
+ ", type.pointerDepth=" + type.pointerDepth());
+ }
+ return promoteTypeInfo(info, i);
+ }
+ }
+ }
+
+ // 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();
+ if (DEBUG_TYPE_INFO) {
+ System.err.println("Looking under typedef name " + name);
+ }
+ TypeInfo info = closestTypeInfo(name, i + type.pointerDepth());
+ if (info != null) {
+ if (DEBUG_TYPE_INFO) {
+ System.err.println(" info.name=" + info.name() + ", name=" + name +
+ ", info.pointerDepth=" + info.pointerDepth() +
+ ", type.pointerDepth=" + type.pointerDepth());
+ }
+ return promoteTypeInfo(info, i);
+ }
+ }
+ }
+
+ if (type.isPointer()) {
+ type = type.asPointer().getTargetType();
+ }
+ }
+
+ return null;
+ }
+
+ // Helper functions for above
+ private TypeInfo closestTypeInfo(String name, int pointerDepth) {
+ TypeInfo info = (TypeInfo) typeInfoMap.get(name);
+ TypeInfo closest = null;
+ while (info != null) {
+ if (DEBUG_TYPE_INFO)
+ System.err.println(" Checking TypeInfo for " + name + " at pointerDepth " + pointerDepth);
+ if (info.pointerDepth() <= pointerDepth &&
+ (closest == null ||
+ info.pointerDepth() > closest.pointerDepth())) {
+ if (DEBUG_TYPE_INFO)
+ System.err.println(" Accepted");
+ closest = info;
+ }
+ info = info.next();
+ }
+ return closest;
+ }
+
+ // Promotes a TypeInfo to a higher pointer type (if necessary)
+ private TypeInfo promoteTypeInfo(TypeInfo info, int numPointersStripped) {
+ int diff = numPointersStripped - info.pointerDepth();
+ if (diff == 0) {
+ return info;
+ }
+
+ if (diff < 0) {
+ throw new RuntimeException("TypeInfo for " + info.name() + " and pointerDepth " +
+ info.pointerDepth() + " should not have matched for depth " +
+ numPointersStripped);
+ }
+
+ Class c = info.javaType().getJavaClass();
+ int pd = info.pointerDepth();
+
+ // Handle single-pointer stripping for types compatible with C
+ // integral and floating-point types specially so we end up
+ // generating NIO variants for these
+ if (diff == 1) {
+ JavaType jt = null;
+ if (c == Boolean.TYPE) jt = JavaType.createForCCharPointer();
+ else if (c == Byte.TYPE) jt = JavaType.createForCCharPointer();
+ else if (c == Short.TYPE) jt = JavaType.createForCShortPointer();
+ else if (c == Integer.TYPE) jt = JavaType.createForCInt32Pointer();
+ else if (c == Long.TYPE) jt = JavaType.createForCInt64Pointer();
+ else if (c == Float.TYPE) jt = JavaType.createForCFloatPointer();
+ else if (c == Double.TYPE) jt = JavaType.createForCDoublePointer();
+
+ if (jt != null)
+ return new TypeInfo(info.name(), pd + numPointersStripped, jt);
+ }
+
+ while (diff > 0) {
+ c = Array.newInstance(c, 0).getClass();
+ --diff;
+ }
+
+ return new TypeInfo(info.name(),
+ numPointersStripped,
+ JavaType.createForClass(c));
+ }
+
+ /** 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. Indicates that the given return value, which must be a
+ pointer to a CompoundType, is actually an array of the
+ CompoundType rather than a pointer to a single object. */
+ 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);
+ }
+
+ public boolean isForceNioOnly4All() { return forceNioOnly4All; }
+
+ public void addNioOnly(String fname ) {
+ nioOnly.add(fname);
+ }
+ public boolean nioOnly(String functionName) {
+ return forceNioOnly4All || nioOnly.contains(functionName);
+ }
+
+ public boolean isForceNioDirectOnly4All() { return forceNioDirectOnly4All; }
+
+ public void addNioDirectOnly(String fname ) {
+ nioDirectOnly.add(fname);
+ }
+ /** Returns true if the given function should only create a java.nio
+ variant, and no array variants, for <code>void*</code> and other
+ C primitive pointers. */
+ public boolean nioDirectOnly(String functionName) {
+ return forceNioDirectOnly4All || nioDirectOnly.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 #packageName}). */
+ 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 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 MessageFormat string of the C expression calculating
+ the length of the array being returned from a native method, or
+ null if no expression has been specified. */
+ public String returnValueLength(String functionName) {
+ return (String) returnValueLengths.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 a List of Strings indicating the interfaces the passed
+ class should declare it implements. May return null or a list
+ of zero length if there are none. */
+ public List/*<String>*/ implementedInterfaces(String className) {
+ List res = (List) implementedInterfaces.get(className);
+ if (res == null) {
+ res = new ArrayList();
+ implementedInterfaces.put(className, res);
+ }
+ return res;
+ }
+
+ /** Returns a List of Strings indicating the interfaces the passed
+ class should declare it implements. May return null or a list
+ of zero length if there are none. */
+ public String extendedParentClass(String className) {
+ return (String) parentClass.get(className);
+ }
+
+ public boolean extendedIntfSymbolsOnly() {
+ return extendedIntfSymbolsOnly;
+ }
+
+ public static final boolean DEBUG_IGNORES = false;
+ public static boolean dumpedIgnores = false;
+
+ public void dumpIgnoresOnce() {
+ if(!dumpedIgnores) {
+ dumpedIgnores = true;
+ dumpIgnores();
+ }
+ }
+
+ public void dumpIgnores() {
+ System.err.println("Extended Intf: ");
+ for (Iterator iter = extendedIntfSymbols.iterator(); iter.hasNext(); ) {
+ System.err.println("\t"+(String)iter.next());
+ }
+ System.err.println("Ignores (All): ");
+ for (Iterator iter = ignores.iterator(); iter.hasNext(); ) {
+ System.err.println("\t"+iter.next());
+ }
+ }
+
+ /** Returns true if this #define, function, struct, or field within
+ a struct should be ignored during glue code generation. */
+ public boolean shouldIgnoreInInterface(String symbol) {
+ if(DEBUG_IGNORES) {
+ dumpIgnoresOnce();
+ }
+ // Simple case; the entire symbol is in the interface ignore table.
+ if (extendedIntfSymbols.contains(symbol)) {
+ if(DEBUG_IGNORES) {
+ System.err.println("Ignore Intf: "+symbol);
+ }
+ return true;
+ }
+ return shouldIgnoreInImpl_Int(symbol);
+ }
+
+ public boolean shouldIgnoreInImpl(String symbol) {
+ return shouldIgnoreInImpl_Int(symbol);
+ }
+
+ private boolean shouldIgnoreInImpl_Int(String symbol) {
+
+ if(DEBUG_IGNORES) {
+ dumpIgnoresOnce();
+ }
+
+ if (extendedIntfSymbolsOnly) {
+ if(!extendedIntfSymbols.contains(symbol)) {
+ if(DEBUG_IGNORES) {
+ System.err.println("Ignore Impl !extended: " + symbol);
+ }
+ return true;
+ }
+ }
+
+ // Simple case; the entire symbol is in the ignore table.
+ if (ignores.contains(symbol)) {
+ if(DEBUG_IGNORES) {
+ System.err.println("Ignore Impl ignores: "+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()) {
+ if(DEBUG_IGNORES) {
+ System.err.println("Ignore Impl RegEx: "+symbol);
+ }
+ 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()) {
+ // Special case as this is most often likely to be the case.
+ // Unignores are not used very often.
+ if(unignores.size() == 0) {
+ if(DEBUG_IGNORES) {
+ System.err.println("Ignore Impl unignores==0: "+symbol);
+ }
+ return true;
+ }
+
+ boolean unignoreFound = false;
+ for (Iterator iter2 = unignores.iterator(); iter2.hasNext(); ) {
+ Pattern unignoreRegexp = (Pattern)iter2.next();
+ Matcher unignoreMatcher = unignoreRegexp.matcher(symbol);
+ if (unignoreMatcher.matches()) {
+ unignoreFound = true;
+ break;
+ }
+ }
+
+ if (!unignoreFound)
+ if(DEBUG_IGNORES) {
+ System.err.println("Ignore Impl !unignore: "+symbol);
+ }
+ 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 a replacement name for this function or definition which
+ should be used as the Java name for the bound method or
+ constant. If a function, it still calls the originally-named C
+ function under the hood. Returns null if this symbol has not
+ been explicitly renamed. */
+ public String getJavaSymbolRename(String symbolName) {
+ return (String) javaSymbolRenames.get(symbolName);
+ }
+
+ /** Programmatically adds a rename directive for the given symbol. */
+ public void addJavaSymbolRename(String origName, String newName) {
+ javaSymbolRenames.put(origName, newName);
+ }
+
+ /** 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);
+ }
+
+ /** Returns a list of Strings which should be emitted as a prologue
+ to the body for the Java-side glue code for the given method.
+ Returns null if no prologue was specified. */
+ public List/*<String>*/ javaPrologueForMethod(MethodBinding binding,
+ boolean forImplementingMethodCall,
+ boolean eraseBufferAndArrayTypes) {
+ List/*<String>*/ res = (List/*<String>*/) javaPrologues.get(binding.getName());
+ if (res == null) {
+ // Try again with method name and descriptor
+ res = (List/*<String>*/) javaPrologues.get(binding.getName() +
+ binding.getDescriptor(forImplementingMethodCall,
+ eraseBufferAndArrayTypes));
+ }
+ return res;
+ }
+
+ /** Returns a list of Strings which should be emitted as an epilogue
+ to the body for the Java-side glue code for the given method.
+ Returns null if no epilogue was specified. */
+ public List/*<String>*/ javaEpilogueForMethod(MethodBinding binding,
+ boolean forImplementingMethodCall,
+ boolean eraseBufferAndArrayTypes) {
+ List/*<String>*/ res = (List/*<String>*/) javaEpilogues.get(binding.getName());
+ if (res == null) {
+ // Try again with method name and descriptor
+ res = (List/*<String>*/) javaEpilogues.get(binding.getName() +
+ binding.getDescriptor(forImplementingMethodCall,
+ eraseBufferAndArrayTypes));
+ }
+ return res;
+ }
+
+ //----------------------------------------------------------------------
+ // 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("GlueGenRuntimePackage")) {
+ gluegenRuntimePackage = readString("GlueGenRuntimePackage", 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("TagNativeBinding")) {
+ tagNativeBinding = readBoolean("TagNativeBinding", tok, filename, lineNo).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("AccessControl")) {
+ readAccessControl(tok, filename, lineNo);
+ } 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("ExtendedInterfaceSymbols")) {
+ readExtendedInterfaceSymbols(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("ExtendedInterfaceSymbolsOnly")) {
+ extendedIntfSymbolsOnly=true;
+ readExtendedInterfaceSymbols(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("Ignore")) {
+ readIgnore(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("Unignore")) {
+ readUnignore(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")) {
+ String funcName = readString("NioOnly", tok, filename, lineNo);
+ if(funcName.equals("__ALL__")) {
+ forceNioOnly4All=true;
+ } else {
+ addNioOnly( funcName );
+ }
+ } else if (cmd.equalsIgnoreCase("NioDirectOnly")) {
+ String funcName = readString("NioDirectOnly", tok, filename, lineNo);
+ if(funcName.equals("__ALL__")) {
+ forceNioDirectOnly4All=true;
+ } else {
+ addNioDirectOnly( funcName );
+ }
+ } else if (cmd.equalsIgnoreCase("EmitStruct")) {
+ forcedStructs.add(readString("EmitStruct", 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("ReturnValueLength")) {
+ readReturnValueLength(tok, filename, lineNo);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because ReturnValueLength 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("Implements")) {
+ readImplements(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("ParentClass")) {
+ readParentClass(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("RenameJavaType")) {
+ readRenameJavaType(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("RenameJavaSymbol") ||
+ // Backward compatibility
+ cmd.equalsIgnoreCase("RenameJavaMethod")) {
+ readRenameJavaSymbol(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("RuntimeExceptionType")) {
+ runtimeExceptionType = readString("RuntimeExceptionType", tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("UnsupportedExceptionType")) {
+ unsupportedExceptionType = readString("UnsupportedExceptionType", tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("JavaPrologue")) {
+ readJavaPrologueOrEpilogue(tok, filename, lineNo, true);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because readJavaPrologueOrEpilogue changes them.
+ } else if (cmd.equalsIgnoreCase("JavaEpilogue")) {
+ readJavaPrologueOrEpilogue(tok, filename, lineNo, false);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because readJavaPrologueOrEpilogue changes them.
+ } else if (cmd.equalsIgnoreCase("RangeCheck")) {
+ readRangeCheck(tok, filename, lineNo, false);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because RangeCheck changes them.
+ } else if (cmd.equalsIgnoreCase("RangeCheckBytes")) {
+ readRangeCheck(tok, filename, lineNo, true);
+ // Warning: make sure delimiters are reset at the top of this loop
+ // because RangeCheckBytes changes them.
+ } 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 Byte.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 readAccessControl(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String methodName = tok.nextToken();
+ String style = tok.nextToken();
+ int acc = 0;
+ if (style.equalsIgnoreCase("PUBLIC")) {
+ acc = JavaEmitter.ACC_PUBLIC;
+ } else if (style.equalsIgnoreCase("PROTECTED")) {
+ acc = JavaEmitter.ACC_PROTECTED;
+ } else if (style.equalsIgnoreCase("PRIVATE")) {
+ acc = JavaEmitter.ACC_PRIVATE;
+ } else if (style.equalsIgnoreCase("PACKAGE_PRIVATE")) {
+ acc = JavaEmitter.ACC_PACKAGE_PRIVATE;
+ } else if (style.equalsIgnoreCase("PUBLIC_ABSTRACT")) {
+ acc = JavaEmitter.ACC_PUBLIC_ABSTRACT;
+ } else {
+ throw new RuntimeException("Error parsing \"AccessControl\" command at line " + lineNo +
+ " in file \"" + filename + "\"");
+ }
+ accessControl.put(methodName, new Integer(acc));
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing \"AccessControl\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ 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 readExtendedInterfaceSymbols(StringTokenizer tok, String filename, int lineNo) {
+ File javaFile;
+ BufferedReader javaReader;
+ try {
+ javaFile = new File(tok.nextToken());
+ javaReader = new BufferedReader(new FileReader(javaFile));
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ JavaLexer lexer = new JavaLexer(javaReader);
+ lexer.setFilename(javaFile.getName());
+
+ JavaParser parser = new JavaParser(lexer);
+ parser.setFilename(javaFile.getName());
+
+ try {
+ parser.compilationUnit();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return;
+ }
+
+ extendedIntfSymbols.addAll(parser.getParsedEnumNames());
+ extendedIntfSymbols.addAll(parser.getParsedFunctionNames());
+ }
+
+ protected void readIgnore(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String regex = tok.nextToken();
+ Pattern pattern = Pattern.compile(regex);
+ ignores.add(pattern);
+ ignoreMap.put(regex, pattern);
+ //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 readUnignore(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String regex = tok.nextToken();
+ Pattern pattern = (Pattern) ignoreMap.get(regex);
+ ignoreMap.remove(regex);
+ ignores.remove(pattern);
+
+ // If the pattern wasn't registered before, then make sure we have a
+ // valid pattern instance to put into the unignores set.
+ if(pattern == null)
+ pattern = Pattern.compile(regex);
+ unignores.add(pattern);
+
+ //System.err.println("UN-IGNORING " + regex + " / " + ignores.get(regex));
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"Unignore\" 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();
+ try {
+ String restOfLine = tok.nextToken("\n\r\f");
+ addCustomJavaCode(className, restOfLine);
+ } catch (NoSuchElementException e) {
+ addCustomJavaCode(className, "");
+ }
+ } 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) {
+ customCCode.add("");
+ }
+ }
+
+ 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 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 readReturnValueLength(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String functionName = tok.nextToken();
+ String restOfLine = tok.nextToken("\n\r\f");
+ restOfLine = restOfLine.trim();
+ returnValueLengths.put(functionName, restOfLine);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"ReturnValueLength\" 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 readImplements(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String className = tok.nextToken();
+ List intfs = implementedInterfaces(className);
+ intfs.add(tok.nextToken());
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"Implements\" command at line " + lineNo +
+ " in file \"" + filename + "\": missing expected parameter", e);
+ }
+ }
+
+ protected void readParentClass(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String className = tok.nextToken();
+ parentClass.put(className, tok.nextToken());
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"ParentClass\" 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 void readRenameJavaSymbol(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String fromName = tok.nextToken();
+ String toName = tok.nextToken();
+ javaSymbolRenames.put(fromName, toName);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"RenameJavaSymbol\" command at line " + lineNo +
+ " in file \"" + filename + "\": missing expected parameter", e);
+ }
+ }
+
+ protected void readJavaPrologueOrEpilogue(StringTokenizer tok, String filename, int lineNo, boolean prologue) {
+ try {
+ String methodName = tok.nextToken();
+ String restOfLine = tok.nextToken("\n\r\f");
+ restOfLine = restOfLine.trim();
+ if (startsWithDescriptor(restOfLine)) {
+ // Assume it starts with signature for disambiguation
+ int spaceIdx = restOfLine.indexOf(' ');
+ if (spaceIdx > 0) {
+ String descriptor = restOfLine.substring(0, spaceIdx);
+ restOfLine = restOfLine.substring(spaceIdx + 1, restOfLine.length());
+ methodName = methodName + descriptor;
+ }
+ }
+ addJavaPrologueOrEpilogue(methodName, restOfLine, prologue);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"" +
+ (prologue ? "JavaPrologue" : "JavaEpilogue") +
+ "\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void addJavaPrologueOrEpilogue(String methodName, String code, boolean prologue) {
+ Map codes = (prologue ? javaPrologues : javaEpilogues);
+ List/*<String>*/ data = (List/*<String>*/) codes.get(methodName);
+ if (data == null) {
+ data = new ArrayList/*<String>*/();
+ codes.put(methodName, data);
+ }
+ data.add(code);
+ }
+
+ protected void readRangeCheck(StringTokenizer tok, String filename, int lineNo, boolean inBytes) {
+ try {
+ String functionName = tok.nextToken();
+ int argNum = Integer.parseInt(tok.nextToken());
+ String restOfLine = tok.nextToken("\n\r\f");
+ restOfLine = restOfLine.trim();
+ // Construct a JavaPrologue for this
+ addJavaPrologueOrEpilogue(functionName,
+ "BufferFactory.rangeCheck" +
+ (inBytes ? "Bytes" : "") +
+ "({" + argNum + "}, " + restOfLine + ");",
+ true);
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing \"RangeCheck" + (inBytes ? "Bytes" : "") + "\" command at line " + lineNo +
+ " in file \"" + filename + "\"", 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);
+ }
+
+ private static int nextIndexAfterType(String s, int idx) {
+ int len = s.length();
+ while (idx < len) {
+ char c = s.charAt(idx);
+
+ if (Character.isJavaIdentifierStart(c) ||
+ Character.isJavaIdentifierPart(c) ||
+ (c == '/')) {
+ idx++;
+ } else if (c == ';') {
+ return (idx + 1);
+ } else {
+ return -1;
+ }
+ }
+ return -1;
+ }
+
+ private static int nextIndexAfterDescriptor(String s, int idx) {
+ char c = s.charAt(idx);
+ switch (c) {
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'F':
+ case 'I':
+ case 'J':
+ case 'S':
+ case 'Z':
+ case 'V': return (1 + idx);
+ case 'L': return nextIndexAfterType(s, idx + 1);
+ case ')': return idx;
+ default: break;
+ }
+ return -1;
+ }
+
+ protected static boolean startsWithDescriptor(String s) {
+ // Try to see whether the String s starts with a valid Java
+ // descriptor.
+
+ int idx = 0;
+ int len = s.length();
+ while ((idx < len) && s.charAt(idx) == ' ') {
+ ++idx;
+ }
+
+ if (idx >= len) return false;
+ if (s.charAt(idx++) != '(') return false;
+ while (idx < len) {
+ int nextIdx = nextIndexAfterDescriptor(s, idx);
+ if (nextIdx < 0) {
+ return false;
+ }
+ if (nextIdx == idx) {
+ // ')'
+ break;
+ }
+ idx = nextIdx;
+ }
+ int nextIdx = nextIndexAfterDescriptor(s, idx + 1);
+ if (nextIdx < 0) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/java/com/sun/gluegen/JavaEmitter.java b/src/java/com/sun/gluegen/JavaEmitter.java
new file mode 100644
index 0000000..ffd273f
--- /dev/null
+++ b/src/java/com/sun/gluegen/JavaEmitter.java
@@ -0,0 +1,1836 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.io.*;
+import java.util.*;
+import java.text.MessageFormat;
+
+import com.sun.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;
+ protected 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).
+ */
+ public static final int ALL_STATIC = 1;
+ public static final int INTERFACE_AND_IMPL = 2;
+ public static final int INTERFACE_ONLY = 3;
+ public static final int IMPL_ONLY = 4;
+
+ /**
+ * Access control for emitted Java methods.
+ */
+ public static final int ACC_PUBLIC = 1;
+ public static final int ACC_PROTECTED = 2;
+ public static final int ACC_PRIVATE = 3;
+ public static final int ACC_PACKAGE_PRIVATE = 4;
+ public static final int ACC_PUBLIC_ABSTRACT = 5;
+
+ 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 machDesc32;
+ private MachineDescription machDesc64;
+
+ public void readConfigurationFile(String filename) throws Exception {
+ cfg = createConfig();
+ cfg.read(filename);
+ }
+
+ public void setMachineDescription(MachineDescription md32,
+ MachineDescription md64) {
+ if ((md32 == null) && (md64 == null)) {
+ throw new RuntimeException("Must specify at least one MachineDescription");
+ }
+
+ machDesc32 = md32;
+ machDesc64 = md64;
+ }
+
+ class ConstantRenamer implements SymbolFilter {
+ private List/*<ConstantDefinition>*/ constants;
+
+ public void filterSymbols(List/*<ConstantDefinition>*/ constants,
+ List/*<FunctionSymbol>*/ functions) {
+ this.constants = constants;
+ doWork();
+ }
+
+ public List/*<ConstantDefinition>*/ getConstants() {
+ return constants;
+ }
+
+ public List/*<FunctionSymbol>*/ getFunctions() {
+ return null;
+ }
+
+ private void doWork() {
+ List/*<ConstantDefinition>*/ newConstants = new ArrayList/*<ConstantDefinition>*/();
+ JavaConfiguration cfg = getConfig();
+ for (Iterator iter = constants.iterator(); iter.hasNext(); ) {
+ ConstantDefinition def = (ConstantDefinition) iter.next();
+ String rename = cfg.getJavaSymbolRename(def.getName());
+ if (rename != null) {
+ ConstantDefinition newDef = new ConstantDefinition(rename, def.getValue(), def.getEnumName());
+ newDef.addAlias(def.getName());
+ def = newDef;
+ }
+ newConstants.add(def);
+ }
+ constants = newConstants;
+ }
+ }
+
+ 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());
+ }
+
+ // Handle renaming of constants
+ controls.runSymbolFilter(new ConstantRenamer());
+ }
+
+ 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();
+ }
+ }
+
+ protected static int getJavaRadix(String name, String value)
+ {
+ // 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);
+ return radix;
+ } catch (NumberFormatException e) {
+ try {
+ // see if it's a double or float
+ double dVal = Double.parseDouble(value);
+ return 10;
+ } catch (NumberFormatException e2) {
+ throw new RuntimeException(
+ "Cannot emit define \""+name+"\": value \""+value+
+ "\" cannot be assigned to a int, long, float, or double", e2);
+ }
+ }
+ }
+
+ protected static Object getJavaValue(String name, String value)
+ {
+ // 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);
+ // if constant is small enough, store it as an int instead of a long
+ if (longVal > Integer.MIN_VALUE && longVal < Integer.MAX_VALUE) {
+ return new Integer((int)longVal);
+ }
+ return new Long(longVal);
+
+ } catch (NumberFormatException e) {
+ try {
+ // see if it's a double or float
+ double dVal = Double.parseDouble(value);
+ double absVal = Math.abs(dVal);
+ // if constant is small enough, store it as a float instead of a double
+ if (absVal < Float.MIN_VALUE || absVal > Float.MAX_VALUE) {
+ return new Double(dVal);
+ }
+ return new Float((float) dVal);
+ } catch (NumberFormatException e2) {
+ throw new RuntimeException(
+ "Cannot emit define \""+name+"\": value \""+value+
+ "\" cannot be assigned to a int, long, float, or double", e2);
+ }
+ }
+ }
+
+ protected static String getJavaType(String name, String value) {
+ Object oval = getJavaValue(name, value);
+ return getJavaType(name, oval);
+ }
+
+ protected static String getJavaType(String name, Object oval) {
+ if(oval instanceof Integer) {
+ return "int";
+ } else if(oval instanceof Long) {
+ return "long";
+ } else if(oval instanceof Float) {
+ return "float";
+ } else if(oval instanceof Double) {
+ return "double";
+ }
+
+ throw new RuntimeException(
+ "Cannot emit define (2) \""+name+"\": value \""+oval+
+ "\" cannot be assigned to a int, long, float, or double");
+ }
+
+ 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.shouldIgnoreInInterface(name)) {
+ String type = getJavaType(name, value);
+ if (optionalComment != null && optionalComment.length() != 0) {
+ javaWriter().println(" /** " + optionalComment + " */");
+ }
+ String suffix = "";
+ if (type.equals("float") && !value.endsWith("f")) {
+ suffix = "f";
+ }
+ javaWriter().println(" public static final " + type + " " + name + " = " + value + suffix + ";");
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+
+ // validateFunctionsToBind(funcsToBindSet);
+
+ 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.shouldIgnoreInImpl(cFunc.getName())) {
+ continue; // don't generate bindings for this symbol
+ }
+
+ List allBindings = generateMethodBindingEmitters(cFunc);
+ methodBindingEmitters.addAll(allBindings);
+ }
+
+ // Emit all the methods
+ for (int i = 0; i < methodBindingEmitters.size(); ++i) {
+ FunctionEmitter emitter = (FunctionEmitter)methodBindingEmitters.get(i);
+ try {
+ if (!emitter.isInterface() || !cfg.shouldIgnoreInInterface(emitter.getName())) {
+ emitter.emit();
+ emitter.getDefaultOutput().println(); // put newline after method body
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Error while emitting binding for \"" + emitter.getName() + "\"", e);
+ }
+ }
+
+ // 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;
+ }
+
+ /**
+ * Generates the public emitters for this MethodBinding which will
+ * produce either simply signatures (for the interface class, if
+ * any) or function definitions with or without a body (depending on
+ * whether or not the implementing function can go directly to
+ * native code because it doesn't need any processing of the
+ * outgoing arguments).
+ */
+ protected void generatePublicEmitters(MethodBinding binding,
+ List allEmitters,
+ boolean signatureOnly) {
+ PrintWriter writer = ((signatureOnly || cfg.allStatic()) ? javaWriter() : javaImplWriter());
+
+ if (cfg.manuallyImplement(binding.getName()) && !signatureOnly) {
+ // We only generate signatures for manually-implemented methods;
+ // user provides the implementation
+ return;
+ }
+
+ int accessControl = cfg.accessControl(binding.getName());
+ // We should not emit anything except public APIs into interfaces
+ if (signatureOnly && (accessControl != ACC_PUBLIC)) {
+ return;
+ }
+
+ // It's possible we may not need a body even if signatureOnly is
+ // set to false; for example, if the routine doesn't take any
+ // arrays or buffers as arguments
+ boolean isUnimplemented = cfg.isUnimplemented(binding.getName());
+ List/*<String>*/ prologue = cfg.javaPrologueForMethod(binding, false, false);
+ List/*<String>*/ epilogue = cfg.javaEpilogueForMethod(binding, false, false);
+ boolean needsBody = (isUnimplemented ||
+ (binding.needsNIOWrappingOrUnwrapping() ||
+ binding.signatureUsesJavaPrimitiveArrays()) ||
+ (prologue != null) ||
+ (epilogue != null));
+
+ JavaMethodBindingEmitter emitter =
+ new JavaMethodBindingEmitter(binding,
+ writer,
+ cfg.runtimeExceptionType(),
+ cfg.unsupportedExceptionType(),
+ !signatureOnly && needsBody,
+ cfg.tagNativeBinding(),
+ false,
+ cfg.nioDirectOnly(binding.getName()),
+ false,
+ false,
+ false,
+ isUnimplemented,
+ signatureOnly,
+ cfg);
+ switch (accessControl) {
+ case ACC_PUBLIC: emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); break;
+ case ACC_PROTECTED: emitter.addModifier(JavaMethodBindingEmitter.PROTECTED); break;
+ case ACC_PRIVATE: emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); break;
+ default: break; // package-private adds no modifiers
+ }
+ if (cfg.allStatic()) {
+ emitter.addModifier(JavaMethodBindingEmitter.STATIC);
+ }
+ if (!isUnimplemented && !needsBody && !signatureOnly) {
+ emitter.addModifier(JavaMethodBindingEmitter.NATIVE);
+ }
+ emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName()));
+ emitter.setPrologue(prologue);
+ emitter.setEpilogue(epilogue);
+ allEmitters.add(emitter);
+ }
+
+ /**
+ * Generates the private emitters for this MethodBinding. On the
+ * Java side these will simply produce signatures for native
+ * methods. On the C side these will create the emitters which will
+ * write the JNI code to interface to the functions. We need to be
+ * careful to make the signatures all match up and not produce too
+ * many emitters which would lead to compilation errors from
+ * creating duplicated methods / functions.
+ */
+ protected void generatePrivateEmitters(MethodBinding binding,
+ List allEmitters) {
+ if (cfg.manuallyImplement(binding.getName())) {
+ // Don't produce emitters for the implementation class
+ return;
+ }
+
+ boolean hasPrologueOrEpilogue =
+ ((cfg.javaPrologueForMethod(binding, false, false) != null) ||
+ (cfg.javaEpilogueForMethod(binding, false, false) != null));
+
+ // If we already generated a public native entry point for this
+ // method, don't emit another one
+ if (!cfg.isUnimplemented(binding.getName()) &&
+ (binding.needsNIOWrappingOrUnwrapping() ||
+ binding.signatureUsesJavaPrimitiveArrays() ||
+ hasPrologueOrEpilogue)) {
+ PrintWriter writer = (cfg.allStatic() ? javaWriter() : javaImplWriter());
+
+ // If the binding uses primitive arrays, we are going to emit
+ // the private native entry point for it along with the version
+ // taking only NIO buffers
+ if (!binding.signatureUsesJavaPrimitiveArrays()) {
+ // (Always) emit the entry point taking only direct buffers
+ JavaMethodBindingEmitter emitter =
+ new JavaMethodBindingEmitter(binding,
+ writer,
+ cfg.runtimeExceptionType(),
+ cfg.unsupportedExceptionType(),
+ false,
+ cfg.tagNativeBinding(),
+ true,
+ cfg.nioDirectOnly(binding.getName()),
+ true,
+ true,
+ false,
+ false,
+ false,
+ cfg);
+ emitter.addModifier(JavaMethodBindingEmitter.PRIVATE);
+ if (cfg.allStatic()) {
+ emitter.addModifier(JavaMethodBindingEmitter.STATIC);
+ }
+ emitter.addModifier(JavaMethodBindingEmitter.NATIVE);
+ emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName()));
+ allEmitters.add(emitter);
+
+ // Optionally emit the entry point taking arrays which handles
+ // both the public entry point taking arrays as well as the
+ // indirect buffer case
+ if (!cfg.nioDirectOnly(binding.getName()) &&
+ binding.signatureCanUseIndirectNIO()) {
+ emitter =
+ new JavaMethodBindingEmitter(binding,
+ writer,
+ cfg.runtimeExceptionType(),
+ cfg.unsupportedExceptionType(),
+ false,
+ cfg.tagNativeBinding(),
+ true,
+ false,
+ true,
+ false,
+ true,
+ false,
+ false,
+ cfg);
+
+ emitter.addModifier(JavaMethodBindingEmitter.PRIVATE);
+ if (cfg.allStatic()) {
+ emitter.addModifier(JavaMethodBindingEmitter.STATIC);
+ }
+ emitter.addModifier(JavaMethodBindingEmitter.NATIVE);
+ emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName()));
+ allEmitters.add(emitter);
+ }
+ }
+ }
+
+ // Now generate the C emitter(s). We need to produce one for every
+ // Java native entry point (public or private). The only
+ // situations where we don't produce one are (a) when the method
+ // is unimplemented, and (b) when the signature contains primitive
+ // arrays, since the latter is handled by the method binding
+ // variant taking only NIO Buffers.
+ if (!cfg.isUnimplemented(binding.getName()) &&
+ !binding.signatureUsesJavaPrimitiveArrays()) {
+ // See whether we need an expression to help calculate the
+ // length of any return type
+ MessageFormat returnValueCapacityFormat = null;
+ MessageFormat returnValueLengthFormat = null;
+ JavaType javaReturnType = binding.getJavaReturnType();
+ if (javaReturnType.isNIOBuffer() ||
+ javaReturnType.isCompoundTypeWrapper()) {
+ // See whether capacity has been specified
+ String capacity = cfg.returnValueCapacity(binding.getName());
+ if (capacity != null) {
+ returnValueCapacityFormat = new MessageFormat(capacity);
+ }
+ } else if (javaReturnType.isArray() ||
+ javaReturnType.isArrayOfCompoundTypeWrappers()) {
+ // NOTE: adding a check here because the CMethodBindingEmitter
+ // also doesn't yet handle returning scalar arrays. In order
+ // to implement this, return the type as a Buffer instead
+ // (i.e., IntBuffer, FloatBuffer) and add code as necessary.
+ if (javaReturnType.isPrimitiveArray()) {
+ throw new RuntimeException("Primitive array return types not yet supported");
+ }
+
+ // See whether length has been specified
+ String len = cfg.returnValueLength(binding.getName());
+ if (len != null) {
+ returnValueLengthFormat = new MessageFormat(len);
+ }
+ }
+
+ CMethodBindingEmitter cEmitter =
+ new CMethodBindingEmitter(binding,
+ cWriter(),
+ cfg.implPackageName(),
+ cfg.implClassName(),
+ true, /* NOTE: we always disambiguate with a suffix now, so this is optional */
+ cfg.allStatic(),
+ (binding.needsNIOWrappingOrUnwrapping() || hasPrologueOrEpilogue),
+ false,
+ machDesc64);
+ if (returnValueCapacityFormat != null) {
+ cEmitter.setReturnValueCapacityExpression(returnValueCapacityFormat);
+ }
+ if (returnValueLengthFormat != null) {
+ cEmitter.setReturnValueLengthExpression(returnValueLengthFormat);
+ }
+ cEmitter.setTemporaryCVariableDeclarations(cfg.temporaryCVariableDeclarations(binding.getName()));
+ cEmitter.setTemporaryCVariableAssignments(cfg.temporaryCVariableAssignments(binding.getName()));
+ allEmitters.add(cEmitter);
+
+ // Now see if we have to emit another entry point to handle the
+ // indirect buffer and array case
+ if (binding.argumentsUseNIO() &&
+ binding.signatureCanUseIndirectNIO() &&
+ !cfg.nioDirectOnly(binding.getName())) {
+ cEmitter =
+ new CMethodBindingEmitter(binding,
+ cWriter(),
+ cfg.implPackageName(),
+ cfg.implClassName(),
+ true, /* NOTE: we always disambiguate with a suffix now, so this is optional */
+ cfg.allStatic(),
+ binding.needsNIOWrappingOrUnwrapping(),
+ true,
+ machDesc64);
+ if (returnValueCapacityFormat != null) {
+ cEmitter.setReturnValueCapacityExpression(returnValueCapacityFormat);
+ }
+ if (returnValueLengthFormat != null) {
+ cEmitter.setReturnValueLengthExpression(returnValueLengthFormat);
+ }
+ cEmitter.setTemporaryCVariableDeclarations(cfg.temporaryCVariableDeclarations(binding.getName()));
+ cEmitter.setTemporaryCVariableAssignments(cfg.temporaryCVariableAssignments(binding.getName()));
+ allEmitters.add(cEmitter);
+ }
+ }
+ }
+
+ /**
+ * Generate all appropriate Java bindings for the specified C function
+ * symbols.
+ */
+ protected List generateMethodBindingEmitters(FunctionSymbol sym) throws Exception {
+
+ ArrayList/*<FunctionEmitter>*/ allEmitters = new ArrayList();
+
+ try {
+ // Get Java binding for the function
+ MethodBinding mb = bindFunction(sym, null, null, machDesc64);
+
+ // JavaTypes representing C pointers in the initial
+ // MethodBinding have not been lowered yet to concrete types
+ List bindings = expandMethodBinding(mb);
+
+ for (Iterator iter = bindings.iterator(); iter.hasNext(); ) {
+ MethodBinding binding = (MethodBinding) iter.next();
+
+ 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 + "\"");
+ }
+
+ // The structure of the generated glue code looks something like this:
+ // Simple method (no arrays, void pointers, etc.):
+ // Interface class:
+ // public void fooMethod();
+ // Implementation class:
+ // public native void fooMethod();
+ //
+ // Method taking void* argument:
+ // Interface class:
+ // public void fooMethod(Buffer arg);
+ // Implementation class:
+ // public void fooMethod(Buffer arg) {
+ // ... bounds checks, etc. ...
+ // if (arg.isDirect()) {
+ // fooMethod0(arg, computeDirectBufferByteOffset(arg));
+ // } else {
+ // fooMethod1(getIndirectBufferArray(arg), computeIndirectBufferByteOffset(arg));
+ // }
+ // }
+ // private native void fooMethod0(Object arg, int arg_byte_offset);
+ // private native void fooMethod1(Object arg, int arg_byte_offset);
+ //
+ // Method taking primitive array argument:
+ // Interface class:
+ // public void fooMethod(int[] arg, int arg_offset);
+ // public void fooMethod(IntBuffer arg);
+ // Implementing class:
+ // public void fooMethod(int[] arg, int arg_offset) {
+ // ... range checks, etc. ...
+ // fooMethod1(arg, SIZEOF_INT * arg_offset);
+ // }
+ // public void fooMethod(IntBuffer arg) {
+ // ... bounds checks, etc. ...
+ // if (arg.isDirect()) {
+ // fooMethod0(arg, computeDirectBufferByteOffset(arg));
+ // } else {
+ // fooMethod1(getIndirectBufferArray(arg), computeIndirectBufferByteOffset(arg));
+ // }
+ // }
+ // private native void fooMethod0(Object arg, int arg_byte_offset);
+ // private native void fooMethod1(Object arg, int arg_byte_offset);
+ //
+ // Note in particular that the public entry point taking an
+ // array is merely a special case of the indirect buffer case.
+
+ if (cfg.emitInterface()) {
+ generatePublicEmitters(binding, allEmitters, true);
+ }
+ if (cfg.emitImpl()) {
+ generatePublicEmitters(binding, allEmitters, false);
+ generatePrivateEmitters(binding, allEmitters);
+ }
+ } // end iteration over expanded bindings
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Error while generating bindings for \"" + sym + "\"", e);
+ }
+
+ return allEmitters;
+ }
+
+
+ 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, String alternateName) throws Exception {
+ // Emit abstract base class delegating to 32-bit or 64-bit implementations
+ emitStructImpl(structType, alternateName, machDesc32, machDesc64, true, false);
+ // Emit concrete implementing class for each variant
+ emitStructImpl(structType, alternateName, machDesc32, machDesc64, false, true);
+ emitStructImpl(structType, alternateName, machDesc32, machDesc64, false, false);
+ }
+
+ public void emitStructImpl(CompoundType structType,
+ String alternateName,
+ MachineDescription md32,
+ MachineDescription md64,
+ boolean doBaseClass,
+ boolean do32Bit) throws Exception {
+ String name = structType.getName();
+ if (name == null && alternateName != null) {
+ name = alternateName;
+ }
+
+ if (name == null) {
+ System.err.println("WARNING: skipping emission of unnamed struct \"" + structType + "\"");
+ return;
+ }
+
+ if (cfg.shouldIgnoreInInterface(name)) {
+ return;
+ }
+
+ Type containingCType = canonicalize(new PointerType(SizeThunk.POINTER, structType, 0));
+ JavaType containingType = typeToJavaType(containingCType, false, null);
+ if (!containingType.isCompoundTypeWrapper()) {
+ return;
+ }
+ String containingTypeName = containingType.getName();
+
+ if ((md32 == null) || (md64 == null)) {
+ throw new RuntimeException("Must supply both 32- and 64-bit MachineDescriptions to emitStructImpl");
+ }
+ String suffix = "";
+
+ // The "external" MachineDescription is the one used to determine
+ // the sizes of the primitive types seen in the public API. For
+ // example, if a C long is an element of a struct, it is the size
+ // of a Java int on a 32-bit machine but the size of a Java long
+ // on a 64-bit machine. To support both of these sizes with the
+ // same API, the abstract base class must take and return a Java
+ // long from the setter and getter for this field. However the
+ // implementation on a 32-bit platform must downcast this to an
+ // int and set only an int's worth of data in the struct. The
+ // "internal" MachineDescription is the one used to determine how
+ // much data to set in or get from the struct and exactly from
+ // where it comes.
+ //
+ // Note that the 64-bit MachineDescription is always used as the
+ // external MachineDescription.
+
+ MachineDescription extMachDesc = md64;
+ MachineDescription intMachDesc = null;
+
+ if (!doBaseClass) {
+ if (do32Bit) {
+ intMachDesc = md32;
+ suffix = "32";
+ } else {
+ intMachDesc = md64;
+ suffix = "64";
+ }
+ }
+
+ boolean needsNativeCode = false;
+ // Native code for calls through function pointers gets emitted
+ // into the abstract base class; Java code which accesses fields
+ // gets emitted into the concrete classes
+ if (doBaseClass) {
+ for (int i = 0; i < structType.getNumFields(); i++) {
+ if (structType.getField(i).getType().isFunctionPointer()) {
+ needsNativeCode = true;
+ break;
+ }
+ }
+ }
+
+ String structClassPkg = cfg.packageForStruct(name);
+ PrintWriter writer = null;
+ PrintWriter cWriter = null;
+ try
+ {
+ writer = openFile(
+ cfg.javaOutputDir() + File.separator +
+ CodeGenUtils.packageAsPath(structClassPkg) +
+ File.separator + containingTypeName + suffix + ".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 " + cfg.gluegenRuntimePackage() + ".*;");
+ writer.println();
+ List/*<String>*/ imports = cfg.imports();
+ for (Iterator iter = imports.iterator(); iter.hasNext(); ) {
+ writer.print("import ");
+ writer.print(iter.next());
+ writer.println(";");
+ }
+ List/*<String>*/ javadoc = cfg.javadocForClass(containingTypeName);
+ for (Iterator iter = javadoc.iterator(); iter.hasNext(); ) {
+ writer.println((String) iter.next());
+ }
+ writer.println();
+ writer.print((doBaseClass ? "public " : "") + (doBaseClass ? "abstract " : "") + "class " + containingTypeName + suffix + " ");
+ if (!doBaseClass) {
+ writer.print("extends " + containingTypeName + " ");
+ }
+ boolean firstIteration = true;
+ List/*<String>*/ userSpecifiedInterfaces = cfg.implementedInterfaces(containingTypeName);
+ for (Iterator iter = userSpecifiedInterfaces.iterator(); iter.hasNext(); ) {
+ if (firstIteration) {
+ writer.print("implements ");
+ }
+ firstIteration = false;
+ writer.print(iter.next());
+ writer.print(" ");
+ }
+ writer.println("{");
+ if (doBaseClass) {
+ writer.println(" StructAccessor accessor;");
+ writer.println();
+ }
+ writer.println(" public static int size() {");
+ if (doBaseClass) {
+ writer.println(" if (CPU.is32Bit()) {");
+ writer.println(" return " + containingTypeName + "32" + ".size();");
+ writer.println(" } else {");
+ writer.println(" return " + containingTypeName + "64" + ".size();");
+ writer.println(" }");
+ } else {
+ writer.println(" return " + structType.getSize(intMachDesc) + ";");
+ }
+ writer.println(" }");
+ writer.println();
+ if (doBaseClass) {
+ writer.println(" public static " + containingTypeName + " create() {");
+ writer.println(" return create(BufferFactory.newDirectByteBuffer(size()));");
+ writer.println(" }");
+ writer.println();
+ writer.println(" public static " + containingTypeName + " create(java.nio.ByteBuffer buf) {");
+ writer.println(" if (CPU.is32Bit()) {");
+ writer.println(" return new " + containingTypeName + "32(buf);");
+ writer.println(" } else {");
+ writer.println(" return new " + containingTypeName + "64(buf);");
+ writer.println(" }");
+ writer.println(" }");
+ writer.println();
+ writer.println(" " + containingTypeName + "(java.nio.ByteBuffer buf) {");
+ writer.println(" accessor = new StructAccessor(buf);");
+ writer.println(" }");
+ writer.println();
+ writer.println(" public java.nio.ByteBuffer getBuffer() {");
+ writer.println(" return accessor.getBuffer();");
+ writer.println(" }");
+ } else {
+ writer.println(" " + containingTypeName + suffix + "(java.nio.ByteBuffer buf) {");
+ writer.println(" super(buf);");
+ writer.println(" }");
+ writer.println();
+ }
+ for (int i = 0; i < structType.getNumFields(); i++) {
+ Field field = structType.getField(i);
+ Type fieldType = field.getType();
+ if (!cfg.shouldIgnoreInInterface(name + " " + field.getName())) {
+ if (fieldType.isFunctionPointer()) {
+ if (doBaseClass) {
+ 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, machDesc64);
+ binding.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis
+ writer.println();
+
+ // Emit public Java entry point for calling this function pointer
+ JavaMethodBindingEmitter emitter =
+ new JavaMethodBindingEmitter(binding,
+ writer,
+ cfg.runtimeExceptionType(),
+ cfg.unsupportedExceptionType(),
+ true,
+ cfg.tagNativeBinding(),
+ false,
+ true, // FIXME: should unify this with the general emission code
+ false,
+ false, // FIXME: should unify this with the general emission code
+ false, // FIXME: should unify this with the general emission code
+ false, // FIXME: should unify this with the general emission code
+ false,
+ cfg);
+ emitter.addModifier(JavaMethodBindingEmitter.PUBLIC);
+ emitter.emit();
+
+ // Emit private native Java entry point for calling this function pointer
+ emitter =
+ new JavaMethodBindingEmitter(binding,
+ writer,
+ cfg.runtimeExceptionType(),
+ cfg.unsupportedExceptionType(),
+ false,
+ cfg.tagNativeBinding(),
+ true,
+ true, // FIXME: should unify this with the general emission code
+ true,
+ true, // FIXME: should unify this with the general emission code
+ false, // FIXME: should unify this with the general emission code
+ false, // FIXME: should unify this with the general emission code
+ false,
+ cfg);
+ emitter.addModifier(JavaMethodBindingEmitter.PRIVATE);
+ emitter.addModifier(JavaMethodBindingEmitter.NATIVE);
+ emitter.emit();
+
+ // Emit (private) C entry point for calling this function pointer
+ CMethodBindingEmitter cEmitter =
+ new CMethodBindingEmitter(binding,
+ cWriter,
+ structClassPkg,
+ containingTypeName,
+ true, // FIXME: this is optional at this point
+ false,
+ true,
+ false, // FIXME: should unify this with the general emission code
+ machDesc64);
+ cEmitter.emit();
+ } catch (Exception e) {
+ System.err.println("While processing field " + field + " of type " + name + ":");
+ 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 \"" + name + "\")");
+ }
+
+ writer.println();
+ writer.print(" public " + (doBaseClass ? "abstract " : "") + fieldType.getName() + " " + field.getName() + "()");
+ if (doBaseClass) {
+ writer.println(";");
+ } else {
+ writer.println(" {");
+ writer.println(" return " + fieldType.getName() + ".create(accessor.slice(" +
+ field.getOffset(intMachDesc) + ", " + fieldType.getSize(intMachDesc) + "));");
+ writer.println(" }");
+ }
+ // FIXME: add setter by autogenerating "copyTo" for all compound type wrappers
+ } else if (fieldType.isArray()) {
+ if (!doBaseClass) {
+ System.err.println("WARNING: Array fields (field \"" + field + "\" of type \"" + name +
+ "\") not implemented yet");
+ }
+ } else {
+ JavaType internalJavaType = null;
+ JavaType externalJavaType = null;
+
+ try {
+ externalJavaType = typeToJavaType(fieldType, false, extMachDesc);
+ if (!doBaseClass) {
+ internalJavaType = typeToJavaType(fieldType, false, intMachDesc);
+ }
+ } catch (Exception e) {
+ System.err.println("Error occurred while creating accessor for field \"" +
+ field.getName() + "\" in type \"" + name + "\"");
+ e.printStackTrace();
+ throw(e);
+ }
+ if (externalJavaType.isPrimitive()) {
+ // Primitive type
+ String externalJavaTypeName = null;
+ String internalJavaTypeName = null;
+ externalJavaTypeName = externalJavaType.getName();
+ if (!doBaseClass) {
+ internalJavaTypeName = internalJavaType.getName();
+ }
+ if (isOpaque(fieldType)) {
+ externalJavaTypeName = compatiblePrimitiveJavaTypeName(fieldType, externalJavaType, extMachDesc);
+ if (!doBaseClass) {
+ internalJavaTypeName = compatiblePrimitiveJavaTypeName(fieldType, internalJavaType, intMachDesc);
+ }
+ }
+ String capitalized = null;
+ if (!doBaseClass) {
+ capitalized =
+ "" + Character.toUpperCase(internalJavaTypeName.charAt(0)) + internalJavaTypeName.substring(1);
+ }
+ int slot = -1;
+ if (!doBaseClass) {
+ slot = slot(fieldType, (int) field.getOffset(intMachDesc), intMachDesc);
+ }
+ // Setter
+ writer.println();
+ writer.print(" public " + (doBaseClass ? "abstract " : "") + containingTypeName + " " + field.getName() + "(" + externalJavaTypeName + " val)");
+ if (doBaseClass) {
+ writer.println(";");
+ } else {
+ writer.println(" {");
+ writer.print (" accessor.set" + capitalized + "At(" + slot + ", ");
+ if (!externalJavaTypeName.equals(internalJavaTypeName)) {
+ writer.print("(" + internalJavaTypeName + ") ");
+ }
+ writer.println("val);");
+ writer.println(" return this;");
+ writer.println(" }");
+ }
+ writer.println();
+ // Getter
+ writer.print(" public " + (doBaseClass ? "abstract " : "") + externalJavaTypeName + " " + field.getName() + "()");
+ if (doBaseClass) {
+ writer.println(";");
+ } else {
+ writer.println(" {");
+ writer.print (" return ");
+ if (!externalJavaTypeName.equals(internalJavaTypeName)) {
+ writer.print("(" + externalJavaTypeName + ") ");
+ }
+ writer.println("accessor.get" + capitalized + "At(" + slot + ");");
+ writer.println(" }");
+ }
+ } else {
+ // FIXME
+ 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");
+ }
+ }
+ }
+ }
+ if (doBaseClass) {
+ 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 JavaType typeToJavaType(Type cType, boolean outgoingArgument, MachineDescription curMachDesc) {
+ // 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 ((int) t.getSize(curMachDesc)) {
+ 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(curMachDesc) + " 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 || t.arrayDimension() > 0) {
+ 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[]; these are expanded out into Java primitive
+ // arrays, NIO buffers, or both in expandMethodBinding
+ if (t.pointerDepth() == 1 || t.arrayDimension() == 1) {
+ if (targetType.isVoid()) {
+ return JavaType.createForVoidPointer();
+ } else if (targetType.isInt()) {
+ switch ((int) targetType.getSize(curMachDesc)) {
+ case 1: return JavaType.createForCCharPointer();
+ case 2: return JavaType.createForCShortPointer();
+ case 4: return JavaType.createForCInt32Pointer();
+ case 8: return JavaType.createForCInt64Pointer();
+ default: throw new RuntimeException("Unknown integer array type of size " +
+ t.getSize(curMachDesc) + " and name " + t.getName());
+ }
+ } else if (targetType.isFloat()) {
+ return JavaType.createForCFloatPointer();
+ } else if (targetType.isDouble()) {
+ return JavaType.createForCDoublePointer();
+ } 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 (t.getName() != null &&
+ t.getName().equals("jobject")) {
+ return javaType(java.lang.Object.class);
+ }
+
+ String name = targetType.getName();
+ if (name == null) {
+ // Try containing pointer type for any typedefs
+ name = t.getName();
+ if (name == null) {
+ throw new RuntimeException("Couldn't find a proper type name for pointer type " + t);
+ }
+ }
+
+ return JavaType.createForCStruct(cfg.renameJavaType(name));
+ } 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 || t.arrayDimension() == 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)
+ Type bottomType;
+ if (targetType.isPointer()) {
+ // t is<type>**, targetType is <type>*, we need to get <type>
+ bottomType = targetType.asPointer().getTargetType();
+ } else {
+ // t is<type>[][], targetType is <type>[], we need to get <type>
+ bottomType = targetType.asArray().getElementType();
+ }
+
+ if (bottomType.isPrimitive()) {
+ if (bottomType.isInt()) {
+ switch ((int) bottomType.getSize(curMachDesc)) {
+ case 1: return javaType(ArrayTypes.byteBufferArrayClass);
+ case 2: return javaType(ArrayTypes.shortBufferArrayClass);
+ case 4: return javaType(ArrayTypes.intBufferArrayClass);
+ case 8: return javaType(ArrayTypes.longBufferArrayClass);
+ default: throw new RuntimeException("Unknown two-dimensional integer array type of element size " +
+ bottomType.getSize(curMachDesc) + " and name " + bottomType.getName());
+ }
+ } else if (bottomType.isFloat()) {
+ return javaType(ArrayTypes.floatBufferArrayClass);
+ } else if (bottomType.isDouble()) {
+ return javaType(ArrayTypes.doubleBufferArrayClass);
+ } else {
+ throw new RuntimeException("Unexpected primitive type " + bottomType.getName() +
+ " in two-dimensional array");
+ }
+ } else if (bottomType.isVoid()) {
+ return javaType(ArrayTypes.bufferArrayClass);
+ } else if (targetType.isPointer() && (targetType.pointerDepth() == 1) &&
+ targetType.asPointer().getTargetType().isCompound()) {
+ // Array of pointers; convert as array of StructAccessors
+ return JavaType.createForCArray(bottomType);
+ } else {
+ throw new RuntimeException(
+ "Could not convert C type \"" + t + "\" " +
+ "to appropriate Java type; need to add more support for " +
+ "depth=2 pointer/array 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=" +
+ t.arrayDimension() + " targetType=\"" + targetType + "\"]");
+ }
+
+ } else {
+ throw new RuntimeException(
+ "Could not convert C type \"" + t + "\" (class " +
+ t.getClass().getName() + ") 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, MachineDescription curMachDesc) {
+ if (t.isInt()) {
+ switch ((int) t.getSize(curMachDesc)) {
+ case 1:
+ case 2:
+ case 4:
+ case 8: return byteOffset / (int) t.getSize(curMachDesc);
+ 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 / curMachDesc.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 boolean isOpaque(Type type) {
+ return (cfg.typeInfo(type, typedefDictionary) != null);
+ }
+
+ private String compatiblePrimitiveJavaTypeName(Type fieldType,
+ JavaType javaType,
+ MachineDescription curMachDesc) {
+ 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 ((int) fieldType.getSize(curMachDesc)) {
+ 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 = null;
+ if (cfg.allStatic() || cfg.emitInterface()) {
+ 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;
+ List userSpecifiedInterfaces = null;
+ if (cfg.emitInterface()) {
+ userSpecifiedInterfaces = cfg.extendedInterfaces(cfg.className());
+ } else {
+ userSpecifiedInterfaces = cfg.implementedInterfaces(cfg.className());
+ }
+ interfaces = new String[userSpecifiedInterfaces.size()];
+ userSpecifiedInterfaces.toArray(interfaces);
+
+ 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());
+ }
+ }
+ };
+
+ String[] accessModifiers = null;
+ if(cfg.accessControl(cfg.className())==ACC_PUBLIC_ABSTRACT) {
+ accessModifiers = new String[] { "public", "abstract" };
+ } else {
+ accessModifiers = new String[] { "public" };
+ }
+
+ CodeGenUtils.emitJavaHeaders(
+ javaWriter,
+ cfg.packageName(),
+ cfg.className(),
+ cfg.gluegenRuntimePackage(),
+ cfg.allStatic() ? true : false,
+ (String[]) cfg.imports().toArray(new String[] {}),
+ accessModifiers,
+ interfaces,
+ cfg.extendedParentClass(cfg.className()),
+ docEmitter);
+ }
+
+ if (!cfg.allStatic() && cfg.emitImpl()) {
+ final List/*<String>*/ implDocs = cfg.javadocForClass(cfg.implClassName());
+ CodeGenUtils.EmissionCallback docEmitter =
+ new CodeGenUtils.EmissionCallback() {
+ public void emit(PrintWriter w) {
+ for (Iterator iter = implDocs.iterator(); iter.hasNext(); ) {
+ w.println((String) iter.next());
+ }
+ }
+ };
+
+ String[] interfaces;
+ List userSpecifiedInterfaces = null;
+ userSpecifiedInterfaces = cfg.implementedInterfaces(cfg.implClassName());
+ int additionalNum = 0;
+ if (cfg.className() != null) {
+ additionalNum = 1;
+ }
+ interfaces = new String[additionalNum + userSpecifiedInterfaces.size()];
+ userSpecifiedInterfaces.toArray(interfaces);
+ if (additionalNum == 1) {
+ interfaces[userSpecifiedInterfaces.size()] = cfg.className();
+ }
+
+ String[] accessModifiers = null;
+ if(cfg.accessControl(cfg.implClassName())==ACC_PUBLIC_ABSTRACT) {
+ accessModifiers = new String[] { "public", "abstract" };
+ } else {
+ accessModifiers = new String[] { "public" };
+ }
+
+ CodeGenUtils.emitJavaHeaders(
+ javaImplWriter,
+ cfg.implPackageName(),
+ cfg.implClassName(),
+ cfg.gluegenRuntimePackage(),
+ true,
+ (String[]) cfg.imports().toArray(new String[] {}),
+ accessModifiers,
+ interfaces,
+ cfg.extendedParentClass(cfg.implClassName()),
+ 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("#include <stdlib.h>");
+ cWriter.println();
+
+ if (getConfig().emitImpl()) {
+ cWriter.println("#include <assert.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);
+ }
+
+ /** Maps the C types in the specified function to Java types through
+ the MethodBinding interface. Note that the JavaTypes in the
+ returned MethodBinding are "intermediate" JavaTypes (some
+ potentially representing C pointers rather than true Java types)
+ and must be lowered to concrete Java types before creating
+ emitters for them. */
+ private MethodBinding bindFunction(FunctionSymbol sym,
+ JavaType containingType,
+ Type containingCType,
+ MachineDescription curMachDesc) {
+
+ MethodBinding binding = new MethodBinding(sym, containingType, containingCType);
+
+ binding.setRenamedMethodName(cfg.getJavaSymbolRename(sym.getName()));
+
+ if (cfg.returnsString(binding.getName())) {
+ PointerType prt = sym.getReturnType().asPointer();
+ if (prt == null ||
+ prt.getTargetType().asInt() == null ||
+ prt.getTargetType().getSize(curMachDesc) != 1) {
+ throw new RuntimeException(
+ "Cannot apply ReturnsString configuration directive to \"" + sym +
+ "\". ReturnsString requires native method to have return type \"char *\"");
+ }
+ binding.setJavaReturnType(javaType(java.lang.String.class));
+ } else {
+ binding.setJavaReturnType(typeToJavaType(sym.getReturnType(), false, curMachDesc));
+ }
+
+ // List of the indices of the arguments in this function that should be
+ // converted from byte[] or short[] 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, curMachDesc);
+ //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.isCVoidPointerType() ||
+ mappedType.isCCharPointerType() ||
+ mappedType.isCShortPointerType() ||
+ (mappedType.isArray() &&
+ (mappedType.getJavaClass() == ArrayTypes.byteBufferArrayClass) ||
+ (mappedType.getJavaClass() == ArrayTypes.shortBufferArrayClass))) {
+ // convert mapped type from:
+ // void*, byte[], and short[] to String
+ // ByteBuffer[] and ShortBuffer[] to String[]
+ if (mappedType.isArray()) {
+ 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 *\", \"short *\", \"char**\", or \"short**\" 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;
+ }
+
+ private MethodBinding lowerMethodBindingPointerTypes(MethodBinding inputBinding,
+ boolean convertToArrays,
+ boolean[] canProduceArrayVariant) {
+ MethodBinding result = inputBinding;
+ boolean arrayPossible = false;
+
+ for (int i = 0; i < inputBinding.getNumArguments(); i++) {
+ JavaType t = inputBinding.getJavaArgumentType(i);
+ if (t.isCPrimitivePointerType()) {
+ if (t.isCVoidPointerType()) {
+ // These are always bound to java.nio.Buffer
+ result = result.replaceJavaArgumentType(i, JavaType.forNIOBufferClass());
+ } else if (t.isCCharPointerType()) {
+ arrayPossible = true;
+ if (convertToArrays) {
+ result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.byteArrayClass));
+ } else {
+ result = result.replaceJavaArgumentType(i, JavaType.forNIOByteBufferClass());
+ }
+ } else if (t.isCShortPointerType()) {
+ arrayPossible = true;
+ if (convertToArrays) {
+ result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.shortArrayClass));
+ } else {
+ result = result.replaceJavaArgumentType(i, JavaType.forNIOShortBufferClass());
+ }
+ } else if (t.isCInt32PointerType()) {
+ arrayPossible = true;
+ if (convertToArrays) {
+ result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.intArrayClass));
+ } else {
+ result = result.replaceJavaArgumentType(i, JavaType.forNIOIntBufferClass());
+ }
+ } else if (t.isCInt64PointerType()) {
+ arrayPossible = true;
+ if (convertToArrays) {
+ result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.longArrayClass));
+ } else {
+ result = result.replaceJavaArgumentType(i, JavaType.forNIOLongBufferClass());
+ }
+ } else if (t.isCFloatPointerType()) {
+ arrayPossible = true;
+ if (convertToArrays) {
+ result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.floatArrayClass));
+ } else {
+ result = result.replaceJavaArgumentType(i, JavaType.forNIOFloatBufferClass());
+ }
+ } else if (t.isCDoublePointerType()) {
+ arrayPossible = true;
+ if (convertToArrays) {
+ result = result.replaceJavaArgumentType(i, javaType(ArrayTypes.doubleArrayClass));
+ } else {
+ result = result.replaceJavaArgumentType(i, JavaType.forNIODoubleBufferClass());
+ }
+ } else {
+ throw new RuntimeException("Unknown C pointer type " + t);
+ }
+ }
+ }
+
+ // Always return primitive pointer types as NIO buffers
+ JavaType t = result.getJavaReturnType();
+ if (t.isCPrimitivePointerType()) {
+ if (t.isCVoidPointerType()) {
+ result = result.replaceJavaArgumentType(-1, JavaType.forNIOByteBufferClass());
+ } else if (t.isCCharPointerType()) {
+ result = result.replaceJavaArgumentType(-1, JavaType.forNIOByteBufferClass());
+ } else if (t.isCShortPointerType()) {
+ result = result.replaceJavaArgumentType(-1, JavaType.forNIOShortBufferClass());
+ } else if (t.isCInt32PointerType()) {
+ result = result.replaceJavaArgumentType(-1, JavaType.forNIOIntBufferClass());
+ } else if (t.isCInt64PointerType()) {
+ result = result.replaceJavaArgumentType(-1, JavaType.forNIOLongBufferClass());
+ } else if (t.isCFloatPointerType()) {
+ result = result.replaceJavaArgumentType(-1, JavaType.forNIOFloatBufferClass());
+ } else if (t.isCDoublePointerType()) {
+ result = result.replaceJavaArgumentType(-1, JavaType.forNIODoubleBufferClass());
+ } else {
+ throw new RuntimeException("Unknown C pointer type " + t);
+ }
+ }
+
+ if (canProduceArrayVariant != null) {
+ canProduceArrayVariant[0] = arrayPossible;
+ }
+
+ return result;
+ }
+
+ // Expands a MethodBinding containing C primitive pointer types into
+ // multiple variants taking Java primitive arrays and NIO buffers, subject
+ // to the per-function "NIO only" rule in the configuration file
+ protected List/*<MethodBinding>*/ expandMethodBinding(MethodBinding binding) {
+ List result = new ArrayList();
+ // Indicates whether it is possible to produce an array variant
+ // Prevents e.g. char* -> String conversions from emitting two entry points
+ boolean[] canProduceArrayVariant = new boolean[1];
+
+ if (binding.signatureUsesCPrimitivePointers() ||
+ binding.signatureUsesCVoidPointers() ||
+ binding.signatureUsesCArrays()) {
+ result.add(lowerMethodBindingPointerTypes(binding, false, canProduceArrayVariant));
+
+ // FIXME: should add new configuration flag for this
+ if (canProduceArrayVariant[0] &&
+ (binding.signatureUsesCPrimitivePointers() ||
+ binding.signatureUsesCArrays()) &&
+ !cfg.nioDirectOnly(binding.getName()) &&
+ !cfg.nioOnly(binding.getName())) {
+ result.add(lowerMethodBindingPointerTypes(binding, true, null));
+ }
+ } else {
+ result.add(binding);
+ }
+
+ 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/java/com/sun/gluegen/JavaMethodBindingEmitter.java b/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java
new file mode 100644
index 0000000..d7fa7c4
--- /dev/null
+++ b/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java
@@ -0,0 +1,873 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.io.*;
+import java.util.*;
+import java.text.MessageFormat;
+
+import com.sun.gluegen.cgram.types.*;
+import com.sun.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 final CommentEmitter defaultJavaCommentEmitter = new DefaultCommentEmitter();
+ protected final CommentEmitter defaultInterfaceCommentEmitter =
+ new InterfaceCommentEmitter();
+
+ // Exception type raised in the generated code if runtime checks fail
+ private String runtimeExceptionType;
+ private String unsupportedExceptionType;
+
+ protected boolean emitBody;
+ protected boolean eraseBufferAndArrayTypes;
+ protected boolean directNIOOnly;
+ protected boolean forImplementingMethodCall;
+ protected boolean forDirectBufferImplementation;
+ protected boolean forIndirectBufferAndArrayImplementation;
+ protected boolean isUnimplemented;
+ protected boolean tagNativeBinding;
+
+ protected MethodBinding binding;
+
+ // Manually-specified prologue and epilogue code
+ protected List/*<String>*/ prologue;
+ protected List/*<String>*/ epilogue;
+
+ // 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;
+
+ // A suffix used to create a temporary outgoing array of Buffers to
+ // represent an array of compound type wrappers
+ private static final String COMPOUND_ARRAY_SUFFIX = "_buf_array_copy";
+
+ // Only present to provide more clear comments
+ private JavaConfiguration cfg;
+
+ public JavaMethodBindingEmitter(MethodBinding binding,
+ PrintWriter output,
+ String runtimeExceptionType,
+ String unsupportedExceptionType,
+ boolean emitBody,
+ boolean tagNativeBinding,
+ boolean eraseBufferAndArrayTypes,
+ boolean directNIOOnly,
+ boolean forImplementingMethodCall,
+ boolean forDirectBufferImplementation,
+ boolean forIndirectBufferAndArrayImplementation,
+ boolean isUnimplemented,
+ boolean isInterface,
+ JavaConfiguration configuration)
+ {
+ super(output, isInterface);
+ this.binding = binding;
+ this.runtimeExceptionType = runtimeExceptionType;
+ this.unsupportedExceptionType = unsupportedExceptionType;
+ this.emitBody = emitBody;
+ this.tagNativeBinding = tagNativeBinding;
+ this.eraseBufferAndArrayTypes = eraseBufferAndArrayTypes;
+ this.directNIOOnly = directNIOOnly;
+ this.forImplementingMethodCall = forImplementingMethodCall;
+ this.forDirectBufferImplementation = forDirectBufferImplementation;
+ this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation;
+ this.isUnimplemented = isUnimplemented;
+ if (forImplementingMethodCall) {
+ setCommentEmitter(defaultJavaCommentEmitter);
+ } else {
+ setCommentEmitter(defaultInterfaceCommentEmitter);
+ }
+ cfg = configuration;
+ }
+
+ public JavaMethodBindingEmitter(JavaMethodBindingEmitter arg) {
+ super(arg);
+ binding = arg.binding;
+ runtimeExceptionType = arg.runtimeExceptionType;
+ unsupportedExceptionType = arg.unsupportedExceptionType;
+ emitBody = arg.emitBody;
+ tagNativeBinding = arg.tagNativeBinding;
+ eraseBufferAndArrayTypes = arg.eraseBufferAndArrayTypes;
+ directNIOOnly = arg.directNIOOnly;
+ forImplementingMethodCall = arg.forImplementingMethodCall;
+ forDirectBufferImplementation = arg.forDirectBufferImplementation;
+ forIndirectBufferAndArrayImplementation = arg.forIndirectBufferAndArrayImplementation;
+ isUnimplemented = arg.isUnimplemented;
+ prologue = arg.prologue;
+ epilogue = arg.epilogue;
+ returnedArrayLengthExpression = arg.returnedArrayLengthExpression;
+ cfg = arg.cfg;
+ }
+
+ public final MethodBinding getBinding() { return binding; }
+
+ public boolean isForImplementingMethodCall() { return forImplementingMethodCall; }
+ public boolean isForDirectBufferImplementation() { return forDirectBufferImplementation; }
+ public boolean isForIndirectBufferAndArrayImplementation() { return forIndirectBufferAndArrayImplementation; }
+
+ public String getName() {
+ return binding.getRenamedMethodName();
+ }
+
+ protected String getArgumentName(int i) {
+ return binding.getArgumentName(i);
+ }
+
+ /** 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;
+ }
+
+ public String getUnsupportedExceptionType() {
+ return unsupportedExceptionType;
+ }
+
+ /** 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;
+ }
+
+ /** Sets the manually-generated prologue code for this emitter. */
+ public void setPrologue(List/*<String>*/ prologue) {
+ this.prologue = prologue;
+ }
+
+ /** Sets the manually-generated epilogue code for this emitter. */
+ public void setEpilogue(List/*<String>*/ epilogue) {
+ this.epilogue = epilogue;
+ }
+
+ /** Indicates whether this emitter will print only a signature, or
+ whether it will emit Java code for the body of the method as
+ well. */
+ public boolean signatureOnly() {
+ return !emitBody;
+ }
+
+ /** Accessor for subclasses. */
+ public void setEmitBody(boolean emitBody) {
+ this.emitBody = emitBody;
+ }
+
+ /** Accessor for subclasses. */
+ public void setEraseBufferAndArrayTypes(boolean erase) {
+ this.eraseBufferAndArrayTypes = erase;
+ }
+
+ /** Accessor for subclasses. */
+ public void setForImplementingMethodCall(boolean impl) {
+ this.forImplementingMethodCall = impl;
+ }
+
+ /** Accessor for subclasses. */
+ public void setForDirectBufferImplementation(boolean direct) {
+ this.forDirectBufferImplementation = direct;
+ }
+
+ /** Accessor for subclasses. */
+ public void setForIndirectBufferAndArrayImplementation(boolean indirect) {
+ this.forIndirectBufferAndArrayImplementation = indirect;
+ }
+
+ protected void emitReturnType(PrintWriter writer)
+ {
+ writer.print(getReturnTypeString(false));
+ }
+
+ protected String erasedTypeString(JavaType type, boolean skipBuffers) {
+ if (eraseBufferAndArrayTypes) {
+ if (type.isNIOBuffer()) {
+ if (!skipBuffers) {
+ // Direct buffers and arrays sent down as Object (but
+ // returned as e.g. ByteBuffer)
+ return "Object";
+ }
+ if (!type.isNIOByteBuffer()) {
+ // Return buffer requiring change of view from ByteBuffer to e.g. LongBuffer
+ return "java.nio.ByteBuffer";
+ }
+ } else if (type.isPrimitiveArray()) {
+ if (!skipBuffers) {
+ // Direct buffers and arrays sent down as Object (but
+ // returned as e.g. ByteBuffer)
+ return "Object";
+ }
+ } else if (type.isNIOBufferArray()) {
+ // Arrays of direct Buffers sent down as Object[]
+ // (Note we don't yet support returning void**)
+ return "Object[]";
+ } else if (type.isCompoundTypeWrapper()) {
+ // Compound type wrappers are unwrapped to ByteBuffer
+ return "java.nio.ByteBuffer";
+ } else if (type.isArrayOfCompoundTypeWrappers()) {
+ if (skipBuffers) {
+ return "java.nio.ByteBuffer";
+ } else {
+ // In the case where this is called with a false skipBuffers
+ // argument we want to erase the array of compound type
+ // wrappers to ByteBuffer[]
+ return "java.nio.ByteBuffer[]";
+ }
+ }
+ }
+ if (type.isArrayOfCompoundTypeWrappers()) {
+ // We don't want to bake the array specification into the type name
+ return type.getName() + "[]";
+ }
+ return type.getName();
+ }
+
+ protected String getReturnTypeString(boolean skipArray) {
+ // The first arm of the "if" clause is used by the glue code
+ // generation for arrays of compound type wrappers
+ if (skipArray ||
+ // The following arm is used by most other kinds of return types
+ (getReturnedArrayLengthExpression() == null &&
+ !binding.getJavaReturnType().isArrayOfCompoundTypeWrappers()) ||
+ // The following arm is used specifically to get the splitting up
+ // of one returned ByteBuffer into an array of compound type
+ // wrappers to work (e.g., XGetVisualInfo)
+ (eraseBufferAndArrayTypes &&
+ binding.getJavaReturnType().isCompoundTypeWrapper() &&
+ (getReturnedArrayLengthExpression() != null))) {
+ return erasedTypeString(binding.getJavaReturnType(), true);
+ }
+ return erasedTypeString(binding.getJavaReturnType(), true) + "[]";
+ }
+
+ protected void emitName(PrintWriter writer)
+ {
+ if (forImplementingMethodCall) {
+ if (forIndirectBufferAndArrayImplementation) {
+ writer.print(getImplMethodName(false));
+ } else {
+ writer.print(getImplMethodName(true));
+ }
+ } else {
+ writer.print(getName());
+ }
+ }
+
+ protected int emitArguments(PrintWriter writer)
+ {
+ boolean needComma = false;
+ int numEmitted = 0;
+
+ if (forImplementingMethodCall && binding.hasContainingType()) {
+ // Always emit outgoing "this" argument
+ writer.print("java.nio.ByteBuffer ");
+ 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(erasedTypeString(type, false));
+ writer.print(" ");
+ writer.print(getArgumentName(i));
+
+ ++numEmitted;
+ needComma = true;
+
+ // Add Buffer and array index offset arguments after each associated argument
+ if (forDirectBufferImplementation || forIndirectBufferAndArrayImplementation) {
+ if (type.isNIOBuffer()) {
+ writer.print(", int " + byteOffsetArgName(i));
+ } else if (type.isNIOBufferArray()) {
+ writer.print(", int[] " +
+ byteOffsetArrayArgName(i));
+ }
+ }
+
+ // Add offset argument after each primitive array
+ if (type.isPrimitiveArray()) {
+ writer.print(", int " + offsetArgName(i));
+ }
+ }
+ return numEmitted;
+ }
+
+
+ protected String getImplMethodName(boolean direct) {
+ if (direct) {
+ return binding.getRenamedMethodName() + "0";
+ } else {
+ return binding.getRenamedMethodName() + "1";
+ }
+ }
+
+ protected String byteOffsetArgName(int i) {
+ return byteOffsetArgName(getArgumentName(i));
+ }
+
+ protected String byteOffsetArgName(String s) {
+ return s + "_byte_offset";
+ }
+
+ protected String byteOffsetArrayArgName(int i) {
+ return getArgumentName(i) + "_byte_offset_array";
+ }
+
+ protected String offsetArgName(int i) {
+ return getArgumentName(i) + "_offset";
+ }
+
+ protected void emitBody(PrintWriter writer)
+ {
+ if (!emitBody) {
+ writer.println(';');
+ } else {
+ MethodBinding binding = getBinding();
+ writer.println();
+ writer.println(" {");
+ if (isUnimplemented) {
+ writer.println(" throw new " + getUnsupportedExceptionType() + "(\"Unimplemented\");");
+ } else {
+ emitPrologueOrEpilogue(prologue, writer);
+ emitPreCallSetup(binding, writer);
+ //emitReturnVariableSetup(binding, writer);
+ emitReturnVariableSetupAndCall(binding, writer);
+ }
+ writer.println(" }");
+ }
+ }
+
+ protected void emitPrologueOrEpilogue(List/*<String>*/ code, PrintWriter writer) {
+ if (code != null) {
+ String[] argumentNames = argumentNameArray();
+ for (Iterator iter = code.iterator(); iter.hasNext(); ) {
+ String str = (String) iter.next();
+ try {
+ MessageFormat fmt = new MessageFormat(str);
+ writer.println(" " + fmt.format(argumentNames));
+ } catch (IllegalArgumentException e) {
+ // (Poorly) handle case where prologue / epilogue contains blocks of code with braces
+ writer.println(" " + str);
+ }
+ }
+ }
+ }
+
+ protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) {
+ emitArrayLengthAndNIOBufferChecks(binding, writer);
+ emitCompoundArrayCopies(binding, writer);
+ }
+
+ protected void emitArrayLengthAndNIOBufferChecks(MethodBinding binding, PrintWriter writer) {
+ int numBufferOffsetArrayArgs = 0;
+ boolean firstBuffer = true;
+ // 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 (" + getArgumentName(i) + ".length < " +
+ arrayType.getLength() + ")");
+ writer.println(" throw new " + getRuntimeExceptionType() +
+ "(\"Length of array \\\"" + getArgumentName(i) +
+ "\\\" was less than the required " + arrayType.getLength() + "\");");
+ } else {
+ JavaType javaType = binding.getJavaArgumentType(i);
+ if (javaType.isNIOBuffer()) {
+ if (directNIOOnly) {
+ writer.println(" if (!BufferFactory.isDirect(" + getArgumentName(i) + "))");
+ writer.println(" throw new " + getRuntimeExceptionType() + "(\"Argument \\\"" +
+ getArgumentName(i) + "\\\" was not a direct buffer\");");
+ } else {
+ if(firstBuffer) {
+ firstBuffer = false;
+ writer.println(" boolean _direct = BufferFactory.isDirect(" + getArgumentName(i) + ");");
+ } else {
+ writer.println(" if (" + getArgumentName(i) + " != null && _direct != BufferFactory.isDirect(" + getArgumentName(i) + "))");
+ writer.println(" throw new " + getRuntimeExceptionType() +
+ "(\"Argument \\\"" + getArgumentName(i) +
+ "\\\" : Buffers passed to this method must all be either direct or indirect\");");
+ }
+ }
+ } else if (javaType.isNIOBufferArray()) {
+ // All buffers passed down in an array of NIO buffers must be direct
+ String argName = getArgumentName(i);
+ String arrayName = byteOffsetArrayArgName(i);
+ writer.println(" int[] " + arrayName + " = new int[" + argName + ".length];");
+ // Check direct buffer properties of all buffers within
+ writer.println(" if (" + argName + " != null) {");
+ writer.println(" for (int _ctr = 0; _ctr < " + argName + ".length; _ctr++) {");
+ writer.println(" if (!BufferFactory.isDirect(" + argName + "[_ctr])) {");
+ writer.println(" throw new " + getRuntimeExceptionType() +
+ "(\"Element \" + _ctr + \" of argument \\\"" +
+ getArgumentName(i) + "\\\" was not a direct buffer\");");
+ writer.println(" }");
+ // get the Buffer Array offset values and save them into another array to send down to JNI
+ writer.print (" " + arrayName + "[_ctr] = BufferFactory.getDirectBufferByteOffset(");
+ writer.println(argName + "[_ctr]);");
+ writer.println(" }");
+ writer.println(" }");
+ } else if (javaType.isPrimitiveArray()) {
+ String argName = getArgumentName(i);
+ String offsetArg = offsetArgName(i);
+ writer.println(" if(" + argName + " != null && " + argName + ".length <= " + offsetArg + ")");
+ writer.print (" throw new " + getRuntimeExceptionType());
+ writer.println("(\"array offset argument \\\"" + offsetArg + "\\\" (\" + " + offsetArg +
+ " + \") equals or exceeds array length (\" + " + argName + ".length + \")\");");
+ }
+ }
+ }
+ }
+
+ protected void emitCompoundArrayCopies(MethodBinding binding, PrintWriter writer) {
+ // If the method binding uses outgoing arrays of compound type
+ // wrappers, we need to generate a temporary copy of this array
+ // into a ByteBuffer[] for processing by the native code
+ if (binding.signatureUsesArraysOfCompoundTypeWrappers()) {
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType javaType = binding.getJavaArgumentType(i);
+ if (javaType.isArrayOfCompoundTypeWrappers()) {
+ String argName = getArgumentName(i);
+ String tempArrayName = argName + COMPOUND_ARRAY_SUFFIX;
+ writer.println(" ByteBuffer[] " + tempArrayName + " = new ByteBuffer[" + argName + ".length];");
+ writer.println(" for (int _ctr = 0; _ctr < + " + argName + ".length; _ctr++) {");
+ writer.println(" " + javaType.getName() + " _tmp = " + argName + "[_ctr];");
+ writer.println(" " + tempArrayName + "[_ctr] = ((_tmp == null) ? null : _tmp.getBuffer());");
+ writer.println(" }");
+ }
+ }
+ }
+ }
+
+ protected void emitCall(MethodBinding binding, PrintWriter writer, boolean direct) {
+ writer.print(getImplMethodName(direct));
+ writer.print("(");
+ emitCallArguments(binding, writer, direct);
+ writer.print(")");
+ }
+
+
+ protected void emitReturnVariableSetupAndCall(MethodBinding binding, PrintWriter writer) {
+ writer.print(" ");
+ JavaType returnType = binding.getJavaReturnType();
+ boolean needsResultAssignment = false;
+
+ if (!returnType.isVoid()) {
+ if (returnType.isCompoundTypeWrapper() ||
+ returnType.isNIOBuffer()) {
+ writer.println("java.nio.ByteBuffer _res;");
+ needsResultAssignment = true;
+ } else if (returnType.isArrayOfCompoundTypeWrappers()) {
+ writer.println("java.nio.ByteBuffer[] _res;");
+ needsResultAssignment = true;
+ } else if (((epilogue != null) && (epilogue.size() > 0)) ||
+ binding.signatureUsesArraysOfCompoundTypeWrappers()) {
+ emitReturnType(writer);
+ writer.println(" _res;");
+ needsResultAssignment = true;
+ }
+ }
+
+ if (binding.signatureCanUseIndirectNIO() && !directNIOOnly) {
+ // Must generate two calls for this gated on whether the NIO
+ // buffers coming in are all direct or indirect
+ writer.println("if (_direct) {");
+ writer.print (" ");
+ }
+
+ if (needsResultAssignment) {
+ writer.print(" _res = ");
+ } else {
+ writer.print(" ");
+ if (!returnType.isVoid()) {
+ writer.print("return ");
+ }
+ }
+
+ if (binding.signatureUsesJavaPrimitiveArrays() &&
+ !binding.signatureCanUseIndirectNIO()) {
+ // FIXME: what happens with a C function of the form
+ // void foo(int* arg0, void* arg1);
+ // ?
+
+ // Only one call being made in this body, going to indirect
+ // buffer / array entry point
+ emitCall(binding, writer, false);
+ writer.print(";");
+ writer.println();
+ } else {
+ emitCall(binding, writer, true);
+ writer.print(";");
+ }
+
+ if (binding.signatureCanUseIndirectNIO() && !directNIOOnly) {
+ // Must generate two calls for this gated on whether the NIO
+ // buffers coming in are all direct or indirect
+ writer.println();
+ writer.println(" } else {");
+ writer.print (" ");
+ if (needsResultAssignment) {
+ writer.print(" _res = ");
+ } else {
+ writer.print(" ");
+ if (!returnType.isVoid()) {
+ writer.print("return ");
+ }
+ }
+ emitCall(binding, writer, false);
+ writer.print(";");
+ writer.println();
+ writer.println(" }");
+ } else {
+ writer.println();
+ }
+ emitPostCallCleanup(binding, writer);
+ emitPrologueOrEpilogue(epilogue, writer);
+ if (needsResultAssignment) {
+ emitCallResultReturn(binding, writer);
+ }
+ }
+
+ protected int emitCallArguments(MethodBinding binding, PrintWriter writer, boolean direct) {
+ 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("((");
+ }
+
+ if (type.isNIOBuffer() && !direct) {
+ writer.print("BufferFactory.getArray(" + getArgumentName(i) + ")");
+ } else if (type.isArrayOfCompoundTypeWrappers()) {
+ writer.print(getArgumentName(i) + COMPOUND_ARRAY_SUFFIX);
+ } else {
+ writer.print(getArgumentName(i));
+ }
+
+ if (type.isCompoundTypeWrapper()) {
+ writer.print(" == null) ? null : ");
+ writer.print(getArgumentName(i));
+ writer.print(".getBuffer())");
+ }
+ if (type.isNIOBuffer()) {
+ if (direct) {
+ writer.print(", BufferFactory.getDirectBufferByteOffset(" + getArgumentName(i) + ")");
+ } else {
+ writer.print(", BufferFactory.getIndirectBufferByteOffset(" + getArgumentName(i) + ")");
+ }
+ } else if (type.isNIOBufferArray()) {
+ writer.print(", " + byteOffsetArrayArgName(i));
+ }
+
+ // Add Array offset parameter for primitive arrays
+ if (type.isPrimitiveArray()) {
+ if(type.isFloatArray()) {
+ writer.print(", BufferFactory.SIZEOF_FLOAT * ");
+ } else if(type.isDoubleArray()) {
+ writer.print(", BufferFactory.SIZEOF_DOUBLE * ");
+ } else if(type.isByteArray()) {
+ writer.print(", ");
+ } else if(type.isLongArray()) {
+ writer.print(", BufferFactory.SIZEOF_LONG * ");
+ } else if(type.isShortArray()) {
+ writer.print(", BufferFactory.SIZEOF_SHORT * ");
+ } else if(type.isIntArray()) {
+ writer.print(", BufferFactory.SIZEOF_INT * ");
+ } else {
+ throw new RuntimeException("Unsupported type for calculating array offset argument for " +
+ getArgumentName(i) +
+ " -- error occurred while processing Java glue code for " + getName());
+ }
+ writer.print(offsetArgName(i));
+ }
+
+ needComma = true;
+ ++numArgsEmitted;
+ }
+ return numArgsEmitted;
+ }
+
+ protected void emitPostCallCleanup(MethodBinding binding, PrintWriter writer) {
+ if (binding.signatureUsesArraysOfCompoundTypeWrappers()) {
+ // For each such array, we need to take the ByteBuffer[] that
+ // came back from the C method invocation and wrap the
+ // ByteBuffers back into the wrapper types
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType javaArgType = binding.getJavaArgumentType(i);
+ if (javaArgType.isArrayOfCompoundTypeWrappers()) {
+ String argName = binding.getArgumentName(i);
+ writer.println(" for (int _ctr = 0; _ctr < " + argName + ".length; _ctr++) {");
+ writer.println(" if ((" + argName + "[_ctr] == null && " + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr] == null) ||");
+ writer.println(" (" + argName + "[_ctr] != null && " + argName + "[_ctr].getBuffer() == " + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr])) {");
+ writer.println(" // No copy back needed");
+ writer.println(" } else {");
+ writer.println(" if (" + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr] == null) {");
+ writer.println(" " + argName + "[_ctr] = null;");
+ writer.println(" } else {");
+ writer.println(" " + argName + "[_ctr] = " + javaArgType.getName() + ".create(" + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr]);");
+ writer.println(" }");
+ writer.println(" }");
+ writer.println(" }");
+ }
+ }
+ }
+ }
+
+ protected void emitCallResultReturn(MethodBinding binding, PrintWriter writer) {
+ JavaType returnType = binding.getJavaReturnType();
+
+ if (returnType.isCompoundTypeWrapper()) {
+ String fmt = getReturnedArrayLengthExpression();
+ writer.println(" if (_res == null) return null;");
+ if (fmt == null) {
+ writer.print(" return " + returnType.getName() + ".create(BufferFactory.nativeOrder(_res))");
+ } else {
+ writer.println(" BufferFactory.nativeOrder(_res);");
+ String expr = new MessageFormat(fmt).format(argumentNameArray());
+ 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 " + 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 * " + getReturnTypeString(true) + ".size());");
+ writer.println(" _res.limit ((1 + _count) * " + getReturnTypeString(true) + ".size());");
+ writer.println(" java.nio.ByteBuffer _tmp = _res.slice();");
+ writer.println(" BufferFactory.nativeOrder(_tmp);");
+ writer.println(" _res.position(0);");
+ writer.println(" _res.limit(_res.capacity());");
+ writer.println(" _retarray[_count] = " + getReturnTypeString(true) + ".create(_tmp);");
+ writer.println(" }");
+ writer.print (" return _retarray");
+ }
+ writer.println(";");
+ } else if (returnType.isNIOBuffer()) {
+ writer.println(" if (_res == null) return null;");
+ writer.println(" BufferFactory.nativeOrder(_res);");
+ if (!returnType.isNIOByteBuffer()) {
+ // See whether we have to expand pointers to longs
+ if (getBinding().getCReturnType().pointerDepth() >= 2) {
+ if (!returnType.isNIOLongBuffer()) {
+ throw new RuntimeException("While emitting glue code for " + getName() +
+ ": can not legally make pointers opaque to anything but longs");
+ }
+ writer.println(" return BufferFactory.asPointerBuffer(_res);");
+ } else {
+ String returnTypeName = returnType.getName().substring("java.nio.".length());
+ writer.println(" return _res.as" + returnTypeName + "();");
+ }
+ } else {
+ writer.println(" return _res;");
+ }
+ } else if (returnType.isArrayOfCompoundTypeWrappers()) {
+ writer.println(" if (_res == null) return null;");
+ writer.println(" " + getReturnTypeString(false) + " _retarray = new " + getReturnTypeString(true) + "[_res.length];");
+ writer.println(" for (int _count = 0; _count < _res.length; _count++) {");
+ writer.println(" _retarray[_count] = " + getReturnTypeString(true) + ".create(_res[_count]);");
+ writer.println(" }");
+ writer.println(" return _retarray;");
+ } else {
+ // Assume it's a primitive type or other type we don't have to
+ // do any conversion on
+ writer.println(" return _res;");
+ }
+ }
+
+ protected String[] argumentNameArray() {
+ String[] argumentNames = new String[binding.getNumArguments()];
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ argumentNames[i] = getArgumentName(i);
+ if (binding.getJavaArgumentType(i).isPrimitiveArray()) {
+ // Add on _offset argument in comma-separated expression
+ argumentNames[i] = argumentNames[i] + ", " + offsetArgName(i);
+ }
+ }
+ return argumentNames;
+ }
+
+ public 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 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: ");
+ }
+ protected void emitBindingCSignature(MethodBinding binding, PrintWriter writer) {
+ writer.print("<code> ");
+ writer.print(binding.getCSymbol().toString(tagNativeBinding));
+ 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.
+ // If we're emitting a direct buffer variant only, then declare
+ // that the NIO buffer arguments must be direct.
+ MethodBinding binding = ((JavaMethodBindingEmitter)emitter).getBinding();
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ Type type = binding.getCArgumentType(i);
+ JavaType javaType = binding.getJavaArgumentType(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 enumType = (EnumType)type;
+ writer.println();
+ writer.print(emitter.getBaseIndentString());
+ writer.print(" ");
+ writer.print("@param ");
+ writer.print(getArgumentName(i));
+ writer.print(" valid values are: <code>");
+ for (int j = 0; j < enumType.getNumEnumerates(); ++j) {
+ if (j>0) writer.print(", ");
+ writer.print(enumType.getEnumName(j));
+ }
+ writer.println("</code>");
+ } else if (directNIOOnly && javaType.isNIOBuffer()) {
+ writer.println();
+ writer.print(emitter.getBaseIndentString());
+ writer.print(" ");
+ writer.print("@param ");
+ writer.print(getArgumentName(i));
+ writer.print(" a direct {@link " + javaType.getName() + "}");
+ }
+ }
+ }
+ }
+
+ protected class InterfaceCommentEmitter
+ extends JavaMethodBindingEmitter.DefaultCommentEmitter
+ {
+ protected void emitBeginning(FunctionEmitter emitter,
+ PrintWriter writer) {
+ writer.print("Interface to C language function: <br> ");
+ }
+ }
+}
+
diff --git a/src/java/com/sun/gluegen/JavaType.java b/src/java/com/sun/gluegen/JavaType.java
new file mode 100644
index 0000000..1f795ef
--- /dev/null
+++ b/src/java/com/sun/gluegen/JavaType.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.nio.*;
+
+import com.sun.gluegen.cgram.types.*;
+
+/**
+ * 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 static final int PTR_C_VOID = 1;
+ private static final int PTR_C_CHAR = 2;
+ private static final int PTR_C_SHORT = 3;
+ private static final int PTR_C_INT32 = 4;
+ private static final int PTR_C_INT64 = 5;
+ private static final int PTR_C_FLOAT = 6;
+ private static final int PTR_C_DOUBLE = 7;
+
+ 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 Type elementType; // Element type if this JavaType represents a C array
+ private int primitivePointerType; // Represents C arrays that
+ // will / can be represented
+ // with NIO buffers (resolved
+ // down to another JavaType
+ // later in processing)
+ private static JavaType nioBufferType;
+ private static JavaType nioByteBufferType;
+ private static JavaType nioShortBufferType;
+ private static JavaType nioIntBufferType;
+ private static JavaType nioLongBufferType;
+ private static JavaType nioFloatBufferType;
+ private static JavaType nioDoubleBufferType;
+ private static JavaType nioByteBufferArrayType;
+
+ public boolean equals(Object arg) {
+ if ((arg == null) || (!(arg instanceof JavaType))) {
+ return false;
+ }
+ JavaType t = (JavaType) arg;
+ return (this == t ||
+ (t.clazz == clazz &&
+ ((name == t.name) ||
+ ((name != null) && (t.name != null) && (name.equals(t.name)))) &&
+ ((elementType == t.elementType) ||
+ (elementType != null) && (t.elementType != null) && (elementType.equals(t.elementType))) &&
+ (primitivePointerType == t.primitivePointerType)));
+ }
+
+ public int hashCode() {
+ if (clazz == null) {
+ if (name == null) {
+ return 0;
+ }
+ return name.hashCode();
+ }
+ return clazz.hashCode();
+ }
+
+ public JavaType getElementType() {
+ return new JavaType(elementType);
+ }
+
+ /** Creates a JavaType corresponding to the given Java type. This
+ can be used to represent arrays of primitive values or Strings;
+ the emitters understand how to perform proper conversion from
+ the corresponding C type. */
+ public static JavaType createForClass(Class clazz) {
+ return new JavaType(clazz);
+ }
+
+ /** Creates a JavaType corresponding to the specified C CompoundType
+ name; for example, if "Foo" is supplied, then this JavaType
+ represents a "Foo *" by way of a StructAccessor. */
+ public static JavaType createForCStruct(String name) {
+ return new JavaType(name);
+ }
+
+ /** Creates a JavaType corresponding to an array of the given
+ element type. This is used to represent arrays of "Foo **" which
+ should be mapped to Foo[] in Java. */
+ public static JavaType createForCArray(Type elementType) {
+ return new JavaType(elementType);
+ }
+
+ public static JavaType createForVoidPointer() {
+ return new JavaType(PTR_C_VOID);
+ }
+
+ public static JavaType createForCCharPointer() {
+ return new JavaType(PTR_C_CHAR);
+ }
+
+ public static JavaType createForCShortPointer() {
+ return new JavaType(PTR_C_SHORT);
+ }
+
+ public static JavaType createForCInt32Pointer() {
+ return new JavaType(PTR_C_INT32);
+ }
+
+ public static JavaType createForCInt64Pointer() {
+ return new JavaType(PTR_C_INT64);
+ }
+
+ public static JavaType createForCFloatPointer() {
+ return new JavaType(PTR_C_FLOAT);
+ }
+
+ public static JavaType createForCDoublePointer() {
+ return new JavaType(PTR_C_DOUBLE);
+ }
+
+ 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;
+ }
+
+ public static JavaType forNIOShortBufferClass() {
+ if (nioShortBufferType == null) {
+ nioShortBufferType = createForClass(java.nio.ShortBuffer.class);
+ }
+ return nioShortBufferType;
+ }
+
+ public static JavaType forNIOIntBufferClass() {
+ if (nioIntBufferType == null) {
+ nioIntBufferType = createForClass(java.nio.IntBuffer.class);
+ }
+ return nioIntBufferType;
+ }
+
+ public static JavaType forNIOLongBufferClass() {
+ if (nioLongBufferType == null) {
+ nioLongBufferType = createForClass(java.nio.LongBuffer.class);
+ }
+ return nioLongBufferType;
+ }
+
+ public static JavaType forNIOFloatBufferClass() {
+ if (nioFloatBufferType == null) {
+ nioFloatBufferType = createForClass(java.nio.FloatBuffer.class);
+ }
+ return nioFloatBufferType;
+ }
+
+ public static JavaType forNIODoubleBufferClass() {
+ if (nioDoubleBufferType == null) {
+ nioDoubleBufferType = createForClass(java.nio.DoubleBuffer.class);
+ }
+ return nioDoubleBufferType;
+ }
+
+ public static JavaType forNIOByteBufferArrayClass() {
+ if (nioByteBufferArrayType == null) {
+ ByteBuffer[] tmp = new ByteBuffer[0];
+ nioByteBufferArrayType = createForClass(tmp.getClass());
+ }
+ return nioByteBufferArrayType;
+ }
+
+ /**
+ * Returns the Java Class corresponding to this type. Returns null if this
+ * object corresponds to a C primitive array type.
+ */
+ public Class getJavaClass() {
+ return clazz;
+ }
+
+ /**
+ * Returns the Java type name corresponding to this type.
+ */
+ public String getName() {
+ if (clazz != null) {
+ if (clazz.isArray()) {
+ return arrayName(clazz);
+ }
+ return clazz.getName();
+ }
+ if (elementType != null) {
+ return elementType.getName();
+ }
+ return name;
+ }
+
+ /**
+ * Returns the descriptor (internal type signature) corresponding to
+ * this type.
+ */
+ public String getDescriptor() {
+ // FIXME: this is not completely accurate at this point (for
+ // example, it knows nothing about the packages for compound
+ // types)
+ if (clazz != null) {
+ return descriptor(clazz);
+ }
+ if (elementType != null) {
+ if(elementType.getName()==null) {
+ throw new RuntimeException("elementType.name is null: "+getDumpString());
+ }
+ return "[" + descriptor(elementType.getName());
+ }
+ return descriptor(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 (isCompoundTypeWrapper()) {
+ // These are sent down as Buffers (e.g., jobject)
+ return "jobject";
+ }
+
+ if (isArrayOfCompoundTypeWrappers()) {
+ // These are returned as arrays of ByteBuffers (e.g., jobjectArray)
+ return "jobjectArray /* of ByteBuffer */";
+ }
+
+ if (clazz == null) {
+ return null;
+ }
+
+ if (isVoid()) {
+ return "void";
+ }
+
+ if (isPrimitive()) {
+ return "j" + clazz.getName();
+ }
+
+ if (isPrimitiveArray() || isNIOBuffer()) {
+ // We now pass primitive arrays and buffers uniformly down to native code as java.lang.Object.
+ return "jobject";
+ }
+
+ if (isArray()) {
+ if (isStringArray()) {
+ return "jobjectArray /*elements are String*/";
+ }
+
+ Class elementType = clazz.getComponentType();
+
+ if (isNIOBufferArray()) {
+ return "jobjectArray /*elements are " + elementType.getName() + "*/";
+ }
+
+ 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.");
+ }
+ }
+
+ // Some unusual type that we don't handle
+ throw new RuntimeException("Unexpected and unsupported array type: \"" + this + "\"");
+ }
+
+ if (isString()) {
+ return "jstring";
+ }
+
+ return "jobject";
+ }
+
+ public boolean isNIOBuffer() {
+ return (clazz != null && java.nio.Buffer.class.isAssignableFrom(clazz));
+ }
+
+ public boolean isNIOByteBuffer() {
+ return (clazz == java.nio.ByteBuffer.class);
+ }
+
+ public boolean isNIOByteBufferArray() {
+ return (this == nioByteBufferArrayType);
+ }
+
+ public boolean isNIOBufferArray() {
+ return (isArray() &&
+ (java.nio.Buffer.class.isAssignableFrom(clazz.getComponentType())));
+ }
+
+ public boolean isNIOLongBuffer() {
+ return (clazz == java.nio.LongBuffer.class);
+ }
+
+ public boolean isString() {
+ return (clazz == java.lang.String.class);
+ }
+
+ public boolean isArray() {
+ return ((clazz != null) && clazz.isArray());
+ }
+
+ public boolean isFloatArray() {
+ return (clazz != null && clazz.isArray() && clazz.getComponentType() == Float.TYPE);
+ }
+
+ public boolean isDoubleArray() {
+ return (clazz != null && clazz.isArray() && clazz.getComponentType() == Double.TYPE);
+ }
+
+ public boolean isByteArray() {
+ return (clazz != null && clazz.isArray() && clazz.getComponentType() == Byte.TYPE);
+ }
+
+ public boolean isIntArray() {
+ return (clazz != null && clazz.isArray() && clazz.getComponentType() == Integer.TYPE);
+ }
+
+ public boolean isShortArray() {
+ return (clazz != null && clazz.isArray() && clazz.getComponentType() == Short.TYPE);
+ }
+
+ public boolean isLongArray() {
+ return (clazz != null && clazz.isArray() && clazz.getComponentType() == Long.TYPE);
+ }
+
+ public boolean isStringArray() {
+ return (clazz != null && clazz.isArray() && clazz.getComponentType() == java.lang.String.class);
+ }
+
+
+ public boolean isPrimitive() {
+ return ((clazz != null) && !isArray() && clazz.isPrimitive() && (clazz != Void.TYPE));
+ }
+
+ public boolean isPrimitiveArray() {
+ return (isArray() && (clazz.getComponentType().isPrimitive()));
+ }
+
+ public boolean isShort() {
+ return (clazz == Short.TYPE);
+ }
+
+ public boolean isFloat() {
+ return (clazz == Float.TYPE);
+ }
+
+ public boolean isDouble() {
+ return (clazz == Double.TYPE);
+ }
+
+ public boolean isByte() {
+ return (clazz == Byte.TYPE);
+ }
+
+ public boolean isLong() {
+ return (clazz == Long.TYPE);
+ }
+
+ public boolean isInt() {
+ return (clazz == Integer.TYPE);
+ }
+
+ public boolean isVoid() {
+ return (clazz == Void.TYPE);
+ }
+
+ public boolean isCompoundTypeWrapper() {
+ return (clazz == null && name != null && !isJNIEnv());
+ }
+
+ public boolean isArrayOfCompoundTypeWrappers() {
+ return (elementType != null);
+ }
+
+ public boolean isCPrimitivePointerType() {
+ return (primitivePointerType != 0);
+ }
+
+ public boolean isCVoidPointerType() {
+ return (primitivePointerType == PTR_C_VOID);
+ }
+
+ public boolean isCCharPointerType() {
+ return (primitivePointerType == PTR_C_CHAR);
+ }
+
+ public boolean isCShortPointerType() {
+ return (primitivePointerType == PTR_C_SHORT);
+ }
+
+ public boolean isCInt32PointerType() {
+ return (primitivePointerType == PTR_C_INT32);
+ }
+
+ public boolean isCInt64PointerType() {
+ return (primitivePointerType == PTR_C_INT64);
+ }
+
+ public boolean isCFloatPointerType() {
+ return (primitivePointerType == PTR_C_FLOAT);
+ }
+
+ public boolean isCDoublePointerType() {
+ return (primitivePointerType == PTR_C_DOUBLE);
+ }
+
+ public boolean isJNIEnv() {
+ return clazz == null && name == "JNIEnv";
+ }
+
+ public Object clone() {
+ JavaType clone = new JavaType(primitivePointerType);
+
+ clone.clazz = this.clazz;
+ clone.name = this.name;
+ clone.elementType = this.elementType;
+
+ return clone;
+ }
+
+ public String toString() {
+ return getName();
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ // For debugging
+ public String getDumpString() {
+ return "[clazz = " + clazz + " , name = " + name + " , elementType = " + elementType + " , primitivePointerType = " + primitivePointerType + "]";
+ }
+ public void dump() {
+ System.err.println(getDumpString());
+ }
+
+ /**
+ * 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;
+ }
+
+ /** Constructs a type representing an array of C pointers. */
+ private JavaType(Type elementType) {
+ this.elementType = elementType;
+ }
+
+ /** Constructs a type representing a pointer to a C primitive
+ (integer, floating-point, or void pointer) type. */
+ private JavaType(int primitivePointerType) {
+ this.primitivePointerType = primitivePointerType;
+ }
+
+ 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();
+ }
+
+ private String arrayDescriptor(Class clazz) {
+ StringBuffer buf = new StringBuffer();
+ int arrayCount = 0;
+ while (clazz.isArray()) {
+ buf.append("[");
+ clazz = clazz.getComponentType();
+ }
+ buf.append(descriptor(clazz));
+ return buf.toString();
+ }
+
+ private String descriptor(Class clazz) {
+ if (clazz.isPrimitive()) {
+ if (clazz == Boolean.TYPE) return "Z";
+ if (clazz == Byte.TYPE) return "B";
+ if (clazz == Double.TYPE) return "D";
+ if (clazz == Float.TYPE) return "F";
+ if (clazz == Integer.TYPE) return "I";
+ if (clazz == Long.TYPE) return "J";
+ if (clazz == Short.TYPE) return "S";
+ if (clazz == Void.TYPE) return "V";
+ throw new RuntimeException("Unexpected primitive type " + clazz.getName());
+ }
+ if (clazz.isArray()) {
+ return arrayDescriptor(clazz);
+ }
+ return descriptor(clazz.getName());
+ }
+
+ private String descriptor(String referenceTypeName) {
+ return "L" + referenceTypeName.replace('.', '/') + ";";
+ }
+}
diff --git a/src/java/com/sun/gluegen/MethodBinding.java b/src/java/com/sun/gluegen/MethodBinding.java
new file mode 100644
index 0000000..5431874
--- /dev/null
+++ b/src/java/com/sun/gluegen/MethodBinding.java
@@ -0,0 +1,594 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.util.*;
+
+import com.sun.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 String renamedMethodName;
+ private JavaType javaReturnType;
+ private List javaArgumentTypes;
+ private boolean computedSignatureProperties;
+ private boolean argumentsUseNIO;
+ private boolean signatureUsesNIO;
+ private boolean signatureCanUseIndirectNIO;
+ private boolean signatureUsesCompoundTypeWrappers;
+ private boolean signatureUsesArraysOfCompoundTypeWrappers;
+ private boolean signatureUsesCVoidPointers;
+ private boolean signatureUsesCPrimitivePointers;
+ private boolean signatureUsesCArrays;
+ private boolean signatureUsesJavaPrimitiveArrays;
+ 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.renamedMethodName = bindingToCopy.renamedMethodName;
+ this.containingType = bindingToCopy.containingType;
+ this.containingCType = bindingToCopy.containingCType;
+ this.javaReturnType = bindingToCopy.javaReturnType;
+ this.javaArgumentTypes = (List)((ArrayList)bindingToCopy.javaArgumentTypes).clone();
+ this.computedSignatureProperties = bindingToCopy.computedSignatureProperties;
+ this.argumentsUseNIO = bindingToCopy.argumentsUseNIO;
+ this.signatureUsesNIO = bindingToCopy.signatureUsesNIO;
+ this.signatureCanUseIndirectNIO = bindingToCopy.signatureCanUseIndirectNIO;
+ this.signatureUsesCompoundTypeWrappers = bindingToCopy.signatureUsesCompoundTypeWrappers;
+ this.signatureUsesArraysOfCompoundTypeWrappers = bindingToCopy.signatureUsesArraysOfCompoundTypeWrappers;
+ this.signatureUsesCVoidPointers = bindingToCopy.signatureUsesCVoidPointers;
+ this.signatureUsesCPrimitivePointers = bindingToCopy.signatureUsesCPrimitivePointers;
+ this.signatureUsesCArrays = bindingToCopy.signatureUsesCArrays;
+ this.signatureUsesJavaPrimitiveArrays = bindingToCopy.signatureUsesJavaPrimitiveArrays;
+ 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;
+ computedSignatureProperties = false;
+ }
+
+ public void addJavaArgumentType(JavaType type) {
+ if (javaArgumentTypes == null) {
+ javaArgumentTypes = new ArrayList();
+ }
+ javaArgumentTypes.add(type);
+ computedSignatureProperties = 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();
+ }
+
+ public String getRenamedMethodName() {
+ // Defaults to same as C symbol unless renamed
+ if (renamedMethodName != null) {
+ return renamedMethodName;
+ }
+ return sym.getName();
+ }
+
+ /** Supports renaming C function in Java binding. */
+ public void setRenamedMethodName(String name) {
+ renamedMethodName = name;
+ }
+
+ /** Creates a new MethodBinding replacing the specified Java
+ argument type with a new argument type. If argumentNumber is
+ less than 0 then replaces the return type. */
+ public MethodBinding replaceJavaArgumentType(int argumentNumber,
+ JavaType newArgType) {
+ MethodBinding binding = (MethodBinding) clone();
+ binding.javaArgumentTypes = null;
+ 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 any of the outgoing arguments in the method's
+ * signature require conversion or checking due to the use of New
+ * I/O.
+ */
+ public boolean argumentsUseNIO() {
+ computeSignatureProperties();
+ return argumentsUseNIO;
+ }
+
+ /**
+ * Returns true if the return type or any of the outgoing arguments
+ * in the method's signature require conversion or checking due to
+ * the use of New I/O.
+ */
+ public boolean signatureUsesNIO() {
+ computeSignatureProperties();
+ return signatureUsesNIO;
+ }
+
+ /**
+ * Returns true if it is possible for any of the outgoing arguments
+ * to be indirect NIO buffers.
+ */
+ public boolean signatureCanUseIndirectNIO() {
+ computeSignatureProperties();
+ return signatureCanUseIndirectNIO;
+ }
+
+ /**
+ * Returns true if the return type or any of the outgoing arguments
+ * in the method's signature use "compound type wrappers", or
+ * NIO-based wrappers for C data structures.
+ */
+ public boolean signatureUsesCompoundTypeWrappers() {
+ computeSignatureProperties();
+ return signatureUsesCompoundTypeWrappers;
+ }
+
+ /**
+ * Returns true if the return type or any of the outgoing arguments
+ * in the method's signature use arrays of "compound type wrappers",
+ * or NIO-based wrappers for C data structures.
+ */
+ public boolean signatureUsesArraysOfCompoundTypeWrappers() {
+ computeSignatureProperties();
+ return signatureUsesArraysOfCompoundTypeWrappers;
+ }
+
+ /**
+ * Returns true if the function needs NIO-related
+ * wrapping/unwrapping or conversion of various arguments. Currently
+ * this returns the logical OR of signatureUsesNIO() and
+ * signatureUsesCompoundTypeWrappers().
+ */
+ public boolean needsNIOWrappingOrUnwrapping() {
+ return (signatureUsesNIO() || signatureUsesCompoundTypeWrappers());
+ }
+
+ /**
+ * Returns true if the return type or any of the outgoing arguments
+ * in the method's signature represent C void* pointers.
+ */
+ public boolean signatureUsesCVoidPointers() {
+ computeSignatureProperties();
+ return signatureUsesCVoidPointers;
+ }
+
+ /**
+ * Returns true if the return type or any of the outgoing arguments
+ * in the method's signature represent C primitive pointers.
+ */
+ public boolean signatureUsesCPrimitivePointers() {
+ computeSignatureProperties();
+ return signatureUsesCPrimitivePointers;
+ }
+
+ /**
+ * Returns true if the return type or any of the outgoing arguments
+ * in the method's signature represent C arrays.
+ */
+ public boolean signatureUsesCArrays() {
+ computeSignatureProperties();
+ return signatureUsesCArrays;
+ }
+
+ /**
+ * Returns true if the return type or any of the outgoing arguments
+ * in the method's signature represent Java primitive arrays.
+ */
+ public boolean signatureUsesJavaPrimitiveArrays() {
+ computeSignatureProperties();
+ return signatureUsesJavaPrimitiveArrays;
+ }
+
+ /**
+ * Computes summary information about the method's C and Java
+ * signatures.
+ */
+ protected void computeSignatureProperties() {
+ if (computedSignatureProperties)
+ return;
+
+ argumentsUseNIO = false;
+ signatureUsesNIO = false;
+ signatureCanUseIndirectNIO = false;
+ signatureUsesCompoundTypeWrappers = false;
+ signatureUsesArraysOfCompoundTypeWrappers = false;
+ signatureUsesCVoidPointers = false;
+ signatureUsesCPrimitivePointers = false;
+ signatureUsesCArrays = false;
+ signatureUsesJavaPrimitiveArrays = false;
+
+ if (javaReturnType.isCompoundTypeWrapper()) {
+ // Needs wrapping and/or setting of byte order (neither of which
+ // can be done easily from native code)
+ signatureUsesCompoundTypeWrappers = true;
+ }
+
+ if (javaReturnType.isNIOBuffer() ||
+ javaReturnType.isArrayOfCompoundTypeWrappers()) {
+ // Needs setting of byte order and possibly viewing as a
+ // different buffer type which can't be done easily from native
+ // code
+ signatureUsesNIO = true;
+ }
+
+ Type cRetType = sym.getReturnType();
+ if (cRetType.isArray()) {
+ // Needs checking of array lengths
+ signatureUsesCArrays = true;
+ if (cRetType.asArray().getElementType().isPrimitive()) {
+ signatureUsesCPrimitivePointers = true;
+ }
+ }
+
+ if (cRetType.isPointer()) {
+ if (cRetType.asPointer().getTargetType().isPrimitive()) {
+ signatureUsesCPrimitivePointers = true;
+ } else if (cRetType.asPointer().getTargetType().isVoid()) {
+ signatureUsesCVoidPointers = true;
+ }
+ }
+
+ for (int i = 0; i < getNumArguments(); i++) {
+ JavaType javaArgType = getJavaArgumentType(i);
+ Type cArgType = getCArgumentType(i);
+ if (javaArgType.isCompoundTypeWrapper()) {
+ // Needs unwrapping of accessors
+ signatureUsesCompoundTypeWrappers = true;
+ }
+
+ if (javaArgType.isArrayOfCompoundTypeWrappers()) {
+ // Needs to be duplicated and this array lowered to an array
+ // of Buffers for code emission
+ signatureUsesArraysOfCompoundTypeWrappers = true;
+ }
+
+ if (javaArgType.isNIOBuffer() ||
+ javaArgType.isNIOBufferArray()) {
+ // Needs checking of direct buffer property
+ signatureUsesNIO = true;
+ argumentsUseNIO = true;
+
+ if (javaArgType.isNIOBuffer()) {
+ // Potential conversion to indirect buffer
+ signatureCanUseIndirectNIO = true;
+ }
+ }
+
+ if (cArgType.isArray()) {
+ // Needs checking of array lengths
+ signatureUsesCArrays = true;
+ if (cArgType.asArray().getElementType().isPrimitive()) {
+ signatureUsesCPrimitivePointers = true;
+ }
+ }
+
+ if (cArgType.isPointer()) {
+ // Handle both real C primitive pointers and any constructions
+ // due to opaque directives
+ if (cArgType.asPointer().getTargetType().isPrimitive() ||
+ javaArgType.isCPrimitivePointerType()) {
+ signatureUsesCPrimitivePointers = true;
+ } else if (cArgType.asPointer().getTargetType().isVoid()) {
+ signatureUsesCVoidPointers = true;
+ }
+ }
+
+ if (javaArgType.isPrimitiveArray()) {
+ // Needs getPrimitiveArrayCritical or similar construct
+ // depending on native code calling convention
+ signatureUsesJavaPrimitiveArrays = true;
+ }
+ }
+
+ computedSignatureProperties = true;
+ }
+
+ /** 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(getRenamedMethodName());
+ 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);
+ }
+
+ /** Returns a String containing the descriptor (signature in
+ internal format) of this MethodBinding as it will be
+ emitted. This is used to disambiguate between overloadings when
+ manually specifying prologue and epilogue code, for example. */
+ public String getDescriptor(boolean forImplementingMethodCall,
+ boolean eraseBufferAndArrayTypes) {
+ StringBuffer buf = new StringBuffer();
+
+ buf.append("(");
+
+ if (forImplementingMethodCall && hasContainingType()) {
+ // Always emit outgoing "this" argument
+ buf.append("Ljava/nio/ByteBuffer;");
+ }
+
+ 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.
+ if (getNumArguments() != 1) {
+ throw new InternalError(
+ "\"void\" argument type found in " +
+ "multi-argument function \"" + this + "\"");
+ }
+ continue;
+ }
+
+ if (type.isJNIEnv() || isArgumentThisPointer(i)) {
+ // Don't need to expose these at the Java level
+ continue;
+ }
+
+ buf.append(erasedTypeDescriptor(type, eraseBufferAndArrayTypes, false));
+
+ // Add Buffer and array index offset arguments after each associated argument
+ if (forImplementingMethodCall) {
+ if (type.isNIOBuffer()) {
+ buf.append("I");
+ } else if (type.isNIOBufferArray()) {
+ buf.append("[I");
+ }
+ }
+
+ // Add offset argument after each primitive array
+ if (type.isPrimitiveArray()) {
+ buf.append("I");
+ }
+ }
+
+ buf.append(")");
+
+ // Emit return type for completeness even though we can't overload
+ // based solely on return type
+ buf.append(erasedTypeDescriptor(getJavaReturnType(), eraseBufferAndArrayTypes, false));
+
+ return buf.toString();
+ }
+
+ protected String erasedTypeDescriptor(JavaType type, boolean eraseBufferAndArrayTypes, boolean skipBuffers) {
+ if (eraseBufferAndArrayTypes) {
+ if (type.isNIOBuffer() ||
+ type.isPrimitiveArray()) {
+ if (!skipBuffers) {
+ // Direct buffers and arrays sent down as Object (but
+ // returned as e.g. ByteBuffer)
+ return "Ljava/lang/Object;";
+ }
+ } else if (type.isCompoundTypeWrapper()) {
+ // Compound type wrappers are unwrapped to ByteBuffer
+ return "Ljava/nio/ByteBuffer;";
+ } else if (type.isArrayOfCompoundTypeWrappers()) {
+ return "Ljava/nio/ByteBuffer;";
+ }
+ }
+ return type.getDescriptor();
+ }
+}
+
diff --git a/src/java/com/sun/gluegen/ReferencedStructs.java b/src/java/com/sun/gluegen/ReferencedStructs.java
new file mode 100644
index 0000000..6c0dfb4
--- /dev/null
+++ b/src/java/com/sun/gluegen/ReferencedStructs.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import java.util.*;
+import com.sun.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.isPointer()) {
+ PointerType p = t.asPointer();
+ if (p.hasTypedefedName()) {
+ CompoundType c = p.getTargetType().asCompound();
+ if (c != null && c.getName() == null) {
+ // This otherwise-unnamed CompoundType is referred to by a
+ // PointerType that has a typedef name. Assume that it is
+ // referred to in the glue code and emit it.
+ results.add(p);
+ }
+ }
+ } else if (t.isCompound()) {
+ results.add(t);
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/StructLayout.java b/src/java/com/sun/gluegen/StructLayout.java
new file mode 100644
index 0000000..7045f89
--- /dev/null
+++ b/src/java/com/sun/gluegen/StructLayout.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+import com.sun.gluegen.cgram.types.*;
+
+/** Encapsulates algorithm for laying out data structures. Note that
+ this ends up embedding code in various places via SizeThunks. If
+ the 32-bit and 64-bit ports on a given platform differ
+ fundamentally in their handling of struct layout then this code
+ will need to be updated and, most likely, two versions of the
+ SizeThunks maintained in various places. */
+
+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();
+ SizeThunk curOffset = SizeThunk.constant(baseOffset);
+ SizeThunk maxSize = SizeThunk.constant(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()) {
+ SizeThunk sz = ft.getSize();
+ curOffset = SizeThunk.roundUp(curOffset, sz);
+ f.setOffset(curOffset);
+ if (t.isUnion()) {
+ maxSize = SizeThunk.max(maxSize, sz);
+ } else {
+ curOffset = SizeThunk.add(curOffset, sz);
+ }
+ } else if (ft.isCompound()) {
+ new StructLayout(0, structAlignment).layout(ft.asCompound());
+ curOffset = SizeThunk.roundUp(curOffset, SizeThunk.constant(structAlignment));
+ f.setOffset(curOffset);
+ if (t.isUnion()) {
+ maxSize = SizeThunk.max(maxSize, ft.getSize());
+ } else {
+ curOffset = SizeThunk.add(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
+ curOffset = SizeThunk.roundUp(curOffset, SizeThunk.constant(structAlignment));
+ f.setOffset(curOffset);
+ curOffset = SizeThunk.add(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() {
+ // Note: this code is replicated in CPU.java
+ String os = System.getProperty("os.name").toLowerCase();
+ String cpu = System.getProperty("os.arch").toLowerCase();
+ if ((os.startsWith("windows") && cpu.equals("x86"))) {
+ // It appears that Windows uses a packing alignment of 4 bytes in 32-bit mode
+ return new StructLayout(0, 4);
+ } else if ((os.startsWith("windows") && cpu.equals("amd64")) ||
+ (os.startsWith("linux") && cpu.equals("i386")) ||
+ (os.startsWith("linux") && cpu.equals("x86")) ||
+ (os.startsWith("linux") && cpu.equals("amd64")) ||
+ (os.startsWith("linux") && cpu.equals("x86_64")) ||
+ (os.startsWith("linux") && cpu.equals("ia64")) ||
+ (os.startsWith("sunos") && cpu.equals("sparc")) ||
+ (os.startsWith("sunos") && cpu.equals("sparcv9")) ||
+ (os.startsWith("sunos") && cpu.equals("x86")) ||
+ (os.startsWith("sunos") && cpu.equals("amd64")) ||
+ (os.startsWith("mac os") && cpu.equals("ppc")) ||
+ (os.startsWith("mac os") && cpu.equals("i386")) ||
+ (os.startsWith("mac os") && cpu.equals("x86_64")) ||
+ (os.startsWith("freebsd") && cpu.equals("i386")) ||
+ (os.startsWith("hp-ux") && cpu.equals("pa_risc2.0"))
+ ) {
+ // 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/java/com/sun/gluegen/SymbolFilter.java b/src/java/com/sun/gluegen/SymbolFilter.java
new file mode 100644
index 0000000..1cc31aa
--- /dev/null
+++ b/src/java/com/sun/gluegen/SymbolFilter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+
+package com.sun.gluegen;
+
+import java.util.List;
+
+/** Provides a mechanism by which the GlueEmitter can look at all of
+ the #defines, enum values and function symbols and perform certain
+ filtering and processing which requires all of them to be visible
+ simultaneously. */
+
+public interface SymbolFilter {
+ /**
+ * Filters the given constant and function symbols. The caller
+ * will query the SymbolFilter for its resulting constant and
+ * function symbol lists after this routine returns.
+ *
+ * @param defines a list of {@link com.sun.gluegen.cgram.Define Define} objects
+ * @param functions a list of {@link com.sun.gluegen.cgram.types.FunctionSymbol FunctionSymbol} objects
+ */
+ public void filterSymbols(List/*<ConstantDefinition>*/ constants,
+ List/*<FunctionSymbol>*/ functions);
+
+ /** Returns the filtered list of constants. This method may return
+ a new list, the original list, or null, in which case the
+ original list will be used. */
+ public List/*<ConstantDefinition>*/ getConstants();
+
+ /** Returns the filtered list of function symbols. This method may
+ return a new list, the original list, or null, in which case
+ the original list will be used. */
+ public List/*<FunctionSymbol>*/ getFunctions();
+}
diff --git a/src/java/com/sun/gluegen/TypeInfo.java b/src/java/com/sun/gluegen/TypeInfo.java
new file mode 100644
index 0000000..8f21c9f
--- /dev/null
+++ b/src/java/com/sun/gluegen/TypeInfo.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen;
+
+/** 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; }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("TypeInfo: ");
+ buf.append(name);
+ buf.append(" pointerDepth ");
+ buf.append(pointerDepth);
+ buf.append(" JavaType " + javaType);
+ return buf.toString();
+ }
+}
diff --git a/src/java/com/sun/gluegen/ant/GlueGenTask.java b/src/java/com/sun/gluegen/ant/GlueGenTask.java
new file mode 100644
index 0000000..af42392
--- /dev/null
+++ b/src/java/com/sun/gluegen/ant/GlueGenTask.java
@@ -0,0 +1,520 @@
+package com.sun.gluegen.ant;
+
+/*
+ * GlueGenTask.java
+ * Copyright (C) 2003 Rob Grzywinski ([email protected])
+ *
+ * Copying, distribution and use of this software in source and binary
+ * forms, with or without modification, is permitted provided that the
+ * following conditions are met:
+ *
+ * Distributions of source code must reproduce the copyright notice,
+ * this list of conditions and the following disclaimer in the source
+ * code header files; and Distributions of binary code must reproduce
+ * the copyright notice, this list of conditions and the following
+ * disclaimer in the documentation, Read me file, license file and/or
+ * other materials provided with the software distribution.
+ *
+ * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright
+ * holder may not 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, NON-INTERFERENCE, ACCURACY OF
+ * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE
+ * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE
+ * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT
+ * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION,
+ * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT
+ * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED
+ * WARRANTY OF FITNESS FOR SUCH USES.
+ */
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.DirSet;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * <p>An <a href="http://ant.apache.org">ANT</a> {@link org.apache.tools.ant.Task}
+ * for using {@link com.sun.gluegen.GlueGen}.</p>
+ *
+ * <p>Usage:</p>
+ * <pre>
+ &lt;gluegen src="[source C file]"
+ outputrootdir="[optional output root dir]"
+ includes="[optional directory pattern of include files to include]"
+ excludes="[optional directory pattern of include files to exclude]"
+ includeRefid="[optional FileSet or DirSet for include files]"
+ literalInclude="[optional hack to get around FileSet / DirSet issues with different drives]"
+ emitter="[emitter class name]"
+ config="[configuration file]" /&gt;
+ * </pre>
+ *
+ * @author Rob Grzywinski <a href="mailto:[email protected]">[email protected]</a>
+ */
+// FIXME: blow out javadoc
+// NOTE: this has not been exhaustively tested
+public class GlueGenTask extends Task
+{
+ /**
+ * <p>The {@link com.sun.gluegen.GlueGen} classname.</p>
+ */
+ private static final String GLUE_GEN = "com.sun.gluegen.GlueGen";
+
+ // =========================================================================
+ /**
+ * <p>The {@link org.apache.tools.ant.types.CommandlineJava} that is used
+ * to execute {@link com.sun.gluegen.GlueGen}.</p>
+ */
+ private CommandlineJava gluegenCommandline;
+
+ // =========================================================================
+ /**
+ * <p>The optional output root dir.</p>
+ */
+ private String outputRootDir;
+
+ /**
+ * <p>The name of the emitter class.</p>
+ */
+ private String emitter;
+
+ /**
+ * <p>The configuration file name.</p>
+ */
+ private String configuration;
+
+ /**
+ * <p>The name of the source C file that is to be parsed.</p>
+ */
+ private String sourceFile;
+
+ /**
+ * <p>The {@link org.apache.tools.ant.types.FileSet} of includes.</p>
+ */
+ private FileSet includeSet = new FileSet();
+
+ /**
+ * <p>Because a {@link org.apache.tools.ant.types.FileSet} will include
+ * everything in its base directory if it is left untouched, the <code>includeSet</code>
+ * must only be added to the set of includes if it has been <i>explicitly</i>
+ * set.</p>
+ */
+ private boolean usedIncludeSet = false; // by default it is not used
+
+ /**
+ * <p>The set of include sets. This allows includes to be added in multiple
+ * fashions.</p>
+ */
+ // FIXME: rename to listXXXX
+ private List setOfIncludeSets = new LinkedList();
+
+ /**
+ * <p>A single literal directory to include. This is to get around the
+ * fact that neither {@link org.apache.tools.ant.types.FileSet} nor
+ * {@link org.apache.tools.ant.types.DirSet} can handle multiple drives in
+ * a sane manner. If <code>null</code> then it has not been specified.</p>
+ */
+ private String literalInclude;
+
+ // =========================================================================
+ /**
+ * <p>Create and add the VM and classname to {@link org.apache.tools.ant.types.CommandlineJava}.</p>
+ */
+ public GlueGenTask()
+ {
+ // create the CommandlineJava that will be used to call GlueGen
+ gluegenCommandline = new CommandlineJava();
+
+ // set the VM and classname in the commandline
+ gluegenCommandline.setVm(JavaEnvUtils.getJreExecutable("java"));
+ gluegenCommandline.setClassname(GLUE_GEN);
+ // gluegenCommandline.createVmArgument().setValue("-verbose:class");
+ }
+
+ // =========================================================================
+ // ANT getters and setters
+
+ /**
+ * <p>Set the output root dir (optional). This is called by ANT.</p>
+ *
+ * @param outputRootDir the optional output root dir
+ */
+ public void setOutputRootDir(String outputRootDir)
+ {
+ log( ("Setting output root dir: " + outputRootDir), Project.MSG_VERBOSE);
+ this.outputRootDir=outputRootDir;
+ }
+
+ /**
+ * <p>Set the emitter class name. This is called by ANT.</p>
+ *
+ * @param emitter the name of the emitter class
+ */
+ public void setEmitter(String emitter)
+ {
+ log( ("Setting emitter class name to: " + emitter), Project.MSG_VERBOSE);
+ this.emitter = emitter;
+ }
+
+ /**
+ * <p>Set the configuration file name. This is called by ANT.</p>
+ *
+ * @param configuration the name of the configuration file
+ */
+ public void setConfig(String configuration)
+ {
+ log( ("Setting configuration file name to: " + configuration),
+ Project.MSG_VERBOSE);
+ this.configuration = configuration;
+ }
+
+ /**
+ * <p>Set the source C file that is to be parsed. This is called by ANT.</p>
+ *
+ * @param sourceFile the name of the source file
+ */
+ public void setSrc(String sourceFile)
+ {
+ log( ("Setting source file name to: " + sourceFile), Project.MSG_VERBOSE);
+ this.sourceFile = sourceFile;
+ }
+
+ /**
+ * <p>Set a single literal include directory. See the <code>literalInclude</code>
+ * javadoc for more information.</p>
+ *
+ * @param directory the directory to include
+ */
+ public void setLiteralInclude(String directory)
+ {
+ this.literalInclude = directory;
+ }
+
+ /**
+ * <p>Add an include file to the list. This is called by ANT for a nested
+ * element.</p>
+ *
+ * @return {@link org.apache.tools.ant.types.PatternSet.NameEntry}
+ */
+ public PatternSet.NameEntry createInclude()
+ {
+ usedIncludeSet = true;
+ return includeSet.createInclude();
+ }
+
+ /**
+ * <p>Add an include file to the list. This is called by ANT for a nested
+ * element.</p>
+ *
+ * @return {@link org.apache.tools.ant.types.PatternSet.NameEntry}
+ */
+ public PatternSet.NameEntry createIncludesFile()
+ {
+ usedIncludeSet = true;
+ return includeSet.createIncludesFile();
+ }
+
+ /**
+ * <p>Set the set of include patterns. Patterns may be separated by a comma
+ * or a space. This is called by ANT.</p>
+ *
+ * @param includes the string containing the include patterns
+ */
+ public void setIncludes(String includes)
+ {
+ usedIncludeSet = true;
+ includeSet.setIncludes(includes);
+ }
+
+ /**
+ * <p>Add an include file to the list that is to be exluded. This is called
+ * by ANT for a nested element.</p>
+ *
+ * @return {@link org.apache.tools.ant.types.PatternSet.NameEntry}
+ */
+ public PatternSet.NameEntry createExclude()
+ {
+ usedIncludeSet = true;
+ return includeSet.createExclude();
+ }
+
+ /**
+ * <p>Add an exclude file to the list. This is called by ANT for a nested
+ * element.</p>
+ *
+ * @return {@link org.apache.tools.ant.types.PatternSet.NameEntry}
+ */
+ public PatternSet.NameEntry createExcludesFile()
+ {
+ usedIncludeSet = true;
+ return includeSet.createExcludesFile();
+ }
+
+ /**
+ * <p>Set the set of exclude patterns. Patterns may be separated by a comma
+ * or a space. This is called by ANT.</p>
+ *
+ * @param includes the string containing the exclude patterns
+ */
+ public void setExcludes(String excludes)
+ {
+ usedIncludeSet = true;
+ includeSet.setExcludes(excludes);
+ }
+
+ /**
+ * <p>Set a {@link org.apache.tools.ant.types.Reference} to simplify adding
+ * of complex sets of files to include. This is called by ANT.</p>?
+ *
+ * @param reference a <code>Reference</code> to a {@link org.apache.tools.ant.types.FileSet}
+ * or {@link org.apache.tools.ant.types.DirSet}
+ * @throws BuildException if the specified <code>Reference</code> is not
+ * either a <code>FileSet</code> or <code>DirSet</code>
+ */
+ public void setIncludeRefid(Reference reference)
+ {
+ // ensure that the referenced object is either a FileSet or DirSet
+ final Object referencedObject = reference.getReferencedObject(getProject());
+ if( !( (referencedObject instanceof FileSet) ||
+ (referencedObject instanceof DirSet)) )
+ {
+ throw new BuildException("Only FileSets or DirSets are allowed as an include refid.");
+ }
+
+ // add the referenced object to the set of include sets
+ setOfIncludeSets.add(referencedObject);
+ }
+
+ /**
+ * <p>Add a nested {@link org.apache.tools.ant.types.DirSet} to specify
+ * the files to include. This is called by ANT.</p>
+ *
+ * @param dirset the <code>DirSet</code> to be added
+ */
+ public void addDirset(DirSet dirset)
+ {
+ setOfIncludeSets.add(dirset);
+ }
+
+ /**
+ * <p>Add an optional classpath that defines the location of {@link com.sun.gluegen.GlueGen}
+ * and <code>GlueGen</code>'s dependencies.</p>
+ *
+ * @returns {@link org.apache.tools.ant.types.Path}
+ */
+ public Path createClasspath()
+ {
+ return gluegenCommandline.createClasspath(project).createPath();
+ }
+
+ // =========================================================================
+ /**
+ * <p>Run the task. This involves validating the set attributes, creating
+ * the command line to be executed and finally executing the command.</p>
+ *
+ * @see org.apache.tools.ant.Task#execute()
+ */
+ public void execute()
+ throws BuildException
+ {
+ // validate that all of the required attributes have been set
+ validateAttributes();
+
+ // TODO: add logic to determine if the generated file needs to be
+ // regenerated
+
+ // add the attributes to the CommandlineJava
+ addAttributes();
+
+ log(gluegenCommandline.describeCommand(), Project.MSG_VERBOSE);
+
+ // execute the command and throw on error
+ final int error = execute(gluegenCommandline.getCommandline());
+ if(error == 1)
+ throw new BuildException( ("GlueGen returned: " + error), location);
+ }
+
+ /**
+ * <p>Ensure that the user specified all required arguments.</p>
+ *
+ * @throws BuildException if there are required arguments that are not
+ * present or not valid
+ */
+ private void validateAttributes()
+ throws BuildException
+ {
+ // outputRootDir is optional ..
+
+ // validate that the emitter class is set
+ if(!isValid(emitter))
+ throw new BuildException("Invalid emitter class name: " + emitter);
+
+ // validate that the configuration file is set
+ if(!isValid(configuration))
+ throw new BuildException("Invalid configuration file name: " + configuration);
+
+ // validate that the source file is set
+ if(!isValid(sourceFile))
+ throw new BuildException("Invalid source file name: " + sourceFile);
+
+ // CHECK: do there need to be includes to be valid?
+ }
+
+ /**
+ * <p>Is the specified string valid? A valid string is non-<code>null</code>
+ * and has a non-zero length.</p>
+ *
+ * @param string the string to be tested for validity
+ * @return <code>true</code> if the string is valid. <code>false</code>
+ * otherwise.
+ */
+ private boolean isValid(String string)
+ {
+ // check for null
+ if(string == null)
+ return false;
+
+ // ensure that the string has a non-zero length
+ // NOTE: must trim() to remove leading and trailing whitespace
+ if(string.trim().length() < 1)
+ return false;
+
+ // the string is valid
+ return true;
+ }
+
+ /**
+ * <p>Add all of the attributes to the command line. They have already
+ * been validated.</p>
+ */
+ private void addAttributes()
+ throws BuildException
+ {
+ // NOTE: GlueGen uses concatenated flag / value rather than two
+ // separate arguments
+
+ // add the output root dir
+ if(null!=outputRootDir && outputRootDir.trim().length()>0) {
+ gluegenCommandline.createArgument().setValue("-O" + outputRootDir);
+ }
+
+ // add the emitter class name
+ gluegenCommandline.createArgument().setValue("-E" + emitter);
+
+ // add the configuration file name
+ gluegenCommandline.createArgument().setValue("-C" + configuration);
+
+ // add the includedSet to the setOfIncludeSets to simplify processing
+ // all types of include sets ONLY if it has been set.
+ // NOTE: see the usedIncludeSet member javadoc for more info
+ // NOTE: references and nested DirSets have already been added to the
+ // set of include sets
+ if(usedIncludeSet)
+ {
+ includeSet.setDir(getProject().getBaseDir()); // NOTE: the base dir must be set
+ setOfIncludeSets.add(includeSet);
+ }
+
+ // iterate over all include sets and add their directories to the
+ // list of included directories.
+ final List includedDirectories = new LinkedList();
+ for(Iterator includes=setOfIncludeSets.iterator(); includes.hasNext(); )
+ {
+ // get the included set and based on its type add the directories
+ // to includedDirectories
+ Object include = (Object)includes.next();
+ final String[] directoryDirs;
+ if(include instanceof FileSet)
+ {
+ final FileSet fileSet = (FileSet)include;
+ DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject());
+ directoryDirs = directoryScanner.getIncludedDirectories();
+ } else if(include instanceof DirSet)
+ {
+ final DirSet dirSet = (DirSet)include;
+ DirectoryScanner directoryScanner = dirSet.getDirectoryScanner(getProject());
+ directoryDirs = directoryScanner.getIncludedDirectories();
+ } else
+ {
+ // NOTE: this cannot occur as it is checked on setXXX() but
+ // just to be pedantic this is here
+ throw new BuildException("Invalid included construct.");
+ }
+
+ // add the directoryDirs to the includedDirectories
+ // TODO: exclude any directory that is already in the list
+ for(int i=0; i<directoryDirs.length; i++)
+ {
+ includedDirectories.add(directoryDirs[i]);
+ }
+ }
+
+ // if literalInclude is valid then add it to the list of included
+ // directories
+ if(isValid(literalInclude))
+ includedDirectories.add(literalInclude);
+
+ // add the included directories to the command
+ for(Iterator includes=includedDirectories.iterator(); includes.hasNext(); )
+ {
+ String directory = (String)includes.next();
+ gluegenCommandline.createArgument().setValue("-I" + directory);
+ }
+
+ // finally, add the source file
+ gluegenCommandline.createArgument().setValue(sourceFile);
+ }
+
+ /**
+ * <p>Execute {@link com.sun.gluegen.GlueGen} in a forked JVM.</p>
+ *
+ * @throws BuildException
+ */
+ private int execute(String[] command)
+ throws BuildException
+ {
+ // create the object that will perform the command execution
+ Execute execute = new Execute(new LogStreamHandler(this, Project.MSG_INFO,
+ Project.MSG_WARN),
+ null);
+
+ // set the project and command line
+ execute.setAntRun(project);
+ execute.setCommandline(command);
+ execute.setWorkingDirectory( project.getBaseDir() );
+
+ // execute the command
+ try
+ {
+ return execute.execute();
+ } catch(IOException ioe)
+ {
+ throw new BuildException(ioe, location);
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/ant/StaticGLGenTask.java b/src/java/com/sun/gluegen/ant/StaticGLGenTask.java
new file mode 100644
index 0000000..8761942
--- /dev/null
+++ b/src/java/com/sun/gluegen/ant/StaticGLGenTask.java
@@ -0,0 +1,304 @@
+package com.sun.gluegen.ant;
+
+/*
+ * StaticGLGenTask.java
+ * Copyright (C) 2003 Rob Grzywinski ([email protected])
+ *
+ * Copying, distribution and use of this software in source and binary
+ * forms, with or without modification, is permitted provided that the
+ * following conditions are met:
+ *
+ * Distributions of source code must reproduce the copyright notice,
+ * this list of conditions and the following disclaimer in the source
+ * code header files; and Distributions of binary code must reproduce
+ * the copyright notice, this list of conditions and the following
+ * disclaimer in the documentation, Read me file, license file and/or
+ * other materials provided with the software distribution.
+ *
+ * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright
+ * holder may not 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, NON-INTERFERENCE, ACCURACY OF
+ * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE
+ * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE
+ * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT
+ * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION,
+ * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT
+ * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED
+ * WARRANTY OF FITNESS FOR SUCH USES.
+ */
+
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * <p>An <a href="http://ant.apache.org">ANT</a> {@link org.apache.tools.ant.Task}
+ * for using {@link com.sun.gluegen.opengl.BuildStaticGLInfo}.</p>
+ *
+ * <p>Usage:</p>
+ * <pre>
+ &lt;staticglgen package="[generated files package]"
+ headers="[file pattern of GL headers]"
+ outputdir="[directory to output the generated files]" /&gt;
+ * </pre>
+ *
+ * @author Rob Grzywinski <a href="mailto:[email protected]">[email protected]</a>
+ */
+// FIXME: blow out javadoc
+public class StaticGLGenTask extends Task
+{
+ /**
+ * <p>The {@link com.sun.gluegen.opengl.BuildStaticGLInfo} classname.</p>
+ */
+ private static final String GL_GEN = "com.sun.gluegen.opengl.BuildStaticGLInfo";
+
+ // =========================================================================
+ /**
+ * <p>The {@link org.apache.tools.ant.types.CommandlineJava} that is used
+ * to execute {@link com.sun.gluegen.opengl.BuildStaticGLInfo}.</p>
+ */
+ private CommandlineJava glgenCommandline;
+
+ // =========================================================================
+ /**
+ * <p>The package name for the generated files.</p>
+ */
+ private String packageName;
+
+ /**
+ * <p>The output directory.</p>
+ */
+ private String outputDirectory;
+
+ /**
+ * <p>The {@link org.apache.tools.ant.types.FileSet} of GL headers.</p>
+ */
+ private FileSet headerSet = new FileSet();
+
+ // =========================================================================
+ /**
+ * <p>Create and add the VM and classname to {@link org.apache.tools.ant.types.CommandlineJava}.</p>
+ */
+ public StaticGLGenTask()
+ {
+ // create the CommandlineJava that will be used to call BuildStaticGLInfo
+ glgenCommandline = new CommandlineJava();
+
+ // set the VM and classname in the commandline
+ glgenCommandline.setVm(JavaEnvUtils.getJreExecutable("java"));
+ glgenCommandline.setClassname(GL_GEN);
+ }
+
+ // =========================================================================
+ // ANT getters and setters
+ /**
+ * <p>Set the package name for the generated files. This is called by ANT.</p>
+ *
+ * @param packageName the name of the package for the generated files
+ */
+ public void setPackage(String packageName)
+ {
+ log( ("Setting package name to: " + packageName), Project.MSG_VERBOSE);
+ this.packageName = packageName;
+ }
+
+ /**
+ * <p>Set the output directory. This is called by ANT.</p>
+ *
+ * @param directory the output directory
+ */
+ public void setOutputDir(String directory)
+ {
+ log( ("Setting output directory to: " + directory),
+ Project.MSG_VERBOSE);
+ this.outputDirectory = directory;
+ }
+
+ /**
+ * <p>Add a header file to the list. This is called by ANT for a nested
+ * element.</p>
+ *
+ * @return {@link org.apache.tools.ant.types.PatternSet.NameEntry}
+ */
+ public PatternSet.NameEntry createHeader()
+ {
+ return headerSet.createInclude();
+ }
+
+ /**
+ * <p>Add a header file to the list. This is called by ANT for a nested
+ * element.</p>
+ *
+ * @return {@link org.apache.tools.ant.types.PatternSet.NameEntry}
+ */
+ public PatternSet.NameEntry createHeadersFile()
+ {
+ return headerSet.createIncludesFile();
+ }
+
+ /**
+ * <p>Set the set of header patterns. Patterns may be separated by a comma
+ * or a space. This is called by ANT.</p>
+ *
+ * @param headers the string containing the header patterns
+ */
+ public void setHeaders(String headers)
+ {
+ headerSet.setIncludes(headers);
+ }
+
+ /**
+ * <p>Add an optional classpath that defines the location of {@link com.sun.gluegen.opengl.BuildStaticGLInfo}
+ * and <code>BuildStaticGLInfo</code>'s dependencies.</p>
+ *
+ * @returns {@link org.apache.tools.ant.types.Path}
+ */
+ public Path createClasspath()
+ {
+ return glgenCommandline.createClasspath(project).createPath();
+ }
+
+ // =========================================================================
+ /**
+ * <p>Run the task. This involves validating the set attributes, creating
+ * the command line to be executed and finally executing the command.</p>
+ *
+ * @see org.apache.tools.ant.Task#execute()
+ */
+ public void execute()
+ throws BuildException
+ {
+ // validate that all of the required attributes have been set
+ validateAttributes();
+
+ // TODO: add logic to determine if the generated file needs to be
+ // regenerated
+
+ // add the attributes to the CommandlineJava
+ addAttributes();
+
+ log(glgenCommandline.describeCommand(), Project.MSG_VERBOSE);
+
+ // execute the command and throw on error
+ final int error = execute(glgenCommandline.getCommandline());
+ if(error == 1)
+ throw new BuildException( ("BuildStaticGLInfo returned: " + error), location);
+ }
+
+ /**
+ * <p>Ensure that the user specified all required arguments.</p>
+ *
+ * @throws BuildException if there are required arguments that are not
+ * present or not valid
+ */
+ private void validateAttributes()
+ throws BuildException
+ {
+ // validate that the package name is set
+ if(!isValid(packageName))
+ throw new BuildException("Invalid package name: " + packageName);
+
+ // validate that the output directory is set
+ // TODO: switch to file and ensure that it exists
+ if(!isValid(outputDirectory))
+ throw new BuildException("Invalid output directory name: " + outputDirectory);
+
+ // TODO: validate that there are headers set
+ }
+
+ /**
+ * <p>Is the specified string valid? A valid string is non-<code>null</code>
+ * and has a non-zero length.</p>
+ *
+ * @param string the string to be tested for validity
+ * @return <code>true</code> if the string is valid. <code>false</code>
+ * otherwise.
+ */
+ private boolean isValid(String string)
+ {
+ // check for null
+ if(string == null)
+ return false;
+
+ // ensure that the string has a non-zero length
+ // NOTE: must trim() to remove leading and trailing whitespace
+ if(string.trim().length() < 1)
+ return false;
+
+ // the string is valid
+ return true;
+ }
+
+ /**
+ * <p>Add all of the attributes to the command line. They have already
+ * been validated.</p>
+ */
+ private void addAttributes()
+ {
+ // add the package name
+ glgenCommandline.createArgument().setValue(packageName);
+
+ // add the output directory name
+ glgenCommandline.createArgument().setValue(outputDirectory);
+
+ // add the header -files- from the FileSet
+ headerSet.setDir(getProject().getBaseDir());
+ DirectoryScanner directoryScanner = headerSet.getDirectoryScanner(getProject());
+ String[] directoryFiles = directoryScanner.getIncludedFiles();
+ for(int i=0; i<directoryFiles.length; i++)
+ {
+ glgenCommandline.createArgument().setValue(directoryFiles[i]);
+ }
+ }
+
+ /**
+ * <p>Execute {@link com.sun.gluegen.opengl.BuildStaticGLInfo} in a
+ * forked JVM.</p>
+ *
+ * @throws BuildException
+ */
+ private int execute(String[] command)
+ throws BuildException
+ {
+ // create the object that will perform the command execution
+ Execute execute = new Execute(new LogStreamHandler(this, Project.MSG_INFO,
+ Project.MSG_WARN),
+ null);
+
+ // set the project and command line
+ execute.setAntRun(project);
+ execute.setCommandline(command);
+ execute.setWorkingDirectory( project.getBaseDir() );
+
+ // execute the command
+ try
+ {
+ return execute.execute();
+ } catch(IOException ioe)
+ {
+ throw new BuildException(ioe, location);
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/cgram/CSymbolTable.java b/src/java/com/sun/gluegen/cgram/CSymbolTable.java
new file mode 100644
index 0000000..51edf44
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/CSymbolTable.java
@@ -0,0 +1,132 @@
+package com.sun.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/java/com/sun/gluegen/cgram/CToken.java b/src/java/com/sun/gluegen/cgram/CToken.java
new file mode 100644
index 0000000..5d85c48
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/CToken.java
@@ -0,0 +1,32 @@
+package com.sun.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/java/com/sun/gluegen/cgram/Define.java b/src/java/com/sun/gluegen/cgram/Define.java
new file mode 100644
index 0000000..a71c538
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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/java/com/sun/gluegen/cgram/GnuCEmitter.g b/src/java/com/sun/gluegen/cgram/GnuCEmitter.g
new file mode 100644
index 0000000..82003c3
--- /dev/null
+++ b/src/java/com/sun/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 com.sun.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/java/com/sun/gluegen/cgram/GnuCParser.g b/src/java/com/sun/gluegen/cgram/GnuCParser.g
new file mode 100644
index 0000000..7de057c
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/GnuCParser.g
@@ -0,0 +1,865 @@
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ 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 com.sun.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"
+ | "__int32"
+ | "__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/java/com/sun/gluegen/cgram/GnuCTreeParser.g b/src/java/com/sun/gluegen/cgram/GnuCTreeParser.g
new file mode 100644
index 0000000..5231dee
--- /dev/null
+++ b/src/java/com/sun/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 com.sun.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/java/com/sun/gluegen/cgram/HeaderParser.g b/src/java/com/sun/gluegen/cgram/HeaderParser.g
new file mode 100644
index 0000000..7c13968
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/HeaderParser.g
@@ -0,0 +1,725 @@
+/*
+ * 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 com.sun.gluegen.cgram;
+
+ import java.io.*;
+ import java.util.*;
+
+ import antlr.CommonAST;
+ import com.sun.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 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, null, 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 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, null, 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(), SizeThunk.mul(SizeThunk.constant(len), tb.type().getSize()), len, 0)));
+ return;
+ } catch (RecognitionException e) {
+ // Fall through
+ }
+ }
+ tb.setType(canonicalize(new PointerType(SizeThunk.POINTER,
+ 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) {
+ // This isn't quite correct. In theory the enum should expand to
+ // the size of the largest element, so if there were a long long
+ // entry the enum should expand to e.g. int64. However, using
+ // "long" here (which is what used to be the case) was
+ // definitely incorrect and caused problems.
+ enumType = new EnumType(enumTypeName, SizeThunk.INT);
+ }
+
+ 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, null, 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(SizeThunk.POINTER,
+ 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", SizeThunk.INT, ((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" , SizeThunk.CHAR, unsigned, cvAttrs); }
+ | "short" { t = new IntType("short", SizeThunk.SHORT, unsigned, cvAttrs); }
+ | "int" { t = new IntType("int" , SizeThunk.INT, unsigned, cvAttrs); }
+ | "long" { t = new IntType("long" , SizeThunk.LONG, unsigned, cvAttrs); }
+ | "__int32" { t = new IntType("__int32", SizeThunk.INT, unsigned, cvAttrs); }
+ | "__int64" { t = new IntType("__int64", SizeThunk.INT64, unsigned, cvAttrs); }
+ | "float" { t = new FloatType("float", SizeThunk.FLOAT, cvAttrs); }
+ | "double" { t = new DoubleType("double", SizeThunk.DOUBLE, 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, null, 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, null));
+ }
+ }
+ }
+ }
+ ;
+
+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", SizeThunk.INT, ((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(), null)); 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 )? {
+ long value = 0;
+ if (eVal != null) {
+ String vTxt = eVal.getAllChildrenText();
+ if (enumHash.containsKey(vTxt)) {
+ EnumType oldEnumType = (EnumType) enumHash.get(vTxt);
+ value = oldEnumType.getEnumValue(vTxt);
+ } else {
+ try {
+ value = Long.decode(vTxt).longValue();
+ } catch (NumberFormatException e) {
+ System.err.println("NumberFormatException: ID[" + eName.getText() + "], VALUE=[" + vTxt + "]");
+ throw e;
+ }
+ }
+ } else {
+ value = defaultValue;
+ }
+
+ 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(SizeThunk.POINTER,
+ 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/java/com/sun/gluegen/cgram/LineObject.java b/src/java/com/sun/gluegen/cgram/LineObject.java
new file mode 100644
index 0000000..0ed470c
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/LineObject.java
@@ -0,0 +1,126 @@
+package com.sun.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/java/com/sun/gluegen/cgram/PreprocessorInfoChannel.java b/src/java/com/sun/gluegen/cgram/PreprocessorInfoChannel.java
new file mode 100644
index 0000000..431af91
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/PreprocessorInfoChannel.java
@@ -0,0 +1,73 @@
+package com.sun.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/java/com/sun/gluegen/cgram/StdCParser.g b/src/java/com/sun/gluegen/cgram/StdCParser.g
new file mode 100644
index 0000000..e84fbfd
--- /dev/null
+++ b/src/java/com/sun/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 com.sun.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/java/com/sun/gluegen/cgram/TNode.java b/src/java/com/sun/gluegen/cgram/TNode.java
new file mode 100644
index 0000000..9fca506
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/TNode.java
@@ -0,0 +1,443 @@
+package com.sun.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_;
+ }
+
+ /** Returns the text for this node and all children */
+ public String getAllChildrenText() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(getText());
+ for (TNode node = (TNode) getFirstChild(); node != null; node = (TNode) node.getNextSibling()) {
+ buf.append(node.getText());
+ }
+ return buf.toString();
+ }
+
+ /** 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/java/com/sun/gluegen/cgram/TNodeFactory.java b/src/java/com/sun/gluegen/cgram/TNodeFactory.java
new file mode 100644
index 0000000..4523632
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/TNodeFactory.java
@@ -0,0 +1,33 @@
+package com.sun.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/java/com/sun/gluegen/cgram/types/ArrayType.java b/src/java/com/sun/gluegen/cgram/types/ArrayType.java
new file mode 100644
index 0000000..0e23d35
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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, SizeThunk 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(SizeThunk.mul(SizeThunk.constant(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/java/com/sun/gluegen/cgram/types/BitType.java b/src/java/com/sun/gluegen/cgram/types/BitType.java
new file mode 100644
index 0000000..293eb39
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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/java/com/sun/gluegen/cgram/types/CVAttributes.java b/src/java/com/sun/gluegen/cgram/types/CVAttributes.java
new file mode 100644
index 0000000..589904b
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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/java/com/sun/gluegen/cgram/types/CompoundType.java b/src/java/com/sun/gluegen/cgram/types/CompoundType.java
new file mode 100644
index 0000000..28d7b76
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/CompoundType.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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, SizeThunk size, CompoundTypeKind kind, int cvAttributes) {
+ this(name, size, kind, cvAttributes, null);
+ }
+
+ private CompoundType(String name, SizeThunk 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 = 0;
+ }
+
+ 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) &&
+ (structName == t.structName || (structName != null && structName.equals(t.structName))) &&
+ 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(SizeThunk 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/java/com/sun/gluegen/cgram/types/CompoundTypeKind.java b/src/java/com/sun/gluegen/cgram/types/CompoundTypeKind.java
new file mode 100644
index 0000000..8df12ac
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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/java/com/sun/gluegen/cgram/types/DoubleType.java b/src/java/com/sun/gluegen/cgram/types/DoubleType.java
new file mode 100644
index 0000000..6d6e62c
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+/** Represents a double-word floating-point type (C type "double".) */
+
+public class DoubleType extends PrimitiveType {
+ public DoubleType(String name, SizeThunk 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/java/com/sun/gluegen/cgram/types/EnumType.java b/src/java/com/sun/gluegen/cgram/types/EnumType.java
new file mode 100644
index 0000000..717d389
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/EnumType.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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;
+
+ public EnumType(String name) {
+ super(name, SizeThunk.LONG, false, CVAttributes.CONST );
+ this.underlyingType = new IntType(name, SizeThunk.LONG, false, CVAttributes.CONST);
+ }
+
+ public EnumType(String name, SizeThunk enumSizeInBytes) {
+ super(name, enumSizeInBytes, false, CVAttributes.CONST );
+ this.underlyingType = new IntType(name, enumSizeInBytes, 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/java/com/sun/gluegen/cgram/types/Field.java b/src/java/com/sun/gluegen/cgram/types/Field.java
new file mode 100644
index 0000000..e6ec18d
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/Field.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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+/** Represents a field in a struct or union. */
+
+public class Field {
+ private String name;
+ private Type type;
+ private SizeThunk offset;
+
+ public Field(String name, Type type, SizeThunk 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;
+ // Note: don't know how to examine offset any more since it's
+ // implemented in terms of code and they're not canonicalized
+ return (((name != null && name.equals(f.name)) ||
+ (name == null && f.name == null)) &&
+ type.equals(f.type));
+ }
+
+ /** Name of this field in the containing data structure. */
+ public String getName() { return name; }
+
+ /** Type of this field. */
+ public Type getType() { return type; }
+
+ /** SizeThunk computing offset, in bytes, of this field in the containing data structure. */
+ public SizeThunk getOffset() { return offset; }
+
+ /** Offset, in bytes, of this field in the containing data structure
+ given the specified MachineDescription. */
+ public long getOffset(MachineDescription machDesc) { return offset.compute(machDesc); }
+
+ /** Sets the offset of this field in the containing data structure. */
+ public void setOffset(SizeThunk 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();
+ // FIXME: pick up calling convention?
+ return ft.toString(getName(), null, false, true) + ";";
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/cgram/types/FloatType.java b/src/java/com/sun/gluegen/cgram/types/FloatType.java
new file mode 100644
index 0000000..7a6fa4d
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+/** Represents a single-word floating-point type (C type "float".) */
+
+public class FloatType extends PrimitiveType {
+ public FloatType(String name, SizeThunk 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/java/com/sun/gluegen/cgram/types/FunctionSymbol.java b/src/java/com/sun/gluegen/cgram/types/FunctionSymbol.java
new file mode 100644
index 0000000..65e172f
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/FunctionSymbol.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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());
+ }
+
+ /** Helper routine for emitting native javadoc tags */
+ public String toString(boolean emitNativeTag) {
+ return getType().toString(getName(), emitNativeTag);
+ }
+
+ 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;
+
+ if(getName()==null && other.getName()!=null) {
+ return false;
+ }
+
+ return (
+ (getName() == other.getName() || getName().equals(other.getName()))
+ && type.equals(other.type));
+ }
+}
diff --git a/src/java/com/sun/gluegen/cgram/types/FunctionType.java b/src/java/com/sun/gluegen/cgram/types/FunctionType.java
new file mode 100644
index 0000000..7a9c2b5
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/FunctionType.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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, SizeThunk 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 void setArgumentName(int i, String name)
+ {
+ argumentNames.set(i,name);
+ }
+
+ public String toString() {
+ return toString(null);
+ }
+
+ public String toString(String functionName) {
+ return toString(functionName, false);
+ }
+
+ public String toString(String functionName, boolean emitNativeTag) {
+ return toString(functionName, null, emitNativeTag, false);
+ }
+
+ String toString(String functionName, String callingConvention, boolean emitNativeTag, boolean isPointer) {
+ StringBuffer res = new StringBuffer();
+ res.append(getReturnType());
+ res.append(" ");
+ if (isPointer) {
+ res.append("(");
+ if (callingConvention != null) {
+ res.append(callingConvention);
+ }
+ res.append("*");
+ }
+ if (functionName != null) {
+ if (emitNativeTag) {
+ // Emit @native tag for javadoc purposes
+ res.append("{@native ");
+ }
+ res.append(functionName);
+ if (emitNativeTag) {
+ res.append("}");
+ }
+ }
+ 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), callingConvention, false, 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/java/com/sun/gluegen/cgram/types/IntType.java b/src/java/com/sun/gluegen/cgram/types/IntType.java
new file mode 100644
index 0000000..acd6a3d
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+public class IntType extends PrimitiveType {
+ private boolean unsigned;
+ private boolean typedefedUnsigned;
+
+ public IntType(String name, SizeThunk size, boolean unsigned, int cvAttributes) {
+ this(name, size, unsigned, cvAttributes, false);
+ }
+
+ private IntType(String name, SizeThunk 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/java/com/sun/gluegen/cgram/types/MachineDescription.java b/src/java/com/sun/gluegen/cgram/types/MachineDescription.java
new file mode 100644
index 0000000..b3aaf53
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/MachineDescription.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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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;
+ private int structAlignmentInBytes;
+
+ public MachineDescription(int charSizeInBytes,
+ int shortSizeInBytes,
+ int intSizeInBytes,
+ int longSizeInBytes,
+ int int64SizeInBytes,
+ int floatSizeInBytes,
+ int doubleSizeInBytes,
+ int pointerSizeInBytes,
+ int structAlignmentInBytes) {
+ this.charSizeInBytes = charSizeInBytes;
+ this.shortSizeInBytes = shortSizeInBytes;
+ this.intSizeInBytes = intSizeInBytes;
+ this.longSizeInBytes = longSizeInBytes;
+ this.int64SizeInBytes = int64SizeInBytes;
+ this.floatSizeInBytes = floatSizeInBytes;
+ this.doubleSizeInBytes = doubleSizeInBytes;
+ this.pointerSizeInBytes = pointerSizeInBytes;
+ this.structAlignmentInBytes = structAlignmentInBytes;
+ }
+
+ 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; }
+ public int structAlignmentInBytes() { return structAlignmentInBytes; }
+}
diff --git a/src/java/com/sun/gluegen/cgram/types/MachineDescription32Bit.java b/src/java/com/sun/gluegen/cgram/types/MachineDescription32Bit.java
new file mode 100644
index 0000000..7b8f12d
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+public class MachineDescription32Bit extends MachineDescription {
+ public MachineDescription32Bit() {
+ super(1, 2, 4, 4, 8, 4, 8, 4, 8);
+ }
+}
diff --git a/src/java/com/sun/gluegen/cgram/types/MachineDescription64Bit.java b/src/java/com/sun/gluegen/cgram/types/MachineDescription64Bit.java
new file mode 100644
index 0000000..1036399
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/MachineDescription64Bit.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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+public class MachineDescription64Bit extends MachineDescription {
+ public MachineDescription64Bit() {
+ super(1, 2, 4, 8, 8, 4, 8, 8, 16);
+ }
+}
diff --git a/src/java/com/sun/gluegen/cgram/types/PointerType.java b/src/java/com/sun/gluegen/cgram/types/PointerType.java
new file mode 100644
index 0000000..f95066a
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/PointerType.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+public class PointerType extends Type {
+ private Type targetType;
+ private String computedName;
+ private boolean hasTypedefedName;
+
+ public PointerType(SizeThunk 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(SizeThunk 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 boolean hasTypedefedName() {
+ return hasTypedefedName;
+ }
+
+ 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, null); // this is a pointer to an unnamed function
+ }
+ }
+
+ /** For use only when printing function pointers. Calling convention
+ string (i.e., "__stdcall") is optional and is generally only
+ needed on Windows. */
+ public String toString(String functionName, String callingConvention) {
+ 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, callingConvention, false, 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/java/com/sun/gluegen/cgram/types/PrimitiveType.java b/src/java/com/sun/gluegen/cgram/types/PrimitiveType.java
new file mode 100644
index 0000000..80dab9a
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+public abstract class PrimitiveType extends Type {
+ protected PrimitiveType(String name, SizeThunk size, int cvAttributes) {
+ super(name, size, cvAttributes);
+ }
+
+ public boolean isPrimitive() {
+ return true;
+ }
+}
diff --git a/src/java/com/sun/gluegen/cgram/types/SizeThunk.java b/src/java/com/sun/gluegen/cgram/types/SizeThunk.java
new file mode 100755
index 0000000..74feef9
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/SizeThunk.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+/** Provides a level of indirection between the definition of a type's
+ size and the absolute value of this size. Necessary when
+ generating glue code for two different CPU architectures (e.g.,
+ 32-bit and 64-bit) from the same internal representation of the
+ various types involved. */
+
+public abstract class SizeThunk {
+ // Private constructor because there are only a few of these
+ private SizeThunk() {}
+
+ public abstract long compute(MachineDescription machDesc);
+
+ public static final SizeThunk CHAR = new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return machDesc.charSizeInBytes();
+ }
+ };
+
+ public static final SizeThunk SHORT = new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return machDesc.shortSizeInBytes();
+ }
+ };
+
+ public static final SizeThunk INT = new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return machDesc.intSizeInBytes();
+ }
+ };
+
+ public static final SizeThunk LONG = new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return machDesc.longSizeInBytes();
+ }
+ };
+
+ public static final SizeThunk INT64 = new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return machDesc.int64SizeInBytes();
+ }
+ };
+
+ public static final SizeThunk FLOAT = new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return machDesc.floatSizeInBytes();
+ }
+ };
+
+ public static final SizeThunk DOUBLE = new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return machDesc.doubleSizeInBytes();
+ }
+ };
+
+ public static final SizeThunk POINTER = new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return machDesc.pointerSizeInBytes();
+ }
+ };
+
+ // Factory methods for performing certain limited kinds of
+ // arithmetic on these values
+ public static SizeThunk add(final SizeThunk thunk1,
+ final SizeThunk thunk2) {
+ return new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return thunk1.compute(machDesc) + thunk2.compute(machDesc);
+ }
+ };
+ }
+
+ public static SizeThunk sub(final SizeThunk thunk1,
+ final SizeThunk thunk2) {
+ return new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return thunk1.compute(machDesc) - thunk2.compute(machDesc);
+ }
+ };
+ }
+
+ public static SizeThunk mul(final SizeThunk thunk1,
+ final SizeThunk thunk2) {
+ return new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return thunk1.compute(machDesc) * thunk2.compute(machDesc);
+ }
+ };
+ }
+
+ public static SizeThunk mod(final SizeThunk thunk1,
+ final SizeThunk thunk2) {
+ return new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return thunk1.compute(machDesc) % thunk2.compute(machDesc);
+ }
+ };
+ }
+
+ public static SizeThunk roundUp(final SizeThunk thunk1,
+ final SizeThunk thunk2) {
+ return new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ long sz1 = thunk1.compute(machDesc);
+ long sz2 = thunk2.compute(machDesc);
+ long rem = (sz1 % sz2);
+ if (rem == 0) {
+ return sz1;
+ }
+ return sz1 + (sz2 - rem);
+ }
+ };
+ }
+
+ public static SizeThunk max(final SizeThunk thunk1,
+ final SizeThunk thunk2) {
+ return new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return Math.max(thunk1.compute(machDesc), thunk2.compute(machDesc));
+ }
+ };
+ }
+
+ public static SizeThunk constant(final int constant) {
+ return new SizeThunk() {
+ public long compute(MachineDescription machDesc) {
+ return constant;
+ }
+ };
+ }
+}
diff --git a/src/java/com/sun/gluegen/cgram/types/Type.java b/src/java/com/sun/gluegen/cgram/types/Type.java
new file mode 100644
index 0000000..0dcaabc
--- /dev/null
+++ b/src/java/com/sun/gluegen/cgram/types/Type.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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 SizeThunk size;
+ private int cvAttributes;
+ private int typedefedCVAttributes;
+ private boolean hasTypedefName;
+
+ protected Type(String name, SizeThunk 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;
+ }
+
+ /** SizeThunk which computes size of this type in bytes. */
+ public SizeThunk getSize() { return size; }
+ /** Size of this type in bytes according to the given MachineDescription. */
+ public long getSize(MachineDescription machDesc) {
+ SizeThunk thunk = getSize();
+ if (thunk == null) {
+ throw new RuntimeException("No size set for type \"" + getName() + "\"");
+ }
+ return thunk.compute(machDesc);
+ }
+ /** Set the size of this type; only available for CompoundTypes. */
+ void setSize(SizeThunk 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). Returns 0 if this
+ type is not a pointer type. */
+ public int pointerDepth() {
+ PointerType pt = asPointer();
+ if (pt == null) {
+ return 0;
+ }
+ return 1 + pt.getTargetType().pointerDepth();
+ }
+
+ /** Helper method for determining how many array dimentions this
+ type represents (i.e., "char[][]" returns 2). Returns 0 if this
+ type is not an array type. */
+ public int arrayDimension() {
+ ArrayType arrayType = asArray();
+ if (arrayType == null) {
+ return 0;
+ }
+ return 1 + arrayType.getElementType().arrayDimension();
+ }
+
+ /** 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/java/com/sun/gluegen/cgram/types/TypeDictionary.java b/src/java/com/sun/gluegen/cgram/types/TypeDictionary.java
new file mode 100644
index 0000000..5c74455
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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.
+ * @return 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/java/com/sun/gluegen/cgram/types/TypeVisitor.java b/src/java/com/sun/gluegen/cgram/types/TypeVisitor.java
new file mode 100644
index 0000000..88f7dd5
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+public interface TypeVisitor {
+ public void visitType(Type t);
+}
diff --git a/src/java/com/sun/gluegen/cgram/types/VoidType.java b/src/java/com/sun/gluegen/cgram/types/VoidType.java
new file mode 100644
index 0000000..3a2f1b9
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.cgram.types;
+
+public class VoidType extends Type {
+ public VoidType(int cvAttributes) {
+ this("void", cvAttributes);
+ }
+
+ private VoidType(String name, int cvAttributes) {
+ super(name, null, cvAttributes);
+ }
+
+ public VoidType asVoid() { return this; }
+
+ Type newCVVariant(int cvAttributes) {
+ return new VoidType(getName(), cvAttributes);
+ }
+}
diff --git a/src/java/com/sun/gluegen/jgram/JavaParser.g b/src/java/com/sun/gluegen/jgram/JavaParser.g
new file mode 100644
index 0000000..e3a1962
--- /dev/null
+++ b/src/java/com/sun/gluegen/jgram/JavaParser.g
@@ -0,0 +1,1315 @@
+/* Java 1.3 Recognizer
+ *
+ * Run 'java Main [-showtree] directory-full-of-java-files'
+ *
+ * [The -showtree option pops up a Swing frame that shows
+ * the AST constructed from the parser.]
+ *
+ * Run 'java Main <directory full of java files>'
+ *
+ * Contributing authors:
+ * John Mitchell [email protected]
+ * Terence Parr [email protected]
+ * John Lilley [email protected]
+ * Scott Stanchfield [email protected]
+ * Markus Mohnen [email protected]
+ * Peter Williams [email protected]
+ * Allan Jacobs [email protected]
+ * Steve Messick [email protected]
+ * John Pybus [email protected]
+ *
+ * Version 1.00 December 9, 1997 -- initial release
+ * Version 1.01 December 10, 1997
+ * fixed bug in octal def (0..7 not 0..8)
+ * Version 1.10 August 1998 (parrt)
+ * added tree construction
+ * fixed definition of WS,comments for mac,pc,unix newlines
+ * added unary plus
+ * Version 1.11 (Nov 20, 1998)
+ * Added "shutup" option to turn off last ambig warning.
+ * Fixed inner class def to allow named class defs as statements
+ * synchronized requires compound not simple statement
+ * add [] after builtInType DOT class in primaryExpression
+ * "const" is reserved but not valid..removed from modifiers
+ * Version 1.12 (Feb 2, 1999)
+ * Changed LITERAL_xxx to xxx in tree grammar.
+ * Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ *
+ * Version 1.13 (Apr 23, 1999)
+ * Didn't have (stat)? for else clause in tree parser.
+ * Didn't gen ASTs for interface extends. Updated tree parser too.
+ * Updated to 2.6.0.
+ * Version 1.14 (Jun 20, 1999)
+ * Allowed final/abstract on local classes.
+ * Removed local interfaces from methods
+ * Put instanceof precedence where it belongs...in relationalExpr
+ * It also had expr not type as arg; fixed it.
+ * Missing ! on SEMI in classBlock
+ * fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ * fixed: didn't like Object[].class in parser or tree parser
+ * Version 1.15 (Jun 26, 1999)
+ * Screwed up rule with instanceof in it. :( Fixed.
+ * Tree parser didn't like (expr).something; fixed.
+ * Allowed multiple inheritance in tree grammar. oops.
+ * Version 1.16 (August 22, 1999)
+ * Extending an interface built a wacky tree: had extra EXTENDS.
+ * Tree grammar didn't allow multiple superinterfaces.
+ * Tree grammar didn't allow empty var initializer: {}
+ * Version 1.17 (October 12, 1999)
+ * ESC lexer rule allowed 399 max not 377 max.
+ * java.tree.g didn't handle the expression of synchronized
+ * statements.
+ * Version 1.18 (August 12, 2001)
+ * Terence updated to Java 2 Version 1.3 by
+ * observing/combining work of Allan Jacobs and Steve
+ * Messick. Handles 1.3 src. Summary:
+ * o primary didn't include boolean.class kind of thing
+ * o constructor calls parsed explicitly now:
+ * see explicitConstructorInvocation
+ * o add strictfp modifier
+ * o missing objBlock after new expression in tree grammar
+ * o merged local class definition alternatives, moved after declaration
+ * o fixed problem with ClassName.super.field
+ * o reordered some alternatives to make things more efficient
+ * o long and double constants were not differentiated from int/float
+ * o whitespace rule was inefficient: matched only one char
+ * o add an examples directory with some nasty 1.3 cases
+ * o made Main.java use buffered IO and a Reader for Unicode support
+ * o supports UNICODE?
+ * Using Unicode charVocabulay makes code file big, but only
+ * in the bitsets at the end. I need to make ANTLR generate
+ * unicode bitsets more efficiently.
+ * Version 1.19 (April 25, 2002)
+ * Terence added in nice fixes by John Pybus concerning floating
+ * constants and problems with super() calls. John did a nice
+ * reorg of the primary/postfix expression stuff to read better
+ * and makes f.g.super() parse properly (it was METHOD_CALL not
+ * a SUPER_CTOR_CALL). Also:
+ *
+ * o "finally" clause was a root...made it a child of "try"
+ * o Added stuff for asserts too for Java 1.4, but *commented out*
+ * as it is not backward compatible.
+ *
+ * Version 1.20 (October 27, 2002)
+ *
+ * Terence ended up reorging John Pybus' stuff to
+ * remove some nondeterminisms and some syntactic predicates.
+ * Note that the grammar is stricter now; e.g., this(...) must
+ * be the first statement.
+ *
+ * Trinary ?: operator wasn't working as array name:
+ * (isBig ? bigDigits : digits)[i];
+ *
+ * Checked parser/tree parser on source for
+ * Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
+ * and the 110k-line jGuru server source.
+ *
+ * Version 1.21 (October 17, 2003)
+ * Fixed lots of problems including:
+ * Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
+ * He found a problem/fix with floating point that start with 0
+ * Ray also fixed problem that (int.class) was not recognized.
+ * Thorsten van Ellen noticed that \n are allowed incorrectly in strings.
+ * TJP fixed CHAR_LITERAL analogously.
+ *
+ * Version 1.22 (April 14, 2004)
+ * Changed vocab to be ..\uFFFE to avoid -1 char. removed dummy VOCAB rule.
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ */
+
+header {
+ package com.sun.gluegen.jgram;
+
+ import java.util.*;
+
+ import antlr.CommonAST;
+}
+
+class JavaParser extends Parser;
+
+options {
+ k = 2; // two token lookahead
+ exportVocab=Java; // Call its vocabulary "Java"
+ codeGenMakeSwitchThreshold = 2; // Some optimizations
+ codeGenBitsetTestThreshold = 3;
+ defaultErrorHandler = false; // Don't generate parser error handlers
+ buildAST = true;
+ //buildAST = false;
+}
+
+tokens {
+ BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF;
+ INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
+ PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+ PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
+ POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT;
+ IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
+ FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+ STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL;
+}
+
+{
+ public void clearParsedEnumNames() {
+ enumNames.clear();
+ }
+
+ /** Returns the EnumTypes this HeaderParser processed. */
+ public Set getParsedEnumNames() {
+ return enumNames;
+ }
+
+ /** Clears the list of functions this HeaderParser has parsed.
+ Useful when reusing the same HeaderParser for more than one
+ header file. */
+ public void clearParsedFunctionNames() {
+ functionNames.clear();
+ }
+
+ /** Returns the list of FunctionSymbols this HeaderParser has parsed. */
+ public Set getParsedFunctionNames() {
+ return functionNames;
+ }
+
+ private Set/*<String>*/ functionNames = new HashSet();
+ // hash from name of an enumerated value to the EnumType to which it belongs
+ private Set/*<String>*/ enumNames = new HashSet();
+
+ private int blockDepth = 0;
+}
+
+// Compilation Unit: In Java, this is a single file. This is the start
+// rule for this parser
+compilationUnit
+ : // A compilation unit starts with an optional package definition
+ ( packageDefinition
+ | /* nothing */
+ )
+
+ // Next we have a series of zero or more import statements
+ ( importDefinition )*
+
+ // Wrapping things up with any number of class or interface
+ // definitions
+ ( typeDefinition )*
+
+ EOF!
+ ;
+
+
+// Package statement: "package" followed by an identifier.
+packageDefinition
+ options {defaultErrorHandler = true;} // let ANTLR handle errors
+ : p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI!
+ ;
+
+
+// Import statement: import followed by a package or class name
+importDefinition
+ options {defaultErrorHandler = true;}
+ : i:"import"^ {#i.setType(IMPORT);} identifierStar SEMI!
+ ;
+
+// A type definition in a file is either a class or interface definition.
+typeDefinition
+ options {defaultErrorHandler = true;}
+ : m:modifiers!
+ ( classDefinition[#m]
+ | interfaceDefinition[#m]
+ )
+ | SEMI!
+ ;
+
+/** A declaration is the creation of a reference or primitive-type variable
+ * Create a separate Type/Var tree for each var in the var list.
+ */
+declaration!
+ : m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
+ {#declaration = #v;}
+ ;
+
+// A type specification is a type name with possible brackets afterwards
+// (which would make it an array type).
+typeSpec[boolean addImagNode]
+ : classTypeSpec[addImagNode]
+ | builtInTypeSpec[addImagNode]
+ ;
+
+// A class type specification is a class type with possible brackets afterwards
+// (which would make it an array type).
+classTypeSpec[boolean addImagNode]
+ : identifier (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ {
+ if ( addImagNode ) {
+ #classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec);
+ }
+ }
+ ;
+
+// A builtin type specification is a builtin type with possible brackets
+// afterwards (which would make it an array type).
+builtInTypeSpec[boolean addImagNode]
+ : builtInType (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ {
+ if ( addImagNode ) {
+ #builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
+ }
+ }
+ ;
+
+// A type name. which is either a (possibly qualified) class name or
+// a primitive (builtin) type
+type
+ : identifier
+ | builtInType
+ ;
+
+// The primitive types.
+builtInType
+ : "void"
+ | "boolean"
+ | "byte"
+ | "char"
+ | "short"
+ | "int"
+ | "float"
+ | "long"
+ | "double"
+ ;
+
+// A (possibly-qualified) java identifier. We start with the first IDENT
+// and expand its name by adding dots and following IDENTS
+identifier
+ : IDENT ( DOT^ IDENT )*
+ ;
+
+identifierStar
+ : IDENT
+ ( DOT^ IDENT )*
+ ( DOT^ STAR )?
+ ;
+
+// A list of zero or more modifiers. We could have used (modifier)* in
+// place of a call to modifiers, but I thought it was a good idea to keep
+// this rule separate so they can easily be collected in a Vector if
+// someone so desires
+modifiers
+ : ( modifier )*
+ {#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);}
+ ;
+
+// modifiers for Java classes, interfaces, class/instance vars and methods
+modifier
+ : "private"
+ | "public"
+ | "protected"
+ | "static"
+ | "transient"
+ | "final"
+ | "abstract"
+ | "native"
+ | "threadsafe"
+ | "synchronized"
+// | "const" // reserved word, but not valid
+ | "volatile"
+ | "strictfp"
+ ;
+
+// Definition of a Java class
+classDefinition![AST modifiers]
+ : "class" IDENT
+ // it _might_ have a superclass...
+ sc:superClassClause
+ // it might implement some interfaces...
+ ic:implementsClause
+ // now parse the body of the class
+ cb:classBlock
+ {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
+ modifiers,IDENT,sc,ic,cb);}
+ ;
+
+superClassClause!
+ : ( "extends" id:identifier )?
+ {#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],id);}
+ ;
+
+// Definition of a Java Interface
+interfaceDefinition![AST modifiers]
+ : "interface" IDENT
+ // it might extend some other interfaces
+ ie:interfaceExtends
+ // now parse the body of the interface (looks like a class...)
+ cb:classBlock
+ {#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"],
+ modifiers,IDENT,ie,cb);}
+ ;
+
+
+// This is the body of a class. You can have fields and extra semicolons,
+// That's about it (until you see what a field is...)
+classBlock
+ : LCURLY! { blockDepth++; }
+ ( field | SEMI! )*
+ RCURLY! { blockDepth--; }
+ {#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
+ ;
+
+// An interface can extend several other interfaces...
+interfaceExtends
+ : (
+ e:"extends"!
+ identifier ( COMMA! identifier )*
+ )?
+ {#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],
+ #interfaceExtends);}
+ ;
+
+// A class can implement several interfaces...
+implementsClause
+ : (
+ i:"implements"! identifier ( COMMA! identifier )*
+ )?
+ {#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"],
+ #implementsClause);}
+ ;
+
+// Now the various things that can be defined inside a class or interface...
+// Note that not all of these are really valid in an interface (constructors,
+// for example), and if this grammar were used for a compiler there would
+// need to be some semantic checks to make sure we're doing the right thing...
+field!
+ : // method, constructor, or variable declaration
+ mods:modifiers
+ ( h:ctorHead s:constructorBody // constructor
+ {#field = #(#[CTOR_DEF,"CTOR_DEF"], mods, h, s);}
+
+ | cd:classDefinition[#mods] // inner class
+ {#field = #cd;}
+
+ | id:interfaceDefinition[#mods] // inner interface
+ {#field = #id;}
+
+ | t:typeSpec[false] // method or variable declaration(s)
+ ( fn:IDENT // the name of the method
+
+ // parse the formal parameter declarations.
+ LPAREN! param:parameterDeclarationList RPAREN!
+
+ rt:declaratorBrackets[#t]
+
+ // get the list of exceptions that this method is
+ // declared to throw
+ (tc:throwsClause)?
+
+ ( s2:compoundStatement | SEMI )
+ {#field = #(#[METHOD_DEF,"METHOD_DEF"],
+ mods,
+ #(#[TYPE,"TYPE"],rt),
+ fn,
+ param,
+ tc,
+ s2);
+ if(blockDepth==1) {
+ functionNames.add(fn.getText()); } }
+ | v:variableDefinitions[#mods,#t] SEMI
+// {#field = #(#[VARIABLE_DEF,"VARIABLE_DEF"], v);}
+ {#field = #v;}
+ )
+ )
+
+ // "static { ... }" class initializer
+ | "static" s3:compoundStatement
+ {#field = #(#[STATIC_INIT,"STATIC_INIT"], s3);}
+
+ // "{ ... }" instance initializer
+ | s4:compoundStatement
+ {#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);}
+ ;
+
+constructorBody
+ : lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; }
+ ( options { greedy=true; } : explicitConstructorInvocation)?
+ (statement)*
+ RCURLY! { blockDepth--; }
+ ;
+
+/** Catch obvious constructor calls, but not the expr.super(...) calls */
+explicitConstructorInvocation
+ : "this"! lp1:LPAREN^ argList RPAREN! SEMI!
+ {#lp1.setType(CTOR_CALL);}
+ | "super"! lp2:LPAREN^ argList RPAREN! SEMI!
+ {#lp2.setType(SUPER_CTOR_CALL);}
+ ;
+
+variableDefinitions[AST mods, AST t]
+ : variableDeclarator[getASTFactory().dupTree(mods),
+ getASTFactory().dupTree(t)]
+ ( COMMA!
+ variableDeclarator[getASTFactory().dupTree(mods),
+ getASTFactory().dupTree(t)]
+ )*
+ ;
+
+/** Declaration of a variable. This can be a class/instance variable,
+ * or a local variable in a method
+ * It can also include possible initialization.
+ */
+variableDeclarator![AST mods, AST t]
+ : id:IDENT d:declaratorBrackets[t] v:varInitializer
+ {#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v);
+ if(blockDepth==1) {
+ enumNames.add(id.getText());
+ }
+ }
+ ;
+
+declaratorBrackets[AST typ]
+ : {#declaratorBrackets=typ;}
+ (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ ;
+
+varInitializer
+ : ( ASSIGN^ initializer )?
+ ;
+
+// This is an initializer used to set up an array.
+arrayInitializer
+ : lc:LCURLY^ {#lc.setType(ARRAY_INIT); blockDepth++; }
+ ( initializer
+ (
+ // CONFLICT: does a COMMA after an initializer start a new
+ // initializer or start the option ',' at end?
+ // ANTLR generates proper code by matching
+ // the comma as soon as possible.
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ COMMA! initializer
+ )*
+ (COMMA!)?
+ )?
+ RCURLY! { blockDepth--; }
+ ;
+
+
+// The two "things" that can initialize an array element are an expression
+// and another (nested) array initializer.
+initializer
+ : expression
+ | arrayInitializer
+ ;
+
+// This is the header of a method. It includes the name and parameters
+// for the method.
+// This also watches for a list of exception classes in a "throws" clause.
+ctorHead
+ : IDENT // the name of the method
+
+ // parse the formal parameter declarations.
+ LPAREN! parameterDeclarationList RPAREN!
+
+ // get the list of exceptions that this method is declared to throw
+ (throwsClause)?
+ ;
+
+// This is a list of exception classes that the method is declared to throw
+throwsClause
+ : "throws"^ identifier ( COMMA! identifier )*
+ ;
+
+
+// A list of formal parameters
+parameterDeclarationList
+ : ( parameterDeclaration ( COMMA! parameterDeclaration )* )?
+ {#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
+ #parameterDeclarationList);}
+ ;
+
+// A formal parameter.
+parameterDeclaration!
+ : pm:parameterModifier t:typeSpec[false] id:IDENT
+ pd:declaratorBrackets[#t]
+ {#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
+ pm, #([TYPE,"TYPE"],pd), id);}
+ ;
+
+parameterModifier
+ : (f:"final")?
+ {#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], f);}
+ ;
+
+// Compound statement. This is used in many contexts:
+// Inside a class definition prefixed with "static":
+// it is a class initializer
+// Inside a class definition without "static":
+// it is an instance initializer
+// As the body of a method
+// As a completely indepdent braced block of code inside a method
+// it starts a new scope for variable definitions
+
+compoundStatement
+ : lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; }
+ // include the (possibly-empty) list of statements
+ (statement)*
+ RCURLY! { blockDepth--; }
+ ;
+
+
+statement
+ // A list of statements in curly braces -- start a new scope!
+ : compoundStatement
+
+ // declarations are ambiguous with "ID DOT" relative to expression
+ // statements. Must backtrack to be sure. Could use a semantic
+ // predicate to test symbol table to see what the type was coming
+ // up, but that's pretty hard without a symbol table ;)
+ | (declaration)=> declaration SEMI!
+
+ // An expression statement. This could be a method call,
+ // assignment statement, or any other expression evaluated for
+ // side-effects.
+ | expression SEMI!
+
+ // class definition
+ | m:modifiers! classDefinition[#m]
+
+ // Attach a label to the front of a statement
+ | IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
+
+ // If-else statement
+ | "if"^ LPAREN! expression RPAREN! statement
+ (
+ // CONFLICT: the old "dangling-else" problem...
+ // ANTLR generates proper code matching
+ // as soon as possible. Hush warning.
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ "else"! statement
+ )?
+
+ // For statement
+ | "for"^
+ LPAREN!
+ forInit SEMI! // initializer
+ forCond SEMI! // condition test
+ forIter // updater
+ RPAREN!
+ statement // statement to loop over
+
+ // While statement
+ | "while"^ LPAREN! expression RPAREN! statement
+
+ // do-while statement
+ | "do"^ statement "while"! LPAREN! expression RPAREN! SEMI!
+
+ // get out of a loop (or switch)
+ | "break"^ (IDENT)? SEMI!
+
+ // do next iteration of a loop
+ | "continue"^ (IDENT)? SEMI!
+
+ // Return an expression
+ | "return"^ (expression)? SEMI!
+
+ // switch/case statement
+ | "switch"^ LPAREN! expression RPAREN! LCURLY! { blockDepth++; }
+ ( casesGroup )*
+ RCURLY! { blockDepth--; }
+
+ // exception try-catch block
+ | tryBlock
+
+ // throw an exception
+ | "throw"^ expression SEMI!
+
+ // synchronize a statement
+ | "synchronized"^ LPAREN! expression RPAREN! compoundStatement
+
+ // asserts (uncomment if you want 1.4 compatibility)
+ // | "assert"^ expression ( COLON! expression )? SEMI!
+
+ // empty statement
+ | s:SEMI {#s.setType(EMPTY_STAT);}
+ ;
+
+casesGroup
+ : ( // CONFLICT: to which case group do the statements bind?
+ // ANTLR generates proper code: it groups the
+ // many "case"/"default" labels together then
+ // follows them with the statements
+ options {
+ greedy = true;
+ }
+ :
+ aCase
+ )+
+ caseSList
+ {#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
+ ;
+
+aCase
+ : ("case"^ expression | "default") COLON!
+ ;
+
+caseSList
+ : (statement)*
+ {#caseSList = #(#[SLIST,"SLIST"],#caseSList);}
+ ;
+
+// The initializer for a for loop
+forInit
+ // if it looks like a declaration, it is
+ : ( (declaration)=> declaration
+ // otherwise it could be an expression list...
+ | expressionList
+ )?
+ {#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);}
+ ;
+
+forCond
+ : (expression)?
+ {#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);}
+ ;
+
+forIter
+ : (expressionList)?
+ {#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);}
+ ;
+
+// an exception handler try/catch block
+tryBlock
+ : "try"^ compoundStatement
+ (handler)*
+ ( finallyClause )?
+ ;
+
+finallyClause
+ : "finally"^ compoundStatement
+ ;
+
+// an exception handler
+handler
+ : "catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement
+ ;
+
+
+// expressions
+// Note that most of these expressions follow the pattern
+// thisLevelExpression :
+// nextHigherPrecedenceExpression
+// (OPERATOR nextHigherPrecedenceExpression)*
+// which is a standard recursive definition for a parsing an expression.
+// The operators in java have the following precedences:
+// lowest (13) = *= /= %= += -= <<= >>= >>>= &= ^= |=
+// (12) ?:
+// (11) ||
+// (10) &&
+// ( 9) |
+// ( 8) ^
+// ( 7) &
+// ( 6) == !=
+// ( 5) < <= > >=
+// ( 4) << >>
+// ( 3) +(binary) -(binary)
+// ( 2) * / %
+// ( 1) ++ -- +(unary) -(unary) ~ ! (type)
+// [] () (method call) . (dot -- identifier qualification)
+// new () (explicit parenthesis)
+//
+// the last two are not usually on a precedence chart; I put them in
+// to point out that new has a higher precedence than '.', so you
+// can validy use
+// new Frame().show()
+//
+// Note that the above precedence levels map to the rules below...
+// Once you have a precedence chart, writing the appropriate rules as below
+// is usually very straightfoward
+
+
+
+// the mother of all expressions
+expression
+ : assignmentExpression
+ {#expression = #(#[EXPR,"EXPR"],#expression);}
+ ;
+
+
+// This is a list of expressions.
+expressionList
+ : expression (COMMA! expression)*
+ {#expressionList = #(#[ELIST,"ELIST"], expressionList);}
+ ;
+
+
+// assignment expression (level 13)
+assignmentExpression
+ : conditionalExpression
+ ( ( ASSIGN^
+ | PLUS_ASSIGN^
+ | MINUS_ASSIGN^
+ | STAR_ASSIGN^
+ | DIV_ASSIGN^
+ | MOD_ASSIGN^
+ | SR_ASSIGN^
+ | BSR_ASSIGN^
+ | SL_ASSIGN^
+ | BAND_ASSIGN^
+ | BXOR_ASSIGN^
+ | BOR_ASSIGN^
+ )
+ assignmentExpression
+ )?
+ ;
+
+
+// conditional test (level 12)
+conditionalExpression
+ : logicalOrExpression
+ ( QUESTION^ assignmentExpression COLON! conditionalExpression )?
+ ;
+
+
+// logical or (||) (level 11)
+logicalOrExpression
+ : logicalAndExpression (LOR^ logicalAndExpression)*
+ ;
+
+
+// logical and (&&) (level 10)
+logicalAndExpression
+ : inclusiveOrExpression (LAND^ inclusiveOrExpression)*
+ ;
+
+
+// bitwise or non-short-circuiting or (|) (level 9)
+inclusiveOrExpression
+ : exclusiveOrExpression (BOR^ exclusiveOrExpression)*
+ ;
+
+
+// exclusive or (^) (level 8)
+exclusiveOrExpression
+ : andExpression (BXOR^ andExpression)*
+ ;
+
+
+// bitwise or non-short-circuiting and (&) (level 7)
+andExpression
+ : equalityExpression (BAND^ equalityExpression)*
+ ;
+
+
+// equality/inequality (==/!=) (level 6)
+equalityExpression
+ : relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
+ ;
+
+
+// boolean relational expressions (level 5)
+relationalExpression
+ : shiftExpression
+ ( ( ( LT^
+ | GT^
+ | LE^
+ | GE^
+ )
+ shiftExpression
+ )*
+ | "instanceof"^ typeSpec[true]
+ )
+ ;
+
+
+// bit shift expressions (level 4)
+shiftExpression
+ : additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
+ ;
+
+
+// binary addition/subtraction (level 3)
+additiveExpression
+ : multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
+ ;
+
+
+// multiplication/division/modulo (level 2)
+multiplicativeExpression
+ : unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
+ ;
+
+unaryExpression
+ : INC^ unaryExpression
+ | DEC^ unaryExpression
+ | MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
+ | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression
+ | unaryExpressionNotPlusMinus
+ ;
+
+unaryExpressionNotPlusMinus
+ : BNOT^ unaryExpression
+ | LNOT^ unaryExpression
+
+ // use predicate to skip cases like: (int.class)
+ | (LPAREN builtInTypeSpec[true] RPAREN) =>
+ lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN!
+ unaryExpression
+
+ // Have to backtrack to see if operator follows. If no operator
+ // follows, it's a typecast. No semantic checking needed to parse.
+ // if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
+ | (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
+ lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN!
+ unaryExpressionNotPlusMinus
+
+ | postfixExpression
+ ;
+
+// qualified names, array expressions, method invocation, post inc/dec
+postfixExpression
+ :
+ /*
+ "this"! lp1:LPAREN^ argList RPAREN!
+ {#lp1.setType(CTOR_CALL);}
+
+ | "super"! lp2:LPAREN^ argList RPAREN!
+ {#lp2.setType(SUPER_CTOR_CALL);}
+ |
+ */
+ primaryExpression
+
+ (
+ /*
+ options {
+ // the use of postfixExpression in SUPER_CTOR_CALL adds DOT
+ // to the lookahead set, and gives loads of false non-det
+ // warnings.
+ // shut them off.
+ generateAmbigWarnings=false;
+ }
+ : */
+ DOT^ IDENT
+ ( lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+ argList
+ RPAREN!
+ )?
+ | DOT^ "this"
+
+ | DOT^ "super"
+ ( // (new Outer()).super() (create enclosing instance)
+ lp3:LPAREN^ argList RPAREN!
+ {#lp3.setType(SUPER_CTOR_CALL);}
+ | DOT^ IDENT
+ ( lps:LPAREN^ {#lps.setType(METHOD_CALL);}
+ argList
+ RPAREN!
+ )?
+ )
+ | DOT^ newExpression
+ | lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK!
+ )*
+
+ ( // possibly add on a post-increment or post-decrement.
+ // allows INC/DEC on too much, but semantics can check
+ in:INC^ {#in.setType(POST_INC);}
+ | de:DEC^ {#de.setType(POST_DEC);}
+ )?
+ ;
+
+// the basic element of an expression
+primaryExpression
+ : identPrimary ( options {greedy=true;} : DOT^ "class" )?
+ | constant
+ | "true"
+ | "false"
+ | "null"
+ | newExpression
+ | "this"
+ | "super"
+ | LPAREN! assignmentExpression RPAREN!
+ // look for int.class and int[].class
+ | builtInType
+ ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
+ DOT^ "class"
+ ;
+
+/** Match a, a.b.c refs, a.b.c(...) refs, a.b.c[], a.b.c[].class,
+ * and a.b.c.class refs. Also this(...) and super(...). Match
+ * this or super.
+ */
+identPrimary
+ : IDENT
+ (
+ options {
+ // .ident could match here or in postfixExpression.
+ // We do want to match here. Turn off warning.
+ greedy=true;
+ }
+ : DOT^ IDENT
+ )*
+ (
+ options {
+ // ARRAY_DECLARATOR here conflicts with INDEX_OP in
+ // postfixExpression on LBRACK RBRACK.
+ // We want to match [] here, so greedy. This overcomes
+ // limitation of linear approximate lookahead.
+ greedy=true;
+ }
+ : ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} argList RPAREN! )
+ | ( options {greedy=true;} :
+ lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK!
+ )+
+ )?
+ ;
+
+/** object instantiation.
+ * Trees are built as illustrated by the following input/tree pairs:
+ *
+ * new T()
+ *
+ * new
+ * |
+ * T -- ELIST
+ * |
+ * arg1 -- arg2 -- .. -- argn
+ *
+ * new int[]
+ *
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR
+ *
+ * new int[] {1,2}
+ *
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR -- ARRAY_INIT
+ * |
+ * EXPR -- EXPR
+ * | |
+ * 1 2
+ *
+ * new int[3]
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR
+ * |
+ * EXPR
+ * |
+ * 3
+ *
+ * new int[1][2]
+ *
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR
+ * |
+ * ARRAY_DECLARATOR -- EXPR
+ * | |
+ * EXPR 1
+ * |
+ * 2
+ *
+ */
+newExpression
+ : "new"^ type
+ ( LPAREN! argList RPAREN! (classBlock)?
+
+ //java 1.1
+ // Note: This will allow bad constructs like
+ // new int[4][][3] {exp,exp}.
+ // There needs to be a semantic check here...
+ // to make sure:
+ // a) [ expr ] and [ ] are not mixed
+ // b) [ expr ] and an init are not used together
+
+ | newArrayDeclarator (arrayInitializer)?
+ )
+ ;
+
+argList
+ : ( expressionList
+ | /*nothing*/
+ {#argList = #[ELIST,"ELIST"];}
+ )
+ ;
+
+newArrayDeclarator
+ : (
+ // CONFLICT:
+ // newExpression is a primaryExpression which can be
+ // followed by an array index reference. This is ok,
+ // as the generated code will stay in this loop as
+ // long as it sees an LBRACK (proper behavior)
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
+ (expression)?
+ RBRACK!
+ )+
+ ;
+
+constant
+ : NUM_INT
+ | CHAR_LITERAL
+ | STRING_LITERAL
+ | NUM_FLOAT
+ | NUM_LONG
+ | NUM_DOUBLE
+ ;
+
+//----------------------------------------------------------------------------
+// The Java scanner
+//----------------------------------------------------------------------------
+class JavaLexer extends Lexer;
+
+options {
+ exportVocab=Java; // call the vocabulary "Java"
+ testLiterals=false; // don't automatically test for literals
+ k=4; // four characters of lookahead
+ charVocabulary='\u0003'..'\u7FFE';
+ // without inlining some bitset tests, couldn't do unicode;
+ // I need to make ANTLR generate smaller bitsets; see
+ // bottom of JavaLexer.java
+ codeGenBitsetTestThreshold=20;
+}
+
+// OPERATORS
+QUESTION : '?' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+LBRACK : '[' ;
+RBRACK : ']' ;
+LCURLY : '{' ;
+RCURLY : '}' ;
+COLON : ':' ;
+COMMA : ',' ;
+//DOT : '.' ;
+ASSIGN : '=' ;
+EQUAL : "==" ;
+LNOT : '!' ;
+BNOT : '~' ;
+NOT_EQUAL : "!=" ;
+DIV : '/' ;
+DIV_ASSIGN : "/=" ;
+PLUS : '+' ;
+PLUS_ASSIGN : "+=" ;
+INC : "++" ;
+MINUS : '-' ;
+MINUS_ASSIGN : "-=" ;
+DEC : "--" ;
+STAR : '*' ;
+STAR_ASSIGN : "*=" ;
+MOD : '%' ;
+MOD_ASSIGN : "%=" ;
+SR : ">>" ;
+SR_ASSIGN : ">>=" ;
+BSR : ">>>" ;
+BSR_ASSIGN : ">>>=" ;
+GE : ">=" ;
+GT : ">" ;
+SL : "<<" ;
+SL_ASSIGN : "<<=" ;
+LE : "<=" ;
+LT : '<' ;
+BXOR : '^' ;
+BXOR_ASSIGN : "^=" ;
+BOR : '|' ;
+BOR_ASSIGN : "|=" ;
+LOR : "||" ;
+BAND : '&' ;
+BAND_ASSIGN : "&=" ;
+LAND : "&&" ;
+SEMI : ';' ;
+
+
+// Whitespace -- ignored
+WS : ( ' '
+ | '\t'
+ | '\f'
+ // handle newlines
+ | ( options {generateAmbigWarnings=false;}
+ : "\r\n" // Evil DOS
+ | '\r' // Macintosh
+ | '\n' // Unix (the right way)
+ )
+ { newline(); }
+ )+
+ { _ttype = Token.SKIP; }
+ ;
+
+// Single-line comments
+SL_COMMENT
+ : "//"
+ (~('\n'|'\r'))* ('\n'|'\r'('\n')?)?
+ {$setType(Token.SKIP); newline();}
+ ;
+
+// multiple-line comments
+ML_COMMENT
+ : "/*"
+ ( /* '\r' '\n' can be matched in one alternative or by matching
+ '\r' in one iteration and '\n' in another. I am trying to
+ handle any flavor of newline that comes in, but the language
+ that allows both "\r\n" and "\r" and "\n" to all be valid
+ newline is ambiguous. Consequently, the resulting grammar
+ must be ambiguous. I'm shutting this warning off.
+ */
+ options {
+ generateAmbigWarnings=false;
+ }
+ :
+ { LA(2)!='/' }? '*'
+ | '\r' '\n' {newline();}
+ | '\r' {newline();}
+ | '\n' {newline();}
+ | ~('*'|'\n'|'\r')
+ )*
+ "*/"
+ {$setType(Token.SKIP);}
+ ;
+
+
+// character literals
+CHAR_LITERAL
+ : '\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\''
+ ;
+
+// string literals
+STRING_LITERAL
+ : '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
+ ;
+
+
+// escape sequence -- note that this is protected; it can only be called
+// from another lexer rule -- it will not ever directly return a token to
+// the parser
+// There are various ambiguities hushed in this rule. The optional
+// '0'...'9' digit matches should be matched here rather than letting
+// them go back to STRING_LITERAL to be matched. ANTLR does the
+// right thing by matching immediately; hence, it's ok to shut off
+// the FOLLOW ambig warnings.
+protected
+ESC
+ : '\\'
+ ( 'n'
+ | 'r'
+ | 't'
+ | 'b'
+ | 'f'
+ | '"'
+ | '\''
+ | '\\'
+ | ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+ | '0'..'3'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )?
+ | '4'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )
+ ;
+
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+ : ('0'..'9'|'A'..'F'|'a'..'f')
+ ;
+
+
+// an identifier. Note that testLiterals is set to true! This means
+// that after we match the rule, we look in the literals table to see
+// if it's a literal or really an identifer
+IDENT
+ options {testLiterals=true;}
+ : ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
+ ;
+
+
+// a numeric literal
+NUM_INT
+ {boolean isDecimal=false; Token t=null;}
+ : '.' {_ttype = DOT;}
+ ( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+ {
+ if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
+ _ttype = NUM_FLOAT;
+ }
+ else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
+ )?
+
+ | ( '0' {isDecimal = true;} // special case for just '0'
+ ( ('x'|'X')
+ ( // hex
+ // the 'e'|'E' and float suffix stuff look
+ // like hex digits, hence the (...)+ doesn't
+ // know when to stop: ambig. ANTLR resolves
+ // it correctly by matching immediately. It
+ // is therefor ok to hush warning.
+ options {
+ warnWhenFollowAmbig=false;
+ }
+ : HEX_DIGIT
+ )+
+
+ | //float or double with leading zero
+ (('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
+
+ | ('0'..'7')+ // octal
+ )?
+ | ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
+ )
+ ( ('l'|'L') { _ttype = NUM_LONG; }
+
+ // only check to see if it's a float if looks like decimal so far
+ | {isDecimal}?
+ ( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
+ | EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
+ | f4:FLOAT_SUFFIX {t=f4;}
+ )
+ {
+ if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+ _ttype = NUM_FLOAT;
+ }
+ else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
+ )?
+ ;
+
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+ : ('e'|'E') ('+'|'-')? ('0'..'9')+
+ ;
+
+
+protected
+FLOAT_SUFFIX
+ : 'f'|'F'|'d'|'D'
+ ;
+
diff --git a/src/java/com/sun/gluegen/jgram/Test.java b/src/java/com/sun/gluegen/jgram/Test.java
new file mode 100644
index 0000000..996d645
--- /dev/null
+++ b/src/java/com/sun/gluegen/jgram/Test.java
@@ -0,0 +1,132 @@
+package com.sun.gluegen.jgram;
+
+import java.util.*;
+
+import java.io.*;
+// import antlr.collections.AST;
+import antlr.collections.impl.*;
+import antlr.debug.misc.*;
+import antlr.*;
+// import java.awt.event.*;
+
+class Test {
+
+ static boolean showTree = false;
+ public static void main(String[] args) {
+ // Use a try/catch block for parser exceptions
+ try {
+ // if we have at least one command-line argument
+ if (args.length > 0 ) {
+ System.err.println("Parsing...");
+
+ // for each directory/file specified on the command line
+ for(int i=0; i< args.length;i++) {
+ if ( args[i].equals("-showtree") ) {
+ showTree = true;
+ }
+ else {
+ doFile(new File(args[i])); // parse it
+ }
+ } }
+ else
+ System.err.println("Usage: java com.sun.gluegen.jgram.Test [-showtree] "+
+ "<directory or file name>");
+ }
+ catch(Exception e) {
+ System.err.println("exception: "+e);
+ e.printStackTrace(System.err); // so we can get stack trace
+ }
+ }
+
+
+ // This method decides what action to take based on the type of
+ // file we are looking at
+ public static void doFile(File f)
+ throws Exception {
+ // If this is a directory, walk each file/dir in that directory
+ if (f.isDirectory()) {
+ String files[] = f.list();
+ for(int i=0; i < files.length; i++)
+ doFile(new File(f, files[i]));
+ }
+
+ // otherwise, if this is a java file, parse it!
+ else if ((f.getName().length()>5) &&
+ f.getName().substring(f.getName().length()-5).equals(".java")) {
+ System.err.println(" "+f.getAbsolutePath());
+ // parseFile(f.getName(), new FileInputStream(f));
+ parseFile(f.getName(), new BufferedReader(new FileReader(f)));
+ }
+ }
+
+ // Here's where we do the real work...
+ public static void parseFile(String f, Reader r)
+ throws Exception {
+ try {
+ // Create a scanner that reads from the input stream passed to us
+ JavaLexer lexer = new JavaLexer(r);
+ lexer.setFilename(f);
+
+ // Create a parser that reads from the scanner
+ JavaParser parser = new JavaParser(lexer);
+ parser.setFilename(f);
+
+ // start parsing at the compilationUnit rule
+ parser.compilationUnit();
+
+ Set set = parser.getParsedEnumNames();
+ System.out.println("Enums");
+ for(Iterator iter = set.iterator(); iter.hasNext(); ) {
+ String s = (String) iter.next();
+ System.out.println(s);
+ }
+ System.out.println("Functions");
+ set = parser.getParsedFunctionNames();
+ for(Iterator iter = set.iterator(); iter.hasNext(); ) {
+ String s = (String) iter.next();
+ System.out.println(s);
+ }
+
+ // do something with the tree
+ //doTreeAction(f, parser.getAST(), parser.getTokenNames());
+ }
+ catch (Exception e) {
+ System.err.println("parser exception: "+e);
+ e.printStackTrace(); // so we can get stack trace
+ }
+ }
+
+ /*
+ public static void doTreeAction(String f, AST t, String[] tokenNames) {
+ if ( t==null ) return;
+ if ( showTree ) {
+ ((CommonAST)t).setVerboseStringConversion(true, tokenNames);
+ ASTFactory factory = new ASTFactory();
+ AST r = factory.create(0,"AST ROOT");
+ r.setFirstChild(t);
+ final ASTFrame frame = new ASTFrame("Java AST", r);
+ frame.setVisible(true);
+ frame.addWindowListener(
+ new WindowAdapter() {
+ public void windowClosing (WindowEvent e) {
+ frame.setVisible(false); // hide the Frame
+ frame.dispose();
+ System.exit(0);
+ }
+ }
+ );
+ // System.out.println(t.toStringList());
+ }
+ JavaTreeParser tparse = new JavaTreeParser();
+ try {
+ tparse.compilationUnit(t);
+ // System.out.println("successful walk of result AST for "+f);
+ }
+ catch (RecognitionException e) {
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ }
+
+ } */
+}
+
diff --git a/src/java/com/sun/gluegen/nativesig/NativeSignatureEmitter.java b/src/java/com/sun/gluegen/nativesig/NativeSignatureEmitter.java
new file mode 100755
index 0000000..4fe81af
--- /dev/null
+++ b/src/java/com/sun/gluegen/nativesig/NativeSignatureEmitter.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.nativesig;
+
+import java.io.*;
+import java.util.*;
+
+import com.sun.gluegen.*;
+import com.sun.gluegen.cgram.types.*;
+import com.sun.gluegen.opengl.*;
+import com.sun.gluegen.procaddress.*;
+
+/** Emitter producing NativeSignature attributes. */
+
+public class NativeSignatureEmitter extends GLEmitter {
+ protected List generateMethodBindingEmitters(FunctionSymbol sym) throws Exception {
+ // Allow superclass to do most of the work for us
+ List res = super.generateMethodBindingEmitters(sym);
+
+ // Filter out all non-JavaMethodBindingEmitters
+ for (Iterator iter = res.iterator(); iter.hasNext(); ) {
+ FunctionEmitter emitter = (FunctionEmitter) iter.next();
+ if (!(emitter instanceof JavaMethodBindingEmitter)) {
+ iter.remove();
+ }
+ }
+
+ if (res.isEmpty()) {
+ return res;
+ }
+
+ PrintWriter writer = (getConfig().allStatic() ? javaWriter() : javaImplWriter());
+
+ List processed = new ArrayList();
+
+ // First, filter out all emitters going to the "other" (public) writer
+ for (Iterator iter = res.iterator(); iter.hasNext(); ) {
+ FunctionEmitter emitter = (FunctionEmitter) iter.next();
+ if (emitter.getDefaultOutput() != writer) {
+ processed.add(emitter);
+ iter.remove();
+ }
+ }
+
+ // Now process all of the remaining emitters sorted by MethodBinding
+ while (!res.isEmpty()) {
+ List emittersForBinding = new ArrayList();
+ JavaMethodBindingEmitter emitter = (JavaMethodBindingEmitter) res.remove(0);
+ emittersForBinding.add(emitter);
+ MethodBinding binding = emitter.getBinding();
+ for (Iterator iter = res.iterator(); iter.hasNext(); ) {
+ JavaMethodBindingEmitter emitter2 = (JavaMethodBindingEmitter) iter.next();
+ if (emitter2.getBinding() == binding) {
+ emittersForBinding.add(emitter2);
+ iter.remove();
+ }
+ }
+ generateNativeSignatureEmitters(binding, emittersForBinding);
+ processed.addAll(emittersForBinding);
+ }
+
+ return processed;
+ }
+
+ protected void generateNativeSignatureEmitters(MethodBinding binding,
+ List allEmitters) {
+ if (allEmitters.isEmpty()) {
+ return;
+ }
+
+ PrintWriter writer = (getConfig().allStatic() ? javaWriter() : javaImplWriter());
+
+ // Give ourselves the chance to interpose on the generation of all code to keep things simple
+ List newEmitters = new ArrayList();
+ for (Iterator iter = allEmitters.iterator(); iter.hasNext(); ) {
+ JavaMethodBindingEmitter javaEmitter = (JavaMethodBindingEmitter) iter.next();
+ NativeSignatureJavaMethodBindingEmitter newEmitter = null;
+ if (javaEmitter instanceof GLJavaMethodBindingEmitter) {
+ newEmitter = new NativeSignatureJavaMethodBindingEmitter((GLJavaMethodBindingEmitter) javaEmitter);
+ } else if (javaEmitter instanceof ProcAddressJavaMethodBindingEmitter) {
+ newEmitter = new NativeSignatureJavaMethodBindingEmitter((ProcAddressJavaMethodBindingEmitter) javaEmitter);
+ } else {
+ newEmitter = new NativeSignatureJavaMethodBindingEmitter(javaEmitter, this);
+ }
+ newEmitters.add(newEmitter);
+ }
+ allEmitters.clear();
+ allEmitters.addAll(newEmitters);
+
+ // Detect whether we need to produce more or modify some of these emitters.
+ // Note that at this point we are assuming that generatePublicEmitters has
+ // been called with signatureOnly both true and false.
+ if (signatureContainsStrings(binding) &&
+ !haveEmitterWithBody(allEmitters)) {
+ // This basically handles glGetString but also any similar methods
+ NativeSignatureJavaMethodBindingEmitter javaEmitter = findEmitterWithWriter(allEmitters, writer);
+
+ // First, we need to clone this emitter to produce the native
+ // entry point
+ NativeSignatureJavaMethodBindingEmitter emitter =
+ new NativeSignatureJavaMethodBindingEmitter(javaEmitter);
+ emitter.removeModifier(JavaMethodBindingEmitter.PUBLIC);
+ emitter.addModifier(JavaMethodBindingEmitter.PRIVATE);
+ emitter.setForImplementingMethodCall(true);
+ // Note: this is chosen so we don't have to change the logic in
+ // emitReturnVariableSetupAndCall which decides which variant
+ // (direct / indirect) to call
+ emitter.setForDirectBufferImplementation(true);
+ allEmitters.add(emitter);
+
+ // Now make the original emitter non-native and cause it to emit a body
+ javaEmitter.removeModifier(JavaMethodBindingEmitter.NATIVE);
+ javaEmitter.setEmitBody(true);
+ }
+ }
+
+ protected boolean signatureContainsStrings(MethodBinding binding) {
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ if (type.isString() || type.isStringArray()) {
+ return true;
+ }
+ }
+ JavaType retType = binding.getJavaReturnType();
+ if (retType.isString() || retType.isStringArray()) {
+ return true;
+ }
+ return false;
+ }
+
+ protected boolean haveEmitterWithBody(List allEmitters) {
+ for (Iterator iter = allEmitters.iterator(); iter.hasNext(); ) {
+ JavaMethodBindingEmitter emitter = (JavaMethodBindingEmitter) iter.next();
+ if (!emitter.signatureOnly()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected NativeSignatureJavaMethodBindingEmitter findEmitterWithWriter(List allEmitters, PrintWriter writer) {
+ for (Iterator iter = allEmitters.iterator(); iter.hasNext(); ) {
+ NativeSignatureJavaMethodBindingEmitter emitter =
+ (NativeSignatureJavaMethodBindingEmitter) iter.next();
+ if (emitter.getDefaultOutput() == writer) {
+ return emitter;
+ }
+ }
+ throw new RuntimeException("Unexpectedly failed to find an emitter with the given writer");
+ }
+}
diff --git a/src/java/com/sun/gluegen/nativesig/NativeSignatureJavaMethodBindingEmitter.java b/src/java/com/sun/gluegen/nativesig/NativeSignatureJavaMethodBindingEmitter.java
new file mode 100755
index 0000000..12a6c0e
--- /dev/null
+++ b/src/java/com/sun/gluegen/nativesig/NativeSignatureJavaMethodBindingEmitter.java
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.nativesig;
+
+import java.io.*;
+import java.util.*;
+import java.text.MessageFormat;
+
+import com.sun.gluegen.*;
+import com.sun.gluegen.cgram.types.*;
+import com.sun.gluegen.cgram.*;
+import com.sun.gluegen.opengl.*;
+import com.sun.gluegen.procaddress.*;
+
+public class NativeSignatureJavaMethodBindingEmitter extends GLJavaMethodBindingEmitter {
+ public NativeSignatureJavaMethodBindingEmitter(GLJavaMethodBindingEmitter methodToWrap) {
+ super(methodToWrap);
+ }
+
+ public NativeSignatureJavaMethodBindingEmitter(ProcAddressJavaMethodBindingEmitter methodToWrap) {
+ super(methodToWrap, false);
+ }
+
+ public NativeSignatureJavaMethodBindingEmitter(JavaMethodBindingEmitter methodToWrap,
+ NativeSignatureEmitter emitter) {
+ super(methodToWrap, false, null, false, false, emitter);
+ }
+
+ protected void emitSignature(PrintWriter writer) {
+ writer.print(getBaseIndentString());
+ emitNativeSignatureAnnotation(writer);
+ super.emitSignature(writer);
+ }
+
+ protected void emitNativeSignatureAnnotation(PrintWriter writer) {
+ if (hasModifier(JavaMethodBindingEmitter.NATIVE)) {
+ // Emit everything as a leaf for now
+ // FIXME: make this configurable
+ writer.print("@NativeSignature(\"l");
+ MethodBinding binding = getBinding();
+ if (callThroughProcAddress) {
+ writer.print("p");
+ }
+ writer.print("(");
+ if (callThroughProcAddress) {
+ writer.print("P");
+ }
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ emitNativeSignatureElement(writer, binding.getJavaArgumentType(i), binding.getCArgumentType(i), i);
+ }
+ writer.print(")");
+ emitNativeSignatureElement(writer, binding.getJavaReturnType(), binding.getCReturnType(), -1);
+ writer.println("\")");
+ }
+ }
+
+ protected void emitNativeSignatureElement(PrintWriter writer, JavaType type, Type cType, int index) {
+ if (type.isVoid()) {
+ if (index > 0) {
+ throw new InternalError("Error parsing arguments -- void should not be seen aside from argument 0");
+ }
+ return;
+ }
+
+ if (type.isNIOBuffer()) {
+ writer.print("A");
+ } else if (type.isPrimitiveArray()) {
+ writer.print("MO");
+ } else if (type.isPrimitive()) {
+ Class clazz = type.getJavaClass();
+ if (clazz == Byte.TYPE) { writer.print("B"); }
+ else if (clazz == Character.TYPE) { writer.print("C"); }
+ else if (clazz == Double.TYPE) { writer.print("D"); }
+ else if (clazz == Float.TYPE) { writer.print("F"); }
+ else if (clazz == Integer.TYPE) { writer.print("I"); }
+ else if (clazz == Long.TYPE) {
+ // See if this is intended to be a pointer at the C level
+ if (cType.isPointer()) {
+ writer.print("A");
+ } else {
+ writer.print("J");
+ }
+ }
+ else if (clazz == Short.TYPE) { writer.print("S"); }
+ else if (clazz == Boolean.TYPE) { writer.print("Z"); }
+ else throw new InternalError("Unhandled primitive type " + clazz);
+ } else if (type.isString()) {
+ writer.print("A");
+ } else {
+ throw new RuntimeException("Type not yet handled: " + type);
+ }
+ }
+
+ protected String getReturnTypeString(boolean skipArray) {
+ if (isForImplementingMethodCall()) {
+ JavaType returnType = getBinding().getJavaReturnType();
+ if (returnType.isString() || returnType.isNIOByteBuffer()) {
+ // Treat these as addresses
+ return "long";
+ }
+ }
+ return super.getReturnTypeString(skipArray);
+ }
+
+ protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) {
+ super.emitPreCallSetup(binding, writer);
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ if (type.isNIOBuffer() && !directNIOOnly) {
+ // Emit declarations for variables holding primitive arrays as type Object
+ // We don't know 100% sure we're going to use these at this point in the code, though
+ writer.println(" Object " + getNIOBufferArrayName(i) + " = (_direct ? null : BufferFactory.getArray(" +
+ getArgumentName(i) + "));");
+ } else if (type.isString()) {
+ writer.println(" long " + binding.getArgumentName(i) + "_c_str = BufferFactoryInternal.newCString(" + binding.getArgumentName(i) + ");");
+ }
+ // FIXME: going to need more of these for Buffer[] and String[], at least
+ }
+ }
+
+ protected String getNIOBufferArrayName(int argNumber) {
+ return "__buffer_array_" + argNumber;
+ }
+
+ protected int emitArguments(PrintWriter writer)
+ {
+ boolean needComma = false;
+ int numEmitted = 0;
+
+ if (callThroughProcAddress) {
+ if (changeNameAndArguments) {
+ writer.print("long procAddress");
+ ++numEmitted;
+ needComma = true;
+ }
+ }
+
+ if (forImplementingMethodCall && binding.hasContainingType()) {
+ if (needComma) {
+ writer.print(", ");
+ }
+
+ // Always emit outgoing "this" argument
+ writer.print("long ");
+ 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(", ");
+ }
+
+ if (forImplementingMethodCall &&
+ (forDirectBufferImplementation && type.isNIOBuffer() ||
+ type.isString())) {
+ // Direct Buffers and Strings go out as longs
+ writer.print("long");
+ // FIXME: will need more tests here to handle other constructs like String and direct Buffer arrays
+ } else {
+ writer.print(erasedTypeString(type, false));
+ }
+ writer.print(" ");
+ writer.print(getArgumentName(i));
+
+ ++numEmitted;
+ needComma = true;
+
+ // Add Buffer and array index offset arguments after each associated argument
+ if (forIndirectBufferAndArrayImplementation) {
+ if (type.isNIOBuffer()) {
+ writer.print(", int " + byteOffsetArgName(i));
+ } else if (type.isNIOBufferArray()) {
+ writer.print(", int[] " +
+ byteOffsetArrayArgName(i));
+ }
+ }
+
+ // Add offset argument after each primitive array
+ if (type.isPrimitiveArray()) {
+ writer.print(", int " + offsetArgName(i));
+ }
+ }
+ return numEmitted;
+ }
+
+ protected void emitReturnVariableSetupAndCall(MethodBinding binding, PrintWriter writer) {
+ writer.print(" ");
+ JavaType returnType = binding.getJavaReturnType();
+ boolean needsResultAssignment = false;
+
+ if (!returnType.isVoid()) {
+ if (returnType.isCompoundTypeWrapper() ||
+ returnType.isNIOByteBuffer()) {
+ writer.println("java.nio.ByteBuffer _res;");
+ needsResultAssignment = true;
+ } else if (returnType.isArrayOfCompoundTypeWrappers()) {
+ writer.println("java.nio.ByteBuffer[] _res;");
+ needsResultAssignment = true;
+ } else if (returnType.isString() || returnType.isNIOByteBuffer()) {
+ writer.print(returnType);
+ writer.println(" _res;");
+ needsResultAssignment = true;
+ } else {
+ // Always assign to "_res" variable so we can clean up
+ // outgoing String arguments, for example
+ emitReturnType(writer);
+ writer.println(" _res;");
+ needsResultAssignment = true;
+ }
+ }
+
+ if (binding.signatureCanUseIndirectNIO() && !directNIOOnly) {
+ // Must generate two calls for this gated on whether the NIO
+ // buffers coming in are all direct or indirect
+ writer.println("if (_direct) {");
+ writer.print (" ");
+ }
+
+ if (needsResultAssignment) {
+ writer.print(" _res = ");
+ if (returnType.isString()) {
+ writer.print("BufferFactoryInternal.newJavaString(");
+ } else if (returnType.isNIOByteBuffer()) {
+ writer.print("BufferFactoryInternal.newDirectByteBuffer(");
+ }
+ } else {
+ writer.print(" ");
+ if (!returnType.isVoid()) {
+ writer.print("return ");
+ }
+ }
+
+ if (binding.signatureUsesJavaPrimitiveArrays() &&
+ !binding.signatureCanUseIndirectNIO()) {
+ // FIXME: what happens with a C function of the form
+ // void foo(int* arg0, void* arg1);
+ // ?
+
+ // Only one call being made in this body, going to indirect
+ // buffer / array entry point
+ emitCall(binding, writer, false);
+ if (returnType.isString() || returnType.isNIOByteBuffer()) {
+ writer.print(")");
+ }
+ writer.print(";");
+ writer.println();
+ } else {
+ emitCall(binding, writer, true);
+ if (returnType.isString() || returnType.isNIOByteBuffer()) {
+ writer.print(")");
+ }
+ writer.print(";");
+ }
+
+ if (binding.signatureCanUseIndirectNIO() && !directNIOOnly) {
+ // Must generate two calls for this gated on whether the NIO
+ // buffers coming in are all direct or indirect
+ writer.println();
+ writer.println(" } else {");
+ writer.print (" ");
+ if (needsResultAssignment) {
+ writer.print(" _res = ");
+ } else {
+ writer.print(" ");
+ if (!returnType.isVoid()) {
+ writer.print("return ");
+ }
+ }
+ emitCall(binding, writer, false);
+ writer.print(";");
+ writer.println();
+ writer.println(" }");
+ } else {
+ writer.println();
+ }
+ emitPrologueOrEpilogue(epilogue, writer);
+ if (needsResultAssignment) {
+ emitCallResultReturn(binding, writer);
+ }
+ }
+
+ protected int emitCallArguments(MethodBinding binding, PrintWriter writer, boolean direct) {
+ // Note that we override this completely because we both need to
+ // move the potential location of the outgoing proc address as
+ // well as change the way we pass out Buffers, arrays, Strings, etc.
+
+ boolean needComma = false;
+ int numArgsEmitted = 0;
+
+ if (callThroughProcAddress) {
+ writer.print("__addr_");
+ needComma = true;
+ ++numArgsEmitted;
+ }
+
+ if (binding.hasContainingType()) {
+ // Emit this pointer
+ assert(binding.getContainingType().isCompoundTypeWrapper());
+ writer.print("BufferFactoryInternal.getDirectBufferAddress(");
+ writer.print("getBuffer()");
+ writer.print(")");
+ 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("BufferFactoryInternal.getDirectBufferAddress(");
+ writer.print("((");
+ }
+
+ if (type.isNIOBuffer()) {
+ if (!direct) {
+ writer.print(getNIOBufferArrayName(i));
+ } else {
+ writer.print("BufferFactoryInternal.getDirectBufferAddress(");
+ writer.print(getArgumentName(i));
+ writer.print(")");
+ }
+ } else {
+ writer.print(getArgumentName(i));
+ }
+
+ if (type.isCompoundTypeWrapper()) {
+ writer.print(" == null) ? null : ");
+ writer.print(getArgumentName(i));
+ writer.print(".getBuffer())");
+ writer.print(")");
+ }
+
+ if (type.isNIOBuffer()) {
+ if (direct) {
+ writer.print("+ BufferFactory.getDirectBufferByteOffset(" + getArgumentName(i) + ")");
+ } else {
+ writer.print(", BufferFactoryInternal.arrayBaseOffset(" +
+ getNIOBufferArrayName(i) +
+ ") + BufferFactory.getIndirectBufferByteOffset(" + getArgumentName(i) + ")");
+ }
+ } else if (type.isNIOBufferArray()) {
+ writer.print(", " + byteOffsetArrayArgName(i));
+ }
+
+ // Add Array offset parameter for primitive arrays
+ if (type.isPrimitiveArray()) {
+ writer.print(", ");
+ writer.print("BufferFactoryInternal.arrayBaseOffset(" + getArgumentName(i) + ") + ");
+ if(type.isFloatArray()) {
+ writer.print("BufferFactory.SIZEOF_FLOAT * ");
+ } else if(type.isDoubleArray()) {
+ writer.print("BufferFactory.SIZEOF_DOUBLE * ");
+ } else if(type.isByteArray()) {
+ writer.print("1 * ");
+ } else if(type.isLongArray()) {
+ writer.print("BufferFactory.SIZEOF_LONG * ");
+ } else if(type.isShortArray()) {
+ writer.print("BufferFactory.SIZEOF_SHORT * ");
+ } else if(type.isIntArray()) {
+ writer.print("BufferFactory.SIZEOF_INT * ");
+ } else {
+ throw new RuntimeException("Unsupported type for calculating array offset argument for " +
+ getArgumentName(i) +
+ "-- error occurred while processing Java glue code for " + getName());
+ }
+ writer.print(offsetArgName(i));
+ }
+
+ if (type.isString()) {
+ writer.print("_c_str");
+ }
+
+ if (type.isCompoundTypeWrapper()) {
+ writer.print(")");
+ }
+
+ needComma = true;
+ ++numArgsEmitted;
+ }
+ return numArgsEmitted;
+ }
+
+ protected void emitCallResultReturn(MethodBinding binding, PrintWriter writer) {
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ JavaType type = binding.getJavaArgumentType(i);
+ if (type.isString()) {
+ writer.println(";");
+ writer.println(" BufferFactoryInternal.freeCString(" + binding.getArgumentName(i) + "_c_str);");
+ }
+ // FIXME: will need more of these cleanups for things like Buffer[] and String[] (see above)
+ }
+
+ super.emitCallResultReturn(binding, writer);
+ }
+
+ public String getName() {
+ String res = super.getName();
+ if (forImplementingMethodCall && bufferObjectVariant) {
+ return res + "BufObj";
+ }
+ return res;
+ }
+
+ protected String getImplMethodName(boolean direct) {
+ String name = null;
+ if (direct) {
+ name = binding.getRenamedMethodName() + "$0";
+ } else {
+ name = binding.getRenamedMethodName() + "$1";
+ }
+ if (bufferObjectVariant) {
+ return name + "BufObj";
+ }
+ return name;
+ }
+}
diff --git a/src/java/com/sun/gluegen/opengl/BuildComposablePipeline.java b/src/java/com/sun/gluegen/opengl/BuildComposablePipeline.java
new file mode 100644
index 0000000..89176f5
--- /dev/null
+++ b/src/java/com/sun/gluegen/opengl/BuildComposablePipeline.java
@@ -0,0 +1,1104 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.opengl;
+
+import com.sun.gluegen.*;
+
+import java.lang.reflect.*;
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+public class BuildComposablePipeline
+{
+ public static final int GEN_DEBUG = 1 << 0 ; // default
+ public static final int GEN_TRACE = 1 << 1 ; // default
+ public static final int GEN_CUSTOM = 1 << 2 ;
+ public static final int GEN_PROLOG_XOR_DOWNSTREAM = 1 << 3 ;
+
+ int mode;
+ private String outputDir;
+ private String outputPackage;
+ private String outputName;
+ private Class classToComposeAround;
+ private Class classPrologOpt;
+ private Class classDownstream;
+ private String basePackage;
+ private String baseName; // does not include package!
+ private String downstreamPackage;
+ private String downstreamName; // does not include package!
+
+ // Only desktop OpenGL has immediate mode glBegin / glEnd
+ private boolean hasImmediateMode;
+
+ // Desktop OpenGL and GLES1 have GL_STACK_OVERFLOW and GL_STACK_UNDERFLOW errors
+ private boolean hasStackOverflow;
+
+ public static Class getClass(String name) {
+ Class clazz=null;
+ try {
+ clazz = Class.forName(name);
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Could not find class \"" + name + "\"", e);
+ }
+ return clazz;
+ }
+
+ public static Method getMethod(Class clazz, Method m) {
+ Method res = null;
+ try {
+ res = clazz.getMethod(m.getName(), m.getParameterTypes());
+ } catch (Exception e) { }
+ return res;
+ }
+
+ public static void main(String[] args)
+ {
+ String classToComposeAroundName = args[0];
+ Class classPrologOpt, classDownstream;
+ Class classToComposeAround = getClass(classToComposeAroundName);
+
+ String outputDir = args[1];
+ String outputPackage, outputName;
+ int mode;
+
+ if(args.length>2) {
+ String outputClazzName = args[2];
+ outputPackage = getPackageName(outputClazzName);
+ outputName = getBaseClassName(outputClazzName);
+ classPrologOpt = getClass(args[3]);
+ classDownstream = getClass(args[4]);
+ mode = GEN_CUSTOM;
+ if(args.length>5) {
+ if(args[5].equals("prolog_xor_downstream")) {
+ mode |= GEN_PROLOG_XOR_DOWNSTREAM;
+ }
+ }
+ } else {
+ outputPackage = getPackageName(classToComposeAroundName);
+ outputName = null; // TBD ..
+ classPrologOpt = null;
+ classDownstream = classToComposeAround;
+ mode = GEN_DEBUG | GEN_TRACE;
+ }
+
+ BuildComposablePipeline composer =
+ new BuildComposablePipeline(mode, outputDir, outputPackage, outputName, classToComposeAround, classPrologOpt, classDownstream);
+
+ try
+ {
+ composer.emit();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(
+ "Error generating composable pipeline source files", e);
+ }
+ }
+
+ protected BuildComposablePipeline(int mode, String outputDir, String outputPackage, String outputName,
+ Class classToComposeAround, Class classPrologOpt, Class classDownstream)
+ {
+ this.mode=mode;
+ this.outputDir=outputDir;
+ this.outputPackage=outputPackage;
+ this.outputName=outputName;
+ this.classToComposeAround=classToComposeAround;
+ this.classPrologOpt=classPrologOpt;
+ this.classDownstream=classDownstream;
+
+ if (! classToComposeAround.isInterface())
+ {
+ throw new IllegalArgumentException(
+ classToComposeAround.getName() + " is not an interface class");
+ }
+
+ try {
+ hasImmediateMode =
+ (classToComposeAround.getMethod("glBegin", new Class[] { Integer.TYPE }) != null);
+ } catch (Exception e) {
+ }
+
+ try {
+ hasStackOverflow =
+ (classToComposeAround.getField("GL_STACK_OVERFLOW") != null);
+ } catch (Exception e) {
+ }
+ }
+
+ /**
+ * Emit the java source code for the classes that comprise the composable
+ * pipeline.
+ */
+ public void emit() throws IOException
+ {
+ List/*<Method>*/ publicMethodsRaw = new ArrayList();
+ publicMethodsRaw.addAll(Arrays.asList(classToComposeAround.getMethods()));
+ Set/*<Method>*/ publicMethodsPlain = new HashSet();
+ for (Iterator iter=publicMethodsRaw.iterator(); iter.hasNext(); ) {
+ Method method = (Method) iter.next();
+ // Don't hook methods which aren't real GL methods,
+ // such as the synthetic "isGL2ES2" "getGL2ES2"
+ String name = method.getName();
+ boolean runHooks = name.startsWith("gl");
+ if (!name.startsWith("getGL") && !name.startsWith("isGL") && !name.equals("toString")) {
+ publicMethodsPlain.add(new PlainMethod(method, runHooks));
+ }
+ }
+
+ if(0!=(mode&GEN_DEBUG)) {
+ (new DebugPipeline(outputDir, outputPackage, classToComposeAround, classDownstream)).emit(publicMethodsPlain.iterator());
+ }
+ if(0!=(mode&GEN_TRACE)) {
+ (new TracePipeline(outputDir, outputPackage, classToComposeAround, classDownstream)).emit(publicMethodsPlain.iterator());
+ }
+ if(0!=(mode&GEN_CUSTOM)) {
+ (new CustomPipeline(mode, outputDir, outputPackage, outputName, classToComposeAround, classPrologOpt, classDownstream)).emit(publicMethodsPlain.iterator());
+ }
+ }
+
+ public static String getPackageName(String clazzName) {
+ int lastDot = clazzName.lastIndexOf('.');
+ if (lastDot == -1)
+ {
+ // no package, class is at root level
+ return null;
+ }
+ return clazzName.substring(0, lastDot);
+ }
+
+ public static String getBaseClassName(String clazzName) {
+ int lastDot = clazzName.lastIndexOf('.');
+ if (lastDot == -1)
+ {
+ // no package, class is at root level
+ return clazzName;
+ }
+ return clazzName.substring(lastDot+1);
+ }
+
+ //-------------------------------------------------------
+
+ protected class PlainMethod
+ {
+ Method m;
+ boolean runHooks;
+
+ public PlainMethod(Method m, boolean runHooks) {
+ this.m=m;
+ this.runHooks = runHooks;
+ }
+
+ public Method getWrappedMethod() { return m; }
+
+ public boolean runHooks() { return runHooks; }
+
+ public boolean equals(Object obj) {
+ if(obj instanceof PlainMethod) {
+ PlainMethod b = (PlainMethod)obj;
+ boolean res =
+ m.getName().equals(b.m.getName()) &&
+ m.getModifiers() == b.m.getModifiers() &&
+ m.getReturnType().equals(b.m.getReturnType()) &&
+ Arrays.equals( m.getParameterTypes() , b.m.getParameterTypes() ) ;
+ return res;
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ int hash = m.getName().hashCode() ^ m.getModifiers() ^ m.getReturnType().hashCode();
+ Class[] args = m.getParameterTypes();
+ for(int i=0; i<args.length; i++) {
+ hash ^= args[i].hashCode();
+ }
+ return hash;
+ }
+
+ public String toString() {
+ Class[] args = m.getParameterTypes();
+ StringBuffer argsString = new StringBuffer();
+ argsString.append("(");
+ for (int i = 0; i < args.length; i++) {
+ if (i > 0)
+ argsString.append(", ");
+ argsString.append(args[i].getName());
+ }
+ argsString.append(")");
+ return m.toString() +
+ "\n\tname: " + m.getName() +
+ "\n\tmods: " + m.getModifiers() +
+ "\n\tretu: " + m.getReturnType() +
+ "\n\targs[" + args.length + "]: "+argsString.toString();
+ }
+ }
+
+ /**
+ * Emits a Java source file that represents one element of the composable
+ * pipeline.
+ */
+ protected abstract class PipelineEmitter
+ {
+ private File file;
+ protected String basePackage;
+ protected String baseName; // does not include package!
+ protected String downstreamPackage;
+ protected String downstreamName; // does not include package!
+ protected String prologPackageOpt=null;
+ protected String prologNameOpt=null; // does not include package!
+
+ protected String outputDir;
+ protected String outputPackage;
+ protected Class baseInterfaceClass;
+ protected Class prologClassOpt=null;
+ protected Class downstreamClass;
+
+ /**
+ * @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 outputPackage, Class baseInterfaceClass, Class prologClassOpt, Class downstreamClass)
+ {
+ this.outputDir=outputDir;
+ this.outputPackage=outputPackage;
+ this.baseInterfaceClass=baseInterfaceClass;
+ this.prologClassOpt=prologClassOpt;
+ this.downstreamClass=downstreamClass;
+
+ basePackage = getPackageName(baseInterfaceClass.getName());
+ baseName = getBaseClassName(baseInterfaceClass.getName());
+ downstreamPackage = getPackageName(downstreamClass.getName());
+ downstreamName = getBaseClassName(downstreamClass.getName());
+ if(null!=prologClassOpt) {
+ prologPackageOpt = getPackageName(prologClassOpt.getName());
+ prologNameOpt = getBaseClassName(prologClassOpt.getName());
+ }
+ }
+
+ public void emit(Iterator/*<Method>*/ methodsToWrap) throws IOException
+ {
+ String outputClassName = getOutputName();
+ this.file = new File(outputDir + File.separatorChar + outputClassName + ".java");
+ String parentDir = file.getParent();
+ if (parentDir != null)
+ {
+ File pDirFile = new File(parentDir);
+ pDirFile.mkdirs();
+ }
+
+ PrintWriter output = new PrintWriter(new BufferedWriter(new FileWriter(file)));
+
+ HashSet clazzList = new HashSet();
+ clazzList.add(baseInterfaceClass);
+ clazzList.addAll(Arrays.asList(baseInterfaceClass.getInterfaces()));
+
+ String[] ifNames = new String[clazzList.size()];
+ {
+ int i=0;
+ for (Iterator iter=clazzList.iterator(); iter.hasNext(); ) {
+ ifNames[i++] = new String(((Class)iter.next()).getName());
+ }
+ }
+
+ clazzList.add(downstreamClass);
+ if(null!=prologClassOpt) {
+ clazzList.add(prologClassOpt);
+ }
+
+ String[] importNames = new String[clazzList.size()+2];
+ {
+ int i=0;
+ importNames[i++] = new String("java.io.*");
+ importNames[i++] = new String("javax.media.opengl.*");
+ for (Iterator iter=clazzList.iterator(); iter.hasNext(); ) {
+ importNames[i++] = new String(((Class)iter.next()).getName());
+ }
+ }
+
+ CodeGenUtils.emitJavaHeaders(output,
+ outputPackage,
+ outputClassName,
+ "com.sun.gluegen.runtime", // FIXME: should make configurable
+ true,
+ importNames,
+ new String[] { "public" },
+ ifNames,
+ null,
+ new CodeGenUtils.EmissionCallback() {
+ public void emit(PrintWriter w) { emitClassDocComment(w); }
+ }
+ );
+
+ preMethodEmissionHook(output);
+
+ constructorHook(output);
+
+ emitGLIsMethods(output);
+ emitGLGetMethods(output);
+
+ while (methodsToWrap.hasNext())
+ {
+ PlainMethod pm = (PlainMethod)methodsToWrap.next();
+ Method m = pm.getWrappedMethod();
+ emitMethodDocComment(output, m);
+ emitSignature(output, m);
+ emitBody(output, m, pm.runHooks());
+ }
+
+ postMethodEmissionHook(output);
+
+ output.println();
+ output.print(" private " + downstreamName + " " + getDownstreamObjectName() + ";");
+
+ // end the class
+ output.println();
+ output.print("} // end class ");
+ output.println(outputClassName);
+
+ output.flush();
+ output.close();
+
+ System.out.println("wrote to file: "+file); // JAU
+ }
+
+ /** Get the name of the object through which API calls should be routed. */
+ protected String getDownstreamObjectName()
+ {
+ return "downstream" + downstreamName;
+ }
+
+ /** Get the name of the object which shall be called as a prolog. */
+ protected String getPrologObjectNameOpt()
+ {
+ if(null!=prologNameOpt) {
+ return "prolog" + prologNameOpt;
+ }
+ return null;
+ }
+
+ protected void emitMethodDocComment(PrintWriter output, Method m)
+ {
+ }
+
+ protected void emitSignature(PrintWriter output, Method m)
+ {
+ output.print(" public ");
+ output.print(' ');
+ output.print(JavaType.createForClass(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, boolean runHooks)
+ {
+ output.println(" {");
+ output.print(" ");
+ Class retType = m.getReturnType();
+
+ boolean callPreDownstreamHook = runHooks && hasPreDownstreamCallHook(m);
+ boolean callPostDownstreamHook = runHooks && hasPostDownstreamCallHook(m);
+ boolean callDownstream = (null!=getMethod(downstreamClass, m)) &&
+ !( 0!=(GEN_PROLOG_XOR_DOWNSTREAM&getMode()) && callPreDownstreamHook ) ;
+ boolean hasResult = (retType != Void.TYPE);
+
+ if(!callDownstream) {
+ if(!emptyDownstreamAllowed()) {
+ throw new RuntimeException("Method "+m+" has no downstream ("+downstreamName+")");
+ }
+ }
+
+ if(!callPreDownstreamHook && !callPostDownstreamHook && !callDownstream) {
+ if(!emptyMethodAllowed()) {
+ throw new RuntimeException("Method "+m+" is empty, no downstream ("+downstreamName+") nor prolog ("+prologNameOpt+").");
+ } else {
+ output.print(" if(DEBUG) { System.out.println(\"WARNING: No prolog, no downstream, empty: \"+");
+ printFunctionCallString(output, m);
+ output.println("); } ");
+ }
+ }
+
+ if (callPreDownstreamHook) {
+ if(hasResult && !callDownstream) {
+ if(callPostDownstreamHook) {
+ output.print(" "+JavaType.createForClass(retType).getName());
+ output.print(" _res = ");
+ } else {
+ output.print(" return ");
+ }
+ }
+ preDownstreamCallHook(output, m);
+ }
+
+ if(callDownstream) {
+ if (hasResult) {
+ if(callPostDownstreamHook) {
+ output.print(" "+JavaType.createForClass(retType).getName());
+ output.print(" _res = ");
+ } else {
+ output.print(" return ");
+ }
+ }
+ output.print(getDownstreamObjectName());
+ output.print('.');
+ output.print(m.getName());
+ output.print('(');
+ output.print(getArgListAsString(m, false, true));
+ output.println(");");
+ }
+
+ if (callPostDownstreamHook) {
+ postDownstreamCallHook(output, m);
+ }
+
+ if (hasResult && callDownstream && callPostDownstreamHook) {
+ output.println(" return _res;");
+ }
+ output.println(" }");
+
+ }
+
+ protected 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 output name for this pipeline class. */
+ protected abstract String getOutputName();
+
+ /**
+ * Called after the class headers have been generated, but before any
+ * method wrappers have been generated.
+ */
+ protected void preMethodEmissionHook(PrintWriter output) {
+ output.println(" public static final boolean DEBUG = com.sun.opengl.impl.Debug.debug(\""+getOutputName()+"\");");
+ }
+
+ /**
+ * Emits the constructor for the pipeline; called after the preMethodEmissionHook.
+ */
+ protected abstract void constructorHook(PrintWriter output);
+
+ /**
+ * Called after the method wrappers have been generated, but before the
+ * closing parenthesis of the class is emitted.
+ */
+ protected void postMethodEmissionHook(PrintWriter output) {
+ output.println( " public String toString() {");
+ output.println( " StringBuffer sb = new StringBuffer();");
+ output.println( " sb.append(\""+getOutputName()+" [ implementing "+baseInterfaceClass.getName()+",\\n\\t\");");
+ if(null!=prologClassOpt) {
+ output.println( " sb.append(\" prolog: \"+"+getPrologObjectNameOpt()+".toString()+\",\\n\\t\");");
+ }
+ output.println( " sb.append(\" downstream: \"+"+getDownstreamObjectName()+".toString()+\"\\n\\t]\");");
+ output.println( " return sb.toString();");
+ output.println( " }");
+ }
+
+ /**
+ * Called before the pipeline routes the call to the downstream object.
+ */
+ protected abstract void preDownstreamCallHook(PrintWriter output, Method m);
+ protected abstract boolean hasPreDownstreamCallHook(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);
+
+ protected abstract boolean hasPostDownstreamCallHook(Method m);
+
+ protected abstract int getMode();
+ protected abstract boolean emptyMethodAllowed();
+ protected abstract boolean emptyDownstreamAllowed();
+
+ /** Emit a Javadoc comment for this pipeline class. */
+ protected abstract void emitClassDocComment(PrintWriter output);
+
+ /**
+ * Emits one of the isGL* methods.
+ */
+ protected void emitGLIsMethod(PrintWriter output, String type) {
+ output.println(" public boolean is" + type + "() {");
+ Class clazz = BuildComposablePipeline.getClass("javax.media.opengl." + type);
+ if (clazz.isAssignableFrom(baseInterfaceClass)) {
+ output.println(" return true;");
+ } else {
+ output.println(" return false;");
+ }
+ output.println(" }");
+ }
+
+ /**
+ * Emits all of the isGL* methods.
+ */
+ protected void emitGLIsMethods(PrintWriter output) {
+ emitGLIsMethod(output, "GL");
+ emitGLIsMethod(output, "GL3");
+ emitGLIsMethod(output, "GL2");
+ emitGLIsMethod(output, "GLES1");
+ emitGLIsMethod(output, "GLES2");
+ emitGLIsMethod(output, "GL2ES1");
+ emitGLIsMethod(output, "GL2ES2");
+ output.println(" public boolean isGLES() {");
+ output.println(" return isGLES2() || isGLES1();");
+ output.println(" }");
+ }
+ /**
+ * Emits one of the getGL* methods.
+ */
+ protected void emitGLGetMethod(PrintWriter output, String type) {
+ output.println(" public javax.media.opengl." + type + " get" + type + "() {");
+ Class clazz = BuildComposablePipeline.getClass("javax.media.opengl." + type);
+ if (clazz.isAssignableFrom(baseInterfaceClass)) {
+ output.println(" return this;");
+ } else {
+ output.println(" throw new GLException(\"Not a " + type + " implementation\");");
+ }
+ output.println(" }");
+ }
+
+ /**
+ * Emits all of the getGL* methods.
+ */
+ protected void emitGLGetMethods(PrintWriter output) {
+ emitGLGetMethod(output, "GL");
+ emitGLGetMethod(output, "GL3");
+ emitGLGetMethod(output, "GL2");
+ emitGLGetMethod(output, "GLES1");
+ emitGLGetMethod(output, "GLES2");
+ emitGLGetMethod(output, "GL2ES1");
+ emitGLGetMethod(output, "GL2ES2");
+ output.println(" public GLProfile getGLProfile() {");
+ output.println(" return "+getDownstreamObjectName()+".getGLProfile();");
+ output.println(" }");
+ }
+ } // end class PipelineEmitter
+
+ //-------------------------------------------------------
+
+ protected class CustomPipeline extends PipelineEmitter
+ {
+ String className;
+ int mode;
+
+ public CustomPipeline(int mode, String outputDir, String outputPackage, String outputName, Class baseInterfaceClass, Class prologClassOpt, Class downstreamClass)
+ {
+ super(outputDir, outputPackage, baseInterfaceClass, prologClassOpt, downstreamClass);
+ className = outputName;
+ this.mode = mode;
+ }
+
+ protected String getOutputName()
+ {
+ return className;
+ }
+
+ protected int getMode() { return mode; }
+
+ protected boolean emptyMethodAllowed() {
+ return true;
+ }
+ protected boolean emptyDownstreamAllowed() {
+ return true;
+ }
+
+ protected void preMethodEmissionHook(PrintWriter output)
+ {
+ super.preMethodEmissionHook(output);
+ }
+
+ protected void constructorHook(PrintWriter output) {
+ output.print( " public " + getOutputName() + "(" );
+ output.print( downstreamName + " " + getDownstreamObjectName() );
+ if(null!=prologNameOpt) {
+ output.println( ", " + prologNameOpt + " " + getPrologObjectNameOpt() + ")");
+ } else {
+ output.println(")");
+ }
+ output.println(" {");
+ output.println(" if (" + getDownstreamObjectName() + " == null) {");
+ output.println(" throw new IllegalArgumentException(\"null " + getDownstreamObjectName() + "\");");
+ output.println(" }");
+ output.print( " this." + getDownstreamObjectName());
+ output.println(" = " + getDownstreamObjectName() + ";");
+ if(null!=prologNameOpt) {
+ output.print( " this." + getPrologObjectNameOpt());
+ output.println(" = " + getPrologObjectNameOpt() + ";");
+ }
+ output.println(" }");
+ output.println();
+ }
+
+ protected void postMethodEmissionHook(PrintWriter output)
+ {
+ super.postMethodEmissionHook(output);
+ if(null!=prologNameOpt) {
+ output.print(" private " + prologNameOpt + " " + getPrologObjectNameOpt() + ";");
+ }
+ }
+
+ protected void emitClassDocComment(PrintWriter output)
+ {
+ output.println("/**");
+ output.println(" * Composable pipeline {@link "+outputPackage+"."+outputName+"}, implementing the interface");
+ output.println(" * {@link "+baseInterfaceClass.getName()+"}");
+ output.println(" * <p>");
+ output.println(" * Each method follows the call graph <ul>");
+ if(null!=prologClassOpt) {
+ output.println(" * <li> call <em>prolog</em> {@link "+prologClassOpt.getName()+"} if available");
+ }
+ output.println(" * <li> call <em>downstream</em> {@link "+downstreamClass.getName()+"} if available");
+ if(null!=prologClassOpt && 0!=(GEN_PROLOG_XOR_DOWNSTREAM&getMode())) {
+ output.println(" * <strong>and</strong> if no call to {@link "+prologClassOpt.getName()+"} is made");
+ }
+ output.println(" * </ul><p>");
+ output.println(" * ");
+ output.println(" * <ul>");
+ output.println(" * <li> <em>Interface</em> {@link "+baseInterfaceClass.getName()+"}");
+ if(null!=prologClassOpt) {
+ output.println(" * <li> <em>Prolog</em> {@link "+prologClassOpt.getName()+"}");
+ }
+ output.println(" * <li> <em>Downstream</em> {@link "+downstreamClass.getName()+"}");
+ output.println(" * </ul><p>");
+ output.println(" * Sample code which installs this pipeline: </P>");
+ output.println(" * ");
+ output.println("<PRE>");
+ if(null!=prologNameOpt) {
+ output.println(" drawable.setGL( new "+className+"( drawable.getGL().getGL2ES2(), new "+prologNameOpt+"( drawable.getGL().getGL2ES2() ) ) );");
+ } else {
+ output.println(" drawable.setGL( new "+className+"( drawable.getGL().getGL2ES2() ) );");
+ }
+ output.println("</PRE>");
+ output.println("*/");
+ }
+
+ protected boolean hasPreDownstreamCallHook(Method m) {
+ return null!=getMethod(prologClassOpt, m);
+ }
+
+ protected void preDownstreamCallHook(PrintWriter output, Method m)
+ {
+ if(null!=prologNameOpt) {
+ output.print(getPrologObjectNameOpt());
+ output.print('.');
+ output.print(m.getName());
+ output.print('(');
+ output.print(getArgListAsString(m, false, true));
+ output.println(");");
+ }
+ }
+
+ protected boolean hasPostDownstreamCallHook(Method m) {
+ return false;
+ }
+
+ protected void postDownstreamCallHook(PrintWriter output, Method m)
+ {
+ }
+
+ } // end class CustomPipeline
+
+ protected class DebugPipeline extends PipelineEmitter
+ {
+ String className;
+ public DebugPipeline(String outputDir, String outputPackage, Class baseInterfaceClass, Class downstreamClass)
+ {
+ super(outputDir, outputPackage, baseInterfaceClass, null, downstreamClass);
+ className = "Debug" + getBaseInterfaceName();
+ }
+
+ protected String getOutputName()
+ {
+ return className;
+ }
+
+ protected int getMode() { return 0; }
+
+ protected boolean emptyMethodAllowed() {
+ return false;
+ }
+ protected boolean emptyDownstreamAllowed() {
+ return false;
+ }
+
+ protected void preMethodEmissionHook(PrintWriter output)
+ {
+ super.preMethodEmissionHook(output);
+ }
+
+ protected void constructorHook(PrintWriter output) {
+ output.print( " public " + getOutputName() + "(" );
+ output.println( downstreamName + " " + getDownstreamObjectName() + ")");
+ output.println(" {");
+ output.println(" if (" + getDownstreamObjectName() + " == null) {");
+ output.println(" throw new IllegalArgumentException(\"null " + getDownstreamObjectName() + "\");");
+ output.println(" }");
+ output.print( " this." + getDownstreamObjectName());
+ output.println(" = " + getDownstreamObjectName() + ";");
+ if(null!=prologNameOpt) {
+ output.print( " this." + getPrologObjectNameOpt());
+ output.println(" = " + getPrologObjectNameOpt() + ";");
+ }
+ output.println(" // Fetch GLContext object for better error checking (if possible)");
+ output.println(" _context = " + getDownstreamObjectName() + ".getContext();");
+ output.println(" }");
+ output.println();
+ }
+
+ protected void postMethodEmissionHook(PrintWriter output)
+ {
+ super.postMethodEmissionHook(output);
+ output.println(" private void checkGLGetError(String caller)");
+ output.println(" {");
+ if (hasImmediateMode) {
+ output.println(" if (insideBeginEndPair) {");
+ output.println(" return;");
+ output.println(" }");
+ 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(Thread.currentThread()+");
+ 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(" int recursionDepth = 10;");
+ 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;");
+ if (hasStackOverflow) {
+ 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: buf.append(\"Unknown glGetError() return value: \");");
+ output.println(" }");
+ output.println(" buf.append(\"( \" + err + \" 0x\"+Integer.toHexString(err).toUpperCase() + \"), \");");
+ output.println(" } while ((--recursionDepth >= 0) && (err = " +
+ getDownstreamObjectName() +
+ ".glGetError()) != GL_NO_ERROR);");
+ output.println(" throw new GLException(buf.toString());");
+ output.println(" }");
+ if (hasImmediateMode) {
+ output.println(" /** True if the pipeline is inside a glBegin/glEnd pair.*/");
+ output.println(" private boolean insideBeginEndPair = false;");
+ output.println();
+ }
+ output.println(" private void checkContext() {");
+ output.println(" GLContext currentContext = GLContext.getCurrent();");
+ output.println(" if (currentContext == null) {");
+ output.println(" throw new GLException(\"No OpenGL context is current on this thread\");");
+ output.println(" }");
+ output.println(" if ((_context != null) && (_context != currentContext)) {");
+ output.println(" throw new GLException(\"This GL object is being incorrectly used with a different GLContext than that which created it\");");
+ output.println(" }");
+ output.println(" }");
+ output.println(" private GLContext _context;");
+ }
+
+ protected void emitClassDocComment(PrintWriter output)
+ {
+ output.println("/** <P> Composable pipeline 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 boolean hasPreDownstreamCallHook(Method m) {
+ return true;
+ }
+
+ protected void preDownstreamCallHook(PrintWriter output, Method m)
+ {
+ output.println(" checkContext();");
+ }
+
+ protected boolean hasPostDownstreamCallHook(Method m) {
+ return true;
+ }
+
+ 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;");
+ }
+
+ output.println(" String txt = new String(\""+ m.getName() + "(\" +");
+ Class[] params = m.getParameterTypes() ;
+ for(int i=0; params!=null && i<params.length; i++) {
+ if(params[i].equals(int.class)) {
+ output.println(" \"<"+params[i].getName()+"> 0x\"+Integer.toHexString(arg"+i+").toUpperCase() +");
+ } else {
+ output.println(" \"<"+params[i].getName()+">\" +");
+ }
+ if(i<params.length-1) {
+ output.println(" \", \" +");
+ }
+ }
+ output.println(" \")\");");
+ // calls to glGetError() are only allowed outside of glBegin/glEnd pairs
+ output.println(" checkGLGetError( txt );");
+ }
+ }
+
+ } // end class DebugPipeline
+
+ //-------------------------------------------------------
+
+ protected class TracePipeline extends PipelineEmitter
+ {
+ String className;
+ public TracePipeline(String outputDir, String outputPackage, Class baseInterfaceClass, Class downstreamClass)
+ {
+ super(outputDir, outputPackage, baseInterfaceClass, null, downstreamClass);
+ className = "Trace" + getBaseInterfaceName();
+ }
+
+ protected String getOutputName()
+ {
+ return className;
+ }
+
+ protected int getMode() { return 0; }
+
+ protected boolean emptyMethodAllowed() {
+ return false;
+ }
+ protected boolean emptyDownstreamAllowed() {
+ return false;
+ }
+
+ protected void preMethodEmissionHook(PrintWriter output)
+ {
+ super.preMethodEmissionHook(output);
+ }
+
+ protected void constructorHook(PrintWriter output) {
+ output.print( " public " + getOutputName() + "(" );
+ output.println( downstreamName + " " + getDownstreamObjectName() + ", PrintStream " + getOutputStreamName() + ")");
+ output.println(" {");
+ output.println(" if (" + getDownstreamObjectName() + " == null) {");
+ output.println(" throw new IllegalArgumentException(\"null " + getDownstreamObjectName() + "\");");
+ 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)
+ {
+ super.postMethodEmissionHook(output);
+ output.println("private PrintStream " + getOutputStreamName() + ";");
+ output.println("private int indent = 0;");
+ output.println("protected String dumpArray(Object obj)");
+ output.println("{");
+ output.println(" if (obj == null) return \"[null]\";");
+ output.println(" StringBuffer sb = new StringBuffer(\"[\");");
+ output.println(" int len = java.lang.reflect.Array.getLength(obj);");
+ output.println(" int count = Math.min(len,16);");
+ output.println(" for ( int i =0; i < count; i++ ) {");
+ output.println(" sb.append(java.lang.reflect.Array.get(obj,i));");
+ output.println(" if (i < count-1)");
+ output.println(" sb.append(',');");
+ output.println(" }");
+ output.println(" if ( len > 16 )");
+ output.println(" sb.append(\"...\").append(len);");
+ output.println(" sb.append(']');");
+ output.println(" return sb.toString();");
+ output.println("}");
+ output.println("protected void print(String str)");
+ output.println("{");
+ output.println(" "+getOutputStreamName()+".print(str);");
+ output.println("}");
+ output.println("protected void println(String str)");
+ output.println("{");
+ output.println(" "+getOutputStreamName()+".println(str);");
+ output.println("}");
+ output.println("protected void printIndent()");
+ output.println("{");
+ output.println(" for( int i =0; i < indent; i++) {"+getOutputStreamName()+".print(' ');}");
+ output.println("}");
+ }
+ protected void emitClassDocComment(PrintWriter output)
+ {
+ output.println("/** <P> Composable pipeline which wraps an underlying {@link GL} implementation,");
+ output.println(" providing tracing information to a user-specified {@link java.io.PrintStream}");
+ output.println(" before and 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 boolean hasPreDownstreamCallHook(Method m) {
+ return true;
+ }
+
+ protected void preDownstreamCallHook(PrintWriter output, Method m)
+ {
+ if ( m.getName().equals("glEnd") || m.getName().equals("glEndList"))
+ {
+ output.println("indent-=2;");
+ output.println(" printIndent();");
+ }
+ else
+ {
+ output.println("printIndent();");
+ }
+
+ output.print(" println(");
+ printFunctionCallString(output, m);
+ output.println(");");
+ }
+
+ protected boolean hasPostDownstreamCallHook(Method m) {
+ return true;
+ }
+
+ protected void postDownstreamCallHook(PrintWriter output, Method m)
+ {
+ Class ret = m.getReturnType();
+ if ( ret != Void.TYPE )
+ {
+ output.println(" println(\" = \"+_res);");
+ }
+ else
+ {
+ output.println(" println(\"\");");
+ }
+ }
+
+ private String getOutputStreamName() {
+ return "stream";
+ }
+
+ } // end class TracePipeline
+
+ public static final void printFunctionCallString(PrintWriter output, Method m) {
+ Class[] params = m.getParameterTypes();
+ output.print(" \"" + m.getName() + "(\"");
+ for ( int i =0; i < params.length; i++ )
+ {
+ if ( params[i].isArray() ) {
+ output.print("+\"<"+params[i].getName()+">\"");
+ } else if(params[i].equals(int.class)) {
+ output.print("+\"<"+params[i].getName()+"> 0x\"+Integer.toHexString(arg"+i+").toUpperCase()");
+ } else {
+ output.print("+\"<"+params[i].getName()+">\"+arg"+i);
+ }
+ if ( i < params.length-1) {
+ output.print("+\",\"");
+ }
+ }
+ output.print("+\")\"");
+ }
+}
diff --git a/src/java/com/sun/gluegen/opengl/BuildStaticGLInfo.java b/src/java/com/sun/gluegen/opengl/BuildStaticGLInfo.java
new file mode 100644
index 0000000..4226f46
--- /dev/null
+++ b/src/java/com/sun/gluegen/opengl/BuildStaticGLInfo.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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
+{
+ // Handles function pointer
+ protected static Pattern funcPattern =
+ Pattern.compile("^(GLAPI|GL_API|GL_APICALL|EGLAPI|extern)?(\\s*)(\\w+)(\\*)?(\\s+)(GLAPIENTRY|GL_APIENTRY|APIENTRY|EGLAPIENTRY|WINAPI)?(\\s*)([ew]?gl\\w+)\\s?(\\(.*)");
+ protected static Pattern associationPattern =
+ Pattern.compile("\\#ifndef ([EW]?GL[X]?_[A-Za-z0-9_]+)");
+ protected static Pattern definePattern =
+ Pattern.compile("\\#define ([EW]?GL[X]?_[A-Za-z0-9_]+)\\s*([A-Za-z0-9_]+)");
+ // Maps function / #define names to the names of the extensions they're declared in
+ protected Map declarationToExtensionMap = new HashMap();
+ // Maps extension names to Set of identifiers (both #defines and
+ // function names) this extension declares
+ protected Map/*<String, Set<String>*/ extensionToDeclarationMap = new HashMap();
+
+ /**
+ * 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) throws IOException
+ {
+ if (args.length > 0 && args[0].equals("-test")) {
+ BuildStaticGLInfo builder = new BuildStaticGLInfo();
+ String[] newArgs = new String[args.length - 1];
+ System.arraycopy(args, 1, newArgs, 0, args.length - 1);
+ builder.parse(newArgs);
+ builder.dump();
+ System.exit(0);
+ }
+
+ 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 {
+ builder.parse(cHeaderFilePaths);
+
+ 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.emitJavaCode(writer, packageName);
+
+ 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);
+ }
+ }
+
+
+ /** Parses the supplied C header files and adds the function
+ associations contained therein to the internal map. */
+ public void parse(String[] cHeaderFilePaths) throws IOException {
+ for (int i = 0; i < cHeaderFilePaths.length; i++) {
+ parse(cHeaderFilePaths[i]);
+ }
+ }
+
+ /** Parses the supplied C header file and adds the function
+ associations contained therein to the internal map. */
+ public void parse(String cHeaderFilePath) throws IOException {
+ BufferedReader reader = new BufferedReader(new FileReader(cHeaderFilePath));
+ String line, activeAssociation = null;
+ Matcher m = null;
+ while ((line = reader.readLine()) != null) {
+ // see if we're inside a #ifndef GL_XXX block and matching a function
+ if (activeAssociation != null) {
+ String identifier = null;
+ if ((m = funcPattern.matcher(line)).matches()) {
+ identifier = m.group(8);
+ } else if ((m = definePattern.matcher(line)).matches()) {
+ identifier = m.group(1);
+ } else if (line.startsWith("#endif")) {
+ activeAssociation = null;
+ }
+ if ((identifier != null) &&
+ (activeAssociation != null) &&
+ // Handles #ifndef GL_... #define GL_...
+ !identifier.equals(activeAssociation)) {
+ addAssociation(identifier, activeAssociation);
+ // System.err.println(" ADDING ASSOCIATION: " + identifier + " " + activeAssociation);
+ }
+ } 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);
+ }
+ }
+ reader.close();
+ }
+
+ public void dump() {
+ for (Iterator i1 = extensionToDeclarationMap.keySet().iterator(); i1.hasNext(); ) {
+ String name = (String) i1.next();
+ Set decls = (Set) extensionToDeclarationMap.get(name);
+ System.out.println(name + ":");
+ List l = new ArrayList();
+ l.addAll(decls);
+ Collections.sort(l);
+ for (Iterator i2 = l.iterator(); i2.hasNext(); ) {
+ System.out.println(" " + (String) i2.next());
+ }
+ }
+ }
+
+ public String getExtension(String identifier) {
+ return (String) declarationToExtensionMap.get(identifier);
+ }
+
+ public Set/*<String>*/ getDeclarations(String extension) {
+ return (Set) extensionToDeclarationMap.get(extension);
+ }
+
+ public Set/*<String>*/ getExtensions() {
+ return extensionToDeclarationMap.keySet();
+ }
+
+ public void emitJavaCode(PrintWriter output, String packageName) {
+ 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;");
+ 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(" String mappedName = null;");
+ output.println(" int funcNamePermNum = com.sun.gluegen.runtime.opengl.GLExtensionNames.getFuncNamePermutationNumber(glFunctionName);");
+ output.println(" for(int i = 0; null==mappedName && i < funcNamePermNum; i++) {");
+ output.println(" String tmp = com.sun.gluegen.runtime.opengl.GLExtensionNames.getFuncNamePermutation(glFunctionName, i);");
+ output.println(" try {");
+ output.println(" mappedName = (String)funcToAssocMap.get(tmp);");
+ output.println(" } catch (Exception e) { }");
+ output.println(" }");
+ output.println(" return mappedName;");
+ output.println(" }");
+ output.println();
+
+ output.println(" static");
+ output.println(" {");
+
+ // Compute max capacity
+ int maxCapacity = 0;
+ for (Iterator iter = declarationToExtensionMap.keySet().iterator(); iter.hasNext(); ) {
+ String name = (String) iter.next();
+ if (!name.startsWith("GL")) {
+ ++maxCapacity;
+ }
+ }
+
+ output.println(" funcToAssocMap = new HashMap(" + maxCapacity + "); // approximate max capacity");
+ output.println(" String group;");
+ ArrayList sets = new ArrayList(extensionToDeclarationMap.keySet());
+ Collections.sort(sets);
+ for (Iterator iter = sets.iterator(); iter.hasNext(); ) {
+ String groupName = (String) iter.next();
+ Set funcs = (Set) extensionToDeclarationMap.get(groupName);
+ List l = new ArrayList();
+ l.addAll(funcs);
+ Collections.sort(l);
+ Iterator funcIter = l.iterator();
+ boolean printedHeader = false;
+ while (funcIter.hasNext()) {
+ String funcName = (String)funcIter.next();
+ if (!funcName.startsWith("GL")) {
+ if (!printedHeader) {
+ output.println();
+ output.println(" //----------------------------------------------------------------");
+ output.println(" // " + groupName);
+ output.println(" //----------------------------------------------------------------");
+ output.println(" group = \"" + groupName + "\";");
+ printedHeader = true;
+ }
+
+ output.println(" funcToAssocMap.put(\"" + funcName + "\", group);");
+ }
+ }
+ }
+ output.println(" }");
+ output.println("} // end class StaticGLInfo");
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ protected void addAssociation(String identifier, String association) {
+ declarationToExtensionMap.put(identifier, association);
+ Set/*<String>*/ identifiers = (Set) extensionToDeclarationMap.get(association);
+ if (identifiers == null) {
+ identifiers = new HashSet/*<String>*/();
+ extensionToDeclarationMap.put(association, identifiers);
+ }
+ identifiers.add(identifier);
+ }
+}
diff --git a/src/java/com/sun/gluegen/opengl/ConvertFromGL4Java.java b/src/java/com/sun/gluegen/opengl/ConvertFromGL4Java.java
new file mode 100644
index 0000000..2f051a7
--- /dev/null
+++ b/src/java/com/sun/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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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 javax.media.opengl.*;";
+ 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/java/com/sun/gluegen/opengl/GLConfiguration.java b/src/java/com/sun/gluegen/opengl/GLConfiguration.java
new file mode 100755
index 0000000..3013848
--- /dev/null
+++ b/src/java/com/sun/gluegen/opengl/GLConfiguration.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.opengl;
+
+import java.io.*;
+import java.util.*;
+
+import com.sun.gluegen.*;
+import com.sun.gluegen.procaddress.*;
+import com.sun.gluegen.runtime.opengl.GLExtensionNames;
+
+public class GLConfiguration extends ProcAddressConfiguration {
+ // The following data members support ignoring an entire extension at a time
+ private List/*<String>*/ glHeaders = new ArrayList();
+ private Set/*<String>*/ ignoredExtensions = new HashSet();
+ private Set/*<String>*/ extensionsRenamedIntoCore = new HashSet();
+ private BuildStaticGLInfo glInfo;
+ // Maps function names to the kind of buffer object it deals with
+ private Map/*<String,GLEmitter.BufferObjectKind>*/ bufferObjectKinds = new HashMap();
+ private GLEmitter emitter;
+ private Set/*String*/ dropUniqVendorExtensions = new HashSet();
+ // This directive is off by default but can help automatically
+ // indicate which extensions have been folded into the core OpenGL
+ // namespace, and if not, then why not
+ private boolean autoUnifyExtensions;
+
+ public GLConfiguration(GLEmitter emitter) {
+ super();
+ this.emitter = emitter;
+ try {
+ setProcAddressNameExpr("PFN $UPPERCASE({0}) PROC");
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error configuring ProcAddressNameExpr", e);
+ }
+ }
+
+ protected void dispatch(String cmd, StringTokenizer tok, File file, String filename, int lineNo) throws IOException {
+ if (cmd.equalsIgnoreCase("IgnoreExtension"))
+ {
+ String sym = readString("IgnoreExtension", tok, filename, lineNo);
+ ignoredExtensions.add(sym);
+ }
+ else if (cmd.equalsIgnoreCase("RenameExtensionIntoCore"))
+ {
+ String sym = readString("RenameExtensionIntoCore", tok, filename, lineNo);
+ extensionsRenamedIntoCore.add(sym);
+ }
+ else if (cmd.equalsIgnoreCase("AutoUnifyExtensions"))
+ {
+ autoUnifyExtensions = readBoolean("AutoUnifyExtensions", tok, filename, lineNo).booleanValue();
+ }
+ else if (cmd.equalsIgnoreCase("GLHeader"))
+ {
+ String sym = readString("GLHeader", tok, filename, lineNo);
+ glHeaders.add(sym);
+ }
+ else if (cmd.equalsIgnoreCase("BufferObjectKind"))
+ {
+ readBufferObjectKind(tok, filename, lineNo);
+ }
+ else if (cmd.equalsIgnoreCase("DropUniqVendorExtensions"))
+ {
+ String sym = readString("DropUniqVendorExtensions", tok, filename, lineNo);
+ dropUniqVendorExtensions.add(sym);
+ }
+ else
+ {
+ super.dispatch(cmd,tok,file,filename,lineNo);
+ }
+ }
+
+ protected void readBufferObjectKind(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String kindString = tok.nextToken();
+ GLEmitter.BufferObjectKind kind = null;
+ String target = tok.nextToken();
+ if (kindString.equalsIgnoreCase("UnpackPixel")) {
+ kind = GLEmitter.BufferObjectKind.UNPACK_PIXEL;
+ } else if (kindString.equalsIgnoreCase("PackPixel")) {
+ kind = GLEmitter.BufferObjectKind.PACK_PIXEL;
+ } else if (kindString.equalsIgnoreCase("Array")) {
+ kind = GLEmitter.BufferObjectKind.ARRAY;
+ } else if (kindString.equalsIgnoreCase("Element")) {
+ kind = GLEmitter.BufferObjectKind.ELEMENT;
+ } else {
+ throw new RuntimeException("Error parsing \"BufferObjectKind\" command at line " + lineNo +
+ " in file \"" + filename + "\": illegal BufferObjectKind \"" +
+ kindString + "\", expected one of UnpackPixel, PackPixel, Array, or Element");
+ }
+
+ bufferObjectKinds.put(target, kind);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"BufferObjectKind\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ /** Overrides javaPrologueForMethod in superclass and
+ automatically generates prologue code for functions associated
+ with buffer objects. */
+ public List/*<String>*/ javaPrologueForMethod(MethodBinding binding,
+ boolean forImplementingMethodCall,
+ boolean eraseBufferAndArrayTypes) {
+ List/*<String>*/ res = super.javaPrologueForMethod(binding,
+ forImplementingMethodCall,
+ eraseBufferAndArrayTypes);
+ GLEmitter.BufferObjectKind kind = getBufferObjectKind(binding.getName());
+ if (kind != null) {
+ // Need to generate appropriate prologue based on both buffer
+ // object kind and whether this variant of the MethodBinding
+ // is the one accepting a "long" as argument
+ //
+ // NOTE we MUST NOT mutate the array returned from the super
+ // call!
+ ArrayList res2 = new ArrayList();
+ if (res != null) {
+ res2.addAll(res);
+ }
+ res = res2;
+
+ String prologue = "check";
+
+ if (kind == GLEmitter.BufferObjectKind.UNPACK_PIXEL) {
+ prologue = prologue + "UnpackPBO";
+ } else if (kind == GLEmitter.BufferObjectKind.PACK_PIXEL) {
+ prologue = prologue + "PackPBO";
+ } else if (kind == GLEmitter.BufferObjectKind.ARRAY) {
+ prologue = prologue + "ArrayVBO";
+ } else if (kind == GLEmitter.BufferObjectKind.ELEMENT) {
+ prologue = prologue + "ElementVBO";
+ } else {
+ throw new RuntimeException("Unknown BufferObjectKind " + kind);
+ }
+
+ if (emitter.isBufferObjectMethodBinding(binding)) {
+ prologue = prologue + "Enabled";
+ } else {
+ prologue = prologue + "Disabled";
+ }
+
+ prologue = prologue + "(true);";
+
+ res.add(0, prologue);
+
+ // Must also filter out bogus rangeCheck directives for VBO/PBO
+ // variants
+ if (emitter.isBufferObjectMethodBinding(binding)) {
+ for (Iterator iter = res.iterator(); iter.hasNext(); ) {
+ String line = (String) iter.next();
+ if (line.indexOf("BufferFactory.rangeCheck") >= 0) {
+ iter.remove();
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public void dumpIgnores() {
+ System.err.println("GL Ignored extensions: ");
+ for (Iterator iter = ignoredExtensions.iterator(); iter.hasNext(); ) {
+ System.err.println("\t"+(String)iter.next());
+ }
+ super.dumpIgnores();
+ }
+
+ protected boolean shouldIgnoreExtension(String symbol, boolean criteria) {
+ if (criteria && glInfo != null) {
+ String extension = glInfo.getExtension(symbol);
+ if (extension != null &&
+ ignoredExtensions.contains(extension)) {
+ return true;
+ }
+ boolean isGLFunc = GLExtensionNames.isGLFunction(symbol);
+ boolean isGLEnum = GLExtensionNames.isGLEnumeration(symbol);
+ if(isGLFunc || isGLEnum) {
+ if(GLExtensionNames.isExtensionVEN(symbol, isGLFunc)) {
+ String extSuffix = GLExtensionNames.getExtensionSuffix(symbol, isGLFunc);
+ if( getDropUniqVendorExtensions(extSuffix) ) {
+ if(DEBUG_IGNORES) {
+ System.err.println("Ignore UniqVendorEXT: "+symbol);
+ }
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean shouldIgnoreInInterface(String symbol) {
+ return shouldIgnoreInInterface(symbol, true);
+ }
+
+ public boolean shouldIgnoreInInterface(String symbol, boolean checkEXT) {
+ return shouldIgnoreExtension(symbol, checkEXT) || super.shouldIgnoreInInterface(symbol);
+ }
+
+ public boolean shouldIgnoreInImpl(String symbol) {
+ return shouldIgnoreInImpl(symbol, true);
+ }
+
+ public boolean shouldIgnoreInImpl(String symbol, boolean checkEXT) {
+ return shouldIgnoreExtension(symbol, checkEXT) || super.shouldIgnoreInImpl(symbol);
+ }
+
+ /** Should we automatically ignore extensions that have already been
+ fully subsumed into the OpenGL core namespace, and if they have
+ not been, indicate which definition is not already in the core? */
+ public boolean getAutoUnifyExtensions() {
+ return autoUnifyExtensions;
+ }
+
+ /** shall the non unified (uniq) vendor extensions be dropped ? */
+ public boolean getDropUniqVendorExtensions(String extName) {
+ return dropUniqVendorExtensions.contains(extName);
+ }
+
+ /** Returns the kind of buffer object this function deals with, or
+ null if none. */
+ public GLEmitter.BufferObjectKind getBufferObjectKind(String name) {
+ return (GLEmitter.BufferObjectKind) bufferObjectKinds.get(name);
+ }
+
+ public boolean isBufferObjectFunction(String name) {
+ return (getBufferObjectKind(name) != null);
+ }
+
+ /** Parses any GL headers specified in the configuration file for
+ the purpose of being able to ignore an extension at a time. */
+ public void parseGLHeaders(GlueEmitterControls controls) throws IOException {
+ if (!glHeaders.isEmpty()) {
+ glInfo = new BuildStaticGLInfo();
+ for (Iterator iter = glHeaders.iterator(); iter.hasNext(); ) {
+ String file = (String) iter.next();
+ String fullPath = controls.findHeaderFile(file);
+ if (fullPath == null) {
+ throw new IOException("Unable to locate header file \"" + file + "\"");
+ }
+ glInfo.parse(fullPath);
+ }
+ }
+ }
+
+ /** Returns the information about the association between #defines,
+ function symbols and the OpenGL extensions they are defined
+ in. */
+ public BuildStaticGLInfo getGLInfo() {
+ return glInfo;
+ }
+
+ /** Returns the OpenGL extensions that should have all of their
+ constant definitions and functions renamed into the core
+ namespace; for example, glGenFramebuffersEXT to
+ glGenFramebuffers and GL_FRAMEBUFFER_EXT to GL_FRAMEBUFFER. */
+ public Set/*<String>*/ getExtensionsRenamedIntoCore() {
+ return extensionsRenamedIntoCore;
+ }
+}
diff --git a/src/java/com/sun/gluegen/opengl/GLEmitter.java b/src/java/com/sun/gluegen/opengl/GLEmitter.java
new file mode 100644
index 0000000..fff9d7e
--- /dev/null
+++ b/src/java/com/sun/gluegen/opengl/GLEmitter.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.opengl;
+
+import java.io.*;
+import java.text.MessageFormat;
+import java.util.*;
+import com.sun.gluegen.*;
+import com.sun.gluegen.cgram.types.*;
+import com.sun.gluegen.procaddress.*;
+import com.sun.gluegen.runtime.*;
+import com.sun.gluegen.runtime.opengl.GLExtensionNames;
+
+/**
+ * A subclass of ProcAddressEmitter with special OpenGL-specific
+ * configuration abilities.
+ */
+public class GLEmitter extends ProcAddressEmitter
+{
+ // Keeps track of which MethodBindings were created for handling
+ // Buffer Object variants. Used as a Set rather than a Map.
+ private Map/*<MethodBinding>*/ bufferObjectMethodBindings = new IdentityHashMap();
+
+ static class BufferObjectKind {
+ private BufferObjectKind() {}
+
+ static final BufferObjectKind UNPACK_PIXEL = new BufferObjectKind();
+ static final BufferObjectKind PACK_PIXEL = new BufferObjectKind();
+ static final BufferObjectKind ARRAY = new BufferObjectKind();
+ static final BufferObjectKind ELEMENT = new BufferObjectKind();
+ }
+
+ public void beginEmission(GlueEmitterControls controls) throws IOException
+ {
+ getGLConfig().parseGLHeaders(controls);
+ renameExtensionsIntoCore();
+ if (getGLConfig().getAutoUnifyExtensions()) {
+ unifyExtensions(controls);
+ }
+ super.beginEmission(controls);
+ }
+
+ protected void renameExtensionsIntoCore() {
+ // This method handles renaming of entire extensions into the
+ // OpenGL core namespace. For example, it is used to move certain
+ // OpenGL ES (OES) extensions into the core namespace which are
+ // already in the core namespace in desktop OpenGL. It builds upon
+ // renaming mechanisms that are built elsewhere.
+
+ GLConfiguration config = getGLConfig();
+ BuildStaticGLInfo glInfo = config.getGLInfo();
+ for (Iterator iter = config.getExtensionsRenamedIntoCore().iterator();
+ iter.hasNext(); ) {
+ String extension = (String) iter.next();
+ Set/*<String>*/ declarations = glInfo.getDeclarations(extension);
+ if (declarations != null) {
+ for (Iterator i2 = declarations.iterator(); i2.hasNext(); ) {
+ String decl = (String) i2.next();
+ boolean isGLFunction = GLExtensionNames.isGLFunction(decl);
+ boolean isGLEnumeration = false;
+ if (!isGLFunction) {
+ isGLEnumeration = GLExtensionNames.isGLEnumeration(decl);
+ }
+ if (isGLFunction || isGLEnumeration) {
+ String renamed = GLExtensionNames.normalize(decl, isGLFunction);
+ if(!renamed.equals(decl)) {
+ config.addJavaSymbolRename(decl, renamed);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ class ExtensionUnifier implements SymbolFilter {
+ private List/*<ConstantDefinition>*/ constants;
+ private List/*<FunctionSymbol>*/ functions;
+
+ public void filterSymbols(List/*<ConstantDefinition>*/ constants,
+ List/*<FunctionSymbol>*/ functions) {
+ this.constants = constants;
+ this.functions = functions;
+ doWork();
+ }
+
+ public List/*<ConstantDefinition>*/ getConstants() {
+ return constants;
+ }
+
+ public List/*<FunctionSymbol>*/ getFunctions() {
+ return functions;
+ }
+
+ private void doWork() {
+ BuildStaticGLInfo glInfo = getGLConfig().getGLInfo();
+ if (glInfo == null) {
+ return;
+ }
+ // Try to retain a "good" ordering for these symbols
+ Map/*<String, ConstantDefinition>*/ constantMap = new LinkedHashMap();
+ Map/*<String, FunctionSymbol>*/ functionMap = new LinkedHashMap();
+ for (Iterator iter = constants.iterator(); iter.hasNext(); ) {
+ ConstantDefinition def = (ConstantDefinition) iter.next();
+ constantMap.put(def.getName(), def);
+ }
+ for (Iterator iter = functions.iterator(); iter.hasNext(); ) {
+ FunctionSymbol sym = (FunctionSymbol) iter.next();
+ functionMap.put(sym.getName(), sym);
+ }
+ // Go through all of the declared extensions.
+ // For each extension, look at its #define and function symbols.
+ // If we find all of the extension's symbols in the core API under
+ // non-ARB (or whatever is the suffix) names, then remove this extension
+ // from the public API. If it turns out that we are running on hardware
+ // that doesn't support the core version of these APIs, the runtime
+ // will take care of looking up the extension version of these entry
+ // points.
+ Set/*<String>*/ extensionNames = glInfo.getExtensions();
+ for (Iterator iter1 = extensionNames.iterator(); iter1.hasNext(); ) {
+ String extension = (String) iter1.next();
+ Set/*<String>*/ declarations = glInfo.getDeclarations(extension);
+ boolean isExtension = true;
+ boolean shouldUnify = true;
+ String cause = null;
+ for (Iterator iter2 = declarations.iterator(); iter2.hasNext(); ) {
+ String decl = (String) iter2.next();
+ boolean isFunc = !decl.startsWith("GL_");
+ if (!GLExtensionNames.isExtension(decl, isFunc)) {
+ isExtension = false;
+ break;
+ }
+ // See whether we're emitting glue code for this
+ // entry point or definition at all
+ if (isFunc) {
+ if (!functionMap.containsKey(decl)) {
+ isExtension = false;
+ break;
+ }
+ } else {
+ if (!constantMap.containsKey(decl)) {
+ isExtension = false;
+ break;
+ }
+ }
+ cause = decl;
+ String unifiedName = GLExtensionNames.normalize(decl, isFunc);
+ // NOTE that we look up the unified name in the
+ // BuildStaticGLInfo's notion of the APIs -- since
+ // we might not be emitting glue code for the
+ // headers that actually contain the core entry
+ // point. Think of the case where we are parsing the
+ // GLES2 gl2.h, which contains certain desktop
+ // OpenGL extensions that have been moved into the
+ // core, but later generating the implementing glue
+ // code (not the interface) for the desktop gl.h /
+ // glext.h.
+ shouldUnify = (glInfo.getExtension(unifiedName) != null);
+ // if (isFunc) {
+ // shouldUnify = functionMap.containsKey(unifiedName);
+ // } else {
+ // shouldUnify = constantMap.containsKey(unifiedName);
+ // }
+ if (!shouldUnify) {
+ break;
+ }
+ }
+ if (isExtension) {
+ if (shouldUnify) {
+ for (Iterator iter2 = declarations.iterator(); iter2.hasNext(); ) {
+ String decl = (String) iter2.next();
+ boolean isFunc = !decl.startsWith("GL_");
+ if (isFunc) {
+ functionMap.remove(decl);
+ } else {
+ constantMap.remove(decl);
+ }
+ }
+ System.err.println("INFO: unified extension " + extension + " into core API");
+ } else {
+ System.err.println("INFO: didn't unify extension " + extension + " into core API because of " + cause);
+ }
+ }
+ }
+ constants = new ArrayList();
+ for (Iterator iter = constantMap.keySet().iterator(); iter.hasNext(); ) {
+ constants.add(constantMap.get(iter.next()));
+ }
+ functions = new ArrayList();
+ for (Iterator iter = functionMap.keySet().iterator(); iter.hasNext(); ) {
+ functions.add(functionMap.get(iter.next()));
+ }
+ }
+ }
+
+ private void unifyExtensions(GlueEmitterControls controls) {
+ controls.runSymbolFilter(new ExtensionUnifier());
+ }
+
+ protected JavaConfiguration createConfig() {
+ return new GLConfiguration(this);
+ }
+
+ /** In order to implement Buffer Object variants of certain
+ functions we generate another MethodBinding which maps the void*
+ argument to a Java long. The generation of emitters then takes
+ place as usual. We do however need to keep track of the modified
+ MethodBinding object so that we can also modify the emitters
+ later to inform them that their argument has changed. We might
+ want to push this functionality down into the MethodBinding
+ (i.e., mutators for argument names). We also would need to
+ inform the CMethodBindingEmitter that it is overloaded in this
+ case (though we default to true currently). */
+ protected List/*<MethodBinding>*/ expandMethodBinding(MethodBinding binding) {
+ List/*<MethodBinding>*/ bindings = super.expandMethodBinding(binding);
+
+ if (!getGLConfig().isBufferObjectFunction(binding.getName())) {
+ return bindings;
+ }
+
+ List/*<MethodBinding>*/ newBindings = new ArrayList();
+ newBindings.addAll(bindings);
+
+ // Need to expand each one of the generated bindings to take a
+ // Java long instead of a Buffer for each void* argument
+ for (Iterator iter = bindings.iterator(); iter.hasNext(); ) {
+ MethodBinding cur = (MethodBinding) iter.next();
+
+ // Some of these routines (glBitmap) take strongly-typed
+ // primitive pointers as arguments which are expanded into
+ // non-void* arguments
+ // This test (rather than !signatureUsesNIO) is used to catch
+ // more unexpected situations
+ if (cur.signatureUsesJavaPrimitiveArrays()) {
+ continue;
+ }
+
+ MethodBinding result = cur;
+ for (int i = 0; i < cur.getNumArguments(); i++) {
+ if (cur.getJavaArgumentType(i).isNIOBuffer()) {
+ result = result.replaceJavaArgumentType(i, JavaType.createForClass(Long.TYPE));
+ }
+ }
+
+ if (result == cur) {
+ throw new RuntimeException("Error: didn't find any void* arguments for BufferObject function " +
+ binding.getName());
+ }
+
+ newBindings.add(result);
+ // Now need to flag this MethodBinding so that we generate the
+ // correct flags in the emitters later
+ bufferObjectMethodBindings.put(result, result);
+ }
+
+ return newBindings;
+ }
+
+ protected boolean needsModifiedEmitters(FunctionSymbol sym) {
+ if ((!needsProcAddressWrapper(sym) && !needsBufferObjectVariant(sym)) ||
+ getConfig().isUnimplemented(sym.getName())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean isBufferObjectMethodBinding(MethodBinding binding) {
+ return bufferObjectMethodBindings.containsKey(binding);
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ protected void generateModifiedEmitters(JavaMethodBindingEmitter baseJavaEmitter, List emitters) {
+ List superEmitters = new ArrayList();
+ super.generateModifiedEmitters(baseJavaEmitter, superEmitters);
+
+ // See whether this is one of the Buffer Object variants
+ boolean bufferObjectVariant = bufferObjectMethodBindings.containsKey(baseJavaEmitter.getBinding());
+
+ for (Iterator iter = superEmitters.iterator(); iter.hasNext(); ) {
+ JavaMethodBindingEmitter emitter = (JavaMethodBindingEmitter) iter.next();
+ if (emitter instanceof ProcAddressJavaMethodBindingEmitter) {
+ emitters.add(new GLJavaMethodBindingEmitter((ProcAddressJavaMethodBindingEmitter) emitter, this, bufferObjectVariant));
+ } else {
+ emitters.add(emitter);
+ }
+ }
+ }
+
+ protected boolean needsBufferObjectVariant(FunctionSymbol sym) {
+ return getGLConfig().isBufferObjectFunction(sym.getName());
+ }
+
+ protected GLConfiguration getGLConfig() {
+ return (GLConfiguration) getConfig();
+ }
+
+ protected void endProcAddressTable() throws Exception
+ {
+ PrintWriter w = tableWriter;
+
+ w.println(" /**");
+ w.println(" * This is a convenience method to get (by name) the native function");
+ w.println(" * pointer for a given function. It lets you avoid having to");
+ w.println(" * manually compute the &quot;" + PROCADDRESS_VAR_PREFIX + " + ");
+ w.println(" * &lt;functionName&gt;&quot; member variable name and look it up via");
+ w.println(" * reflection; it also will throw an exception if you try to get the");
+ w.println(" * address of an unknown function, or one that is statically linked");
+ w.println(" * and therefore does not have a function pointer in this table.");
+ w.println(" *");
+ w.println(" * @throws RuntimeException if the function pointer was not found in");
+ w.println(" * this table, either because the function was unknown or because");
+ w.println(" * it was statically linked.");
+ w.println(" */");
+ w.println(" public long getAddressFor(String functionNameUsr) {");
+ w.println(" String functionNameBase = com.sun.gluegen.runtime.opengl.GLExtensionNames.normalizeVEN(com.sun.gluegen.runtime.opengl.GLExtensionNames.normalizeARB(functionNameUsr, true), true);");
+ w.println(" String addressFieldNameBase = " + getProcAddressConfig().gluegenRuntimePackage() + ".ProcAddressHelper.PROCADDRESS_VAR_PREFIX + functionNameBase;");
+ w.println(" java.lang.reflect.Field addressField = null;");
+ w.println(" int funcNamePermNum = com.sun.gluegen.runtime.opengl.GLExtensionNames.getFuncNamePermutationNumber(functionNameBase);");
+ w.println(" for(int i = 0; null==addressField && i < funcNamePermNum; i++) {");
+ w.println(" String addressFieldName = com.sun.gluegen.runtime.opengl.GLExtensionNames.getFuncNamePermutation(addressFieldNameBase, i);");
+ w.println(" try {");
+ w.println(" addressField = getClass().getField(addressFieldName);");
+ w.println(" } catch (Exception e) { }");
+ w.println(" }");
+ w.println("");
+ w.println(" if(null==addressField) {");
+ w.println(" // The user is calling a bogus function or one which is not");
+ w.println(" // runtime linked");
+ w.println(" throw new RuntimeException(");
+ w.println(" \"WARNING: Address field query failed for \\\"\" + functionNameBase + \"\\\"/\\\"\" + functionNameUsr +");
+ w.println(" \"\\\"; it's either statically linked or address field is not a known \" +");
+ w.println(" \"function\");");
+ w.println(" } ");
+ w.println(" try {");
+ w.println(" return addressField.getLong(this);");
+ w.println(" } catch (Exception e) {");
+ w.println(" throw new RuntimeException(");
+ w.println(" \"WARNING: Address query failed for \\\"\" + functionNameBase + \"\\\"/\\\"\" + functionNameUsr +");
+ w.println(" \"\\\"; it's either statically linked or is not a known \" +");
+ w.println(" \"function\", e);");
+ w.println(" }");
+ w.println(" }");
+
+ w.println("} // end of class " + tableClassName);
+ w.flush();
+ w.close();
+ }
+
+ protected void emitProcAddressTableEntryForSymbol(FunctionSymbol cFunc)
+ {
+ emitProcAddressTableEntryForString(cFunc.getName());
+ }
+
+ protected void emitProcAddressTableEntryForString(String str)
+ {
+ // Deal gracefully with forced proc address generation in the face
+ // of having the function pointer typedef in the header file too
+ if (emittedTableEntries.contains(str))
+ return;
+ emittedTableEntries.add(str);
+ tableWriter.print(" public long ");
+ tableWriter.print(PROCADDRESS_VAR_PREFIX);
+ tableWriter.print(str);
+ tableWriter.println(";");
+ }
+
+}
diff --git a/src/java/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java b/src/java/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java
new file mode 100755
index 0000000..c6a0309
--- /dev/null
+++ b/src/java/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.opengl;
+
+import java.io.*;
+import java.util.*;
+import com.sun.gluegen.*;
+import com.sun.gluegen.cgram.types.*;
+import com.sun.gluegen.procaddress.*;
+
+/** A specialization of the proc address emitter which knows how to
+ change argument names to take into account Vertex Buffer Object /
+ Pixel Buffer Object variants. */
+
+public class GLJavaMethodBindingEmitter extends ProcAddressJavaMethodBindingEmitter {
+ protected boolean bufferObjectVariant;
+ protected GLEmitter glEmitter;
+
+ public GLJavaMethodBindingEmitter(JavaMethodBindingEmitter methodToWrap,
+ boolean callThroughProcAddress,
+ String getProcAddressTableExpr,
+ boolean changeNameAndArguments,
+ boolean bufferObjectVariant,
+ GLEmitter emitter) {
+ super(methodToWrap,
+ callThroughProcAddress,
+ getProcAddressTableExpr,
+ changeNameAndArguments,
+ emitter);
+ this.bufferObjectVariant = bufferObjectVariant;
+ this.glEmitter=emitter;
+ }
+
+ public GLJavaMethodBindingEmitter(ProcAddressJavaMethodBindingEmitter methodToWrap,
+ GLEmitter emitter,
+ boolean bufferObjectVariant) {
+ super(methodToWrap);
+ this.bufferObjectVariant = bufferObjectVariant;
+ this.glEmitter=emitter;
+ }
+
+ public GLJavaMethodBindingEmitter(GLJavaMethodBindingEmitter methodToWrap) {
+ this(methodToWrap, methodToWrap.glEmitter, methodToWrap.bufferObjectVariant);
+ }
+
+ protected String getArgumentName(int i) {
+ String name = super.getArgumentName(i);
+
+ if (!bufferObjectVariant) {
+ return name;
+ }
+
+ // Emitters for VBO/PBO-related routines change the outgoing
+ // argument name for the buffer
+ if (binding.getJavaArgumentType(i).isLong()) {
+ Type cType = binding.getCArgumentType(i);
+ if (cType.isPointer() &&
+ (cType.asPointer().getTargetType().isVoid() ||
+ cType.asPointer().getTargetType().isPrimitive())) {
+ return name + "_buffer_offset";
+ }
+ }
+
+ return name;
+ }
+}
diff --git a/src/java/com/sun/gluegen/pcpp/ConcatenatingReader.java b/src/java/com/sun/gluegen/pcpp/ConcatenatingReader.java
new file mode 100755
index 0000000..11249f7
--- /dev/null
+++ b/src/java/com/sun/gluegen/pcpp/ConcatenatingReader.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.pcpp;
+
+import java.io.*;
+
+/** A Reader implementation which finds lines ending in the backslash
+ character ('\') and concatenates them with the next line. */
+
+public class ConcatenatingReader extends FilterReader {
+ // Any leftover characters go here
+ private char[] curBuf;
+ private int curPos;
+ private BufferedReader in;
+ private static String newline = System.getProperty("line.separator");
+
+ /** This class requires that the input reader be a BufferedReader so
+ it can do line-oriented operations. */
+ public ConcatenatingReader(BufferedReader in) {
+ super(in);
+ this.in = in;
+ }
+
+ public int read() throws IOException {
+ char[] tmp = new char[1];
+ int num = read(tmp, 0, 1);
+ if (num < 0)
+ return -1;
+ return tmp[0];
+ }
+
+ // It's easier not to support mark/reset since we don't need it
+ public boolean markSupported() {
+ return false;
+ }
+
+ public void mark(int readAheadLimit) throws IOException {
+ throw new IOException("mark/reset not supported");
+ }
+
+ public void reset() throws IOException {
+ throw new IOException("mark/reset not supported");
+ }
+
+ public boolean ready() throws IOException {
+ if (curBuf != null || in.ready())
+ return true;
+ return false;
+ }
+
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ if (curBuf == null) {
+ nextLine();
+ }
+
+ if (curBuf == null) {
+ return -1;
+ }
+
+ int numRead = 0;
+
+ while ((len > 0) && (curBuf != null) && (curPos < curBuf.length)) {
+ cbuf[off] = curBuf[curPos];
+ ++curPos;
+ ++off;
+ --len;
+ ++numRead;
+ if (curPos == curBuf.length) {
+ nextLine();
+ }
+ }
+
+ return numRead;
+ }
+
+ public long skip(long n) throws IOException {
+ long numSkipped = 0;
+
+ while (n > 0) {
+ int intN = (int) n;
+ char[] tmp = new char[intN];
+ int numRead = read(tmp, 0, intN);
+ n -= numRead;
+ numSkipped += numRead;
+ if (numRead < intN)
+ break;
+ }
+ return numSkipped;
+ }
+
+ private void nextLine() throws IOException {
+ String cur = in.readLine();
+ if (cur == null) {
+ curBuf = null;
+ return;
+ }
+ // The trailing newline was trimmed by the readLine() method. See
+ // whether we have to put it back or not, depending on whether the
+ // last character of the line is the concatenation character.
+ int numChars = cur.length();
+ boolean needNewline = true;
+ if ((numChars > 0) &&
+ (cur.charAt(cur.length() - 1) == '\\')) {
+ --numChars;
+ needNewline = false;
+ }
+ char[] buf = new char[numChars + (needNewline ? newline.length() : 0)];
+ cur.getChars(0, numChars, buf, 0);
+ if (needNewline) {
+ newline.getChars(0, newline.length(), buf, numChars);
+ }
+ curBuf = buf;
+ curPos = 0;
+ }
+
+ // Test harness
+ /*
+ public static void main(String[] args) throws IOException {
+ if (args.length != 1) {
+ System.out.println("Usage: java ConcatenatingReader [file name]");
+ System.exit(1);
+ }
+
+ ConcatenatingReader reader = new ConcatenatingReader(new BufferedReader(new FileReader(args[0])));
+ OutputStreamWriter writer = new OutputStreamWriter(System.out);
+ char[] buf = new char[8192];
+ boolean done = false;
+ while (!done && reader.ready()) {
+ int numRead = reader.read(buf, 0, buf.length);
+ writer.write(buf, 0, numRead);
+ if (numRead < buf.length)
+ done = true;
+ }
+ writer.flush();
+ }
+ */
+}
diff --git a/src/java/com/sun/gluegen/pcpp/PCPP.java b/src/java/com/sun/gluegen/pcpp/PCPP.java
new file mode 100644
index 0000000..4523032
--- /dev/null
+++ b/src/java/com/sun/gluegen/pcpp/PCPP.java
@@ -0,0 +1,865 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.pcpp;
+
+import java.io.*;
+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 = null;
+ BufferedReader bufReader = null;
+ if (reader instanceof BufferedReader) {
+ bufReader = (BufferedReader) reader;
+ } else {
+ bufReader = new BufferedReader(reader);
+ }
+ tok = new StreamTokenizer(new ConcatenatingReader(bufReader));
+ 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();
+ }
+ }
+
+ public String findFile(String filename) {
+ String sep = 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;
+ }
+
+ //----------------------------------------------------------------------
+ // 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();
+ private Set/*<String>*/ nonConstantDefines = new HashSet();
+
+ /** 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)
+
+ // !!HACK!! - print space only for word tokens. This way multicharacter
+ // operators such as ==, != etc. are property printed.
+ if (tok == StreamTokenizer.TT_WORD) {
+ print(" ");
+ }
+ String s = curTokenAsString();
+ String newS = (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() + ")");
+ }
+ nonConstantDefines.remove(name);
+ }
+ 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 value = "";
+ String oldDef = (String) defineMap.put(name, value);
+ if (oldDef != null && !oldDef.equals(value)) {
+ 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 && !oldDef.equals(value)) {
+ 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 = resolveDefine(value, true);
+ if (newValue != null) {
+ // Set the value to the value of the symbol.
+ //
+ // TO DO: Is this correct? Why not output the symbol unchanged?
+ // I think that it's a good thing to see that some symbols are
+ // defined in terms of others. -chris
+ values.set(0, newValue);
+ } else {
+ // Still perform textual replacement
+ defineMap.put(name, value);
+ nonConstantDefines.add(name);
+ emitDefine = false;
+ }
+ }
+ } else {
+ // Non-constant define; try to do reasonable textual substitution anyway
+ // (FIXME: should identify some of these, like (-1), as constants)
+ emitDefine = false;
+ StringBuffer val = new StringBuffer();
+ for (int i = 0; i < sz; i++) {
+ if (i != 0) {
+ val.append(" ");
+ }
+ val.append(resolveDefine((String) values.get(i), false));
+ }
+ if (defineMap.get(name) != null) {
+ // This is probably something the user should investigate.
+ throw new RuntimeException("Cannot redefine symbol \"" + name +
+ " from \"" + defineMap.get(name) + "\" to non-constant " +
+ " definition \"" + val.toString() + "\"");
+ }
+ defineMap.put(name, val.toString());
+ nonConstantDefines.add(name);
+ }
+
+ 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;
+ }
+
+ private String resolveDefine(String word, boolean returnNullIfNotFound) {
+ String lastWord = (String) defineMap.get(word);
+ if (lastWord == null) {
+ if (returnNullIfNotFound) {
+ return null;
+ }
+ return word;
+ }
+ String nextWord = null;
+ do {
+ nextWord = (String) defineMap.get(lastWord);
+ if (nextWord != null) {
+ lastWord = nextWord;
+ }
+ } while (nextWord != null);
+ return lastWord;
+ }
+
+ ////////////////////////////////////////////////
+ // Handling of #if/#ifdef/ifndef/endif directives //
+ ////////////////////////////////////////////////
+
+ /**
+ * @param isIfdef if true, we're processing #ifdef; if false, we're
+ * processing #ifndef.
+ */
+ private void handleIfdef(boolean isIfdef) throws IOException {
+ // Next token is the name of the #ifdef
+ String symbolName = nextWord();
+ debugPrint(true, (isIfdef ? "#ifdef " : "#ifndef ") + symbolName);
+ boolean symbolIsDefined = defineMap.get(symbolName) != null;
+ //debugPrint(true, "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(enabled() && defineEvaluatedToTrue == isIf);
+ //System.out.println("OUT HANDLE_" + (isIf ? "IF" : "ELIF") +" (evaluated to " + defineEvaluatedToTrue + ")");
+ }
+
+ //static int tmp = -1;
+
+ /**
+ * This method is called recursively to process nested sub-expressions such as:
+ * <pre>
+ * #if !defined(OPENSTEP) && !(defined(NeXT) || !defined(NeXT_PDO))
+ *</pre>
+ *
+ * @param greedy if true, continue evaluating sub-expressions until EOL is
+ * reached. If false, return as soon as the first sub-expression is
+ * processed.
+ * @return the value of the sub-expression or (if greedy==true)
+ * series of sub-expressions.
+ */
+ private boolean handleIfRecursive(boolean greedy) throws IOException {
+ //System.out.println("IN HANDLE_IF_RECURSIVE (" + ++tmp + ", greedy = " + greedy + ")"); System.out.flush();
+
+ // ifValue keeps track of the current value of the potentially nested
+ // "defined()" expressions as we process them.
+ boolean ifValue = true;
+ int openParens = 0;
+ int tok;
+ do {
+ tok = nextToken(true);
+ //System.out.println("-- READ: [" + (tok == StreamTokenizer.TT_EOL ? "<EOL>" :curTokenAsString()) + "]");
+ switch (tok) {
+ case '(':
+ ++openParens;
+ //System.out.println("OPEN PARENS = " + openParens);
+ ifValue = ifValue && handleIfRecursive(true);
+ break;
+ case ')':
+ --openParens;
+ //System.out.println("OPEN PARENS = " + openParens);
+ break;
+ case '!':
+ {
+ //System.out.println("HANDLE_IF_RECURSIVE HANDLING !");
+ boolean rhs = handleIfRecursive(false);
+ ifValue = !rhs;
+ //System.out.println("HANDLE_IF_RECURSIVE HANDLED OUT !, RHS = " + rhs);
+ }
+ break;
+ case '&':
+ {
+ nextRequiredToken('&');
+ //System.out.println("HANDLE_IF_RECURSIVE HANDLING &&, LHS = " + ifValue);
+ boolean rhs = handleIfRecursive(true);
+ //System.out.println("HANDLE_IF_RECURSIVE HANDLED &&, RHS = " + rhs);
+ ifValue = ifValue && rhs;
+ }
+ break;
+ case '|':
+ {
+ nextRequiredToken('|');
+ //System.out.println("HANDLE_IF_RECURSIVE HANDLING ||, LHS = " + ifValue);
+ boolean rhs = handleIfRecursive(true);
+ //System.out.println("HANDLE_IF_RECURSIVE HANDLED ||, RHS = " + rhs);
+ ifValue = ifValue || rhs;
+ }
+ break;
+ case '>':
+ {
+ // NOTE: we don't handle expressions like this properly
+ boolean rhs = handleIfRecursive(true);
+ ifValue = false;
+ }
+ break;
+ case '<':
+ {
+ // NOTE: we don't handle expressions like this properly
+ boolean rhs = handleIfRecursive(true);
+ ifValue = false;
+ }
+ break;
+ case '=':
+ {
+ // NOTE: we don't handle expressions like this properly
+ boolean rhs = handleIfRecursive(true);
+ ifValue = false;
+ }
+ break;
+ case StreamTokenizer.TT_WORD:
+ {
+ String word = curTokenAsString();
+ if (word.equals("defined")) {
+ // Handle things like #if defined(SOMESYMBOL)
+ nextRequiredToken('(');
+ String symbol = nextWord();
+ boolean isDefined = defineMap.get(symbol) != null;
+ //System.out.println("HANDLE_IF_RECURSIVE HANDLING defined(" + symbol + ") = " + isDefined);
+ ifValue = ifValue && isDefined;
+ nextRequiredToken(')');
+ } else {
+ // Handle things like #if SOME_SYMBOL.
+ String symbolValue = (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 and is a constant expression
+ return (!nonConstantDefines.contains(word));
+ } else {
+ // The statement is true if the symbol evaluates to a non-zero value
+ //
+ // NOTE: This doesn't yet handle evaluable expressions like "#if
+ // SOME_SYMBOL > 5" or "#if SOME_SYMBOL == 0", both of which are
+ // valid syntax. It only handles numeric symbols like "#if 1"
+
+ try {
+ // see if it's in decimal form
+ return Double.parseDouble(word) != 0;
+ } catch (NumberFormatException nfe1) {
+ try {
+ // ok, it's not a valid decimal value, try hex/octal value
+ return Long.parseLong(word) != 0;
+ } catch (NumberFormatException nfe2) {
+ try {
+ // ok, it's not a valid hex/octal value, try boolean
+ return Boolean.valueOf(word) == Boolean.TRUE;
+ } catch (NumberFormatException nfe3) {
+ // give up; the symbol isn't a numeric or boolean value
+ return false;
+ }
+ }
+ }
+ }
+ }
+ } // end case TT_WORD
+ break;
+ case StreamTokenizer.TT_EOL:
+ //System.out.println("HANDLE_IF_RECURSIVE HIT <EOL>!");
+ 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);
+ }
+ }
+
+ ////////////
+ // 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("# " + lineNumber() + " \"" + filename() + "\"");
+ println();
+ }
+}
diff --git a/src/java/com/sun/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java b/src/java/com/sun/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
new file mode 100755
index 0000000..b7aadc9
--- /dev/null
+++ b/src/java/com/sun/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.procaddress;
+
+import java.io.*;
+import java.util.*;
+import com.sun.gluegen.*;
+import com.sun.gluegen.cgram.types.*;
+
+public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
+ private boolean callThroughProcAddress;
+ private boolean needsLocalTypedef;
+ private String localTypedefCallingConvention;
+ private static String procAddressJavaTypeName =
+ JavaType.createForClass(Long.TYPE).jniTypeName();
+ private ProcAddressEmitter emitter;
+
+ public ProcAddressCMethodBindingEmitter(CMethodBindingEmitter methodToWrap,
+ final boolean callThroughProcAddress,
+ boolean needsLocalTypedef,
+ String localTypedefCallingConvention,
+ ProcAddressEmitter emitter) {
+ super(
+ new MethodBinding(methodToWrap.getBinding()) {
+ public String getName() {
+ if (callThroughProcAddress) {
+ return ProcAddressEmitter.WRAP_PREFIX + super.getName();
+ } else {
+ return super.getName();
+ }
+ }
+
+ public String getRenamedMethodName() {
+ if (callThroughProcAddress) {
+ return ProcAddressEmitter.WRAP_PREFIX + super.getRenamedMethodName();
+ } else {
+ return super.getRenamedMethodName();
+ }
+ }
+ },
+ methodToWrap.getDefaultOutput(),
+ methodToWrap.getJavaPackageName(),
+ methodToWrap.getJavaClassName(),
+ methodToWrap.getIsOverloadedBinding(),
+ methodToWrap.getIsJavaMethodStatic(),
+ true,
+ methodToWrap.forIndirectBufferAndArrayImplementation(),
+ methodToWrap.getMachineDescription()
+ );
+
+ if (methodToWrap.getReturnValueCapacityExpression() != null) {
+ setReturnValueCapacityExpression(methodToWrap.getReturnValueCapacityExpression());
+ }
+ if (methodToWrap.getReturnValueLengthExpression() != null) {
+ setReturnValueLengthExpression(methodToWrap.getReturnValueLengthExpression());
+ }
+ setTemporaryCVariableDeclarations(methodToWrap.getTemporaryCVariableDeclarations());
+ setTemporaryCVariableAssignments (methodToWrap.getTemporaryCVariableAssignments ());
+
+ setCommentEmitter(defaultCommentEmitter);
+ this.callThroughProcAddress = callThroughProcAddress;
+ this.needsLocalTypedef = needsLocalTypedef;
+ this.localTypedefCallingConvention = localTypedefCallingConvention;
+ this.emitter = emitter;
+ }
+
+ protected int emitArguments(PrintWriter writer) {
+ int numEmitted = super.emitArguments(writer);
+ if (callThroughProcAddress) {
+ if (numEmitted > 0)
+ {
+ writer.print(", ");
+ }
+ writer.print(procAddressJavaTypeName);
+ writer.print(" procAddress");
+ ++numEmitted;
+ }
+
+ return numEmitted;
+ }
+
+ protected void emitBodyVariableDeclarations(PrintWriter writer) {
+ if (callThroughProcAddress) {
+ // create variable for the function pointer with the right type, and set
+ // it to the value of the passed-in proc address
+ FunctionSymbol cSym = getBinding().getCSymbol();
+ String funcPointerTypedefName =
+ emitter.getFunctionPointerTypedefName(cSym);
+
+ if (needsLocalTypedef) {
+ // We (probably) didn't get a typedef for this function
+ // pointer type in the header file; the user requested that we
+ // forcibly generate one. Here we force the emission of one.
+ PointerType funcPtrType = new PointerType(null, cSym.getType(), 0);
+ // Just for safety, emit this name slightly differently than
+ // the mangling would otherwise produce
+ funcPointerTypedefName = "_local_" + funcPointerTypedefName;
+
+ writer.print(" typedef ");
+ writer.print(funcPtrType.toString(funcPointerTypedefName, localTypedefCallingConvention));
+ writer.println(";");
+ }
+
+ writer.print(" ");
+ writer.print(funcPointerTypedefName);
+ writer.print(" ptr_");
+ writer.print(cSym.getName());
+ writer.println(";");
+ }
+
+ super.emitBodyVariableDeclarations(writer);
+ }
+
+ protected void emitBodyVariablePreCallSetup(PrintWriter writer,
+ boolean emittingPrimitiveArrayCritical) {
+ super.emitBodyVariablePreCallSetup(writer, emittingPrimitiveArrayCritical);
+
+ if (callThroughProcAddress) {
+ if (!emittingPrimitiveArrayCritical) {
+ // set the function pointer to the value of the passed-in procAddress
+ FunctionSymbol cSym = getBinding().getCSymbol();
+ String funcPointerTypedefName = emitter.getFunctionPointerTypedefName(cSym);
+ if (needsLocalTypedef) {
+ funcPointerTypedefName = "_local_" + funcPointerTypedefName;
+ }
+
+ String ptrVarName = "ptr_" + cSym.getName();
+
+ writer.print(" ");
+ writer.print(ptrVarName);
+ writer.print(" = (");
+ writer.print(funcPointerTypedefName);
+ writer.println(") (intptr_t) procAddress;");
+
+ writer.println(" assert(" + ptrVarName + " != NULL);");
+ }
+ }
+ }
+
+ protected void emitBodyCallCFunction(PrintWriter writer) {
+ if (!callThroughProcAddress) {
+ super.emitBodyCallCFunction(writer);
+ } else {
+ // 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 = ");
+ }
+ MethodBinding binding = getBinding();
+ if (binding.hasContainingType()) {
+ // FIXME: this can and should be handled and unified with the
+ // associated code in the CMethodBindingEmitter
+ throw new IllegalStateException("Cannot call through function pointer because binding has containing type: " + binding);
+ }
+
+ // call throught the run-time function pointer
+ writer.print("(* ptr_");
+ writer.print(binding.getCSymbol().getName());
+ writer.print(") ");
+ writer.print("(");
+ emitBodyPassCArguments(writer);
+ writer.println(");");
+ }
+ }
+
+ protected String jniMangle(MethodBinding binding) {
+ StringBuffer buf = new StringBuffer(super.jniMangle(binding));
+ if (callThroughProcAddress) {
+ jniMangle(Long.TYPE, buf, false); // to account for the additional _addr_ parameter
+ }
+ return buf.toString();
+ }
+}
diff --git a/src/java/com/sun/gluegen/procaddress/ProcAddressConfiguration.java b/src/java/com/sun/gluegen/procaddress/ProcAddressConfiguration.java
new file mode 100755
index 0000000..9409a1e
--- /dev/null
+++ b/src/java/com/sun/gluegen/procaddress/ProcAddressConfiguration.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.procaddress;
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+
+import com.sun.gluegen.*;
+
+public class ProcAddressConfiguration extends JavaConfiguration
+{
+ private boolean emitProcAddressTable = false;
+ private String tableClassPackage;
+ private String tableClassName = "ProcAddressTable";
+ private Set/*<String>*/ skipProcAddressGen = new HashSet();
+ private List/*<String>*/ forceProcAddressGen = new ArrayList();
+ private Set/*<String>*/ forceProcAddressGenSet = new HashSet();
+ private boolean forceProcAddressGen4All=false;
+ private String getProcAddressTableExpr;
+ private ConvNode procAddressNameConverter;
+ // This is needed only on Windows. Ideally we would modify the
+ // HeaderParser and PCPP to automatically pick up the calling
+ // convention from the headers
+ private Map/*<String,String>*/ localProcAddressCallingConventionMap = new HashMap();
+ private String localProcAddressCallingConvention4All=null;
+
+ 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 if (cmd.equalsIgnoreCase("ProcAddressTablePackage"))
+ {
+ tableClassPackage = readString("ProcAddressTablePackage", tok, filename, lineNo);
+ }
+ else if (cmd.equalsIgnoreCase("ProcAddressTableClassName"))
+ {
+ tableClassName = readString("ProcAddressTableClassName", tok, filename, lineNo);
+ }
+ else if (cmd.equalsIgnoreCase("SkipProcAddressGen"))
+ {
+ String sym = readString("SkipProcAddressGen", tok, filename, lineNo);
+ skipProcAddressGen.add(sym);
+ }
+ else if (cmd.equalsIgnoreCase("ForceProcAddressGen"))
+ {
+ String funcName = readString("ForceProcAddressGen", tok, filename, lineNo);
+ if(funcName.equals("__ALL__")) {
+ forceProcAddressGen4All=true;
+ } else {
+ addForceProcAddressGen( funcName );
+ }
+ }
+ else if (cmd.equalsIgnoreCase("GetProcAddressTableExpr"))
+ {
+ getProcAddressTableExpr = readGetProcAddressTableExpr(tok, filename, lineNo);
+ }
+ else if (cmd.equalsIgnoreCase("ProcAddressNameExpr"))
+ {
+ readProcAddressNameExpr(tok, filename, lineNo);
+ }
+ else if (cmd.equalsIgnoreCase("LocalProcAddressCallingConvention"))
+ {
+ readLocalProcAddressCallingConvention(tok, filename, lineNo);
+ }
+ else
+ {
+ super.dispatch(cmd,tok,file,filename,lineNo);
+ }
+ }
+
+ protected String readGetProcAddressTableExpr(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String restOfLine = tok.nextToken("\n\r\f");
+ return restOfLine.trim();
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"GetProcAddressTableExpr\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void setProcAddressNameExpr(String expr) {
+ // Parse this into something allowing us to map from a function
+ // name to the typedef'ed function pointer name
+ List/*<String>*/ tokens = new ArrayList/*<String>*/();
+ StringTokenizer tok1 = new StringTokenizer(expr);
+ while (tok1.hasMoreTokens()) {
+ String sstr = tok1.nextToken();
+ StringTokenizer tok2 = new StringTokenizer(sstr, "$()", true);
+ while (tok2.hasMoreTokens()) {
+ tokens.add(tok2.nextToken());
+ }
+ }
+
+ // Now that the string is flattened out, convert it to nodes
+ procAddressNameConverter = makeConverter(tokens.iterator());
+ if (procAddressNameConverter == null) {
+ throw new NoSuchElementException("Error creating converter from string");
+ }
+ }
+
+ protected void readProcAddressNameExpr(StringTokenizer tok, String filename, int lineNo) {
+ try {
+ String restOfLine = tok.nextToken("\n\r\f");
+ restOfLine = restOfLine.trim();
+ setProcAddressNameExpr(restOfLine);
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"ProcAddressNameExpr\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ protected void readLocalProcAddressCallingConvention(StringTokenizer tok, String filename, int lineNo) throws IOException {
+ try {
+ String functionName = tok.nextToken();
+ String callingConvention = tok.nextToken();
+ if(functionName.equals("__ALL__")) {
+ localProcAddressCallingConvention4All=callingConvention;
+ } else {
+ localProcAddressCallingConventionMap.put(functionName, callingConvention);
+ }
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"LocalProcAddressCallingConvention\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
+ private static ConvNode makeConverter(Iterator/*<String>*/ iter) {
+ List/*<ConvNode>*/ result = new ArrayList/*<ConvNode>*/();
+ while (iter.hasNext()) {
+ String str = (String) iter.next();
+ if (str.equals("$")) {
+ String command = (String) iter.next();
+ String openParen = (String) iter.next();
+ if (!openParen.equals("(")) {
+ throw new NoSuchElementException("Expected \"(\"");
+ }
+ boolean uppercase = false;
+ if (command.equalsIgnoreCase("UPPERCASE")) {
+ uppercase = true;
+ } else if (!command.equalsIgnoreCase("LOWERCASE")) {
+ throw new NoSuchElementException("Unknown ProcAddressNameExpr command \"" + command + "\"");
+ }
+ result.add(new CaseNode(uppercase, makeConverter(iter)));
+ } else if (str.equals(")")) {
+ // Fall through and return
+ } else if (str.indexOf('{') >= 0) {
+ result.add(new FormatNode(str));
+ } else {
+ result.add(new ConstStringNode(str));
+ }
+ }
+ if (result.size() == 0) {
+ return null;
+ } else if (result.size() == 1) {
+ return (ConvNode) result.get(0);
+ } else {
+ return new ConcatNode(result);
+ }
+ }
+
+ /** Helper class for converting a function name to the typedef'ed
+ function pointer name */
+ static abstract class ConvNode {
+ abstract String convert(String funcName);
+ }
+
+ static class FormatNode extends ConvNode {
+ private MessageFormat msgFmt;
+
+ FormatNode(String fmt) {
+ msgFmt = new MessageFormat(fmt);
+ }
+
+ String convert(String funcName) {
+ StringBuffer buf = new StringBuffer();
+ msgFmt.format(new Object[] { funcName }, buf, null);
+ return buf.toString();
+ }
+ }
+
+ static class ConstStringNode extends ConvNode {
+ private String str;
+
+ ConstStringNode(String str) {
+ this.str = str;
+ }
+
+ String convert(String funcName) {
+ return str;
+ }
+ }
+
+ static class ConcatNode extends ConvNode {
+ private List/*<ConvNode>*/ children;
+
+ ConcatNode(List/*<ConvNode>*/ children) {
+ this.children = children;
+ }
+
+ String convert(String funcName) {
+ StringBuffer res = new StringBuffer();
+ for (Iterator iter = children.iterator(); iter.hasNext(); ) {
+ ConvNode node = (ConvNode) iter.next();
+ res.append(node.convert(funcName));
+ }
+ return res.toString();
+ }
+ }
+
+ static class CaseNode extends ConvNode {
+ private boolean upperCase;
+ private ConvNode child;
+
+ CaseNode(boolean upperCase, ConvNode child) {
+ this.upperCase = upperCase;
+ this.child = child;
+ }
+
+ public String convert(String funcName) {
+ if (upperCase) {
+ return child.convert(funcName).toUpperCase();
+ } else {
+ return child.convert(funcName).toLowerCase();
+ }
+ }
+ }
+
+ public boolean emitProcAddressTable() { return emitProcAddressTable; }
+ public String tableClassPackage() { return tableClassPackage; }
+ public String tableClassName() { return tableClassName; }
+ public boolean skipProcAddressGen (String name) { return skipProcAddressGen.contains(name); }
+ public boolean isForceProcAddressGen4All() { return forceProcAddressGen4All; }
+ public List getForceProcAddressGen() { return forceProcAddressGen; }
+ public String getProcAddressTableExpr() {
+ if (getProcAddressTableExpr == null) {
+ throw new RuntimeException("GetProcAddressTableExpr was not defined in .cfg file");
+ }
+ return getProcAddressTableExpr;
+ }
+ public String convertToFunctionPointerName(String funcName) {
+ if (procAddressNameConverter == null) {
+ throw new RuntimeException("ProcAddressNameExpr was not defined in .cfg file");
+ }
+
+ return procAddressNameConverter.convert(funcName);
+ }
+ public boolean forceProcAddressGen(String funcName) {
+ return forceProcAddressGen4All || forceProcAddressGenSet.contains(funcName);
+ }
+
+ public void addForceProcAddressGen(String funcName) {
+ forceProcAddressGen.add(funcName);
+ forceProcAddressGenSet.add(funcName);
+ }
+
+ public void addLocalProcAddressCallingConvention(String funcName, String callingConvention) {
+ localProcAddressCallingConventionMap.put(funcName, callingConvention);
+ }
+
+ public String getLocalProcAddressCallingConvention(String funcName) {
+ if(isLocalProcAddressCallingConvention4All()) return getLocalProcAddressCallingConvention4All();
+ return (String) localProcAddressCallingConventionMap.get(funcName);
+ }
+ public boolean isLocalProcAddressCallingConvention4All() { return localProcAddressCallingConvention4All!=null; }
+ public String getLocalProcAddressCallingConvention4All() { return localProcAddressCallingConvention4All; }
+}
diff --git a/src/java/com/sun/gluegen/procaddress/ProcAddressEmitter.java b/src/java/com/sun/gluegen/procaddress/ProcAddressEmitter.java
new file mode 100755
index 0000000..8f849ac
--- /dev/null
+++ b/src/java/com/sun/gluegen/procaddress/ProcAddressEmitter.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.procaddress;
+
+import java.io.*;
+import java.text.MessageFormat;
+import java.util.*;
+import com.sun.gluegen.*;
+import com.sun.gluegen.cgram.types.*;
+import com.sun.gluegen.runtime.*;
+
+/**
+ * A subclass of JavaEmitter that modifies the normal emission of C
+ * and Java code to allow dynamic lookups of the C entry points
+ * associated with the Java methods.
+ */
+
+public class ProcAddressEmitter extends JavaEmitter
+{
+ public static final String PROCADDRESS_VAR_PREFIX = ProcAddressHelper.PROCADDRESS_VAR_PREFIX;
+ protected static final String WRAP_PREFIX = "dispatch_";
+ private TypeDictionary typedefDictionary;
+ protected PrintWriter tableWriter;
+ protected Set emittedTableEntries;
+ protected String tableClassPackage;
+ protected String tableClassName;
+
+ public void beginFunctions(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) throws Exception
+ {
+ this.typedefDictionary = typedefDictionary;
+
+ if (getProcAddressConfig().emitProcAddressTable())
+ {
+ beginProcAddressTable();
+ }
+ super.beginFunctions(typedefDictionary, structDictionary, canonMap);
+ }
+
+ public void endFunctions() throws Exception
+ {
+ if (getProcAddressConfig().emitProcAddressTable())
+ {
+ endProcAddressTable();
+ }
+ super.endFunctions();
+ }
+
+ public void beginStructs(TypeDictionary typedefDictionary,
+ TypeDictionary structDictionary,
+ Map canonMap) throws Exception {
+ super.beginStructs(typedefDictionary, structDictionary, canonMap);
+ }
+
+ public String runtimeExceptionType() {
+ return getConfig().runtimeExceptionType();
+ }
+
+ public String unsupportedExceptionType() {
+ return getConfig().unsupportedExceptionType();
+ }
+
+ protected JavaConfiguration createConfig() {
+ return new ProcAddressConfiguration();
+ }
+
+ protected List generateMethodBindingEmitters(FunctionSymbol sym) throws Exception
+ {
+ return generateMethodBindingEmittersImpl(sym);
+ }
+
+ protected boolean needsModifiedEmitters(FunctionSymbol sym) {
+ if (!needsProcAddressWrapper(sym) ||
+ getConfig().isUnimplemented(sym.getName())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private List generateMethodBindingEmittersImpl(FunctionSymbol sym) throws Exception
+ {
+ List 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.isEmpty())
+ {
+ return defaultEmitters;
+ }
+
+ // Don't do anything special if this symbol doesn't require
+ // modifications
+ if (!needsModifiedEmitters(sym))
+ {
+ return defaultEmitters;
+ }
+
+ ArrayList modifiedEmitters = new ArrayList(defaultEmitters.size());
+
+ if (needsProcAddressWrapper(sym)) {
+ if (getProcAddressConfig().emitProcAddressTable()) {
+ // emit an entry in the GL proc address table for this method.
+ emitProcAddressTableEntryForSymbol(sym);
+ }
+ }
+
+ for (Iterator iter = defaultEmitters.iterator(); iter.hasNext(); )
+ {
+ FunctionEmitter emitter = (FunctionEmitter) iter.next();
+ if (emitter instanceof JavaMethodBindingEmitter)
+ {
+ generateModifiedEmitters((JavaMethodBindingEmitter) emitter, modifiedEmitters);
+ }
+ else if (emitter instanceof CMethodBindingEmitter)
+ {
+ generateModifiedEmitters((CMethodBindingEmitter) emitter, modifiedEmitters);
+ }
+ else
+ {
+ throw new RuntimeException("Unexpected emitter type: " +
+ emitter.getClass().getName());
+ }
+ }
+
+ return modifiedEmitters;
+ }
+
+ /**
+ * Returns the name of the typedef for a pointer to the function
+ * represented by the argument as defined by the ProcAddressNameExpr
+ * in the .cfg file. For example, in the OpenGL headers, 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.
+ */
+ protected String getFunctionPointerTypedefName(FunctionSymbol sym) {
+ return getProcAddressConfig().convertToFunctionPointerName(sym.getName());
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ protected void generateModifiedEmitters(JavaMethodBindingEmitter baseJavaEmitter, List emitters) {
+ if (getConfig().manuallyImplement(baseJavaEmitter.getName())) {
+ // User will provide Java-side implementation of this routine;
+ // pass through any emitters which will produce signatures for
+ // it unmodified
+ emitters.add(baseJavaEmitter);
+ return;
+ }
+
+ // See whether we need a proc address entry for this one
+ boolean callThroughProcAddress = needsProcAddressWrapper(baseJavaEmitter.getBinding().getCSymbol());
+
+ ProcAddressJavaMethodBindingEmitter emitter =
+ new ProcAddressJavaMethodBindingEmitter(baseJavaEmitter,
+ callThroughProcAddress,
+ getProcAddressConfig().getProcAddressTableExpr(),
+ baseJavaEmitter.isForImplementingMethodCall(),
+ this);
+ emitters.add(emitter);
+
+ // If this emitter doesn't have a body (i.e., is a direct native
+ // call with no intervening argument processing), we need to force
+ // it to emit a body, and produce another one to act as the entry
+ // point
+ // FIXME: the negative test against the PRIVATE modifier is a
+ // nasty hack to prevent the ProcAddressJavaMethodBindingEmitter
+ // from incorrectly introducing method bodies to the private
+ // native implementing methods; want this to work at least for
+ // public and package-private methods
+ if (baseJavaEmitter.signatureOnly() &&
+ !baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.PRIVATE) &&
+ baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.NATIVE) &&
+ callThroughProcAddress) {
+ emitter.setEmitBody(true);
+ emitter.removeModifier(JavaMethodBindingEmitter.NATIVE);
+ emitter = new ProcAddressJavaMethodBindingEmitter(baseJavaEmitter,
+ callThroughProcAddress,
+ getProcAddressConfig().getProcAddressTableExpr(),
+ true,
+ this);
+ emitter.setForImplementingMethodCall(true);
+ emitters.add(emitter);
+ }
+ }
+
+ protected void generateModifiedEmitters(CMethodBindingEmitter baseCEmitter, List emitters)
+ {
+ // See whether we need a proc address entry for this one
+ boolean callThroughProcAddress = needsProcAddressWrapper(baseCEmitter.getBinding().getCSymbol());
+ boolean forceProcAddress = getProcAddressConfig().forceProcAddressGen(baseCEmitter.getBinding().getCSymbol().getName());
+ String forcedCallingConvention = null;
+ if (forceProcAddress) {
+ forcedCallingConvention = getProcAddressConfig().getLocalProcAddressCallingConvention(baseCEmitter.getBinding().getCSymbol().getName());
+ }
+ // Note that we don't care much about the naming of the C argument
+ // variables so to keep things simple we ignore the buffer object
+ // property for the binding
+
+ // 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
+ ProcAddressCMethodBindingEmitter res = new ProcAddressCMethodBindingEmitter(baseCEmitter,
+ callThroughProcAddress,
+ forceProcAddress,
+ forcedCallingConvention,
+ this);
+ MessageFormat exp = baseCEmitter.getReturnValueCapacityExpression();
+ if (exp != null) {
+ res.setReturnValueCapacityExpression(exp);
+ }
+ emitters.add(res);
+ }
+
+ protected boolean needsProcAddressWrapper(FunctionSymbol sym)
+ {
+ String symName = sym.getName();
+
+ ProcAddressConfiguration config = getProcAddressConfig();
+
+ // We should only generate code to call through a function pointer
+ // if the symbol has an associated function pointer typedef.
+ String funcPointerTypedefName = getFunctionPointerTypedefName(sym);
+ boolean shouldWrap = typedefDictionary.containsKey(funcPointerTypedefName);
+ //System.err.println(funcPointerTypedefName + " defined: " + shouldWrap);
+
+ if (config.skipProcAddressGen(symName)) {
+ shouldWrap = false;
+ }
+
+ if (config.forceProcAddressGen(symName)) {
+ shouldWrap = true;
+ }
+
+ if (shouldWrap)
+ {
+ // Hoist argument names from function pointer if not supplied in prototype
+ Type funcPointerType = typedefDictionary.get(funcPointerTypedefName);
+ if (funcPointerType != null) {
+ FunctionType typedef = funcPointerType.asPointer().getTargetType().asFunction();
+ FunctionType fun = sym.getType();
+ int numarg = typedef.getNumArguments();
+ for (int i =0; i < numarg; i++) {
+ if (fun.getArgumentName(i) == null)
+ fun.setArgumentName(i,typedef.getArgumentName(i));
+ }
+ }
+ }
+
+ return shouldWrap;
+ }
+
+ protected void beginProcAddressTable() throws Exception
+ {
+ tableClassPackage = getProcAddressConfig().tableClassPackage();
+ tableClassName = getProcAddressConfig().tableClassName();
+
+ // Table defaults to going into the impl directory unless otherwise overridden
+ String implPackageName = tableClassPackage;
+ if (implPackageName == null) {
+ implPackageName = getImplPackageName();
+ }
+ String jImplRoot =
+ getJavaOutputDir() + File.separator +
+ CodeGenUtils.packageAsPath(implPackageName);
+
+ tableWriter = openFile(jImplRoot + File.separator + tableClassName + ".java");
+ emittedTableEntries = new HashSet();
+
+ CodeGenUtils.emitAutogeneratedWarning(tableWriter, this);
+
+ tableWriter.println("package " + implPackageName + ";");
+ tableWriter.println();
+ for (Iterator iter = getConfig().imports().iterator(); iter.hasNext(); ) {
+ tableWriter.println("import " + ((String) iter.next()) + ";");
+ }
+ tableWriter.println();
+
+ tableWriter.println("/**");
+ tableWriter.println(" * This table is a cache of pointers to the dynamically-linkable C");
+ tableWriter.println(" * functions this autogenerated Java binding has exposed. Some");
+ tableWriter.println(" * libraries such as OpenGL, OpenAL and others define function pointer");
+ tableWriter.println(" * signatures rather than statically linkable entry points for the");
+ tableWriter.println(" * purposes of being able to query at run-time whether a particular");
+ tableWriter.println(" * extension is available. This table acts as a cache of these");
+ tableWriter.println(" * function pointers. Each function pointer is typically looked up at");
+ tableWriter.println(" * run-time by a platform-dependent mechanism such as dlsym(),");
+ tableWriter.println(" * wgl/glXGetProcAddress(), or alGetProcAddress(). The associated");
+ tableWriter.println(" * autogenerated Java and C code accesses the fields in this table to");
+ tableWriter.println(" * call the various functions. If the field containing the function");
+ tableWriter.println(" * pointer is 0, the function is considered to be unavailable and can");
+ tableWriter.println(" * not be called.");
+ tableWriter.println(" */");
+ tableWriter.println("public class " + tableClassName + " implements com.sun.gluegen.runtime.ProcAddressTable");
+ tableWriter.println("{");
+
+ for (Iterator iter = getProcAddressConfig().getForceProcAddressGen().iterator(); iter.hasNext(); ) {
+ emitProcAddressTableEntryForString((String) iter.next());
+ }
+ }
+
+ protected void endProcAddressTable() throws Exception
+ {
+ PrintWriter w = tableWriter;
+
+ w.println(" /**");
+ w.println(" * This is a convenience method to get (by name) the native function");
+ w.println(" * pointer for a given function. It lets you avoid having to");
+ w.println(" * manually compute the &quot;" + PROCADDRESS_VAR_PREFIX + " + ");
+ w.println(" * &lt;functionName&gt;&quot; member variable name and look it up via");
+ w.println(" * reflection; it also will throw an exception if you try to get the");
+ w.println(" * address of an unknown function, or one that is statically linked");
+ w.println(" * and therefore does not have a function pointer in this table.");
+ w.println(" *");
+ w.println(" * @throws RuntimeException if the function pointer was not found in");
+ w.println(" * this table, either because the function was unknown or because");
+ w.println(" * it was statically linked.");
+ w.println(" */");
+ w.println(" public long getAddressFor(String functionName) {");
+ w.println(" String addressFieldName = " + getProcAddressConfig().gluegenRuntimePackage() + ".ProcAddressHelper.PROCADDRESS_VAR_PREFIX + functionName;");
+ w.println(" try { ");
+ w.println(" java.lang.reflect.Field addressField = 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");
+ w.println(" // runtime linked");
+ w.println(" throw new RuntimeException(");
+ w.println(" \"WARNING: Address query failed for \\\"\" + functionName +");
+ w.println(" \"\\\"; it's either statically linked or is not a known \" +");
+ w.println(" \"function\", e);");
+ w.println(" } ");
+ w.println(" }");
+
+ w.println("} // end of class " + tableClassName);
+ w.flush();
+ w.close();
+ }
+
+ protected void emitProcAddressTableEntryForSymbol(FunctionSymbol cFunc)
+ {
+ emitProcAddressTableEntryForString(cFunc.getName());
+ }
+
+ protected void emitProcAddressTableEntryForString(String str)
+ {
+ // Deal gracefully with forced proc address generation in the face
+ // of having the function pointer typedef in the header file too
+ if (emittedTableEntries.contains(str))
+ return;
+ emittedTableEntries.add(str);
+ tableWriter.print(" public long ");
+ tableWriter.print(PROCADDRESS_VAR_PREFIX);
+ tableWriter.print(str);
+ tableWriter.println(";");
+ }
+
+ protected ProcAddressConfiguration getProcAddressConfig() {
+ return (ProcAddressConfiguration) getConfig();
+ }
+}
diff --git a/src/java/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java b/src/java/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
new file mode 100755
index 0000000..f6ae58e
--- /dev/null
+++ b/src/java/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.procaddress;
+
+import java.io.*;
+import java.util.*;
+import com.sun.gluegen.*;
+import com.sun.gluegen.cgram.types.*;
+
+/** A specialization of JavaMethodBindingEmitter with knowledge of how
+ to call through a function pointer. */
+
+public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitter {
+ private final CommentEmitter commentEmitterForWrappedMethod =
+ new WrappedMethodCommentEmitter();
+
+ protected boolean callThroughProcAddress;
+ protected String getProcAddressTableExpr;
+ protected boolean changeNameAndArguments;
+ protected ProcAddressEmitter emitter;
+
+ public ProcAddressJavaMethodBindingEmitter(JavaMethodBindingEmitter methodToWrap,
+ boolean callThroughProcAddress,
+ String getProcAddressTableExpr,
+ boolean changeNameAndArguments,
+ ProcAddressEmitter emitter) {
+ super(methodToWrap);
+ this.callThroughProcAddress = callThroughProcAddress;
+ this.getProcAddressTableExpr = getProcAddressTableExpr;
+ this.changeNameAndArguments = changeNameAndArguments;
+ this.emitter = emitter;
+ if (callThroughProcAddress) {
+ setCommentEmitter(new WrappedMethodCommentEmitter());
+ }
+
+ if (methodToWrap.getBinding().hasContainingType())
+ {
+ throw new IllegalArgumentException(
+ "Cannot create proc. address wrapper; method has containing type: \"" +
+ methodToWrap.getBinding() + "\"");
+ }
+ }
+
+ public ProcAddressJavaMethodBindingEmitter(ProcAddressJavaMethodBindingEmitter methodToWrap) {
+ this(methodToWrap,
+ methodToWrap.callThroughProcAddress,
+ methodToWrap.getProcAddressTableExpr,
+ methodToWrap.changeNameAndArguments,
+ methodToWrap.emitter);
+ }
+
+ public String getName() {
+ String res = super.getName();
+ if (changeNameAndArguments) {
+ return ProcAddressEmitter.WRAP_PREFIX + res;
+ }
+ return res;
+ }
+
+ protected int emitArguments(PrintWriter writer) {
+ int numEmitted = super.emitArguments(writer);
+ if (callThroughProcAddress) {
+ if (changeNameAndArguments) {
+ if (numEmitted > 0) {
+ writer.print(", ");
+ }
+
+ writer.print("long procAddress");
+ ++numEmitted;
+ }
+ }
+
+ return numEmitted;
+ }
+
+ protected String getImplMethodName(boolean direct) {
+ String name = super.getImplMethodName(direct);
+ if (callThroughProcAddress) {
+ return ProcAddressEmitter.WRAP_PREFIX + name;
+ }
+ return name;
+ }
+
+ protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) {
+ super.emitPreCallSetup(binding, writer);
+
+ if (callThroughProcAddress) {
+ String procAddressVariable =
+ ProcAddressEmitter.PROCADDRESS_VAR_PREFIX + binding.getName();
+ writer.println(" final long __addr_ = " + getProcAddressTableExpr + "." + procAddressVariable + ";");
+ writer.println(" if (__addr_ == 0) {");
+ writer.println(" throw new " + emitter.unsupportedExceptionType() + "(\"Method \\\"" + binding.getName() + "\\\" not available\");");
+ writer.println(" }");
+ }
+ }
+
+ protected int emitCallArguments(MethodBinding binding, PrintWriter writer, boolean indirect) {
+ int numEmitted = super.emitCallArguments(binding, writer, indirect);
+ if (callThroughProcAddress) {
+ if (numEmitted > 0) {
+ writer.print(", ");
+ }
+ writer.print("__addr_");
+ ++numEmitted;
+ }
+
+ return numEmitted;
+ }
+
+ /** This class emits the comment for the wrapper method */
+ public class WrappedMethodCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter {
+ protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) {
+ writer.print("Entry point (through function pointer) to C language function: <br> ");
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/BufferFactory.java.javame_cdc_fp b/src/java/com/sun/gluegen/runtime/BufferFactory.java.javame_cdc_fp
new file mode 100755
index 0000000..622cc37
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/BufferFactory.java.javame_cdc_fp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+import java.nio.*;
+
+public class BufferFactory {
+ public static final int SIZEOF_BYTE = 1;
+ public static final int SIZEOF_SHORT = 2;
+ public static final int SIZEOF_INT = 4;
+ public static final int SIZEOF_FLOAT = 4;
+
+ public static ByteBuffer newDirectByteBuffer(int size) {
+ ByteBuffer buf = ByteBuffer.allocateDirect(size);
+ return buf;
+ }
+
+ /** Helper routine to set a ByteBuffer to the native byte order, if
+ that operation is supported by the underlying NIO
+ implementation. */
+ public static ByteBuffer nativeOrder(ByteBuffer buf) {
+ return buf;
+ }
+
+ /** Helper routine to tell whether a buffer is direct or not. Null
+ pointers are considered direct. isDirect() should really be
+ public in Buffer and not replicated in all subclasses. */
+ public static boolean isDirect(Buffer buf) {
+ if (buf == null) {
+ return true;
+ }
+ if (buf instanceof ByteBuffer) {
+ return ((ByteBuffer) buf).isDirect();
+ } else if (buf instanceof FloatBuffer) {
+ return ((FloatBuffer) buf).isDirect();
+ } else if (buf instanceof ShortBuffer) {
+ return ((ShortBuffer) buf).isDirect();
+ } else if (buf instanceof IntBuffer) {
+ return ((IntBuffer) buf).isDirect();
+ }
+ throw new RuntimeException("Unexpected buffer type " + buf.getClass().getName());
+ }
+
+
+ /** Helper routine to get the Buffer byte offset by taking into
+ account the Buffer position and the underlying type. This is
+ the total offset for Direct Buffers. */
+
+ public static int getDirectBufferByteOffset(Buffer buf) {
+ if(buf == null) {
+ return 0;
+ }
+ if(buf instanceof ByteBuffer) {
+ return (buf.position());
+ } else if (buf instanceof FloatBuffer) {
+ return (buf.position() * SIZEOF_FLOAT);
+ } else if (buf instanceof IntBuffer) {
+ return (buf.position() * SIZEOF_INT);
+ } else if (buf instanceof ShortBuffer) {
+ return (buf.position() * SIZEOF_SHORT);
+ }
+
+ throw new RuntimeException("Disallowed array backing store type in buffer "
+ + buf.getClass().getName());
+ }
+
+
+ /** Helper routine to return the array backing store reference from
+ a Buffer object. */
+
+ public static Object getArray(Buffer buf) {
+ if (buf == null) {
+ return null;
+ }
+ if(buf instanceof ByteBuffer) {
+ return ((ByteBuffer) buf).array();
+ } else if (buf instanceof FloatBuffer) {
+ return ((FloatBuffer) buf).array();
+ } else if (buf instanceof IntBuffer) {
+ return ((IntBuffer) buf).array();
+ } else if (buf instanceof ShortBuffer) {
+ return ((ShortBuffer) buf).array();
+ }
+
+ throw new RuntimeException("Disallowed array backing store type in buffer "
+ + buf.getClass().getName());
+ }
+
+
+ /** Helper routine to get the full byte offset from the beginning of
+ the array that is the storage for the indirect Buffer
+ object. The array offset also includes the position offset
+ within the buffer, in addition to any array offset. */
+
+ public static int getIndirectBufferByteOffset(Buffer buf) {
+ if(buf == null) {
+ return 0;
+ }
+ int pos = buf.position();
+ if(buf instanceof ByteBuffer) {
+ return (((ByteBuffer)buf).arrayOffset() + pos);
+ } else if(buf instanceof FloatBuffer) {
+ return (SIZEOF_FLOAT*(((FloatBuffer)buf).arrayOffset() + pos));
+ } else if(buf instanceof IntBuffer) {
+ return (SIZEOF_INT*(((IntBuffer)buf).arrayOffset() + pos));
+ } else if(buf instanceof ShortBuffer) {
+ return (SIZEOF_SHORT*(((ShortBuffer)buf).arrayOffset() + pos));
+ }
+
+ throw new RuntimeException("Unknown buffer type " + buf.getClass().getName());
+ }
+
+ public static void rangeCheck(byte[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(char[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(short[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(int[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(float[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(Buffer buffer, int minElementsRemaining) {
+ if (buffer == null) {
+ return;
+ }
+
+ if (buffer.remaining() < minElementsRemaining) {
+ throw new IndexOutOfBoundsException("Required " + minElementsRemaining + " remaining elements in buffer, only had " + buffer.remaining());
+ }
+ }
+
+ public static void rangeCheckBytes(Buffer buffer, int minBytesRemaining) {
+ if (buffer == null) {
+ return;
+ }
+
+ int elementsRemaining = buffer.remaining();
+ int bytesRemaining = 0;
+ if (buffer instanceof ByteBuffer) {
+ bytesRemaining = elementsRemaining;
+ } else if (buffer instanceof FloatBuffer) {
+ bytesRemaining = elementsRemaining * SIZEOF_FLOAT;
+ } else if (buffer instanceof IntBuffer) {
+ bytesRemaining = elementsRemaining * SIZEOF_INT;
+ } else if (buffer instanceof ShortBuffer) {
+ bytesRemaining = elementsRemaining * SIZEOF_SHORT;
+ }
+ if (bytesRemaining < minBytesRemaining) {
+ throw new IndexOutOfBoundsException("Required " + minBytesRemaining + " remaining bytes in buffer, only had " + bytesRemaining);
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/BufferFactory.java.javase b/src/java/com/sun/gluegen/runtime/BufferFactory.java.javase
new file mode 100755
index 0000000..3986bf6
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/BufferFactory.java.javase
@@ -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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+import java.nio.*;
+
+public class BufferFactory {
+ public static final int SIZEOF_BYTE = 1;
+ public static final int SIZEOF_SHORT = 2;
+ public static final int SIZEOF_CHAR = 2;
+ public static final int SIZEOF_INT = 4;
+ public static final int SIZEOF_FLOAT = 4;
+ public static final int SIZEOF_LONG = 8;
+ public static final int SIZEOF_DOUBLE = 8;
+
+ public static ByteBuffer newDirectByteBuffer(int size) {
+ ByteBuffer buf = ByteBuffer.allocateDirect(size);
+ buf.order(ByteOrder.nativeOrder());
+ return buf;
+ }
+
+ /** Helper routine to set a ByteBuffer to the native byte order, if
+ that operation is supported by the underlying NIO
+ implementation. */
+ public static ByteBuffer nativeOrder(ByteBuffer buf) {
+ return buf.order(ByteOrder.nativeOrder());
+ }
+
+ /** Helper routine to tell whether a buffer is direct or not. Null
+ pointers are considered direct. isDirect() should really be
+ public in Buffer and not replicated in all subclasses. */
+ public static boolean isDirect(Buffer buf) {
+ if (buf == null) {
+ return true;
+ }
+ if (buf instanceof ByteBuffer) {
+ return ((ByteBuffer) buf).isDirect();
+ } else if (buf instanceof FloatBuffer) {
+ return ((FloatBuffer) buf).isDirect();
+ } else if (buf instanceof DoubleBuffer) {
+ return ((DoubleBuffer) buf).isDirect();
+ } else if (buf instanceof CharBuffer) {
+ return ((CharBuffer) buf).isDirect();
+ } else if (buf instanceof ShortBuffer) {
+ return ((ShortBuffer) buf).isDirect();
+ } else if (buf instanceof IntBuffer) {
+ return ((IntBuffer) buf).isDirect();
+ } else if (buf instanceof LongBuffer) {
+ return ((LongBuffer) buf).isDirect();
+ }
+ throw new RuntimeException("Unexpected buffer type " + buf.getClass().getName());
+ }
+
+
+ /** Helper routine to get the Buffer byte offset by taking into
+ account the Buffer position and the underlying type. This is
+ the total offset for Direct Buffers. */
+
+ public static int getDirectBufferByteOffset(Buffer buf) {
+ if(buf == null) {
+ return 0;
+ }
+ if(buf instanceof ByteBuffer) {
+ return (buf.position());
+ } else if (buf instanceof FloatBuffer) {
+ return (buf.position() * SIZEOF_FLOAT);
+ } else if (buf instanceof IntBuffer) {
+ return (buf.position() * SIZEOF_INT);
+ } else if (buf instanceof ShortBuffer) {
+ return (buf.position() * SIZEOF_SHORT);
+ } else if (buf instanceof DoubleBuffer) {
+ return (buf.position() * SIZEOF_DOUBLE);
+ } else if (buf instanceof LongBuffer) {
+ return (buf.position() * SIZEOF_LONG);
+ } else if (buf instanceof CharBuffer) {
+ return (buf.position() * SIZEOF_CHAR);
+ }
+
+ throw new RuntimeException("Disallowed array backing store type in buffer "
+ + buf.getClass().getName());
+ }
+
+
+ /** Helper routine to return the array backing store reference from
+ a Buffer object. */
+
+ public static Object getArray(Buffer buf) {
+ if (buf == null) {
+ return null;
+ }
+ if(buf instanceof ByteBuffer) {
+ return ((ByteBuffer) buf).array();
+ } else if (buf instanceof FloatBuffer) {
+ return ((FloatBuffer) buf).array();
+ } else if (buf instanceof IntBuffer) {
+ return ((IntBuffer) buf).array();
+ } else if (buf instanceof ShortBuffer) {
+ return ((ShortBuffer) buf).array();
+ } else if (buf instanceof DoubleBuffer) {
+ return ((DoubleBuffer) buf).array();
+ } else if (buf instanceof LongBuffer) {
+ return ((LongBuffer) buf).array();
+ } else if (buf instanceof CharBuffer) {
+ return ((CharBuffer) buf).array();
+ }
+
+ throw new RuntimeException("Disallowed array backing store type in buffer "
+ + buf.getClass().getName());
+ }
+
+
+ /** Helper routine to get the full byte offset from the beginning of
+ the array that is the storage for the indirect Buffer
+ object. The array offset also includes the position offset
+ within the buffer, in addition to any array offset. */
+
+ public static int getIndirectBufferByteOffset(Buffer buf) {
+ if(buf == null) {
+ return 0;
+ }
+ int pos = buf.position();
+ if(buf instanceof ByteBuffer) {
+ return (((ByteBuffer)buf).arrayOffset() + pos);
+ } else if(buf instanceof FloatBuffer) {
+ return (SIZEOF_FLOAT*(((FloatBuffer)buf).arrayOffset() + pos));
+ } else if(buf instanceof IntBuffer) {
+ return (SIZEOF_INT*(((IntBuffer)buf).arrayOffset() + pos));
+ } else if(buf instanceof ShortBuffer) {
+ return (SIZEOF_SHORT*(((ShortBuffer)buf).arrayOffset() + pos));
+ } else if(buf instanceof DoubleBuffer) {
+ return (SIZEOF_DOUBLE*(((DoubleBuffer)buf).arrayOffset() + pos));
+ } else if(buf instanceof LongBuffer) {
+ return (SIZEOF_LONG*(((LongBuffer)buf).arrayOffset() + pos));
+ } else if(buf instanceof CharBuffer) {
+ return (SIZEOF_CHAR*(((CharBuffer)buf).arrayOffset() + pos));
+ }
+
+ throw new RuntimeException("Unknown buffer type " + buf.getClass().getName());
+ }
+
+ public static void rangeCheck(byte[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(char[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(short[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(int[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(long[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(float[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(double[] array, int offset, int minElementsRemaining) {
+ if (array == null) {
+ return;
+ }
+
+ if (array.length < offset + minElementsRemaining) {
+ throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset));
+ }
+ }
+
+ public static void rangeCheck(Buffer buffer, int minElementsRemaining) {
+ if (buffer == null) {
+ return;
+ }
+
+ if (buffer.remaining() < minElementsRemaining) {
+ throw new IndexOutOfBoundsException("Required " + minElementsRemaining + " remaining elements in buffer, only had " + buffer.remaining());
+ }
+ }
+
+ public static void rangeCheckBytes(Buffer buffer, int minBytesRemaining) {
+ if (buffer == null) {
+ return;
+ }
+
+ int elementsRemaining = buffer.remaining();
+ int bytesRemaining = 0;
+ if (buffer instanceof ByteBuffer) {
+ bytesRemaining = elementsRemaining;
+ } else if (buffer instanceof FloatBuffer) {
+ bytesRemaining = elementsRemaining * SIZEOF_FLOAT;
+ } else if (buffer instanceof IntBuffer) {
+ bytesRemaining = elementsRemaining * SIZEOF_INT;
+ } else if (buffer instanceof ShortBuffer) {
+ bytesRemaining = elementsRemaining * SIZEOF_SHORT;
+ } else if (buffer instanceof DoubleBuffer) {
+ bytesRemaining = elementsRemaining * SIZEOF_DOUBLE;
+ } else if (buffer instanceof LongBuffer) {
+ bytesRemaining = elementsRemaining * SIZEOF_LONG;
+ } else if (buffer instanceof CharBuffer) {
+ bytesRemaining = elementsRemaining * SIZEOF_CHAR;
+ }
+ if (bytesRemaining < minBytesRemaining) {
+ throw new IndexOutOfBoundsException("Required " + minBytesRemaining + " remaining bytes in buffer, only had " + bytesRemaining);
+ }
+ }
+
+ public static LongBuffer asPointerBuffer(ByteBuffer src) {
+ if (CPU.is32Bit()) {
+ // Must convert each pointer from 32-bit to 64-bit
+ IntBuffer buf = src.asIntBuffer();
+ int len = buf.capacity();
+ LongBuffer res = LongBuffer.wrap(new long[len]);
+ for (int i = 0; i < len; i++) {
+ res.put(i, buf.get(i));
+ }
+ return res;
+ } else {
+ return src.asLongBuffer();
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/BufferFactoryInternal.java b/src/java/com/sun/gluegen/runtime/BufferFactoryInternal.java
new file mode 100755
index 0000000..7a0e6a8
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/BufferFactoryInternal.java
@@ -0,0 +1,115 @@
+/*
+
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.nio.*;
+import sun.misc.Unsafe;
+
+public class BufferFactoryInternal {
+ private static final long addressFieldOffset;
+ private static final Constructor directByteBufferConstructor;
+
+ static {
+ try {
+ Field f = Buffer.class.getDeclaredField("address");
+ addressFieldOffset = UnsafeAccess.getUnsafe().objectFieldOffset(f);
+
+ Class directByteBufferClass = Class.forName("java.nio.DirectByteBuffer");
+ directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(new Class[] { Long.TYPE, Integer.TYPE });
+ directByteBufferConstructor.setAccessible(true);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static long getDirectBufferAddress(Buffer buf) {
+ return ((buf == null) ? 0 : UnsafeAccess.getUnsafe().getLong(buf, addressFieldOffset));
+ }
+
+ public static ByteBuffer newDirectByteBuffer(long address, int capacity) {
+ try {
+ if (address == 0) {
+ return null;
+ }
+ return (ByteBuffer) directByteBufferConstructor.newInstance(new Object[] { new Long(address), new Integer(capacity) });
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static long newCString(String str) {
+ byte[] strBytes = str.getBytes();
+ long strBlock = UnsafeAccess.getUnsafe().allocateMemory(strBytes.length+1);
+ for (int i = 0; i < strBytes.length; i++) {
+ UnsafeAccess.getUnsafe().putByte(strBlock+i, strBytes[i]);
+ }
+ UnsafeAccess.getUnsafe().putByte(strBlock+strBytes.length, (byte)0); // null termination
+ return strBlock;
+ }
+
+ public static void freeCString(long cStr) {
+ UnsafeAccess.getUnsafe().freeMemory(cStr);
+ }
+
+ public static String newJavaString(long cStr) {
+ if (cStr == 0) {
+ return null;
+ }
+ int numChars = 0;
+ while (UnsafeAccess.getUnsafe().getByte(cStr + numChars) != 0) {
+ ++numChars;
+ }
+ byte[] bytes = new byte[numChars];
+ for (int i = 0; i < numChars; i++) {
+ bytes[i] = UnsafeAccess.getUnsafe().getByte(cStr + i);
+ }
+ return new String(bytes);
+ }
+
+ public static int arrayBaseOffset(Object array) {
+ return UnsafeAccess.getUnsafe().arrayBaseOffset(array.getClass());
+ }
+ public static int arrayIndexScale(Object array) {
+ return UnsafeAccess.getUnsafe().arrayIndexScale(array.getClass());
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/CPU.java b/src/java/com/sun/gluegen/runtime/CPU.java
new file mode 100755
index 0000000..0456e9f
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/CPU.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+/** Provides information to autogenerated struct accessors about what
+ kind of data model (32- or 64-bit) is being used by the currently
+ running process. */
+
+public class CPU {
+ private static boolean is32Bit;
+
+ static {
+ // We don't seem to need an AccessController.doPrivileged() block
+ // here as these system properties are visible even to unsigned
+ // applets
+ // Note: this code is replicated in StructLayout.java
+ String os = System.getProperty("os.name").toLowerCase();
+ String cpu = System.getProperty("os.arch").toLowerCase();
+ if ((os.startsWith("windows") && cpu.equals("x86")) ||
+ (os.startsWith("windows") && cpu.equals("arm")) ||
+ (os.startsWith("linux") && cpu.equals("i386")) ||
+ (os.startsWith("linux") && cpu.equals("x86")) ||
+ (os.startsWith("mac os") && cpu.equals("ppc")) ||
+ (os.startsWith("mac os") && cpu.equals("i386")) ||
+ (os.startsWith("darwin") && cpu.equals("ppc")) ||
+ (os.startsWith("darwin") && cpu.equals("i386")) ||
+ (os.startsWith("sunos") && cpu.equals("sparc")) ||
+ (os.startsWith("sunos") && cpu.equals("x86")) ||
+ (os.startsWith("freebsd") && cpu.equals("i386")) ||
+ (os.startsWith("hp-ux") && cpu.equals("pa_risc2.0"))) {
+ is32Bit = true;
+ } else if ((os.startsWith("windows") && cpu.equals("amd64")) ||
+ (os.startsWith("linux") && cpu.equals("amd64")) ||
+ (os.startsWith("linux") && cpu.equals("x86_64")) ||
+ (os.startsWith("linux") && cpu.equals("ia64")) ||
+ (os.startsWith("mac os") && cpu.equals("x86_64")) ||
+ (os.startsWith("darwin") && cpu.equals("x86_64")) ||
+ (os.startsWith("sunos") && cpu.equals("sparcv9")) ||
+ (os.startsWith("sunos") && cpu.equals("amd64"))) {
+ } else {
+ throw new RuntimeException("Please port CPU detection (32/64 bit) to your platform (" + os + "/" + cpu + ")");
+ }
+ }
+
+ public static boolean is32Bit() {
+ return is32Bit;
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/DynamicLinker.java b/src/java/com/sun/gluegen/runtime/DynamicLinker.java
new file mode 100755
index 0000000..871be04
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/DynamicLinker.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+/** Provides an abstract interface to the OS's low-level dynamic
+ linking functionality. */
+
+interface DynamicLinker {
+ public long openLibraryGlobal(String pathname, boolean debug);
+ public long openLibraryLocal(String pathname, boolean debug);
+ public long lookupSymbol(long libraryHandle, String symbolName);
+ public void closeLibrary(long libraryHandle);
+}
diff --git a/src/java/com/sun/gluegen/runtime/DynamicLookupHelper.java b/src/java/com/sun/gluegen/runtime/DynamicLookupHelper.java
new file mode 100755
index 0000000..ad3de7f
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/DynamicLookupHelper.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+/** Interface callers may use to use the ProcAddressHelper's {@link
+ ProcAddressHelper#resetProcAddressTable resetProcAddressTable}
+ helper method to install function pointers into a
+ ProcAddressTable. This must typically be written with native
+ code. */
+
+public interface DynamicLookupHelper {
+ /**
+ * Try to fetch the function pointer for function 'funcName'.
+ */
+ public long dynamicLookupFunction(String funcName);
+}
diff --git a/src/java/com/sun/gluegen/runtime/MacOSXDynamicLinkerImpl.java b/src/java/com/sun/gluegen/runtime/MacOSXDynamicLinkerImpl.java
new file mode 100755
index 0000000..83ebd7a
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/MacOSXDynamicLinkerImpl.java
@@ -0,0 +1,60 @@
+/* !---- DO NOT EDIT: This file autogenerated by com\sun\gluegen\JavaEmitter.java on Mon Jul 31 16:27:00 PDT 2006 ----! */
+
+package com.sun.gluegen.runtime;
+
+import com.sun.gluegen.runtime.*;
+
+public class MacOSXDynamicLinkerImpl implements DynamicLinker
+{
+
+ public static final int RTLD_LAZY = 0x1;
+ public static final int RTLD_NOW = 0x2;
+ public static final int RTLD_LOCAL = 0x4;
+ public static final int RTLD_GLOBAL = 0x8;
+
+ /** Interface to C language function: <br> <code> int dlclose(void * __handle); </code> */
+ private static native int dlclose(long __handle);
+
+ /** Interface to C language function: <br> <code> char * dlerror(void); </code> */
+ private static native java.lang.String dlerror();
+
+ /** Interface to C language function: <br> <code> void * dlopen(const char * __path, int __mode); </code> */
+ private static native long dlopen(java.lang.String __path, int __mode);
+
+ /** Interface to C language function: <br> <code> void * dlsym(void * __handle, const char * __symbol); </code> */
+ private static native long dlsym(long __handle, java.lang.String __symbol);
+
+
+ // --- Begin CustomJavaCode .cfg declarations
+ public long openLibraryLocal(String pathname, boolean debug) {
+ // Note we use RTLD_LOCAL visibility to _NOT_ allow this functionality to
+ // be used to pre-resolve dependent libraries of JNI code without
+ // requiring that all references to symbols in those libraries be
+ // looked up dynamically via the ProcAddressTable mechanism; in
+ // other words, one can actually link against the library instead of
+ // having to dlsym all entry points. System.loadLibrary() uses
+ // RTLD_LOCAL visibility so can't be used for this purpose.
+ return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL);
+ }
+
+ public long openLibraryGlobal(String pathname, boolean debug) {
+ // Note we use RTLD_GLOBAL visibility to allow this functionality to
+ // be used to pre-resolve dependent libraries of JNI code without
+ // requiring that all references to symbols in those libraries be
+ // looked up dynamically via the ProcAddressTable mechanism; in
+ // other words, one can actually link against the library instead of
+ // having to dlsym all entry points. System.loadLibrary() uses
+ // RTLD_LOCAL visibility so can't be used for this purpose.
+ return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL);
+ }
+
+ public long lookupSymbol(long libraryHandle, String symbolName) {
+ return dlsym(libraryHandle, symbolName);
+ }
+
+ public void closeLibrary(long libraryHandle) {
+ dlclose(libraryHandle);
+ }
+ // ---- End CustomJavaCode .cfg declarations
+
+} // end of class MacOSXDynamicLinkerImpl
diff --git a/src/java/com/sun/gluegen/runtime/NativeLibLoader.java b/src/java/com/sun/gluegen/runtime/NativeLibLoader.java
new file mode 100755
index 0000000..0e6e3da
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/NativeLibLoader.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.*;
+
+/** Class providing control over whether GlueGen loads the native code
+ associated with the NativeLibrary implementation. Alternative app
+ launchers such as those running within applets may want to disable
+ this default loading behavior and load the native code via another
+ (manual) mechanism. */
+public class NativeLibLoader {
+ private static volatile boolean loadingEnabled = true;
+ private static volatile boolean didLoading;
+
+ public static void disableLoading() {
+ loadingEnabled = false;
+ }
+
+ public static void enableLoading() {
+ loadingEnabled = true;
+ }
+
+ public static void loadGlueGenRT() {
+ if (!didLoading && loadingEnabled) {
+ synchronized (NativeLibLoader.class) {
+ if (!didLoading && loadingEnabled) {
+ didLoading = true;
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ loadLibraryInternal("gluegen-rt");
+ return null;
+ }
+ });
+ }
+ }
+ }
+ }
+
+ private static void loadLibraryInternal(String libraryName) {
+ String sunAppletLauncher = System.getProperty("sun.jnlp.applet.launcher");
+ boolean usingJNLPAppletLauncher = Boolean.valueOf(sunAppletLauncher).booleanValue();
+
+ if (usingJNLPAppletLauncher) {
+ try {
+ Class jnlpAppletLauncherClass = Class.forName("org.jdesktop.applet.util.JNLPAppletLauncher");
+ Method jnlpLoadLibraryMethod = jnlpAppletLauncherClass.getDeclaredMethod("loadLibrary", new Class[] { String.class });
+ jnlpLoadLibraryMethod.invoke(null, new Object[] { libraryName });
+ } catch (Exception e) {
+ Throwable t = e;
+ if (t instanceof InvocationTargetException) {
+ t = ((InvocationTargetException) t).getTargetException();
+ }
+ if (t instanceof Error)
+ throw (Error) t;
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ }
+ // Throw UnsatisfiedLinkError for best compatibility with System.loadLibrary()
+ throw (UnsatisfiedLinkError) new UnsatisfiedLinkError().initCause(e);
+ }
+ } else {
+ System.loadLibrary(libraryName);
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/NativeLibrary.java b/src/java/com/sun/gluegen/runtime/NativeLibrary.java
new file mode 100755
index 0000000..22063a5
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/NativeLibrary.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.security.*;
+import java.util.*;
+
+/** Provides low-level, relatively platform-independent access to
+ shared ("native") libraries. The core library routines
+ <code>System.load()</code> and <code>System.loadLibrary()</code>
+ in general provide suitable functionality for applications using
+ native code, but are not flexible enough to support certain kinds
+ of glue code generation and deployment strategies. This class
+ supports direct linking of native libraries to other shared
+ objects not necessarily installed on the system (in particular,
+ via the use of dlopen(RTLD_GLOBAL) on Unix platforms) as well as
+ manual lookup of function names to support e.g. GlueGen's
+ ProcAddressTable glue code generation style without additional
+ supporting code needed in the generated library. */
+
+public class NativeLibrary {
+ private static final int WINDOWS = 1;
+ private static final int UNIX = 2;
+ private static final int MACOSX = 3;
+ private static boolean DEBUG;
+ private static int platform;
+ private static DynamicLinker dynLink;
+ private static String[] prefixes;
+ private static String[] suffixes;
+
+ static {
+ // Determine platform we're running on
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ String osName = System.getProperty("os.name").toLowerCase();
+ if (osName.startsWith("wind")) {
+ platform = WINDOWS;
+ } else if (osName.startsWith("mac os x")) {
+ platform = MACOSX;
+ } else {
+ platform = UNIX;
+ }
+
+ DEBUG = (System.getProperty("gluegen.debug.NativeLibrary") != null);
+
+ return null;
+ }
+ });
+ // Instantiate dynamic linker implementation
+ switch (platform) {
+ case WINDOWS:
+ dynLink = new WindowsDynamicLinkerImpl();
+ prefixes = new String[] { "" };
+ suffixes = new String[] { ".dll" };
+ break;
+ case UNIX:
+ dynLink = new UnixDynamicLinkerImpl();
+ prefixes = new String[] { "lib" };
+ suffixes = new String[] { ".so" };
+ break;
+ case MACOSX:
+ dynLink = new MacOSXDynamicLinkerImpl();
+ prefixes = new String[] { "lib", "" };
+ suffixes = new String[] { ".dylib", ".jnilib", "" };
+ break;
+ default:
+ throw new InternalError("Platform not initialized properly");
+ }
+ }
+
+ // Platform-specific representation for the handle to the open
+ // library. This is an HMODULE on Windows and a void* (the result of
+ // a dlopen() call) on Unix and Mac OS X platforms.
+ private long libraryHandle;
+
+ // May as well keep around the path to the library we opened
+ private String libraryPath;
+
+ // Private constructor to prevent arbitrary instances from floating around
+ private NativeLibrary(long libraryHandle, String libraryPath) {
+ this.libraryHandle = libraryHandle;
+ this.libraryPath = libraryPath;
+ }
+
+ /** Opens the given native library, assuming it has the same base
+ name on all platforms, looking first in the system's search
+ path, and in the context of the specified ClassLoader, which is
+ used to help find the library in the case of e.g. Java Web Start. */
+ public static NativeLibrary open(String libName, ClassLoader loader) {
+ return open(libName, libName, libName, true, loader, true);
+ }
+
+ /** Opens the given native library, assuming it has the same base
+ name on all platforms, looking first in the system's search
+ path, and in the context of the specified ClassLoader, which is
+ used to help find the library in the case of e.g. Java Web Start. */
+ public static NativeLibrary open(String libName, ClassLoader loader, boolean global) {
+ return open(libName, libName, libName, true, loader, global);
+ }
+
+ /** Opens the given native library, assuming it has the given base
+ names (no "lib" prefix or ".dll/.so/.dylib" suffix) on the
+ Windows, Unix and Mac OS X platforms, respectively, and in the
+ context of the specified ClassLoader, which is used to help find
+ the library in the case of e.g. Java Web Start. The
+ searchSystemPathFirst argument changes the behavior to first
+ search the default system path rather than searching it last.
+ Note that we do not currently handle DSO versioning on Unix.
+ Experience with JOAL and OpenAL has shown that it is extremely
+ problematic to rely on a specific .so version (for one thing,
+ ClassLoader.findLibrary on Unix doesn't work with files not
+ ending in .so, for example .so.0), and in general if this
+ dynamic loading facility is used correctly the version number
+ will be irrelevant.
+ */
+ public static NativeLibrary open(String windowsLibName,
+ String unixLibName,
+ String macOSXLibName,
+ boolean searchSystemPathFirst,
+ ClassLoader loader) {
+ return open(windowsLibName, unixLibName, macOSXLibName, searchSystemPathFirst, loader, true);
+ }
+
+ public static NativeLibrary open(String windowsLibName,
+ String unixLibName,
+ String macOSXLibName,
+ boolean searchSystemPathFirst,
+ ClassLoader loader, boolean global) {
+ List possiblePaths = enumerateLibraryPaths(windowsLibName,
+ unixLibName,
+ macOSXLibName,
+ searchSystemPathFirst,
+ loader);
+ // Iterate down these and see which one if any we can actually find.
+ for (Iterator iter = possiblePaths.iterator(); iter.hasNext(); ) {
+ String path = (String) iter.next();
+ if (DEBUG) {
+ System.out.println("Trying to load " + path);
+ }
+ ensureNativeLibLoaded();
+ long res;
+ if(global) {
+ res = dynLink.openLibraryGlobal(path, DEBUG);
+ } else {
+ res = dynLink.openLibraryLocal(path, DEBUG);
+ }
+ if (res != 0) {
+ if (DEBUG) {
+ System.out.println("Successfully loaded " + path + ": res = 0x" + Long.toHexString(res));
+ }
+ return new NativeLibrary(res, path);
+ }
+ }
+
+ if (DEBUG) {
+ System.out.println("Did not succeed in loading (" + windowsLibName + ", " + unixLibName + ", " + macOSXLibName + ")");
+ }
+
+ // For now, just return null to indicate the open operation didn't
+ // succeed (could also throw an exception if we could tell which
+ // of the openLibrary operations actually failed)
+ return null;
+ }
+
+ /** Looks up the given function name in this native library. */
+ public long lookupFunction(String functionName) {
+ if (libraryHandle == 0)
+ throw new RuntimeException("Library is not open");
+ return dynLink.lookupSymbol(libraryHandle, functionName);
+ }
+
+ /** Retrieves the low-level library handle from this NativeLibrary
+ object. On the Windows platform this is an HMODULE, and on Unix
+ and Mac OS X platforms the void* result of calling dlopen(). */
+ public long getLibraryHandle() {
+ return libraryHandle;
+ }
+
+ /** Retrieves the path under which this library was opened. */
+ public String getLibraryPath() {
+ return libraryPath;
+ }
+
+ /** Closes this native library. Further lookup operations are not
+ allowed after calling this method. */
+ public void close() {
+ if (libraryHandle == 0)
+ throw new RuntimeException("Library already closed");
+ long handle = libraryHandle;
+ libraryHandle = 0;
+ dynLink.closeLibrary(handle);
+ }
+
+ /** Given the base library names (no prefixes/suffixes) for the
+ various platforms, enumerate the possible locations and names of
+ the indicated native library on the system. */
+ private static List enumerateLibraryPaths(String windowsLibName,
+ String unixLibName,
+ String macOSXLibName,
+ boolean searchSystemPathFirst,
+ ClassLoader loader) {
+ List paths = new ArrayList();
+ String libName = selectName(windowsLibName, unixLibName, macOSXLibName);
+ if (libName == null)
+ return paths;
+
+ // Allow user's full path specification to override our building of paths
+ File file = new File(libName);
+ if (file.isAbsolute()) {
+ paths.add(libName);
+ return paths;
+ }
+
+ String[] baseNames = buildNames(libName);
+
+ if (searchSystemPathFirst) {
+ // Add just the library names to use the OS's search algorithm
+ for (int i = 0; i < baseNames.length; i++) {
+ paths.add(baseNames[i]);
+ }
+ }
+
+ // The idea to ask the ClassLoader to find the library is borrowed
+ // from the LWJGL library
+ String clPath = getPathFromClassLoader(libName, loader);
+ if (DEBUG) {
+ System.out.println("Class loader path to " + libName + ": " + clPath);
+ }
+ if (clPath != null) {
+ paths.add(clPath);
+ }
+
+ // Add entries from java.library.path
+ String javaLibraryPath =
+ (String) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return System.getProperty("java.library.path");
+ }
+ });
+ if (javaLibraryPath != null) {
+ StringTokenizer tokenizer = new StringTokenizer(javaLibraryPath, File.pathSeparator);
+ while (tokenizer.hasMoreTokens()) {
+ addPaths(tokenizer.nextToken(), baseNames, paths);
+ }
+ }
+
+ // Add current working directory
+ String userDir =
+ (String) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return System.getProperty("user.dir");
+ }
+ });
+ addPaths(userDir, baseNames, paths);
+
+ // Add probable Mac OS X-specific paths
+ if (platform == MACOSX) {
+ // Add historical location
+ addPaths("/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
+ // Add current location
+ addPaths("/System/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
+ }
+
+ if (!searchSystemPathFirst) {
+ // Add just the library names to use the OS's search algorithm
+ for (int i = 0; i < baseNames.length; i++) {
+ paths.add(baseNames[i]);
+ }
+ }
+
+ return paths;
+ }
+
+
+ private static String selectName(String windowsLibName,
+ String unixLibName,
+ String macOSXLibName) {
+ switch (platform) {
+ case WINDOWS:
+ return windowsLibName;
+ case UNIX:
+ return unixLibName;
+ case MACOSX:
+ return macOSXLibName;
+ default:
+ throw new InternalError();
+ }
+ }
+
+ private static String[] buildNames(String libName) {
+ // If the library name already has the prefix / suffix added
+ // (principally because we want to force a version number on Unix
+ // operating systems) then just return the library name.
+ if (libName.startsWith(prefixes[0])) {
+ if (libName.endsWith(suffixes[0])) {
+ return new String[] { libName };
+ }
+
+ int idx = libName.indexOf(suffixes[0]);
+ boolean ok = true;
+ if (idx >= 0) {
+ // Check to see if everything after it is a Unix version number
+ for (int i = idx + suffixes[0].length();
+ i < libName.length();
+ i++) {
+ char c = libName.charAt(i);
+ if (!(c == '.' || (c >= '0' && c <= '9'))) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ return new String[] { libName };
+ }
+ }
+ }
+
+ String[] res = new String[prefixes.length * suffixes.length];
+ int idx = 0;
+ for (int i = 0; i < prefixes.length; i++) {
+ for (int j = 0; j < suffixes.length; j++) {
+ res[idx++] = prefixes[i] + libName + suffixes[j];
+ }
+ }
+ return res;
+ }
+
+ private static void addPaths(String path, String[] baseNames, List paths) {
+ for (int j = 0; j < baseNames.length; j++) {
+ paths.add(path + File.separator + baseNames[j]);
+ }
+ }
+
+ private static boolean initializedFindLibraryMethod = false;
+ private static Method findLibraryMethod = null;
+ private static String getPathFromClassLoader(final String libName, final ClassLoader loader) {
+ if (loader == null)
+ return null;
+ if (!initializedFindLibraryMethod) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ try {
+ findLibraryMethod = ClassLoader.class.getDeclaredMethod("findLibrary",
+ new Class[] { String.class });
+ findLibraryMethod.setAccessible(true);
+ } catch (Exception e) {
+ // Fail silently disabling this functionality
+ }
+ initializedFindLibraryMethod = true;
+ return null;
+ }
+ });
+ }
+ if (findLibraryMethod != null) {
+ try {
+ return (String) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ try {
+ return findLibraryMethod.invoke(loader, new Object[] { libName });
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ } catch (Exception e) {
+ if (DEBUG) {
+ e.printStackTrace();
+ }
+ // Fail silently and continue with other search algorithms
+ }
+ }
+ return null;
+ }
+
+ private static volatile boolean loadedDynLinkNativeLib;
+ private static void ensureNativeLibLoaded() {
+ if (!loadedDynLinkNativeLib) {
+ synchronized (NativeLibrary.class) {
+ if (!loadedDynLinkNativeLib) {
+ loadedDynLinkNativeLib = true;
+ NativeLibLoader.loadGlueGenRT();
+ }
+ }
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/ProcAddressHelper.java b/src/java/com/sun/gluegen/runtime/ProcAddressHelper.java
new file mode 100644
index 0000000..f0dbe8b
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/ProcAddressHelper.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+import java.security.*;
+
+// Debugging only
+import java.io.*;
+
+/** Helper class containing constants and methods to assist with the
+ manipulation of auto-generated ProcAddressTables. */
+
+public class ProcAddressHelper {
+ public static final String PROCADDRESS_VAR_PREFIX = "_addressof_";
+ protected static boolean DEBUG;
+ protected static String DEBUG_PREFIX;
+ protected static int debugNum;
+
+ static {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ DEBUG = (System.getProperty("gluegen.debug.ProcAddressHelper") != null);
+ if (DEBUG) {
+ DEBUG_PREFIX = System.getProperty("gluegen.debug.ProcAddressHelper.prefix");
+ }
+ return null;
+ }
+ });
+ }
+
+ protected static PrintStream getDebugOutStream() {
+ PrintStream out = null;
+ if (DEBUG) {
+ if (DEBUG_PREFIX != null) {
+ try {
+ out = new PrintStream(new BufferedOutputStream(new FileOutputStream(DEBUG_PREFIX + File.separatorChar +
+ "procaddresshelper-" + (++debugNum) + ".txt")));
+ } catch (IOException e) {
+ e.printStackTrace();
+ out = System.err;
+ }
+ } else {
+ out = System.err;
+ }
+ }
+ return out;
+ }
+
+ public static void resetProcAddressTable(Object table,
+ DynamicLookupHelper lookup) throws RuntimeException {
+ Class tableClass = table.getClass();
+ java.lang.reflect.Field[] fields = tableClass.getFields();
+ PrintStream dout = getDebugOutStream();
+
+ if (DEBUG) {
+ dout.println("ProcAddressHelper.resetProcAddressTable(" + table.getClass().getName() + ")");
+ }
+ for (int i = 0; i < fields.length; ++i) {
+ String addressFieldName = fields[i].getName();
+ if (!addressFieldName.startsWith(ProcAddressHelper.PROCADDRESS_VAR_PREFIX)) {
+ // not a proc address variable
+ continue;
+ }
+ int startOfMethodName = ProcAddressHelper.PROCADDRESS_VAR_PREFIX.length();
+ String funcName = addressFieldName.substring(startOfMethodName);
+ try {
+ java.lang.reflect.Field addressField = fields[i];
+ assert(addressField.getType() == Long.TYPE);
+ long newProcAddress = lookup.dynamicLookupFunction(funcName);
+ // set the current value of the proc address variable in the table object
+ addressField.setLong(table, newProcAddress);
+ if (DEBUG) {
+ dout.println(" " + addressField.getName() + " -> 0x" + Long.toHexString(newProcAddress));
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Can not get proc address for method \"" +
+ funcName + "\": Couldn't set value of field \"" + addressFieldName +
+ "\" in class " + tableClass.getName(), e);
+ }
+ }
+ if (DEBUG) {
+ dout.flush();
+ if (DEBUG_PREFIX != null) {
+ dout.close();
+ }
+ }
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/ProcAddressTable.java b/src/java/com/sun/gluegen/runtime/ProcAddressTable.java
new file mode 100644
index 0000000..4271a8c
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/ProcAddressTable.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ */
+
+package com.sun.gluegen.runtime;
+
+public interface ProcAddressTable {
+ public long getAddressFor(String functionName);
+}
diff --git a/src/java/com/sun/gluegen/runtime/StructAccessor.java.javame_cdc_fp b/src/java/com/sun/gluegen/runtime/StructAccessor.java.javame_cdc_fp
new file mode 100755
index 0000000..3e3f372
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/StructAccessor.java.javame_cdc_fp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.runtime;
+
+import java.nio.*;
+
+public class StructAccessor {
+ private ByteBuffer bb;
+ private FloatBuffer fb;
+ private IntBuffer ib;
+ private ShortBuffer sb;
+
+ public StructAccessor(ByteBuffer bb) {
+ this.bb = bb;
+ }
+
+ 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 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 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 FloatBuffer floatBuffer() {
+ if (fb == null) {
+ fb = bb.asFloatBuffer();
+ }
+ return fb;
+ }
+
+ private IntBuffer intBuffer() {
+ if (ib == null) {
+ ib = bb.asIntBuffer();
+ }
+ return ib;
+ }
+
+ private ShortBuffer shortBuffer() {
+ if (sb == null) {
+ sb = bb.asShortBuffer();
+ }
+ return sb;
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/StructAccessor.java.javase b/src/java/com/sun/gluegen/runtime/StructAccessor.java.javase
new file mode 100755
index 0000000..5a0fa5d
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/StructAccessor.java.javase
@@ -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
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.gluegen.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;
+ }
+}
diff --git a/src/java/com/sun/gluegen/runtime/UnixDynamicLinkerImpl.java b/src/java/com/sun/gluegen/runtime/UnixDynamicLinkerImpl.java
new file mode 100755
index 0000000..773d832
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/UnixDynamicLinkerImpl.java
@@ -0,0 +1,66 @@
+/* !---- DO NOT EDIT: This file autogenerated by com\sun\gluegen\JavaEmitter.java on Mon Jul 31 16:26:59 PDT 2006 ----! */
+
+package com.sun.gluegen.runtime;
+
+import com.sun.gluegen.runtime.*;
+
+public class UnixDynamicLinkerImpl implements DynamicLinker
+{
+
+ public static final int RTLD_LAZY = 0x00001;
+ public static final int RTLD_NOW = 0x00002;
+ public static final int RTLD_NOLOAD = 0x00004;
+ public static final int RTLD_GLOBAL = 0x00100;
+ public static final int RTLD_LOCAL = 0x00000;
+ public static final int RTLD_PARENT = 0x00200;
+ public static final int RTLD_GROUP = 0x00400;
+ public static final int RTLD_WORLD = 0x00800;
+ public static final int RTLD_NODELETE = 0x01000;
+ public static final int RTLD_FIRST = 0x02000;
+
+ /** Interface to C language function: <br> <code> int dlclose(void * ); </code> */
+ private static native int dlclose(long arg0);
+
+ /** Interface to C language function: <br> <code> char * dlerror(void); </code> */
+ private static native java.lang.String dlerror();
+
+ /** Interface to C language function: <br> <code> void * dlopen(const char * , int); </code> */
+ private static native long dlopen(java.lang.String arg0, int arg1);
+
+ /** Interface to C language function: <br> <code> void * dlsym(void * , const char * ); </code> */
+ private static native long dlsym(long arg0, java.lang.String arg1);
+
+
+ // --- Begin CustomJavaCode .cfg declarations
+ public long openLibraryLocal(String pathname, boolean debug) {
+ // Note we use RTLD_GLOBAL visibility to _NOT_ allow this functionality to
+ // be used to pre-resolve dependent libraries of JNI code without
+ // requiring that all references to symbols in those libraries be
+ // looked up dynamically via the ProcAddressTable mechanism; in
+ // other words, one can actually link against the library instead of
+ // having to dlsym all entry points. System.loadLibrary() uses
+ // RTLD_LOCAL visibility so can't be used for this purpose.
+ return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL);
+ }
+
+ public long openLibraryGlobal(String pathname, boolean debug) {
+ // Note we use RTLD_GLOBAL visibility to allow this functionality to
+ // be used to pre-resolve dependent libraries of JNI code without
+ // requiring that all references to symbols in those libraries be
+ // looked up dynamically via the ProcAddressTable mechanism; in
+ // other words, one can actually link against the library instead of
+ // having to dlsym all entry points. System.loadLibrary() uses
+ // RTLD_LOCAL visibility so can't be used for this purpose.
+ return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL);
+ }
+
+ public long lookupSymbol(long libraryHandle, String symbolName) {
+ return dlsym(libraryHandle, symbolName);
+ }
+
+ public void closeLibrary(long libraryHandle) {
+ dlclose(libraryHandle);
+ }
+ // ---- End CustomJavaCode .cfg declarations
+
+} // end of class UnixDynamicLinkerImpl
diff --git a/src/java/com/sun/gluegen/runtime/WindowsDynamicLinkerImpl.java b/src/java/com/sun/gluegen/runtime/WindowsDynamicLinkerImpl.java
new file mode 100755
index 0000000..325078b
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/WindowsDynamicLinkerImpl.java
@@ -0,0 +1,49 @@
+/* !---- DO NOT EDIT: This file autogenerated by com\sun\gluegen\JavaEmitter.java on Tue May 27 02:37:55 PDT 2008 ----! */
+
+package com.sun.gluegen.runtime;
+
+import com.sun.gluegen.runtime.*;
+
+public class WindowsDynamicLinkerImpl implements DynamicLinker
+{
+
+
+ /** Interface to C language function: <br> <code> BOOL FreeLibrary(HANDLE hLibModule); </code> */
+ private static native int FreeLibrary(long hLibModule);
+
+ /** Interface to C language function: <br> <code> DWORD GetLastError(void); </code> */
+ private static native int GetLastError();
+
+ /** Interface to C language function: <br> <code> PROC GetProcAddressA(HANDLE hModule, LPCSTR lpProcName); </code> */
+ private static native long GetProcAddressA(long hModule, java.lang.String lpProcName);
+
+ /** Interface to C language function: <br> <code> HANDLE LoadLibraryW(LPCWSTR lpLibFileName); </code> */
+ private static native long LoadLibraryW(java.lang.String lpLibFileName);
+
+
+ // --- Begin CustomJavaCode .cfg declarations
+ public long openLibraryLocal(String libraryName, boolean debug) {
+ // How does that work under Windows ?
+ // Don't know .. so it's an alias for the time being
+ return openLibraryGlobal(libraryName, debug);
+ }
+
+ public long openLibraryGlobal(String libraryName, boolean debug) {
+ long handle = LoadLibraryW(libraryName);
+ if(0==handle && debug) {
+ int err = GetLastError();
+ System.err.println("LoadLibraryW \""+libraryName+"\" failed, error code: 0x"+Integer.toHexString(err)+", "+err);
+ }
+ return handle;
+ }
+
+ public long lookupSymbol(long libraryHandle, String symbolName) {
+ return GetProcAddressA(libraryHandle, symbolName);
+ }
+
+ public void closeLibrary(long libraryHandle) {
+ FreeLibrary(libraryHandle);
+ }
+ // ---- End CustomJavaCode .cfg declarations
+
+} // end of class WindowsDynamicLinkerImpl
diff --git a/src/java/com/sun/gluegen/runtime/opengl/GLExtensionNames.java b/src/java/com/sun/gluegen/runtime/opengl/GLExtensionNames.java
new file mode 100644
index 0000000..3c6f600
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/opengl/GLExtensionNames.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ */
+
+package com.sun.gluegen.runtime.opengl;
+
+import java.util.*;
+import com.sun.gluegen.runtime.*;
+
+public class GLExtensionNames {
+ //GL_XYZ : GL_XYZ, GL_XYZ_GL2, GL_XYZ_ARB, GL_XYZ_OES, GL_XYZ_OML
+ //GL_XYZ : GL_XYZ, GL_GL2_XYZ, GL_ARB_XYZ, GL_OES_XYZ, GL_OML_XYZ
+ //
+ // Pass-1 Unify ARB extensions with the same value
+ // Pass-2 Unify vendor extensions,
+ // if exist as an ARB extension with the same value.
+ // Pass-3 Emit
+
+ public static final String[] extensionsARB = { "ARB", "GL2", "OES", "KHR", "OML" };
+ public static final String[] extensionsVEN = { "3DFX",
+ "AMD",
+ "APPLE",
+ "ATI",
+ "EXT",
+ "HP",
+ "IBM",
+ "MESA",
+ "MESAX",
+ "NV",
+ "SGI",
+ "SGIS",
+ "SGIX",
+ "SUN",
+ "WIN"
+ };
+
+
+ public static final boolean isGLFunction(String str) {
+ return str.startsWith("gl") || /* str.startsWith("glu") || str.startsWith("glX") || */
+ str.startsWith("egl") || str.startsWith("wgl") || str.startsWith("agl") ||
+ str.startsWith("cgl") ;
+ }
+
+ public static final boolean isGLEnumeration(String str) {
+ return str.startsWith("GL_") || str.startsWith("GLU_") || str.startsWith("GLX_") ||
+ str.startsWith("EGL_") || str.startsWith("WGL_") || str.startsWith("AGL_") ||
+ str.startsWith("CGL_") ;
+ }
+
+ public static final int getExtensionIdx(String[] extensions, String str, boolean isGLFunc) {
+ if(isGLFunc) {
+ for(int i = extensions.length - 1 ; i>=0 ; i--) {
+ if( str.endsWith(extensions[i]) ) {
+ return i;
+ }
+ }
+ } else {
+ for(int i = extensions.length - 1 ; i>=0 ; i--) {
+ if( str.endsWith("_"+extensions[i]) ) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ public static final boolean isExtension(String[] extensions, String str, boolean isGLFunc) {
+ return getExtensionIdx(extensions, str, isGLFunc)>=0;
+ }
+
+ public static final String getExtensionSuffix(String str, boolean isGLFunc) {
+ int idx = getExtensionIdx(extensionsARB, str, isGLFunc);
+ if(idx>=0) {
+ return extensionsARB[idx];
+ }
+ idx = getExtensionIdx(extensionsVEN, str, isGLFunc);
+ if(idx>=0) {
+ return extensionsVEN[idx];
+ }
+ return null;
+ }
+
+ public static final String normalize(String[] extensions, String str, boolean isGLFunc) {
+ boolean touched = false;
+ for(int i = extensions.length - 1 ; !touched && i>=0 ; i--) {
+ if(isGLFunc) {
+ if(str.endsWith(extensions[i])) {
+ // functions
+ str = str.substring(0, str.length()-extensions[i].length());
+ touched=true;
+ }
+ } else {
+ if(str.endsWith("_"+extensions[i])) {
+ // enums
+ str = str.substring(0, str.length()-1-extensions[i].length());
+ touched=true;
+ }
+ }
+ }
+ return str;
+ }
+ public static final String normalizeARB(String str, boolean isGLFunc) {
+ return normalize(extensionsARB, str, isGLFunc);
+ }
+ public static final boolean isExtensionARB(String str, boolean isGLFunc) {
+ return isExtension(extensionsARB, str, isGLFunc);
+ }
+ public static final String normalizeVEN(String str, boolean isGLFunc) {
+ return normalize(extensionsVEN, str, isGLFunc);
+ }
+ public static final boolean isExtensionVEN(String str, boolean isGLFunc) {
+ return isExtension(extensionsVEN, str, isGLFunc);
+ }
+ public static final String normalize(String str, boolean isGLFunc) {
+ if (isExtensionARB(str, isGLFunc)) {
+ return normalizeARB(str, isGLFunc);
+ }
+ if (isExtensionVEN(str, isGLFunc)) {
+ return normalizeVEN(str, isGLFunc);
+ }
+ return str;
+ }
+ public static final boolean isExtension(String str, boolean isGLFunc) {
+ return isExtension(extensionsARB, str, isGLFunc) ||
+ isExtension(extensionsVEN, str, isGLFunc);
+ }
+
+ public static final int getFuncNamePermutationNumber(String name) {
+ if(isExtensionARB(name, true) || isExtensionVEN(name, true)) {
+ // no name permutation, if it's already a known extension
+ return 1;
+ }
+ return 1 + extensionsARB.length + extensionsVEN.length;
+ }
+
+ public static final String getFuncNamePermutation(String name, int i) {
+ // identity
+ if(i==0) {
+ return name;
+ }
+ if(0>i || i>=(1+extensionsARB.length + extensionsVEN.length)) {
+ throw new RuntimeException("Index out of range [0.."+(1+extensionsARB.length+extensionsVEN.length-1)+"]: "+i);
+ }
+ // ARB
+ i-=1;
+ if(i<extensionsARB.length) {
+ return name+extensionsARB[i];
+ }
+ // VEN
+ i-=extensionsARB.length;
+ return name+extensionsVEN[i];
+ }
+}
+
diff --git a/src/java/com/sun/gluegen/runtime/opengl/GLProcAddressHelper.java b/src/java/com/sun/gluegen/runtime/opengl/GLProcAddressHelper.java
new file mode 100644
index 0000000..4110b6f
--- /dev/null
+++ b/src/java/com/sun/gluegen/runtime/opengl/GLProcAddressHelper.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ */
+
+package com.sun.gluegen.runtime.opengl;
+
+import com.sun.gluegen.runtime.*;
+
+import java.security.*;
+
+// Debugging only
+import java.io.PrintStream;
+
+/** Helper class containing constants and methods to assist with the
+ manipulation of auto-generated ProcAddressTables. */
+
+public class GLProcAddressHelper extends ProcAddressHelper {
+
+ public static void resetProcAddressTable(Object table,
+ DynamicLookupHelper lookup) throws RuntimeException {
+ Class tableClass = table.getClass();
+ java.lang.reflect.Field[] fields = tableClass.getFields();
+ PrintStream dout = getDebugOutStream();
+
+ if (DEBUG) {
+ dout.println("ProcAddressHelper.resetProcAddressTable(" + table.getClass().getName() + ")");
+ }
+ for (int i = 0; i < fields.length; ++i) {
+ String addressFieldName = fields[i].getName();
+ if (!addressFieldName.startsWith(ProcAddressHelper.PROCADDRESS_VAR_PREFIX)) {
+ // not a proc address variable
+ continue;
+ }
+ int startOfMethodName = ProcAddressHelper.PROCADDRESS_VAR_PREFIX.length();
+ String funcNameBase = addressFieldName.substring(startOfMethodName);
+ java.lang.reflect.Field addressField;
+ try {
+ addressField = fields[i];
+ assert(addressField.getType() == Long.TYPE);
+ } catch (Exception e) {
+ throw new RuntimeException("Can not get proper proc address field for method \"" +
+ funcNameBase + "\": Couldn't get field \"" + addressFieldName +
+ "\" in class " + tableClass.getName(), e);
+ }
+ long newProcAddress = 0;
+ int funcNamePermNum = GLExtensionNames.getFuncNamePermutationNumber(funcNameBase);
+ String funcName = null;
+ for(int j = 0; 0==newProcAddress && j < funcNamePermNum; j++) {
+ funcName = GLExtensionNames.getFuncNamePermutation(funcNameBase, j);
+ try {
+ newProcAddress = lookup.dynamicLookupFunction(funcName);
+ } catch (Exception e) {
+ if (DEBUG) {
+ dout.println(e);
+ e.printStackTrace();
+ }
+ }
+ }
+ try {
+ // set the current value of the proc address variable in the table object
+ addressField.setLong(table, newProcAddress);
+ if (DEBUG) {
+ dout.println(" " + addressField.getName() + " "+funcName+" -> 0x" + Long.toHexString(newProcAddress));
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Can not set proc address field for method \"" +
+ funcNameBase + "\": Couldn't set field \"" + addressFieldName +
+ "\" in class " + tableClass.getName(), e);
+ }
+ }
+ if (DEBUG) {
+ dout.flush();
+ if (DEBUG_PREFIX != null) {
+ dout.close();
+ }
+ }
+ }
+}
diff --git a/src/java/net/highteq/nativetaglet/NativeTaglet.java b/src/java/net/highteq/nativetaglet/NativeTaglet.java
new file mode 100755
index 0000000..5744253
--- /dev/null
+++ b/src/java/net/highteq/nativetaglet/NativeTaglet.java
@@ -0,0 +1,227 @@
+package net.highteq.nativetaglet;
+
+import com.sun.tools.doclets.Taglet;
+import com.sun.javadoc.*;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.Iterator;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+public class NativeTaglet implements Taglet
+{
+ private Properties mapping= null;
+ private static final String NAME = "native";
+
+ /**
+ * Return the name of this custom tag.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * @return true since this tag can be used in a field
+ * doc comment
+ */
+ public boolean inField()
+ {
+ return true;
+ }
+
+ /**
+ * @return true since this tag can be used in a constructor
+ * doc comment
+ */
+ public boolean inConstructor()
+ {
+ return true;
+ }
+
+ /**
+ * @return true since this tag can be used in a method
+ * doc comment
+ */
+ public boolean inMethod()
+ {
+ return true;
+ }
+
+ /**
+ * @return true since this tag can be used in an overview
+ * doc comment
+ */
+ public boolean inOverview()
+ {
+ return true;
+ }
+
+ /**
+ * @return true since this tag can be used in a package
+ * doc comment
+ */
+ public boolean inPackage()
+ {
+ return true;
+ }
+
+ /**
+ * @return true since this
+ */
+ public boolean inType()
+ {
+ return true;
+ }
+
+ /**
+ * Will return true since this is an inline tag.
+ *
+ * @return true since this is an inline tag.
+ */
+
+ public boolean isInlineTag()
+ {
+ return true;
+ }
+
+ /**
+ * Register this Taglet.
+ *
+ * @param tagletMap the map to register this tag to.
+ */
+ public static void register(Map tagletMap)
+ {
+ NativeTaglet tag = new NativeTaglet();
+ Taglet t = (Taglet) tagletMap.get(tag.getName());
+ if (t != null)
+ {
+ tagletMap.remove(tag.getName());
+ }
+ tagletMap.put(tag.getName(), tag);
+ }
+
+ /**
+ * Given the <code>Tag</code> representation of this custom
+ * tag, return its string representation.
+ *
+ * @param tag the <code>Tag</code> representation of this custom tag.
+ */
+ public String toString(Tag tag)
+ {
+ String text= tag.text().trim();
+ if(mapping== null)
+ {
+ mapping= new Properties();
+ InputStream in= null;
+ try
+ {
+ URL url;
+ try
+ {
+ url = new URL(System.getProperty("nativetaglet.mapping","file:native-taglet.properties"));
+ }
+ catch (MalformedURLException e)
+ {
+ url = new URL("file:"+System.getProperty("nativetaglet.mapping","file:native-taglet.properties"));
+ }
+ in= url.openStream();
+ mapping.load(in);
+ }
+ catch (Exception e)
+ {
+ System.err.println("[NATIVE TAGLET] Could not read mapping file");
+ System.err.println("-->");
+ e.printStackTrace(System.err);
+ System.err.println("<--");
+ System.err.println("[NATIVE TAGLET] !!! NO LINKS WILL BE GENERATED !!!");
+ }
+ finally
+ {
+ if(in!=null) try{ in.close(); }catch(Exception ignore){}
+ }
+ }
+
+ if(mapping!=null)
+ {
+ // First check to see whether this key exists in the mapping
+ String url = mapping.getProperty(text);
+ if (url == null) {
+ // Try iterating the keySet seeing if we can find a partial match
+ // In the OpenGL spec this handles the case of glVertex -> glVertex3f
+ for(Iterator i= mapping.keySet().iterator(); i.hasNext();) {
+ String name= (String) i.next();
+ if (hasOpenGLSuffix(text, name)) {
+ url = mapping.getProperty(name);
+ break;
+ }
+ }
+ }
+ if (url != null) {
+ url = mapping.getProperty("nativetaglet.baseUrl", "") + url;
+ text = "<a href=\"" + url + "\">" + text + "</a>";
+ }
+ }
+ return text;
+ }
+
+ private static final String[] openGLSuffixes = {
+ "b",
+ "s",
+ "i",
+ "f",
+ "d",
+ "ub",
+ "us",
+ "ui",
+ "bv",
+ "sv",
+ "iv",
+ "fv",
+ "dv",
+ "ubv",
+ "usv",
+ "uiv"
+ };
+ private static boolean hasOpenGLSuffix(String name,
+ String baseName) {
+ if (!name.startsWith(baseName)) {
+ return false;
+ }
+ for (int i = 0; i < openGLSuffixes.length; i++) {
+ String suffix = openGLSuffixes[i];
+ if (name.endsWith(suffix)) {
+ // First see whether it's a simple concatenation
+ if (name.equals(baseName + suffix)) {
+ return true;
+ }
+ // Now chop prefix and suffix off and see whether the
+ // resulting is a number
+ try {
+ String tmp = name.substring(baseName.length(),
+ name.length() - suffix.length());
+ if (tmp.length() == 1 &&
+ Character.isDigit(tmp.charAt(0))) {
+ return true;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This method should not be called since arrays of inline tags do not
+ * exist. Method {@link #tostring(Tag)} should be used to convert this
+ * inline tag to a string.
+ *
+ * @param tags the array of <code>Tag</code>s representing of this custom tag.
+ */
+ public String toString(Tag[] tags)
+ {
+ return null;
+ }
+}