[nasm:master] preproc: get rid of the prepreprocessor and the nop preprocessor

nasm-bot for H. Peter Anvin (Intel) hpa at zytor.com
Thu Jul 9 23:44:04 PDT 2020


Commit-ID:  32322a9a93e52ab7406f996f9fd67d0634bed7bd
Gitweb:     http://repo.or.cz/w/nasm.git?a=commitdiff;h=32322a9a93e52ab7406f996f9fd67d0634bed7bd
Author:     H. Peter Anvin (Intel) <hpa at zytor.com>
AuthorDate: Thu, 9 Jul 2020 23:34:52 -0700
Committer:  H. Peter Anvin (Intel) <hpa at zytor.com>
CommitDate: Thu, 9 Jul 2020 23:34:52 -0700

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 at zytor.com>


---
 Makefile.in          |   1 -
 Mkfiles/msvc.mak     |   1 -
 Mkfiles/openwcom.mak |   1 -
 asm/nasm.c           |  20 +--
 asm/pptok.dat        |  15 +-
 asm/pptok.pl         |  80 +++++++++-
 asm/preproc-nop.c    | 205 -------------------------
 asm/preproc.c        | 414 +++++++++++++++++++++++++--------------------------
 asm/preproc.h        |   4 +-
 include/nasm.h       |  11 +-
 10 files changed, 311 insertions(+), 441 deletions(-)

diff --git a/Makefile.in b/Makefile.in
index bb023d02..3152aca1 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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) \
diff --git a/Mkfiles/msvc.mak b/Mkfiles/msvc.mak
index 9346c293..9e6cc361 100644
--- a/Mkfiles/msvc.mak
+++ b/Mkfiles/msvc.mak
@@ -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) \
diff --git a/Mkfiles/openwcom.mak b/Mkfiles/openwcom.mak
index 262a0419..d15dd667 100644
--- a/Mkfiles/openwcom.mak
+++ b/Mkfiles/openwcom.mak
@@ -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) &
diff --git a/asm/nasm.c b/asm/nasm.c
index c5d9aff1..918bce91 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -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;
diff --git a/asm/pptok.dat b/asm/pptok.dat
index 9b890a19..3dede0bc 100644
--- a/asm/pptok.dat
+++ b/asm/pptok.dat
@@ -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
+ at arg
+ at elif
+ at else
+ at endif
+ at if
+ at ifdef
+ at ifdifi
+ at ifndef
+ at include
+ at local
diff --git a/asm/pptok.pl b/asm/pptok.pl
index 5498cb46..0ac044f4 100755
--- a/asm/pptok.pl
+++ b/asm/pptok.pl
@@ -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
- at cctok = sort { $a eq 'if' ? -1 : $b eq 'if' ? 1 : $a cmp $b } @cctok;
- at cond = sort @cond;
- at pptok = sort @pptok;
+ at cctok  = sort { $a eq 'if' ? -1 : $b eq 'if' ? 1 : $a cmp $b } @cctok;
+ at cond   = sort @cond;
+ at pptok  = sort @pptok;
 @ppitok = sort @ppitok;
+ at 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";
 }
 
 #
diff --git a/asm/preproc-nop.c b/asm/preproc-nop.c
deleted file mode 100644
index a927880c..00000000
--- a/asm/preproc-nop.c
+++ /dev/null
@@ -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
-};
diff --git a/asm/preproc.c b/asm/preproc.c
index 68078ec8..c342d0a5 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -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,70 +3452,59 @@ 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;
 
-    casesense = true;
-    if (PP_HAS_CASE(op) & PP_INSENSITIVE(op)) {
-        casesense = false;
-        op--;
+    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;
     }
 
-    /*
-     * %line directives are always processed immediately and
-     * unconditionally, as they are intended to reflect position
-     * in externally preprocessed sources.
-     */
-    if (op == PP_LINE) {
+    switch (op) {
+    case PP_INVALID:
+        return NO_DIRECTIVE_FOUND;
+
+    case PP_LINE:
         /*
-         * Syntax is `%line nnn[+mmm] [filename]'
+         * %line directives are always processed immediately and
+         * unconditionally, as they are intended to reflect position
+         * in externally preprocessed sources.
          */
-        if (pp_noline || istk->mstk.mstk)
-            goto done;
+        if (op == PP_LINE)
+            return line_directive(origline, tline);
 
-        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);
+    default:
+        break;
+    }
 
-        istk->where = src_where();
-        istk->lineinc = m;
+    if (unlikely(ppopt & PP_TRIVIAL))
         goto done;
+
+    casesense = true;
+    if (PP_HAS_CASE(op) & PP_INSENSITIVE(op)) {
+        casesense = false;
+        op--;
     }
 
     /*
@@ -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,
diff --git a/asm/preproc.h b/asm/preproc.h
index 14d4cfd3..71130466 100644
--- a/asm/preproc.h
+++ b/asm/preproc.h
@@ -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);
diff --git a/include/nasm.h b/include/nasm.h
index 22fd6264..df1593e4 100644
--- a/include/nasm.h
+++ b/include/nasm.h
@@ -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;


More information about the Nasm-commits mailing list