1 /*****************************************************************************/
5 /* Local variable handling for the cc65 C compiler */
9 /* (C) 2000-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
55 /*****************************************************************************/
57 /*****************************************************************************/
61 static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
62 /* Parse the declaration of a register variable. The function returns the
63 * symbol data, which is the offset of the variable in the register bank.
68 /* Determine if this is a compound variable */
69 int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
71 /* Get the size of the variable */
72 unsigned Size = SizeOf (Decl->Type);
74 /* Save the current contents of the register variable on stack */
75 F_AllocLocalSpace (CurrentFunc);
76 g_save_regvars (Reg, Size);
78 /* Check for an optional initialization */
79 if (CurTok.Tok == TOK_ASSIGN) {
86 /* Special handling for compound types */
89 /* Switch to read only data */
92 /* Define a label for the initialization data */
93 InitLabel = GetLocalLabel ();
94 g_defdatalabel (InitLabel);
96 /* Parse the initialization generating a memory image of the
97 * data in the RODATA segment. The function does return the size
98 * of the initialization data, which may be greater than the
99 * actual size of the type, if the type is a structure with a
100 * flexible array member that has been initialized. Since we must
101 * know the size of the data in advance for register variables,
102 * we cannot allow that here.
104 if (ParseInit (Decl->Type) != Size) {
105 Error ("Cannot initialize flexible array members of storage class `register'");
108 /* Generate code to copy this data into the variable space */
109 g_initregister (InitLabel, Reg, Size);
113 /* Parse the expression */
114 int k = hie1 (InitExprDesc (&lval));
116 /* Convert it to the target type */
117 k = TypeConversion (&lval, k, Decl->Type);
119 /* Load the value into the primary */
120 exprhs (CF_NONE, k, &lval);
122 /* Store the value into the variable */
123 g_putstatic (CF_REGVAR | TypeOf (Decl->Type), Reg, 0);
127 /* Mark the variable as referenced */
131 /* Cannot allocate a variable of zero size */
133 Error ("Variable `%s' has unknown size", Decl->Ident);
136 /* Return the symbol data */
142 static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
143 /* Parse the declaration of an auto variable. The function returns the symbol
144 * data, which is the offset for variables on the stack, and the label for
152 /* Determine if this is a compound variable */
153 int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
155 /* Get the size of the variable */
156 unsigned Size = SizeOf (Decl->Type);
158 /* Check if this is a variable on the stack or in static memory */
159 if (StaticLocals == 0) {
161 /* Check for an optional initialization */
162 if (CurTok.Tok == TOK_ASSIGN) {
169 /* Special handling for compound types */
172 /* Switch to read only data */
175 /* Define a label for the initialization data */
176 InitLabel = GetLocalLabel ();
177 g_defdatalabel (InitLabel);
179 /* Parse the initialization generating a memory image of the
180 * data in the RODATA segment. The function will return the
181 * actual size of the initialization data, which may be
182 * greater than the size of the variable if it is a struct
183 * that contains a flexible array member and we're not in
186 Size = ParseInit (Decl->Type);
188 /* Now reserve space for the variable on the stack */
189 SymData = F_ReserveLocalSpace (CurrentFunc, Size);
191 /* Next, allocate the space on the stack. This means that the
192 * variable is now located at offset 0 from the current sp.
194 F_AllocLocalSpace (CurrentFunc);
196 /* Generate code to copy the initialization data into the
199 g_initauto (InitLabel, Size);
205 /* Allocate previously reserved local space */
206 F_AllocLocalSpace (CurrentFunc);
208 /* Setup the type flags for the assignment */
209 Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
211 /* Parse the expression */
212 k = hie1 (InitExprDesc (&lval));
214 /* Convert it to the target type */
215 k = TypeConversion (&lval, k, Decl->Type);
217 /* If the value is not const, load it into the primary.
218 * Otherwise pass the information to the code generator.
220 if (k != 0 || lval.Flags != E_MCONST) {
221 exprhs (CF_NONE, k, &lval);
228 g_push (Flags | TypeOf (Decl->Type), lval.ConstVal);
232 /* Mark the variable as referenced */
235 /* Variable is located at the current SP */
239 /* Non-initialized local variable. Just keep track of
242 SymData = F_ReserveLocalSpace (CurrentFunc, Size);
247 /* Static local variables. */
248 *SC = (*SC & ~SC_AUTO) | SC_STATIC;
250 /* Put them into the BSS */
253 /* Define the variable label */
254 SymData = GetLocalLabel ();
255 g_defdatalabel (SymData);
257 /* Reserve space for the data */
260 /* Allow assignments */
261 if (CurTok.Tok == TOK_ASSIGN) {
270 /* Switch to read only data */
273 /* Define a label for the initialization data */
274 InitLabel = GetLocalLabel ();
275 g_defdatalabel (InitLabel);
277 /* Parse the initialization generating a memory image of the
278 * data in the RODATA segment.
280 ParseInit (Decl->Type);
282 /* Generate code to copy this data into the variable space */
283 g_initstatic (InitLabel, SymData, Size);
287 /* Parse the expression */
288 int k = hie1 (InitExprDesc (&lval));
290 /* Convert it to the target type */
291 k = TypeConversion (&lval, k, Decl->Type);
293 /* Load the value into the primary */
294 exprhs (CF_NONE, k, &lval);
296 /* Store the value into the variable */
297 g_putstatic (TypeOf (Decl->Type), SymData, 0);
300 /* Mark the variable as referenced */
305 /* Cannot allocate a variable of zero size */
307 Error ("Variable `%s' has unknown size", Decl->Ident);
310 /* Return the symbol data */
316 static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC)
317 /* Parse the declaration of a static variable. The function returns the symbol
318 * data, which is the asm label of the variable.
323 /* Get the size of the variable */
324 unsigned Size = SizeOf (Decl->Type);
327 if (CurTok.Tok == TOK_ASSIGN) {
329 /* Initialization ahead, switch to data segment */
330 if (IsQualConst (Decl->Type)) {
336 /* Define the variable label */
337 SymData = GetLocalLabel ();
338 g_defdatalabel (SymData);
343 /* Allow initialization of static vars */
344 ParseInit (Decl->Type);
346 /* If the previous size has been unknown, it must be known now */
348 Size = SizeOf (Decl->Type);
351 /* Mark the variable as referenced */
356 /* Uninitialized data, use BSS segment */
359 /* Define the variable label */
360 SymData = GetLocalLabel ();
361 g_defdatalabel (SymData);
363 /* Reserve space for the data */
368 /* Cannot allocate a variable of zero size */
370 Error ("Variable `%s' has unknown size", Decl->Ident);
373 /* Return the symbol data */
379 static void ParseOneDecl (const DeclSpec* Spec)
380 /* Parse one variable declaration */
382 unsigned SC; /* Storage class for symbol */
383 unsigned SymData = 0; /* Symbol data (offset, label name, ...) */
384 Declaration Decl; /* Declaration data structure */
387 /* Remember the storage class for the new symbol */
388 SC = Spec->StorageClass;
390 /* Read the declaration */
391 ParseDecl (Spec, &Decl, DM_NEED_IDENT);
393 /* Set the correct storage class for functions */
394 if (IsTypeFunc (Decl.Type)) {
395 /* Function prototypes are always external */
396 if ((SC & SC_EXTERN) == 0) {
397 Warning ("Function must be extern");
399 SC |= SC_FUNC | SC_EXTERN;
403 /* If we don't have a name, this was flagged as an error earlier.
404 * To avoid problems later, use an anonymous name here.
406 if (Decl.Ident[0] == '\0') {
407 AnonName (Decl.Ident, "param");
410 /* Handle anything that needs storage (no functions, no typdefs) */
411 if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) {
413 /* If we have a register variable, try to allocate a register and
414 * convert the declaration to "auto" if this is not possible.
416 int Reg = 0; /* Initialize to avoid gcc complains */
417 if ((SC & SC_REGISTER) != 0 && (Reg = F_AllocRegVar (CurrentFunc, Decl.Type)) < 0) {
418 /* No space for this register variable, convert to auto */
419 SC = (SC & ~SC_REGISTER) | SC_AUTO;
422 /* Check the variable type */
423 if ((SC & SC_REGISTER) == SC_REGISTER) {
424 /* Register variable */
425 SymData = ParseRegisterDecl (&Decl, &SC, Reg);
426 } else if ((SC & SC_AUTO) == SC_AUTO) {
428 SymData = ParseAutoDecl (&Decl, &SC);
429 } else if ((SC & SC_STATIC) == SC_STATIC) {
430 /* Static variable */
431 SymData = ParseStaticDecl (&Decl, &SC);
433 Internal ("Invalid storage class in ParseOneDecl: %04X", SC);
437 /* If the symbol is not marked as external, it will be defined now */
438 if ((SC & SC_EXTERN) == 0) {
442 /* Add the symbol to the symbol table */
443 AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
448 void DeclareLocals (void)
449 /* Declare local variables and types. */
451 /* Remember the current stack pointer */
452 int InitialStack = oursp;
454 /* Loop until we don't find any more variables */
457 /* Check variable declarations. We need to distinguish between a
458 * default int type and the end of variable declarations. So we
459 * will do the following: If there is no explicit storage class
460 * specifier *and* no explicit type given, *and* no type qualifiers
461 * have been read, it is assumed that we have reached the end of
465 ParseDeclSpec (&Spec, SC_AUTO, T_INT);
466 if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
467 (Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */
468 GetQualifier (Spec.Type) == T_QUAL_NONE) { /* No type qualifier */
472 /* Accept type only declarations */
473 if (CurTok.Tok == TOK_SEMI) {
474 /* Type declaration only */
475 CheckEmptyDecl (&Spec);
480 /* Parse a comma separated variable list */
483 /* Parse one declaration */
484 ParseOneDecl (&Spec);
486 /* Check if there is more */
487 if (CurTok.Tok == TOK_COMMA) {
496 /* A semicolon must follow */
500 /* Be sure to allocate any reserved space for locals */
501 F_AllocLocalSpace (CurrentFunc);
503 /* In case we've allocated local variables in this block, emit a call to
504 * the stack checking routine if stack checks are enabled.
506 if (CheckStack && InitialStack != oursp) {