From: cuz Date: Mon, 14 Aug 2000 22:18:26 +0000 (+0000) Subject: Reworked type comparison and handling of type qualifiers X-Git-Tag: V2.12.0~3236 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=25f5c69efab6e28fe9f12494e83e80140b50556a;p=cc65 Reworked type comparison and handling of type qualifiers git-svn-id: svn://svn.cc65.org/cc65/trunk@285 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/cc65/compile.c b/src/cc65/compile.c index cb3dd92c5..58ee19f5c 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -173,7 +173,7 @@ static void Parse (void) } /* Switch to the data or rodata segment */ - if (IsConst (Decl.Type)) { + if (IsQualConst (Decl.Type)) { g_userodata (); } else { g_usedata (); diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index a450d0972..ba2fa33ff 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -62,8 +62,6 @@ type type_uint [] = { T_UINT, T_END }; type type_long [] = { T_LONG, T_END }; type type_ulong [] = { T_ULONG, T_END }; type type_void [] = { T_VOID, T_END }; -type type_pschar [] = { T_PTR, T_SCHAR, T_END }; -type type_puchar [] = { T_PTR, T_UCHAR, T_END }; @@ -77,7 +75,7 @@ unsigned TypeLen (const type* T) /* Return the length of the type string */ { const type* Start = T; - while (*T) { + while (*T != T_END) { ++T; } return T - Start; @@ -85,20 +83,6 @@ unsigned TypeLen (const type* T) -int TypeCmp (const type* T1, const type* T2) -/* Compare two type strings */ -{ - int A, B, D; - do { - A = *T1++; - B = *T2++; - D = A - B; - } while (D == 0 && A != 0); - return D; -} - - - type* TypeCpy (type* Dest, const type* Src) /* Copy a type string */ { @@ -502,40 +486,58 @@ type* Indirect (type* T) -int IsConst (const type* T) -/* Return true if the given type has a const memory image */ +int IsTypeChar (const type* T) +/* Return true if this is a character type */ { - /* If this is an array, look at the element type, otherwise look at the - * type itself. - */ - if (IsTypeArray (T)) { - T += DECODE_SIZE + 1; - } - return ((T[0] & T_QUAL_CONST) == T_QUAL_CONST); + return (T[0] & T_MASK_TYPE) == T_TYPE_CHAR; } -int IsTypeVoid (const type* T) -/* Return true if this is a void type */ +int IsTypeInt (const type* T) +/* Return true if this is an int type (signed or unsigned) */ { - return ((T[0] & T_MASK_TYPE) == T_TYPE_VOID && T[1] == T_END); + return (T[0] & T_MASK_TYPE) == T_TYPE_INT; } -int IsClassPtr (const type* T) +int IsTypeLong (const type* T) +/* Return true if this is a long type (signed or unsigned) */ +{ + return (T[0] & T_MASK_TYPE) == T_TYPE_LONG; +} + + + +int IsTypePtr (const type* T) /* Return true if this is a pointer type */ { - return (T[0] & T_MASK_CLASS) == T_CLASS_PTR; + return ((T[0] & T_MASK_TYPE) == T_TYPE_PTR); } -int IsTypeChar (const type* T) -/* Return true if this is a character type */ +int IsTypeArray (const type* T) +/* Return true if this is an array type */ +{ + return ((T[0] & T_MASK_TYPE) == T_TYPE_ARRAY); +} + + + +int IsTypeVoid (const type* T) +/* Return true if this is a void type */ +{ + return (T[0] & T_MASK_TYPE) == T_TYPE_VOID; +} + + + +int IsTypeFunc (const type* T) +/* Return true if this is a function class */ { - return (T[0] & T_MASK_TYPE) == T_TYPE_CHAR && T[1] == T_END; + return ((T[0] & T_MASK_TYPE) == T_TYPE_FUNC); } @@ -548,15 +550,23 @@ int IsClassInt (const type* T) -int IsTypeLong (const type* T) -/* Return true if this is a long type (signed or unsigned) */ +int IsClassPtr (const type* T) +/* Return true if this is a pointer type */ { - return (T[0] & T_MASK_TYPE) == T_TYPE_LONG; + return (T[0] & T_MASK_CLASS) == T_CLASS_PTR; +} + + + +int IsClassStruct (const type* T) +/* Return true if this is a struct type */ +{ + return (T[0] & T_MASK_CLASS) == T_CLASS_STRUCT; } -int IsUnsigned (const type* T) +int IsSignUnsigned (const type* T) /* Return true if this is an unsigned type */ { return (T[0] & T_MASK_SIGN) == T_SIGN_UNSIGNED; @@ -564,18 +574,18 @@ int IsUnsigned (const type* T) -int IsClassStruct (const type* T) -/* Return true if this is a struct type */ +int IsQualConst (const type* T) +/* Return true if the given type has a const memory image */ { - return (T[0] & T_MASK_CLASS) == T_CLASS_STRUCT; + return (GetQualifier (T) & T_QUAL_CONST) != 0; } -int IsTypeFunc (const type* T) -/* Return true if this is a function class */ +int IsQualVolatile (const type* T) +/* Return true if the given type has a volatile type qualifier */ { - return ((T[0] & T_MASK_TYPE) == T_TYPE_FUNC); + return (GetQualifier (T) & T_QUAL_VOLATILE) != 0; } @@ -599,10 +609,52 @@ int IsTypeFuncPtr (const type* T) -int IsTypeArray (const type* T) -/* Return true if this is an array type */ +type GetType (const type* T) +/* Get the raw type */ { - return ((T[0] & T_MASK_TYPE) == T_TYPE_ARRAY); + PRECONDITION (T[0] != T_END); + return (T[0] & T_MASK_TYPE); +} + + + +type GetClass (const type* T) +/* Get the class of a type string */ +{ + PRECONDITION (T[0] != T_END); + return (T[0] & T_MASK_CLASS); +} + + + +type GetSignedness (const type* T) +/* Get the sign of a type */ +{ + PRECONDITION (T[0] != T_END); + return (T[0] & T_MASK_SIGN); +} + + + +type GetSizeModifier (const type* T) +/* Get the size modifier of a type */ +{ + PRECONDITION (T[0] != T_END); + return (T[0] & T_MASK_SIZE); +} + + + +type GetQualifier (const type* T) +/* Get the qualifier from the given type string */ +{ + /* If this is an array, look at the element type, otherwise look at the + * type itself. + */ + if (IsTypeArray (T)) { + T += DECODE_SIZE + 1; + } + return (T[0] & T_QUAL_CONST); } diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index cdef535f8..a710dc9e1 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -143,8 +143,6 @@ extern type type_uint []; extern type type_long []; extern type type_ulong []; extern type type_void []; -extern type type_pschar []; -extern type type_puchar []; @@ -157,9 +155,6 @@ extern type type_puchar []; unsigned TypeLen (const type* Type); /* Return the length of the type string */ -int TypeCmp (const type* T1, const type* T2); -/* Compare two type strings */ - type* TypeCpy (type* Dest, const type* Src); /* Copy a type string */ @@ -227,43 +222,67 @@ type* Indirect (type* Type); * given type points to. */ -int IsConst (const type* T); -/* Return true if the given type has a const memory image */ +int IsTypeChar (const type* T); +/* Return true if this is a character type */ -int IsTypeVoid (const type* Type); -/* Return true if this is a void type */ +int IsTypeInt (const type* T); +/* Return true if this is an int type (signed or unsigned) */ -int IsClassPtr (const type* Type); +int IsTypeLong (const type* T); +/* Return true if this is a long type (signed or unsigned) */ + +int IsTypePtr (const type* Type); /* Return true if this is a pointer type */ -int IsTypeChar (const type* Type); -/* Return true if this is a character type */ +int IsTypeArray (const type* Type); +/* Return true if this is an array type */ + +int IsTypeVoid (const type* Type); +/* Return true if this is a void type */ + +int IsTypeFunc (const type* Type); +/* Return true if this is a function class */ int IsClassInt (const type* Type); /* Return true if this is an integer type */ -int IsTypeLong (const type* Type); -/* Return true if this is a long type (signed or unsigned) */ - -int IsUnsigned (const type* Type); -/* Return true if this is an unsigned type */ +int IsClassPtr (const type* Type); +/* Return true if this is a pointer type */ int IsClassStruct (const type* Type); /* Return true if this is a struct type */ -int IsTypeFunc (const type* Type); -/* Return true if this is a function class */ +int IsSignUnsigned (const type* Type); +/* Return true if this is an unsigned type */ -int IsFastCallFunc (const type* Type); +int IsQualConst (const type* T); +/* Return true if the given type has a const memory image */ + +int IsQualVolatile (const type* T); +/* Return true if the given type has a volatile type qualifier */ + +int IsFastCallFunc (const type* T); /* Return true if this is a function type with __fastcall__ calling conventions */ -int IsTypeFuncPtr (const type* Type); +int IsTypeFuncPtr (const type* T); /* Return true if this is a function pointer */ -int IsTypeArray (const type* Type); -/* Return true if this is an array type */ +type GetType (const type* T); +/* Get the raw type */ + +type GetClass (const type* T); +/* Get the class of a type string */ + +type GetSignedness (const type* T); +/* Get the sign of a type */ + +type GetSizeModifier (const type* T); +/* Get the size modifier of a type */ + +type GetQualifier (const type* T); +/* Get the qualifier from the given type string */ -struct FuncDesc* GetFuncDesc (const type* Type); +struct FuncDesc* GetFuncDesc (const type* T); /* Get the FuncDesc pointer from a function or pointer-to-function type */ diff --git a/src/cc65/error.c b/src/cc65/error.c index 4a8a0ecb7..13cb24db5 100644 --- a/src/cc65/error.c +++ b/src/cc65/error.c @@ -107,7 +107,8 @@ static char* ErrMsg [ERR_COUNT-1] = { "Unexpected `#else'", "`#endif' expected", "Compiler directive expected", - "Symbol `%s' defined more than once", + "Redefinition of `%s'", + "Conflicting types for `%s'", "String literal expected", "`while' expected", "Function must return a value", @@ -152,8 +153,8 @@ static char* ErrMsg [ERR_COUNT-1] = { "Variable has unknown size", "Unknown identifier: `%s'", "Duplicate qualifier: `%s'", - "Assignment discards `const' qualifier", - "Passing argument %u discards `const' qualifier", + "Assignment to const", + "Pointer types differ in type qualifiers", }; diff --git a/src/cc65/error.h b/src/cc65/error.h index 4220d86a5..afedb3dd3 100644 --- a/src/cc65/error.h +++ b/src/cc65/error.h @@ -103,6 +103,7 @@ enum Errors { ERR_CPP_ENDIF_EXPECTED, ERR_CPP_DIRECTIVE_EXPECTED, ERR_MULTIPLE_DEFINITION, + ERR_CONFLICTING_TYPES, ERR_STRLIT_EXPECTED, ERR_WHILE_EXPECTED, ERR_MUST_RETURN_VALUE, @@ -148,7 +149,7 @@ enum Errors { ERR_UNKNOWN_IDENT, ERR_DUPLICATE_QUALIFIER, ERR_CONST_ASSIGN, - ERR_CONST_PARAM, + ERR_QUAL_DIFF, ERR_COUNT /* Error count */ }; diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 434813220..dc2252c7d 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -30,6 +30,7 @@ #include "scanner.h" #include "stdfunc.h" #include "symtab.h" +#include "typecmp.h" #include "expr.h" @@ -132,13 +133,13 @@ static type* promoteint (type* lhst, type* rhst) * - Otherwise the result is an int. */ if (IsTypeLong (lhst) || IsTypeLong (rhst)) { - if (IsUnsigned (lhst) || IsUnsigned (rhst)) { + if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) { return type_ulong; } else { return type_long; } } else { - if (IsUnsigned (lhst) || IsUnsigned (rhst)) { + if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) { return type_uint; } else { return type_int; @@ -232,11 +233,23 @@ unsigned assignadjust (type* lhst, struct expent* rhs) * - the rhs pointer is a void pointer, or * - the lhs pointer is a void pointer. */ - type* left = Indirect (lhst); - type* right = Indirect (rhst); - if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) { - Error (ERR_INCOMPATIBLE_POINTERS); - } + if (!IsTypeVoid (Indirect (lhst)) && !IsTypeVoid (Indirect (rhst))) { + /* Compare the types */ + switch (TypeCmp (lhst, rhst)) { + + case TC_INCOMPATIBLE: + Error (ERR_INCOMPATIBLE_POINTERS); + break; + + case TC_QUAL_DIFF: + Error (ERR_QUAL_DIFF); + break; + + default: + /* Ok */ + break; + } + } } else if (IsClassInt (rhst)) { /* Int to pointer assignment is valid only for constant zero */ if ((rhs->e_flags & E_MCONST) == 0 || rhs->e_const != 0) { @@ -246,7 +259,7 @@ unsigned assignadjust (type* lhst, struct expent* rhs) /* Assignment of function to function pointer is allowed, provided * that both functions have the same parameter list. */ - if (!EqualTypes(Indirect (lhst), rhst)) { + if (TypeCmp (Indirect (lhst), rhst) < TC_EQUAL) { Error (ERR_INCOMPATIBLE_TYPES); } } else { @@ -580,18 +593,9 @@ static void callfunction (struct expent* lval) * convert the actual argument to the type needed. */ if (!Ellipsis) { - /* If the left side is not const and the right is const, print - * an error. Note: This is an incomplete check, since other parts - * of the type string may have a const qualifier, but it catches - * some errors and is cheap here. We will redo it the right way - * as soon as the parser is rewritten. #### - */ - if (!IsConst (Param->Type) && IsConst (lval2.e_tptr)) { - Error (ERR_CONST_PARAM, ParamCount); - } - /* Promote the argument if needed */ assignadjust (Param->Type, &lval2); + /* If we have a prototype, chars may be pushed as chars */ Flags |= CF_FORCECHAR; } @@ -1713,7 +1717,7 @@ static int hie_compare (GenDesc** ops, /* List of generators */ */ type* left = Indirect (lval->e_tptr); type* right = Indirect (lval2.e_tptr); - if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) { + if (TypeCmp (left, right) < TC_EQUAL && *left != T_VOID && *right != T_VOID) { /* Incomatible pointers */ Error (ERR_INCOMPATIBLE_TYPES); } @@ -1756,7 +1760,7 @@ static int hie_compare (GenDesc** ops, /* List of generators */ */ if (IsTypeChar (lval->e_tptr) && (IsTypeChar (lval2.e_tptr) || rconst)) { flags |= CF_CHAR; - if (IsUnsigned (lval->e_tptr) || IsUnsigned (lval2.e_tptr)) { + if (IsSignUnsigned (lval->e_tptr) || IsSignUnsigned (lval2.e_tptr)) { flags |= CF_UNSIGNED; } if (rconst) { @@ -2017,7 +2021,7 @@ static void parsesub (int k, struct expent* lval) /* Operate on pointers, result type is a pointer */ } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { /* Left is pointer, right is pointer, must scale result */ - if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) { + if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_EQUAL) { Error (ERR_INCOMPATIBLE_POINTERS); } else { lval->e_const = (lval->e_const - lval2.e_const) / PSizeOf (lhst); @@ -2052,7 +2056,7 @@ static void parsesub (int k, struct expent* lval) flags = CF_PTR; } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { /* Left is pointer, right is pointer, must scale result */ - if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) { + if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_EQUAL) { Error (ERR_INCOMPATIBLE_POINTERS); } else { rscale = PSizeOf (lhst); @@ -2095,7 +2099,7 @@ static void parsesub (int k, struct expent* lval) flags = CF_PTR; } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { /* Left is pointer, right is pointer, must scale result */ - if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) { + if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_EQUAL) { Error (ERR_INCOMPATIBLE_POINTERS); } else { rscale = PSizeOf (lhst); @@ -2454,7 +2458,7 @@ static int hieQuest (struct expent *lval) } else if (IsClassPtr (type2) && IsClassPtr (type3)) { /* Must point to same type */ - if (TypeCmp (Indirect (type2), Indirect (type3)) != 0) { + if (TypeCmp (Indirect (type2), Indirect (type3)) < TC_EQUAL) { Error (ERR_INCOMPATIBLE_TYPES); } /* Result has the common type */ @@ -2667,7 +2671,7 @@ static void Assignment (struct expent* lval) type* ltype = lval->e_tptr; /* Check for assignment to const */ - if (IsConst (ltype)) { + if (IsQualConst (ltype)) { Error (ERR_CONST_ASSIGN); } @@ -2695,7 +2699,7 @@ static void Assignment (struct expent* lval) g_push (CF_PTR | CF_UNSIGNED, 0); /* Check for equality of the structs */ - if (!EqualTypes (ltype, lval2.e_tptr)) { + if (TypeCmp (ltype, lval2.e_tptr) < TC_EQUAL) { Error (ERR_INCOMPATIBLE_TYPES); } diff --git a/src/cc65/locals.c b/src/cc65/locals.c index 3a6e6a5ab..332c7589c 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -269,7 +269,7 @@ static void ParseOneDecl (const DeclSpec* Spec) if (curtok == TOK_ASSIGN) { /* Initialization ahead, switch to data segment */ - if (IsConst (Decl.Type)) { + if (IsQualConst (Decl.Type)) { g_userodata (); } else { g_usedata (); diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 5ec175017..cc6f8b086 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -45,6 +45,7 @@ OBJS = anonname.o \ stmt.o \ symentry.o \ symtab.o \ + typecmp.o \ util.o LIBS = $(COMMON)/common.a diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index 056b6ed1f..000f33a4b 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -100,6 +100,7 @@ OBJS = anonname.obj \ stdfunc.obj \ symentry.obj \ symtab.obj \ + typecmp.obj \ util.obj LIBS = ..\common\common.lib @@ -156,6 +157,7 @@ FILE segname.obj FILE stdfunc.obj FILE symentry.obj FILE symtab.obj +FILE typecmp.obj FILE util.obj LIBRARY ..\common\common.lib | diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index 445d11405..95d01b39f 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -52,6 +52,7 @@ static const struct Keyword { { "__EAX__", TOK_EAX, TT_C }, { "__asm__", TOK_ASM, TT_C }, { "__attribute__", TOK_ATTRIBUTE, TT_C }, + { "__far__", TOK_FAR, TT_C }, { "__fastcall__", TOK_FASTCALL, TT_C }, { "asm", TOK_ASM, TT_EXT }, { "auto", TOK_AUTO, TT_C }, @@ -66,6 +67,7 @@ static const struct Keyword { { "else", TOK_ELSE, TT_C }, { "enum", TOK_ENUM, TT_C }, { "extern", TOK_EXTERN, TT_C }, + { "far", TOK_FAR, TT_EXT }, { "fastcall", TOK_FASTCALL, TT_EXT }, { "float", TOK_FLOAT, TT_C }, { "for", TOK_FOR, TT_C }, @@ -129,7 +131,7 @@ static int FindKey (const char* Key) } - + static int SkipWhite (void) /* Skip white space in the input stream, reading and preprocessing new lines * if necessary. Return 0 if end of file is reached, return 1 otherwise. diff --git a/src/cc65/scanner.h b/src/cc65/scanner.h index bbbed9ee6..a707e4d14 100644 --- a/src/cc65/scanner.h +++ b/src/cc65/scanner.h @@ -125,10 +125,11 @@ typedef enum token_t { TOK_FCONST, TOK_ATTRIBUTE, + TOK_FAR, TOK_FASTCALL, TOK_AX, TOK_EAX, - + TOK_PRAGMA } token_t; diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index bc6faebf0..60576ff52 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -111,6 +111,8 @@ static void StdFunc_strlen (struct expent* lval) /* Handle the strlen function */ { struct expent pval; + static type ArgType[] = { T_PTR, T_SCHAR, T_END }; + /* Fetch the parameter */ int k = hie1 (&pval); @@ -135,8 +137,11 @@ static void StdFunc_strlen (struct expent* lval) exprhs (CF_NONE, k, &pval); } + /* Setup the argument type string */ + ArgType[1] = GetDefaultChar () | T_QUAL_CONST; + /* Convert the parameter type to the type needed, check for mismatches */ - assignadjust (SignedChars? type_pschar : type_puchar, &pval); + assignadjust (ArgType, &pval); /* Generate the strlen code */ g_strlen (flags, pval.e_name, pval.e_const); diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index 7a80b81be..11a4252f4 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -53,6 +53,7 @@ #include "funcdesc.h" #include "global.h" #include "symentry.h" +#include "typecmp.h" #include "symtab.h" @@ -692,9 +693,9 @@ SymEntry* AddGlobalSym (const char* Name, type* Type, unsigned Flags) unsigned ESize = Decode (EType + 1); if ((Size != 0 && ESize != 0) || - TypeCmp (Type+DECODE_SIZE+1, EType+DECODE_SIZE+1) != 0) { - /* Types not identical: Duplicate definition */ - Error (ERR_MULTIPLE_DEFINITION, Name); + TypeCmp (Type+DECODE_SIZE+1, EType+DECODE_SIZE+1) < TC_EQUAL) { + /* Types not identical: Conflicting types */ + Error (ERR_CONFLICTING_TYPES, Name); } else { /* Check if we have a size in the existing definition */ if (ESize == 0) { @@ -705,8 +706,8 @@ SymEntry* AddGlobalSym (const char* Name, type* Type, unsigned Flags) } else { /* New type must be identical */ - if (!EqualTypes (EType, Type) != 0) { - Error (ERR_MULTIPLE_DEFINITION, Name); + if (TypeCmp (EType, Type) < TC_EQUAL) { + Error (ERR_CONFLICTING_TYPES, Name); } /* In case of a function, use the new type descriptor, since it @@ -761,152 +762,6 @@ int SymIsLocal (SymEntry* Sym) -static int EqualSymTables (SymTable* Tab1, SymTable* Tab2) -/* Compare two symbol tables. Return 1 if they are equal and 0 otherwise */ -{ - /* Compare the parameter lists */ - SymEntry* Sym1 = Tab1->SymHead; - SymEntry* Sym2 = Tab2->SymHead; - - /* Compare the fields */ - while (Sym1 && Sym2) { - - /* Compare this field */ - if (!EqualTypes (Sym1->Type, Sym2->Type)) { - /* Field types not equal */ - return 0; - } - - /* Get the pointers to the next fields */ - Sym1 = Sym1->NextSym; - Sym2 = Sym2->NextSym; - } - - /* Check both pointers against NULL to compare the field count */ - return (Sym1 == 0 && Sym2 == 0); -} - - - -int EqualTypes (const type* Type1, const type* Type2) -/* Recursively compare two types. Return 1 if the types match, return 0 - * otherwise. - */ -{ - int v1, v2; - SymEntry* Sym1; - SymEntry* Sym2; - SymTable* Tab1; - SymTable* Tab2; - FuncDesc* F1; - FuncDesc* F2; - int Ok; - - - /* Shortcut here: If the pointers are identical, the types are identical */ - if (Type1 == Type2) { - return 1; - } - - /* Compare two types. Determine, where they differ */ - while (*Type1 == *Type2 && *Type1 != T_END) { - - switch (*Type1) { - - case T_FUNC: - /* Compare the function descriptors */ - F1 = DecodePtr (Type1+1); - F2 = DecodePtr (Type2+1); - - /* If one of the functions is implicitly declared, both - * functions are considered equal. If one of the functions is - * old style, and the other is empty, the functions are - * considered equal. - */ - if ((F1->Flags & FD_IMPLICIT) != 0 || (F2->Flags & FD_IMPLICIT) != 0) { - Ok = 1; - } else if ((F1->Flags & FD_OLDSTYLE) != 0 && (F2->Flags & FD_EMPTY) != 0) { - Ok = 1; - } else if ((F1->Flags & FD_EMPTY) != 0 && (F2->Flags & FD_OLDSTYLE) != 0) { - Ok = 1; - } else { - Ok = 0; - } - - if (!Ok) { - - /* Check the remaining flags */ - if ((F1->Flags & ~FD_IGNORE) != (F2->Flags & ~FD_IGNORE)) { - /* Flags differ */ - return 0; - } - - /* Compare the parameter lists */ - if (EqualSymTables (F1->SymTab, F2->SymTab) == 0 || - EqualSymTables (F1->TagTab, F2->TagTab) == 0) { - /* One of the tables is not identical */ - return 0; - } - } - - /* Skip the FuncDesc pointers to compare the return type */ - Type1 += DECODE_SIZE; - Type2 += DECODE_SIZE; - break; - - case T_ARRAY: - /* Check member count */ - v1 = Decode (Type1+1); - v2 = Decode (Type2+1); - if (v1 != 0 && v2 != 0 && v1 != v2) { - /* Member count given but different */ - return 0; - } - Type1 += DECODE_SIZE; - Type2 += DECODE_SIZE; - break; - - case T_STRUCT: - case T_UNION: - /* Compare the fields recursively. To do that, we fetch the - * pointer to the struct definition from the type, and compare - * the fields. - */ - Sym1 = DecodePtr (Type1+1); - Sym2 = DecodePtr (Type2+1); - - /* Get the field tables from the struct entry */ - Tab1 = Sym1->V.S.SymTab; - Tab2 = Sym2->V.S.SymTab; - - /* One or both structs may be forward definitions. In this case, - * the symbol tables are both non existant. Assume that the - * structs are equal in this case. - */ - if (Tab1 != 0 && Tab2 != 0) { - - if (EqualSymTables (Tab1, Tab2) == 0) { - /* Field lists are not equal */ - return 0; - } - - } - - /* Structs are equal */ - Type1 += DECODE_SIZE; - Type2 += DECODE_SIZE; - break; - } - ++Type1; - ++Type2; - } - - /* Done, types are equal */ - return 1; -} - - - void MakeZPSym (const char* Name) /* Mark the given symbol as zero page symbol */ { diff --git a/src/cc65/symtab.h b/src/cc65/symtab.h index 5c37f2186..2e8c2a0e5 100644 --- a/src/cc65/symtab.h +++ b/src/cc65/symtab.h @@ -163,11 +163,6 @@ SymTable* GetSymTab (void); int SymIsLocal (SymEntry* Sym); /* Return true if the symbol is defined in the highest lexical level */ -int EqualTypes (const type* t1, const type* t2); -/* Recursively compare two types. Return 1 if the types match, return 0 - * otherwise. - */ - void MakeZPSym (const char* Name); /* Mark the given symbol as zero page symbol */ @@ -185,6 +180,3 @@ void EmitExternals (void); - - - diff --git a/src/cc65/typecmp.c b/src/cc65/typecmp.c new file mode 100644 index 000000000..46eda0baf --- /dev/null +++ b/src/cc65/typecmp.c @@ -0,0 +1,315 @@ +/*****************************************************************************/ +/* */ +/* typecmp.c */ +/* */ +/* Type compare function for the cc65 C compiler */ +/* */ +/* */ +/* */ +/* (C) 1998-2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#include "funcdesc.h" +#include "symtab.h" +#include "typecmp.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static void SetResult (typecmp_t* Result, typecmp_t Val) +/* Set a new result value if it is less than the existing one */ +{ + if (Val < *Result) { + *Result = Val; + } +} + + + +static int EqualSymTables (SymTable* Tab1, SymTable* Tab2) +/* Compare two symbol tables. Return 1 if they are equal and 0 otherwise */ +{ + /* Compare the parameter lists */ + SymEntry* Sym1 = Tab1->SymHead; + SymEntry* Sym2 = Tab2->SymHead; + + /* Compare the fields */ + while (Sym1 && Sym2) { + + /* Compare this field */ + if (TypeCmp (Sym1->Type, Sym2->Type) < TC_EQUAL) { + /* Field types not equal */ + return 0; + } + + /* Get the pointers to the next fields */ + Sym1 = Sym1->NextSym; + Sym2 = Sym2->NextSym; + } + + /* Check both pointers against NULL to compare the field count */ + return (Sym1 == 0 && Sym2 == 0); +} + + + +static void DoCompare (const type* lhs, const type* rhs, typecmp_t* Result) +/* Recursively compare two types. */ +{ + unsigned Indirections; + unsigned ElementCount; + SymEntry* Sym1; + SymEntry* Sym2; + SymTable* Tab1; + SymTable* Tab2; + FuncDesc* F1; + FuncDesc* F2; + int Ok; + + + /* Initialize stuff */ + Indirections = 0; + ElementCount = 0; + + /* Compare two types. Determine, where they differ */ + while (*lhs != T_END) { + + type LeftType, RightType; + type LeftSign, RightSign; + type LeftQual, RightQual; + unsigned LeftCount, RightCount; + + /* Check if the end of the type string is reached */ + if (*rhs == T_END) { + /* End of comparison reached */ + return; + } + + /* Get the raw left and right types, signs and qualifiers */ + LeftType = GetType (lhs); + RightType = GetType (rhs); + LeftSign = GetSignedness (lhs); + RightSign = GetSignedness (rhs); + LeftQual = GetQualifier (lhs); + RightQual = GetQualifier (rhs); + + /* If the left type is a pointer and the right is an array, both + * are compatible. + */ + if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) { + RightType = T_TYPE_PTR; + rhs += DECODE_SIZE; + } + + /* If the raw types are not identical, the types are incompatible */ + if (LeftType != RightType) { + SetResult (Result, TC_INCOMPATIBLE); + return; + } + + /* On indirection level zero, a qualifier or sign difference is + * accepted. The types are no longer equal, but compatible. + */ + if (LeftSign != RightSign) { + if (ElementCount == 0) { + SetResult (Result, TC_SIGN_DIFF); + } else { + SetResult (Result, TC_INCOMPATIBLE); + return; + } + } + if (LeftQual != RightQual) { + /* On the first indirection level, different qualifiers mean + * that the types are still compatible. On the second level, + * this is a (maybe minor) error, so we create a special + * return code, since a qualifier is dropped from a pointer. + * Starting from the next level, the types are incompatible + * if the qualifiers differ. + */ + switch (Indirections) { + + case 0: + SetResult (Result, TC_STRICT_COMPATIBLE); + break; + + case 1: + /* A non const value on the right is compatible to a + * const one to the left, same for volatile. + */ + if ((LeftQual & T_QUAL_CONST) < (RightQual & T_QUAL_CONST) || + (LeftQual & T_QUAL_VOLATILE) < (RightQual & T_QUAL_VOLATILE)) { + SetResult (Result, TC_QUAL_DIFF); + } else { + SetResult (Result, TC_STRICT_COMPATIBLE); + } + break; + + default: + SetResult (Result, TC_INCOMPATIBLE); + return; + } + } + + /* Check for special type elements */ + switch (LeftType) { + + case T_TYPE_PTR: + ++Indirections; + break; + + case T_TYPE_FUNC: + /* Compare the function descriptors */ + F1 = DecodePtr (lhs+1); + F2 = DecodePtr (rhs+1); + + /* If one of the functions is implicitly declared, both + * functions are considered equal. If one of the functions is + * old style, and the other is empty, the functions are + * considered equal. + */ + if ((F1->Flags & FD_IMPLICIT) != 0 || (F2->Flags & FD_IMPLICIT) != 0) { + Ok = 1; + } else if ((F1->Flags & FD_OLDSTYLE) != 0 && (F2->Flags & FD_EMPTY) != 0) { + Ok = 1; + } else if ((F1->Flags & FD_EMPTY) != 0 && (F2->Flags & FD_OLDSTYLE) != 0) { + Ok = 1; + } else { + Ok = 0; + } + + if (!Ok) { + + /* Check the remaining flags */ + if ((F1->Flags & ~FD_IGNORE) != (F2->Flags & ~FD_IGNORE)) { + /* Flags differ */ + SetResult (Result, TC_INCOMPATIBLE); + return; + } + + /* Compare the parameter lists */ + if (EqualSymTables (F1->SymTab, F2->SymTab) == 0 || + EqualSymTables (F1->TagTab, F2->TagTab) == 0) { + /* One of the tables is not identical */ + SetResult (Result, TC_INCOMPATIBLE); + return; + } + } + + /* Skip the FuncDesc pointers to compare the return type */ + lhs += DECODE_SIZE; + rhs += DECODE_SIZE; + break; + + case T_TYPE_ARRAY: + /* Check member count */ + LeftCount = Decode (lhs+1); + RightCount = Decode (rhs+1); + if (LeftCount != 0 && RightCount != 0 && LeftCount != RightCount) { + /* Member count given but different */ + SetResult (Result, TC_INCOMPATIBLE); + return; + } + lhs += DECODE_SIZE; + rhs += DECODE_SIZE; + break; + + case T_TYPE_STRUCT: + case T_TYPE_UNION: + /* Compare the fields recursively. To do that, we fetch the + * pointer to the struct definition from the type, and compare + * the fields. + */ + Sym1 = DecodePtr (lhs+1); + Sym2 = DecodePtr (rhs+1); + + /* Get the field tables from the struct entry */ + Tab1 = Sym1->V.S.SymTab; + Tab2 = Sym2->V.S.SymTab; + + /* One or both structs may be forward definitions. In this case, + * the symbol tables are both non existant. Assume that the + * structs are equal in this case. + */ + if (Tab1 != 0 && Tab2 != 0) { + + if (EqualSymTables (Tab1, Tab2) == 0) { + /* Field lists are not equal */ + SetResult (Result, TC_INCOMPATIBLE); + return; + } + + } + + /* Structs are equal */ + lhs += DECODE_SIZE; + rhs += DECODE_SIZE; + break; + } + + /* Next type string element */ + ++lhs; + ++rhs; + ++ElementCount; + } + + /* Check if end of rhs reached */ + if (*rhs == T_END) { + SetResult (Result, TC_EQUAL); + } else { + SetResult (Result, TC_INCOMPATIBLE); + } +} + + + +typecmp_t TypeCmp (const type* lhs, const type* rhs) +/* Compare two types and return the result */ +{ + /* Assume the types are identical */ + typecmp_t Result = TC_IDENTICAL; + +#if 0 + printf ("Left : "); PrintRawType (stdout, lhs); + printf ("Right: "); PrintRawType (stdout, rhs); +#endif + + /* Recursively compare the types if they aren't identical */ + if (rhs != lhs) { + DoCompare (lhs, rhs, &Result); + } + + /* Return the result */ + return Result; +} + + + diff --git a/src/cc65/typecmp.h b/src/cc65/typecmp.h new file mode 100644 index 000000000..584bd2c44 --- /dev/null +++ b/src/cc65/typecmp.h @@ -0,0 +1,81 @@ +/*****************************************************************************/ +/* */ +/* typecmp.h */ +/* */ +/* Type compare function for the cc65 C compiler */ +/* */ +/* */ +/* */ +/* (C) 1998-2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef TYPECMP_H +#define TYPECMP_H + + + +#include "datatype.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Degree of type compatibility. Must be in ascending order */ +typedef enum { + TC_INCOMPATIBLE, /* Distinct types */ + TC_QUAL_DIFF, /* Types differ in qualifier of pointer */ + TC_SIGN_DIFF, /* Signedness differs */ + TC_COMPATIBLE = TC_SIGN_DIFF, /* Compatible types */ + TC_STRICT_COMPATIBLE, /* Struct compatibility */ + TC_EQUAL, /* Types are equal */ + TC_IDENTICAL /* Types are identical */ +} typecmp_t; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +typecmp_t TypeCmp (const type* lhs, const type* rhs); +/* Compare two types and return the result */ + + + +/* End of typecmp.h */ + +#endif + + + +