summaryrefslogtreecommitdiff
path: root/preproc.c
diff options
context:
space:
mode:
authorCyrill Gorcunov <gorcunov@gmail.com>2010-06-05 01:50:23 +0400
committerCyrill Gorcunov <gorcunov@gmail.com>2010-06-05 01:50:59 +0400
commitc29404d7bad7308218ef04b8c22d4d9c54adbfad (patch)
tree33fd5c7b5a2eef8cb0f5c29548161c2834f7e113 /preproc.c
parentca61119a01fd7174368a0144b6b5fe96ee2a26df (diff)
downloadnasm-c29404d7bad7308218ef04b8c22d4d9c54adbfad.tar.gz
nasm-c29404d7bad7308218ef04b8c22d4d9c54adbfad.tar.bz2
nasm-c29404d7bad7308218ef04b8c22d4d9c54adbfad.zip
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>
Diffstat (limited to 'preproc.c')
-rw-r--r--preproc.c241
1 files changed, 164 insertions, 77 deletions
diff --git a/preproc.c b/preproc.c
index 248e13a..70933f8 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 {