X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Flocals.c;h=fccc8040e94429ffd5f36384ce1efbcba9f7b146;hb=08443d5e7aca1686a7b69dd23ff496516dfdf569;hp=ec242c181cc8d5f1266e1447fb6605744bb5d987;hpb=9cc25f13b6aabc4fd299c54c9c38c5825689eb47;p=cc65 diff --git a/src/cc65/locals.c b/src/cc65/locals.c index ec242c181..fccc8040e 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2000 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 2000-2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -33,14 +33,19 @@ +/* common */ +#include "xmalloc.h" +#include "xsprintf.h" + +/* cc65 */ #include "anonname.h" #include "asmlabel.h" #include "codegen.h" #include "declare.h" +#include "error.h" #include "expr.h" #include "function.h" #include "global.h" -#include "mem.h" #include "symtab.h" #include "locals.h" @@ -79,7 +84,7 @@ void InitRegVars (void) * will usually waste some space but we don't need to dynamically * grow the array. */ - RegSyms = xmalloc (MaxRegSpace * sizeof (RegSyms[0])); + RegSyms = (const SymEntry**) xmalloc (MaxRegSpace * sizeof (RegSyms[0])); RegOffs = MaxRegSpace; } @@ -128,276 +133,247 @@ static int AllocRegVar (const SymEntry* Sym, const type* tarray) -void DeclareLocals (void) -/* Declare local variables and types. */ +static void ParseOneDecl (const DeclSpec* Spec) +/* Parse one variable declaration */ { - int offs = oursp; /* Current stack offset for variable */ - int AutoSpace = 0; /* Unallocated space on the stack */ - int Size; /* Size of an auto variable */ - int Reg; /* Register variable offset */ - unsigned flags = 0; /* Code generator flags */ - int SymbolSC; /* Storage class for symbol */ - int ldata = 0; /* Local symbol data temp storage */ - - /* Loop until we don't find any more variables */ - while (1) { - - /* Check variable declarations. We need to distinguish between a - * default int type and the end of variable declarations. So we - * will do the following: If there is no explicit storage class - * specifier *and* no explicit type given, it is assume that we - * have reached the end of declarations. - */ - DeclSpec Spec; - ParseDeclSpec (&Spec, SC_AUTO, T_INT); - if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) { - break; - } - - /* Accept type only declarations */ - if (curtok == TOK_SEMI) { - /* Type declaration only */ - CheckEmptyDecl (&Spec); - NextToken (); - continue; + int Size; /* Size of an auto variable */ + int SC; /* Storage class for symbol */ + int SymData = 0; /* Symbol data (offset, label name, ...) */ + unsigned flags = 0; /* Code generator flags */ + Declaration Decl; /* Declaration data structure */ + + /* Remember the storage class for the new symbol */ + SC = Spec->StorageClass; + + /* Read the declaration */ + ParseDecl (Spec, &Decl, DM_NEED_IDENT); + + /* Set the correct storage class for functions */ + if (IsTypeFunc (Decl.Type)) { + /* Function prototypes are always external */ + if ((SC & SC_EXTERN) == 0) { + Warning ("Function must be extern"); } + SC |= SC_FUNC | SC_EXTERN; - /* Parse a comma separated variable list */ - while (1) { - - Declaration Decl; - - /* Remember the storage class for the new symbol */ - SymbolSC = Spec.StorageClass; - - /* Read the declaration */ - ParseDecl (&Spec, &Decl, DM_NEED_IDENT); - - /* If we don't have a name, this was flagged as an error earlier. - * To avoid problems later, use an anonymous name here. - */ - if (Decl.Ident[0] == '\0') { - AnonName (Decl.Ident, "param"); - } - - if (!IsFunc (Decl.Type) && (SymbolSC & SC_TYPEDEF) != SC_TYPEDEF) { - - /* Get the size of the variable */ - Size = SizeOf (Decl.Type); - -#if 0 - /* Check the storage class */ - if ((SymbolSC & SC_REGISTER) && (Reg = AllocRegVar (psym, tarray)) >= 0) { - - /* We will store the current value of the register onto the - * stack, thus making functions with register variables - * reentrant. If we have pending auto variables, emit them - * now. - */ - g_usecode (); - g_space (AutoSpace); - oursp -= AutoSpace; - AutoSpace = 0; - - /* Remember the register bank offset */ - ldata = Reg; - - /* Save the current register value onto the stack */ - g_save_regvars (Reg, Size); - - /* Allow variable initialization */ - if (curtok == TOK_ASSIGN) { + } - struct expent lval; + /* If we don't have a name, this was flagged as an error earlier. + * To avoid problems later, use an anonymous name here. + */ + if (Decl.Ident[0] == '\0') { + AnonName (Decl.Ident, "param"); + } - /* Skip the '=' */ - NextToken (); + /* Handle anything that needs storage (no functions, no typdefs) */ + if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) { - /* Get the expression into the primary */ - expression1 (&lval); + /* Get the size of the variable */ + Size = SizeOf (Decl.Type); - /* Make type adjustments if needed */ - assignadjust (tarray, &lval); + if (SC & (SC_AUTO | SC_REGISTER)) { - /* Setup the type flags for the assignment */ - flags = TypeOf (tarray) | CF_REGVAR; - if (Size == 1) { - flags |= CF_FORCECHAR; - } + /* Auto variable */ + if (StaticLocals == 0) { - /* Store the value into the register */ - g_putstatic (flags, Reg, 0); + /* Change SC in case it was register */ + SC = (SC & ~SC_REGISTER) | SC_AUTO; + if (CurTok.Tok == TOK_ASSIGN) { - /* Mark the variable as referenced */ - SymbolSC |= SC_REF; + ExprDesc lval; - } + /* Allocate previously reserved local space */ + AllocLocalSpace (CurrentFunc); - /* Account for the stack space needed and remember the - * stack offset of the save area. - */ - offs -= Size; - psym->h_lattr = offs; + /* Skip the '=' */ + NextToken (); - } else if (SymbolSC & (SC_AUTO | SC_REGISTER)) { -#endif - if (SymbolSC & (SC_AUTO | SC_REGISTER)) { + /* Setup the type flags for the assignment */ + flags = Size == 1? CF_FORCECHAR : CF_NONE; - /* Auto variable */ - if (LocalsAreStatic == 0) { + /* Get the expression into the primary */ + if (evalexpr (flags, hie1, &lval) == 0) { + /* Constant expression. Adjust the types */ + assignadjust (Decl.Type, &lval); + flags |= CF_CONST; + } else { + /* Expression is not constant and in the primary */ + assignadjust (Decl.Type, &lval); + } - /* Change SC in case it was register */ - SymbolSC = (SymbolSC & ~SC_REGISTER) | SC_AUTO; - if (curtok == TOK_ASSIGN) { + /* Push the value */ + g_push (flags | TypeOf (Decl.Type), lval.ConstVal); - struct expent lval; + /* Mark the variable as referenced */ + SC |= SC_REF; - /* Switch to the code segment, allocate space for - * uninitialized variables. - */ - g_usecode (); - g_space (AutoSpace); - oursp -= AutoSpace; - AutoSpace = 0; + /* Variable is located at the current SP */ + SymData = oursp; - /* Skip the '=' */ - NextToken (); + } else { + /* Non-initialized local variable. Just keep track of + * the space needed. + */ + SymData = ReserveLocalSpace (CurrentFunc, Size); + } - /* Setup the type flags for the assignment */ - flags = Size == 1? CF_FORCECHAR : CF_NONE; + } else { - /* Get the expression into the primary */ - if (evalexpr (flags, hie1, &lval) == 0) { - /* Constant expression. Adjust the types */ - assignadjust (Decl.Type, &lval); - flags |= CF_CONST; - } else { - /* Expression is not constant and in the primary */ - assignadjust (Decl.Type, &lval); - } + /* Static local variables. */ + SC = (SC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC; - /* Push the value */ - g_push (flags | TypeOf (Decl.Type), lval.e_const); + /* Put them into the BSS */ + g_usebss (); - /* Mark the variable as referenced */ - SymbolSC |= SC_REF; + /* Define the variable label */ + SymData = GetLocalLabel (); + g_defdatalabel (SymData); - } else { - /* Non-initialized local variable. Just keep track of - * the space needed. - */ - AutoSpace += Size; - } + /* Reserve space for the data */ + g_res (Size); - /* Allocate space on the stack, assign the offset */ - offs -= Size; - ldata = offs; + /* Allow assignments */ + if (CurTok.Tok == TOK_ASSIGN) { - } else { + ExprDesc lval; - /* Static local variables. */ - SymbolSC = (SymbolSC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC; + /* Skip the '=' */ + NextToken (); - /* Put them into the BSS */ - g_usebss (); + /* Setup the type flags for the assignment */ + flags = Size == 1? CF_FORCECHAR : CF_NONE; - /* Define the variable label */ - g_defloclabel (ldata = GetLabel ()); + /* Get the expression into the primary */ + if (evalexpr (flags, hie1, &lval) == 0) { + /* Constant expression. Adjust the types */ + assignadjust (Decl.Type, &lval); + flags |= CF_CONST; + /* Load it into the primary */ + exprhs (flags, 0, &lval); + } else { + /* Expression is not constant and in the primary */ + assignadjust (Decl.Type, &lval); + } - /* Reserve space for the data */ - g_res (Size); + /* Store the value into the variable */ + g_putstatic (flags | TypeOf (Decl.Type), SymData, 0); - /* Allow assignments */ - if (curtok == TOK_ASSIGN) { + /* Mark the variable as referenced */ + SC |= SC_REF; + } + } - struct expent lval; + } else if ((SC & SC_STATIC) == SC_STATIC) { - /* Switch to the code segment. */ - g_usecode (); + /* Static data */ + if (CurTok.Tok == TOK_ASSIGN) { - /* Skip the '=' */ - NextToken (); + /* Initialization ahead, switch to data segment */ + if (IsQualConst (Decl.Type)) { + g_userodata (); + } else { + g_usedata (); + } - /* Get the expression into the primary */ - expression1 (&lval); + /* Define the variable label */ + SymData = GetLocalLabel (); + g_defdatalabel (SymData); - /* Make type adjustments if needed */ - assignadjust (Decl.Type, &lval); + /* Skip the '=' */ + NextToken (); - /* Setup the type flags for the assignment */ - flags = TypeOf (Decl.Type); - if (Size == 1) { - flags |= CF_FORCECHAR; - } + /* Allow initialization of static vars */ + ParseInit (Decl.Type); - /* Store the value into the variable */ - g_putstatic (flags, ldata, 0); + /* Mark the variable as referenced */ + SC |= SC_REF; - /* Mark the variable as referenced */ - SymbolSC |= SC_REF; - } - } + } else { - } else if ((SymbolSC & SC_STATIC) == SC_STATIC) { + /* Uninitialized data, use BSS segment */ + g_usebss (); - /* Static data */ - if (curtok == TOK_ASSIGN) { + /* Define the variable label */ + SymData = GetLocalLabel (); + g_defdatalabel (SymData); - /* Initialization ahead, switch to data segment */ - g_usedata (); + /* Reserve space for the data */ + g_res (Size); - /* Define the variable label */ - g_defloclabel (ldata = GetLabel ()); + } + } - /* Skip the '=' */ - NextToken (); + } - /* Allow initialization of static vars */ - ParseInit (Decl.Type); + /* If the symbol is not marked as external, it will be defined */ + if ((SC & SC_EXTERN) == 0) { + SC |= SC_DEF; + } - /* Mark the variable as referenced */ - SymbolSC |= SC_REF; + /* Add the symbol to the symbol table */ + AddLocalSym (Decl.Ident, Decl.Type, SC, SymData); +} - } else { - /* Uninitialized data, use BSS segment */ - g_usebss (); - /* Define the variable label */ - g_defloclabel (ldata = GetLabel ()); +void DeclareLocals (void) +/* Declare local variables and types. */ +{ + /* Remember the current stack pointer */ + int InitialStack = oursp; - /* Reserve space for the data */ - g_res (Size); + /* Loop until we don't find any more variables */ + while (1) { - } - } + /* Check variable declarations. We need to distinguish between a + * default int type and the end of variable declarations. So we + * will do the following: If there is no explicit storage class + * specifier *and* no explicit type given, it is assume that we + * have reached the end of declarations. + */ + DeclSpec Spec; + ParseDeclSpec (&Spec, SC_AUTO, T_INT); + if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) { + break; + } - } + /* Accept type only declarations */ + if (CurTok.Tok == TOK_SEMI) { + /* Type declaration only */ + CheckEmptyDecl (&Spec); + NextToken (); + continue; + } - /* If the symbol is not marked as external, it will be defined */ - if ((SymbolSC & SC_EXTERN) == 0) { - SymbolSC |= SC_DEF; - } + /* Parse a comma separated variable list */ + while (1) { - /* Add the symbol to the symbol table */ - AddLocalSym (Decl.Ident, Decl.Type, SymbolSC, ldata); + /* Parse one declaration */ + ParseOneDecl (&Spec); - if (curtok != TOK_COMMA) { + /* Check if there is more */ + if (CurTok.Tok == TOK_COMMA) { + /* More to come */ + NextToken (); + } else { + /* Done */ break; } - NextToken (); } - if (curtok == TOK_SEMI) { - NextToken (); - } + + /* A semicolon must follow */ + ConsumeSemi (); } - /* In case we switched away from code segment, switch back now */ - g_usecode (); + /* Be sure to allocate any reserved space for locals */ + AllocLocalSpace (CurrentFunc); - /* Create space for locals */ - g_space (AutoSpace); - oursp -= AutoSpace; + /* In case we've allocated local variables in this block, emit a call to + * the stack checking routine if stack checks are enabled. + */ + if (CheckStack && InitialStack != oursp) { + g_cstackcheck (); + } }