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