]> git.sur5r.net Git - cc65/blob - src/cc65/locals.c
Added support for old style (K&R) function declarations.
[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     Ullrich von Bassewitz                                        */
10 /*              Wacholderweg 14                                              */
11 /*              D-70597 Stuttgart                                            */
12 /* EMail:       uz@musoftware.de                                             */
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 #include "anonname.h"
37 #include "asmlabel.h"
38 #include "codegen.h"
39 #include "declare.h"
40 #include "expr.h"
41 #include "function.h"
42 #include "global.h"
43 #include "mem.h"
44 #include "symtab.h"
45 #include "locals.h"
46
47
48
49 /*****************************************************************************/
50 /*                                   Data                                    */
51 /*****************************************************************************/
52
53
54
55 /* Register variable management */
56 unsigned MaxRegSpace            = 6;    /* Maximum space available */
57 static unsigned RegOffs         = 0;    /* Offset into register space */
58 static const SymEntry** RegSyms = 0;    /* The register variables */
59 static unsigned RegSymCount     = 0;    /* Number of register variables */
60
61
62
63 /*****************************************************************************/
64 /*                                   Code                                    */
65 /*****************************************************************************/
66
67
68
69 void InitRegVars (void)
70 /* Initialize register variable control data */
71 {
72     /* If the register space is zero, bail out */
73     if (MaxRegSpace == 0) {
74         return;
75     }
76
77     /* The maximum number of register variables is equal to the register
78      * variable space available. So allocate one pointer per byte. This
79      * will usually waste some space but we don't need to dynamically
80      * grow the array.
81      */
82     RegSyms = xmalloc (MaxRegSpace * sizeof (RegSyms[0]));
83     RegOffs = MaxRegSpace;
84 }
85
86
87
88 void DoneRegVars (void)
89 /* Free the register variables */
90 {
91     xfree (RegSyms);
92     RegSyms = 0;
93     RegOffs = MaxRegSpace;
94     RegSymCount = 0;
95 }
96
97
98
99 static int AllocRegVar (const SymEntry* Sym, const type* tarray)
100 /* Allocate a register variable with the given amount of storage. If the
101  * allocation was successful, return the offset of the register variable in
102  * the register bank (zero page storage). If there is no register space left,
103  * return -1.
104  */
105 {
106     /* Maybe register variables are disabled... */
107     if (EnableRegVars) {
108
109         /* Get the size of the variable */
110         unsigned Size = SizeOf (tarray);
111
112         /* Do we have space left? */
113         if (RegOffs >= Size) {
114
115             /* Space left. We allocate the variables from high to low addresses,
116              * so the adressing is compatible with the saved values on stack.
117              * This allows shorter code when saving/restoring the variables.
118              */
119             RegOffs -= Size;
120             RegSyms [RegSymCount++] = Sym;
121             return RegOffs;
122         }
123     }
124
125     /* No space left or no allocation */
126     return -1;
127 }
128
129
130
131 void DeclareLocals (void)
132 /* Declare local variables and types. */
133 {
134     int offs = oursp;           /* Current stack offset for variable */
135     int AutoSpace = 0;          /* Unallocated space on the stack */
136     int Size;                   /* Size of an auto variable */
137     int Reg;                    /* Register variable offset */
138     unsigned flags = 0;         /* Code generator flags */
139     int SymbolSC;               /* Storage class for symbol */
140     int ldata = 0;              /* Local symbol data temp storage */
141
142     /* Loop until we don't find any more variables */
143     while (1) {
144
145         /* Check variable declarations. We need to distinguish between a
146          * default int type and the end of variable declarations. So we
147          * will do the following: If there is no explicit storage class
148          * specifier *and* no explicit type given, it is assume that we
149          * have reached the end of declarations.
150          */
151         DeclSpec Spec;
152         ParseDeclSpec (&Spec, SC_AUTO, T_INT);
153         if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) {
154             break;
155         }
156
157         /* Accept type only declarations */
158         if (curtok == TOK_SEMI) {
159             /* Type declaration only */
160             CheckEmptyDecl (&Spec);
161             NextToken ();
162             continue;
163         }
164
165         /* Parse a comma separated variable list */
166         while (1) {
167
168             Declaration Decl;
169
170             /* Remember the storage class for the new symbol */
171             SymbolSC = Spec.StorageClass;
172
173             /* Read the declaration */
174             ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
175
176             /* If we don't have a name, this was flagged as an error earlier.
177              * To avoid problems later, use an anonymous name here.
178              */
179             if (Decl.Ident[0] == '\0') {
180                 AnonName (Decl.Ident, "param");
181             }
182
183             if (!IsFunc (Decl.Type) && (SymbolSC & SC_TYPEDEF) != SC_TYPEDEF) {
184
185                 /* Get the size of the variable */
186                 Size = SizeOf (Decl.Type);
187
188 #if 0
189                 /* Check the storage class */
190                 if ((SymbolSC & SC_REGISTER) && (Reg = AllocRegVar (psym, tarray)) >= 0) {
191
192                     /* We will store the current value of the register onto the
193                      * stack, thus making functions with register variables
194                      * reentrant. If we have pending auto variables, emit them
195                      * now.
196                      */
197                     g_usecode ();
198                     g_space (AutoSpace);
199                     oursp -= AutoSpace;
200                     AutoSpace = 0;
201
202                     /* Remember the register bank offset */
203                     ldata = Reg;
204
205                     /* Save the current register value onto the stack */
206                     g_save_regvars (Reg, Size);
207
208                     /* Allow variable initialization */
209                     if (curtok == TOK_ASSIGN) {
210
211                         struct expent lval;
212
213                         /* Skip the '=' */
214                         NextToken ();
215
216                         /* Get the expression into the primary */
217                         expression1 (&lval);
218
219                         /* Make type adjustments if needed */
220                         assignadjust (tarray, &lval);
221
222                         /* Setup the type flags for the assignment */
223                         flags = TypeOf (tarray) | CF_REGVAR;
224                         if (Size == 1) {
225                             flags |= CF_FORCECHAR;
226                         }
227
228                         /* Store the value into the register */
229                         g_putstatic (flags, Reg, 0);
230
231                         /* Mark the variable as referenced */
232                         SymbolSC |= SC_REF;
233
234                     }
235
236                     /* Account for the stack space needed and remember the
237                      * stack offset of the save area.
238                      */
239                     offs -= Size;
240                     psym->h_lattr = offs;
241
242                 } else if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
243 #endif
244                 if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
245
246                     /* Auto variable */
247                     if (LocalsAreStatic == 0) {
248
249                         /* Change SC in case it was register */
250                         SymbolSC = (SymbolSC & ~SC_REGISTER) | SC_AUTO;
251                         if (curtok == TOK_ASSIGN) {
252
253                             struct expent lval;
254
255                             /* Switch to the code segment, allocate space for
256                              * uninitialized variables.
257                              */
258                             g_usecode ();
259                             g_space (AutoSpace);
260                             oursp -= AutoSpace;
261                             AutoSpace = 0;
262
263                             /* Skip the '=' */
264                             NextToken ();
265
266                             /* Setup the type flags for the assignment */
267                             flags = Size == 1? CF_FORCECHAR : CF_NONE;
268
269                             /* Get the expression into the primary */
270                             if (evalexpr (flags, hie1, &lval) == 0) {
271                                 /* Constant expression. Adjust the types */
272                                 assignadjust (Decl.Type, &lval);
273                                 flags |= CF_CONST;
274                             } else {
275                                 /* Expression is not constant and in the primary */
276                                 assignadjust (Decl.Type, &lval);
277                             }
278
279                             /* Push the value */
280                             g_push (flags | TypeOf (Decl.Type), lval.e_const);
281
282                             /* Mark the variable as referenced */
283                             SymbolSC |= SC_REF;
284
285                         } else {
286                             /* Non-initialized local variable. Just keep track of
287                              * the space needed.
288                              */
289                             AutoSpace += Size;
290                         }
291
292                         /* Allocate space on the stack, assign the offset */
293                         offs -= Size;
294                         ldata = offs;
295
296                     } else {
297
298                         /* Static local variables. */
299                         SymbolSC = (SymbolSC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
300
301                         /* Put them into the BSS */
302                         g_usebss ();
303
304                         /* Define the variable label */
305                         g_defloclabel (ldata = GetLabel ());
306
307                         /* Reserve space for the data */
308                         g_res (Size);
309
310                         /* Allow assignments */
311                         if (curtok == TOK_ASSIGN) {
312
313                             struct expent lval;
314
315                             /* Switch to the code segment. */
316                             g_usecode ();
317
318                             /* Skip the '=' */
319                             NextToken ();
320
321                             /* Get the expression into the primary */
322                             expression1 (&lval);
323
324                             /* Make type adjustments if needed */
325                             assignadjust (Decl.Type, &lval);
326
327                             /* Setup the type flags for the assignment */
328                             flags = TypeOf (Decl.Type);
329                             if (Size == 1) {
330                                 flags |= CF_FORCECHAR;
331                             }
332
333                             /* Store the value into the variable */
334                             g_putstatic (flags, ldata, 0);
335
336                             /* Mark the variable as referenced */
337                             SymbolSC |= SC_REF;
338                         }
339                     }
340
341                 } else if ((SymbolSC & SC_STATIC) == SC_STATIC) {
342
343                     /* Static data */
344                     if (curtok == TOK_ASSIGN) {
345
346                         /* Initialization ahead, switch to data segment */
347                         g_usedata ();
348
349                         /* Define the variable label */
350                         g_defloclabel (ldata = GetLabel ());
351
352                         /* Skip the '=' */
353                         NextToken ();
354
355                         /* Allow initialization of static vars */
356                         ParseInit (Decl.Type);
357
358                         /* Mark the variable as referenced */
359                         SymbolSC |= SC_REF;
360
361                     } else {
362
363                         /* Uninitialized data, use BSS segment */
364                         g_usebss ();
365
366                         /* Define the variable label */
367                         g_defloclabel (ldata = GetLabel ());
368
369                         /* Reserve space for the data */
370                         g_res (Size);
371
372                     }
373                 }
374
375             }
376
377             /* If the symbol is not marked as external, it will be defined */
378             if ((SymbolSC & SC_EXTERN) == 0) {
379                 SymbolSC |= SC_DEF;
380             }
381
382             /* Add the symbol to the symbol table */
383             AddLocalSym (Decl.Ident, Decl.Type, SymbolSC, ldata);
384
385             if (curtok != TOK_COMMA) {
386                 break;
387             }
388             NextToken ();
389         }
390         if (curtok == TOK_SEMI) {
391             NextToken ();
392         }
393     }
394
395     /* In case we switched away from code segment, switch back now */
396     g_usecode ();
397
398     /* Create space for locals */
399     g_space (AutoSpace);
400     oursp -= AutoSpace;
401 }
402
403
404
405 void RestoreRegVars (int HaveResult)
406 /* Restore the register variables for the local function if there are any.
407  * The parameter tells us if there is a return value in ax, in that case,
408  * the accumulator must be saved across the restore.
409  */
410 {
411     unsigned I, J;
412     int Bytes, Offs;
413
414     /* If we don't have register variables in this function, bail out early */
415     if (RegSymCount == 0) {
416         return;
417     }
418
419     /* Save the accumulator if needed */
420     if (!HasVoidReturn (CurrentFunc) && HaveResult) {
421         g_save (CF_CHAR | CF_FORCECHAR);
422     }
423
424     /* Walk through all variables. If there are several variables in a row
425      * (that is, with increasing stack offset), restore them in one chunk.
426      */
427     I = 0;
428     while (I < RegSymCount) {
429
430         /* Check for more than one variable */
431         const SymEntry* Sym = RegSyms[I];
432         Offs  = Sym->V.Offs;
433         Bytes = SizeOf (Sym->Type);
434         J = I+1;
435
436         while (J < RegSymCount) {
437
438             /* Get the next symbol */
439             const SymEntry* NextSym = RegSyms [J];
440
441             /* Get the size */
442             int Size = SizeOf (NextSym->Type);
443
444             /* Adjacent variable? */
445             if (NextSym->V.Offs + Size != Offs) {
446                 /* No */
447                 break;
448             }
449
450             /* Adjacent variable */
451             Bytes += Size;
452             Offs  -= Size;
453             Sym   = NextSym;
454             ++J;
455         }
456
457         /* Restore the memory range */
458         g_restore_regvars (Offs, Sym->V.Offs, Bytes);
459
460         /* Next round */
461         I = J;
462     }
463
464     /* Restore the accumulator if needed */
465     if (!HasVoidReturn (CurrentFunc) && HaveResult) {
466         g_restore (CF_CHAR | CF_FORCECHAR);
467     }
468 }
469
470
471