Fixed underlying types of enums.
Made enumerator diagnostics more sensible. Fixed Issue #1048 as a natural result.
This commit is contained in:
@@ -83,14 +83,9 @@ const char* GetBasicTypeName (const Type* T)
|
|||||||
** Return "type" for unknown basic types.
|
** Return "type" for unknown basic types.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
switch (GetType (T)) {
|
switch (GetRawType (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";
|
|
||||||
case T_TYPE_ENUM: return "enum";
|
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_DOUBLE: return "double";
|
||||||
case T_TYPE_VOID: return "void";
|
case T_TYPE_VOID: return "void";
|
||||||
case T_TYPE_STRUCT: return "struct";
|
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_PTR: return "pointer";
|
||||||
case T_TYPE_FUNC: return "function";
|
case T_TYPE_FUNC: return "function";
|
||||||
case T_TYPE_NONE: /* FALLTHROUGH */
|
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)
|
Type* PointerTo (const Type* T)
|
||||||
/* Return a type string that is "pointer to T". The type string is allocated
|
/* Return a type string that is "pointer to T". The type string is allocated
|
||||||
** on the heap and may be freed after use.
|
** on the heap and may be freed after use.
|
||||||
@@ -321,6 +393,9 @@ void PrintType (FILE* F, const Type* T)
|
|||||||
case T_TYPE_LONGLONG:
|
case T_TYPE_LONGLONG:
|
||||||
fprintf (F, "long long");
|
fprintf (F, "long long");
|
||||||
break;
|
break;
|
||||||
|
case T_TYPE_ENUM:
|
||||||
|
fprintf (F, "enum");
|
||||||
|
break;
|
||||||
case T_TYPE_FLOAT:
|
case T_TYPE_FLOAT:
|
||||||
fprintf (F, "float");
|
fprintf (F, "float");
|
||||||
break;
|
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)
|
unsigned SizeOf (const Type* T)
|
||||||
/* Compute size of object represented by type array. */
|
/* Compute size of object represented by type array. */
|
||||||
{
|
{
|
||||||
switch (UnqualifiedType (T->C)) {
|
switch (GetUnderlyingTypeCode (T)) {
|
||||||
|
|
||||||
case T_VOID:
|
case T_VOID:
|
||||||
/* A void variable is a cc65 extension.
|
/* A void variable is a cc65 extension.
|
||||||
@@ -470,9 +603,6 @@ unsigned SizeOf (const Type* T)
|
|||||||
case T_ULONGLONG:
|
case T_ULONGLONG:
|
||||||
return SIZEOF_LONGLONG;
|
return SIZEOF_LONGLONG;
|
||||||
|
|
||||||
case T_ENUM:
|
|
||||||
return SIZEOF_INT;
|
|
||||||
|
|
||||||
case T_FLOAT:
|
case T_FLOAT:
|
||||||
return SIZEOF_FLOAT;
|
return SIZEOF_FLOAT;
|
||||||
|
|
||||||
@@ -491,7 +621,12 @@ unsigned SizeOf (const Type* T)
|
|||||||
return T->A.U * SizeOf (T + 1);
|
return T->A.U * SizeOf (T + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case T_ENUM:
|
||||||
|
/* Incomplete enum type */
|
||||||
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
Internal ("Unknown type in SizeOf: %04lX", T->C);
|
Internal ("Unknown type in SizeOf: %04lX", T->C);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -547,7 +682,9 @@ unsigned CheckedPSizeOf (const Type* T)
|
|||||||
unsigned TypeOf (const Type* T)
|
unsigned TypeOf (const Type* T)
|
||||||
/* Get the code generator base type of the object */
|
/* Get the code generator base type of the object */
|
||||||
{
|
{
|
||||||
switch (UnqualifiedType (T->C)) {
|
unsigned NewType;
|
||||||
|
|
||||||
|
switch (GetUnderlyingTypeCode (T)) {
|
||||||
|
|
||||||
case T_SCHAR:
|
case T_SCHAR:
|
||||||
return CF_CHAR;
|
return CF_CHAR;
|
||||||
@@ -557,7 +694,6 @@ unsigned TypeOf (const Type* T)
|
|||||||
|
|
||||||
case T_SHORT:
|
case T_SHORT:
|
||||||
case T_INT:
|
case T_INT:
|
||||||
case T_ENUM:
|
|
||||||
return CF_INT;
|
return CF_INT;
|
||||||
|
|
||||||
case T_USHORT:
|
case T_USHORT:
|
||||||
@@ -582,6 +718,10 @@ unsigned TypeOf (const Type* T)
|
|||||||
|
|
||||||
case T_STRUCT:
|
case T_STRUCT:
|
||||||
case T_UNION:
|
case T_UNION:
|
||||||
|
NewType = TypeOfBySize (T);
|
||||||
|
if (NewType != CF_NONE) {
|
||||||
|
return NewType;
|
||||||
|
}
|
||||||
/* Address of ... */
|
/* Address of ... */
|
||||||
return CF_INT | CF_UNSIGNED;
|
return CF_INT | CF_UNSIGNED;
|
||||||
|
|
||||||
@@ -726,8 +866,8 @@ Type* GetBaseElementType (Type* T)
|
|||||||
SymEntry* GetSymEntry (const Type* T)
|
SymEntry* GetSymEntry (const Type* T)
|
||||||
/* Return a SymEntry pointer from a type */
|
/* Return a SymEntry pointer from a type */
|
||||||
{
|
{
|
||||||
/* Only structs or unions have a SymEntry attribute */
|
/* Only enums, structs or unions have a SymEntry attribute */
|
||||||
CHECK (IsClassStruct (T));
|
CHECK (IsClassStruct (T) || IsTypeEnum (T));
|
||||||
|
|
||||||
/* Return the attribute */
|
/* Return the attribute */
|
||||||
return T->A.P;
|
return T->A.P;
|
||||||
@@ -738,8 +878,8 @@ SymEntry* GetSymEntry (const Type* T)
|
|||||||
void SetSymEntry (Type* T, SymEntry* S)
|
void SetSymEntry (Type* T, SymEntry* S)
|
||||||
/* Set the SymEntry pointer for a type */
|
/* Set the SymEntry pointer for a type */
|
||||||
{
|
{
|
||||||
/* Only structs or unions have a SymEntry attribute */
|
/* Only enums, structs or unions have a SymEntry attribute */
|
||||||
CHECK (IsClassStruct (T));
|
CHECK (IsClassStruct (T) || IsTypeEnum (T));
|
||||||
|
|
||||||
/* Set the attribute */
|
/* Set the attribute */
|
||||||
T->A.P = S;
|
T->A.P = S;
|
||||||
|
|||||||
@@ -96,37 +96,39 @@ enum {
|
|||||||
|
|
||||||
/* Type size modifiers */
|
/* Type size modifiers */
|
||||||
T_SIZE_NONE = 0x000000,
|
T_SIZE_NONE = 0x000000,
|
||||||
T_SIZE_SHORT = 0x000200,
|
T_SIZE_CHAR = 0x000200,
|
||||||
T_SIZE_LONG = 0x000400,
|
T_SIZE_SHORT = 0x000400,
|
||||||
T_SIZE_LONGLONG = 0x000600,
|
T_SIZE_INT = 0x000600,
|
||||||
T_MASK_SIZE = 0x000600,
|
T_SIZE_LONG = 0x000800,
|
||||||
|
T_SIZE_LONGLONG = 0x000A00,
|
||||||
|
T_MASK_SIZE = 0x000E00,
|
||||||
|
|
||||||
/* Type qualifiers */
|
/* Type qualifiers */
|
||||||
T_QUAL_NONE = 0x000000,
|
T_QUAL_NONE = 0x000000,
|
||||||
T_QUAL_CONST = 0x000800,
|
T_QUAL_CONST = 0x001000,
|
||||||
T_QUAL_VOLATILE = 0x001000,
|
T_QUAL_VOLATILE = 0x002000,
|
||||||
T_QUAL_RESTRICT = 0x002000,
|
T_QUAL_RESTRICT = 0x004000,
|
||||||
T_QUAL_NEAR = 0x004000,
|
T_QUAL_NEAR = 0x008000,
|
||||||
T_QUAL_FAR = 0x008000,
|
T_QUAL_FAR = 0x010000,
|
||||||
T_QUAL_ADDRSIZE = T_QUAL_NEAR | T_QUAL_FAR,
|
T_QUAL_ADDRSIZE = T_QUAL_NEAR | T_QUAL_FAR,
|
||||||
T_QUAL_FASTCALL = 0x010000,
|
T_QUAL_FASTCALL = 0x020000,
|
||||||
T_QUAL_CDECL = 0x020000,
|
T_QUAL_CDECL = 0x040000,
|
||||||
T_QUAL_CCONV = T_QUAL_FASTCALL | T_QUAL_CDECL,
|
T_QUAL_CCONV = T_QUAL_FASTCALL | T_QUAL_CDECL,
|
||||||
T_MASK_QUAL = 0x03F800,
|
T_MASK_QUAL = 0x07F000,
|
||||||
|
|
||||||
/* Types */
|
/* Types */
|
||||||
T_CHAR = 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_NONE,
|
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_NONE,
|
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_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_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_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_NONE,
|
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_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_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_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_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_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_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,
|
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);
|
const Type* GetStructReplacementType (const Type* SType);
|
||||||
/* Get a replacement type for passing a struct/union in the primary register */
|
/* 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);
|
Type* PointerTo (const Type* T);
|
||||||
/* Return a type string that is "pointer to T". The type string is allocated
|
/* Return a type string that is "pointer to T". The type string is allocated
|
||||||
** on the heap and may be freed after use.
|
** 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)
|
# define UnqualifiedType(T) ((T) & ~T_MASK_QUAL)
|
||||||
#endif
|
#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);
|
unsigned SizeOf (const Type* T);
|
||||||
/* Compute size of object represented by type array. */
|
/* 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 */
|
/* Convert an array to a pointer to it's first element */
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE TypeCode GetType (const Type* T)
|
INLINE TypeCode GetRawType (const Type* T)
|
||||||
/* Get the raw type */
|
/* Get the raw type */
|
||||||
{
|
{
|
||||||
return (T->C & T_MASK_TYPE);
|
return (T->C & T_MASK_TYPE);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define GetType(T) ((T)->C & T_MASK_TYPE)
|
# define GetRawType(T) ((T)->C & T_MASK_TYPE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeChar (const Type* T)
|
INLINE int IsTypeChar (const Type* T)
|
||||||
/* Return true if this is a character type */
|
/* Return true if this is a character type */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_CHAR);
|
return (GetRawType (GetUnderlyingType (T)) == T_TYPE_CHAR);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define IsTypeChar(T) (GetType (T) == T_TYPE_CHAR)
|
# define IsTypeChar(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_CHAR)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeInt (const Type* T)
|
INLINE int IsTypeInt (const Type* T)
|
||||||
/* Return true if this is an int type (signed or unsigned) */
|
/* 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
|
#else
|
||||||
# define IsTypeInt(T) (GetType (T) == T_TYPE_INT)
|
# define IsTypeInt(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_INT)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeLong (const Type* T)
|
INLINE 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) */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_LONG);
|
return (GetRawType (GetUnderlyingType (T)) == T_TYPE_LONG);
|
||||||
}
|
}
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeFloat (const Type* T)
|
INLINE int IsTypeFloat (const Type* T)
|
||||||
/* Return true if this is a float type */
|
/* Return true if this is a float type */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_FLOAT);
|
return (GetRawType (T) == T_TYPE_FLOAT);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define IsTypeFloat(T) (GetType (T) == T_TYPE_FLOAT)
|
# define IsTypeFloat(T) (GetRawType (T) == T_TYPE_FLOAT)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeDouble (const Type* T)
|
INLINE int IsTypeDouble (const Type* T)
|
||||||
/* Return true if this is a double type */
|
/* Return true if this is a double type */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_DOUBLE);
|
return (GetRawType (T) == T_TYPE_DOUBLE);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define IsTypeDouble(T) (GetType (T) == T_TYPE_DOUBLE)
|
# define IsTypeDouble(T) (GetRawType (T) == T_TYPE_DOUBLE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypePtr (const Type* T)
|
INLINE int IsTypePtr (const Type* T)
|
||||||
/* Return true if this is a pointer type */
|
/* Return true if this is a pointer type */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_PTR);
|
return (GetRawType (T) == T_TYPE_PTR);
|
||||||
}
|
}
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeStruct (const Type* T)
|
INLINE int IsTypeStruct (const Type* T)
|
||||||
/* Return true if this is a struct type */
|
/* Return true if this is a struct type */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_STRUCT);
|
return (GetRawType (T) == T_TYPE_STRUCT);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define IsTypeStruct(T) (GetType (T) == T_TYPE_STRUCT)
|
# define IsTypeStruct(T) (GetRawType (T) == T_TYPE_STRUCT)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeUnion (const Type* T)
|
INLINE int IsTypeUnion (const Type* T)
|
||||||
/* Return true if this is a union type */
|
/* Return true if this is a union type */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_UNION);
|
return (GetRawType (T) == T_TYPE_UNION);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define IsTypeUnion(T) (GetType (T) == T_TYPE_UNION)
|
# define IsTypeUnion(T) (GetRawType (T) == T_TYPE_UNION)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeArray (const Type* T)
|
INLINE int IsTypeArray (const Type* T)
|
||||||
/* Return true if this is an array type */
|
/* Return true if this is an array type */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_ARRAY);
|
return (GetRawType (T) == T_TYPE_ARRAY);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define IsTypeArray(T) (GetType (T) == T_TYPE_ARRAY)
|
# define IsTypeArray(T) (GetRawType (T) == T_TYPE_ARRAY)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeVoid (const Type* T)
|
INLINE int IsTypeVoid (const Type* T)
|
||||||
/* Return true if this is a void type */
|
/* Return true if this is a void type */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_VOID);
|
return (GetRawType (T) == T_TYPE_VOID);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define IsTypeVoid(T) (GetType (T) == T_TYPE_VOID)
|
# define IsTypeVoid(T) (GetRawType (T) == T_TYPE_VOID)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsTypeFunc (const Type* T)
|
INLINE int IsTypeFunc (const Type* T)
|
||||||
/* Return true if this is a function class */
|
/* Return true if this is a function class */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_FUNC);
|
return (GetRawType (T) == T_TYPE_FUNC);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define IsTypeFunc(T) (GetType (T) == T_TYPE_FUNC)
|
# define IsTypeFunc(T) (GetRawType (T) == T_TYPE_FUNC)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
@@ -502,13 +558,23 @@ INLINE int IsClassFunc (const Type* T)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE TypeCode GetSignedness (const Type* T)
|
INLINE TypeCode GetRawSignedness (const Type* T)
|
||||||
/* Get the sign of a type */
|
/* Get the raw signedness of a type */
|
||||||
{
|
{
|
||||||
return (T->C & T_MASK_SIGN);
|
return ((T)->C & T_MASK_SIGN);
|
||||||
}
|
}
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
|
|||||||
@@ -453,27 +453,99 @@ static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParseEnumDecl (void)
|
static SymEntry* ESUForwardDecl (const char* Name, unsigned Type)
|
||||||
/* Process an enum declaration . */
|
/* Handle an enum, struct or union forward decl */
|
||||||
{
|
{
|
||||||
int EnumVal;
|
/* Try to find an enum/struct/union with the given name. If there is none,
|
||||||
ident Ident;
|
** 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 */
|
/* Accept forward definitions */
|
||||||
if (CurTok.Tok != TOK_LCURLY) {
|
if (CurTok.Tok != TOK_LCURLY) {
|
||||||
return;
|
return ESUForwardDecl (Name, SC_ENUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add the enum tag */
|
||||||
|
AddEnumSym (Name, 0, 0);
|
||||||
|
|
||||||
/* Skip the opening curly brace */
|
/* Skip the opening curly brace */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Read the enum tags */
|
/* Read the enum tags */
|
||||||
EnumVal = 0;
|
EnumVal = -1L;
|
||||||
while (CurTok.Tok != TOK_RCURLY) {
|
while (CurTok.Tok != TOK_RCURLY) {
|
||||||
|
|
||||||
/* We expect an identifier */
|
/* We expect an identifier */
|
||||||
if (CurTok.Tok != TOK_IDENT) {
|
if (CurTok.Tok != TOK_IDENT) {
|
||||||
Error ("Identifier expected");
|
Error ("Identifier expected for enumerator declarator");
|
||||||
|
/* Avoid excessive errors */
|
||||||
|
NextToken ();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,21 +555,116 @@ static void ParseEnumDecl (void)
|
|||||||
|
|
||||||
/* Check for an assigned value */
|
/* Check for an assigned value */
|
||||||
if (CurTok.Tok == TOK_ASSIGN) {
|
if (CurTok.Tok == TOK_ASSIGN) {
|
||||||
|
|
||||||
ExprDesc Expr;
|
ExprDesc Expr;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
ConstAbsIntExpr (hie1, &Expr);
|
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 */
|
/* Track down the min/max values and evaluate the type of EnumVal
|
||||||
AddConstSym (Ident, type_int, SC_ENUMERATOR | SC_CONST, 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 */
|
/* Check for end of definition */
|
||||||
if (CurTok.Tok != TOK_COMMA)
|
if (CurTok.Tok != TOK_COMMA) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
NextToken ();
|
NextToken ();
|
||||||
}
|
}
|
||||||
ConsumeRCurly ();
|
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)
|
static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
|
||||||
/* Copy fields from an anon union/struct into the current lexical level. The
|
/* Copy fields from an anon union/struct into the current lexical level. The
|
||||||
** function returns the size of the embedded struct/union.
|
** function returns the size of the embedded struct/union.
|
||||||
@@ -617,7 +766,7 @@ static SymEntry* ParseUnionDecl (const char* Name)
|
|||||||
|
|
||||||
if (CurTok.Tok != TOK_LCURLY) {
|
if (CurTok.Tok != TOK_LCURLY) {
|
||||||
/* Just a forward declaration. */
|
/* 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 */
|
/* 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) {
|
if (CurTok.Tok != TOK_LCURLY) {
|
||||||
/* Just a forward declaration. */
|
/* 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 */
|
/* 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:
|
case TOK_ENUM:
|
||||||
NextToken ();
|
NextToken ();
|
||||||
if (CurTok.Tok != TOK_LCURLY) {
|
/* Named enum */
|
||||||
/* Named enum */
|
if (CurTok.Tok == TOK_IDENT) {
|
||||||
if (CurTok.Tok == TOK_IDENT) {
|
strcpy (Ident, CurTok.Ident);
|
||||||
/* Find an entry with this name */
|
NextToken ();
|
||||||
Entry = FindTagSym (CurTok.Ident);
|
} else {
|
||||||
if (Entry) {
|
if (CurTok.Tok != TOK_LCURLY) {
|
||||||
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 {
|
|
||||||
Error ("Identifier expected");
|
Error ("Identifier expected");
|
||||||
|
} else {
|
||||||
|
AnonName (Ident, "enum");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Remember we have an extra type decl */
|
/* Remember we have an extra type decl */
|
||||||
D->Flags |= DS_EXTRA_TYPE;
|
D->Flags |= DS_EXTRA_TYPE;
|
||||||
/* Parse the enum decl */
|
/* Parse the enum decl */
|
||||||
ParseEnumDecl ();
|
Entry = ParseEnumDecl (Ident);
|
||||||
D->Type[0].C = T_INT;
|
D->Type[0].C |= T_ENUM;
|
||||||
|
SetSymEntry (D->Type, Entry);
|
||||||
D->Type[1].C = T_END;
|
D->Type[1].C = T_END;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1624,7 +1767,7 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
|||||||
/* The return type must not be qualified */
|
/* The return type must not be qualified */
|
||||||
if (GetQualifier (RetType) != T_QUAL_NONE && RetType[1].C == T_END) {
|
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 */
|
/* A qualified void type is always an error */
|
||||||
Error ("function definition has qualified void return type");
|
Error ("function definition has qualified void return type");
|
||||||
} else {
|
} else {
|
||||||
@@ -1916,7 +2059,7 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
|
|||||||
long ElementCount = GetElementCount (T);
|
long ElementCount = GetElementCount (T);
|
||||||
|
|
||||||
/* Special handling for a character array initialized by a literal */
|
/* 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_SCONST || CurTok.Tok == TOK_WCSCONST ||
|
||||||
(CurTok.Tok == TOK_LCURLY &&
|
(CurTok.Tok == TOK_LCURLY &&
|
||||||
(NextTok.Tok == TOK_SCONST || NextTok.Tok == TOK_WCSCONST)))) {
|
(NextTok.Tok == TOK_SCONST || NextTok.Tok == TOK_WCSCONST)))) {
|
||||||
@@ -2180,7 +2323,7 @@ static unsigned ParseVoidInit (Type* T)
|
|||||||
Size = 0;
|
Size = 0;
|
||||||
do {
|
do {
|
||||||
ConstExpr (hie1, &Expr);
|
ConstExpr (hie1, &Expr);
|
||||||
switch (UnqualifiedType (Expr.Type[0].C)) {
|
switch (GetUnderlyingTypeCode (&Expr.Type[0])) {
|
||||||
|
|
||||||
case T_SCHAR:
|
case T_SCHAR:
|
||||||
case T_UCHAR:
|
case T_UCHAR:
|
||||||
@@ -2244,7 +2387,7 @@ static unsigned ParseVoidInit (Type* T)
|
|||||||
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
|
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
|
||||||
/* Parse initialization of variables. Return the number of data bytes. */
|
/* Parse initialization of variables. Return the number of data bytes. */
|
||||||
{
|
{
|
||||||
switch (UnqualifiedType (T->C)) {
|
switch (GetUnderlyingTypeCode (T)) {
|
||||||
|
|
||||||
case T_SCHAR:
|
case T_SCHAR:
|
||||||
case T_UCHAR:
|
case T_UCHAR:
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ void NewFunc (SymEntry* Func)
|
|||||||
/* Determine if this is a main function in a C99 environment that
|
/* Determine if this is a main function in a C99 environment that
|
||||||
** returns an int.
|
** returns an int.
|
||||||
*/
|
*/
|
||||||
if (IsTypeInt (F_GetReturnType (CurrentFunc)) &&
|
if (IsRawTypeInt (F_GetReturnType (CurrentFunc)) &&
|
||||||
IS_Get (&Standard) == STD_C99) {
|
IS_Get (&Standard) == STD_C99) {
|
||||||
C99MainFunc = 1;
|
C99MainFunc = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ void SwitchStatement (void)
|
|||||||
|
|
||||||
/* Setup the control structure, save the old and activate the new one */
|
/* Setup the control structure, save the old and activate the new one */
|
||||||
SwitchData.Nodes = NewCollection ();
|
SwitchData.Nodes = NewCollection ();
|
||||||
SwitchData.ExprType = UnqualifiedType (SwitchExpr.Type[0].C);
|
SwitchData.ExprType = GetUnderlyingTypeCode (&SwitchExpr.Type[0]);
|
||||||
SwitchData.Depth = SizeOf (SwitchExpr.Type);
|
SwitchData.Depth = SizeOf (SwitchExpr.Type);
|
||||||
SwitchData.DefaultLabel = 0;
|
SwitchData.DefaultLabel = 0;
|
||||||
OldSwitch = Switch;
|
OldSwitch = Switch;
|
||||||
|
|||||||
@@ -165,6 +165,12 @@ struct SymEntry {
|
|||||||
unsigned Size; /* Size of the union/struct */
|
unsigned Size; /* Size of the union/struct */
|
||||||
} S;
|
} S;
|
||||||
|
|
||||||
|
/* Data for enums */
|
||||||
|
struct {
|
||||||
|
struct SymTable* SymTab; /* Member symbol table */
|
||||||
|
const Type* Type; /* Underlying type */
|
||||||
|
} E;
|
||||||
|
|
||||||
/* Data for bit fields */
|
/* Data for bit fields */
|
||||||
struct {
|
struct {
|
||||||
unsigned Offs; /* Byte offset into struct */
|
unsigned Offs; /* Byte offset into struct */
|
||||||
|
|||||||
@@ -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)
|
SymEntry* AddStructSym (const char* Name, unsigned Type, unsigned Size, SymTable* Tab)
|
||||||
/* Add a struct/union entry and return it */
|
/* 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 */
|
/* Create a new entry */
|
||||||
Entry = NewSymEntry (Name, Flags);
|
Entry = NewSymEntry (Name, Flags);
|
||||||
|
|
||||||
/* Enum values are ints */
|
/* We only have integer constants for now */
|
||||||
Entry->Type = TypeDup (T);
|
Entry->Type = TypeDup (T);
|
||||||
|
|
||||||
/* Set the enum data */
|
/* Set the constant data */
|
||||||
Entry->V.ConstVal = Val;
|
Entry->V.ConstVal = Val;
|
||||||
|
|
||||||
/* Add the entry to the symbol table */
|
/* Add the entry to the symbol table */
|
||||||
|
|||||||
@@ -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);
|
SymEntry* AddStructSym (const char* Name, unsigned Type, unsigned Size, SymTable* Tab);
|
||||||
/* Add a struct/union entry and return it */
|
/* Add a struct/union entry and return it */
|
||||||
|
|
||||||
|
|||||||
@@ -214,9 +214,9 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the raw left and right types, signs and qualifiers */
|
/* Get the left and right types, signs and qualifiers */
|
||||||
LeftType = GetType (lhs);
|
LeftType = GetUnderlyingTypeCode (lhs);
|
||||||
RightType = GetType (rhs);
|
RightType = GetUnderlyingTypeCode (rhs);
|
||||||
LeftSign = GetSignedness (lhs);
|
LeftSign = GetSignedness (lhs);
|
||||||
RightSign = GetSignedness (rhs);
|
RightSign = GetSignedness (rhs);
|
||||||
LeftQual = GetQualifier (lhs);
|
LeftQual = GetQualifier (lhs);
|
||||||
@@ -229,7 +229,7 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
|||||||
RightType = T_TYPE_PTR;
|
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) {
|
if (LeftType != RightType) {
|
||||||
SetResult (Result, TC_INCOMPATIBLE);
|
SetResult (Result, TC_INCOMPATIBLE);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user