diff options
Diffstat (limited to 'src/antlr/com/jogamp/gluegen')
-rw-r--r-- | src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g | 3 | ||||
-rw-r--r-- | src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g | 577 | ||||
-rw-r--r-- | src/antlr/com/jogamp/gluegen/cgram/StdCParser.g | 15 | ||||
-rw-r--r-- | src/antlr/com/jogamp/gluegen/jgram/JavaParser.g | 1509 |
4 files changed, 1177 insertions, 927 deletions
diff --git a/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g b/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g index e8ca8c5..bf01b12 100644 --- a/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g +++ b/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g @@ -23,6 +23,7 @@ header { import antlr.CommonAST; import antlr.DumpASTVisitor; + import com.jogamp.gluegen.ASTLocusTag; } @@ -715,7 +716,7 @@ tokens { public void addDefine(String name, String value) { - defines.add(new Define(name, value)); + defines.add(new Define(name, value, new ASTLocusTag(lineObject.getSource(), lineObject.getLine()+deferredLineCount, -1, name))); } /** Returns a list of Define objects corresponding to the diff --git a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g index 01f10c3..59eaca3 100644 --- a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g +++ b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g @@ -45,7 +45,14 @@ header { import java.util.*; import antlr.CommonAST; + import com.jogamp.gluegen.ASTLocusTag; + import com.jogamp.gluegen.ConstantDefinition; + import com.jogamp.gluegen.ConstantDefinition.CNumber; + import com.jogamp.gluegen.GlueGenException; + import com.jogamp.gluegen.JavaConfiguration; import com.jogamp.gluegen.cgram.types.*; + import com.jogamp.gluegen.cgram.types.EnumType; + import com.jogamp.gluegen.cgram.types.EnumType.Enumerator; } class HeaderParser extends GnuCTreeParser; @@ -67,6 +74,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 +118,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,22 +138,25 @@ options { return functions; } - private CompoundType lookupInStructDictionary(String typeName, + private CompoundType lookupInStructDictionary(String structName, CompoundTypeKind kind, - int cvAttrs) { - CompoundType t = (CompoundType) structDictionary.get(typeName); + int cvAttrs, final ASTLocusTag locusTag) + { + 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, locusTag); + structDictionary.put(structName, t); + debugPrintln("Adding compound mapping: [" + structName + "] -> "+getDebugTypeString(t)+" @ "+locusTag); + debugPrintln(t.getStructString()); } return t; } - private Type lookupInTypedefDictionary(String typeName) { + private Type lookupInTypedefDictionary(final AST _t, String typeName) { Type t = typedefDictionary.get(typeName); if (t == null) { - throw new RuntimeException("Undefined reference to typedef name " + typeName); + throwGlueGenException(_t, + "Undefined reference to typedef name " + typeName); } return t; } @@ -153,8 +169,10 @@ 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()+"]"; } } // A box for a Type. Allows type to be passed down to be modified by recursive rules. @@ -207,22 +225,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 +259,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 +281,41 @@ 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 ASTLocusTag funcLocusTag; - private void doDeclaration() { - doDeclaration = true; + private void resetFuncDeclaration() { + isFuncDeclaration = false; + funcDeclName = null; + funcDeclParams = null; + funcLocusTag = null; + } + private void setFuncDeclaration(final String name, final List<ParameterDeclaration> p, final ASTLocusTag locusTag) { + isFuncDeclaration = true; + funcDeclName = name; + funcDeclParams = p; + funcLocusTag = locusTag; } 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, returnType, 0, funcLocusTag), + funcLocusTag); + debugPrintln("Function ... "+sym.toString()+" @ "+funcLocusTag); + 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(pd.type()); + debugPrintln(" add "+pd.toString()); sym.addArgument(pd.type(), pd.id()); } - } + } + debugPrintln("Function Added "+sym.toString()); functions.add(sym); + resetFuncDeclaration(); } } @@ -294,19 +332,18 @@ options { /** Helper routine which handles creating a pointer or array type for [] expressions */ - private void handleArrayExpr(TypeBox tb, AST t) { + private void handleArrayExpr(TypeBox tb, AST t, ASTLocusTag locusTag) { if (t != null) { try { final int len = parseIntConstExpr(t); - tb.setType(canonicalize(new ArrayType(tb.type(), SizeThunk.mul(SizeThunk.constant(len), tb.type().getSize()), len, 0))); + tb.setType(canonicalize(new ArrayType(tb.type(), SizeThunk.mul(SizeThunk.constant(len), tb.type().getSize()), len, 0, locusTag))); return; } catch (RecognitionException e) { // Fall through } } tb.setType(canonicalize(new PointerType(SizeThunk.POINTER, - tb.type(), - 0))); + tb.type(), 0, locusTag))); } private int parseIntConstExpr(AST t) throws RecognitionException { @@ -315,49 +352,104 @@ 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, ASTLocusTag locusTag) { 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. - enumType = new EnumType(enumTypeName, SizeThunk.INT32); + // 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, locusTag); } 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; + } + } + + private void throwGlueGenException(final AST t, final String message) throws GlueGenException { + // dumpASTTree("XXX", t); + throw new GlueGenException(message, findASTLocusTag(t)); + } + private void throwGlueGenException(final ASTLocusTag locusTag, final String message) throws GlueGenException { + // dumpASTTree("XXX", t); + throw new GlueGenException(message, locusTag); + } + + /** + * Return ASTLocusTag in tree, or null if not found. + */ + private ASTLocusTag findASTLocusTag(final AST astIn) { + AST ast = astIn; + while(null != ast) { + if( ast instanceof TNode ) { + final TNode tn = (TNode) ast; + final ASTLocusTag tag = tn.getASTLocusTag(); + if( null != tag ) { + return tag; + } + } + ast = ast.getFirstChild(); + } + return null; + } + private void dumpASTTree(final String pre, final AST t) { + int i=0; + AST it = t; + while( null != it ) { + it = dumpAST(pre+"."+i, it); + i++; + } + } + private AST dumpAST(final String pre, final AST ast) { + if( null == ast ) { + System.err.println(pre+".0: AST NULL"); + return null; + } else { + System.err.println(pre+".0: AST Type: "+ast.getClass().getName()); + System.err.println(pre+".1: line:col "+ast.getLine()+":"+ast.getColumn()+" -> "+ast.getText()); + if( ast instanceof TNode ) { + final TNode tn = (TNode) ast; + final ASTLocusTag tag = tn.getASTLocusTag(); + System.err.println(pre+".TN.1: "+tag); + final Hashtable<String, Object> attributes = tn.getAttributesTable(); + System.err.println(pre+".TN.2: "+attributes); + } + return ast.getFirstChild(); } - 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; + final ASTLocusTag locusTag = findASTLocusTag(declarator_AST_in); } : #( NDeclarator ( pointerGroup[tb] )? @@ -374,32 +466,29 @@ 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, locusTag); } else if ( funcPointerName != null ) { /* TypeBox becomes function pointer in this case */ - FunctionType ft = new FunctionType(null, null, tb.type(), 0); + final FunctionType ft = new FunctionType(null, null, tb.type(), 0, locusTag); 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, locusTag), "/*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, locusTag))); s = funcPointerName; } } - | LBRACKET ( e:expr )? RBRACKET { handleArrayExpr(tb, e); } + | LBRACKET ( e:expr )? RBRACKET { handleArrayExpr(tb, e, locusTag); } )* ) ; @@ -422,8 +511,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] { @@ -435,7 +524,13 @@ parameterDeclaration returns [ParameterDeclaration pd] { : #( NParameterDeclaration tb = declSpecifiers (decl = declarator[tb] | nonemptyAbstractDeclarator[tb])? - ) { pd = new ParameterDeclaration(decl, tb.type()); } + ) { + if( null == tb ) { + throwGlueGenException(parameterDeclaration_AST_in, + String.format("Undefined type for declaration '%s'", decl)); + } + pd = new ParameterDeclaration(decl, tb.type()); + } ; functionDef { @@ -462,7 +557,10 @@ declSpecifiers returns [TypeBox tb] { { if (t == null && (x & (SIGNED | UNSIGNED)) != 0) { - t = new IntType("int", SizeThunk.INTxx, ((x & UNSIGNED) != 0), attrs2CVAttrs(x)); + t = new IntType("int", SizeThunk.INTxx, + ((x & UNSIGNED) != 0), + attrs2CVAttrs(x), + findASTLocusTag(declSpecifiers_AST_in)); } tb = new TypeBox(t, ((x & TYPEDEF) != 0)); } @@ -493,30 +591,35 @@ typeQualifier returns [int x] { x = 0; } typeSpecifier[int attributes] returns [Type t] { t = null; int cvAttrs = attrs2CVAttrs(attributes); - boolean unsigned = ((attributes & UNSIGNED) != 0); + boolean unsig = ((attributes & UNSIGNED) != 0); + final ASTLocusTag locusTag = findASTLocusTag(typeSpecifier_AST_in); } - : "void" { t = new VoidType(cvAttrs); } - | "char" { t = new IntType("char" , SizeThunk.INT8, unsigned, cvAttrs); } - | "short" { t = new IntType("short", SizeThunk.INT16, unsigned, cvAttrs); } - | "int" { t = new IntType("int" , SizeThunk.INTxx, unsigned, cvAttrs); } - | "long" { t = new IntType("long" , SizeThunk.LONG, unsigned, cvAttrs); } - | "float" { t = new FloatType("float", SizeThunk.FLOAT, cvAttrs); } - | "double" { t = new DoubleType("double", SizeThunk.DOUBLE, cvAttrs); } - | "__int32" { t = new IntType("__int32", SizeThunk.INT32, unsigned, cvAttrs); } - | "__int64" { t = new IntType("__int64", SizeThunk.INT64, unsigned, cvAttrs); } - | "int8_t" { t = new IntType("int8_t", SizeThunk.INT8, false, cvAttrs); /* TS: always signed */ } - | "uint8_t" { t = new IntType("uint8_t", SizeThunk.INT8, true, cvAttrs); /* TS: always unsigned */ } - | "int16_t" { t = new IntType("int16_t", SizeThunk.INT16, false, cvAttrs); /* TS: always signed */ } - | "uint16_t" { t = new IntType("uint16_t", SizeThunk.INT16, true, cvAttrs); /* TS: always unsigned */ } - | "int32_t" { t = new IntType("int32_t", SizeThunk.INT32, false, cvAttrs); /* TS: always signed */ } - | "wchar_t" { t = new IntType("wchar_t", SizeThunk.INT32, false, cvAttrs); /* TS: always signed */ } - | "uint32_t" { t = new IntType("uint32_t", SizeThunk.INT32, true, cvAttrs, true); /* TS: always unsigned */ } - | "int64_t" { t = new IntType("int64_t", SizeThunk.INT64, false, cvAttrs); /* TS: always signed */ } - | "uint64_t" { t = new IntType("uint64_t", SizeThunk.INT64, true, cvAttrs, true); /* TS: always unsigned */ } - | "ptrdiff_t" { t = new IntType("ptrdiff_t", SizeThunk.POINTER, false, cvAttrs); /* TS: always signed */ } - | "intptr_t" { t = new IntType("intptr_t", SizeThunk.POINTER, false, cvAttrs); /* TS: always signed */ } - | "size_t" { t = new IntType("size_t", SizeThunk.POINTER, true, cvAttrs, true); /* TS: always unsigned */ } - | "uintptr_t" { t = new IntType("uintptr_t", SizeThunk.POINTER, true, cvAttrs, true); /* TS: always unsigned */ } + // TYPEDEF + // | TYPEDEF-UNSIGNED + // UNSIGNED | | + // TOKEN TYPE NAME SIZE | ATTRIBS | | LOCUS + : "void" { t = new VoidType( cvAttrs, locusTag); } + | "char" { t = new IntType("char" , SizeThunk.INT8, unsig, cvAttrs, false, false, locusTag); } + | "short" { t = new IntType("short", SizeThunk.INT16, unsig, cvAttrs, false, false, locusTag); } + | "int" { t = new IntType("int" , SizeThunk.INTxx, unsig, cvAttrs, false, false, locusTag); } + | "long" { t = new IntType("long" , SizeThunk.LONG, unsig, cvAttrs, false, false, locusTag); } + | "float" { t = new FloatType("float", SizeThunk.FLOAT, cvAttrs, locusTag); } + | "double" { t = new DoubleType("double", SizeThunk.DOUBLE, cvAttrs, locusTag); } + | "__int32" { t = new IntType("__int32", SizeThunk.INT32, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */ + | "__int64" { t = new IntType("__int64", SizeThunk.INT64, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */ + | "int8_t" { t = new IntType("int8_t", SizeThunk.INT8, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */ + | "uint8_t" { t = new IntType("uint8_t", SizeThunk.INT8, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */ + | "int16_t" { t = new IntType("int16_t", SizeThunk.INT16, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */ + | "uint16_t" { t = new IntType("uint16_t", SizeThunk.INT16, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */ + | "int32_t" { t = new IntType("int32_t", SizeThunk.INT32, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */ + | "wchar_t" { t = new IntType("wchar_t", SizeThunk.INT32, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */ + | "uint32_t" { t = new IntType("uint32_t", SizeThunk.INT32, unsig, cvAttrs, true, true, locusTag); } /* TS: unsigned */ + | "int64_t" { t = new IntType("int64_t", SizeThunk.INT64, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */ + | "uint64_t" { t = new IntType("uint64_t", SizeThunk.INT64, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */ + | "ptrdiff_t" { t = new IntType("ptrdiff_t", SizeThunk.POINTER, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */ + | "intptr_t" { t = new IntType("intptr_t", SizeThunk.POINTER, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */ + | "size_t" { t = new IntType("size_t", SizeThunk.POINTER, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */ + | "uintptr_t" { t = new IntType("uintptr_t", SizeThunk.POINTER, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */ | t = structSpecifier[cvAttrs] ( attributeDecl )* | t = unionSpecifier [cvAttrs] ( attributeDecl )* | t = enumSpecifier [cvAttrs] @@ -533,9 +636,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(typedefName_AST_in, id.getText()); + debugPrint("Adding typedef lookup: [" + id.getText() + "] -> "+getDebugTypeString(t0)); + final Type t1 = t0.newCVVariant(cvAttrs); + debugPrintln(" - cvvar -> "+getDebugTypeString(t1)); + t = canonicalize(t1); + debugPrintln(" - canon -> "+getDebugTypeString(t)); } ; @@ -549,31 +655,50 @@ unionSpecifier[int cvAttrs] returns [Type t] { t = null; } structOrUnionBody[CompoundTypeKind kind, int cvAttrs] returns [CompoundType t] { t = null; + boolean addedAny = false; + final ASTLocusTag locusTag = findASTLocusTag(structOrUnionBody_AST_in); } : ( (ID LCURLY) => id:ID LCURLY { - t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs)); - } ( structDeclarationList[t] )? + // fully declared struct, i.e. not anonymous + t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs, locusTag)); + } ( addedAny = structDeclarationList[t] )? RCURLY { t.setBodyParsed(); } - | LCURLY { t = CompoundType.create(null, null, kind, cvAttrs); } - ( structDeclarationList[t] )? + | LCURLY { + // anonymous declared struct + t = CompoundType.create(null, null, kind, cvAttrs, locusTag); + } ( structDeclarationList[t] )? RCURLY { t.setBodyParsed(); } - | id2:ID { t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs)); } - ) + | id2:ID { + // anonymous struct + t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs, locusTag)); + } + ) { + debugPrintln("Adding compound body: [" + t.getName() + "] -> "+getDebugTypeString(t)+" @ "+locusTag); + debugPrintln(t.getStructString()); + } ; -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) { if (t != null) { CompoundType ct = t.asCompound(); - if (ct.isUnion()) { + if( null == ct ) { + throwGlueGenException(structDeclaration_AST_in, + String.format("Anonymous compound, w/ NULL type:%n containing '%s'", + getTypeString(containingType))); + } + if ( ct.isUnion() ) { // Anonymous union containingType.addField(new Field(null, t, null)); } @@ -591,7 +716,8 @@ specifierQualifierList returns [Type t] { )+ { if (t == null && (x & (SIGNED | UNSIGNED)) != 0) { - t = new IntType("int", SizeThunk.INTxx, ((x & UNSIGNED) != 0), attrs2CVAttrs(x)); + t = new IntType("int", SizeThunk.INTxx, ((x & UNSIGNED) != 0), attrs2CVAttrs(x), + findASTLocusTag(specifierQualifierList_AST_in)); } } ; @@ -616,7 +742,7 @@ structDeclarator[CompoundType containingType, Type t] returns [boolean addedAny] ) ; -// FIXME: this will not correctly set the name of the enumeration when +// This will not correctly set the name of the enumeration when // encountering a declaration like this: // // typedef enum { } enumName; @@ -625,65 +751,88 @@ structDeclarator[CompoundType containingType, Type t] returns [boolean addedAny] // 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. +// The followup typedef, see 'initDecl', will alias this name, +// hence correct the issue! enumSpecifier [int cvAttrs] returns [Type t] { t = null; + EnumType e = null; + ASTLocusTag locusTag = findASTLocusTag(enumSpecifier_AST_in); } : #( "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(), locusTag))] RCURLY + | LCURLY enumList[(EnumType)(e = getEnumType(ANONYMOUS_ENUM_NAME, locusTag))] RCURLY + | ID { e = getEnumType(i.getText(), locusTag); } + ) { + 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) ) { + throwGlueGenException(enumSpecifier_AST_in, + String.format("Duplicate enum w/ incompatible type:%n this '%s',%n have '%s',%n %s: previous definition is here", + getTypeString(e), getTypeString(dupE), dupE.getASTLocusTag().toString(new StringBuilder(), "note", true))); + } + enumMap.put(eName, (EnumType)e.clone(locusTag)); + } + } + t = e; // return val + } + ) ; enumList[EnumType enumeration] { - long defaultEnumerantValue = 0; + ConstantDefinition defEnumerant = new ConstantDefinition("def", "0", new CNumber(true, false, 0), findASTLocusTag(enumList_AST_in)); } - : ( defaultEnumerantValue = enumerator[enumeration, defaultEnumerantValue] )+ + : ( defEnumerant = enumerator[enumeration, defEnumerant] )+ ; -enumerator[EnumType enumeration, long defaultValue] returns [long newDefaultValue] { +enumerator[EnumType enumeration, ConstantDefinition defaultValue] returns [ConstantDefinition newDefaultValue] { newDefaultValue = defaultValue; } : eName:ID ( ASSIGN eVal:expr )? { - long value = 0; + final String eTxt = eName.getText(); + final Enumerator newEnum; if (eVal != null) { - String vTxt = eVal.getAllChildrenText(); + String vTxt = eVal.getAllChildrenText(eTxt); if (enumHash.containsKey(vTxt)) { EnumType oldEnumType = enumHash.get(vTxt); - value = oldEnumType.getEnumValue(vTxt); + Enumerator oldEnum = oldEnumType.getEnum(vTxt); + newEnum = oldEnum; } else { - try { - value = Long.decode(vTxt).longValue(); - } catch (NumberFormatException e) { - System.err.println("NumberFormatException: ID[" + eName.getText() + "], VALUE=[" + vTxt + "]"); - throw e; - } + newEnum = new Enumerator(eTxt, vTxt); } + } else if( defaultValue.hasNumber() ) { + newEnum = new Enumerator(eTxt, defaultValue.getNumber()); } else { - value = defaultValue; + newEnum = new Enumerator(eTxt, defaultValue.getNativeExpr()); } - - 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 + ")"); - } + final ASTLocusTag locus = findASTLocusTag(enumerator_AST_in); + final CNumber newEnumNum = newEnum.getNumber(); + if( null != newEnumNum && newEnumNum.isInteger ) { + final long n = newEnumNum.i+1; + newDefaultValue = new ConstantDefinition("def", String.valueOf(n), new CNumber(newEnumNum.isLong, newEnumNum.isUnsigned, n), locus); + } else { + newDefaultValue = new ConstantDefinition("def", "("+newEnum.getExpr()+")+1", null, locus); + } + if (enumHash.containsKey(eTxt)) { + EnumType oldEnumType = enumHash.get(eTxt); + final Enumerator oldEnum = oldEnumType.getEnum(eTxt); + final String oldExpr = oldEnum.getExpr(); + if( !oldExpr.equals(newEnum.getExpr()) ) { + throwGlueGenException(enumerator_AST_in, + String.format("Duplicate enum value '%s.%s' w/ diff value:%n this %s,%n have %s", + oldEnumType.getName(), eTxt, newEnum, oldEnum)); + } + // remove old definition + oldEnumType.removeEnumerate(eTxt); + } + // insert new definition + enumeration.addEnum(eTxt, newEnum); + enumHash.put(eTxt, enumeration); + debugPrintln("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + newEnum + + " (new default = " + newDefaultValue + ")"); + } ; initDeclList[TypeBox tb] @@ -692,6 +841,7 @@ initDeclList[TypeBox tb] initDecl[TypeBox tb] { String declName = null; + final ASTLocusTag locusTag = findASTLocusTag(initDecl_AST_in); } : #( NInitDecl declName = declarator[tb] { @@ -705,23 +855,99 @@ initDecl[TypeBox tb] { { if ((declName != null) && (tb != null) && tb.isTypedef()) { Type t = tb.type(); - debugPrint("Adding typedef mapping: [" + declName + "] -> "+getTypeString(t)); - if (!t.hasTypedefName()) { - t.setName(declName); - debugPrint(" - declName -> "+getTypeString(t)); + debugPrintln("Adding typedef mapping: [" + declName + "] -> "+getDebugTypeString(t)); + final Type tg; + if( t.isPointer() ) { + tg = t.getTargetType(); + debugPrintln(" - has target: "+getDebugTypeString(tg)); } else { - // copy type to preserve declName ! - t = (Type) t.clone(); - t.setName(declName); - debugPrint(" - copy -> "+getTypeString(t)); + tg = null; + } + // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser) + // Also see NOTE below. + if (!t.isTypedef()) { + if( t.isCompound() || t.isEnum() ) { + // This aliases '_a' -> 'A' for 'typedef struct _a { } A;' in-place + // This aliases '_a' -> 'A' for 'typedef enum _a { } A;' in-place + t.setTypedefName(declName); + debugPrintln(" - alias.11 -> "+getDebugTypeString(t)); + } else { + // Use new typedef, using a copy to preserve canonicalized base type + t = t.clone(locusTag); + t.setTypedefName(declName); + debugPrintln(" - newdefine.12 -> "+getDebugTypeString(t)); + } + } else { + // Adds typeInfo alias w/ t's typeInfo, if exists + cfg.addTypeInfo(declName, t); + final Type alias; + if( t.isCompound() ) { + // This aliases 'D' -> 'A' for 'typedef struct _a { } A, D;' in-place + debugPrintln(" - alias.21 -> "+getDebugTypeString(t)); + } else { + // copy to preserve canonicalized base type + t = t.clone(locusTag); + t.setTypedefName(declName); + debugPrintln(" - copy.22 -> "+getDebugTypeString(t)); + } + } + final Type dupT = typedefDictionary.get(declName); + if( null != dupT && !dupT.equalSemantics(t) ) { + throwGlueGenException(locusTag, + String.format("Duplicate typedef w/ incompatible type:%n this '%s',%n have '%s',%n %s: previous definition is here", + getTypeString(t), getTypeString(dupT), dupT.getASTLocusTag().toString(new StringBuilder(), "note", true))); } 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(); } } + /* + // Below just shows a different handling using copying + // and enforcing aliased names, which is not desired. + // Keeping it in here for documentation. + // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser) + if ( !t.isTypedef() ) { + if( t.isCompound() ) { + // This aliases '_a' -> 'A' for 'typedef struct _a { } A;' + t.setTypedefName(declName); + debugPrintln(" - alias.10 -> "+getDebugTypeString(t)); + } else if( null != tg && tg.isCompound() ) { + if( !tg.isTypedef() ) { + // This aliases '_a *' -> 'A*' for 'typedef struct _a { } *A;' + t.setTypedefName(declName); + debugPrintln(" - alias.11 -> "+getDebugTypeString(t)); + } else { + // This aliases 'B' -> 'A*' for 'typedef struct _a { } A, *B;' and 'typedef A * B;' + t = new PointerType(SizeThunk.POINTER, tg, 0, locusTag); // name: 'A*' + t.setTypedefName(t.getName()); // make typedef + debugPrintln(" - alias.12 -> "+getDebugTypeString(t)); + } + } else { + // Use new typedef, using a copy to preserve canonicalized base type + t = t.clone(locusTag); + t.setTypedefName(declName); + debugPrintln(" - newdefine.13 -> "+getDebugTypeString(t)); + } + } else { + // Adds typeInfo alias w/ t's typeInfo, if exists + cfg.addTypeInfo(declName, t); + if( t.isCompound() ) { + // This aliases 'D' -> 'A' for 'typedef struct _a { } A, D;' + debugPrintln(" - alias.20 -> "+getDebugTypeString(t)); + } else if( null != tg && tg.isCompound() ) { + // This aliases 'B' -> 'A' for 'typedef A B;', where A is pointer to compound + debugPrintln(" - alias.21 -> "+getDebugTypeString(t)); + } else { + // copy to preserve canonicalized base type + t = t.clone(locusTag); + t.setTypedefName(declName); + debugPrintln(" - copy.22 -> "+getDebugTypeString(t)); + } + } +*/ ; pointerGroup[TypeBox tb] { int x = 0; int y = 0; } @@ -731,7 +957,8 @@ 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), + findASTLocusTag(pointerGroup_AST_in)))); } } )+ ) @@ -756,7 +983,9 @@ typeName { /* 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] +nonemptyAbstractDeclarator[TypeBox tb] { + final ASTLocusTag locusTag = findASTLocusTag(nonemptyAbstractDeclarator_AST_in); +} : #( NNonemptyAbstractDeclarator ( pointerGroup[tb] ( (LPAREN @@ -764,7 +993,7 @@ nonemptyAbstractDeclarator[TypeBox tb] | parameterTypeList )? RPAREN) - | (LBRACKET (e1:expr)? RBRACKET) { handleArrayExpr(tb, e1); } + | (LBRACKET (e1:expr)? RBRACKET) { handleArrayExpr(tb, e1, locusTag); } )* | ( (LPAREN @@ -772,7 +1001,7 @@ nonemptyAbstractDeclarator[TypeBox tb] | parameterTypeList )? RPAREN) - | (LBRACKET (e2:expr)? RBRACKET) { handleArrayExpr(tb, e2); } + | (LBRACKET (e2:expr)? RBRACKET) { handleArrayExpr(tb, e2, locusTag); } )+ ) ) @@ -786,13 +1015,17 @@ intConstExpr returns [int i] { i = -1; } final String enumName = e.getText(); final EnumType enumType = enumHash.get(enumName); if( null == enumType ) { - throw new IllegalArgumentException("Error: intConstExpr ID "+enumName+" recognized, but no containing enum-type found"); + throwGlueGenException(intConstExpr_AST_in, + "Error: intConstExpr ID "+enumName+" recognized, but no containing enum-type found"); } - final long enumValue = enumType.getEnumValue(enumName); - System.err.println("INFO: intConstExpr: enum[Type "+enumType.getName()+", name "+enumName+", value "+enumValue+"]"); - if( (long)Integer.MIN_VALUE > enumValue || (long)Integer.MAX_VALUE < enumValue ) { - throw new IndexOutOfBoundsException("Error: intConstExpr ID "+enumName+" enum-value "+enumValue+" out of int range"); + final Enumerator enumerator = enumType.getEnum(enumName); + final CNumber number = enumerator.getNumber(); + if( null != number && number.isInteger && !number.isLong ) { + debugPrintln("INFO: intConstExpr: enum[Type "+enumType.getName()+", "+enumerator+"]"); + } else { + throwGlueGenException(intConstExpr_AST_in, + "Error: intConstExpr ID "+enumName+" enum "+enumerator+" not an int32_t"); } - return (int)enumValue; + return (int)number.i; } ; diff --git a/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g b/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g index 7b34656..26da996 100644 --- a/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g +++ b/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g @@ -1131,11 +1131,12 @@ options { nw:NonWhitespace ("\r\n" | "\r" | "\n") ) { if (n != null) { - //System.out.println("addDefine: #define " + i.getText() + " " + n.getText()); + // System.out.println("addDefine: #define " + i.getText() + " " + n.getText()+" @ "+lineObject.getSource()+":"+(lineObject.line+deferredLineCount)); addDefine(i.getText(), n.getText()); } else { setPreprocessingDirective("#define " + i.getText() + " " + nw.getText()); } + deferredNewline(); } | (~'\n')* { setPreprocessingDirective(getText()); } ) @@ -1165,15 +1166,19 @@ protected LineDirective } : { - lineObject = new LineObject(); - deferredLineCount = 0; + 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())); } + n:Number { + lineObject.setLine(Integer.parseInt(n.getText())); + } (Space)+ ( fn:StringLiteral { try { - lineObject.setSource(fn.getText().substring(1,fn.getText().length()-1)); + final String newSource = fn.getText().substring(1,fn.getText().length()-1); + // System.out.println("line: "+lineObject.getSource()+" -> "+newSource+", line "+(lineObject.line+deferredLineCount)); + lineObject.setSource(newSource); } catch (StringIndexOutOfBoundsException e) { /*not possible*/ } } diff --git a/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g b/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g index f67579e..1c06bfd 100644 --- a/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g +++ b/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g @@ -8,105 +8,105 @@ * 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] + * 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] + * 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) + * 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 + * 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 + * 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). + * 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. + * 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 + * 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. + * 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: {} + * 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. + * 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. + * 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: + * 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. + * 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. + * 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. + * 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 + * 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. @@ -129,24 +129,24 @@ header { 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; + 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; + 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; } { @@ -181,250 +181,250 @@ tokens { // 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 */ - ) + : // A compilation unit starts with an optional package definition + ( packageDefinition + | /* nothing */ + ) - // Next we have a series of zero or more import statements - ( importDefinition )* + // Next we have a series of zero or more import statements + ( importDefinition )* - // Wrapping things up with any number of class or interface - // definitions - ( typeDefinition )* + // Wrapping things up with any number of class or interface + // definitions + ( typeDefinition )* - EOF! - ; + EOF! + ; // Package statement: "package" followed by an identifier. packageDefinition - options {defaultErrorHandler = true;} // let ANTLR handle errors - : p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI! - ; + 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! - ; + 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! - ; + 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;} - ; + : 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] - ; + : 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); - } - } - ; + : 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); - } - } - ; + : 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 - ; + : identifier + | builtInType + ; // The primitive types. builtInType - : "void" - | "boolean" - | "byte" - | "char" - | "short" - | "int" - | "float" - | "long" - | "double" - ; + : "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 )* - ; + : IDENT ( DOT^ IDENT )* + ; identifierStar - : IDENT - ( DOT^ IDENT )* - ( DOT^ STAR )? - ; + : 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);} - ; + : ( 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" - ; + : "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);} - ; + : "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);} - ; + : ( "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);} - ; + : "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);} - ; + : 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);} - ; + : ( + 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);} - ; + : ( + 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);} + : // 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;} + | cd:classDefinition[#mods] // inner class + {#field = #cd;} - | id:interfaceDefinition[#mods] // inner interface - {#field = #id;} + | id:interfaceDefinition[#mods] // inner interface + {#field = #id;} - | t:typeSpec[false] // method or variable declaration(s) - ( fn:IDENT // the name of the method + | t:typeSpec[false] // method or variable declaration(s) + ( fn:IDENT // the name of the method - // parse the formal parameter declarations. - LPAREN! param:parameterDeclarationList RPAREN! + // parse the formal parameter declarations. + LPAREN! param:parameterDeclarationList RPAREN! - rt:declaratorBrackets[#t] + rt:declaratorBrackets[#t] - // get the list of exceptions that this method is - // declared to throw - (tc:throwsClause)? + // 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); + ( 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;} - ) - ) + | 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);} + | "static" s3:compoundStatement + {#field = #(#[STATIC_INIT,"STATIC_INIT"], s3);} // "{ ... }" instance initializer - | s4:compoundStatement - {#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);} - ; + | s4:compoundStatement + {#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);} + ; constructorBody : lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; } @@ -436,108 +436,108 @@ constructorBody /** Catch obvious constructor calls, but not the expr.super(...) calls */ explicitConstructorInvocation : "this"! lp1:LPAREN^ argList RPAREN! SEMI! - {#lp1.setType(CTOR_CALL);} + {#lp1.setType(CTOR_CALL);} | "super"! lp2:LPAREN^ argList RPAREN! SEMI! - {#lp2.setType(SUPER_CTOR_CALL);} + {#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)] - )* - ; + : 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); + : 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!)* - ; + : {#declaratorBrackets=typ;} + (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)* + ; varInitializer - : ( ASSIGN^ initializer )? - ; + : ( 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--; } - ; + : 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 - ; + : 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 + : IDENT // the name of the method - // parse the formal parameter declarations. - LPAREN! parameterDeclarationList RPAREN! + // parse the formal parameter declarations. + LPAREN! parameterDeclarationList RPAREN! - // get the list of exceptions that this method is declared to throw - (throwsClause)? - ; + // 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 )* - ; + : "throws"^ identifier ( COMMA! identifier )* + ; // A list of formal parameters parameterDeclarationList - : ( parameterDeclaration ( COMMA! parameterDeclaration )* )? - {#parameterDeclarationList = #(#[PARAMETERS,"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);} - ; + : 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);} - ; + : (f:"final")? + {#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], f);} + ; // Compound statement. This is used in many contexts: // Inside a class definition prefixed with "static": @@ -549,151 +549,151 @@ parameterModifier // 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--; } - ; + : 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);} - ; + // 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);} - ; + : ( // 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! - ; + : ("case"^ expression | "default") COLON! + ; caseSList - : (statement)* - {#caseSList = #(#[SLIST,"SLIST"],#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);} - ; + // 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);} - ; + : (expression)? + {#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);} + ; forIter - : (expressionList)? - {#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);} - ; + : (expressionList)? + {#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);} + ; // an exception handler try/catch block tryBlock - : "try"^ compoundStatement - (handler)* - ( finallyClause )? - ; + : "try"^ compoundStatement + (handler)* + ( finallyClause )? + ; finallyClause - : "finally"^ compoundStatement - ; + : "finally"^ compoundStatement + ; // an exception handler handler - : "catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement - ; + : "catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement + ; // expressions @@ -732,22 +732,22 @@ handler // the mother of all expressions expression - : assignmentExpression - {#expression = #(#[EXPR,"EXPR"],#expression);} - ; + : assignmentExpression + {#expression = #(#[EXPR,"EXPR"],#expression);} + ; // This is a list of expressions. expressionList - : expression (COMMA! expression)* - {#expressionList = #(#[ELIST,"ELIST"], expressionList);} - ; + : expression (COMMA! expression)* + {#expressionList = #(#[ELIST,"ELIST"], expressionList);} + ; // assignment expression (level 13) assignmentExpression - : conditionalExpression - ( ( ASSIGN^ + : conditionalExpression + ( ( ASSIGN^ | PLUS_ASSIGN^ | MINUS_ASSIGN^ | STAR_ASSIGN^ @@ -760,99 +760,99 @@ assignmentExpression | BXOR_ASSIGN^ | BOR_ASSIGN^ ) - assignmentExpression - )? - ; + assignmentExpression + )? + ; // conditional test (level 12) conditionalExpression - : logicalOrExpression - ( QUESTION^ assignmentExpression COLON! conditionalExpression )? - ; + : logicalOrExpression + ( QUESTION^ assignmentExpression COLON! conditionalExpression )? + ; // logical or (||) (level 11) logicalOrExpression - : logicalAndExpression (LOR^ logicalAndExpression)* - ; + : logicalAndExpression (LOR^ logicalAndExpression)* + ; // logical and (&&) (level 10) logicalAndExpression - : inclusiveOrExpression (LAND^ inclusiveOrExpression)* - ; + : inclusiveOrExpression (LAND^ inclusiveOrExpression)* + ; // bitwise or non-short-circuiting or (|) (level 9) inclusiveOrExpression - : exclusiveOrExpression (BOR^ exclusiveOrExpression)* - ; + : exclusiveOrExpression (BOR^ exclusiveOrExpression)* + ; // exclusive or (^) (level 8) exclusiveOrExpression - : andExpression (BXOR^ andExpression)* - ; + : andExpression (BXOR^ andExpression)* + ; // bitwise or non-short-circuiting and (&) (level 7) andExpression - : equalityExpression (BAND^ equalityExpression)* - ; + : equalityExpression (BAND^ equalityExpression)* + ; // equality/inequality (==/!=) (level 6) equalityExpression - : relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)* - ; + : relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)* + ; // boolean relational expressions (level 5) relationalExpression - : shiftExpression - ( ( ( LT^ - | GT^ - | LE^ - | GE^ - ) - shiftExpression - )* - | "instanceof"^ typeSpec[true] - ) - ; + : shiftExpression + ( ( ( LT^ + | GT^ + | LE^ + | GE^ + ) + shiftExpression + )* + | "instanceof"^ typeSpec[true] + ) + ; // bit shift expressions (level 4) shiftExpression - : additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)* - ; + : additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)* + ; // binary addition/subtraction (level 3) additiveExpression - : multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)* - ; + : multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)* + ; // multiplication/division/modulo (level 2) multiplicativeExpression - : unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)* - ; + : unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)* + ; unaryExpression - : INC^ unaryExpression - | DEC^ unaryExpression - | MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression - | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression - | unaryExpressionNotPlusMinus - ; + : INC^ unaryExpression + | DEC^ unaryExpression + | MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression + | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression + | unaryExpressionNotPlusMinus + ; unaryExpressionNotPlusMinus - : BNOT^ unaryExpression - | LNOT^ unaryExpression + : BNOT^ unaryExpression + | LNOT^ unaryExpression - // use predicate to skip cases like: (int.class) + // use predicate to skip cases like: (int.class) | (LPAREN builtInTypeSpec[true] RPAREN) => lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN! unaryExpression @@ -860,108 +860,108 @@ unaryExpressionNotPlusMinus // 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)=> + | (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=> lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN! unaryExpressionNotPlusMinus - | postfixExpression - ; + | postfixExpression + ; // qualified names, array expressions, method invocation, post inc/dec postfixExpression - : + : /* "this"! lp1:LPAREN^ argList RPAREN! - {#lp1.setType(CTOR_CALL);} + {#lp1.setType(CTOR_CALL);} | "super"! lp2:LPAREN^ argList RPAREN! - {#lp2.setType(SUPER_CTOR_CALL);} + {#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; - } - : */ + // 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" + ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} + argList + RPAREN! + )? + | DOT^ "this" - | DOT^ "super" + | 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);} + | DOT^ IDENT + ( lps:LPAREN^ {#lps.setType(METHOD_CALL);} argList RPAREN! )? ) - | DOT^ newExpression - | lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK! - )* + | DOT^ newExpression + | lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK! + )* - ( // possibly add on a post-increment or post-decrement. + ( // 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);} - )? - ; + 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" )? + : identPrimary ( options {greedy=true;} : DOT^ "class" )? | constant - | "true" - | "false" - | "null" + | "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" - ; + | "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 - ( + : IDENT + ( options { - // .ident could match here or in postfixExpression. - // We do want to match here. Turn off warning. - greedy=true; - } - : DOT^ IDENT - )* - ( + // .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 + // 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;} : + greedy=true; + } + : ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} argList RPAREN! ) + | ( options {greedy=true;} : lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK! )+ - )? + )? ; /** object instantiation. @@ -1014,53 +1014,53 @@ identPrimary * */ 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)? - ) - ; + : "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"];} - ) - ; + : ( 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! - )+ - ; + : ( + // 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 - ; + : NUM_INT + | CHAR_LITERAL + | STRING_LITERAL + | NUM_FLOAT + | NUM_LONG + | NUM_DOUBLE + ; //---------------------------------------------------------------------------- // The Java scanner @@ -1068,121 +1068,121 @@ constant 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; + 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 : ';' ; +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; } - ; +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();} - ; + : "//" + (~('\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);} - ; + : "/*" + ( /* '\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'|'\\') ) '\'' - ; + : '\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\'' + ; // string literals STRING_LITERAL - : '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"' - ; + : '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"' + ; // escape sequence -- note that this is protected; it can only be called @@ -1195,121 +1195,132 @@ STRING_LITERAL // 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' - )? - ) - ; + : '\\' + ( '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') - ; + : ('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'|'$')* - ; + options {testLiterals=true;} + : ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')* + ; // a numeric literal NUM_INT - {boolean isDecimal=false; Token t=null;} + {boolean isDecimal=false, isHexadecimal=false; Token t=null;} : '.' {_ttype = DOT;} - ( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})? + ( ('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 - } - } + 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 - } - } + | ( '0' {isDecimal = true;} // special case for just '0' + ( ('x'|'X') { isHexadecimal=true; } // 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; } + + // check to see if it's a hexadecimal w/ binary exponent float if looks like hexadecimal so far + | {isHexadecimal}? + ( '.' ( options { warnWhenFollowAmbig=false; } : HEX_DIGIT )* )? + ('p'|'P') ('+'|'-')? ('0'..'9')+ (f5:FLOAT_SUFFIX {t=f5;})? + { + if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) { + _ttype = NUM_FLOAT; + } else { + _ttype = NUM_DOUBLE; // assume double + } + } + // 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')+ - ; + : ('e'|'E') (PLUS|MINUS)? ('0'..'9')+ + ; protected FLOAT_SUFFIX - : 'f'|'F'|'d'|'D' - ; + : 'f'|'F'|'d'|'D' + ; |