// MACRO.C - Macro Definition and Invocation
// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
-// Source Utilised with the Kind Permission of Landon Dyer
+// Source utilised with the kind permission of Landon Dyer
//
#include "macro.h"
-#include "token.h"
+#include "debug.h"
+#include "direct.h"
#include "error.h"
#include "expr.h"
#include "listing.h"
-#include "symbol.h"
#include "procln.h"
-#include "direct.h"
-#include "debug.h"
+#include "symbol.h"
+#include "token.h"
+
LONG curuniq; // Current macro's unique number
-TOKEN ** argp; // Free spot in argptrs[]
+//TOKEN ** argp; // Free spot in argptrs[]
int macnum; // Unique number for macro definition
+TOKEN * argPtrs[128]; // 128 arguments ought to be enough for anyone
+static int argp;
static LONG macuniq; // Unique-per-macro number
static SYM * curmac; // Macro currently being defined
-static char ** curmln; // Previous macro line (or NULL)
+//static char ** curmln; // Previous macro line (or NULL)
static VALUE argno; // Formal argument count
static LONG * firstrpt; // First .rept line
//
-// Initialize Macro Processor
+// Initialize macro processor
//
-void init_macro(void)
+void InitMacro(void)
{
macuniq = 0;
macnum = 1;
- argp = NULL;
- ib_macro();
+ argp = 0;
}
//
-// Exit from a Macro;
-// o pop any intervening include files and repeat blocks;
-// o restore argument stack;
-// o pop the macro.
+// Exit from a macro;
+// -- pop any intervening include files and repeat blocks;
+// -- restore argument stack;
+// -- pop the macro.
//
-int exitmac(void)
+int ExitMacro(void)
{
- IMACRO * imacro;
- TOKEN ** p;
+WARNING(!!! Bad macro exiting !!!)
+/*
+This is a problem. Currently, the argument logic just keeps the current
+arguments and doesn't save anything if a new macro is called in the middle
+of another (nested macros). Need to fix that somehow.
+*/
// Pop intervening include files and .rept blocks
while (cur_inobj != NULL && cur_inobj->in_type != SRC_IMACRO)
fpop();
// o old unique number
// ...and then pop the macro.
- imacro = cur_inobj->inobj.imacro;
+ IMACRO * imacro = cur_inobj->inobj.imacro;
curuniq = imacro->im_olduniq;
- p = --argp;
- argp = (TOKEN **)*argp;
-
- fpop();
-
- mjump_align = 0;
+// /*TOKEN ** p = */argp--;
+// argp = (TOKEN **)*argp;
+ DEBUG printf("ExitMacro: argp: %d -> ", argp);
+ argp -= imacro->im_nargs;
+ DEBUG printf("%d (nargs = %d)\n", argp, imacro->im_nargs);
- return 0;
+ return fpop();
}
//
-// Add a Formal Argument to a Macro Definition
+// Add a formal argument to a macro definition
//
int defmac2(char * argname)
{
SYM * arg;
if (lookup(argname, MACARG, (int)curmac->sattr) != NULL)
- return(error("multiple formal argument definition"));
- arg = newsym(argname, MACARG, (int)curmac->sattr);
+ return error("multiple formal argument definition");
+
+ arg = NewSymbol(argname, MACARG, (int)curmac->sattr);
arg->svalue = argno++;
return OK;
//
// Add a line to a macro definition; also print lines to listing file (if
// enabled). The last line of the macro (containing .endm) is not included in
-// the macro. A label on that line will be lost. `endflg' is misleading here.
-// It is -1 for all lines but the last one (.endm), when it is 0.
+// the macro. A label on that line will be lost.
+// notEndFlag is -1 for all lines but the last one (.endm), when it is 0.
//
-int defmac1(char * ln, int endflg)
+int defmac1(char * ln, int notEndFlag)
{
- PTR p;
- LONG len;
+// PTR p;
+// LONG len;
if (list_flag)
{
- listeol(); // Flush previous source line
- lstout('.'); // Mark macro definition with period
+ listeol(); // Flush previous source line
+ lstout('.'); // Mark macro definition with period
}
- if (endflg)
+ // This is just wrong, wrong, wrong. It makes up a weird kind of string with
+ // a pointer on front, and then uses a ** to manage them: This is a recipe
+ // for disaster.
+ // How to manage it then?
+ // Could use a linked list, like Landon uses everywhere else.
+/*
+How it works:
+Allocate a space big enough for the string + NULL + pointer.
+Set the pointer to NULL.
+Copy the string to the space after the pointer.
+If this is the 1st time through, set the SYM * "svalue" to the pointer.
+If this is the 2nd time through, derefence the ** to point to the memory you just allocated.
+Then, set the ** to the location of the memory you allocated for the next pass through.
+
+This is a really low level way to do a linked list, and by bypassing all the safety
+features of the language. Seems like we can do better here.
+*/
+ if (notEndFlag)
{
+#if 0
len = strlen(ln) + 1 + sizeof(LONG);
-// p.cp = amem(len);
p.cp = malloc(len);
*p.lp = 0;
strcpy(p.cp + sizeof(LONG), ln);
// Link line of text onto end of list
if (curmln == NULL)
- curmac->svalue = (VALUE)p.cp;
+ curmac->svalue = p.cp;
else
*curmln = p.cp;
curmln = (char **)p.cp;
- return 1; // Keep looking
+ return 1; // Keep looking
+#else
+ if (curmac->lineList == NULL)
+ {
+ curmac->lineList = malloc(sizeof(struct LineList));
+ curmac->lineList->next = NULL;
+ curmac->lineList->line = strdup(ln);
+ curmac->last = curmac->lineList;
+ }
+ else
+ {
+ curmac->last->next = malloc(sizeof(struct LineList));
+ curmac->last->next->next = NULL;
+ curmac->last->next->line = strdup(ln);
+ curmac->last = curmac->last->next;
+ }
+
+ return 1; // Keep looking
+#endif
}
- else
- return 0; // Stop looking at the end
+
+ return 0; // Stop looking at the end
}
// `defmac1' adds lines of text to the macro definition
// `defmac2' processes the formal arguments (and sticks them into the symbol table)
//
-int defmac(void)
+int DefineMacro(void)
{
- char * p;
- SYM * mac;
-
- // Setup entry in symbol table, make sure the macro isn't a duplicate entry, and that
- // it doesn't override any processor mnemonic or assembler directive.
+ // Setup entry in symbol table, make sure the macro isn't a duplicate
+ // entry, and that it doesn't override any processor mnemonic or assembler
+ // directive.
if (*tok++ != SYMBOL)
return error("missing symbol");
- p = (char *)*tok++;
+ char * name = string[*tok++];
- if (lookup(p, MACRO, 0) != NULL)
- return error("multiple macro definition");
+ if (lookup(name, MACRO, 0) != NULL)
+ return error("duplicate macro definition");
- curmac = mac = newsym(p, MACRO, 0);
- mac->svalue = 0;
- mac->sattr = (WORD)(macnum++);
+ curmac = NewSymbol(name, MACRO, 0);
+ curmac->svalue = 0;
+ curmac->sattr = (WORD)(macnum++);
// Parse and define formal arguments in symbol table
if (*tok != EOL)
// Suck in the macro definition; we're looking for an ENDM symbol on a line
// by itself to terminate the definition.
- curmln = NULL;
+// curmln = NULL;
+ curmac->lineList = NULL;
lncatch(defmac1, "endm ");
return 0;
return(0);
goto addln;
case 1: // .rept
- ++rptlevel;
+ rptlevel++;
default:
+//MORE stupidity here...
+WARNING(!!! Casting (char *) as LONG !!!)
addln:
// Allocate length of line + 1('\0') + LONG
len = strlen(ln) + 1 + sizeof(LONG);
int k;
if (lnfunc != NULL)
- ++lnsave; // Tell tokenizer to keep lines
+ lnsave++; // Tell tokenizer to keep lines
for(;;)
{
- if (tokln() == TKEOF)
+ if (TokenizeLine() == TKEOF)
{
errors("encountered end-of-file looking for '%s'", dirlist);
fatal("cannot continue");
if ((tok[2] == ':' || tok[2] == DCOLON))
{
if (tok[3] == SYMBOL) // label: symbol
- p = (char *)tok[4];
+ p = string[tok[4]];
}
else
{
- p = (char *)tok[1]; // symbol
+ p = string[tok[1]]; // Symbol
}
}
if (p != NULL)
{
if (*p == '.') // ignore leading '.'s
- ++p;
+ p++;
k = kwmatch(p, dirlist);
}
}
if (lnfunc != NULL)
- --lnsave; // Tell tokenizer to stop keeping lines
+ lnsave--; // Tell tokenizer to stop keeping lines
return 0;
}
++kwlist;
if (*kwlist== ' ')
- ++kwlist;
+ kwlist++;
}
return -1;
// o parse, count and copy arguments
// o push macro's string-stream
//
-int invokemac(SYM * mac, WORD siz)
+int InvokeMacro(SYM * mac, WORD siz)
{
TOKEN * p = NULL;
- IMACRO * imacro;
- INOBJ * inobj;
int dry_run;
- WORD nargs;
WORD arg_siz = 0;
- TOKEN ** argptr = NULL;
- TOKEN * beg_tok;
-
- if ((!strcmp(mac->sname, "mjump") || !strcmp(mac->sname, "mpad")) && !in_main)
- {
- error("macro cannot be used outside of .gpumain");
- return ERROR;
- }
+// TOKEN ** argptr = NULL;
+//Doesn't need to be global! (or does it???--it does)
+// argp = 0;
+ DEBUG printf("InvokeMacro: argp: %d -> ", argp);
- inobj = a_inobj(SRC_IMACRO); // Alloc and init IMACRO
- imacro = inobj->inobj.imacro;
+ INOBJ * inobj = a_inobj(SRC_IMACRO); // Alloc and init IMACRO
+ IMACRO * imacro = inobj->inobj.imacro;
imacro->im_siz = siz;
- nargs = 0;
- beg_tok = tok; // 'tok' comes from token.c
-
- for(dry_run=1;; --dry_run)
+ WORD nargs = 0;
+ TOKEN * beg_tok = tok; // 'tok' comes from token.c
+ TOKEN * startOfArg;
+ TOKEN * dest;
+ int stringNum = 0;
+ int argumentNum = 0;
+// int i;
+
+ for(dry_run=1; ; dry_run--)
{
for(tok=beg_tok; *tok!=EOL;)
{
if (dry_run)
nargs++;
else
+ {
+#if 0
*argptr++ = p;
+#else
+ argPtrs[argp++] = p;
+ startOfArg = p;
+#endif
+ }
// Keep going while tok isn't pointing at a comma or EOL
while (*tok != ',' && *tok != EOL)
{
case CONST:
case SYMBOL:
+//Shamus: Possible bug. ACONST has 2 tokens after it, not just 1
case ACONST:
if (dry_run)
{
tok++;
}
else
+ {
*p++ = *tok++;
+ }
// FALLTHROUGH (picks up the arg after a CONST, SYMBOL or ACONST)
default:
if (dry_run)
tok++;
}
else
+ {
*p++ = *tok++;
+ }
break;
}
// If we hit the comma instead of an EOL, skip over it
if (*tok == ',')
tok++;
+
+ // Do our QnD token grabbing (this will be redone once we get all
+ // the data structures fixed as this is a really dirty hack)
+ if (!dry_run)
+ {
+ dest = imacro->argument[argumentNum].token;
+ stringNum = 0;
+
+ do
+ {
+ // Remap strings to point the IMACRO internal token storage
+ if (*startOfArg == SYMBOL || *startOfArg == STRING)
+ {
+ *dest++ = *startOfArg++;
+ imacro->argument[argumentNum].string[stringNum] = strdup(string[*startOfArg++]);
+ *dest++ = stringNum++;
+ }
+ else
+ *dest++ = *startOfArg++;
+ }
+ while (*startOfArg != EOL);
+
+ *dest = *startOfArg; // Copy EOL...
+ argumentNum++;
+ }
}
// Allocate space for argument ptrs and so on and then go back and
if (dry_run)
{
if (nargs != 0)
-//Barfing here with memory corruption in glibc. TOKEN is defined as LONG, which is uint32_t
-// p = (TOKEN *)malloc(arg_siz + 1);
- p = (TOKEN *)malloc(arg_siz + sizeof(TOKEN));
-
+ p = (TOKEN *)malloc(arg_siz);
+// p = (TOKEN *)malloc(arg_siz + sizeof(TOKEN));
+
+/*
+Shamus:
+This construct is meant to deal with nested macros, so the simple minded way
+we deal with them now won't work. :-/ Have to think about how to fix.
+What we could do is simply move the argp with each call, and move it back by
+the number of arguments in the macro that's ending. That would solve the
+problem nicely.
+[Which we do now. But that uncovered another problem: the token strings are all
+stale by the time a nested macro gets to the end. But they're supposed to be
+symbols, which means if we put symbol references into the argument token
+streams, we can alleviate this problem.]
+*/
+#if 0
argptr = (TOKEN **)malloc((nargs + 1) * sizeof(LONG));
*argptr++ = (TOKEN *)argp;
argp = argptr;
+#else
+ // We don't need to do anything here since we already advance argp
+ // when parsing the arguments.
+// argp += nargs;
+#endif
}
else
break;
}
+ DEBUG printf("%d\n", argp);
+
// Setup imacro:
- // o #arguments;
+ // o # arguments;
// o -> macro symbol;
// o -> macro definition string list;
// o save 'curuniq', to be restored when the macro pops;
// o bump `macuniq' counter and set 'curuniq' to it;
imacro->im_nargs = nargs;
imacro->im_macro = mac;
- imacro->im_nextln = (TOKEN *)mac->svalue;
+// imacro->im_nextln = (TOKEN *)mac->svalue;
+ imacro->im_nextln = mac->lineList;
imacro->im_olduniq = curuniq;
curuniq = macuniq++;
-/*IMACRO {
- IMACRO * im_link; // Pointer to ancient IMACROs
- LONG * im_nextln; // Next line to include
- WORD im_nargs; // # of arguments supplied on invocation
- WORD im_siz; // Size suffix supplied on invocation
- LONG im_olduniq; // Old value of 'macuniq'
- SYM * im_macro; // Pointer to macro we're in
- char im_lnbuf[LNSIZ]; // Line buffer
-};*/
+ imacro->argBase = argp - nargs; // Shamus: keep track of argument base
DEBUG
{
printf("nargs=%d\n", nargs);
- for(nargs=0; nargs<imacro->im_nargs; ++nargs)
+ for(nargs=0; nargs<imacro->im_nargs; nargs++)
{
printf("arg%d=", nargs);
- dumptok(argp[imacro->im_nargs - nargs - 1]);
+// dumptok(argp[imacro->im_nargs - nargs - 1]);
+// dumptok(argPtrs[imacro->im_nargs - nargs - 1]);
+ dumptok(argPtrs[(argp - imacro->im_nargs) + nargs]);
}
}
return OK;
}
-
-//
-// Setup inbuilt macros
-//
-void ib_macro(void)
-{
- SYM * mac;
-
- curmac = mac = newsym("mjump", MACRO, 0);
- mac->svalue = 0;
- mac->sattr = (WORD)(macnum++);
- argno = 0;
- defmac2("cc");
- defmac2("addr");
- defmac2("jreg");
- curmln = NULL;
- defmac1(" nop", -1);
- defmac1(" movei #\\addr,\\jreg", -1);
- defmac1(" jump \\cc,(\\jreg)", -1);
- defmac1(" nop", -1);
- defmac1(" nop", -1);
-
- curmac = mac = newsym("mjr", MACRO, 0);
- mac->svalue = 0;
- mac->sattr = (WORD)(macnum++);
- argno = 0;
- defmac2("cc");
- defmac2("addr");
- curmln = NULL;
- defmac1(" jr \\cc,\\addr", -1);
- defmac1(" nop", -1);
- defmac1(" nop", -1);
-
- curmac = mac = newsym("mpad", MACRO, 0);
- mac->svalue = 0;
- mac->sattr = (WORD)(macnum++);
- argno = 0;
- defmac2("size");
- curmln = NULL;
- defmac1(" .rept (\\size/2)", -1);
- defmac1(" nop", -1);
- defmac1(" .endr", -1);
-}