]> git.sur5r.net Git - cc65/blob - src/ca65/condasm.c
This commit was generated by cvs2svn to compensate for changes in r2,
[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 "scanner.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         32
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         } else {
128             Done = (D->Flags & ifNeedTerm) != 0;
129             --IfCount;
130         }
131     } while (!Done);
132 }
133
134
135
136 static int GetCurrentIfCond (void)
137 /* Return the current condition based on all conditions on the stack */
138 {
139     unsigned Count;
140     for (Count = 0; Count < IfCount; ++Count) {
141         if ((IfStack[Count].Flags & ifCond) == 0) {
142             return 0;
143         }
144     }
145     return 1;
146 }
147
148
149
150 static void SetIfCond (IfDesc* ID, int C)
151 /* Set the .IF condition */
152 {
153     if (C) {
154         ID->Flags |= ifCond;
155     } else {
156         ID->Flags &= ~ifCond;
157     }
158 }
159
160
161
162 static void InvertIfCond (IfDesc* ID)
163 /* Invert the current condition */
164 {
165     ID->Flags ^= ifCond;
166 }
167
168
169
170 static int GetElse (const IfDesc* ID)
171 /* Return true if we had a .ELSE */
172 {
173     return (ID->Flags & ifElse) != 0;
174 }
175
176
177
178 static void SetElse (IfDesc* ID, int E)
179 /* Set the .ELSE flag */
180 {
181     if (E) {
182         ID->Flags |= ifElse;
183     } else {
184         ID->Flags &= ~ifElse;
185     }
186 }
187
188
189
190 /*****************************************************************************/
191 /*                                   Code                                    */
192 /*****************************************************************************/
193
194
195
196 void DoConditionals (void)
197 /* Catch all for conditional directives */
198 {
199     IfDesc* D;
200
201     int IfCond = GetCurrentIfCond ();
202     do {
203
204         switch (Tok) {
205
206             case TOK_ELSE:
207                 D = GetCurrentIf ();
208                 if (D == 0) {
209                     Error (ERR_UNEXPECTED, ".ELSE");
210                 } else if (GetElse(D)) {
211                     /* We already had a .ELSE ! */
212                     Error (ERR_DUPLICATE_ELSE);
213                 } else {
214                     /* Allow an .ELSE */
215                     InvertIfCond (D);
216                     SetElse (D, 1);
217                     D->Pos = CurPos;
218                     D->Name = ".ELSE";
219                     IfCond = GetCurrentIfCond ();
220                 }
221                 NextTok ();
222                 break;
223
224             case TOK_ELSEIF:
225                 D = GetCurrentIf ();
226                 if (D == 0) {
227                     Error (ERR_UNEXPECTED, ".ELSEIF");
228                 } else if (GetElse(D)) {
229                     /* We already had a .ELSE */
230                     Error (ERR_DUPLICATE_ELSE);
231                 } else {
232                     /* Handle as if there was an .ELSE first */
233                     InvertIfCond (D);
234                     SetElse (D, 1);
235
236                     /* Allocate and prepare a new descriptor */
237                     D = AllocIf (".ELSEIF", 0);
238                     NextTok ();
239
240                     /* Ignore the new condition if we are inside a false .ELSE
241                      * branch. This way we won't get any errors about undefined
242                      * symbols or similar...
243                      */
244                     if (IfCond == 0) {
245                         SetIfCond (D, ConstExpression ());
246                     }
247
248                     /* Get the new overall condition */
249                     IfCond = GetCurrentIfCond ();
250                 }
251                 break;
252
253             case TOK_ENDIF:
254                 /* We're done with this .IF.. - remove the descriptor(s) */
255                 FreeIf ();
256
257                 /* Be sure not to read the next token until the .IF stack
258                  * has been cleanup up, since we may be at end of file.
259                  */
260                 NextTok ();
261
262                 /* Get the new overall condition */
263                 IfCond = GetCurrentIfCond ();
264                 break;
265
266             case TOK_IF:
267                 D = AllocIf (".IF", 1);
268                 NextTok ();
269                 if (IfCond) {
270                     SetIfCond (D, ConstExpression ());
271                 }
272                 IfCond = GetCurrentIfCond ();
273                 break;
274
275             case TOK_IFBLANK:
276                 D = AllocIf (".IFBLANK", 1);
277                 NextTok ();
278                 if (IfCond) {
279                     SetIfCond (D, Tok == TOK_SEP);
280                 }
281                 IfCond = GetCurrentIfCond ();
282                 break;
283
284             case TOK_IFCONST:
285                 D = AllocIf (".IFCONST", 1);
286                 NextTok ();
287                 if (IfCond) {
288                     ExprNode* Expr = Expression();
289                     SetIfCond (D, IsConstExpr (Expr));
290                     FreeExpr (Expr);
291                 }
292                 IfCond = GetCurrentIfCond ();
293                 break;
294
295             case TOK_IFDEF:
296                 D = AllocIf (".IFDEF", 1);
297                 NextTok ();
298                 if (IfCond) {
299                     if (Tok != TOK_IDENT) {
300                         ErrorSkip (ERR_IDENT_EXPECTED);
301                     } else {
302                         SetIfCond (D, SymIsDef (SVal));
303                         NextTok ();
304                     }
305                 }
306                 IfCond = GetCurrentIfCond ();
307                 break;
308
309             case TOK_IFNBLANK:
310                 D = AllocIf (".IFNBLANK", 1);
311                 NextTok ();
312                 if (IfCond) {
313                     SetIfCond (D, Tok != TOK_SEP);
314                 }
315                 IfCond = GetCurrentIfCond ();
316                 break;
317
318             case TOK_IFNCONST:
319                 D = AllocIf (".IFNCONST", 1);
320                 NextTok ();
321                 if (IfCond) {
322                     ExprNode* Expr = Expression();
323                     SetIfCond (D, !IsConstExpr (Expr));
324                     FreeExpr (Expr);
325                 }
326                 IfCond = GetCurrentIfCond ();
327                 break;
328
329             case TOK_IFNDEF:
330                 D = AllocIf (".IFNDEF", 1);
331                 NextTok ();
332                 if (IfCond) {
333                     if (Tok != TOK_IDENT) {
334                         ErrorSkip (ERR_IDENT_EXPECTED);
335                     } else {
336                         SetIfCond (D, !SymIsDef (SVal));
337                         NextTok ();
338                     }
339                 }
340                 IfCond = GetCurrentIfCond ();
341                 break;
342
343             case TOK_IFNREF:
344                 D = AllocIf (".IFNREF", 1);
345                 NextTok ();
346                 if (IfCond) {
347                     if (Tok != TOK_IDENT) {
348                         ErrorSkip (ERR_IDENT_EXPECTED);
349                     } else {
350                         SetIfCond (D, !SymIsRef (SVal));
351                         NextTok ();
352                     }
353                 }
354                 IfCond = GetCurrentIfCond ();
355                 break;
356
357             case TOK_IFP02:
358                 break;
359
360             case TOK_IFP816:
361                 break;
362
363             case TOK_IFPC02:
364                 break;
365
366             case TOK_IFREF:
367                 D = AllocIf (".IFREF", 1);
368                 NextTok ();
369                 if (IfCond) {
370                     if (Tok != TOK_IDENT) {
371                         ErrorSkip (ERR_IDENT_EXPECTED);
372                     } else {
373                         SetIfCond (D, SymIsRef (SVal));
374                         NextTok ();
375                     }
376                 }
377                 IfCond = GetCurrentIfCond ();
378                 break;
379
380             default:
381                 // Skip tokens
382                 NextTok ();
383
384         }
385
386     } while (IfCond == 0 && Tok != TOK_EOF);
387 }
388
389
390
391 void CheckOpenIfs (void)
392 /* Called from the scanner before closing an input file. Will check for any
393  * open .ifs in this file.
394  */
395 {
396     while (1) {
397         /* Get the current file number and check if the topmost entry on the
398          * .IF stack was inserted with this file number
399          */
400         IfDesc* D = GetCurrentIf ();
401         if (D == 0) {
402             /* There are no open .IFs */
403             break;
404         }
405           
406         if (D->Pos.Name != CurPos.Name) {
407             /* The .if is from another file, bail out */
408             break;
409         }
410
411         /* Start of .if is in the file we're about to leave */
412         PError (&D->Pos, ERR_OPEN_IF);
413         FreeIf ();
414     }
415 }
416
417
418