1 /*****************************************************************************/
5 /* Local variable handling for the cc65 C compiler */
9 /* (C) 2000-2004 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 */
116 /* Convert it to the target type */
117 TypeConversion (&Expr, Decl->Type);
119 /* Load the value into the primary */
120 ExprLoad (CF_NONE, &Expr);
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 (IS_Get (&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);
203 /* Allocate previously reserved local space */
204 F_AllocLocalSpace (CurrentFunc);
206 /* Setup the type flags for the assignment */
207 Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
209 /* Parse the expression */
212 /* Convert it to the target type */
213 TypeConversion (&Expr, Decl->Type);
215 /* If the value is not const, load it into the primary.
216 * Otherwise pass the information to the code generator.
218 if (ED_IsConstAbsInt (&Expr)) {
221 ExprLoad (CF_NONE, &Expr);
226 g_push (Flags | TypeOf (Decl->Type), Expr.Val);
230 /* Mark the variable as referenced */
233 /* Variable is located at the current SP */
237 /* Non-initialized local variable. Just keep track of
240 SymData = F_ReserveLocalSpace (CurrentFunc, Size);
245 /* Static local variables. */
246 *SC = (*SC & ~SC_AUTO) | SC_STATIC;
248 /* Put them into the BSS */
251 /* Define the variable label */
252 SymData = GetLocalLabel ();
253 g_defdatalabel (SymData);
255 /* Reserve space for the data */
258 /* Allow assignments */
259 if (CurTok.Tok == TOK_ASSIGN) {
268 /* Switch to read only data */
271 /* Define a label for the initialization data */
272 InitLabel = GetLocalLabel ();
273 g_defdatalabel (InitLabel);
275 /* Parse the initialization generating a memory image of the
276 * data in the RODATA segment.
278 ParseInit (Decl->Type);
280 /* Generate code to copy this data into the variable space */
281 g_initstatic (InitLabel, SymData, Size);
285 /* Parse the expression */
288 /* Convert it to the target type */
289 TypeConversion (&Expr, Decl->Type);
291 /* Load the value into the primary */
292 ExprLoad (CF_NONE, &Expr);
294 /* Store the value into the variable */
295 g_putstatic (TypeOf (Decl->Type), SymData, 0);
298 /* Mark the variable as referenced */
303 /* Cannot allocate a variable of zero size */
305 Error ("Variable `%s' has unknown size", Decl->Ident);
308 /* Return the symbol data */
314 static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC)
315 /* Parse the declaration of a static variable. The function returns the symbol
316 * data, which is the asm label of the variable.
321 /* Get the size of the variable */
322 unsigned Size = SizeOf (Decl->Type);
325 if (CurTok.Tok == TOK_ASSIGN) {
327 /* Initialization ahead, switch to data segment */
328 if (IsQualConst (Decl->Type)) {
334 /* Define the variable label */
335 SymData = GetLocalLabel ();
336 g_defdatalabel (SymData);
341 /* Allow initialization of static vars */
342 ParseInit (Decl->Type);
344 /* If the previous size has been unknown, it must be known now */
346 Size = SizeOf (Decl->Type);
349 /* Mark the variable as referenced */
354 /* Uninitialized data, use BSS segment */
357 /* Define the variable label */
358 SymData = GetLocalLabel ();
359 g_defdatalabel (SymData);
361 /* Reserve space for the data */
366 /* Cannot allocate a variable of zero size */
368 Error ("Variable `%s' has unknown size", Decl->Ident);
371 /* Return the symbol data */
377 static void ParseOneDecl (const DeclSpec* Spec)
378 /* Parse one variable declaration */
380 unsigned SC; /* Storage class for symbol */
381 unsigned SymData = 0; /* Symbol data (offset, label name, ...) */
382 Declaration Decl; /* Declaration data structure */
385 /* Remember the storage class for the new symbol */
386 SC = Spec->StorageClass;
388 /* Read the declaration */
389 ParseDecl (Spec, &Decl, DM_NEED_IDENT);
391 /* Set the correct storage class for functions */
392 if (IsTypeFunc (Decl.Type)) {
393 /* Function prototypes are always external */
394 if ((SC & SC_EXTERN) == 0) {
395 Warning ("Function must be extern");
397 SC |= SC_FUNC | SC_EXTERN;
401 /* If we don't have a name, this was flagged as an error earlier.
402 * To avoid problems later, use an anonymous name here.
404 if (Decl.Ident[0] == '\0') {
405 AnonName (Decl.Ident, "param");
408 /* Handle anything that needs storage (no functions, no typdefs) */
409 if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) {
411 /* If we have a register variable, try to allocate a register and
412 * convert the declaration to "auto" if this is not possible.
414 int Reg = 0; /* Initialize to avoid gcc complains */
415 if ((SC & SC_REGISTER) != 0 && (Reg = F_AllocRegVar (CurrentFunc, Decl.Type)) < 0) {
416 /* No space for this register variable, convert to auto */
417 SC = (SC & ~SC_REGISTER) | SC_AUTO;
420 /* Check the variable type */
421 if ((SC & SC_REGISTER) == SC_REGISTER) {
422 /* Register variable */
423 SymData = ParseRegisterDecl (&Decl, &SC, Reg);
424 } else if ((SC & SC_AUTO) == SC_AUTO) {
426 SymData = ParseAutoDecl (&Decl, &SC);
427 } else if ((SC & SC_STATIC) == SC_STATIC) {
428 /* Static variable */
429 SymData = ParseStaticDecl (&Decl, &SC);
431 Internal ("Invalid storage class in ParseOneDecl: %04X", SC);
435 /* If the symbol is not marked as external, it will be defined now */
436 if ((SC & SC_EXTERN) == 0) {
440 /* Add the symbol to the symbol table */
441 AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
446 void DeclareLocals (void)
447 /* Declare local variables and types. */
449 /* Remember the current stack pointer */
450 int InitialStack = StackPtr;
452 /* Loop until we don't find any more variables */
455 /* Check variable declarations. We need to distinguish between a
456 * default int type and the end of variable declarations. So we
457 * will do the following: If there is no explicit storage class
458 * specifier *and* no explicit type given, *and* no type qualifiers
459 * have been read, it is assumed that we have reached the end of
463 ParseDeclSpec (&Spec, SC_AUTO, T_INT);
464 if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
465 (Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */
466 GetQualifier (Spec.Type) == T_QUAL_NONE) { /* No type qualifier */
470 /* Accept type only declarations */
471 if (CurTok.Tok == TOK_SEMI) {
472 /* Type declaration only */
473 CheckEmptyDecl (&Spec);
478 /* Parse a comma separated variable list */
481 /* Parse one declaration */
482 ParseOneDecl (&Spec);
484 /* Check if there is more */
485 if (CurTok.Tok == TOK_COMMA) {
494 /* A semicolon must follow */
498 /* Be sure to allocate any reserved space for locals */
499 F_AllocLocalSpace (CurrentFunc);
501 /* In case we've allocated local variables in this block, emit a call to
502 * the stack checking routine if stack checks are enabled.
504 if (IS_Get (&CheckStack) && InitialStack != StackPtr) {