X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fdeclare.c;h=9f0a94a27d9f267b4fadc266d0fdd5222e44a5b8;hb=3f4096d3030095605f28b4cfa73563c53a563df6;hp=6d0c47f5e87e552a18b14222d235fe80a9253131;hpb=e925aa27eebaf734203cc5f57f8c532c379708c8;p=cc65 diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 6d0c47f5e..9f0a94a27 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -6,8 +6,8 @@ /* */ /* */ /* */ -/* (C) 1998-2003 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ +/* (C) 1998-2004 Ullrich von Bassewitz */ +/* Römerstraße 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ @@ -38,12 +38,15 @@ #include /* common */ +#include "addrsize.h" +#include "mmodel.h" #include "xmalloc.h" /* cc65 */ #include "anonname.h" #include "codegen.h" #include "datatype.h" +#include "declare.h" #include "declattr.h" #include "error.h" #include "expr.h" @@ -54,7 +57,7 @@ #include "pragma.h" #include "scanner.h" #include "symtab.h" -#include "declare.h" +#include "typeconv.h" @@ -421,7 +424,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default) optionalsigned (); optionalint (); D->Type[0] = T_SHORT; - D->Type[1] = T_END; + D->Type[1] = T_END; } break; @@ -459,7 +462,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default) NextToken (); /* FALL THROUGH */ - default: + default: D->Type[0] = T_INT; D->Type[1] = T_END; break; @@ -501,6 +504,18 @@ static void ParseTypeSpec (DeclSpec* D, int Default) } break; + case TOK_FLOAT: + NextToken (); + D->Type[0] = T_FLOAT; + D->Type[1] = T_END; + break; + + case TOK_DOUBLE: + NextToken (); + D->Type[0] = T_DOUBLE; + D->Type[1] = T_END; + break; + case TOK_STRUCT: case TOK_UNION: StructType = (CurTok.Tok == TOK_STRUCT)? T_STRUCT : T_UNION; @@ -806,11 +821,18 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec) 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. + */ + F->LastParam = GetSymTab()->SymTail; + /* Assign offsets. If the function has a variable parameter list, * there's one additional byte (the arg size). */ Offs = (F->Flags & FD_VARIADIC)? 1 : 0; - Sym = GetSymTab()->SymTail; + Sym = F->LastParam; while (Sym) { unsigned Size = CheckedSizeOf (Sym->Type); if (SymIsRegVar (Sym)) { @@ -823,6 +845,13 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec) Sym = Sym->PrevSym; } + /* Add the default address size for the function */ + if (CodeAddrSize == ADDR_SIZE_FAR) { + F->Flags |= FD_FAR; + } else { + F->Flags |= FD_NEAR; + } + /* Leave the lexical level remembering the symbol tables */ RememberFunctionLevel (F); @@ -832,39 +861,114 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec) +static unsigned FunctionModifierFlags (void) +/* Parse __fastcall__, __near__ and __far__ and return the matching FD_ flags */ +{ + /* Read the flags */ + unsigned Flags = FD_NONE; + while (CurTok.Tok == TOK_FASTCALL || CurTok.Tok == TOK_NEAR || CurTok.Tok == TOK_FAR) { + + /* Get the flag bit for the next token */ + unsigned F = FD_NONE; + switch (CurTok.Tok) { + case TOK_FASTCALL: F = FD_FASTCALL; break; + case TOK_NEAR: F = FD_NEAR; break; + case TOK_FAR: F = FD_FAR; break; + default: Internal ("Unexpected token: %d", CurTok.Tok); + } + + /* Remember the flag for this modifier */ + if (Flags & F) { + Error ("Duplicate modifier"); + } + Flags |= F; + + /* Skip the token */ + NextToken (); + } + + /* Sanity check */ + if ((Flags & (FD_NEAR | FD_FAR)) == (FD_NEAR | FD_FAR)) { + Error ("Cannot specify both, `__near__' and `__far__' modifiers"); + Flags &= ~(FD_NEAR | FD_FAR); + } + + /* Return the flags read */ + return Flags; +} + + + +static void ApplyFunctionModifiers (type* T, unsigned Flags) +/* Apply a set of function modifier flags to a function */ +{ + /* Get the function descriptor */ + FuncDesc* F = GetFuncDesc (T); + + /* Special check for __fastcall__ */ + if ((Flags & FD_FASTCALL) != 0 && IsVariadicFunc (T)) { + Error ("Cannot apply `__fastcall__' to functions with " + "variable parameter list"); + Flags &= ~FD_FASTCALL; + } + + /* Remove the default function address size modifiers */ + F->Flags &= ~(FD_NEAR | FD_FAR); + + /* Add the new modifers */ + F->Flags |= Flags; +} + + + static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode) /* Recursively process declarators. Build a type array in reverse order. */ { - + /* Pointer to something */ if (CurTok.Tok == TOK_STAR) { - type T = T_PTR; + + type T; + + /* Skip the star */ NextToken (); + /* Allow optional const or volatile qualifiers */ - T |= OptionalQualifiers (T_QUAL_NONE); + T = T_PTR | OptionalQualifiers (T_QUAL_NONE); + + /* Parse the type, the pointer points to */ Decl (Spec, D, Mode); + *D->T++ = T; return; - } else if (CurTok.Tok == TOK_LPAREN) { - NextToken (); - Decl (Spec, D, Mode); - ConsumeRParen (); - } else if (CurTok.Tok == TOK_FASTCALL) { + } + + /* Function modifiers */ + if (CurTok.Tok == TOK_FASTCALL || CurTok.Tok == TOK_NEAR || CurTok.Tok == TOK_FAR) { + /* Remember the current type pointer */ type* T = D->T; - /* Skip the fastcall token */ - NextToken (); + + /* Read the flags */ + unsigned Flags = FunctionModifierFlags (); + /* Parse the function */ Decl (Spec, D, Mode); - /* Set the fastcall flag */ + + /* Check that we have a function */ if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) { - Error ("__fastcall__ modifier applied to non function"); - } else if (IsVariadicFunc (T)) { - Error ("Cannot apply __fastcall__ to functions with variable parameter list"); + Error ("Function modifier applied to non function"); } else { - FuncDesc* F = GetFuncDesc (T); - F->Flags |= FD_FASTCALL; - } + ApplyFunctionModifiers (T, Flags); + } + + /* Done */ return; + } + + if (CurTok.Tok == TOK_LPAREN) { + NextToken (); + Decl (Spec, D, Mode); + ConsumeRParen (); } else { /* Things depend on Mode now: * - Mode == DM_NEED_IDENT means: @@ -944,7 +1048,6 @@ type* ParseType (type* Type) ParseTypeSpec (&Spec, -1); /* Parse additional declarators */ - InitDeclaration (&Decl); ParseDecl (&Spec, &Decl, DM_NO_IDENT); /* Copy the type to the target buffer */ @@ -1008,70 +1111,198 @@ void CheckEmptyDecl (const DeclSpec* D) -static unsigned ParseVoidInit (void) -/* Parse an initialization of a void variable (special cc65 extension). - * Return the number of bytes initialized. +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. */ { - ExprDesc lval; - unsigned Size; + 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 (); + } +} - ConsumeLCurly (); - /* Allow an arbitrary list of values */ - Size = 0; - do { - ConstExpr (&lval); - switch (UnqualifiedType (lval.Type[0])) { - case T_SCHAR: - case T_UCHAR: - if ((lval.Flags & E_MCTYPE) == E_TCONST) { - /* Make it byte sized */ - lval.ConstVal &= 0xFF; - } - DefineData (&lval); - Size += SIZEOF_CHAR; - break; +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. + */ +{ + unsigned BraceCount = 0; + while (CurTok.Tok == TOK_LCURLY) { + ++BraceCount; + NextToken (); + } + if (BraceCount < BracesNeeded) { + Error ("`{' expected"); + } + return BraceCount; +} - case T_SHORT: - case T_USHORT: - case T_INT: - 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); - Size += SIZEOF_INT; - break; - case T_LONG: - case T_ULONG: - DefineData (&lval); - Size += SIZEOF_LONG; - break; - default: - Error ("Illegal type in initialization"); - break; +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. + */ +{ + while (BracesExpected) { + if (CurTok.Tok == TOK_RCURLY) { + NextToken (); + } else if (CurTok.Tok == TOK_COMMA && NextTok.Tok == TOK_RCURLY) { + NextToken (); + NextToken (); + } else { + Error ("`}' expected"); + return; + } + --BracesExpected; + } +} - } - if (CurTok.Tok != TOK_COMMA) { - break; - } - NextToken (); - } while (CurTok.Tok != TOK_RCURLY); +static unsigned ParseScalarInit (type* T) +/* Parse initializaton for scalar data types. Return the number of data bytes. */ +{ + ExprDesc ED; - /* Closing brace */ - ConsumeRCurly (); + /* Optional opening brace */ + unsigned BraceCount = OpeningCurlyBraces (0); - /* Return the number of bytes initialized */ - return Size; + /* 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. + */ + if (BraceCount > 0) { + Warning ("Braces around scalar initializer"); + } + + /* Get the expression and convert it to the target type */ + ConstExpr (&ED); + TypeConversion (&ED, 0, T); + + /* Output the data */ + DefineData (&ED); + + /* Close eventually opening braces */ + ClosingCurlyBraces (BraceCount); + + /* Done */ + return SizeOf (T); +} + + + +static unsigned ParsePointerInit (type* T) +/* Parse initializaton for pointer data types. Return the number of data bytes. */ +{ + /* Optional opening brace */ + unsigned BraceCount = OpeningCurlyBraces (0); + + /* Expression */ + ExprDesc ED; + ConstExpr (&ED); + if ((ED.Flags & E_MCTYPE) == E_TCONST) { + /* Make the const value the correct size */ + ED.ConstVal &= 0xFFFF; + } + TypeConversion (&ED, 0, T); + + /* Output the data */ + DefineData (&ED); + + /* Close eventually opening braces */ + ClosingCurlyBraces (BraceCount); + + /* Done */ + return SIZEOF_PTR; +} + + + +static unsigned ParseArrayInit (type* T, int AllowFlexibleMembers) +/* Parse initializaton for arrays. Return the number of data bytes. */ +{ + int Count; + + /* Get the array data */ + type* ElementType = GetElementType (T); + unsigned ElementSize = CheckedSizeOf (ElementType); + long ElementCount = GetElementCount (T); + + /* Special handling for a character array initialized by a literal */ + if (IsTypeChar (ElementType) && CurTok.Tok == TOK_SCONST) { + + /* Char array initialized by string constant */ + const char* Str = GetLiteral (CurTok.IVal); + Count = GetLiteralPoolOffs () - CurTok.IVal; + + /* Translate into target charset */ + TranslateLiteralPool (CurTok.IVal); + + /* If the array is one too small for the string literal, omit the + * trailing zero. + */ + if (ElementCount != UNSPECIFIED && + ElementCount != FLEXIBLE && + Count == ElementCount + 1) { + /* Omit the trailing zero */ + --Count; + } + + /* Output the data */ + g_defbytes (Str, Count); + + /* Remove string from pool */ + ResetLiteralPoolOffs (CurTok.IVal); + NextToken (); + + } else { + + /* Curly brace */ + ConsumeLCurly (); + + /* Initialize the array members */ + 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). + */ + ParseInitInternal (ElementType, 0); + ++Count; + if (CurTok.Tok != TOK_COMMA) + break; + NextToken (); + } + + /* Closing curly braces */ + ConsumeRCurly (); + } + + + if (ElementCount == UNSPECIFIED) { + /* Number of elements determined by initializer */ + Encode (T + 1, Count); + 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"); + } + return ElementCount * ElementSize; } @@ -1084,8 +1315,6 @@ static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers) unsigned StructSize; unsigned Size; - static const token_t EndTokens[] = { TOK_RCURLY, TOK_SEMI }; - /* Consume the opening curly brace */ ConsumeLCurly (); @@ -1103,10 +1332,7 @@ static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers) if (Tab == 0) { Error ("Cannot initialize variables with incomplete type"); /* Try error recovery */ - SkipTokens (EndTokens, sizeof(EndTokens)/sizeof(EndTokens[0])); - if (CurTok.Tok == TOK_RCURLY) { - NextToken (); - } + SkipInitializer (1); /* Nothing initialized */ return 0; } @@ -1119,6 +1345,7 @@ static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers) while (CurTok.Tok != TOK_RCURLY) { if (Entry == 0) { Error ("Too many initializers"); + SkipInitializer (1); return Size; } /* Parse initialization of one field. Flexible array members may @@ -1150,99 +1377,95 @@ static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers) +static unsigned ParseVoidInit (void) +/* Parse an initialization of a void variable (special cc65 extension). + * Return the number of bytes initialized. + */ +{ + ExprDesc lval; + unsigned Size; + + /* Opening brace */ + ConsumeLCurly (); + + /* Allow an arbitrary list of values */ + Size = 0; + do { + ConstExpr (&lval); + switch (UnqualifiedType (lval.Type[0])) { + + case T_SCHAR: + case T_UCHAR: + if ((lval.Flags & E_MCTYPE) == E_TCONST) { + /* Make it byte sized */ + lval.ConstVal &= 0xFF; + } + DefineData (&lval); + Size += SIZEOF_CHAR; + break; + + case T_SHORT: + case T_USHORT: + case T_INT: + 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); + Size += SIZEOF_INT; + break; + + case T_LONG: + case T_ULONG: + DefineData (&lval); + Size += SIZEOF_LONG; + break; + + default: + Error ("Illegal type in initialization"); + break; + + } + + if (CurTok.Tok != TOK_COMMA) { + break; + } + NextToken (); + + } while (CurTok.Tok != TOK_RCURLY); + + /* Closing brace */ + ConsumeRCurly (); + + /* Return the number of bytes initialized */ + return Size; +} + + + static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers) /* Parse initialization of variables. Return the number of data bytes. */ { - ExprDesc lval; - const char* str; - int Count; - type* ElementType; - unsigned ElementSize; - long ElementCount; - switch (UnqualifiedType (*T)) { case T_SCHAR: case T_UCHAR: - ConstExpr (&lval); - if ((lval.Flags & E_MCTYPE) == E_TCONST) { - /* Make it byte sized */ - lval.ConstVal &= 0xFF; - } - assignadjust (T, &lval); - DefineData (&lval); - return SIZEOF_CHAR; - case T_SHORT: case T_USHORT: case T_INT: case T_UINT: - case T_PTR: - ConstExpr (&lval); - if ((lval.Flags & E_MCTYPE) == E_TCONST) { - /* Make it word sized */ - lval.ConstVal &= 0xFFFF; - } - assignadjust (T, &lval); - DefineData (&lval); - return SIZEOF_INT; - case T_LONG: case T_ULONG: - ConstExpr (&lval); - if ((lval.Flags & E_MCTYPE) == E_TCONST) { - /* Make it long sized */ - lval.ConstVal &= 0xFFFFFFFF; - } - assignadjust (T, &lval); - DefineData (&lval); - return SIZEOF_LONG; + return ParseScalarInit (T); + + case T_PTR: + return ParsePointerInit (T); case T_ARRAY: - 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 = GetLiteralPoolOffs () - CurTok.IVal; - /* Translate into target charset */ - TranslateLiteralPool (CurTok.IVal); - g_defbytes (str, Count); - /* Remove string from pool */ - ResetLiteralPoolOffs (CurTok.IVal); - NextToken (); - } else { - ConsumeLCurly (); - 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). - */ - ParseInitInternal (ElementType, 0); - ++Count; - if (CurTok.Tok != TOK_COMMA) - break; - NextToken (); - } - ConsumeRCurly (); - } - if (ElementCount == UNSPECIFIED) { - /* Number of elements determined by initializer */ - Encode (T + 1, Count); - 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"); - } - return ElementCount * ElementSize; + return ParseArrayInit (T, AllowFlexibleMembers); case T_STRUCT: case T_UNION: @@ -1267,7 +1490,19 @@ static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers) unsigned ParseInit (type* T) /* Parse initialization of variables. Return the number of data bytes. */ { - return ParseInitInternal (T, !ANSI); + /* Parse the initialization */ + unsigned Size = ParseInitInternal (T, !ANSI); + + /* The initialization may not generate code on global level, because code + * outside function scope will never get executed. + */ + if (HaveGlobalCode ()) { + Error ("Non constant initializers"); + RemoveGlobalCode (); + } + + /* Return the size needed for the initialization */ + return Size; }