diff options
author | Keith Kanios <keith@kanios.net> | 2010-08-01 02:30:33 -0500 |
---|---|---|
committer | Keith Kanios <keith@kanios.net> | 2010-08-01 02:30:33 -0500 |
commit | 973d4a49e81fa4fc1d246d34582ef1713dcd2628 (patch) | |
tree | a89879518e6781648ceab91cde342070a44d5466 | |
parent | d7b654c73da25a597f526303b967fcb713c0ae20 (diff) | |
download | nasm-973d4a49e81fa4fc1d246d34582ef1713dcd2628.tar.gz |
preproc.c: initial branch of revamped preprocessor
-rw-r--r-- | preproc.c | 1456 |
1 files changed, 758 insertions, 698 deletions
@@ -83,7 +83,8 @@ typedef struct SMacro SMacro; typedef struct MMacro MMacro; -typedef struct MMacroInvocation MMacroInvocation; +typedef struct ExpDef ExpDef; +typedef struct ExpInv ExpInv; typedef struct Context Context; typedef struct Token Token; typedef struct Blocks Blocks; @@ -114,64 +115,6 @@ struct SMacro { }; /* - * Store the definition of a multi-line macro. This is also used to - * store the interiors of `%rep...%endrep' blocks, which are - * effectively self-re-invoking multi-line macros which simply - * don't have a name or bother to appear in the hash tables. %rep - * blocks are signified by having a NULL `name' field. - * - * In a MMacro describing a `%rep' block, the `in_progress' field - * isn't merely boolean, but gives the number of repeats left to - * run. - * - * The `next' field is used for storing MMacros in hash tables; the - * `next_active' field is for stacking them on istk entries. - * - * When a MMacro is being expanded, `params', `iline', `nparam', - * `paramlen', `rotate' and `unique' are local to the invocation. - */ -struct MMacro { - MMacro *next; - MMacroInvocation *prev; /* previous invocation */ - char *name; - int nparam_min, nparam_max; - bool casesense; - bool plus; /* is the last parameter greedy? */ - bool nolist; /* is this macro listing-inhibited? */ - int64_t in_progress; /* is this macro currently being expanded? */ - int32_t max_depth; /* maximum number of recursive expansions allowed */ - Token *dlist; /* All defaults as one list */ - Token **defaults; /* Parameter default pointers */ - int ndefs; /* number of default parameters */ - Line *expansion; - - MMacro *next_active; - MMacro *rep_nest; /* used for nesting %rep */ - Token **params; /* actual parameters */ - Token *iline; /* invocation line */ - unsigned int nparam, rotate; - int *paramlen; - uint64_t unique; - int lineno; /* Current line number on expansion */ - uint64_t condcnt; /* number of if blocks... */ -}; - - -/* Store the definition of a multi-line macro, as defined in a - * previous recursive macro expansion. - */ -struct MMacroInvocation { - MMacroInvocation *prev; /* previous invocation */ - Token **params; /* actual parameters */ - Token *iline; /* invocation line */ - unsigned int nparam, rotate; - int *paramlen; - uint64_t unique; - uint64_t condcnt; -}; - - -/* * The context stack is composed of a linked list of these. */ struct Context { @@ -246,11 +189,85 @@ struct Token { */ struct Line { Line *next; - MMacro *finishes; Token *first; }; /* + * Expansion Types + */ +enum pp_exp_type { + EXP_NONE = 0, EXP_PREDEF, + EXP_MMACRO, EXP_REP, + EXP_IF, + EXP_MAX = INT_MAX /* Keep compiler from reducing the range */ +}; + +/* + * Store the definition of an expansion. This is also used to + * store the interiors of `%rep...%endrep' blocks, which are + * effectively self-re-invoking multi-line macros which simply + * don't have a name or bother to appear in the hash tables. %rep + * blocks are signified by having a NULL `name' field. + * + * In a ExpDef describing a `%rep' block, the `cur_depth' field + * isn't merely boolean, but gives the number of repeats left to + * run. + * + * The `next' field is used for storing ExpDef in hash tables; the + * `prev' field is for the `expansions` linked-list. + */ +struct ExpDef { + ExpDef *prev; /* previous definition */ + ExpDef *next; /* next in hash table */ + enum pp_exp_type type; /* expansion type */ + char *name; + int nparam_min, nparam_max; + bool casesense; + bool plus; /* is the last parameter greedy? */ + bool nolist; /* is this expansion listing-inhibited? */ + Token *dlist; /* All defaults as one list */ + Token **defaults; /* Parameter default pointers */ + int ndefs; /* number of default parameters */ + + Line *label; + Line *line; + Line *last; + + uint32_t def_depth; /* current number of definition pairs deep */ + uint32_t cur_depth; /* current number of expansions */ + uint32_t max_depth; /* maximum number of expansions allowed */ + + int state; /* condition state */ + bool ignoring; /* ignoring definition lines */ +}; + +/* + * Store the invocation of an expansion. + * + * The `prev' field is for the `istk->expansion` linked-list. + * + * When an expansion is being expanded, `params', `iline', `nparam', + * `paramlen', `rotate' and `unique' are local to the invocation. + */ +struct ExpInv { + ExpInv *prev; /* previous invocation */ + enum pp_exp_type type; /* expansion type */ + ExpDef *def; /* pointer to expansion definition */ + Line *label; /* pointer to label */ + char *label_text; /* pointer to label text */ + Line *current; /* pointer to current line in invocation */ + + Token **params; /* actual parameters */ + Token *iline; /* invocation line */ + unsigned int nparam, rotate; + int *paramlen; + + uint64_t unique; + bool emitting; + int lineno; /* current line number in expansion */ +}; + +/* * To handle an arbitrary level of file inclusion, we maintain a * stack (ie linked list) of these things. */ @@ -258,10 +275,9 @@ struct Include { Include *next; FILE *fp; Cond *conds; - Line *expansion; + ExpInv *expansion; char *fname; int lineno, lineinc; - MMacro *mstk; /* stack of active macros/reps */ }; /* @@ -281,10 +297,6 @@ struct IncPath { * included from within the true branch of a `%if' won't terminate * it and cause confusion: instead, rightly, it'll cause an error.) */ -struct Cond { - Cond *next; - int state; -}; enum { /* * These states are for use just after %if or %elif: IF_TRUE @@ -349,15 +361,6 @@ static const enum pp_conds inverse_ccs[] = { c_Z, c_NO, c_NP, c_PO, c_PE, -1, c_NS, c_NZ }; -/* - * Directive names. - */ -/* If this is a an IF, ELIF, ELSE or ENDIF keyword */ -static int is_condition(enum preproc_token arg) -{ - return PP_IS_COND(arg) || (arg == PP_ELSE) || (arg == PP_ENDIF); -} - /* For TASM compatibility we need to be able to recognise TASM compatible * conditional compilation directives. Using the NASM pre-processor does * not work, so we look for them specifically from the following list and @@ -394,9 +397,9 @@ static bool do_predef; static ListGen *list; /* - * The current set of multi-line macros we have defined. + * The current set of expansion definitions we have defined. */ -static struct hash_table mmacros; +static struct hash_table expdefs; /* * The current set of single-line macros we have defined. @@ -404,10 +407,14 @@ static struct hash_table mmacros; static struct hash_table smacros; /* - * The multi-line macro we are currently defining, or the %rep - * block we are currently reading, if any. + * Linked List of all active expansion definitions */ -static MMacro *defining; +struct ExpDef *expansions = NULL; + +/* + * The expansion we are currently defining + */ +static ExpDef *defining = NULL; static uint64_t nested_mac_count; static uint64_t nested_rep_count; @@ -457,7 +464,11 @@ static void *new_Block(size_t size); static void delete_Blocks(void); static Token *new_Token(Token * next, enum pp_token_type type, const char *text, int txtlen); +static Token *copy_Token(Token * tline); static Token *delete_Token(Token * t); +static Line *new_Line(void); +static ExpDef *new_ExpDef(void); +static ExpInv *new_ExpInv(void); /* * Macros for safe checking of token pointers, avoid *(NULL) @@ -590,15 +601,15 @@ static void free_llist(Line * list) } /* - * Free an MMacro + * Free an ExpDef */ -static void free_mmacro(MMacro * m) +static void free_expdef(ExpDef * ed) { - nasm_free(m->name); - free_tlist(m->dlist); - nasm_free(m->defaults); - free_llist(m->expansion); - nasm_free(m); + nasm_free(ed->name); + free_tlist(ed->dlist); + nasm_free(ed->defaults); + free_llist(ed->line); + nasm_free(ed); } /* @@ -621,25 +632,25 @@ static void free_smacro_table(struct hash_table *smt) hash_free(smt); } -static void free_mmacro_table(struct hash_table *mmt) +static void free_mmacro_table(struct hash_table *edt) { - MMacro *m, *tmp; + ExpDef *ed, *tmp; const char *key; struct hash_tbl_node *it = NULL; it = NULL; - while ((m = hash_iterate(mmt, &it, &key)) != NULL) { + while ((ed = hash_iterate(edt, &it, &key)) != NULL) { nasm_free((void *)key); - list_for_each_safe(m ,tmp, m) - free_mmacro(m); + list_for_each_safe(ed ,tmp, ed) + free_expdef(ed); } - hash_free(mmt); + hash_free(edt); } static void free_macros(void) { free_smacro_table(&smacros); - free_mmacro_table(&mmacros); + free_mmacro_table(&expdefs); } /* @@ -648,7 +659,7 @@ static void free_macros(void) static void init_macros(void) { hash_init(&smacros, HASH_LARGE); - hash_init(&mmacros, HASH_LARGE); + hash_init(&expdefs, HASH_LARGE); } /* @@ -698,7 +709,7 @@ hash_findix(struct hash_table *hash, const char *str) } /* - * read line from standart macros set, + * read line from standard macros set, * if there no more left -- return NULL */ static char *line_from_stdmac(void) @@ -739,6 +750,7 @@ static char *line_from_stdmac(void) stdmacpos = extrastdmac; any_extrastdmac = false; } else if (do_predef) { + ExpInv *ei; Line *pd, *l; Token *head, **tail, *t; @@ -757,12 +769,14 @@ static char *line_from_stdmac(void) tail = &(*tail)->next; } - l = nasm_malloc(sizeof(Line)); - l->next = istk->expansion; - l->first = head; - l->finishes = NULL; - - istk->expansion = l; + l = new_Line(); + l->first = head; + ei = new_ExpInv(); + ei->type = EXP_PREDEF; + ei->current = l; + ei->emitting = true; + ei->prev = istk->expansion; + istk->expansion = ei; } do_predef = false; } @@ -1192,6 +1206,34 @@ static Token *new_Token(Token * next, enum pp_token_type type, return t; } +static Token *copy_Token(Token * tline) +{ + Token *t, *tt, *first = NULL, *prev = NULL; + int i; + for (tt = tline; tt != NULL; tt = tt->next) { + if (!freeTokens) { + freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token)); + for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++) + freeTokens[i].next = &freeTokens[i + 1]; + freeTokens[i].next = NULL; + } + t = freeTokens; + freeTokens = t->next; + t->next = NULL; + t->text = ((tt->text != NULL) ? strdup(tt->text) : NULL); + t->a.mac = tt->a.mac; + t->a.len = tt->a.len; + t->type = tt->type; + if (prev != NULL) { + prev->next = t; + } else { + first = t; + } + prev = t; + } + return first; +} + static Token *delete_Token(Token * t) { Token *next = t->next; @@ -1280,6 +1322,72 @@ static char *detoken(Token * tlist, bool expand_locals) } /* + * Initialize a new Line + */ +static Line *new_Line(void) +{ + Line *l = nasm_malloc(sizeof(Line)); + l->next = NULL; + l->first = NULL; + return l; +} + + +/* + * Initialize a new Expansion Definition + */ +static ExpDef *new_ExpDef(void) +{ + ExpDef *ed = nasm_malloc(sizeof(ExpDef)); + ed->prev = NULL; + ed->next = NULL; + ed->type = EXP_NONE; + ed->name = NULL; + ed->nparam_min = 0; + ed->nparam_max = 0; + ed->casesense = true; + ed->plus = false; + ed->label = NULL; + ed->line = NULL; + ed->last = NULL; + ed->dlist = NULL; + ed->defaults = NULL; + ed->ndefs = 0; + ed->state = COND_NEVER; + ed->nolist = false; + ed->def_depth = 0; + ed->cur_depth = 0; + ed->max_depth = 0; + ed->ignoring = false; + return ed; +} + + +/* + * Initialize a new Expansion Instance + */ +static ExpInv *new_ExpInv(void) +{ + unique ++; + ExpInv *ei = nasm_malloc(sizeof(ExpInv)); + ei->prev = NULL; + ei->type = EXP_NONE; + ei->def = NULL; + ei->label = NULL; + ei->label_text = NULL; + ei->current = NULL; + ei->params = NULL; + ei->iline = NULL; + ei->nparam = 0; + ei->rotate = 0; + ei->paramlen = NULL; + ei->unique = unique; + ei->emitting = false; + ei->lineno = 0; + return ei; +} + +/* * A scanner, suitable for use by the expression evaluator, which * operates on a line of Tokens. Expects a pointer to a pointer to * the first token in the line to be passed in as its private_data @@ -1787,7 +1895,7 @@ static bool if_condition(Token * tline, enum preproc_token ct) case PPC_IFMACRO: { bool found = false; - MMacro searching, *mmac; + ExpDef searching, *ed; skip_white_(tline); tline = expand_id(tline); @@ -1800,9 +1908,9 @@ static bool if_condition(Token * tline, enum preproc_token ct) searching.casesense = true; searching.plus = false; searching.nolist = false; - searching.in_progress = 0; + //searching.in_progress = 0; searching.max_depth = 0; - searching.rep_nest = NULL; + //searching.rep_nest = NULL; searching.nparam_min = 0; searching.nparam_max = INT_MAX; tline = expand_smacro(tline->next); @@ -1843,17 +1951,17 @@ static bool if_condition(Token * tline, enum preproc_token ct) tline = tline->next; searching.plus = true; } - mmac = (MMacro *) hash_findix(&mmacros, searching.name); - while (mmac) { - if (!strcmp(mmac->name, searching.name) && - (mmac->nparam_min <= searching.nparam_max + ed = (ExpDef *) hash_findix(&expdefs, searching.name); + while (ed != NULL) { + if (!strcmp(ed->name, searching.name) && + (ed->nparam_min <= searching.nparam_max || searching.plus) - && (searching.nparam_min <= mmac->nparam_max - || mmac->plus)) { + && (searching.nparam_min <= ed->nparam_max + || ed->plus)) { found = true; break; } - mmac = mmac->next; + ed = ed->next; } if (tline && tline->next) error(ERR_WARNING|ERR_PASS1, @@ -2018,7 +2126,7 @@ static void undef_smacro(Context *ctx, const char *mname) /* * Parse a mmacro specification. */ -static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive) +static bool parse_mmacro_spec(Token *tline, ExpDef *def, const char *directive) { bool err; @@ -2030,12 +2138,11 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive) return false; } - def->prev = NULL; def->name = nasm_strdup(tline->text); def->plus = false; def->nolist = false; - def->in_progress = 0; - def->rep_nest = NULL; +// def->in_progress = 0; +// def->rep_nest = NULL; def->nparam_min = 0; def->nparam_max = 0; @@ -2089,7 +2196,7 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive) def->dlist = NULL; def->defaults = NULL; } - def->expansion = NULL; + def->line = NULL; if (def->defaults && def->ndefs > def->nparam_max - def->nparam_min && !def->plus) @@ -2138,13 +2245,11 @@ static int do_directive(Token * tline) const char *mname; Include *inc; Context *ctx; - Cond *cond; - MMacro *mmac, **mmhead; Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline; - Line *l; struct tokenval tokval; expr *evalresult; - MMacro *tmp_defining; /* Used when manipulating rep_nest */ + ExpDef *ed, *eed, **edhead; + ExpInv *ei, *eei; int64_t count; size_t len; int severity; @@ -2159,72 +2264,15 @@ static int do_directive(Token * tline) i = pp_token_hash(tline->text); - /* - * FIXME: We zap execution of PP_RMACRO, PP_IRMACRO, PP_EXITMACRO - * since they are known to be buggy at moment, we need to fix them - * in future release (2.09-2.10) - */ - if (i == PP_RMACRO || i == PP_RMACRO || i == PP_EXITMACRO) { - error(ERR_NONFATAL, "unknown preprocessor directive `%s'", - tline->text); - return NO_DIRECTIVE_FOUND; - } - - /* - * If we're in a non-emitting branch of a condition construct, - * or walking to the end of an already terminated %rep block, - * we should ignore all directives except for condition - * directives. - */ - if (((istk->conds && !emitting(istk->conds->state)) || - (istk->mstk && !istk->mstk->in_progress)) && !is_condition(i)) { - return NO_DIRECTIVE_FOUND; - } - - /* - * If we're defining a macro or reading a %rep block, we should - * ignore all directives except for %macro/%imacro (which nest), - * %endm/%endmacro, and (only if we're in a %rep block) %endrep. - * If we're in a %rep block, another %rep nests, so should be let through. - */ - if (defining && i != PP_MACRO && i != PP_IMACRO && - i != PP_RMACRO && i != PP_IRMACRO && - i != PP_ENDMACRO && i != PP_ENDM && - (defining->name || (i != PP_ENDREP && i != PP_REP))) { - return NO_DIRECTIVE_FOUND; - } - - if (defining) { - if (i == PP_MACRO || i == PP_IMACRO || - i == PP_RMACRO || i == PP_IRMACRO) { - nested_mac_count++; - return NO_DIRECTIVE_FOUND; - } else if (nested_mac_count > 0) { - if (i == PP_ENDMACRO) { - nested_mac_count--; - return NO_DIRECTIVE_FOUND; - } - } - if (!defining->name) { - if (i == PP_REP) { - nested_rep_count++; - return NO_DIRECTIVE_FOUND; - } else if (nested_rep_count > 0) { - if (i == PP_ENDREP) { - nested_rep_count--; - return NO_DIRECTIVE_FOUND; - } - } - } - } - switch (i) { case PP_INVALID: + if (defining != NULL) return NO_DIRECTIVE_FOUND; error(ERR_NONFATAL, "unknown preprocessor directive `%s'", tline->text); return NO_DIRECTIVE_FOUND; /* didn't get it */ case PP_STACKSIZE: + if (defining != NULL) return NO_DIRECTIVE_FOUND; /* Directive to tell NASM what the default stack size is. The * default is for a 16-bit stack, and this can be overriden with * %stacksize large. @@ -2274,6 +2322,7 @@ static int do_directive(Token * tline) return DIRECTIVE_FOUND; case PP_ARG: + if (defining != NULL) return NO_DIRECTIVE_FOUND; /* TASM like ARG directive to define arguments to functions, in * the following form: * @@ -2343,6 +2392,7 @@ static int do_directive(Token * tline) return DIRECTIVE_FOUND; case PP_LOCAL: + if (defining != NULL) return NO_DIRECTIVE_FOUND; /* TASM like LOCAL directive to define local variables for a * function, in the following form: * @@ -2424,6 +2474,7 @@ static int do_directive(Token * tline) return DIRECTIVE_FOUND; case PP_CLEAR: + if (defining != NULL) return NO_DIRECTIVE_FOUND; if (tline->next) error(ERR_WARNING|ERR_PASS1, "trailing garbage after `%%clear' ignored"); @@ -2433,6 +2484,7 @@ static int do_directive(Token * tline) return DIRECTIVE_FOUND; case PP_DEPEND: + if (defining != NULL) return NO_DIRECTIVE_FOUND; t = tline->next = expand_smacro(tline->next); skip_white_(t); if (!t || (t->type != TOK_STRING && @@ -2458,6 +2510,7 @@ static int do_directive(Token * tline) return DIRECTIVE_FOUND; case PP_INCLUDE: + if (defining != NULL) return NO_DIRECTIVE_FOUND; t = tline->next = expand_smacro(tline->next); skip_white_(t); @@ -2475,7 +2528,6 @@ static int do_directive(Token * tline) nasm_unquote_cstr(p, i); inc = nasm_malloc(sizeof(Include)); inc->next = istk; - inc->conds = NULL; inc->fp = inc_fopen(p, dephead, &deptail, pass == 0); if (!inc->fp) { /* -MG given but file not found */ @@ -2485,7 +2537,6 @@ static int do_directive(Token * tline) inc->lineno = src_set_linnum(0); inc->lineinc = 1; inc->expansion = NULL; - inc->mstk = NULL; istk = inc; list->uplevel(LIST_INCLUDE); } @@ -2493,6 +2544,7 @@ static int do_directive(Token * tline) return DIRECTIVE_FOUND; case PP_USE: + if (defining != NULL) return NO_DIRECTIVE_FOUND; { static macros_t *use_pkg; const char *pkg_macro = NULL; @@ -2528,6 +2580,7 @@ static int do_directive(Token * tline) case PP_PUSH: case PP_REPL: case PP_POP: + if (defining != NULL) return NO_DIRECTIVE_FOUND; tline = tline->next; skip_white_(tline); tline = expand_id(tline); @@ -2587,6 +2640,7 @@ static int do_directive(Token * tline) goto issue_error; issue_error: + if (defining != NULL) return NO_DIRECTIVE_FOUND; { /* Only error out if this is the final pass */ if (pass != 2 && i != PP_FATAL) @@ -2613,39 +2667,59 @@ issue_error: } CASE_PP_IF: - if (istk->conds && !emitting(istk->conds->state)) - j = COND_NEVER; - else { - j = if_condition(tline->next, i); - tline->next = NULL; /* it got freed */ - j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; - } - cond = nasm_malloc(sizeof(Cond)); - cond->next = istk->conds; - cond->state = j; - istk->conds = cond; - if(istk->mstk) - istk->mstk->condcnt ++; + if (defining != NULL) { + if (defining->type == EXP_IF) { + defining->def_depth ++; + } + return NO_DIRECTIVE_FOUND; + } + if ((istk->expansion != NULL) && + (istk->expansion->emitting == false)) { + j = COND_NEVER; + } else { + j = if_condition(tline->next, i); + tline->next = NULL; /* it got freed */ + j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE); + } + ed = new_ExpDef(); + ed->type = EXP_IF; + ed->state = j; + ed->nolist = NULL; + ed->def_depth = 0; + ed->cur_depth = 0; + ed->max_depth = 0; + ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true); + ed->prev = defining; + defining = ed; free_tlist(origline); return DIRECTIVE_FOUND; CASE_PP_ELIF: - if (!istk->conds) - error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]); - switch(istk->conds->state) { - case COND_IF_TRUE: - istk->conds->state = COND_DONE; - break; + if (defining != NULL) { + if ((defining->type != EXP_IF) || (defining->def_depth > 0)) { + return NO_DIRECTIVE_FOUND; + } + } + if ((defining == NULL) || (defining->type != EXP_IF)) { + error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]); + } + switch (defining->state) { + case COND_IF_TRUE: + defining->state = COND_DONE; + defining->ignoring = true; + break; - case COND_DONE: - case COND_NEVER: - break; + case COND_DONE: + case COND_NEVER: + defining->ignoring = true; + break; case COND_ELSE_TRUE: case COND_ELSE_FALSE: error_precond(ERR_WARNING|ERR_PASS1, "`%%elif' after `%%else' ignored"); - istk->conds->state = COND_NEVER; + defining->state = COND_NEVER; + defining->ignoring = true; break; case COND_IF_FALSE: @@ -2659,53 +2733,81 @@ issue_error: */ j = if_condition(expand_mmac_params(tline->next), i); tline->next = NULL; /* it got freed */ - istk->conds->state = + defining->state = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; + defining->ignoring = ((defining->state == COND_IF_TRUE) ? false : true); break; } free_tlist(origline); return DIRECTIVE_FOUND; case PP_ELSE: + if (defining != NULL) { + if ((defining->type != EXP_IF) || (defining->def_depth > 0)) { + return NO_DIRECTIVE_FOUND; + } + } if (tline->next) error_precond(ERR_WARNING|ERR_PASS1, "trailing garbage after `%%else' ignored"); - if (!istk->conds) - error(ERR_FATAL, "`%%else': no matching `%%if'"); - switch(istk->conds->state) { - case COND_IF_TRUE: - case COND_DONE: - istk->conds->state = COND_ELSE_FALSE; - break; - - case COND_NEVER: - break; - - case COND_IF_FALSE: - istk->conds->state = COND_ELSE_TRUE; - break; + if ((defining == NULL) || (defining->type != EXP_IF)) { + error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]); + } + switch (defining->state) { + case COND_IF_TRUE: + case COND_DONE: + defining->state = COND_ELSE_FALSE; + defining->ignoring = true; + break; + + case COND_NEVER: + defining->ignoring = true; + break; + + case COND_IF_FALSE: + defining->state = COND_ELSE_TRUE; + defining->ignoring = false; + break; case COND_ELSE_TRUE: case COND_ELSE_FALSE: error_precond(ERR_WARNING|ERR_PASS1, "`%%else' after `%%else' ignored."); - istk->conds->state = COND_NEVER; + defining->state = COND_NEVER; + defining->ignoring = true; break; } free_tlist(origline); return DIRECTIVE_FOUND; case PP_ENDIF: + if (defining != NULL) { + if (defining->type == EXP_IF) { + if (defining->def_depth > 0) { + defining->def_depth --; + return NO_DIRECTIVE_FOUND; + } + } else { + return NO_DIRECTIVE_FOUND; + } + } if (tline->next) error_precond(ERR_WARNING|ERR_PASS1, "trailing garbage after `%%endif' ignored"); - if (!istk->conds) - error(ERR_FATAL, "`%%endif': no matching `%%if'"); - cond = istk->conds; - istk->conds = cond->next; - nasm_free(cond); - if(istk->mstk) - istk->mstk->condcnt --; + if ((defining == NULL) || (defining->type != EXP_IF)) { + error(ERR_NONFATAL, "`%%endif': no matching `%%if'"); + } + ed = defining; + defining = ed->prev; + ed->prev = expansions; + expansions = ed; + ei = new_ExpInv(); + ei->type = EXP_IF; + ei->def = ed; + ei->current = ed->line; + ei->emitting = true; + ei->prev = istk->expansion; + istk->expansion = ei; free_tlist(origline); return DIRECTIVE_FOUND; @@ -2713,99 +2815,123 @@ issue_error: case PP_IRMACRO: case PP_MACRO: case PP_IMACRO: - if (defining) { - error(ERR_FATAL, "`%s': already defining a macro", - pp_directives[i]); - return DIRECTIVE_FOUND; - } - defining = nasm_malloc(sizeof(MMacro)); - defining->max_depth = + if (defining != NULL) { + if (defining->type == EXP_MMACRO) { + defining->def_depth ++; + } + return NO_DIRECTIVE_FOUND; + } + ed = new_ExpDef(); + ed->max_depth = (i == PP_RMACRO) || (i == PP_IRMACRO) ? DEADMAN_LIMIT : 0; - defining->casesense = (i == PP_MACRO) || (i == PP_RMACRO); - if (!parse_mmacro_spec(tline, defining, pp_directives[i])) { - nasm_free(defining); - defining = NULL; + ed->casesense = (i == PP_MACRO) || (i == PP_RMACRO); + if (!parse_mmacro_spec(tline, ed, pp_directives[i])) { + nasm_free(ed); + ed = NULL; return DIRECTIVE_FOUND; } - - mmac = (MMacro *) hash_findix(&mmacros, defining->name); - while (mmac) { - if (!strcmp(mmac->name, defining->name) && - (mmac->nparam_min <= defining->nparam_max - || defining->plus) - && (defining->nparam_min <= mmac->nparam_max - || mmac->plus)) { - error(ERR_WARNING|ERR_PASS1, - "redefining multi-line macro `%s'", defining->name); - return DIRECTIVE_FOUND; - } - mmac = mmac->next; - } + ed->type = EXP_MMACRO; + ed->def_depth = 0; + ed->cur_depth = 0; + ed->max_depth = (ed->max_depth + 1); + ed->ignoring = false; + ed->prev = defining; + defining = ed; + + eed = (ExpDef *) hash_findix(&expdefs, ed->name); + while (eed) { + if (!strcmp(eed->name, ed->name) && + (eed->nparam_min <= ed->nparam_max + || ed->plus) + && (ed->nparam_min <= eed->nparam_max + || eed->plus)) { + error(ERR_WARNING|ERR_PASS1, + "redefining multi-line macro `%s'", ed->name); + return DIRECTIVE_FOUND; + } + eed = eed->next; + } free_tlist(origline); return DIRECTIVE_FOUND; case PP_ENDM: case PP_ENDMACRO: - if (! (defining && defining->name)) { - error(ERR_NONFATAL, "`%s': not defining a macro", tline->text); - return DIRECTIVE_FOUND; - } - mmhead = (MMacro **) hash_findi_add(&mmacros, defining->name); - defining->next = *mmhead; - *mmhead = defining; - defining = NULL; + if (defining != NULL) { + if (defining->type == EXP_MMACRO) { + if (defining->def_depth > 0) { + defining->def_depth --; + return NO_DIRECTIVE_FOUND; + } + } else { + return NO_DIRECTIVE_FOUND; + } + } + if (!(defining) || (defining->type != EXP_MMACRO)) { + error(ERR_NONFATAL, "`%s': not defining a macro", tline->text); + return DIRECTIVE_FOUND; + } + edhead = (ExpDef **) hash_findi_add(&expdefs, defining->name); + defining->next = *edhead; + *edhead = defining; + ed = defining; + defining = ed->prev; + ed->prev = expansions; + expansions = ed; + ed = NULL; free_tlist(origline); return DIRECTIVE_FOUND; case PP_EXITMACRO: - /* - * We must search along istk->expansion until we hit a - * macro-end marker for a macro with a name. Then we - * bypass all lines between exitmacro and endmacro. - */ - list_for_each(l, istk->expansion) - if (l->finishes && l->finishes->name) - break; - - if (l) { - /* - * Remove all conditional entries relative to this - * macro invocation. (safe to do in this context) - */ - for ( ; l->finishes->condcnt > 0; l->finishes->condcnt --) { - cond = istk->conds; - istk->conds = cond->next; - nasm_free(cond); - } - istk->expansion = l; - } else { - error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block"); - } + if (defining != NULL) return NO_DIRECTIVE_FOUND; + /* + * We must search along istk->expansion until we hit a + * macro invocation. Then we disable the emitting state(s) + * between exitmacro and endmacro. + */ + for (ei = istk->expansion; ei != NULL; ei = ei->prev) { + if(ei->type == EXP_MMACRO) { + break; + } + } + + if (ei != NULL) { + /* + * Set all invocations leading back to the macro + * invocation to a non-emitting state. + */ + for (eei = istk->expansion; eei != ei; eei = eei->prev) { + eei->emitting = false; + } + eei->emitting = false; + } else { + error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block"); + } free_tlist(origline); return DIRECTIVE_FOUND; case PP_UNMACRO: case PP_UNIMACRO: + if (defining != NULL) return NO_DIRECTIVE_FOUND; { - MMacro **mmac_p; - MMacro spec; + ExpDef **ed_p; + ExpDef spec; spec.casesense = (i == PP_UNMACRO); if (!parse_mmacro_spec(tline, &spec, pp_directives[i])) { return DIRECTIVE_FOUND; } - mmac_p = (MMacro **) hash_findi(&mmacros, spec.name, NULL); - while (mmac_p && *mmac_p) { - mmac = *mmac_p; - if (mmac->casesense == spec.casesense && - !mstrcmp(mmac->name, spec.name, spec.casesense) && - mmac->nparam_min == spec.nparam_min && - mmac->nparam_max == spec.nparam_max && - mmac->plus == spec.plus) { - *mmac_p = mmac->next; - free_mmacro(mmac); + ed_p = (ExpDef **) hash_findi(&expdefs, spec.name, NULL); + while (ed_p && *ed_p) { + ed = *ed_p; + if (ed->casesense == spec.casesense && + !mstrcmp(ed->name, spec.name, spec.casesense) && + ed->nparam_min == spec.nparam_min && + ed->nparam_max == spec.nparam_max && + ed->plus == spec.plus) { + *ed_p = ed->next; + free_expdef(ed); } else { - mmac_p = &mmac->next; + ed_p = &ed->next; } } free_tlist(origline); @@ -2814,6 +2940,7 @@ issue_error: } case PP_ROTATE: + if (defining != NULL) return NO_DIRECTIVE_FOUND; if (tline->next && tline->next->type == TOK_WHITESPACE) tline = tline->next; if (!tline->next) { @@ -2839,26 +2966,33 @@ issue_error: error(ERR_NONFATAL, "non-constant value given to `%%rotate'"); return DIRECTIVE_FOUND; } - mmac = istk->mstk; - while (mmac && !mmac->name) /* avoid mistaking %reps for macros */ - mmac = mmac->next_active; - if (!mmac) { - error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call"); - } else if (mmac->nparam == 0) { - error(ERR_NONFATAL, - "`%%rotate' invoked within macro without parameters"); - } else { - int rotate = mmac->rotate + reloc_value(evalresult); - - rotate %= (int)mmac->nparam; - if (rotate < 0) - rotate += mmac->nparam; - - mmac->rotate = rotate; - } + for (ei = istk->expansion; ei != NULL; ei = ei->prev) { + if (ei->type == EXP_MMACRO) { + break; + } + } + if (ei == NULL) { + error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call"); + } else if (ei->nparam == 0) { + error(ERR_NONFATAL, + "`%%rotate' invoked within macro without parameters"); + } else { + int rotate = ei->rotate + reloc_value(evalresult); + + rotate %= (int)ei->nparam; + if (rotate < 0) + rotate += ei->nparam; + ei->rotate = rotate; + } return DIRECTIVE_FOUND; case PP_REP: + if (defining != NULL) { + if (defining->type == EXP_REP) { + defining->def_depth ++; + } + return NO_DIRECTIVE_FOUND; + } nolist = false; do { tline = tline->next; @@ -2895,26 +3029,29 @@ issue_error: count = 0; } free_tlist(origline); - - tmp_defining = defining; - defining = nasm_malloc(sizeof(MMacro)); - defining->prev = NULL; - defining->name = NULL; /* flags this macro as a %rep block */ - defining->casesense = false; - defining->plus = false; - defining->nolist = nolist; - defining->in_progress = count; - defining->max_depth = 0; - defining->nparam_min = defining->nparam_max = 0; - defining->defaults = NULL; - defining->dlist = NULL; - defining->expansion = NULL; - defining->next_active = istk->mstk; - defining->rep_nest = tmp_defining; + ed = new_ExpDef(); + ed->type = EXP_REP; + ed->nolist = nolist; + ed->def_depth = 0; + ed->cur_depth = 1; + ed->max_depth = (count - 1); + ed->ignoring = false; + ed->prev = defining; + defining = ed; return DIRECTIVE_FOUND; case PP_ENDREP: - if (!defining || defining->name) { + if (defining != NULL) { + if (defining->type == EXP_REP) { + if (defining->def_depth > 0) { + defining->def_depth --; + return NO_DIRECTIVE_FOUND; + } + } else { + return NO_DIRECTIVE_FOUND; + } + } + if ((defining == NULL) || (defining->type != EXP_REP)) { error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'"); return DIRECTIVE_FOUND; } @@ -2930,34 +3067,48 @@ issue_error: * continues) until the whole expansion is forcibly removed * from istk->expansion by a %exitrep. */ - l = nasm_malloc(sizeof(Line)); - l->next = istk->expansion; - l->finishes = defining; - l->first = NULL; - istk->expansion = l; - - istk->mstk = defining; - - list->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); - tmp_defining = defining; - defining = defining->rep_nest; + ed = defining; + defining = ed->prev; + ed->prev = expansions; + expansions = ed; + ei = new_ExpInv(); + ei->type = EXP_REP; + ei->def = ed; + ei->current = ed->line; + ei->emitting = ((ed->max_depth > 0) ? true : false); + list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); + ei->prev = istk->expansion; + istk->expansion = ei; free_tlist(origline); return DIRECTIVE_FOUND; case PP_EXITREP: - /* - * We must search along istk->expansion until we hit a - * macro-end marker for a macro with no name. Then we set - * its `in_progress' flag to 0. - */ - list_for_each(l, istk->expansion) - if (l->finishes && !l->finishes->name) - break; - - if (l) - l->finishes->in_progress = 1; - else - error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block"); + if (defining != NULL) return NO_DIRECTIVE_FOUND; + /* + * We must search along istk->expansion until we hit a + * rep invocation. Then we disable the emitting state(s) + * between exitrep and endrep. + */ + for (ei = istk->expansion; ei != NULL; ei = ei->prev) { + if (ei->type == EXP_REP) { + break; + } + } + + if (ei != NULL) { + /* + * Set all invocations leading back to the rep + * invocation to a non-emitting state. + */ + for (eei = istk->expansion; eei != ei; eei = eei->prev) { + eei->emitting = false; + } + eei->emitting = false; + eei->current = NULL; + eei->def->cur_depth = eei->def->max_depth; + } else { + error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block"); + } free_tlist(origline); return DIRECTIVE_FOUND; @@ -2965,6 +3116,7 @@ issue_error: case PP_IXDEFINE: case PP_DEFINE: case PP_IDEFINE: + if (defining != NULL) return NO_DIRECTIVE_FOUND; casesense = (i == PP_DEFINE || i == PP_XDEFINE); tline = tline->next; @@ -3056,6 +3208,7 @@ issue_error: return DIRECTIVE_FOUND; case PP_UNDEF: + if (defining != NULL) return NO_DIRECTIVE_FOUND; tline = tline->next; skip_white_(tline); tline = expand_id(tline); @@ -3079,6 +3232,7 @@ issue_error: case PP_DEFSTR: case PP_IDEFSTR: + if (defining != NULL) return NO_DIRECTIVE_FOUND; casesense = (i == PP_DEFSTR); tline = tline->next; @@ -3120,6 +3274,7 @@ issue_error: case PP_DEFTOK: case PP_IDEFTOK: + if (defining != NULL) return NO_DIRECTIVE_FOUND; casesense = (i == PP_DEFTOK); tline = tline->next; @@ -3166,6 +3321,7 @@ issue_error: return DIRECTIVE_FOUND; case PP_PATHSEARCH: + if (defining != NULL) return NO_DIRECTIVE_FOUND; { FILE *fp; StrList *xsl = NULL; @@ -3232,6 +3388,7 @@ issue_error: } case PP_STRLEN: + if (defining != NULL) return NO_DIRECTIVE_FOUND; casesense = true; tline = tline->next; @@ -3278,6 +3435,7 @@ issue_error: return DIRECTIVE_FOUND; case PP_STRCAT: + if (defining != NULL) return NO_DIRECTIVE_FOUND; casesense = true; tline = tline->next; @@ -3339,6 +3497,7 @@ issue_error: return DIRECTIVE_FOUND; case PP_SUBSTR: + if (defining != NULL) return NO_DIRECTIVE_FOUND; { int64_t a1, a2; size_t len; @@ -3437,6 +3596,7 @@ issue_error: case PP_ASSIGN: case PP_IASSIGN: + if (defining != NULL) return NO_DIRECTIVE_FOUND; casesense = (i == PP_ASSIGN); tline = tline->next; @@ -3494,6 +3654,7 @@ issue_error: return DIRECTIVE_FOUND; case PP_LINE: + if (defining != NULL) return NO_DIRECTIVE_FOUND; /* * Syntax is `%line nnn[+mmm] [filename]' */ @@ -3684,12 +3845,12 @@ static bool paste_tokens(Token **head, bool handle_paste_tokens) /* * expands to a list of tokens from %{x:y} */ -static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) +static Token *expand_mmac_params_range(ExpInv *ei, Token *tline, Token ***last) { Token *t = tline, **tt, *tm, *head; char *pos; int fst, lst, j, i; - + pos = strchr(tline->text, ':'); nasm_assert(pos); @@ -3705,12 +3866,12 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) goto err; /* the values should be sane */ - if ((fst > (int)mac->nparam || fst < (-(int)mac->nparam)) || - (lst > (int)mac->nparam || lst < (-(int)mac->nparam))) + if ((fst > (int)ei->nparam || fst < (-(int)ei->nparam)) || + (lst > (int)ei->nparam || lst < (-(int)ei->nparam))) goto err; - fst = fst < 0 ? fst + (int)mac->nparam + 1: fst; - lst = lst < 0 ? lst + (int)mac->nparam + 1: lst; + fst = fst < 0 ? fst + (int)ei->nparam + 1: fst; + lst = lst < 0 ? lst + (int)ei->nparam + 1: lst; /* counted from zero */ fst--, lst--; @@ -3718,15 +3879,15 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) /* * it will be at least one token */ - tm = mac->params[(fst + mac->rotate) % mac->nparam]; + tm = ei->params[(fst + ei->rotate) % ei->nparam]; t = new_Token(NULL, tm->type, tm->text, 0); head = t, tt = &t->next; if (fst < lst) { for (i = fst + 1; i <= lst; i++) { t = new_Token(NULL, TOK_OTHER, ",", 0); *tt = t, tt = &t->next; - j = (i + mac->rotate) % mac->nparam; - tm = mac->params[j]; + j = (i + ei->rotate) % ei->nparam; + tm = ei->params[j]; t = new_Token(NULL, tm->type, tm->text, 0); *tt = t, tt = &t->next; } @@ -3734,8 +3895,8 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) for (i = fst - 1; i >= lst; i--) { t = new_Token(NULL, TOK_OTHER, ",", 0); *tt = t, tt = &t->next; - j = (i + mac->rotate) % mac->nparam; - tm = mac->params[j]; + j = (i + ei->rotate) % ei->nparam; + tm = ei->params[j]; t = new_Token(NULL, tm->type, tm->text, 0); *tt = t, tt = &t->next; } @@ -3774,15 +3935,17 @@ static Token *expand_mmac_params(Token * tline) char tmpbuf[30]; unsigned int n; int i; - MMacro *mac; + ExpInv *ei; t = tline; tline = tline->next; - mac = istk->mstk; - while (mac && !mac->name) /* avoid mistaking %reps for macros */ - mac = mac->next_active; - if (!mac) { + for (ei = istk->expansion; ei != NULL; ei = ei->prev) { + if (ei->type == EXP_MMACRO) { + break; + } + } + if (ei == NULL) { error(ERR_NONFATAL, "`%s': not in a macro call", t->text); } else { pos = strchr(t->text, ':'); @@ -3793,24 +3956,29 @@ static Token *expand_mmac_params(Token * tline) * forms %1, %-1, %+1, %%foo, %0. */ case '0': - type = TOK_NUMBER; - snprintf(tmpbuf, sizeof(tmpbuf), "%d", mac->nparam); - text = nasm_strdup(tmpbuf); - break; + if ((strlen(t->text) > 2) && (t->text[2] == '0')) { + type = TOK_ID; + text = nasm_strdup(ei->label_text); + } else { + type = TOK_NUMBER; + snprintf(tmpbuf, sizeof(tmpbuf), "%d", ei->nparam); + text = nasm_strdup(tmpbuf); + } + break; case '%': type = TOK_ID; snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".", - mac->unique); + ei->unique); text = nasm_strcat(tmpbuf, t->text + 2); break; case '-': n = atoi(t->text + 2) - 1; - if (n >= mac->nparam) + if (n >= ei->nparam) tt = NULL; else { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; + if (ei->nparam > 1) + n = (n + ei->rotate) % ei->nparam; + tt = ei->params[n]; } cc = find_cc(tt); if (cc == -1) { @@ -3831,12 +3999,12 @@ static Token *expand_mmac_params(Token * tline) break; case '+': n = atoi(t->text + 2) - 1; - if (n >= mac->nparam) + if (n >= ei->nparam) tt = NULL; else { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; + if (ei->nparam > 1) + n = (n + ei->rotate) % ei->nparam; + tt = ei->params[n]; } cc = find_cc(tt); if (cc == -1) { @@ -3851,15 +4019,15 @@ static Token *expand_mmac_params(Token * tline) break; default: n = atoi(t->text + 1) - 1; - if (n >= mac->nparam) + if (n >= ei->nparam) tt = NULL; else { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; + if (ei->nparam > 1) + n = (n + ei->rotate) % ei->nparam; + tt = ei->params[n]; } if (tt) { - for (i = 0; i < mac->paramlen[n]; i++) { + for (i = 0; i < ei->paramlen[n]; i++) { *tail = new_Token(NULL, tt->type, tt->text, 0); tail = &(*tail)->next; tt = tt->next; @@ -3873,7 +4041,7 @@ static Token *expand_mmac_params(Token * tline) * seems we have a parameters range here */ Token *head, **last; - head = expand_mmac_params_range(mac, t, &last); + head = expand_mmac_params_range(ei, t, &last); if (head != t) { *tail = head; *last = tline; @@ -4318,19 +4486,19 @@ static Token *expand_id(Token * tline) /* * Determine whether the given line constitutes a multi-line macro - * call, and return the MMacro structure called if so. Doesn't have + * call, and return the ExpDef structure called if so. Doesn't have * to check for an initial label - that's taken care of in * expand_mmacro - but must check numbers of parameters. Guaranteed * to be called with tline->type == TOK_ID, so the putative macro * name is easy to find. */ -static MMacro *is_mmacro(Token * tline, Token *** params_array) +static ExpDef *is_mmacro(Token * tline, Token *** params_array) { - MMacro *head, *m; + ExpDef *head, *ed; Token **params; int nparam; - head = (MMacro *) hash_findix(&mmacros, tline->text); + head = (ExpDef *) hash_findix(&expdefs, tline->text); /* * Efficiency: first we see if any macro exists with the given @@ -4338,10 +4506,10 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array) * count the parameters, and then we look further along the * list if necessary to find the proper MMacro. */ - list_for_each(m, head) - if (!mstrcmp(m->name, tline->text, m->casesense)) + list_for_each(ed, head) + if (!mstrcmp(ed->name, tline->text, ed->casesense)) break; - if (!m) + if (!ed) return NULL; /* @@ -4351,36 +4519,23 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array) count_mmac_params(tline->next, &nparam, ¶ms); /* - * So we know how many parameters we've got. Find the MMacro + * So we know how many parameters we've got. Find the ExpDef * structure that handles this number. */ - while (m) { - if (m->nparam_min <= nparam - && (m->plus || nparam <= m->nparam_max)) { - /* - * This one is right. Just check if cycle removal - * prohibits us using it before we actually celebrate... - */ - if (m->in_progress > m->max_depth) { - if (m->max_depth > 0) { - error(ERR_WARNING, - "reached maximum recursion depth of %i", - m->max_depth); - } - nasm_free(params); - return NULL; - } + while (ed) { + if (ed->nparam_min <= nparam + && (ed->plus || nparam <= ed->nparam_max)) { /* * It's right, and we can use it. Add its default * parameters to the end of our list if necessary. */ - if (m->defaults && nparam < m->nparam_min + m->ndefs) { + if (ed->defaults && nparam < ed->nparam_min + ed->ndefs) { params = nasm_realloc(params, - ((m->nparam_min + m->ndefs + + ((ed->nparam_min + ed->ndefs + 1) * sizeof(*params))); - while (nparam < m->nparam_min + m->ndefs) { - params[nparam] = m->defaults[nparam - m->nparam_min]; + while (nparam < ed->nparam_min + ed->ndefs) { + params[nparam] = ed->defaults[nparam - ed->nparam_min]; nparam++; } } @@ -4389,8 +4544,8 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array) * we're in Plus mode), ignore parameters beyond * nparam_max. */ - if (m->plus && nparam > m->nparam_max) - nparam = m->nparam_max; + if (ed->plus && nparam > ed->nparam_max) + nparam = ed->nparam_max; /* * Then terminate the parameter list, and leave. */ @@ -4400,14 +4555,14 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array) } params[nparam] = NULL; *params_array = params; - return m; + return ed; } /* * This one wasn't right: look for the next one with the * same name. */ - list_for_each(m, m->next) - if (!mstrcmp(m->name, tline->text, m->casesense)) + list_for_each(ed, ed->next) + if (!mstrcmp(ed->name, tline->text, ed->casesense)) break; } @@ -4422,51 +4577,6 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array) return NULL; } - -/* - * Save MMacro invocation specific fields in - * preparation for a recursive macro expansion - */ -static void push_mmacro(MMacro *m) -{ - MMacroInvocation *i; - - i = nasm_malloc(sizeof(MMacroInvocation)); - i->prev = m->prev; - i->params = m->params; - i->iline = m->iline; - i->nparam = m->nparam; - i->rotate = m->rotate; - i->paramlen = m->paramlen; - i->unique = m->unique; - i->condcnt = m->condcnt; - m->prev = i; -} - - -/* - * Restore MMacro invocation specific fields that were - * saved during a previous recursive macro expansion - */ -static void pop_mmacro(MMacro *m) -{ - MMacroInvocation *i; - - if (m->prev) { - i = m->prev; - m->prev = i->prev; - m->params = i->params; - m->iline = i->iline; - m->nparam = i->nparam; - m->rotate = i->rotate; - m->paramlen = i->paramlen; - m->unique = i->unique; - m->condcnt = i->condcnt; - nasm_free(i); - } -} - - /* * Expand the multi-line macro call made by the given line, if * there is one to be expanded. If there is, push the expansion on @@ -4478,8 +4588,9 @@ static int expand_mmacro(Token * tline) Token *label = NULL; int dont_prepend = 0; Token **params, *t, *mtok, *tt; - MMacro *m; - Line *l, *ll; + Line *l; + ExpDef *ed; + ExpInv *ei; int i, nparam, *paramlen; const char *mname; @@ -4489,8 +4600,8 @@ static int expand_mmacro(Token * tline) if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID)) return 0; mtok = t; - m = is_mmacro(t, ¶ms); - if (m) { + ed = is_mmacro(t, ¶ms); + if (ed != NULL) { mname = t->text; } else { Token *last; @@ -4510,7 +4621,7 @@ static int expand_mmacro(Token * tline) if (tok_type_(t, TOK_WHITESPACE)) last = t, t = t->next; } - if (!tok_type_(t, TOK_ID) || !(m = is_mmacro(t, ¶ms))) + if (!tok_type_(t, TOK_ID) || !(ed = is_mmacro(t, ¶ms))) return 0; last->next = NULL; mname = t->text; @@ -4527,7 +4638,7 @@ static int expand_mmacro(Token * tline) for (i = 0; params[i]; i++) { int brace = false; - int comma = (!m->plus || i < nparam - 1); + int comma = (!ed->plus || i < nparam - 1); t = params[i]; skip_white_(t); @@ -4548,6 +4659,17 @@ static int expand_mmacro(Token * tline) } } + if (ed->cur_depth >= ed->max_depth) { + if (ed->max_depth > 1) { + error(ERR_WARNING, + "reached maximum macro recursion depth of %i for %s", + ed->max_depth,ed->name); + } + return 0; + } else { + ed->cur_depth ++; + } + /* * OK, we have a MMacro structure together with a set of * parameters. We must now go through the expansion and push @@ -4561,42 +4683,34 @@ static int expand_mmacro(Token * tline) * macro as in progress, and set up its invocation-specific * variables. */ - ll = nasm_malloc(sizeof(Line)); - ll->next = istk->expansion; - ll->finishes = m; - ll->first = NULL; - istk->expansion = ll; - - /* - * Save the previous MMacro expansion in the case of - * macro recursion - */ - if (m->max_depth && m->in_progress) - push_mmacro(m); - - m->in_progress ++; - m->params = params; - m->iline = tline; - m->nparam = nparam; - m->rotate = 0; - m->paramlen = paramlen; - m->unique = unique++; - m->lineno = 0; - m->condcnt = 0; - - m->next_active = istk->mstk; - istk->mstk = m; - + ei = new_ExpInv(); + ei->type = EXP_MMACRO; + ei->def = ed; +// ei->label = label; + ei->label_text = detoken(label, false); + ei->current = ed->line; + ei->emitting = true; +// ei->iline = tline; + ei->params = params; + ei->nparam = nparam; + ei->rotate = 0; + ei->paramlen = paramlen; + ei->lineno = 0; + + ei->prev = istk->expansion; + istk->expansion = ei; + + /***** todo: relocate %? (Q) and %?? (QQ); %00 already relocated *****/ + /* list_for_each(l, m->expansion) { Token **tail; - ll = nasm_malloc(sizeof(Line)); - ll->finishes = NULL; - ll->next = istk->expansion; - istk->expansion = ll; - tail = &ll->first; + l = new_Line(); + l->next = istk->expansion; + istk->expansion = l; + tail = &l->first; - list_for_each(t, l->first) { + list_for_each(t, ei->current->first) { Token *x = t; switch (t->type) { case TOK_PREPROC_Q: @@ -4612,7 +4726,7 @@ static int expand_mmacro(Token * tline) if (!x) continue; } - /* fall through */ + // fall through default: tt = *tail = new_Token(NULL, x->type, x->text, 0); break; @@ -4620,7 +4734,7 @@ static int expand_mmacro(Token * tline) tail = &tt->next; } *tail = NULL; - } + */ /* * If we had a label, push it on as the first line of @@ -4630,11 +4744,9 @@ static int expand_mmacro(Token * tline) if (dont_prepend < 0) free_tlist(startline); else { - ll = nasm_malloc(sizeof(Line)); - ll->finishes = NULL; - ll->next = istk->expansion; - istk->expansion = ll; - ll->first = startline; + l = new_Line(); + ei->label = l; + l->first = startline; if (!dont_prepend) { while (label->next) label = label->next; @@ -4643,7 +4755,7 @@ static int expand_mmacro(Token * tline) } } - list->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); + list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); return 1; } @@ -4655,11 +4767,15 @@ static void verror(int severity, const char *fmt, va_list arg) vsnprintf(buff, sizeof(buff), fmt, arg); - if (istk && istk->mstk && istk->mstk->name) - nasm_error(severity, "(%s:%d) %s", istk->mstk->name, - istk->mstk->lineno, buff); - else + if ((istk != NULL) && + (istk->expansion != NULL) && + (istk->expansion->type == EXP_MMACRO)) { + ExpDef *ed = istk->expansion->def; + nasm_error(severity, "(%s:%d) %s", ed->name, + istk->expansion->lineno, buff); + } else { nasm_error(severity, "%s", buff); + } } /* @@ -4671,7 +4787,10 @@ static void error(int severity, const char *fmt, ...) va_list arg; /* If we're in a dead branch of IF or something like it, ignore the error */ - if (istk && istk->conds && !emitting(istk->conds->state)) + if ((istk != NULL) && + (istk->expansion != NULL) && + (istk->expansion->type == EXP_IF) && + !emitting(istk->expansion->def->state)) return; va_start(arg, fmt); @@ -4690,7 +4809,10 @@ static void error_precond(int severity, const char *fmt, ...) va_list arg; /* Only ignore the error if it's really in a dead branch */ - if (istk && istk->conds && istk->conds->state == COND_NEVER) + if ((istk != NULL) && + (istk->expansion != NULL) && + (istk->expansion->type == EXP_IF) && + (istk->expansion->def->state == COND_NEVER)) return; va_start(arg, fmt); @@ -4706,9 +4828,7 @@ pp_reset(char *file, int apass, ListGen * listgen, StrList **deplist) cstk = NULL; istk = nasm_malloc(sizeof(Include)); istk->next = NULL; - istk->conds = NULL; istk->expansion = NULL; - istk->mstk = NULL; istk->fp = fopen(file, "r"); istk->fname = NULL; src_set_fname(nasm_strdup(file)); @@ -4763,114 +4883,79 @@ static char *pp_getline(void) { char *line; Token *tline; - + while (1) { /* - * Fetch a tokenized line, either from the macro-expansion + * Fetch a tokenized line, either from the expansion * buffer or from the input file. */ tline = NULL; - while (istk->expansion && istk->expansion->finishes) { - Line *l = istk->expansion; - if (!l->finishes->name && l->finishes->in_progress > 1) { - Line *ll; - - /* - * This is a macro-end marker for a macro with no - * name, which means it's not really a macro at all - * but a %rep block, and the `in_progress' field is - * more than 1, meaning that we still need to - * repeat. (1 means the natural last repetition; 0 - * means termination by %exitrep.) We have - * therefore expanded up to the %endrep, and must - * push the whole block on to the expansion buffer - * again. We don't bother to remove the macro-end - * marker: we'd only have to generate another one - * if we did. - */ - l->finishes->in_progress--; - list_for_each(l, l->finishes->expansion) { - Token *t, *tt, **tail; - - ll = nasm_malloc(sizeof(Line)); - ll->next = istk->expansion; - ll->finishes = NULL; - ll->first = NULL; - tail = &ll->first; - - list_for_each(t, l->first) { - if (t->text || t->type == TOK_WHITESPACE) { - tt = *tail = new_Token(NULL, t->type, t->text, 0); - tail = &tt->next; - } - } - - istk->expansion = ll; - } - } else { - /* - * Check whether a `%rep' was started and not ended - * within this macro expansion. This can happen and - * should be detected. It's a fatal error because - * I'm too confused to work out how to recover - * sensibly from it. - */ - if (defining) { - if (defining->name) - error(ERR_PANIC, - "defining with name in expansion"); - else if (istk->mstk->name) - error(ERR_FATAL, - "`%%rep' without `%%endrep' within" - " expansion of macro `%s'", - istk->mstk->name); - } - - /* - * FIXME: investigate the relationship at this point between - * istk->mstk and l->finishes - */ - { - MMacro *m = istk->mstk; - istk->mstk = m->next_active; - if (m->name) { - /* - * This was a real macro call, not a %rep, and - * therefore the parameter information needs to - * be freed. - */ - if (m->prev) { - pop_mmacro(m); - l->finishes->in_progress --; - } else { - nasm_free(m->params); - free_tlist(m->iline); - nasm_free(m->paramlen); - l->finishes->in_progress = 0; - } - } else - free_mmacro(m); - } - istk->expansion = l->next; - nasm_free(l); - list->downlevel(LIST_MACRO); - } - } + while (1) { /* until we get a line we can use */ - - if (istk->expansion) { /* from a macro expansion */ - char *p; - Line *l = istk->expansion; - if (istk->mstk) - istk->mstk->lineno++; - tline = l->first; - istk->expansion = l->next; - nasm_free(l); - p = detoken(tline, false); - list->line(LIST_MACRO, p); - nasm_free(p); - break; - } + /* + * Fetch a tokenized line from the expansion buffer + */ + if (istk->expansion != NULL) { + + ExpInv *e = istk->expansion; + if (e->current != NULL) { + if (e->emitting == false) { + e->current = NULL; + continue; + } + Line *l = NULL; + l = e->current; + e->current = l->next; + e->lineno++; + tline = copy_Token(l->first); + if (((e->type == EXP_REP) || (e->type == EXP_MMACRO)) + && (e->def->nolist == false)) { + char *p = detoken(tline, false); + list->line(LIST_MACRO, p); + nasm_free(p); + } + break; + } else if ((e->type == EXP_REP) && + (e->def->cur_depth < e->def->max_depth)) { + e->def->cur_depth ++; + e->current = e->def->line; + e->lineno = 0; + continue; + } else { + istk->expansion = e->prev; + ExpDef *ed = e->def; + if (ed != NULL) { + if (ed->cur_depth > 0) { + ed->cur_depth --; + } else if ((ed->type != EXP_MMACRO) && (ed->type != EXP_IF)) { + /***** should this really be right here??? *****/ + /* + Line *l = NULL, *ll = NULL; + for (l = ed->line; l != NULL;) { + if (l->first != NULL) { + free_tlist(l->first); + l->first = NULL; + } + ll = l; + l = l->next; + nasm_free(ll); + } + expansions = ed->prev; + nasm_free(ed); + */ + } + if ((e->type == EXP_REP) || (e->type == EXP_MMACRO)) { + list->downlevel(LIST_MACRO); + } + } + nasm_free(e); + continue; + } + } + + /* + * Read in line from input and tokenize + */ line = read_line(); if (line) { /* from the current input file */ line = prepreproc(line); @@ -4878,15 +4963,17 @@ static char *pp_getline(void) nasm_free(line); break; } + /* * The current file has ended; work down the istk */ { Include *i = istk; fclose(i->fp); - if (i->conds) - error(ERR_FATAL, - "expected `%%endif' before end of file"); + if (i->expansion != NULL) { + error(ERR_FATAL, + "end of file while still in an expansion"); + } /* only set line and file name if there's a next node */ if (i->next) { src_set_linnum(i->lineno); @@ -4895,64 +4982,50 @@ static char *pp_getline(void) istk = i->next; list->downlevel(LIST_INCLUDE); nasm_free(i); - if (!istk) + if (istk == NULL) { return NULL; - if (istk->expansion && istk->expansion->finishes) - break; + } + continue; } - } - - /* - * We must expand MMacro parameters and MMacro-local labels - * _before_ we plunge into directive processing, to cope - * with things like `%define something %1' such as STRUC - * uses. Unless we're _defining_ a MMacro, in which case - * those tokens should be left alone to go into the - * definition; and unless we're in a non-emitting - * condition, in which case we don't want to meddle with - * anything. - */ - if (!defining && !(istk->conds && !emitting(istk->conds->state)) - && !(istk->mstk && !istk->mstk->in_progress)) { - tline = expand_mmac_params(tline); - } - + } + + if (defining == NULL) { + tline = expand_mmac_params(tline); + } + /* * Check the line to see if it's a preprocessor directive. */ if (do_directive(tline) == DIRECTIVE_FOUND) { continue; - } else if (defining) { + } else if (defining != NULL) { /* - * We're defining a multi-line macro. We emit nothing - * at all, and just - * shove the tokenized line on to the macro definition. + * We're defining an expansion. We emit nothing at all, + * and just shove the tokenized line on to the definition. */ - Line *l = nasm_malloc(sizeof(Line)); - l->next = defining->expansion; - l->first = tline; - l->finishes = NULL; - defining->expansion = l; + if (defining->ignoring == false) { + Line *l = new_Line(); + l->first = tline; + if (defining->line == NULL) { + defining->line = l; + defining->last = l; + } else { + defining->last->next = l; + defining->last = l; + } + } else { + //free_tlist(tline); /***** sanity check: is this supposed to be here? *****/ + } continue; - } else if (istk->conds && !emitting(istk->conds->state)) { + } else if ((istk->expansion != NULL) && + (istk->expansion->emitting != true)) { /* - * We're in a non-emitting branch of a condition block. + * We're in a non-emitting branch of an expansion. * Emit nothing at all, not even a blank line: when we - * emerge from the condition we'll give a line-number + * emerge from the expansion we'll give a line-number * directive so we keep our place correctly. */ - free_tlist(tline); - continue; - } else if (istk->mstk && !istk->mstk->in_progress) { - /* - * We're in a %rep block which has been terminated, so - * we're walking through to the %endrep without - * emitting anything. Emit nothing at all, not even a - * blank line: when we emerge from the %rep block we'll - * give a line-number directive so we keep our place - * correctly. - */ - free_tlist(tline); + free_tlist(tline); continue; } else { tline = expand_smacro(tline); @@ -4960,36 +5033,28 @@ static char *pp_getline(void) /* * De-tokenize the line again, and emit it. */ - line = detoken(tline, true); - free_tlist(tline); + line = detoken(tline, true); + free_tlist(tline); break; } else { continue; /* expand_mmacro calls free_tlist */ } } - } - - return line; + } + return line; } static void pp_cleanup(int pass) { - if (defining) { - if (defining->name) { - error(ERR_NONFATAL, - "end of file while still defining macro `%s'", - defining->name); - } else { - error(ERR_NONFATAL, "end of file while still in %%rep"); - } - - free_mmacro(defining); - defining = NULL; + if (defining != NULL) { + error(ERR_NONFATAL, "end of file while still defining an expansion"); + nasm_free(defining); /***** todo: free everything to avoid mem leaks *****/ + defining = NULL; } - while (cstk) + while (cstk != NULL) ctx_pop(); free_macros(); - while (istk) { + while (istk != NULL) { Include *i = istk; istk = istk->next; fclose(i->fp); @@ -5039,10 +5104,9 @@ void pp_pre_include(char *fname) space = new_Token(name, TOK_WHITESPACE, NULL, 0); inc = new_Token(space, TOK_PREPROC_ID, "%include", 0); - l = nasm_malloc(sizeof(Line)); + l = new_Line(); l->next = predef; l->first = inc; - l->finishes = NULL; predef = l; } @@ -5061,10 +5125,9 @@ void pp_pre_define(char *definition) if (equals) *equals = '='; - l = nasm_malloc(sizeof(Line)); + l = new_Line(); l->next = predef; l->first = def; - l->finishes = NULL; predef = l; } @@ -5077,18 +5140,15 @@ void pp_pre_undefine(char *definition) def = new_Token(space, TOK_PREPROC_ID, "%undef", 0); space->next = tokenize(definition); - l = nasm_malloc(sizeof(Line)); + l = new_Line(); l->next = predef; l->first = def; - l->finishes = NULL; predef = l; } /* - * Added by Keith Kanios: - * * This function is used to assist with "runtime" preprocessor - * directives. (e.g. pp_runtime("%define __BITS__ 64");) + * directives, e.g. pp_runtime("%define __BITS__ 64"); * * ERRORS ARE IGNORED HERE, SO MAKE COMPLETELY SURE THAT YOU * PASS A VALID STRING TO THIS FUNCTION!!!!! |