1 /*****************************************************************************/
5 /* Conditional assembly support for ca65 */
9 /* (C) 2000 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 /*****************************************************************************/
44 /*****************************************************************************/
46 /*****************************************************************************/
50 /* Maximum count of nested .ifs */
53 /* Set of bitmapped flags for the if descriptor */
55 ifNone = 0x0000, /* No flag */
56 ifCond = 0x0001, /* IF condition was true */
57 ifElse = 0x0002, /* We had a .ELSE branch */
58 ifNeedTerm = 0x0004 /* Need .ENDIF termination */
63 /*****************************************************************************/
65 /*****************************************************************************/
69 /* One .IF descriptor */
70 typedef struct IfDesc_ IfDesc;
72 unsigned Flags; /* Bitmapped flags, see above */
73 FilePos Pos; /* File position of the .IF */
74 const char* Name; /* Name of the directive */
78 static IfDesc IfStack [MAX_IFS];
79 static unsigned IfCount = 0;
83 static IfDesc* AllocIf (const char* Directive, int NeedTerm)
84 /* Alloc a new element from the .IF stack */
88 /* Check for stack overflow */
89 if (IfCount >= MAX_IFS) {
90 Error (ERR_IF_NESTING);
93 /* Alloc one element */
94 ID = &IfStack [IfCount++];
96 /* Initialize elements */
97 ID->Flags = NeedTerm? ifNeedTerm : ifNone;
101 /* Return the result */
107 static IfDesc* GetCurrentIf (void)
108 /* Return the current .IF descriptor */
113 return &IfStack [IfCount-1];
119 static void FreeIf (void)
120 /* Free all .IF descriptors until we reach one with the NeedTerm bit set */
124 IfDesc* D = GetCurrentIf();
126 Error (ERR_UNEXPECTED, ".ENDIF");
129 Done = (D->Flags & ifNeedTerm) != 0;
137 static int GetCurrentIfCond (void)
138 /* Return the current condition based on all conditions on the stack */
141 for (Count = 0; Count < IfCount; ++Count) {
142 if ((IfStack[Count].Flags & ifCond) == 0) {
151 static void SetIfCond (IfDesc* ID, int C)
152 /* Set the .IF condition */
157 ID->Flags &= ~ifCond;
163 static void InvertIfCond (IfDesc* ID)
164 /* Invert the current condition */
171 static int GetElse (const IfDesc* ID)
172 /* Return true if we had a .ELSE */
174 return (ID->Flags & ifElse) != 0;
179 static void SetElse (IfDesc* ID, int E)
180 /* Set the .ELSE flag */
185 ID->Flags &= ~ifElse;
191 /*****************************************************************************/
193 /*****************************************************************************/
197 void DoConditionals (void)
198 /* Catch all for conditional directives */
202 int IfCond = GetCurrentIfCond ();
210 Error (ERR_UNEXPECTED, ".ELSE");
211 } else if (GetElse(D)) {
212 /* We already had a .ELSE ! */
213 Error (ERR_DUPLICATE_ELSE);
220 IfCond = GetCurrentIfCond ();
228 Error (ERR_UNEXPECTED, ".ELSEIF");
229 } else if (GetElse(D)) {
230 /* We already had a .ELSE */
231 Error (ERR_DUPLICATE_ELSE);
233 /* Handle as if there was an .ELSE first */
237 /* Allocate and prepare a new descriptor */
238 D = AllocIf (".ELSEIF", 0);
241 /* Ignore the new condition if we are inside a false .ELSE
242 * branch. This way we won't get any errors about undefined
243 * symbols or similar...
246 SetIfCond (D, ConstExpression ());
249 /* Get the new overall condition */
250 IfCond = GetCurrentIfCond ();
255 /* We're done with this .IF.. - remove the descriptor(s) */
258 /* Be sure not to read the next token until the .IF stack
259 * has been cleanup up, since we may be at end of file.
263 /* Get the new overall condition */
264 IfCond = GetCurrentIfCond ();
268 D = AllocIf (".IF", 1);
271 SetIfCond (D, ConstExpression ());
273 IfCond = GetCurrentIfCond ();
277 D = AllocIf (".IFBLANK", 1);
280 SetIfCond (D, Tok == TOK_SEP);
282 IfCond = GetCurrentIfCond ();
286 D = AllocIf (".IFCONST", 1);
289 ExprNode* Expr = Expression();
290 SetIfCond (D, IsConstExpr (Expr));
293 IfCond = GetCurrentIfCond ();
297 D = AllocIf (".IFDEF", 1);
300 if (Tok != TOK_IDENT) {
301 ErrorSkip (ERR_IDENT_EXPECTED);
303 SetIfCond (D, SymIsDef (SVal));
307 IfCond = GetCurrentIfCond ();
311 D = AllocIf (".IFNBLANK", 1);
314 SetIfCond (D, Tok != TOK_SEP);
316 IfCond = GetCurrentIfCond ();
320 D = AllocIf (".IFNCONST", 1);
323 ExprNode* Expr = Expression();
324 SetIfCond (D, !IsConstExpr (Expr));
327 IfCond = GetCurrentIfCond ();
331 D = AllocIf (".IFNDEF", 1);
334 if (Tok != TOK_IDENT) {
335 ErrorSkip (ERR_IDENT_EXPECTED);
337 SetIfCond (D, !SymIsDef (SVal));
341 IfCond = GetCurrentIfCond ();
345 D = AllocIf (".IFNREF", 1);
348 if (Tok != TOK_IDENT) {
349 ErrorSkip (ERR_IDENT_EXPECTED);
351 SetIfCond (D, !SymIsRef (SVal));
355 IfCond = GetCurrentIfCond ();
368 D = AllocIf (".IFREF", 1);
371 if (Tok != TOK_IDENT) {
372 ErrorSkip (ERR_IDENT_EXPECTED);
374 SetIfCond (D, SymIsRef (SVal));
378 IfCond = GetCurrentIfCond ();
387 } while (IfCond == 0 && Tok != TOK_EOF);
392 void CheckOpenIfs (void)
393 /* Called from the scanner before closing an input file. Will check for any
394 * open .ifs in this file.
398 /* Get the current file number and check if the topmost entry on the
399 * .IF stack was inserted with this file number
401 IfDesc* D = GetCurrentIf ();
403 /* There are no open .IFs */
407 if (D->Pos.Name != CurPos.Name) {
408 /* The .if is from another file, bail out */
412 /* Start of .if is in the file we're about to leave */
413 PError (&D->Pos, ERR_OPEN_IF);
420 unsigned GetIfStack (void)
421 /* Get the current .IF stack pointer */
428 void CleanupIfStack (unsigned SP)
429 /* Cleanup the .IF stack, remove anything above the given stack pointer */
431 while (IfCount > SP) {