1
0
mirror of https://github.com/cc65/cc65.git synced 2025-02-03 22:32:24 +00:00

Fixed underlying types of enums.

Made enumerator diagnostics more sensible.
Fixed Issue #1048 as a natural result.
This commit is contained in:
acqn 2020-07-26 20:12:55 +08:00 committed by Oliver Schmidt
parent c272c73686
commit daa65199b3
9 changed files with 526 additions and 124 deletions

View File

@ -83,14 +83,9 @@ const char* GetBasicTypeName (const Type* T)
** Return "type" for unknown basic types.
*/
{
switch (GetType (T)) {
case T_TYPE_CHAR: return "char";
case T_TYPE_SHORT: return "short";
case T_TYPE_INT: return "integer";
case T_TYPE_LONG: return "long";
case T_TYPE_LONGLONG: return "long long";
switch (GetRawType (T)) {
case T_TYPE_ENUM: return "enum";
case T_TYPE_FLOAT: return "poinfloatter";
case T_TYPE_FLOAT: return "float";
case T_TYPE_DOUBLE: return "double";
case T_TYPE_VOID: return "void";
case T_TYPE_STRUCT: return "struct";
@ -99,8 +94,42 @@ const char* GetBasicTypeName (const Type* T)
case T_TYPE_PTR: return "pointer";
case T_TYPE_FUNC: return "function";
case T_TYPE_NONE: /* FALLTHROUGH */
default: return "type";
default: break;
}
if (IsClassInt (T)) {
if (IsSignSigned (T)) {
switch (GetRawType (T)) {
case T_TYPE_CHAR: return "signed char";
case T_TYPE_SHORT: return "short";
case T_TYPE_INT: return "int";
case T_TYPE_LONG: return "long";
case T_TYPE_LONGLONG: return "long long";
default:
return "signed integer";
}
} else if (IsSignUnsigned (T)) {
switch (GetRawType (T)) {
case T_TYPE_CHAR: return "unsigned char";
case T_TYPE_SHORT: return "unsigned short";
case T_TYPE_INT: return "unsigned int";
case T_TYPE_LONG: return "unsigned long";
case T_TYPE_LONGLONG: return "unsigned long long";
default:
return "unsigned integer";
}
} else {
switch (GetRawType (T)) {
case T_TYPE_CHAR: return "char";
case T_TYPE_SHORT: return "short";
case T_TYPE_INT: return "int";
case T_TYPE_LONG: return "long";
case T_TYPE_LONGLONG: return "long long";
default:
return "integer";
}
}
}
return "type";
}
@ -245,6 +274,49 @@ const Type* GetStructReplacementType (const Type* SType)
long GetIntegerTypeMin (const Type* Type)
/* Get the smallest possible value of the integer type */
{
if (IsSignSigned (Type)) {
return (long)(0xFFFFFFFF << (CHAR_BITS * SizeOf (Type) - 1U));
} else {
return 0;
}
}
unsigned long GetIntegerTypeMax (const Type* Type)
/* Get the largest possible value of the integer type */
{
if (IsSignSigned (Type)) {
return (1UL << (CHAR_BITS * SizeOf (Type) - 1U)) - 1UL;
} else {
return (1UL << (CHAR_BITS * SizeOf (Type))) - 1UL;
}
}
static unsigned TypeOfBySize (const Type* Type)
/* Get the code generator replacement type of the object by its size */
{
unsigned NewType;
/* If the size is less than or equal to that of a a long, we will copy
** the struct using the primary register, otherwise we use memcpy.
*/
switch (SizeOf (Type)) {
case 1: NewType = CF_CHAR; break;
case 2: NewType = CF_INT; break;
case 3: /* FALLTHROUGH */
case 4: NewType = CF_LONG; break;
default: NewType = CF_NONE; break;
}
return NewType;
}
Type* PointerTo (const Type* T)
/* Return a type string that is "pointer to T". The type string is allocated
** on the heap and may be freed after use.
@ -321,6 +393,9 @@ void PrintType (FILE* F, const Type* T)
case T_TYPE_LONGLONG:
fprintf (F, "long long");
break;
case T_TYPE_ENUM:
fprintf (F, "enum");
break;
case T_TYPE_FLOAT:
fprintf (F, "float");
break;
@ -430,10 +505,68 @@ int TypeHasAttr (const Type* T)
const Type* GetUnderlyingType (const Type* Type)
/* Get the underlying type of an enum or other integer class type */
{
if (IsTypeEnum (Type)) {
/* This should not happen, but just in case */
if (Type->A.P == 0) {
Internal ("Enum tag type error in GetUnderlyingTypeCode");
}
return ((SymEntry*)Type->A.P)->V.E.Type;
}
return Type;
}
TypeCode GetUnderlyingTypeCode (const Type* Type)
/* Get the type code of the unqualified underlying type of TCode.
** Return UnqualifiedType (TCode) if TCode is not scalar.
*/
{
TypeCode Underlying = UnqualifiedType (Type->C);
TypeCode TCode;
/* We could also support other T_CLASS_INT types, but just enums for now */
if (IsTypeEnum (Type)) {
/* This should not happen, but just in case */
if (Type->A.P == 0) {
Internal ("Enum tag type error in GetUnderlyingTypeCode");
}
/* Inspect the underlying type of the enum */
if (((SymEntry*)Type->A.P)->V.E.Type == 0) {
/* Incomplete enum type is used */
return Underlying;
}
TCode = UnqualifiedType (((SymEntry*)Type->A.P)->V.E.Type->C);
/* Replace the type code with integer */
Underlying = (TCode & ~T_MASK_TYPE);
switch (TCode & T_MASK_SIZE) {
case T_SIZE_INT: Underlying |= T_TYPE_INT; break;
case T_SIZE_LONG: Underlying |= T_TYPE_LONG; break;
case T_SIZE_SHORT: Underlying |= T_TYPE_SHORT; break;
case T_SIZE_CHAR: Underlying |= T_TYPE_CHAR; break;
case T_SIZE_LONGLONG: Underlying |= T_TYPE_LONGLONG; break;
default: Underlying |= T_TYPE_INT; break;
}
}
return Underlying;
}
unsigned SizeOf (const Type* T)
/* Compute size of object represented by type array. */
{
switch (UnqualifiedType (T->C)) {
switch (GetUnderlyingTypeCode (T)) {
case T_VOID:
/* A void variable is a cc65 extension.
@ -470,9 +603,6 @@ unsigned SizeOf (const Type* T)
case T_ULONGLONG:
return SIZEOF_LONGLONG;
case T_ENUM:
return SIZEOF_INT;
case T_FLOAT:
return SIZEOF_FLOAT;
@ -491,7 +621,12 @@ unsigned SizeOf (const Type* T)
return T->A.U * SizeOf (T + 1);
}
case T_ENUM:
/* Incomplete enum type */
return 0;
default:
Internal ("Unknown type in SizeOf: %04lX", T->C);
return 0;
@ -547,7 +682,9 @@ unsigned CheckedPSizeOf (const Type* T)
unsigned TypeOf (const Type* T)
/* Get the code generator base type of the object */
{
switch (UnqualifiedType (T->C)) {
unsigned NewType;
switch (GetUnderlyingTypeCode (T)) {
case T_SCHAR:
return CF_CHAR;
@ -557,7 +694,6 @@ unsigned TypeOf (const Type* T)
case T_SHORT:
case T_INT:
case T_ENUM:
return CF_INT;
case T_USHORT:
@ -582,6 +718,10 @@ unsigned TypeOf (const Type* T)
case T_STRUCT:
case T_UNION:
NewType = TypeOfBySize (T);
if (NewType != CF_NONE) {
return NewType;
}
/* Address of ... */
return CF_INT | CF_UNSIGNED;
@ -726,8 +866,8 @@ Type* GetBaseElementType (Type* T)
SymEntry* GetSymEntry (const Type* T)
/* Return a SymEntry pointer from a type */
{
/* Only structs or unions have a SymEntry attribute */
CHECK (IsClassStruct (T));
/* Only enums, structs or unions have a SymEntry attribute */
CHECK (IsClassStruct (T) || IsTypeEnum (T));
/* Return the attribute */
return T->A.P;
@ -738,8 +878,8 @@ SymEntry* GetSymEntry (const Type* T)
void SetSymEntry (Type* T, SymEntry* S)
/* Set the SymEntry pointer for a type */
{
/* Only structs or unions have a SymEntry attribute */
CHECK (IsClassStruct (T));
/* Only enums, structs or unions have a SymEntry attribute */
CHECK (IsClassStruct (T) || IsTypeEnum (T));
/* Set the attribute */
T->A.P = S;

View File

@ -96,37 +96,39 @@ enum {
/* Type size modifiers */
T_SIZE_NONE = 0x000000,
T_SIZE_SHORT = 0x000200,
T_SIZE_LONG = 0x000400,
T_SIZE_LONGLONG = 0x000600,
T_MASK_SIZE = 0x000600,
T_SIZE_CHAR = 0x000200,
T_SIZE_SHORT = 0x000400,
T_SIZE_INT = 0x000600,
T_SIZE_LONG = 0x000800,
T_SIZE_LONGLONG = 0x000A00,
T_MASK_SIZE = 0x000E00,
/* Type qualifiers */
T_QUAL_NONE = 0x000000,
T_QUAL_CONST = 0x000800,
T_QUAL_VOLATILE = 0x001000,
T_QUAL_RESTRICT = 0x002000,
T_QUAL_NEAR = 0x004000,
T_QUAL_FAR = 0x008000,
T_QUAL_CONST = 0x001000,
T_QUAL_VOLATILE = 0x002000,
T_QUAL_RESTRICT = 0x004000,
T_QUAL_NEAR = 0x008000,
T_QUAL_FAR = 0x010000,
T_QUAL_ADDRSIZE = T_QUAL_NEAR | T_QUAL_FAR,
T_QUAL_FASTCALL = 0x010000,
T_QUAL_CDECL = 0x020000,
T_QUAL_FASTCALL = 0x020000,
T_QUAL_CDECL = 0x040000,
T_QUAL_CCONV = T_QUAL_FASTCALL | T_QUAL_CDECL,
T_MASK_QUAL = 0x03F800,
T_MASK_QUAL = 0x07F000,
/* Types */
T_CHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_NONE,
T_SCHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_NONE,
T_UCHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_NONE,
T_CHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_CHAR,
T_SCHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_CHAR,
T_UCHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_CHAR,
T_SHORT = T_TYPE_SHORT | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_SHORT,
T_USHORT = T_TYPE_SHORT | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_SHORT,
T_INT = T_TYPE_INT | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_NONE,
T_UINT = T_TYPE_INT | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_NONE,
T_INT = T_TYPE_INT | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_INT,
T_UINT = T_TYPE_INT | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_INT,
T_LONG = T_TYPE_LONG | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_LONG,
T_ULONG = T_TYPE_LONG | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_LONG,
T_LONGLONG = T_TYPE_LONGLONG | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_LONGLONG,
T_ULONGLONG = T_TYPE_LONGLONG | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_LONGLONG,
T_ENUM = T_TYPE_ENUM | T_CLASS_INT | T_SIGN_SIGNED | T_SIZE_NONE,
T_ENUM = T_TYPE_ENUM | T_CLASS_INT | T_SIGN_NONE | T_SIZE_NONE,
T_FLOAT = T_TYPE_FLOAT | T_CLASS_FLOAT | T_SIGN_NONE | T_SIZE_NONE,
T_DOUBLE = T_TYPE_DOUBLE | T_CLASS_FLOAT | T_SIGN_NONE | T_SIZE_NONE,
T_VOID = T_TYPE_VOID | T_CLASS_NONE | T_SIGN_NONE | T_SIZE_NONE,
@ -246,6 +248,12 @@ Type* GetImplicitFuncType (void);
const Type* GetStructReplacementType (const Type* SType);
/* Get a replacement type for passing a struct/union in the primary register */
long GetIntegerTypeMin (const Type* Type);
/* Get the smallest possible value of the integer type */
unsigned long GetIntegerTypeMax (const Type* Type);
/* Get the largest possible value of the integer type */
Type* PointerTo (const Type* T);
/* Return a type string that is "pointer to T". The type string is allocated
** on the heap and may be freed after use.
@ -283,6 +291,14 @@ INLINE TypeCode UnqualifiedType (TypeCode T)
# define UnqualifiedType(T) ((T) & ~T_MASK_QUAL)
#endif
const Type* GetUnderlyingType (const Type* Type);
/* Get the underlying type of an enum or other integer class type */
TypeCode GetUnderlyingTypeCode (const Type* Type);
/* Get the type code of the unqualified underlying type of TCode.
** Return TCode if it is not scalar.
*/
unsigned SizeOf (const Type* T);
/* Compute size of object represented by type array. */
@ -312,123 +328,163 @@ Type* ArrayToPtr (Type* T);
/* Convert an array to a pointer to it's first element */
#if defined(HAVE_INLINE)
INLINE TypeCode GetType (const Type* T)
INLINE TypeCode GetRawType (const Type* T)
/* Get the raw type */
{
return (T->C & T_MASK_TYPE);
}
#else
# define GetType(T) ((T)->C & T_MASK_TYPE)
# define GetRawType(T) ((T)->C & T_MASK_TYPE)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeChar (const Type* T)
/* Return true if this is a character type */
{
return (GetType (T) == T_TYPE_CHAR);
return (GetRawType (GetUnderlyingType (T)) == T_TYPE_CHAR);
}
#else
# define IsTypeChar(T) (GetType (T) == T_TYPE_CHAR)
# define IsTypeChar(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_CHAR)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeInt (const Type* T)
/* Return true if this is an int type (signed or unsigned) */
{
return (GetType (T) == T_TYPE_INT);
return (GetRawType (GetUnderlyingType (T)) == T_TYPE_INT);
}
#else
# define IsTypeInt(T) (GetType (T) == T_TYPE_INT)
# define IsTypeInt(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_INT)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeLong (const Type* T)
/* Return true if this is a long type (signed or unsigned) */
{
return (GetType (T) == T_TYPE_LONG);
return (GetRawType (GetUnderlyingType (T)) == T_TYPE_LONG);
}
#else
# define IsTypeLong(T) (GetType (T) == T_TYPE_LONG)
# define IsTypeLong(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_LONG)
#endif
#if defined(HAVE_INLINE)
INLINE int IsRawTypeChar (const Type* T)
/* Return true if this is a character raw type */
{
return (GetRawType (T) == T_TYPE_CHAR);
}
#else
# define IsRawTypeChar(T) (GetRawType (T) == T_TYPE_CHAR)
#endif
#if defined(HAVE_INLINE)
INLINE int IsRawTypeInt (const Type* T)
/* Return true if this is an int raw type (signed or unsigned) */
{
return (GetRawType (T) == T_TYPE_INT);
}
#else
# define IsRawTypeInt(T) (GetRawType (T) == T_TYPE_INT)
#endif
#if defined(HAVE_INLINE)
INLINE int IsRawTypeLong (const Type* T)
/* Return true if this is a long raw type (signed or unsigned) */
{
return (GetRawType (T) == T_TYPE_LONG);
}
#else
# define IsRawTypeLong(T) (GetRawType (T) == T_TYPE_LONG)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeFloat (const Type* T)
/* Return true if this is a float type */
{
return (GetType (T) == T_TYPE_FLOAT);
return (GetRawType (T) == T_TYPE_FLOAT);
}
#else
# define IsTypeFloat(T) (GetType (T) == T_TYPE_FLOAT)
# define IsTypeFloat(T) (GetRawType (T) == T_TYPE_FLOAT)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeDouble (const Type* T)
/* Return true if this is a double type */
{
return (GetType (T) == T_TYPE_DOUBLE);
return (GetRawType (T) == T_TYPE_DOUBLE);
}
#else
# define IsTypeDouble(T) (GetType (T) == T_TYPE_DOUBLE)
# define IsTypeDouble(T) (GetRawType (T) == T_TYPE_DOUBLE)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypePtr (const Type* T)
/* Return true if this is a pointer type */
{
return (GetType (T) == T_TYPE_PTR);
return (GetRawType (T) == T_TYPE_PTR);
}
#else
# define IsTypePtr(T) (GetType (T) == T_TYPE_PTR)
# define IsTypePtr(T) (GetRawType (T) == T_TYPE_PTR)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeEnum (const Type* T)
/* Return true if this is an enum type */
{
return (GetRawType (T) == T_TYPE_ENUM);
}
#else
# define IsTypeEnum(T) (GetRawType (T) == T_TYPE_ENUM)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeStruct (const Type* T)
/* Return true if this is a struct type */
{
return (GetType (T) == T_TYPE_STRUCT);
return (GetRawType (T) == T_TYPE_STRUCT);
}
#else
# define IsTypeStruct(T) (GetType (T) == T_TYPE_STRUCT)
# define IsTypeStruct(T) (GetRawType (T) == T_TYPE_STRUCT)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeUnion (const Type* T)
/* Return true if this is a union type */
{
return (GetType (T) == T_TYPE_UNION);
return (GetRawType (T) == T_TYPE_UNION);
}
#else
# define IsTypeUnion(T) (GetType (T) == T_TYPE_UNION)
# define IsTypeUnion(T) (GetRawType (T) == T_TYPE_UNION)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeArray (const Type* T)
/* Return true if this is an array type */
{
return (GetType (T) == T_TYPE_ARRAY);
return (GetRawType (T) == T_TYPE_ARRAY);
}
#else
# define IsTypeArray(T) (GetType (T) == T_TYPE_ARRAY)
# define IsTypeArray(T) (GetRawType (T) == T_TYPE_ARRAY)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeVoid (const Type* T)
/* Return true if this is a void type */
{
return (GetType (T) == T_TYPE_VOID);
return (GetRawType (T) == T_TYPE_VOID);
}
#else
# define IsTypeVoid(T) (GetType (T) == T_TYPE_VOID)
# define IsTypeVoid(T) (GetRawType (T) == T_TYPE_VOID)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeFunc (const Type* T)
/* Return true if this is a function class */
{
return (GetType (T) == T_TYPE_FUNC);
return (GetRawType (T) == T_TYPE_FUNC);
}
#else
# define IsTypeFunc(T) (GetType (T) == T_TYPE_FUNC)
# define IsTypeFunc(T) (GetRawType (T) == T_TYPE_FUNC)
#endif
#if defined(HAVE_INLINE)
@ -502,13 +558,23 @@ INLINE int IsClassFunc (const Type* T)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetSignedness (const Type* T)
/* Get the sign of a type */
INLINE TypeCode GetRawSignedness (const Type* T)
/* Get the raw signedness of a type */
{
return (T->C & T_MASK_SIGN);
return ((T)->C & T_MASK_SIGN);
}
#else
# define GetSignedness(T) ((T)->C & T_MASK_SIGN)
# define GetRawSignedness(T) ((T)->C & T_MASK_SIGN)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetSignedness (const Type* T)
/* Get the signedness of a type */
{
return (GetUnderlyingTypeCode (T) & T_MASK_SIGN);
}
#else
# define GetSignedness(T) (GetUnderlyingTypeCode (T) & T_MASK_SIGN)
#endif
#if defined(HAVE_INLINE)

View File

@ -453,27 +453,99 @@ static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
static void ParseEnumDecl (void)
/* Process an enum declaration . */
static SymEntry* ESUForwardDecl (const char* Name, unsigned Type)
/* Handle an enum, struct or union forward decl */
{
int EnumVal;
ident Ident;
/* Try to find an enum/struct/union with the given name. If there is none,
** insert a forward declaration into the current lexical level.
*/
SymEntry* Entry = FindTagSym (Name);
if (Entry == 0) {
if (Type != SC_ENUM) {
Entry = AddStructSym (Name, Type, 0, 0);
} else {
Entry = AddEnumSym (Name, 0, 0);
}
} else if ((Entry->Flags & SC_TYPEMASK) != Type) {
/* Already defined, but not the same type class */
Error ("Symbol '%s' is already different kind", Name);
}
return Entry;
}
static const Type* GetEnumeratorType (long Min, unsigned long Max, int Signed)
/* GitHub #1093 - We use unsigned types to save spaces whenever possible.
** If both the signed and unsigned integer types of the same minimum size
** capable of representing all values of the enum, we prefer the unsigned
** one.
** Return 0 if impossible to represent Min and Max as the same integer type.
*/
{
const Type* Underlying = type_int; /* default type */
/* Change the underlying type if necessary */
if (Min < 0 || Signed) {
/* We can't use unsigned types if there are any negative values */
if (Max > (unsigned long)INT32_MAX) {
/* No way to represent both Min and Max as the same integer type */
Underlying = 0;
} else if (Min < INT16_MIN || Max > (unsigned long)INT16_MAX) {
Underlying = type_long;
} else if (Min < INT8_MIN || Max > (unsigned long)INT8_MAX) {
Underlying = type_int;
} else {
Underlying = type_schar;
}
} else {
if (Max > UINT16_MAX) {
Underlying = type_ulong;
} else if (Max > UINT8_MAX) {
Underlying = type_uint;
} else {
Underlying = type_uchar;
}
}
return Underlying;
}
static SymEntry* ParseEnumDecl (const char* Name)
/* Process an enum declaration */
{
SymTable* FieldTab;
long EnumVal;
int IsSigned;
int IsIncremented;
ident Ident;
long MinConstant = 0;
unsigned long MaxConstant = 0;
const Type* NewType = type_int; /* new enumerator type */
const Type* MemberType = type_int; /* default enumerator type */
/* Accept forward definitions */
if (CurTok.Tok != TOK_LCURLY) {
return;
return ESUForwardDecl (Name, SC_ENUM);
}
/* Add the enum tag */
AddEnumSym (Name, 0, 0);
/* Skip the opening curly brace */
NextToken ();
/* Read the enum tags */
EnumVal = 0;
EnumVal = -1L;
while (CurTok.Tok != TOK_RCURLY) {
/* We expect an identifier */
if (CurTok.Tok != TOK_IDENT) {
Error ("Identifier expected");
Error ("Identifier expected for enumerator declarator");
/* Avoid excessive errors */
NextToken ();
continue;
}
@ -483,21 +555,116 @@ static void ParseEnumDecl (void)
/* Check for an assigned value */
if (CurTok.Tok == TOK_ASSIGN) {
ExprDesc Expr;
NextToken ();
ConstAbsIntExpr (hie1, &Expr);
EnumVal = Expr.IVal;
EnumVal = Expr.IVal;
MemberType = Expr.Type;
IsSigned = IsSignSigned (MemberType);
IsIncremented = 0;
} else {
/* Defaulted with the same signedness as the previous member's */
IsSigned = IsSignSigned (MemberType) &&
(unsigned long)EnumVal != GetIntegerTypeMax (MemberType);
/* Enumerate. Signed integer overflow is UB but unsigned integers
** are guaranteed to wrap around.
*/
EnumVal = (long)((unsigned long)EnumVal + 1UL);
if (UnqualifiedType (MemberType->C) == T_ULONG && EnumVal == 0) {
/* Warn on 'unsigned long' overflow in enumeration */
Warning ("Enumerator '%s' overflows the range of '%s'",
Ident,
GetBasicTypeName (type_ulong));
}
IsIncremented = 1;
}
/* Add an entry to the symbol table */
AddConstSym (Ident, type_int, SC_ENUMERATOR | SC_CONST, EnumVal++);
/* Track down the min/max values and evaluate the type of EnumVal
** using GetEnumeratorType in a tricky way.
*/
if (!IsSigned || EnumVal >= 0) {
if ((unsigned long)EnumVal > MaxConstant) {
MaxConstant = (unsigned long)EnumVal;
}
NewType = GetEnumeratorType (0, EnumVal, IsSigned);
} else {
if (EnumVal < MinConstant) {
MinConstant = EnumVal;
}
NewType = GetEnumeratorType (EnumVal, 0, 1);
}
/* GetEnumeratorType above should never fail, but just in case */
if (NewType == 0) {
Internal ("Unexpected failure with GetEnumeratorType: %lx", EnumVal);
NewType = type_ulong;
} else if (SizeOf (NewType) < SizeOf (type_int)) {
/* Integer constants are not shorter than int */
NewType = type_int;
}
/* Warn if the incremented value exceeds the range of the previous
** type.
*/
if (IsIncremented &&
EnumVal >= 0 &&
NewType->C != UnqualifiedType (MemberType->C)) {
/* The possible overflow here can only be when EnumVal > 0 */
Warning ("Enumerator '%s' (value = %lu) is of type '%s'",
Ident,
(unsigned long)EnumVal,
GetBasicTypeName (NewType));
}
/* Warn if the value exceeds range of 'int' in standard mode */
if (IS_Get (&Standard) != STD_CC65 && NewType->C != T_INT) {
if (!IsSigned || EnumVal >= 0) {
Warning ("ISO C restricts enumerator values to range of 'int'\n"
"\tEnumerator '%s' (value = %lu) is too large",
Ident,
(unsigned long)EnumVal);
} else {
Warning ("ISO C restricts enumerator values to range of 'int'\n"
"\tEnumerator '%s' (value = %ld) is too small",
Ident,
EnumVal);
}
}
/* Add an entry of the enumerator to the symbol table */
AddConstSym (Ident, NewType, SC_ENUMERATOR | SC_CONST, EnumVal);
/* Use this type for following members */
MemberType = NewType;
/* Check for end of definition */
if (CurTok.Tok != TOK_COMMA)
if (CurTok.Tok != TOK_COMMA) {
break;
}
NextToken ();
}
ConsumeRCurly ();
/* This evaluates the underlying type of the whole enum */
MemberType = GetEnumeratorType (MinConstant, MaxConstant, 0);
if (MemberType == 0) {
/* It is very likely that the program is wrong */
Error ("Enumeration values cannot be represented all as 'long'\n"
"\tMin enumerator value = %ld, Max enumerator value = %lu",
MinConstant, MaxConstant);
/* Avoid more errors */
MemberType = type_long;
}
FieldTab = GetSymTab ();
return AddEnumSym (Name, MemberType, FieldTab);
}
@ -541,24 +708,6 @@ static int ParseFieldWidth (Declaration* Decl)
static SymEntry* StructOrUnionForwardDecl (const char* Name, unsigned Type)
/* Handle a struct or union forward decl */
{
/* Try to find a struct/union with the given name. If there is none,
** insert a forward declaration into the current lexical level.
*/
SymEntry* Entry = FindTagSym (Name);
if (Entry == 0) {
Entry = AddStructSym (Name, Type, 0, 0);
} else if ((Entry->Flags & SC_TYPEMASK) != Type) {
/* Already defined, but no struct */
Error ("Symbol '%s' is already different kind", Name);
}
return Entry;
}
static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
/* Copy fields from an anon union/struct into the current lexical level. The
** function returns the size of the embedded struct/union.
@ -617,7 +766,7 @@ static SymEntry* ParseUnionDecl (const char* Name)
if (CurTok.Tok != TOK_LCURLY) {
/* Just a forward declaration. */
return StructOrUnionForwardDecl (Name, SC_UNION);
return ESUForwardDecl (Name, SC_UNION);
}
/* Add a forward declaration for the struct in the current lexical level */
@ -722,7 +871,7 @@ static SymEntry* ParseStructDecl (const char* Name)
if (CurTok.Tok != TOK_LCURLY) {
/* Just a forward declaration. */
return StructOrUnionForwardDecl (Name, SC_STRUCT);
return ESUForwardDecl (Name, SC_STRUCT);
}
/* Add a forward declaration for the struct in the current lexical level */
@ -1069,29 +1218,23 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
case TOK_ENUM:
NextToken ();
if (CurTok.Tok != TOK_LCURLY) {
/* Named enum */
if (CurTok.Tok == TOK_IDENT) {
/* Find an entry with this name */
Entry = FindTagSym (CurTok.Ident);
if (Entry) {
if (SymIsLocal (Entry) && (Entry->Flags & SC_ENUM) == 0) {
Error ("Symbol '%s' is already different kind", Entry->Name);
}
} else {
/* Insert entry into table ### */
}
/* Skip the identifier */
NextToken ();
} else {
/* Named enum */
if (CurTok.Tok == TOK_IDENT) {
strcpy (Ident, CurTok.Ident);
NextToken ();
} else {
if (CurTok.Tok != TOK_LCURLY) {
Error ("Identifier expected");
} else {
AnonName (Ident, "enum");
}
}
/* Remember we have an extra type decl */
D->Flags |= DS_EXTRA_TYPE;
/* Parse the enum decl */
ParseEnumDecl ();
D->Type[0].C = T_INT;
Entry = ParseEnumDecl (Ident);
D->Type[0].C |= T_ENUM;
SetSymEntry (D->Type, Entry);
D->Type[1].C = T_END;
break;
@ -1624,7 +1767,7 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
/* The return type must not be qualified */
if (GetQualifier (RetType) != T_QUAL_NONE && RetType[1].C == T_END) {
if (GetType (RetType) == T_TYPE_VOID) {
if (GetRawType (RetType) == T_TYPE_VOID) {
/* A qualified void type is always an error */
Error ("function definition has qualified void return type");
} else {
@ -1916,7 +2059,7 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
long ElementCount = GetElementCount (T);
/* Special handling for a character array initialized by a literal */
if (IsTypeChar (ElementType) &&
if (IsRawTypeChar (ElementType) &&
(CurTok.Tok == TOK_SCONST || CurTok.Tok == TOK_WCSCONST ||
(CurTok.Tok == TOK_LCURLY &&
(NextTok.Tok == TOK_SCONST || NextTok.Tok == TOK_WCSCONST)))) {
@ -2180,7 +2323,7 @@ static unsigned ParseVoidInit (Type* T)
Size = 0;
do {
ConstExpr (hie1, &Expr);
switch (UnqualifiedType (Expr.Type[0].C)) {
switch (GetUnderlyingTypeCode (&Expr.Type[0])) {
case T_SCHAR:
case T_UCHAR:
@ -2244,7 +2387,7 @@ static unsigned ParseVoidInit (Type* T)
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
/* Parse initialization of variables. Return the number of data bytes. */
{
switch (UnqualifiedType (T->C)) {
switch (GetUnderlyingTypeCode (T)) {
case T_SCHAR:
case T_UCHAR:

View File

@ -452,7 +452,7 @@ void NewFunc (SymEntry* Func)
/* Determine if this is a main function in a C99 environment that
** returns an int.
*/
if (IsTypeInt (F_GetReturnType (CurrentFunc)) &&
if (IsRawTypeInt (F_GetReturnType (CurrentFunc)) &&
IS_Get (&Standard) == STD_C99) {
C99MainFunc = 1;
}

View File

@ -132,7 +132,7 @@ void SwitchStatement (void)
/* Setup the control structure, save the old and activate the new one */
SwitchData.Nodes = NewCollection ();
SwitchData.ExprType = UnqualifiedType (SwitchExpr.Type[0].C);
SwitchData.ExprType = GetUnderlyingTypeCode (&SwitchExpr.Type[0]);
SwitchData.Depth = SizeOf (SwitchExpr.Type);
SwitchData.DefaultLabel = 0;
OldSwitch = Switch;

View File

@ -165,6 +165,12 @@ struct SymEntry {
unsigned Size; /* Size of the union/struct */
} S;
/* Data for enums */
struct {
struct SymTable* SymTab; /* Member symbol table */
const Type* Type; /* Underlying type */
} E;
/* Data for bit fields */
struct {
unsigned Offs; /* Byte offset into struct */

View File

@ -551,6 +551,50 @@ static void AddSymEntry (SymTable* T, SymEntry* S)
SymEntry* AddEnumSym (const char* Name, const Type* Type, SymTable* Tab)
/* Add an enum entry and return it */
{
/* Do we have an entry with this name already? */
SymEntry* Entry = FindSymInTable (TagTab, Name, HashStr (Name));
if (Entry) {
/* We do have an entry. This may be a forward, so check it. */
if ((Entry->Flags & SC_TYPEMASK) != SC_ENUM) {
/* Existing symbol is not an enum */
Error ("Symbol '%s' is already different kind", Name);
} else {
/* Define the struct size if the underlying type is given. */
if (Type != 0) {
if (Type !=0 && Entry->V.E.Type != 0) {
/* Both are definitions. */
Error ("Multiple definition for enum '%s'", Name);
}
Entry->Type = 0;
Entry->V.E.SymTab = Tab;
Entry->V.E.Type = Type;
}
}
} else {
/* Create a new entry */
Entry = NewSymEntry (Name, SC_ENUM);
/* Set the enum type data */
Entry->Type = 0;
Entry->V.E.SymTab = Tab;
Entry->V.E.Type = Type;
/* Add it to the current table */
AddSymEntry (TagTab, Entry);
}
/* Return the entry */
return Entry;
}
SymEntry* AddStructSym (const char* Name, unsigned Type, unsigned Size, SymTable* Tab)
/* Add a struct/union entry and return it */
{
@ -649,10 +693,10 @@ SymEntry* AddConstSym (const char* Name, const Type* T, unsigned Flags, long Val
/* Create a new entry */
Entry = NewSymEntry (Name, Flags);
/* Enum values are ints */
/* We only have integer constants for now */
Entry->Type = TypeDup (T);
/* Set the enum data */
/* Set the constant data */
Entry->V.ConstVal = Val;
/* Add the entry to the symbol table */

View File

@ -146,6 +146,9 @@ unsigned short FindSPAdjustment (const char* Name);
SymEntry* AddEnumSym (const char* Name, const Type* Type, SymTable* Tab);
/* Add an enum entry and return it */
SymEntry* AddStructSym (const char* Name, unsigned Type, unsigned Size, SymTable* Tab);
/* Add a struct/union entry and return it */

View File

@ -214,9 +214,9 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
return;
}
/* Get the raw left and right types, signs and qualifiers */
LeftType = GetType (lhs);
RightType = GetType (rhs);
/* Get the left and right types, signs and qualifiers */
LeftType = GetUnderlyingTypeCode (lhs);
RightType = GetUnderlyingTypeCode (rhs);
LeftSign = GetSignedness (lhs);
RightSign = GetSignedness (rhs);
LeftQual = GetQualifier (lhs);
@ -229,7 +229,7 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
RightType = T_TYPE_PTR;
}
/* If the raw types are not identical, the types are incompatible */
/* If the underlying types are not identical, the types are incompatible */
if (LeftType != RightType) {
SetResult (Result, TC_INCOMPATIBLE);
return;