mirror of
https://github.com/netwide-assembler/nasm
synced 2026-08-26 16:23:04 -04:00
Merge remote-tracking branch 'github/nasm-2.15.xx'
This commit is contained in:
commit
63769c588e
8 changed files with 304 additions and 191 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
105
asm/nasm.c
105
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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1917,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,
|
||||
|
|
@ -1924,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;
|
||||
|
||||
|
|
@ -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, ¤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);
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
181
asm/preproc.c
181
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;
|
||||
}
|
||||
|
|
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
m = inc->mstk.mstk;
|
||||
if (m && m->name && !m->nolist) {
|
||||
src_update(inc->where);
|
||||
nasm_error(severity, "... from macro `%s' defined", m->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void pp_error_list_macros(errflags severity)
|
||||
{
|
||||
struct src_location saved;
|
||||
|
||||
if (!istk)
|
||||
return;
|
||||
const MMacro *m;
|
||||
|
||||
severity |= ERR_PP_LISTMACRO | ERR_NO_SEVERITY | ERR_HERE;
|
||||
saved = src_where();
|
||||
pp_list_macro_istk(istk, severity);
|
||||
src_update(saved);
|
||||
|
||||
while ((m = src_error_down())) {
|
||||
nasm_error(severity, "... from macro `%s' defined", m->name);
|
||||
}
|
||||
|
||||
src_error_reset();
|
||||
}
|
||||
|
||||
const struct preproc_ops nasmpp = {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
%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
|
||||
testrep .nolist
|
||||
|
||||
testrep_nl
|
||||
testrep_nl .nolist
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue