preproc: Add new %[...] indirection construct

Add a new %[...] construct to support indirect macro expansion.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2008-10-19 15:45:05 -07:00
parent 8b5e68079a
commit 992fe7591d

View File

@ -159,6 +159,7 @@ enum pp_token_type {
TOK_NUMBER, TOK_FLOAT, TOK_SMAC_END, TOK_OTHER,
TOK_INTERNAL_STRING,
TOK_PREPROC_Q, TOK_PREPROC_QQ,
TOK_INDIRECT, /* %[...] */
TOK_SMAC_PARAM, /* MUST BE LAST IN THE LIST!!! */
TOK_MAX = INT_MAX /* Keep compiler from reducing the range */
};
@ -396,6 +397,7 @@ static Blocks blocks = { NULL, NULL };
static Token *expand_mmac_params(Token * tline);
static Token *expand_smacro(Token * tline);
static Token *expand_id(Token * tline);
static Token *expand_indirect(Token * tline, int level);
static Context *get_ctx(const char *name, bool all_contexts);
static void make_tok_num(Token * tok, int64_t val);
static void error(int severity, const char *fmt, ...);
@ -804,6 +806,22 @@ static Token *tokenize(char *line)
if (*p)
p++;
type = TOK_PREPROC_ID;
} else if (*p == '[') {
int lvl = 1;
line += 2; /* Skip the leading %[ */
p++;
while (*p) {
if (*p == ']') {
if (!--lvl)
break;
} else if (*p == '%' && p[1] == '[') {
lvl++;
}
p++;
}
if (*p)
*p++ = '\0';
type = TOK_INDIRECT;
} else if (*p == '?') {
type = TOK_PREPROC_Q; /* %? */
p++;
@ -2446,10 +2464,13 @@ static int do_directive(Token * tline)
* called expand_mmac_params(); however, if we're
* processing an %elif we must have been in a
* non-emitting mode, which would have inhibited
* the normal invocation of expand_mmac_params(). Therefore,
* we have to do it explicitly here.
* the normal invocation of expand_indirect() and
* expand_mmac_params(). Therefore, we have to do it
* explicitly here.
*/
j = if_condition(expand_mmac_params(tline->next), i);
t = expand_indirect(tline->next,0);
t = expand_mmac_params(t);
j = if_condition(expand_mmac_params(t), i);
tline->next = NULL; /* it got freed */
istk->conds->state =
j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
@ -3442,15 +3463,8 @@ static Token *expand_mmac_params(Token * tline)
}
break;
case TOK_ID:
if (tt->type == TOK_ID || tt->type == TOK_NUMBER) {
char *tmp = nasm_strcat(t->text, tt->text);
nasm_free(t->text);
t->text = tmp;
t->next = delete_Token(tt);
}
break;
case TOK_NUMBER:
if (tt->type == TOK_NUMBER) {
if (tt->type == t->type || tt->type == TOK_NUMBER) {
char *tmp = nasm_strcat(t->text, tt->text);
nasm_free(t->text);
t->text = tmp;
@ -3886,6 +3900,61 @@ static Token *expand_id(Token * tline)
return tline;
}
/*
* Expand indirect tokens, %[...].
*/
static Token *expand_indirect(Token * tline, int level)
{
const int max_indirect_level = 1000;
Token *t, *thead, **tp;
Token *it;
bool skip;
if (level >= max_indirect_level) {
error(ERR_NONFATAL, "interminable indirect expansion");
} else {
thead = NULL;
for (tp = &tline; (t = *tp); thead = t, tp = &t->next) {
if (t->type != TOK_INDIRECT)
continue;
it = tokenize(t->text);
it = expand_indirect(it, level+1);
it = expand_smacro(it);
while (it) {
skip = false;
switch (thead ? thead->type : TOK_NONE) {
case TOK_WHITESPACE:
skip = (it->type == TOK_WHITESPACE);
break;
case TOK_ID:
case TOK_NUMBER:
if (it->type == thead->type || it->type == TOK_NUMBER) {
char *tmp = nasm_strcat(thead->text, it->text);
thead->text = tmp;
skip = true;
}
break;
default:
break;
}
if (skip) {
it = delete_Token(it);
} else {
*tp = thead = it;
tp = &it->next;
it = it->next;
}
}
*tp = t->next;
delete_Token(t);
}
}
return tline;
}
/*
* Determine whether the given line constitutes a multi-line macro
* call, and return the MMacro structure called if so. Doesn't have
@ -4428,8 +4497,10 @@ static char *pp_getline(void)
* anything.
*/
if (!defining && !(istk->conds && !emitting(istk->conds->state))
&& !(istk->mstk && !istk->mstk->in_progress))
&& !(istk->mstk && !istk->mstk->in_progress)) {
tline = expand_indirect(tline,0);
tline = expand_mmac_params(tline);
}
/*
* Check the line to see if it's a preprocessor directive.