]> git.sur5r.net Git - cc65/blob - src/ca65/condasm.c
Add #pragma charmap()
[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         Error (ERR_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                     SetIfCond (D, Tok == TOK_SEP);
283                 }
284                 IfCond = GetCurrentIfCond ();
285                 break;
286
287             case TOK_IFCONST:
288                 D = AllocIf (".IFCONST", 1);
289                 NextTok ();
290                 if (IfCond) {
291                     ExprNode* Expr = Expression();
292                     SetIfCond (D, IsConstExpr (Expr));
293                     FreeExpr (Expr);
294                 }
295                 IfCond = GetCurrentIfCond ();
296                 break;
297
298             case TOK_IFDEF:
299                 D = AllocIf (".IFDEF", 1);
300                 NextTok ();
301                 if (IfCond) {
302                     if (Tok != TOK_IDENT) {
303                         ErrorSkip (ERR_IDENT_EXPECTED);
304                     } else {
305                         SetIfCond (D, SymIsDef (SVal));
306                         NextTok ();
307                     }
308                 }
309                 IfCond = GetCurrentIfCond ();
310                 break;
311
312             case TOK_IFNBLANK:
313                 D = AllocIf (".IFNBLANK", 1);
314                 NextTok ();
315                 if (IfCond) {
316                     SetIfCond (D, Tok != TOK_SEP);
317                 }
318                 IfCond = GetCurrentIfCond ();
319                 break;
320
321             case TOK_IFNCONST:
322                 D = AllocIf (".IFNCONST", 1);
323                 NextTok ();
324                 if (IfCond) {
325                     ExprNode* Expr = Expression();
326                     SetIfCond (D, !IsConstExpr (Expr));
327                     FreeExpr (Expr);
328                 }
329                 IfCond = GetCurrentIfCond ();
330                 break;
331
332             case TOK_IFNDEF:
333                 D = AllocIf (".IFNDEF", 1);
334                 NextTok ();
335                 if (IfCond) {
336                     if (Tok != TOK_IDENT) {
337                         ErrorSkip (ERR_IDENT_EXPECTED);
338                     } else {
339                         SetIfCond (D, !SymIsDef (SVal));
340                         NextTok ();
341                     }
342                 }
343                 IfCond = GetCurrentIfCond ();
344                 break;
345
346             case TOK_IFNREF:
347                 D = AllocIf (".IFNREF", 1);
348                 NextTok ();
349                 if (IfCond) {
350                     if (Tok != TOK_IDENT) {
351                         ErrorSkip (ERR_IDENT_EXPECTED);
352                     } else {
353                         SetIfCond (D, !SymIsRef (SVal));
354                         NextTok ();
355                     }
356                 }
357                 IfCond = GetCurrentIfCond ();
358                 break;
359
360             case TOK_IFP02:
361                 D = AllocIf (".IFP02", 1);
362                 NextTok ();
363                 if (IfCond) {
364                     SetIfCond (D, GetCPU() == CPU_6502);
365                 }
366                 IfCond = GetCurrentIfCond ();
367                 break;
368
369             case TOK_IFP816:
370                 D = AllocIf (".IFP816", 1);
371                 NextTok ();
372                 if (IfCond) {
373                     SetIfCond (D, GetCPU() == CPU_65816);
374                 }
375                 IfCond = GetCurrentIfCond ();
376                 break;
377
378             case TOK_IFPC02:
379                 D = AllocIf (".IFPC02", 1);
380                 NextTok ();
381                 if (IfCond) {
382                     SetIfCond (D, GetCPU() == CPU_65C02);
383                 }
384                 IfCond = GetCurrentIfCond ();
385                 break;
386
387             case TOK_IFREF:
388                 D = AllocIf (".IFREF", 1);
389                 NextTok ();
390                 if (IfCond) {
391                     if (Tok != TOK_IDENT) {
392                         ErrorSkip (ERR_IDENT_EXPECTED);
393                     } else {
394                         SetIfCond (D, SymIsRef (SVal));
395                         NextTok ();
396                     }
397                 }
398                 IfCond = GetCurrentIfCond ();
399                 break;
400
401             default:
402                 /* Skip tokens */
403                 NextTok ();
404
405         }
406
407     } while (IfCond == 0 && Tok != TOK_EOF);
408 }
409
410
411
412 void CheckOpenIfs (void)
413 /* Called from the scanner before closing an input file. Will check for any
414  * open .ifs in this file.
415  */
416 {
417     while (1) {
418         /* Get the current file number and check if the topmost entry on the
419          * .IF stack was inserted with this file number
420          */
421         IfDesc* D = GetCurrentIf ();
422         if (D == 0) {
423             /* There are no open .IFs */
424             break;
425         }
426
427         if (D->Pos.Name != CurPos.Name) {
428             /* The .if is from another file, bail out */
429             break;
430         }
431
432         /* Start of .if is in the file we're about to leave */
433         PError (&D->Pos, ERR_OPEN_IF);
434         FreeIf ();
435     }
436 }
437
438
439
440 unsigned GetIfStack (void)
441 /* Get the current .IF stack pointer */
442 {
443     return IfCount;
444 }
445
446
447
448 void CleanupIfStack (unsigned SP)
449 /* Cleanup the .IF stack, remove anything above the given stack pointer */
450 {
451     while (IfCount > SP) {
452         FreeIf ();
453     }
454 }
455
456
457