//
-// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RMAC - Reboot's Macro Assembler for all Atari computers
// MACRO.C - Macro Definition and Invocation
-// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2017 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"
-LONG curuniq; // Current macro's unique number
-//TOKEN ** argp; // Free spot in argptrs[]
-int macnum; // Unique number for macro definition
-TOKEN * argPtrs[128]; // 128 arguments ought to be enough for anyone
+LONG curuniq; // Current macro's unique number
+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 VALUE argno; // Formal argument count
+static LONG macuniq; // Unique-per-macro number
+static SYM * curmac; // Macro currently being defined
+static VALUE argno; // Formal argument count
-static LONG * firstrpt; // First .rept line
-static LONG * nextrpt; // Last .rept line
-static int rptlevel; // .rept nesting level
+static LLIST * firstrpt; // First .rept line
+static LLIST * nextrpt; // Last .rept line
+static int rptlevel; // .rept nesting level
+
+// Function prototypes
+static int KWMatch(char *, char *);
+static int LNCatch(int (*)(), char *);
//
-// Initialize Macro Processor
+// Initialize macro processor
//
void InitMacro(void)
{
macuniq = 0;
macnum = 1;
-// argp = NULL;
argp = 0;
}
//
-// Exit from a Macro;
+// Exit from a macro;
// -- pop any intervening include files and repeat blocks;
// -- restore argument stack;
// -- pop the macro.
//
int ExitMacro(void)
{
-#warning !!! Bad macro exiting !!!
+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
// /*TOKEN ** p = */argp--;
// argp = (TOKEN **)*argp;
- DEBUG printf("ExitMacro: argp: %d -> ", argp);
+ DEBUG { printf("ExitMacro: argp: %d -> ", argp); }
argp -= imacro->im_nargs;
- DEBUG printf("%d (nargs = %d)\n", argp, imacro->im_nargs);
+ DEBUG { printf("%d (nargs = %d)\n", argp, imacro->im_nargs); }
- fpop();
- 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 = NewSymbol(argname, MACARG, (int)curmac->sattr);
+ SYM * arg = NewSymbol(argname, MACARG, (int)curmac->sattr);
arg->svalue = argno++;
return OK;
//
int defmac1(char * ln, int notEndFlag)
{
- PTR p;
- LONG len;
-
if (list_flag)
{
listeol(); // Flush previous source line
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.
+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.
+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)
{
*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 = malloc(sizeof(LLIST));
curmac->lineList->next = NULL;
curmac->lineList->line = strdup(ln);
curmac->last = curmac->lineList;
}
else
{
- curmac->last->next = malloc(sizeof(struct LineList));
+ curmac->last->next = malloc(sizeof(LLIST));
curmac->last->next->next = NULL;
curmac->last->next->line = strdup(ln);
curmac->last = curmac->last->next;
// Helper functions:
// -----------------
// `defmac1' adds lines of text to the macro definition
-// `defmac2' processes the formal arguments (and sticks them into the symbol table)
+// `defmac2' processes the formal arguments (and sticks them into the symbol
+// table)
//
int DefineMacro(void)
{
// by itself to terminate the definition.
// curmln = NULL;
curmac->lineList = NULL;
- lncatch(defmac1, "endm ");
+ LNCatch(defmac1, "endm ");
return 0;
}
//
// Add lines to a .rept definition
//
-int defr1(char * ln, int kwno)
+int defr1(char * line, int kwno)
{
- LONG len;
- LONG * p;
-
if (list_flag)
{
- listeol(); // Flush previous source line
- lstout('#'); // Mark this a 'rept' block
+ listeol(); // Flush previous source line
+ lstout('#'); // Mark this a 'rept' block
}
- switch (kwno)
+ if (kwno == 0) // .endr
{
- case 0: // .endr
if (--rptlevel == 0)
- return(0);
- goto addln;
- case 1: // .rept
+ return 0;
+ }
+ else if (kwno == 1) // .rept
rptlevel++;
- default:
-//MORE stupidity here...
-#warning "!!! Casting (char *) as LONG !!!"
- addln:
- // Allocate length of line + 1('\0') + LONG
- len = strlen(ln) + 1 + sizeof(LONG);
-// p = (LONG *)amem(len);
- p = (LONG *)malloc(len);
- *p = 0;
-
- strcpy((char *)(p + 1), ln);
-
- if (nextrpt == NULL)
- {
- firstrpt = p; // First line of rept statement
- }
- else
- {
- *nextrpt = (LONG)p;
- }
- nextrpt = p;
+//DEBUG { printf(" defr1: line=\"%s\", kwno=%d, rptlevel=%d\n", line, kwno, rptlevel); }
- return rptlevel;
+#if 0
+//MORE stupidity here...
+WARNING("!!! Casting (char *) as LONG !!!")
+ // Allocate length of line + 1('\0') + LONG
+ LONG * p = (LONG *)malloc(strlen(line) + 1 + sizeof(LONG));
+ *p = 0;
+ strcpy((char *)(p + 1), line);
+
+ if (nextrpt == NULL)
+ firstrpt = p; // First line of rept statement
+ else
+ *nextrpt = (LONG)p;
+
+ nextrpt = p;
+#else
+ if (firstrpt == NULL)
+ {
+ firstrpt = malloc(sizeof(LLIST));
+ firstrpt->next = NULL;
+ firstrpt->line = strdup(line);
+ nextrpt = firstrpt;
}
+ else
+ {
+ nextrpt->next = malloc(sizeof(LLIST));
+ nextrpt->next->next = NULL;
+ nextrpt->next->line = strdup(line);
+ nextrpt = nextrpt->next;
+ }
+#endif
+
+ return rptlevel;
}
//
-// Define a .rept block, this gets hairy because they can be nested
+// Handle a .rept block; this gets hairy because they can be nested
//
-int defrept(void)
+int HandleRept(void)
{
- INOBJ * inobj;
- IREPT * irept;
VALUE eval;
// Evaluate repeat expression
firstrpt = NULL;
nextrpt = NULL;
rptlevel = 1;
- lncatch(defr1, "endr rept ");
+ LNCatch(defr1, "endr rept ");
+//DEBUG { printf("HandleRept: firstrpt=$%X\n", firstrpt); }
// Alloc and init input object
if (firstrpt)
{
- inobj = a_inobj(SRC_IREPT); // Create a new REPT input object
- irept = inobj->inobj.irept;
+ INOBJ * inobj = a_inobj(SRC_IREPT); // Create a new REPT input object
+ IREPT * irept = inobj->inobj.irept;
irept->ir_firstln = firstrpt;
irept->ir_nextln = NULL;
irept->ir_count = eval;
//
-// Hand off lines of text to the function `lnfunc' until a line containing one
-// of the directives in `dirlist' is encountered. Return the number of the
-// keyword encountered (0..n)
-//
-// `dirlist' contains null-seperated terminated keywords. A final null
-// terminates the list. Directives are compared to the keywords without regard
-// to case.
-//
-// If `lnfunc' is NULL, then lines are simply skipped.
-// If `lnfunc' returns an error, processing is stopped.
-//
-// `lnfunc' is called with an argument of -1 for every line but the last one,
+// Hand off lines of text to the function 'lnfunc' until a line containing one
+// of the directives in 'dirlist' is encountered.
+//
+// 'dirlist' contains space-separated terminated keywords. A final space
+// terminates the list. Directives are case-insensitively compared to the
+// keywords.
+//
+// If 'lnfunc' is NULL, then lines are simply skipped.
+// If 'lnfunc' returns an error, processing is stopped.
+//
+// 'lnfunc' is called with an argument of -1 for every line but the last one,
// when it is called with an argument of the keyword number that caused the
// match.
//
-int lncatch(int (* lnfunc)(), char * dirlist)
+static int LNCatch(int (* lnfunc)(), char * dirlist)
{
- char * p;
- int k;
-
if (lnfunc != NULL)
- lnsave++; // Tell tokenizer to keep lines
+ lnsave++; // Tell tokenizer to keep lines
- for(;;)
+ while (1)
{
if (TokenizeLine() == TKEOF)
{
- errors("encountered end-of-file looking for '%s'", dirlist);
+ error("encountered end-of-file looking for '%s'", dirlist);
fatal("cannot continue");
}
// Test for end condition. Two cases to handle:
// <directive>
// symbol: <directive>
- p = NULL;
- k = -1;
+ char * p = NULL;
+ int k = -1;
if (*tok == SYMBOL)
{
+ // A string followed by a colon or double colon is a symbol and
+ // *not* a directive, see if we can find the directive after it
if ((tok[2] == ':' || tok[2] == DCOLON))
{
- if (tok[3] == SYMBOL) // label: symbol
+ if (tok[3] == SYMBOL)
p = string[tok[4]];
}
else
{
- p = string[tok[1]]; // Symbol
+ // Otherwise, just grab the directive
+ p = string[tok[1]];
}
}
if (p != NULL)
{
- if (*p == '.') // ignore leading '.'s
+ if (*p == '.') // Ignore leading periods
p++;
- k = kwmatch(p, dirlist);
+ k = KWMatch(p, dirlist);
}
// Hand-off line to function
if (lnfunc != NULL)
k = (*lnfunc)(lnbuf, k);
- if (!k)
+ if (k == 0)
break;
}
if (lnfunc != NULL)
- lnsave--; // Tell tokenizer to stop keeping lines
+ lnsave--; // Tell tokenizer to stop keeping lines
return 0;
}
//
-// See if the string `kw' matches one of the keywords in `kwlist'. If so,
-// return the number of the keyword matched. Return -1 if there was no match.
+// See if the string `kw' matches one of the keywords in `kwlist'. If so,
+// return the number of the keyword matched. Return -1 if there was no match.
// Strings are compared without regard for case.
//
-int kwmatch(char * kw, char * kwlist)
+static int KWMatch(char * kw, char * kwlist)
{
- char * p;
- char c1;
- char c2;
- int k;
-
- for(k=0; *kwlist; ++k)
+ for(int k=0; *kwlist; k++)
{
- for(p=kw;;)
+ for(char * p=kw;;)
{
- c1 = *kwlist++;
- c2 = *p++;
+ char c1 = *kwlist++;
+ char c2 = *p++;
if (c2 >= 'A' && c2 <= 'Z')
c2 += 32;
}
// Skip to beginning of next keyword in `kwlist'
- while (*kwlist && *kwlist != ' ')
+ while (*kwlist && (*kwlist != ' '))
++kwlist;
if (*kwlist== ' ')
//
// Invoke a macro
-// o parse, count and copy arguments
-// o push macro's string-stream
+// o parse, count and copy arguments
+// o push macro's string-stream
//
int InvokeMacro(SYM * mac, WORD siz)
{
// argp = 0;
DEBUG printf("InvokeMacro: argp: %d -> ", argp);
- INOBJ * inobj = a_inobj(SRC_IMACRO); // Alloc and init IMACRO
+ INOBJ * inobj = a_inobj(SRC_IMACRO); // Alloc and init IMACRO
IMACRO * imacro = inobj->inobj.imacro;
imacro->im_siz = siz;
WORD nargs = 0;
TOKEN * dest;
int stringNum = 0;
int argumentNum = 0;
- int i;
for(dry_run=1; ; dry_run--)
{
nargs++;
else
{
-#if 0
+#if 0
*argptr++ = p;
#else
argPtrs[argp++] = p;
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.
+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.]
+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));
// argp += nargs;
#endif
}
- else
+ else
break;
}
- DEBUG printf("%d\n", argp);
+ DEBUG { printf("%d\n", argp); }
// Setup imacro:
- // 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;
+ // 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 = mac->lineList;
imacro->im_olduniq = curuniq;
curuniq = macuniq++;
- imacro->argBase = argp - nargs; // Shamus: keep track of argument base
+ imacro->argBase = argp - nargs; // Shamus: keep track of argument base
DEBUG
{
for(nargs=0; nargs<imacro->im_nargs; nargs++)
{
printf("arg%d=", nargs);
-// dumptok(argp[imacro->im_nargs - nargs - 1]);
-// dumptok(argPtrs[imacro->im_nargs - nargs - 1]);
dumptok(argPtrs[(argp - imacro->im_nargs) + nargs]);
}
}