diff --git a/src/da65/asminc.c b/src/da65/asminc.c new file mode 100644 index 000000000..b326edbce --- /dev/null +++ b/src/da65/asminc.c @@ -0,0 +1,225 @@ +/*****************************************************************************/ +/* */ +/* asminc.c */ +/* */ +/* Read an assembler include file containing symbols */ +/* */ +/* */ +/* */ +/* (C) 2005 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* 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 + +/* common */ +#include "chartype.h" +#include "strbuf.h" + +/* da65 */ +#include "asminc.h" +#include "attrtab.h" +#include "error.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static char* SkipWhitespace (char* L) +/* Ignore white space in L */ +{ + while (IsBlank (*L)) { + ++L; + } + return L; +} + + + +unsigned DigitVal (unsigned char C) +/* Return the value of the given digit */ +{ + if (IsDigit (C)) { + return C - '0'; + } else { + return tolower (C) - 'a' + 10; + } +} + + + +void AsmInc (const char* Filename, char CommentStart, int IgnoreUnknown) +/* Read an assembler include file */ +{ + char Buf[1024]; + char* L; + unsigned Line; + unsigned Len; + long Val; + unsigned DVal; + int Sign; + unsigned Base; + unsigned Digits; + StrBuf Ident = STATIC_STRBUF_INITIALIZER; + + /* Try to open the file for reading */ + FILE* F = fopen (Filename, "r"); + if (F == 0) { + Error ("Cannot open asm include file \"%s\": %s", + Filename, strerror (errno)); + } + + /* Read line by line, check for NAME = VALUE lines */ + Line = 0; + while ((L = fgets (Buf, sizeof (Buf), F)) != 0) { + + /* One more line read */ + ++Line; + + /* Ignore leading white space */ + while (IsBlank (*L)) { + ++L; + } + + /* Remove trailing whitespace */ + Len = strlen (L); + while (Len > 0 && IsSpace (L[Len-1])) { + --Len; + } + L[Len] = '\0'; + + /* If the line is empty or starts with a comment char, ignore it */ + if (*L == '\0' || *L == CommentStart) { + continue; + } + + /* Read an identifier */ + SB_Clear (&Ident); + if (IsAlpha (*L) || *L == '_') { + SB_AppendChar (&Ident, *L++); + while (IsAlNum (*L) || *L == '_') { + SB_AppendChar (&Ident, *L++); + } + SB_Terminate (&Ident); + } else { + if (!IgnoreUnknown) { + Error ("%s(%u): Syntax error", Filename, Line); + } + continue; + } + + /* Ignore white space */ + L = SkipWhitespace (L); + + /* Check for := or = */ + if (*L == '=') { + ++L; + } else if (*L == ':' && *++L == '=') { + ++L; + } else { + if (!IgnoreUnknown) { + Error ("%s(%u): Missing `='", Filename, Line); + } + continue; + } + + /* Allow white space once again */ + L = SkipWhitespace (L); + + /* A number follows. Read the sign. */ + if (*L == '-') { + Sign = -1; + ++L; + } else { + Sign = 1; + if (*L == '+') { + ++L; + } + } + + /* Determine the base of the number. Allow $ and % as prefixes for + * hex and binary numbers respectively. + */ + if (*L == '$') { + Base = 16; + ++L; + } else if (*L == '%') { + Base = 2; + ++L; + } else { + Base = 10; + } + + /* Decode the number */ + Digits = 0; + Val = 0; + while (IsXDigit (*L) && (DVal = DigitVal (*L)) < Base) { + Val = (Val * Base) + DVal; + ++Digits; + ++L; + } + + /* Must have at least one digit */ + if (Digits == 0) { + if (!IgnoreUnknown) { + Error ("%s(%u): Error in number format", Filename, Line); + } + continue; + } + + /* Skip whitespace again */ + L = SkipWhitespace (L); + + /* Check for a comment character or end of line */ + if (*L != CommentStart && *L != '\0') { + if (!IgnoreUnknown) { + Error ("%s(%u): Trailing garbage", Filename, Line); + } + continue; + } + + /* Apply the sign */ + Val *= Sign; + + /* Define the symbol */ + AddExtLabelRange (Val, SB_GetConstBuf (&Ident), 1); + + } + + /* Delete the string buffer contents */ + DoneStrBuf (&Ident); + + /* Close the include file ignoring errors (we were just reading). */ + (void) fclose (F); +} + + + diff --git a/src/da65/asminc.h b/src/da65/asminc.h new file mode 100644 index 000000000..7b5c553e8 --- /dev/null +++ b/src/da65/asminc.h @@ -0,0 +1,56 @@ +/*****************************************************************************/ +/* */ +/* asminc.h */ +/* */ +/* Read an assembler include file containing symbols */ +/* */ +/* */ +/* */ +/* (C) 2005 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* 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 ASMINC_H +#define ASMINC_H + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void AsmInc (const char* Filename, char CommentStart, int IgnoreUnknown); +/* Read an assembler include file */ + + + +/* End of asminc.h */ +#endif + + + diff --git a/src/da65/infofile.c b/src/da65/infofile.c index 493054f45..cf20411fd 100644 --- a/src/da65/infofile.c +++ b/src/da65/infofile.c @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2000-2004 Ullrich von Bassewitz */ +/* (C) 2000-2005 Ullrich von Bassewitz */ /* Römerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -48,6 +48,7 @@ #include "xmalloc.h" /* da65 */ +#include "asminc.h" #include "attrtab.h" #include "error.h" #include "global.h" @@ -425,10 +426,10 @@ static void LabelSection (void) Size = 1; } if (Value + Size > 0x10000) { - InfoError ("Invalid size (address out of range)"); + InfoError ("Invalid size (address out of range)"); } if (HaveLabel ((unsigned) Value)) { - InfoError ("Label for address $%04lX already defined", Value); + InfoError ("Label for address $%04lX already defined", Value); } /* Define the label(s) */ @@ -443,13 +444,104 @@ static void LabelSection (void) +static void AsmIncSection (void) +/* Parse a asminc section */ +{ + static const IdentTok LabelDefs[] = { + { "COMMENTSTART", INFOTOK_COMMENTSTART }, + { "FILE", INFOTOK_FILE }, + { "IGNOREUNKNOWN", INFOTOK_IGNOREUNKNOWN }, + }; + + /* Locals - initialize to avoid gcc warnings */ + char* Name = 0; + int CommentStart = EOF; + int IgnoreUnknown = -1; + + /* Skip the token */ + InfoNextTok (); + + /* Expect the opening curly brace */ + InfoConsumeLCurly (); + + /* Look for section tokens */ + while (InfoTok != INFOTOK_RCURLY) { + + /* Convert to special token */ + InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive"); + + /* Look at the token */ + switch (InfoTok) { + + case INFOTOK_COMMENTSTART: + InfoNextTok (); + if (CommentStart != EOF) { + InfoError ("Commentstart already given"); + } + InfoAssureChar (); + CommentStart = (char) InfoIVal; + InfoNextTok (); + break; + + case INFOTOK_FILE: + InfoNextTok (); + if (Name) { + InfoError ("File name already given"); + } + InfoAssureStr (); + if (InfoSVal[0] == '\0') { + InfoError ("File name may not be empty"); + } + Name = xstrdup (InfoSVal); + InfoNextTok (); + break; + + case INFOTOK_IGNOREUNKNOWN: + InfoNextTok (); + if (IgnoreUnknown != -1) { + InfoError ("Ignoreunknown already specified"); + } + InfoBoolToken (); + IgnoreUnknown = (InfoTok != INFOTOK_FALSE); + InfoNextTok (); + break; + } + + /* Directive is followed by a semicolon */ + InfoConsumeSemi (); + } + + /* Check for the necessary data and assume defaults */ + if (Name == 0) { + InfoError ("File name is missing"); + } + if (CommentStart == EOF) { + CommentStart = ';'; + } + if (IgnoreUnknown == -1) { + IgnoreUnknown = 0; + } + + /* Open the file and read the symbol definitions */ + AsmInc (Name, CommentStart, IgnoreUnknown); + + /* Delete the dynamically allocated memory for Name */ + xfree (Name); + + /* Consume the closing brace */ + InfoConsumeRCurly (); +} + + + static void InfoParse (void) /* Parse the config file */ { static const IdentTok Globals[] = { - { "GLOBAL", INFOTOK_GLOBAL }, - { "RANGE", INFOTOK_RANGE }, - { "LABEL", INFOTOK_LABEL }, + { "GLOBAL", INFOTOK_GLOBAL }, + { "RANGE", INFOTOK_RANGE }, + { "LABEL", INFOTOK_LABEL }, + { "ASMINC", INFOTOK_ASMINC }, }; while (InfoTok != INFOTOK_EOF) { @@ -472,6 +564,9 @@ static void InfoParse (void) LabelSection (); break; + case INFOTOK_ASMINC: + AsmIncSection (); + break; } /* Semicolon expected */ diff --git a/src/da65/make/gcc.mak b/src/da65/make/gcc.mak index 49d4991f4..d4ac9d77b 100644 --- a/src/da65/make/gcc.mak +++ b/src/da65/make/gcc.mak @@ -10,7 +10,8 @@ CC=gcc EBIND=emxbind LDFLAGS= -OBJS = attrtab.o \ +OBJS = asminc.o \ + attrtab.o \ code.o \ data.o \ error.o \ diff --git a/src/da65/make/watcom.mak b/src/da65/make/watcom.mak index b288cb8ca..5d500f746 100644 --- a/src/da65/make/watcom.mak +++ b/src/da65/make/watcom.mak @@ -59,7 +59,8 @@ endif # ------------------------------------------------------------------------------ # All OBJ files -OBJS = attrtab.obj \ +OBJS = asminc.obj \ + attrtab.obj \ code.obj \ data.obj \ error.obj \ diff --git a/src/da65/scanner.c b/src/da65/scanner.c index 6d1315faf..9b58981df 100644 --- a/src/da65/scanner.c +++ b/src/da65/scanner.c @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2000-2003 Ullrich von Bassewitz */ +/* (C) 2000-2005 Ullrich von Bassewitz */ /* Römerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -262,6 +262,20 @@ Again: InfoTok = INFOTOK_STRCON; break; + case '\'': + NextChar (); + if (C == EOF || IsControl (C)) { + InfoError ("Invalid character constant"); + } + InfoIVal = C; + NextChar (); + if (C != '\'') { + InfoError ("Unterminated character constant"); + } + NextChar (); + InfoTok = INFOTOK_CHARCON; + break; + case '#': /* Comment */ while (C != '\n' && C != EOF) { @@ -368,6 +382,16 @@ void InfoAssureStr (void) +void InfoAssureChar (void) +/* Make sure the next token is a char constant */ +{ + if (InfoTok != INFOTOK_STRCON) { + InfoError ("Character constant expected"); + } +} + + + void InfoAssureIdent (void) /* Make sure the next token is an identifier */ { @@ -427,6 +451,8 @@ void InfoBoolToken (void) { "NO", INFOTOK_FALSE }, { "TRUE", INFOTOK_TRUE }, { "FALSE", INFOTOK_FALSE }, + { "ON", INFOTOK_TRUE }, + { "OFF", INFOTOK_FALSE }, }; /* If we have an identifier, map it to a boolean token */ diff --git a/src/da65/scanner.h b/src/da65/scanner.h index 4a14d0d5d..5e3f6efab 100644 --- a/src/da65/scanner.h +++ b/src/da65/scanner.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2000-2003 Ullrich von Bassewitz */ +/* (C) 2000-2005 Ullrich von Bassewitz */ /* Römerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -49,6 +49,7 @@ typedef enum token_t { INFOTOK_NONE, INFOTOK_INTCON, INFOTOK_STRCON, + INFOTOK_CHARCON, INFOTOK_IDENT, INFOTOK_LCURLY, INFOTOK_RCURLY, @@ -63,6 +64,7 @@ typedef enum token_t { INFOTOK_GLOBAL, INFOTOK_RANGE, INFOTOK_LABEL, + INFOTOK_ASMINC, /* Global section */ INFOTOK_COMMENTS, @@ -95,6 +97,11 @@ typedef enum token_t { INFOTOK_ADDR, INFOTOK_SIZE, + /* ASMINC section */ + INFOTOK_FILE, + INFOTOK_COMMENTSTART, + INFOTOK_IGNOREUNKNOWN, + /* */ INFOTOK_TRUE, INFOTOK_FALSE @@ -104,8 +111,8 @@ typedef enum token_t { /* Mapping table entry, special identifier --> token */ typedef struct IdentTok IdentTok; struct IdentTok { - const char* Ident; /* Identifier */ - token_t Tok; /* Token for identifier */ + const char* Ident; /* Identifier */ + token_t Tok; /* Token for identifier */ }; #define ENTRY_COUNT(s) (sizeof (s) / sizeof (s [0])) @@ -113,8 +120,8 @@ struct IdentTok { /* Current token and attributes */ #define CFG_MAX_IDENT_LEN 255 -extern unsigned InfoTok; -extern char InfoSVal [CFG_MAX_IDENT_LEN+1]; +extern unsigned InfoTok; +extern char InfoSVal[CFG_MAX_IDENT_LEN+1]; extern long InfoIVal; /* Error location */ @@ -165,6 +172,9 @@ void InfoAssureInt (void); void InfoAssureStr (void); /* Make sure the next token is a string constant */ +void InfoAssureChar (void); +/* Make sure the next token is a char constant */ + void InfoAssureIdent (void); /* Make sure the next token is an identifier */