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 <nasm64developer@users.sf.net>
Inspired-by: Mathieu Monnier <mathieu.monnier@polytechnique.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
This commit is contained in:
Cyrill Gorcunov 2010-06-05 01:50:23 +04:00
parent ca61119a01
commit c29404d7ba

247
preproc.c
View File

@ -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) {
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;
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 {
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;
}
} 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;
}
text = NULL; /* we've done it here */
break;
}
}
if (!text) {
delete_Token(t);
} else {