new style decls. git-svn-id: svn://svn.cc65.org/cc65/trunk@3869 b7a2c559-68d2-44c3-8de9-860c34a00d81
425 lines
13 KiB
C
425 lines
13 KiB
C
/*****************************************************************************/
|
|
/* */
|
|
/* typecmp.c */
|
|
/* */
|
|
/* Type compare function for the cc65 C compiler */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* (C) 1998-2008 Ullrich von Bassewitz */
|
|
/* Roemerstrasse 52 */
|
|
/* D-70794 Filderstadt */
|
|
/* EMail: uz@cc65.org */
|
|
/* */
|
|
/* */
|
|
/* 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 <string.h>
|
|
|
|
/* cc65 */
|
|
#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 ParamsHaveDefaultPromotions (const FuncDesc* F)
|
|
/* Check if any of the parameters of function F has a default promotion. In
|
|
* this case, the function is not compatible with an empty parameter name list
|
|
* declaration.
|
|
*/
|
|
{
|
|
/* Get the symbol table */
|
|
const SymTable* Tab = F->SymTab;
|
|
|
|
/* Get the first parameter in the list */
|
|
const SymEntry* Sym = Tab->SymHead;
|
|
|
|
/* Walk over all parameters */
|
|
while (Sym && (Sym->Flags & SC_PARAM)) {
|
|
|
|
/* If this is an integer type, check if the promoted type is equal
|
|
* to the original type. If not, we have a default promotion.
|
|
*/
|
|
if (IsClassInt (Sym->Type)) {
|
|
if (IntPromotion (Sym->Type) != Sym->Type) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* Get the pointer to the next param */
|
|
Sym = Sym->NextSym;
|
|
}
|
|
|
|
/* No default promotions in the parameter list */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static int EqualFuncParams (const FuncDesc* F1, const FuncDesc* F2)
|
|
/* Compare two function symbol tables regarding function parameters. Return 1
|
|
* if they are equal and 0 otherwise.
|
|
*/
|
|
{
|
|
/* Get the symbol tables */
|
|
const SymTable* Tab1 = F1->SymTab;
|
|
const SymTable* Tab2 = F2->SymTab;
|
|
|
|
/* Compare the parameter lists */
|
|
const SymEntry* Sym1 = Tab1->SymHead;
|
|
const SymEntry* Sym2 = Tab2->SymHead;
|
|
|
|
/* Compare the fields */
|
|
while (Sym1 && (Sym1->Flags & SC_PARAM) && Sym2 && (Sym2->Flags & SC_PARAM)) {
|
|
|
|
/* Get the symbol types */
|
|
Type* Type1 = Sym1->Type;
|
|
Type* Type2 = Sym2->Type;
|
|
|
|
/* If either of both functions is old style, apply the default
|
|
* promotions to the parameter type.
|
|
*/
|
|
if (F1->Flags & FD_OLDSTYLE) {
|
|
if (IsClassInt (Type1)) {
|
|
Type1 = IntPromotion (Type1);
|
|
}
|
|
}
|
|
if (F2->Flags & FD_OLDSTYLE) {
|
|
if (IsClassInt (Type2)) {
|
|
Type2 = IntPromotion (Type2);
|
|
}
|
|
}
|
|
|
|
/* Compare this field */
|
|
if (TypeCmp (Type1, Type2) < 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 or a non parameter to compare the
|
|
* field count
|
|
*/
|
|
return (Sym1 == 0 || (Sym1->Flags & SC_PARAM) == 0) &&
|
|
(Sym2 == 0 || (Sym2->Flags & SC_PARAM) == 0);
|
|
}
|
|
|
|
|
|
|
|
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 the names of this field */
|
|
if (!HasAnonName (Sym1) || !HasAnonName (Sym2)) {
|
|
if (strcmp (Sym1->Name, Sym2->Name) != 0) {
|
|
/* Names are not identical */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Compare the types of 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;
|
|
|
|
|
|
/* Initialize stuff */
|
|
Indirections = 0;
|
|
ElementCount = 0;
|
|
|
|
/* Compare two types. Determine, where they differ */
|
|
while (lhs->C != T_END) {
|
|
|
|
TypeCode LeftType, RightType;
|
|
TypeCode LeftSign, RightSign;
|
|
TypeCode LeftQual, RightQual;
|
|
long LeftCount, RightCount;
|
|
|
|
/* Check if the end of the type string is reached */
|
|
if (rhs->C == 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;
|
|
}
|
|
|
|
/* 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 = GetFuncDesc (lhs);
|
|
F2 = GetFuncDesc (rhs);
|
|
|
|
/* If one of both functions has an empty parameter list (which
|
|
* does also mean, it is not a function definition, because the
|
|
* flag is reset in this case), it is considered equal to any
|
|
* other definition, provided that the other has no default
|
|
* promotions in the parameter list. If none of both parameter
|
|
* lists is empty, we have to check the parameter lists and
|
|
* other attributes.
|
|
*/
|
|
if (F1->Flags & FD_EMPTY) {
|
|
if ((F2->Flags & FD_EMPTY) == 0) {
|
|
if (ParamsHaveDefaultPromotions (F2)) {
|
|
/* Flags differ */
|
|
SetResult (Result, TC_INCOMPATIBLE);
|
|
return;
|
|
}
|
|
}
|
|
} else if (F2->Flags & FD_EMPTY) {
|
|
if (ParamsHaveDefaultPromotions (F1)) {
|
|
/* Flags differ */
|
|
SetResult (Result, TC_INCOMPATIBLE);
|
|
return;
|
|
}
|
|
} else {
|
|
|
|
/* 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 (EqualFuncParams (F1, F2) == 0) {
|
|
/* Parameter list is not identical */
|
|
SetResult (Result, TC_INCOMPATIBLE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Keep on and compare the return type */
|
|
break;
|
|
|
|
case T_TYPE_ARRAY:
|
|
/* Check member count */
|
|
LeftCount = GetElementCount (lhs);
|
|
RightCount = GetElementCount (rhs);
|
|
if (LeftCount != UNSPECIFIED &&
|
|
RightCount != UNSPECIFIED &&
|
|
LeftCount != RightCount) {
|
|
/* Member count given but different */
|
|
SetResult (Result, TC_INCOMPATIBLE);
|
|
return;
|
|
}
|
|
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 = GetSymEntry (lhs);
|
|
Sym2 = GetSymEntry (rhs);
|
|
|
|
/* If one symbol has a name, the names must be identical */
|
|
if (!HasAnonName (Sym1) || !HasAnonName (Sym2)) {
|
|
if (strcmp (Sym1->Name, Sym2->Name) != 0) {
|
|
/* Names are not identical */
|
|
SetResult (Result, TC_INCOMPATIBLE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* 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 */
|
|
break;
|
|
}
|
|
|
|
/* Next type string element */
|
|
++lhs;
|
|
++rhs;
|
|
++ElementCount;
|
|
}
|
|
|
|
/* Check if end of rhs reached */
|
|
if (rhs->C == 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;
|
|
}
|
|
|
|
|
|
|
|
|