1 /*****************************************************************************/
5 /* Conditional assembly support for ca65 */
9 /* (C) 2000-2003 Ullrich von Bassewitz */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
47 /*****************************************************************************/
49 /*****************************************************************************/
53 /* Maximum count of nested .ifs */
56 /* Set of bitmapped flags for the if descriptor */
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 */
66 /*****************************************************************************/
68 /*****************************************************************************/
72 /* One .IF descriptor */
73 typedef struct IfDesc IfDesc;
75 unsigned Flags; /* Bitmapped flags, see above */
76 FilePos Pos; /* File position of the .IF */
77 const char* Name; /* Name of the directive */
81 static IfDesc IfStack [MAX_IFS];
82 static unsigned IfCount = 0;
86 static IfDesc* AllocIf (const char* Directive, int NeedTerm)
87 /* Alloc a new element from the .IF stack */
91 /* Check for stack overflow */
92 if (IfCount >= MAX_IFS) {
93 Fatal ("Too many nested .IFs");
96 /* Alloc one element */
97 ID = &IfStack [IfCount++];
99 /* Initialize elements */
100 ID->Flags = NeedTerm? ifNeedTerm : ifNone;
102 ID->Name = Directive;
104 /* Return the result */
110 static IfDesc* GetCurrentIf (void)
111 /* Return the current .IF descriptor */
116 return &IfStack [IfCount-1];
122 static void FreeIf (void)
123 /* Free all .IF descriptors until we reach one with the NeedTerm bit set */
127 IfDesc* D = GetCurrentIf();
129 Error (" Unexpected .ENDIF");
132 Done = (D->Flags & ifNeedTerm) != 0;
140 static int GetCurrentIfCond (void)
141 /* Return the current condition based on all conditions on the stack */
144 for (Count = 0; Count < IfCount; ++Count) {
145 if ((IfStack[Count].Flags & ifCond) == 0) {
154 static void SetIfCond (IfDesc* ID, int C)
155 /* Set the .IF condition */
160 ID->Flags &= ~ifCond;
166 static void InvertIfCond (IfDesc* ID)
167 /* Invert the current condition */
174 static int GetElse (const IfDesc* ID)
175 /* Return true if we had a .ELSE */
177 return (ID->Flags & ifElse) != 0;
182 static void SetElse (IfDesc* ID, int E)
183 /* Set the .ELSE flag */
188 ID->Flags &= ~ifElse;
194 /*****************************************************************************/
196 /*****************************************************************************/
200 void DoConditionals (void)
201 /* Catch all for conditional directives */
205 int IfCond = GetCurrentIfCond ();
213 Error ("Unexpected .ELSE");
214 } else if (GetElse(D)) {
215 /* We already had a .ELSE ! */
216 Error ("Duplicate .ELSE");
223 IfCond = GetCurrentIfCond ();
231 Error ("Unexpected .ELSEIF");
232 } else if (GetElse(D)) {
233 /* We already had a .ELSE */
234 Error ("Duplicate .ELSE");
236 /* Handle as if there was an .ELSE first */
240 /* Allocate and prepare a new descriptor */
241 D = AllocIf (".ELSEIF", 0);
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...
249 SetIfCond (D, ConstExpression ());
252 /* Get the new overall condition */
253 IfCond = GetCurrentIfCond ();
258 /* We're done with this .IF.. - remove the descriptor(s) */
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.
266 /* Get the new overall condition */
267 IfCond = GetCurrentIfCond ();
271 D = AllocIf (".IF", 1);
274 SetIfCond (D, ConstExpression ());
276 IfCond = GetCurrentIfCond ();
280 D = AllocIf (".IFBLANK", 1);
283 if (TokIsSep (Tok)) {
290 IfCond = GetCurrentIfCond ();
294 D = AllocIf (".IFCONST", 1);
297 ExprNode* Expr = Expression();
298 SetIfCond (D, IsConstExpr (Expr, 0));
301 IfCond = GetCurrentIfCond ();
305 D = AllocIf (".IFDEF", 1);
308 SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
309 SetIfCond (D, Sym != 0 && SymIsDef (Sym));
311 IfCond = GetCurrentIfCond ();
315 D = AllocIf (".IFNBLANK", 1);
318 if (TokIsSep (Tok)) {
325 IfCond = GetCurrentIfCond ();
329 D = AllocIf (".IFNCONST", 1);
332 ExprNode* Expr = Expression();
333 SetIfCond (D, !IsConstExpr (Expr, 0));
336 IfCond = GetCurrentIfCond ();
340 D = AllocIf (".IFNDEF", 1);
343 SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
344 SetIfCond (D, Sym == 0 || !SymIsDef (Sym));
346 IfCond = GetCurrentIfCond ();
350 D = AllocIf (".IFNREF", 1);
353 SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
354 SetIfCond (D, Sym == 0 || !SymIsRef (Sym));
356 IfCond = GetCurrentIfCond ();
360 D = AllocIf (".IFP02", 1);
363 SetIfCond (D, GetCPU() == CPU_6502);
365 IfCond = GetCurrentIfCond ();
369 D = AllocIf (".IFP816", 1);
372 SetIfCond (D, GetCPU() == CPU_65816);
374 IfCond = GetCurrentIfCond ();
378 D = AllocIf (".IFPC02", 1);
381 SetIfCond (D, GetCPU() == CPU_65C02);
383 IfCond = GetCurrentIfCond ();
387 D = AllocIf (".IFPSC02", 1);
390 SetIfCond (D, GetCPU() == CPU_65SC02);
392 IfCond = GetCurrentIfCond ();
396 D = AllocIf (".IFREF", 1);
399 SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
400 SetIfCond (D, Sym != 0 && SymIsRef (Sym));
402 IfCond = GetCurrentIfCond ();
411 } while (IfCond == 0 && Tok != TOK_EOF);
416 void CheckOpenIfs (void)
417 /* Called from the scanner before closing an input file. Will check for any
418 * open .ifs in this file.
422 /* Get the current file number and check if the topmost entry on the
423 * .IF stack was inserted with this file number
425 IfDesc* D = GetCurrentIf ();
427 /* There are no open .IFs */
431 if (D->Pos.Name != CurPos.Name) {
432 /* The .if is from another file, bail out */
436 /* Start of .if is in the file we're about to leave */
437 PError (&D->Pos, "Conditional assembly branch was never closed");
444 unsigned GetIfStack (void)
445 /* Get the current .IF stack pointer */
452 void CleanupIfStack (unsigned SP)
453 /* Cleanup the .IF stack, remove anything above the given stack pointer */
455 while (IfCount > SP) {