preproc: get rid of the prepreprocessor and the nop preprocessor

Fold the prepreprocessor and the nop preprocessor into the main
preprocessor. This means handling # cpp-like lines and TASM
compatibility tokens in the preprocessor proper, but that is really
not very hard to do.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel) 2020-07-09 23:34:52 -07:00
parent c36cdf8a55
commit 32322a9a93
10 changed files with 314 additions and 444 deletions

View File

@ -132,7 +132,6 @@ LIBOBJ = stdlib/snprintf.$(O) stdlib/vsnprintf.$(O) stdlib/strlcpy.$(O) \
asm/stdscan.$(O) \
asm/strfunc.$(O) asm/tokhash.$(O) \
asm/segalloc.$(O) \
asm/preproc-nop.$(O) \
asm/rdstrnum.$(O) \
asm/srcfile.$(O) \
macros/macros.$(O) \

View File

@ -96,7 +96,6 @@ LIBOBJ = stdlib\snprintf.$(O) stdlib\vsnprintf.$(O) stdlib\strlcpy.$(O) \
asm\stdscan.$(O) \
asm\strfunc.$(O) asm\tokhash.$(O) \
asm\segalloc.$(O) \
asm\preproc-nop.$(O) \
asm\rdstrnum.$(O) \
asm\srcfile.$(O) \
macros\macros.$(O) \

View File

@ -85,7 +85,6 @@ LIBOBJ = stdlib\snprintf.$(O) stdlib\vsnprintf.$(O) stdlib\strlcpy.$(O) &
asm\stdscan.$(O) &
asm\strfunc.$(O) asm\tokhash.$(O) &
asm\segalloc.$(O) &
asm\preproc-nop.$(O) &
asm\rdstrnum.$(O) &
asm\srcfile.$(O) &
macros\macros.$(O) &

View File

@ -143,9 +143,9 @@ static struct RAA *offsets;
static struct SAA *forwrefs; /* keep track of forward references */
static const struct forwrefinfo *forwref;
static const struct preproc_ops *preproc;
#define preproc (&preproc_nasm) /* Hack */
static struct strlist *include_path;
bool pp_noline; /* Ignore %line directives */
static enum preproc_opt ppopt;
#define OP_NORMAL (1U << 0)
#define OP_PREPROCESS (1U << 1)
@ -364,7 +364,7 @@ static void define_macros(void)
*/
static void preproc_init(struct strlist *ipath)
{
preproc->init();
preproc->init(ppopt);
define_macros();
preproc->include_path(ipath);
}
@ -549,7 +549,6 @@ int main(int argc, char **argv)
offsets = raa_init();
forwrefs = saa_init((int32_t)sizeof(struct forwrefinfo));
preproc = &nasmpp;
operating_mode = OP_NORMAL;
parse_cmdline(argc, argv, 1);
@ -574,6 +573,11 @@ int main(int argc, char **argv)
}
}
/* Have we enabled TASM mode? */
if (tasm_compatible_mode) {
ppopt |= PP_TASM;
nasm_ctype_tasm_mode();
}
preproc_init(include_path);
parse_cmdline(argc, argv, 2);
@ -1138,10 +1142,8 @@ static bool process_arg(char *p, char *q, int pass)
break;
case 't':
if (pass == 2) {
if (pass == 1)
tasm_compatible_mode = true;
nasm_ctype_tasm_mode();
}
break;
case 'v':
@ -1156,7 +1158,7 @@ static bool process_arg(char *p, char *q, int pass)
case 'a': /* assemble only - don't preprocess */
if (pass == 1)
preproc = &preproc_nop;
ppopt |= PP_TRIVIAL;
break;
case 'w':
@ -1325,7 +1327,7 @@ static bool process_arg(char *p, char *q, int pass)
keep_all = true;
break;
case OPT_NO_LINE:
pp_noline = true;
ppopt |= PP_NOLINE;
break;
case OPT_DEBUG:
debug_nasm = param ? strtoul(param, NULL, 10) : debug_nasm+1;

View File

@ -40,11 +40,12 @@
%if*
%elif*
# Condition tests
# Condition tests.
*
*ctx
*def
*defalias
*difi
*empty
*env
*id
@ -101,3 +102,15 @@
%undefalias
%use
%warning
# These directives do not require % in TASM-compatible mode
@arg
@elif
@else
@endif
@if
@ifdef
@ifdifi
@ifndef
@include
@local

View File

@ -63,15 +63,19 @@ while (defined($line = <IN>)) {
} elsif ($line =~ /^\*(.*)$/) {
# Condition tail
push(@cond, $1);
} elsif ($line =~ /^\@(.*)$/) {
# TASM compatibility directive
push(@tasm, $1);
}
}
close(IN);
# Always sort %if first
@cctok = sort { $a eq 'if' ? -1 : $b eq 'if' ? 1 : $a cmp $b } @cctok;
@cond = sort @cond;
@pptok = sort @pptok;
@cctok = sort { $a eq 'if' ? -1 : $b eq 'if' ? 1 : $a cmp $b } @cctok;
@cond = sort @cond;
@pptok = sort @pptok;
@ppitok = sort @ppitok;
@tasm = sort @tasm;
# Generate the expanded list including conditionals. The conditionals
# are at the beginning, padded to a power of 2, with the inverses
@ -217,14 +221,15 @@ if ($what eq 'c') {
}
print OUT "};\n";
print OUT "enum preproc_token pp_token_hash(const char *token)\n";
print OUT "{\n";
# Put a large value in unused slots. This makes it extremely unlikely
# that any combination that involves unused slot will pass the range test.
# This speeds up rejection of unrecognized tokens, i.e. identifiers.
print OUT "#define UNUSED_HASH_ENTRY (65535/3)\n";
print OUT "\n\n/* Primary preprocessor token hash */\n\n";
print OUT "enum preproc_token pp_token_hash(const char *token)\n";
print OUT "{\n";
print OUT " static const int16_t hash1[$n] = {\n";
for ($i = 0; $i < $n; $i++) {
my $h = ${$g}[$i*2+0];
@ -261,6 +266,69 @@ if ($what eq 'c') {
print OUT "\n";
print OUT " return ix;\n";
print OUT "}\n";
my %tasmtokens = ();
foreach $pt (@tasm) {
# TASM compatiblity token
$nasmt = '%'.$pt;
if (!defined($tokens{$nasmt})) {
die "$in: TASM compat token $pt does not have a ".
"corresponding $nasmt\n";
}
$tasmtokens{$pt} = $tokens{$nasmt};
}
@hashinfo = gen_perfect_hash(\%tasmtokens);
if (!@hashinfo) {
die "$0: no hash found\n";
}
# Paranoia...
verify_hash_table(\%tasmtokens, \@hashinfo);
($n, $sv, $g) = @hashinfo;
die if ($n & ($n-1));
print OUT "\n\n/* TASM compatibility preprocessor token hash */\n";
print OUT "enum preproc_token pp_tasm_token_hash(const char *token)\n";
print OUT "{\n";
print OUT " static const int16_t hash1[$n] = {\n";
for ($i = 0; $i < $n; $i++) {
my $h = ${$g}[$i*2+0];
print OUT " ", defined($h) ? $h : 'UNUSED_HASH_ENTRY', ",\n";
}
print OUT " };\n";
print OUT " static const int16_t hash2[$n] = {\n";
for ($i = 0; $i < $n; $i++) {
my $h = ${$g}[$i*2+1];
print OUT " ", defined($h) ? $h : 'UNUSED_HASH_ENTRY', ",\n";
}
print OUT " };\n";
print OUT " uint32_t k1, k2;\n";
print OUT " uint64_t crc;\n";
# For correct overflow behavior, "ix" should be unsigned of the same
# width as the hash arrays.
print OUT " uint16_t ix;\n";
print OUT "\n";
printf OUT " crc = crc64i(UINT64_C(0x%08x%08x), token);\n",
$$sv[0], $$sv[1];
print OUT " k1 = (uint32_t)crc;\n";
print OUT " k2 = (uint32_t)(crc >> 32);\n";
print OUT "\n";
printf OUT " ix = hash1[k1 & 0x%x] + hash2[k2 & 0x%x];\n", $n-1, $n-1;
printf OUT " if (ix >= %d)\n", scalar(@pptok);
print OUT " return PP_INVALID;\n";
print OUT "\n";
print OUT " if (!pp_directives[ix] || nasm_stricmp(pp_directives[ix]+1, token))\n";
print OUT " return PP_INVALID;\n";
print OUT "\n";
print OUT " return ix;\n";
print OUT "}\n";
}
#

View File

@ -1,205 +0,0 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 1996-2016 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ----------------------------------------------------------------------- */
/*
* This is a null preprocessor which just copies lines from input
* to output. It's used when someone explicitly requests that NASM
* not preprocess their source file.
*/
#include "compiler.h"
#include "nctype.h"
#include <time.h>
#include "nasm.h"
#include "nasmlib.h"
#include "error.h"
#include "preproc.h"
#include "listing.h"
#define BUF_DELTA 512
static FILE *nop_fp;
static int32_t nop_lineinc;
static void nop_init(void)
{
/* Nothing to do */
}
static void nop_reset(const char *file, enum preproc_mode mode,
struct strlist *deplist)
{
(void)mode; /* placate compilers */
src_set(0, file);
nop_lineinc = 1;
nop_fp = nasm_open_read(file, NF_TEXT);
if (!nop_fp)
nasm_fatalf(ERR_NOFILE, "unable to open input file `%s'", file);
strlist_add(deplist, file);
}
static char *nop_getline(void)
{
char *buffer, *p, *q;
int bufsize;
bufsize = BUF_DELTA;
buffer = nasm_malloc(BUF_DELTA);
src_set_linnum(src_get_linnum() + nop_lineinc);
while (1) { /* Loop to handle %line */
p = buffer;
while (1) { /* Loop to handle long lines */
q = fgets(p, bufsize - (p - buffer), nop_fp);
if (!q)
break;
p += strlen(p);
if (p > buffer && p[-1] == '\n')
break;
if (p - buffer > bufsize - 10) {
int offset;
offset = p - buffer;
bufsize += BUF_DELTA;
buffer = nasm_realloc(buffer, bufsize);
p = buffer + offset;
}
}
if (!q && p == buffer) {
nasm_free(buffer);
return NULL;
}
/*
* Play safe: remove CRs, LFs and any spurious ^Zs, if any of
* them are present at the end of the line.
*/
buffer[strcspn(buffer, "\r\n\032")] = '\0';
if (!nasm_strnicmp(buffer, "%line", 5)) {
int32_t ln;
int li;
char *nm = nasm_malloc(strlen(buffer));
int conv = sscanf(buffer + 5, "%"PRId32"+%d %s", &ln, &li, nm);
if (conv >= 2) {
if (!pp_noline)
src_set(ln, conv >= 3 ? nm : NULL);
nop_lineinc = li;
}
nasm_free(nm);
if (conv >= 2)
continue;
}
break;
}
lfmt->line(LIST_READ, src_get_linnum(), buffer);
return buffer;
}
static void nop_cleanup_pass(void)
{
if (nop_fp) {
fclose(nop_fp);
nop_fp = NULL;
}
}
static void nop_cleanup_session(void)
{
/* Nothing we need to do */
}
static void nop_extra_stdmac(macros_t *macros)
{
(void)macros;
}
static void nop_pre_define(char *definition)
{
(void)definition;
}
static void nop_pre_undefine(char *definition)
{
(void)definition;
}
static void nop_pre_include(char *fname)
{
(void)fname;
}
static void nop_pre_command(const char *what, char *string)
{
(void)what;
(void)string;
}
static void nop_include_path(struct strlist *list)
{
(void)list;
}
static void nop_error_list_macros(errflags severity)
{
(void)severity;
}
static bool nop_suppress_error(errflags severity)
{
(void)severity;
return false;
}
const struct preproc_ops preproc_nop = {
nop_init,
nop_reset,
nop_getline,
nop_cleanup_pass,
nop_cleanup_session,
nop_extra_stdmac,
nop_pre_define,
nop_pre_undefine,
nop_pre_include,
nop_pre_command,
nop_include_path,
nop_error_list_macros,
nop_suppress_error
};

View File

@ -82,15 +82,23 @@
* other directives. This structure is initialized to zero on each
* pass; this *must* reflect the default initial state.
*/
static struct pp_opts {
static struct pp_config {
bool noaliases;
bool sane_empty_expansion;
} ppopt;
} ppconf;
/*
* Preprocessor debug-related flags
*/
static enum pp_debug_flags {
PDBG_MACROS = 1 /* Collect macro information */
} ppdbg;
/*
* Preprocessor options configured on the command line
*/
static enum preproc_opt ppopt;
typedef struct SMacro SMacro;
typedef struct MMacro MMacro;
typedef struct MMacroInvocation MMacroInvocation;
@ -582,22 +590,6 @@ static int is_condition(enum preproc_token arg)
return PP_IS_COND(arg) || (arg == PP_ELSE) || (arg == PP_ENDIF);
}
/* For TASM compatibility we need to be able to recognise TASM compatible
* conditional compilation directives. Using the NASM pre-processor does
* not work, so we look for them specifically from the following list and
* then jam in the equivalent NASM directive into the input stream.
*/
enum {
TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI,
TM_IFNDEF, TM_INCLUDE, TM_LOCAL
};
static const char * const tasm_directives[] = {
"arg", "elif", "else", "endif", "if", "ifdef", "ifdifi",
"ifndef", "include", "local"
};
static int StackSize = 4;
static const char *StackPointer = "ebp";
static int ArgOffset = 8;
@ -892,90 +884,6 @@ static const char *pp_getenv(const Token *t, bool warn)
return v;
}
/*
* Handle TASM specific directives, which do not contain a % in
* front of them. We do it here because I could not find any other
* place to do it for the moment, and it is a hack (ideally it would
* be nice to be able to use the NASM pre-processor to do it).
*/
static char *check_tasm_directive(char *line)
{
int32_t i, j, k, m, len;
char *p, *q, *oldline, oldchar;
p = nasm_skip_spaces(line);
/* Binary search for the directive name */
i = -1;
j = ARRAY_SIZE(tasm_directives);
q = nasm_skip_word(p);
len = q - p;
if (len) {
oldchar = p[len];
p[len] = 0;
while (j - i > 1) {
k = (j + i) / 2;
m = nasm_stricmp(p, tasm_directives[k]);
if (m == 0) {
/* We have found a directive, so jam a % in front of it
* so that NASM will then recognise it as one if it's own.
*/
p[len] = oldchar;
len = strlen(p);
oldline = line;
line = nasm_malloc(len + 2);
line[0] = '%';
if (k == TM_IFDIFI) {
/*
* NASM does not recognise IFDIFI, so we convert
* it to %if 0. This is not used in NASM
* compatible code, but does need to parse for the
* TASM macro package.
*/
strcpy(line + 1, "if 0");
} else {
memcpy(line + 1, p, len + 1);
}
nasm_free(oldline);
return line;
} else if (m < 0) {
j = k;
} else
i = k;
}
p[len] = oldchar;
}
return line;
}
/*
* The pre-preprocessing stage... This function translates line
* number indications as they emerge from GNU cpp (`# lineno "file"
* flags') into NASM preprocessor line number indications (`%line
* lineno file').
*/
static char *prepreproc(char *line)
{
int lineno, fnlen;
char *fname, *oldline;
if (line[0] == '#' && line[1] == ' ') {
oldline = line;
fname = oldline + 2;
lineno = atoi(fname);
fname += strspn(fname, "0123456789 ");
if (*fname == '"')
fname++;
fnlen = strcspn(fname, "\"");
line = nasm_malloc(20 + fnlen);
snprintf(line, 20 + fnlen, "%%line %d %.*s", lineno, fnlen, fname);
nasm_free(oldline);
}
if (tasm_compatible_mode)
return check_tasm_directive(line);
return line;
}
/*
* Free a linked list of tokens.
*/
@ -2421,7 +2329,7 @@ restart:
(nparam <= 0 || m->nparam == 0 || nparam == m->nparam ||
(m->greedy && nparam >= m->nparam-1))) {
if (m->alias && !find_alias) {
if (!ppopt.noaliases) {
if (!ppconf.noaliases) {
name = tok_text(m->expansion);
goto restart;
} else {
@ -2602,6 +2510,15 @@ static enum cond_state if_condition(Token * tline, enum preproc_token ct)
break;
}
case PP_IFDIFI:
/*
* %ifdifi doesn't actually exist; it ignores its argument and is
* always false. This exists solely to stub out the corresponding
* TASM directive.
*/
j = false;
goto fail;
case PP_IFENV:
tline = expand_smacro(tline);
j = false; /* have we matched yet? */
@ -3100,7 +3017,7 @@ static SMacro *define_smacro(const char *mname, bool casesense,
* some others didn't. What is the right thing to do here?
*/
goto fail;
} else if (!smac->alias || ppopt.noaliases || defining_alias) {
} else if (!smac->alias || ppconf.noaliases || defining_alias) {
/*
* We're redefining, so we have to take over an
* existing SMacro structure. This means freeing
@ -3169,7 +3086,7 @@ static void undef_smacro(const char *mname, bool undefalias)
while ((s = *sp) != NULL) {
if (!mstrcmp(s->name, mname, s->casesense)) {
if (s->alias && !undefalias) {
if (!ppopt.noaliases) {
if (!ppconf.noaliases) {
if (s->in_progress) {
nasm_nonfatal("macro alias loop");
} else {
@ -3255,7 +3172,7 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
def->dlist = tline->next;
tline->next = NULL;
comma = count_mmac_params(def->dlist, &def->ndefs, &def->defaults);
if (!ppopt.sane_empty_expansion && comma) {
if (!ppconf.sane_empty_expansion && comma) {
*comma = NULL;
def->ndefs--;
nasm_warn(WARN_MACRO_PARAMS_LEGACY,
@ -3313,8 +3230,8 @@ static void do_pragma_preproc(Token *tline)
txt = tok_text(tline);
if (!nasm_stricmp(txt, "sane_empty_expansion")) {
tline = skip_white(tline->next);
ppopt.sane_empty_expansion =
pp_get_boolean_option(tline, ppopt.sane_empty_expansion);
ppconf.sane_empty_expansion =
pp_get_boolean_option(tline, ppconf.sane_empty_expansion);
} else {
/* Unknown pragma, ignore for now */
}
@ -3422,6 +3339,78 @@ static void do_clear(enum clear_what what, bool context)
}
}
/*
* Process a %line directive, including the gcc/cpp compatibility
* form with a # at the front.
*/
static int line_directive(Token *origline, Token *tline)
{
int k, m;
bool err;
const char *dname;
/*
* Valid syntaxes:
* %line nnn[+mmm] [filename]
* %line nnn[+mmm] "filename" flags...
*
* "flags" are for gcc compatibility and are currently ignored.
*
* '#' at the beginning of the line is also treated as a %line
* directive, again for compatibility with gcc.
*/
if ((ppopt & PP_NOLINE) || istk->mstk.mstk)
goto done;
dname = tok_text(tline);
tline = tline->next;
tline = skip_white(tline);
if (!tok_type(tline, TOK_NUMBER)) {
nasm_nonfatal("`%s' expects a 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 a 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) {
/*
* If this is a quoted string, ignore anything after
* it; this allows for compatiblity with gcc's
* additional flags options.
*/
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;
done:
free_tlist(origline);
return DIRECTIVE_FOUND;
}
/**
* find and process preprocessor directive in passed line
* Find out if a line contains a preprocessor directive, and deal
@ -3439,10 +3428,8 @@ static int do_directive(Token *tline, Token **output)
{
enum preproc_token op;
int j;
bool err;
enum nolist_flags nolist;
bool casesense;
int k, m;
int offset;
const char *p;
char *q, *qbuf;
@ -3465,15 +3452,54 @@ static int do_directive(Token *tline, Token **output)
*output = NULL; /* No output generated */
origline = tline;
/* cpp-like line directive, must not be preceeded by whitespace */
if (tok_is(tline, '#'))
return line_directive(origline, tline);
tline = skip_white(tline);
if (!tline || !tok_type(tline, TOK_PREPROC_ID))
return NO_DIRECTIVE_FOUND;
if (!tline)
return NO_DIRECTIVE_FOUND;
dname = tok_text(tline);
if (dname[1] == '%')
return NO_DIRECTIVE_FOUND;
switch (tline->type) {
case TOK_PREPROC_ID:
dname = tok_text(tline);
if (dname[1] == '%' || dname[1] == '$')
return NO_DIRECTIVE_FOUND;
op = pp_token_hash(dname);
op = pp_token_hash(dname);
break;
case TOK_ID:
if (likely(!(ppopt & PP_TASM)))
return NO_DIRECTIVE_FOUND;
dname = tok_text(tline);
op = pp_tasm_token_hash(dname);
break;
default:
return NO_DIRECTIVE_FOUND;
}
switch (op) {
case PP_INVALID:
return NO_DIRECTIVE_FOUND;
case PP_LINE:
/*
* %line directives are always processed immediately and
* unconditionally, as they are intended to reflect position
* in externally preprocessed sources.
*/
if (op == PP_LINE)
return line_directive(origline, tline);
default:
break;
}
if (unlikely(ppopt & PP_TRIVIAL))
goto done;
casesense = true;
if (PP_HAS_CASE(op) & PP_INSENSITIVE(op)) {
@ -3481,56 +3507,6 @@ static int do_directive(Token *tline, Token **output)
op--;
}
/*
* %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,
@ -4703,7 +4679,7 @@ issue_error:
case PP_ALIASES:
tline = tline->next;
tline = expand_smacro(tline);
ppopt.noaliases = !pp_get_boolean_option(tline, !ppopt.noaliases);
ppconf.noaliases = !pp_get_boolean_option(tline, !ppconf.noaliases);
break;
case PP_LINE:
@ -5244,7 +5220,7 @@ static SMacro *expand_one_smacro(Token ***tpp)
* checking for parameters if necessary.
*/
list_for_each(m, head) {
if (unlikely(m->alias && ppopt.noaliases))
if (unlikely(m->alias && ppconf.noaliases))
continue;
if (!mstrcmp(m->name, mname, m->casesense))
break;
@ -6004,7 +5980,7 @@ static MMacro *is_mmacro(Token * tline, int *nparamp, Token ***paramsp)
*!-
*! It is highly recommended to use this option in new code.
*/
if (!ppopt.sane_empty_expansion) {
if (!ppconf.sane_empty_expansion) {
if (!found) {
if (raw_nparam == 0 && !empty_args) {
/*
@ -6190,7 +6166,7 @@ static struct debug_macro_addr *
debug_macro_get_addr_inv(int32_t seg, struct debug_macro_inv *inv)
{
struct debug_macro_addr *addr;
static_assert(offsetof(struct debug_macro_addr, tree) == 0);
nasm_static_assert(offsetof(struct debug_macro_addr, tree) == 0);
if (likely(seg == inv->lastseg))
return inv->addr.last;
@ -6280,7 +6256,7 @@ static void debug_macro_end(MMacro *m)
static void free_debug_macro_addr_tree(struct rbtree *tree)
{
struct rbtree *left, *right;
static_assert(offsetof(struct debug_macro_addr,tree) == 0);
nasm_static_assert(offsetof(struct debug_macro_addr,tree) == 0);
if (!tree)
return;
@ -6573,11 +6549,13 @@ static bool pp_suppress_error(errflags severity)
static Token *
stdmac_file(const SMacro *s, Token **params, int nparams)
{
const char *fname = src_get_fname();
(void)s;
(void)params;
(void)nparams;
return make_tok_qstr(NULL, src_get_fname());
return fname ? make_tok_qstr(NULL, fname) : NULL;
}
static Token *
@ -6648,60 +6626,25 @@ static void pp_add_magic_stdmac(void)
}
}
static void
pp_reset(const char *file, enum preproc_mode mode, struct strlist *dep_list)
static void pp_reset_stdmac(enum preproc_mode mode)
{
int apass;
struct Include *inc;
cstk = NULL;
defining = NULL;
nested_mac_count = 0;
nested_rep_count = 0;
init_macros();
unique = 0;
deplist = dep_list;
pp_mode = mode;
/* Reset options to default */
nasm_zero(ppopt);
/* Disable all debugging info, except in the last pass */
ppdbg = 0;
if (pass_final()) {
if (dfmt->debug_macros)
ppdbg |= PDBG_MACROS;
}
if (!use_loaded)
use_loaded = nasm_malloc(use_package_count * sizeof(bool));
memset(use_loaded, 0, use_package_count * sizeof(bool));
/* 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;
strlist_add(deplist, file);
/*
* Set up the stdmac packages as a virtual include file,
* indicated by a null file pointer.
*/
nasm_new(inc);
inc->next = istk;
src_set(0, NULL);
inc->where = src_where();
inc->nolist = inc->noline = !list_option('b');
istk = inc;
if (!istk->nolist)
lfmt->uplevel(LIST_INCLUDE, 0);
if (!istk->noline)
src_set(0, NULL);
istk->where = src_where();
pp_add_magic_stdmac();
@ -6747,8 +6690,55 @@ pp_reset(const char *file, enum preproc_mode mode, struct strlist *dep_list)
define_smacro("__?PASS?__", true, make_tok_num(NULL, apass), NULL);
}
static void pp_init(void)
static void pp_reset(const char *file, enum preproc_mode mode,
struct strlist *dep_list)
{
cstk = NULL;
defining = NULL;
nested_mac_count = 0;
nested_rep_count = 0;
init_macros();
unique = 0;
deplist = dep_list;
pp_mode = mode;
/* Reset options to default */
nasm_zero(ppconf);
/* Disable all debugging info, except in the last pass */
ppdbg = 0;
if (!(ppopt & PP_TRIVIAL)) {
if (pass_final()) {
if (dfmt->debug_macros)
ppdbg |= PDBG_MACROS;
}
}
memset(use_loaded, 0, use_package_count * sizeof(bool));
/* 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;
strlist_add(deplist, file);
do_predef = false;
if (!(ppopt & PP_TRIVIAL))
pp_reset_stdmac(mode);
}
static void pp_init(enum preproc_opt opt)
{
ppopt = opt;
nasm_newn(use_loaded, use_package_count);
}
/*
@ -6909,7 +6899,6 @@ static Token *pp_tokline(void)
nasm_free(line);
}
} else if ((line = read_line())) {
line = prepreproc(line);
tline = tokenize(line);
nasm_free(line);
} else {
@ -7236,7 +7225,8 @@ static void pp_error_list_macros(errflags severity)
src_error_reset();
}
const struct preproc_ops nasmpp = {
/* The normal NASM preprocessor */
const struct preproc_ops preproc_nasm = {
pp_init,
pp_reset,
pp_getline,

View File

@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 1996-2009 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,12 +43,12 @@
extern const char * const pp_directives[];
extern const uint8_t pp_directives_len[];
extern bool pp_noline;
/* Pointer to a macro chain */
typedef const unsigned char macros_t;
enum preproc_token pp_token_hash(const char *token);
enum preproc_token pp_tasm_token_hash(const char *token);
/* Opens an include file or input file. This uses the include path. */
FILE *pp_input_fopen(const char *filename, enum file_flags mode);

View File

@ -344,11 +344,17 @@ enum preproc_mode {
PP_PREPROC /* Preprocessing only */
};
enum preproc_opt {
PP_TRIVIAL = 1, /* Only %line or # directives */
PP_NOLINE = 2, /* Ignore %line and # directives */
PP_TASM = 4 /* TASM compatibility hacks */
};
struct preproc_ops {
/*
* Called once at the very start of assembly.
*/
void (*init)(void);
void (*init)(enum preproc_opt opt);
/*
* Called at the start of a pass; given a file name, the number
@ -398,8 +404,7 @@ struct preproc_ops {
bool (*suppress_error)(errflags severity);
};
extern const struct preproc_ops nasmpp;
extern const struct preproc_ops preproc_nop;
extern const struct preproc_ops preproc_nasm;
/* List of dependency files */
extern struct strlist *depend_list;