/* */
/* */
/* */
-/* (C) 1998-2007 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2010, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
-enum Token Tok = TOK_NONE; /* Current token */
+Token Tok = TOK_NONE; /* Current token */
int WS; /* Flag: Whitespace before token */
long IVal; /* Integer token attribute */
-char SVal[MAX_STR_LEN+1]; /* String token attribute */
+StrBuf SVal = STATIC_STRBUF_INITIALIZER;/* String token attribute */
FilePos CurPos = { 0, 0, 0 }; /* Name and position in current file */
struct InputFile {
FILE* F; /* Input file descriptor */
FilePos Pos; /* Position in file */
- enum Token Tok; /* Last token */
+ Token Tok; /* Last token */
int C; /* Last character */
char Line[256]; /* The current input line */
InputFile* Next; /* Linked list of input files */
char* Text; /* Pointer to the text data */
const char* Pos; /* Pointer to current position */
int Malloced; /* Memory was malloced */
- enum Token Tok; /* Last token */
+ Token Tok; /* Last token */
int C; /* Last character */
InputData* Next; /* Linked list of input data */
};
/* Input source: Either file or data */
struct CharSource {
CharSource* Next; /* Linked list of char sources */
- enum Token Tok; /* Last token */
+ Token Tok; /* Last token */
int C; /* Last character */
const CharSourceFunctions* Func; /* Pointer to function table */
union {
/* List of dot keywords with the corresponding tokens */
struct DotKeyword {
const char* Key; /* MUST be first field */
- enum Token Tok;
+ Token Tok;
} DotKeywords [] = {
{ ".A16", TOK_A16 },
{ ".A8", TOK_A8 },
{ ".ASSERT", TOK_ASSERT },
{ ".AUTOIMPORT", TOK_AUTOIMPORT },
{ ".BANKBYTE", TOK_BANKBYTE },
+ { ".BANKBYTES", TOK_BANKBYTES },
{ ".BITAND", TOK_AND },
{ ".BITNOT", TOK_NOT },
{ ".BITOR", TOK_OR },
{ ".GLOBAL", TOK_GLOBAL },
{ ".GLOBALZP", TOK_GLOBALZP },
{ ".HIBYTE", TOK_HIBYTE },
+ { ".HIBYTES", TOK_HIBYTES },
{ ".HIWORD", TOK_HIWORD },
{ ".I16", TOK_I16 },
{ ".I8", TOK_I8 },
{ ".LIST", TOK_LIST },
{ ".LISTBYTES", TOK_LISTBYTES },
{ ".LOBYTE", TOK_LOBYTE },
+ { ".LOBYTES", TOK_LOBYTES },
{ ".LOCAL", TOK_LOCAL },
{ ".LOCALCHAR", TOK_LOCALCHAR },
{ ".LOWORD", TOK_LOWORD },
{ ".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 },
-void NewInputFile (const char* Name)
-/* Open a new input file */
+int NewInputFile (const char* Name)
+/* Open a new input file. Returns true if the file could be successfully opened
+ * and false otherwise.
+ */
{
+ int RetCode = 0; /* Return code. Assume an error. */
char* PathName = 0;
/* First try to open the file */
/* We are on include level. Search for the file in the include
* directories.
*/
- PathName = FindInclude (Name);
+ PathName = FindInclude (Name, INC_STD);
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 */
/* check again if we do now have an open file */
if (F != 0) {
+ StrBuf NameBuf;
unsigned FileIdx;
CharSource* S;
}
/* Add the file to the input file table and remember the index */
- FileIdx = AddFile (Name, Buf.st_size, Buf.st_mtime);
+ 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));
UseCharSource (S);
}
+ /* File successfully opened */
+ RetCode = 1;
+
+ExitPoint:
/* Free an allocated name buffer */
xfree (PathName);
+
+ /* Return the success code */
+ return RetCode;
}
void LocaseSVal (void)
/* Make SVal lower case */
{
- unsigned I = 0;
- while (SVal [I]) {
- SVal [I] = tolower (SVal [I]);
- ++I;
- }
+ SB_ToLower (&SVal);
}
void UpcaseSVal (void)
/* Make SVal upper case */
{
- unsigned I = 0;
- while (SVal [I]) {
- SVal [I] = toupper (SVal [I]);
- ++I;
- }
+ SB_ToUpper (&SVal);
}
* return TOK_NONE if not found.
*/
{
- static const struct DotKeyword K = { SVal, 0 };
+ struct DotKeyword K;
struct DotKeyword* R;
+ /* Initialize K */
+ K.Key = SB_GetConstBuf (&SVal);
+ K.Tok = 0;
+
/* If we aren't in ignore case mode, we have to uppercase the keyword */
if (!IgnoreCase) {
UpcaseSVal ();
-static void ReadIdent (unsigned Index)
+static void ReadIdent (void)
/* 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.
+ * starts at the current position with the next character in C. It is assumed
+ * that any characters already filled in are ok, and the character in C is
+ * checked.
*/
{
/* Read the identifier */
do {
- if (Index < MAX_STR_LEN) {
- SVal [Index++] = C;
- }
- NextChar ();
+ SB_AppendChar (&SVal, C);
+ NextChar ();
} while (IsIdChar (C));
- SVal [Index] = '\0';
+ SB_Terminate (&SVal);
/* If we should ignore case, convert the identifier to upper case */
if (IgnoreCase) {
-static unsigned ReadStringConst (int StringTerm)
-/* Read a string constant into SVal. Check for maximum string length and all
- * other stuff. The length of the string is returned.
- */
+static void ReadStringConst (int StringTerm)
+/* Read a string constant into SVal. */
{
- unsigned I;
-
/* Skip the leading string terminator */
NextChar ();
/* Read the string */
- I = 0;
while (1) {
if (C == StringTerm) {
break;
break;
}
- /* Check for string length, print an error message once */
- if (I == MAX_STR_LEN) {
- Error ("Maximum string size exceeded");
- } else if (I < MAX_STR_LEN) {
- SVal [I] = C;
- }
- ++I;
+ /* Append the char to the string */
+ SB_AppendChar (&SVal, C);
/* Skip the character */
NextChar ();
NextChar ();
/* Terminate the string */
- if (I >= MAX_STR_LEN) {
- I = MAX_STR_LEN;
- }
- SVal [I] = '\0';
-
- /* Return the length of the string */
- return I;
+ SB_Terminate (&SVal);
}
-static int Sweet16Reg (const char* Ident)
+static int Sweet16Reg (const StrBuf* Id)
/* Check if the given identifier is a sweet16 register. Return -1 if this is
* not the case, return the register number otherwise.
*/
unsigned RegNum;
char Check;
- if (Ident[0] != 'r' && Ident[0] != 'R') {
+ if (SB_GetLen (Id) < 2) {
return -1;
}
- if (!IsDigit (Ident[1])) {
+ if (toupper (SB_AtUnchecked (Id, 0)) != 'R') {
+ return -1;
+ }
+ if (!IsDigit (SB_AtUnchecked (Id, 1))) {
return -1;
}
- if (sscanf (Ident+1, "%u%c", &RegNum, &Check) != 1 || RegNum > 15) {
+ if (sscanf (SB_GetConstBuf (Id)+1, "%u%c", &RegNum, &Check) != 1 || RegNum > 15) {
/* Invalid register */
return -1;
}
/* Mark the file position of the next token */
Source->Func->MarkStart (Source);
+ /* Clear the string attribute */
+ SB_Clear (&SVal);
+
/* Hex number or PC symbol? */
if (C == '$') {
NextChar ();
}
}
- /* Read the number */
+ /* Read the number */
IVal = 0;
while (IsXDigit (C)) {
if (IVal & 0xF0000000) {
Error ("Binary digit expected");
}
- /* Read the number */
+ /* Read the number */
IVal = 0;
while (IsBDigit (C)) {
if (IVal & 0x80000000) {
/* This is an integer constant */
Tok = TOK_INTCON;
- return;
+ return;
}
/* Control command? */
} else {
/* Read the remainder of the identifier */
- SVal[0] = '.';
- ReadIdent (1);
+ SB_AppendChar (&SVal, '.');
+ ReadIdent ();
/* Dot keyword, search for it */
Tok = FindDotKeyword ();
if (Tok == TOK_NONE) {
- /* Not found */
+ /* Not found */
if (!LeadingDotInIdents) {
/* Invalid pseudo instruction */
- Error ("`%s' is not a recognized control command", SVal);
+ Error ("`%m%p' is not a recognized control command", &SVal);
goto Again;
}
/* An identifier with a dot. Check if it's a define style
* macro.
*/
- if (IsDefine (SVal)) {
+ if (IsDefine (&SVal)) {
/* This is a define style macro - expand it */
MacExpandStart ();
goto Restart;
/* Local symbol? */
if (C == LocalStart) {
- /* Read the identifier */
- ReadIdent (0);
+ /* Read the identifier. */
+ ReadIdent ();
/* Start character alone is not enough */
- if (SVal [1] == '\0') {
+ if (SB_GetLen (&SVal) == 1) {
Error ("Invalid cheap local symbol");
goto Again;
}
if (IsIdStart (C)) {
/* Read the identifier */
- ReadIdent (0);
+ 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 (SVal[1] == '\0') {
- switch (toupper (SVal [0])) {
+ if (SB_GetLen (&SVal) == 1) {
+ switch (toupper (SB_AtUnchecked (&SVal, 0))) {
case 'A':
if (C == ':') {
break;
case 'S':
- Tok = TOK_S;
- return;
+ if (CPU == CPU_65816) {
+ Tok = TOK_S;
+ return;
+ }
+ break;
case 'X':
Tok = TOK_X;
}
break;
- default:
+ default:
break;
}
- } else if (CPU == CPU_SWEET16 && (IVal = Sweet16Reg (SVal)) >= 0) {
+ } else if (CPU == CPU_SWEET16 && (IVal = Sweet16Reg (&SVal)) >= 0) {
/* A sweet16 register number in sweet16 mode */
Tok = TOK_REG;
}
/* Check for define style macro */
- if (IsDefine (SVal)) {
+ if (IsDefine (&SVal)) {
/* Macro - expand it */
MacExpandStart ();
goto Restart;
case '/':
NextChar ();
- Tok = TOK_DIV;
+ if (C != '*') {
+ Tok = TOK_DIV;
+ } else if (CComments) {
+ /* Remember the position, then skip the '*' */
+ FilePos Pos = CurPos;
+ NextChar ();
+ do {
+ while (C != '*') {
+ if (C == EOF) {
+ PError (&Pos, "Unterminated comment");
+ goto CharAgain;
+ }
+ NextChar ();
+ }
+ NextChar ();
+ } while (C != '/');
+ NextChar ();
+ goto Again;
+ }
return;
case '*':
case '^':
NextChar ();
- Tok = TOK_XOR;
+ Tok = TOK_XOR;
return;
case '&':
case ':':
NextChar ();
- switch (C) {
+ switch (C) {
case ':':
NextChar ();
case '#':
NextChar ();
- Tok = TOK_HASH;
+ Tok = TOK_HASH;
return;
case '(':
case '{':
NextChar ();
- Tok = TOK_LCURLY;
+ Tok = TOK_LCURLY;
return;
case '}':
return;
case '=':
- NextChar ();
+ NextChar ();
Tok = TOK_EQ;
return;
case '~':
NextChar ();
Tok = TOK_NOT;
- return;
+ return;
case '\'':
/* Hack: If we allow ' as terminating character for strings, read
* string later.
*/
if (LooseStringTerm) {
- if (ReadStringConst ('\'') == 1) {
- IVal = SVal[0];
+ ReadStringConst ('\'');
+ if (SB_GetLen (&SVal) == 1) {
+ IVal = SB_AtUnchecked (&SVal, 0);
Tok = TOK_CHARCON;
} else {
Tok = TOK_STRCON;
case '\\':
/* Line continuation? */
if (LineCont) {
- NextChar ();
- if (C == '\n') {
+ NextChar ();
+ if (C == '\n') {
/* Handle as white space */
NextChar ();
C = ' ';
goto Again;
}
}
- break;
+ break;
case '\n':
NextChar ();
-int TokHasSVal (enum Token Tok)
-/* Return true if the given token has an attached SVal */
-{
- return (Tok == TOK_IDENT || TOK_LOCAL_IDENT || Tok == TOK_STRCON);
-}
-
-
-
-int TokHasIVal (enum Token Tok)
-/* Return true if the given token has an attached IVal */
-{
- return (Tok == TOK_INTCON || Tok == TOK_CHARCON || Tok == TOK_REG);
-}
-
-
-
int GetSubKey (const char** Keys, unsigned Count)
/* Search for a subkey in a table of keywords. The current token must be an
* identifier and all keys must be in upper case. The identifier will be
/* Do a linear search (a binary search is not worth the effort) */
for (I = 0; I < Count; ++I) {
- if (strcmp (SVal, Keys [I]) == 0) {
+ if (SB_CompareStr (&SVal, Keys [I]) == 0) {
/* Found it */
return I;
}
* 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) {
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 (&SVal));
+ if (AddrSize == ADDR_SIZE_INVALID) {
+ Error ("Address size specifier expected");
+ AddrSize = ADDR_SIZE_DEFAULT;
}
+
+ /* Done */
+ return AddrSize;
}