summaryrefslogtreecommitdiff
path: root/asm/preproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'asm/preproc.c')
-rw-r--r--asm/preproc.c179
1 files changed, 103 insertions, 76 deletions
diff --git a/asm/preproc.c b/asm/preproc.c
index 116ceef6..a2c5083d 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -231,6 +231,17 @@ struct SMacro {
};
/*
+ * "No listing" flags. Inside a loop (%rep..%endrep) we may have
+ * macro listing suppressed with .nolist, but we still need to
+ * update line numbers for error messages and debug information...
+ * unless we are nested inside an actual .nolist macro.
+ */
+enum nolist_flags {
+ NL_LIST = 1, /* Suppress list output */
+ NL_LINE = 2 /* Don't update line information */
+};
+
+/*
* Store the definition of a multi-line macro. This is also used to
* store the interiors of `%rep...%endrep' blocks, which are
* effectively self-re-invoking multi-line macros which simply
@@ -264,9 +275,9 @@ struct MMacro {
#endif
char *name;
int nparam_min, nparam_max;
+ enum nolist_flags nolist; /* is this macro listing-inhibited? */
bool casesense;
bool plus; /* is the last parameter greedy? */
- bool nolist; /* is this macro listing-inhibited? */
bool capture_label; /* macro definition has %00; capture label */
int32_t in_progress; /* is this macro currently being expanded? */
int32_t max_depth; /* maximum number of recursive expansions allowed */
@@ -447,16 +458,22 @@ struct Line {
/*
* To handle an arbitrary level of file inclusion, we maintain a
* stack (ie linked list) of these things.
+ *
+ * Note: when we issue a message for a continuation line, we want to
+ * issue it for the actual *start* of the continuation line. This means
+ * we need to remember how many lines to skip over for the next one.
*/
struct Include {
Include *next;
FILE *fp;
Cond *conds;
Line *expansion;
+ uint64_t nolist; /* Listing inhibit counter */
+ uint64_t noline; /* Line number update inhibit counter */
struct mstk mstk;
- struct src_location where; /* Filename and current line number */
+ struct src_location where; /* Filename and current line number */
int32_t lineinc; /* Increment given by %line */
- bool nolist;
+ int32_t lineskip; /* Accounting for passed continuation lines */
};
/*
@@ -1298,10 +1315,13 @@ static char *line_from_file(FILE *f)
unsigned int size, next;
const unsigned int delta = 512;
const unsigned int pad = 8;
- unsigned int nr_cont = 0;
bool cont = false;
char *buffer, *p;
+ istk->where.lineno += istk->lineskip + istk->lineinc;
+ src_set_linnum(istk->where.lineno);
+ istk->lineskip = 0;
+
size = delta;
p = buffer = nasm_malloc(size);
@@ -1345,7 +1365,7 @@ static char *line_from_file(FILE *f)
ungetc(next, f);
if (next == '\r' || next == '\n') {
cont = true;
- nr_cont++;
+ istk->lineskip += istk->lineinc;
continue;
}
break;
@@ -1360,9 +1380,6 @@ static char *line_from_file(FILE *f)
*p++ = c;
} while (c);
- istk->where.lineno += (nr_cont + 1) * istk->lineinc;
- src_set_linnum(istk->where.lineno);
-
return buffer;
}
@@ -1382,8 +1399,8 @@ static char *read_line(void)
if (!line)
return NULL;
- if (!istk->nolist)
- lfmt->line(LIST_READ, istk->where.lineno, line);
+ if (!istk->nolist)
+ lfmt->line(LIST_READ, istk->where.lineno, line);
return line;
}
@@ -3184,7 +3201,7 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
#endif
def->name = dup_text(tline);
def->plus = false;
- def->nolist = false;
+ def->nolist = 0;
def->nparam_min = 0;
def->nparam_max = 0;
@@ -3216,7 +3233,8 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
tline->next->len == 7 &&
!nasm_stricmp(tline->next->text.a, ".nolist")) {
tline = tline->next;
- def->nolist = !list_option('f') || istk->nolist;
+ if (!list_option('f'))
+ def->nolist |= NL_LIST|NL_LINE;
}
/*
@@ -3413,7 +3431,7 @@ static int do_directive(Token *tline, Token **output)
enum preproc_token op;
int j;
bool err;
- bool nolist;
+ enum nolist_flags nolist;
bool casesense;
int k, m;
int offset;
@@ -3851,10 +3869,12 @@ static int do_directive(Token *tline, Token **output)
/* -MG given but file not found, or repeated %require */
nasm_free(inc);
} else {
- src_set(0, found_path ? found_path : p);
inc->where = src_where();
inc->lineinc = 1;
inc->nolist = istk->nolist;
+ inc->noline = istk->noline;
+ if (!inc->noline)
+ src_set(0, found_path ? found_path : p);
istk = inc;
lfmt->uplevel(LIST_INCLUDE, 0);
}
@@ -3880,8 +3900,10 @@ static int do_directive(Token *tline, Token **output)
stdmacpos = pkg->macros;
nasm_new(inc);
inc->next = istk;
- src_set(0, NULL);
- inc->nolist = !list_option('b') || istk->nolist;
+ inc->nolist = istk->nolist + !list_option('b');
+ inc->noline = istk->noline;
+ if (!inc->noline)
+ src_set(0, NULL);
istk = inc;
lfmt->uplevel(LIST_INCLUDE, 0);
}
@@ -4206,11 +4228,12 @@ issue_error:
{
MMacro *tmp_defining;
- nolist = false;
+ nolist = 0;
tline = skip_white(tline->next);
if (tok_type(tline, TOK_ID) && tline->len == 7 &&
!nasm_memicmp(tline->text.a, ".nolist", 7)) {
- nolist = !list_option('f') || istk->nolist;
+ if (!list_option('f'))
+ nolist |= NL_LIST; /* ... but update line numbers */
tline = skip_white(tline->next);
}
@@ -4287,7 +4310,11 @@ issue_error:
istk->mstk.mstk = defining;
- lfmt->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO, 0);
+ /* A loop does not change istk->noline */
+ istk->nolist += !!(defining->nolist & NL_LIST);
+ if (!istk->nolist)
+ lfmt->uplevel(LIST_MACRO, 0);
+
defining = defining->dstk.mstk;
break;
@@ -4752,9 +4779,8 @@ static bool paste_tokens(Token **head, const struct tokseq_match *m,
if (!handle_explicit)
break;
- /* Left pasting token is start of line */
+ /* Left pasting token is start of line, just drop %+ */
if (!prev_nonspace) {
- nasm_nonfatal("No lvalue found on pasting");
tok = delete_Token(tok);
break;
}
@@ -4767,28 +4793,25 @@ static bool paste_tokens(Token **head, const struct tokseq_match *m,
/* Delete leading whitespace */
next = zap_white(t->next);
- /* Delete the %+ token itself */
- nasm_assert(next == tok);
- next = delete_Token(next);
-
- /* Delete trailing whitespace */
- next = zap_white(next);
+ /*
+ * Delete the %+ token itself, followed by any whitespace.
+ * In a sequence of %+ ... %+ ... %+ pasting sequences where
+ * some expansions in the middle have ended up empty,
+ * we can end up having multiple %+ tokens in a row;
+ * just drop whem in that case.
+ */
+ while (next) {
+ if (next->type == TOK_PASTE || next->type == TOK_WHITESPACE)
+ next = delete_Token(next);
+ else
+ break;
+ }
/*
- * No ending token, this might happen in two
- * cases
- *
- * 1) There indeed no right token at all
- * 2) There is a bare "%define ID" statement,
- * and @ID does expand to whitespace.
- *
- * So technically we need to do a grammar analysis
- * in another stage of parsing, but for now lets don't
- * change the behaviour people used to. Simply allow
- * whitespace after paste token.
+ * Nothing after? Just leave the existing token.
*/
if (!next) {
- *prev_nonspace = tok = NULL; /* End of line */
+ t->next = tok = NULL; /* End of line */
break;
}
@@ -6342,10 +6365,18 @@ static int expand_mmacro(Token * tline)
}
}
- lfmt->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO, 0);
+ istk->nolist += !!(m->nolist & NL_LIST);
+ istk->noline += !!(m->nolist & NL_LINE);
- if (list_option('m') && !m->nolist)
- list_mmacro_call(m);
+ if (!istk->nolist) {
+ lfmt->uplevel(LIST_MACRO, 0);
+
+ if (list_option('m'))
+ list_mmacro_call(m);
+ }
+
+ if (!istk->noline)
+ src_macro_push(m, istk->where);
return 1;
}
@@ -6568,6 +6599,8 @@ static Token *pp_tokline(void)
while (l && l->finishes) {
MMacro *fm = l->finishes;
+ nasm_assert(fm == istk->mstk.mstk);
+
if (!fm->name && fm->in_progress > 1) {
/*
* This is a macro-end marker for a macro with no
@@ -6647,6 +6680,22 @@ static Token *pp_tokline(void)
}
}
+ if (fm->nolist & NL_LIST) {
+ istk->nolist--;
+ } else if (!istk->nolist) {
+ lfmt->downlevel(LIST_MACRO);
+ }
+
+ if (fm->nolist & NL_LINE) {
+ istk->noline--;
+ } else if (!istk->noline) {
+ if (fm == src_macro_current())
+ src_macro_pop();
+ src_update(l->where);
+ }
+
+ istk->where = l->where;
+
/*
* FIXME It is incorrect to always free_mmacro here.
* It leads to usage-after-free.
@@ -6658,10 +6707,9 @@ static Token *pp_tokline(void)
free_mmacro(m);
#endif
}
- istk->where = l->where;
istk->expansion = l->next;
nasm_free(l);
- lfmt->downlevel(LIST_MACRO);
+
return &tok_pop;
}
@@ -6676,6 +6724,9 @@ static Token *pp_tokline(void)
tline = l->first;
nasm_free(l);
+ if (!istk->noline)
+ src_update(istk->where);
+
if (!istk->nolist) {
line = detoken(tline, false);
lfmt->line(LIST_MACRO, istk->where.lineno, line);
@@ -6992,44 +7043,20 @@ static Token *make_tok_char(Token *next, char op)
}
/*
- * Descend the istk looking for macro definitions; we have to
- * recurse because we want to show the messages in top-down order.
+ * Descent the macro hierarchy and display the expansion after
+ * encountering an error message.
*/
-static void pp_list_macro_istk(Include *inc, errflags severity)
+static void pp_error_list_macros(errflags severity)
{
- MMacro *m;
- Include *inext;
-
- /* Find the next higher level true macro invocation if any */
- inext = inc->next;
- if (inext && inext->mstk.mmac) {
- while (inext) {
- if (inext->mstk.mstk->name) {
- pp_list_macro_istk(inext, severity);
- break;
- }
- inext = inext->next;
- }
- }
+ const MMacro *m;
+
+ severity |= ERR_PP_LISTMACRO | ERR_NO_SEVERITY | ERR_HERE;
- m = inc->mstk.mstk;
- if (m && m->name && !m->nolist) {
- src_update(inc->where);
+ while ((m = src_error_down())) {
nasm_error(severity, "... from macro `%s' defined", m->name);
}
-}
-
-static void pp_error_list_macros(errflags severity)
-{
- struct src_location saved;
- if (!istk)
- return;
-
- severity |= ERR_PP_LISTMACRO | ERR_NO_SEVERITY | ERR_HERE;
- saved = src_where();
- pp_list_macro_istk(istk, severity);
- src_update(saved);
+ src_error_reset();
}
const struct preproc_ops nasmpp = {