X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=macro.c;h=22bd0d9f7c444d4824228cab8307e82c648c9f85;hp=23d879719d7d47ad45d6ecd99c010033effa0a4f;hb=4205233c8397c581b4d27ab36ab81ec896ef3dd0;hpb=c3bb316d42b8471dbe87fa4b8c9787265e7b01da diff --git a/macro.c b/macro.c index 23d8797..22bd0d9 100644 --- a/macro.c +++ b/macro.c @@ -1,7 +1,7 @@ // // RMAC - Reboot's Macro Assembler for all Atari computers // MACRO.C - Macro Definition and Invocation -// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends +// Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 // Source utilised with the kind permission of Landon Dyer // @@ -19,15 +19,13 @@ 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 VALUE argno; // Formal argument count +static uint32_t argno; // Formal argument count -static LONG * firstrpt; // First .rept line -static LONG * nextrpt; // Last .rept line +static LLIST * firstrpt; // First .rept line +static LLIST * nextrpt; // Last .rept line static int rptlevel; // .rept nesting level // Function prototypes @@ -42,7 +40,6 @@ void InitMacro(void) { macuniq = 0; macnum = 1; - argp = 0; } @@ -55,11 +52,13 @@ void InitMacro(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. + +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) @@ -76,11 +75,7 @@ of another (nested macros). Need to fix that somehow. IMACRO * imacro = cur_inobj->inobj.imacro; curuniq = imacro->im_olduniq; -// /*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); } + DEBUG { printf("ExitMacro: nargs = %d\n", imacro->im_nargs); } return fpop(); } @@ -91,12 +86,10 @@ of another (nested macros). Need to fix that somehow. // 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; @@ -113,65 +106,33 @@ int defmac1(char * ln, int notEndFlag) { if (list_flag) { - listeol(); // Flush previous source line - lstout('.'); // Mark macro definition with period + listeol(); // Flush previous source line + lstout('.'); // Mark macro definition with period } - // This is just wrong, wrong, wrong. It makes up a weird kind of string with - // a pointer on front, and then uses a ** to manage them: This is a recipe - // for disaster. - // How to manage it then? - // Could use a linked list, like Landon uses everywhere else. -/* -How it works: -Allocate a space big enough for the string + NULL + pointer. -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. - -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) { -#if 0 - len = strlen(ln) + 1 + sizeof(LONG); - p.cp = malloc(len); - *p.lp = 0; - strcpy(p.cp + sizeof(LONG), ln); - - // Link line of text onto end of list - if (curmln == NULL) - curmac->svalue = p.cp; - else - *curmln = p.cp; - - curmln = (char **)p.cp; - 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->lineList->lineno = curlineno; 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->lineList->lineno = curlineno; curmac->last = curmac->last->next; } - return 1; // Keep looking -#endif + return 1; // Keep looking } - return 0; // Stop looking at the end + return 0; // Stop looking; at the end } @@ -211,7 +172,7 @@ int DefineMacro(void) { argno = 0; symlist(defmac2); - at_eol(); + ErrorIfNotAtEOL(); } // Suck in the macro definition; we're looking for an ENDM symbol on a line @@ -227,55 +188,67 @@ int DefineMacro(void) // // Add lines to a .rept definition // -int defr1(char * ln, int kwno) +int defr1(char * line, int kwno) { 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; - - break; - case 1: // .rept - rptlevel++; } + 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 len = strlen(ln) + 1 + sizeof(LONG); - LONG * p = (LONG *)malloc(len); + LONG * p = (LONG *)malloc(strlen(line) + 1 + sizeof(LONG)); *p = 0; - - strcpy((char *)(p + 1), ln); + 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); + firstrpt->lineno = curlineno; + nextrpt = firstrpt; + } + else + { + nextrpt->next = malloc(sizeof(LLIST)); + nextrpt->next->next = NULL; + nextrpt->next->line = strdup(line); + nextrpt->next->lineno = curlineno; + 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 DefineRept(void) +int HandleRept(void) { - VALUE eval; + uint64_t eval; // Evaluate repeat expression if (abs_expr(&eval) != OK) @@ -287,6 +260,7 @@ int DefineRept(void) rptlevel = 1; LNCatch(defr1, "endr rept "); +//DEBUG { printf("HandleRept: firstrpt=$%X\n", firstrpt); } // Alloc and init input object if (firstrpt) { @@ -294,7 +268,7 @@ int DefineRept(void) IREPT * irept = inobj->inobj.irept; irept->ir_firstln = firstrpt; irept->ir_nextln = NULL; - irept->ir_count = eval; + irept->ir_count = (uint32_t)eval; } return 0; @@ -303,12 +277,11 @@ int DefineRept(void) // // 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 -// keywords encountered (0..n) +// of the directives in 'dirlist' is encountered. // -// 'dirlist' contains null-seperated terminated keywords. A final null -// terminates the list. Directives are compared to the keywords without regard -// to case. +// '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. @@ -319,13 +292,10 @@ int DefineRept(void) // static int LNCatch(int (* lnfunc)(), char * dirlist) { - char * p; - int k; - if (lnfunc != NULL) lnsave++; // Tell tokenizer to keep lines - for(;;) + while (1) { if (TokenizeLine() == TKEOF) { @@ -333,28 +303,33 @@ static int LNCatch(int (* lnfunc)(), char * dirlist) fatal("cannot continue"); } + DEBUG { DumpTokenBuffer(); } + // Test for end condition. Two cases to handle: // // symbol: - 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); @@ -366,7 +341,7 @@ static int LNCatch(int (* lnfunc)(), char * dirlist) if (lnfunc != NULL) k = (*lnfunc)(lnbuf, k); - if (!k) + if (k == 0) break; } @@ -378,8 +353,8 @@ static int LNCatch(int (* lnfunc)(), char * dirlist) // -// 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. // static int KWMatch(char * kw, char * kwlist) @@ -414,157 +389,67 @@ static int KWMatch(char * kw, char * kwlist) // -// Invoke a macro -// o parse, count and copy arguments -// o push macro's string-stream +// Invoke a macro by creating a new IMACRO object & chopping up the arguments // 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 + DEBUG { printf("InvokeMacro: arguments="); DumpTokens(tok); } + + 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--) + 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) { - for(tok=beg_tok; *tok!=EOL;) + // Parse out the arguments and set them up correctly + TOKEN * p = imacro->argument[nargs].token; + int stringNum = 0; + + while (*tok != EOL) { - if (dry_run) - nargs++; - else + if (*tok == ACONST) { -#if 0 - *argptr++ = p; -#else - argPtrs[argp++] = p; - startOfArg = p; -#endif + for(int i=0; i<3; i++) + *p++ = *tok++; } - - // Keep going while tok isn't pointing at a comma or EOL - while (*tok != ',' && *tok != EOL) + else if (*tok == CONST) // Constants are 64-bits { - // 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; - } + *p++ = *tok++; // Token + uint64_t *p64 = (uint64_t *)p; + uint64_t *tok64 = (uint64_t *)tok; + *p64++ = *tok64++; + tok = (TOKEN *)tok64; + p = (uint32_t *)p64; } - - // We hit the comma or EOL, so count/stuff it - if (dry_run) - arg_siz += sizeof(TOKEN); - else + 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; - - // 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++; + nargs++; + p = imacro->argument[nargs].token; + } + else + { + *p++ = *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(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; + // Make sure to stuff the final EOL (otherwise, it will be skipped) + *p++ = EOL; + nargs++; } - DEBUG { printf("%d\n", argp); } - - // Setup imacro: + // Setup IMACRO: // o # arguments; // o -> macro symbol; // o -> macro definition string list; @@ -572,19 +457,19 @@ streams, we can alleviate this problem.] // 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++; - imacro->argBase = argp - nargs; // Shamus: keep track of argument base DEBUG { - printf("nargs=%d\n", nargs); + printf("# args = %d\n", nargs); - for(nargs=0; nargsim_nargs; nargs++) + for(uint16_t i=0; i