]> git.sur5r.net Git - cc65/blob - src/cc65/locals.c
Fixed the address
[cc65] / src / cc65 / locals.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 locals.c                                  */
4 /*                                                                           */
5 /*              Local variable handling for the cc65 C compiler              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 /* common */
37 #include "xmalloc.h"
38 #include "xsprintf.h"
39
40 /* cc65 */
41 #include "anonname.h"
42 #include "asmlabel.h"
43 #include "codegen.h"
44 #include "declare.h"
45 #include "error.h"
46 #include "expr.h"
47 #include "function.h"
48 #include "global.h"
49 #include "symtab.h"
50 #include "locals.h"
51
52
53
54 /*****************************************************************************/
55 /*                                   Code                                    */
56 /*****************************************************************************/
57
58
59
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.
63  */
64 {
65     unsigned Flags;
66     unsigned InitLabel;
67
68     /* Determine if this is a compound variable */
69     int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
70
71     /* Get the size of the variable */
72     unsigned Size = SizeOf (Decl->Type);
73
74     /* Save the current contents of the register variable on stack */
75     F_AllocLocalSpace (CurrentFunc);
76     g_save_regvars (Reg, Size);
77
78     /* Check for an optional initialization */
79     if (CurTok.Tok == TOK_ASSIGN) {
80
81         ExprDesc lval;
82
83         /* Skip the '=' */
84         NextToken ();
85
86         /* Special handling for compound types */
87         if (IsCompound) {
88
89             /* Switch to read only data */
90             g_userodata ();
91
92             /* Define a label for the initialization data */
93             InitLabel = GetLocalLabel ();
94             g_defdatalabel (InitLabel);
95
96             /* Parse the initialization generating a memory image of the
97              * data in the RODATA segment.
98              */
99             ParseInit (Decl->Type);
100
101             /* Generate code to copy this data into the variable space */
102             g_initregister (InitLabel, Reg, Size);
103
104         } else {
105
106             /* Setup the type flags for the assignment */
107             Flags = CF_NONE;
108             if (Size == SIZEOF_CHAR) {
109                 Flags |= CF_FORCECHAR;
110             }
111
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);
116                 Flags |= CF_CONST;
117                 /* Load it into the primary */
118                 exprhs (Flags, 0, &lval);
119             } else {
120                 /* Expression is not constant and in the primary */
121                 assignadjust (Decl->Type, &lval);
122             }
123
124             /* Store the value into the variable */
125             Flags |= CF_REGVAR;
126             g_putstatic (Flags | TypeOf (Decl->Type), Reg, 0);
127
128         }
129
130         /* Mark the variable as referenced */
131         *SC |= SC_REF;
132     }
133
134     /* Cannot allocate a variable of zero size */
135     if (Size == 0) {
136         Error ("Variable `%s' has unknown size", Decl->Ident);
137     }
138
139     /* Return the symbol data */
140     return Reg;
141 }
142
143
144
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
148  * static variables.
149  */
150 {
151     unsigned Flags;
152     unsigned SymData;
153     unsigned InitLabel;
154
155     /* Determine if this is a compound variable */
156     int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
157
158     /* Get the size of the variable */
159     unsigned Size = SizeOf (Decl->Type);
160
161     /* Check if this is a variable on the stack or in static memory */
162     if (StaticLocals == 0) {
163
164         /* Check for an optional initialization */
165         if (CurTok.Tok == TOK_ASSIGN) {
166
167             ExprDesc lval;
168
169             /* Skip the '=' */
170             NextToken ();
171
172             /* Special handling for compound types */
173             if (IsCompound) {
174
175                 /* First reserve space for the variable */
176                 SymData = F_ReserveLocalSpace (CurrentFunc, Size);
177
178                 /* Next, allocate the space on the stack. This means that the
179                  * variable is now located at offset 0 from the current sp.
180                  */
181                 F_AllocLocalSpace (CurrentFunc);
182
183                 /* Switch to read only data */
184                 g_userodata ();
185
186                 /* Define a label for the initialization data */
187                 InitLabel = GetLocalLabel ();
188                 g_defdatalabel (InitLabel);
189
190                 /* Parse the initialization generating a memory image of the
191                  * data in the RODATA segment.
192                  */
193                 ParseInit (Decl->Type);
194
195                 /* Generate code to copy this data into the variable space */
196                 g_initauto (InitLabel, Size);
197
198             } else {
199
200                 /* Allocate previously reserved local space */
201                 F_AllocLocalSpace (CurrentFunc);
202
203                 /* Setup the type flags for the assignment */
204                 Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
205
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);
210                     Flags |= CF_CONST;
211                 } else {
212                     /* Expression is not constant and in the primary */
213                     assignadjust (Decl->Type, &lval);
214                 }
215
216                 /* Push the value */
217                 g_push (Flags | TypeOf (Decl->Type), lval.ConstVal);
218
219             }
220
221             /* Mark the variable as referenced */
222             *SC |= SC_REF;
223
224             /* Variable is located at the current SP */
225             SymData = oursp;
226
227         } else {
228             /* Non-initialized local variable. Just keep track of
229              * the space needed.
230              */
231             SymData = F_ReserveLocalSpace (CurrentFunc, Size);
232         }
233
234     } else {
235
236         /* Static local variables. */
237         *SC = (*SC & ~SC_AUTO) | SC_STATIC;
238
239         /* Put them into the BSS */
240         g_usebss ();
241
242         /* Define the variable label */
243         SymData = GetLocalLabel ();
244         g_defdatalabel (SymData);
245
246         /* Reserve space for the data */
247         g_res (Size);
248
249         /* Allow assignments */
250         if (CurTok.Tok == TOK_ASSIGN) {
251
252             ExprDesc lval;
253
254             /* Skip the '=' */
255             NextToken ();
256
257             if (IsCompound) {
258
259                 /* Switch to read only data */
260                 g_userodata ();
261
262                 /* Define a label for the initialization data */
263                 InitLabel = GetLocalLabel ();
264                 g_defdatalabel (InitLabel);
265
266                 /* Parse the initialization generating a memory image of the
267                  * data in the RODATA segment.
268                  */
269                 ParseInit (Decl->Type);
270
271                 /* Generate code to copy this data into the variable space */
272                 g_initstatic (InitLabel, SymData, Size);
273
274             } else {
275
276                 /* Setup the type flags for the assignment */
277                 Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
278
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);
283                     Flags |= CF_CONST;
284                     /* Load it into the primary */
285                     exprhs (Flags, 0, &lval);
286                 } else {
287                     /* Expression is not constant and in the primary */
288                     assignadjust (Decl->Type, &lval);
289                 }
290
291                 /* Store the value into the variable */
292                 g_putstatic (Flags | TypeOf (Decl->Type), SymData, 0);
293
294             }
295
296             /* Mark the variable as referenced */
297             *SC |= SC_REF;
298         }
299     }
300
301     /* Cannot allocate a variable of zero size */
302     if (Size == 0) {
303         Error ("Variable `%s' has unknown size", Decl->Ident);
304     }
305
306     /* Return the symbol data */
307     return SymData;
308 }
309
310
311
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.
315  */
316 {
317     unsigned SymData;
318
319     /* Get the size of the variable */
320     unsigned Size = SizeOf (Decl->Type);
321
322     /* Static data */
323     if (CurTok.Tok == TOK_ASSIGN) {
324
325         /* Initialization ahead, switch to data segment */
326         if (IsQualConst (Decl->Type)) {
327             g_userodata ();
328         } else {
329             g_usedata ();
330         }
331
332         /* Define the variable label */
333         SymData = GetLocalLabel ();
334         g_defdatalabel (SymData);
335
336         /* Skip the '=' */
337         NextToken ();
338
339         /* Allow initialization of static vars */
340         ParseInit (Decl->Type);
341
342         /* If the previous size has been unknown, it must be known now */
343         if (Size == 0) {
344             Size = SizeOf (Decl->Type);
345         }
346
347         /* Mark the variable as referenced */
348         *SC |= SC_REF;
349
350     } else {
351
352         /* Uninitialized data, use BSS segment */
353         g_usebss ();
354
355         /* Define the variable label */
356         SymData = GetLocalLabel ();
357         g_defdatalabel (SymData);
358
359         /* Reserve space for the data */
360         g_res (Size);
361
362     }
363
364     /* Cannot allocate a variable of zero size */
365     if (Size == 0) {
366         Error ("Variable `%s' has unknown size", Decl->Ident);
367     }
368
369     /* Return the symbol data */
370     return SymData;
371 }
372
373
374
375 static void ParseOneDecl (const DeclSpec* Spec)
376 /* Parse one variable declaration */
377 {
378     unsigned    SC;             /* Storage class for symbol */
379     unsigned    SymData = 0;    /* Symbol data (offset, label name, ...) */
380     Declaration Decl;           /* Declaration data structure */
381
382
383     /* Remember the storage class for the new symbol */
384     SC = Spec->StorageClass;
385
386     /* Read the declaration */
387     ParseDecl (Spec, &Decl, DM_NEED_IDENT);
388
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");
394         }
395         SC |= SC_FUNC | SC_EXTERN;
396
397     }
398
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.
401      */
402     if (Decl.Ident[0] == '\0') {
403         AnonName (Decl.Ident, "param");
404     }
405
406     /* Handle anything that needs storage (no functions, no typdefs) */
407     if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) {
408
409         /* If we have a register variable, try to allocate a register and
410          * convert the declaration to "auto" if this is not possible.
411          */
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;
416         }
417
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) {
423             /* Auto variable */
424             SymData = ParseAutoDecl (&Decl, &SC);
425         } else if ((SC & SC_STATIC) == SC_STATIC) {
426             /* Static variable */
427             SymData = ParseStaticDecl (&Decl, &SC);
428         } else {
429             Internal ("Invalid storage class in ParseOneDecl: %04X", SC);
430         }
431     }
432
433     /* If the symbol is not marked as external, it will be defined now */
434     if ((SC & SC_EXTERN) == 0) {
435         SC |= SC_DEF;
436     }
437
438     /* Add the symbol to the symbol table */
439     AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
440 }
441
442
443
444 void DeclareLocals (void)
445 /* Declare local variables and types. */
446 {
447     /* Remember the current stack pointer */
448     int InitialStack = oursp;
449
450     /* Loop until we don't find any more variables */
451     while (1) {
452
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
458          * declarations.
459          */
460         DeclSpec Spec;
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 */
465             break;
466         }
467
468         /* Accept type only declarations */
469         if (CurTok.Tok == TOK_SEMI) {
470             /* Type declaration only */
471             CheckEmptyDecl (&Spec);
472             NextToken ();
473             continue;
474         }
475
476         /* Parse a comma separated variable list */
477         while (1) {
478
479             /* Parse one declaration */
480             ParseOneDecl (&Spec);
481
482             /* Check if there is more */
483             if (CurTok.Tok == TOK_COMMA) {
484                 /* More to come */
485                 NextToken ();
486             } else {
487                 /* Done */
488                 break;
489             }
490         }
491
492         /* A semicolon must follow */
493         ConsumeSemi ();
494     }
495
496     /* Be sure to allocate any reserved space for locals */
497     F_AllocLocalSpace (CurrentFunc);
498
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.
501      */
502     if (CheckStack && InitialStack != oursp) {
503         g_cstackcheck ();
504     }
505 }
506
507
508