X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fdeclare.c;h=b6e78e27c5ddddea7b19e4d0f041aca5bb33a2cf;hb=b9e04d5242618b83d78016d57b032e2518ddba17;hp=9989cd4cee8151a726337034afe10ee86cba2075;hpb=a96da498f559cc9e794d26924ce0fb7c81c459a0;p=cc65 diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 9989cd4ce..b6e78e27c 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1998-2002 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -67,6 +67,9 @@ static void ParseTypeSpec (DeclSpec* D, int Default); /* Parse a type specificier */ +static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers); +/* Parse initialization of variables. Return the number of data bytes. */ + /*****************************************************************************/ @@ -83,7 +86,7 @@ static type OptionalQualifiers (type Q) switch (CurTok.Tok) { case TOK_CONST: - if (Q & T_QUAL_CONST) { + if (Q & T_QUAL_CONST) { Error ("Duplicate qualifier: `const'"); } Q |= T_QUAL_CONST; @@ -251,8 +254,10 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType) /* Parse a struct/union declaration. */ { - unsigned Size; - unsigned Offs; + unsigned StructSize; + unsigned FieldSize; + unsigned Offs; + int FlexibleMember; SymTable* FieldTab; SymEntry* Entry; @@ -282,7 +287,8 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType) EnterStructLevel (); /* Parse struct fields */ - Size = 0; + FlexibleMember = 0; + StructSize = 0; while (CurTok.Tok != TOK_RCURLY) { /* Get the type of the entry */ @@ -293,25 +299,55 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType) /* Read fields with this type */ while (1) { - /* Get type and name of the struct field */ 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); - /* Add a field entry to the table */ - AddLocalSym (Decl.Ident, Decl.Type, SC_SFLD, (StructType == T_STRUCT)? Size : 0); + /* Get the offset of this field */ + Offs = (StructType == T_STRUCT)? StructSize : 0; + + /* Calculate the sizes, handle flexible array members */ + 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, FLEXIBLE); + } else { + StructSize += CheckedSizeOf (Decl.Type); + } - /* Calculate offset of next field/size of the union */ - Offs = CheckedSizeOf (Decl.Type); - if (StructType == T_STRUCT) { - Size += Offs; } else { - if (Offs > Size) { - Size = Offs; + + /* It's a union */ + FieldSize = CheckedSizeOf (Decl.Type); + if (FieldSize > StructSize) { + 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; + } NextToken (); } ConsumeSemi (); @@ -325,7 +361,7 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType) LeaveStructLevel (); /* Make a real entry from the forward decl and return it */ - return AddStructSym (Name, Size, FieldTab); + return AddStructSym (Name, StructSize, FieldTab); } @@ -336,7 +372,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default) ident Ident; SymEntry* Entry; type StructType; - type Qualifiers; /* Type qualifiers */ + type Qualifiers; /* Type qualifiers */ /* Assume we have an explicit type */ D->Flags &= ~DS_DEF_TYPE; @@ -424,7 +460,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default) /* FALL THROUGH */ default: - D->Type[0] = T_INT; + D->Type[0] = T_INT; D->Type[1] = T_END; break; } @@ -516,7 +552,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default) case TOK_IDENT: Entry = FindSym (CurTok.Ident); - if (Entry && IsTypeDef (Entry)) { + if (Entry && SymIsTypeDef (Entry)) { /* It's a typedef */ NextToken (); TypeCpy (D->Type, Entry->Type); @@ -660,14 +696,15 @@ static void ParseAnsiParamList (FuncDesc* F) /* 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 and use auto. - */ - if ((Spec.StorageClass & SC_AUTO) == 0 && - (Spec.StorageClass & SC_REGISTER) == 0) { + /* 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"); + Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF; } - 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. @@ -741,23 +778,23 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec) 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 || !IsTypeDef (Sym)) { - /* Old style (K&R) function. Assume variable param list. */ - F->Flags |= (FD_OLDSTYLE | FD_VARIADIC); - - /* Check for an implicit int return in the K&R function */ - if ((Spec->Flags & DS_DEF_TYPE) != 0 && - Spec->Type[0] == T_INT && - Spec->Type[1] == T_END) { - /* Function has an implicit int return */ - F->Flags |= FD_OLDSTYLE_INTRET; - } - } + (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. Assume variable param list. */ + F->Flags |= (FD_OLDSTYLE | FD_VARIADIC); + } + } + + /* Check for an implicit int return in the function */ + if ((Spec->Flags & DS_DEF_TYPE) != 0 && + Spec->Type[0] == T_INT && + Spec->Type[1] == T_END) { + /* Function has an implicit int return */ + F->Flags |= FD_OLDSTYLE_INTRET; } /* Parse params */ @@ -776,7 +813,11 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec) Sym = GetSymTab()->SymTail; while (Sym) { unsigned Size = CheckedSizeOf (Sym->Type); - Sym->V.Offs = Offs; + if (SymIsRegVar (Sym)) { + Sym->V.R.SaveOffs = Offs; + } else { + Sym->V.Offs = Offs; + } Offs += Size; F->ParamSize += Size; Sym = Sym->PrevSym; @@ -845,7 +886,6 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode) Error ("Identifier expected"); } D->Ident[0] = '\0'; - return; } } @@ -861,12 +901,20 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode) D->T += DECODE_SIZE; } else { /* Array declaration */ - unsigned long Size = 0; + long Size = UNSPECIFIED; NextToken (); /* Read the size if it is given */ if (CurTok.Tok != TOK_RBRACK) { ExprDesc lval; ConstExpr (&lval); + if (lval.ConstVal <= 0) { + if (D->Ident[0] != '\0') { + Error ("Size of array `%s' is invalid", D->Ident); + } else { + Error ("Size of array is invalid"); + } + lval.ConstVal = 1; + } Size = lval.ConstVal; } ConsumeRBrack (); @@ -960,16 +1008,21 @@ void CheckEmptyDecl (const DeclSpec* D) -static void ParseVoidInit (void) -/* Parse an initialization of a void variable (special cc65 extension) */ +static unsigned ParseVoidInit (void) +/* Parse an initialization of a void variable (special cc65 extension). + * Return the number of bytes initialized. + */ { ExprDesc lval; + unsigned Size; - /* Allow an arbitrary list of values */ ConsumeLCurly (); + + /* Allow an arbitrary list of values */ + Size = 0; do { ConstExpr (&lval); - switch (lval.Type[0]) { + switch (UnqualifiedType (lval.Type[0])) { case T_SCHAR: case T_UCHAR: @@ -978,7 +1031,8 @@ static void ParseVoidInit (void) lval.ConstVal &= 0xFF; } DefineData (&lval); - break; + Size += SIZEOF_CHAR; + break; case T_SHORT: case T_USHORT: @@ -986,47 +1040,58 @@ static void ParseVoidInit (void) case T_UINT: case T_PTR: case T_ARRAY: - if ((lval.Flags & E_MCTYPE) == E_TCONST) { - /* Make it word sized */ - lval.ConstVal &= 0xFFFF; - } - DefineData (&lval); - break; + if ((lval.Flags & E_MCTYPE) == E_TCONST) { + /* Make it word sized */ + lval.ConstVal &= 0xFFFF; + } + DefineData (&lval); + Size += SIZEOF_INT; + break; case T_LONG: case T_ULONG: - DefineData (&lval); - break; + DefineData (&lval); + Size += SIZEOF_LONG; + break; default: - Error ("Illegal type in initialization"); + 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 (); + + /* Return the number of bytes initialized */ + return Size; } -static void ParseStructInit (type* Type) -/* Parse initialization of a struct or union */ +static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers) +/* Parse initialization of a struct or union. Return the number of data bytes. */ { SymEntry* Entry; SymTable* Tab; + unsigned StructSize; + unsigned Size; /* Consume the opening curly brace */ ConsumeLCurly (); /* 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 * is an incomplete definition. @@ -1034,44 +1099,58 @@ static void ParseStructInit (type* Type) Tab = Entry->V.S.SymTab; if (Tab == 0) { Error ("Cannot initialize variables with incomplete type"); - /* Returning here will cause lots of errors, but recovery is difficult */ - return; + /* Returning here will cause lots of errors, but recovery is difficult */ + return 0; } /* Get a pointer to the list of symbols */ Entry = Tab->SymHead; + + /* Initialize fields */ + Size = 0; while (CurTok.Tok != TOK_RCURLY) { - if (Entry == 0) { - Error ("Too many initializers"); - return; - } - ParseInit (Entry->Type); - Entry = Entry->NextSym; - if (CurTok.Tok != TOK_COMMA) - break; - NextToken (); + if (Entry == 0) { + Error ("Too many initializers"); + return Size; + } + /* Parse initialization of one field. Flexible array members may + * only be initialized if they are the last field (or part of the + * last struct field). + */ + Size += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0); + Entry = Entry->NextSym; + if (CurTok.Tok != TOK_COMMA) + break; + NextToken (); } /* Consume the closing curly brace */ ConsumeRCurly (); /* If there are struct fields left, reserve additional storage */ - while (Entry) { - g_zerobytes (CheckedSizeOf (Entry->Type)); - Entry = Entry->NextSym; + if (Size < StructSize) { + g_zerobytes (StructSize - Size); + Size = StructSize; } + + /* Return the actual number of bytes initialized. This number may be + * larger than StructSize if flexible array members are present and were + * initialized (possible in non ANSI mode). + */ + return Size; } -void ParseInit (type* T) -/* Parse initialization of variables. */ +static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers) +/* Parse initialization of variables. Return the number of data bytes. */ { - ExprDesc lval; - type* t; + ExprDesc lval; const char* str; - int Count; - int Size; + int Count; + type* ElementType; + unsigned ElementSize; + long ElementCount; switch (UnqualifiedType (*T)) { @@ -1084,7 +1163,7 @@ void ParseInit (type* T) } assignadjust (T, &lval); DefineData (&lval); - break; + return SIZEOF_CHAR; case T_SHORT: case T_USHORT: @@ -1098,7 +1177,7 @@ void ParseInit (type* T) } assignadjust (T, &lval); DefineData (&lval); - break; + return SIZEOF_INT; case T_LONG: case T_ULONG: @@ -1109,23 +1188,31 @@ void ParseInit (type* T) } assignadjust (T, &lval); DefineData (&lval); - break; + return SIZEOF_LONG; case T_ARRAY: - Size = Decode (T + 1); - t = T + DECODE_SIZE + 1; - if (IsTypeChar(t) && CurTok.Tok == TOK_SCONST) { + ElementType = GetElementType (T); + ElementSize = CheckedSizeOf (ElementType); + ElementCount = GetElementCount (T); + if (IsTypeChar (ElementType) && CurTok.Tok == TOK_SCONST) { + /* Char array initialized by string constant */ str = GetLiteral (CurTok.IVal); - Count = strlen (str) + 1; - TranslateLiteralPool (CurTok.IVal); /* Translate into target charset */ + Count = GetLiteralPoolOffs () - CurTok.IVal; + /* Translate into target charset */ + TranslateLiteralPool (CurTok.IVal); g_defbytes (str, Count); - ResetLiteralPoolOffs (CurTok.IVal); /* Remove string from pool */ + /* Remove string from pool */ + ResetLiteralPoolOffs (CurTok.IVal); NextToken (); } else { ConsumeLCurly (); Count = 0; while (CurTok.Tok != TOK_RCURLY) { - ParseInit (T + DECODE_SIZE + 1); + /* Flexible array members may not be initialized within + * an array (because the size of each element may differ + * otherwise). + */ + ParseInitInternal (ElementType, 0); ++Count; if (CurTok.Tok != TOK_COMMA) break; @@ -1133,34 +1220,47 @@ void ParseInit (type* T) } ConsumeRCurly (); } - if (Size == 0) { + if (ElementCount == UNSPECIFIED) { + /* Number of elements determined by initializer */ Encode (T + 1, Count); - } else if (Count < Size) { - g_zerobytes ((Size - Count) * CheckedSizeOf (T + DECODE_SIZE + 1)); - } else if (Count > Size) { + ElementCount = Count; + } else if (ElementCount == FLEXIBLE && AllowFlexibleMembers) { + /* In non ANSI mode, allow initialization of flexible array + * members. + */ + ElementCount = Count; + } else if (Count < ElementCount) { + g_zerobytes ((ElementCount - Count) * ElementSize); + } else if (Count > ElementCount) { Error ("Too many initializers"); } - break; + return ElementCount * ElementSize; case T_STRUCT: case T_UNION: - ParseStructInit (T); - break; + return ParseStructInit (T, AllowFlexibleMembers); case T_VOID: if (!ANSI) { /* Special cc65 extension in non ANSI mode */ - ParseVoidInit (); - break; + return ParseVoidInit (); } /* FALLTHROUGH */ default: Error ("Illegal type"); - break; + return SIZEOF_CHAR; } } +unsigned ParseInit (type* T) +/* Parse initialization of variables. Return the number of data bytes. */ +{ + return ParseInitInternal (T, !ANSI); +} + + +