mirror of
https://github.com/cc65/cc65.git
synced 2025-02-26 07:29:25 +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 */
|
||||
if (IsConst (Decl.Type)) {
|
||||
if (IsQualConst (Decl.Type)) {
|
||||
g_userodata ();
|
||||
} else {
|
||||
g_usedata ();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 ();
|
||||
|
@ -45,6 +45,7 @@ OBJS = anonname.o \
|
||||
stmt.o \
|
||||
symentry.o \
|
||||
symtab.o \
|
||||
typecmp.o \
|
||||
util.o
|
||||
|
||||
LIBS = $(COMMON)/common.a
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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.
|
||||
|
@ -125,10 +125,11 @@ typedef enum token_t {
|
||||
TOK_FCONST,
|
||||
|
||||
TOK_ATTRIBUTE,
|
||||
TOK_FAR,
|
||||
TOK_FASTCALL,
|
||||
TOK_AX,
|
||||
TOK_EAX,
|
||||
|
||||
|
||||
TOK_PRAGMA
|
||||
} token_t;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
{
|
||||
|
@ -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
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