mirror of
https://github.com/netwide-assembler/nasm.git
synced 2024-11-21 03:14:19 +08:00
preproc: %clear options, backwards compatibility hack for x264
The handling of empty arguments in NASM 2.14 and below was at best "interesting"; a single whitespace token expansion, which can happen during macro expansion, would sometimes be counted as an argument and sometimes not. One really weird effect of this was that %0 doesn't always match the permitted range in the macro specification! Add some backwards compatibility code to make x264/ffmpeg compile. Add override via: %pragma preproc sane_empty_expansion true Add support for %clear to clear specific subsets of the macro definitions. In particular: %clear defalias ... can be used to wipe the __FOO__ backwards macro compatibility aliases which may interfere with the C namespace. Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
parent
f9f37ddcfe
commit
ee0e3ec5a4
452
asm/preproc.c
452
asm/preproc.c
@ -76,6 +76,16 @@
|
||||
#include "tables.h"
|
||||
#include "listing.h"
|
||||
|
||||
/*
|
||||
* Preprocessor execution options that can be controlled by %pragma or
|
||||
* other directives. This structure is initialized to zero on each
|
||||
* pass; this *must* reflect the default initial state.
|
||||
*/
|
||||
static struct pp_opts {
|
||||
bool noaliases;
|
||||
bool sane_empty_expansion;
|
||||
} ppopt;
|
||||
|
||||
typedef struct SMacro SMacro;
|
||||
typedef struct MMacro MMacro;
|
||||
typedef struct MMacroInvocation MMacroInvocation;
|
||||
@ -567,7 +577,6 @@ static int LocalOffset = 0;
|
||||
static Context *cstk;
|
||||
static Include *istk;
|
||||
static const struct strlist *ipath_list;
|
||||
static bool do_aliases;
|
||||
|
||||
static struct strlist *deplist;
|
||||
|
||||
@ -1079,21 +1088,53 @@ static void free_smacro(SMacro *s)
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all currently defined macros, and free the hash tables
|
||||
* Free all currently defined macros, and free the hash tables if empty
|
||||
*/
|
||||
static void free_smacro_table(struct hash_table *smt)
|
||||
enum clear_what {
|
||||
CLEAR_NONE = 0,
|
||||
CLEAR_DEFINE = 1, /* Clear smacros */
|
||||
CLEAR_DEFALIAS = 2, /* Clear smacro aliases */
|
||||
CLEAR_ALLDEFINE = CLEAR_DEFINE|CLEAR_DEFALIAS,
|
||||
CLEAR_MMACRO = 4,
|
||||
CLEAR_ALL = CLEAR_ALLDEFINE|CLEAR_MMACRO
|
||||
};
|
||||
|
||||
static void clear_smacro_table(struct hash_table *smt, enum clear_what what)
|
||||
{
|
||||
struct hash_iterator it;
|
||||
const struct hash_node *np;
|
||||
bool empty = true;
|
||||
|
||||
/*
|
||||
* Walk the hash table and clear out anything we don't want
|
||||
*/
|
||||
hash_for_each(smt, it, np) {
|
||||
SMacro *tmp;
|
||||
SMacro *s = np->data;
|
||||
nasm_free((void *)np->key);
|
||||
list_for_each_safe(s, tmp, s)
|
||||
free_smacro(s);
|
||||
SMacro **head = (SMacro **)&np->data;
|
||||
|
||||
list_for_each_safe(s, tmp, s) {
|
||||
if (what & ((enum clear_what)s->alias + 1)) {
|
||||
*head = s->next;
|
||||
free_smacro(s);
|
||||
} else {
|
||||
empty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
hash_free(smt);
|
||||
|
||||
/*
|
||||
* Free the hash table and keys if and only if it is now empty.
|
||||
* Note: we cannot free keys even for an empty list above, as that
|
||||
* mucks up the hash algorithm.
|
||||
*/
|
||||
if (empty)
|
||||
hash_free_all(smt, true);
|
||||
}
|
||||
|
||||
static void free_smacro_table(struct hash_table *smt)
|
||||
{
|
||||
clear_smacro_table(smt, CLEAR_ALLDEFINE);
|
||||
}
|
||||
|
||||
static void free_mmacro_table(struct hash_table *mmt)
|
||||
@ -2301,7 +2342,7 @@ restart:
|
||||
(nparam <= 0 || m->nparam == 0 || nparam == m->nparam ||
|
||||
(m->greedy && nparam >= m->nparam-1))) {
|
||||
if (m->alias && !find_alias) {
|
||||
if (do_aliases) {
|
||||
if (!ppopt.noaliases) {
|
||||
name = tok_text(m->expansion);
|
||||
goto restart;
|
||||
} else {
|
||||
@ -2344,55 +2385,54 @@ static int read_param_count(const char *str)
|
||||
* Note that we need space in the params array for parameter 0 being
|
||||
* a possible captured label as well as the final NULL.
|
||||
*/
|
||||
static void count_mmac_params(Token * t, int *nparamp, Token ***paramsp)
|
||||
static void count_mmac_params(Token *tline, int *nparamp, Token ***paramsp)
|
||||
{
|
||||
int paramsize;
|
||||
int nparam = 0;
|
||||
Token *t;
|
||||
Token **params;
|
||||
|
||||
paramsize = PARAM_DELTA;
|
||||
params = nasm_malloc(paramsize * sizeof(*params));
|
||||
params[0] = NULL;
|
||||
nasm_newn(params, paramsize);
|
||||
|
||||
while (true) {
|
||||
t = skip_white(t);
|
||||
if (!t && !nparam)
|
||||
break; /* No arguments */
|
||||
t = skip_white(tline);
|
||||
if (t) {
|
||||
while (true) {
|
||||
/* Need two slots for captured label and NULL */
|
||||
if (unlikely(nparam+2 >= paramsize)) {
|
||||
paramsize += PARAM_DELTA;
|
||||
params = nasm_realloc(params, sizeof(*params) * paramsize);
|
||||
}
|
||||
params[++nparam] = t;
|
||||
if (tok_is(t, '{')) {
|
||||
int brace = 1;
|
||||
while (brace && (t = t->next)) {
|
||||
brace += tok_is(t, '{');
|
||||
brace -= tok_is(t, '}');
|
||||
}
|
||||
|
||||
/* 2 slots for captured label and NULL */
|
||||
if (nparam+2 >= paramsize) {
|
||||
paramsize += PARAM_DELTA;
|
||||
params = nasm_realloc(params, sizeof(*params) * paramsize);
|
||||
}
|
||||
params[++nparam] = t;
|
||||
if (tok_is(t, '{')) {
|
||||
int brace = 1;
|
||||
while (brace && (t = t->next)) {
|
||||
brace += tok_is(t, '{');
|
||||
brace -= tok_is(t, '}');
|
||||
if (t) {
|
||||
/*
|
||||
* Now we've found the closing brace, look further
|
||||
* for the comma.
|
||||
*/
|
||||
t = skip_white(t->next);
|
||||
if (tok_isnt(t, ','))
|
||||
nasm_nonfatal("braces do not enclose all of macro parameter");
|
||||
} else {
|
||||
nasm_nonfatal("expecting closing brace in macro parameter");
|
||||
}
|
||||
}
|
||||
|
||||
if (t) {
|
||||
/*
|
||||
* Now we've found the closing brace, look further
|
||||
* for the comma.
|
||||
*/
|
||||
t = skip_white(t->next);
|
||||
if (tok_isnt(t, ','))
|
||||
nasm_nonfatal("braces do not enclose all of macro parameter");
|
||||
} else {
|
||||
nasm_nonfatal("expecting closing brace in macro parameter");
|
||||
}
|
||||
/* Advance to the next comma */
|
||||
while (tok_isnt(t, ','))
|
||||
t = t->next;
|
||||
|
||||
if (!t)
|
||||
break; /* End of string */
|
||||
|
||||
t = skip_white(t->next); /* Eat the comma and whitespace */
|
||||
}
|
||||
|
||||
/* Advance to the next comma */
|
||||
while (tok_isnt(t, ','))
|
||||
t = t->next;
|
||||
|
||||
if (!t)
|
||||
break; /* End of line */
|
||||
|
||||
t = t->next; /* Eat the comma, start over */
|
||||
}
|
||||
|
||||
params[nparam+1] = NULL;
|
||||
@ -2966,7 +3006,7 @@ static SMacro *define_smacro(const char *mname, bool casesense,
|
||||
* some others didn't. What is the right thing to do here?
|
||||
*/
|
||||
goto fail;
|
||||
} else if (!smac->alias || !do_aliases || defining_alias) {
|
||||
} else if (!smac->alias || ppopt.noaliases || defining_alias) {
|
||||
/*
|
||||
* We're redefining, so we have to take over an
|
||||
* existing SMacro structure. This means freeing
|
||||
@ -3035,7 +3075,7 @@ static void undef_smacro(const char *mname, bool undefalias)
|
||||
while ((s = *sp) != NULL) {
|
||||
if (!mstrcmp(s->name, mname, s->casesense)) {
|
||||
if (s->alias && !undefalias) {
|
||||
if (do_aliases) {
|
||||
if (!ppopt.noaliases) {
|
||||
if (s->in_progress) {
|
||||
nasm_nonfatal("macro alias loop");
|
||||
} else {
|
||||
@ -3157,13 +3197,23 @@ static int parse_size(const char *str) {
|
||||
*/
|
||||
static void do_pragma_preproc(Token *tline)
|
||||
{
|
||||
const char *txt;
|
||||
|
||||
/* Skip to the real stuff */
|
||||
tline = tline->next;
|
||||
tline = skip_white(tline);
|
||||
if (!tline)
|
||||
|
||||
if (!tok_type(tline, TOK_ID))
|
||||
return;
|
||||
|
||||
(void)tline; /* Nothing else to do at present */
|
||||
txt = tok_text(tline);
|
||||
if (!nasm_stricmp(txt, "sane_empty_expansion")) {
|
||||
tline = skip_white(tline->next);
|
||||
ppopt.sane_empty_expansion =
|
||||
pp_get_boolean_option(tline, ppopt.sane_empty_expansion);
|
||||
} else {
|
||||
/* Unknown pragma, ignore for now */
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_macro_id(const Token *t)
|
||||
@ -3248,6 +3298,26 @@ static void mark_smac_params(Token *tline, const SMacro *tmpl,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* %clear selected macro sets either globally or in contexts
|
||||
*/
|
||||
static void do_clear(enum clear_what what, bool context)
|
||||
{
|
||||
if (context) {
|
||||
if (what & CLEAR_ALLDEFINE) {
|
||||
Context *ctx;
|
||||
list_for_each(ctx, cstk)
|
||||
clear_smacro_table(&ctx->localmac, what);
|
||||
}
|
||||
/* Nothing else can be context-local */
|
||||
} else {
|
||||
if (what & CLEAR_ALLDEFINE)
|
||||
clear_smacro_table(&smacros, what);
|
||||
if (what & CLEAR_MMACRO)
|
||||
free_mmacro_table(&mmacros);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find and process preprocessor directive in passed line
|
||||
* Find out if a line contains a preprocessor directive, and deal
|
||||
@ -3565,11 +3635,56 @@ static int do_directive(Token *tline, Token **output)
|
||||
break;
|
||||
|
||||
case PP_CLEAR:
|
||||
if (tline->next)
|
||||
{
|
||||
bool context = false;
|
||||
|
||||
t = tline->next = expand_smacro(tline->next);
|
||||
t = skip_white(t);
|
||||
if (!t) {
|
||||
/* Emulate legacy behavior */
|
||||
do_clear(CLEAR_DEFINE|CLEAR_MMACRO, false);
|
||||
} else {
|
||||
while ((t = skip_white(t)) && t->type == TOK_ID) {
|
||||
const char *txt = tok_text(t);
|
||||
if (!nasm_stricmp(txt, "all")) {
|
||||
do_clear(CLEAR_ALL, context);
|
||||
} else if (!nasm_stricmp(txt, "define") ||
|
||||
!nasm_stricmp(txt, "def") ||
|
||||
!nasm_stricmp(txt, "smacro")) {
|
||||
do_clear(CLEAR_DEFINE, context);
|
||||
} else if (!nasm_stricmp(txt, "defalias") ||
|
||||
!nasm_stricmp(txt, "alias") ||
|
||||
!nasm_stricmp(txt, "salias")) {
|
||||
do_clear(CLEAR_DEFALIAS, context);
|
||||
} else if (!nasm_stricmp(txt, "alldef") ||
|
||||
!nasm_stricmp(txt, "alldefine")) {
|
||||
do_clear(CLEAR_ALLDEFINE, context);
|
||||
} else if (!nasm_stricmp(txt, "macro") ||
|
||||
!nasm_stricmp(txt, "mmacro")) {
|
||||
do_clear(CLEAR_MMACRO, context);
|
||||
} else if (!nasm_stricmp(txt, "context") ||
|
||||
!nasm_stricmp(txt, "ctx")) {
|
||||
context = true;
|
||||
} else if (!nasm_stricmp(txt, "global")) {
|
||||
context = false;
|
||||
} else if (!nasm_stricmp(txt, "nothing") ||
|
||||
!nasm_stricmp(txt, "none") ||
|
||||
!nasm_stricmp(txt, "ignore") ||
|
||||
!nasm_stricmp(txt, "-") ||
|
||||
!nasm_stricmp(txt, "--")) {
|
||||
/* Do nothing */
|
||||
} else {
|
||||
nasm_nonfatal("invalid option to %s: %s", dname, txt);
|
||||
t = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t = skip_white(t);
|
||||
if (t)
|
||||
nasm_warn(WARN_OTHER, "trailing garbage after `%s' ignored", dname);
|
||||
free_macros();
|
||||
init_macros();
|
||||
break;
|
||||
}
|
||||
|
||||
case PP_DEPEND:
|
||||
t = tline->next = expand_smacro(tline->next);
|
||||
@ -4419,7 +4534,7 @@ issue_error:
|
||||
case PP_ALIASES:
|
||||
tline = tline->next;
|
||||
tline = expand_smacro(tline);
|
||||
do_aliases = pp_get_boolean_option(tline, do_aliases);
|
||||
ppopt.noaliases = !pp_get_boolean_option(tline, !ppopt.noaliases);
|
||||
break;
|
||||
|
||||
case PP_LINE:
|
||||
@ -4971,6 +5086,39 @@ static Token *expand_mmac_params(Token * tline)
|
||||
}
|
||||
};
|
||||
paste_tokens(&thead, t, ARRAY_SIZE(t), false);
|
||||
|
||||
/*
|
||||
* For backwards compatibility reasons, if we expanded
|
||||
* anything, we cannot return an empty token list. Legacy
|
||||
* NASM behavior is that:
|
||||
*
|
||||
* foobar %1
|
||||
*
|
||||
* ... where foobar is a macro is treated as a one-
|
||||
* parameter macro call with an empty argument, instead
|
||||
* of the far more sensible zero-argument call... except
|
||||
* that %0 is set to zero, which is illegal according to the
|
||||
* macro definition!
|
||||
*
|
||||
* This applies ONLY to the case of zero arguments, which
|
||||
* is what makes it completely brain damaged. If this is
|
||||
* the actual desired behavior, the correct way to code it
|
||||
* is:
|
||||
*
|
||||
* foobar {%1}
|
||||
*
|
||||
* This rather brain damaged backwards compatibility hack can
|
||||
* be disabled with:
|
||||
*
|
||||
* %pragma preproc sane_empty_expansion true
|
||||
*/
|
||||
if (!ppopt.sane_empty_expansion) {
|
||||
for (tail = &thead; tok_white(*tail); tail = &((*tail)->next)) {
|
||||
/* See if we can find anything not whitespace... */
|
||||
}
|
||||
if (!*tail)
|
||||
*tail = new_White(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return thead;
|
||||
@ -5032,7 +5180,7 @@ static SMacro *expand_one_smacro(Token ***tpp)
|
||||
* checking for parameters if necessary.
|
||||
*/
|
||||
list_for_each(m, head) {
|
||||
if (unlikely(m->alias && !do_aliases))
|
||||
if (unlikely(m->alias && ppopt.noaliases))
|
||||
continue;
|
||||
if (!mstrcmp(m->name, mname, m->casesense))
|
||||
break;
|
||||
@ -5598,6 +5746,62 @@ static Token *expand_id(Token * tline)
|
||||
return tline;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called from is_mmacro() after finding a suitable macro.
|
||||
*/
|
||||
static MMacro *use_mmacro(MMacro *m, int *nparamp, Token ***paramsp)
|
||||
{
|
||||
int nparam = *nparamp;
|
||||
Token **params = *paramsp;
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
nasm_warn(WARN_OTHER, "reached maximum recursion depth of %i",
|
||||
m->max_depth);
|
||||
}
|
||||
nasm_free(params);
|
||||
*nparamp = 0;
|
||||
*paramsp = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
int newnparam = m->nparam_min + m->ndefs;
|
||||
params = nasm_realloc(params, sizeof(*params) * (newnparam+2));
|
||||
memcpy(¶ms[nparam+1], &m->defaults[nparam+1-m->nparam_min],
|
||||
(newnparam - nparam) * sizeof(*params));
|
||||
nparam = newnparam;
|
||||
}
|
||||
/*
|
||||
* If we've gone over the maximum parameter count (and
|
||||
* we're in Plus mode), ignore parameters beyond
|
||||
* nparam_max.
|
||||
*/
|
||||
if (m->plus && nparam > m->nparam_max)
|
||||
nparam = m->nparam_max;
|
||||
|
||||
/*
|
||||
* If nparam was adjusted above, make sure the list is still
|
||||
* NULL-terminated.
|
||||
*/
|
||||
params[nparam+1] = NULL;
|
||||
|
||||
/* Done! */
|
||||
*paramsp = params;
|
||||
*nparamp = nparam;
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Determine whether the given line constitutes a multi-line macro
|
||||
* call, and return the MMacro structure called if so. Doesn't have
|
||||
@ -5606,13 +5810,16 @@ static Token *expand_id(Token * tline)
|
||||
* to be called with tline->type == TOK_ID, so the putative macro
|
||||
* name is easy to find.
|
||||
*/
|
||||
static MMacro *is_mmacro(Token * tline, int *nparamp, Token ***params_array)
|
||||
static MMacro *is_mmacro(Token * tline, int *nparamp, Token ***paramsp)
|
||||
{
|
||||
MMacro *head, *m;
|
||||
MMacro *head, *m, *mone;
|
||||
Token **params;
|
||||
int nparam;
|
||||
const char *finding = tok_text(tline);
|
||||
|
||||
*nparamp = 0;
|
||||
*paramsp = NULL;
|
||||
|
||||
head = (MMacro *) hash_findix(&mmacros, finding);
|
||||
|
||||
/*
|
||||
@ -5637,64 +5844,72 @@ static MMacro *is_mmacro(Token * tline, int *nparamp, Token ***params_array)
|
||||
* OK, we have a potential macro. Count and demarcate the
|
||||
* parameters.
|
||||
*/
|
||||
count_mmac_params(tline->next, &nparam, ¶ms);
|
||||
count_mmac_params(tline->next, nparamp, paramsp);
|
||||
nparam = *nparamp;
|
||||
params = *paramsp;
|
||||
|
||||
/*
|
||||
* So we know how many parameters we've got. Find the MMacro
|
||||
* structure that handles this number.
|
||||
* If we find a macro which doesn't match, but accepts one argument
|
||||
* but not zero, remember it for the special handling below.
|
||||
*/
|
||||
mone = NULL;
|
||||
|
||||
/*
|
||||
* Search for an exact match. This cannot come *before* the m
|
||||
* found in the list search before.
|
||||
*/
|
||||
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...
|
||||
* This one matches, use it.
|
||||
*/
|
||||
if (m->in_progress > m->max_depth) {
|
||||
if (m->max_depth > 0) {
|
||||
nasm_warn(WARN_OTHER, "reached maximum recursion depth of %i",
|
||||
m->max_depth);
|
||||
}
|
||||
nasm_free(params);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* 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) {
|
||||
int newnparam = m->nparam_min + m->ndefs;
|
||||
params = nasm_realloc(params, sizeof(*params) * (newnparam+2));
|
||||
memcpy(¶ms[nparam+1], &m->defaults[nparam+1-m->nparam_min],
|
||||
(newnparam - nparam) * sizeof(*params));
|
||||
nparam = newnparam;
|
||||
}
|
||||
/*
|
||||
* If we've gone over the maximum parameter count (and
|
||||
* we're in Plus mode), ignore parameters beyond
|
||||
* nparam_max.
|
||||
*/
|
||||
if (m->plus && nparam > m->nparam_max)
|
||||
nparam = m->nparam_max;
|
||||
|
||||
/*
|
||||
* If nparam was adjusted above, make sure the list is still
|
||||
* NULL-terminated.
|
||||
*/
|
||||
params[nparam+1] = NULL;
|
||||
|
||||
/* Done! */
|
||||
*params_array = params;
|
||||
*nparamp = nparam;
|
||||
return m;
|
||||
return use_mmacro(m, nparamp, paramsp);
|
||||
} else if (m->nparam_min == 1 && !mone) {
|
||||
mone = m;
|
||||
}
|
||||
|
||||
/*
|
||||
* This one wasn't right: look for the next one with the
|
||||
* same name.
|
||||
* Otherwise search for the next one with a name match.
|
||||
*/
|
||||
list_for_each(m, m->next)
|
||||
if (!mstrcmp(m->name, tok_text(tline), m->casesense))
|
||||
list_for_each(m, m->next) {
|
||||
if (!mstrcmp(m->name, finding, m->casesense))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Special weirdness: in NASM < 2.15, an expansion of
|
||||
* *only* whitespace, as can happen during macro expansion under
|
||||
* certain circumstances, is counted as zero arguments for the
|
||||
* purpose of %0, but one argument for the purpose of macro
|
||||
* matching! In particular, this affects:
|
||||
*
|
||||
* foobar %1
|
||||
*
|
||||
* ... with %1 being empty; this would call the one-argument
|
||||
* version of "foobar" with an empty argument, equivalent to
|
||||
*
|
||||
* foobar {%1}
|
||||
*
|
||||
* ... except that %0 would be set to 0 inside foobar, even if
|
||||
* foobar is declared with "%macro foobar 1" or equivalent!
|
||||
*
|
||||
* The proper way to do that is to define "%macro foobar 0-1".
|
||||
*
|
||||
* To be compatible without doing something too stupid, try to
|
||||
* match a zero-argument macro first, but if that fails, try
|
||||
* for a one-argument macro with the above behavior.
|
||||
*
|
||||
* To disable this insane legacy behavior, use:
|
||||
*
|
||||
* %pragma preproc sane_empty_expansion yes
|
||||
*/
|
||||
if (!nparam && tline->next && !ppopt.sane_empty_expansion && mone) {
|
||||
nasm_warn(WARN_MACRO_PARAMS_MULTI,
|
||||
"improperly calling multi-line macro `%s' with 0 parameters (legacy hack)",
|
||||
finding);
|
||||
return use_mmacro(mone, nparamp, paramsp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5708,7 +5923,7 @@ static MMacro *is_mmacro(Token * tline, int *nparamp, Token ***params_array)
|
||||
*/
|
||||
nasm_warn(WARN_MACRO_PARAMS_MULTI,
|
||||
"multi-line macro `%s' exists, but not taking %d parameter%s",
|
||||
tok_text(tline), nparam, (nparam == 1) ? "" : "s");
|
||||
finding, nparam, (nparam == 1) ? "" : "s");
|
||||
nasm_free(params);
|
||||
return NULL;
|
||||
}
|
||||
@ -5820,7 +6035,7 @@ static int expand_mmacro(Token * tline)
|
||||
Token **params, *t, *tt;
|
||||
MMacro *m;
|
||||
Line *l, *ll;
|
||||
int i, *paramlen;
|
||||
int i, last_nonempty, *paramlen;
|
||||
const char *mname;
|
||||
int nparam = 0;
|
||||
|
||||
@ -5871,13 +6086,14 @@ static int expand_mmacro(Token * tline)
|
||||
|
||||
/*
|
||||
* Fix up the parameters: this involves stripping leading and
|
||||
* trailing whitespace, then stripping braces if they are
|
||||
* present.
|
||||
* trailing whitespace and stripping braces if they are present.
|
||||
*/
|
||||
nasm_newn(paramlen, nparam+1);
|
||||
|
||||
nasm_assert(params[nparam+1] == NULL);
|
||||
|
||||
/* Last nonempty *unbraced* parameter */
|
||||
last_nonempty = 0;
|
||||
|
||||
for (i = 1; (t = params[i]); i++) {
|
||||
bool braced = false;
|
||||
int brace = 0;
|
||||
@ -5914,6 +6130,7 @@ static int expand_mmacro(Token * tline)
|
||||
brace--;
|
||||
if (braced && !brace) {
|
||||
paramlen[i] += white;
|
||||
last_nonempty = i;
|
||||
goto endparam;
|
||||
}
|
||||
break;
|
||||
@ -5924,12 +6141,27 @@ static int expand_mmacro(Token * tline)
|
||||
}
|
||||
|
||||
paramlen[i] += white + 1;
|
||||
last_nonempty = i;
|
||||
white = 0;
|
||||
}
|
||||
endparam:
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* NASM < 2.15 would not count terminal empty arguemnts
|
||||
* in %0, even though it counted for matching.
|
||||
* This implements this legacy behavior.
|
||||
*
|
||||
* Use:
|
||||
*
|
||||
* %pragma preproc sane_empty_expansion true
|
||||
*
|
||||
* ... to disable this rather crazy legacy behavior.
|
||||
*/
|
||||
if (!ppopt.sane_empty_expansion)
|
||||
nparam = last_nonempty;
|
||||
|
||||
/*
|
||||
* OK, we have a MMacro structure together with a set of
|
||||
* parameters. We must now go through the expansion and push
|
||||
@ -6132,7 +6364,9 @@ pp_reset(const char *file, enum preproc_mode mode, struct strlist *dep_list)
|
||||
unique = 0;
|
||||
deplist = dep_list;
|
||||
pp_mode = mode;
|
||||
do_aliases = true;
|
||||
|
||||
/* Reset options to default */
|
||||
nasm_zero(ppopt);
|
||||
|
||||
if (!use_loaded)
|
||||
use_loaded = nasm_malloc(use_package_count * sizeof(bool));
|
||||
|
Loading…
Reference in New Issue
Block a user