preproc: mmacro argument fixes; listing option for mmacro args

Correctly handle empty mmacro arguments that still have preceding
whitespace tokens.

Default mmacro parameters are obtained by count_mmac_params() so they,
too, need to be shifted over by one.

Add an option to list mmacro calls with arguments. Name this -Lm;
remove the old -Lm option to -Ls since it is related to single-line
macros.

Trivially optimize the case where an mmacro is called from within
itself: if all possible mmacros are excluded by loop removal, there is
no need to delve into the mmac processing code.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel) 2019-08-20 16:00:57 -07:00
parent 68075f8fa6
commit 41d91a9273
2 changed files with 86 additions and 23 deletions

View File

@ -2023,8 +2023,9 @@ static void help(FILE *out)
" -Ld show byte and repeat counts in decimal, not hex\n"
" -Le show the preprocessed output\n"
" -Lf ignore .nolist (force output)\n"
" -Lm show all single-line macro definitions\n"
" -Lm show multi-line macro calls with expanded parmeters\n"
" -Lp output a list file every pass, in case of errors\n"
" -Ls show all single-line macro definitions\n"
" -L+ enable all listing options (very verbose!)\n"
"\n"
" -Oflags... optimize opcodes, immediates and branch offsets\n"

View File

@ -527,7 +527,7 @@ static Token *delete_Token(Token * t);
* Macros for safe checking of token pointers, avoid *(NULL)
*/
#define tok_type_(x,t) ((x) && (x)->type == (t))
#define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next
#define skip_white_(x) ((x) = (tok_type_((x), TOK_WHITESPACE) ? (x)->next : (x)))
#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v)))
#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
@ -1869,13 +1869,12 @@ static void count_mmac_params(Token * t, int *nparamp, Token ***paramsp)
params = nasm_malloc(paramsize * sizeof(*params));
params[0] = NULL;
while (t) {
while (skip_white_(t)) {
/* 2 slots for captured label and NULL */
if (nparam+2 >= paramsize) {
paramsize += PARAM_DELTA;
params = nasm_realloc(params, sizeof(*params) * paramsize);
}
skip_white_(t);
brace = 0;
if (tok_is_(t, "{"))
brace++;
@ -2508,7 +2507,7 @@ static SMacro *define_smacro(const char *mname, bool casesense,
if (tmpl->expand)
smac->expand = tmpl->expand;
}
if (list_option('m')) {
if (list_option('s')) {
list_smacro_def((smac->alias ? PP_DEFALIAS : PP_DEFINE)
+ !casesense, ctx, smac);
}
@ -2550,7 +2549,7 @@ static void undef_smacro(const char *mname, bool undefalias)
s->in_progress = false;
}
} else {
if (list_option('m'))
if (list_option('d'))
list_smacro_def(s->alias ? PP_UNDEFALIAS : PP_UNDEF,
ctx, s);
*sp = s->next;
@ -5084,13 +5083,19 @@ static MMacro *is_mmacro(Token * tline, int *nparamp, Token ***params_array)
/*
* Efficiency: first we see if any macro exists with the given
* name. If not, we can return NULL immediately. _Then_ we
* name which isn't already excluded by macro cycle removal.
* (The cycle removal test here helps optimize the case of wrapping
* instructions, and is cheap to do here.)
*
* If not, we can return NULL immediately. _Then_ we
* count the parameters, and then we look further along the
* list if necessary to find the proper MMacro.
*/
list_for_each(m, head)
if (!mstrcmp(m->name, tline->text, m->casesense))
break;
list_for_each(m, head) {
if (!mstrcmp(m->name, tline->text, m->casesense) &&
(m->in_progress != 1 || m->max_depth > 0))
break; /* Found something that needs consideration */
}
if (!m)
return NULL;
@ -5124,13 +5129,12 @@ static MMacro *is_mmacro(Token * tline, int *nparamp, Token ***params_array)
* parameters to the end of our list if necessary.
*/
if (m->defaults && nparam < m->nparam_min + m->ndefs) {
params =
nasm_realloc(params, sizeof(*params) *
(m->nparam_min + m->ndefs + 2));
while (nparam < m->nparam_min + m->ndefs) {
nparam++;
params[nparam] = m->defaults[nparam - m->nparam_min];
}
int newnparam = m->nparam_min + m->ndefs;
params = nasm_realloc(params, sizeof(*params) * (newnparam+2));
memcpy(&params[nparam+1], &m->defaults[nparam+1-m->nparam_min],
(newnparam - nparam) * sizeof(*params));
nparam = newnparam;
params[nparam+1] = NULL;
}
/*
* If we've gone over the maximum parameter count (and
@ -5218,6 +5222,57 @@ static void pop_mmacro(MMacro *m)
#endif
/*
* List an mmacro call with arguments (-La option)
*/
static void list_mmacro_call(const MMacro *m)
{
const char prefix[] = " ;;; [macro] ";
size_t namelen, size;
char *buf, *p;
unsigned int i;
const Token *t;
namelen = strlen(m->iname);
size = namelen + sizeof(prefix); /* Includes final null (from prefix) */
for (i = 1; i <= m->nparam; i++) {
int j = 0;
size += 3; /* Braces and space/comma */
list_for_each(t, m->params[i]) {
if (j++ >= m->paramlen[i])
break;
size += (t->type == TOK_WHITESPACE) ? 1 : t->len;
}
}
buf = p = nasm_malloc(size);
p = mempcpy(p, prefix, sizeof(prefix) - 1);
p = mempcpy(p, m->iname, namelen);
*p++ = ' ';
for (i = 1; i <= m->nparam; i++) {
int j = 0;
*p++ = '{';
list_for_each(t, m->params[i]) {
if (j++ >= m->paramlen[i])
break;
if (!t->text) {
if (t->type == TOK_WHITESPACE)
*p++ = ' ';
} else {
p = mempcpy(p, t->text, t->len);
}
}
*p++ = '}';
*p++ = ',';
}
*--p = '\0'; /* Replace last delimeter with null */
lfmt->line(LIST_MACRO, -1, buf);
nasm_free(buf);
}
/*
* Expand the multi-line macro call made by the given line, if
* there is one to be expanded. If there is, push the expansion on
@ -5287,20 +5342,24 @@ static int expand_mmacro(Token * tline)
*/
nasm_newn(paramlen, nparam+1);
nasm_assert(params[nparam+1] == NULL);
for (i = 1; (t = params[i]); i++) {
int brace = 0;
int comma = !m->plus || i < nparam;
bool comma = !m->plus || i < nparam;
skip_white_(t);
if (tok_is_(t, "{"))
t = t->next, brace++, comma = false;
params[i] = t;
while (t) {
if (comma && t->type == TOK_OTHER && !strcmp(t->text, ","))
break; /* ... because we have hit a comma */
if (comma && t->type == TOK_WHITESPACE
&& tok_is_(t->next, ","))
break; /* ... or a space then a comma */
if (comma) {
/* Check if we hit a comma that ends this argument */
if (tok_is_(t, ","))
break;
else if (t->type == TOK_WHITESPACE && tok_is_(t->next, ","))
break;
}
if (brace && t->type == TOK_OTHER) {
if (t->text[0] == '{')
brace++; /* ... or a nested opening brace */
@ -5396,6 +5455,9 @@ static int expand_mmacro(Token * tline)
lfmt->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO, 0);
if (list_option('m') && !m->nolist)
list_mmacro_call(m);
return 1;
}