summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2020-07-05 15:27:04 -0700
committerH. Peter Anvin <hpa@zytor.com>2020-07-05 15:27:04 -0700
commit63769c588e2d0ecc49b898c0a5c035cf0d11e78e (patch)
treece7859cca6de47fb384238187181071af909add9
parent37c0942409298317aa5206f09250527793b3b593 (diff)
parent122c5fb75986adc37dfb147cc2a613e3ebc66e80 (diff)
downloadnasm-63769c588e2d0ecc49b898c0a5c035cf0d11e78e.tar.gz
Merge remote-tracking branch 'github/nasm-2.15.xx'
-rw-r--r--asm/listing.c50
-rw-r--r--asm/nasm.c105
-rw-r--r--asm/preproc.c179
-rw-r--r--asm/srcfile.c41
-rw-r--r--asm/srcfile.h77
-rwxr-xr-xdoc/genps.pl4
-rw-r--r--include/nasm.h7
-rw-r--r--test/exitrep.asm30
8 files changed, 303 insertions, 190 deletions
diff --git a/asm/listing.c b/asm/listing.c
index 6d6f3606..f6ef6d1b 100644
--- a/asm/listing.c
+++ b/asm/listing.c
@@ -49,14 +49,6 @@
#define LIST_INDENT 40
#define LIST_HEXBIT 18
-typedef struct MacroInhibit MacroInhibit;
-
-static struct MacroInhibit {
- MacroInhibit *next;
- int level;
- int inhibiting;
-} *mistack;
-
static const char xdigit[] = "0123456789ABCDEF";
#define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]);
@@ -135,12 +127,6 @@ static void list_cleanup(void)
if (!listfp)
return;
- while (mistack) {
- MacroInhibit *temp = mistack;
- mistack = temp->next;
- nasm_free(temp);
- }
-
list_emit();
fclose(listfp);
listfp = NULL;
@@ -172,10 +158,6 @@ static void list_init(const char *fname)
list_errors = NULL;
listlevel = 0;
suppress = 0;
- nasm_new(mistack);
- mistack->next = NULL;
- mistack->level = 0;
- mistack->inhibiting = true;
}
static void list_out(int64_t offset, char *str)
@@ -292,21 +274,14 @@ static void list_output(const struct out_data *data)
static void list_line(int type, int32_t lineno, const char *line)
{
+ (void)type;
+
if (!listfp)
return;
if (user_nolist)
return;
- if (mistack && mistack->inhibiting) {
- if (type == LIST_MACRO)
- return;
- else { /* pop the m i stack */
- MacroInhibit *temp = mistack;
- mistack = temp->next;
- nasm_free(temp);
- }
- }
list_emit();
if (lineno >= 0)
listlineno = lineno;
@@ -316,15 +291,6 @@ static void list_line(int type, int32_t lineno, const char *line)
listlevel_e = listlevel;
}
-static void mistack_push(bool inhibiting)
-{
- MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
- temp->next = mistack;
- temp->level = listlevel;
- temp->inhibiting = inhibiting;
- mistack = temp;
-}
-
static void list_uplevel(int type, int64_t size)
{
if (!listfp)
@@ -343,13 +309,6 @@ static void list_uplevel(int type, int64_t size)
case LIST_INCLUDE:
listlevel++;
- if (mistack && mistack->inhibiting)
- mistack_push(false);
- break;
-
- case LIST_MACRO_NOLIST:
- listlevel++;
- mistack_push(true);
break;
default:
@@ -374,11 +333,6 @@ static void list_downlevel(int type)
default:
listlevel--;
- while (mistack && mistack->level > listlevel) {
- MacroInhibit *temp = mistack;
- mistack = temp->next;
- nasm_free(temp);
- }
break;
}
}
diff --git a/asm/nasm.c b/asm/nasm.c
index 7c64569f..69a3db55 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -644,7 +644,7 @@ int main(int argc, char **argv)
location.known = false;
- _pass_type = PASS_FIRST; /* We emulate this assembly pass */
+ _pass_type = PASS_PREPROC;
preproc->reset(inname, PP_PREPROC, depend_list);
while ((line = preproc->getline())) {
@@ -1651,8 +1651,19 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
while (!terminate_after_phase && !pass_final()) {
_passn++;
- if (pass_type() != PASS_OPT || !global_offset_changed)
+ switch (pass_type()) {
+ case PASS_INIT:
+ _pass_type = PASS_FIRST;
+ break;
+ case PASS_OPT:
+ if (global_offset_changed)
+ break; /* One more optimization pass */
+ /* fall through */
+ default:
_pass_type++;
+ break;
+ }
+
global_offset_changed = 0;
/*
@@ -1830,8 +1841,12 @@ static bool skip_this_pass(errflags severity)
if (type == ERR_LISTMSG)
return true;
- /* This message not applicable unless pass_final */
- return (severity & ERR_PASS2) && !pass_final();
+ /*
+ * This message not applicable unless it is the last pass we are going
+ * to execute; this can be either the final code-generation pass or
+ * the single pass executed in preproc-only mode.
+ */
+ return (severity & ERR_PASS2) && !pass_final_or_preproc();
}
/**
@@ -1918,14 +1933,39 @@ static fatal_func die_hard(errflags true_type, errflags severity)
}
/*
+ * Returns the struct src_location appropriate for use, after some
+ * potential filename mangling.
+ */
+static struct src_location error_where(errflags severity)
+{
+ struct src_location where;
+
+ if (severity & ERR_NOFILE) {
+ where.filename = NULL;
+ where.lineno = 0;
+ } else {
+ where = src_where_error();
+
+ if (!where.filename) {
+ where.filename =
+ inname && inname[0] ? inname :
+ outname && outname[0] ? outname :
+ NULL;
+ where.lineno = 0;
+ }
+ }
+
+ return where;
+}
+
+/*
* error reporting for critical and panic errors: minimize
* the amount of system dependencies for getting a message out,
* and in particular try to avoid memory allocations.
*/
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list args)
{
- const char *currentfile = no_file_name;
- int32_t lineno = 0;
+ struct src_location where;
errflags true_type = severity & ERR_MASK;
static bool been_here = false;
@@ -1934,22 +1974,15 @@ fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list args
been_here = true;
- if (!(severity & ERR_NOFILE)) {
- src_get(&lineno, &currentfile);
- if (!currentfile) {
- currentfile =
- inname && inname[0] ? inname :
- outname && outname[0] ? outname :
- no_file_name;
- lineno = 0;
- }
- }
+ where = error_where(severity);
+ if (!where.filename)
+ where.filename = no_file_name;
fputs(error_pfx_table[severity], error_file);
- fputs(currentfile, error_file);
- if (lineno) {
+ fputs(where.filename, error_file);
+ if (where.lineno) {
fprintf(error_file, "%s%"PRId32"%s",
- errfmt->beforeline, lineno, errfmt->afterline);
+ errfmt->beforeline, where.lineno, errfmt->afterline);
}
fputs(errfmt->beforemsg, error_file);
vfprintf(error_file, fmt, args);
@@ -1963,11 +1996,10 @@ fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list args
*/
struct nasm_errtext {
struct nasm_errtext *next;
- const char *currentfile; /* Owned by the filename system */
char *msg; /* Owned by this structure */
+ struct src_location where; /* Owned by the srcfile system */
errflags severity;
errflags true_type;
- int32_t lineno;
};
struct nasm_errhold {
struct nasm_errhold *up;
@@ -2052,17 +2084,7 @@ void nasm_verror(errflags severity, const char *fmt, va_list args)
et->severity = severity;
et->true_type = true_type;
et->msg = nasm_vasprintf(fmt, args);
- if (!(severity & ERR_NOFILE)) {
- src_get(&et->lineno, &et->currentfile);
-
- if (!et->currentfile) {
- et->currentfile =
- inname && inname[0] ? inname :
- outname && outname[0] ? outname :
- NULL;
- et->lineno = 0;
- }
- }
+ et->where = error_where(severity);
if (errhold_stack && true_type <= ERR_NONFATAL) {
/* It is a tentative error */
@@ -2094,8 +2116,7 @@ static void nasm_issue_error(struct nasm_errtext *et)
char linestr[64]; /* Formatted line number if applicable */
const errflags severity = et->severity;
const errflags true_type = et->true_type;
- const char * const currentfile = et->currentfile;
- const uint32_t lineno = et->lineno;
+ const struct src_location where = et->where;
if (severity & ERR_NO_SEVERITY)
pfx = "";
@@ -2114,17 +2135,17 @@ static void nasm_issue_error(struct nasm_errtext *et)
}
*linestr = 0;
- if (lineno) {
+ if (where.lineno) {
snprintf(linestr, sizeof linestr, "%s%"PRId32"%s",
- errfmt->beforeline, lineno, errfmt->afterline);
+ errfmt->beforeline, where.lineno, errfmt->afterline);
}
if (!skip_this_pass(severity)) {
- const char *file = currentfile ? currentfile : no_file_name;
+ const char *file = where.filename ? where.filename : no_file_name;
const char *here = "";
if (severity & ERR_HERE) {
- here = currentfile ? " here" : " in an unknown location";
+ here = where.filename ? " here" : " in an unknown location";
}
if (warn_list && true_type < ERR_NONFATAL &&
@@ -2161,12 +2182,12 @@ static void nasm_issue_error(struct nasm_errtext *et)
* pass1 or preprocessor warnings in the list file
*/
if (severity & ERR_HERE) {
- if (lineno)
+ if (where.lineno)
lfmt->error(severity, "%s%s at %s:%"PRId32"%s",
- pfx, et->msg, currentfile, lineno, warnsuf);
- else if (currentfile)
+ pfx, et->msg, where.filename, where.lineno, warnsuf);
+ else if (where.filename)
lfmt->error(severity, "%s%s in file %s%s",
- pfx, et->msg, currentfile, warnsuf);
+ pfx, et->msg, where.filename, warnsuf);
else
lfmt->error(severity, "%s%s in an unknown location%s",
pfx, et->msg, warnsuf);
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 = {
diff --git a/asm/srcfile.c b/asm/srcfile.c
index a27fffac..b44c021c 100644
--- a/asm/srcfile.c
+++ b/asm/srcfile.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ * Copyright 1996-2020 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@@ -32,7 +32,14 @@
* ----------------------------------------------------------------------- */
/*
- * srcfile.c - keep track of the current position in the input stream
+ * srcfile.c - keep track of the current position in the input stream.
+ *
+ * This is used for error messages, listing, and debug information. In
+ * both cases we also want to understand where inside a non-nolist
+ * macro we may be.
+ *
+ * This hierarchy is a stack that is kept as a doubly-linked list, as
+ * we want to traverse it in either top-down order or bottom-up.
*/
#include "compiler.h"
@@ -42,7 +49,9 @@
#include "hashtbl.h"
#include "srcfile.h"
-struct src_location _src_here;
+struct src_location_stack _src_top;
+struct src_location_stack *_src_bottom = &_src_top;
+struct src_location_stack *_src_error = &_src_top;
static struct hash_table filename_hash;
@@ -75,8 +84,8 @@ const char *src_set_fname(const char *newname)
}
}
- oldname = _src_here.filename;
- _src_here.filename = newname;
+ oldname = _src_bottom->l.filename;
+ _src_bottom->l.filename = newname;
return oldname;
}
@@ -85,3 +94,25 @@ void src_set(int32_t line, const char *fname)
src_set_fname(fname);
src_set_linnum(line);
}
+
+void src_macro_push(const void *macro, struct src_location where)
+{
+ struct src_location_stack *sl;
+
+ nasm_new(sl);
+ sl->l = where;
+ sl->macro = macro;
+ sl->up = _src_bottom;
+ _src_bottom->down = sl;
+ _src_bottom = sl;
+}
+
+void src_macro_pop(void)
+{
+ struct src_location_stack *sl = _src_bottom;
+
+ _src_bottom = sl->up;
+ _src_bottom->down = NULL;
+
+ nasm_free(sl);
+}
diff --git a/asm/srcfile.h b/asm/srcfile.h
index 759ceabf..a26e1e4f 100644
--- a/asm/srcfile.h
+++ b/asm/srcfile.h
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2016 The NASM Authors - All Rights Reserved
+ * Copyright 1996-2020 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@@ -43,24 +43,31 @@ struct src_location {
const char *filename;
int32_t lineno;
};
-extern struct src_location _src_here;
+struct src_location_stack {
+ struct src_location l;
+ struct src_location_stack *up, *down;
+ const void *macro;
+};
+extern struct src_location_stack _src_top;
+extern struct src_location_stack *_src_bottom;
+extern struct src_location_stack *_src_error;
void src_init(void);
void src_free(void);
const char *src_set_fname(const char *newname);
static inline const char *src_get_fname(void)
{
- return _src_here.filename;
+ return _src_bottom->l.filename;
}
static inline int32_t src_set_linnum(int32_t newline)
{
- int32_t oldline = _src_here.lineno;
- _src_here.lineno = newline;
+ int32_t oldline = _src_bottom->l.lineno;
+ _src_bottom->l.lineno = newline;
return oldline;
}
static inline int32_t src_get_linnum(void)
{
- return _src_here.lineno;
+ return _src_bottom->l.lineno;
}
/* Can be used when there is no need for the old information */
@@ -80,15 +87,16 @@ static inline int32_t src_get(int32_t *xline, const char **xname)
{
const char *xn = *xname;
int32_t xl = *xline;
+ int32_t line = _src_bottom->l.lineno;
- *xline = _src_here.lineno;
- *xname = _src_here.filename;
+ *xline = line;
+ *xname = _src_bottom->l.filename;
/* The return value is expected to be optimized out almost everywhere */
- if (!xn || xn != _src_here.filename)
+ if (!xn || xn != _src_bottom->l.filename)
return -2;
else
- return _src_here.lineno - xl;
+ return line - xl;
}
/*
@@ -96,7 +104,39 @@ static inline int32_t src_get(int32_t *xline, const char **xname)
*/
static inline struct src_location src_where(void)
{
- return _src_here;
+ return _src_bottom->l;
+}
+
+/*
+ * Returns the top-level information as a structure. Use this for panic
+ * errors, since descent is not possible there.
+ */
+static inline struct src_location src_where_top(void)
+{
+ return _src_top.l;
+}
+
+/*
+ * Returns the appropriate level of the location stack to use for error
+ * messages. This is the same as the top level except during the descent
+ * through the macro hierarchy for elucidation;
+ */
+static inline struct src_location src_where_error(void)
+{
+ return _src_error->l;
+}
+static inline const void *src_error_down(void)
+{
+ if (_src_error->down) {
+ _src_error = _src_error->down;
+ return _src_error->macro;
+ } else {
+ return NULL;
+ }
+}
+static inline void src_error_reset(void)
+{
+ _src_error = &_src_top;
}
/*
@@ -106,9 +146,20 @@ static inline struct src_location src_where(void)
*/
static inline struct src_location src_update(struct src_location whence)
{
- struct src_location old = _src_here;
- _src_here = whence;
+ struct src_location old = _src_bottom->l;
+ _src_bottom->l = whence;
return old;
}
+/*
+ * Push/pop macro expansion level. "macroname" must remain constant at
+ * least until the same macro expansion level is popped.
+ */
+void src_macro_push(const void *macroname, struct src_location where);
+static inline const void *src_macro_current(void)
+{
+ return _src_bottom->macro;
+}
+void src_macro_pop(void);
+
#endif /* ASM_SRCFILE_H */
diff --git a/doc/genps.pl b/doc/genps.pl
index b5a1a8a2..72985cc7 100755
--- a/doc/genps.pl
+++ b/doc/genps.pl
@@ -237,7 +237,7 @@ if (defined($fontmap)) {
'dieresis', undef, 'ring', 'cedilla', undef, 'hungarumlaut',
'ogonek', 'caron', 'space', 'exclam', 'quotedbl', 'numbersign',
'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft',
- 'parenright', 'asterisk', 'plus', 'comma', 'minus', 'period',
+ 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period',
'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six',
'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal',
'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
@@ -254,7 +254,7 @@ if (defined($fontmap)) {
'scaron', 'guilsignlright', 'oe', undef, 'zcaron', 'Ydieresis',
'space', 'exclamdown', 'cent', 'sterling', 'currency', 'yen',
'brokenbar', 'section', 'dieresis', 'copyright', 'ordfeminine',
- 'guillemotleft', 'logicalnot', 'hyphen', 'registered', 'macron',
+ 'guillemotleft', 'logicalnot', 'minus', 'registered', 'macron',
'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute', 'mu',
'paragraph', 'periodcentered', 'cedilla', 'onesuperior',
'ordmasculine', 'guillemotright', 'onequarter', 'onehalf',
diff --git a/include/nasm.h b/include/nasm.h
index 046f5fb9..616ffb37 100644
--- a/include/nasm.h
+++ b/include/nasm.h
@@ -428,7 +428,6 @@ static inline char *nasm_skip_identifier(const char *str)
enum {
LIST_READ,
LIST_MACRO,
- LIST_MACRO_NOLIST,
LIST_INCLUDE,
LIST_INCBIN,
LIST_TIMES
@@ -1284,6 +1283,7 @@ struct optimization {
*/
enum pass_type {
PASS_INIT, /* Initialization, not doing anything yet */
+ PASS_PREPROC, /* Preprocess-only mode (similar to PASS_FIRST) */
PASS_FIRST, /* The very first pass over the code */
PASS_OPT, /* Optimization pass */
PASS_STAB, /* Stabilization pass (original pass 1) */
@@ -1319,6 +1319,11 @@ static inline bool pass_final(void)
{
return pass_type() >= PASS_FINAL;
}
+/* True for code generation *or* preprocess-only mode */
+static inline bool pass_final_or_preproc(void)
+{
+ return pass_type() >= PASS_FINAL || pass_type() == PASS_PREPROC;
+}
/*
* The actual pass number. 0 is used during initialization, the very
diff --git a/test/exitrep.asm b/test/exitrep.asm
index 4e1b6e3c..755f05d5 100644
--- a/test/exitrep.asm
+++ b/test/exitrep.asm
@@ -1,16 +1,40 @@
-%macro testrep 0.nolist
+%macro testrep 0-1
%assign i 1
- %rep 4
+ %rep %1 4
mov eax,i
%if i==3
%exitrep
%endif
mov ebx,i
+ %warning in %?%1 iteration i
%if i >= 3
%error iteration i should not be seen
%endif
%assign i i+1
%endrep
+ ret
%endmacro
-testrep
+%macro testrep_nl 0-1.nolist
+ %assign i 1
+ %rep %1 4
+ mov eax,i
+ %if i==3
+ %exitrep
+ %endif
+ %warning in %?%1 iteration i
+ mov ebx,i
+ %if i >= 3
+ %error iteration i should not be seen
+ %endif
+ %assign i i+1
+ %endrep
+ ret
+%endmacro
+
+
+ testrep
+ testrep .nolist
+
+ testrep_nl
+ testrep_nl .nolist