1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-08 15:29:37 +00:00

Added a more generic way to push sources that deliver a token stream

independent of the actual input from the file. Change macro handling
to use the new input stack.
Fixed an error in FreeIf: If an unexpected .ENDIF was reached, the
assembler started an endless loop printing error messages.


git-svn-id: svn://svn.cc65.org/cc65/trunk@24 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2000-06-03 11:15:11 +00:00
parent 5e561a0f40
commit 522c7e8c46
21 changed files with 880 additions and 300 deletions

View File

@ -35,7 +35,7 @@
#include "error.h" #include "error.h"
#include "expr.h" #include "expr.h"
#include "scanner.h" #include "nexttok.h"
#include "symtab.h" #include "symtab.h"
#include "condasm.h" #include "condasm.h"
@ -124,6 +124,7 @@ static void FreeIf (void)
IfDesc* D = GetCurrentIf(); IfDesc* D = GetCurrentIf();
if (D == 0) { if (D == 0) {
Error (ERR_UNEXPECTED, ".ENDIF"); Error (ERR_UNEXPECTED, ".ENDIF");
Done = 1;
} else { } else {
Done = (D->Flags & ifNeedTerm) != 0; Done = (D->Flags & ifNeedTerm) != 0;
--IfCount; --IfCount;
@ -402,7 +403,7 @@ void CheckOpenIfs (void)
/* There are no open .IFs */ /* There are no open .IFs */
break; break;
} }
if (D->Pos.Name != CurPos.Name) { if (D->Pos.Name != CurPos.Name) {
/* The .if is from another file, bail out */ /* The .if is from another file, bail out */
break; break;
@ -416,3 +417,21 @@ void CheckOpenIfs (void)
unsigned GetIfStack (void)
/* Get the current .IF stack pointer */
{
return IfCount;
}
void CleanupIfStack (unsigned SP)
/* Cleanup the .IF stack, remove anything above the given stack pointer */
{
while (IfCount > SP) {
FreeIf ();
}
}

View File

@ -52,6 +52,12 @@ void CheckOpenIfs (void);
* open .ifs in this file. * open .ifs in this file.
*/ */
unsigned GetIfStack (void);
/* Get the current .IF stack pointer */
void CleanupIfStack (unsigned SP);
/* Cleanup the .IF stack, remove anything above the given stack pointer */
/* End of condasm.h */ /* End of condasm.h */

View File

@ -36,7 +36,7 @@
#include "error.h" #include "error.h"
#include "expr.h" #include "expr.h"
#include "instr.h" #include "instr.h"
#include "scanner.h" #include "nexttok.h"
#include "ea.h" #include "ea.h"

View File

@ -37,7 +37,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include "scanner.h" #include "nexttok.h"
#include "error.h" #include "error.h"
@ -190,6 +190,7 @@ void ErrorMsg (const FilePos* Pos, unsigned ErrNum, va_list ap)
"CPU not supported", "CPU not supported",
"Counter underflow", "Counter underflow",
"Undefined label", "Undefined label",
"Open `%s´",
}; };
fprintf (stderr, "%s(%lu): Error #%u: ", fprintf (stderr, "%s(%lu): Error #%u: ",
@ -257,7 +258,7 @@ void Fatal (unsigned FatNum, ...)
"Cannot open listing file: %s", "Cannot open listing file: %s",
"Cannot write to listing file: %s", "Cannot write to listing file: %s",
"Cannot read from listing file: %s", "Cannot read from listing file: %s",
"Macro nesting too deep", "Too many nested constructs",
"Too many symbols", "Too many symbols",
}; };
va_list ap; va_list ap;

View File

@ -123,6 +123,7 @@ enum Errors {
ERR_CPU_NOT_SUPPORTED, ERR_CPU_NOT_SUPPORTED,
ERR_COUNTER_UNDERFLOW, ERR_COUNTER_UNDERFLOW,
ERR_UNDEFINED_LABEL, ERR_UNDEFINED_LABEL,
ERR_OPEN_STMT,
ERR_COUNT /* Error count */ ERR_COUNT /* Error count */
}; };
@ -140,7 +141,7 @@ enum Fatals {
FAT_CANNOT_OPEN_LISTING, FAT_CANNOT_OPEN_LISTING,
FAT_CANNOT_WRITE_LISTING, FAT_CANNOT_WRITE_LISTING,
FAT_CANNOT_READ_LISTING, FAT_CANNOT_READ_LISTING,
FAT_MACRO_NESTING, FAT_NESTING,
FAT_TOO_MANY_SYMBOLS, FAT_TOO_MANY_SYMBOLS,
FAT_COUNT /* Fatal error count */ FAT_COUNT /* Fatal error count */
}; };

View File

@ -39,11 +39,11 @@
#include "global.h" #include "global.h"
#include "instr.h" #include "instr.h"
#include "mem.h" #include "mem.h"
#include "nexttok.h"
#include "objcode.h" #include "objcode.h"
#include "objfile.h" #include "objfile.h"
#include "scanner.h"
#include "symtab.h" #include "symtab.h"
#include "toknode.h" #include "toklist.h"
#include "ulabel.h" #include "ulabel.h"
#include "expr.h" #include "expr.h"

View File

@ -43,8 +43,8 @@
#include "error.h" #include "error.h"
#include "expr.h" #include "expr.h"
#include "global.h" #include "global.h"
#include "nexttok.h"
#include "objcode.h" #include "objcode.h"
#include "scanner.h"
#include "instr.h" #include "instr.h"

149
src/ca65/istack.c Normal file
View File

@ -0,0 +1,149 @@
/*****************************************************************************/
/* */
/* istack.c */
/* */
/* Input stack for the scanner */
/* */
/* */
/* */
/* (C) 2000 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 "error.h"
#include "mem.h"
#include "istack.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Size of the stack (== maximum nested macro or repeat count) */
#define ISTACK_MAX 256
/* Structure holding a stack element */
typedef struct IElement IElement;
struct IElement {
IElement* Next; /* Next stack element */
int (*Func)(void*); /* Function called for input */
void* Data; /* User data given as argument */
const char* Desc; /* Description */
};
/* The stack */
static IElement* IStack = 0; /* Input stack pointer */
static unsigned ICount = 0; /* Number of items on the stack */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void PushInput (int (*Func) (void*), void* Data, const char* Desc)
/* Push an input function onto the input stack */
{
IElement* E;
/* Check for a stack overflow */
if (ICount > ISTACK_MAX) {
Fatal (FAT_NESTING);
}
/* Create a new stack element */
E = Xmalloc (sizeof (*E));
/* Initialize it */
E->Func = Func;
E->Data = Data;
E->Desc = Desc;
/* Push it */
E->Next = IStack;
IStack = E;
}
void PopInput (void)
/* Pop the current input function from the input stack */
{
IElement* E;
/* We cannot pop from an empty stack */
PRECONDITION (IStack != 0);
/* Remember the last element */
E = IStack;
/* Pop it */
IStack = IStack->Next;
/* And delete it */
Xfree (E);
}
int InputFromStack (void)
/* Try to get input from the input stack. Return true if we had such input,
* return false otherwise.
*/
{
/* Repeatedly call the TOS routine until we have a token or if run out of
* routines.
*/
while (IStack) {
if (IStack->Func (IStack->Data) != 0) {
/* We have a token */
return 1;
}
}
/* Nothing is on the stack */
return 0;
}
void CheckInputStack (void)
/* Called from the scanner before closing an input file. Will check for any
* stuff on the input stack.
*/
{
if (IStack) {
Error (ERR_OPEN_STMT, IStack->Desc);
}
}

71
src/ca65/istack.h Normal file
View File

@ -0,0 +1,71 @@
/*****************************************************************************/
/* */
/* istack.h */
/* */
/* Input stack for the scanner */
/* */
/* */
/* */
/* (C) 2000 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 ISTACK_H
#define ISTACK_H
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void PushInput (int (*Func) (void*), void* Data, const char* Desc);
/* Push an input function onto the input stack */
void PopInput (void);
/* Pop the current input function from the input stack */
int InputFromStack (void);
/* Try to get input from the input stack. Return true if we had such input,
* return false otherwise.
*/
void CheckInputStack (void);
/* Called from the scanner before closing an input file. Will check for any
* stuff on the input stack.
*/
/* End of istack.h */
#endif

View File

@ -38,11 +38,13 @@
#include "../common/hashstr.h" #include "../common/hashstr.h"
#include "mem.h" #include "condasm.h"
#include "error.h" #include "error.h"
#include "scanner.h" #include "istack.h"
#include "toknode.h" #include "mem.h"
#include "nexttok.h"
#include "pseudo.h" #include "pseudo.h"
#include "toklist.h"
#include "macro.h" #include "macro.h"
@ -90,6 +92,7 @@ typedef struct MacExp_ MacExp;
struct MacExp_ { struct MacExp_ {
MacExp* Next; /* Pointer to next expansion */ MacExp* Next; /* Pointer to next expansion */
Macro* M; /* Which macro do we expand? */ Macro* M; /* Which macro do we expand? */
unsigned IfSP; /* .IF stack pointer at start of expansion */
TokNode* Exp; /* Pointer to current token */ TokNode* Exp; /* Pointer to current token */
TokNode* Final; /* Pointer to final token */ TokNode* Final; /* Pointer to final token */
unsigned LocalStart; /* Start of counter for local symbol names */ unsigned LocalStart; /* Start of counter for local symbol names */
@ -98,11 +101,14 @@ struct MacExp_ {
TokNode* ParamExp; /* Node for expanding parameters */ TokNode* ParamExp; /* Node for expanding parameters */
}; };
/* Data for macro expansions */ /* Number of active macro expansions */
#define MAX_MACRO_EXPANSIONS 255 static unsigned MacExpansions = 0;
static unsigned MacroNesting = 0;
static MacExp* CurMac = 0; /* Flag if a macro expansion should get aborted */
static unsigned LocalName = 0; static int DoMacAbort = 0;
/* Counter to create local names for symbols */
static unsigned LocalName = 0;
@ -172,6 +178,7 @@ static MacExp* NewMacExp (Macro* M)
/* Initialize the data */ /* Initialize the data */
E->M = M; E->M = M;
E->IfSP = GetIfStack ();
E->Exp = M->TokRoot; E->Exp = M->TokRoot;
E->Final = 0; E->Final = 0;
E->LocalStart = LocalName; E->LocalStart = LocalName;
@ -183,44 +190,34 @@ static MacExp* NewMacExp (Macro* M)
E->Params [I] = 0; E->Params [I] = 0;
} }
/* And return it... */ /* One macro expansion more */
++MacExpansions;
/* Return the new macro expansion */
return E; return E;
} }
static void MacInsertExp (MacExp* E) static void FreeMacExp (MacExp* E)
/* Insert a macro expansion into the list */
{
E->Next = CurMac;
CurMac = E;
++MacroNesting;
}
static void FreeMacExp (void)
/* Remove and free the current macro expansion */ /* Remove and free the current macro expansion */
{ {
unsigned I; unsigned I;
MacExp* E;
/* One macro expansion less */
--MacExpansions;
/* Free the parameter list */ /* Free the parameter list */
for (I = 0; I < CurMac->ParamCount; ++I) { for (I = 0; I < E->ParamCount; ++I) {
Xfree (CurMac->Params [I]); Xfree (E->Params [I]);
} }
Xfree (CurMac->Params); Xfree (E->Params);
/* Free the final token if we have one */ /* Free the final token if we have one */
if (CurMac->Final) { if (E->Final) {
FreeTokNode (CurMac->Final); FreeTokNode (E->Final);
} }
/* Reset the list pointer */
E = CurMac;
CurMac = E->Next;
--MacroNesting;
/* Free the structure itself */ /* Free the structure itself */
Xfree (E); Xfree (E);
} }
@ -390,7 +387,7 @@ void MacDef (unsigned Style)
IdDesc* I; IdDesc* I;
/* Skip .local or comma */ /* Skip .local or comma */
NextTok (); NextTok ();
/* Need an identifer */ /* Need an identifer */
@ -461,6 +458,123 @@ void MacDef (unsigned Style)
static int MacExpand (void* Data)
/* If we're currently expanding a macro, set the the scanner token and
* attribute to the next value and return true. If we are not expanding
* a macro, return false.
*/
{
/* Cast the Data pointer to the actual data structure */
MacExp* Mac = (MacExp*) Data;
/* Check if we should abort this macro */
if (DoMacAbort) {
/* Reset the flag */
DoMacAbort = 0;
/* Abort any open .IF statements in this macro expansion */
CleanupIfStack (Mac->IfSP);
/* Terminate macro expansion */
goto MacEnd;
}
/* We're expanding a macro. Check if we are expanding one of the
* macro parameters.
*/
if (Mac->ParamExp) {
/* Ok, use token from parameter list */
TokSet (Mac->ParamExp);
/* Set pointer to next token */
Mac->ParamExp = Mac->ParamExp->Next;
/* Done */
return 1;
}
/* We're not expanding macro parameters. Check if we have tokens left from
* the macro itself.
*/
if (Mac->Exp) {
/* Use next macro token */
TokSet (Mac->Exp);
/* Set pointer to next token */
Mac->Exp = Mac->Exp->Next;
/* Is it a request for actual parameter count? */
if (Tok == TOK_PARAMCOUNT) {
Tok = TOK_INTCON;
IVal = Mac->ParamCount;
return 1;
}
/* Is it the name of a macro parameter? */
if (Tok == TOK_MACPARAM) {
/* Start to expand the parameter token list */
Mac->ParamExp = Mac->Params [IVal];
/* Recursive call to expand the parameter */
return MacExpand (Mac);
}
/* If it's an identifier, it may in fact be a local symbol */
if (Tok == TOK_IDENT && Mac->M->LocalCount) {
/* Search for the local symbol in the list */
unsigned Index = 0;
IdDesc* I = Mac->M->Locals;
while (I) {
if (strcmp (SVal, I->Id) == 0) {
/* This is in fact a local symbol, change the name */
sprintf (SVal, "___%04X__", Mac->LocalStart + Index);
break;
}
/* Next symbol */
++Index;
I = I->Next;
}
/* Done */
return 1;
}
/* The token was successfully set */
return 1;
}
/* No more macro tokens. Do we have a final token? */
if (Mac->Final) {
/* Set the final token and remove it */
TokSet (Mac->Final);
FreeTokNode (Mac->Final);
Mac->Final = 0;
/* The token was successfully set */
return 1;
}
MacEnd:
/* End of macro expansion */
FreeMacExp (Mac);
/* Pop the input function */
PopInput ();
/* No token available */
return 0;
}
static void StartExpClassic (Macro* M) static void StartExpClassic (Macro* M)
/* Start expanding the classic macro M */ /* Start expanding the classic macro M */
{ {
@ -522,8 +636,8 @@ static void StartExpClassic (Macro* M)
} }
} }
/* Insert the newly created structure into the expansion list */ /* Insert a new token input function */
MacInsertExp (E); PushInput (MacExpand, E, ".MACRO");
} }
@ -596,8 +710,8 @@ static void StartExpDefine (Macro* M)
*/ */
E->Final = NewTokNode (); E->Final = NewTokNode ();
/* Insert the newly created structure into the expansion list */ /* Insert a new token input function */
MacInsertExp (E); PushInput (MacExpand, E, ".DEFINE");
} }
@ -605,123 +719,15 @@ static void StartExpDefine (Macro* M)
void MacExpandStart (void) void MacExpandStart (void)
/* Start expanding the macro in SVal */ /* Start expanding the macro in SVal */
{ {
Macro* M;
/* Beware of runoff macros */
if (MacroNesting == MAX_MACRO_EXPANSIONS) {
Fatal (FAT_MACRO_NESTING);
}
/* Search for the macro */ /* Search for the macro */
M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE); Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
CHECK (M != 0); CHECK (M != 0);
/* Call the apropriate subroutine */ /* Call the apropriate subroutine */
switch (M->Style) { switch (M->Style) {
case MAC_STYLE_CLASSIC: StartExpClassic (M); break; case MAC_STYLE_CLASSIC: StartExpClassic (M); break;
case MAC_STYLE_DEFINE: StartExpDefine (M); break; case MAC_STYLE_DEFINE: StartExpDefine (M); break;
default: Internal ("Invalid macro style: %d", M->Style); default: Internal ("Invalid macro style: %d", M->Style);
}
}
int MacExpand (void)
/* If we're currently expanding a macro, set the the scanner token and
* attribute to the next value and return true. If we are not expanding
* a macro, return false.
*/
{
if (MacroNesting == 0) {
/* Not expanding a macro */
return 0;
}
/* We're expanding a macro. Check if we are expanding one of the
* macro parameters.
*/
if (CurMac->ParamExp) {
/* Ok, use token from parameter list */
TokSet (CurMac->ParamExp);
/* Set pointer to next token */
CurMac->ParamExp = CurMac->ParamExp->Next;
/* Done */
return 1;
} else if (CurMac->Exp) {
/* We're not expanding a parameter, use next macro token */
TokSet (CurMac->Exp);
/* Set pointer to next token */
CurMac->Exp = CurMac->Exp->Next;
/* Is it a request for actual parameter count? */
if (Tok == TOK_PARAMCOUNT) {
Tok = TOK_INTCON;
IVal = CurMac->ParamCount;
return 1;
}
/* Is it an .exitmacro command? */
if (Tok == TOK_EXITMACRO) {
/* Forced exit from macro expansion */
FreeMacExp ();
return MacExpand ();
}
/* Is it the name of a macro parameter? */
if (Tok == TOK_MACPARAM) {
/* Start to expand the parameter token list */
CurMac->ParamExp = CurMac->Params [IVal];
/* Recursive call to expand the parameter */
return MacExpand ();
}
/* If it's an identifier, it may in fact be a local symbol */
if (Tok == TOK_IDENT && CurMac->M->LocalCount) {
/* Search for the local symbol in the list */
unsigned Index = 0;
IdDesc* I = CurMac->M->Locals;
while (I) {
if (strcmp (SVal, I->Id) == 0) {
/* This is in fact a local symbol, change the name */
sprintf (SVal, "___%04X__", CurMac->LocalStart + Index);
break;
}
/* Next symbol */
++Index;
I = I->Next;
}
/* Done */
return 1;
}
/* The token was successfully set */
return 1;
} else if (CurMac->Final) {
/* Set the final token and remove it */
TokSet (CurMac->Final);
FreeTokNode (CurMac->Final);
CurMac->Final = 0;
/* The token was successfully set */
return 1;
} else {
/* End of macro expansion */
FreeMacExp ();
return MacExpand ();
} }
} }
@ -731,10 +737,10 @@ void MacAbort (void)
/* Abort the current macro expansion */ /* Abort the current macro expansion */
{ {
/* Must have an expansion */ /* Must have an expansion */
CHECK (CurMac != 0); CHECK (MacExpansions > 0);
/* Free current structure */ /* Set a flag so macro expansion will terminate on the next call */
FreeMacExp (); DoMacAbort = 1;
} }
@ -759,7 +765,7 @@ int IsDefine (const char* Name)
int InMacExpansion (void) int InMacExpansion (void)
/* Return true if we're currently expanding a macro */ /* Return true if we're currently expanding a macro */
{ {
return MacroNesting != 0; return (MacExpansions > 0);
} }

View File

@ -62,12 +62,6 @@ void MacDef (unsigned Style);
void MacExpandStart (void); void MacExpandStart (void);
/* Start expanding the macro in SVal */ /* Start expanding the macro in SVal */
int MacExpand (void);
/* If we're currently expanding a macro, set the the scanner token and
* attribute to the next value and return true. If we are not expanding
* a macro, return false.
*/
void MacAbort (void); void MacAbort (void);
/* Abort the current macro expansion */ /* Abort the current macro expansion */
@ -77,7 +71,7 @@ int IsMacro (const char* Name);
int IsDefine (const char* Name); int IsDefine (const char* Name);
/* Return true if the given name is the name of a define style macro */ /* Return true if the given name is the name of a define style macro */
int InMacExpansion (void); int InMacExpansion (void);
/* Return true if we're currently expanding a macro */ /* Return true if we're currently expanding a macro */

View File

@ -49,6 +49,7 @@
#include "listing.h" #include "listing.h"
#include "macro.h" #include "macro.h"
#include "mem.h" #include "mem.h"
#include "nexttok.h"
#include "objcode.h" #include "objcode.h"
#include "objfile.h" #include "objfile.h"
#include "options.h" #include "options.h"
@ -543,7 +544,7 @@ int main (int argc, char* argv [])
OptIgnoreCase (Arg); OptIgnoreCase (Arg);
break; break;
case 'l': case 'l':
OptListing (Arg); OptListing (Arg);
break; break;

View File

@ -15,11 +15,13 @@ OBJS = condasm.o \
global.o \ global.o \
incpath.o \ incpath.o \
instr.o \ instr.o \
istack.o \
listing.o \ listing.o \
macpack.o \ macpack.o \
macro.o \ macro.o \
main.o \ main.o \
mem.o \ mem.o \
nexttok.o \
objcode.o \ objcode.o \
objfile.o \ objfile.o \
options.o \ options.o \
@ -27,7 +29,7 @@ OBJS = condasm.o \
scanner.o \ scanner.o \
strexpr.o \ strexpr.o \
symtab.o \ symtab.o \
toknode.o \ toklist.o \
ulabel.o ulabel.o
LIBS = ../common/common.a LIBS = ../common/common.a
@ -62,3 +64,4 @@ depend dep: $(OBJS:.o=.c)
@echo "Creating dependency information" @echo "Creating dependency information"
$(CC) -MM $^ > .depend $(CC) -MM $^ > .depend

View File

@ -72,11 +72,13 @@ OBJS = condasm.obj \
global.obj \ global.obj \
incpath.obj \ incpath.obj \
instr.obj \ instr.obj \
istack.obj \
listing.obj \ listing.obj \
macpack.obj \ macpack.obj \
macro.obj \ macro.obj \
main.obj \ main.obj \
mem.obj \ mem.obj \
nexttok.obj \
objcode.obj \ objcode.obj \
objfile.obj \ objfile.obj \
options.obj \ options.obj \
@ -84,7 +86,7 @@ OBJS = condasm.obj \
scanner.obj \ scanner.obj \
strexpr.obj \ strexpr.obj \
symtab.obj \ symtab.obj \
toknode.obj \ toklist.obj \
ulabel.obj ulabel.obj
LIBS = ..\common\common.lib LIBS = ..\common\common.lib
@ -116,11 +118,13 @@ FILE fragment.obj
FILE global.obj FILE global.obj
FILE incpath.obj FILE incpath.obj
FILE instr.obj FILE instr.obj
FILE istack.obj
FILE listing.obj FILE listing.obj
FILE macpack.obj FILE macpack.obj
FILE macro.obj FILE macro.obj
FILE main.obj FILE main.obj
FILE mem.obj FILE mem.obj
FILE nexttok.obj
FILE objcode.obj FILE objcode.obj
FILE objfile.obj FILE objfile.obj
FILE options.obj FILE options.obj
@ -128,7 +132,7 @@ FILE pseudo.obj
FILE scanner.obj FILE scanner.obj
FILE strexpr.obj FILE strexpr.obj
FILE symtab.obj FILE symtab.obj
FILE toknode.obj FILE toklist.obj
FILE ulabel.obj FILE ulabel.obj
LIBRARY ..\common\common.lib LIBRARY ..\common\common.lib
| |

219
src/ca65/nexttok.c Normal file
View File

@ -0,0 +1,219 @@
/*****************************************************************************/
/* */
/* nexttok.c */
/* */
/* Get next token and handle token level functions */
/* */
/* */
/* */
/* (C) 2000 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 "error.h"
#include "expr.h"
#include "scanner.h"
#include "toklist.h"
#include "nexttok.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static TokList* CollectTokens (unsigned Start, unsigned Count)
/* Read a list of tokens that is terminated by a right paren. For all tokens
* starting at the one with index Start, and ending at (Start+Count-1), place
* them into a token list, and return this token list.
*/
{
/* Create the token list */
TokList* List = NewTokList ();
/* Read the token list */
unsigned Current = 0;
unsigned Parens = 0;
while (Parens != 0 && Tok != TOK_RPAREN) {
/* Check for end of line or end of input */
if (Tok == TOK_SEP || Tok == TOK_EOF) {
Error (ERR_UNEXPECTED_EOL);
return List;
}
/* Collect tokens in the given range */
if (Current >= Start && Current < Start+Count) {
/* Add the current token to the list */
AddCurTok (List);
}
/* Check for and count parenthesii */
if (Tok == TOK_LPAREN) {
++Parens;
} else if (Tok == TOK_RPAREN) {
--Parens;
}
/* Get the next token */
NextTok ();
}
/* Eat the closing paren */
ConsumeRParen ();
/* Return the list of collected tokens */
return List;
}
static void FuncMid (void)
/* Handle the .MID function */
{
long Start;
long Count;
TokList* List;
/* Skip it */
NextTok ();
/* Left paren expected */
ConsumeRParen ();
/* Start argument */
Start = ConstExpression ();
if (Start < 0 || Start > 100) {
Error (ERR_RANGE);
Start = 0;
}
ConsumeComma ();
/* Count argument */
Count = ConstExpression ();
if (Count > 100) {
Error (ERR_RANGE);
Count = 1;
}
ConsumeComma ();
/* Read the token list */
List = CollectTokens ((unsigned) Start, (unsigned) Count);
/* Insert it into the scanner feed */
}
void NextTok (void)
/* Get next token and handle token level functions */
{
/* Get the next raw token */
NextRawTok ();
/* Check for token handling functions */
switch (Tok) {
case TOK_MID:
FuncMid ();
break;
default:
/* Quiet down gcc */
break;
}
}
void Consume (enum Token Expected, unsigned ErrMsg)
/* Consume Expected, print an error if we don't find it */
{
if (Tok == Expected) {
NextTok ();
} else {
Error (ErrMsg);
}
}
void ConsumeSep (void)
/* Consume a separator token */
{
/* Accept an EOF as separator */
if (Tok != TOK_EOF) {
if (Tok != TOK_SEP) {
Error (ERR_TOO_MANY_CHARS);
SkipUntilSep ();
} else {
NextTok ();
}
}
}
void ConsumeLParen (void)
/* Consume a left paren */
{
Consume (TOK_LPAREN, ERR_LPAREN_EXPECTED);
}
void ConsumeRParen (void)
/* Consume a right paren */
{
Consume (TOK_RPAREN, ERR_RPAREN_EXPECTED);
}
void ConsumeComma (void)
/* Consume a comma */
{
Consume (TOK_COMMA, ERR_COMMA_EXPECTED);
}
void SkipUntilSep (void)
/* Skip tokens until we reach a line separator */
{
while (Tok != TOK_SEP && Tok != TOK_EOF) {
NextTok ();
}
}

80
src/ca65/nexttok.h Normal file
View File

@ -0,0 +1,80 @@
/*****************************************************************************/
/* */
/* nexttok.h */
/* */
/* Get next token and handle token level functions */
/* */
/* */
/* */
/* (C) 2000 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 NEXTTOK_H
#define NEXTTOK_H
#include "scanner.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void NextTok (void);
/* Get next token and handle token level functions */
void Consume (enum Token Expected, unsigned ErrMsg);
/* Consume Token, print an error if we don't find it */
void ConsumeSep (void);
/* Consume a separator token */
void ConsumeLParen (void);
/* Consume a left paren */
void ConsumeRParen (void);
/* Consume a right paren */
void ConsumeComma (void);
/* Consume a comma */
void SkipUntilSep (void);
/* Skip tokens until we reach a line separator */
/* End of nexttok.h */
#endif

View File

@ -49,9 +49,9 @@
#include "listing.h" #include "listing.h"
#include "macpack.h" #include "macpack.h"
#include "macro.h" #include "macro.h"
#include "nexttok.h"
#include "objcode.h" #include "objcode.h"
#include "options.h" #include "options.h"
#include "scanner.h"
#include "strexpr.h" #include "strexpr.h"
#include "symtab.h" #include "symtab.h"
#include "pseudo.h" #include "pseudo.h"
@ -789,6 +789,16 @@ static void DoMacro (void)
static void DoMid (void)
/* Handle .MID - this should never happen, since the keyword is actually
* handled on a much lower level of the expression hierarchy.
*/
{
Internal ("Unexpected token: .MID");
}
static void DoNull (void) static void DoNull (void)
/* Switch to the NULL segment */ /* Switch to the NULL segment */
{ {
@ -1119,6 +1129,7 @@ static CtrlDesc CtrlCmdTab [] = {
{ ccNone, DoMacPack }, { ccNone, DoMacPack },
{ ccNone, DoMacro }, { ccNone, DoMacro },
{ ccNone, DoUnexpected }, /* .MATCH */ { ccNone, DoUnexpected }, /* .MATCH */
{ ccNone, DoMid },
{ ccNone, DoNull }, { ccNone, DoNull },
{ ccNone, DoOrg }, { ccNone, DoOrg },
{ ccNone, DoOut }, { ccNone, DoOut },

View File

@ -46,10 +46,12 @@
#include "global.h" #include "global.h"
#include "incpath.h" #include "incpath.h"
#include "instr.h" #include "instr.h"
#include "istack.h"
#include "listing.h" #include "listing.h"
#include "macro.h" #include "macro.h"
#include "mem.h" #include "mem.h"
#include "objfile.h" #include "objfile.h"
#include "toklist.h"
#include "scanner.h" #include "scanner.h"
@ -104,10 +106,10 @@ static struct {
static unsigned FileCount = 0; static unsigned FileCount = 0;
/* Current input variables */ /* Current input variables */
static InputFile* IFile = 0; static InputFile* IFile = 0; /* Current input file */
static InputData* IData = 0; static InputData* IData = 0; /* Current input memory data */
static unsigned ICount = 0; /* Count of input files */ static unsigned ICount = 0; /* Count of input files */
static int C = 0; static int C = 0; /* Current input character */
/* Force end of assembly */ /* Force end of assembly */
int ForcedEnd = 0; int ForcedEnd = 0;
@ -121,7 +123,7 @@ struct DotKeyword {
{ "A8", TOK_A8 }, { "A8", TOK_A8 },
{ "ADDR", TOK_ADDR }, { "ADDR", TOK_ADDR },
{ "ALIGN", TOK_ALIGN }, { "ALIGN", TOK_ALIGN },
{ "AND", TOK_BAND }, { "AND", TOK_BAND },
{ "ASCIIZ", TOK_ASCIIZ }, { "ASCIIZ", TOK_ASCIIZ },
{ "AUTOIMPORT", TOK_AUTOIMPORT }, { "AUTOIMPORT", TOK_AUTOIMPORT },
{ "BITAND", TOK_AND }, { "BITAND", TOK_AND },
@ -131,15 +133,15 @@ struct DotKeyword {
{ "BLANK", TOK_BLANK }, { "BLANK", TOK_BLANK },
{ "BSS", TOK_BSS }, { "BSS", TOK_BSS },
{ "BYTE", TOK_BYTE }, { "BYTE", TOK_BYTE },
{ "CASE", TOK_CASE }, { "CASE", TOK_CASE },
{ "CODE", TOK_CODE }, { "CODE", TOK_CODE },
{ "CONST", TOK_CONST }, { "CONST", TOK_CONST },
{ "CPU", TOK_CPU }, { "CPU", TOK_CPU },
{ "DATA", TOK_DATA }, { "DATA", TOK_DATA },
{ "DBYT", TOK_DBYT }, { "DBYT", TOK_DBYT },
{ "DEBUGINFO", TOK_DEBUGINFO }, { "DEBUGINFO", TOK_DEBUGINFO },
{ "DEF", TOK_DEFINED }, { "DEF", TOK_DEFINED },
{ "DEFINE", TOK_DEFINE }, { "DEFINE", TOK_DEFINE },
{ "DEFINED", TOK_DEFINED }, { "DEFINED", TOK_DEFINED },
{ "DWORD", TOK_DWORD }, { "DWORD", TOK_DWORD },
{ "ELSE", TOK_ELSE }, { "ELSE", TOK_ELSE },
@ -189,10 +191,11 @@ struct DotKeyword {
{ "MACPACK", TOK_MACPACK }, { "MACPACK", TOK_MACPACK },
{ "MACRO", TOK_MACRO }, { "MACRO", TOK_MACRO },
{ "MATCH", TOK_MATCH }, { "MATCH", TOK_MATCH },
{ "MOD", TOK_MOD }, { "MID", TOK_MID },
{ "NOT", TOK_BNOT }, { "MOD", TOK_MOD },
{ "NOT", TOK_BNOT },
{ "NULL", TOK_NULL }, { "NULL", TOK_NULL },
{ "OR", TOK_BOR }, { "OR", TOK_BOR },
{ "ORG", TOK_ORG }, { "ORG", TOK_ORG },
{ "OUT", TOK_OUT }, { "OUT", TOK_OUT },
{ "P02", TOK_P02 }, { "P02", TOK_P02 },
@ -202,15 +205,15 @@ struct DotKeyword {
{ "PARAMCOUNT", TOK_PARAMCOUNT }, { "PARAMCOUNT", TOK_PARAMCOUNT },
{ "PC02", TOK_PC02 }, { "PC02", TOK_PC02 },
{ "PROC", TOK_PROC }, { "PROC", TOK_PROC },
{ "REF", TOK_REFERENCED }, { "REF", TOK_REFERENCED },
{ "REFERENCED", TOK_REFERENCED }, { "REFERENCED", TOK_REFERENCED },
{ "RELOC", TOK_RELOC }, { "RELOC", TOK_RELOC },
{ "REPEAT", TOK_REPEAT }, { "REPEAT", TOK_REPEAT },
{ "RES", TOK_RES }, { "RES", TOK_RES },
{ "RODATA", TOK_RODATA }, { "RODATA", TOK_RODATA },
{ "SEGMENT", TOK_SEGMENT }, { "SEGMENT", TOK_SEGMENT },
{ "SHL", TOK_SHL }, { "SHL", TOK_SHL },
{ "SHR", TOK_SHR }, { "SHR", TOK_SHR },
{ "SMART", TOK_SMART }, { "SMART", TOK_SMART },
{ "STRING", TOK_STRING }, { "STRING", TOK_STRING },
{ "SUNPLUS", TOK_SUNPLUS }, { "SUNPLUS", TOK_SUNPLUS },
@ -489,7 +492,7 @@ static void NextChar (void)
/* End of file. Add an empty line to the listing. This is a /* End of file. Add an empty line to the listing. This is a
* small hack needed to keep the PC output in sync. * small hack needed to keep the PC output in sync.
*/ */
NewListingLine ("", IFile->Pos.Name, ICount); NewListingLine ("", IFile->Pos.Name, ICount);
C = EOF; C = EOF;
return; return;
} }
@ -627,7 +630,7 @@ static unsigned ReadStringConst (int StringTerm)
void NextTok (void) void NextRawTok (void)
/* Read the next raw token from the input stream */ /* Read the next raw token from the input stream */
{ {
/* If we've a forced end of assembly, don't read further */ /* If we've a forced end of assembly, don't read further */
@ -636,8 +639,9 @@ void NextTok (void)
return; return;
} }
/* If we're expanding a macro, the tokens come from the macro expansion */ Restart:
if (MacExpand ()) { /* Check if we have tokens from another input source */
if (InputFromStack ()) {
return; return;
} }
@ -813,9 +817,7 @@ Again:
} else if (IsDefine (SVal)) { } else if (IsDefine (SVal)) {
/* This is a define style macro - expand it */ /* This is a define style macro - expand it */
MacExpandStart (); MacExpandStart ();
if (!MacExpand ()) { goto Restart;
goto Again;
}
} else { } else {
/* An identifier */ /* An identifier */
Tok = TOK_IDENT; Tok = TOK_IDENT;
@ -894,8 +896,8 @@ CharAgain:
IVal = 0; IVal = 0;
do { do {
++IVal; ++IVal;
NextChar (); NextChar ();
} while (C == '+'); } while (C == '+');
Tok = TOK_ULABEL; Tok = TOK_ULABEL;
break; break;
@ -1029,8 +1031,8 @@ CharAgain:
/* Handle as white space */ /* Handle as white space */
NextChar (); NextChar ();
C = ' '; C = ' ';
goto Again; goto Again;
} }
} }
break; break;
@ -1042,6 +1044,8 @@ CharAgain:
case EOF: case EOF:
/* Check if we have any open .IFs in this file */ /* Check if we have any open .IFs in this file */
CheckOpenIfs (); CheckOpenIfs ();
/* Check if we have any open token lists in this file */
CheckInputStack ();
/* If this was an include file, then close it and handle like a /* If this was an include file, then close it and handle like a
* separator. Do not close the main file, but return EOF. * separator. Do not close the main file, but return EOF.
@ -1065,68 +1069,6 @@ CharAgain:
void Consume (enum Token Expected, unsigned ErrMsg)
/* Consume Expected, print an error if we don't find it */
{
if (Tok == Expected) {
NextTok ();
} else {
Error (ErrMsg);
}
}
void ConsumeSep (void)
/* Consume a separator token */
{
/* Accept an EOF as separator */
if (Tok != TOK_EOF) {
if (Tok != TOK_SEP) {
Error (ERR_TOO_MANY_CHARS);
SkipUntilSep ();
} else {
NextTok ();
}
}
}
void ConsumeLParen (void)
/* Consume a left paren */
{
Consume (TOK_LPAREN, ERR_LPAREN_EXPECTED);
}
void ConsumeRParen (void)
/* Consume a right paren */
{
Consume (TOK_RPAREN, ERR_RPAREN_EXPECTED);
}
void ConsumeComma (void)
/* Consume a comma */
{
Consume (TOK_COMMA, ERR_COMMA_EXPECTED);
}
void SkipUntilSep (void)
/* Skip tokens until we reach a line separator */
{
while (Tok != TOK_SEP && Tok != TOK_EOF) {
NextTok ();
}
}
int TokHasSVal (enum Token Tok) int TokHasSVal (enum Token Tok)
/* Return true if the given token has an attached SVal */ /* Return true if the given token has an attached SVal */
{ {

View File

@ -168,6 +168,7 @@ enum Token {
TOK_MACPACK, TOK_MACPACK,
TOK_MACRO, TOK_MACRO,
TOK_MATCH, TOK_MATCH,
TOK_MID,
TOK_NULL, TOK_NULL,
TOK_ORG, TOK_ORG,
TOK_OUT, TOK_OUT,
@ -230,26 +231,8 @@ void NewInputData (const char* Data, int Malloced);
void UpcaseSVal (void); void UpcaseSVal (void);
/* Make SVal upper case */ /* Make SVal upper case */
void NextTok (void); void NextRawTok (void);
/* Read the next token from the input stream */ /* Read the next raw token from the input stream */
void Consume (enum Token Expected, unsigned ErrMsg);
/* Consume Token, print an error if we don't find it */
void ConsumeSep (void);
/* Consume a separator token */
void ConsumeLParen (void);
/* Consume a left paren */
void ConsumeRParen (void);
/* Consume a right paren */
void ConsumeComma (void);
/* Consume a comma */
void SkipUntilSep (void);
/* Skip tokens until we reach a line separator */
int TokHasSVal (enum Token Tok); int TokHasSVal (enum Token Tok);
/* Return true if the given token has an attached SVal */ /* Return true if the given token has an attached SVal */

View File

@ -1,8 +1,8 @@
/*****************************************************************************/ /*****************************************************************************/
/* */ /* */
/* toknode.c */ /* toklist.c */
/* */ /* */
/* Token list node for the ca65 macroassembler */ /* Token list for the ca65 macroassembler */
/* */ /* */
/* */ /* */
/* */ /* */
@ -37,7 +37,7 @@
#include "mem.h" #include "mem.h"
#include "scanner.h" #include "scanner.h"
#include "toknode.h" #include "toklist.h"
@ -97,7 +97,7 @@ enum TC TokCmp (const TokNode* T)
/* Different token */ /* Different token */
return tcDifferent; return tcDifferent;
} }
/* If the token has string attribute, check it */ /* If the token has string attribute, check it */
if (TokHasSVal (T->Tok)) { if (TokHasSVal (T->Tok)) {
if (strcmp (T->SVal, SVal) != 0) { if (strcmp (T->SVal, SVal) != 0) {
@ -108,10 +108,78 @@ enum TC TokCmp (const TokNode* T)
return tcSameToken; return tcSameToken;
} }
} }
/* Tokens are identical */ /* Tokens are identical */
return tcIdentical; return tcIdentical;
} }
void InitTokList (TokList* T)
/* Initialize a token list structure for later use */
{
/* Initialize the fields */
T->Next = 0;
T->Root = 0;
T->Last = 0;
T->Repeat = 1;
T->Count = 0;
}
TokList* NewTokList (void)
/* Create a new, empty token list */
{
/* Allocate memory for the list structure */
TokList* T = Xmalloc (sizeof (TokList));
/* Initialize the fields */
InitTokList (T);
/* Return the new list */
return T;
}
void FreeTokList (TokList* List)
/* Delete the token list including all token nodes */
{
/* Free the token list */
TokNode* T = List->Root;
while (T) {
TokNode* Tmp = T;
T = T->Next;
FreeTokNode (Tmp);
}
/* Free the list structure itself */
Xfree (List);
}
void AddCurTok (TokList* List)
/* Add the current token to the token list */
{
/* Create a token node with the current token value */
TokNode* T = NewTokNode ();
/* Insert the node into the list */
if (List->Root == 0) {
List->Root = T;
} else {
List->Last->Next = T;
}
List->Last = T;
/* Count nodes */
List->Count++;
}

View File

@ -1,12 +1,12 @@
/*****************************************************************************/ /*****************************************************************************/
/* */ /* */
/* toknode.h */ /* toklist.h */
/* */ /* */
/* Token list node for the ca65 macroassembler */ /* Token list for the ca65 macroassembler */
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998 Ullrich von Bassewitz */ /* (C) 2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Wacholderweg 14 */
/* D-70597 Stuttgart */ /* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */ /* EMail: uz@musoftware.de */
@ -33,8 +33,8 @@
#ifndef TOKNODE_H #ifndef TOKLIST_H
#define TOKNODE_H #define TOKLIST_H
@ -45,22 +45,32 @@
/* Struct holding a token */ /* Struct holding a token */
typedef struct TokNode_ TokNode; typedef struct TokNode TokNode;
struct TokNode_ { struct TokNode {
TokNode* Next; /* For single linked list */ TokNode* Next; /* For single linked list */
enum Token Tok; /* Token value */ enum Token Tok; /* Token value */
int WS; /* Whitespace before token? */ int WS; /* Whitespace before token? */
long IVal; /* Integer token attribute */ long IVal; /* Integer token attribute */
char SVal [1]; /* String attribute, dyn. allocated */ char SVal [1]; /* String attribute, dyn. allocated */
};
/* Struct holding a token list */
typedef struct TokList TokList;
struct TokList {
TokList* Next; /* Single linked list (for replay) */
TokNode* Root; /* First node in list */
TokNode* Last; /* Last node in list or replay */
unsigned Repeat; /* Repeat counter (used for replay) */
unsigned Count; /* Token count */
}; };
/* Return codes for TokCmp - higher numeric code means better match */ /* Return codes for TokCmp - higher numeric code means better match */
enum TC { enum TC {
tcDifferent, /* Different tokents */ tcDifferent, /* Different tokents */
tcSameToken, /* Same token, different attribute */ tcSameToken, /* Same token, different attribute */
tcIdentical /* Identical (token + attribute) */ tcIdentical /* Identical (token + attribute) */
}; };
@ -83,9 +93,21 @@ void TokSet (TokNode* T);
enum TC TokCmp (const TokNode* T); enum TC TokCmp (const TokNode* T);
/* Compare the token given as parameter against the current token */ /* Compare the token given as parameter against the current token */
void InitTokList (TokList* T);
/* Initialize a token list structure for later use */
TokList* NewTokList (void);
/* Create a new, empty token list */
void FreeTokList (TokList* T);
/* Delete the token list including all token nodes */
void AddCurTok (TokList* T);
/* Add the current token to the token list */
/* End of toknode.h */
/* End of toklist.h */
#endif #endif