1 /*****************************************************************************/
5 /* Conditional assembly support for ca65 */
9 /* (C) 2000-2003 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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 /*****************************************************************************/
46 /*****************************************************************************/
48 /*****************************************************************************/
52 /* Maximum count of nested .ifs */
55 /* Set of bitmapped flags for the if descriptor */
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 */
65 /*****************************************************************************/
67 /*****************************************************************************/
71 /* One .IF descriptor */
72 typedef struct IfDesc IfDesc;
74 unsigned Flags; /* Bitmapped flags, see above */
75 FilePos Pos; /* File position of the .IF */
76 const char* Name; /* Name of the directive */
80 static IfDesc IfStack [MAX_IFS];
81 static unsigned IfCount = 0;
85 static IfDesc* AllocIf (const char* Directive, int NeedTerm)
86 /* Alloc a new element from the .IF stack */
90 /* Check for stack overflow */
91 if (IfCount >= MAX_IFS) {
92 Fatal (FAT_IF_NESTING);
95 /* Alloc one element */
96 ID = &IfStack [IfCount++];
98 /* Initialize elements */
99 ID->Flags = NeedTerm? ifNeedTerm : ifNone;
101 ID->Name = Directive;
103 /* Return the result */
109 static IfDesc* GetCurrentIf (void)
110 /* Return the current .IF descriptor */
115 return &IfStack [IfCount-1];
121 static void FreeIf (void)
122 /* Free all .IF descriptors until we reach one with the NeedTerm bit set */
126 IfDesc* D = GetCurrentIf();
128 Error (ERR_UNEXPECTED, ".ENDIF");
131 Done = (D->Flags & ifNeedTerm) != 0;
139 static int GetCurrentIfCond (void)
140 /* Return the current condition based on all conditions on the stack */
143 for (Count = 0; Count < IfCount; ++Count) {
144 if ((IfStack[Count].Flags & ifCond) == 0) {
153 static void SetIfCond (IfDesc* ID, int C)
154 /* Set the .IF condition */
159 ID->Flags &= ~ifCond;
165 static void InvertIfCond (IfDesc* ID)
166 /* Invert the current condition */
173 static int GetElse (const IfDesc* ID)
174 /* Return true if we had a .ELSE */
176 return (ID->Flags & ifElse) != 0;
181 static void SetElse (IfDesc* ID, int E)
182 /* Set the .ELSE flag */
187 ID->Flags &= ~ifElse;
193 /*****************************************************************************/
195 /*****************************************************************************/
199 void DoConditionals (void)
200 /* Catch all for conditional directives */
204 int IfCond = GetCurrentIfCond ();
212 Error (ERR_UNEXPECTED, ".ELSE");
213 } else if (GetElse(D)) {
214 /* We already had a .ELSE ! */
215 Error (ERR_DUPLICATE_ELSE);
222 IfCond = GetCurrentIfCond ();
230 Error (ERR_UNEXPECTED, ".ELSEIF");
231 } else if (GetElse(D)) {
232 /* We already had a .ELSE */
233 Error (ERR_DUPLICATE_ELSE);
235 /* Handle as if there was an .ELSE first */
239 /* Allocate and prepare a new descriptor */
240 D = AllocIf (".ELSEIF", 0);
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...
248 SetIfCond (D, ConstExpression ());
251 /* Get the new overall condition */
252 IfCond = GetCurrentIfCond ();
257 /* We're done with this .IF.. - remove the descriptor(s) */
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.
265 /* Get the new overall condition */
266 IfCond = GetCurrentIfCond ();
270 D = AllocIf (".IF", 1);
273 SetIfCond (D, ConstExpression ());
275 IfCond = GetCurrentIfCond ();
279 D = AllocIf (".IFBLANK", 1);
282 if (TokIsSep (Tok)) {
289 IfCond = GetCurrentIfCond ();
293 D = AllocIf (".IFCONST", 1);
296 ExprNode* Expr = Expression();
297 SetIfCond (D, IsConstExpr (Expr));
300 IfCond = GetCurrentIfCond ();
304 D = AllocIf (".IFDEF", 1);
307 if (Tok != TOK_IDENT) {
308 ErrorSkip (ERR_IDENT_EXPECTED);
310 SetIfCond (D, SymIsDef (SVal, SCOPE_ANY));
314 IfCond = GetCurrentIfCond ();
318 D = AllocIf (".IFNBLANK", 1);
321 if (TokIsSep (Tok)) {
328 IfCond = GetCurrentIfCond ();
332 D = AllocIf (".IFNCONST", 1);
335 ExprNode* Expr = Expression();
336 SetIfCond (D, !IsConstExpr (Expr));
339 IfCond = GetCurrentIfCond ();
343 D = AllocIf (".IFNDEF", 1);
346 if (Tok != TOK_IDENT) {
347 ErrorSkip (ERR_IDENT_EXPECTED);
349 SetIfCond (D, !SymIsDef (SVal, SCOPE_ANY));
353 IfCond = GetCurrentIfCond ();
357 D = AllocIf (".IFNREF", 1);
360 if (Tok != TOK_IDENT) {
361 ErrorSkip (ERR_IDENT_EXPECTED);
363 SetIfCond (D, !SymIsRef (SVal, SCOPE_ANY));
367 IfCond = GetCurrentIfCond ();
371 D = AllocIf (".IFP02", 1);
374 SetIfCond (D, GetCPU() == CPU_6502);
376 IfCond = GetCurrentIfCond ();
380 D = AllocIf (".IFP816", 1);
383 SetIfCond (D, GetCPU() == CPU_65816);
385 IfCond = GetCurrentIfCond ();
389 D = AllocIf (".IFPC02", 1);
392 SetIfCond (D, GetCPU() == CPU_65C02);
394 IfCond = GetCurrentIfCond ();
398 D = AllocIf (".IFPSC02", 1);
401 SetIfCond (D, GetCPU() == CPU_65SC02);
403 IfCond = GetCurrentIfCond ();
407 D = AllocIf (".IFREF", 1);
410 if (Tok != TOK_IDENT) {
411 ErrorSkip (ERR_IDENT_EXPECTED);
413 SetIfCond (D, SymIsRef (SVal, SCOPE_ANY));
417 IfCond = GetCurrentIfCond ();
426 } while (IfCond == 0 && Tok != TOK_EOF);
431 void CheckOpenIfs (void)
432 /* Called from the scanner before closing an input file. Will check for any
433 * open .ifs in this file.
437 /* Get the current file number and check if the topmost entry on the
438 * .IF stack was inserted with this file number
440 IfDesc* D = GetCurrentIf ();
442 /* There are no open .IFs */
446 if (D->Pos.Name != CurPos.Name) {
447 /* The .if is from another file, bail out */
451 /* Start of .if is in the file we're about to leave */
452 PError (&D->Pos, ERR_OPEN_IF);
459 unsigned GetIfStack (void)
460 /* Get the current .IF stack pointer */
467 void CleanupIfStack (unsigned SP)
468 /* Cleanup the .IF stack, remove anything above the given stack pointer */
470 while (IfCount > SP) {