From 61be48a383dd951f036631ea35723f2a6a8b96ee Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin (Intel)" Date: Thu, 2 Jul 2020 21:06:29 -0700 Subject: doc: swap 'hyphen' and 'minus' in PostScript definition It appears that at least with the Adobe Source fonts: 'hyphen' -> U+002D (ASCII) 'minus' -> U+2212 This is ugly for cut & paste purposes. Reported-by: C. Masloch Signed-off-by: H. Peter Anvin (Intel) --- doc/genps.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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', -- cgit v1.2.1 From 87a832e391ccf5a24dc70ceec1e13d94df16968e Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin (Intel)" Date: Fri, 3 Jul 2020 18:44:55 -0700 Subject: BR 3392691: errors: issue ERR_PASS2 messages in preproc-only mode In preproc-only mode, we only ever execute a single pass, so we need to still issue error messages created during that pass, otherwise we don't even generate %warning or %error messages... Reported-by: Jason Hood Signed-off-by: H. Peter Anvin (Intel) --- asm/nasm.c | 23 +++++++++++++++++++---- include/nasm.h | 6 ++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/asm/nasm.c b/asm/nasm.c index 7c64569f..557484c1 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(); } /** diff --git a/include/nasm.h b/include/nasm.h index 046f5fb9..91dc9e6f 100644 --- a/include/nasm.h +++ b/include/nasm.h @@ -1284,6 +1284,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 +1320,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 -- cgit v1.2.1 From 5b7369d7e0e256684bc92ab2ec8a822d9eb32e32 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin (Intel)" Date: Sun, 5 Jul 2020 02:16:13 -0700 Subject: Make debug info and error messages correctly reflect macros and reps 1. Error messages would issue with the line number of %endrep. 2. Debug line information would ignore both macros and reps. This is doubly wrong; macros are semantically equivalent to inline functions, and it is expected that debuggers trace into these functions. These changes finishes the last parts of moving all responsibility for the listing enable/disable into the preprocessor, so remove the way over-complicated macro inhibit facility from the listing module entirely. Signed-off-by: H. Peter Anvin (Intel) --- asm/listing.c | 50 +------------------ asm/nasm.c | 82 ++++++++++++++++--------------- asm/preproc.c | 143 +++++++++++++++++++++++++++++++++---------------------- asm/srcfile.c | 41 ++++++++++++++-- asm/srcfile.h | 77 +++++++++++++++++++++++++----- include/nasm.h | 1 - test/exitrep.asm | 30 ++++++++++-- 7 files changed, 260 insertions(+), 164 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 557484c1..69a3db55 100644 --- a/asm/nasm.c +++ b/asm/nasm.c @@ -1932,6 +1932,32 @@ static fatal_func die_hard(errflags true_type, errflags severity) exit(true_type - ERR_FATAL + 1); } +/* + * 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, @@ -1939,8 +1965,7 @@ static fatal_func die_hard(errflags true_type, errflags severity) */ 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; @@ -1949,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, ¤tfile); - 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); @@ -1978,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; @@ -2067,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 */ @@ -2109,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 = ""; @@ -2129,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 && @@ -2176,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 aded0bec..5cb92879 100644 --- a/asm/preproc.c +++ b/asm/preproc.c @@ -230,6 +230,17 @@ struct SMacro { bool alias; /* This is an alias macro */ }; +/* + * "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 @@ -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; } @@ -3133,7 +3150,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; @@ -3165,7 +3182,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; } /* @@ -3362,7 +3380,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; @@ -3798,10 +3816,12 @@ static int do_directive(Token *tline, Token **output) /* -MG given but file not found */ 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); } @@ -3827,8 +3847,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); } @@ -4153,11 +4175,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); } @@ -4234,7 +4257,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; @@ -6289,10 +6316,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; } @@ -6515,6 +6550,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 @@ -6594,6 +6631,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. @@ -6605,10 +6658,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; } @@ -6623,6 +6675,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); @@ -6939,44 +6994,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; - m = inc->mstk.mstk; - if (m && m->name && !m->nolist) { - src_update(inc->where); + severity |= ERR_PP_LISTMACRO | ERR_NO_SEVERITY | ERR_HERE; + + 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/include/nasm.h b/include/nasm.h index 91dc9e6f..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 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 -- cgit v1.2.1 From 122c5fb75986adc37dfb147cc2a613e3ebc66e80 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin (Intel)" Date: Sun, 5 Jul 2020 03:39:04 -0700 Subject: preproc: handle %+ pasting after empty expansions %+ tokens can end up next to each other, or at the beginning or the end of an expansion if we try to paste the output of empty macros. This is perhaps particularly likely to happen in %[] expressions. Signed-off-by: H. Peter Anvin (Intel) --- asm/preproc.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/asm/preproc.c b/asm/preproc.c index 5cb92879..81c72042 100644 --- a/asm/preproc.c +++ b/asm/preproc.c @@ -4726,9 +4726,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; } @@ -4741,28 +4740,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; } -- cgit v1.2.1