1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-09 22:29:35 +00:00

Reworked type comparison and handling of type qualifiers

git-svn-id: svn://svn.cc65.org/cc65/trunk@285 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2000-08-14 22:18:26 +00:00
parent dcc0fe91a2
commit 25f5c69efa
16 changed files with 618 additions and 287 deletions

View File

@ -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 ();

View File

@ -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,48 +486,18 @@ type* Indirect (type* T)
int IsConst (const type* T)
/* Return true if the given type has a const memory image */
{
/* 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);
}
int IsTypeVoid (const type* T)
/* Return true if this is a void type */
{
return ((T[0] & T_MASK_TYPE) == T_TYPE_VOID && T[1] == T_END);
}
int IsClassPtr (const type* T)
/* Return true if this is a pointer type */
{
return (T[0] & T_MASK_CLASS) == T_CLASS_PTR;
}
int IsTypeChar (const type* T)
/* Return true if this is a character type */
{
return (T[0] & T_MASK_TYPE) == T_TYPE_CHAR && T[1] == T_END;
return (T[0] & T_MASK_TYPE) == T_TYPE_CHAR;
}
int IsClassInt (const type* T)
/* Return true if this is an integer type */
int IsTypeInt (const type* T)
/* Return true if this is an int type (signed or unsigned) */
{
return (T[0] & T_MASK_CLASS) == T_CLASS_INT;
return (T[0] & T_MASK_TYPE) == T_TYPE_INT;
}
@ -556,10 +510,50 @@ int IsTypeLong (const type* T)
int IsUnsigned (const type* T)
/* Return true if this is an unsigned type */
int IsTypePtr (const type* T)
/* Return true if this is a pointer type */
{
return (T[0] & T_MASK_SIGN) == T_SIGN_UNSIGNED;
return ((T[0] & T_MASK_TYPE) == T_TYPE_PTR);
}
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_FUNC);
}
int IsClassInt (const type* T)
/* Return true if this is an integer type */
{
return (T[0] & T_MASK_CLASS) == T_CLASS_INT;
}
int IsClassPtr (const type* T)
/* Return true if this is a pointer type */
{
return (T[0] & T_MASK_CLASS) == T_CLASS_PTR;
}
@ -572,10 +566,26 @@ int IsClassStruct (const type* T)
int IsTypeFunc (const type* T)
/* Return true if this is a function class */
int IsSignUnsigned (const type* T)
/* Return true if this is an unsigned type */
{
return ((T[0] & T_MASK_TYPE) == T_TYPE_FUNC);
return (T[0] & T_MASK_SIGN) == T_SIGN_UNSIGNED;
}
int IsQualConst (const type* T)
/* Return true if the given type has a const memory image */
{
return (GetQualifier (T) & T_QUAL_CONST) != 0;
}
int IsQualVolatile (const type* T)
/* Return true if the given type has a volatile type qualifier */
{
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);
}

View File

@ -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 IsTypeVoid (const type* Type);
/* Return true if this is a void type */
int IsClassPtr (const type* Type);
/* Return true if this is a pointer type */
int IsTypeChar (const type* Type);
int IsTypeChar (const type* T);
/* Return true if this is a character type */
int IsClassInt (const type* Type);
/* Return true if this is an integer type */
int IsTypeInt (const type* T);
/* Return true if this is an int type (signed or unsigned) */
int IsTypeLong (const type* Type);
int IsTypeLong (const type* T);
/* 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 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 IsFastCallFunc (const type* Type);
/* Return true if this is a function type with __fastcall__ calling conventions */
int IsTypeFuncPtr (const type* Type);
/* Return true if this is a function pointer */
int IsTypePtr (const type* Type);
/* Return true if this is a pointer type */
int IsTypeArray (const type* Type);
/* Return true if this is an array type */
struct FuncDesc* GetFuncDesc (const type* 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 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 IsSignUnsigned (const type* Type);
/* Return true if this is an unsigned 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* T);
/* Return true if this is a function pointer */
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* T);
/* Get the FuncDesc pointer from a function or pointer-to-function type */

View File

@ -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",
};

View File

@ -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 */
};

View File

@ -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);
}

View File

@ -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 ();

View File

@ -45,6 +45,7 @@ OBJS = anonname.o \
stmt.o \
symentry.o \
symtab.o \
typecmp.o \
util.o
LIBS = $(COMMON)/common.a

View File

@ -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
|

View File

@ -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.

View File

@ -125,10 +125,11 @@ typedef enum token_t {
TOK_FCONST,
TOK_ATTRIBUTE,
TOK_FAR,
TOK_FASTCALL,
TOK_AX,
TOK_EAX,
TOK_PRAGMA
} token_t;

View File

@ -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);

View File

@ -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 */
{

View File

@ -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);

315
src/cc65/typecmp.c Normal file
View File

@ -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;
}

81
src/cc65/typecmp.h Normal file
View File

@ -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