1
0
mirror of https://github.com/cc65/cc65.git synced 2025-02-06 12:31:12 +00:00

Added flexible array members for structs

git-svn-id: svn://svn.cc65.org/cc65/trunk@1925 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2003-02-03 22:14:20 +00:00
parent d5481ff95b
commit c123666d24
8 changed files with 194 additions and 112 deletions

View File

@ -6,9 +6,9 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2002 Ullrich von Bassewitz */ /* (C) 1998-2003 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Römerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
@ -4013,10 +4013,12 @@ void g_defbytes (const void* Bytes, unsigned Count)
void g_zerobytes (unsigned n) void g_zerobytes (unsigned Count)
/* Output n bytes of data initialized with zero */ /* Output Count bytes of data initialized with zero */
{ {
AddDataLine ("\t.res\t%u,$00", n); if (Count > 0) {
AddDataLine ("\t.res\t%u,$00", Count);
}
} }

View File

@ -6,9 +6,9 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2002 Ullrich von Bassewitz */ /* (C) 1998-2003 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Römerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
@ -432,8 +432,8 @@ void g_defdata (unsigned flags, unsigned long val, long offs);
void g_defbytes (const void* bytes, unsigned count); void g_defbytes (const void* bytes, unsigned count);
/* Output a row of bytes as a constant */ /* Output a row of bytes as a constant */
void g_zerobytes (unsigned n); void g_zerobytes (unsigned Count);
/* Output n bytes of data initialized with zero */ /* Output Count bytes of data initialized with zero */
void g_initregister (unsigned Label, unsigned Reg, unsigned Size); void g_initregister (unsigned Label, unsigned Reg, unsigned Size);
/* Initialize a register variable from static initialization data */ /* Initialize a register variable from static initialization data */

View File

@ -6,9 +6,9 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2002 Ullrich von Bassewitz */ /* (C) 1998-2003 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Römerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@musoftware.de */ /* EMail: uz@musoftware.de */
/* */ /* */
/* */ /* */
@ -368,7 +368,7 @@ void PrintRawType (FILE* F, const type* Type)
void Encode (type* Type, unsigned long Val) void Encode (type* Type, unsigned long Val)
/* Encode p[0] and p[1] so that neither p[0] nore p[1] is zero */ /* Encode Val into the given type string */
{ {
int I; int I;
for (I = 0; I < DECODE_SIZE; ++I) { for (I = 0; I < DECODE_SIZE; ++I) {
@ -429,6 +429,7 @@ unsigned SizeOf (const type* T)
/* Compute size of object represented by type array. */ /* Compute size of object represented by type array. */
{ {
SymEntry* Entry; SymEntry* Entry;
long ElementCount;
switch (UnqualifiedType (T[0])) { switch (UnqualifiedType (T[0])) {
@ -470,11 +471,17 @@ unsigned SizeOf (const type* T)
case T_STRUCT: case T_STRUCT:
case T_UNION: case T_UNION:
Entry = (SymEntry*) DecodePtr (T+1); Entry = DecodePtr (T+1);
return Entry->V.S.Size; return Entry->V.S.Size;
case T_ARRAY: case T_ARRAY:
return (Decode (T+ 1) * SizeOf (T + DECODE_SIZE + 1)); ElementCount = GetElementCount (T);
if (ElementCount < 0) {
/* Array with unspecified size */
return 0;
} else {
return ElementCount * SizeOf (T + DECODE_SIZE + 1);
}
default: default:
Internal ("Unknown type in SizeOf: %04X", *T); Internal ("Unknown type in SizeOf: %04X", *T);
@ -564,7 +571,7 @@ unsigned TypeOf (const type* T)
return CF_LONG | CF_UNSIGNED; return CF_LONG | CF_UNSIGNED;
case T_FUNC: case T_FUNC:
F = (FuncDesc*) DecodePtr (T+1); F = DecodePtr (T+1);
return (F->Flags & FD_VARIADIC)? 0 : CF_FIXARGC; return (F->Flags & FD_VARIADIC)? 0 : CF_FIXARGC;
case T_STRUCT: case T_STRUCT:
@ -714,7 +721,7 @@ FuncDesc* GetFuncDesc (const type* T)
CHECK (T[0] == T_FUNC); CHECK (T[0] == T_FUNC);
/* Decode the function descriptor and return it */ /* Decode the function descriptor and return it */
return (FuncDesc*) DecodePtr (T+1); return DecodePtr (T+1);
} }
@ -737,3 +744,14 @@ type* GetFuncReturn (type* T)
long GetElementCount (const type* T)
/* Get the element count of the array specified in T (which must be of
* array type).
*/
{
CHECK (IsTypeArray (T));
return (unsigned) Decode (T+1);
}

View File

@ -144,6 +144,9 @@ typedef unsigned short type;
/* Type elements needed for Encode/Decode */ /* Type elements needed for Encode/Decode */
#define DECODE_SIZE 5 #define DECODE_SIZE 5
/* Unspecified size for the element count of an array */
#define UNSPECIFIED -1L
/* Sizes */ /* Sizes */
#define SIZEOF_CHAR 1 #define SIZEOF_CHAR 1
#define SIZEOF_SHORT 2 #define SIZEOF_SHORT 2
@ -218,7 +221,7 @@ void PrintFuncSig (FILE* F, const char* Name, type* Type);
/* Print a function signature. */ /* Print a function signature. */
void Encode (type* Type, unsigned long Val); void Encode (type* Type, unsigned long Val);
/* Encode an unsigned long into a type array */ /* Encode Val into the given type string */
void EncodePtr (type* Type, void* P); void EncodePtr (type* Type, void* P);
/* Encode a pointer into a type array */ /* Encode a pointer into a type array */
@ -474,6 +477,11 @@ FuncDesc* GetFuncDesc (const type* T) attribute ((const));
type* GetFuncReturn (type* T) attribute ((const)); type* GetFuncReturn (type* T) attribute ((const));
/* Return a pointer to the return type of a function or pointer-to-function type */ /* Return a pointer to the return type of a function or pointer-to-function type */
long GetElementCount (const type* T);
/* Get the element count of the array specified in T (which must be of
* array type).
*/
/* End of datatype.h */ /* End of datatype.h */

View File

@ -9,7 +9,7 @@
/* (C) 1998-2003 Ullrich von Bassewitz */ /* (C) 1998-2003 Ullrich von Bassewitz */
/* Römerstrasse 52 */ /* Römerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@musoftware.de */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -236,7 +236,7 @@ static void ParseEnumDecl (void)
/* Add an entry to the symbol table */ /* Add an entry to the symbol table */
AddConstSym (Ident, type_int, SC_ENUM, EnumVal++); AddConstSym (Ident, type_int, SC_ENUM, EnumVal++);
/* Check for end of definition */ /* Check for end of definition */
if (CurTok.Tok != TOK_COMMA) if (CurTok.Tok != TOK_COMMA)
break; break;
@ -251,9 +251,10 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
/* Parse a struct/union declaration. */ /* Parse a struct/union declaration. */
{ {
unsigned StructSize; unsigned StructSize;
unsigned FieldSize; unsigned FieldSize;
unsigned Offs; unsigned Offs;
int FlexibleMember;
SymTable* FieldTab; SymTable* FieldTab;
SymEntry* Entry; SymEntry* Entry;
@ -283,7 +284,8 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
EnterStructLevel (); EnterStructLevel ();
/* Parse struct fields */ /* Parse struct fields */
StructSize = 0; FlexibleMember = 0;
StructSize = 0;
while (CurTok.Tok != TOK_RCURLY) { while (CurTok.Tok != TOK_RCURLY) {
/* Get the type of the entry */ /* Get the type of the entry */
@ -294,30 +296,55 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
/* Read fields with this type */ /* Read fields with this type */
while (1) { while (1) {
/* Get type and name of the struct field */
Declaration Decl; Declaration Decl;
/* If we had a flexible array member before, no other fields can
* follow.
*/
if (FlexibleMember) {
Error ("Flexible array member must be last field");
FlexibleMember = 0; /* Avoid further errors */
}
/* Get type and name of the struct field */
ParseDecl (&Spec, &Decl, 0); ParseDecl (&Spec, &Decl, 0);
/* Get the offset of this field */ /* Get the offset of this field */
Offs = (StructType == T_STRUCT)? StructSize : 0; Offs = (StructType == T_STRUCT)? StructSize : 0;
/* Add a field entry to the table */ /* Calculate the sizes, handle flexible array members */
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs); if (StructType == T_STRUCT) {
/* It's a struct. Check if this field is a flexible array
* member, and calculate the size of the field.
*/
if (IsTypeArray (Decl.Type) && GetElementCount (Decl.Type) == UNSPECIFIED) {
/* Array with unspecified size */
if (StructSize == 0) {
Error ("Flexible array member cannot be first struct field");
}
FlexibleMember = 1;
/* Assume zero for size calculations */
Encode (Decl.Type + 1, 0);
} else {
StructSize += CheckedSizeOf (Decl.Type);
}
/* Calculate offset of next field/size of the union */
FieldSize = CheckedSizeOf (Decl.Type);
if (StructType == T_STRUCT) {
/* It's a struct */
StructSize += FieldSize;
} else { } else {
/* It's a union */ /* It's a union */
FieldSize = CheckedSizeOf (Decl.Type);
if (FieldSize > StructSize) { if (FieldSize > StructSize) {
StructSize = FieldSize; StructSize = FieldSize;
} }
} }
if (CurTok.Tok != TOK_COMMA) /* Add a field entry to the table */
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs);
if (CurTok.Tok != TOK_COMMA) {
break; break;
}
NextToken (); NextToken ();
} }
ConsumeSemi (); ConsumeSemi ();
@ -871,17 +898,17 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
D->T += DECODE_SIZE; D->T += DECODE_SIZE;
} else { } else {
/* Array declaration */ /* Array declaration */
unsigned long Size = 0; long Size = UNSPECIFIED;
NextToken (); NextToken ();
/* Read the size if it is given */ /* Read the size if it is given */
if (CurTok.Tok != TOK_RBRACK) { if (CurTok.Tok != TOK_RBRACK) {
ExprDesc lval; ExprDesc lval;
ConstExpr (&lval); ConstExpr (&lval);
if (lval.ConstVal < 0) { if (lval.ConstVal <= 0) {
if (D->Ident[0] != '\0') { if (D->Ident[0] != '\0') {
Error ("Size of array `%s' is negative", D->Ident); Error ("Size of array `%s' is invalid", D->Ident);
} else { } else {
Error ("Size of array is negative"); Error ("Size of array is invalid");
} }
lval.ConstVal = 1; lval.ConstVal = 1;
} }
@ -978,16 +1005,21 @@ void CheckEmptyDecl (const DeclSpec* D)
static void ParseVoidInit (void) static unsigned ParseVoidInit (void)
/* Parse an initialization of a void variable (special cc65 extension) */ /* Parse an initialization of a void variable (special cc65 extension).
* Return the number of bytes initialized.
*/
{ {
ExprDesc lval; ExprDesc lval;
unsigned Size;
ConsumeLCurly ();
/* Allow an arbitrary list of values */ /* Allow an arbitrary list of values */
ConsumeLCurly (); Size = 0;
do { do {
ConstExpr (&lval); ConstExpr (&lval);
switch (lval.Type[0]) { switch (UnqualifiedType (lval.Type[0])) {
case T_SCHAR: case T_SCHAR:
case T_UCHAR: case T_UCHAR:
@ -996,7 +1028,8 @@ static void ParseVoidInit (void)
lval.ConstVal &= 0xFF; lval.ConstVal &= 0xFF;
} }
DefineData (&lval); DefineData (&lval);
break; Size += SIZEOF_CHAR;
break;
case T_SHORT: case T_SHORT:
case T_USHORT: case T_USHORT:
@ -1009,42 +1042,53 @@ static void ParseVoidInit (void)
lval.ConstVal &= 0xFFFF; lval.ConstVal &= 0xFFFF;
} }
DefineData (&lval); DefineData (&lval);
break; Size += SIZEOF_INT;
break;
case T_LONG: case T_LONG:
case T_ULONG: case T_ULONG:
DefineData (&lval); DefineData (&lval);
break; Size += SIZEOF_LONG;
break;
default: default:
Error ("Illegal type in initialization"); Error ("Illegal type in initialization");
break; break;
} }
if (CurTok.Tok != TOK_COMMA) { if (CurTok.Tok != TOK_COMMA) {
break; break;
} }
NextToken (); NextToken ();
} while (CurTok.Tok != TOK_RCURLY); } while (CurTok.Tok != TOK_RCURLY);
/* Closing brace */
ConsumeRCurly (); ConsumeRCurly ();
/* Return the number of bytes initialized */
return Size;
} }
static void ParseStructInit (type* Type) static unsigned ParseStructInit (type* Type)
/* Parse initialization of a struct or union */ /* Parse initialization of a struct or union. Return the number of data bytes. */
{ {
SymEntry* Entry; SymEntry* Entry;
SymTable* Tab; SymTable* Tab;
unsigned StructSize;
unsigned Size;
/* Consume the opening curly brace */ /* Consume the opening curly brace */
ConsumeLCurly (); ConsumeLCurly ();
/* Get a pointer to the struct entry from the type */ /* Get a pointer to the struct entry from the type */
Entry = (SymEntry*) Decode (Type + 1); Entry = DecodePtr (Type + 1);
/* Get the size of the struct from the symbol table entry */
StructSize = Entry->V.S.Size;
/* Check if this struct definition has a field table. If it doesn't, it /* Check if this struct definition has a field table. If it doesn't, it
* is an incomplete definition. * is an incomplete definition.
@ -1052,44 +1096,50 @@ static void ParseStructInit (type* Type)
Tab = Entry->V.S.SymTab; Tab = Entry->V.S.SymTab;
if (Tab == 0) { if (Tab == 0) {
Error ("Cannot initialize variables with incomplete type"); Error ("Cannot initialize variables with incomplete type");
/* Returning here will cause lots of errors, but recovery is difficult */ /* Returning here will cause lots of errors, but recovery is difficult */
return; return 0;
} }
/* Get a pointer to the list of symbols */ /* Get a pointer to the list of symbols */
Entry = Tab->SymHead; Entry = Tab->SymHead;
/* Initialize fields */
Size = 0;
while (CurTok.Tok != TOK_RCURLY) { while (CurTok.Tok != TOK_RCURLY) {
if (Entry == 0) { if (Entry == 0) {
Error ("Too many initializers"); Error ("Too many initializers");
return; return Size;
} }
ParseInit (Entry->Type); Size += ParseInit (Entry->Type);
Entry = Entry->NextSym; Entry = Entry->NextSym;
if (CurTok.Tok != TOK_COMMA) if (CurTok.Tok != TOK_COMMA)
break; break;
NextToken (); NextToken ();
} }
/* Consume the closing curly brace */ /* Consume the closing curly brace */
ConsumeRCurly (); ConsumeRCurly ();
/* If there are struct fields left, reserve additional storage */ /* If there are struct fields left, reserve additional storage */
while (Entry) { if (Size < StructSize) {
g_zerobytes (CheckedSizeOf (Entry->Type)); g_zerobytes (StructSize - Size);
Entry = Entry->NextSym;
} }
/* Return the number of bytes initialized */
return StructSize;
} }
void ParseInit (type* T) unsigned ParseInit (type* T)
/* Parse initialization of variables. */ /* Parse initialization of variables. Return the number of data bytes. */
{ {
ExprDesc lval; ExprDesc lval;
type* t; type* t;
const char* str; const char* str;
int Count; int Count;
int Size; long ElementCount;
unsigned ElementSize;
switch (UnqualifiedType (*T)) { switch (UnqualifiedType (*T)) {
@ -1102,7 +1152,7 @@ void ParseInit (type* T)
} }
assignadjust (T, &lval); assignadjust (T, &lval);
DefineData (&lval); DefineData (&lval);
break; return SIZEOF_CHAR;
case T_SHORT: case T_SHORT:
case T_USHORT: case T_USHORT:
@ -1116,7 +1166,7 @@ void ParseInit (type* T)
} }
assignadjust (T, &lval); assignadjust (T, &lval);
DefineData (&lval); DefineData (&lval);
break; return SIZEOF_INT;
case T_LONG: case T_LONG:
case T_ULONG: case T_ULONG:
@ -1127,14 +1177,15 @@ void ParseInit (type* T)
} }
assignadjust (T, &lval); assignadjust (T, &lval);
DefineData (&lval); DefineData (&lval);
break; return SIZEOF_LONG;
case T_ARRAY: case T_ARRAY:
Size = Decode (T + 1); ElementCount = GetElementCount (T);
ElementSize = CheckedSizeOf (T + DECODE_SIZE + 1);
t = T + DECODE_SIZE + 1; t = T + DECODE_SIZE + 1;
if (IsTypeChar(t) && CurTok.Tok == TOK_SCONST) { if (IsTypeChar (t) && CurTok.Tok == TOK_SCONST) {
str = GetLiteral (CurTok.IVal); str = GetLiteral (CurTok.IVal);
Count = strlen (str) + 1; Count = GetLiteralPoolOffs () - CurTok.IVal;
TranslateLiteralPool (CurTok.IVal); /* Translate into target charset */ TranslateLiteralPool (CurTok.IVal); /* Translate into target charset */
g_defbytes (str, Count); g_defbytes (str, Count);
ResetLiteralPoolOffs (CurTok.IVal); /* Remove string from pool */ ResetLiteralPoolOffs (CurTok.IVal); /* Remove string from pool */
@ -1151,34 +1202,33 @@ void ParseInit (type* T)
} }
ConsumeRCurly (); ConsumeRCurly ();
} }
if (Size == 0) { if (ElementCount == UNSPECIFIED) {
Encode (T + 1, Count); Encode (T + 1, Count);
} else if (Count < Size) { } else if (Count < ElementCount) {
g_zerobytes ((Size - Count) * CheckedSizeOf (T + DECODE_SIZE + 1)); g_zerobytes ((ElementCount - Count) * ElementSize);
} else if (Count > Size) { } else if (Count > ElementCount) {
Error ("Too many initializers"); Error ("Too many initializers");
} }
break; return ElementCount * ElementSize;
case T_STRUCT: case T_STRUCT:
case T_UNION: case T_UNION:
ParseStructInit (T); return ParseStructInit (T);
break;
case T_VOID: case T_VOID:
if (!ANSI) { if (!ANSI) {
/* Special cc65 extension in non ANSI mode */ /* Special cc65 extension in non ANSI mode */
ParseVoidInit (); return ParseVoidInit ();
break;
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
default: default:
Error ("Illegal type"); Error ("Illegal type");
break; return SIZEOF_CHAR;
} }
} }

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2001 Ullrich von Bassewitz */ /* (C) 1998-2003 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Römerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@musoftware.de */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -101,8 +101,10 @@ void CheckEmptyDecl (const DeclSpec* D);
* warning if not. * warning if not.
*/ */
void ParseInit (type* T); unsigned ParseInit (type* T);
/* Parse initialization of variables. */ /* Parse initialization of variables. Return the number of initialized data
* bytes.
*/

View File

@ -6,9 +6,9 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2000-2001 Ullrich von Bassewitz */ /* (C) 2000-2003 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Römerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
@ -717,17 +717,17 @@ SymEntry* AddGlobalSym (const char* Name, const type* Type, unsigned Flags)
if (IsTypeArray (Type) && IsTypeArray (EType)) { if (IsTypeArray (Type) && IsTypeArray (EType)) {
/* Get the array sizes */ /* Get the array sizes */
unsigned Size = Decode (Type + 1); long Size = GetElementCount (Type);
unsigned ESize = Decode (EType + 1); long ESize = GetElementCount (EType);
if ((Size != 0 && ESize != 0 && Size != ESize) || if ((Size != UNSPECIFIED && ESize != UNSPECIFIED && Size != ESize) ||
TypeCmp (Type+DECODE_SIZE+1, EType+DECODE_SIZE+1) < TC_EQUAL) { TypeCmp (Type+DECODE_SIZE+1, EType+DECODE_SIZE+1) < TC_EQUAL) {
/* Types not identical: Conflicting types */ /* Types not identical: Conflicting types */
Error ("Conflicting types for `%s'", Name); Error ("Conflicting types for `%s'", Name);
return Entry; return Entry;
} else { } else {
/* Check if we have a size in the existing definition */ /* Check if we have a size in the existing definition */
if (ESize == 0) { if (ESize == UNSPECIFIED) {
/* Existing, size not given, use size from new def */ /* Existing, size not given, use size from new def */
Encode (EType + 1, Size); Encode (EType + 1, Size);
} }

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2000 Ullrich von Bassewitz */ /* (C) 1998-2003 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Römerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@musoftware.de */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -107,7 +107,7 @@ static int EqualSymTables (SymTable* Tab1, SymTable* Tab2)
return 0; return 0;
} }
} }
/* Compare the types of this field */ /* Compare the types of this field */
if (TypeCmp (Sym1->Type, Sym2->Type) < TC_EQUAL) { if (TypeCmp (Sym1->Type, Sym2->Type) < TC_EQUAL) {
/* Field types not equal */ /* Field types not equal */
@ -149,7 +149,7 @@ static void DoCompare (const type* lhs, const type* rhs, typecmp_t* Result)
type LeftType, RightType; type LeftType, RightType;
type LeftSign, RightSign; type LeftSign, RightSign;
type LeftQual, RightQual; type LeftQual, RightQual;
unsigned LeftCount, RightCount; long LeftCount, RightCount;
/* Check if the end of the type string is reached */ /* Check if the end of the type string is reached */
if (*rhs == T_END) { if (*rhs == T_END) {
@ -274,9 +274,11 @@ static void DoCompare (const type* lhs, const type* rhs, typecmp_t* Result)
case T_TYPE_ARRAY: case T_TYPE_ARRAY:
/* Check member count */ /* Check member count */
LeftCount = Decode (lhs+1); LeftCount = GetElementCount (lhs);
RightCount = Decode (rhs+1); RightCount = GetElementCount (rhs);
if (LeftCount != 0 && RightCount != 0 && LeftCount != RightCount) { if (LeftCount != UNSPECIFIED &&
RightCount != UNSPECIFIED &&
LeftCount != RightCount) {
/* Member count given but different */ /* Member count given but different */
SetResult (Result, TC_INCOMPATIBLE); SetResult (Result, TC_INCOMPATIBLE);
return; return;