2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // MACRO.C - Macro Definition and Invocation
4 // Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
19 LONG curuniq; // Current macro's unique number
20 TOKEN ** argp; // Free spot in argptrs[]
21 int macnum; // Unique number for macro definition
23 static LONG macuniq; // Unique-per-macro number
24 static SYM * curmac; // Macro currently being defined
25 static char ** curmln; // Previous macro line (or NULL)
26 static VALUE argno; // Formal argument count
28 static LONG * firstrpt; // First .rept line
29 static LONG * nextrpt; // Last .rept line
30 static int rptlevel; // .rept nesting level
34 // Initialize Macro Processor
47 // o pop any intervening include files and repeat blocks;
48 // o restore argument stack;
56 // Pop intervening include files and .rept blocks
57 while (cur_inobj != NULL && cur_inobj->in_type != SRC_IMACRO)
60 if (cur_inobj == NULL)
61 fatal("too many ENDMs");
65 // o old unique number
66 // ...and then pop the macro.
68 imacro = cur_inobj->inobj.imacro;
69 curuniq = imacro->im_olduniq;
72 argp = (TOKEN **)*argp;
83 // Add a Formal Argument to a Macro Definition
85 int defmac2(char * argname)
89 if (lookup(argname, MACARG, (int)curmac->sattr) != NULL)
90 return(error("multiple formal argument definition"));
91 arg = newsym(argname, MACARG, (int)curmac->sattr);
92 arg->svalue = argno++;
99 // Add a line to a macro definition; also print lines to listing file (if
100 // enabled). The last line of the macro (containing .endm) is not included in
101 // the macro. A label on that line will be lost. `endflg' is misleading here.
102 // It is -1 for all lines but the last one (.endm), when it is 0.
104 int defmac1(char * ln, int endflg)
111 listeol(); // Flush previous source line
112 lstout('.'); // Mark macro definition with period
117 len = strlen(ln) + 1 + sizeof(LONG);
121 strcpy(p.cp + sizeof(LONG), ln);
123 // Link line of text onto end of list
125 curmac->svalue = (VALUE)p.cp;
129 curmln = (char **)p.cp;
130 return 1; // Keep looking
133 return 0; // Stop looking at the end
140 // macro foo arg1,arg2,...
147 // `defmac1' adds lines of text to the macro definition
148 // `defmac2' processes the formal arguments (and sticks them into the symbol table)
155 // Setup entry in symbol table, make sure the macro isn't a duplicate entry, and that
156 // it doesn't override any processor mnemonic or assembler directive.
157 if (*tok++ != SYMBOL)
158 return error("missing symbol");
162 if (lookup(p, MACRO, 0) != NULL)
163 return error("multiple macro definition");
165 curmac = mac = newsym(p, MACRO, 0);
167 mac->sattr = (WORD)(macnum++);
169 // Parse and define formal arguments in symbol table
177 // Suck in the macro definition; we're looking for an ENDM symbol on a line
178 // by itself to terminate the definition.
180 lncatch(defmac1, "endm ");
187 // Add lines to a .rept definition
189 int defr1(char * ln, int kwno)
196 listeol(); // Flush previous source line
197 lstout('#'); // Mark this a 'rept' block
210 // Allocate length of line + 1('\0') + LONG
211 len = strlen(ln) + 1 + sizeof(LONG);
212 // p = (LONG *)amem(len);
213 p = (LONG *)malloc(len);
216 strcpy((char *)(p + 1), ln);
220 firstrpt = p; // First line of rept statement
235 // Define a .rept block, this gets hairy because they can be nested
243 // Evaluate repeat expression
244 if (abs_expr(&eval) != OK)
247 // Suck in lines for .rept block
251 lncatch(defr1, "endr rept ");
253 // Alloc and init input object
256 inobj = a_inobj(SRC_IREPT); // Create a new REPT input object
257 irept = inobj->inobj.irept;
258 irept->ir_firstln = firstrpt;
259 irept->ir_nextln = NULL;
260 irept->ir_count = eval;
268 // Hand off lines of text to the function `lnfunc' until a line containing one
269 // of the directives in `dirlist' is encountered. Return the number of the
270 // keyword encountered (0..n)
272 // `dirlist' contains null-seperated terminated keywords. A final null
273 // terminates the list. Directives are compared to the keywords without regard
276 // If `lnfunc' is NULL, then lines are simply skipped.
277 // If `lnfunc' returns an error, processing is stopped.
279 // `lnfunc' is called with an argument of -1 for every line but the last one,
280 // when it is called with an argument of the keyword number that caused the
283 int lncatch(int (* lnfunc)(), char * dirlist)
289 ++lnsave; // Tell tokenizer to keep lines
293 if (tokln() == TKEOF)
295 errors("encountered end-of-file looking for '%s'", dirlist);
296 fatal("cannot continue");
299 // Test for end condition. Two cases to handle:
301 // symbol: <directive>
307 if ((tok[2] == ':' || tok[2] == DCOLON))
309 if (tok[3] == SYMBOL) // label: symbol
314 p = (char *)tok[1]; // symbol
320 if (*p == '.') // ignore leading '.'s
323 k = kwmatch(p, dirlist);
326 // Hand-off line to function
327 // if it returns 0, and we found a keyword, stop looking.
328 // if it returns 1, hand off the line and keep looking.
330 k = (*lnfunc)(lnbuf, k);
337 --lnsave; // Tell tokenizer to stop keeping lines
344 // See if the string `kw' matches one of the keywords in `kwlist'. If so,
345 // return the number of the keyword matched. Return -1 if there was no match.
346 // Strings are compared without regard for case.
348 int kwmatch(char * kw, char * kwlist)
355 for(k=0; *kwlist; ++k)
362 if (c2 >= 'A' && c2 <= 'Z')
365 if (c1 == ' ' && c2 == EOS)
372 // Skip to beginning of next keyword in `kwlist'
373 while (*kwlist && *kwlist != ' ')
386 // o parse, count and copy arguments
387 // o push macro's string-stream
389 int invokemac(SYM * mac, WORD siz)
397 TOKEN ** argptr = NULL;
400 if ((!strcmp(mac->sname, "mjump") || !strcmp(mac->sname, "mpad")) && !in_main)
402 error("macro cannot be used outside of .gpumain");
406 inobj = a_inobj(SRC_IMACRO); // Alloc and init IMACRO
407 imacro = inobj->inobj.imacro;
408 imacro->im_siz = siz;
410 beg_tok = tok; // 'tok' comes from token.c
412 for(dry_run=1;; --dry_run)
414 for(tok=beg_tok; *tok!=EOL;)
421 // Keep going while tok isn't pointing at a comma or EOL
422 while (*tok != ',' && *tok != EOL)
424 // Skip over backslash character, unless it's followed by an EOL
425 if (*tok == '\\' && tok[1] != EOL)
435 arg_siz += sizeof(TOKEN);
440 // FALLTHROUGH (picks up the arg after a CONST, SYMBOL or ACONST)
444 arg_siz += sizeof(TOKEN);
454 // We hit the comma or EOL, so count/stuff it
456 arg_siz += sizeof(TOKEN);
460 // If we hit the comma instead of an EOL, skip over it
465 // Allocate space for argument ptrs and so on and then go back and
466 // construct the arg frame
470 //Barfing here with memory corruption in glibc. TOKEN is defined as LONG, which is uint32_t
471 // p = (TOKEN *)malloc(arg_siz + 1);
472 p = (TOKEN *)malloc(arg_siz + sizeof(TOKEN));
474 argptr = (TOKEN **)malloc((nargs + 1) * sizeof(LONG));
475 *argptr++ = (TOKEN *)argp;
484 // o -> macro symbol;
485 // o -> macro definition string list;
486 // o save 'curuniq', to be restored when the macro pops;
487 // o bump `macuniq' counter and set 'curuniq' to it;
488 imacro->im_nargs = nargs;
489 imacro->im_macro = mac;
490 imacro->im_nextln = (TOKEN *)mac->svalue;
491 imacro->im_olduniq = curuniq;
494 IMACRO * im_link; // Pointer to ancient IMACROs
495 LONG * im_nextln; // Next line to include
496 WORD im_nargs; // # of arguments supplied on invocation
497 WORD im_siz; // Size suffix supplied on invocation
498 LONG im_olduniq; // Old value of 'macuniq'
499 SYM * im_macro; // Pointer to macro we're in
500 char im_lnbuf[LNSIZ]; // Line buffer
505 printf("nargs=%d\n", nargs);
507 for(nargs=0; nargs<imacro->im_nargs; ++nargs)
509 printf("arg%d=", nargs);
510 dumptok(argp[imacro->im_nargs - nargs - 1]);
519 // Setup inbuilt macros
525 curmac = mac = newsym("mjump", MACRO, 0);
527 mac->sattr = (WORD)(macnum++);
534 defmac1(" movei #\\addr,\\jreg", -1);
535 defmac1(" jump \\cc,(\\jreg)", -1);
539 curmac = mac = newsym("mjr", MACRO, 0);
541 mac->sattr = (WORD)(macnum++);
546 defmac1(" jr \\cc,\\addr", -1);
550 curmac = mac = newsym("mpad", MACRO, 0);
552 mac->sattr = (WORD)(macnum++);
556 defmac1(" .rept (\\size/2)", -1);
558 defmac1(" .endr", -1);