-////////////////////////////////////////////////////////////////////////////////////////////////////
-// 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"
+#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[]
-int macnum; // Unique number for macro definition
-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
+LONG curuniq; // Current macro's unique number
+int macnum; // Unique number for macro definition
-static LONG *firstrpt; // First .rept line
-static LONG *nextrpt; // Last .rept line
-static int rptlevel; // .rept nesting level
+static LONG macuniq; // Unique-per-macro number
+static SYM * curmac; // Macro currently being defined
+static uint32_t argno; // Formal argument count
-//
-// --- Initialize Macro Processor ------------------------------------------------------------------
-//
+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 *);
-void init_macro(void) {
- macuniq = 0;
- macnum = 1;
- argp = NULL;
- ib_macro();
-}
//
-// -------------------------------------------------------------------------------------------------
-// Exit from a Macro;
-// o pop any intervening include files and repeat blocks;
-// o restore argument stack;
-// o pop the macro.
-// -------------------------------------------------------------------------------------------------
+// Initialize macro processor
//
+void InitMacro(void)
+{
+ macuniq = 0;
+ macnum = 1;
+}
-int exitmac(void) {
- IMACRO *imacro;
- TOKEN **p;
-
- // Pop intervening include files and .rept blocks
- while(cur_inobj != NULL && cur_inobj->in_type != SRC_IMACRO)
- fpop();
-
- if(cur_inobj == NULL)
- fatal("too many ENDMs");
-
- // Restore
- // o old arg context
- // o old unique number
- // ...and then pop the macro.
-
- imacro = cur_inobj->inobj.imacro;
- curuniq = imacro->im_olduniq;
-
- p = --argp;
- argp = (TOKEN **)*argp;
-
- fpop();
-
- mjump_align = 0;
- return(0);
+//
+// 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 !!!)
+/*
+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.
+
+Is this still true, now that we have IMACROs with TOKENSTREAMs in them? Need to
+check it out for sure...!
+*/
+ // Pop intervening include files and .rept blocks
+ while (cur_inobj != NULL && cur_inobj->in_type != SRC_IMACRO)
+ fpop();
+
+ if (cur_inobj == NULL)
+ fatal("too many ENDMs");
+
+ // Restore
+ // o old arg context
+ // o old unique number
+ // ...and then pop the macro.
+
+ IMACRO * imacro = cur_inobj->inobj.imacro;
+ curuniq = imacro->im_olduniq;
+
+ DEBUG { printf("ExitMacro: nargs = %d\n", imacro->im_nargs); }
+
+ return fpop();
}
+
//
-// --- Add a Formal Argument to a Macro Definition -------------------------------------------------
+// Add a formal argument to a macro definition
//
+int defmac2(char * argname)
+{
+ if (lookup(argname, MACARG, (int)curmac->sattr) != NULL)
+ return error("multiple formal argument 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);
- arg->svalue = argno++;
+ SYM * arg = NewSymbol(argname, MACARG, (int)curmac->sattr);
+ arg->svalue = argno++;
- return(OK);
+ 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.
-// -------------------------------------------------------------------------------------------------
+// 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.
+// notEndFlag is -1 for all lines but the last one (.endm), when it is 0.
//
-
-int defmac1(char *ln, int endflg) {
- PTR p;
- LONG len;
-
- if(list_flag) {
- listeol(); // Flush previous source line
- lstout('.'); // Mark macro definition with period
- }
-
- if(endflg) {
- len = strlen(ln) + 1 + sizeof(LONG);
- p.cp = amem(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;
- else
- *curmln = p.cp;
- curmln = (char **)p.cp;
- return(1); // Keep looking
- }
- else
- return(0); // Stop looking at the end
+int defmac1(char * ln, int notEndFlag)
+{
+ if (list_flag)
+ {
+ listeol(); // Flush previous source line
+ lstout('.'); // Mark macro definition with period
+ }
+
+ if (notEndFlag)
+ {
+ if (curmac->lineList == NULL)
+ {
+ curmac->lineList = malloc(sizeof(LLIST));
+ curmac->lineList->next = NULL;
+ curmac->lineList->line = strdup(ln);
+ curmac->last = curmac->lineList;
+ }
+ else
+ {
+ curmac->last->next = malloc(sizeof(LLIST));
+ curmac->last->next->next = NULL;
+ curmac->last->next->line = strdup(ln);
+ curmac->last = curmac->last->next;
+ }
+
+ return 1; // Keep looking
+ }
+
+ return 0; // Stop looking; at the end
}
+
//
-// -------------------------------------------------------------------------------------------------
// Define macro
//
// macro foo arg1,arg2,...
// 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 defmac(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.
- if(*tok++ != SYMBOL) return(error("missing symbol"));
- p = (char *)*tok++;
- if(lookup(p, MACRO, 0) != NULL)
- return(error("multiple macro definition"));
-
- curmac = mac = newsym(p, MACRO, 0);
- mac->svalue = 0;
- mac->sattr = (WORD)(macnum++);
-
- // Parse and define formal arguments in symbol table
- if(*tok != EOL) {
- argno = 0;
- symlist(defmac2);
- at_eol();
- }
-
- // Suck in the macro definition; we're looking for an ENDM symbol on a line
- // by itself to terminate the definition.
- curmln = NULL;
- lncatch(defmac1, "endm ");
-
- return(0);
+int DefineMacro(void)
+{
+ // 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");
+
+ char * name = string[*tok++];
+
+ if (lookup(name, MACRO, 0) != NULL)
+ return error("duplicate macro definition");
+
+ curmac = NewSymbol(name, MACRO, 0);
+ curmac->svalue = 0;
+ curmac->sattr = (WORD)(macnum++);
+
+ // Parse and define formal arguments in symbol table
+ if (*tok != EOL)
+ {
+ argno = 0;
+ symlist(defmac2);
+ at_eol();
+ }
+
+ // Suck in the macro definition; we're looking for an ENDM symbol on a line
+ // by itself to terminate the definition.
+// curmln = NULL;
+ curmac->lineList = NULL;
+ LNCatch(defmac1, "endm ");
+
+ return 0;
}
+
//
-// --- Add lines to a .rept definition -------------------------------------------------------------
+// Add lines to a .rept definition
//
-
-int defr1(char *ln, int kwno) {
- LONG len;
- LONG *p;
-
- if(list_flag) {
- listeol(); // Flush previous source line
- lstout('#'); // Mark this a 'rept' block
- }
-
- switch(kwno) {
- case 0: // .endr
- if(--rptlevel == 0)
- return(0);
- goto addln;
- case 1: // .rept
- ++rptlevel;
- default:
-
- addln:
-
- // Allocate length of line + 1('\0') + LONG
- len = strlen(ln) + 1 + sizeof(LONG);
- p = (LONG *)amem(len);
- *p = 0;
-
- strcpy((char*)(p + 1), ln);
-
- if(nextrpt == NULL) {
- firstrpt = p; // First line of rept statement
- } else {
- *nextrpt = (LONG)p;
- }
- nextrpt = p;
-
- return(rptlevel);
- }
+int defr1(char * line, int kwno)
+{
+ if (list_flag)
+ {
+ listeol(); // Flush previous source line
+ lstout('#'); // Mark this a 'rept' block
+ }
+
+ if (kwno == 0) // .endr
+ {
+ if (--rptlevel == 0)
+ return 0;
+ }
+ else if (kwno == 1) // .rept
+ rptlevel++;
+
+//DEBUG { printf(" defr1: line=\"%s\", kwno=%d, rptlevel=%d\n", line, kwno, 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) {
- INOBJ *inobj;
- IREPT *irept;
- VALUE eval;
-
- // Evaluate repeat expression
- if(abs_expr(&eval) != OK)
- return(ERROR);
-
- // Suck in lines for .rept block
- firstrpt = NULL;
- nextrpt = NULL;
- rptlevel = 1;
- lncatch(defr1, "endr rept ");
-
- // Alloc and init input object
- if(firstrpt) {
- inobj = a_inobj(SRC_IREPT); // Create a new REPT input object
- irept = inobj->inobj.irept;
- irept->ir_firstln = firstrpt;
- irept->ir_nextln = NULL;
- irept->ir_count = eval;
- }
-
- return(0);
+int HandleRept(void)
+{
+ uint32_t eval;
+
+ // Evaluate repeat expression
+ if (abs_expr(&eval) != OK)
+ return ERROR;
+
+ // Suck in lines for .rept block
+ firstrpt = NULL;
+ nextrpt = NULL;
+ rptlevel = 1;
+ LNCatch(defr1, "endr rept ");
+
+//DEBUG { printf("HandleRept: firstrpt=$%X\n", firstrpt); }
+ // Alloc and init input object
+ if (firstrpt)
+ {
+ 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;
+ }
+
+ return 0;
}
+
//
-// -------------------------------------------------------------------------------------------------
-// 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, when it is called
-// with an argument of the keyword number that caused the match.
-// -------------------------------------------------------------------------------------------------
+// Hand off lines of text to the function 'lnfunc' until a line containing one
+// of the directives in 'dirlist' is encountered.
//
-
-int lncatch(int (*lnfunc)(), char *dirlist) {
- char *p;
- int k;
-
- if(lnfunc != NULL)
- ++lnsave; // Tell tokenizer to keep lines
-
- for(;;) {
- if(tokln() == TKEOF) {
- errors("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;
-
- if(*tok == SYMBOL) {
- if((tok[2] == ':' || tok[2] == DCOLON)) {
- if(tok[3] == SYMBOL) // label: symbol
- p = (char *)tok[4];
- } else {
- p = (char *)tok[1]; // symbol
- }
- }
-
- if(p != NULL) {
- if(*p == '.') // ignore leading '.'s
- ++p;
- k = kwmatch(p, dirlist);
- }
-
- // Hand-off line to function
- // if it returns 0, and we found a keyword, stop looking.
- // if it returns 1, hand off the line and keep looking.
- if(lnfunc != NULL)
- k = (*lnfunc)(lnbuf, k);
-
- if(!k)
- break;
- }
-
- if(lnfunc != NULL)
- --lnsave; // Tell tokenizer to stop keeping lines
-
- return(0);
-}
-
+// 'dirlist' contains space-separated terminated keywords. A final space
+// terminates the list. Directives are case-insensitively compared to the
+// keywords.
//
-// -------------------------------------------------------------------------------------------------
-// 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.
-// -------------------------------------------------------------------------------------------------
+// If 'lnfunc' is NULL, then lines are simply skipped.
+// If 'lnfunc' returns an error, processing is stopped.
//
-
-int kwmatch(char *kw, char *kwlist) {
- char *p;
- char c1;
- char c2;
- int k;
-
- for(k = 0; *kwlist; ++k) {
- for(p = kw;;) {
- c1 = *kwlist++;
- c2 = *p++;
-
- if(c2 >= 'A' && c2 <= 'Z')
- c2 += 32;
-
- if(c1 == ' ' && c2 == EOS)
- return(k);
-
- if(c1 != c2)
- break;
- }
-
- // Skip to beginning of next keyword in `kwlist'
- while(*kwlist && *kwlist != ' ')
- ++kwlist;
- if(*kwlist== ' ')
- ++kwlist;
- }
-
- return(-1);
+// '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.
+//
+static int LNCatch(int (* lnfunc)(), char * dirlist)
+{
+ if (lnfunc != NULL)
+ lnsave++; // Tell tokenizer to keep lines
+
+ while (1)
+ {
+ if (TokenizeLine() == TKEOF)
+ {
+ error("encountered end-of-file looking for '%s'", dirlist);
+ fatal("cannot continue");
+ }
+
+ DEBUG { DumpTokenBuffer(); }
+
+ // Test for end condition. Two cases to handle:
+ // <directive>
+ // symbol: <directive>
+ 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)
+ p = string[tok[4]];
+ }
+ else
+ {
+ // Otherwise, just grab the directive
+ p = string[tok[1]];
+ }
+ }
+
+ if (p != NULL)
+ {
+ if (*p == '.') // Ignore leading periods
+ p++;
+
+ k = KWMatch(p, dirlist);
+ }
+
+ // Hand-off line to function
+ // if it returns 0, and we found a keyword, stop looking.
+ // if it returns 1, hand off the line and keep looking.
+ if (lnfunc != NULL)
+ k = (*lnfunc)(lnbuf, k);
+
+ if (k == 0)
+ break;
+ }
+
+ if (lnfunc != NULL)
+ lnsave--; // Tell tokenizer to stop keeping lines
+
+ return 0;
}
+
//
-// -------------------------------------------------------------------------------------------------
-// Invoke a macro
-// o parse, count and copy arguments
-// o push macro's string-stream
-// -------------------------------------------------------------------------------------------------
+// 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 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);
+static int KWMatch(char * kw, char * kwlist)
+{
+ for(int k=0; *kwlist; k++)
+ {
+ for(char * p=kw;;)
+ {
+ char c1 = *kwlist++;
+ char c2 = *p++;
+
+ if (c2 >= 'A' && c2 <= 'Z')
+ c2 += 32;
+
+ if (c1 == ' ' && c2 == EOS)
+ return k;
+
+ if (c1 != c2)
+ break;
+ }
+
+ // Skip to beginning of next keyword in `kwlist'
+ while (*kwlist && (*kwlist != ' '))
+ ++kwlist;
+
+ if (*kwlist== ' ')
+ kwlist++;
+ }
+
+ return -1;
}
+
//
-// -------------------------------------------------------------------------------------------------
-// Setup inbuilt macros
-// -------------------------------------------------------------------------------------------------
+// Invoke a macro by creating a new IMACRO object & chopping up the arguments
//
+int InvokeMacro(SYM * mac, WORD siz)
+{
+ DEBUG { printf("InvokeMacro: arguments="); DumpTokens(tok); }
+
+ INOBJ * inobj = a_inobj(SRC_IMACRO); // Alloc and init IMACRO
+ IMACRO * imacro = inobj->inobj.imacro;
+ uint16_t nargs = 0;
+
+ // Chop up the arguments, if any (tok comes from token.c, which at this
+ // point points at the macro argument token stream)
+ if (*tok != EOL)
+ {
+ // Parse out the arguments and set them up correctly
+ TOKEN * p = imacro->argument[nargs].token;
+ int stringNum = 0;
+
+ while (*tok != EOL)
+ {
+ if (*tok == ACONST)
+ {
+ for(int i=0; i<3; i++)
+ *p++ = *tok++;
+ }
+ else if (*tok == CONST)
+ {
+ *p++ = *tok++;
+ *p++ = *tok++;
+ }
+ else if ((*tok == STRING) || (*tok == SYMBOL))
+ {
+ *p++ = *tok++;
+ imacro->argument[nargs].string[stringNum] = strdup(string[*tok++]);
+ *p++ = stringNum++;
+ }
+ else if (*tok == ',')
+ {
+ // Comma delimiter was found, so set up for next argument
+ *p++ = EOL;
+ tok++;
+ stringNum = 0;
+ nargs++;
+ p = imacro->argument[nargs].token;
+ }
+ else
+ {
+ *p++ = *tok++;
+ }
+ }
+
+ // Make sure to stuff the final EOL (otherwise, it will be skipped)
+ *p++ = EOL;
+ nargs++;
+ }
+
+ // 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_siz = siz;
+ imacro->im_nextln = mac->lineList;
+ imacro->im_olduniq = curuniq;
+ curuniq = macuniq++;
+
+ DEBUG
+ {
+ printf("# args = %d\n", nargs);
+
+ for(uint16_t i=0; i<nargs; i++)
+ {
+ printf("arg%d=", i);
+ DumpTokens(imacro->argument[i].token);
+ }
+ }
+
+ return OK;
+}
-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);
-}
\ No newline at end of file