tp++;
break;
case CONST:
- printf("$%ux ", *tp++);
+ printf("$%X ", *tp++);
break;
case ACONST:
- printf("ACONST=($%ux,$%ux) ", *tp, tp[1]);
+ printf("ACONST=($%X,$%X) ", *tp, tp[1]);
tp += 2;
break;
default:
}
}
- printf(";\n");
+// printf(";\n");
return tp + 1;
}
{
while (ch != NULL)
{
- printf("chloc=$%08ux, chsize=$%ux\n", ch->chloc, ch->ch_size);
+ printf("chloc=$%08X, chsize=$%X\n", ch->chloc, ch->ch_size);
mdump(ch->chptr, ch->ch_size, format, ch->chloc);
ch = ch->chnext;
}
file = *p.wp++;
line = *p.wp++;
- printf("$%04x $%08ux %d.%d: ", (int)attr, loc, (int)file, (int)line);
+ printf("$%04X $%08X %d.%d: ", (int)attr, loc, (int)file, (int)line);
if (attr & FU_EXPR)
{
}
else
{
- printf("`%s' ;\n", (*p.sy)->sname);
+// printf("`%s' ;\n", (*p.sy)->sname);
+ printf("`%s' ;", (*p.sy)->sname);
p.sy++;
}
if ((attr & 0x0F00) == FU_JR)
+ {
+ printf(" *=$%X", *p.lp);
p.lp++;
+ }
+
+ printf("\n");
}
ch = ch->chnext;
for(mch=firstmch; mch!=NULL; mch=mch->mcnext)
{
- printf("mch=$%08ux mcptr=$%08ux mcalloc=$%ux mcused=$%x\n",
+ printf("mch=$%08X mcptr=$%08X mcalloc=$%X mcused=$%X\n",
(uint32_t)mch,
(mch->mcptr.lw),
mch->mcalloc,
if (w & MSYMBOL)
symbol = *p.sy++;
- printf("m=$%04x to=%d loc=$%ux from=%d siz=%s",
- w, w & 0x00ff, loc, from, (w & MLONG) ? "long" : "word");
+ printf("m=$%04X to=%d loc=$%X from=%d siz=%s",
+ w, w & 0x00FF, loc, from, (w & MLONG) ? "long" : "word");
if (symbol != NULL)
printf(" sym=`%s'", symbol->sname);
j = i;
if (base != -1)
- printf("%08ux ", base);
+ printf("%08X ", base);
}
switch (flg & 3)
{
case 0:
- printf("%02x ", start[i] & 0xff);
+ printf("%02X ", start[i] & 0xff);
++i;
break;
case 1:
- printf("%02x%02x ", start[i] & 0xff, start[i+1] & 0xff);
+ printf("%02X%02X ", start[i] & 0xff, start[i+1] & 0xff);
i += 2;
break;
case 2:
- printf("%02x%02x%02x%02x ", start[i] & 0xff, start[i+1] & 0xff,
+ printf("%02X%02X%02X%02X ", start[i] & 0xff, start[i+1] & 0xff,
start[i+2] & 0xff, start[i+3] & 0xff);
i += 4;
break;
if (*tk >= 128)
{
- printf("REG=%ud", *tk++ - 128);
+ printf("REG=%u", *tk++ - 128);
continue;
}
switch ((int)*tk++)
{
case CONST: // CONST <value>
- printf("CONST=%ud", *tk++);
+ printf("CONST=%u", *tk++);
break;
case STRING: // STRING <address>
-// printf("STRING='%s'", (char *)*tk++);
printf("STRING='%s'", string[*tk++]);
break;
case SYMBOL: // SYMBOL <address>
-// printf("SYMBOL='%s'", (char *)*tk++);
printf("SYMBOL='%s'", string[*tk++]);
break;
case EOL: // End of line
{
if (sect[i].scattr & SUSED)
{
- printf("Section %d sloc=$%ux\n", i, sect[i].sloc);
+ printf("Section %d sloc=$%X\n", i, sect[i].sloc);
printf("Code:\n");
chdump(sect[i].sfcode, 1);
}
printf("\nMarks:\n");
- mudump(); // Dump marks
- printf("Total memory allocated=$%ux\n", amemtot);
+ mudump(); // Dump marks
+ printf("Total memory allocated=$%X\n", amemtot);
return 0;
}
d_include, // 33 include
fpop, // 34 end
d_unimpl, // 35* macro
- exitmac, // 36* exitm
+ ExitMacro, // 36* exitm
d_unimpl, // 37* endm
d_list, // 38 list
d_nlist, // 39 nlist
int d_if(void);
int d_endif(void);
int d_include(void);
-int exitmac(void);
+int ExitMacro(void);
int d_list(void);
int d_nlist(void);
int d_title(void);
{
VALUE v;
- for(v=0; *p; ++p)
+ for(v=0; *p; p++)
v = (v << 8) | (*p & 0xFF);
return v;
char * p; // Token pointer
// Initialize token-class table
- for(i=0; i<128; ++i) // Mark all entries END
+ for(i=0; i<128; i++) // Mark all entries END
tokcl[i] = END;
for(i=0, p=itokcl; *p!=1; p++)
#else
p = string[*tok++];
#endif
-
-#if 0
- if (lookup(p, MACRO, 0) == NULL)
- w = 0;
- else
- w = 1;
-#else
w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
-#endif
-
*tk++ = CONST;
*tk++ = (TOKEN)w;
break;
if (*p == '.')
j = curenv;
-#if 0
- if ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w))
- w = 1;
- else
- w = 0;
-#else
w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
-#endif
-
*tk++ = CONST;
*tk++ = (TOKEN)w;
break;
#include "symbol.h"
#include "token.h"
+
+static void SetupDefaultMacros(void);
+
LONG curuniq; // Current macro's unique number
//TOKEN ** argp; // Free spot in argptrs[]
int macnum; // Unique number for macro definition
//
// Initialize Macro Processor
//
-void init_macro(void)
+void InitMacro(void)
{
macuniq = 0;
macnum = 1;
// argp = NULL;
argp = 0;
- ib_macro();
+ SetupDefaultMacros();
}
// -- restore argument stack;
// -- pop the macro.
//
-int exitmac(void)
+int ExitMacro(void)
{
+#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();
IMACRO * imacro = cur_inobj->inobj.imacro;
curuniq = imacro->im_olduniq;
- /*TOKEN ** p = */argp--;
+// /*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);
fpop();
mjump_align = 0;
int dry_run;
WORD arg_siz = 0;
// TOKEN ** argptr = NULL;
-//Doesn't need to be global! (or does it???)
- argp = 0;
+//Doesn't need to be global! (or does it???--it does)
+// argp = 0;
+ DEBUG printf("InvokeMacro: argp: %d -> ", argp);
if ((!strcmp(mac->sname, "mjump") || !strcmp(mac->sname, "mpad")) && !in_main)
{
imacro->im_siz = siz;
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--)
{
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);
// p = (TOKEN *)malloc(arg_siz + sizeof(TOKEN));
-// 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.
+/*
+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;
imacro->im_nextln = mac->lineList;
imacro->im_olduniq = curuniq;
curuniq = macuniq++;
+ 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(argPtrs[imacro->im_nargs - nargs - 1]);
+// dumptok(argPtrs[imacro->im_nargs - nargs - 1]);
+ dumptok(argPtrs[(argp - imacro->im_nargs) + nargs]);
}
}
//
-// Setup inbuilt macros
+// Setup inbuilt macros (SubQMod)
//
-void ib_macro(void)
+static void SetupDefaultMacros(void)
{
curmac = NewSymbol("mjump", MACRO, 0);
curmac->svalue = 0;
extern TOKEN * argPtrs[];
// Prototypes
-void init_macro(void);
-int exitmac(void);
+void InitMacro(void);
+int ExitMacro(void);
int DefineMacro(void);
int defrept(void);
int lncatch(int (*)(), char *);
int kwmatch(char *, char *);
int InvokeMacro(SYM *, WORD);
-void ib_macro(void);
#endif // __MACRO_H__
//
// Line Processor
//
-void assemble(void)
+void Assemble(void)
{
int state; // Keyword machine state (output)
int j; // Random int, must be fast
if (label != NULL)
warn(lab_ignored);
- exitmac();
+ ExitMacro();
}
goto loop;
if (label != NULL)
{
do_label:
+ // Check for dot in front of label; means this is a local label if present
+#if 0
j = 0;
if (*label == '.')
j = curenv;
+#else
+ j = (*label == '.' ? curenv : 0);
+#endif
sy = lookup(label, LABEL, j);
lab_sym = sy;
if (!j)
- ++curenv;
+ curenv++;
// Make label global
if (labtyp == DCOLON)
// Prototypes
void init_procln(void);
-void assemble(void);
+void Assemble(void);
int eject(void);
int d_if(void);
int d_else(void);
init_expr(); // Expression analyzer
init_sect(); // Section manager / code generator
init_mark(); // Mark tape-recorder
- init_macro(); // Macro processor
+ InitMacro(); // Macro processor
init_list(); // Listing generator
// Process command line arguments and assemble source files
break;
default:
printf("-f: unknown object format specified\n");
- ++errcnt;
+ errcnt++;
return errcnt;
}
break;
list_fname = argv[argno] + 2;
listing = 1;
list_flag = 1;
- ++lnsave;
+ lnsave++;
break;
case 'o': // Direct object file output
case 'O':
if (++argno >= argc)
{
printf("Missing argument to -o");
- ++errcnt;
+ errcnt++;
return errcnt;
}
objfname = argv[argno];
firstfname = defname;
include(0, "(stdin)");
- assemble();
+ Assemble();
break;
case 'h': // Display command line usage
case 'H':
case '?':
display_version();
display_help();
- ++errcnt;
+ errcnt++;
break;
default:
display_version();
printf("Unknown switch: %s\n\n", argv[argno]);
display_help();
- ++errcnt;
+ errcnt++;
break;
}
}
if (fd < 0)
{
printf("Cannot open: %s\n", fnbuf);
- ++errcnt;
+ errcnt++;
continue;
}
include(fd, fnbuf);
- assemble();
+ Assemble();
}
}
//
void mksect(int sno, WORD attr)
{
- SECT * p; // Section pointer
-
- p = §[sno];
+ SECT * p = §[sno];
p->scattr = attr;
p->sloc = 0;
p->scode = p->sfcode = NULL;
{
SECT * p = §[cursect];
- p->scattr = scattr; // Bailout section vars
+ p->scattr = scattr; // Bailout section vars
p->sloc = sloc;
- if (scode != NULL) // Bailout code chunk
+ if (scode != NULL) // Bailout code chunk
scode->ch_size = ch_size;
- if (sfix != NULL) // Bailout fixup chunk
+ if (sfix != NULL) // Bailout fixup chunk
sfix->ch_size = fchsize;
}
static SYM * sordtail; // * -> Last symbol in sorder list
static SYM * sdecl; // * -> Symbols, in order of declaration
static SYM * sdecltail; // * -> Last symbol in sdecl list
+static uint32_t currentUID; // Symbol UID tracking (done by NewSymbol())
// Tags for marking symbol spaces
// a = absolute
sordtail = NULL;
sdecl = NULL; // Init symbol-decl list
sdecltail = NULL;
+ currentUID = 0;
}
if (symbol == NULL)
{
- printf("SYMALLOC ERROR (%s)\n", name);
+ printf("NewSymbol: MALLOC ERROR (symbol=\"%s\")\n", name);
return NULL;
}
- symbol->sname = strdup(name);
-
// Fill-in the symbol
+ symbol->sname = strdup(name);
symbol->stype = (BYTE)type;
symbol->senv = (WORD)envno;
symbol->sattr = 0;
symbol->sattre = (rgpu || rdsp ? RISCSYM : 0);
symbol->svalue = 0;
+ symbol->sorder = NULL;
+ symbol->uid = currentUID++;
// Install symbol in symbol table
int hash = HashSymbol(name, envno);
else
sordtail->sorder = symbol; // Or append to tail of list
- symbol->sorder = NULL;
sordtail = symbol;
-
return symbol;
}
//
-// Lookup the symbol `name', of the specified type, with the specified
-// enviroment level
+// Look up the symbol name by its UID and return the pointer to the name.
+// If it's not found, return NULL.
//
-SYM * lookup(char * name, int type, int envno)
+char * GetSymbolNameByUID(uint32_t uid)
{
-#if 0
- SYM * sy; // Symbol record pointer
- int k, sum; // Hash bucket calculation
- char * s; // String pointer
+ //problem is with string lookup, that's why we're writing this
+ //so once this is written, we can put the uid in the token stream
- // Pick a hash-bucket (SAME algorithm as HashSymbol())
- k = 0;
- s = name;
+ // A much better approach to the symbol order list would be to make an
+ // array--that way you can do away with the UIDs and all the rest, and
+ // simply do an array lookup based on position. But meh, let's do this for
+ // now until we can rewrite things so they make sense.
+ SYM * symbol = sorder;
- for(sum=envno; *s;)
+ for(; symbol; symbol=symbol->sorder)
{
- if (k++ == 1)
- sum += *s++ << 2;
- else
- sum += *s++;
+ if (symbol->uid == uid)
+ return symbol->sname;
}
- sy = symbolTable[sum & (NBUCKETS-1)];
-#else
+ return NULL;
+}
+
+
+//
+// Lookup the symbol `name', of the specified type, with the specified
+// enviroment level
+//
+SYM * lookup(char * name, int type, int envno)
+{
SYM * symbol = symbolTable[HashSymbol(name, envno)];
-#endif
// Do linear-search for symbol in bucket
while (symbol != NULL)
&& *name == *symbol->sname // Fast check for first character
&& !strcmp(name, symbol->sname))
break;
- else
- symbol = symbol->snext;
+
+ symbol = symbol->snext;
}
return symbol; // Return NULL or matching symbol
//
// Put symbol on "order-of-declaration" list of symbols
//
-void sym_decl(SYM * sym)
+void sym_decl(SYM * symbol)
{
- if (sym->sattr & SDECLLIST)
+ if (symbol->sattr & SDECLLIST)
return; // Already on list
- sym->sattr |= SDECLLIST; // Mark "already on list"
+ symbol->sattr |= SDECLLIST; // Mark "already on list"
if (sdecl == NULL)
- sdecl = sym; // First on decl-list
+ sdecl = symbol; // First on decl-list
else
- sdecltail->sdecl = sym; // Add to end of list
+ sdecltail->sdecl = symbol; // Add to end of list
- sym->sdecl = NULL; // Fix up list's tail
- sdecltail = sym;
+ symbol->sdecl = NULL; // Fix up list's tail
+ sdecltail = symbol;
}
strcpy(ln2, "external");
else
{
- sprintf(ln2, "%08ux", q->svalue);
+ sprintf(ln2, "%08X", q->svalue);
uc_string(ln2);
}
char * sname; // * -> Symbol's print-name
struct LineList * lineList; // * -> Macro's linked list of lines
struct LineList * last; // * -> end of macro linked list
+ uint32_t uid; // Symbol's unique ID
};
// Globals, externals etc
int syg_fix(void);
int symtable(void);
int sy_assign(char *, char *(*)());
+char * GetSymbolNameByUID(uint32_t);
#endif // __SYMBOL_H__
TOKEN * tok; // Ptr to current token
TOKEN * etok; // Ptr past last token in tokbuf[]
TOKEN tokeol[1] = {EOL}; // Bailout end-of-line token
-char * string[TOKBUFSIZE]; // Token buffer string pointer storage
+char * string[TOKBUFSIZE*2]; // Token buffer string pointer storage
// File record, used to maintain a list of every include file ever visited
#define FILEREC struct _filerec
// Allocate and initialize INOBJ first
if (f_inobj == NULL)
-// inobj = (INOBJ *)amem((LONG)sizeof(INOBJ));
- inobj = (INOBJ *)malloc(sizeof(INOBJ));
+ inobj = malloc(sizeof(INOBJ));
else
{
inobj = f_inobj;
{
case SRC_IFILE: // Alloc and init an IFILE
if (f_ifile == NULL)
-// ifile = (IFILE *)amem((LONG)sizeof(IFILE));
- ifile = (IFILE *)malloc(sizeof(IFILE));
+ ifile = malloc(sizeof(IFILE));
else
{
ifile = f_ifile;
break;
case SRC_IMACRO: // Alloc and init an IMACRO
if (f_imacro == NULL)
-// imacro = (IMACRO *)amem((LONG)sizeof(IMACRO));
- imacro = (IMACRO *)malloc(sizeof(IMACRO));
+ imacro = malloc(sizeof(IMACRO));
else
{
imacro = f_imacro;
inobj->inobj.imacro = imacro;
break;
case SRC_IREPT: // Alloc and init an IREPT
-// inobj->inobj.irept = (IREPT *)amem((LONG)sizeof(IREPT));
- inobj->inobj.irept = (IREPT *)malloc(sizeof(IREPT));
+ inobj->inobj.irept = malloc(sizeof(IREPT));
DEBUG printf("alloc IREPT\n");
break;
}
char numbuf[20]; // Buffer for text of CONSTs
TOKEN * tk;
SYM * arg;
+ char ** symbolString;
- DEBUG { printf("EM: src=\"%s\"\n", src); }
+ DEBUG { printf("ExM: src=\"%s\"\n", src); }
IMACRO * imacro = cur_inobj->inobj.imacro;
int macnum = (int)(imacro->im_macro->sattr);
goto copy_d;
case '~': // ==> unique label string Mnnnn...
- sprintf(numbuf, "M%ud", curuniq);
+ sprintf(numbuf, "M%u", curuniq);
copystr:
d = numbuf;
copy_d:
// macro invocation) then it is ignored.
i = (int)arg->svalue;
arg_num:
- DEBUG printf("~argnumber=%d\n", i);
-
+ DEBUG printf("~argnumber=%d (argBase=%u)\n", i, imacro->argBase);
tk = NULL;
if (i < imacro->im_nargs)
+ {
+#if 0
// tk = argp[i];
- tk = argPtrs[i];
+// tk = argPtrs[i];
+ tk = argPtrs[imacro->argBase + i];
+#else
+ tk = imacro->argument[i].token;
+ symbolString = imacro->argument[i].string;
+//DEBUG
+//{
+// printf("ExM: Preparing to parse argument #%u...\n", i);
+// dumptok(tk);
+//}
+#endif
+ }
// \?arg yields:
// 0 if the argument is empty or non-existant,
switch ((int)*tk++)
{
case SYMBOL:
+#if 0
// d = (char *)*tk++;
d = string[*tk++];
+#else
+ // This fix should be done for strings too
+ d = symbolString[*tk++];
+DEBUG printf("ExM: SYMBOL=\"%s\"", d);
+#endif
break;
case STRING:
+#if 0
// d = (char *)*tk++;
d = string[*tk++];
-
+#else
+ d = symbolString[*tk++];
+#endif
if (dst >= edst)
goto overflow;
}
*dst = EOS;
+ DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
return OK;
overflow:
*dst = EOS;
+ DEBUG printf("*** OVERFLOW LINE ***\n%s\n", dest);
return fatal("line too long as a result of macro expansion");
}
case SRC_IMACRO:
if ((ln = getmln()) == NULL)
{
- exitmac(); // Exit macro (pop args, do fpop(), etc)
+ ExitMacro(); // Exit macro (pop args, do fpop(), etc)
goto retry; // Try for more lines...
}
if (j < 0 || state < 0)
{
*tk++ = SYMBOL;
-#warning
+//#warning
//problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit system,
//this will cause all kinds of mischief.
#if 0
case '\"': // "string"
c1 = ln[-1];
*tk++ = STRING;
-#warning
+//#warning
// More char * stuffing (8 bytes) into the space of 4 (TOKEN).
// Need to figure out how to fix this crap.
#if 0
void DumpTokenBuffer(void)
{
TOKEN * t;
- printf("Tokens: ");
+ printf("Tokens [%X]: ", sloc);
for(t=tokbuf; *t!=EOL; t++)
{
char ifbuf[LNBUFSIZ]; // Line buffer
};
+#define TOKENSTREAM struct _tokenstream
+TOKENSTREAM {
+ TOKEN token[10]; // 10 ought to be enough for anybody
+ char * string[10]; // same for attached strings
+};
+
// Information about a macro invocation
IMACRO {
IMACRO * im_link; // Pointer to ancient IMACROs
LONG im_olduniq; // Old value of 'macuniq'
SYM * im_macro; // Pointer to macro we're in
char im_lnbuf[LNSIZ]; // Line buffer
+ uint32_t argBase; // Base in argPtrs[] for current macro
+ TOKENSTREAM argument[20]; // Assume no more than 20 arguments in an invocation
};
// Information about a .rept invocation