mirror of
https://github.com/cc65/cc65.git
synced 2025-02-26 23:30:03 +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:
parent
dcc0fe91a2
commit
25f5c69efa
@ -173,7 +173,7 @@ static void Parse (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Switch to the data or rodata segment */
|
/* Switch to the data or rodata segment */
|
||||||
if (IsConst (Decl.Type)) {
|
if (IsQualConst (Decl.Type)) {
|
||||||
g_userodata ();
|
g_userodata ();
|
||||||
} else {
|
} else {
|
||||||
g_usedata ();
|
g_usedata ();
|
||||||
|
@ -62,8 +62,6 @@ type type_uint [] = { T_UINT, T_END };
|
|||||||
type type_long [] = { T_LONG, T_END };
|
type type_long [] = { T_LONG, T_END };
|
||||||
type type_ulong [] = { T_ULONG, T_END };
|
type type_ulong [] = { T_ULONG, T_END };
|
||||||
type type_void [] = { T_VOID, 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 */
|
/* Return the length of the type string */
|
||||||
{
|
{
|
||||||
const type* Start = T;
|
const type* Start = T;
|
||||||
while (*T) {
|
while (*T != T_END) {
|
||||||
++T;
|
++T;
|
||||||
}
|
}
|
||||||
return T - Start;
|
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)
|
type* TypeCpy (type* Dest, const type* Src)
|
||||||
/* Copy a type string */
|
/* 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)
|
int IsTypeChar (const type* T)
|
||||||
/* Return true if this is a character type */
|
/* 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)
|
int IsTypeInt (const type* T)
|
||||||
/* Return true if this is an integer type */
|
/* 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)
|
int IsTypePtr (const type* T)
|
||||||
/* Return true if this is an unsigned type */
|
/* 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)
|
int IsSignUnsigned (const type* T)
|
||||||
/* Return true if this is a function class */
|
/* 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)
|
type GetType (const type* T)
|
||||||
/* Return true if this is an array type */
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -143,8 +143,6 @@ extern type type_uint [];
|
|||||||
extern type type_long [];
|
extern type type_long [];
|
||||||
extern type type_ulong [];
|
extern type type_ulong [];
|
||||||
extern type type_void [];
|
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);
|
unsigned TypeLen (const type* Type);
|
||||||
/* Return the length of the type string */
|
/* 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);
|
type* TypeCpy (type* Dest, const type* Src);
|
||||||
/* Copy a type string */
|
/* Copy a type string */
|
||||||
|
|
||||||
@ -227,43 +222,67 @@ type* Indirect (type* Type);
|
|||||||
* given type points to.
|
* given type points to.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int IsConst (const type* T);
|
int IsTypeChar (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);
|
|
||||||
/* Return true if this is a character type */
|
/* Return true if this is a character type */
|
||||||
|
|
||||||
int IsClassInt (const type* Type);
|
int IsTypeInt (const type* T);
|
||||||
/* Return true if this is an integer type */
|
/* 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) */
|
/* Return true if this is a long type (signed or unsigned) */
|
||||||
|
|
||||||
int IsUnsigned (const type* Type);
|
int IsTypePtr (const type* Type);
|
||||||
/* Return true if this is an unsigned 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 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 IsTypeArray (const type* Type);
|
int IsTypeArray (const type* Type);
|
||||||
/* Return true if this is an array 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 */
|
/* Get the FuncDesc pointer from a function or pointer-to-function type */
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,7 +107,8 @@ static char* ErrMsg [ERR_COUNT-1] = {
|
|||||||
"Unexpected `#else'",
|
"Unexpected `#else'",
|
||||||
"`#endif' expected",
|
"`#endif' expected",
|
||||||
"Compiler directive expected",
|
"Compiler directive expected",
|
||||||
"Symbol `%s' defined more than once",
|
"Redefinition of `%s'",
|
||||||
|
"Conflicting types for `%s'",
|
||||||
"String literal expected",
|
"String literal expected",
|
||||||
"`while' expected",
|
"`while' expected",
|
||||||
"Function must return a value",
|
"Function must return a value",
|
||||||
@ -152,8 +153,8 @@ static char* ErrMsg [ERR_COUNT-1] = {
|
|||||||
"Variable has unknown size",
|
"Variable has unknown size",
|
||||||
"Unknown identifier: `%s'",
|
"Unknown identifier: `%s'",
|
||||||
"Duplicate qualifier: `%s'",
|
"Duplicate qualifier: `%s'",
|
||||||
"Assignment discards `const' qualifier",
|
"Assignment to const",
|
||||||
"Passing argument %u discards `const' qualifier",
|
"Pointer types differ in type qualifiers",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,6 +103,7 @@ enum Errors {
|
|||||||
ERR_CPP_ENDIF_EXPECTED,
|
ERR_CPP_ENDIF_EXPECTED,
|
||||||
ERR_CPP_DIRECTIVE_EXPECTED,
|
ERR_CPP_DIRECTIVE_EXPECTED,
|
||||||
ERR_MULTIPLE_DEFINITION,
|
ERR_MULTIPLE_DEFINITION,
|
||||||
|
ERR_CONFLICTING_TYPES,
|
||||||
ERR_STRLIT_EXPECTED,
|
ERR_STRLIT_EXPECTED,
|
||||||
ERR_WHILE_EXPECTED,
|
ERR_WHILE_EXPECTED,
|
||||||
ERR_MUST_RETURN_VALUE,
|
ERR_MUST_RETURN_VALUE,
|
||||||
@ -148,7 +149,7 @@ enum Errors {
|
|||||||
ERR_UNKNOWN_IDENT,
|
ERR_UNKNOWN_IDENT,
|
||||||
ERR_DUPLICATE_QUALIFIER,
|
ERR_DUPLICATE_QUALIFIER,
|
||||||
ERR_CONST_ASSIGN,
|
ERR_CONST_ASSIGN,
|
||||||
ERR_CONST_PARAM,
|
ERR_QUAL_DIFF,
|
||||||
ERR_COUNT /* Error count */
|
ERR_COUNT /* Error count */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "stdfunc.h"
|
#include "stdfunc.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
|
#include "typecmp.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
|
||||||
|
|
||||||
@ -132,13 +133,13 @@ static type* promoteint (type* lhst, type* rhst)
|
|||||||
* - Otherwise the result is an int.
|
* - Otherwise the result is an int.
|
||||||
*/
|
*/
|
||||||
if (IsTypeLong (lhst) || IsTypeLong (rhst)) {
|
if (IsTypeLong (lhst) || IsTypeLong (rhst)) {
|
||||||
if (IsUnsigned (lhst) || IsUnsigned (rhst)) {
|
if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) {
|
||||||
return type_ulong;
|
return type_ulong;
|
||||||
} else {
|
} else {
|
||||||
return type_long;
|
return type_long;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (IsUnsigned (lhst) || IsUnsigned (rhst)) {
|
if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) {
|
||||||
return type_uint;
|
return type_uint;
|
||||||
} else {
|
} else {
|
||||||
return type_int;
|
return type_int;
|
||||||
@ -232,11 +233,23 @@ unsigned assignadjust (type* lhst, struct expent* rhs)
|
|||||||
* - the rhs pointer is a void pointer, or
|
* - the rhs pointer is a void pointer, or
|
||||||
* - the lhs pointer is a void pointer.
|
* - the lhs pointer is a void pointer.
|
||||||
*/
|
*/
|
||||||
type* left = Indirect (lhst);
|
if (!IsTypeVoid (Indirect (lhst)) && !IsTypeVoid (Indirect (rhst))) {
|
||||||
type* right = Indirect (rhst);
|
/* Compare the types */
|
||||||
if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) {
|
switch (TypeCmp (lhst, rhst)) {
|
||||||
Error (ERR_INCOMPATIBLE_POINTERS);
|
|
||||||
}
|
case TC_INCOMPATIBLE:
|
||||||
|
Error (ERR_INCOMPATIBLE_POINTERS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TC_QUAL_DIFF:
|
||||||
|
Error (ERR_QUAL_DIFF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Ok */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (IsClassInt (rhst)) {
|
} else if (IsClassInt (rhst)) {
|
||||||
/* Int to pointer assignment is valid only for constant zero */
|
/* Int to pointer assignment is valid only for constant zero */
|
||||||
if ((rhs->e_flags & E_MCONST) == 0 || rhs->e_const != 0) {
|
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
|
/* Assignment of function to function pointer is allowed, provided
|
||||||
* that both functions have the same parameter list.
|
* that both functions have the same parameter list.
|
||||||
*/
|
*/
|
||||||
if (!EqualTypes(Indirect (lhst), rhst)) {
|
if (TypeCmp (Indirect (lhst), rhst) < TC_EQUAL) {
|
||||||
Error (ERR_INCOMPATIBLE_TYPES);
|
Error (ERR_INCOMPATIBLE_TYPES);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -580,18 +593,9 @@ static void callfunction (struct expent* lval)
|
|||||||
* convert the actual argument to the type needed.
|
* convert the actual argument to the type needed.
|
||||||
*/
|
*/
|
||||||
if (!Ellipsis) {
|
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 */
|
/* Promote the argument if needed */
|
||||||
assignadjust (Param->Type, &lval2);
|
assignadjust (Param->Type, &lval2);
|
||||||
|
|
||||||
/* If we have a prototype, chars may be pushed as chars */
|
/* If we have a prototype, chars may be pushed as chars */
|
||||||
Flags |= CF_FORCECHAR;
|
Flags |= CF_FORCECHAR;
|
||||||
}
|
}
|
||||||
@ -1713,7 +1717,7 @@ static int hie_compare (GenDesc** ops, /* List of generators */
|
|||||||
*/
|
*/
|
||||||
type* left = Indirect (lval->e_tptr);
|
type* left = Indirect (lval->e_tptr);
|
||||||
type* right = Indirect (lval2.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 */
|
/* Incomatible pointers */
|
||||||
Error (ERR_INCOMPATIBLE_TYPES);
|
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)) {
|
if (IsTypeChar (lval->e_tptr) && (IsTypeChar (lval2.e_tptr) || rconst)) {
|
||||||
flags |= CF_CHAR;
|
flags |= CF_CHAR;
|
||||||
if (IsUnsigned (lval->e_tptr) || IsUnsigned (lval2.e_tptr)) {
|
if (IsSignUnsigned (lval->e_tptr) || IsSignUnsigned (lval2.e_tptr)) {
|
||||||
flags |= CF_UNSIGNED;
|
flags |= CF_UNSIGNED;
|
||||||
}
|
}
|
||||||
if (rconst) {
|
if (rconst) {
|
||||||
@ -2017,7 +2021,7 @@ static void parsesub (int k, struct expent* lval)
|
|||||||
/* Operate on pointers, result type is a pointer */
|
/* Operate on pointers, result type is a pointer */
|
||||||
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
||||||
/* Left is pointer, right is pointer, must scale result */
|
/* 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);
|
Error (ERR_INCOMPATIBLE_POINTERS);
|
||||||
} else {
|
} else {
|
||||||
lval->e_const = (lval->e_const - lval2.e_const) / PSizeOf (lhst);
|
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;
|
flags = CF_PTR;
|
||||||
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
||||||
/* Left is pointer, right is pointer, must scale result */
|
/* 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);
|
Error (ERR_INCOMPATIBLE_POINTERS);
|
||||||
} else {
|
} else {
|
||||||
rscale = PSizeOf (lhst);
|
rscale = PSizeOf (lhst);
|
||||||
@ -2095,7 +2099,7 @@ static void parsesub (int k, struct expent* lval)
|
|||||||
flags = CF_PTR;
|
flags = CF_PTR;
|
||||||
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
||||||
/* Left is pointer, right is pointer, must scale result */
|
/* 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);
|
Error (ERR_INCOMPATIBLE_POINTERS);
|
||||||
} else {
|
} else {
|
||||||
rscale = PSizeOf (lhst);
|
rscale = PSizeOf (lhst);
|
||||||
@ -2454,7 +2458,7 @@ static int hieQuest (struct expent *lval)
|
|||||||
|
|
||||||
} else if (IsClassPtr (type2) && IsClassPtr (type3)) {
|
} else if (IsClassPtr (type2) && IsClassPtr (type3)) {
|
||||||
/* Must point to same type */
|
/* Must point to same type */
|
||||||
if (TypeCmp (Indirect (type2), Indirect (type3)) != 0) {
|
if (TypeCmp (Indirect (type2), Indirect (type3)) < TC_EQUAL) {
|
||||||
Error (ERR_INCOMPATIBLE_TYPES);
|
Error (ERR_INCOMPATIBLE_TYPES);
|
||||||
}
|
}
|
||||||
/* Result has the common type */
|
/* Result has the common type */
|
||||||
@ -2667,7 +2671,7 @@ static void Assignment (struct expent* lval)
|
|||||||
type* ltype = lval->e_tptr;
|
type* ltype = lval->e_tptr;
|
||||||
|
|
||||||
/* Check for assignment to const */
|
/* Check for assignment to const */
|
||||||
if (IsConst (ltype)) {
|
if (IsQualConst (ltype)) {
|
||||||
Error (ERR_CONST_ASSIGN);
|
Error (ERR_CONST_ASSIGN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2695,7 +2699,7 @@ static void Assignment (struct expent* lval)
|
|||||||
g_push (CF_PTR | CF_UNSIGNED, 0);
|
g_push (CF_PTR | CF_UNSIGNED, 0);
|
||||||
|
|
||||||
/* Check for equality of the structs */
|
/* Check for equality of the structs */
|
||||||
if (!EqualTypes (ltype, lval2.e_tptr)) {
|
if (TypeCmp (ltype, lval2.e_tptr) < TC_EQUAL) {
|
||||||
Error (ERR_INCOMPATIBLE_TYPES);
|
Error (ERR_INCOMPATIBLE_TYPES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
|||||||
if (curtok == TOK_ASSIGN) {
|
if (curtok == TOK_ASSIGN) {
|
||||||
|
|
||||||
/* Initialization ahead, switch to data segment */
|
/* Initialization ahead, switch to data segment */
|
||||||
if (IsConst (Decl.Type)) {
|
if (IsQualConst (Decl.Type)) {
|
||||||
g_userodata ();
|
g_userodata ();
|
||||||
} else {
|
} else {
|
||||||
g_usedata ();
|
g_usedata ();
|
||||||
|
@ -45,6 +45,7 @@ OBJS = anonname.o \
|
|||||||
stmt.o \
|
stmt.o \
|
||||||
symentry.o \
|
symentry.o \
|
||||||
symtab.o \
|
symtab.o \
|
||||||
|
typecmp.o \
|
||||||
util.o
|
util.o
|
||||||
|
|
||||||
LIBS = $(COMMON)/common.a
|
LIBS = $(COMMON)/common.a
|
||||||
|
@ -100,6 +100,7 @@ OBJS = anonname.obj \
|
|||||||
stdfunc.obj \
|
stdfunc.obj \
|
||||||
symentry.obj \
|
symentry.obj \
|
||||||
symtab.obj \
|
symtab.obj \
|
||||||
|
typecmp.obj \
|
||||||
util.obj
|
util.obj
|
||||||
|
|
||||||
LIBS = ..\common\common.lib
|
LIBS = ..\common\common.lib
|
||||||
@ -156,6 +157,7 @@ FILE segname.obj
|
|||||||
FILE stdfunc.obj
|
FILE stdfunc.obj
|
||||||
FILE symentry.obj
|
FILE symentry.obj
|
||||||
FILE symtab.obj
|
FILE symtab.obj
|
||||||
|
FILE typecmp.obj
|
||||||
FILE util.obj
|
FILE util.obj
|
||||||
LIBRARY ..\common\common.lib
|
LIBRARY ..\common\common.lib
|
||||||
|
|
|
|
||||||
|
@ -52,6 +52,7 @@ static const struct Keyword {
|
|||||||
{ "__EAX__", TOK_EAX, TT_C },
|
{ "__EAX__", TOK_EAX, TT_C },
|
||||||
{ "__asm__", TOK_ASM, TT_C },
|
{ "__asm__", TOK_ASM, TT_C },
|
||||||
{ "__attribute__", TOK_ATTRIBUTE, TT_C },
|
{ "__attribute__", TOK_ATTRIBUTE, TT_C },
|
||||||
|
{ "__far__", TOK_FAR, TT_C },
|
||||||
{ "__fastcall__", TOK_FASTCALL, TT_C },
|
{ "__fastcall__", TOK_FASTCALL, TT_C },
|
||||||
{ "asm", TOK_ASM, TT_EXT },
|
{ "asm", TOK_ASM, TT_EXT },
|
||||||
{ "auto", TOK_AUTO, TT_C },
|
{ "auto", TOK_AUTO, TT_C },
|
||||||
@ -66,6 +67,7 @@ static const struct Keyword {
|
|||||||
{ "else", TOK_ELSE, TT_C },
|
{ "else", TOK_ELSE, TT_C },
|
||||||
{ "enum", TOK_ENUM, TT_C },
|
{ "enum", TOK_ENUM, TT_C },
|
||||||
{ "extern", TOK_EXTERN, TT_C },
|
{ "extern", TOK_EXTERN, TT_C },
|
||||||
|
{ "far", TOK_FAR, TT_EXT },
|
||||||
{ "fastcall", TOK_FASTCALL, TT_EXT },
|
{ "fastcall", TOK_FASTCALL, TT_EXT },
|
||||||
{ "float", TOK_FLOAT, TT_C },
|
{ "float", TOK_FLOAT, TT_C },
|
||||||
{ "for", TOK_FOR, TT_C },
|
{ "for", TOK_FOR, TT_C },
|
||||||
|
@ -125,6 +125,7 @@ typedef enum token_t {
|
|||||||
TOK_FCONST,
|
TOK_FCONST,
|
||||||
|
|
||||||
TOK_ATTRIBUTE,
|
TOK_ATTRIBUTE,
|
||||||
|
TOK_FAR,
|
||||||
TOK_FASTCALL,
|
TOK_FASTCALL,
|
||||||
TOK_AX,
|
TOK_AX,
|
||||||
TOK_EAX,
|
TOK_EAX,
|
||||||
|
@ -111,6 +111,8 @@ static void StdFunc_strlen (struct expent* lval)
|
|||||||
/* Handle the strlen function */
|
/* Handle the strlen function */
|
||||||
{
|
{
|
||||||
struct expent pval;
|
struct expent pval;
|
||||||
|
static type ArgType[] = { T_PTR, T_SCHAR, T_END };
|
||||||
|
|
||||||
|
|
||||||
/* Fetch the parameter */
|
/* Fetch the parameter */
|
||||||
int k = hie1 (&pval);
|
int k = hie1 (&pval);
|
||||||
@ -135,8 +137,11 @@ static void StdFunc_strlen (struct expent* lval)
|
|||||||
exprhs (CF_NONE, k, &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 */
|
/* 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 */
|
/* Generate the strlen code */
|
||||||
g_strlen (flags, pval.e_name, pval.e_const);
|
g_strlen (flags, pval.e_name, pval.e_const);
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "funcdesc.h"
|
#include "funcdesc.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "symentry.h"
|
#include "symentry.h"
|
||||||
|
#include "typecmp.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
|
|
||||||
|
|
||||||
@ -692,9 +693,9 @@ SymEntry* AddGlobalSym (const char* Name, type* Type, unsigned Flags)
|
|||||||
unsigned ESize = Decode (EType + 1);
|
unsigned ESize = Decode (EType + 1);
|
||||||
|
|
||||||
if ((Size != 0 && ESize != 0) ||
|
if ((Size != 0 && ESize != 0) ||
|
||||||
TypeCmp (Type+DECODE_SIZE+1, EType+DECODE_SIZE+1) != 0) {
|
TypeCmp (Type+DECODE_SIZE+1, EType+DECODE_SIZE+1) < TC_EQUAL) {
|
||||||
/* Types not identical: Duplicate definition */
|
/* Types not identical: Conflicting types */
|
||||||
Error (ERR_MULTIPLE_DEFINITION, Name);
|
Error (ERR_CONFLICTING_TYPES, Name);
|
||||||
} else {
|
} else {
|
||||||
/* Check if we have a size in the existing definition */
|
/* Check if we have a size in the existing definition */
|
||||||
if (ESize == 0) {
|
if (ESize == 0) {
|
||||||
@ -705,8 +706,8 @@ SymEntry* AddGlobalSym (const char* Name, type* Type, unsigned Flags)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* New type must be identical */
|
/* New type must be identical */
|
||||||
if (!EqualTypes (EType, Type) != 0) {
|
if (TypeCmp (EType, Type) < TC_EQUAL) {
|
||||||
Error (ERR_MULTIPLE_DEFINITION, Name);
|
Error (ERR_CONFLICTING_TYPES, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In case of a function, use the new type descriptor, since it
|
/* 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)
|
void MakeZPSym (const char* Name)
|
||||||
/* Mark the given symbol as zero page symbol */
|
/* Mark the given symbol as zero page symbol */
|
||||||
{
|
{
|
||||||
|
@ -163,11 +163,6 @@ SymTable* GetSymTab (void);
|
|||||||
int SymIsLocal (SymEntry* Sym);
|
int SymIsLocal (SymEntry* Sym);
|
||||||
/* Return true if the symbol is defined in the highest lexical level */
|
/* 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);
|
void MakeZPSym (const char* Name);
|
||||||
/* Mark the given symbol as zero page symbol */
|
/* Mark the given symbol as zero page symbol */
|
||||||
|
|
||||||
@ -185,6 +180,3 @@ void EmitExternals (void);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
315
src/cc65/typecmp.c
Normal file
315
src/cc65/typecmp.c
Normal 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
81
src/cc65/typecmp.h
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user