]> git.sur5r.net Git - cc65/blobdiff - src/ca65/pseudo.c
Replaced builtin macro packages with .mac files that are included like ordinary ...
[cc65] / src / ca65 / pseudo.c
index c331f79b540afe012f9fefde9aabbf79213fb694..3f67c2fe65b24750ff680032967cad11ec2993e1 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2010, Ullrich von Bassewitz                                      */
+/* (C) 1998-2012, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
 #include <errno.h>
 
 /* common */
+#include "alignment.h"
 #include "assertion.h"
 #include "bitops.h"
 #include "cddefs.h"
 #include "coll.h"
+#include "filestat.h"
+#include "gentype.h"
+#include "intstack.h"
+#include "scopedefs.h"
 #include "symdefs.h"
 #include "tgttrans.h"
 #include "xmalloc.h"
 #include "error.h"
 #include "expr.h"
 #include "feature.h"
+#include "filetab.h"
 #include "global.h"
 #include "incpath.h"
 #include "instr.h"
 #include "listing.h"
-#include "macpack.h"
 #include "macro.h"
 #include "nexttok.h"
 #include "objcode.h"
@@ -70,6 +75,7 @@
 #include "repeat.h"
 #include "segment.h"
 #include "sizeof.h"
+#include "span.h"
 #include "spool.h"
 #include "struct.h"
 #include "symbol.h"
@@ -86,6 +92,9 @@
 /* Keyword we're about to handle */
 static StrBuf Keyword = STATIC_STRBUF_INITIALIZER;
 
+/* CPU stack */
+static IntStack CPUStack = STATIC_INTSTACK_INITIALIZER;
+
 /* Segment stack */
 #define MAX_PUSHED_SEGMENTS     16
 static Collection SegStack = STATIC_COLLECTION_INITIALIZER;
@@ -124,7 +133,7 @@ static unsigned char OptionalAddrSize (void)
  */
 {
     unsigned AddrSize = ADDR_SIZE_DEFAULT;
-    if (Tok == TOK_COLON) {
+    if (CurTok.Tok == TOK_COLON) {
         NextTok ();
         AddrSize = ParseAddrSize ();
         if (!ValidAddrSizeForCPU (AddrSize)) {
@@ -147,20 +156,20 @@ static void SetBoolOption (unsigned char* Flag)
        "ON",
     };
 
-    if (Tok == TOK_PLUS) {
+    if (CurTok.Tok == TOK_PLUS) {
                *Flag = 1;
        NextTok ();
-    } else if (Tok == TOK_MINUS) {
+    } else if (CurTok.Tok == TOK_MINUS) {
        *Flag = 0;
        NextTok ();
-    } else if (Tok == TOK_IDENT) {
+    } else if (CurTok.Tok == TOK_IDENT) {
                /* Map the keyword to a number */
                switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
            case 0:     *Flag = 0; NextTok ();                  break;
            case 1:     *Flag = 1; NextTok ();                  break;
            default:    ErrorSkip ("`on' or `off' expected");   break;
        }
-    } else if (TokIsSep (Tok)) {
+    } else if (TokIsSep (CurTok.Tok)) {
        /* Without anything assume switch on */
        *Flag = 1;
     } else {
@@ -176,10 +185,10 @@ static void ExportWithAssign (SymEntry* Sym, unsigned char AddrSize, unsigned Fl
     /* The name and optional address size spec may be followed by an assignment
      * or equal token.
      */
-    if (Tok == TOK_ASSIGN || Tok == TOK_EQ) {
+    if (CurTok.Tok == TOK_ASSIGN || CurTok.Tok == TOK_EQ) {
 
         /* Assignment means the symbol is a label */
-        if (Tok == TOK_ASSIGN) {
+        if (CurTok.Tok == TOK_ASSIGN) {
             Flags |= SF_LABEL;
         }
 
@@ -207,13 +216,13 @@ static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned),
     while (1) {
 
         /* We need an identifier here */
-       if (Tok != TOK_IDENT) {
+       if (CurTok.Tok != TOK_IDENT) {
                    ErrorSkip ("Identifier expected");
            return;
        }
 
         /* Find the symbol table entry, allocate a new one if necessary */
-        Sym = SymFind (CurrentScope, &SVal, SYM_ALLOC_NEW);
+        Sym = SymFind (CurrentScope, &CurTok.SVal, SYM_ALLOC_NEW);
 
         /* Skip the name */
         NextTok ();
@@ -228,7 +237,7 @@ static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned),
         Func (Sym, AddrSize, Flags);
 
         /* More symbols? */
-       if (Tok == TOK_COMMA) {
+       if (CurTok.Tok == TOK_COMMA) {
            NextTok ();
        } else {
            break;
@@ -243,7 +252,7 @@ static long IntArg (long Min, long Max)
  * and return -1 in this case.
  */
 {
-    if (Tok == TOK_IDENT && SB_CompareStr (&SVal, "unlimited") == 0) {
+    if (CurTok.Tok == TOK_IDENT && SB_CompareStr (&CurTok.SVal, "unlimited") == 0) {
        NextTok ();
        return -1;
     } else {
@@ -268,7 +277,7 @@ static void ConDes (const StrBuf* Name, unsigned Type)
     SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
 
     /* Optional constructor priority */
-    if (Tok == TOK_COMMA) {
+    if (CurTok.Tok == TOK_COMMA) {
        /* Priority value follows */
        NextTok ();
        Prio = ConstExpression ();
@@ -288,8 +297,35 @@ static void ConDes (const StrBuf* Name, unsigned Type)
 
 
 
+static StrBuf* GenArrayType (StrBuf* Type, unsigned SpanSize,
+                             const char* ElementType,
+                             unsigned ElementTypeLen)
+/* Create an array (or single data) of the given type. SpanSize is the size
+ * of the span, ElementType is a string that encodes the element data type.
+ * The function returns Type.
+ */
+{
+    /* Get the size of the element type */
+    unsigned ElementSize = GT_GET_SIZE (ElementType[0]);
+
+    /* Get the number of array elements */
+    unsigned ElementCount = SpanSize / ElementSize;
+
+    /* The span size must be divideable by the element size */
+    CHECK ((SpanSize % ElementSize) == 0);
+
+    /* Encode the array */
+    GT_AddArray (Type, ElementCount);
+    SB_AppendBuf (Type, ElementType, ElementTypeLen);
+
+    /* Return the pointer to the created array type */
+    return Type;
+}
+
+
+
 /*****************************************************************************/
-/*                            Handler functions                             */
+/*                            Handler functions                             */
 /*****************************************************************************/
 
 
@@ -323,19 +359,34 @@ static void DoA8 (void)
 static void DoAddr (void)
 /* Define addresses */
 {
+    /* Element type for the generated array */
+    static const char EType[2] = { GT_PTR, GT_VOID };
+
+    /* Record type information */
+    Span* S = OpenSpan ();
+    StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+    /* Parse arguments */
     while (1) {
-       if (GetCPU() == CPU_65816) {
-                   EmitWord (GenWordExpr (Expression ()));
-       } else {
+        ExprNode* Expr = Expression ();
+       if (GetCPU () == CPU_65816 || ForceRange) {
            /* Do a range check */
-           EmitWord (Expression ());
-               }
-       if (Tok != TOK_COMMA) {
+            Expr = GenWordExpr (Expr);
+       }
+        EmitWord (Expr);
+       if (CurTok.Tok != TOK_COMMA) {
            break;
        } else {
            NextTok ();
        }
     }
+
+    /* Close the span, then add type information to it */
+    S = CloseSpan (S);
+    SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+    /* Free the strings */
+    SB_Done (&Type);
 }
 
 
@@ -343,37 +394,31 @@ static void DoAddr (void)
 static void DoAlign (void)
 /* Align the PC to some boundary */
 {
-    long Val;
-    long Align;
-    unsigned Bit;
+    long FillVal;
+    long Alignment;
 
     /* Read the alignment value */
-    Align = ConstExpression ();
-    if (Align <= 0 || Align > 0x10000) {
-               ErrorSkip ("Range error");
-       return;
+    Alignment = ConstExpression ();
+    if (Alignment <= 0 || (unsigned long) Alignment > MAX_ALIGNMENT) {
+        ErrorSkip ("Range error");
+        return;
     }
 
     /* Optional value follows */
-    if (Tok == TOK_COMMA) {
-       NextTok ();
-       Val = ConstExpression ();
-       /* We need a byte value here */
-       if (!IsByteRange (Val)) {
-                   ErrorSkip ("Range error");
-           return;
-       }
+    if (CurTok.Tok == TOK_COMMA) {
+        NextTok ();
+        FillVal = ConstExpression ();
+        /* We need a byte value here */
+        if (!IsByteRange (FillVal)) {
+            ErrorSkip ("Range error");
+            return;
+        }
     } else {
-       Val = -1;
+        FillVal = -1;
     }
 
-    /* Check if the alignment is a power of two */
-    Bit = BitFind (Align);
-    if (Align != (0x01L << Bit)) {
-       Error ("Alignment value must be a power of 2");
-    } else {
-       SegAlign (Bit, (int) Val);
-    }
+    /* Generate the alignment */
+    SegAlign (Alignment, (int) FillVal);
 }
 
 
@@ -383,16 +428,16 @@ static void DoASCIIZ (void)
 {
     while (1) {
        /* Must have a string constant */
-       if (Tok != TOK_STRCON) {
+       if (CurTok.Tok != TOK_STRCON) {
                    ErrorSkip ("String constant expected");
            return;
        }
 
        /* Translate into target charset and emit */
-               TgtTranslateStrBuf (&SVal);
-               EmitStrBuf (&SVal);
+               TgtTranslateStrBuf (&CurTok.SVal);
+               EmitStrBuf (&CurTok.SVal);
        NextTok ();
-       if (Tok == TOK_COMMA) {
+       if (CurTok.Tok == TOK_COMMA) {
            NextTok ();
        } else {
            break;
@@ -421,7 +466,7 @@ static void DoAssert (void)
     ConsumeComma ();
 
     /* Action follows */
-    if (Tok != TOK_IDENT) {
+    if (CurTok.Tok != TOK_IDENT) {
         ErrorSkip ("Identifier expected");
         return;
     }
@@ -461,13 +506,13 @@ static void DoAssert (void)
     /* We can have an optional message. If no message is present, use
      * "Assertion failed".
      */
-    if (Tok == TOK_COMMA) {
+    if (CurTok.Tok == TOK_COMMA) {
 
         /* Skip the comma */
         NextTok ();
 
         /* Read the message */
-        if (Tok != TOK_STRCON) {
+        if (CurTok.Tok != TOK_STRCON) {
             ErrorSkip ("String constant expected");
             return;
         }
@@ -475,7 +520,7 @@ static void DoAssert (void)
         /* Translate the message into a string id. We can then skip the input
          * string.
          */
-        Msg = GetStrBufId (&SVal);
+        Msg = GetStrBufId (&CurTok.SVal);
         NextTok ();
 
     } else {
@@ -503,7 +548,7 @@ static void DoBankBytes (void)
 {
     while (1) {
         EmitByte (FuncBankByte ());
-        if (Tok != TOK_COMMA) {
+        if (CurTok.Tok != TOK_COMMA) {
             break;
         } else {
             NextTok ();
@@ -524,26 +569,41 @@ static void DoBss (void)
 static void DoByte (void)
 /* Define bytes */
 {
+    /* Element type for the generated array */
+    static const char EType[1] = { GT_BYTE };
+
+    /* Record type information */
+    Span* S = OpenSpan ();
+    StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+    /* Parse arguments */
     while (1) {
-       if (Tok == TOK_STRCON) {
+       if (CurTok.Tok == TOK_STRCON) {
            /* A string, translate into target charset and emit */
-                   TgtTranslateStrBuf (&SVal);
-           EmitStrBuf (&SVal);
+                   TgtTranslateStrBuf (&CurTok.SVal);
+           EmitStrBuf (&CurTok.SVal);
            NextTok ();
        } else {
-           EmitByte (Expression ());
+            EmitByte (BoundedExpr (Expression, 1));
        }
-       if (Tok != TOK_COMMA) {
+       if (CurTok.Tok != TOK_COMMA) {
            break;
        } else {
            NextTok ();
            /* Do smart handling of dangling comma */
-           if (Tok == TOK_SEP) {
+           if (CurTok.Tok == TOK_SEP) {
                Error ("Unexpected end of line");
-               break;
+               break;
            }
        }
     }
+
+    /* Close the span, then add type information to it */
+    S = CloseSpan (S);
+    SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+    /* Free the type string */
+    SB_Done (&Type);
 }
 
 
@@ -565,7 +625,7 @@ static void DoCharMap (void)
 
     /* Read the index as numerical value */
     Index = ConstExpression ();
-    if (Index < 0 || Index > 255) {
+    if (Index <= 0 || Index > 255) {
        /* Value out of range */
                ErrorSkip ("Range error");
        return;
@@ -608,16 +668,16 @@ static void DoConDes (void)
     long Type;
 
     /* Symbol name follows */
-    if (Tok != TOK_IDENT) {
+    if (CurTok.Tok != TOK_IDENT) {
        ErrorSkip ("Identifier expected");
        return;
     }
-    SB_Copy (&Name, &SVal);
+    SB_Copy (&Name, &CurTok.SVal);
     NextTok ();
 
     /* Type follows. May be encoded as identifier or numerical */
     ConsumeComma ();
-    if (Tok == TOK_IDENT) {
+    if (CurTok.Tok == TOK_IDENT) {
 
        /* Map the following keyword to a number, then skip it */
        Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
@@ -657,11 +717,11 @@ static void DoConstructor (void)
     StrBuf Name = STATIC_STRBUF_INITIALIZER;
 
     /* Symbol name follows */
-    if (Tok != TOK_IDENT) {
+    if (CurTok.Tok != TOK_IDENT) {
        ErrorSkip ("Identifier expected");
        return;
     }
-    SB_Copy (&Name, &SVal);
+    SB_Copy (&Name, &CurTok.SVal);
     NextTok ();
 
     /* Parse the remainder of the line and export the symbol */
@@ -686,6 +746,7 @@ static void DoDbg (void)
 {
     static const char* Keys[] = {
                "FILE",
+        "FUNC",
        "LINE",
        "SYM",
     };
@@ -693,7 +754,7 @@ static void DoDbg (void)
 
 
     /* We expect a subkey */
-    if (Tok != TOK_IDENT) {
+    if (CurTok.Tok != TOK_IDENT) {
        ErrorSkip ("Identifier expected");
        return;
     }
@@ -707,8 +768,9 @@ static void DoDbg (void)
     /* Check the key and dispatch to a handler */
     switch (Key) {
        case 0:     DbgInfoFile ();             break;
-       case 1:     DbgInfoLine ();             break;
-       case 2:     DbgInfoSym ();              break;
+        case 1:     DbgInfoFunc ();             break;
+       case 2:     DbgInfoLine ();             break;
+       case 3:     DbgInfoSym ();              break;
        default:    ErrorSkip ("Syntax error"); break;
     }
 }
@@ -718,14 +780,29 @@ static void DoDbg (void)
 static void DoDByt (void)
 /* Output double bytes */
 {
+    /* Element type for the generated array */
+    static const char EType[1] = { GT_DBYTE };
+
+    /* Record type information */
+    Span* S = OpenSpan ();
+    StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+    /* Parse arguments */
     while (1) {
-       EmitWord (GenSwapExpr (Expression ()));
-       if (Tok != TOK_COMMA) {
+       EmitWord (GenSwapExpr (BoundedExpr (Expression, 2)));
+       if (CurTok.Tok != TOK_COMMA) {
            break;
        } else {
            NextTok ();
        }
     }
+
+    /* Close the span, then add type information to it */
+    S = CloseSpan (S);
+    SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+    /* Free the type string */
+    SB_Done (&Type);
 }
 
 
@@ -746,17 +823,31 @@ static void DoDefine (void)
 
 
 
+static void DoDelMac (void)
+/* Delete a classic macro */
+{
+    /* We expect an identifier */
+    if (CurTok.Tok != TOK_IDENT) {
+       ErrorSkip ("Identifier expected");
+    } else {
+        MacUndef (&CurTok.SVal, MAC_STYLE_CLASSIC);
+        NextTok ();
+    }
+}
+
+
+
 static void DoDestructor (void)
 /* Export a symbol as destructor */
 {
     StrBuf Name = STATIC_STRBUF_INITIALIZER;
 
     /* Symbol name follows */
-    if (Tok != TOK_IDENT) {
+    if (CurTok.Tok != TOK_IDENT) {
        ErrorSkip ("Identifier expected");
        return;
     }
-    SB_Copy (&Name, &SVal);
+    SB_Copy (&Name, &CurTok.SVal);
     NextTok ();
 
     /* Parse the remainder of the line and export the symbol */
@@ -772,8 +863,8 @@ static void DoDWord (void)
 /* Define dwords */
 {
     while (1) {
-               EmitDWord (Expression ());
-       if (Tok != TOK_COMMA) {
+               EmitDWord (BoundedExpr (Expression, 4));
+       if (CurTok.Tok != TOK_COMMA) {
            break;
        } else {
            NextTok ();
@@ -795,7 +886,7 @@ static void DoEnd (void)
 static void DoEndProc (void)
 /* Leave a lexical level */
 {
-    if (GetCurrentSymTabType () != ST_PROC) {
+    if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label == 0) {
         /* No local scope */
         ErrorSkip ("No open .PROC");
     } else {
@@ -808,7 +899,7 @@ static void DoEndProc (void)
 static void DoEndScope (void)
 /* Leave a lexical level */
 {
-    if ( GetCurrentSymTabType () != ST_SCOPE) {
+    if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label != 0) {
         /* No local scope */
         ErrorSkip ("No open .SCOPE");
     } else {
@@ -821,10 +912,10 @@ static void DoEndScope (void)
 static void DoError (void)
 /* User error */
 {
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
        ErrorSkip ("String constant expected");
     } else {
-               Error ("User error: %m%p", &SVal);
+               Error ("User error: %m%p", &CurTok.SVal);
        SkipUntilSep ();
     }
 }
@@ -863,14 +954,42 @@ static void DoExportZP (void)
 static void DoFarAddr (void)
 /* Define far addresses (24 bit) */
 {
+    /* Element type for the generated array */
+    static const char EType[2] = { GT_FAR_PTR, GT_VOID };
+
+    /* Record type information */
+    Span* S = OpenSpan ();
+    StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+    /* Parse arguments */
     while (1) {
-               EmitFarAddr (Expression ());
-       if (Tok != TOK_COMMA) {
+               EmitFarAddr (BoundedExpr (Expression, 3));
+       if (CurTok.Tok != TOK_COMMA) {
            break;
        } else {
            NextTok ();
        }
     }
+
+    /* Close the span, then add type information to it */
+    S = CloseSpan (S);
+    SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+    /* Free the type string */
+    SB_Done (&Type);
+}
+
+
+
+static void DoFatal (void)
+/* Fatal user error */
+{
+    if (CurTok.Tok != TOK_STRCON) {
+       ErrorSkip ("String constant expected");
+    } else {
+               Fatal ("User error: %m%p", &CurTok.SVal);
+       SkipUntilSep ();
+    }
 }
 
 
@@ -882,7 +1001,7 @@ static void DoFeature (void)
     while (1) {
 
        /* We expect an identifier */
-       if (Tok != TOK_IDENT) {
+       if (CurTok.Tok != TOK_IDENT) {
            ErrorSkip ("Identifier expected");
            return;
        }
@@ -891,9 +1010,9 @@ static void DoFeature (void)
        LocaseSVal ();
 
        /* Set the feature and check for errors */
-       if (SetFeature (&SVal) == FEAT_UNKNOWN) {
+       if (SetFeature (&CurTok.SVal) == FEAT_UNKNOWN) {
            /* Not found */
-           ErrorSkip ("Invalid feature: `%m%p'", &SVal);
+           ErrorSkip ("Invalid feature: `%m%p'", &CurTok.SVal);
            return;
        } else {
            /* Skip the keyword */
@@ -901,7 +1020,7 @@ static void DoFeature (void)
        }
 
        /* Allow more than one keyword */
-       if (Tok == TOK_COMMA) {
+       if (CurTok.Tok == TOK_COMMA) {
            NextTok ();
        } else {
            break;
@@ -917,7 +1036,7 @@ static void DoFileOpt (void)
     long OptNum;
 
     /* The option type may be given as a keyword or as a number. */
-    if (Tok == TOK_IDENT) {
+    if (CurTok.Tok == TOK_IDENT) {
 
        /* Option given as keyword */
        static const char* Keys [] = {
@@ -939,7 +1058,7 @@ static void DoFileOpt (void)
        ConsumeComma ();
 
        /* We accept only string options for now */
-       if (Tok != TOK_STRCON) {
+       if (CurTok.Tok != TOK_STRCON) {
            ErrorSkip ("String constant expected");
            return;
        }
@@ -949,17 +1068,17 @@ static void DoFileOpt (void)
 
            case 0:
                /* Author */
-               OptAuthor (&SVal);
+               OptAuthor (&CurTok.SVal);
                break;
 
            case 1:
                /* Comment */
-               OptComment (&SVal);
+               OptComment (&CurTok.SVal);
                break;
 
            case 2:
                /* Compiler */
-               OptCompiler (&SVal);
+               OptCompiler (&CurTok.SVal);
                break;
 
            default:
@@ -983,13 +1102,13 @@ static void DoFileOpt (void)
        ConsumeComma ();
 
        /* We accept only string options for now */
-       if (Tok != TOK_STRCON) {
+       if (CurTok.Tok != TOK_STRCON) {
            ErrorSkip ("String constant expected");
            return;
        }
 
        /* Insert the option */
-       OptStr ((unsigned char) OptNum, &SVal);
+       OptStr ((unsigned char) OptNum, &CurTok.SVal);
 
        /* Done */
        NextTok ();
@@ -1026,7 +1145,7 @@ static void DoHiBytes (void)
 {
     while (1) {
         EmitByte (FuncHiByte ());
-        if (Tok != TOK_COMMA) {
+        if (CurTok.Tok != TOK_COMMA) {
             break;
         } else {
             NextTok ();
@@ -1082,27 +1201,28 @@ static void DoIncBin (void)
 /* Include a binary file */
 {
     StrBuf Name = STATIC_STRBUF_INITIALIZER;
+    struct stat StatBuf;
     long Start = 0L;
     long Count = -1L;
     long Size;
     FILE* F;
 
     /* Name must follow */
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
        ErrorSkip ("String constant expected");
        return;
     }
-    SB_Copy (&Name, &SVal);
+    SB_Copy (&Name, &CurTok.SVal);
     SB_Terminate (&Name);
     NextTok ();
 
     /* A starting offset may follow */
-    if (Tok == TOK_COMMA) {
+    if (CurTok.Tok == TOK_COMMA) {
        NextTok ();
        Start = ConstExpression ();
 
        /* And a length may follow */
-       if (Tok == TOK_COMMA) {
+       if (CurTok.Tok == TOK_COMMA) {
            NextTok ();
            Count = ConstExpression ();
        }
@@ -1114,30 +1234,46 @@ static void DoIncBin (void)
     if (F == 0) {
 
                /* Search for the file in the binary include directory */
-       char* PathName = FindInclude (SB_GetConstBuf (&Name), INC_BIN);
+       char* PathName = SearchFile (BinSearchPath, SB_GetConstBuf (&Name));
                if (PathName == 0 || (F = fopen (PathName, "rb")) == 0) {
            /* Not found or cannot open, print an error and bail out */
                    ErrorSkip ("Cannot open include file `%m%p': %s", &Name, strerror (errno));
+            xfree (PathName);
+            goto ExitPoint;
        }
 
+        /* Remember the new file name */
+        SB_CopyStr (&Name, PathName);
+
        /* Free the allocated memory */
        xfree (PathName);
-
-        /* If we had an error before, bail out now */
-        if (F == 0) {
-            goto ExitPoint;
-        }
     }
 
     /* Get the size of the file */
     fseek (F, 0, SEEK_END);
     Size = ftell (F);
 
+    /* Stat the file and remember the values. There a race condition here,
+     * since we cannot use fileno() (non standard identifier in standard
+     * header file), and therefore not fstat. When using stat with the
+     * file name, there's a risk that the file was deleted and recreated
+     * while it was open. Since mtime and size are only used to check
+     * if a file has changed in the debugger, we will ignore this problem
+     * here.
+     */
+    SB_Terminate (&Name);
+    if (FileStat (SB_GetConstBuf (&Name), &StatBuf) != 0) {
+        Fatal ("Cannot stat input file `%m%p': %s", &Name, strerror (errno));
+    }
+
+    /* Add the file to the input file table */
+    AddFile (&Name, FT_BINARY, Size, StatBuf.st_mtime);
+
     /* If a count was not given, calculate it now */
     if (Count < 0) {
-       Count = Size - Start;
-       if (Count < 0) {
-           /* Nothing to read - flag this as a range error */
+       Count = Size - Start;
+       if (Count < 0) {
+           /* Nothing to read - flag this as a range error */
            ErrorSkip ("Range error");
            goto Done;
        }
@@ -1191,11 +1327,11 @@ static void DoInclude (void)
 /* Include another file */
 {
     /* Name must follow */
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
        ErrorSkip ("String constant expected");
     } else {
-        SB_Terminate (&SVal);
-       if (NewInputFile (SB_GetConstBuf (&SVal)) == 0) {
+        SB_Terminate (&CurTok.SVal);
+       if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) {
             /* Error opening the file, skip remainder of line */
             SkipUntilSep ();
         }
@@ -1210,11 +1346,11 @@ static void DoInterruptor (void)
     StrBuf Name = STATIC_STRBUF_INITIALIZER;
 
     /* Symbol name follows */
-    if (Tok != TOK_IDENT) {
+    if (CurTok.Tok != TOK_IDENT) {
        ErrorSkip ("Identifier expected");
        return;
     }
-    SB_Copy (&Name, &SVal);
+    SB_Copy (&Name, &CurTok.SVal);
     NextTok ();
 
     /* Parse the remainder of the line and export the symbol */
@@ -1270,7 +1406,7 @@ static void DoLoBytes (void)
 {
     while (1) {
         EmitByte (FuncLoByte ());
-        if (Tok != TOK_COMMA) {
+        if (CurTok.Tok != TOK_COMMA) {
             break;
         } else {
             NextTok ();
@@ -1290,13 +1426,13 @@ static void DoListBytes (void)
 static void DoLocalChar (void)
 /* Define the character that starts local labels */
 {
-    if (Tok != TOK_CHARCON) {
+    if (CurTok.Tok != TOK_CHARCON) {
        ErrorSkip ("Character constant expected");
     } else {
-       if (IVal != '@' && IVal != '?') {
+       if (CurTok.IVal != '@' && CurTok.IVal != '?') {
            Error ("Invalid start character for locals");
        } else {
-           LocalStart = (char) IVal;
+           LocalStart = (char) CurTok.IVal;
                }
        NextTok ();
     }
@@ -1307,28 +1443,16 @@ static void DoLocalChar (void)
 static void DoMacPack (void)
 /* Insert a macro package */
 {
-    int Package;
-
     /* We expect an identifier */
-    if (Tok != TOK_IDENT) {
+    if (CurTok.Tok != TOK_IDENT) {
        ErrorSkip ("Identifier expected");
-       return;
-    }
-
-    /* Search for the macro package name */
-    LocaseSVal ();
-    Package = MacPackFind (&SVal);
-    if (Package < 0) {
-       /* Not found */
-       ErrorSkip ("Invalid macro package");
-       return;
-    }
-
-    /* Insert the package. If this fails, skip the remainder of the line to
-     * avoid additional error messages.
-     */
-    if (MacPackInsert (Package) == 0) {
-        SkipUntilSep ();
+    } else {
+        SB_AppendStr (&CurTok.SVal, ".mac");
+        SB_Terminate (&CurTok.SVal);
+       if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) {
+            /* Error opening the file, skip remainder of line */
+            SkipUntilSep ();
+        }
     }
 }
 
@@ -1366,13 +1490,15 @@ static void DoOrg (void)
 static void DoOut (void)
 /* Output a string */
 {
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
        ErrorSkip ("String constant expected");
     } else {
        /* Output the string and be sure to flush the output to keep it in
         * sync with any error messages if the output is redirected to a file.
         */
-       printf ("%.*s\n", (int) SB_GetLen (&SVal), SB_GetConstBuf (&SVal));
+       printf ("%.*s\n",
+                (int) SB_GetLen (&CurTok.SVal),
+                SB_GetConstBuf (&CurTok.SVal));
        fflush (stdout);
        NextTok ();
     }
@@ -1412,6 +1538,21 @@ static void DoPageLength (void)
 
 
 
+static void DoPopCPU (void)
+/* Pop an old CPU setting from the CPU stack */
+{
+    /* Must have a CPU on the stack */
+    if (IS_IsEmpty (&CPUStack)) {
+        ErrorSkip ("CPU stack is empty");
+        return;
+    }
+
+    /* Set the CPU to the value popped from stack */
+    SetCPU (IS_Pop (&CPUStack));
+}
+
+
+
 static void DoPopSeg (void)
 /* Pop an old segment from the segment stack */
 {
@@ -1440,13 +1581,13 @@ static void DoProc (void)
 {
     StrBuf Name = STATIC_STRBUF_INITIALIZER;
     unsigned char AddrSize;
+    SymEntry* Sym = 0;
 
-    if (Tok == TOK_IDENT) {
 
-        SymEntry* Sym;
+    if (CurTok.Tok == TOK_IDENT) {
 
-       /* The new scope has a name. Remember it. */
-        SB_Copy (&Name, &SVal);
+       /* The new scope has a name. Remember it. */
+        SB_Copy (&Name, &CurTok.SVal);
 
         /* Search for the symbol, generate a new one if needed */
                Sym = SymFind (CurrentScope, &Name, SYM_ALLOC_NEW);
@@ -1470,7 +1611,7 @@ static void DoProc (void)
     }
 
     /* Enter a new scope */
-    SymEnterLevel (&Name, ST_PROC, AddrSize);
+    SymEnterLevel (&Name, SCOPE_SCOPE, AddrSize, Sym);
 
     /* Free memory for Name */
     SB_Done (&Name);
@@ -1486,6 +1627,21 @@ static void DoPSC02 (void)
 
 
 
+static void DoPushCPU (void)
+/* Push the current CPU setting onto the CPU stack */
+{
+    /* Can only push a limited size of segments */
+    if (IS_IsFull (&CPUStack)) {
+        ErrorSkip ("CPU stack overflow");
+        return;
+    }
+
+    /* Get the current segment and push it */
+    IS_Push (&CPUStack, GetCPU ());
+}
+
+
+
 static void DoPushSeg (void)
 /* Push the current segment onto the segment stack */
 {
@@ -1528,7 +1684,7 @@ static void DoRes (void)
        ErrorSkip ("Range error");
        return;
     }
-    if (Tok == TOK_COMMA) {
+    if (CurTok.Tok == TOK_COMMA) {
        NextTok ();
        Val = ConstExpression ();
        /* We need a byte value here */
@@ -1565,10 +1721,10 @@ static void DoScope (void)
     unsigned char AddrSize;
 
 
-    if (Tok == TOK_IDENT) {
+    if (CurTok.Tok == TOK_IDENT) {
 
        /* The new scope has a name. Remember and skip it. */
-        SB_Copy (&Name, &SVal);
+        SB_Copy (&Name, &CurTok.SVal);
         NextTok ();
 
     } else {
@@ -1582,7 +1738,7 @@ static void DoScope (void)
     AddrSize = OptionalAddrSize ();
 
     /* Enter the new scope */
-    SymEnterLevel (&Name, ST_SCOPE, AddrSize);
+    SymEnterLevel (&Name, SCOPE_SCOPE, AddrSize, 0);
 
     /* Free memory for Name */
     SB_Done (&Name);
@@ -1596,12 +1752,12 @@ static void DoSegment (void)
     StrBuf Name = STATIC_STRBUF_INITIALIZER;
     SegDef Def;
 
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
        ErrorSkip ("String constant expected");
     } else {
 
        /* Save the name of the segment and skip it */
-       SB_Copy (&Name, &SVal);
+       SB_Copy (&Name, &CurTok.SVal);
        NextTok ();
 
         /* Use the name for the segment definition */
@@ -1625,14 +1781,14 @@ static void DoSetCPU (void)
 /* Switch the CPU instruction set */
 {
     /* We expect an identifier */
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
        ErrorSkip ("String constant expected");
     } else {
         cpu_t CPU;
 
         /* Try to find the CPU */
-        SB_Terminate (&SVal);
-        CPU = FindCPU (SB_GetConstBuf (&SVal));
+        SB_Terminate (&CurTok.SVal);
+        CPU = FindCPU (SB_GetConstBuf (&CurTok.SVal));
 
         /* Switch to the new CPU */
         SetCPU (CPU);
@@ -1676,7 +1832,7 @@ static void DoTag (void)
         ErrorSkip ("Unknown struct");
         return;
     }
-    if (GetSymTabType (Struct) != ST_STRUCT) {
+    if (GetSymTabType (Struct) != SCOPE_STRUCT) {
         ErrorSkip ("Not a struct");
         return;
     }
@@ -1691,7 +1847,7 @@ static void DoTag (void)
     }
 
     /* Optional multiplicator may follow */
-    if (Tok == TOK_COMMA) {
+    if (CurTok.Tok == TOK_COMMA) {
         long Multiplicator;
         NextTok ();
         Multiplicator = ConstExpression ();
@@ -1709,6 +1865,29 @@ static void DoTag (void)
 
 
 
+static void DoUnDef (void)
+/* Undefine a define style macro */
+{
+    /* The function is called with the .UNDEF token in place, because we need
+     * to disable .define macro expansions before reading the next token.
+     * Otherwise the name of the macro would be expanded, so we would never
+     * see it.
+     */
+    DisableDefineStyleMacros ();
+    NextTok ();
+    EnableDefineStyleMacros ();
+
+    /* We expect an identifier */
+    if (CurTok.Tok != TOK_IDENT) {
+       ErrorSkip ("Identifier expected");
+    } else {
+        MacUndef (&CurTok.SVal, MAC_STYLE_DEFINE);
+        NextTok ();
+    }
+}
+
+
+
 static void DoUnexpected (void)
 /* Got an unexpected keyword */
 {
@@ -1721,10 +1900,10 @@ static void DoUnexpected (void)
 static void DoWarning (void)
 /* User warning */
 {
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
        ErrorSkip ("String constant expected");
     } else {
-               Warning (0, "User warning: %m%p", &SVal);
+               Warning (0, "User warning: %m%p", &CurTok.SVal);
        SkipUntilSep ();
     }
 }
@@ -1734,14 +1913,29 @@ static void DoWarning (void)
 static void DoWord (void)
 /* Define words */
 {
+    /* Element type for the generated array */
+    static const char EType[1] = { GT_WORD };
+
+    /* Record type information */
+    Span* S = OpenSpan ();
+    StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+    /* Parse arguments */
     while (1) {
-               EmitWord (Expression ());
-       if (Tok != TOK_COMMA) {
+               EmitWord (BoundedExpr (Expression, 2));
+       if (CurTok.Tok != TOK_COMMA) {
            break;
        } else {
            NextTok ();
        }
     }
+
+    /* Close the span, then add type information to it */
+    S = CloseSpan (S);
+    SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+    /* Free the type string */
+    SB_Done (&Type);
 }
 
 
@@ -1755,21 +1949,21 @@ static void DoZeropage (void)
 
 
 /*****************************************************************************/
-/*                               Table data                                 */
+/*                               Table data                                 */
 /*****************************************************************************/
 
 
 
 /* Control commands flags */
 enum {
-    ccNone     = 0x0000,               /* No special flags */
-    ccKeepToken        = 0x0001                /* Do not skip the current token */
+    ccNone     = 0x0000,               /* No special flags */
+    ccKeepToken        = 0x0001                /* Do not skip the current token */
 };
 
 /* Control command table */
 typedef struct CtrlDesc CtrlDesc;
 struct CtrlDesc {
-    unsigned           Flags;                  /* Flags for this directive */
+    unsigned           Flags;                  /* Flags for this directive */
     void               (*Handler) (void);      /* Command handler */
 };
 
@@ -1782,6 +1976,7 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,          DoASCIIZ        },
     { ccNone,           DoAssert        },
     { ccNone,          DoAutoImport    },
+    { ccNone,           DoUnexpected    },      /* .BANK */
     { ccNone,          DoUnexpected    },      /* .BANKBYTE */
     { ccNone,           DoBankBytes     },
     { ccNone,          DoUnexpected    },      /* .BLANK */
@@ -1801,6 +1996,7 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,          DoDebugInfo     },
     { ccNone,          DoDefine        },
     { ccNone,          DoUnexpected    },      /* .DEFINED */
+    { ccNone,           DoDelMac        },
     { ccNone,          DoDestructor    },
     { ccNone,          DoDWord         },
     { ccKeepToken,     DoConditionals  },      /* .ELSE */
@@ -1820,6 +2016,7 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,          DoExport        },
     { ccNone,          DoExportZP      },
     { ccNone,          DoFarAddr       },
+    { ccNone,                  DoFatal         },
     { ccNone,          DoFeature       },
     { ccNone,          DoFileOpt       },
     { ccNone,           DoForceImport   },
@@ -1844,7 +2041,7 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccKeepToken,     DoConditionals  },      /* .IFP816 */
     { ccKeepToken,     DoConditionals  },      /* .IFPC02 */
     { ccKeepToken,     DoConditionals  },      /* .IFPSC02 */
-    { ccKeepToken,     DoConditionals  },      /* .IFREF */
+    { ccKeepToken,     DoConditionals  },      /* .IFREF */
     { ccNone,          DoImport        },
     { ccNone,          DoImportZP      },
     { ccNone,          DoIncBin        },
@@ -1865,17 +2062,19 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,                  DoUnexpected    },      /* .MAX */
     { ccNone,                  DoInvalid       },      /* .MID */
     { ccNone,                  DoUnexpected    },      /* .MIN */
-    { ccNone,          DoNull          },             
-    { ccNone,          DoOrg           },
+    { ccNone,          DoNull          },
+    { ccNone,          DoOrg           },
     { ccNone,          DoOut           },
     { ccNone,          DoP02           },
     { ccNone,          DoP816          },
     { ccNone,                  DoPageLength    },
     { ccNone,          DoUnexpected    },      /* .PARAMCOUNT */
     { ccNone,          DoPC02          },
+    { ccNone,           DoPopCPU        },
     { ccNone,           DoPopSeg        },
     { ccNone,          DoProc          },
     { ccNone,                  DoPSC02         },
+    { ccNone,           DoPushCPU       },
     { ccNone,           DoPushSeg       },
     { ccNone,          DoUnexpected    },      /* .REFERENCED */
     { ccNone,          DoReloc         },
@@ -1898,10 +2097,11 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,           DoTag           },
     { ccNone,          DoUnexpected    },      /* .TCOUNT */
     { ccNone,                  DoUnexpected    },      /* .TIME */
+    { ccKeepToken,      DoUnDef         },
     { ccNone,           DoUnion         },
     { ccNone,           DoUnexpected    },      /* .VERSION */
     { ccNone,          DoWarning       },
-    { ccNone,          DoWord          },
+    { ccNone,          DoWord          },
     { ccNone,                  DoUnexpected    },      /* .XMATCH */
     { ccNone,          DoZeropage      },
 };
@@ -1909,7 +2109,7 @@ static CtrlDesc CtrlCmdTab [] = {
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                          Code                                    */
 /*****************************************************************************/
 
 
@@ -1920,7 +2120,7 @@ void HandlePseudo (void)
     CtrlDesc* D;
 
     /* Calculate the index into the table */
-    unsigned Index = Tok - TOK_FIRSTPSEUDO;
+    unsigned Index = CurTok.Tok - TOK_FIRSTPSEUDO;
 
     /* Safety check */
     if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
@@ -1934,7 +2134,7 @@ void HandlePseudo (void)
 
     /* Remember the instruction, then skip it if needed */
     if ((D->Flags & ccKeepToken) == 0) {
-       SB_Copy (&Keyword, &SVal);
+       SB_Copy (&Keyword, &CurTok.SVal);
        NextTok ();
     }
 
@@ -1944,11 +2144,14 @@ void HandlePseudo (void)
 
 
 
-void SegStackCheck (void)
-/* Check if the segment stack is empty at end of assembly */
+void CheckPseudo (void)
+/* Check if the stacks are empty at end of assembly */
 {
     if (CollCount (&SegStack) != 0) {
-        Error ("Segment stack is not empty");
+        Warning (1, "Segment stack is not empty");
+    }
+    if (!IS_IsEmpty (&CPUStack)) {
+        Warning (1, "CPU stack is not empty");
     }
 }