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 /*****************************************************************************/
54 /*****************************************************************************/
56 /*****************************************************************************/
60 static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
61 /* Parse the declaration of a register variable. The function returns the
62 * 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.
99 ParseInit (Decl->Type);
101 /* Generate code to copy this data into the variable space */
102 g_initregister (InitLabel, Reg, Size);
106 /* Setup the type flags for the assignment */
108 if (Size == SIZEOF_CHAR) {
109 Flags |= CF_FORCECHAR;
112 /* Get the expression into the primary */
113 if (evalexpr (Flags, hie1, &lval) == 0) {
114 /* Constant expression. Adjust the types */
115 assignadjust (Decl->Type, &lval);
117 /* Load it into the primary */
118 exprhs (Flags, 0, &lval);
120 /* Expression is not constant and in the primary */
121 assignadjust (Decl->Type, &lval);
124 /* Store the value into the variable */
126 g_putstatic (Flags | TypeOf (Decl->Type), Reg, 0);
130 /* Mark the variable as referenced */
134 /* Cannot allocate a variable of zero size */
136 Error ("Variable `%s' has unknown size", Decl->Ident);
139 /* Return the symbol data */
145 static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
146 /* Parse the declaration of an auto variable. The function returns the symbol
147 * data, which is the offset for variables on the stack, and the label for
155 /* Determine if this is a compound variable */
156 int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
158 /* Get the size of the variable */
159 unsigned Size = SizeOf (Decl->Type);
161 /* Check if this is a variable on the stack or in static memory */
162 if (StaticLocals == 0) {
164 /* Check for an optional initialization */
165 if (CurTok.Tok == TOK_ASSIGN) {
172 /* Special handling for compound types */
175 /* First reserve space for the variable */
176 SymData = F_ReserveLocalSpace (CurrentFunc, Size);
178 /* Next, allocate the space on the stack. This means that the
179 * variable is now located at offset 0 from the current sp.
181 F_AllocLocalSpace (CurrentFunc);
183 /* Switch to read only data */
186 /* Define a label for the initialization data */
187 InitLabel = GetLocalLabel ();
188 g_defdatalabel (InitLabel);
190 /* Parse the initialization generating a memory image of the
191 * data in the RODATA segment.
193 ParseInit (Decl->Type);
195 /* Generate code to copy this data into the variable space */
196 g_initauto (InitLabel, Size);
200 /* Allocate previously reserved local space */
201 F_AllocLocalSpace (CurrentFunc);
203 /* Setup the type flags for the assignment */
204 Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
206 /* Get the expression into the primary */
207 if (evalexpr (Flags, hie1, &lval) == 0) {
208 /* Constant expression. Adjust the types */
209 assignadjust (Decl->Type, &lval);
212 /* Expression is not constant and in the primary */
213 assignadjust (Decl->Type, &lval);
217 g_push (Flags | TypeOf (Decl->Type), lval.ConstVal);
221 /* Mark the variable as referenced */
224 /* Variable is located at the current SP */
228 /* Non-initialized local variable. Just keep track of
231 SymData = F_ReserveLocalSpace (CurrentFunc, Size);
236 /* Static local variables. */
237 *SC = (*SC & ~SC_AUTO) | SC_STATIC;
239 /* Put them into the BSS */
242 /* Define the variable label */
243 SymData = GetLocalLabel ();
244 g_defdatalabel (SymData);
246 /* Reserve space for the data */
249 /* Allow assignments */
250 if (CurTok.Tok == TOK_ASSIGN) {
259 /* Switch to read only data */
262 /* Define a label for the initialization data */
263 InitLabel = GetLocalLabel ();
264 g_defdatalabel (InitLabel);
266 /* Parse the initialization generating a memory image of the
267 * data in the RODATA segment.
269 ParseInit (Decl->Type);
271 /* Generate code to copy this data into the variable space */
272 g_initstatic (InitLabel, SymData, Size);
276 /* Setup the type flags for the assignment */
277 Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
279 /* Get the expression into the primary */
280 if (evalexpr (Flags, hie1, &lval) == 0) {
281 /* Constant expression. Adjust the types */
282 assignadjust (Decl->Type, &lval);
284 /* Load it into the primary */
285 exprhs (Flags, 0, &lval);
287 /* Expression is not constant and in the primary */
288 assignadjust (Decl->Type, &lval);
291 /* Store the value into the variable */
292 g_putstatic (Flags | TypeOf (Decl->Type), SymData, 0);
296 /* Mark the variable as referenced */
301 /* Cannot allocate a variable of zero size */
303 Error ("Variable `%s' has unknown size", Decl->Ident);
306 /* Return the symbol data */
312 static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC)
313 /* Parse the declaration of a static variable. The function returns the symbol
314 * data, which is the asm label of the variable.
319 /* Get the size of the variable */
320 unsigned Size = SizeOf (Decl->Type);
323 if (CurTok.Tok == TOK_ASSIGN) {
325 /* Initialization ahead, switch to data segment */
326 if (IsQualConst (Decl->Type)) {
332 /* Define the variable label */
333 SymData = GetLocalLabel ();
334 g_defdatalabel (SymData);
339 /* Allow initialization of static vars */
340 ParseInit (Decl->Type);
342 /* If the previous size has been unknown, it must be known now */
344 Size = SizeOf (Decl->Type);
347 /* Mark the variable as referenced */
352 /* Uninitialized data, use BSS segment */
355 /* Define the variable label */
356 SymData = GetLocalLabel ();
357 g_defdatalabel (SymData);
359 /* Reserve space for the data */
364 /* Cannot allocate a variable of zero size */
366 Error ("Variable `%s' has unknown size", Decl->Ident);
369 /* Return the symbol data */
375 static void ParseOneDecl (const DeclSpec* Spec)
376 /* Parse one variable declaration */
378 unsigned SC; /* Storage class for symbol */
379 unsigned SymData = 0; /* Symbol data (offset, label name, ...) */
380 Declaration Decl; /* Declaration data structure */
383 /* Remember the storage class for the new symbol */
384 SC = Spec->StorageClass;
386 /* Read the declaration */
387 ParseDecl (Spec, &Decl, DM_NEED_IDENT);
389 /* Set the correct storage class for functions */
390 if (IsTypeFunc (Decl.Type)) {
391 /* Function prototypes are always external */
392 if ((SC & SC_EXTERN) == 0) {
393 Warning ("Function must be extern");
395 SC |= SC_FUNC | SC_EXTERN;
399 /* If we don't have a name, this was flagged as an error earlier.
400 * To avoid problems later, use an anonymous name here.
402 if (Decl.Ident[0] == '\0') {
403 AnonName (Decl.Ident, "param");
406 /* Handle anything that needs storage (no functions, no typdefs) */
407 if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) {
409 /* If we have a register variable, try to allocate a register and
410 * convert the declaration to "auto" if this is not possible.
412 int Reg = 0; /* Initialize to avoid gcc complains */
413 if ((SC & SC_REGISTER) != 0 && (Reg = F_AllocRegVar (CurrentFunc, Decl.Type)) < 0) {
414 /* No space for this register variable, convert to auto */
415 SC = (SC & ~SC_REGISTER) | SC_AUTO;
418 /* Check the variable type */
419 if ((SC & SC_REGISTER) == SC_REGISTER) {
420 /* Register variable */
421 SymData = ParseRegisterDecl (&Decl, &SC, Reg);
422 } else if ((SC & SC_AUTO) == SC_AUTO) {
424 SymData = ParseAutoDecl (&Decl, &SC);
425 } else if ((SC & SC_STATIC) == SC_STATIC) {
426 /* Static variable */
427 SymData = ParseStaticDecl (&Decl, &SC);
429 Internal ("Invalid storage class in ParseOneDecl: %04X", SC);
433 /* If the symbol is not marked as external, it will be defined now */
434 if ((SC & SC_EXTERN) == 0) {
438 /* Add the symbol to the symbol table */
439 AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
444 void DeclareLocals (void)
445 /* Declare local variables and types. */
447 /* Remember the current stack pointer */
448 int InitialStack = oursp;
450 /* Loop until we don't find any more variables */
453 /* Check variable declarations. We need to distinguish between a
454 * default int type and the end of variable declarations. So we
455 * will do the following: If there is no explicit storage class
456 * specifier *and* no explicit type given, *and* no type qualifiers
457 * have been read, it is assumed that we have reached the end of
461 ParseDeclSpec (&Spec, SC_AUTO, T_INT);
462 if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
463 (Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */
464 GetQualifier (Spec.Type) == T_QUAL_NONE) { /* No type qualifier */
468 /* Accept type only declarations */
469 if (CurTok.Tok == TOK_SEMI) {
470 /* Type declaration only */
471 CheckEmptyDecl (&Spec);
476 /* Parse a comma separated variable list */
479 /* Parse one declaration */
480 ParseOneDecl (&Spec);
482 /* Check if there is more */
483 if (CurTok.Tok == TOK_COMMA) {
492 /* A semicolon must follow */
496 /* Be sure to allocate any reserved space for locals */
497 F_AllocLocalSpace (CurrentFunc);
499 /* In case we've allocated local variables in this block, emit a call to
500 * the stack checking routine if stack checks are enabled.
502 if (CheckStack && InitialStack != oursp) {