X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fdeclare.c;h=e3b5edfeca4010f3514210f341899f871719b56e;hb=e767c8990d07003d9c91a6151cc61f0ea28639ea;hp=40235ea8427e10c0b1ad21d73393f066e04c68fa;hpb=1f92d6bfa22a4fa7ff9d059e80d722e66bcf989e;p=cc65 diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 40235ea84..e3b5edfec 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -1,15 +1,15 @@ /*****************************************************************************/ /* */ -/* declare.c */ +/* declare.c */ /* */ -/* Parse variable and function declarations */ +/* Parse variable and function declarations */ /* */ /* */ /* */ -/* (C) 1998-2008 Ullrich von Bassewitz */ -/* Roemerstrasse 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 1998-2015, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -58,6 +58,7 @@ #include "scanner.h" #include "standard.h" #include "symtab.h" +#include "wrappedcall.h" #include "typeconv.h" @@ -79,13 +80,13 @@ struct StructInitData { /*****************************************************************************/ -/* Forwards */ +/* Forwards */ /*****************************************************************************/ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers); -/* Parse a type specificier */ +/* Parse a type specifier */ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers); /* Parse initialization of variables. Return the number of data bytes. */ @@ -93,7 +94,7 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers); /*****************************************************************************/ -/* Internal functions */ +/* Internal functions */ /*****************************************************************************/ @@ -101,15 +102,15 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers); static void DuplicateQualifier (const char* Name) /* Print an error message */ { - Warning ("Duplicate qualifier: `%s'", Name); + Warning ("Duplicate qualifier: '%s'", Name); } static TypeCode OptionalQualifiers (TypeCode Allowed) /* Read type qualifiers if we have any. Allowed specifies the allowed - * qualifiers. - */ +** qualifiers. +*/ { /* We start without any qualifiers */ TypeCode Q = T_QUAL_NONE; @@ -117,9 +118,9 @@ static TypeCode OptionalQualifiers (TypeCode Allowed) /* Check for more qualifiers */ while (1) { - switch (CurTok.Tok) { + switch (CurTok.Tok) { - case TOK_CONST: + case TOK_CONST: if (Allowed & T_QUAL_CONST) { if (Q & T_QUAL_CONST) { DuplicateQualifier ("const"); @@ -130,7 +131,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed) } break; - case TOK_VOLATILE: + case TOK_VOLATILE: if (Allowed & T_QUAL_VOLATILE) { if (Q & T_QUAL_VOLATILE) { DuplicateQualifier ("volatile"); @@ -139,7 +140,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed) } else { goto Done; } - break; + break; case TOK_RESTRICT: if (Allowed & T_QUAL_RESTRICT) { @@ -185,13 +186,24 @@ static TypeCode OptionalQualifiers (TypeCode Allowed) } break; - default: - goto Done; + case TOK_CDECL: + if (Allowed & T_QUAL_CDECL) { + if (Q & T_QUAL_CDECL) { + DuplicateQualifier ("cdecl"); + } + Q |= T_QUAL_CDECL; + } else { + goto Done; + } + break; - } + default: + goto Done; - /* Skip the token */ - NextToken (); + } + + /* Skip the token */ + NextToken (); } Done: @@ -208,6 +220,19 @@ Done: Q &= ~T_QUAL_ADDRSIZE; } + /* We cannot have more than one calling convention specifier */ + switch (Q & T_QUAL_CCONV) { + + case T_QUAL_NONE: + case T_QUAL_FASTCALL: + case T_QUAL_CDECL: + break; + + default: + Error ("Cannot specify more than one calling convention qualifier"); + Q &= ~T_QUAL_CCONV; + } + /* Return the qualifiers read */ return Q; } @@ -218,8 +243,8 @@ static void OptionalInt (void) /* Eat an optional "int" token */ { if (CurTok.Tok == TOK_INT) { - /* Skip it */ - NextToken (); + /* Skip it */ + NextToken (); } } @@ -229,8 +254,8 @@ static void OptionalSigned (void) /* Eat an optional "signed" token */ { if (CurTok.Tok == TOK_SIGNED) { - /* Skip it */ - NextToken (); + /* Skip it */ + NextToken (); } } @@ -249,9 +274,10 @@ static void InitDeclSpec (DeclSpec* D) static void InitDeclaration (Declaration* D) /* Initialize the Declaration struct for use */ { - D->Ident[0] = '\0'; - D->Type[0].C = T_END; - D->Index = 0; + D->Ident[0] = '\0'; + D->Type[0].C = T_END; + D->Index = 0; + D->Attributes = 0; } @@ -260,11 +286,11 @@ static void NeedTypeSpace (Declaration* D, unsigned Count) /* Check if there is enough space for Count type specifiers within D */ { if (D->Index + Count >= MAXTYPELEN) { - /* We must call Fatal() here, since calling Error() will try to - * continue, and the declaration type is not correctly terminated - * in case we come here. - */ - Fatal ("Too many type specifiers"); + /* We must call Fatal() here, since calling Error() will try to + ** continue, and the declaration type is not correctly terminated + ** in case we come here. + */ + Fatal ("Too many type specifiers"); } } @@ -286,9 +312,9 @@ static void FixQualifiers (Type* DataType) TypeCode Q; /* Using typedefs, it is possible to generate declarations that have - * type qualifiers attached to an array, not the element type. Go and - * fix these here. - */ + ** type qualifiers attached to an array, not the element type. Go and + ** fix these here. + */ T = DataType; Q = T_QUAL_NONE; while (T->C != T_END) { @@ -310,18 +336,30 @@ static void FixQualifiers (Type* DataType) T = DataType; while (T->C != T_END) { if (IsTypePtr (T)) { - - /* Fastcall qualifier on the pointer? */ - if (IsQualFastcall (T)) { - /* Pointer to function which is not fastcall? */ - if (IsTypeFunc (T+1) && !IsQualFastcall (T+1)) { - /* Move the fastcall qualifier from the pointer to - * the function. - */ - T[0].C &= ~T_QUAL_FASTCALL; - T[1].C |= T_QUAL_FASTCALL; + /* Calling convention qualifier on the pointer? */ + if (IsQualCConv (T)) { + /* Pull the convention off of the pointer */ + Q = T[0].C & T_QUAL_CCONV; + T[0].C &= ~T_QUAL_CCONV; + + /* Pointer to a function which doesn't have an explicit convention? */ + if (IsTypeFunc (T + 1)) { + if (IsQualCConv (T + 1)) { + if ((T[1].C & T_QUAL_CCONV) == Q) { + Warning ("Pointer duplicates function's calling convention"); + } else { + Error ("Function's and pointer's calling conventions are different"); + } + } else { + if (Q == T_QUAL_FASTCALL && IsVariadicFunc (T + 1)) { + Error ("Variadic-function pointers cannot be __fastcall__"); + } else { + /* Move the qualifier from the pointer to the function. */ + T[1].C |= Q; + } + } } else { - Error ("Invalid `_fastcall__' qualifier for pointer"); + Error ("Not pointer to a function; can't use a calling convention"); } } @@ -330,9 +368,9 @@ static void FixQualifiers (Type* DataType) if (Q == T_QUAL_NONE) { /* No address size qualifiers specified */ if (IsTypeFunc (T+1)) { - /* Pointer to function. Use the qualifier from the function - * or the default if the function don't has one. - */ + /* Pointer to function. Use the qualifier from the function, + ** or the default if the function doesn't have one. + */ Q = (T[1].C & T_QUAL_ADDRSIZE); if (Q == T_QUAL_NONE) { Q = CodeAddrSizeQualifier (); @@ -343,8 +381,8 @@ static void FixQualifiers (Type* DataType) T[0].C |= Q; } else { /* We have address size qualifiers. If followed by a function, - * apply these also to the function. - */ + ** apply them to the function also. + */ if (IsTypeFunc (T+1)) { TypeCode FQ = (T[1].C & T_QUAL_ADDRSIZE); if (FQ == T_QUAL_NONE) { @@ -379,36 +417,36 @@ static void ParseStorageClass (DeclSpec* D, unsigned DefStorage) /* Check the storage class given */ switch (CurTok.Tok) { - case TOK_EXTERN: - D->StorageClass = SC_EXTERN | SC_STATIC; - NextToken (); - break; - - case TOK_STATIC: - D->StorageClass = SC_STATIC; - NextToken (); - break; - - case TOK_REGISTER: - D->StorageClass = SC_REGISTER | SC_STATIC; - NextToken (); - break; - - case TOK_AUTO: - D->StorageClass = SC_AUTO; - NextToken (); - break; - - case TOK_TYPEDEF: - D->StorageClass = SC_TYPEDEF; - NextToken (); - break; - - default: - /* No storage class given, use default */ - D->Flags |= DS_DEF_STORAGE; - D->StorageClass = DefStorage; - break; + case TOK_EXTERN: + D->StorageClass = SC_EXTERN | SC_STATIC; + NextToken (); + break; + + case TOK_STATIC: + D->StorageClass = SC_STATIC; + NextToken (); + break; + + case TOK_REGISTER: + D->StorageClass = SC_REGISTER | SC_STATIC; + NextToken (); + break; + + case TOK_AUTO: + D->StorageClass = SC_AUTO; + NextToken (); + break; + + case TOK_TYPEDEF: + D->StorageClass = SC_TYPEDEF; + NextToken (); + break; + + default: + /* No storage class given, use default */ + D->Flags |= DS_DEF_STORAGE; + D->StorageClass = DefStorage; + break; } } @@ -422,7 +460,7 @@ static void ParseEnumDecl (void) /* Accept forward definitions */ if (CurTok.Tok != TOK_LCURLY) { - return; + return; } /* Skip the opening curly brace */ @@ -432,31 +470,31 @@ static void ParseEnumDecl (void) EnumVal = 0; while (CurTok.Tok != TOK_RCURLY) { - /* We expect an identifier */ - if (CurTok.Tok != TOK_IDENT) { - Error ("Identifier expected"); - continue; - } - - /* Remember the identifier and skip it */ - strcpy (Ident, CurTok.Ident); - NextToken (); - - /* Check for an assigned value */ - if (CurTok.Tok == TOK_ASSIGN) { - ExprDesc Expr; - NextToken (); - ConstAbsIntExpr (hie1, &Expr); - EnumVal = Expr.IVal; - } - - /* Add an entry to the symbol table */ - AddConstSym (Ident, type_int, SC_ENUM, EnumVal++); - - /* Check for end of definition */ - if (CurTok.Tok != TOK_COMMA) - break; - NextToken (); + /* We expect an identifier */ + if (CurTok.Tok != TOK_IDENT) { + Error ("Identifier expected"); + continue; + } + + /* Remember the identifier and skip it */ + strcpy (Ident, CurTok.Ident); + NextToken (); + + /* Check for an assigned value */ + if (CurTok.Tok == TOK_ASSIGN) { + ExprDesc Expr; + NextToken (); + ConstAbsIntExpr (hie1, &Expr); + EnumVal = Expr.IVal; + } + + /* Add an entry to the symbol table */ + AddConstSym (Ident, type_int, SC_ENUM, EnumVal++); + + /* Check for end of definition */ + if (CurTok.Tok != TOK_COMMA) + break; + NextToken (); } ConsumeRCurly (); } @@ -464,9 +502,9 @@ static void ParseEnumDecl (void) static int ParseFieldWidth (Declaration* Decl) -/* Parse an optional field width. Returns -1 if no field width is speficied, - * otherwise the width of the field. - */ +/* Parse an optional field width. Returns -1 if no field width is specified, +** otherwise the width of the field. +*/ { ExprDesc Expr; @@ -502,24 +540,70 @@ static int ParseFieldWidth (Declaration* Decl) -static SymEntry* StructOrUnionForwardDecl (const char* Name) +static SymEntry* StructOrUnionForwardDecl (const char* Name, unsigned Type) /* Handle a struct or union forward decl */ { - /* Try to find a struct with the given name. If there is none, - * insert a forward declaration into the current lexical level. - */ + /* 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, 0, 0); - } else if (SymIsLocal (Entry) && (Entry->Flags & SC_STRUCT) != SC_STRUCT) { - /* Already defined in the level, but no struct */ - Error ("Symbol `%s' is already different kind", Name); + 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. +*/ +{ + /* 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; + } + + /* Get a pointer to the list of symbols. Then walk the list adding copies + ** of the embedded struct to the current level. + */ + 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); + + /* Currently, there can not be any attributes, but if there will be + ** some in the future, we want to know this. + */ + CHECK (Entry->Attr == 0); + + /* Next entry */ + Entry = Entry->NextSym; + } + + /* Return the size of the embedded struct */ + return Size; +} + + + static SymEntry* ParseUnionDecl (const char* Name) /* Parse a union declaration. */ { @@ -528,16 +612,15 @@ static SymEntry* ParseUnionDecl (const char* Name) unsigned FieldSize; int FieldWidth; /* Width in bits, -1 if not a bit-field */ SymTable* FieldTab; - SymEntry* Entry; if (CurTok.Tok != TOK_LCURLY) { - /* Just a forward declaration. */ - return StructOrUnionForwardDecl (Name); + /* Just a forward declaration. */ + return StructOrUnionForwardDecl (Name, SC_UNION); } /* Add a forward declaration for the struct in the current lexical level */ - Entry = AddStructSym (Name, 0, 0); + AddStructSym (Name, SC_UNION, 0, 0); /* Skip the curly brace */ NextToken (); @@ -549,18 +632,18 @@ static SymEntry* ParseUnionDecl (const char* Name) UnionSize = 0; while (CurTok.Tok != TOK_RCURLY) { - /* Get the type of the entry */ - DeclSpec Spec; - InitDeclSpec (&Spec); - ParseTypeSpec (&Spec, -1, T_QUAL_NONE); + /* Get the type of the entry */ + DeclSpec Spec; + InitDeclSpec (&Spec); + ParseTypeSpec (&Spec, -1, T_QUAL_NONE); - /* Read fields with this type */ - while (1) { + /* Read fields with this type */ + while (1) { - Declaration Decl; + Declaration Decl; - /* Get type and name of the struct field */ - ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT); + /* Get type and name of the struct field */ + ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT); /* Check for a bit-field declaration */ FieldWidth = ParseFieldWidth (&Decl); @@ -572,8 +655,22 @@ static SymEntry* ParseUnionDecl (const char* Name) /* Check for fields without a name */ if (Decl.Ident[0] == '\0') { - /* Any field without a name is legal but useless in a union */ - Warning ("Declaration does not declare anything"); + /* In cc65 mode, we allow anonymous structs/unions within + ** a union. + */ + if (IS_Get (&Standard) >= STD_CC65 && IsClassStruct (Decl.Type)) { + /* This is an anonymous struct or union. Copy the fields + ** into the current level. + */ + FieldSize = CopyAnonStructFields (&Decl, 0); + if (FieldSize > UnionSize) { + UnionSize = FieldSize; + } + + } else { + /* A non bit-field without a name is legal but useless */ + Warning ("Declaration does not declare anything"); + } goto NextMember; } @@ -591,11 +688,11 @@ static SymEntry* ParseUnionDecl (const char* Name) } NextMember: if (CurTok.Tok != TOK_COMMA) { - break; + break; } - NextToken (); - } - ConsumeSemi (); + NextToken (); + } + ConsumeSemi (); } /* Skip the closing brace */ @@ -606,7 +703,7 @@ NextMember: if (CurTok.Tok != TOK_COMMA) { LeaveStructLevel (); /* Make a real entry from the forward decl and return it */ - return AddStructSym (Name, UnionSize, FieldTab); + return AddStructSym (Name, SC_UNION, UnionSize, FieldTab); } @@ -620,16 +717,15 @@ static SymEntry* ParseStructDecl (const char* Name) int BitOffs; /* Bit offset for bit-fields */ int FieldWidth; /* Width in bits, -1 if not a bit-field */ SymTable* FieldTab; - SymEntry* Entry; if (CurTok.Tok != TOK_LCURLY) { - /* Just a forward declaration. */ - return StructOrUnionForwardDecl (Name); + /* Just a forward declaration. */ + return StructOrUnionForwardDecl (Name, SC_STRUCT); } /* Add a forward declaration for the struct in the current lexical level */ - Entry = AddStructSym (Name, 0, 0); + AddStructSym (Name, SC_STRUCT, 0, 0); /* Skip the curly brace */ NextToken (); @@ -643,36 +739,36 @@ static SymEntry* ParseStructDecl (const char* Name) BitOffs = 0; while (CurTok.Tok != TOK_RCURLY) { - /* Get the type of the entry */ - DeclSpec Spec; - InitDeclSpec (&Spec); - ParseTypeSpec (&Spec, -1, T_QUAL_NONE); + /* Get the type of the entry */ + DeclSpec Spec; + InitDeclSpec (&Spec); + ParseTypeSpec (&Spec, -1, T_QUAL_NONE); - /* Read fields with this type */ - while (1) { + /* Read fields with this type */ + while (1) { - Declaration Decl; + Declaration Decl; ident Ident; /* If we had a flexible array member before, no other fields can - * follow. - */ + ** 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, DM_ACCEPT_IDENT); + /* Get type and name of the struct field */ + ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT); /* Check for a bit-field declaration */ FieldWidth = ParseFieldWidth (&Decl); /* If this is not a bit field, or the bit field is too large for - * the remainder of the current member, or we have a bit field - * with width zero, align the struct to the next member by adding - * a member with an anonymous name. - */ + ** the remainder of the current member, or we have a bit field + ** with width zero, align the struct to the next member by adding + ** a member with an anonymous name. + */ if (BitOffs > 0) { if (FieldWidth <= 0 || (BitOffs + FieldWidth) > (int) INT_BITS) { @@ -680,8 +776,8 @@ static SymEntry* ParseStructDecl (const char* Name) AnonName (Ident, "bit-field"); /* Add an anonymous bit-field that aligns to the next - * storage unit. - */ + ** storage unit. + */ AddBitField (Ident, StructSize, BitOffs, INT_BITS - BitOffs); /* No bits left */ @@ -691,27 +787,15 @@ static SymEntry* ParseStructDecl (const char* Name) } /* Apart from the above, a bit field with width 0 is not processed - * further. - */ + ** further. + */ if (FieldWidth == 0) { goto NextMember; } - /* Check for fields without names */ - if (Decl.Ident[0] == '\0') { - if (FieldWidth < 0) { - /* 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"); - } - } - /* Check if this field is a flexible array member, and - * calculate the size of the field. - */ + ** calculate the size of the field. + */ if (IsTypeArray (Decl.Type) && GetElementCount (Decl.Type) == UNSPECIFIED) { /* Array with unspecified size */ if (StructSize == 0) { @@ -722,12 +806,36 @@ static SymEntry* ParseStructDecl (const char* Name) SetElementCount (Decl.Type, FLEXIBLE); } + /* Check for fields without names */ + if (Decl.Ident[0] == '\0') { + if (FieldWidth < 0) { + /* In cc65 mode, we allow anonymous structs/unions within + ** a struct. + */ + if (IS_Get (&Standard) >= STD_CC65 && IsClassStruct (Decl.Type)) { + + /* This is an anonymous struct or union. Copy the + ** fields into the current level. + */ + StructSize += CopyAnonStructFields (&Decl, StructSize); + + } 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"); + } + } + /* Add a field entry to the table */ if (FieldWidth > 0) { /* Add full byte from the bit offset to the variable offset. - * This simplifies handling he bit-field as a char type - * in expressions. - */ + ** This simplifies handling he bit-field as a char type + ** in expressions. + */ unsigned Offs = StructSize + (BitOffs / CHAR_BITS); AddBitField (Decl.Ident, Offs, BitOffs % CHAR_BITS, FieldWidth); BitOffs += FieldWidth; @@ -744,11 +852,11 @@ static SymEntry* ParseStructDecl (const char* Name) } NextMember: if (CurTok.Tok != TOK_COMMA) { - break; + break; } - NextToken (); - } - ConsumeSemi (); + NextToken (); + } + ConsumeSemi (); } /* If we have bits from bit-fields left, add them to the size. */ @@ -764,16 +872,16 @@ NextMember: if (CurTok.Tok != TOK_COMMA) { LeaveStructLevel (); /* Make a real entry from the forward decl and return it */ - return AddStructSym (Name, StructSize, FieldTab); + return AddStructSym (Name, SC_STRUCT, StructSize, FieldTab); } static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers) -/* Parse a type specificier */ +/* Parse a type specifier */ { - ident Ident; - SymEntry* Entry; + ident Ident; + SymEntry* Entry; /* Assume we have an explicit type */ D->Flags &= ~DS_DEF_TYPE; @@ -784,223 +892,224 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers) /* Look at the data type */ switch (CurTok.Tok) { - case TOK_VOID: - NextToken (); - D->Type[0].C = T_VOID; - D->Type[1].C = T_END; - break; - - case TOK_CHAR: - NextToken (); - D->Type[0].C = GetDefaultChar(); - D->Type[1].C = T_END; - break; - - case TOK_LONG: - NextToken (); - if (CurTok.Tok == TOK_UNSIGNED) { - NextToken (); - OptionalInt (); - D->Type[0].C = T_ULONG; - D->Type[1].C = T_END; - } else { - OptionalSigned (); - OptionalInt (); - D->Type[0].C = T_LONG; - D->Type[1].C = T_END; - } - break; - - case TOK_SHORT: - NextToken (); - if (CurTok.Tok == TOK_UNSIGNED) { - NextToken (); - OptionalInt (); - D->Type[0].C = T_USHORT; - D->Type[1].C = T_END; - } else { - OptionalSigned (); - OptionalInt (); - D->Type[0].C = T_SHORT; - D->Type[1].C = T_END; - } - break; - - case TOK_INT: - NextToken (); - D->Type[0].C = T_INT; - D->Type[1].C = T_END; - break; + case TOK_VOID: + NextToken (); + D->Type[0].C = T_VOID; + D->Type[0].A.U = 0; + D->Type[1].C = T_END; + break; + + case TOK_CHAR: + NextToken (); + D->Type[0].C = GetDefaultChar(); + D->Type[1].C = T_END; + break; + + case TOK_LONG: + NextToken (); + if (CurTok.Tok == TOK_UNSIGNED) { + NextToken (); + OptionalInt (); + D->Type[0].C = T_ULONG; + D->Type[1].C = T_END; + } else { + OptionalSigned (); + OptionalInt (); + D->Type[0].C = T_LONG; + D->Type[1].C = T_END; + } + break; + + case TOK_SHORT: + NextToken (); + if (CurTok.Tok == TOK_UNSIGNED) { + NextToken (); + OptionalInt (); + D->Type[0].C = T_USHORT; + D->Type[1].C = T_END; + } else { + OptionalSigned (); + OptionalInt (); + D->Type[0].C = T_SHORT; + D->Type[1].C = T_END; + } + break; + + case TOK_INT: + NextToken (); + D->Type[0].C = T_INT; + D->Type[1].C = T_END; + break; case TOK_SIGNED: - NextToken (); - switch (CurTok.Tok) { - - case TOK_CHAR: - NextToken (); - D->Type[0].C = T_SCHAR; - D->Type[1].C = T_END; - break; - - case TOK_SHORT: - NextToken (); - OptionalInt (); - D->Type[0].C = T_SHORT; - D->Type[1].C = T_END; - break; - - case TOK_LONG: - NextToken (); - OptionalInt (); - D->Type[0].C = T_LONG; - D->Type[1].C = T_END; - break; - - case TOK_INT: - NextToken (); - /* FALL THROUGH */ - - default: - D->Type[0].C = T_INT; - D->Type[1].C = T_END; - break; - } - break; - - case TOK_UNSIGNED: - NextToken (); - switch (CurTok.Tok) { - - case TOK_CHAR: - NextToken (); - D->Type[0].C = T_UCHAR; - D->Type[1].C = T_END; - break; - - case TOK_SHORT: - NextToken (); - OptionalInt (); - D->Type[0].C = T_USHORT; - D->Type[1].C = T_END; - break; - - case TOK_LONG: - NextToken (); - OptionalInt (); - D->Type[0].C = T_ULONG; - D->Type[1].C = T_END; - break; - - case TOK_INT: - NextToken (); - /* FALL THROUGH */ - - default: - D->Type[0].C = T_UINT; - D->Type[1].C = T_END; - break; - } - break; + NextToken (); + switch (CurTok.Tok) { + + case TOK_CHAR: + NextToken (); + D->Type[0].C = T_SCHAR; + D->Type[1].C = T_END; + break; + + case TOK_SHORT: + NextToken (); + OptionalInt (); + D->Type[0].C = T_SHORT; + D->Type[1].C = T_END; + break; + + case TOK_LONG: + NextToken (); + OptionalInt (); + D->Type[0].C = T_LONG; + D->Type[1].C = T_END; + break; + + case TOK_INT: + NextToken (); + /* FALL THROUGH */ + + default: + D->Type[0].C = T_INT; + D->Type[1].C = T_END; + break; + } + break; + + case TOK_UNSIGNED: + NextToken (); + switch (CurTok.Tok) { + + case TOK_CHAR: + NextToken (); + D->Type[0].C = T_UCHAR; + D->Type[1].C = T_END; + break; + + case TOK_SHORT: + NextToken (); + OptionalInt (); + D->Type[0].C = T_USHORT; + D->Type[1].C = T_END; + break; + + case TOK_LONG: + NextToken (); + OptionalInt (); + D->Type[0].C = T_ULONG; + D->Type[1].C = T_END; + break; + + case TOK_INT: + NextToken (); + /* FALL THROUGH */ + + default: + D->Type[0].C = T_UINT; + D->Type[1].C = T_END; + break; + } + break; case TOK_FLOAT: - NextToken (); - D->Type[0].C = T_FLOAT; - D->Type[1].C = T_END; - break; + NextToken (); + D->Type[0].C = T_FLOAT; + D->Type[1].C = T_END; + break; case TOK_DOUBLE: - NextToken (); - D->Type[0].C = T_DOUBLE; - D->Type[1].C = T_END; - break; - - case TOK_UNION: - NextToken (); - /* */ - if (CurTok.Tok == TOK_IDENT) { - strcpy (Ident, CurTok.Ident); - NextToken (); - } else { - AnonName (Ident, "union"); - } - /* Remember we have an extra type decl */ - D->Flags |= DS_EXTRA_TYPE; - /* Declare the union in the current scope */ - Entry = ParseUnionDecl (Ident); - /* Encode the union entry into the type */ - D->Type[0].C = T_UNION; - SetSymEntry (D->Type, Entry); - D->Type[1].C = T_END; - break; - - case TOK_STRUCT: - NextToken (); - /* */ - if (CurTok.Tok == TOK_IDENT) { - strcpy (Ident, CurTok.Ident); - NextToken (); - } else { - AnonName (Ident, "struct"); - } - /* Remember we have an extra type decl */ - D->Flags |= DS_EXTRA_TYPE; - /* Declare the struct in the current scope */ - Entry = ParseStructDecl (Ident); - /* Encode the struct entry into the type */ - D->Type[0].C = T_STRUCT; - SetSymEntry (D->Type, Entry); - D->Type[1].C = T_END; - break; - - 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 { - Error ("Identifier expected"); - } - } - /* Remember we have an extra type decl */ - D->Flags |= DS_EXTRA_TYPE; - /* Parse the enum decl */ - ParseEnumDecl (); - D->Type[0].C = T_INT; - D->Type[1].C = T_END; - break; + NextToken (); + D->Type[0].C = T_DOUBLE; + D->Type[1].C = T_END; + break; + + case TOK_UNION: + NextToken (); + /* */ + if (CurTok.Tok == TOK_IDENT) { + strcpy (Ident, CurTok.Ident); + NextToken (); + } else { + AnonName (Ident, "union"); + } + /* Remember we have an extra type decl */ + D->Flags |= DS_EXTRA_TYPE; + /* Declare the union in the current scope */ + Entry = ParseUnionDecl (Ident); + /* Encode the union entry into the type */ + D->Type[0].C = T_UNION; + SetSymEntry (D->Type, Entry); + D->Type[1].C = T_END; + break; + + case TOK_STRUCT: + NextToken (); + /* */ + if (CurTok.Tok == TOK_IDENT) { + strcpy (Ident, CurTok.Ident); + NextToken (); + } else { + AnonName (Ident, "struct"); + } + /* Remember we have an extra type decl */ + D->Flags |= DS_EXTRA_TYPE; + /* Declare the struct in the current scope */ + Entry = ParseStructDecl (Ident); + /* Encode the struct entry into the type */ + D->Type[0].C = T_STRUCT; + SetSymEntry (D->Type, Entry); + D->Type[1].C = T_END; + break; + + 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 { + Error ("Identifier expected"); + } + } + /* Remember we have an extra type decl */ + D->Flags |= DS_EXTRA_TYPE; + /* Parse the enum decl */ + ParseEnumDecl (); + D->Type[0].C = T_INT; + D->Type[1].C = T_END; + break; case TOK_IDENT: - Entry = FindSym (CurTok.Ident); - if (Entry && SymIsTypeDef (Entry)) { - /* It's a typedef */ - NextToken (); - TypeCopy (D->Type, Entry->Type); - break; - } - /* FALL THROUGH */ - - default: - if (Default < 0) { - Error ("Type expected"); - D->Type[0].C = T_INT; - D->Type[1].C = T_END; - } else { - D->Flags |= DS_DEF_TYPE; - D->Type[0].C = (TypeCode) Default; - D->Type[1].C = T_END; - } - break; + Entry = FindSym (CurTok.Ident); + if (Entry && SymIsTypeDef (Entry)) { + /* It's a typedef */ + NextToken (); + TypeCopy (D->Type, Entry->Type); + break; + } + /* FALL THROUGH */ + + default: + if (Default < 0) { + Error ("Type expected"); + D->Type[0].C = T_INT; + D->Type[1].C = T_END; + } else { + D->Flags |= DS_DEF_TYPE; + D->Type[0].C = (TypeCode) Default; + D->Type[1].C = T_END; + } + break; } /* There may also be qualifiers *after* the initial type */ @@ -1011,11 +1120,11 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers) static Type* ParamTypeCvt (Type* T) /* If T is an array, convert it to a pointer else do nothing. Return the - * resulting type. - */ +** resulting type. +*/ { if (IsTypeArray (T)) { - T->C = T_PTR; + T->C = T_PTR; } return T; } @@ -1025,67 +1134,76 @@ static Type* ParamTypeCvt (Type* T) static void ParseOldStyleParamList (FuncDesc* F) /* Parse an old style (K&R) parameter list */ { + /* Some fix point tokens that are used for error recovery */ + static const token_t TokenList[] = { TOK_COMMA, TOK_RPAREN, TOK_SEMI }; + /* Parse params */ while (CurTok.Tok != TOK_RPAREN) { - /* List of identifiers expected */ - if (CurTok.Tok != TOK_IDENT) { - Error ("Identifier expected"); - } + /* List of identifiers expected */ + if (CurTok.Tok == TOK_IDENT) { + + /* Create a symbol table entry with type int */ + AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF | SC_DEFTYPE, 0); - /* Create a symbol table entry with type int */ - AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF | SC_DEFTYPE, 0); + /* Count arguments */ + ++F->ParamCount; - /* Count arguments */ - ++F->ParamCount; + /* Skip the identifier */ + NextToken (); - /* Skip the identifier */ - NextToken (); + } else { + /* Not a parameter name */ + Error ("Identifier expected"); - /* Check for more parameters */ - if (CurTok.Tok == TOK_COMMA) { - NextToken (); - } else { - break; - } + /* Try some smart error recovery */ + SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0])); + } + + /* Check for more parameters */ + if (CurTok.Tok == TOK_COMMA) { + NextToken (); + } else { + break; + } } /* Skip right paren. We must explicitly check for one here, since some of - * the breaks above bail out without checking. - */ + ** the breaks above bail out without checking. + */ ConsumeRParen (); /* An optional list of type specifications follows */ while (CurTok.Tok != TOK_LCURLY) { - DeclSpec Spec; + DeclSpec Spec; - /* Read the declaration specifier */ - ParseDeclSpec (&Spec, SC_AUTO, T_INT); + /* Read the declaration specifier */ + ParseDeclSpec (&Spec, SC_AUTO, T_INT); - /* We accept only auto and register as storage class specifiers, but - * we ignore all this, since we use auto anyway. - */ - if ((Spec.StorageClass & SC_AUTO) == 0 && - (Spec.StorageClass & SC_REGISTER) == 0) { - Error ("Illegal storage class"); - } + /* We accept only auto and register as storage class specifiers, but + ** we ignore all this, since we use auto anyway. + */ + if ((Spec.StorageClass & SC_AUTO) == 0 && + (Spec.StorageClass & SC_REGISTER) == 0) { + Error ("Illegal storage class"); + } - /* Parse a comma separated variable list */ - while (1) { + /* Parse a comma separated variable list */ + while (1) { - Declaration Decl; + Declaration Decl; - /* Read the parameter */ - ParseDecl (&Spec, &Decl, DM_NEED_IDENT); - if (Decl.Ident[0] != '\0') { + /* Read the parameter */ + ParseDecl (&Spec, &Decl, DM_NEED_IDENT); + if (Decl.Ident[0] != '\0') { - /* We have a name given. Search for the symbol */ - SymEntry* Sym = FindLocalSym (Decl.Ident); - if (Sym) { + /* We have a name given. Search for the symbol */ + SymEntry* Sym = FindLocalSym (Decl.Ident); + if (Sym) { /* Check if we already changed the type for this - * parameter - */ + ** parameter + */ if (Sym->Flags & SC_DEFTYPE) { /* Found it, change the default type to the one given */ ChangeSymType (Sym, ParamTypeCvt (Decl.Type)); @@ -1093,23 +1211,23 @@ static void ParseOldStyleParamList (FuncDesc* F) Sym->Flags &= ~SC_DEFTYPE; } else { /* Type has already been changed */ - Error ("Redefinition for parameter `%s'", Sym->Name); + Error ("Redefinition for parameter '%s'", Sym->Name); } - } else { - Error ("Unknown identifier: `%s'", Decl.Ident); - } - } + } else { + Error ("Unknown identifier: '%s'", Decl.Ident); + } + } - if (CurTok.Tok == TOK_COMMA) { - NextToken (); - } else { - break; - } + if (CurTok.Tok == TOK_COMMA) { + NextToken (); + } else { + break; + } - } + } - /* Variable list must be semicolon terminated */ - ConsumeSemi (); + /* Variable list must be semicolon terminated */ + ConsumeSemi (); } } @@ -1121,85 +1239,77 @@ static void ParseAnsiParamList (FuncDesc* F) /* Parse params */ while (CurTok.Tok != TOK_RPAREN) { - DeclSpec Spec; - Declaration Decl; - DeclAttr Attr; + DeclSpec Spec; + Declaration Decl; + SymEntry* Sym; - /* Allow an ellipsis as last parameter */ - if (CurTok.Tok == TOK_ELLIPSIS) { - NextToken (); - F->Flags |= FD_VARIADIC; - break; - } + /* Allow an ellipsis as last parameter */ + if (CurTok.Tok == TOK_ELLIPSIS) { + NextToken (); + F->Flags |= FD_VARIADIC; + break; + } - /* Read the declaration specifier */ - ParseDeclSpec (&Spec, SC_AUTO, T_INT); + /* Read the declaration specifier */ + ParseDeclSpec (&Spec, SC_AUTO, T_INT); - /* We accept only auto and register as storage class specifiers */ + /* We accept only auto and register as storage class specifiers */ if ((Spec.StorageClass & SC_AUTO) == SC_AUTO) { Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF; } else if ((Spec.StorageClass & SC_REGISTER) == SC_REGISTER) { Spec.StorageClass = SC_REGISTER | SC_STATIC | SC_PARAM | SC_DEF; } else { - Error ("Illegal storage class"); + Error ("Illegal storage class"); Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF; - } + } - /* Allow parameters without a name, but remember if we had some to - * eventually print an error message later. - */ - ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT); - if (Decl.Ident[0] == '\0') { + /* Allow parameters without a name, but remember if we had some to + ** eventually print an error message later. + */ + ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT); + if (Decl.Ident[0] == '\0') { - /* Unnamed symbol. Generate a name that is not user accessible, - * then handle the symbol normal. - */ - AnonName (Decl.Ident, "param"); - F->Flags |= FD_UNNAMED_PARAMS; + /* Unnamed symbol. Generate a name that is not user accessible, + ** then handle the symbol normal. + */ + AnonName (Decl.Ident, "param"); + F->Flags |= FD_UNNAMED_PARAMS; - /* Clear defined bit on nonames */ - Decl.StorageClass &= ~SC_DEF; - } + /* Clear defined bit on nonames */ + Decl.StorageClass &= ~SC_DEF; + } + + /* Parse attributes for this parameter */ + ParseAttribute (&Decl); - /* Parse an attribute ### */ - ParseAttribute (&Decl, &Attr); + /* Create a symbol table entry */ + Sym = AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Decl.StorageClass, 0); - /* Create a symbol table entry */ - AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Decl.StorageClass, 0); + /* Add attributes if we have any */ + SymUseAttr (Sym, &Decl); /* If the parameter is a struct or union, emit a warning */ if (IsClassStruct (Decl.Type)) { if (IS_Get (&WarnStructParam)) { - Warning ("Passing struct by value for parameter `%s'", Decl.Ident); + Warning ("Passing struct by value for parameter '%s'", Decl.Ident); } } - /* Count arguments */ - ++F->ParamCount; + /* Count arguments */ + ++F->ParamCount; - /* Check for more parameters */ - if (CurTok.Tok == TOK_COMMA) { - NextToken (); - } else { - break; - } + /* Check for more parameters */ + if (CurTok.Tok == TOK_COMMA) { + NextToken (); + } else { + break; + } } /* Skip right paren. We must explicitly check for one here, since some of - * the breaks above bail out without checking. - */ + ** the breaks above bail out without checking. + */ ConsumeRParen (); - - /* Check if this is a function definition */ - if (CurTok.Tok == TOK_LCURLY) { - /* Print an error if we have unnamed parameters and cc65 extensions - * are disabled. - */ - if (IS_Get (&Standard) != STD_CC65 && - (F->Flags & FD_UNNAMED_PARAMS) != 0) { - Error ("Parameter name omitted"); - } - } } @@ -1209,6 +1319,8 @@ static FuncDesc* ParseFuncDecl (void) { unsigned Offs; SymEntry* Sym; + SymEntry* WrappedCall; + unsigned char WrappedCallData; /* Create a new function descriptor */ FuncDesc* F = NewFuncDesc (); @@ -1218,60 +1330,69 @@ static FuncDesc* ParseFuncDecl (void) /* Check for several special parameter lists */ if (CurTok.Tok == TOK_RPAREN) { - /* Parameter list is empty */ - F->Flags |= (FD_EMPTY | FD_VARIADIC); + /* Parameter list is empty */ + F->Flags |= (FD_EMPTY | FD_VARIADIC); } else if (CurTok.Tok == TOK_VOID && NextTok.Tok == TOK_RPAREN) { - /* Parameter list declared as void */ - NextToken (); - F->Flags |= FD_VOID_PARAM; + /* Parameter list declared as void */ + NextToken (); + F->Flags |= FD_VOID_PARAM; } else if (CurTok.Tok == TOK_IDENT && - (NextTok.Tok == TOK_COMMA || NextTok.Tok == TOK_RPAREN)) { - /* If the identifier is a typedef, we have a new style parameter list, - * if it's some other identifier, it's an old style parameter list. - */ - Sym = FindSym (CurTok.Ident); - if (Sym == 0 || !SymIsTypeDef (Sym)) { - /* Old style (K&R) function. */ - F->Flags |= FD_OLDSTYLE; - } + (NextTok.Tok == TOK_COMMA || NextTok.Tok == TOK_RPAREN)) { + /* If the identifier is a typedef, we have a new style parameter list, + ** if it's some other identifier, it's an old style parameter list. + */ + Sym = FindSym (CurTok.Ident); + if (Sym == 0 || !SymIsTypeDef (Sym)) { + /* Old style (K&R) function. */ + F->Flags |= FD_OLDSTYLE; + } } /* Parse params */ if ((F->Flags & FD_OLDSTYLE) == 0) { - /* New style function */ - ParseAnsiParamList (F); + + /* New style function */ + ParseAnsiParamList (F); + } else { - /* Old style function */ - ParseOldStyleParamList (F); + /* Old style function */ + ParseOldStyleParamList (F); } /* Remember the last function parameter. We need it later for several - * purposes, for example when passing stuff to fastcall functions. Since - * more symbols are added to the table, it is easier if we remember it - * now, since it is currently the last entry in the symbol table. - */ + ** purposes, for example when passing stuff to fastcall functions. Since + ** more symbols are added to the table, it is easier if we remember it + ** now, since it is currently the last entry in the symbol table. + */ F->LastParam = GetSymTab()->SymTail; /* Assign offsets. If the function has a variable parameter list, - * there's one additional byte (the arg size). - */ + ** there's one additional byte (the arg size). + */ Offs = (F->Flags & FD_VARIADIC)? 1 : 0; Sym = F->LastParam; while (Sym) { - unsigned Size = CheckedSizeOf (Sym->Type); + unsigned Size = CheckedSizeOf (Sym->Type); if (SymIsRegVar (Sym)) { Sym->V.R.SaveOffs = Offs; } else { - Sym->V.Offs = Offs; + Sym->V.Offs = Offs; } - Offs += Size; - F->ParamSize += Size; - Sym = Sym->PrevSym; + Offs += Size; + F->ParamSize += Size; + Sym = Sym->PrevSym; } /* Leave the lexical level remembering the symbol tables */ RememberFunctionLevel (F); + /* Did we have a WrappedCall for this function? */ + GetWrappedCall((void **) &WrappedCall, &WrappedCallData); + if (WrappedCall) { + F->WrappedCall = WrappedCall; + F->WrappedCallData = WrappedCallData; + } + /* Return the function descriptor */ return F; } @@ -1281,78 +1402,89 @@ static FuncDesc* ParseFuncDecl (void) static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode) /* Recursively process declarators. Build a type array in reverse order. */ { - /* Read optional function or pointer qualifiers. These modify the - * identifier or token to the right. For convenience, we allow the fastcall - * qualifier also for pointers here. If it is a pointer-to-function, the - * qualifier will later be transfered to the function itself. If it's a - * pointer to something else, it will be flagged as an error. - */ - TypeCode Qualifiers = OptionalQualifiers (T_QUAL_ADDRSIZE | T_QUAL_FASTCALL); + /* Read optional function or pointer qualifiers. They modify the + ** identifier or token to the right. For convenience, we allow a calling + ** convention also for pointers here. If it's a pointer-to-function, the + ** qualifier later will be transfered to the function itself. If it's a + ** pointer to something else, it will be flagged as an error. + */ + TypeCode Qualifiers = OptionalQualifiers (T_QUAL_ADDRSIZE | T_QUAL_CCONV); /* Pointer to something */ if (CurTok.Tok == TOK_STAR) { /* Skip the star */ - NextToken (); + NextToken (); - /* Allow const, restrict and volatile qualifiers */ + /* Allow const, restrict, and volatile qualifiers */ Qualifiers |= OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE | T_QUAL_RESTRICT); - /* Parse the type, the pointer points to */ - Declarator (Spec, D, Mode); + /* Parse the type that the pointer points to */ + Declarator (Spec, D, Mode); - /* Add the type */ - AddTypeToDeclaration (D, T_PTR | Qualifiers); - return; + /* Add the type */ + AddTypeToDeclaration (D, T_PTR | Qualifiers); + return; } if (CurTok.Tok == TOK_LPAREN) { - NextToken (); - Declarator (Spec, D, Mode); - ConsumeRParen (); + NextToken (); + Declarator (Spec, D, Mode); + ConsumeRParen (); } else { - /* Things depend on Mode now: - * - Mode == DM_NEED_IDENT means: - * we *must* have a type and a variable identifer. - * - Mode == DM_NO_IDENT means: - * we must have a type but no variable identifer - * (if there is one, it's not read). - * - Mode == DM_ACCEPT_IDENT means: - * we *may* have an identifier. If there is an identifier, - * it is read, but it is no error, if there is none. - */ - if (Mode == DM_NO_IDENT) { - D->Ident[0] = '\0'; - } else if (CurTok.Tok == TOK_IDENT) { - strcpy (D->Ident, CurTok.Ident); - NextToken (); - } else { - if (Mode == DM_NEED_IDENT) { - Error ("Identifier expected"); - } - D->Ident[0] = '\0'; - } + /* Things depend on Mode now: + ** - Mode == DM_NEED_IDENT means: + ** we *must* have a type and a variable identifer. + ** - Mode == DM_NO_IDENT means: + ** we must have a type but no variable identifer + ** (if there is one, it's not read). + ** - Mode == DM_ACCEPT_IDENT means: + ** we *may* have an identifier. If there is an identifier, + ** it is read, but it is no error, if there is none. + */ + if (Mode == DM_NO_IDENT) { + D->Ident[0] = '\0'; + } else if (CurTok.Tok == TOK_IDENT) { + strcpy (D->Ident, CurTok.Ident); + NextToken (); + } else { + if (Mode == DM_NEED_IDENT) { + Error ("Identifier expected"); + } + D->Ident[0] = '\0'; + } } while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) { - if (CurTok.Tok == TOK_LPAREN) { + if (CurTok.Tok == TOK_LPAREN) { - /* Function declaration */ - FuncDesc* F; + /* Function declaration */ + FuncDesc* F; + SymEntry* PrevEntry; /* Skip the opening paren */ - NextToken (); + NextToken (); - /* Parse the function declaration */ - F = ParseFuncDecl (); + /* Parse the function declaration */ + F = ParseFuncDecl (); /* We cannot specify fastcall for variadic functions */ if ((F->Flags & FD_VARIADIC) && (Qualifiers & T_QUAL_FASTCALL)) { - Error ("Variadic functions cannot be `__fastcall'"); + Error ("Variadic functions cannot be __fastcall__"); Qualifiers &= ~T_QUAL_FASTCALL; } - /* Add the function type. Be sure to bounds check the type buffer */ + /* Was there a previous entry? If so, copy WrappedCall info from it */ + PrevEntry = FindGlobalSym (D->Ident); + if (PrevEntry && PrevEntry->Flags & SC_FUNC) { + FuncDesc* D = PrevEntry->V.F.Func; + if (D->WrappedCall && !F->WrappedCall) { + F->WrappedCall = D->WrappedCall; + F->WrappedCallData = D->WrappedCallData; + } + } + + /* Add the function type. Be sure to bounds check the type buffer */ NeedTypeSpace (D, 1); D->Type[D->Index].C = T_FUNC | Qualifiers; D->Type[D->Index].A.P = F; @@ -1361,9 +1493,9 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode) /* Qualifiers now used */ Qualifiers = T_QUAL_NONE; - } else { - /* Array declaration. */ - long Size = UNSPECIFIED; + } else { + /* Array declaration. */ + long Size = UNSPECIFIED; /* We cannot have any qualifiers for an array */ if (Qualifiers != T_QUAL_NONE) { @@ -1372,50 +1504,53 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode) } /* Skip the left bracket */ - NextToken (); + NextToken (); - /* Read the size if it is given */ - if (CurTok.Tok != TOK_RBRACK) { - ExprDesc Expr; - ConstAbsIntExpr (hie1, &Expr); + /* Read the size if it is given */ + if (CurTok.Tok != TOK_RBRACK) { + ExprDesc Expr; + ConstAbsIntExpr (hie1, &Expr); if (Expr.IVal <= 0) { if (D->Ident[0] != '\0') { - Error ("Size of array `%s' is invalid", D->Ident); + Error ("Size of array '%s' is invalid", D->Ident); } else { Error ("Size of array is invalid"); } Expr.IVal = 1; } - Size = Expr.IVal; - } + Size = Expr.IVal; + } /* Skip the right bracket */ - ConsumeRBrack (); + ConsumeRBrack (); - /* Add the array type with the size to the type */ + /* Add the array type with the size to the type */ NeedTypeSpace (D, 1); D->Type[D->Index].C = T_ARRAY; D->Type[D->Index].A.L = Size; ++D->Index; - } + } } /* If we have remaining qualifiers, flag them as invalid */ if (Qualifiers & T_QUAL_NEAR) { - Error ("Invalid `__near__' qualifier"); + Error ("Invalid '__near__' qualifier"); } if (Qualifiers & T_QUAL_FAR) { - Error ("Invalid `__far__' qualifier"); + Error ("Invalid '__far__' qualifier"); } if (Qualifiers & T_QUAL_FASTCALL) { - Error ("Invalid `__fastcall__' qualifier"); + Error ("Invalid '__fastcall__' qualifier"); + } + if (Qualifiers & T_QUAL_CDECL) { + Error ("Invalid '__cdecl__' qualifier"); } } /*****************************************************************************/ -/* code */ +/* code */ /*****************************************************************************/ @@ -1452,7 +1587,7 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode) Declarator (Spec, D, Mode); /* Add the base type. */ - NeedTypeSpace (D, TypeLen (Spec->Type) + 1); /* Bounds check */ + NeedTypeSpace (D, TypeLen (Spec->Type) + 1); /* Bounds check */ TypeCopy (D->Type + D->Index, Spec->Type); /* Use the storage class from the declspec */ @@ -1466,6 +1601,9 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode) D->StorageClass |= SC_FUNC; } + /* Parse attributes for this declaration */ + ParseAttribute (D); + /* Check several things for function or function pointer types */ if (IsTypeFunc (D->Type) || IsTypeFuncPtr (D->Type)) { @@ -1496,10 +1634,10 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode) if ((Spec->Flags & DS_DEF_TYPE) != 0 && RetType[0].C == T_INT && RetType[1].C == T_END) { /* Function has an implicit int return. Output a warning if we don't - * have the C89 standard enabled explicitly. - */ + ** have the C89 standard enabled explicitly. + */ if (IS_Get (&Standard) >= STD_C99) { - Warning ("Implicit `int' return type is an obsolete feature"); + Warning ("Implicit 'int' return type is an obsolete feature"); } GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET; } @@ -1507,15 +1645,15 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode) } /* For anthing that is not a function or typedef, check for an implicit - * int declaration. - */ + ** int declaration. + */ if ((D->StorageClass & SC_FUNC) != SC_FUNC && - (D->StorageClass & SC_TYPEDEF) != SC_TYPEDEF) { + (D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) { /* If the standard was not set explicitly to C89, print a warning - * for variables with implicit int type. - */ + ** for variables with implicit int type. + */ if ((Spec->Flags & DS_DEF_TYPE) != 0 && IS_Get (&Standard) >= STD_C99) { - Warning ("Implicit `int' is an obsolete feature"); + Warning ("Implicit 'int' is an obsolete feature"); } } @@ -1524,7 +1662,7 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode) unsigned Size = SizeOf (D->Type); if (Size >= 0x10000) { if (D->Ident[0] != '\0') { - Error ("Size of `%s' is invalid (0x%06X)", D->Ident, Size); + Error ("Size of '%s' is invalid (0x%06X)", D->Ident, Size); } else { Error ("Invalid size in declaration (0x%06X)", Size); } @@ -1557,12 +1695,12 @@ void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType) void CheckEmptyDecl (const DeclSpec* D) /* Called after an empty type declaration (that is, a type declaration without - * a variable). Checks if the declaration does really make sense and issues a - * warning if not. - */ +** a variable). Checks if the declaration does really make sense and issues a +** warning if not. +*/ { if ((D->Flags & DS_EXTRA_TYPE) == 0) { - Warning ("Useless declaration"); + Warning ("Useless declaration"); } } @@ -1570,8 +1708,8 @@ void CheckEmptyDecl (const DeclSpec* D) static void SkipInitializer (unsigned 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. - */ +** smart so we don't have too many following errors. +*/ { while (CurTok.Tok != TOK_CEOF && CurTok.Tok != TOK_SEMI && BracesExpected > 0) { switch (CurTok.Tok) { @@ -1587,9 +1725,9 @@ static void SkipInitializer (unsigned BracesExpected) static unsigned OpeningCurlyBraces (unsigned BracesNeeded) /* Accept any number of opening curly braces around an initialization, skip - * them and return the number. If the number of curly braces is less than - * BracesNeeded, issue a warning. - */ +** them and return the number. If the number of curly braces is less than +** BracesNeeded, issue a warning. +*/ { unsigned BraceCount = 0; while (CurTok.Tok == TOK_LCURLY) { @@ -1597,7 +1735,7 @@ static unsigned OpeningCurlyBraces (unsigned BracesNeeded) NextToken (); } if (BraceCount < BracesNeeded) { - Error ("`{' expected"); + Error ("'{' expected"); } return BraceCount; } @@ -1606,9 +1744,9 @@ static unsigned OpeningCurlyBraces (unsigned BracesNeeded) static void ClosingCurlyBraces (unsigned BracesExpected) /* Accept and skip the given number of closing curly braces together with - * an optional comma. Output an error messages, if the input does not contain - * the expected number of braces. - */ +** an optional comma. Output an error messages, if the input does not contain +** the expected number of braces. +*/ { while (BracesExpected) { if (CurTok.Tok == TOK_RCURLY) { @@ -1617,7 +1755,7 @@ static void ClosingCurlyBraces (unsigned BracesExpected) NextToken (); NextToken (); } else { - Error ("`}' expected"); + Error ("'}' expected"); return; } --BracesExpected; @@ -1633,7 +1771,7 @@ static void DefineData (ExprDesc* Expr) case E_LOC_ABS: /* Absolute: numeric address or const */ - g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); break; case E_LOC_GLOBAL: @@ -1648,12 +1786,12 @@ static void DefineData (ExprDesc* Expr) break; case E_LOC_REGISTER: - /* Register variable. Taking the address is usually not - * allowed. - */ - if (IS_Get (&AllowRegVarAddr) == 0) { - Error ("Cannot take the address of a register variable"); - } + /* Register variable. Taking the address is usually not + ** allowed. + */ + if (IS_Get (&AllowRegVarAddr) == 0) { + Error ("Cannot take the address of a register variable"); + } g_defdata (CF_REGVAR, Expr->Name, Expr->IVal); break; @@ -1663,8 +1801,8 @@ static void DefineData (ExprDesc* Expr) Error ("Non constant initializer"); break; - default: - Internal ("Unknown constant type: 0x%04X", ED_GetLoc (Expr)); + default: + Internal ("Unknown constant type: 0x%04X", ED_GetLoc (Expr)); } } @@ -1690,15 +1828,15 @@ static void OutputBitFieldData (StructInitData* SI) static void ParseScalarInitInternal (Type* T, ExprDesc* ED) /* Parse initializaton for scalar data types. This function will not output the - * data but return it in ED. - */ +** data but return it in ED. +*/ { /* Optional opening brace */ unsigned BraceCount = OpeningCurlyBraces (0); /* We warn if an initializer for a scalar contains braces, because this is - * quite unusual and often a sign for some problem in the input. - */ + ** quite unusual and often a sign for some problem in the input. + */ if (BraceCount > 0) { Warning ("Braces around scalar initializer"); } @@ -1771,26 +1909,22 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers) /* Char array initialized by string constant */ int NeedParen; - const char* Str; /* If we initializer is enclosed in brackets, remember this fact and - * skip the opening bracket. - */ + ** skip the opening bracket. + */ NeedParen = (CurTok.Tok == TOK_LCURLY); if (NeedParen) { NextToken (); } - /* Get the initializer string and its size */ - Str = GetLiteral (CurTok.IVal); - Count = GetLiteralPoolOffs () - CurTok.IVal; - /* Translate into target charset */ - TranslateLiteralPool (CurTok.IVal); + TranslateLiteral (CurTok.SVal); /* If the array is one too small for the string literal, omit the - * trailing zero. - */ + ** trailing zero. + */ + Count = GetLiteralSize (CurTok.SVal); if (ElementCount != UNSPECIFIED && ElementCount != FLEXIBLE && Count == ElementCount + 1) { @@ -1799,15 +1933,14 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers) } /* Output the data */ - g_defbytes (Str, Count); + g_defbytes (GetLiteralStr (CurTok.SVal), Count); - /* Remove string from pool */ - ResetLiteralPoolOffs (CurTok.IVal); + /* Skip the string */ NextToken (); /* If the initializer was enclosed in curly braces, we need a closing - * one. - */ + ** one. + */ if (NeedParen) { ConsumeRCurly (); } @@ -1821,9 +1954,9 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers) Count = 0; while (CurTok.Tok != TOK_RCURLY) { /* Flexible array members may not be initialized within - * an array (because the size of each element may differ - * otherwise). - */ + ** an array (because the size of each element may differ + ** otherwise). + */ ParseInitInternal (ElementType, 0); ++Count; if (CurTok.Tok != TOK_COMMA) @@ -1841,8 +1974,8 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers) ElementCount = Count; } else if (ElementCount == FLEXIBLE && AllowFlexibleMembers) { /* In non ANSI mode, allow initialization of flexible array - * members. - */ + ** members. + */ ElementCount = Count; } else if (Count < ElementCount) { g_zerobytes ((ElementCount - Count) * ElementSize); @@ -1872,15 +2005,15 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers) SI.Size = Entry->V.S.Size; /* Check if this struct definition has a field table. If it doesn't, it - * is an incomplete definition. - */ + ** is an incomplete definition. + */ Tab = Entry->V.S.SymTab; if (Tab == 0) { - Error ("Cannot initialize variables with incomplete type"); + Error ("Cannot initialize variables with incomplete type"); /* Try error recovery */ SkipInitializer (1); - /* Nothing initialized */ - return 0; + /* Nothing initialized */ + return 0; } /* Get a pointer to the list of symbols */ @@ -1893,15 +2026,15 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers) while (CurTok.Tok != TOK_RCURLY) { /* */ - if (Entry == 0) { - Error ("Too many initializers"); + if (Entry == 0) { + Error ("Too many initializers"); SkipInitializer (1); - return SI.Offs; - } + return SI.Offs; + } /* Parse initialization of one field. Bit-fields need a special - * handling. - */ + ** handling. + */ if (SymIsBitField (Entry)) { ExprDesc ED; @@ -1916,8 +2049,8 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers) SI.Offs * CHAR_BITS + SI.ValBits); /* This may be an anonymous bit-field, in which case it doesn't - * have an initializer. - */ + ** have an initializer. + */ if (IsAnonName (Entry->Name)) { /* Account for the data and output it if we have a full word */ SI.ValBits += Entry->V.B.BitWidth; @@ -1928,8 +2061,8 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers) goto NextMember; } else { /* Read the data, check for a constant integer, do a range - * check. - */ + ** check. + */ ParseScalarInitInternal (type_uint, &ED); if (!ED_IsConstAbsInt (&ED)) { Error ("Constant initializer expected"); @@ -1956,19 +2089,19 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers) } else { /* Standard member. We should never have stuff from a - * bit-field left - */ + ** bit-field left + */ CHECK (SI.ValBits == 0); /* Flexible array members may only be initialized if they are - * the last field (or part of the last struct field). - */ + ** the last field (or part of the last struct field). + */ SI.Offs += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0); } /* More initializers? */ - if (CurTok.Tok != TOK_COMMA) { - break; + if (CurTok.Tok != TOK_COMMA) { + break; } /* Skip the comma */ @@ -1993,23 +2126,23 @@ NextMember: /* If there are struct fields left, reserve additional storage */ if (SI.Offs < SI.Size) { - g_zerobytes (SI.Size - SI.Offs); + g_zerobytes (SI.Size - SI.Offs); SI.Offs = SI.Size; } /* Return the actual number of bytes initialized. This number may be - * larger than sizeof (Struct) if flexible array members are present and - * were initialized (possible in non ANSI mode). - */ + ** larger than sizeof (Struct) if flexible array members are present and + ** were initialized (possible in non ANSI mode). + */ return SI.Offs; } -static unsigned ParseVoidInit (void) +static unsigned ParseVoidInit (Type* T) /* Parse an initialization of a void variable (special cc65 extension). - * Return the number of bytes initialized. - */ +** Return the number of bytes initialized. +*/ { ExprDesc Expr; unsigned Size; @@ -2020,59 +2153,62 @@ static unsigned ParseVoidInit (void) /* Allow an arbitrary list of values */ Size = 0; do { - ConstExpr (hie1, &Expr); - switch (UnqualifiedType (Expr.Type[0].C)) { - - case T_SCHAR: - case T_UCHAR: - if (ED_IsConstAbsInt (&Expr)) { - /* Make it byte sized */ - Expr.IVal &= 0xFF; - } - DefineData (&Expr); + ConstExpr (hie1, &Expr); + switch (UnqualifiedType (Expr.Type[0].C)) { + + case T_SCHAR: + case T_UCHAR: + if (ED_IsConstAbsInt (&Expr)) { + /* Make it byte sized */ + Expr.IVal &= 0xFF; + } + DefineData (&Expr); Size += SIZEOF_CHAR; break; - case T_SHORT: - case T_USHORT: - case T_INT: - case T_UINT: - case T_PTR: - case T_ARRAY: - if (ED_IsConstAbsInt (&Expr)) { - /* Make it word sized */ - Expr.IVal &= 0xFFFF; - } - DefineData (&Expr); - Size += SIZEOF_INT; + case T_SHORT: + case T_USHORT: + case T_INT: + case T_UINT: + case T_PTR: + case T_ARRAY: + if (ED_IsConstAbsInt (&Expr)) { + /* Make it word sized */ + Expr.IVal &= 0xFFFF; + } + DefineData (&Expr); + Size += SIZEOF_INT; break; - case T_LONG: - case T_ULONG: - if (ED_IsConstAbsInt (&Expr)) { - /* Make it dword sized */ - Expr.IVal &= 0xFFFFFFFF; - } - DefineData (&Expr); - Size += SIZEOF_LONG; + case T_LONG: + case T_ULONG: + if (ED_IsConstAbsInt (&Expr)) { + /* Make it dword sized */ + Expr.IVal &= 0xFFFFFFFF; + } + DefineData (&Expr); + Size += SIZEOF_LONG; break; - default: - Error ("Illegal type in initialization"); - break; + default: + Error ("Illegal type in initialization"); + break; - } + } - if (CurTok.Tok != TOK_COMMA) { - break; - } - NextToken (); + if (CurTok.Tok != TOK_COMMA) { + break; + } + NextToken (); } while (CurTok.Tok != TOK_RCURLY); /* Closing brace */ ConsumeRCurly (); + /* Number of bytes determined by initializer */ + T->A.U = Size; + /* Return the number of bytes initialized */ return Size; } @@ -2084,38 +2220,38 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers) { switch (UnqualifiedType (T->C)) { - case T_SCHAR: - case T_UCHAR: - case T_SHORT: - case T_USHORT: - case T_INT: - case T_UINT: - case T_LONG: - case T_ULONG: + case T_SCHAR: + case T_UCHAR: + case T_SHORT: + case T_USHORT: + case T_INT: + case T_UINT: + case T_LONG: + case T_ULONG: case T_FLOAT: case T_DOUBLE: return ParseScalarInit (T); - case T_PTR: + case T_PTR: return ParsePointerInit (T); - case T_ARRAY: + case T_ARRAY: return ParseArrayInit (T, AllowFlexibleMembers); case T_STRUCT: case T_UNION: - return ParseStructInit (T, AllowFlexibleMembers); + return ParseStructInit (T, AllowFlexibleMembers); - case T_VOID: - if (IS_Get (&Standard) == STD_CC65) { - /* Special cc65 extension in non ANSI mode */ - return ParseVoidInit (); - } - /* FALLTHROUGH */ + case T_VOID: + if (IS_Get (&Standard) == STD_CC65) { + /* Special cc65 extension in non-ANSI mode */ + return ParseVoidInit (T); + } + /* FALLTHROUGH */ - default: - Error ("Illegal type"); - return SIZEOF_CHAR; + default: + Error ("Illegal type"); + return SIZEOF_CHAR; } } @@ -2126,13 +2262,13 @@ unsigned ParseInit (Type* T) /* Parse initialization of variables. Return the number of data bytes. */ { /* Parse the initialization. Flexible array members can only be initialized - * in cc65 mode. - */ + ** in cc65 mode. + */ unsigned Size = ParseInitInternal (T, IS_Get (&Standard) == STD_CC65); /* The initialization may not generate code on global level, because code - * outside function scope will never get executed. - */ + ** outside function scope will never get executed. + */ if (HaveGlobalCode ()) { Error ("Non constant initializers"); RemoveGlobalCode (); @@ -2141,6 +2277,3 @@ unsigned ParseInit (Type* T) /* Return the size needed for the initialization */ return Size; } - - -