1 /*****************************************************************************/
5 /* Conditional assembly support for ca65 */
9 /* (C) 2000-2010, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
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 ();
232 Error ("Unexpected .ELSEIF");
233 } else if (GetElse(D)) {
234 /* We already had a .ELSE */
235 Error ("Duplicate .ELSE");
237 /* Handle as if there was an .ELSE first */
241 /* Allocate and prepare a new descriptor */
242 D = AllocIf (".ELSEIF", 0);
245 /* Ignore the new condition if we are inside a false .ELSE
246 * branch. This way we won't get any errors about undefined
247 * symbols or similar...
250 SetIfCond (D, ConstExpression ());
254 /* Get the new overall condition */
255 IfCond = GetCurrentIfCond ();
260 /* We're done with this .IF.. - remove the descriptor(s) */
263 /* Be sure not to read the next token until the .IF stack
264 * has been cleanup up, since we may be at end of file.
269 /* Get the new overall condition */
270 IfCond = GetCurrentIfCond ();
274 D = AllocIf (".IF", 1);
277 SetIfCond (D, ConstExpression ());
280 IfCond = GetCurrentIfCond ();
284 D = AllocIf (".IFBLANK", 1);
287 if (TokIsSep (Tok)) {
294 IfCond = GetCurrentIfCond ();
298 D = AllocIf (".IFCONST", 1);
301 ExprNode* Expr = Expression();
302 SetIfCond (D, IsConstExpr (Expr, 0));
306 IfCond = GetCurrentIfCond ();
310 D = AllocIf (".IFDEF", 1);
313 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
314 SetIfCond (D, Sym != 0 && SymIsDef (Sym));
316 IfCond = GetCurrentIfCond ();
320 D = AllocIf (".IFNBLANK", 1);
323 if (TokIsSep (Tok)) {
330 IfCond = GetCurrentIfCond ();
334 D = AllocIf (".IFNCONST", 1);
337 ExprNode* Expr = Expression();
338 SetIfCond (D, !IsConstExpr (Expr, 0));
342 IfCond = GetCurrentIfCond ();
346 D = AllocIf (".IFNDEF", 1);
349 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
350 SetIfCond (D, Sym == 0 || !SymIsDef (Sym));
353 IfCond = GetCurrentIfCond ();
357 D = AllocIf (".IFNREF", 1);
360 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
361 SetIfCond (D, Sym == 0 || !SymIsRef (Sym));
364 IfCond = GetCurrentIfCond ();
368 D = AllocIf (".IFP02", 1);
371 SetIfCond (D, GetCPU() == CPU_6502);
373 IfCond = GetCurrentIfCond ();
378 D = AllocIf (".IFP816", 1);
381 SetIfCond (D, GetCPU() == CPU_65816);
383 IfCond = GetCurrentIfCond ();
388 D = AllocIf (".IFPC02", 1);
391 SetIfCond (D, GetCPU() == CPU_65C02);
393 IfCond = GetCurrentIfCond ();
398 D = AllocIf (".IFPSC02", 1);
401 SetIfCond (D, GetCPU() == CPU_65SC02);
403 IfCond = GetCurrentIfCond ();
408 D = AllocIf (".IFREF", 1);
411 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
412 SetIfCond (D, Sym != 0 && SymIsRef (Sym));
415 IfCond = GetCurrentIfCond ();
424 } while (IfCond == 0 && Tok != TOK_EOF);
429 int CheckConditionals (void)
430 /* Check if the current token is one that starts a conditional directive, and
431 * call DoConditionals if so. Return true if a conditional directive was found,
432 * return false otherwise.
462 void CheckOpenIfs (void)
463 /* Called from the scanner before closing an input file. Will check for any
464 * open .ifs in this file.
468 /* Get the current file number and check if the topmost entry on the
469 * .IF stack was inserted with this file number
471 IfDesc* D = GetCurrentIf ();
473 /* There are no open .IFs */
477 if (D->Pos.Name != CurPos.Name) {
478 /* The .if is from another file, bail out */
482 /* Start of .if is in the file we're about to leave */
483 PError (&D->Pos, "Conditional assembly branch was never closed");
490 unsigned GetIfStack (void)
491 /* Get the current .IF stack pointer */
498 void CleanupIfStack (unsigned SP)
499 /* Cleanup the .IF stack, remove anything above the given stack pointer */
501 while (IfCount > SP) {