]> git.sur5r.net Git - cc65/blob - src/ca65/condasm.c
Removed an unused assignment
[cc65] / src / ca65 / condasm.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 condasm.c                                 */
4 /*                                                                           */
5 /*                   Conditional assembly support for ca65                   */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstraße 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 /* ca65 */
37 #include "error.h"
38 #include "expr.h"
39 #include "instr.h"
40 #include "nexttok.h"
41 #include "symbol.h"
42 #include "symtab.h"
43 #include "condasm.h"
44
45
46
47 /*****************************************************************************/
48 /*                                   Data                                    */
49 /*****************************************************************************/
50
51
52
53 /* Maximum count of nested .ifs */
54 #define MAX_IFS         256
55
56 /* Set of bitmapped flags for the if descriptor */
57 enum {
58     ifNone      = 0x0000,               /* No flag */
59     ifCond      = 0x0001,               /* IF condition was true */
60     ifElse      = 0x0002,               /* We had a .ELSE branch */
61     ifNeedTerm  = 0x0004                /* Need .ENDIF termination */
62 };
63
64
65
66 /*****************************************************************************/
67 /*                               struct IfDesc                               */
68 /*****************************************************************************/
69
70
71
72 /* One .IF descriptor */
73 typedef struct IfDesc IfDesc;
74 struct IfDesc {
75     unsigned    Flags;          /* Bitmapped flags, see above */
76     FilePos     Pos;            /* File position of the .IF */
77     const char* Name;           /* Name of the directive */
78 };
79
80 /* The .IF stack */
81 static IfDesc IfStack [MAX_IFS];
82 static unsigned IfCount = 0;
83
84
85
86 static IfDesc* AllocIf (const char* Directive, int NeedTerm)
87 /* Alloc a new element from the .IF stack */
88 {
89     IfDesc* ID;
90
91     /* Check for stack overflow */
92     if (IfCount >= MAX_IFS) {
93         Fatal ("Too many nested .IFs");
94     }
95
96     /* Alloc one element */
97     ID = &IfStack [IfCount++];
98
99     /* Initialize elements */
100     ID->Flags = NeedTerm? ifNeedTerm : ifNone;
101     ID->Pos   = CurPos;
102     ID->Name  = Directive;
103
104     /* Return the result */
105     return ID;
106 }
107
108
109
110 static IfDesc* GetCurrentIf (void)
111 /* Return the current .IF descriptor */
112 {
113     if (IfCount == 0) {
114         return 0;
115     } else {
116         return &IfStack [IfCount-1];
117     }
118 }
119
120
121
122 static void FreeIf (void)
123 /* Free all .IF descriptors until we reach one with the NeedTerm bit set */
124 {
125     int Done;
126     do {
127         IfDesc* D = GetCurrentIf();
128         if (D == 0) {
129             Error (" Unexpected .ENDIF");
130             Done = 1;
131         } else {
132             Done = (D->Flags & ifNeedTerm) != 0;
133             --IfCount;
134         }
135     } while (!Done);
136 }
137
138
139
140 static int GetCurrentIfCond (void)
141 /* Return the current condition based on all conditions on the stack */
142 {
143     unsigned Count;
144     for (Count = 0; Count < IfCount; ++Count) {
145         if ((IfStack[Count].Flags & ifCond) == 0) {
146             return 0;
147         }
148     }
149     return 1;
150 }
151
152
153
154 static void SetIfCond (IfDesc* ID, int C)
155 /* Set the .IF condition */
156 {
157     if (C) {
158         ID->Flags |= ifCond;
159     } else {
160         ID->Flags &= ~ifCond;
161     }
162 }
163
164
165
166 static void InvertIfCond (IfDesc* ID)
167 /* Invert the current condition */
168 {
169     ID->Flags ^= ifCond;
170 }
171
172
173
174 static int GetElse (const IfDesc* ID)
175 /* Return true if we had a .ELSE */
176 {
177     return (ID->Flags & ifElse) != 0;
178 }
179
180
181
182 static void SetElse (IfDesc* ID, int E)
183 /* Set the .ELSE flag */
184 {
185     if (E) {
186         ID->Flags |= ifElse;
187     } else {
188         ID->Flags &= ~ifElse;
189     }
190 }
191
192
193
194 /*****************************************************************************/
195 /*                                   Code                                    */
196 /*****************************************************************************/
197
198
199
200 void DoConditionals (void)
201 /* Catch all for conditional directives */
202 {
203     IfDesc* D;
204
205     int IfCond = GetCurrentIfCond ();
206     do {
207
208         switch (Tok) {
209
210             case TOK_ELSE:
211                 D = GetCurrentIf ();
212                 if (D == 0) {
213                     Error ("Unexpected .ELSE");
214                 } else if (GetElse(D)) {
215                     /* We already had a .ELSE ! */
216                     Error ("Duplicate .ELSE");
217                 } else {
218                     /* Allow an .ELSE */
219                     InvertIfCond (D);
220                     SetElse (D, 1);
221                     D->Pos = CurPos;
222                     D->Name = ".ELSE";
223                     IfCond = GetCurrentIfCond ();
224                 }
225                 NextTok ();
226                 break;
227
228             case TOK_ELSEIF:
229                 D = GetCurrentIf ();
230                 if (D == 0) {
231                     Error ("Unexpected .ELSEIF");
232                 } else if (GetElse(D)) {
233                     /* We already had a .ELSE */
234                     Error ("Duplicate .ELSE");
235                 } else {
236                     /* Handle as if there was an .ELSE first */
237                     InvertIfCond (D);
238                     SetElse (D, 1);
239
240                     /* Allocate and prepare a new descriptor */
241                     D = AllocIf (".ELSEIF", 0);
242                     NextTok ();
243
244                     /* Ignore the new condition if we are inside a false .ELSE
245                      * branch. This way we won't get any errors about undefined
246                      * symbols or similar...
247                      */
248                     if (IfCond == 0) {
249                         SetIfCond (D, ConstExpression ());
250                     }
251
252                     /* Get the new overall condition */
253                     IfCond = GetCurrentIfCond ();
254                 }
255                 break;
256
257             case TOK_ENDIF:
258                 /* We're done with this .IF.. - remove the descriptor(s) */
259                 FreeIf ();
260
261                 /* Be sure not to read the next token until the .IF stack
262                  * has been cleanup up, since we may be at end of file.
263                  */
264                 NextTok ();
265
266                 /* Get the new overall condition */
267                 IfCond = GetCurrentIfCond ();
268                 break;
269
270             case TOK_IF:
271                 D = AllocIf (".IF", 1);
272                 NextTok ();
273                 if (IfCond) {
274                     SetIfCond (D, ConstExpression ());
275                 }
276                 IfCond = GetCurrentIfCond ();
277                 break;
278
279             case TOK_IFBLANK:
280                 D = AllocIf (".IFBLANK", 1);
281                 NextTok ();
282                 if (IfCond) {
283                     if (TokIsSep (Tok)) {
284                         SetIfCond (D, 1);
285                     } else {
286                         SetIfCond (D, 0);
287                         SkipUntilSep ();
288                     }
289                 }
290                 IfCond = GetCurrentIfCond ();
291                 break;
292
293             case TOK_IFCONST:
294                 D = AllocIf (".IFCONST", 1);
295                 NextTok ();
296                 if (IfCond) {
297                     ExprNode* Expr = Expression();
298                     SetIfCond (D, IsConstExpr (Expr, 0));
299                     FreeExpr (Expr);
300                 }
301                 IfCond = GetCurrentIfCond ();
302                 break;
303
304             case TOK_IFDEF:
305                 D = AllocIf (".IFDEF", 1);
306                 NextTok ();
307                 if (IfCond) {
308                     SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
309                     SetIfCond (D, Sym != 0 && SymIsDef (Sym));
310                 }
311                 IfCond = GetCurrentIfCond ();
312                 break;
313
314             case TOK_IFNBLANK:
315                 D = AllocIf (".IFNBLANK", 1);
316                 NextTok ();
317                 if (IfCond) {
318                     if (TokIsSep (Tok)) {
319                         SetIfCond (D, 0);
320                     } else {
321                         SetIfCond (D, 1);
322                         SkipUntilSep ();
323                     }
324                 }
325                 IfCond = GetCurrentIfCond ();
326                 break;
327
328             case TOK_IFNCONST:
329                 D = AllocIf (".IFNCONST", 1);
330                 NextTok ();
331                 if (IfCond) {
332                     ExprNode* Expr = Expression();
333                     SetIfCond (D, !IsConstExpr (Expr, 0));
334                     FreeExpr (Expr);
335                 }
336                 IfCond = GetCurrentIfCond ();
337                 break;
338
339             case TOK_IFNDEF:
340                 D = AllocIf (".IFNDEF", 1);
341                 NextTok ();
342                 if (IfCond) {
343                     SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
344                     SetIfCond (D, Sym == 0 || !SymIsDef (Sym));
345                 }
346                 IfCond = GetCurrentIfCond ();
347                 break;
348
349             case TOK_IFNREF:
350                 D = AllocIf (".IFNREF", 1);
351                 NextTok ();
352                 if (IfCond) {
353                     SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
354                     SetIfCond (D, Sym == 0 || !SymIsRef (Sym));
355                 }
356                 IfCond = GetCurrentIfCond ();
357                 break;
358
359             case TOK_IFP02:
360                 D = AllocIf (".IFP02", 1);
361                 NextTok ();
362                 if (IfCond) {
363                     SetIfCond (D, GetCPU() == CPU_6502);
364                 }
365                 IfCond = GetCurrentIfCond ();
366                 break;
367
368             case TOK_IFP816:
369                 D = AllocIf (".IFP816", 1);
370                 NextTok ();
371                 if (IfCond) {
372                     SetIfCond (D, GetCPU() == CPU_65816);
373                 }
374                 IfCond = GetCurrentIfCond ();
375                 break;
376
377             case TOK_IFPC02:
378                 D = AllocIf (".IFPC02", 1);
379                 NextTok ();
380                 if (IfCond) {
381                     SetIfCond (D, GetCPU() == CPU_65C02);
382                 }
383                 IfCond = GetCurrentIfCond ();
384                 break;
385
386             case TOK_IFPSC02:
387                 D = AllocIf (".IFPSC02", 1);
388                 NextTok ();
389                 if (IfCond) {
390                     SetIfCond (D, GetCPU() == CPU_65SC02);
391                 }
392                 IfCond = GetCurrentIfCond ();
393                 break;
394
395             case TOK_IFREF:
396                 D = AllocIf (".IFREF", 1);
397                 NextTok ();
398                 if (IfCond) {
399                     SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
400                     SetIfCond (D, Sym != 0 && SymIsRef (Sym));
401                 }
402                 IfCond = GetCurrentIfCond ();
403                 break;
404
405             default:
406                 /* Skip tokens */
407                 NextTok ();
408
409         }
410
411     } while (IfCond == 0 && Tok != TOK_EOF);
412 }
413
414
415
416 int CheckConditionals (void)
417 /* Check if the current token is one that starts a conditional directive, and
418  * call DoConditionals if so. Return true if a conditional directive was found,
419  * return false otherwise.
420  */
421 {
422     switch (Tok) {
423         case TOK_ELSE:
424         case TOK_ELSEIF:
425         case TOK_ENDIF:
426         case TOK_IF:
427         case TOK_IFBLANK:
428         case TOK_IFCONST:
429         case TOK_IFDEF:
430         case TOK_IFNBLANK:
431         case TOK_IFNCONST:
432         case TOK_IFNDEF:
433         case TOK_IFNREF:
434         case TOK_IFP02:
435         case TOK_IFP816:
436         case TOK_IFPC02:
437         case TOK_IFPSC02:
438         case TOK_IFREF:
439             DoConditionals ();
440             return 1;
441
442         default:
443             return 0;
444     }
445 }
446
447
448
449 void CheckOpenIfs (void)
450 /* Called from the scanner before closing an input file. Will check for any
451  * open .ifs in this file.
452  */
453 {
454     while (1) {
455         /* Get the current file number and check if the topmost entry on the
456          * .IF stack was inserted with this file number
457          */
458         IfDesc* D = GetCurrentIf ();
459         if (D == 0) {
460             /* There are no open .IFs */
461             break;
462         }
463
464         if (D->Pos.Name != CurPos.Name) {
465             /* The .if is from another file, bail out */
466             break;
467         }
468
469         /* Start of .if is in the file we're about to leave */
470         PError (&D->Pos, "Conditional assembly branch was never closed");
471         FreeIf ();
472     }
473 }
474
475
476
477 unsigned GetIfStack (void)
478 /* Get the current .IF stack pointer */
479 {
480     return IfCount;
481 }
482
483
484
485 void CleanupIfStack (unsigned SP)
486 /* Cleanup the .IF stack, remove anything above the given stack pointer */
487 {
488     while (IfCount > SP) {
489         FreeIf ();
490     }
491 }
492
493
494