aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin (Intel) <hpa@zytor.com>2020-06-14 20:09:11 -0700
committerH. Peter Anvin (Intel) <hpa@zytor.com>2020-06-14 20:09:11 -0700
commitb292748d9f5fc2ac89a75df4b160a1451a767851 (patch)
tree243013d5b5c2efa78eb79166ea8ae94aa74ca5cd
parent4ed23c8f8557db0ed8578a090a0c483cd993c076 (diff)
downloadnasm-b292748d9f5fc2ac89a75df4b160a1451a767851.tar.gz
nasm-b292748d9f5fc2ac89a75df4b160a1451a767851.tar.xz
nasm-b292748d9f5fc2ac89a75df4b160a1451a767851.zip
preproc, srcfile: much saner handling of %line directives
%line directives really need to be preprocessed early, before normal directive processing. In particular, they are *not* affected by such thing as smacro expansion, or deferred into an mmacro expansion. The %line directive is special because it is explicitly indented to be inserted by an external preprocessor, which can happen at any point. For mmacro and rep expansions, store the current file and line for each expansion line. Similarly, let each istk entry contain such information. Don't emit empty lines in preprocessing-only mode when we are already required to issue a %line directive anyway. This cuts down on clutter a fair bit. Quote filenames in %line directives (and accept quoted filenames in %line directives) if and only if it is necessary for disambiguation. This is required if: 1. The filename contains control characters; 2. The filename begins or ends with whitespace or a quotation mark; 3. The filename is empty. Otherwise issue the filename as-is, for backwards compatibility. Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
-rw-r--r--asm/nasm.c107
-rw-r--r--asm/preproc.c255
-rw-r--r--asm/srcfile.c10
-rw-r--r--asm/srcfile.h16
-rw-r--r--travis/test/weirdpaste.i.t7
5 files changed, 235 insertions, 160 deletions
diff --git a/asm/nasm.c b/asm/nasm.c
index 51a74dfc..a9793a20 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -55,6 +55,7 @@
#include "outform.h"
#include "listing.h"
#include "iflag.h"
+#include "quote.h"
#include "ver.h"
/*
@@ -292,15 +293,6 @@ static void increment_offset(int64_t delta)
set_curr_offs(location.offset);
}
-static void nasm_fputs(const char *line, FILE * outfile)
-{
- if (outfile) {
- fputs(line, outfile);
- putc('\n', outfile);
- } else
- puts(line);
-}
-
/*
* Define system-defined macros that are not part of
* macros/standard.mac.
@@ -449,6 +441,41 @@ static int64_t make_posix_time(const struct tm *tm)
return t;
}
+/*
+ * Quote a filename string if and only if it is necessary.
+ * It is considered necessary if any one of these is true:
+ * 1. The filename contains control characters;
+ * 2. The filename starts or ends with a space or quote mark;
+ * 3. The filename is empty.
+ *
+ * The filename is returned in a newly allocated buffer.
+ */
+static char *nasm_quote_filename(const char *fn)
+{
+ const char *p = fn;
+
+ if (!p || !*p)
+ return nasm_strdup("\"\"");
+
+ if (*p <= ' ' || nasm_isquote(*p)) {
+ goto quote;
+ } else {
+ while (*p) {
+ if (*p < ' ')
+ goto quote;
+ p++;
+ }
+ if (p[-1] <= ' ' || nasm_isquote(p[-1]))
+ goto quote;
+ }
+
+ /* Quoting not necessary */
+ return nasm_strdup(fn);
+
+quote:
+ return nasm_quote(fn, NULL);
+}
+
static void timestamp(void)
{
struct compile_time * const oct = &official_compile_time;
@@ -595,15 +622,20 @@ int main(int argc, char **argv)
} else if (operating_mode & OP_PREPROCESS) {
char *line;
const char *file_name = NULL;
- int32_t prior_linnum = 0;
- int lineinc = 0;
+ char *quoted_file_name = nasm_quote_filename(file_name);
+ int32_t linnum = 0;
+ int32_t lineinc = 0;
+ FILE *out;
if (outname) {
ofile = nasm_open_write(outname, NF_TEXT);
if (!ofile)
nasm_fatal("unable to open output file `%s'", outname);
- } else
+ out = ofile;
+ } else {
ofile = NULL;
+ out = stdout;
+ }
location.known = false;
@@ -614,22 +646,47 @@ int main(int argc, char **argv)
/*
* We generate %line directives if needed for later programs
*/
- int32_t linnum = prior_linnum += lineinc;
- int altline = src_get(&linnum, &file_name);
- if (altline) {
- if (altline == 1 && lineinc == 1)
- nasm_fputs("", ofile);
- else {
- lineinc = (altline != -1 || lineinc != 1);
- fprintf(ofile ? ofile : stdout,
- "%%line %"PRId32"+%d %s\n", linnum, lineinc,
- file_name);
+ struct src_location where = src_where();
+ if (file_name != where.filename) {
+ file_name = where.filename;
+ linnum = -1; /* Force a new %line statement */
+ lineinc = file_name ? 1 : 0;
+ nasm_free(quoted_file_name);
+ quoted_file_name = nasm_quote_filename(file_name);
+ } else if (lineinc) {
+ if (linnum + lineinc == where.lineno) {
+ /* Add one blank line to account for increment */
+ fputc('\n', out);
+ linnum += lineinc;
+ } else if (linnum - lineinc == where.lineno) {
+ /*
+ * Standing still, probably a macro. Set increment
+ * to zero.
+ */
+ lineinc = 0;
}
- prior_linnum = linnum;
+ } else {
+ /* lineinc == 0 */
+ if (linnum + 1 == where.lineno)
+ lineinc = 1;
}
- nasm_fputs(line, ofile);
- nasm_free(line);
+
+ /* Skip blank lines if we will need a %line anyway */
+ if (linnum == -1 && !line[0])
+ continue;
+
+ if (linnum != where.lineno) {
+ fprintf(out, "%%line %"PRId32"%+"PRId32" %s\n",
+ where.lineno, lineinc, quoted_file_name);
+ }
+ linnum = where.lineno + lineinc;
+
+ fputs(line, out);
+ fputc('\n', out);
}
+
+ nasm_free(quoted_file_name);
+
preproc->cleanup_pass();
reset_warnings();
if (ofile)
diff --git a/asm/preproc.c b/asm/preproc.c
index fd06ba89..69c87087 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -279,15 +279,12 @@ struct MMacro {
struct mstk dstk; /* Macro definitions stack */
Token **params; /* actual parameters */
Token *iline; /* invocation line */
+ struct src_location where; /* location of definition */
unsigned int nparam, rotate;
char *iname; /* name invoked as */
int *paramlen;
uint64_t unique;
- int lineno; /* Current line number on expansion */
uint64_t condcnt; /* number of if blocks... */
-
- const char *fname; /* File where defined */
- int32_t xline; /* First line in macro */
};
@@ -365,24 +362,18 @@ static size_t tok_strlen(const char *str)
*/
static Token *set_text(struct Token *t, const char *text, size_t len)
{
+ char *textp;
+
if (t->len > INLINE_TEXT)
nasm_free(t->text.p.ptr);
nasm_zero(t->text);
t->len = len = tok_check_len(len);
- if (len > INLINE_TEXT) {
- char *textp;
-
- t->text.p.ptr = textp = nasm_malloc(len+1);
- memcpy(textp, text, len);
- textp[len] = '\0';
- } else {
- /* Null-terminated due to nasm_zero() above */
- t->len = len;
- memcpy(t->text.a, text, len);
- }
-
+ textp = (len > INLINE_TEXT)
+ ? (t->text.p.ptr = nasm_malloc(len+1)) : t->text.a;
+ memcpy(textp, text, len);
+ textp[len] = '\0';
return t;
}
@@ -390,8 +381,10 @@ static Token *set_text(struct Token *t, const char *text, size_t len)
* Set the text field to the existing pre-allocated string, either
* taking over or freeing the allocation in the process.
*/
-static Token *set_text_free(struct Token *t, char *text, size_t len)
+static Token *set_text_free(struct Token *t, char *text, unsigned int len)
{
+ char *textp;
+
if (t->len > INLINE_TEXT)
nasm_free(t->text.p.ptr);
@@ -399,13 +392,12 @@ static Token *set_text_free(struct Token *t, char *text, size_t len)
t->len = len = tok_check_len(len);
if (len > INLINE_TEXT) {
- t->text.p.ptr = text;
- text[len] = '\0';
+ textp = t->text.p.ptr = text;
} else {
- /* Null-terminated due to nasm_zero() above */
- memcpy(t->text.a, text, len);
+ textp = memcpy(t->text.a, text, len);
nasm_free(text);
}
+ textp[len] = '\0';
return t;
}
@@ -448,6 +440,7 @@ struct Line {
Line *next;
MMacro *finishes;
Token *first;
+ struct src_location where; /* Where defined */
};
/*
@@ -459,9 +452,9 @@ struct Include {
FILE *fp;
Cond *conds;
Line *expansion;
- const char *fname;
struct mstk mstk;
- int lineno, lineinc;
+ struct src_location where; /* Filename and current line number */
+ int32_t lineinc; /* Increment given by %line */
bool nolist;
};
@@ -1306,7 +1299,6 @@ static char *line_from_file(FILE *f)
unsigned int nr_cont = 0;
bool cont = false;
char *buffer, *p;
- int32_t lineno;
size = delta;
p = buffer = nasm_malloc(size);
@@ -1366,9 +1358,8 @@ static char *line_from_file(FILE *f)
*p++ = c;
} while (c);
- lineno = src_get_linnum() + istk->lineinc +
- (nr_cont * istk->lineinc);
- src_set_linnum(lineno);
+ istk->where.lineno += (nr_cont + 1) * istk->lineinc;
+ src_set_linnum(istk->where.lineno);
return buffer;
}
@@ -1390,7 +1381,7 @@ static char *read_line(void)
return NULL;
if (!istk->nolist)
- lfmt->line(LIST_READ, src_get_linnum(), line);
+ lfmt->line(LIST_READ, istk->where.lineno, line);
return line;
}
@@ -3411,6 +3402,56 @@ static int do_directive(Token *tline, Token **output)
}
/*
+ * %line directives are always processed immediately and
+ * unconditionally, as they are intended to reflect position
+ * in externally preprocessed sources.
+ */
+ if (op == PP_LINE) {
+ /*
+ * Syntax is `%line nnn[+mmm] [filename]'
+ */
+ if (pp_noline || istk->mstk.mstk)
+ goto done;
+
+ tline = tline->next;
+ tline = skip_white(tline);
+ if (!tok_type(tline, TOK_NUMBER)) {
+ nasm_nonfatal("`%s' expects line number", dname);
+ goto done;
+ }
+ k = readnum(tok_text(tline), &err);
+ m = 1;
+ tline = tline->next;
+ if (tok_is(tline, '+') || tok_is(tline, '-')) {
+ bool minus = tok_is(tline, '-');
+ tline = tline->next;
+ if (!tok_type(tline, TOK_NUMBER)) {
+ nasm_nonfatal("`%s' expects line increment", dname);
+ goto done;
+ }
+ m = readnum(tok_text(tline), &err);
+ if (minus)
+ m = -m;
+ tline = tline->next;
+ }
+ tline = skip_white(tline);
+ if (tline) {
+ if (tline->type == TOK_STRING) {
+ src_set_fname(unquote_token(tline));
+ } else {
+ char *fname = detoken(tline, false);
+ src_set_fname(fname);
+ nasm_free(fname);
+ }
+ }
+ src_set_linnum(k);
+
+ istk->where = src_where();
+ istk->lineinc = m;
+ goto done;
+ }
+
+ /*
* If we're in a non-emitting branch of a condition construct,
* or walking to the end of an already terminated %rep block,
* we should ignore all directives except for condition
@@ -3425,7 +3466,7 @@ static int do_directive(Token *tline, Token **output)
/*
* If we're defining a macro or reading a %rep block, we should
* ignore all directives except for %macro/%imacro (which nest),
- * %endm/%endmacro, and (only if we're in a %rep block) %endrep.
+ * %endm/%endmacro, %line and (only if we're in a %rep block) %endrep.
* If we're in a %rep block, another %rep nests, so should be let through.
*/
if (defining && op != PP_MACRO && op != PP_RMACRO &&
@@ -3755,8 +3796,8 @@ static int do_directive(Token *tline, Token **output)
/* -MG given but file not found */
nasm_free(inc);
} else {
- inc->fname = src_set_fname(found_path ? found_path : p);
- inc->lineno = src_set_linnum(0);
+ src_set(0, found_path ? found_path : p);
+ inc->where = src_where();
inc->lineinc = 1;
inc->nolist = istk->nolist;
istk = inc;
@@ -3784,8 +3825,7 @@ static int do_directive(Token *tline, Token **output)
stdmacpos = pkg->macros;
nasm_new(inc);
inc->next = istk;
- inc->fname = src_set_fname(NULL);
- inc->lineno = src_set_linnum(0);
+ src_set(0, NULL);
inc->nolist = !list_option('b') || istk->nolist;
istk = inc;
lfmt->uplevel(LIST_INCLUDE, 0);
@@ -3980,7 +4020,7 @@ issue_error:
}
defining = def;
- src_get(&defining->xline, &defining->fname);
+ defining->where = istk->where;
mmac = (MMacro *) hash_findix(&mmacros, defining->name);
while (mmac) {
@@ -4162,7 +4202,7 @@ issue_error:
defining->mstk = istk->mstk;
defining->dstk.mstk = tmp_defining;
defining->dstk.mmac = tmp_defining ? tmp_defining->dstk.mmac : NULL;
- src_get(&defining->xline, &defining->fname);
+ defining->where = istk->where;
break;
}
@@ -4187,6 +4227,7 @@ issue_error:
l->next = istk->expansion;
l->finishes = defining;
l->first = NULL;
+ l->where = src_where();
istk->expansion = l;
istk->mstk.mstk = defining;
@@ -4571,38 +4612,7 @@ issue_error:
break;
case PP_LINE:
- /*
- * Syntax is `%line nnn[+mmm] [filename]'
- */
- if (unlikely(pp_noline))
- goto done;
-
- tline = tline->next;
- tline = skip_white(tline);
- if (!tok_type(tline, TOK_NUMBER)) {
- nasm_nonfatal("`%s' expects line number", dname);
- goto done;
- }
- k = readnum(tok_text(tline), &err);
- m = 1;
- tline = tline->next;
- if (tok_is(tline, '+')) {
- tline = tline->next;
- if (!tok_type(tline, TOK_NUMBER)) {
- nasm_nonfatal("`%s' expects line increment", dname);
- goto done;
- }
- m = readnum(tok_text(tline), &err);
- tline = tline->next;
- }
- tline = skip_white(tline);
- src_set_linnum(k);
- istk->lineinc = m;
- if (tline) {
- char *fname = detoken(tline, false);
- src_set_fname(fname);
- nasm_free(fname);
- }
+ nasm_panic("`%s' directive not preprocessed early", dname);
break;
}
@@ -6250,6 +6260,7 @@ static int expand_mmacro(Token * tline)
nasm_new(ll);
ll->next = istk->expansion;
ll->finishes = m;
+ ll->where = istk->where;
istk->expansion = ll;
/*
@@ -6269,7 +6280,6 @@ static int expand_mmacro(Token * tline)
m->rotate = 0;
m->paramlen = paramlen;
m->unique = unique++;
- m->lineno = 0;
m->condcnt = 0;
m->mstk = istk->mstk;
@@ -6280,6 +6290,7 @@ static int expand_mmacro(Token * tline)
ll->next = istk->expansion;
istk->expansion = ll;
ll->first = dup_tlist(l->first, NULL);
+ ll->where = l->where;
}
/*
@@ -6304,6 +6315,7 @@ static int expand_mmacro(Token * tline)
ll->next = istk->expansion;
istk->expansion = ll;
ll->first = startline;
+ ll->where = istk->where;
if (!dont_prepend) {
while (label->next)
label = label->next;
@@ -6446,10 +6458,13 @@ pp_reset(const char *file, enum preproc_mode mode, struct strlist *dep_list)
/* First set up the top level input file */
nasm_new(istk);
istk->fp = nasm_open_read(file, NF_TEXT);
+ if (!istk->fp) {
+ nasm_fatalf(ERR_NOFILE, "unable to open input file `%s'%s%s",
+ file, errno ? " " : "", errno ? strerror(errno) : "");
+ }
src_set(0, file);
+ istk->where = src_where();
istk->lineinc = 1;
- if (!istk->fp)
- nasm_fatalf(ERR_NOFILE, "unable to open input file `%s'", file);
strlist_add(deplist, file);
@@ -6459,7 +6474,8 @@ pp_reset(const char *file, enum preproc_mode mode, struct strlist *dep_list)
*/
nasm_new(inc);
inc->next = istk;
- inc->fname = src_set_fname(NULL);
+ src_set(0, NULL);
+ inc->where = src_where();
inc->nolist = !list_option('b');
istk = inc;
lfmt->uplevel(LIST_INCLUDE, 0);
@@ -6550,20 +6566,12 @@ static Token *pp_tokline(void)
*/
fm->in_progress--;
list_for_each(l, fm->expansion) {
- Token *t, *tt, **tail;
Line *ll;
- istk->mstk.mstk->lineno = 0;
nasm_new(ll);
- ll->next = istk->expansion;
- tail = &ll->first;
-
- list_for_each(t, l->first) {
- if (t->len) {
- tt = *tail = dup_Token(NULL, t);
- tail = &tt->next;
- }
- }
+ ll->next = istk->expansion;
+ ll->first = dup_tlist(l->first, NULL);
+ ll->where = l->where;
istk->expansion = ll;
}
break;
@@ -6632,6 +6640,7 @@ static Token *pp_tokline(void)
free_mmacro(m);
#endif
}
+ istk->where = l->where;
istk->expansion = l->next;
nasm_free(l);
lfmt->downlevel(LIST_MACRO);
@@ -6643,27 +6652,17 @@ static Token *pp_tokline(void)
if (istk->expansion) { /* from a macro expansion */
Line *l = istk->expansion;
- int32_t lineno;
- if (istk->mstk.mstk) {
- istk->mstk.mstk->lineno++;
- if (istk->mstk.mstk->fname)
- lineno = istk->mstk.mstk->lineno +
- istk->mstk.mstk->xline;
- else
- lineno = 0; /* Defined at init time or builtin */
- } else {
- lineno = src_get_linnum();
- }
-
- tline = l->first;
istk->expansion = l->next;
+ istk->where = l->where;
+ tline = l->first;
nasm_free(l);
- line = detoken(tline, false);
- if (!istk->nolist)
- lfmt->line(LIST_MACRO, lineno, line);
- nasm_free(line);
+ if (!istk->nolist) {
+ line = detoken(tline, false);
+ lfmt->line(LIST_MACRO, istk->where.lineno, line);
+ nasm_free(line);
+ }
} else if ((line = read_line())) {
line = prepreproc(line);
tline = tokenize(line);
@@ -6673,17 +6672,23 @@ static Token *pp_tokline(void)
* The current file has ended; work down the istk
*/
Include *i = istk;
+ Include *is;
+
if (i->fp)
fclose(i->fp);
if (i->conds) {
- /* nasm_error can't be conditionally suppressed */
+ /* nasm_fatal can't be conditionally suppressed */
nasm_fatal("expected `%%endif' before end of file");
}
- /* only set line and file name if there's a next node */
- if (i->next)
- src_set(i->lineno, i->fname);
+
+ list_for_each(is, i->next) {
+ if (is->fp) {
+ lfmt->downlevel(LIST_INCLUDE);
+ src_update(is->where);
+ break;
+ }
+ }
istk = i->next;
- lfmt->downlevel(LIST_INCLUDE);
nasm_free(i);
return &tok_pop;
}
@@ -6718,11 +6723,13 @@ static Token *pp_tokline(void)
* shove the tokenized line on to the macro definition.
*/
MMacro *mmac = defining->dstk.mmac;
+ Line *l;
- Line *l = nasm_malloc(sizeof(Line));
+ nasm_new(l);
l->next = defining->expansion;
l->first = tline;
l->finishes = NULL;
+ l->where = istk->where;
defining->expansion = l;
/*
@@ -6966,16 +6973,30 @@ static Token *make_tok_char(Token *next, char op)
return t;
}
-static void pp_list_one_macro(MMacro *m, errflags severity)
+/*
+ * Descend the istk looking for macro definitions; we have to
+ * recurse because we want to show the messages in top-down order.
+ */
+static void pp_list_macro_istk(Include *inc, errflags severity)
{
- if (!m)
- return;
-
- /* We need to print the mstk.mmac list in reverse order */
- pp_list_one_macro(m->mstk.mmac, 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;
+ }
+ }
- if (m->name && !m->nolist) {
- src_set(m->xline + m->lineno, m->fname);
+ m = inc->mstk.mstk;
+ if (m && m->name && !m->nolist) {
+ src_update(inc->where);
nasm_error(severity, "... from macro `%s' defined", m->name);
}
}
@@ -6984,12 +7005,12 @@ 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();
-
- if (istk)
- pp_list_one_macro(istk->mstk.mmac, severity);
-
+ pp_list_macro_istk(istk, severity);
src_update(saved);
}
diff --git a/asm/srcfile.c b/asm/srcfile.c
index 0f35c5af..a27fffac 100644
--- a/asm/srcfile.c
+++ b/asm/srcfile.c
@@ -85,13 +85,3 @@ void src_set(int32_t line, const char *fname)
src_set_fname(fname);
src_set_linnum(line);
}
-
-struct src_location src_update(struct src_location whence)
-{
- struct src_location oldhere = _src_here;
-
- src_set_fname(whence.filename);
- src_set_linnum(whence.lineno);
-
- return oldhere;
-}
diff --git a/asm/srcfile.h b/asm/srcfile.h
index 3af6595e..759ceabf 100644
--- a/asm/srcfile.h
+++ b/asm/srcfile.h
@@ -62,6 +62,7 @@ static inline int32_t src_get_linnum(void)
{
return _src_here.lineno;
}
+
/* Can be used when there is no need for the old information */
void src_set(int32_t line, const char *filename);
@@ -91,12 +92,23 @@ static inline int32_t src_get(int32_t *xline, const char **xname)
}
/*
- * Returns and sets/returns the current information as a structure.
+ * Returns the current information as a structure.
*/
static inline struct src_location src_where(void)
{
return _src_here;
}
-struct src_location src_update(struct src_location);
+
+/*
+ * Sets the current information. The filename member of the structure
+ * *must* have been previously returned by src_get(), src_where(), or
+ * src_get_fname() and therefore be present in the hash.
+ */
+static inline struct src_location src_update(struct src_location whence)
+{
+ struct src_location old = _src_here;
+ _src_here = whence;
+ return old;
+}
#endif /* ASM_SRCFILE_H */
diff --git a/travis/test/weirdpaste.i.t b/travis/test/weirdpaste.i.t
index ac7ddf08..1725bdf5 100644
--- a/travis/test/weirdpaste.i.t
+++ b/travis/test/weirdpaste.i.t
@@ -1,9 +1,4 @@
-%line 3+1 ./travis/test/weirdpaste.asm
-
-
-
-%line 10+1 ./travis/test/weirdpaste.asm
-
+%line 11+1 ./travis/test/weirdpaste.asm
dw 25
%line 18+1 ./travis/test/weirdpaste.asm