]> git.sur5r.net Git - cc65/blobdiff - src/ca65/pseudo.c
Allow optional assignments in .export and .exportzp statements.
[cc65] / src / ca65 / pseudo.c
index 6e815c87a3748f7b23b2389414ef57a6d61b1bb4..e7e5d1a6eaec6edbf568786f1ad9d1dcb385d83d 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2000 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@musoftware.de                                            */
+/* (C) 1998-2007, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 #include <errno.h>
 
 /* common */
+#include "assertdefs.h"
 #include "bitops.h"
 #include "cddefs.h"
-#include "check.h"
+#include "coll.h"
 #include "symdefs.h"
 #include "tgttrans.h"
+#include "xmalloc.h"
 
 /* ca65 */
+#include "anonname.h"
+#include "asserts.h"
 #include "condasm.h"
 #include "dbginfo.h"
+#include "enum.h"
 #include "error.h"
 #include "expr.h"
 #include "feature.h"
 #include "global.h"
+#include "incpath.h"
 #include "instr.h"
 #include "listing.h"
 #include "macpack.h"
 #include "nexttok.h"
 #include "objcode.h"
 #include "options.h"
+#include "pseudo.h"
 #include "repeat.h"
+#include "segment.h"
+#include "sizeof.h"
+#include "spool.h"
+#include "struct.h"
+#include "symbol.h"
 #include "symtab.h"
-#include "pseudo.h"
 
 
 
 
 
 /* Keyword we're about to handle */
-static char Keyword [sizeof (SVal)+1] = ".";
+static char Keyword [sizeof (SVal)+1];
+
+/* Segment stack */
+#define MAX_PUSHED_SEGMENTS     16
+static Collection SegStack = STATIC_COLLECTION_INITIALIZER;
 
 
 
@@ -103,6 +118,22 @@ static void DoInvalid (void);
 
 
 
+static unsigned char OptionalAddrSize (void)
+/* If a colon follows, parse an optional address size spec and return it.
+ * Otherwise return ADDR_SIZE_DEFAULT.
+ */
+{
+    unsigned AddrSize = ADDR_SIZE_DEFAULT;
+    if (Tok == TOK_COLON) {
+        NextTok ();
+        AddrSize = ParseAddrSize ();
+        NextTok ();
+    }
+    return AddrSize;
+}
+
+
+
 static void SetBoolOption (unsigned char* Flag)
 /* Read a on/off/+/- option and set flag accordingly */
 {
@@ -120,30 +151,78 @@ static void SetBoolOption (unsigned char* Flag)
     } else if (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 (ERR_ONOFF_EXPECTED); break;
+           case 0:     *Flag = 0; NextTok ();                  break;
+           case 1:     *Flag = 1; NextTok ();                  break;
+           default:    ErrorSkip ("`on' or `off' expected");   break;
        }
-    } else if (Tok == TOK_SEP || Tok == TOK_EOF) {
+    } else if (TokIsSep (Tok)) {
        /* Without anything assume switch on */
        *Flag = 1;
     } else {
-               ErrorSkip (ERR_ONOFF_EXPECTED);
+               ErrorSkip ("`on' or `off' expected");
     }
 }
 
 
 
-static void ExportImport (void (*SymFunc) (const char*, int), int ZP)
+static void ExportWithAssign (SymEntry* Sym, unsigned char AddrSize, unsigned Flags)
+/* Allow to assign the value of an export in an .export statement */
+{
+    /* The name and optional address size spec may be followed by an assignment
+     * or equal token.
+     */
+    if (Tok == TOK_ASSIGN || Tok == TOK_EQ) {
+
+        /* Assignment means the symbol is a label */
+        if (Tok == TOK_ASSIGN) {
+            Flags |= SF_LABEL;
+        }
+
+        /* Skip the assignment token */
+        NextTok ();
+
+        /* Define the symbol with the expression following the '=' */
+        SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags);
+
+    }
+
+    /* Now export the symbol */
+    SymExport (Sym, AddrSize, Flags);
+}
+
+
+
+static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned),
+                          unsigned char DefAddrSize, unsigned Flags)
 /* Export or import symbols */
 {
+    SymEntry* Sym;
+    unsigned char AddrSize;
+
     while (1) {
+
+        /* We need an identifier here */
        if (Tok != TOK_IDENT) {
-                   ErrorSkip (ERR_IDENT_EXPECTED);
-           break;
+                   ErrorSkip ("Identifier expected");
+           return;
        }
-       SymFunc (SVal, ZP);
-       NextTok ();
+
+        /* Find the symbol table entry, allocate a new one if necessary */
+        Sym = SymFind (CurrentScope, SVal, SYM_ALLOC_NEW);
+
+        /* Skip the name */
+        NextTok ();
+
+        /* Get an optional address size */
+        AddrSize = OptionalAddrSize ();
+        if (AddrSize == ADDR_SIZE_DEFAULT) {
+            AddrSize = DefAddrSize;
+        }
+
+        /* Call the actual import/export function */
+        Func (Sym, AddrSize, Flags);
+
+        /* More symbols? */
        if (Tok == TOK_COMMA) {
            NextTok ();
        } else {
@@ -165,7 +244,7 @@ static long IntArg (long Min, long Max)
     } else {
        long Val = ConstExpression ();
        if (Val < Min || Val > Max) {
-           Error (ERR_RANGE);
+           Error ("Range error");
            Val = Min;
        }
        return Val;
@@ -179,6 +258,10 @@ static void ConDes (const char* Name, unsigned Type)
 {
     long Prio;
 
+
+    /* Find the symbol table entry, allocate a new one if necessary */
+    SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
+
     /* Optional constructor priority */
     if (Tok == TOK_COMMA) {
        /* Priority value follows */
@@ -186,7 +269,7 @@ static void ConDes (const char* Name, unsigned Type)
        Prio = ConstExpression ();
        if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
            /* Value out of range */
-           Error (ERR_RANGE);
+           Error ("Range error");
            return;
        }
     } else {
@@ -195,7 +278,7 @@ static void ConDes (const char* Name, unsigned Type)
     }
 
     /* Define the symbol */
-    SymConDes (Name, Type, (unsigned) Prio);
+    SymConDes (Sym, ADDR_SIZE_DEFAULT, Type, (unsigned) Prio);
 }
 
 
@@ -210,10 +293,10 @@ static void DoA16 (void)
 /* Switch the accu to 16 bit mode (assembler only) */
 {
     if (GetCPU() != CPU_65816) {
-       Error (ERR_816_MODE_ONLY);
+       Error ("Command is only valid in 65816 mode");
     } else {
                /* Immidiate mode has two extension bytes */
-       ExtBytes [AMI_IMM_ACCU] = 2;
+       ExtBytes [AM65I_IMM_ACCU] = 2;
     }
 }
 
@@ -223,10 +306,10 @@ static void DoA8 (void)
 /* Switch the accu to 8 bit mode (assembler only) */
 {
     if (GetCPU() != CPU_65816) {
-       Error (ERR_816_MODE_ONLY);
+       Error ("Command is only valid in 65816 mode");
     } else {
        /* Immidiate mode has one extension byte */
-       ExtBytes [AMI_IMM_ACCU] = 1;
+       ExtBytes [AM65I_IMM_ACCU] = 1;
     }
 }
 
@@ -237,7 +320,7 @@ static void DoAddr (void)
 {
     while (1) {
        if (GetCPU() == CPU_65816) {
-                   EmitWord (ForceWordExpr (Expression ()));
+                   EmitWord (GenWordExpr (Expression ()));
        } else {
            /* Do a range check */
            EmitWord (Expression ());
@@ -262,7 +345,7 @@ static void DoAlign (void)
     /* Read the alignment value */
     Align = ConstExpression ();
     if (Align <= 0 || Align > 0x10000) {
-               ErrorSkip (ERR_RANGE);
+               ErrorSkip ("Range error");
        return;
     }
 
@@ -272,7 +355,7 @@ static void DoAlign (void)
        Val = ConstExpression ();
        /* We need a byte value here */
        if (!IsByteRange (Val)) {
-                   ErrorSkip (ERR_RANGE);
+                   ErrorSkip ("Range error");
            return;
        }
     } else {
@@ -282,7 +365,7 @@ static void DoAlign (void)
     /* Check if the alignment is a power of two */
     Bit = BitFind (Align);
     if (Align != (0x01L << Bit)) {
-       Error (ERR_ALIGN);
+       Error ("Alignment value must be a power of 2");
     } else {
        SegAlign (Bit, (int) Val);
     }
@@ -298,7 +381,7 @@ static void DoASCIIZ (void)
     while (1) {
        /* Must have a string constant */
        if (Tok != TOK_STRCON) {
-           ErrorSkip (ERR_STRCON_EXPECTED);
+                   ErrorSkip ("String constant expected");
            return;
        }
 
@@ -320,6 +403,78 @@ static void DoASCIIZ (void)
 
 
 
+static void DoAssert (void)
+/* Add an assertion */
+{
+    static const char* ActionTab [] = {
+       "WARN", "WARNING",
+        "ERROR"
+    };
+
+    int      Action;
+    unsigned Msg;
+
+    /* First we have the expression that has to evaluated */
+    ExprNode* Expr = Expression ();
+    ConsumeComma ();
+
+    /* Action follows */
+    if (Tok != TOK_IDENT) {
+        ErrorSkip ("Identifier expected");
+        return;
+    }
+    Action = GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]));
+    switch (Action) {
+
+        case 0:
+        case 1:
+            /* Warning */
+            Action = ASSERT_ACT_WARN;
+            break;
+
+        case 2:
+            /* Error */
+            Action = ASSERT_ACT_ERROR;
+            break;
+
+        default:
+            Error ("Illegal assert action specifier");
+    }
+    NextTok ();
+
+    /* We can have an optional message. If no message is present, use
+     * "Assertion failed".
+     */
+    if (Tok == TOK_COMMA) {
+
+        /* Skip the comma */
+        NextTok ();
+
+        /* Read the message */
+        if (Tok != TOK_STRCON) {
+            ErrorSkip ("String constant expected");
+            return;
+        }
+
+        /* Translate the message into a string id. We can then skip the input
+         * string.
+         */
+        Msg = GetStringId (SVal);
+        NextTok ();
+
+    } else {
+
+        /* Use "Assertion failed" */
+        Msg = GetStringId ("Assertion failed");
+
+    }
+
+    /* Remember the assertion */
+    AddAssertion (Expr, Action, Msg);
+}
+
+
+
 static void DoAutoImport (void)
 /* Mark unresolved symbols as imported */
 {
@@ -331,7 +486,7 @@ static void DoAutoImport (void)
 static void DoBss (void)
 /* Switch to the BSS segment */
 {
-    UseBssSeg ();
+    UseSeg (&BssSegDef);
 }
 
 
@@ -349,13 +504,13 @@ static void DoByte (void)
        } else {
            EmitByte (Expression ());
        }
-       if (Tok != TOK_COMMA) {
+       if (Tok != TOK_COMMA) {
            break;
        } else {
            NextTok ();
            /* Do smart handling of dangling comma */
            if (Tok == TOK_SEP) {
-               Error (ERR_UNEXPECTED_EOL);
+               Error ("Unexpected end of line");
                break;
            }
        }
@@ -373,10 +528,41 @@ static void DoCase (void)
 
 
 
+static void DoCharMap (void)
+/* Allow custome character mappings */
+{
+    long Index;
+    long Code;
+
+    /* Read the index as numerical value */
+    Index = ConstExpression ();
+    if (Index < 0 || Index > 255) {
+       /* Value out of range */
+               ErrorSkip ("Range error");
+       return;
+    }
+
+    /* Comma follows */
+    ConsumeComma ();
+
+    /* Read the character code */
+    Code = ConstExpression ();
+    if (Code < 0 || Code > 255) {
+       /* Value out of range */
+               ErrorSkip ("Range error");
+       return;
+    }
+
+    /* Set the character translation */
+    TgtTranslateSet ((unsigned) Index, (unsigned char) Code);
+}
+
+
+
 static void DoCode (void)
 /* Switch to the code segment */
 {
-    UseCodeSeg ();
+    UseSeg (&CodeSegDef);
 }
 
 
@@ -387,13 +573,14 @@ static void DoConDes (void)
     static const char* Keys[] = {
                "CONSTRUCTOR",
        "DESTRUCTOR",
+        "INTERRUPTOR",
     };
     char Name [sizeof (SVal)];
     long Type;
 
     /* Symbol name follows */
     if (Tok != TOK_IDENT) {
-       ErrorSkip (ERR_IDENT_EXPECTED);
+       ErrorSkip ("Identifier expected");
        return;
     }
     strcpy (Name, SVal);
@@ -409,7 +596,7 @@ static void DoConDes (void)
 
        /* Check if we got a valid keyword */
        if (Type < 0) {
-           Error (ERR_SYNTAX);
+           Error ("Syntax error");
            SkipUntilSep ();
            return;
        }
@@ -420,7 +607,7 @@ static void DoConDes (void)
                Type = ConstExpression ();
        if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
            /* Value out of range */
-           Error (ERR_RANGE);
+           Error ("Range error");
            return;
        }
 
@@ -439,7 +626,7 @@ static void DoConstructor (void)
 
     /* Symbol name follows */
     if (Tok != TOK_IDENT) {
-       ErrorSkip (ERR_IDENT_EXPECTED);
+       ErrorSkip ("Identifier expected");
        return;
     }
     strcpy (Name, SVal);
@@ -454,7 +641,7 @@ static void DoConstructor (void)
 static void DoData (void)
 /* Switch to the data segment */
 {
-    UseDataSeg ();
+    UseSeg (&DataSegDef);
 }
 
 
@@ -472,7 +659,7 @@ static void DoDbg (void)
 
     /* We expect a subkey */
     if (Tok != TOK_IDENT) {
-       ErrorSkip (ERR_IDENT_EXPECTED);
+       ErrorSkip ("Identifier expected");
        return;
     }
 
@@ -487,7 +674,7 @@ static void DoDbg (void)
        case 0:     DbgInfoFile ();             break;
        case 1:     DbgInfoLine ();             break;
        case 2:     DbgInfoSym ();              break;
-       default:    ErrorSkip (ERR_SYNTAX);     break;
+       default:    ErrorSkip ("Syntax error"); break;
     }
 }
 
@@ -497,7 +684,7 @@ static void DoDByt (void)
 /* Output double bytes */
 {
     while (1) {
-       EmitWord (SwapExpr (Expression ()));
+       EmitWord (GenSwapExpr (Expression ()));
        if (Tok != TOK_COMMA) {
            break;
        } else {
@@ -531,7 +718,7 @@ static void DoDestructor (void)
 
     /* Symbol name follows */
     if (Tok != TOK_IDENT) {
-       ErrorSkip (ERR_IDENT_EXPECTED);
+       ErrorSkip ("Identifier expected");
        return;
     }
     strcpy (Name, SVal);
@@ -562,6 +749,7 @@ static void DoEnd (void)
 /* End of assembly */
 {
     ForcedEnd = 1;
+    NextTok ();
 }
 
 
@@ -569,7 +757,25 @@ static void DoEnd (void)
 static void DoEndProc (void)
 /* Leave a lexical level */
 {
-    SymLeaveLevel ();
+    if (GetCurrentSymTabType () != ST_PROC) {
+        /* No local scope */
+        ErrorSkip ("No open .PROC");
+    } else {
+        SymLeaveLevel ();
+    }
+}
+
+
+
+static void DoEndScope (void)
+/* Leave a lexical level */
+{
+    if ( GetCurrentSymTabType () != ST_SCOPE) {
+        /* No local scope */
+        ErrorSkip ("No open .SCOPE");
+    } else {
+        SymLeaveLevel ();
+    }
 }
 
 
@@ -578,9 +784,9 @@ static void DoError (void)
 /* User error */
 {
     if (Tok != TOK_STRCON) {
-       ErrorSkip (ERR_STRCON_EXPECTED);
+       ErrorSkip ("String constant expected");
     } else {
-               Error (ERR_USER, SVal);
+               Error ("User error: %s", SVal);
        SkipUntilSep ();
     }
 }
@@ -603,7 +809,7 @@ static void DoExitMacro (void)
 static void DoExport (void)
 /* Export a symbol */
 {
-    ExportImport (SymExport, 0);
+    ExportImport (ExportWithAssign, ADDR_SIZE_DEFAULT, SF_NONE);
 }
 
 
@@ -611,7 +817,7 @@ static void DoExport (void)
 static void DoExportZP (void)
 /* Export a zeropage symbol */
 {
-    ExportImport (SymExport, 1);
+    ExportImport (ExportWithAssign, ADDR_SIZE_ZP, SF_NONE);
 }
 
 
@@ -639,7 +845,7 @@ static void DoFeature (void)
 
        /* We expect an identifier */
        if (Tok != TOK_IDENT) {
-           ErrorSkip (ERR_IDENT_EXPECTED);
+           ErrorSkip ("Identifier expected");
            return;
        }
 
@@ -649,7 +855,7 @@ static void DoFeature (void)
        /* Set the feature and check for errors */
        if (SetFeature (SVal) == FEAT_UNKNOWN) {
            /* Not found */
-           ErrorSkip (ERR_ILLEGAL_FEATURE);
+           ErrorSkip ("Invalid feature: `%s'", SVal);
            return;
        } else {
            /* Skip the keyword */
@@ -684,7 +890,7 @@ static void DoFileOpt (void)
        OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
        if (OptNum < 0) {
            /* Not found */
-           ErrorSkip (ERR_OPTION_KEY_EXPECTED);
+           ErrorSkip ("File option keyword expected");
            return;
        }
 
@@ -696,7 +902,7 @@ static void DoFileOpt (void)
 
        /* We accept only string options for now */
        if (Tok != TOK_STRCON) {
-           ErrorSkip (ERR_STRCON_EXPECTED);
+           ErrorSkip ("String constant expected");
            return;
        }
 
@@ -719,7 +925,7 @@ static void DoFileOpt (void)
                break;
 
            default:
-               Internal ("Invalid OptNum: %l", OptNum);
+               Internal ("Invalid OptNum: %ld", OptNum);
 
        }
 
@@ -731,7 +937,7 @@ static void DoFileOpt (void)
        /* Option given as number */
                OptNum = ConstExpression ();
        if (!IsByteRange (OptNum)) {
-           ErrorSkip (ERR_RANGE);
+           ErrorSkip ("Range error");
            return;
        }
 
@@ -740,7 +946,7 @@ static void DoFileOpt (void)
 
        /* We accept only string options for now */
        if (Tok != TOK_STRCON) {
-           ErrorSkip (ERR_STRCON_EXPECTED);
+           ErrorSkip ("String constant expected");
            return;
        }
 
@@ -754,10 +960,18 @@ static void DoFileOpt (void)
 
 
 
+static void DoForceImport (void)
+/* Do a forced import on a symbol */
+{
+    ExportImport (SymImport, ADDR_SIZE_DEFAULT, SF_FORCED);
+}
+
+
+
 static void DoGlobal (void)
 /* Declare a global symbol */
 {
-    ExportImport (SymGlobal, 0);
+    ExportImport (SymGlobal, ADDR_SIZE_DEFAULT, SF_NONE);
 }
 
 
@@ -765,7 +979,7 @@ static void DoGlobal (void)
 static void DoGlobalZP (void)
 /* Declare a global zeropage symbol */
 {
-    ExportImport (SymGlobal, 1);
+    ExportImport (SymGlobal, ADDR_SIZE_ZP, SF_NONE);
 }
 
 
@@ -774,10 +988,10 @@ static void DoI16 (void)
 /* Switch the index registers to 16 bit mode (assembler only) */
 {
     if (GetCPU() != CPU_65816) {
-       Error (ERR_816_MODE_ONLY);
+       Error ("Command is only valid in 65816 mode");
     } else {
                /* Immidiate mode has two extension bytes */
-       ExtBytes [AMI_IMM_INDEX] = 2;
+       ExtBytes [AM65I_IMM_INDEX] = 2;
     }
 }
 
@@ -787,10 +1001,10 @@ static void DoI8 (void)
 /* Switch the index registers to 16 bit mode (assembler only) */
 {
     if (GetCPU() != CPU_65816) {
-       Error (ERR_816_MODE_ONLY);
+       Error ("Command is only valid in 65816 mode");
     } else {
        /* Immidiate mode has one extension byte */
-       ExtBytes [AMI_IMM_INDEX] = 1;
+       ExtBytes [AM65I_IMM_INDEX] = 1;
     }
 }
 
@@ -799,7 +1013,7 @@ static void DoI8 (void)
 static void DoImport (void)
 /* Import a symbol */
 {
-    ExportImport (SymImport, 0);
+    ExportImport (SymImport, ADDR_SIZE_DEFAULT, SF_NONE);
 }
 
 
@@ -807,7 +1021,7 @@ static void DoImport (void)
 static void DoImportZP (void)
 /* Import a zero page symbol */
 {
-    ExportImport (SymImport, 1);
+    ExportImport (SymImport, ADDR_SIZE_ZP, SF_NONE);
 }
 
 
@@ -823,7 +1037,7 @@ static void DoIncBin (void)
 
     /* Name must follow */
     if (Tok != TOK_STRCON) {
-       ErrorSkip (ERR_STRCON_EXPECTED);
+       ErrorSkip ("String constant expected");
        return;
     }
     strcpy (Name, SVal);
@@ -845,8 +1059,21 @@ static void DoIncBin (void)
     /* Try to open the file */
     F = fopen (Name, "rb");
     if (F == 0) {
-               ErrorSkip (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
-       return;
+
+               /* Search for the file in the include directories. */
+       char* PathName = FindInclude (Name);
+               if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
+           /* Not found or cannot open, print an error and bail out */
+                   ErrorSkip ("Cannot open include file `%s': %s", Name, strerror (errno));
+       }
+
+       /* Free the allocated memory */
+       xfree (PathName);
+
+        /* If we had an error before, bail out now */
+        if (F == 0) {
+            return;
+        }
     }
 
     /* Get the size of the file */
@@ -858,13 +1085,13 @@ static void DoIncBin (void)
        Count = Size - Start;
        if (Count < 0) {
            /* Nothing to read - flag this as a range error */
-           ErrorSkip (ERR_RANGE);
+           ErrorSkip ("Range error");
            goto Done;
        }
     } else {
        /* Count was given, check if it is valid */
        if (Start + Count > Size) {
-           ErrorSkip (ERR_RANGE);
+           ErrorSkip ("Range error");
            goto Done;
        }
     }
@@ -884,7 +1111,8 @@ static void DoIncBin (void)
        size_t BytesRead = fread (Buf, 1, BytesToRead, F);
        if (BytesToRead != BytesRead) {
            /* Some sort of error */
-           ErrorSkip (ERR_CANNOT_READ_INCLUDE, Name, strerror (errno));
+           ErrorSkip ("Cannot read from include file `%s': %s",
+                       Name, strerror (errno));
            break;
        }
 
@@ -905,20 +1133,35 @@ Done:
 static void DoInclude (void)
 /* Include another file */
 {
-    char Name [MAX_STR_LEN+1];
-
     /* Name must follow */
     if (Tok != TOK_STRCON) {
-       ErrorSkip (ERR_STRCON_EXPECTED);
+       ErrorSkip ("String constant expected");
     } else {
-       strcpy (Name, SVal);
-       NextTok ();
-       NewInputFile (Name);
+       NewInputFile (SVal);
     }
 }
 
 
 
+static void DoInterruptor (void)
+/* Export a symbol as interruptor */
+{
+    char Name [sizeof (SVal)];
+
+    /* Symbol name follows */
+    if (Tok != TOK_IDENT) {
+       ErrorSkip ("Identifier expected");
+       return;
+    }
+    strcpy (Name, SVal);
+    NextTok ();
+
+    /* Parse the remainder of the line and export the symbol */
+    ConDes (Name, CD_TYPE_INT);
+}
+
+
+
 static void DoInvalid (void)
 /* Handle a token that is invalid here, since it should have been handled on
  * a much lower level of the expression hierarchy. Getting this sort of token
@@ -970,10 +1213,10 @@ static void DoLocalChar (void)
 /* Define the character that starts local labels */
 {
     if (Tok != TOK_CHARCON) {
-       ErrorSkip (ERR_CHARCON_EXPECTED);
+       ErrorSkip ("Character constant expected");
     } else {
        if (IVal != '@' && IVal != '?') {
-           Error (ERR_ILLEGAL_LOCALSTART);
+           Error ("Invalid start character for locals");
        } else {
            LocalStart = (char) IVal;
                }
@@ -986,33 +1229,24 @@ static void DoLocalChar (void)
 static void DoMacPack (void)
 /* Insert a macro package */
 {
-    /* Macro package names */
-    static const char* Keys [] = {
-       "GENERIC",
-               "LONGBRANCH",
-    };
-
     int Package;
 
     /* We expect an identifier */
     if (Tok != TOK_IDENT) {
-       ErrorSkip (ERR_IDENT_EXPECTED);
+       ErrorSkip ("Identifier expected");
        return;
     }
 
-    /* Map the keyword to a number */
-    Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
+    /* Search for the macro package name */
+    Package = MacPackFind (SVal);
     if (Package < 0) {
        /* Not found */
-       ErrorSkip (ERR_ILLEGAL_MACPACK);
+       ErrorSkip ("Invalid macro package");
        return;
     }
 
-    /* Skip the package name */
-    NextTok ();
-
     /* Insert the package */
-    InsertMacPack (Package);
+    MacPackInsert (Package);
 }
 
 
@@ -1028,7 +1262,7 @@ static void DoMacro (void)
 static void DoNull (void)
 /* Switch to the NULL segment */
 {
-    UseNullSeg ();
+    UseSeg (&NullSegDef);
 }
 
 
@@ -1038,10 +1272,10 @@ static void DoOrg (void)
 {
     long PC = ConstExpression ();
     if (PC < 0 || PC > 0xFFFFFF) {
-       Error (ERR_RANGE);
+       Error ("Range error");
        return;
     }
-    SetAbsPC (PC);
+    EnterAbsoluteMode (PC);
 }
 
 
@@ -1050,7 +1284,7 @@ static void DoOut (void)
 /* Output a string */
 {
     if (Tok != TOK_STRCON) {
-       ErrorSkip (ERR_STRCON_EXPECTED);
+       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.
@@ -1095,15 +1329,88 @@ static void DoPageLength (void)
 
 
 
+static void DoPopSeg (void)
+/* Pop an old segment from the segment stack */
+{
+    SegDef* Def;
+
+    /* Must have a segment on the stack */
+    if (CollCount (&SegStack) == 0) {
+        ErrorSkip ("Segment stack is empty");
+        return;
+    }
+
+    /* Pop the last element */
+    Def = CollPop (&SegStack);
+
+    /* Restore this segment */
+    UseSeg (Def);
+
+    /* Delete the segment definition */
+    FreeSegDef (Def);
+}
+
+
+
 static void DoProc (void)
 /* Start a new lexical scope */
 {
+    char Name[sizeof(SVal)];
+    unsigned char AddrSize;
+
     if (Tok == TOK_IDENT) {
-       /* The new scope has a name */
-       SymDef (SVal, CurrentPC (), IsZPSeg (), 1);
-       NextTok ();
+
+        SymEntry* Sym;
+
+       /* The new scope has a name. Remember it. */
+        strcpy (Name, SVal);
+
+        /* Search for the symbol, generate a new one if needed */
+               Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
+
+        /* Skip the scope name */
+        NextTok ();
+
+        /* Read an optional address size specifier */
+        AddrSize = OptionalAddrSize ();
+
+        /* Mark the symbol as defined */
+       SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL);
+
+    } else {
+
+        /* A .PROC statement without a name */
+        Warning (1, "Unnamed .PROCs are deprecated, please use .SCOPE");
+        AnonName (Name, sizeof (Name), "PROC");
+        AddrSize = ADDR_SIZE_DEFAULT;
+
+    }
+
+    /* Enter a new scope */
+    SymEnterLevel (Name, ST_PROC, AddrSize);
+}
+
+
+
+static void DoPSC02 (void)
+/* Switch to 65SC02 CPU */
+{
+    SetCPU (CPU_65SC02);
+}
+
+
+
+static void DoPushSeg (void)
+/* Push the current segment onto the segment stack */
+{
+    /* Can only push a limited size of segments */
+    if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
+        ErrorSkip ("Segment stack overflow");
+        return;
     }
-    SymEnterLevel ();
+
+    /* Get the current segment and push it */
+    CollAppend (&SegStack, DupSegDef (GetCurrentSegDef ()));
 }
 
 
@@ -1111,7 +1418,7 @@ static void DoProc (void)
 static void DoReloc (void)
 /* Enter relocatable mode */
 {
-    RelocMode = 1;
+    EnterRelocMode ();
 }
 
 
@@ -1132,7 +1439,7 @@ static void DoRes (void)
 
     Count = ConstExpression ();
     if (Count > 0xFFFF || Count < 0) {
-       ErrorSkip (ERR_RANGE);
+       ErrorSkip ("Range error");
        return;
     }
     if (Tok == TOK_COMMA) {
@@ -1140,7 +1447,7 @@ static void DoRes (void)
        Val = ConstExpression ();
        /* We need a byte value here */
        if (!IsByteRange (Val)) {
-                   ErrorSkip (ERR_RANGE);
+                   ErrorSkip ("Range error");
            return;
        }
 
@@ -1160,7 +1467,37 @@ static void DoRes (void)
 static void DoROData (void)
 /* Switch to the r/o data segment */
 {
-    UseRODataSeg ();
+    UseSeg (&RODataSegDef);
+}
+
+
+
+static void DoScope (void)
+/* Start a local scope */
+{
+    char Name[sizeof (SVal)];
+    unsigned char AddrSize;
+
+
+    if (Tok == TOK_IDENT) {
+
+       /* The new scope has a name. Remember and skip it. */
+        strcpy (Name, SVal);
+        NextTok ();
+
+    } else {
+
+        /* An unnamed scope */
+        AnonName (Name, sizeof (Name), "SCOPE");
+
+    }
+
+    /* Read an optional address size specifier */
+    AddrSize = OptionalAddrSize ();
+
+    /* Enter the new scope */
+    SymEnterLevel (Name, ST_SCOPE, AddrSize);
+
 }
 
 
@@ -1168,58 +1505,45 @@ static void DoROData (void)
 static void DoSegment (void)
 /* Switch to another segment */
 {
-    static const char* AttrTab [] = {
-       "ZEROPAGE", "DIRECT",
-       "ABSOLUTE",
-       "FAR", "LONG"
-    };
     char Name [sizeof (SVal)];
-    int SegType;
+    SegDef Def;
+    Def.Name = Name;
 
     if (Tok != TOK_STRCON) {
-       ErrorSkip (ERR_STRCON_EXPECTED);
+       ErrorSkip ("String constant expected");
     } else {
 
        /* Save the name of the segment and skip it */
        strcpy (Name, SVal);
        NextTok ();
 
-       /* Check for an optional segment attribute */
-       SegType = SEGTYPE_DEFAULT;
-       if (Tok == TOK_COMMA) {
-           NextTok ();
-           if (Tok != TOK_IDENT) {
-               ErrorSkip (ERR_IDENT_EXPECTED);
-           } else {
-               int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
-               switch (Attr) {
-
-                   case 0:
-                   case 1:
-                       /* Zeropage */
-                       SegType = SEGTYPE_ZP;
-                       break;
-
-                   case 2:
-                       /* Absolute */
-                       SegType = SEGTYPE_ABS;
-                       break;
-
-                   case 3:
-                   case 4:
-                       /* Far */
-                       SegType = SEGTYPE_FAR;
-                       break;
-
-                   default:
-                       Error (ERR_ILLEGAL_SEG_ATTR);
-               }
-               NextTok ();
-           }
-       }
+       /* Check for an optional address size modifier */
+        Def.AddrSize = OptionalAddrSize ();
 
        /* Set the segment */
-       UseSeg (Name, SegType);
+       UseSeg (&Def);
+    }
+}
+
+
+
+static void DoSetCPU (void)
+/* Switch the CPU instruction set */
+{
+    /* We expect an identifier */
+    if (Tok != TOK_STRCON) {
+       ErrorSkip ("String constant expected");
+    } else {
+        /* Try to find the CPU */
+        cpu_t CPU = FindCPU (SVal);
+
+        /* Switch to the new CPU */
+        SetCPU (CPU);
+
+        /* Skip the identifier. If the CPU switch was successful, the scanner
+         * will treat the input now correctly for the new CPU.
+         */
+        NextTok ();
     }
 }
 
@@ -1241,10 +1565,57 @@ static void DoSunPlus (void)
 
 
 
+static void DoTag (void)
+/* Allocate space for a struct */
+{
+    SymEntry* SizeSym;
+    long Size;
+
+    /* Read the struct name */
+    SymTable* Struct = ParseScopedSymTable ();
+
+    /* Check the supposed struct */
+    if (Struct == 0) {
+        ErrorSkip ("Unknown struct");
+        return;
+    }
+    if (GetSymTabType (Struct) != ST_STRUCT) {
+        ErrorSkip ("Not a struct");
+        return;
+    }
+
+    /* Get the symbol that defines the size of the struct */
+    SizeSym = GetSizeOfScope (Struct);
+
+    /* Check if it does exist and if its value is known */
+    if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
+        ErrorSkip ("Size of struct/union is unknown");
+        return;
+    }
+
+    /* Optional multiplicator may follow */
+    if (Tok == TOK_COMMA) {
+        long Multiplicator;
+        NextTok ();
+        Multiplicator = ConstExpression ();
+        /* Multiplicator must make sense */
+        if (Multiplicator <= 0) {
+            ErrorSkip ("Range error");
+            return;
+        }
+        Size *= Multiplicator;
+    }
+
+    /* Emit fill fragments */
+    EmitFill (Size);
+}
+
+
+
 static void DoUnexpected (void)
 /* Got an unexpected keyword */
 {
-    Error (ERR_UNEXPECTED, Keyword);
+    Error ("Unexpected `%s'", Keyword);
     SkipUntilSep ();
 }
 
@@ -1254,9 +1625,9 @@ static void DoWarning (void)
 /* User warning */
 {
     if (Tok != TOK_STRCON) {
-       ErrorSkip (ERR_STRCON_EXPECTED);
+       ErrorSkip ("String constant expected");
     } else {
-               Warning (WARN_USER, SVal);
+               Warning (0, "User warning: %s", SVal);
        SkipUntilSep ();
     }
 }
@@ -1281,7 +1652,7 @@ static void DoWord (void)
 static void DoZeropage (void)
 /* Switch to the zeropage segment */
 {
-    UseZeropageSeg ();
+    UseSeg (&ZeropageSegDef);
 }
 
 
@@ -1299,11 +1670,11 @@ enum {
 };
 
 /* Control command table */
-struct CtrlDesc_ {
+typedef struct CtrlDesc CtrlDesc;
+struct CtrlDesc {
     unsigned           Flags;                  /* Flags for this directive */
     void               (*Handler) (void);      /* Command handler */
 };
-typedef struct CtrlDesc_ CtrlDesc;
 
 #define PSEUDO_COUNT   (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
 static CtrlDesc CtrlCmdTab [] = {
@@ -1312,11 +1683,14 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,          DoAddr          },      /* .ADDR */
     { ccNone,          DoAlign         },
     { ccNone,          DoASCIIZ        },
+    { ccNone,           DoAssert        },
     { ccNone,          DoAutoImport    },
+    { ccNone,          DoUnexpected    },      /* .BANKBYTE */
     { ccNone,          DoUnexpected    },      /* .BLANK */
     { ccNone,          DoBss           },
     { ccNone,          DoByte          },
     { ccNone,          DoCase          },
+    { ccNone,                  DoCharMap       },
     { ccNone,          DoCode          },
     { ccNone,          DoUnexpected,   },      /* .CONCAT */
     { ccNone,          DoConDes        },
@@ -1333,11 +1707,16 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,          DoDWord         },
     { ccKeepToken,     DoConditionals  },      /* .ELSE */
     { ccKeepToken,     DoConditionals  },      /* .ELSEIF */
-    { ccNone,          DoEnd           },
+    { ccKeepToken,             DoEnd           },
+    { ccNone,           DoUnexpected    },      /* .ENDENUM */
     { ccKeepToken,     DoConditionals  },      /* .ENDIF */
     { ccNone,          DoUnexpected    },      /* .ENDMACRO */
     { ccNone,          DoEndProc       },
     { ccNone,          DoUnexpected    },      /* .ENDREPEAT */
+    { ccNone,           DoEndScope      },
+    { ccNone,           DoUnexpected    },      /* .ENDSTRUCT */
+    { ccNone,           DoUnexpected    },      /* .ENDUNION */
+    { ccNone,           DoEnum          },
     { ccNone,          DoError         },
     { ccNone,          DoExitMacro     },
     { ccNone,          DoExport        },
@@ -1345,11 +1724,15 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,          DoFarAddr       },
     { ccNone,          DoFeature       },
     { ccNone,          DoFileOpt       },
+    { ccNone,           DoForceImport   },
     { ccNone,          DoUnexpected    },      /* .FORCEWORD */
     { ccNone,          DoGlobal        },
     { ccNone,          DoGlobalZP      },
+    { ccNone,          DoUnexpected    },      /* .HIBYTE */
+    { ccNone,          DoUnexpected    },      /* .HIWORD */
     { ccNone,          DoI16           },
     { ccNone,          DoI8            },
+    { ccNone,           DoUnexpected    },      /* .IDENT */
     { ccKeepToken,     DoConditionals  },      /* .IF */
     { ccKeepToken,     DoConditionals  },      /* .IFBLANK */
     { ccKeepToken,     DoConditionals  },      /* .IFCONST */
@@ -1361,17 +1744,21 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccKeepToken,     DoConditionals  },      /* .IFP02 */
     { ccKeepToken,     DoConditionals  },      /* .IFP816 */
     { ccKeepToken,     DoConditionals  },      /* .IFPC02 */
+    { ccKeepToken,     DoConditionals  },      /* .IFPSC02 */
     { ccKeepToken,     DoConditionals  },      /* .IFREF */
     { ccNone,          DoImport        },
     { ccNone,          DoImportZP      },
     { ccNone,          DoIncBin        },
     { ccNone,          DoInclude       },
+    { ccNone,           DoInterruptor   },
     { ccNone,          DoInvalid       },      /* .LEFT */
     { ccNone,          DoLineCont      },
     { ccNone,          DoList          },
     { ccNone,                  DoListBytes     },
+    { ccNone,          DoUnexpected    },      /* .LOBYTE */
     { ccNone,          DoUnexpected    },      /* .LOCAL */
     { ccNone,          DoLocalChar     },
+    { ccNone,          DoUnexpected    },      /* .LOWORD */
     { ccNone,          DoMacPack       },
     { ccNone,          DoMacro         },
     { ccNone,                  DoUnexpected    },      /* .MATCH */
@@ -1382,44 +1769,49 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,          DoP02           },
     { ccNone,          DoP816          },
     { ccNone,                  DoPageLength    },
-    { ccNone,          DoUnexpected    },      /* .PARAMCOUNT */
+    { ccNone,          DoUnexpected    },      /* .PARAMCOUNT */
     { ccNone,          DoPC02          },
+    { ccNone,           DoPopSeg        },
     { ccNone,          DoProc          },
-    { ccNone,          DoUnexpected    },      /* .REFERENCED */
+    { ccNone,                  DoPSC02         },
+    { ccNone,           DoPushSeg       },
+    { ccNone,          DoUnexpected    },      /* .REFERENCED */
     { ccNone,          DoReloc         },
     { ccNone,          DoRepeat        },
     { ccNone,          DoRes           },
     { ccNone,          DoInvalid       },      /* .RIGHT */
     { ccNone,          DoROData        },
+    { ccNone,           DoScope         },
     { ccNone,          DoSegment       },
+    { ccNone,           DoUnexpected    },      /* .SET */
+    { ccNone,                  DoSetCPU        },
+    { ccNone,           DoUnexpected    },      /* .SIZEOF */
     { ccNone,          DoSmart         },
-    { ccNone,          DoUnexpected    },      /* .STRAT */
-    { ccNone,                  DoUnexpected    },      /* .STRING */
-    { ccNone,          DoUnexpected    },      /* .STRLEN */
+    { ccNone,           DoUnexpected    },      /* .SPRINTF */
+    { ccNone,          DoUnexpected    },      /* .STRAT */
+    { ccNone,                  DoUnexpected    },      /* .STRING */
+    { ccNone,          DoUnexpected    },      /* .STRLEN */
+    { ccNone,           DoStruct        },
     { ccNone,          DoSunPlus       },
-    { ccNone,          DoUnexpected    },      /* .TCOUNT */
+    { ccNone,           DoTag           },
+    { ccNone,          DoUnexpected    },      /* .TCOUNT */
+    { ccNone,                  DoUnexpected    },      /* .TIME */
+    { ccNone,           DoUnion         },
+    { ccNone,           DoUnexpected    },      /* .VERSION */
     { ccNone,          DoWarning       },
     { ccNone,          DoWord          },
-    { ccNone,                  DoUnexpected    },      /* .XMATCH */
+    { ccNone,                  DoUnexpected    },      /* .XMATCH */
     { ccNone,          DoZeropage      },
 };
 
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                          Code                                    */
 /*****************************************************************************/
 
 
 
-int TokIsPseudo (unsigned Tok)
-/* Return true if the given token is a pseudo instruction token */
-{
-    return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
-}
-
-
-
 void HandlePseudo (void)
 /* Handle a pseudo instruction */
 {
@@ -1431,7 +1823,7 @@ void HandlePseudo (void)
     /* Safety check */
     if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
        Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
-                 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
+                         (unsigned) PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
     }
     CHECK (Index < PSEUDO_COUNT);
 
@@ -1440,7 +1832,7 @@ void HandlePseudo (void)
 
     /* Remember the instruction, then skip it if needed */
     if ((D->Flags & ccKeepToken) == 0) {
-       strcpy (Keyword+1, SVal);
+       strcpy (Keyword, SVal);
        NextTok ();
     }
 
@@ -1450,3 +1842,13 @@ void HandlePseudo (void)
 
 
 
+void SegStackCheck (void)
+/* Check if the segment stack is empty at end of assembly */
+{
+    if (CollCount (&SegStack) != 0) {
+        Error ("Segment stack is not empty");
+    }
+}
+
+
+