-
-int invokemac(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);
- }
-
- inobj = a_inobj(SRC_IMACRO); // Alloc and init IMACRO
- imacro = inobj->inobj.imacro;
- imacro->im_siz = siz;
- nargs = 0;
- beg_tok = tok;
-
- for(dry_run = 1;; --dry_run) {
- for(tok = beg_tok; *tok != EOL;) {
- if(dry_run) ++nargs;
- else *argptr++ = p;
-
- while(*tok != ',' && *tok != EOL) {
- if(*tok == '\\' && tok[1] != EOL) ++tok;
- switch((int)*tok) {
- case CONST:
- case SYMBOL:
- case ACONST:
- if(dry_run) arg_siz += sizeof(TOKEN), ++tok;
- else *p++ = *tok++;
- // FALLTHROUGH
- default:
- if(dry_run) arg_siz += sizeof(TOKEN), ++tok;
- else *p++ = *tok++;
- break;
- }
- }
-
- if(dry_run) arg_siz += sizeof(TOKEN);
- else *p++ = EOL;
-
- if(*tok == ',') ++tok;
- }
-
- // Allocate space for argument ptrs and so on and then go back and construct the arg frame
- if(dry_run) {
- if(nargs != 0) p = (TOKEN *)malloc((LONG)(arg_siz + 1));
- argptr = (TOKEN **)malloc((LONG)((nargs + 1) * sizeof(LONG)));
- *argptr++ = (TOKEN *)argp;
- argp = argptr;
- } else
- break;
- }
-
-
- // 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;
- imacro->im_nargs = nargs;
- imacro->im_macro = mac;
- imacro->im_nextln = (LONG *)mac->svalue;
- imacro->im_olduniq = curuniq;
- curuniq = ++macuniq;
-
- DEBUG {
- printf("nargs=%d\n", nargs);
- for(nargs = 0; nargs < imacro->im_nargs; ++nargs) {
- printf("arg%d=", nargs);
- dumptok(argp[imacro->im_nargs - nargs - 1]);
- }
- }
-
- return(OK);
+int InvokeMacro(SYM * mac, WORD siz)
+{
+ TOKEN * p = NULL;
+ int dry_run;
+ WORD arg_siz = 0;
+// TOKEN ** argptr = NULL;
+//Doesn't need to be global! (or does it???--it does)
+// argp = 0;
+ DEBUG printf("InvokeMacro: argp: %d -> ", argp);
+
+ INOBJ * inobj = a_inobj(SRC_IMACRO); // Alloc and init IMACRO
+ IMACRO * imacro = inobj->inobj.imacro;
+ 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;
+
+ 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)
+ {
+ // Skip over backslash character, unless it's followed by an EOL
+ if (*tok == '\\' && tok[1] != EOL)
+ tok++;
+
+ switch (*tok)
+ {
+ case CONST:
+ case SYMBOL:
+//Shamus: Possible bug. ACONST has 2 tokens after it, not just 1
+ case ACONST:
+ if (dry_run)
+ {
+ arg_siz += sizeof(TOKEN);
+ tok++;
+ }
+ else
+ {
+ *p++ = *tok++;
+ }
+ // FALLTHROUGH (picks up the arg after a CONST, SYMBOL or ACONST)
+ default:
+ if (dry_run)
+ {
+ arg_siz += sizeof(TOKEN);
+ tok++;
+ }
+ else
+ {
+ *p++ = *tok++;
+ }
+
+ break;
+ }
+ }
+
+ // We hit the comma or EOL, so count/stuff it
+ if (dry_run)
+ arg_siz += sizeof(TOKEN);
+ else
+ *p++ = EOL;
+
+ // 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
+ // construct the arg frame
+ if (dry_run)
+ {
+ if (nargs != 0)
+ 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 -> 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
+
+ DEBUG
+ {
+ printf("nargs=%d\n", 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[(argp - imacro->im_nargs) + nargs]);
+ }
+ }
+
+ return OK;