]> git.sur5r.net Git - cc65/blobdiff - src/ca65/scanner.c
Allow conditional directives within .STRUCT7:UNION and .ENUM
[cc65] / src / ca65 / scanner.c
index e1a08e2e40ef1c8330351623970cc54e3a7afe16..cb4712a65b81fbacf5da17f3e2b3c3b0bc57767a 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2000 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@musoftware.de                                            */
+/* (C) 1998-2003 Ullrich von Bassewitz                                       */
+/*               Römerstraße 52                                              */
+/*               D-70794 Filderstadt                                         */
+/* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -42,6 +42,8 @@
 #include <sys/stat.h>
 
 /* common */
+#include "addrsize.h"
+#include "chartype.h"
 #include "check.h"
 #include "fname.h"
 #include "xmalloc.h"
@@ -94,7 +96,7 @@ struct InputFile_ {
 /* Struct to handle textual input data */
 typedef struct InputData_ InputData;
 struct InputData_ {
-    const char*            Data;               /* Pointer to the data */
+    char*          Data;               /* Pointer to the data */
     const char*     Pos;               /* Pointer to current position */
     int                    Malloced;           /* Memory was malloced */
     enum Token     Tok;                /* Last token */
@@ -116,121 +118,141 @@ struct DotKeyword {
     const char*        Key;                    /* MUST be first field */
     enum Token  Tok;
 } DotKeywords [] = {
-    { "A16",           TOK_A16         },
-    { "A8",            TOK_A8          },
-    { "ADDR",          TOK_ADDR        },
-    { "ALIGN",         TOK_ALIGN       },
-    { "AND",           TOK_BAND        },
-    { "ASCIIZ",                TOK_ASCIIZ      },
-    { "AUTOIMPORT",    TOK_AUTOIMPORT  },
-    { "BITAND",                TOK_AND         },
-    { "BITNOT",                TOK_NOT         },
-    { "BITOR",         TOK_OR          },
-    { "BITXOR",                TOK_XOR         },
-    { "BLANK",         TOK_BLANK       },
-    { "BSS",           TOK_BSS         },
-    { "BYT",           TOK_BYTE        },
-    { "BYTE",          TOK_BYTE        },
-    { "CASE",                  TOK_CASE        },
-    { "CODE",          TOK_CODE        },
-    { "CONCAT",                TOK_CONCAT      },
-    { "CONDES",                TOK_CONDES      },
-    { "CONST",                 TOK_CONST       },
-    { "CONSTRUCTOR",   TOK_CONSTRUCTOR },
-    { "CPU",           TOK_CPU         },
-    { "DATA",                  TOK_DATA        },
-    { "DBG",           TOK_DBG         },
-    { "DBYT",                  TOK_DBYT        },
-    { "DEBUGINFO",     TOK_DEBUGINFO   },
-    { "DEF",                   TOK_DEFINED     },
-    { "DEFINE",                TOK_DEFINE      },
-    { "DEFINED",       TOK_DEFINED     },
-    { "DESTRUCTOR",    TOK_DESTRUCTOR  },
-    { "DWORD",                 TOK_DWORD       },
-    { "ELSE",                  TOK_ELSE        },
-    { "ELSEIF",                TOK_ELSEIF      },
-    { "END",                   TOK_END         },
-    { "ENDIF",                 TOK_ENDIF       },
-    { "ENDMAC",                TOK_ENDMACRO    },
-    { "ENDMACRO",      TOK_ENDMACRO    },
-    { "ENDPROC",       TOK_ENDPROC     },
-    { "ENDREP",                TOK_ENDREP      },
-    { "ENDREPEAT",     TOK_ENDREP      },
-    { "ERROR",                 TOK_ERROR       },
-    { "EXITMAC",       TOK_EXITMACRO   },
-    { "EXITMACRO",     TOK_EXITMACRO   },
-    { "EXPORT",                TOK_EXPORT      },
-    { "EXPORTZP",      TOK_EXPORTZP    },
-    { "FARADDR",       TOK_FARADDR     },
-    { "FEATURE",       TOK_FEATURE     },
-    { "FILEOPT",       TOK_FILEOPT     },
-    { "FOPT",                  TOK_FILEOPT     },
-    { "FORCEWORD",     TOK_FORCEWORD   },
-    { "GLOBAL",                TOK_GLOBAL      },
-    { "GLOBALZP",      TOK_GLOBALZP    },
-    { "I16",                   TOK_I16         },
-    { "I8",                    TOK_I8          },
-    { "IF",                    TOK_IF          },
-    { "IFBLANK",       TOK_IFBLANK     },
-    { "IFCONST",       TOK_IFCONST     },
-    { "IFDEF",                 TOK_IFDEF       },
-    { "IFNBLANK",      TOK_IFNBLANK    },
-    { "IFNCONST",      TOK_IFNCONST    },
-    { "IFNDEF",                TOK_IFNDEF      },
-    { "IFNREF",                TOK_IFNREF      },
-    { "IFP02",         TOK_IFP02       },
-    { "IFP816",                TOK_IFP816      },
-    { "IFPC02",                TOK_IFPC02      },
-    { "IFREF",         TOK_IFREF       },
-    { "IMPORT",                TOK_IMPORT      },
-    { "IMPORTZP",      TOK_IMPORTZP    },
-    { "INCBIN",                TOK_INCBIN      },
-    { "INCLUDE",       TOK_INCLUDE     },
-    { "LEFT",          TOK_LEFT        },
-    { "LINECONT",      TOK_LINECONT    },
-    { "LIST",          TOK_LIST        },
-    { "LISTBYTES",     TOK_LISTBYTES   },
-    { "LOCAL",         TOK_LOCAL       },
-    { "LOCALCHAR",     TOK_LOCALCHAR   },
-    { "MAC",           TOK_MACRO       },
-    { "MACPACK",       TOK_MACPACK     },
-    { "MACRO",         TOK_MACRO       },
-    { "MATCH",         TOK_MATCH       },
-    { "MID",                   TOK_MID         },
-    { "MOD",           TOK_MOD         },
-    { "NOT",           TOK_BNOT        },
-    { "NULL",          TOK_NULL        },
-    { "OR",            TOK_BOR         },
-    { "ORG",           TOK_ORG         },
-    { "OUT",           TOK_OUT         },
-    { "P02",           TOK_P02         },
-    { "P816",          TOK_P816        },
-    { "PAGELEN",       TOK_PAGELENGTH  },
-    { "PAGELENGTH",    TOK_PAGELENGTH  },
-    { "PARAMCOUNT",    TOK_PARAMCOUNT  },
-    { "PC02",          TOK_PC02        },
-    { "PROC",          TOK_PROC        },
-    { "REF",           TOK_REFERENCED  },
-    { "REFERENCED",    TOK_REFERENCED  },
-    { "RELOC",         TOK_RELOC       },
-    { "REPEAT",                TOK_REPEAT      },
-    { "RES",           TOK_RES         },
-    { "RIGHT",         TOK_RIGHT       },
-    { "RODATA",                TOK_RODATA      },
-    { "SEGMENT",       TOK_SEGMENT     },
-    { "SHL",           TOK_SHL         },
-    { "SHR",           TOK_SHR         },
-    { "SMART",         TOK_SMART       },
-    { "STRAT",         TOK_STRAT       },
-    { "STRING",                TOK_STRING      },
-    { "STRLEN",                TOK_STRLEN      },
-    { "SUNPLUS",       TOK_SUNPLUS     },
-    { "TCOUNT",                TOK_TCOUNT      },
-    { "WARNING",       TOK_WARNING     },
-    { "WORD",          TOK_WORD        },
-    { "XMATCH",                TOK_XMATCH      },
-    { "XOR",           TOK_BXOR        },
-    { "ZEROPAGE",      TOK_ZEROPAGE    },
+    { ".A16",                  TOK_A16         },
+    { ".A8",                   TOK_A8          },
+    { ".ADDR",                 TOK_ADDR        },
+    { ".ALIGN",                TOK_ALIGN       },
+    { ".AND",          TOK_BOOLAND     },
+    { ".ASCIIZ",               TOK_ASCIIZ      },
+    { ".ASSERT",        TOK_ASSERT      },
+    { ".AUTOIMPORT",   TOK_AUTOIMPORT  },
+    { ".BITAND",       TOK_AND         },
+    { ".BITNOT",       TOK_NOT         },
+    { ".BITOR",                TOK_OR          },
+    { ".BITXOR",       TOK_XOR         },
+    { ".BLANK",                TOK_BLANK       },
+    { ".BSS",                  TOK_BSS         },
+    { ".BYT",          TOK_BYTE        },
+    { ".BYTE",                 TOK_BYTE        },
+    { ".CASE",         TOK_CASE        },
+    { ".CHARMAP",      TOK_CHARMAP     },
+    { ".CODE",                 TOK_CODE        },
+    { ".CONCAT",               TOK_CONCAT      },
+    { ".CONDES",       TOK_CONDES      },
+    { ".CONST",        TOK_CONST       },
+    { ".CONSTRUCTOR",  TOK_CONSTRUCTOR },
+    { ".CPU",          TOK_CPU         },
+    { ".DATA",         TOK_DATA        },
+    { ".DBG",          TOK_DBG         },
+    { ".DBYT",         TOK_DBYT        },
+    { ".DEBUGINFO",    TOK_DEBUGINFO   },
+    { ".DEF",          TOK_DEFINED     },
+    { ".DEFINE",       TOK_DEFINE      },
+    { ".DEFINED",      TOK_DEFINED     },
+    { ".DESTRUCTOR",   TOK_DESTRUCTOR  },
+    { ".DWORD",        TOK_DWORD       },
+    { ".ELSE",         TOK_ELSE        },
+    { ".ELSEIF",       TOK_ELSEIF      },
+    { ".END",          TOK_END         },
+    { ".ENDENUM",       TOK_ENDENUM     },
+    { ".ENDIF",        TOK_ENDIF       },
+    { ".ENDMAC",       TOK_ENDMACRO    },
+    { ".ENDMACRO",     TOK_ENDMACRO    },
+    { ".ENDPROC",      TOK_ENDPROC     },
+    { ".ENDREP",       TOK_ENDREP      },
+    { ".ENDREPEAT",    TOK_ENDREP      },
+    { ".ENDSCOPE",      TOK_ENDSCOPE    },
+    { ".ENDSTRUCT",    TOK_ENDSTRUCT   },
+    { ".ENDUNION",             TOK_ENDUNION    },
+    { ".ENUM",          TOK_ENUM        },
+    { ".ERROR",        TOK_ERROR       },
+    { ".EXITMAC",      TOK_EXITMACRO   },
+    { ".EXITMACRO",    TOK_EXITMACRO   },
+    { ".EXPORT",       TOK_EXPORT      },
+    { ".EXPORTZP",     TOK_EXPORTZP    },
+    { ".FARADDR",      TOK_FARADDR     },
+    { ".FEATURE",      TOK_FEATURE     },
+    { ".FILEOPT",      TOK_FILEOPT     },
+    { ".FOPT",         TOK_FILEOPT     },
+    { ".FORCEIMPORT",   TOK_FORCEIMPORT },
+    { ".FORCEWORD",    TOK_FORCEWORD   },
+    { ".GLOBAL",       TOK_GLOBAL      },
+    { ".GLOBALZP",     TOK_GLOBALZP    },
+    { ".I16",          TOK_I16         },
+    { ".I8",           TOK_I8          },
+    { ".IF",           TOK_IF          },
+    { ".IFBLANK",      TOK_IFBLANK     },
+    { ".IFCONST",      TOK_IFCONST     },
+    { ".IFDEF",        TOK_IFDEF       },
+    { ".IFNBLANK",     TOK_IFNBLANK    },
+    { ".IFNCONST",     TOK_IFNCONST    },
+    { ".IFNDEF",       TOK_IFNDEF      },
+    { ".IFNREF",       TOK_IFNREF      },
+    { ".IFP02",                TOK_IFP02       },
+    { ".IFP816",       TOK_IFP816      },
+    { ".IFPC02",       TOK_IFPC02      },
+    { ".IFPSC02",              TOK_IFPSC02     },
+    { ".IFREF",                TOK_IFREF       },
+    { ".IMPORT",       TOK_IMPORT      },
+    { ".IMPORTZP",     TOK_IMPORTZP    },
+    { ".INCBIN",       TOK_INCBIN      },
+    { ".INCLUDE",      TOK_INCLUDE     },
+    { ".LEFT",         TOK_LEFT        },
+    { ".LINECONT",     TOK_LINECONT    },
+    { ".LIST",         TOK_LIST        },
+    { ".LISTBYTES",    TOK_LISTBYTES   },
+    { ".LOCAL",                TOK_LOCAL       },
+    { ".LOCALCHAR",    TOK_LOCALCHAR   },
+    { ".MAC",                  TOK_MACRO       },
+    { ".MACPACK",      TOK_MACPACK     },
+    { ".MACRO",                TOK_MACRO       },
+    { ".MATCH",                TOK_MATCH       },
+    { ".MID",          TOK_MID         },
+    { ".MOD",          TOK_MOD         },
+    { ".NOT",          TOK_BOOLNOT     },
+    { ".NULL",         TOK_NULL        },
+    { ".OR",           TOK_BOOLOR      },
+    { ".ORG",                  TOK_ORG         },
+    { ".OUT",                  TOK_OUT         },
+    { ".P02",                  TOK_P02         },
+    { ".P816",                 TOK_P816        },
+    { ".PAGELEN",      TOK_PAGELENGTH  },
+    { ".PAGELENGTH",   TOK_PAGELENGTH  },
+    { ".PARAMCOUNT",   TOK_PARAMCOUNT  },
+    { ".PC02",                 TOK_PC02        },
+    { ".POPSEG",       TOK_POPSEG      },
+    { ".PROC",                 TOK_PROC        },
+    { ".PSC02",                TOK_PSC02       },
+    { ".PUSHSEG",              TOK_PUSHSEG     },
+    { ".REF",          TOK_REFERENCED  },
+    { ".REFERENCED",   TOK_REFERENCED  },
+    { ".RELOC",                TOK_RELOC       },
+    { ".REPEAT",       TOK_REPEAT      },
+    { ".RES",                  TOK_RES         },
+    { ".RIGHT",                TOK_RIGHT       },
+    { ".RODATA",       TOK_RODATA      },
+    { ".SCOPE",         TOK_SCOPE       },
+    { ".SEGMENT",      TOK_SEGMENT     },
+    { ".SETCPU",       TOK_SETCPU      },
+    { ".SHL",          TOK_SHL         },
+    { ".SHR",          TOK_SHR         },
+    { ".SIZEOF",        TOK_SIZEOF      },
+    { ".SMART",                TOK_SMART       },
+    { ".STRAT",                TOK_STRAT       },
+    { ".STRING",       TOK_STRING      },
+    { ".STRLEN",       TOK_STRLEN      },
+    { ".STRUCT",        TOK_STRUCT      },
+    { ".SUNPLUS",      TOK_SUNPLUS     },
+    { ".TAG",           TOK_TAG         },
+    { ".TCOUNT",       TOK_TCOUNT      },
+    { ".TIME",                 TOK_TIME        },
+    { ".UNION",         TOK_UNION       },
+    { ".VERSION",       TOK_VERSION     },
+    { ".WARNING",      TOK_WARNING     },
+    { ".WORD",                 TOK_WORD        },
+    { ".XMATCH",       TOK_XMATCH      },
+    { ".XOR",                  TOK_BOOLXOR     },
+    { ".ZEROPAGE",     TOK_ZEROPAGE    },
 };
 
 
@@ -252,42 +274,10 @@ static void NextChar (void);
 
 
 
-static int IsBlank (int C)
-/* Return true if the character is a blank or tab */
-{
-    return (C == ' ' || C == '\t');
-}
-
-
-
-static int IsDigit (int C)
-/* Return true if the character is a digit */
-{
-    return isdigit (C);
-}
-
-
-
-static int IsXDigit (int C)
-/* Return true if the character is a hexadecimal digit */
-{
-    return isxdigit (C);
-}
-
-
-
-static int IsDDigit (int C)
-/* Return true if the character is a dual digit */
-{
-    return (C == '0' || C == '1');
-}
-
-
-
 static int IsIdChar (int C)
 /* Return true if the character is a valid character for an identifier */
 {
-    return isalnum (C)                         ||
+    return IsAlNum (C)                         ||
           (C == '_')                   ||
           (C == '@' && AtInIdents)     ||
           (C == '$' && DollarInIdents);
@@ -298,7 +288,7 @@ static int IsIdChar (int C)
 static int IsIdStart (int C)
 /* Return true if the character may start an identifier */
 {
-    return isalpha (C) || C == '_';
+    return IsAlpha (C) || C == '_';
 }
 
 
@@ -323,7 +313,7 @@ void NewInputFile (const char* Name)
 
        /* Error (fatal error if this is the main file) */
        if (ICount == 0) {
-           Fatal (FAT_CANNOT_OPEN_INPUT, Name, strerror (errno));
+           Fatal ("Cannot open input file `%s': %s", Name, strerror (errno));
                }
 
                /* We are on include level. Search for the file in the include
@@ -332,7 +322,7 @@ void NewInputFile (const char* Name)
        PathName = FindInclude (Name);
                if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
            /* Not found or cannot open, print an error and bail out */
-           Error (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
+           Error ("Cannot open include file `%s': %s", Name, strerror (errno));
        }
 
        /* Free the allocated memory */
@@ -348,7 +338,7 @@ void NewInputFile (const char* Name)
        /* Stat the file and remember the values */
        struct stat Buf;
        if (fstat (fileno (F), &Buf) != 0) {
-           Fatal (FAT_CANNOT_STAT_INPUT, Name, strerror (errno));
+           Fatal ("Cannot stat input file `%s': %s", Name, strerror (errno));
        }
 
        /* Add the file to the input file table and remember the index */
@@ -397,7 +387,7 @@ void DoneInputFile (void)
 
 
 
-void NewInputData (const char* Data, int Malloced)
+void NewInputData (char* Data, int Malloced)
 /* Add a chunk of input data to the input stream */
 {
     InputData* I;
@@ -555,20 +545,20 @@ static unsigned char FindDotKeyword (void)
 
 
 
-static void ReadIdent (void)
-/* Read an identifier from the current input position into Ident. It is
- * assumed that the first character has already been checked.
+static void ReadIdent (unsigned Index)
+/* Read an identifier from the current input position into Ident. Filling SVal
+ * starts at Index with the current character in C. It is assumed that any
+ * characters already filled in are ok, and the character in C is checked.
  */
 {
     /* Read the identifier */
-    unsigned I = 0;
     do {
-       if (I < MAX_STR_LEN) {
-           SVal [I++] = C;
+       if (Index < MAX_STR_LEN) {
+           SVal [Index++] = C;
        }
        NextChar ();
     } while (IsIdChar (C));
-    SVal [I] = '\0';
+    SVal [Index] = '\0';
 
     /* If we should ignore case, convert the identifier to upper case */
     if (IgnoreCase) {
@@ -595,13 +585,13 @@ static unsigned ReadStringConst (int StringTerm)
            break;
        }
        if (C == '\n' || C == EOF) {
-           Error (ERR_NEWLINE_IN_STRING);
+           Error ("Newline in string constant");
            break;
        }
 
        /* Check for string length, print an error message once */
        if (I == MAX_STR_LEN) {
-           Error (ERR_STRING_TOO_LONG);
+           Error ("Maximum string size exceeded");
        } else if (I < MAX_STR_LEN) {
            SVal [I] = C;
        }
@@ -667,7 +657,7 @@ Again:
                Tok = TOK_PC;
                return;
            } else {
-               Error (ERR_HEX_DIGIT_EXPECTED);
+               Error ("Hexadecimal digit expected");
            }
        }
 
@@ -675,7 +665,7 @@ Again:
        IVal = 0;
        while (IsXDigit (C)) {
            if (IVal & 0xF0000000) {
-               Error (ERR_NUM_OVERFLOW);
+               Error ("Overflow in hexadecimal number");
                IVal = 0;
            }
            IVal = (IVal << 4) + DigitVal (C);
@@ -687,20 +677,20 @@ Again:
        return;
     }
 
-    /* Dual number? */
+    /* Binary number? */
     if (C == '%') {
        NextChar ();
 
        /* 0 or 1 must follow */
-       if (!IsDDigit (C)) {
-           Error (ERR_01_EXPECTED);
+       if (!IsBDigit (C)) {
+           Error ("Binary digit expected");
        }
 
        /* Read the number */
        IVal = 0;
-       while (IsDDigit (C)) {
+       while (IsBDigit (C)) {
            if (IVal & 0x80000000) {
-               Error (ERR_NUM_OVERFLOW);
+               Error ("Overflow in binary number");
                IVal = 0;
            }
            IVal = (IVal << 1) + DigitVal (C);
@@ -718,8 +708,8 @@ Again:
        /* Read the number */
        IVal = 0;
        while (IsDigit (C)) {
-           if (IVal > (0xFFFFFFFF / 10)) {
-                       Error (ERR_NUM_OVERFLOW);
+                   if (IVal > (long) (0xFFFFFFFFUL / 10)) {
+                       Error ("Overflow in decimal number");
                IVal = 0;
            }
            IVal = (IVal * 10) + DigitVal (C);
@@ -734,23 +724,35 @@ Again:
     /* Control command? */
     if (C == '.') {
 
+       /* Remember and skip the dot */
        NextChar ();
 
-       if (!IsIdStart (C)) {
-           Error (ERR_PSEUDO_EXPECTED);
-           /* Try to read an identifier */
-           goto Again;
-       }
+       /* Check if it's just a dot */
+               if (!IsIdStart (C)) {
+
+           /* Just a dot */
+           Tok = TOK_DOT;
 
-       /* Read the identifier */
-       ReadIdent ();
+       } else {
+
+           /* Read the remainder of the identifier */
+            SVal[0] = '.';
+           ReadIdent (1);
+
+           /* Dot keyword, search for it */
+           Tok = FindDotKeyword ();
+           if (Tok == TOK_NONE) {
+               /* Not found */
+               if (LeadingDotInIdents) {
+                   /* An identifier with a dot */
+                   Tok = TOK_IDENT;
+               } else {
+                   /* Invalid pseudo instruction */
+                   Error ("`%s' is not a recognized control command", SVal);
+                   goto Again;
+               }
+           }
 
-       /* Search the keyword */
-       Tok = FindDotKeyword ();
-       if (Tok == TOK_NONE) {
-           /* Not found */
-           Error (ERR_PSEUDO_EXPECTED);
-           goto Again;
        }
        return;
     }
@@ -759,11 +761,11 @@ Again:
     if (C == LocalStart) {
 
        /* Read the identifier */
-       ReadIdent ();
+       ReadIdent (0);
 
        /* Start character alone is not enough */
         if (SVal [1] == '\0') {
-           Error (ERR_IDENT_EXPECTED);
+           Error ("Invalid cheap local symbol");
                    goto Again;
        }
 
@@ -777,16 +779,34 @@ Again:
     if (IsIdStart (C)) {
 
        /* Read the identifier */
-       ReadIdent ();
+       ReadIdent (0);
 
                /* Check for special names */
-        if (SVal [1] == '\0') {
+        if (SVal[1] == '\0') {
            switch (toupper (SVal [0])) {
 
                case 'A':
-                   Tok = TOK_A;
+                    if (C == ':') {
+                        NextChar ();
+                        Tok = TOK_OVERRIDE_ABS;
+                    } else {
+                       Tok = TOK_A;
+                    }
                    return;
 
+                case 'F':
+                    if (C == ':') {
+                        NextChar ();
+                        Tok = TOK_OVERRIDE_FAR;
+                    } else {
+                        Tok = TOK_IDENT;
+                    }
+                    return;
+
+               case 'S':
+                   Tok = TOK_S;
+                   return;
+
                case 'X':
                    Tok = TOK_X;
                    return;
@@ -795,9 +815,14 @@ Again:
                    Tok = TOK_Y;
                    return;
 
-               case 'S':
-                   Tok = TOK_S;
-                   return;
+                case 'Z':
+                    if (C == ':') {
+                        NextChar ();
+                        Tok = TOK_OVERRIDE_ZP;
+                    } else {
+                        Tok = TOK_IDENT;
+                    }
+                    return;
 
                default:
                    Tok = TOK_IDENT;
@@ -854,7 +879,7 @@ CharAgain:
            NextChar ();
            if (C == '&') {
                NextChar ();
-               Tok = TOK_BAND;
+               Tok = TOK_BOOLAND;
            } else {
                Tok = TOK_AND;
            }
@@ -864,7 +889,7 @@ CharAgain:
            NextChar ();
            if (C == '|') {
                NextChar ();
-               Tok = TOK_BOR;
+               Tok = TOK_BOOLOR;
            } else {
                Tok = TOK_OR;
            }
@@ -897,6 +922,11 @@ CharAgain:
                    Tok = TOK_ULABEL;
                    break;
 
+                case '=':
+                    NextChar ();
+                    Tok = TOK_ASSIGN;
+                    break;
+
                default:
                    Tok = TOK_COLON;
                    break;
@@ -963,7 +993,7 @@ CharAgain:
 
        case '!':
            NextChar ();
-           Tok = TOK_BNOT;
+           Tok = TOK_BOOLNOT;
            return;
 
        case '>':
@@ -1000,14 +1030,14 @@ CharAgain:
                /* Always a character constant */
                NextChar ();
                if (C == '\n' || C == EOF) {
-                   Error (ERR_ILLEGAL_CHARCON);
+                   Error ("Illegal character constant");
                    goto CharAgain;
                }
                IVal = C;
                Tok = TOK_CHARCON;
                NextChar ();
                if (C != '\'') {
-                   Error (ERR_ILLEGAL_CHARCON);
+                   Error ("Illegal character constant");
                } else {
                    NextChar ();
                }
@@ -1058,7 +1088,7 @@ CharAgain:
     /* If we go here, we could not identify the current character. Skip it
      * and try again.
      */
-    Error (ERR_INVALID_CHAR, C & 0xFF);
+    Error ("Invalid input character: 0x%02X", C & 0xFF);
     NextChar ();
     goto Again;
 }
@@ -1112,6 +1142,41 @@ int GetSubKey (const char** Keys, unsigned Count)
 
 
 
+unsigned char ParseAddrSize (void)
+/* Check if the next token is a keyword that denotes an address size specifier.
+ * If so, return the corresponding address size constant, otherwise output an
+ * error message and return ADDR_SIZE_DEFAULT.
+ */
+{
+    static const char* Keys[] = {
+        "DIRECT", "ZEROPAGE", "ZP",
+        "ABSOLUTE", "ABS", "NEAR",
+        "FAR",
+    };
+
+    /* Check for an identifier */
+    if (Tok != TOK_IDENT) {
+        Error ("Address size specifier expected");
+        return ADDR_SIZE_DEFAULT;
+    }
+
+    /* Search for the attribute */
+    switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
+        case 0:
+        case 1:
+        case 2: return ADDR_SIZE_ZP;
+        case 3:
+        case 4:
+        case 5: return ADDR_SIZE_ABS;
+        case 6: return ADDR_SIZE_FAR;
+        default:
+            Error ("Address size specifier expected");
+            return ADDR_SIZE_DEFAULT;
+    }
+}
+
+
+
 void InitScanner (const char* InFile)
 /* Initialize the scanner, open the given input file */
 {