Fixed nested struct/union initialization.

Fixed bit-fields offsets in anonymous structs.
This commit is contained in:
acqn 2020-07-29 15:09:53 +08:00 committed by Oliver Schmidt
parent d6d667a688
commit 25d10d9d9a
7 changed files with 201 additions and 105 deletions

View File

@ -61,6 +61,17 @@ static const char AnonTag[] = "$anon";
char* AnonFieldName (char* Buf, const char* Spec, int ANumber)
/* Get a name for an anonymous field of a struct or union. The given buffer is
** expected to be IDENTSIZE characters long. A pointer to the buffer is returned.
*/
{
xsprintf (Buf, IDENTSIZE, "%s-%s-%04X", AnonTag, Spec, ANumber);
return Buf;
}
char* AnonName (char* Buf, const char* Spec)
/* Get a name for an anonymous variable or type. The given buffer is expected
** to be IDENTSIZE characters long. A pointer to the buffer is returned.

View File

@ -44,6 +44,11 @@
char* AnonFieldName (char* Buf, const char* Spec, int ANumber);
/* Get a name for an anonymous field of a struct or union. The given buffer is
** expected to be IDENTSIZE characters long. A pointer to the buffer is returned.
*/
char* AnonName (char* Buf, const char* Spec);
/* Get a name for an anonymous variable or type. The given buffer is expected
** to be IDENTSIZE characters long. A pointer to the buffer is returned.

View File

@ -89,7 +89,7 @@ struct StructInitData {
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers);
/* Parse a type specifier */
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers);
static unsigned ParseInitInternal (Type* T, int* Braces, int AllowFlexibleMembers);
/* Parse initialization of variables. Return the number of data bytes. */
@ -717,24 +717,24 @@ static int ParseFieldWidth (Declaration* Decl)
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.
static unsigned AliasAnonStructFields (const Declaration* Decl, SymEntry* Anon)
/* Create alias fields from an anon union/struct in the current lexical level.
** The function returns the count of created aliases.
*/
{
unsigned Count = 0;
SymEntry* Alias;
/* Get the pointer to the symbol table entry of the anon struct */
SymEntry* Entry = GetSymEntry (Decl->Type);
/* Get the size of the anon struct */
unsigned Size = Entry->V.S.Size;
/* Get the symbol table containing the fields. If it is empty, there has
** been an error before, so bail out.
*/
SymTable* Tab = Entry->V.S.SymTab;
if (Tab == 0) {
/* Incomplete definition - has been flagged before */
return Size;
return 0;
}
/* Get a pointer to the list of symbols. Then walk the list adding copies
@ -743,10 +743,13 @@ static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
Entry = Tab->SymHead;
while (Entry) {
/* Enter a copy of this symbol adjusting the offset. We will just
** reuse the type string here.
*/
AddLocalSym (Entry->Name, Entry->Type, SC_STRUCTFIELD, Offs + Entry->V.Offs);
/* Enter an alias of this symbol */
if (!IsAnonName (Entry->Name)) {
Alias = AddLocalSym (Entry->Name, Entry->Type, SC_STRUCTFIELD|SC_ALIAS, 0);
Alias->V.A.Field = Entry;
Alias->V.A.Offs = Anon->V.Offs + Entry->V.Offs;
++Count;
}
/* Currently, there can not be any attributes, but if there will be
** some in the future, we want to know this.
@ -757,8 +760,8 @@ static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
Entry = Entry->NextSym;
}
/* Return the size of the embedded struct */
return Size;
/* Return the count of created aliases */
return Count;
}
@ -771,6 +774,8 @@ static SymEntry* ParseUnionDecl (const char* Name)
unsigned FieldSize;
int FieldWidth; /* Width in bits, -1 if not a bit-field */
SymTable* FieldTab;
SymEntry* StructTypeEntry;
SymEntry* Entry;
if (CurTok.Tok != TOK_LCURLY) {
@ -779,7 +784,9 @@ static SymEntry* ParseUnionDecl (const char* Name)
}
/* Add a forward declaration for the struct in the current lexical level */
AddStructSym (Name, SC_UNION, 0, 0);
StructTypeEntry = AddStructSym (Name, SC_UNION, 0, 0);
StructTypeEntry->V.S.ACount = 0;
/* Skip the curly brace */
NextToken ();
@ -821,16 +828,11 @@ static SymEntry* ParseUnionDecl (const char* Name)
/* This is an anonymous struct or union. Copy the fields
** into the current level.
*/
FieldSize = CopyAnonStructFields (&Decl, 0);
if (FieldSize > UnionSize) {
UnionSize = FieldSize;
}
AnonFieldName (Decl.Ident, "field", StructTypeEntry->V.S.ACount);
} else {
/* A non bit-field without a name is legal but useless */
Warning ("Declaration does not declare anything");
}
goto NextMember;
}
/* Handle sizes */
@ -843,7 +845,13 @@ static SymEntry* ParseUnionDecl (const char* Name)
if (FieldWidth > 0) {
AddBitField (Decl.Ident, 0, 0, FieldWidth);
} else {
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
if (IsAnonName (Decl.Ident)) {
Entry = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
Entry->V.A.ANumber = StructTypeEntry->V.S.ACount++;
AliasAnonStructFields (&Decl, Entry);
} else {
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
}
}
NextMember: if (CurTok.Tok != TOK_COMMA) {
@ -876,6 +884,8 @@ static SymEntry* ParseStructDecl (const char* Name)
unsigned BitOffs; /* Bit offset for bit-fields */
int FieldWidth; /* Width in bits, -1 if not a bit-field */
SymTable* FieldTab;
SymEntry* StructTypeEntry;
SymEntry* Entry;
if (CurTok.Tok != TOK_LCURLY) {
@ -884,7 +894,9 @@ static SymEntry* ParseStructDecl (const char* Name)
}
/* Add a forward declaration for the struct in the current lexical level */
AddStructSym (Name, SC_STRUCT, 0, 0);
StructTypeEntry = AddStructSym (Name, SC_STRUCT, 0, 0);
StructTypeEntry->V.S.ACount = 0;
/* Skip the curly brace */
NextToken ();
@ -981,13 +993,11 @@ static SymEntry* ParseStructDecl (const char* Name)
/* This is an anonymous struct or union. Copy the
** fields into the current level.
*/
StructSize += CopyAnonStructFields (&Decl, StructSize);
AnonFieldName (Decl.Ident, "field", StructTypeEntry->V.S.ACount);
} else {
/* A non bit-field without a name is legal but useless */
Warning ("Declaration does not declare anything");
}
goto NextMember;
} else {
/* A bit-field without a name will get an anonymous one */
AnonName (Decl.Ident, "bit-field");
@ -1009,7 +1019,13 @@ static SymEntry* ParseStructDecl (const char* Name)
StructSize += BitOffs / CHAR_BITS;
BitOffs %= CHAR_BITS;
} else {
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
if (IsAnonName (Decl.Ident)) {
Entry = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
Entry->V.A.ANumber = StructTypeEntry->V.S.ACount++;
AliasAnonStructFields (&Decl, Entry);
} else {
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
}
if (!FlexibleMember) {
StructSize += CheckedSizeOf (Decl.Type);
}
@ -1874,18 +1890,20 @@ void CheckEmptyDecl (const DeclSpec* D)
static void SkipInitializer (unsigned BracesExpected)
static void SkipInitializer (int BracesExpected)
/* Skip the remainder of an initializer in case of errors. Try to be somewhat
** smart so we don't have too many following errors.
*/
{
while (CurTok.Tok != TOK_CEOF && CurTok.Tok != TOK_SEMI && BracesExpected > 0) {
while (CurTok.Tok != TOK_CEOF && CurTok.Tok != TOK_SEMI && BracesExpected >= 0) {
switch (CurTok.Tok) {
case TOK_RCURLY: --BracesExpected; break;
case TOK_LCURLY: ++BracesExpected; break;
default: break;
}
NextToken ();
if (BracesExpected >= 0) {
NextToken ();
}
}
}
@ -1917,6 +1935,7 @@ static void ClosingCurlyBraces (unsigned BracesExpected)
*/
{
while (BracesExpected) {
/* TODO: Skip all excess initializers until next closing curly brace */
if (CurTok.Tok == TOK_RCURLY) {
NextToken ();
} else if (CurTok.Tok == TOK_COMMA && NextTok.Tok == TOK_RCURLY) {
@ -2069,7 +2088,7 @@ static unsigned ParsePointerInit (Type* T)
static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
static unsigned ParseArrayInit (Type* T, int* Braces, int AllowFlexibleMembers)
/* Parse initializaton for arrays. Return the number of data bytes. */
{
int Count;
@ -2135,7 +2154,7 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
** an array (because the size of each element may differ
** otherwise).
*/
ParseInitInternal (ElementType, 0);
ParseInitInternal (ElementType, Braces, 0);
++Count;
if (CurTok.Tok != TOK_COMMA)
break;
@ -2158,23 +2177,29 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
} else if (Count < ElementCount) {
g_zerobytes ((ElementCount - Count) * ElementSize);
} else if (Count > ElementCount) {
Error ("Too many initializers");
Error ("Excess elements in array initializer");
}
return ElementCount * ElementSize;
}
static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
/* Parse initialization of a struct or union. Return the number of data bytes. */
{
SymEntry* Entry;
SymTable* Tab;
StructInitData SI;
int HasCurly = 0;
int SkipComma = 0;
/* Consume the opening curly brace */
ConsumeLCurly ();
/* Fields can be initialized without a pair of curly braces */
if (*Braces == 0 || CurTok.Tok == TOK_LCURLY) {
/* Consume the opening curly brace */
HasCurly = ConsumeLCurly ();
*Braces += HasCurly;
}
/* Get a pointer to the struct entry from the type */
Entry = GetSymEntry (T);
@ -2189,7 +2214,7 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
if (Tab == 0) {
Error ("Cannot initialize variables with incomplete type");
/* Try error recovery */
SkipInitializer (1);
SkipInitializer (HasCurly);
/* Nothing initialized */
return 0;
}
@ -2203,18 +2228,50 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
SI.ValBits = 0;
while (CurTok.Tok != TOK_RCURLY) {
/* */
/* Check for excess elements */
if (Entry == 0) {
Error ("Too many initializers");
SkipInitializer (1);
if (HasCurly) {
Error ("Excess elements in %s initializer", GetBasicTypeName (T));
SkipInitializer (HasCurly);
}
return SI.Offs;
}
/* Parse initialization of one field. Bit-fields need a special
** handling.
/* Check for special members that don't consume the initializer */
if ((Entry->Flags & SC_ALIAS) == SC_ALIAS) {
/* Just skip */
goto NextMember;
}
/* This may be an anonymous bit-field, in which case it doesn't
** have an initializer.
*/
if (SymIsBitField (Entry) && (IsAnonName (Entry->Name))) {
/* Account for the data and output it if we have at least a full
** word. We may have more if there was storage unit overlap, for
** example two consecutive 10 bit fields. These will be packed
** into 3 bytes.
*/
SI.ValBits += Entry->V.B.BitWidth;
CHECK (SI.ValBits <= CHAR_BITS + INT_BITS - 2);
while (SI.ValBits >= CHAR_BITS) {
OutputBitFieldData (&SI);
}
/* Avoid consuming the comma if any */
goto NextMember;
}
/* Skip comma this round */
if (SkipComma) {
NextToken ();
SkipComma = 0;
}
if (SymIsBitField (Entry)) {
/* Parse initialization of one field. Bit-fields need a special
** handling.
*/
ExprDesc ED;
unsigned Val;
unsigned Shift;
@ -2226,36 +2283,17 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
CHECK (Entry->V.B.Offs * CHAR_BITS + Entry->V.B.BitOffs ==
SI.Offs * CHAR_BITS + SI.ValBits);
/* This may be an anonymous bit-field, in which case it doesn't
** have an initializer.
*/
if (IsAnonName (Entry->Name)) {
/* Account for the data and output it if we have at least a
** full word. We may have more if there was storage unit
** overlap, for example two consecutive 10 bit fields.
** These will be packed into 3 bytes.
*/
SI.ValBits += Entry->V.B.BitWidth;
CHECK (SI.ValBits <= CHAR_BITS + INT_BITS - 2);
while (SI.ValBits >= CHAR_BITS) {
OutputBitFieldData (&SI);
}
goto NextMember;
} else {
/* Read the data, check for a constant integer, do a range
** check.
*/
ParseScalarInitInternal (type_uint, &ED);
if (!ED_IsConstAbsInt (&ED)) {
Error ("Constant initializer expected");
ED_MakeConstAbsInt (&ED, 1);
}
if (ED.IVal > (long) Mask) {
Warning ("Truncating value in bit-field initializer");
ED.IVal &= (long) Mask;
}
Val = (unsigned) ED.IVal;
/* Read the data, check for a constant integer, do a range check */
ParseScalarInitInternal (type_uint, &ED);
if (!ED_IsConstAbsInt (&ED)) {
Error ("Constant initializer expected");
ED_MakeConstAbsInt (&ED, 1);
}
if (ED.IVal > (long) Mask) {
Warning ("Truncating value in bit-field initializer");
ED.IVal &= (long) Mask;
}
Val = (unsigned) ED.IVal;
/* Add the value to the currently stored bit-field value */
Shift = (Entry->V.B.Offs - SI.Offs) * CHAR_BITS + Entry->V.B.BitOffs;
@ -2285,7 +2323,7 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
/* Flexible array members may only be initialized if they are
** the last field (or part of the last struct field).
*/
SI.Offs += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0);
SI.Offs += ParseInitInternal (Entry->Type, Braces, AllowFlexibleMembers && Entry->NextSym == 0);
}
/* More initializers? */
@ -2293,8 +2331,8 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
break;
}
/* Skip the comma */
NextToken ();
/* Skip the comma next round */
SkipComma = 1;
NextMember:
/* Next member. For unions, only the first one can be initialized */
@ -2307,8 +2345,10 @@ NextMember:
}
}
/* Consume the closing curly brace */
ConsumeRCurly ();
if (HasCurly) {
/* Consume the closing curly brace */
ConsumeRCurly ();
}
/* If we have data from a bit-field left, output it now */
CHECK (SI.ValBits < CHAR_BITS);
@ -2405,7 +2445,7 @@ static unsigned ParseVoidInit (Type* T)
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
static unsigned ParseInitInternal (Type* T, int *Braces, int AllowFlexibleMembers)
/* Parse initialization of variables. Return the number of data bytes. */
{
switch (GetUnderlyingTypeCode (T)) {
@ -2426,11 +2466,11 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
return ParsePointerInit (T);
case T_ARRAY:
return ParseArrayInit (T, AllowFlexibleMembers);
return ParseArrayInit (T, Braces, AllowFlexibleMembers);
case T_STRUCT:
case T_UNION:
return ParseStructInit (T, AllowFlexibleMembers);
return ParseStructInit (T, Braces, AllowFlexibleMembers);
case T_VOID:
if (IS_Get (&Standard) == STD_CC65) {
@ -2451,10 +2491,13 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
unsigned ParseInit (Type* T)
/* Parse initialization of variables. Return the number of data bytes. */
{
/* Current curly braces layers */
int Braces = 0;
/* Parse the initialization. Flexible array members can only be initialized
** in cc65 mode.
*/
unsigned Size = ParseInitInternal (T, IS_Get (&Standard) == STD_CC65);
unsigned Size = ParseInitInternal (T, &Braces, IS_Get (&Standard) == STD_CC65);
/* The initialization may not generate code on global level, because code
** outside function scope will never get executed.

View File

@ -1201,7 +1201,6 @@ static void StructRef (ExprDesc* Expr)
/* Process struct/union field after . or ->. */
{
ident Ident;
SymEntry* Field;
Type* FinalType;
TypeCode Q;
@ -1217,8 +1216,8 @@ static void StructRef (ExprDesc* Expr)
/* Get the symbol table entry and check for a struct/union field */
strcpy (Ident, CurTok.Ident);
NextToken ();
Field = FindStructField (Expr->Type, Ident);
if (Field == 0) {
const SymEntry Field = FindStructField (Expr->Type, Ident);
if (Field.Type == 0) {
Error ("No field named '%s' found in %s", Ident, GetBasicTypeName (Expr->Type));
/* Make the expression an integer at address zero */
ED_MakeConstAbs (Expr, 0, type_int);
@ -1264,10 +1263,10 @@ static void StructRef (ExprDesc* Expr)
} else {
Q = GetQualifier (Indirect (Expr->Type));
}
if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) {
FinalType = Field->Type;
if (GetQualifier (Field.Type) == (GetQualifier (Field.Type) | Q)) {
FinalType = Field.Type;
} else {
FinalType = TypeDup (Field->Type);
FinalType = TypeDup (Field.Type);
FinalType->C |= Q;
}
@ -1278,10 +1277,10 @@ static void StructRef (ExprDesc* Expr)
/* Get the size of the type */
unsigned StructSize = SizeOf (Expr->Type);
unsigned FieldSize = SizeOf (Field->Type);
unsigned FieldSize = SizeOf (Field.Type);
/* Safety check */
CHECK (Field->V.Offs + FieldSize <= StructSize);
CHECK (Field.V.Offs + FieldSize <= StructSize);
/* The type of the operation depends on the type of the struct/union */
switch (StructSize) {
@ -1304,16 +1303,16 @@ static void StructRef (ExprDesc* Expr)
/* Generate a shift to get the field in the proper position in the
** primary. For bit fields, mask the value.
*/
BitOffs = Field->V.Offs * CHAR_BITS;
if (SymIsBitField (Field)) {
BitOffs += Field->V.B.BitOffs;
BitOffs = Field.V.Offs * CHAR_BITS;
if (SymIsBitField (&Field)) {
BitOffs += Field.V.B.BitOffs;
g_asr (Flags, BitOffs);
/* Mask the value. This is unnecessary if the shift executed above
** moved only zeroes into the value.
*/
if (BitOffs + Field->V.B.BitWidth != FieldSize * CHAR_BITS) {
if (BitOffs + Field.V.B.BitWidth != FieldSize * CHAR_BITS) {
g_and (CF_INT | CF_UNSIGNED | CF_CONST,
(0x0001U << Field->V.B.BitWidth) - 1U);
(0x0001U << Field.V.B.BitWidth) - 1U);
}
} else {
g_asr (Flags, BitOffs);
@ -1325,7 +1324,7 @@ static void StructRef (ExprDesc* Expr)
} else {
/* Set the struct/union field offset */
Expr->IVal += Field->V.Offs;
Expr->IVal += Field.V.Offs;
/* Use the new type */
Expr->Type = FinalType;
@ -1341,8 +1340,8 @@ static void StructRef (ExprDesc* Expr)
}
/* Make the expression a bit field if necessary */
if (SymIsBitField (Field)) {
ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth);
if (SymIsBitField (&Field)) {
ED_MakeBitField (Expr, Field.V.B.BitOffs, Field.V.B.BitWidth);
}
}

View File

@ -105,6 +105,7 @@ struct CodeEntry;
#define SC_SPADJUSTMENT 0x400000U
#define SC_GOTO_IND 0x800000U /* Indirect goto */
#define SC_ALIAS 0x01000000U /* Alias of anonymous field */
@ -138,6 +139,14 @@ struct SymEntry {
/* Offset for locals or struct members */
int Offs;
/* Data for anonymous struct or union members */
struct {
int Offs; /* Byte offset into struct */
unsigned ANumber; /* Numeric ID */
SymEntry* Field; /* The real field aliased */
} A;
/* Label name for static symbols */
struct {
unsigned Label;
@ -163,6 +172,7 @@ struct SymEntry {
struct {
struct SymTable* SymTab; /* Member symbol table */
unsigned Size; /* Size of the union/struct */
unsigned ACount; /* Count of anonymous fields */
} S;
/* Data for enums */

View File

@ -490,10 +490,15 @@ SymEntry* FindTagSym (const char* Name)
SymEntry* FindStructField (const Type* T, const char* Name)
/* Find a struct/union field in the fields list */
SymEntry FindStructField (const Type* T, const char* Name)
/* Find a struct/union field in the fields list.
** Return the info about the found field symbol filled in an entry struct by
** value, or an empty entry struct if the field is not found.
*/
{
SymEntry* Field = 0;
SymEntry* Entry = 0;
SymEntry Field;
int Offs = 0;
/* The given type may actually be a pointer to struct/union */
if (IsTypePtr (T)) {
@ -511,10 +516,26 @@ SymEntry* FindStructField (const Type* T, const char* Name)
** not exist.
*/
if (Struct->V.S.SymTab) {
Field = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));
Entry = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));
if (Entry != 0) {
Offs = Entry->V.Offs;
}
while (Entry != 0 && (Entry->Flags & SC_ALIAS) == SC_ALIAS) {
/* Get the real field */
Entry = Entry->V.A.Field;
}
}
}
if (Entry != 0) {
Field = *Entry;
Field.V.Offs = Offs;
} else {
memset (&Field, 0, sizeof(SymEntry));
}
return Field;
}
@ -1001,7 +1022,13 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
/* Set the symbol attributes */
Entry->Type = TypeDup (T);
if ((Flags & SC_AUTO) == SC_AUTO || (Flags & SC_TYPEMASK) == SC_TYPEDEF) {
if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD ||
(Flags & SC_TYPEDEF) == SC_TYPEDEF) {
if ((Flags & SC_ALIAS) != SC_ALIAS) {
Entry->V.Offs = Offs;
}
} else if ((Flags & SC_AUTO) == SC_AUTO) {
Entry->V.Offs = Offs;
} else if ((Flags & SC_REGISTER) == SC_REGISTER) {
Entry->V.R.RegOffs = Offs;
@ -1013,8 +1040,6 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
/* Generate the assembler name from the label number */
Entry->V.L.Label = Offs;
Entry->AsmName = xstrdup (LocalLabelName (Entry->V.L.Label));
} else if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD) {
Entry->V.Offs = Offs;
} else {
Internal ("Invalid flags in AddLocalSym: %04X", Flags);
}

View File

@ -133,8 +133,11 @@ SymEntry* FindLocalSym (const char* Name);
SymEntry* FindTagSym (const char* Name);
/* Find the symbol with the given name in the tag table */
SymEntry* FindStructField (const Type* TypeArray, const char* Name);
/* Find a struct/union field in the fields list */
SymEntry FindStructField (const Type* TypeArray, const char* Name);
/* Find a struct/union field in the fields list.
** Return the info about the found field symbol filled in an entry struct by
** value, or an empty entry struct if the field is not found.
*/
unsigned short FindSPAdjustment (const char* Name);
/* Search for an entry in the table of SP adjustments */