X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fdeclare.c;h=2b4a09a42a61f2644755c169679236b067ef2b2e;hb=6ecca264e4541336d4030dff8b8d0cdbd06b74c6;hp=59a618dac423253696cfedd9b3b688d0cad1b416;hpb=81f94afd5ca9e84124d4743d1c631c028e6be754;p=cc65 diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 59a618dac..2b4a09a42 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-2008 Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ @@ -38,6 +38,8 @@ #include /* common */ +#include "addrsize.h" +#include "mmodel.h" #include "xmalloc.h" /* cc65 */ @@ -54,6 +56,7 @@ #include "litpool.h" #include "pragma.h" #include "scanner.h" +#include "standard.h" #include "symtab.h" #include "typeconv.h" @@ -65,10 +68,10 @@ -static void ParseTypeSpec (DeclSpec* D, int Default); +static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers); /* Parse a type specificier */ -static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers); +static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers); /* Parse initialization of variables. Return the number of data bytes. */ @@ -79,10 +82,10 @@ static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers); -static type OptionalQualifiers (type Q) +static TypeCode OptionalQualifiers (TypeCode Q) /* Read type qualifiers if we have any */ { - while (CurTok.Tok == TOK_CONST || CurTok.Tok == TOK_VOLATILE) { + while (TokIsTypeQual (&CurTok)) { switch (CurTok.Tok) { @@ -100,9 +103,15 @@ static type OptionalQualifiers (type Q) Q |= T_QUAL_VOLATILE; break; + case TOK_RESTRICT: + if (Q & T_QUAL_RESTRICT) { + Error ("Duplicate qualifier: `restrict'"); + } + Q |= T_QUAL_RESTRICT; + break; + default: - /* Keep gcc silent */ - break; + Internal ("Unexpected type qualifier token: %d", CurTok.Tok); } @@ -116,7 +125,7 @@ static type OptionalQualifiers (type Q) -static void optionalint (void) +static void OptionalInt (void) /* Eat an optional "int" token */ { if (CurTok.Tok == TOK_INT) { @@ -127,7 +136,7 @@ static void optionalint (void) -static void optionalsigned (void) +static void OptionalSigned (void) /* Eat an optional "signed" token */ { if (CurTok.Tok == TOK_SIGNED) { @@ -141,9 +150,9 @@ static void optionalsigned (void) static void InitDeclSpec (DeclSpec* D) /* Initialize the DeclSpec struct for use */ { - D->StorageClass = 0; - D->Type[0] = T_END; - D->Flags = 0; + D->StorageClass = 0; + D->Type[0].C = T_END; + D->Flags = 0; } @@ -151,9 +160,80 @@ static void InitDeclSpec (DeclSpec* D) static void InitDeclaration (Declaration* D) /* Initialize the Declaration struct for use */ { - D->Ident[0] = '\0'; - D->Type[0] = T_END; - D->T = D->Type; + D->Ident[0] = '\0'; + D->Type[0].C = T_END; + D->Index = 0; +} + + + +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"); + } +} + + + +static void AddTypeToDeclaration (Declaration* D, TypeCode T) +/* Add a type specifier to the type of a declaration */ +{ + NeedTypeSpace (D, 1); + D->Type[D->Index++].C = T; +} + + + +static void AddFuncTypeToDeclaration (Declaration* D, FuncDesc* F) +/* Add a function type plus function descriptor to the type of a declaration */ +{ + NeedTypeSpace (D, 1); + D->Type[D->Index].C = T_FUNC; + SetFuncDesc (D->Type + D->Index, F); + ++D->Index; +} + + + +static void AddArrayToDeclaration (Declaration* D, long Size) +/* Add an array type plus size to the type of a declaration */ +{ + NeedTypeSpace (D, 1); + D->Type[D->Index].C = T_ARRAY; + D->Type[D->Index].A.L = Size; + ++D->Index; +} + + + +static void FixArrayQualifiers (Type* T) +/* 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. + */ +{ + TypeCode Q = T_QUAL_NONE; + while (T->C != T_END) { + if (IsTypeArray (T)) { + /* Extract any type qualifiers */ + Q |= T->C & T_MASK_QUAL; + T->C = UnqualifiedType (T->C); + } else { + /* Add extracted type qualifiers here */ + T->C |= Q; + Q = T_QUAL_NONE; + } + ++T; + } + + /* Q must be empty now */ + CHECK (Q == T_QUAL_NONE); } @@ -223,7 +303,7 @@ static void ParseEnumDecl (void) /* We expect an identifier */ if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); - continue; + continue; } /* Remember the identifier and skip it */ @@ -232,16 +312,16 @@ static void ParseEnumDecl (void) /* Check for an assigned value */ if (CurTok.Tok == TOK_ASSIGN) { - ExprDesc lval; + ExprDesc Expr; NextToken (); - ConstExpr (&lval); - EnumVal = lval.ConstVal; + 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 */ + /* Check for end of definition */ if (CurTok.Tok != TOK_COMMA) break; NextToken (); @@ -251,7 +331,7 @@ static void ParseEnumDecl (void) -static SymEntry* ParseStructDecl (const char* Name, type StructType) +static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType) /* Parse a struct/union declaration. */ { @@ -295,7 +375,7 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType) /* Get the type of the entry */ DeclSpec Spec; InitDeclSpec (&Spec); - ParseTypeSpec (&Spec, -1); + ParseTypeSpec (&Spec, -1, T_QUAL_NONE); /* Read fields with this type */ while (1) { @@ -329,7 +409,7 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType) } FlexibleMember = 1; /* Assume zero for size calculations */ - Encode (Decl.Type + 1, FLEXIBLE); + SetElementCount (Decl.Type, FLEXIBLE); } else { StructSize += CheckedSizeOf (Decl.Type); } @@ -341,7 +421,7 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType) if (FieldSize > StructSize) { StructSize = FieldSize; } - } + } /* Add a field entry to the table */ AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs); @@ -351,7 +431,7 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType) } NextToken (); } - ConsumeSemi (); + ConsumeSemi (); } /* Skip the closing brace */ @@ -367,47 +447,46 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType) -static void ParseTypeSpec (DeclSpec* D, int Default) +static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers) /* Parse a type specificier */ { ident Ident; SymEntry* Entry; - type StructType; - type Qualifiers; /* Type qualifiers */ + TypeCode StructType; /* Assume we have an explicit type */ D->Flags &= ~DS_DEF_TYPE; /* Read type qualifiers if we have any */ - Qualifiers = OptionalQualifiers (T_QUAL_NONE); + Qualifiers = OptionalQualifiers (Qualifiers); /* Look at the data type */ switch (CurTok.Tok) { case TOK_VOID: NextToken (); - D->Type[0] = T_VOID; - D->Type[1] = T_END; + D->Type[0].C = T_VOID; + D->Type[1].C = T_END; break; case TOK_CHAR: NextToken (); - D->Type[0] = GetDefaultChar(); - D->Type[1] = T_END; + 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] = T_ULONG; - D->Type[1] = T_END; + OptionalInt (); + D->Type[0].C = T_ULONG; + D->Type[1].C = T_END; } else { - optionalsigned (); - optionalint (); - D->Type[0] = T_LONG; - D->Type[1] = T_END; + OptionalSigned (); + OptionalInt (); + D->Type[0].C = T_LONG; + D->Type[1].C = T_END; } break; @@ -415,21 +494,21 @@ static void ParseTypeSpec (DeclSpec* D, int Default) NextToken (); if (CurTok.Tok == TOK_UNSIGNED) { NextToken (); - optionalint (); - D->Type[0] = T_USHORT; - D->Type[1] = T_END; + OptionalInt (); + D->Type[0].C = T_USHORT; + D->Type[1].C = T_END; } else { - optionalsigned (); - optionalint (); - D->Type[0] = T_SHORT; - D->Type[1] = T_END; + OptionalSigned (); + OptionalInt (); + D->Type[0].C = T_SHORT; + D->Type[1].C = T_END; } - break; + break; case TOK_INT: NextToken (); - D->Type[0] = T_INT; - D->Type[1] = T_END; + D->Type[0].C = T_INT; + D->Type[1].C = T_END; break; case TOK_SIGNED: @@ -438,31 +517,31 @@ static void ParseTypeSpec (DeclSpec* D, int Default) case TOK_CHAR: NextToken (); - D->Type[0] = T_SCHAR; - D->Type[1] = T_END; + D->Type[0].C = T_SCHAR; + D->Type[1].C = T_END; break; case TOK_SHORT: NextToken (); - optionalint (); - D->Type[0] = T_SHORT; - D->Type[1] = T_END; + OptionalInt (); + D->Type[0].C = T_SHORT; + D->Type[1].C = T_END; break; case TOK_LONG: NextToken (); - optionalint (); - D->Type[0] = T_LONG; - D->Type[1] = T_END; + OptionalInt (); + D->Type[0].C = T_LONG; + D->Type[1].C = T_END; break; case TOK_INT: NextToken (); /* FALL THROUGH */ - default: - D->Type[0] = T_INT; - D->Type[1] = T_END; + default: + D->Type[0].C = T_INT; + D->Type[1].C = T_END; break; } break; @@ -473,22 +552,22 @@ static void ParseTypeSpec (DeclSpec* D, int Default) case TOK_CHAR: NextToken (); - D->Type[0] = T_UCHAR; - D->Type[1] = T_END; + D->Type[0].C = T_UCHAR; + D->Type[1].C = T_END; break; case TOK_SHORT: NextToken (); - optionalint (); - D->Type[0] = T_USHORT; - D->Type[1] = T_END; + OptionalInt (); + D->Type[0].C = T_USHORT; + D->Type[1].C = T_END; break; case TOK_LONG: NextToken (); - optionalint (); - D->Type[0] = T_ULONG; - D->Type[1] = T_END; + OptionalInt (); + D->Type[0].C = T_ULONG; + D->Type[1].C = T_END; break; case TOK_INT: @@ -496,12 +575,24 @@ static void ParseTypeSpec (DeclSpec* D, int Default) /* FALL THROUGH */ default: - D->Type[0] = T_UINT; - D->Type[1] = T_END; + 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; + + case TOK_DOUBLE: + NextToken (); + D->Type[0].C = T_DOUBLE; + D->Type[1].C = T_END; + break; + case TOK_STRUCT: case TOK_UNION: StructType = (CurTok.Tok == TOK_STRUCT)? T_STRUCT : T_UNION; @@ -518,18 +609,18 @@ static void ParseTypeSpec (DeclSpec* D, int Default) /* Declare the struct in the current scope */ Entry = ParseStructDecl (Ident, StructType); /* Encode the struct entry into the type */ - D->Type[0] = StructType; - EncodePtr (D->Type+1, Entry); - D->Type[DECODE_SIZE+1] = T_END; + D->Type[0].C = StructType; + SetSymEntry (D->Type, Entry); + D->Type[1].C = T_END; break; case TOK_ENUM: NextToken (); - if (CurTok.Tok != TOK_LCURLY) { + if (CurTok.Tok != TOK_LCURLY) { /* Named enum */ if (CurTok.Tok == TOK_IDENT) { /* Find an entry with this name */ - Entry = FindTagSym (CurTok.Ident); + Entry = FindTagSym (CurTok.Ident); if (Entry) { if (SymIsLocal (Entry) && (Entry->Flags & SC_ENUM) == 0) { Error ("Symbol `%s' is already different kind", Entry->Name); @@ -539,24 +630,24 @@ static void ParseTypeSpec (DeclSpec* D, int Default) } /* Skip the identifier */ NextToken (); - } else { + } else { Error ("Identifier expected"); - } - } - /* Remember we have an extra type decl */ - D->Flags |= DS_EXTRA_TYPE; - /* Parse the enum decl */ + } + } + /* Remember we have an extra type decl */ + D->Flags |= DS_EXTRA_TYPE; + /* Parse the enum decl */ ParseEnumDecl (); - D->Type[0] = T_INT; - D->Type[1] = T_END; + D->Type[0].C = T_INT; + D->Type[1].C = T_END; break; case TOK_IDENT: - Entry = FindSym (CurTok.Ident); - if (Entry && SymIsTypeDef (Entry)) { + Entry = FindSym (CurTok.Ident); + if (Entry && SymIsTypeDef (Entry)) { /* It's a typedef */ NextToken (); - TypeCpy (D->Type, Entry->Type); + TypeCpy (D->Type, Entry->Type); break; } /* FALL THROUGH */ @@ -564,30 +655,29 @@ static void ParseTypeSpec (DeclSpec* D, int Default) default: if (Default < 0) { Error ("Type expected"); - D->Type[0] = T_INT; - D->Type[1] = T_END; + D->Type[0].C = T_INT; + D->Type[1].C = T_END; } else { - D->Flags |= DS_DEF_TYPE; - D->Type[0] = (type) Default; - D->Type[1] = T_END; - } - break; + 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 */ - D->Type[0] |= OptionalQualifiers (Qualifiers); + D->Type[0].C |= OptionalQualifiers (Qualifiers); } -static type* ParamTypeCvt (type* T) +static Type* ParamTypeCvt (Type* T) /* If T is an array, convert it to a pointer else do nothing. Return the * resulting type. */ { if (IsTypeArray (T)) { - T += DECODE_SIZE; - T[0] = T_PTR; + T->C = T_PTR; } return T; } @@ -606,7 +696,7 @@ static void ParseOldStyleParamList (FuncDesc* F) } /* Create a symbol table entry with type int */ - AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF, 0); + AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF | SC_DEFTYPE, 0); /* Count arguments */ ++F->ParamCount; @@ -639,24 +729,34 @@ static void ParseOldStyleParamList (FuncDesc* F) * we ignore all this, since we use auto anyway. */ if ((Spec.StorageClass & SC_AUTO) == 0 && - (Spec.StorageClass & SC_REGISTER) == 0) { + (Spec.StorageClass & SC_REGISTER) == 0) { Error ("Illegal storage class"); } /* 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') { - /* We have a name given. Search for the symbol */ + /* We have a name given. Search for the symbol */ SymEntry* Sym = FindLocalSym (Decl.Ident); if (Sym) { - /* Found it, change the default type to the one given */ - ChangeSymType (Sym, ParamTypeCvt (Decl.Type)); + /* Check if we already changed the type for this + * parameter + */ + if (Sym->Flags & SC_DEFTYPE) { + /* Found it, change the default type to the one given */ + ChangeSymType (Sym, ParamTypeCvt (Decl.Type)); + /* Reset the "default type" flag */ + Sym->Flags &= ~SC_DEFTYPE; + } else { + /* Type has already been changed */ + Error ("Redefinition for parameter `%s'", Sym->Name); + } } else { Error ("Unknown identifier: `%s'", Decl.Ident); } @@ -689,7 +789,7 @@ static void ParseAnsiParamList (FuncDesc* F) /* Allow an ellipsis as last parameter */ if (CurTok.Tok == TOK_ELLIPSIS) { - NextToken (); + NextToken (); F->Flags |= FD_VARIADIC; break; } @@ -747,10 +847,11 @@ static void ParseAnsiParamList (FuncDesc* F) /* Check if this is a function definition */ if (CurTok.Tok == TOK_LCURLY) { - /* Print an error if in strict ANSI mode and we have unnamed - * parameters. + /* Print an error if we have unnamed parameters and cc65 extensions + * are disabled. */ - if (ANSI && (F->Flags & FD_UNNAMED_PARAMS) != 0) { + if (IS_Get (&Standard) != STD_CC65 && + (F->Flags & FD_UNNAMED_PARAMS) != 0) { Error ("Parameter name omitted"); } } @@ -758,7 +859,7 @@ static void ParseAnsiParamList (FuncDesc* F) -static FuncDesc* ParseFuncDecl (const DeclSpec* Spec) +static FuncDesc* ParseFuncDecl (void) /* Parse the argument list of a function. */ { unsigned Offs; @@ -785,19 +886,11 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec) */ Sym = FindSym (CurTok.Ident); if (Sym == 0 || !SymIsTypeDef (Sym)) { - /* Old style (K&R) function. Assume variable param list. */ - F->Flags |= (FD_OLDSTYLE | FD_VARIADIC); + /* Old style (K&R) function. */ + F->Flags |= FD_OLDSTYLE; } } - /* 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 */ if ((F->Flags & FD_OLDSTYLE) == 0) { /* New style function */ @@ -831,6 +924,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); @@ -840,39 +940,115 @@ 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; + + TypeCode C; + + /* Skip the star */ NextToken (); + /* Allow optional const or volatile qualifiers */ - T |= OptionalQualifiers (T_QUAL_NONE); + C = T_PTR | OptionalQualifiers (T_QUAL_NONE); + + /* Parse the type, the pointer points to */ Decl (Spec, D, Mode); - *D->T++ = T; + + /* Add the type */ + AddTypeToDeclaration (D, C); return; - } else if (CurTok.Tok == TOK_LPAREN) { + } + + /* Function modifiers */ + if (CurTok.Tok == TOK_FASTCALL || CurTok.Tok == TOK_NEAR || CurTok.Tok == TOK_FAR) { + + /* Remember the current type pointer */ + Type* T = D->Type + D->Index; + + /* Read the flags */ + unsigned Flags = FunctionModifierFlags (); + + /* Parse the function */ + Decl (Spec, D, Mode); + + /* Check that we have a function */ + if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) { + Error ("Function modifier applied to non function"); + } else { + ApplyFunctionModifiers (T, Flags); + } + + /* Done */ + return; + } + + if (CurTok.Tok == TOK_LPAREN) { NextToken (); Decl (Spec, D, Mode); ConsumeRParen (); - } else if (CurTok.Tok == TOK_FASTCALL) { - /* Remember the current type pointer */ - type* T = D->T; - /* Skip the fastcall token */ - NextToken (); - /* Parse the function */ - Decl (Spec, D, Mode); - /* Set the fastcall flag */ - 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"); - } else { - FuncDesc* F = GetFuncDesc (T); - F->Flags |= FD_FASTCALL; - } - return; } else { /* Things depend on Mode now: * - Mode == DM_NEED_IDENT means: @@ -899,36 +1075,38 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode) while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) { if (CurTok.Tok == TOK_LPAREN) { + /* Function declaration */ - FuncDesc* F; + FuncDesc* F; NextToken (); - /* Parse the function declaration */ - F = ParseFuncDecl (Spec); - *D->T++ = T_FUNC; - EncodePtr (D->T, F); - D->T += DECODE_SIZE; + + /* Parse the function declaration */ + F = ParseFuncDecl (); + + /* Add the function type. Be sure to bounds check the type buffer */ + AddFuncTypeToDeclaration (D, F); } else { - /* Array declaration */ + /* Array declaration */ long Size = UNSPECIFIED; NextToken (); - /* Read the size if it is given */ + /* Read the size if it is given */ if (CurTok.Tok != TOK_RBRACK) { - ExprDesc lval; - ConstExpr (&lval); - if (lval.ConstVal <= 0) { + ExprDesc Expr; + ConstAbsIntExpr (hie1, &Expr); + if (Expr.IVal <= 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; + Expr.IVal = 1; } - Size = lval.ConstVal; + Size = Expr.IVal; } ConsumeRBrack (); - *D->T++ = T_ARRAY; - Encode (D->T, Size); - D->T += DECODE_SIZE; + + /* Add the array type with the size */ + AddArrayToDeclaration (D, Size); } } } @@ -941,7 +1119,7 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode) -type* ParseType (type* Type) +Type* ParseType (Type* T) /* Parse a complete type specification */ { DeclSpec Spec; @@ -949,17 +1127,16 @@ type* ParseType (type* Type) /* Get a type without a default */ InitDeclSpec (&Spec); - ParseTypeSpec (&Spec, -1); + ParseTypeSpec (&Spec, -1, T_QUAL_NONE); /* Parse additional declarators */ - InitDeclaration (&Decl); ParseDecl (&Spec, &Decl, DM_NO_IDENT); /* Copy the type to the target buffer */ - TypeCpy (Type, Decl.Type); + TypeCpy (T, Decl.Type); /* Return a pointer to the target buffer */ - return Type; + return T; } @@ -974,31 +1151,84 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode) Decl (Spec, D, Mode); /* Add the base type. */ - TypeCpy (D->T, Spec->Type); + NeedTypeSpace (D, TypeLen (Spec->Type) + 1); /* Bounds check */ + TypeCpy (D->Type + D->Index, Spec->Type); + + /* Fix any type qualifiers attached to an array type */ + FixArrayQualifiers (D->Type); + + /* Check several things for function or function pointer types */ + if (IsTypeFunc (D->Type) || IsTypeFuncPtr (D->Type)) { + + /* A function. Check the return type */ + Type* RetType = GetFuncReturn (D->Type); + + /* Functions may not return functions or arrays */ + if (IsTypeFunc (RetType)) { + Error ("Functions are not allowed to return functions"); + } else if (IsTypeArray (RetType)) { + Error ("Functions are not allowed to return arrays"); + } + + /* The return type must not be qualified */ + if (GetQualifier (RetType) != T_QUAL_NONE && RetType[1].C == T_END) { + + if (GetType (RetType) == T_TYPE_VOID) { + /* A qualified void type is always an error */ + Error ("function definition has qualified void return type"); + } else { + /* For others, qualifiers are ignored */ + Warning ("type qualifiers ignored on function return type"); + RetType[0].C = UnqualifiedType (RetType[0].C); + } + } + + /* Warn about an implicit int return in the function */ + 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. + */ + if (IS_Get (&Standard) >= STD_C99) { + Warning ("Implicit `int' return type is an obsolete feature"); + } + GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET; + } + + } /* Check the size of the generated type */ - if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type) && SizeOf (D->Type) >= 0x10000) { - if (D->Ident[0] != '\0') { - Error ("Size of `%s' is invalid", D->Ident); - } else { - Error ("Invalid size"); - } + if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type)) { + unsigned Size = SizeOf (D->Type); + if (Size >= 0x10000) { + if (D->Ident[0] != '\0') { + Error ("Size of `%s' is invalid (0x%06X)", D->Ident, Size); + } else { + Error ("Invalid size in declaration (0x%06X)", Size); + } + } } + } -void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType) +void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType) /* Parse a declaration specification */ { + TypeCode Qualifiers; + /* Initialize the DeclSpec struct */ InitDeclSpec (D); - /* First, get the storage class specifier for this declaration */ + /* There may be qualifiers *before* the storage class specifier */ + Qualifiers = OptionalQualifiers (T_QUAL_NONE); + + /* Now get the storage class specifier for this declaration */ ParseStorageClass (D, DefStorage); - /* Parse the type specifiers */ - ParseTypeSpec (D, DefType); + /* Parse the type specifiers passing any initial type qualifiers */ + ParseTypeSpec (D, DefType, Qualifiers); } @@ -1074,7 +1304,51 @@ static void ClosingCurlyBraces (unsigned BracesExpected) -static unsigned ParseScalarInit (type* T) +static void DefineData (ExprDesc* Expr) +/* Output a data definition for the given expression */ +{ + switch (ED_GetLoc (Expr)) { + + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + break; + + case E_LOC_GLOBAL: + /* Global variable */ + g_defdata (CF_EXTERNAL, Expr->Name, Expr->IVal); + break; + + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + g_defdata (CF_STATIC, Expr->Name, Expr->IVal); + 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"); + } + g_defdata (CF_REGVAR, Expr->Name, Expr->IVal); + break; + + case E_LOC_STACK: + case E_LOC_PRIMARY: + case E_LOC_EXPR: + Error ("Non constant initializer"); + break; + + default: + Internal ("Unknown constant type: 0x%04X", ED_GetLoc (Expr)); + } +} + + + +static unsigned ParseScalarInit (Type* T) /* Parse initializaton for scalar data types. Return the number of data bytes. */ { ExprDesc ED; @@ -1090,8 +1364,8 @@ static unsigned ParseScalarInit (type* T) } /* Get the expression and convert it to the target type */ - ConstExpr (&ED); - TypeConversion (&ED, 0, T); + ConstExpr (hie1, &ED); + TypeConversion (&ED, T); /* Output the data */ DefineData (&ED); @@ -1105,7 +1379,7 @@ static unsigned ParseScalarInit (type* T) -static unsigned ParsePointerInit (type* T) +static unsigned ParsePointerInit (Type* T) /* Parse initializaton for pointer data types. Return the number of data bytes. */ { /* Optional opening brace */ @@ -1113,12 +1387,8 @@ static unsigned ParsePointerInit (type* T) /* 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); + ConstExpr (hie1, &ED); + TypeConversion (&ED, T); /* Output the data */ DefineData (&ED); @@ -1132,21 +1402,35 @@ static unsigned ParsePointerInit (type* T) -static unsigned ParseArrayInit (type* T, int AllowFlexibleMembers) +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); + 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) { + if (IsTypeChar (ElementType) && + (CurTok.Tok == TOK_SCONST || + (CurTok.Tok == TOK_LCURLY && NextTok.Tok == TOK_SCONST))) { /* Char array initialized by string constant */ - const char* Str = GetLiteral (CurTok.IVal); + int NeedParen; + const char* Str; + + /* If we initializer is enclosed in brackets, remember this fact and + * 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 */ @@ -1169,6 +1453,13 @@ static unsigned ParseArrayInit (type* T, int AllowFlexibleMembers) ResetLiteralPoolOffs (CurTok.IVal); NextToken (); + /* If the initializer was enclosed in curly braces, we need a closing + * one. + */ + if (NeedParen) { + ConsumeRCurly (); + } + } else { /* Curly brace */ @@ -1192,10 +1483,9 @@ static unsigned ParseArrayInit (type* T, int AllowFlexibleMembers) ConsumeRCurly (); } - if (ElementCount == UNSPECIFIED) { /* Number of elements determined by initializer */ - Encode (T + 1, Count); + SetElementCount (T, Count); ElementCount = Count; } else if (ElementCount == FLEXIBLE && AllowFlexibleMembers) { /* In non ANSI mode, allow initialization of flexible array @@ -1212,7 +1502,7 @@ static unsigned ParseArrayInit (type* T, int AllowFlexibleMembers) -static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers) +static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers) /* Parse initialization of a struct or union. Return the number of data bytes. */ { SymEntry* Entry; @@ -1225,7 +1515,7 @@ static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers) ConsumeLCurly (); /* Get a pointer to the struct entry from the type */ - Entry = DecodePtr (Type + 1); + Entry = GetSymEntry (T); /* Get the size of the struct from the symbol table entry */ StructSize = Entry->V.S.Size; @@ -1287,7 +1577,7 @@ static unsigned ParseVoidInit (void) * Return the number of bytes initialized. */ { - ExprDesc lval; + ExprDesc Expr; unsigned Size; /* Opening brace */ @@ -1296,16 +1586,16 @@ static unsigned ParseVoidInit (void) /* Allow an arbitrary list of values */ Size = 0; do { - ConstExpr (&lval); - switch (UnqualifiedType (lval.Type[0])) { + ConstExpr (hie1, &Expr); + switch (UnqualifiedType (Expr.Type[0].C)) { case T_SCHAR: case T_UCHAR: - if ((lval.Flags & E_MCTYPE) == E_TCONST) { + if (ED_IsConstAbsInt (&Expr)) { /* Make it byte sized */ - lval.ConstVal &= 0xFF; + Expr.IVal &= 0xFF; } - DefineData (&lval); + DefineData (&Expr); Size += SIZEOF_CHAR; break; @@ -1315,17 +1605,21 @@ static unsigned ParseVoidInit (void) case T_UINT: case T_PTR: case T_ARRAY: - if ((lval.Flags & E_MCTYPE) == E_TCONST) { + if (ED_IsConstAbsInt (&Expr)) { /* Make it word sized */ - lval.ConstVal &= 0xFFFF; + Expr.IVal &= 0xFFFF; } - DefineData (&lval); + DefineData (&Expr); Size += SIZEOF_INT; break; case T_LONG: case T_ULONG: - DefineData (&lval); + if (ED_IsConstAbsInt (&Expr)) { + /* Make it dword sized */ + Expr.IVal &= 0xFFFFFFFF; + } + DefineData (&Expr); Size += SIZEOF_LONG; break; @@ -1351,10 +1645,10 @@ static unsigned ParseVoidInit (void) -static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers) +static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers) /* Parse initialization of variables. Return the number of data bytes. */ { - switch (UnqualifiedType (*T)) { + switch (UnqualifiedType (T->C)) { case T_SCHAR: case T_UCHAR: @@ -1377,7 +1671,7 @@ static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers) return ParseStructInit (T, AllowFlexibleMembers); case T_VOID: - if (!ANSI) { + if (IS_Get (&Standard) == STD_CC65) { /* Special cc65 extension in non ANSI mode */ return ParseVoidInit (); } @@ -1392,11 +1686,13 @@ static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers) -unsigned ParseInit (type* T) +unsigned ParseInit (Type* T) /* Parse initialization of variables. Return the number of data bytes. */ { - /* Parse the initialization */ - unsigned Size = ParseInitInternal (T, !ANSI); + /* Parse the initialization. Flexible array members can only be initialized + * 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.