X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fca65%2Fscanner.c;h=cb4712a65b81fbacf5da17f3e2b3c3b0bc57767a;hb=5ef1f65c9bd9f83ecbb8c66c6d8f8da0dec85e47;hp=e1a08e2e40ef1c8330351623970cc54e3a7afe16;hpb=77ec52a06d0f7c7bafe1ad6eb3a34f046de83389;p=cc65 diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c index e1a08e2e4..cb4712a65 100644 --- a/src/ca65/scanner.c +++ b/src/ca65/scanner.c @@ -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 /* 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 */ {