/*****************************************************************************/
/* */
-/* scanner.c */
+/* scanner.c */
/* */
-/* The scanner for the ca65 macroassembler */
+/* The scanner for the ca65 macroassembler */
/* */
/* */
/* */
-/* (C) 1998-2008 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2013, Ullrich von Bassewitz */
+/* Roemerstrasse 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 "attrib.h"
#include "chartype.h"
#include "check.h"
+#include "filestat.h"
#include "fname.h"
#include "xmalloc.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
-Token Tok = TOK_NONE; /* Current token */
-int WS; /* Flag: Whitespace before token */
-long IVal; /* Integer token attribute */
-StrBuf SVal = STATIC_STRBUF_INITIALIZER;/* String token attribute */
-
-FilePos CurPos = { 0, 0, 0 }; /* Name and position in current file */
-
-
+/* Current input token incl. attributes */
+Token CurTok = STATIC_TOKEN_INITIALIZER;
/* Struct to handle include files. */
typedef struct InputFile InputFile;
struct InputFile {
- FILE* F; /* Input file descriptor */
- FilePos Pos; /* Position in file */
- Token Tok; /* Last token */
- int C; /* Last character */
- char Line[256]; /* The current input line */
- InputFile* Next; /* Linked list of input files */
+ FILE* F; /* Input file descriptor */
+ FilePos Pos; /* Position in file */
+ token_t Tok; /* Last token */
+ int C; /* Last character */
+ StrBuf Line; /* The current input line */
+ int IncSearchPath; /* True if we've added a search path */
+ int BinSearchPath; /* True if we've added a search path */
+ InputFile* Next; /* Linked list of input files */
};
/* Struct to handle textual input data */
typedef struct InputData InputData;
struct InputData {
- char* Text; /* Pointer to the text data */
- const char* Pos; /* Pointer to current position */
- int Malloced; /* Memory was malloced */
- Token Tok; /* Last token */
- int C; /* Last character */
- InputData* Next; /* Linked list of input data */
+ char* Text; /* Pointer to the text data */
+ const char* Pos; /* Pointer to current position */
+ int Malloced; /* Memory was malloced */
+ token_t Tok; /* Last token */
+ int C; /* Last character */
+ InputData* Next; /* Linked list of input data */
};
/* Input source: Either file or data */
/* Input source: Either file or data */
struct CharSource {
CharSource* Next; /* Linked list of char sources */
- Token Tok; /* Last token */
- int C; /* Last character */
+ token_t Tok; /* Last token */
+ int C; /* Last character */
const CharSourceFunctions* Func; /* Pointer to function table */
union {
InputFile File; /* File data */
/* Current input variables */
static CharSource* Source = 0; /* Current char source */
-static unsigned FCount = 0; /* Count of input files */
-static int C = 0; /* Current input character */
+static unsigned FCount = 0; /* Count of input files */
+static int C = 0; /* Current input character */
/* Force end of assembly */
-int ForcedEnd = 0;
+int ForcedEnd = 0;
/* List of dot keywords with the corresponding tokens */
struct DotKeyword {
- const char* Key; /* MUST be first field */
- Token Tok;
+ const char* Key; /* MUST be first field */
+ token_t Tok;
} DotKeywords [] = {
- { ".A16", TOK_A16 },
- { ".A8", TOK_A8 },
- { ".ADDR", TOK_ADDR },
- { ".ALIGN", TOK_ALIGN },
- { ".AND", TOK_BOOLAND },
- { ".ASCIIZ", TOK_ASCIIZ },
+ { ".A16", TOK_A16 },
+ { ".A8", TOK_A8 },
+ { ".ADDR", TOK_ADDR },
+ { ".ALIGN", TOK_ALIGN },
+ { ".AND", TOK_BOOLAND },
+ { ".ASCIIZ", TOK_ASCIIZ },
{ ".ASSERT", TOK_ASSERT },
- { ".AUTOIMPORT", TOK_AUTOIMPORT },
+ { ".AUTOIMPORT", TOK_AUTOIMPORT },
+ { ".BANK", TOK_BANK },
{ ".BANKBYTE", TOK_BANKBYTE },
- { ".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 },
+ { ".BANKBYTES", TOK_BANKBYTES },
+ { ".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 },
+ { ".DELMAC", TOK_DELMAC },
+ { ".DELMACRO", TOK_DELMAC },
+ { ".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 },
+ { ".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 },
+ { ".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 },
+ { ".ERROR", TOK_ERROR },
+ { ".EXITMAC", TOK_EXITMACRO },
+ { ".EXITMACRO", TOK_EXITMACRO },
+ { ".EXPORT", TOK_EXPORT },
+ { ".EXPORTZP", TOK_EXPORTZP },
+ { ".FARADDR", TOK_FARADDR },
+ { ".FATAL", TOK_FATAL },
+ { ".FEATURE", TOK_FEATURE },
+ { ".FILEOPT", TOK_FILEOPT },
+ { ".FOPT", TOK_FILEOPT },
{ ".FORCEIMPORT", TOK_FORCEIMPORT },
- { ".FORCEWORD", TOK_FORCEWORD },
- { ".GLOBAL", TOK_GLOBAL },
- { ".GLOBALZP", TOK_GLOBALZP },
+ { ".FORCEWORD", TOK_FORCEWORD },
+ { ".GLOBAL", TOK_GLOBAL },
+ { ".GLOBALZP", TOK_GLOBALZP },
{ ".HIBYTE", TOK_HIBYTE },
+ { ".HIBYTES", TOK_HIBYTES },
{ ".HIWORD", TOK_HIWORD },
- { ".I16", TOK_I16 },
- { ".I8", TOK_I8 },
+ { ".I16", TOK_I16 },
+ { ".I8", TOK_I8 },
{ ".IDENT", TOK_MAKEIDENT },
- { ".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 },
+ { ".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 },
{ ".INTERRUPTOR", TOK_INTERRUPTOR },
- { ".LEFT", TOK_LEFT },
- { ".LINECONT", TOK_LINECONT },
- { ".LIST", TOK_LIST },
- { ".LISTBYTES", TOK_LISTBYTES },
+ { ".LEFT", TOK_LEFT },
+ { ".LINECONT", TOK_LINECONT },
+ { ".LIST", TOK_LIST },
+ { ".LISTBYTES", TOK_LISTBYTES },
{ ".LOBYTE", TOK_LOBYTE },
- { ".LOCAL", TOK_LOCAL },
- { ".LOCALCHAR", TOK_LOCALCHAR },
+ { ".LOBYTES", TOK_LOBYTES },
+ { ".LOCAL", TOK_LOCAL },
+ { ".LOCALCHAR", TOK_LOCALCHAR },
{ ".LOWORD", TOK_LOWORD },
- { ".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 },
+ { ".MAC", TOK_MACRO },
+ { ".MACPACK", TOK_MACPACK },
+ { ".MACRO", TOK_MACRO },
+ { ".MATCH", TOK_MATCH },
+ { ".MAX", TOK_MAX },
+ { ".MID", TOK_MID },
+ { ".MIN", TOK_MIN },
+ { ".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 },
+ { ".POPCPU", TOK_POPCPU },
+ { ".POPSEG", TOK_POPSEG },
+ { ".PROC", TOK_PROC },
+ { ".PSC02", TOK_PSC02 },
+ { ".PUSHCPU", TOK_PUSHCPU },
+ { ".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 },
+ { ".SEGMENT", TOK_SEGMENT },
{ ".SET", TOK_SET },
- { ".SETCPU", TOK_SETCPU },
- { ".SHL", TOK_SHL },
- { ".SHR", TOK_SHR },
+ { ".SETCPU", TOK_SETCPU },
+ { ".SHL", TOK_SHL },
+ { ".SHR", TOK_SHR },
{ ".SIZEOF", TOK_SIZEOF },
- { ".SMART", TOK_SMART },
+ { ".SMART", TOK_SMART },
{ ".SPRINTF", TOK_SPRINTF },
- { ".STRAT", TOK_STRAT },
- { ".STRING", TOK_STRING },
- { ".STRLEN", TOK_STRLEN },
+ { ".STRAT", TOK_STRAT },
+ { ".STRING", TOK_STRING },
+ { ".STRLEN", TOK_STRLEN },
{ ".STRUCT", TOK_STRUCT },
- { ".SUNPLUS", TOK_SUNPLUS },
{ ".TAG", TOK_TAG },
- { ".TCOUNT", TOK_TCOUNT },
- { ".TIME", TOK_TIME },
+ { ".TCOUNT", TOK_TCOUNT },
+ { ".TIME", TOK_TIME },
+ { ".UNDEF", TOK_UNDEF },
+ { ".UNDEFINE", TOK_UNDEF },
{ ".UNION", TOK_UNION },
{ ".VERSION", TOK_VERSION },
- { ".WARNING", TOK_WARNING },
- { ".WORD", TOK_WORD },
- { ".XMATCH", TOK_XMATCH },
- { ".XOR", TOK_BOOLXOR },
- { ".ZEROPAGE", TOK_ZEROPAGE },
+ { ".WARNING", TOK_WARNING },
+ { ".WORD", TOK_WORD },
+ { ".XMATCH", TOK_XMATCH },
+ { ".XOR", TOK_BOOLXOR },
+ { ".ZEROPAGE", TOK_ZEROPAGE },
};
/* Initialize a new input source and start to use it. */
{
/* Remember the current input char and token */
- S->Tok = Tok;
+ S->Tok = CurTok.Tok;
S->C = C;
/* Use the new input source */
- S->Next = Source;
+ S->Next = Source;
Source = S;
/* Read the first character from the new file */
/* Setup the next token so it will be skipped on the next call to
* NextRawTok().
*/
- Tok = TOK_SEP;
+ CurTok.Tok = TOK_SEP;
}
Source->Func->Done (Source);
/* Restore the old token */
- Tok = Source->Tok;
+ CurTok.Tok = Source->Tok;
C = Source->C;
/* Remember the last stacked input source */
static void IFMarkStart (CharSource* S)
/* Mark the start of the next token */
{
- CurPos = S->V.File.Pos;
+ CurTok.Pos = S->V.File.Pos;
}
/* Read the next character from the input file */
{
/* Check for end of line, read the next line if needed */
- while (S->V.File.Line [S->V.File.Pos.Col] == '\0') {
+ while (SB_GetIndex (&S->V.File.Line) >= SB_GetLen (&S->V.File.Line)) {
- unsigned Len, Removed;
+ unsigned Len;
/* End of current line reached, read next line */
- if (fgets (S->V.File.Line, sizeof (S->V.File.Line), S->V.File.F) == 0) {
- /* End of file. Add an empty line to the listing. This is a
- * small hack needed to keep the PC output in sync.
- */
- NewListingLine ("", S->V.File.Pos.Name, FCount);
- C = EOF;
- return;
+ SB_Clear (&S->V.File.Line);
+ while (1) {
+
+ int N = fgetc (S->V.File.F);
+ if (N == EOF) {
+ /* End of file. Accept files without a newline at the end */
+ if (SB_NotEmpty (&S->V.File.Line)) {
+ break;
+ }
+
+ /* No more data - add an empty line to the listing. This
+ * is a small hack needed to keep the PC output in sync.
+ */
+ NewListingLine (&EmptyStrBuf, S->V.File.Pos.Name, FCount);
+ C = EOF;
+ return;
+
+ /* Check for end of line */
+ } else if (N == '\n') {
+
+ /* End of line */
+ break;
+
+ /* Collect other stuff */
+ } else {
+
+ /* Append data to line */
+ SB_AppendChar (&S->V.File.Line, N);
+
+ }
}
- /* For better handling of files with unusual line endings (DOS
- * files that are accidently translated on Unix for example),
- * first remove all whitespace at the end, then add a single
- * newline.
+
+ /* If we come here, we have a new input line. To avoid problems
+ * with strange line terminators, remove all whitespace from the
+ * end of the line, the add a single newline.
*/
- Len = strlen (S->V.File.Line);
- Removed = 0;
- while (Len > 0 && IsSpace (S->V.File.Line[Len-1])) {
- ++Removed;
+ Len = SB_GetLen (&S->V.File.Line);
+ while (Len > 0 && IsSpace (SB_AtUnchecked (&S->V.File.Line, Len-1))) {
--Len;
}
- if (Removed) {
- S->V.File.Line[Len+0] = '\n';
- S->V.File.Line[Len+1] = '\0';
- }
+ SB_Drop (&S->V.File.Line, SB_GetLen (&S->V.File.Line) - Len);
+ SB_AppendChar (&S->V.File.Line, '\n');
+
+ /* Terminate the string buffer */
+ SB_Terminate (&S->V.File.Line);
/* One more line */
S->V.File.Pos.Line++;
- S->V.File.Pos.Col = 0;
/* Remember the new line for the listing */
- NewListingLine (S->V.File.Line, S->V.File.Pos.Name, FCount);
+ NewListingLine (&S->V.File.Line, S->V.File.Pos.Name, FCount);
}
- /* Return the next character from the file */
- C = S->V.File.Line [S->V.File.Pos.Col++];
+ /* Set the column pointer */
+ S->V.File.Pos.Col = SB_GetIndex (&S->V.File.Line);
+
+ /* Return the next character from the buffer */
+ C = SB_Get (&S->V.File.Line);
}
*/
CheckOpenIfs ();
+ /* If we've added search paths for this file, remove them */
+ if (S->V.File.IncSearchPath) {
+ PopSearchPath (IncSearchPath);
+ }
+ if (S->V.File.BinSearchPath) {
+ PopSearchPath (BinSearchPath);
+ }
+
+ /* Free the line buffer */
+ SB_Done (&S->V.File.Line);
+
/* Close the input file and decrement the file count. We will ignore
* errors here, since we were just reading from the file.
*/
* and false otherwise.
*/
{
- int RetCode = 0; /* Return code. Assume an error. */
- char* PathName = 0;
-
- /* First try to open the file */
- FILE* F = fopen (Name, "r");
- if (F == 0) {
-
- /* Error (fatal error if this is the main file) */
- if (FCount == 0) {
- Fatal ("Cannot open input file `%s': %s", Name, strerror (errno));
- }
-
- /* We are on include level. Search for the file in the include
- * directories.
- */
- PathName = FindInclude (Name);
- if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
- /* Not found or cannot open, print an error and bail out */
- Error ("Cannot open include file `%s': %s", Name, strerror (errno));
+ int RetCode = 0; /* Return code. Assume an error. */
+ char* PathName = 0;
+ FILE* F;
+ struct stat Buf;
+ StrBuf NameBuf; /* No need to initialize */
+ StrBuf Path = AUTO_STRBUF_INITIALIZER;
+ unsigned FileIdx;
+ CharSource* S;
+
+
+ /* If this is the main file, just try to open it. If it's an include file,
+ * search for it using the include path list.
+ */
+ if (FCount == 0) {
+ /* Main file */
+ F = fopen (Name, "r");
+ if (F == 0) {
+ Fatal ("Cannot open input file `%s': %s", Name, strerror (errno));
+ }
+ } else {
+ /* We are on include level. Search for the file in the include
+ * directories.
+ */
+ PathName = SearchFile (IncSearchPath, Name);
+ if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
+ /* Not found or cannot open, print an error and bail out */
+ Error ("Cannot open include file `%s': %s", Name, strerror (errno));
goto ExitPoint;
- }
+ }
- /* Use the path name from now on */
+ /* Use the path name from now on */
Name = PathName;
}
- /* check again if we do now have an open file */
- if (F != 0) {
+ /* Stat the file and remember the values. There a race condition here,
+ * since we cannot use fileno() (non standard identifier in standard
+ * header file), and therefore not fstat. When using stat with the
+ * file name, there's a risk that the file was deleted and recreated
+ * while it was open. Since mtime and size are only used to check
+ * if a file has changed in the debugger, we will ignore this problem
+ * here.
+ */
+ if (FileStat (Name, &Buf) != 0) {
+ Fatal ("Cannot stat input file `%s': %s", Name, strerror (errno));
+ }
- StrBuf NameBuf;
- unsigned FileIdx;
- CharSource* S;
+ /* Add the file to the input file table and remember the index */
+ FileIdx = AddFile (SB_InitFromString (&NameBuf, Name),
+ (FCount == 0)? FT_MAIN : FT_INCLUDE,
+ Buf.st_size, (unsigned long) Buf.st_mtime);
- /* Stat the file and remember the values. There a race condition here,
- * since we cannot use fileno() (non standard identifier in standard
- * header file), and therefore not fstat. When using stat with the
- * file name, there's a risk that the file was deleted and recreated
- * while it was open. Since mtime and size are only used to check
- * if a file has changed in the debugger, we will ignore this problem
- * here.
- */
- struct stat Buf;
- if (stat (Name, &Buf) != 0) {
- Fatal ("Cannot stat input file `%s': %s", Name, strerror (errno));
- }
-
- /* Add the file to the input file table and remember the index */
- FileIdx = AddFile (SB_InitFromString (&NameBuf, Name), Buf.st_size, Buf.st_mtime);
-
- /* Create a new input source variable and initialize it */
- S = xmalloc (sizeof (*S));
- S->Func = &IFFunc;
- S->V.File.F = F;
- S->V.File.Pos.Line = 0;
- S->V.File.Pos.Col = 0;
- S->V.File.Pos.Name = FileIdx;
- S->V.File.Line[0] = '\0';
-
- /* Count active input files */
- ++FCount;
-
- /* Use this input source */
- UseCharSource (S);
- }
+ /* Create a new input source variable and initialize it */
+ S = xmalloc (sizeof (*S));
+ S->Func = &IFFunc;
+ S->V.File.F = F;
+ S->V.File.Pos.Line = 0;
+ S->V.File.Pos.Col = 0;
+ S->V.File.Pos.Name = FileIdx;
+ SB_Init (&S->V.File.Line);
+
+ /* Push the path for this file onto the include search lists */
+ SB_CopyBuf (&Path, Name, FindName (Name) - Name);
+ SB_Terminate (&Path);
+ S->V.File.IncSearchPath = PushSearchPath (IncSearchPath, SB_GetConstBuf (&Path));
+ S->V.File.BinSearchPath = PushSearchPath (BinSearchPath, SB_GetConstBuf (&Path));
+ SB_Done (&Path);
+
+ /* Count active input files */
+ ++FCount;
+
+ /* Use this input source */
+ UseCharSource (S);
/* File successfully opened */
RetCode = 1;
{
/* Cleanup the current stuff */
if (S->V.Data.Malloced) {
- xfree (S->V.Data.Text);
+ xfree (S->V.Data.Text);
}
}
/*****************************************************************************/
-/* Character classification functions */
+/* Character classification functions */
/*****************************************************************************/
int IsIdChar (int C)
/* Return true if the character is a valid character for an identifier */
{
- return IsAlNum (C) ||
- (C == '_') ||
- (C == '@' && AtInIdents) ||
- (C == '$' && DollarInIdents);
+ return IsAlNum (C) ||
+ (C == '_') ||
+ (C == '@' && AtInIdents) ||
+ (C == '$' && DollarInIdents);
}
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
/* Convert a digit into it's numerical representation */
{
if (IsDigit (C)) {
- return C - '0';
+ return C - '0';
} else {
- return toupper (C) - 'A' + 10;
+ return toupper (C) - 'A' + 10;
}
}
void LocaseSVal (void)
/* Make SVal lower case */
{
- SB_ToLower (&SVal);
+ SB_ToLower (&CurTok.SVal);
}
void UpcaseSVal (void)
/* Make SVal upper case */
{
- SB_ToUpper (&SVal);
+ SB_ToUpper (&CurTok.SVal);
}
-static unsigned char FindDotKeyword (void)
+static token_t FindDotKeyword (void)
/* Find the dot keyword in SVal. Return the corresponding token if found,
* return TOK_NONE if not found.
*/
struct DotKeyword* R;
/* Initialize K */
- K.Key = SB_GetConstBuf (&SVal);
+ K.Key = SB_GetConstBuf (&CurTok.SVal);
K.Tok = 0;
/* If we aren't in ignore case mode, we have to uppercase the keyword */
if (!IgnoreCase) {
- UpcaseSVal ();
+ UpcaseSVal ();
}
/* Search for the keyword */
R = bsearch (&K, DotKeywords, sizeof (DotKeywords) / sizeof (DotKeywords [0]),
- sizeof (DotKeywords [0]), CmpDotKeyword);
+ sizeof (DotKeywords [0]), CmpDotKeyword);
if (R != 0) {
- return R->Tok;
+ return R->Tok;
} else {
- return TOK_NONE;
+ return TOK_NONE;
}
}
-
+
static void ReadIdent (void)
/* Read an identifier from the current input position into Ident. Filling SVal
* starts at the current position with the next character in C. It is assumed
{
/* Read the identifier */
do {
- SB_AppendChar (&SVal, C);
- NextChar ();
+ SB_AppendChar (&CurTok.SVal, C);
+ NextChar ();
} while (IsIdChar (C));
- SB_Terminate (&SVal);
+ SB_Terminate (&CurTok.SVal);
/* If we should ignore case, convert the identifier to upper case */
if (IgnoreCase) {
- UpcaseSVal ();
+ UpcaseSVal ();
}
}
/* Read the string */
while (1) {
- if (C == StringTerm) {
- break;
- }
- if (C == '\n' || C == EOF) {
- Error ("Newline in string constant");
- break;
- }
-
- /* Append the char to the string */
- SB_AppendChar (&SVal, C);
-
- /* Skip the character */
- NextChar ();
+ if (C == StringTerm) {
+ break;
+ }
+ if (C == '\n' || C == EOF) {
+ Error ("Newline in string constant");
+ break;
+ }
+
+ /* Append the char to the string */
+ SB_AppendChar (&CurTok.SVal, C);
+
+ /* Skip the character */
+ NextChar ();
}
/* Skip the trailing terminator */
NextChar ();
/* Terminate the string */
- SB_Terminate (&SVal);
+ SB_Terminate (&CurTok.SVal);
}
void NextRawTok (void)
/* Read the next raw token from the input stream */
{
+ Macro* M;
+
/* If we've a forced end of assembly, don't read further */
if (ForcedEnd) {
- Tok = TOK_EOF;
- return;
+ CurTok.Tok = TOK_EOF;
+ return;
}
Restart:
/* Check if we have tokens from another input source */
if (InputFromStack ()) {
- return;
+ if (CurTok.Tok == TOK_IDENT && (M = FindDefine (&CurTok.SVal)) != 0) {
+ /* This is a define style macro - expand it */
+ MacExpandStart (M);
+ goto Restart;
+ }
+ return;
}
Again:
/* Skip whitespace, remember if we had some */
- if ((WS = IsBlank (C)) != 0) {
- do {
- NextChar ();
+ if ((CurTok.WS = IsBlank (C)) != 0) {
+ do {
+ NextChar ();
} while (IsBlank (C));
}
Source->Func->MarkStart (Source);
/* Clear the string attribute */
- SB_Clear (&SVal);
+ SB_Clear (&CurTok.SVal);
+
+ /* Generate line info for the current token */
+ NewAsmLine ();
/* Hex number or PC symbol? */
if (C == '$') {
- NextChar ();
-
- /* Hex digit must follow or DollarIsPC must be enabled */
- if (!IsXDigit (C)) {
- if (DollarIsPC) {
- Tok = TOK_PC;
- return;
- } else {
- Error ("Hexadecimal digit expected");
- }
- }
-
- /* Read the number */
- IVal = 0;
- while (IsXDigit (C)) {
- if (IVal & 0xF0000000) {
- Error ("Overflow in hexadecimal number");
- IVal = 0;
- }
- IVal = (IVal << 4) + DigitVal (C);
- NextChar ();
- }
-
- /* This is an integer constant */
- Tok = TOK_INTCON;
- return;
+ NextChar ();
+
+ /* Hex digit must follow or DollarIsPC must be enabled */
+ if (!IsXDigit (C)) {
+ if (DollarIsPC) {
+ CurTok.Tok = TOK_PC;
+ return;
+ } else {
+ Error ("Hexadecimal digit expected");
+ }
+ }
+
+ /* Read the number */
+ CurTok.IVal = 0;
+ while (1) {
+ if (UnderlineInNumbers && C == '_') {
+ while (C == '_') {
+ NextChar ();
+ }
+ if (!IsXDigit (C)) {
+ Error ("Number may not end with underline");
+ }
+ }
+ if (IsXDigit (C)) {
+ if (CurTok.IVal & 0xF0000000) {
+ Error ("Overflow in hexadecimal number");
+ CurTok.IVal = 0;
+ }
+ CurTok.IVal = (CurTok.IVal << 4) + DigitVal (C);
+ NextChar ();
+ } else {
+ break;
+ }
+ }
+
+ /* This is an integer constant */
+ CurTok.Tok = TOK_INTCON;
+ return;
}
/* Binary number? */
if (C == '%') {
- NextChar ();
-
- /* 0 or 1 must follow */
- if (!IsBDigit (C)) {
- Error ("Binary digit expected");
- }
-
- /* Read the number */
- IVal = 0;
- while (IsBDigit (C)) {
- if (IVal & 0x80000000) {
- Error ("Overflow in binary number");
- IVal = 0;
- }
- IVal = (IVal << 1) + DigitVal (C);
- NextChar ();
- }
-
- /* This is an integer constant */
- Tok = TOK_INTCON;
- return;
+ NextChar ();
+
+ /* 0 or 1 must follow */
+ if (!IsBDigit (C)) {
+ Error ("Binary digit expected");
+ }
+
+ /* Read the number */
+ CurTok.IVal = 0;
+ while (1) {
+ if (UnderlineInNumbers && C == '_') {
+ while (C == '_') {
+ NextChar ();
+ }
+ if (!IsBDigit (C)) {
+ Error ("Number may not end with underline");
+ }
+ }
+ if (IsBDigit (C)) {
+ if (CurTok.IVal & 0x80000000) {
+ Error ("Overflow in binary number");
+ CurTok.IVal = 0;
+ }
+ CurTok.IVal = (CurTok.IVal << 1) + DigitVal (C);
+ NextChar ();
+ } else {
+ break;
+ }
+ }
+
+ /* This is an integer constant */
+ CurTok.Tok = TOK_INTCON;
+ return;
}
/* Number? */
/* Read the number into Buf counting the digits */
Digits = 0;
- while (IsXDigit (C)) {
-
- /* Buf is big enough to allow any decimal and hex number to
- * overflow, so ignore excess digits here, they will be detected
- * when we convert the value.
- */
- if (Digits < sizeof (Buf)) {
- Buf[Digits++] = C;
+ while (1) {
+ if (UnderlineInNumbers && C == '_') {
+ while (C == '_') {
+ NextChar ();
+ }
+ if (!IsXDigit (C)) {
+ Error ("Number may not end with underline");
+ }
+ }
+ if (IsXDigit (C)) {
+ /* Buf is big enough to allow any decimal and hex number to
+ * overflow, so ignore excess digits here, they will be detected
+ * when we convert the value.
+ */
+ if (Digits < sizeof (Buf)) {
+ Buf[Digits++] = C;
+ }
+ NextChar ();
+ } else {
+ break;
}
-
- NextChar ();
}
/* Allow zilog/intel style hex numbers with a 'h' suffix */
}
/* Convert the number using the given base */
- IVal = 0;
+ CurTok.IVal = 0;
for (I = 0; I < Digits; ++I) {
- if (IVal > Max) {
- Error ("Number out of range");
- IVal = 0;
+ if (CurTok.IVal > Max) {
+ Error ("Number out of range");
+ CurTok.IVal = 0;
break;
- }
+ }
DVal = DigitVal (Buf[I]);
if (DVal > Base) {
Error ("Invalid digits in number");
- IVal = 0;
+ CurTok.IVal = 0;
break;
}
- IVal = (IVal * Base) + DVal;
+ CurTok.IVal = (CurTok.IVal * Base) + DVal;
}
- /* This is an integer constant */
- Tok = TOK_INTCON;
- return;
+ /* This is an integer constant */
+ CurTok.Tok = TOK_INTCON;
+ return;
}
/* Control command? */
if (C == '.') {
- /* Remember and skip the dot */
- NextChar ();
-
- /* Check if it's just a dot */
- if (!IsIdStart (C)) {
-
- /* Just a dot */
- Tok = TOK_DOT;
-
- } else {
-
- /* Read the remainder of the identifier */
- SB_AppendChar (&SVal, '.');
- ReadIdent ();
+ /* Remember and skip the dot */
+ NextChar ();
- /* Dot keyword, search for it */
- Tok = FindDotKeyword ();
- if (Tok == TOK_NONE) {
+ /* Check if it's just a dot */
+ if (!IsIdStart (C)) {
- /* Not found */
- if (!LeadingDotInIdents) {
- /* Invalid pseudo instruction */
- Error ("`%m%p' is not a recognized control command", &SVal);
- goto Again;
- }
+ /* Just a dot */
+ CurTok.Tok = TOK_DOT;
- /* An identifier with a dot. Check if it's a define style
- * macro.
- */
- if (IsDefine (&SVal)) {
- /* This is a define style macro - expand it */
- MacExpandStart ();
- goto Restart;
- }
+ } else {
- /* Just an identifier with a dot */
- Tok = TOK_IDENT;
- }
+ /* Read the remainder of the identifier */
+ SB_AppendChar (&CurTok.SVal, '.');
+ ReadIdent ();
+
+ /* Dot keyword, search for it */
+ CurTok.Tok = FindDotKeyword ();
+ if (CurTok.Tok == TOK_NONE) {
+
+ /* Not found */
+ if (!LeadingDotInIdents) {
+ /* Invalid pseudo instruction */
+ Error ("`%m%p' is not a recognized control command", &CurTok.SVal);
+ goto Again;
+ }
+
+ /* An identifier with a dot. Check if it's a define style
+ * macro.
+ */
+ if ((M = FindDefine (&CurTok.SVal)) != 0) {
+ /* This is a define style macro - expand it */
+ MacExpandStart (M);
+ goto Restart;
+ }
+
+ /* Just an identifier with a dot */
+ CurTok.Tok = TOK_IDENT;
+ }
- }
- return;
+ }
+ return;
}
/* Indirect op for sweet16 cpu. Must check this before checking for local
*/
if (CPU == CPU_SWEET16 && C == '@') {
NextChar ();
- Tok = TOK_AT;
+ CurTok.Tok = TOK_AT;
return;
}
/* Local symbol? */
if (C == LocalStart) {
- /* Read the identifier. */
- ReadIdent ();
+ /* Read the identifier. */
+ ReadIdent ();
- /* Start character alone is not enough */
- if (SB_GetLen (&SVal) == 1) {
- Error ("Invalid cheap local symbol");
- goto Again;
- }
+ /* Start character alone is not enough */
+ if (SB_GetLen (&CurTok.SVal) == 1) {
+ Error ("Invalid cheap local symbol");
+ goto Again;
+ }
- /* A local identifier */
- Tok = TOK_LOCAL_IDENT;
- return;
+ /* A local identifier */
+ CurTok.Tok = TOK_LOCAL_IDENT;
+ return;
}
/* Identifier or keyword? */
if (IsIdStart (C)) {
- /* Read the identifier */
- ReadIdent ();
+ /* Read the identifier */
+ ReadIdent ();
- /* Check for special names. Bail out if we have identified the type of
- * the token. Go on if the token is an identifier.
- */
- if (SB_GetLen (&SVal) == 1) {
- switch (toupper (SB_AtUnchecked (&SVal, 0))) {
+ /* Check for special names. Bail out if we have identified the type of
+ * the token. Go on if the token is an identifier.
+ */
+ if (SB_GetLen (&CurTok.SVal) == 1) {
+ switch (toupper (SB_AtUnchecked (&CurTok.SVal, 0))) {
- case 'A':
+ case 'A':
if (C == ':') {
NextChar ();
- Tok = TOK_OVERRIDE_ABS;
+ CurTok.Tok = TOK_OVERRIDE_ABS;
} else {
- Tok = TOK_A;
+ CurTok.Tok = TOK_A;
}
- return;
+ return;
case 'F':
if (C == ':') {
NextChar ();
- Tok = TOK_OVERRIDE_FAR;
- return;
+ CurTok.Tok = TOK_OVERRIDE_FAR;
+ return;
}
- break;
+ break;
- case 'S':
+ case 'S':
if (CPU == CPU_65816) {
- Tok = TOK_S;
+ CurTok.Tok = TOK_S;
return;
}
break;
- case 'X':
- Tok = TOK_X;
- return;
+ case 'X':
+ CurTok.Tok = TOK_X;
+ return;
- case 'Y':
- Tok = TOK_Y;
- return;
+ case 'Y':
+ CurTok.Tok = TOK_Y;
+ return;
case 'Z':
if (C == ':') {
NextChar ();
- Tok = TOK_OVERRIDE_ZP;
- return;
+ CurTok.Tok = TOK_OVERRIDE_ZP;
+ return;
}
break;
- default:
- break;
- }
+ default:
+ break;
+ }
- } else if (CPU == CPU_SWEET16 && (IVal = Sweet16Reg (&SVal)) >= 0) {
+ } else if (CPU == CPU_SWEET16 &&
+ (CurTok.IVal = Sweet16Reg (&CurTok.SVal)) >= 0) {
/* A sweet16 register number in sweet16 mode */
- Tok = TOK_REG;
+ CurTok.Tok = TOK_REG;
return;
}
- /* Check for define style macro */
- if (IsDefine (&SVal)) {
- /* Macro - expand it */
- MacExpandStart ();
- goto Restart;
- } else {
- /* An identifier */
- Tok = TOK_IDENT;
- }
- return;
+ /* Check for define style macro */
+ if ((M = FindDefine (&CurTok.SVal)) != 0) {
+ /* Macro - expand it */
+ MacExpandStart (M);
+ goto Restart;
+ } else {
+ /* An identifier */
+ CurTok.Tok = TOK_IDENT;
+ }
+ return;
}
/* Ok, let's do the switch */
CharAgain:
switch (C) {
- case '+':
- NextChar ();
- Tok = TOK_PLUS;
- return;
+ case '+':
+ NextChar ();
+ CurTok.Tok = TOK_PLUS;
+ return;
- case '-':
- NextChar ();
- Tok = TOK_MINUS;
- return;
+ case '-':
+ NextChar ();
+ CurTok.Tok = TOK_MINUS;
+ return;
- case '/':
- NextChar ();
+ case '/':
+ NextChar ();
if (C != '*') {
- Tok = TOK_DIV;
+ CurTok.Tok = TOK_DIV;
} else if (CComments) {
/* Remember the position, then skip the '*' */
- FilePos Pos = CurPos;
+ Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
+ GetFullLineInfo (&LineInfos);
NextChar ();
do {
while (C != '*') {
if (C == EOF) {
- PError (&Pos, "Unterminated comment");
+ LIError (&LineInfos, "Unterminated comment");
+ ReleaseFullLineInfo (&LineInfos);
+ DoneCollection (&LineInfos);
goto CharAgain;
}
NextChar ();
NextChar ();
} while (C != '/');
NextChar ();
+ ReleaseFullLineInfo (&LineInfos);
+ DoneCollection (&LineInfos);
goto Again;
}
- return;
-
- case '*':
- NextChar ();
- Tok = TOK_MUL;
- return;
-
- case '^':
- NextChar ();
- Tok = TOK_XOR;
- return;
-
- case '&':
- NextChar ();
- if (C == '&') {
- NextChar ();
- Tok = TOK_BOOLAND;
- } else {
- Tok = TOK_AND;
- }
- return;
-
- case '|':
- NextChar ();
- if (C == '|') {
- NextChar ();
- Tok = TOK_BOOLOR;
- } else {
- Tok = TOK_OR;
- }
- return;
-
- case ':':
- NextChar ();
- switch (C) {
-
- case ':':
- NextChar ();
- Tok = TOK_NAMESPACE;
- break;
-
- case '-':
- IVal = 0;
- do {
- --IVal;
- NextChar ();
- } while (C == '-');
- Tok = TOK_ULABEL;
- break;
-
- case '+':
- IVal = 0;
- do {
- ++IVal;
- NextChar ();
- } while (C == '+');
- Tok = TOK_ULABEL;
- break;
+ return;
+
+ case '*':
+ NextChar ();
+ CurTok.Tok = TOK_MUL;
+ return;
+
+ case '^':
+ NextChar ();
+ CurTok.Tok = TOK_XOR;
+ return;
+
+ case '&':
+ NextChar ();
+ if (C == '&') {
+ NextChar ();
+ CurTok.Tok = TOK_BOOLAND;
+ } else {
+ CurTok.Tok = TOK_AND;
+ }
+ return;
+
+ case '|':
+ NextChar ();
+ if (C == '|') {
+ NextChar ();
+ CurTok.Tok = TOK_BOOLOR;
+ } else {
+ CurTok.Tok = TOK_OR;
+ }
+ return;
+
+ case ':':
+ NextChar ();
+ switch (C) {
+
+ case ':':
+ NextChar ();
+ CurTok.Tok = TOK_NAMESPACE;
+ break;
+
+ case '-':
+ CurTok.IVal = 0;
+ do {
+ --CurTok.IVal;
+ NextChar ();
+ } while (C == '-');
+ CurTok.Tok = TOK_ULABEL;
+ break;
+
+ case '+':
+ CurTok.IVal = 0;
+ do {
+ ++CurTok.IVal;
+ NextChar ();
+ } while (C == '+');
+ CurTok.Tok = TOK_ULABEL;
+ break;
case '=':
NextChar ();
- Tok = TOK_ASSIGN;
+ CurTok.Tok = TOK_ASSIGN;
+ break;
+
+ default:
+ CurTok.Tok = TOK_COLON;
break;
+ }
+ return;
+
+ case ',':
+ NextChar ();
+ CurTok.Tok = TOK_COMMA;
+ return;
+
+ case ';':
+ NextChar ();
+ while (C != '\n' && C != EOF) {
+ NextChar ();
+ }
+ goto CharAgain;
+
+ case '#':
+ NextChar ();
+ CurTok.Tok = TOK_HASH;
+ return;
+
+ case '(':
+ NextChar ();
+ CurTok.Tok = TOK_LPAREN;
+ return;
+
+ case ')':
+ NextChar ();
+ CurTok.Tok = TOK_RPAREN;
+ return;
- default:
- Tok = TOK_COLON;
- break;
- }
- return;
-
- case ',':
- NextChar ();
- Tok = TOK_COMMA;
- return;
-
- case ';':
- NextChar ();
- while (C != '\n' && C != EOF) {
- NextChar ();
- }
- goto CharAgain;
-
- case '#':
- NextChar ();
- Tok = TOK_HASH;
- return;
-
- case '(':
- NextChar ();
- Tok = TOK_LPAREN;
- return;
-
- case ')':
- NextChar ();
- Tok = TOK_RPAREN;
- return;
-
- case '[':
- NextChar ();
- Tok = TOK_LBRACK;
- return;
-
- case ']':
- NextChar ();
- Tok = TOK_RBRACK;
- return;
-
- case '{':
- NextChar ();
- Tok = TOK_LCURLY;
- return;
-
- case '}':
- NextChar ();
- Tok = TOK_RCURLY;
- return;
-
- case '<':
- NextChar ();
- if (C == '=') {
- NextChar ();
- Tok = TOK_LE;
- } else if (C == '<') {
- NextChar ();
- Tok = TOK_SHL;
- } else if (C == '>') {
- NextChar ();
- Tok = TOK_NE;
- } else {
- Tok = TOK_LT;
- }
- return;
-
- case '=':
- NextChar ();
- Tok = TOK_EQ;
- return;
-
- case '!':
- NextChar ();
- Tok = TOK_BOOLNOT;
- return;
-
- case '>':
- NextChar ();
- if (C == '=') {
- NextChar ();
- Tok = TOK_GE;
- } else if (C == '>') {
- NextChar ();
- Tok = TOK_SHR;
- } else {
- Tok = TOK_GT;
- }
- return;
+ case '[':
+ NextChar ();
+ CurTok.Tok = TOK_LBRACK;
+ return;
+
+ case ']':
+ NextChar ();
+ CurTok.Tok = TOK_RBRACK;
+ return;
+
+ case '{':
+ NextChar ();
+ CurTok.Tok = TOK_LCURLY;
+ return;
+
+ case '}':
+ NextChar ();
+ CurTok.Tok = TOK_RCURLY;
+ return;
+
+ case '<':
+ NextChar ();
+ if (C == '=') {
+ NextChar ();
+ CurTok.Tok = TOK_LE;
+ } else if (C == '<') {
+ NextChar ();
+ CurTok.Tok = TOK_SHL;
+ } else if (C == '>') {
+ NextChar ();
+ CurTok.Tok = TOK_NE;
+ } else {
+ CurTok.Tok = TOK_LT;
+ }
+ return;
+
+ case '=':
+ NextChar ();
+ CurTok.Tok = TOK_EQ;
+ return;
+
+ case '!':
+ NextChar ();
+ CurTok.Tok = TOK_BOOLNOT;
+ return;
+
+ case '>':
+ NextChar ();
+ if (C == '=') {
+ NextChar ();
+ CurTok.Tok = TOK_GE;
+ } else if (C == '>') {
+ NextChar ();
+ CurTok.Tok = TOK_SHR;
+ } else {
+ CurTok.Tok = TOK_GT;
+ }
+ return;
case '~':
- NextChar ();
- Tok = TOK_NOT;
- return;
-
- case '\'':
- /* Hack: If we allow ' as terminating character for strings, read
- * the following stuff as a string, and check for a one character
- * string later.
- */
- if (LooseStringTerm) {
- ReadStringConst ('\'');
- if (SB_GetLen (&SVal) == 1) {
- IVal = SB_AtUnchecked (&SVal, 0);
- Tok = TOK_CHARCON;
- } else {
- Tok = TOK_STRCON;
- }
- } else {
- /* Always a character constant */
- NextChar ();
- if (C == EOF || IsControl (C)) {
- Error ("Illegal character constant");
- goto CharAgain;
- }
- IVal = C;
- Tok = TOK_CHARCON;
- NextChar ();
- if (C != '\'') {
+ NextChar ();
+ CurTok.Tok = TOK_NOT;
+ return;
+
+ case '\'':
+ /* Hack: If we allow ' as terminating character for strings, read
+ * the following stuff as a string, and check for a one character
+ * string later.
+ */
+ if (LooseStringTerm) {
+ ReadStringConst ('\'');
+ if (SB_GetLen (&CurTok.SVal) == 1) {
+ CurTok.IVal = SB_AtUnchecked (&CurTok.SVal, 0);
+ CurTok.Tok = TOK_CHARCON;
+ } else {
+ CurTok.Tok = TOK_STRCON;
+ }
+ } else {
+ /* Always a character constant */
+ NextChar ();
+ if (C == EOF || IsControl (C)) {
+ Error ("Illegal character constant");
+ goto CharAgain;
+ }
+ CurTok.IVal = C;
+ CurTok.Tok = TOK_CHARCON;
+ NextChar ();
+ if (C != '\'') {
if (!MissingCharTerm) {
Error ("Illegal character constant");
}
- } else {
- NextChar ();
- }
- }
- return;
-
- case '\"':
- ReadStringConst ('\"');
- Tok = TOK_STRCON;
- return;
-
- case '\\':
- /* Line continuation? */
- if (LineCont) {
- NextChar ();
- if (C == '\n') {
- /* Handle as white space */
- NextChar ();
- C = ' ';
- goto Again;
- }
- }
- break;
+ } else {
+ NextChar ();
+ }
+ }
+ return;
+
+ case '\"':
+ ReadStringConst ('\"');
+ CurTok.Tok = TOK_STRCON;
+ return;
+
+ case '\\':
+ /* Line continuation? */
+ if (LineCont) {
+ NextChar ();
+ if (C == '\n') {
+ /* Handle as white space */
+ NextChar ();
+ C = ' ';
+ goto Again;
+ }
+ }
+ break;
case '\n':
- NextChar ();
- Tok = TOK_SEP;
- return;
+ NextChar ();
+ CurTok.Tok = TOK_SEP;
+ return;
case EOF:
CheckInputStack ();
DoneCharSource ();
goto Again;
} else {
- Tok = TOK_EOF;
+ CurTok.Tok = TOK_EOF;
}
return;
}
unsigned I;
/* Must have an identifier */
- PRECONDITION (Tok == TOK_IDENT);
+ PRECONDITION (CurTok.Tok == TOK_IDENT);
/* If we aren't in ignore case mode, we have to uppercase the identifier */
if (!IgnoreCase) {
- UpcaseSVal ();
+ UpcaseSVal ();
}
/* Do a linear search (a binary search is not worth the effort) */
for (I = 0; I < Count; ++I) {
- if (SB_CompareStr (&SVal, Keys [I]) == 0) {
- /* Found it */
- return I;
- }
+ if (SB_CompareStr (&CurTok.SVal, Keys [I]) == 0) {
+ /* Found it */
+ return I;
+ }
}
/* Not found */
* error message and return ADDR_SIZE_DEFAULT.
*/
{
- static const char* Keys[] = {
- "DIRECT", "ZEROPAGE", "ZP",
- "ABSOLUTE", "ABS", "NEAR",
- "FAR",
- "LONG", "DWORD",
- };
+ unsigned char AddrSize;
/* Check for an identifier */
- if (Tok != TOK_IDENT) {
+ if (CurTok.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;
- case 7:
- case 8: return ADDR_SIZE_LONG;
- default:
- Error ("Address size specifier expected");
- return ADDR_SIZE_DEFAULT;
+ /* Convert the attribute */
+ AddrSize = AddrSizeFromStr (SB_GetConstBuf (&CurTok.SVal));
+ if (AddrSize == ADDR_SIZE_INVALID) {
+ Error ("Address size specifier expected");
+ AddrSize = ADDR_SIZE_DEFAULT;
}
+
+ /* Done */
+ return AddrSize;
}
{
DoneCharSource ();
}
-
-
-