1 /*****************************************************************************/
5 /* Conditional assembly support for ca65 */
9 /* (C) 2000-2011, 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 /*****************************************************************************/
48 /*****************************************************************************/
50 /*****************************************************************************/
54 /* Maximum count of nested .ifs */
57 /* Set of bitmapped flags for the if descriptor */
59 ifNone = 0x0000, /* No flag */
60 ifCond = 0x0001, /* IF condition was true */
61 ifElse = 0x0002, /* We had a .ELSE branch */
62 ifNeedTerm = 0x0004 /* Need .ENDIF termination */
67 /*****************************************************************************/
69 /*****************************************************************************/
73 /* One .IF descriptor */
74 typedef struct IfDesc IfDesc;
76 unsigned Flags; /* Bitmapped flags, see above */
77 Collection LineInfos; /* File position of the .IF */
78 const char* Name; /* Name of the directive */
82 static IfDesc IfStack [MAX_IFS];
83 static unsigned IfCount = 0;
87 static IfDesc* AllocIf (const char* Directive, int NeedTerm)
88 /* Alloc a new element from the .IF stack */
92 /* Check for stack overflow */
93 if (IfCount >= MAX_IFS) {
94 Fatal ("Too many nested .IFs");
97 /* Alloc one element */
98 ID = &IfStack [IfCount++];
100 /* Initialize elements */
101 ID->Flags = NeedTerm? ifNeedTerm : ifNone;
102 ID->LineInfos = EmptyCollection;
103 GetFullLineInfo (&ID->LineInfos, 0);
104 ID->Name = Directive;
106 /* Return the result */
112 static IfDesc* GetCurrentIf (void)
113 /* Return the current .IF descriptor */
118 return &IfStack [IfCount-1];
124 static void FreeIf (void)
125 /* Free all .IF descriptors until we reach one with the NeedTerm bit set */
129 IfDesc* D = GetCurrentIf();
131 Error (" Unexpected .ENDIF");
134 Done = (D->Flags & ifNeedTerm) != 0;
142 static int GetCurrentIfCond (void)
143 /* Return the current condition based on all conditions on the stack */
146 for (Count = 0; Count < IfCount; ++Count) {
147 if ((IfStack[Count].Flags & ifCond) == 0) {
156 static void SetIfCond (IfDesc* ID, int C)
157 /* Set the .IF condition */
162 ID->Flags &= ~ifCond;
168 static void InvertIfCond (IfDesc* ID)
169 /* Invert the current condition */
176 static int GetElse (const IfDesc* ID)
177 /* Return true if we had a .ELSE */
179 return (ID->Flags & ifElse) != 0;
184 static void SetElse (IfDesc* ID, int E)
185 /* Set the .ELSE flag */
190 ID->Flags &= ~ifElse;
196 /*****************************************************************************/
198 /*****************************************************************************/
202 void DoConditionals (void)
203 /* Catch all for conditional directives */
207 int IfCond = GetCurrentIfCond ();
210 switch (CurTok.Tok) {
215 Error ("Unexpected .ELSE");
216 } else if (GetElse(D)) {
217 /* We already had a .ELSE ! */
218 Error ("Duplicate .ELSE");
223 GetFullLineInfo (&D->LineInfos, 0);
225 IfCond = GetCurrentIfCond ();
234 Error ("Unexpected .ELSEIF");
235 } else if (GetElse(D)) {
236 /* We already had a .ELSE */
237 Error ("Duplicate .ELSE");
239 /* Handle as if there was an .ELSE first */
243 /* Allocate and prepare a new descriptor */
244 D = AllocIf (".ELSEIF", 0);
247 /* Ignore the new condition if we are inside a false .ELSE
248 * branch. This way we won't get any errors about undefined
249 * symbols or similar...
252 SetIfCond (D, ConstExpression ());
256 /* Get the new overall condition */
257 IfCond = GetCurrentIfCond ();
262 /* We're done with this .IF.. - remove the descriptor(s) */
265 /* Be sure not to read the next token until the .IF stack
266 * has been cleanup up, since we may be at end of file.
271 /* Get the new overall condition */
272 IfCond = GetCurrentIfCond ();
276 D = AllocIf (".IF", 1);
279 SetIfCond (D, ConstExpression ());
282 IfCond = GetCurrentIfCond ();
286 D = AllocIf (".IFBLANK", 1);
289 if (TokIsSep (CurTok.Tok)) {
296 IfCond = GetCurrentIfCond ();
300 D = AllocIf (".IFCONST", 1);
303 ExprNode* Expr = Expression();
304 SetIfCond (D, IsConstExpr (Expr, 0));
308 IfCond = GetCurrentIfCond ();
312 D = AllocIf (".IFDEF", 1);
315 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
316 SetIfCond (D, Sym != 0 && SymIsDef (Sym));
318 IfCond = GetCurrentIfCond ();
322 D = AllocIf (".IFNBLANK", 1);
325 if (TokIsSep (CurTok.Tok)) {
332 IfCond = GetCurrentIfCond ();
336 D = AllocIf (".IFNCONST", 1);
339 ExprNode* Expr = Expression();
340 SetIfCond (D, !IsConstExpr (Expr, 0));
344 IfCond = GetCurrentIfCond ();
348 D = AllocIf (".IFNDEF", 1);
351 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
352 SetIfCond (D, Sym == 0 || !SymIsDef (Sym));
355 IfCond = GetCurrentIfCond ();
359 D = AllocIf (".IFNREF", 1);
362 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
363 SetIfCond (D, Sym == 0 || !SymIsRef (Sym));
366 IfCond = GetCurrentIfCond ();
370 D = AllocIf (".IFP02", 1);
373 SetIfCond (D, GetCPU() == CPU_6502);
375 IfCond = GetCurrentIfCond ();
380 D = AllocIf (".IFP816", 1);
383 SetIfCond (D, GetCPU() == CPU_65816);
385 IfCond = GetCurrentIfCond ();
390 D = AllocIf (".IFPC02", 1);
393 SetIfCond (D, GetCPU() == CPU_65C02);
395 IfCond = GetCurrentIfCond ();
400 D = AllocIf (".IFPSC02", 1);
403 SetIfCond (D, GetCPU() == CPU_65SC02);
405 IfCond = GetCurrentIfCond ();
410 D = AllocIf (".IFREF", 1);
413 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
414 SetIfCond (D, Sym != 0 && SymIsRef (Sym));
417 IfCond = GetCurrentIfCond ();
426 } while (IfCond == 0 && CurTok.Tok != TOK_EOF);
431 int CheckConditionals (void)
432 /* Check if the current token is one that starts a conditional directive, and
433 * call DoConditionals if so. Return true if a conditional directive was found,
434 * return false otherwise.
437 switch (CurTok.Tok) {
464 void CheckOpenIfs (void)
465 /* Called from the scanner before closing an input file. Will check for any
466 * open .ifs in this file.
472 /* Get the current file number and check if the topmost entry on the
473 * .IF stack was inserted with this file number
475 IfDesc* D = GetCurrentIf ();
477 /* There are no open .IFs */
481 LI = CollConstAt (&D->LineInfos, 0);
482 if (LI->Pos.Name != CurTok.Pos.Name) {
483 /* The .if is from another file, bail out */
487 /* Start of .if is in the file we're about to leave */
488 LIError (&D->LineInfos, "Conditional assembly branch was never closed");
495 unsigned GetIfStack (void)
496 /* Get the current .IF stack pointer */
503 void CleanupIfStack (unsigned SP)
504 /* Cleanup the .IF stack, remove anything above the given stack pointer */
506 while (IfCount > SP) {