/* */
/* */
/* */
-/* (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 */
#include <string.h>
#include <ctype.h>
#include <errno.h>
+#include <sys/types.h> /* EMX needs this */
#include <sys/stat.h>
/* common */
+#include "addrsize.h"
+#include "chartype.h"
#include "check.h"
#include "fname.h"
#include "xmalloc.h"
/* 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 */
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 },
- { "BYTE", TOK_BYTE },
- { "CASE", TOK_CASE },
- { "CODE", TOK_CODE },
- { "CONCAT", TOK_CONCAT },
- { "CONST", TOK_CONST },
- { "CPU", TOK_CPU },
- { "DATA", TOK_DATA },
- { "DBG", TOK_DBG },
- { "DBYT", TOK_DBYT },
- { "DEBUGINFO", TOK_DEBUGINFO },
- { "DEF", TOK_DEFINED },
- { "DEFINE", TOK_DEFINE },
- { "DEFINED", TOK_DEFINED },
- { "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 },
};
-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);
static int IsIdStart (int C)
/* Return true if the character may start an identifier */
{
- return isalpha (C) || C == '_';
+ return IsAlpha (C) || C == '_';
}
/* 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
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 */
/* 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 */
-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;
+void LocaseSVal (void)
+/* Make SVal lower case */
+{
+ unsigned I = 0;
+ while (SVal [I]) {
+ SVal [I] = tolower (SVal [I]);
+ ++I;
+ }
+}
+
+
+
void UpcaseSVal (void)
/* Make SVal upper case */
{
-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) {
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;
}
Tok = TOK_PC;
return;
} else {
- Error (ERR_HEX_DIGIT_EXPECTED);
+ Error ("Hexadecimal digit expected");
}
}
IVal = 0;
while (IsXDigit (C)) {
if (IVal & 0xF0000000) {
- Error (ERR_NUM_OVERFLOW);
+ Error ("Overflow in hexadecimal number");
IVal = 0;
}
IVal = (IVal << 4) + DigitVal (C);
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);
/* 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);
/* 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;
}
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;
}
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;
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;
NextChar ();
if (C == '&') {
NextChar ();
- Tok = TOK_BAND;
+ Tok = TOK_BOOLAND;
} else {
Tok = TOK_AND;
}
NextChar ();
if (C == '|') {
NextChar ();
- Tok = TOK_BOR;
+ Tok = TOK_BOOLOR;
} else {
Tok = TOK_OR;
}
Tok = TOK_ULABEL;
break;
+ case '=':
+ NextChar ();
+ Tok = TOK_ASSIGN;
+ break;
+
default:
Tok = TOK_COLON;
break;
case '!':
NextChar ();
- Tok = TOK_BNOT;
+ Tok = TOK_BOOLNOT;
return;
case '>':
/* 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 ();
}
/* 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;
}
+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 */
{