}
/* Switch to the data or rodata segment */
- if (IsConst (Decl.Type)) {
+ if (IsQualConst (Decl.Type)) {
g_userodata ();
} else {
g_usedata ();
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 };
/* Return the length of the type string */
{
const type* Start = T;
- while (*T) {
+ while (*T != T_END) {
++T;
}
return T - Start;
-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 */
{
-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);
}
-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;
-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;
}
-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);
}
extern type type_long [];
extern type type_ulong [];
extern type type_void [];
-extern type type_pschar [];
-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 */
* 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 */
"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",
"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",
};
ERR_CPP_ENDIF_EXPECTED,
ERR_CPP_DIRECTIVE_EXPECTED,
ERR_MULTIPLE_DEFINITION,
+ ERR_CONFLICTING_TYPES,
ERR_STRLIT_EXPECTED,
ERR_WHILE_EXPECTED,
ERR_MUST_RETURN_VALUE,
ERR_UNKNOWN_IDENT,
ERR_DUPLICATE_QUALIFIER,
ERR_CONST_ASSIGN,
- ERR_CONST_PARAM,
+ ERR_QUAL_DIFF,
ERR_COUNT /* Error count */
};
#include "scanner.h"
#include "stdfunc.h"
#include "symtab.h"
+#include "typecmp.h"
#include "expr.h"
* - 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;
* - 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) {
/* 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 {
* 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;
}
*/
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);
}
*/
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) {
/* 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);
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);
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);
} 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 */
type* ltype = lval->e_tptr;
/* Check for assignment to const */
- if (IsConst (ltype)) {
+ if (IsQualConst (ltype)) {
Error (ERR_CONST_ASSIGN);
}
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);
}
if (curtok == TOK_ASSIGN) {
/* Initialization ahead, switch to data segment */
- if (IsConst (Decl.Type)) {
+ if (IsQualConst (Decl.Type)) {
g_userodata ();
} else {
g_usedata ();
stmt.o \
symentry.o \
symtab.o \
+ typecmp.o \
util.o
LIBS = $(COMMON)/common.a
stdfunc.obj \
symentry.obj \
symtab.obj \
+ typecmp.obj \
util.obj
LIBS = ..\common\common.lib
FILE stdfunc.obj
FILE symentry.obj
FILE symtab.obj
+FILE typecmp.obj
FILE util.obj
LIBRARY ..\common\common.lib
|
{ "__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 },
{ "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 },
}
-
+
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.
TOK_FCONST,
TOK_ATTRIBUTE,
+ TOK_FAR,
TOK_FASTCALL,
TOK_AX,
TOK_EAX,
-
+
TOK_PRAGMA
} token_t;
/* Handle the strlen function */
{
struct expent pval;
+ static type ArgType[] = { T_PTR, T_SCHAR, T_END };
+
/* Fetch the parameter */
int k = hie1 (&pval);
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);
#include "funcdesc.h"
#include "global.h"
#include "symentry.h"
+#include "typecmp.h"
#include "symtab.h"
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) {
} 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
-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 */
{
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 */
-
-
-
--- /dev/null
+/*****************************************************************************/
+/* */
+/* 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;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* 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
+
+
+
+