From 09f288e43d674af61007bc9f496616aba704c652 Mon Sep 17 00:00:00 2001 From: cuz Date: Mon, 8 Apr 2002 18:52:47 +0000 Subject: [PATCH] Working git-svn-id: svn://svn.cc65.org/cc65/trunk@1230 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/sim65/main.c | 56 ++++- src/sim65/make/gcc.mak | 3 +- src/sim65/scanner.c | 516 +++++++++++++++++++++++++++++++++++++++++ src/sim65/scanner.h | 164 +++++++++++++ 4 files changed, 732 insertions(+), 7 deletions(-) create mode 100644 src/sim65/scanner.c create mode 100644 src/sim65/scanner.h diff --git a/src/sim65/main.c b/src/sim65/main.c index ec865bfdb..51c64faae 100644 --- a/src/sim65/main.c +++ b/src/sim65/main.c @@ -50,8 +50,11 @@ #include "chippath.h" #include "cpucore.h" #include "cputype.h" +#include "error.h" #include "global.h" #include "memory.h" +#include "scanner.h" + /*****************************************************************************/ @@ -65,12 +68,16 @@ static void Usage (void) fprintf (stderr, "Usage: %s [options] file\n" "Short options:\n" + " -C name\t\tUse simulator config file\n" + " -L dir\t\tSet a chip directory search path\n" " -V\t\t\tPrint the simulator version number\n" " -d\t\t\tDebug mode\n" " -h\t\t\tHelp (this text)\n" " -v\t\t\tIncrease verbosity\n" - "\n" - "Long options:\n" + "\n" + "Long options:\n" + " --chipdir dir\t\tSet a chip directory search path\n" + " --config name\t\tUse simulator config file\n" " --cpu type\t\tSet cpu type\n" " --debug\t\tDebug mode\n" " --help\t\tHelp (this text)\n" @@ -81,6 +88,14 @@ static void Usage (void) +static void OptChipDir (const char* Opt attribute ((unused)), const char* Arg) +/* Handle the --chipdir option */ +{ + AddChipPath (Arg); +} + + + static void OptCPU (const char* Opt, const char* Arg) /* Handle the --cpu option */ { @@ -95,8 +110,19 @@ static void OptCPU (const char* Opt, const char* Arg) +static void OptConfig (const char* Opt attribute ((unused)), const char* Arg) +/* Define the config file */ +{ + if (CfgAvail ()) { + Error ("Cannot use -C twice"); + } + CfgSetName (Arg); +} + + + static void OptDebug (const char* Opt attribute ((unused)), - const char* Arg attribute ((unused))) + const char* Arg attribute ((unused))) /* Simulator debug mode */ { Debug = 1; @@ -128,7 +154,7 @@ static void OptVersion (const char* Opt attribute ((unused)), /* Print the assembler version */ { fprintf (stderr, - "cc65 V%u.%u.%u\n", + "sim65 V%u.%u.%u\n", VER_MAJOR, VER_MINOR, VER_PATCH); } @@ -138,9 +164,11 @@ int main (int argc, char* argv[]) { /* Program long options */ static const LongOpt OptTab[] = { + { "--chipdir", 1, OptChipDir }, + { "--config", 1, OptConfig }, { "--cpu", 1, OptCPU }, { "--debug", 0, OptDebug }, - { "--help", 0, OptHelp }, + { "--help", 0, OptHelp }, { "--verbose", 0, OptVerbose }, { "--version", 0, OptVersion }, }; @@ -173,7 +201,7 @@ int main (int argc, char* argv[]) OptDebug (Arg, 0); break; - case 'h': + case 'h': case '?': OptHelp (Arg, 0); break; @@ -182,6 +210,14 @@ int main (int argc, char* argv[]) OptVerbose (Arg, 0); break; + case 'C': + OptConfig (Arg, GetArg (&I, 2)); + break; + + case 'L': + OptChipDir (Arg, GetArg (&I, 2)); + break; + case 'V': OptVersion (Arg, 0); break; @@ -202,6 +238,14 @@ int main (int argc, char* argv[]) ++I; } + /* Check if we have a valid configuration */ + if (!CfgAvail ()) { + Error ("Simulator configuration missing"); + } + + /* Read the config file */ +// CfgRead (); + /* Initialize modules */ AddChipPath ("chips"); LoadChipLibrary ("ram.so"); diff --git a/src/sim65/make/gcc.mak b/src/sim65/make/gcc.mak index aab8d3974..c66585190 100644 --- a/src/sim65/make/gcc.mak +++ b/src/sim65/make/gcc.mak @@ -18,7 +18,8 @@ OBJS = chip.o \ error.o \ global.o \ main.o \ - memory.o + memory.o \ + scanner.o LIBS = $(COMMON)/common.a diff --git a/src/sim65/scanner.c b/src/sim65/scanner.c new file mode 100644 index 000000000..ed71c74ed --- /dev/null +++ b/src/sim65/scanner.c @@ -0,0 +1,516 @@ +/*****************************************************************************/ +/* */ +/* scanner.c */ +/* */ +/* Configuration file scanner for the sim65 6502 simulator */ +/* */ +/* */ +/* */ +/* (C) 1998-2002 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#include +#include +#include +#include +#include + +/* common */ +#include "xsprintf.h" + +/* sim65 */ +#include "error.h" +#include "scanner.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Current token and attributes */ +cfgtok_t CfgTok; +char CfgSVal [CFG_MAX_IDENT_LEN+1]; +unsigned long CfgIVal; + +/* Error location */ +unsigned CfgErrorLine; +unsigned CfgErrorCol; + +/* Input sources for the configuration */ +static const char* CfgName = 0; +static const char* CfgBuf = 0; + +/* Other input stuff */ +static int C = ' '; +static unsigned InputLine = 1; +static unsigned InputCol = 0; +static FILE* InputFile = 0; + + + +/*****************************************************************************/ +/* Error handling */ +/*****************************************************************************/ + + + +void CfgWarning (const char* Format, ...) +/* Print a warning message adding file name and line number of the config file */ +{ + char Buf [512]; + va_list ap; + + va_start (ap, Format); + xvsprintf (Buf, sizeof (Buf), Format, ap); + va_end (ap); + + Warning ("%s(%u): %s", CfgGetName(), CfgErrorLine, Buf); +} + + + +void CfgError (const char* Format, ...) +/* Print an error message adding file name and line number of the config file */ +{ + char Buf [512]; + va_list ap; + + va_start (ap, Format); + xvsprintf (Buf, sizeof (Buf), Format, ap); + va_end (ap); + + Error ("%s(%u): %s", CfgGetName(), CfgErrorLine, Buf); +} + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static void NextChar (void) +/* Read the next character from the input file */ +{ + if (CfgBuf) { + /* Read from buffer */ + C = (unsigned char)(*CfgBuf); + if (C == 0) { + C = EOF; + } else { + ++CfgBuf; + } + } else { + /* Read from the file */ + C = getc (InputFile); + } + + /* Count columns */ + if (C != EOF) { + ++InputCol; + } + + /* Count lines */ + if (C == '\n') { + ++InputLine; + InputCol = 0; + } +} + + + +static unsigned DigitVal (int C) +/* Return the value for a numeric digit */ +{ + if (isdigit (C)) { + return C - '0'; + } else { + return toupper (C) - 'A' + 10; + } +} + + + +void CfgNextTok (void) +/* Read the next token from the input stream */ +{ + unsigned I; + + +Again: + /* Skip whitespace */ + while (isspace (C)) { + NextChar (); + } + + /* Remember the current position */ + CfgErrorLine = InputLine; + CfgErrorCol = InputCol; + + /* Identifier? */ + if (C == '_' || isalpha (C)) { + + /* Read the identifier */ + I = 0; + while (C == '_' || isalnum (C)) { + if (I < CFG_MAX_IDENT_LEN) { + CfgSVal [I++] = C; + } + NextChar (); + } + CfgSVal [I] = '\0'; + CfgTok = CFGTOK_IDENT; + return; + } + + /* Hex number? */ + if (C == '$') { + NextChar (); + if (!isxdigit (C)) { + Error ("%s(%u): Hex digit expected", CfgName, InputLine); + } + CfgIVal = 0; + while (isxdigit (C)) { + CfgIVal = CfgIVal * 16 + DigitVal (C); + NextChar (); + } + CfgTok = CFGTOK_INTCON; + return; + } + + /* Decimal number? */ + if (isdigit (C)) { + CfgIVal = 0; + while (isdigit (C)) { + CfgIVal = CfgIVal * 10 + DigitVal (C); + NextChar (); + } + CfgTok = CFGTOK_INTCON; + return; + } + + /* Other characters */ + switch (C) { + + case '{': + NextChar (); + CfgTok = CFGTOK_LCURLY; + break; + + case '}': + NextChar (); + CfgTok = CFGTOK_RCURLY; + break; + + case ';': + NextChar (); + CfgTok = CFGTOK_SEMI; + break; + + case '.': + NextChar (); + CfgTok = CFGTOK_DOT; + break; + + case ',': + NextChar (); + CfgTok = CFGTOK_COMMA; + break; + + case '=': + NextChar (); + CfgTok = CFGTOK_EQ; + break; + + case ':': + NextChar (); + CfgTok = CFGTOK_COLON; + break; + + case '\"': + NextChar (); + I = 0; + while (C != '\"') { + if (C == EOF || C == '\n') { + Error ("%s(%u): Unterminated string", CfgName, InputLine); + } + if (I < CFG_MAX_IDENT_LEN) { + CfgSVal [I++] = C; + } + NextChar (); + } + NextChar (); + CfgSVal [I] = '\0'; + CfgTok = CFGTOK_STRCON; + break; + + case '#': + /* Comment */ + while (C != '\n' && C != EOF) { + NextChar (); + } + if (C != EOF) { + goto Again; + } + CfgTok = CFGTOK_EOF; + break; + + case EOF: + CfgTok = CFGTOK_EOF; + break; + + default: + Error ("%s(%u): Invalid character `%c'", CfgName, InputLine, C); + + } +} + + + +void CfgConsume (cfgtok_t T, const char* Msg) +/* Skip a token, print an error message if not found */ +{ + if (CfgTok != T) { + CfgError (Msg); + } + CfgNextTok (); +} + + + +void CfgConsumeSemi (void) +/* Consume a semicolon */ +{ + CfgConsume (CFGTOK_SEMI, "`;' expected"); +} + + + +void CfgConsumeColon (void) +/* Consume a colon */ +{ + CfgConsume (CFGTOK_COLON, "`:' expected"); +} + + + +void CfgOptionalComma (void) +/* Consume a comma if there is one */ +{ + if (CfgTok == CFGTOK_COMMA) { + CfgNextTok (); + } +} + + + +void CfgOptionalAssign (void) +/* Consume an equal sign if there is one */ +{ + if (CfgTok == CFGTOK_EQ) { + CfgNextTok (); + } +} + + + +void CfgAssureInt (void) +/* Make sure the next token is an integer */ +{ + if (CfgTok != CFGTOK_INTCON) { + CfgError ("Integer constant expected"); + } +} + + + +void CfgAssureStr (void) +/* Make sure the next token is a string constant */ +{ + if (CfgTok != CFGTOK_STRCON) { + CfgError ("String constant expected"); + } +} + + + +void CfgAssureIdent (void) +/* Make sure the next token is an identifier */ +{ + if (CfgTok != CFGTOK_IDENT) { + CfgError ("Identifier expected"); + } +} + + + +void CfgRangeCheck (unsigned long Lo, unsigned long Hi) +/* Check the range of CfgIVal */ +{ + if (CfgIVal < Lo || CfgIVal > Hi) { + CfgError ("Range error"); + } +} + + + +void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name) +/* Map an identifier to one of the special tokens in the table */ +{ + unsigned I; + + /* We need an identifier */ + if (CfgTok == CFGTOK_IDENT) { + + /* Make it upper case */ + I = 0; + while (CfgSVal [I]) { + CfgSVal [I] = toupper (CfgSVal [I]); + ++I; + } + + /* Linear search */ + for (I = 0; I < Size; ++I) { + if (strcmp (CfgSVal, Table [I].Ident) == 0) { + CfgTok = Table [I].Tok; + return; + } + } + + } + + /* Not found or no identifier */ + Error ("%s(%u): %s expected", CfgName, InputLine, Name); +} + + + +void CfgBoolToken (void) +/* Map an identifier or integer to a boolean token */ +{ + static const IdentTok Booleans [] = { + { "YES", CFGTOK_TRUE }, + { "NO", CFGTOK_FALSE }, + { "TRUE", CFGTOK_TRUE }, + { "FALSE", CFGTOK_FALSE }, + }; + + /* If we have an identifier, map it to a boolean token */ + if (CfgTok == CFGTOK_IDENT) { + CfgSpecialToken (Booleans, ENTRY_COUNT (Booleans), "Boolean"); + } else { + /* We expected an integer here */ + if (CfgTok != CFGTOK_INTCON) { + CfgError ("Boolean value expected"); + } + CfgTok = (CfgIVal == 0)? CFGTOK_FALSE : CFGTOK_TRUE; + } +} + + + +void CfgSetName (const char* Name) +/* Set a name for a config file */ +{ + CfgName = Name; +} + + + +const char* CfgGetName (void) +/* Get the name of the config file */ +{ + if (CfgName) { + return CfgName; + } else if (CfgBuf) { + return "[builtin config]"; + } else { + return ""; + } +} + + + +void CfgSetBuf (const char* Buf) +/* Set a memory buffer for the config */ +{ + CfgBuf = Buf; +} + + + +int CfgAvail (void) +/* Return true if we have a configuration available */ +{ + return CfgName != 0 || CfgBuf != 0; +} + + + +void CfgOpenInput (void) +/* Open the input file if we have one */ +{ + /* If we have a config name given, open the file, otherwise we will read + * from a buffer. + */ + if (!CfgBuf) { + + /* Open the file */ + InputFile = fopen (CfgName, "r"); + if (InputFile == 0) { + Error ("Cannot open `%s': %s", CfgName, strerror (errno)); + } + + } + + /* Initialize variables */ + C = ' '; + InputLine = 1; + InputCol = 0; + + /* Start the ball rolling ... */ + CfgNextTok (); +} + + + +void CfgCloseInput (void) +/* Close the input file if we have one */ +{ + /* Close the input file if we had one */ + if (InputFile) { + (void) fclose (InputFile); + InputFile = 0; + } +} + + + diff --git a/src/sim65/scanner.h b/src/sim65/scanner.h new file mode 100644 index 000000000..db8142e4e --- /dev/null +++ b/src/sim65/scanner.h @@ -0,0 +1,164 @@ +/*****************************************************************************/ +/* */ +/* scanner.h */ +/* */ +/* Configuration file scanner for the sim65 6502 simulator */ +/* */ +/* */ +/* */ +/* (C) 1998-2002 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef SCANNER_H +#define SCANNER_H + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Config file tokens */ +typedef enum { + CFGTOK_NONE, + CFGTOK_INTCON, + CFGTOK_STRCON, + CFGTOK_IDENT, + CFGTOK_LCURLY, + CFGTOK_RCURLY, + CFGTOK_SEMI, + CFGTOK_COMMA, + CFGTOK_EQ, + CFGTOK_COLON, + CFGTOK_DOT, + CFGTOK_EOF, + + /* Special identifiers */ + CFGTOK_TRUE, + CFGTOK_FALSE + +} cfgtok_t; + + + +/* Mapping table entry, special identifier --> token */ +typedef struct IdentTok IdentTok; +struct IdentTok { + const char* Ident; /* Identifier */ + cfgtok_t Tok; /* Token for identifier */ +}; +#define ENTRY_COUNT(s) (sizeof (s) / sizeof (s [0])) + + + +/* Current token and attributes */ +#define CFG_MAX_IDENT_LEN 255 +extern cfgtok_t CfgTok; +extern char CfgSVal [CFG_MAX_IDENT_LEN+1]; +extern unsigned long CfgIVal; + +/* Error location */ +extern unsigned CfgErrorLine; +extern unsigned CfgErrorCol; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void CfgWarning (const char* Format, ...) attribute((format(printf,1,2))); +/* Print a warning message adding file name and line number of the config file */ + +void CfgError (const char* Format, ...) attribute((format(printf,1,2))); +/* Print an error message adding file name and line number of the config file */ + +void CfgNextTok (void); +/* Read the next token from the input stream */ + +void CfgConsume (cfgtok_t T, const char* Msg); +/* Skip a token, print an error message if not found */ + +void CfgConsumeSemi (void); +/* Consume a semicolon */ + +void CfgConsumeColon (void); +/* Consume a colon */ + +void CfgOptionalComma (void); +/* Consume a comma if there is one */ + +void CfgOptionalAssign (void); +/* Consume an equal sign if there is one */ + +void CfgAssureInt (void); +/* Make sure the next token is an integer */ + +void CfgAssureStr (void); +/* Make sure the next token is a string constant */ + +void CfgAssureIdent (void); +/* Make sure the next token is an identifier */ + +void CfgRangeCheck (unsigned long Lo, unsigned long Hi); +/* Check the range of CfgIVal */ + +void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name); +/* Map an identifier to one of the special tokens in the table */ + +void CfgBoolToken (void); +/* Map an identifier or integer to a boolean token */ + +void CfgSetName (const char* Name); +/* Set a name for a config file */ + +const char* CfgGetName (void); +/* Get the name of the config file */ + +void CfgSetBuf (const char* Buf); +/* Set a memory buffer for the config */ + +int CfgAvail (void); +/* Return true if we have a configuration available */ + +void CfgOpenInput (void); +/* Open the input file if we have one */ + +void CfgCloseInput (void); +/* Close the input file if we have one */ + + + +/* End of scanner.h */ +#endif + + + -- 2.39.5