]> git.sur5r.net Git - cc65/blobdiff - src/ca65/condasm.c
Renamed some stuff. Write out the segment size as var, not 32 bit.
[cc65] / src / ca65 / condasm.c
index 831802c377ba1343ab48a24ed4925209539f9ee8..a14bbc2f6b0e3fb12a5d68bf719ee6c2c45246a4 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2000      Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@musoftware.de                                            */
+/* (C) 2000-2011, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 
 
 
+/* ca65 */
 #include "error.h"
 #include "expr.h"
-#include "scanner.h"
+#include "instr.h"
+#include "lineinfo.h"
+#include "nexttok.h"
+#include "symbol.h"
 #include "symtab.h"
 #include "condasm.h"
 
 
 
 /* Maximum count of nested .ifs */
-#define MAX_IFS                32
+#define MAX_IFS                256
 
 /* Set of bitmapped flags for the if descriptor */
 enum {
-    ifNone     = 0x0000,               /* No flag */
-    ifCond     = 0x0001,               /* IF condition was true */
-    ifElse     = 0x0002,               /* We had a .ELSE branch */
-    ifNeedTerm = 0x0004                /* Need .ENDIF termination */
+    ifNone     = 0x0000,               /* No flag */
+    ifCond     = 0x0001,               /* IF condition was true */
+    ifParentCond= 0x0002,               /* IF condition of parent */
+    ifElse             = 0x0004,               /* We had a .ELSE branch */
+    ifNeedTerm         = 0x0008,               /* Need .ENDIF termination */
 };
 
+/* The overall .IF condition */
+int IfCond      = 1;
+
 
 
 /*****************************************************************************/
-/*                              struct IfDesc                               */
+/*                              struct IfDesc                               */
 /*****************************************************************************/
 
 
 
 /* One .IF descriptor */
-typedef struct IfDesc_ IfDesc;
-struct IfDesc_ {
+typedef struct IfDesc IfDesc;
+struct IfDesc {
     unsigned           Flags;          /* Bitmapped flags, see above */
-    FilePos            Pos;            /* File position of the .IF */
+    Collection  LineInfos;      /* File position of the .IF */
     const char* Name;          /* Name of the directive */
 };
 
@@ -80,69 +88,35 @@ static unsigned IfCount = 0;
 
 
 
-static IfDesc* AllocIf (const char* Directive, int NeedTerm)
-/* Alloc a new element from the .IF stack */
-{
-    IfDesc* ID;
-
-    /* Check for stack overflow */
-    if (IfCount >= MAX_IFS) {
-               Error (ERR_IF_NESTING);
-    }
-
-    /* Alloc one element */
-    ID = &IfStack [IfCount++];
-
-    /* Initialize elements */
-    ID->Flags = NeedTerm? ifNeedTerm : ifNone;
-    ID->Pos   = CurPos;
-    ID->Name  = Directive;
-
-    /* Return the result */
-    return ID;
-}
-
-
-
 static IfDesc* GetCurrentIf (void)
 /* Return the current .IF descriptor */
 {
     if (IfCount == 0) {
                return 0;
     } else {
-        return &IfStack [IfCount-1];
+        return &IfStack[IfCount-1];
     }
 }
 
 
 
-static void FreeIf (void)
-/* Free all .IF descriptors until we reach one with the NeedTerm bit set */
+static int GetOverallIfCond (void)
+/* Get the overall condition based on all conditions on the stack. */
 {
-    int Done = 0;
-    do {
-               IfDesc* D = GetCurrentIf();
-               if (D == 0) {
-                   Error (ERR_UNEXPECTED, ".ENDIF");
-               } else {
-                   Done = (D->Flags & ifNeedTerm) != 0;
-            --IfCount;
-               }
-    } while (!Done);
+    /* Since the last entry contains the overall condition of the parent, we
+     * must check it in combination of the current condition. If there is no
+     * last entry, the overall condition is true.
+     */
+    return (IfCount == 0) ||
+           ((IfStack[IfCount-1].Flags & (ifCond | ifParentCond)) == (ifCond | ifParentCond));
 }
 
 
 
-static int GetCurrentIfCond (void)
-/* Return the current condition based on all conditions on the stack */
+static void CalcOverallIfCond (void)
+/* Caclulate the overall condition based on all conditions on the stack. */
 {
-    unsigned Count;
-    for (Count = 0; Count < IfCount; ++Count) {
-               if ((IfStack[Count].Flags & ifCond) == 0) {
-                   return 0;
-               }
-    }
-    return 1;
+    IfCond = GetOverallIfCond ();
 }
 
 
@@ -159,36 +133,82 @@ static void SetIfCond (IfDesc* ID, int C)
 
 
 
-static void InvertIfCond (IfDesc* ID)
-/* Invert the current condition */
+static void ElseClause (IfDesc* ID, const char* Directive)
+/* Enter an .ELSE clause */
 {
+    /* Check if we have an open .IF - otherwise .ELSE is not allowed */
+    if (ID == 0) {
+        Error ("Unexpected %s", Directive);
+        return;
+    }
+
+    /* Check for a duplicate else, then remember that we had one */
+    if (ID->Flags & ifElse) {
+        /* We already had a .ELSE ! */
+        Error ("Duplicate .ELSE");
+    }
+    ID->Flags |= ifElse;
+
+    /* Condition is inverted now */
     ID->Flags ^= ifCond;
 }
 
 
 
-static int GetElse (const IfDesc* ID)
-/* Return true if we had a .ELSE */
+static IfDesc* AllocIf (const char* Directive, int NeedTerm)
+/* Alloc a new element from the .IF stack */
 {
-    return (ID->Flags & ifElse) != 0;
+    IfDesc* ID;
+
+    /* Check for stack overflow */
+    if (IfCount >= MAX_IFS) {
+               Fatal ("Too many nested .IFs");
+    }
+
+    /* Get the next element */
+    ID = &IfStack[IfCount];
+
+    /* Initialize elements */
+    ID->Flags = NeedTerm? ifNeedTerm : ifNone;
+    if (GetOverallIfCond ()) {
+        /* The parents .IF condition is true */
+        ID->Flags |= ifParentCond;
+    }
+    ID->LineInfos = EmptyCollection;
+    GetFullLineInfo (&ID->LineInfos);
+    ID->Name = Directive;
+
+    /* One more slot allocated */
+    ++IfCount;
+
+    /* Return the result */
+    return ID;
 }
 
 
 
-static void SetElse (IfDesc* ID, int E)
-/* Set the .ELSE flag */
+static void FreeIf (void)
+/* Free all .IF descriptors until we reach one with the NeedTerm bit set */
 {
-    if (E) {
-       ID->Flags |= ifElse;
-    } else {
-       ID->Flags &= ~ifElse;
-    }
+    int Done;
+    do {
+               IfDesc* ID = GetCurrentIf();
+               if (ID == 0) {
+                   Error (" Unexpected .ENDIF");
+           Done = 1;
+               } else {
+                   Done = (ID->Flags & ifNeedTerm) != 0;
+            ReleaseFullLineInfo (&ID->LineInfos);
+            DoneCollection (&ID->LineInfos);
+            --IfCount;
+               }
+    } while (!Done);
 }
 
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                          Code                                    */
 /*****************************************************************************/
 
 
@@ -198,87 +218,92 @@ void DoConditionals (void)
 {
     IfDesc* D;
 
-    int IfCond = GetCurrentIfCond ();
     do {
 
-       switch (Tok) {
+       switch (CurTok.Tok) {
 
            case TOK_ELSE:
                        D = GetCurrentIf ();
-               if (D == 0) {
-                   Error (ERR_UNEXPECTED, ".ELSE");
-                       } else if (GetElse(D)) {
-                   /* We already had a .ELSE ! */
-                   Error (ERR_DUPLICATE_ELSE);
-                       } else {
-                   /* Allow an .ELSE */
-                   InvertIfCond (D);
-                   SetElse (D, 1);
-                   D->Pos = CurPos;
-                   D->Name = ".ELSE";
-                   IfCond = GetCurrentIfCond ();
-               }
+
+                /* Allow an .ELSE */
+                ElseClause (D, ".ELSE");
+
+                /* Remember the data for the .ELSE */
+                if (D) {
+                    ReleaseFullLineInfo (&D->LineInfos);
+                    GetFullLineInfo (&D->LineInfos);
+                    D->Name = ".ELSE";
+                }
+
+                /* Calculate the new overall condition */
+                CalcOverallIfCond ();
+
+                /* Skip .ELSE */
                NextTok ();
+               ExpectSep ();
                        break;
 
                    case TOK_ELSEIF:
                D = GetCurrentIf ();
-               if (D == 0) {
-                   Error (ERR_UNEXPECTED, ".ELSEIF");
-               } else if (GetElse(D)) {
-                   /* We already had a .ELSE */
-                   Error (ERR_DUPLICATE_ELSE);
-               } else {
-                   /* Handle as if there was an .ELSE first */
-                   InvertIfCond (D);
-                   SetElse (D, 1);
-
-                   /* Allocate and prepare a new descriptor */
-                           D = AllocIf (".ELSEIF", 0);
-                   NextTok ();
-
-                   /* Ignore the new condition if we are inside a false .ELSE
-                    * branch. This way we won't get any errors about undefined
-                    * symbols or similar...
-                    */
-                   if (IfCond == 0) {
-                       SetIfCond (D, ConstExpression ());
-                   }
-
-                   /* Get the new overall condition */
-                   IfCond = GetCurrentIfCond ();
-               }
-               break;
-
-           case TOK_ENDIF:
-               /* We're done with this .IF.. - remove the descriptor(s) */
-               FreeIf ();
-
-               /* Be sure not to read the next token until the .IF stack
-                * has been cleanup up, since we may be at end of file.
-                */
-               NextTok ();
-
-               /* Get the new overall condition */
-               IfCond = GetCurrentIfCond ();
-               break;
+                /* Handle as if there was an .ELSE first */
+                ElseClause (D, ".ELSEIF");
+
+                /* Calculate the new overall if condition */
+                CalcOverallIfCond ();
+
+                /* Allocate and prepare a new descriptor */
+                D = AllocIf (".ELSEIF", 0);
+                NextTok ();
+
+                /* Ignore the new condition if we are inside a false .ELSE
+                 * branch. This way we won't get any errors about undefined
+                 * symbols or similar...
+                 */
+                if (IfCond) {
+                    SetIfCond (D, ConstExpression ());
+                    ExpectSep ();
+                }
+
+                /* Get the new overall condition */
+                CalcOverallIfCond ();
+               break;
+
+           case TOK_ENDIF:
+               /* We're done with this .IF.. - remove the descriptor(s) */
+               FreeIf ();
+
+               /* Be sure not to read the next token until the .IF stack
+                * has been cleanup up, since we may be at end of file.
+                */
+               NextTok ();
+               ExpectSep ();
+
+               /* Get the new overall condition */
+                CalcOverallIfCond ();
+               break;
 
            case TOK_IF:
                D = AllocIf (".IF", 1);
                NextTok ();
                if (IfCond) {
-                   SetIfCond (D, ConstExpression ());
+                    SetIfCond (D, ConstExpression ());
+                    ExpectSep ();
                }
-               IfCond = GetCurrentIfCond ();
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFBLANK:
                D = AllocIf (".IFBLANK", 1);
                NextTok ();
                if (IfCond) {
-                   SetIfCond (D, Tok == TOK_SEP);
+                    if (TokIsSep (CurTok.Tok)) {
+                        SetIfCond (D, 1);
+                    } else {
+                       SetIfCond (D, 0);
+                        SkipUntilSep ();
+                    }
                }
-               IfCond = GetCurrentIfCond ();
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFCONST:
@@ -286,33 +311,35 @@ void DoConditionals (void)
                NextTok ();
                if (IfCond) {
                    ExprNode* Expr = Expression();
-                   SetIfCond (D, IsConstExpr (Expr));
+                   SetIfCond (D, IsConstExpr (Expr, 0));
                    FreeExpr (Expr);
+                   ExpectSep ();
                }
-               IfCond = GetCurrentIfCond ();
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFDEF:
                D = AllocIf (".IFDEF", 1);
                NextTok ();
                if (IfCond) {
-                   if (Tok != TOK_IDENT) {
-                       ErrorSkip (ERR_IDENT_EXPECTED);
-                   } else {
-                       SetIfCond (D, SymIsDef (SVal));
-                       NextTok ();
-                   }
+                           SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
+                   SetIfCond (D, Sym != 0 && SymIsDef (Sym));
                }
-               IfCond = GetCurrentIfCond ();
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFNBLANK:
-               D = AllocIf (".IFNBLANK", 1);
+               D = AllocIf (".IFNBLANK", 1);
                NextTok ();
                if (IfCond) {
-                   SetIfCond (D, Tok != TOK_SEP);
-               }
-               IfCond = GetCurrentIfCond ();
+                    if (TokIsSep (CurTok.Tok)) {
+                        SetIfCond (D, 0);
+                    } else {
+                       SetIfCond (D, 1);
+                        SkipUntilSep ();
+                    }
+               }
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFNCONST:
@@ -320,70 +347,126 @@ void DoConditionals (void)
                NextTok ();
                if (IfCond) {
                    ExprNode* Expr = Expression();
-                   SetIfCond (D, !IsConstExpr (Expr));
+                   SetIfCond (D, !IsConstExpr (Expr, 0));
                    FreeExpr (Expr);
+                   ExpectSep ();
                }
-               IfCond = GetCurrentIfCond ();
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFNDEF:
                D = AllocIf (".IFNDEF", 1);
                NextTok ();
                if (IfCond) {
-                   if (Tok != TOK_IDENT) {
-                       ErrorSkip (ERR_IDENT_EXPECTED);
-                   } else {
-                       SetIfCond (D, !SymIsDef (SVal));
-                       NextTok ();
-                   }
+                   SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
+                   SetIfCond (D, Sym == 0 || !SymIsDef (Sym));
+                   ExpectSep ();
                }
-               IfCond = GetCurrentIfCond ();
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFNREF:
                D = AllocIf (".IFNREF", 1);
                NextTok ();
                if (IfCond) {
-                   if (Tok != TOK_IDENT) {
-                       ErrorSkip (ERR_IDENT_EXPECTED);
-                   } else {
-                       SetIfCond (D, !SymIsRef (SVal));
-                       NextTok ();
-                   }
-               }
-               IfCond = GetCurrentIfCond ();
+                   SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
+                   SetIfCond (D, Sym == 0 || !SymIsRef (Sym));
+                   ExpectSep ();
+               }
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFP02:
+                       D = AllocIf (".IFP02", 1);
+               NextTok ();
+               if (IfCond) {
+                   SetIfCond (D, GetCPU() == CPU_6502);
+               }
+               ExpectSep ();
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFP816:
+               D = AllocIf (".IFP816", 1);
+               NextTok ();
+               if (IfCond) {
+                           SetIfCond (D, GetCPU() == CPU_65816);
+               }
+               ExpectSep ();
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFPC02:
+               D = AllocIf (".IFPC02", 1);
+               NextTok ();
+               if (IfCond) {
+                           SetIfCond (D, GetCPU() == CPU_65C02);
+               }
+               ExpectSep ();
+                CalcOverallIfCond ();
+               break;
+
+           case TOK_IFPSC02:
+               D = AllocIf (".IFPSC02", 1);
+               NextTok ();
+               if (IfCond) {
+                           SetIfCond (D, GetCPU() == CPU_65SC02);
+               }
+               ExpectSep ();
+                CalcOverallIfCond ();
                break;
 
            case TOK_IFREF:
                D = AllocIf (".IFREF", 1);
                NextTok ();
                if (IfCond) {
-                   if (Tok != TOK_IDENT) {
-                       ErrorSkip (ERR_IDENT_EXPECTED);
-                   } else {
-                       SetIfCond (D, SymIsRef (SVal));
-                       NextTok ();
-                   }
+                   SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
+                   SetIfCond (D, Sym != 0 && SymIsRef (Sym));
+                   ExpectSep ();
                }
-               IfCond = GetCurrentIfCond ();
+                CalcOverallIfCond ();
                break;
 
            default:
-               // Skip tokens
+               /* Skip tokens */
                NextTok ();
 
        }
 
-    } while (IfCond == 0 && Tok != TOK_EOF);
+    } while (IfCond == 0 && CurTok.Tok != TOK_EOF);
+}
+
+
+
+int CheckConditionals (void)
+/* Check if the current token is one that starts a conditional directive, and
+ * call DoConditionals if so. Return true if a conditional directive was found,
+ * return false otherwise.
+ */
+{
+    switch (CurTok.Tok) {
+        case TOK_ELSE:
+        case TOK_ELSEIF:
+        case TOK_ENDIF:
+        case TOK_IF:
+        case TOK_IFBLANK:
+        case TOK_IFCONST:
+        case TOK_IFDEF:
+        case TOK_IFNBLANK:
+        case TOK_IFNCONST:
+        case TOK_IFNDEF:
+        case TOK_IFNREF:
+        case TOK_IFP02:
+        case TOK_IFP816:
+        case TOK_IFPC02:
+        case TOK_IFPSC02:
+        case TOK_IFREF:
+            DoConditionals ();
+            return 1;
+
+        default:
+            return 0;
+    }
 }
 
 
@@ -393,6 +476,8 @@ void CheckOpenIfs (void)
  * open .ifs in this file.
  */
 {
+    const LineInfo* LI;
+
     while (1) {
        /* Get the current file number and check if the topmost entry on the
         * .IF stack was inserted with this file number
@@ -402,17 +487,43 @@ void CheckOpenIfs (void)
            /* There are no open .IFs */
            break;
        }
-         
-       if (D->Pos.Name != CurPos.Name) {
+
+        LI = CollConstAt (&D->LineInfos, 0);
+               if (GetSourcePos (LI)->Name != CurTok.Pos.Name) {
            /* The .if is from another file, bail out */
            break;
        }
 
                /* Start of .if is in the file we're about to leave */
-       PError (&D->Pos, ERR_OPEN_IF);
+       LIError (&D->LineInfos, "Conditional assembly branch was never closed");
        FreeIf ();
     }
+
+    /* Calculate the new overall .IF condition */
+    CalcOverallIfCond ();
 }
 
 
 
+unsigned GetIfStack (void)
+/* Get the current .IF stack pointer */
+{
+    return IfCount;
+}
+
+
+
+void CleanupIfStack (unsigned SP)
+/* Cleanup the .IF stack, remove anything above the given stack pointer */
+{
+    while (IfCount > SP) {
+       FreeIf ();
+    }
+
+    /* Calculate the new overall .IF condition */
+    CalcOverallIfCond ();
+}
+
+
+
+