From c29404d7bad7308218ef04b8c22d4d9c54adbfad Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 5 Jun 2010 01:50:23 +0400 Subject: preproc.c: Introduce macros parameters range expansion Introduce an ability to expand multi-line macros parameters in a range/sequence manner. For this purpose a special form is introduced %{x:y} which means to expand %{x:y} to %{x},%{x+1},%{x+2},...,%{y}. Both arguments could be negative or positive but MUST NOT be zero. The arguments take into account possible %rotate as well. Note that unlike the approach implemented in yasm we refer :-1 as _last_ argument passed to a macro call, this makes possible to refer the last element from macro via record as %{-1:-1} which could be a convenient trick. Also you can refer the argument in reverse order, ie it's legitime to write %{5:4}, or even to reverse the all arguments %{-1:1}. An example | | %macro mpar 1-* | db %{1:-2} | %endmacro | | mpar 1,2,3,4,5,6 in result we'll get the sequence of 1,2,3,4,5 Reported-by: nasm64developer Inspired-by: Mathieu Monnier Signed-off-by: Cyrill Gorcunov --- preproc.c | 241 ++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 164 insertions(+), 77 deletions(-) (limited to 'preproc.c') diff --git a/preproc.c b/preproc.c index 248e13a4..70933f86 100644 --- a/preproc.c +++ b/preproc.c @@ -3592,15 +3592,86 @@ static bool paste_tokens(Token **head, bool handle_paste_tokens) } return did_paste; } + +/* + * expands to a list of tokens from %{x:y} + */ +static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) +{ + Token *t = tline, **tt, *tm, *head; + char *pos; + int fst, lst, j, i; + + pos = strchr(tline->text, ':'); + nasm_assert(pos); + + lst = atoi(pos + 1); + fst = atoi(tline->text + 1); + + /* + * only macros params are accounted so + * if someone passes %0 -- we reject such + * value(s) + */ + if (lst == 0 || fst == 0) + goto err; + + /* the values should be sane */ + if ((fst > mac->nparam || fst < -(int)mac->nparam) || + (lst > mac->nparam || lst < -(int)mac->nparam)) + goto err; + + fst = fst < 0 ? fst + mac->nparam + 1: fst; + lst = lst < 0 ? lst + mac->nparam + 1: lst; + + /* counted from zero */ + fst--, lst--; + + /* + * it will be at least one token + */ + tm = mac->params[(fst + mac->rotate) % mac->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]; + t = new_Token(NULL, tm->type, tm->text, 0); + *tt = t, tt = &t->next; + } + } else { + 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]; + t = new_Token(NULL, tm->type, tm->text, 0); + *tt = t, tt = &t->next; + } + } + + *last = tt; + return head; + +err: + error(ERR_NONFATAL, "`%%{%s}': macro parameters out of range", + &tline->text[1]); + return tline; +} + /* * Expand MMacro-local things: parameter references (%0, %n, %+n, * %-n) and MMacro-local identifiers (%%foo) as well as - * macro indirection (%[...]). + * macro indirection (%[...]) and range (%{..:..}). */ static Token *expand_mmac_params(Token * tline) { Token *t, *tt, **tail, *thead; bool changed = false; + char *pos; tail = &thead; thead = NULL; @@ -3623,90 +3694,106 @@ static Token *expand_mmac_params(Token * tline) mac = istk->mstk; while (mac && !mac->name) /* avoid mistaking %reps for macros */ mac = mac->next_active; - if (!mac) + if (!mac) { error(ERR_NONFATAL, "`%s': not in a macro call", t->text); - else - switch (t->text[1]) { - /* - * We have to make a substitution of one of the - * forms %1, %-1, %+1, %%foo, %0. - */ - case '0': - type = TOK_NUMBER; - snprintf(tmpbuf, sizeof(tmpbuf), "%d", mac->nparam); - text = nasm_strdup(tmpbuf); - break; - case '%': - type = TOK_ID; - snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".", - mac->unique); - text = nasm_strcat(tmpbuf, t->text + 2); - break; - case '-': - n = atoi(t->text + 2) - 1; - if (n >= mac->nparam) - tt = NULL; - else { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; - } - cc = find_cc(tt); - if (cc == -1) { - error(ERR_NONFATAL, - "macro parameter %d is not a condition code", - n + 1); - text = NULL; - } else { + } else { + pos = strchr(t->text, ':'); + if (!pos) { + switch (t->text[1]) { + /* + * We have to make a substitution of one of the + * forms %1, %-1, %+1, %%foo, %0. + */ + case '0': + type = TOK_NUMBER; + snprintf(tmpbuf, sizeof(tmpbuf), "%d", mac->nparam); + text = nasm_strdup(tmpbuf); + break; + case '%': type = TOK_ID; - if (inverse_ccs[cc] == -1) { + snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".", + mac->unique); + text = nasm_strcat(tmpbuf, t->text + 2); + break; + case '-': + n = atoi(t->text + 2) - 1; + if (n >= mac->nparam) + tt = NULL; + else { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + cc = find_cc(tt); + if (cc == -1) { error(ERR_NONFATAL, - "condition code `%s' is not invertible", - conditions[cc]); + "macro parameter %d is not a condition code", + n + 1); text = NULL; - } else - text = nasm_strdup(conditions[inverse_ccs[cc]]); - } - break; - case '+': - n = atoi(t->text + 2) - 1; - if (n >= mac->nparam) - tt = NULL; - else { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; + } else { + type = TOK_ID; + if (inverse_ccs[cc] == -1) { + error(ERR_NONFATAL, + "condition code `%s' is not invertible", + conditions[cc]); + text = NULL; + } else + text = nasm_strdup(conditions[inverse_ccs[cc]]); + } + break; + case '+': + n = atoi(t->text + 2) - 1; + if (n >= mac->nparam) + tt = NULL; + else { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + cc = find_cc(tt); + if (cc == -1) { + error(ERR_NONFATAL, + "macro parameter %d is not a condition code", + n + 1); + text = NULL; + } else { + type = TOK_ID; + text = nasm_strdup(conditions[cc]); + } + break; + default: + n = atoi(t->text + 1) - 1; + if (n >= mac->nparam) + tt = NULL; + else { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + if (tt) { + for (i = 0; i < mac->paramlen[n]; i++) { + *tail = new_Token(NULL, tt->type, tt->text, 0); + tail = &(*tail)->next; + tt = tt->next; + } + } + text = NULL; /* we've done it here */ + break; } - cc = find_cc(tt); - if (cc == -1) { - error(ERR_NONFATAL, - "macro parameter %d is not a condition code", - n + 1); + } else { + /* + * seems we have a parameters range here + */ + Token *head, **last; + head = expand_mmac_params_range(mac, t, &last); + if (head != t) { + *tail = head; + *last = tline; + tline = head; text = NULL; - } else { - type = TOK_ID; - text = nasm_strdup(conditions[cc]); - } - break; - default: - n = atoi(t->text + 1) - 1; - if (n >= mac->nparam) - tt = NULL; - else { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; } - if (tt) { - for (i = 0; i < mac->paramlen[n]; i++) { - *tail = new_Token(NULL, tt->type, tt->text, 0); - tail = &(*tail)->next; - tt = tt->next; - } - } - text = NULL; /* we've done it here */ - break; } + } if (!text) { delete_Token(t); } else { -- cgit v1.2.1