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