summaryrefslogtreecommitdiffstats
path: root/src/antlr/com/jogamp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2015-03-05 07:14:04 +0100
committerSven Gothel <[email protected]>2015-03-05 07:14:04 +0100
commit72d3635279ffc8ad88e47dff9bbe95d211226d11 (patch)
tree62b3735680dfc5980a94afa14c56045bd082af24 /src/antlr/com/jogamp
parentdd2440cbadc642a561d8f92c502fe822b2f11762 (diff)
Bug 1134 - Enhance GlueGen Compiler: Minimal GL Header Changes _and_ Typesafety
- We shall be able to import 'most' vanilla GL header, i.e. only change the typedef part using our GlueGen types - Type Safety: - GlueGen now detects '#define' and 'enum' redefines and throw an exception in this case. This helps detecting wrongly renamed GL extensions into core! - GlueGen now detects function redefines (overloading) and throw an exception in this case. Hence the semantics of duplicate functions has to be equal! This helps detecting wrongly renamed GL extensions into core! - Semantic equality for all types is provided via interface TypeComparator.SemanticEqualityOp, i.e. 'boolean equalSemantics(..)' implemented by com.jogamp.gluegen.cgram.types.Type. Semantic equality can be relaxed via config "RelaxedEqualSemanticsTest true", i.e. ignoring integer size, and const / volatile qualifiers. - All equality/hash methods of 'com.jogamp.gluegen.cgram.types.*' are restructured. - Track and simplify renamed 'symbol', i.e. use a common sub-interface for all renamed symbols (ConstantDefinition, FunctionSymbol, ..) - This is provided in a unified manner via interface com.jogamp.gluegen.cgram.types.AliasedSymbol and its common implementation AliasedSymbolImpl - All JavaConfiguration.shouldIgnore* methods operate w/ 'AliasedSymbol' trying to match all aliases. - Support 'struct NAME [ { ... } ]' w/o typedef's - New GL / CL headers do not use typedef's for anonymous opaque types - Opaque Type handling - JavaConfiguration.typeInfo(..), identifying opaque types, no more back references from target-type -> typedef. Hence the following is possible now: typedef void * Opaque01; // Opaque typedef void * APointerBuffer; // A Buffer - All Logger instances are no more static and derive their warning level from the package's root Logger via Logging.getLogger(..).
Diffstat (limited to 'src/antlr/com/jogamp')
-rw-r--r--src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g330
1 files changed, 216 insertions, 114 deletions
diff --git a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g
index 01f10c3..3088610 100644
--- a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g
+++ b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g
@@ -45,6 +45,7 @@ header {
import java.util.*;
import antlr.CommonAST;
+ import com.jogamp.gluegen.JavaConfiguration;
import com.jogamp.gluegen.cgram.types.*;
}
@@ -67,6 +68,12 @@ options {
this.debug = debug;
}
+ /** Set the configuration for this
+ HeaderParser. Must be done before parsing. */
+ public void setJavaConfiguration(JavaConfiguration cfg) {
+ this.cfg = cfg;
+ }
+
/** Set the dictionary mapping typedef names to types for this
HeaderParser. Must be done before parsing. */
public void setTypedefDictionary(TypeDictionary dict) {
@@ -105,7 +112,7 @@ options {
// 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!");
+ throw new RuntimeException("setEnums is Unimplemented!");
}
/** Returns the EnumTypes this HeaderParser processed. */
@@ -125,14 +132,13 @@ options {
return functions;
}
- private CompoundType lookupInStructDictionary(String typeName,
+ private CompoundType lookupInStructDictionary(String structName,
CompoundTypeKind kind,
int cvAttrs) {
- CompoundType t = (CompoundType) structDictionary.get(typeName);
+ CompoundType t = (CompoundType) structDictionary.get(structName);
if (t == null) {
- t = CompoundType.create(null, null, kind, cvAttrs);
- t.setStructName(typeName);
- structDictionary.put(typeName, t);
+ t = CompoundType.create(structName, null, kind, cvAttrs);
+ structDictionary.put(structName, t);
}
return t;
}
@@ -153,8 +159,33 @@ options {
this.id = id;
this.type = type;
}
- String id() { return id; }
- Type type() { return type; }
+ String id() { return id; }
+ Type type() { return type; }
+ void setType(final Type t) { type = t; }
+ public String toString() { return "ParamDecl["+id+": "+type.getDebugString()+"]"; }
+ }
+ Type resolveAnonCompound(Type type) {
+ int mode = 0;
+ debugPrint("resolveAnonCompound: "+type.getDebugString());
+ if( !type.hasName() ) {
+ if( type.isCompound() ) {
+ final CompoundType ct = type.asCompound();
+ // return a copy w/ resolved name
+ type = ((CompoundType) ct.clone()).evalStructTypeName();
+ mode = 1;
+ } else if( type.isPointer() ) {
+ // non typedefed PointerType and base-elem w/o name
+ final PointerType pt = type.asPointer();
+ final Type b = pt.getBaseElementType();
+ if( b != null && b.isCompound() && !b.hasName() ) {
+ // return same w/ resolved name
+ b.asCompound().evalStructTypeName();
+ mode = 2;
+ }
+ }
+ }
+ debugPrintln(" -> "+type.getDebugString()+" - MODE "+mode);
+ return type;
}
// A box for a Type. Allows type to be passed down to be modified by recursive rules.
@@ -207,22 +238,27 @@ options {
}
}
+ private String getDebugTypeString(Type t) {
+ if(debug) {
+ return getTypeString(t);
+ } else {
+ return null;
+ }
+ }
private String getTypeString(Type t) {
StringBuilder sb = new StringBuilder();
sb.append("[");
- sb.append(t);
- sb.append(", size: ");
if(null!=t) {
- SizeThunk st = t.getSize();
- if(null!=st) {
- sb.append(st.getClass().getName());
- } else {
- sb.append("undef");
- }
+ sb.append(t.getDebugString());
+ sb.append(", opaque ").append(isOpaque(t)).append("]");
+ } else {
+ sb.append("nil]");
}
- sb.append("]");
return sb.toString();
}
+ private boolean isOpaque(final Type type) {
+ return (cfg.typeInfo(type) != null);
+ }
private void debugPrintln(String msg) {
if(debug) {
@@ -236,14 +272,13 @@ options {
}
}
- private boolean doDeclaration; // Used to only process function typedefs
- private String declId;
- private List parameters;
+ private JavaConfiguration cfg;
private TypeDictionary typedefDictionary;
private TypeDictionary structDictionary;
private List<FunctionSymbol> functions = new ArrayList<FunctionSymbol>();
// hash from name of an enumerated value to the EnumType to which it belongs
private HashMap<String, EnumType> enumHash = new HashMap<String, EnumType>();
+ private HashMap<String, EnumType> enumMap = new HashMap<String, EnumType>();
// Storage class specifiers
private static final int AUTO = 1 << 0;
@@ -259,25 +294,36 @@ options {
private static final int SIGNED = 1 << 8;
private static final int UNSIGNED = 1 << 9;
- private void initDeclaration() {
- doDeclaration = false;
- declId = null;
- }
+ private boolean isFuncDeclaration; // Used to only process function typedefs
+ private String funcDeclName;
+ private List<ParameterDeclaration> funcDeclParams;
- private void doDeclaration() {
- doDeclaration = true;
+ private void resetFuncDeclaration() {
+ isFuncDeclaration = false;
+ funcDeclName = null;
+ funcDeclParams = null;
+ }
+ private void setFuncDeclaration(final String name, final List<ParameterDeclaration> p) {
+ isFuncDeclaration = true;
+ funcDeclName = name;
+ funcDeclParams = p;
}
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();
+ if (isFuncDeclaration) {
+ final FunctionSymbol sym = new FunctionSymbol(funcDeclName, new FunctionType(null, null, resolveAnonCompound(returnType), 0));
+ debugPrintln("Function ... "+sym.toString());
+ if (funcDeclParams != null) { // handle funcs w/ empty parameter lists (e.g., "foo()")
+ for (Iterator<ParameterDeclaration> iter = funcDeclParams.iterator(); iter.hasNext(); ) {
+ ParameterDeclaration pd = iter.next();
+ pd.setType(resolveAnonCompound(pd.type()));
+ debugPrintln(" add "+pd.toString());
sym.addArgument(pd.type(), pd.id());
}
- }
+ }
+ debugPrintln("Function Added "+sym.toString());
functions.add(sym);
+ resetFuncDeclaration();
}
}
@@ -305,8 +351,7 @@ options {
}
}
tb.setType(canonicalize(new PointerType(SizeThunk.POINTER,
- tb.type(),
- 0)));
+ tb.type(), 0, null)));
}
private int parseIntConstExpr(AST t) throws RecognitionException {
@@ -315,47 +360,49 @@ options {
/** 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) {
+ private EnumType getEnumType(String enumTypeName) {
EnumType enumType = null;
Iterator<EnumType> it = enumHash.values().iterator();
while (it.hasNext()) {
EnumType potentialMatch = it.next();
if (potentialMatch.getName().equals(enumTypeName)) {
- enumType = potentialMatch;
- break;
+ 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.
+ // 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.INT32);
}
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();
+ // Opaque canonical types are excluded.
+ private Map<Type, Type> canonMap = new HashMap<Type, Type>();
private Type canonicalize(Type t) {
Type res = (Type) canonMap.get(t);
if (res != null) {
return res;
+ } else {
+ canonMap.put(t, t);
+ return t;
}
- canonMap.put(t, t);
- return t;
}
}
declarator[TypeBox tb] returns [String s] {
- initDeclaration();
+ resetFuncDeclaration();
s = null;
- List params = null;
+ List<ParameterDeclaration> params = null;
String funcPointerName = null;
TypeBox dummyTypeBox = null;
}
@@ -374,28 +421,25 @@ declarator[TypeBox tb] returns [String s] {
RPAREN
) {
if (id != null) {
- declId = id.getText();
- parameters = params; // FIXME: Ken, why are we setting this class member here?
- doDeclaration();
+ setFuncDeclaration(id.getText(), params);
} 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
+ // 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());
- }
+ // 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)));
+ ft, 0, null)));
s = funcPointerName;
}
}
@@ -422,8 +466,8 @@ declaration {
) { processDeclaration(tb.type()); }
;
-parameterTypeList returns [List l] { l = new ArrayList(); ParameterDeclaration decl = null; }
- : ( decl = parameterDeclaration { if (decl != null) l.add(decl); } ( COMMA | SEMI )? )+ ( VARARGS )?
+parameterTypeList returns [List<ParameterDeclaration> l] { l = new ArrayList<ParameterDeclaration>(); ParameterDeclaration decl = null; }
+ : ( decl = parameterDeclaration { if (decl != null) { l.add(decl); } } ( COMMA | SEMI )? )+ ( VARARGS )?
;
parameterDeclaration returns [ParameterDeclaration pd] {
@@ -533,9 +577,12 @@ typeSpecifier[int attributes] returns [Type t] {
typedefName[int cvAttrs] returns [Type t] { t = null; }
: #(NTypedefName id : ID)
{
- Type tdict = lookupInTypedefDictionary(id.getText());
- t = canonicalize(tdict.getCVVariant(cvAttrs));
- debugPrintln("Adding typedef canon : [" + id.getText() + "] -> [" + tdict + "] -> "+getTypeString(t));
+ final Type t0 = lookupInTypedefDictionary(id.getText());
+ debugPrint("Adding typedef lookup: [" + id.getText() + "] -> "+getDebugTypeString(t0));
+ final Type t1 = t0.getCVVariant(cvAttrs);
+ debugPrintln(" - cvvar -> "+getDebugTypeString(t1));
+ t = canonicalize(t1);
+ debugPrintln(" - canon -> "+getDebugTypeString(t));
}
;
@@ -549,25 +596,35 @@ unionSpecifier[int cvAttrs] returns [Type t] { t = null; }
structOrUnionBody[CompoundTypeKind kind, int cvAttrs] returns [CompoundType t] {
t = null;
+ boolean addedAny = false;
}
: ( (ID LCURLY) => id:ID LCURLY {
+ // fully declared struct, i.e. not anonymous
t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs));
- } ( structDeclarationList[t] )?
- RCURLY { t.setBodyParsed(); }
- | LCURLY { t = CompoundType.create(null, null, kind, cvAttrs); }
- ( structDeclarationList[t] )?
- RCURLY { t.setBodyParsed(); }
- | id2:ID { t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs)); }
+ } ( addedAny = structDeclarationList[t] )?
+ RCURLY { t.setBodyParsed(addedAny); }
+ | LCURLY {
+ // anonymous declared struct
+ t = CompoundType.create(null, null, kind, cvAttrs);
+ } ( structDeclarationList[t] )?
+ RCURLY { t.setBodyParsed(false); }
+ | id2:ID {
+ // anonymous struct
+ t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs));
+ }
)
;
-structDeclarationList[CompoundType t]
- : ( structDeclaration[t] )+
+structDeclarationList[CompoundType t] returns [boolean addedAny] {
+ addedAny = false;
+ boolean addedOne = false;
+}
+ : ( addedOne = structDeclaration[t] { addedAny |= addedOne; } )+
;
-structDeclaration[CompoundType containingType] {
+structDeclaration[CompoundType containingType] returns [boolean addedAny] {
+ addedAny = false;
Type t = null;
- boolean addedAny = false;
}
: t = specifierQualifierList addedAny = structDeclaratorList[containingType, t] {
if (!addedAny) {
@@ -629,13 +686,28 @@ structDeclarator[CompoundType containingType, Type t] returns [boolean addedAny]
// "enumName" *before* executing the enumList rule.
enumSpecifier [int cvAttrs] returns [Type t] {
t = null;
+ EnumType e = 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()); }
- )
- )
+ ( ( ID LCURLY )=> i:ID LCURLY enumList[(EnumType)(e = getEnumType(i.getText()))] RCURLY
+ | LCURLY enumList[(EnumType)(e = getEnumType(ANONYMOUS_ENUM_NAME))] RCURLY
+ | ID { e = getEnumType(i.getText()); }
+ ) {
+ debugPrintln("Adding enum mapping: "+getDebugTypeString(e));
+ if( null != e ) {
+ final String eName = e.getName();
+ if( null != eName && !eName.equals(ANONYMOUS_ENUM_NAME) ) { // validate only non-anonymous enum
+ final EnumType dupE = enumMap.get(eName);
+ if( null != dupE && !dupE.equalSemantics(e) ) {
+ throw new RuntimeException(String.format("Duplicate enum w/ incompatible type:%n have '%s',%n this '%s'",
+ getTypeString(dupE), getTypeString(e)));
+ }
+ enumMap.put(eName, (EnumType)e.clone());
+ }
+ }
+ t = e; // return val
+ }
+ )
;
enumList[EnumType enumeration] {
@@ -648,42 +720,42 @@ enumerator[EnumType enumeration, long defaultValue] returns [long newDefaultValu
newDefaultValue = defaultValue;
}
: eName:ID ( ASSIGN eVal:expr )? {
- long value = 0;
+ final long newValue;
if (eVal != null) {
String vTxt = eVal.getAllChildrenText();
if (enumHash.containsKey(vTxt)) {
EnumType oldEnumType = enumHash.get(vTxt);
- value = oldEnumType.getEnumValue(vTxt);
+ newValue = oldEnumType.getEnumValue(vTxt);
} else {
try {
- value = Long.decode(vTxt).longValue();
+ newValue = Long.decode(vTxt).longValue();
} catch (NumberFormatException e) {
System.err.println("NumberFormatException: ID[" + eName.getText() + "], VALUE=[" + vTxt + "]");
throw e;
}
}
} else {
- value = defaultValue;
+ newValue = defaultValue;
}
- newDefaultValue = value+1;
- String eTxt = eName.getText();
- if (enumHash.containsKey(eTxt)) {
- EnumType oldEnumType = 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);
- debugPrintln("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + enumeration.getEnumValue(eTxt) +
- " (new default = " + newDefaultValue + ")");
- }
+ newDefaultValue = newValue+1;
+ String eTxt = eName.getText();
+ if (enumHash.containsKey(eTxt)) {
+ EnumType oldEnumType = enumHash.get(eTxt);
+ final long oldValue = oldEnumType.getEnumValue(eTxt);
+ if( oldValue != newValue ) {
+ throw new RuntimeException(String.format("Duplicate enum value '%s.%s' w/ diff value:%n have %d,%n this %d",
+ oldEnumType.getName(), eTxt, oldValue, newValue));
+ }
+ // remove old definition
+ oldEnumType.removeEnumerate(eTxt);
+ }
+ // insert new definition
+ enumeration.addEnum(eTxt, newValue);
+ enumHash.put(eTxt, enumeration);
+ debugPrintln("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + enumeration.getEnumValue(eTxt) +
+ " (new default = " + newDefaultValue + ")");
+ }
;
initDeclList[TypeBox tb]
@@ -705,18 +777,48 @@ initDecl[TypeBox tb] {
{
if ((declName != null) && (tb != null) && tb.isTypedef()) {
Type t = tb.type();
- debugPrint("Adding typedef mapping: [" + declName + "] -> "+getTypeString(t));
+ debugPrint("Adding typedef mapping: [" + declName + "] -> "+getDebugTypeString(t));
if (!t.hasTypedefName()) {
- t.setName(declName);
- debugPrint(" - declName -> "+getTypeString(t));
+ if( t.isCompound() ) {
+ // Allow redefinition of newly defined struct, i.e. use same instance.
+ // This aliases '_a' -> 'A' for 'typedef struct _a { } A, *B;', where '*B' will become also '*A'.
+ t.setTypedefName(declName);
+ debugPrint(" - redefine -> "+getDebugTypeString(t));
+ } else {
+ // Use new typedef, using a copy to preserve canonicalized base type
+ t = (Type) t.clone();
+ t.setTypedefName(declName);
+ debugPrint(" - newdefine -> "+getDebugTypeString(t));
+ }
} else {
- // copy type to preserve declName !
- t = (Type) t.clone();
- t.setName(declName);
- debugPrint(" - copy -> "+getTypeString(t));
+ // Adds typeInfo alias w/ t's typeInfo, if exists
+ cfg.addTypeInfo(declName, t);
+ final Type alias;
+ if( t.isCompound() ) {
+ // Attempt to find a previous declared compound typedef
+ // This aliases 'D' -> 'A' for 'typedef struct _a { } A, D;'
+ alias = typedefDictionary.getEqualSemantics1(t, cfg, true);
+ } else {
+ alias = null;
+ }
+ if( null != alias ) {
+ // use previous typedef
+ t = alias;
+ debugPrint(" - alias -> "+getDebugTypeString(t));
+ } else {
+ // copy to preserve canonicalized base type
+ t = (Type) t.clone();
+ t.setTypedefName(declName);
+ debugPrint(" - copy -> "+getDebugTypeString(t));
+ }
+ }
+ final Type dupT = typedefDictionary.get(declName);
+ if( null != dupT && !dupT.equalSemantics(t) ) {
+ throw new RuntimeException(String.format("Duplicate typedef w/ incompatible type:%n have '%s',%n this '%s'",
+ getTypeString(dupT), getTypeString(t)));
}
t = canonicalize(t);
- debugPrintln(" - canon -> "+getTypeString(t));
+ debugPrintln(" - canon -> "+getDebugTypeString(t));
typedefDictionary.put(declName, t);
// Clear out PointerGroup effects in case another typedef variant follows
tb.reset();
@@ -731,7 +833,7 @@ pointerGroup[TypeBox tb] { int x = 0; int y = 0; }
if (tb != null) {
tb.setType(canonicalize(new PointerType(SizeThunk.POINTER,
tb.type(),
- attrs2CVAttrs(x))));
+ attrs2CVAttrs(x), null)));
}
}
)+ )