aboutsummaryrefslogtreecommitdiffstats
path: root/asm
diff options
context:
space:
mode:
Diffstat (limited to 'asm')
-rw-r--r--asm/assemble.c94
-rw-r--r--asm/listing.c3
-rw-r--r--asm/listing.h38
-rw-r--r--asm/nasm.c95
-rwxr-xr-xasm/phash.pl109
-rw-r--r--asm/pptok.dat16
-rwxr-xr-xasm/pptok.pl158
-rw-r--r--asm/preproc-nop.c205
-rw-r--r--asm/preproc.c1847
-rw-r--r--asm/preproc.h4
-rw-r--r--asm/quote.c75
-rw-r--r--asm/quote.h15
-rw-r--r--asm/srcfile.h6
-rwxr-xr-xasm/tokhash.pl25
14 files changed, 1407 insertions, 1283 deletions
diff --git a/asm/assemble.c b/asm/assemble.c
index 4801ad87..ecf5c093 100644
--- a/asm/assemble.c
+++ b/asm/assemble.c
@@ -186,6 +186,7 @@
#include "tables.h"
#include "disp8.h"
#include "listing.h"
+#include "dbginfo.h"
enum match_result {
/*
@@ -300,30 +301,40 @@ static void warn_overflow_const(int64_t data, int size)
warn_overflow(size);
}
-static void warn_overflow_out(int64_t data, int size, enum out_sign sign)
+static void warn_overflow_out(int64_t data, int size, enum out_flags flags)
{
bool err;
- switch (sign) {
- case OUT_WRAP:
- err = overflow_general(data, size);
- break;
- case OUT_SIGNED:
+ if (flags & OUT_SIGNED)
err = overflow_signed(data, size);
- break;
- case OUT_UNSIGNED:
+ else if (flags & OUT_UNSIGNED)
err = overflow_unsigned(data, size);
- break;
- default:
- panic();
- break;
- }
+ else
+ err = overflow_general(data, size);
if (err)
warn_overflow(size);
}
/*
+ * Collect macro-related debug information, if applicable.
+ */
+static void debug_macro_out(const struct out_data *data)
+{
+ struct debug_macro_addr *addr;
+ uint64_t start = data->offset;
+ uint64_t end = start + data->size;
+
+ addr = debug_macro_get_addr(data->segment);
+ while (addr) {
+ if (!addr->len)
+ addr->start = start;
+ addr->len = end - addr->start;
+ addr = addr->up;
+ }
+}
+
+/*
* This routine wrappers the real output format's output routine,
* in order to pass a copy of the data off to the listing file
* generator at the same time, flatten unnecessary relocations,
@@ -376,11 +387,14 @@ static void out(struct out_data *data)
nasm_assert(data->size <= 8);
asize = data->size;
amax = ofmt->maxbits >> 3; /* Maximum address size in bytes */
- if ((ofmt->flags & OFMT_KEEP_ADDR) == 0 && data->tsegment == fixseg &&
+ if (!(ofmt->flags & OFMT_KEEP_ADDR) &&
+ data->tsegment == fixseg &&
data->twrt == NO_SEG) {
- if (asize >= (size_t)(data->bits >> 3))
- data->sign = OUT_WRAP; /* Support address space wrapping for low-bit modes */
- warn_overflow_out(addrval, asize, data->sign);
+ if (asize >= (size_t)(data->bits >> 3)) {
+ /* Support address space wrapping for low-bit modes */
+ data->flags &= ~OUT_SIGNMASK;
+ }
+ warn_overflow_out(addrval, asize, data->flags);
xdata.q = cpu_to_le64(addrval);
data->data = xdata.b;
data->type = OUT_RAWDATA;
@@ -415,7 +429,7 @@ static void out(struct out_data *data)
}
if (asize > amax) {
- if (data->type == OUT_RELADDR || data->sign == OUT_SIGNED) {
+ if (data->type == OUT_RELADDR || (data->flags & OUT_SIGNED)) {
nasm_nonfatal("%u-bit signed relocation unsupported by output format %s",
(unsigned int)(asize << 3), ofmt->shortname);
} else {
@@ -436,6 +450,12 @@ static void out(struct out_data *data)
lfmt->output(data);
if (likely(data->segment != NO_SEG)) {
+ /*
+ * Collect macro-related information for the debugger, if applicable
+ */
+ if (debug_current_macro)
+ debug_macro_out(data);
+
ofmt->output(data);
} else {
/* Outputting to ABSOLUTE section - only reserve is permitted */
@@ -487,17 +507,17 @@ static void out_segment(struct out_data *data, const struct operand *opx)
if (opx->opflags & OPFLAG_RELATIVE)
nasm_nonfatal("segment references cannot be relative");
- data->type = OUT_SEGMENT;
- data->sign = OUT_UNSIGNED;
- data->size = 2;
- data->toffset = opx->offset;
- data->tsegment = ofmt->segbase(opx->segment | 1);
- data->twrt = opx->wrt;
+ data->type = OUT_SEGMENT;
+ data->flags = OUT_UNSIGNED;
+ data->size = 2;
+ data->toffset = opx->offset;
+ data->tsegment = ofmt->segbase(opx->segment | 1);
+ data->twrt = opx->wrt;
out(data);
}
static void out_imm(struct out_data *data, const struct operand *opx,
- int size, enum out_sign sign)
+ int size, enum out_flags sign)
{
if (opx->segment != NO_SEG && (opx->segment & 1)) {
/*
@@ -512,10 +532,10 @@ static void out_imm(struct out_data *data, const struct operand *opx,
data->type = (opx->opflags & OPFLAG_RELATIVE)
? OUT_RELADDR : OUT_ADDRESS;
}
- data->sign = sign;
- data->toffset = opx->offset;
+ data->flags = sign;
+ data->toffset = opx->offset;
data->tsegment = opx->segment;
- data->twrt = opx->wrt;
+ data->twrt = opx->wrt;
/*
* XXX: improve this if at some point in the future we can
* distinguish the subtrahend in expressions like [foo - bar]
@@ -534,13 +554,13 @@ static void out_reladdr(struct out_data *data, const struct operand *opx,
if (opx->opflags & OPFLAG_RELATIVE)
nasm_nonfatal("invalid use of self-relative expression");
- data->type = OUT_RELADDR;
- data->sign = OUT_SIGNED;
- data->size = size;
- data->toffset = opx->offset;
+ data->type = OUT_RELADDR;
+ data->flags = OUT_SIGNED;
+ data->size = size;
+ data->toffset = opx->offset;
data->tsegment = opx->segment;
- data->twrt = opx->wrt;
- data->relbase = data->offset + (data->inslen - data->insoffs);
+ data->twrt = opx->wrt;
+ data->relbase = data->offset + (data->inslen - data->insoffs);
out(data);
}
@@ -641,12 +661,12 @@ static void out_eops(struct out_data *data, const extop *e)
data->relbase = 0;
if (e->val.num.segment != NO_SEG &&
(e->val.num.segment & 1)) {
- data->type = OUT_SEGMENT;
- data->sign = OUT_UNSIGNED;
+ data->type = OUT_SEGMENT;
+ data->flags = OUT_UNSIGNED;
} else {
data->type = e->val.num.relative
? OUT_RELADDR : OUT_ADDRESS;
- data->sign = OUT_WRAP;
+ data->flags = OUT_WRAP;
}
out(data);
}
diff --git a/asm/listing.c b/asm/listing.c
index 3bb31ef6..186b8b4e 100644
--- a/asm/listing.c
+++ b/asm/listing.c
@@ -130,6 +130,7 @@ static void list_cleanup(void)
list_emit();
fclose(listfp);
listfp = NULL;
+ active_list_options = 0;
}
static void list_init(const char *fname)
@@ -153,6 +154,8 @@ static void list_init(const char *fname)
return;
}
+ active_list_options = list_options | 1;
+
*listline = '\0';
listlineno = 0;
list_errors = NULL;
diff --git a/asm/listing.h b/asm/listing.h
index f62fc08f..639a56ee 100644
--- a/asm/listing.h
+++ b/asm/listing.h
@@ -126,34 +126,37 @@ extern bool user_nolist;
extern uint64_t list_options, active_list_options;
/*
- * This maps the characters a-z, A-Z and 0-9 onto a 64-bit bitmask
- * (with two bits left over for future use! This isn't particularly
- * efficient code, but just about every instance of it should be
- * fed a constant, so the entire function can be precomputed at
- * compile time. The only cases where the full computation is needed
- * is when parsing the -L option or %pragma list options, neither of
- * which is in any way performance critical.
+ * This maps the characters a-z, A-Z and 0-9 onto a 64-bit bitmask.
+ * Bit 0 is used to indicate that the listing engine is active, and
+ * bit 1 is reserved, so this will only return mask bits 2 and higher;
+ * as there are 62 possible characters this fits nicely.
+ *
+ * The mask returned is 0 for invalid characters, accessing no bits at
+ * all.
+ *
+ * This isn't particularly efficient code, but just about every
+ * instance of it should be fed a constant, so the entire function can
+ * be precomputed at compile time. The only cases where the full
+ * computation is needed is when parsing the -L option or %pragma list
+ * options, neither of which is in any way performance critical.
*
* The character + represents ALL listing options except -Lw (flush
* after every line.)
- *
- * This returns 0 for invalid values, so that no bit is accessed
- * for unsupported characters.
*/
static inline const_func uint64_t list_option_mask_val(unsigned char x)
{
if (x >= 'a') {
if (x > 'z')
return 0;
- x = x - 'a';
+ x = x - 'a' + 2;
} else if (x >= 'A') {
if (x > 'Z')
return 0;
- x = x - 'A' + 26;
+ x = x - 'A' + 2 + 26;
} else if (x >= '0') {
if (x > '9')
return 0;
- x = x - '0' + 26*2;
+ x = x - '0' + 2 + 26*2;
} else {
return 0;
}
@@ -164,11 +167,12 @@ static inline const_func uint64_t list_option_mask_val(unsigned char x)
static inline const_func uint64_t list_option_mask(unsigned char x)
{
if (x == '+')
- return ~list_option_mask_val('w');
+ return ~(list_option_mask_val('w') | 3);
else
return list_option_mask_val(x);
}
+/* Return true if the listing engine is active and a certain option is set. */
static inline pure_func bool list_option(unsigned char x)
{
return unlikely(active_list_options & list_option_mask(x));
@@ -180,6 +184,12 @@ static inline pure_func bool list_on_every_pass(void)
return unlikely(list_options & list_option_mask('p'));
}
+/* Is the listing engine active? */
+static inline pure_func bool list_active(void)
+{
+ return (active_list_options & 1);
+}
+
/* Pragma handler */
enum directive_result list_pragma(const struct pragma *);
diff --git a/asm/nasm.c b/asm/nasm.c
index e5ae89af..6af92754 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -143,9 +143,8 @@ static struct RAA *offsets;
static struct SAA *forwrefs; /* keep track of forward references */
static const struct forwrefinfo *forwref;
-static const struct preproc_ops *preproc;
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)
@@ -304,29 +303,29 @@ static void define_macros(void)
if (oct->have_local) {
strftime(temp, sizeof temp, "__?DATE?__=\"%Y-%m-%d\"", &oct->local);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
strftime(temp, sizeof temp, "__?DATE_NUM?__=%Y%m%d", &oct->local);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
strftime(temp, sizeof temp, "__?TIME?__=\"%H:%M:%S\"", &oct->local);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
strftime(temp, sizeof temp, "__?TIME_NUM?__=%H%M%S", &oct->local);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
}
if (oct->have_gm) {
strftime(temp, sizeof temp, "__?UTC_DATE?__=\"%Y-%m-%d\"", &oct->gm);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
strftime(temp, sizeof temp, "__?UTC_DATE_NUM?__=%Y%m%d", &oct->gm);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
strftime(temp, sizeof temp, "__?UTC_TIME?__=\"%H:%M:%S\"", &oct->gm);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
strftime(temp, sizeof temp, "__?UTC_TIME_NUM?__=%H%M%S", &oct->gm);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
}
if (oct->have_posix) {
snprintf(temp, sizeof temp, "__?POSIX_TIME?__=%"PRId64, oct->posix);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
}
/*
@@ -336,20 +335,20 @@ static void define_macros(void)
*/
snprintf(temp, sizeof(temp), "__?OUTPUT_FORMAT?__=%s",
ofmt_alias ? ofmt_alias->shortname : ofmt->shortname);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
/*
* Output-format specific macros.
*/
if (ofmt->stdmac)
- preproc->extra_stdmac(ofmt->stdmac);
+ pp_extra_stdmac(ofmt->stdmac);
/*
* Debug format, if any
*/
if (dfmt != &null_debug_form) {
snprintf(temp, sizeof(temp), "__?DEBUG_FORMAT?__=%s", dfmt->shortname);
- preproc->pre_define(temp);
+ pp_pre_define(temp);
}
}
@@ -364,9 +363,9 @@ static void define_macros(void)
*/
static void preproc_init(struct strlist *ipath)
{
- preproc->init();
+ pp_init(ppopt);
define_macros();
- preproc->include_path(ipath);
+ pp_include_path(ipath);
}
static void emit_dependencies(struct strlist *list)
@@ -551,7 +550,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);
@@ -576,6 +574,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);
@@ -618,13 +621,13 @@ int main(int argc, char **argv)
char *line;
if (depend_missing_ok)
- preproc->include_path(NULL); /* "assume generated" */
+ pp_include_path(NULL); /* "assume generated" */
- preproc->reset(inname, PP_DEPS, depend_list);
+ pp_reset(inname, PP_DEPS, depend_list);
ofile = NULL;
- while ((line = preproc->getline()))
+ while ((line = pp_getline()))
nasm_free(line);
- preproc->cleanup_pass();
+ pp_cleanup_pass();
reset_warnings();
} else if (operating_mode & OP_PREPROCESS) {
char *line;
@@ -647,9 +650,9 @@ int main(int argc, char **argv)
location.known = false;
_pass_type = PASS_PREPROC;
- preproc->reset(inname, PP_PREPROC, depend_list);
+ pp_reset(inname, PP_PREPROC, depend_list);
- while ((line = preproc->getline())) {
+ while ((line = pp_getline())) {
/*
* We generate %line directives if needed for later programs
*/
@@ -694,7 +697,7 @@ int main(int argc, char **argv)
nasm_free(quoted_file_name);
- preproc->cleanup_pass();
+ pp_cleanup_pass();
reset_warnings();
if (ofile)
fclose(ofile);
@@ -729,7 +732,7 @@ int main(int argc, char **argv)
}
}
- preproc->cleanup_session();
+ pp_cleanup_session();
if (depend_list && !terminate_after_phase)
emit_dependencies(depend_list);
@@ -1066,19 +1069,19 @@ static bool process_arg(char *p, char *q, int pass)
case 'p': /* pre-include */
case 'P':
if (pass == 2)
- preproc->pre_include(param);
+ pp_pre_include(param);
break;
case 'd': /* pre-define */
case 'D':
if (pass == 2)
- preproc->pre_define(param);
+ pp_pre_define(param);
break;
case 'u': /* un-define */
case 'U':
if (pass == 2)
- preproc->pre_undefine(param);
+ pp_pre_undefine(param);
break;
case 'i': /* include search path */
@@ -1142,10 +1145,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':
@@ -1160,7 +1161,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':
@@ -1311,15 +1312,15 @@ static bool process_arg(char *p, char *q, int pass)
break;
case OPT_INCLUDE:
if (pass == 2)
- preproc->pre_include(q);
+ pp_pre_include(q);
break;
case OPT_PRAGMA:
if (pass == 2)
- preproc->pre_command("pragma", param);
+ pp_pre_command("%pragma", param);
break;
case OPT_BEFORE:
if (pass == 2)
- preproc->pre_command(NULL, param);
+ pp_pre_command(NULL, param);
break;
case OPT_LIMIT:
if (pass == 1)
@@ -1329,7 +1330,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;
@@ -1689,9 +1690,8 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
cpu = cmd_cpu;
if (listname) {
if (pass_final() || list_on_every_pass()) {
- active_list_options = list_options;
lfmt->init(listname);
- } else if (active_list_options) {
+ } else if (list_active()) {
/*
* Looks like we used the list engine on a previous pass,
* but now it is turned off, presumably via %pragma -p
@@ -1699,7 +1699,6 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
lfmt->cleanup();
if (!keep_all)
remove(listname);
- active_list_options = 0;
}
}
@@ -1716,11 +1715,11 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
location.known = true;
ofmt->reset();
switch_segment(ofmt->section(NULL, &globalbits));
- preproc->reset(fname, PP_NORMAL, pass_final() ? depend_list : NULL);
+ pp_reset(fname, PP_NORMAL, pass_final() ? depend_list : NULL);
globallineno = 0;
- while ((line = preproc->getline())) {
+ while ((line = pp_getline())) {
if (++globallineno > nasm_limit[LIMIT_LINES])
nasm_fatal("overall line count exceeds the maximum %"PRId64"\n",
nasm_limit[LIMIT_LINES]);
@@ -1740,9 +1739,9 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
end_of_line:
nasm_free(line);
- } /* end while (line = preproc->getline... */
+ } /* end while (line = pp_getline... */
- preproc->cleanup_pass();
+ pp_cleanup_pass();
/* We better not be having an error hold still... */
nasm_assert(!errhold_stack);
@@ -1875,8 +1874,8 @@ static bool is_suppressed(errflags severity)
if (!(warning_state[warn_index(severity)] & WARN_ST_ENABLED))
return true;
- if (preproc && !(severity & ERR_PP_LISTMACRO))
- return preproc->suppress_error(severity);
+ if (!(severity & ERR_PP_LISTMACRO))
+ return pp_suppress_error(severity);
return false;
}
@@ -2109,8 +2108,7 @@ void nasm_verror(errflags severity, const char *fmt, va_list args)
return;
if (!(severity & (ERR_HERE|ERR_PP_LISTMACRO)))
- if (preproc)
- preproc->error_list_macros(severity);
+ pp_error_list_macros(severity);
}
/*
@@ -2155,8 +2153,7 @@ static void nasm_issue_error(struct nasm_errtext *et)
here = where.filename ? " here" : " in an unknown location";
}
- if (warn_list && true_type < ERR_NONFATAL &&
- !(pass_first() && (severity & ERR_PASS1))) {
+ if (warn_list && true_type < ERR_NONFATAL) {
/*
* Buffer up warnings until we either get an error
* or we are on the code-generation pass.
diff --git a/asm/phash.pl b/asm/phash.pl
deleted file mode 100755
index 3ef6e714..00000000
--- a/asm/phash.pl
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/perl
-## --------------------------------------------------------------------------
-##
-## Copyright 1996-2009 the NASM Authors - All rights reserved.
-##
-## 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.
-##
-## --------------------------------------------------------------------------
-
-#
-# Perfect Minimal Hash Generator written in Perl, which produces
-# C output.
-#
-
-require 'phash.ph';
-
-#
-# Read input file
-#
-sub read_input() {
- my $key,$val;
- my %out;
- my $x = 0;
-
- while (defined($l = <STDIN>)) {
- chomp $l;
- $l =~ s/\s*(\#.*|)$//;
-
- next if ($l eq '');
-
- if ($l =~ /^([^=]+)\=([^=]+)$/) {
- $out{$1} = $2;
- $x = $2;
- } else {
- $out{$l} = $x;
- }
- $x++;
- }
-
- return %out;
-}
-
-#
-# Main program
-#
-sub main() {
- my $n;
- my %data;
- my @hashinfo;
- my $x, $i;
-
- %data = read_input();
- @hashinfo = gen_perfect_hash(\%data);
-
- if (!@hashinfo) {
- die "$0: no hash found\n";
- }
-
- verify_hash_table(\%data, \@hashinfo);
-
- ($n, $sv, $f1, $f2, $g) = @hashinfo;
-
- print "static int HASHNAME_fg1[$n] =\n";
- print "{\n";
- for ($i = 0; $i < $n; $i++) {
- print "\t", ${$g}[${$f1}[$i]], "\n";
- }
- print "};\n\n";
-
- print "static int HASHNAME_fg2[$n] =\n";
- print "{\n";
- for ($i = 0; $i < $n; $i++) {
- print "\t", ${$g}[${$f2}[$i]], "\n";
- }
- print "};\n\n";
-
- print "struct p_hash HASHNAME =\n";
- print "{\n";
- print "\t$n\n";
- print "\t$sv\n";
- print "\tHASHNAME_fg1,\n";
- print "\tHASHNAME_fg2,\n";
- print "};\n";
-}
-
-main();
diff --git a/asm/pptok.dat b/asm/pptok.dat
index 0fdbbad6..21144973 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
@@ -95,9 +96,22 @@
%push
%rep
%repl
+%require
%rotate
%stacksize
%undef
%undefalias
%use
%warning
+
+# These directives do not require % in TASM-compatible mode
+@arg
+@elif
+@else
+@endif
+@if
+@ifdef
+@ifdifi
+@ifndef
+@include
+@local
diff --git a/asm/pptok.pl b/asm/pptok.pl
index de1fac22..f40cb58e 100755
--- a/asm/pptok.pl
+++ b/asm/pptok.pl
@@ -1,7 +1,7 @@
#!/usr/bin/perl
## --------------------------------------------------------------------------
##
-## Copyright 1996-2019 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.
##
@@ -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
@@ -120,9 +124,11 @@ if ($what eq 'h') {
print OUT "enum preproc_token {\n";
$n = 0;
+ my $maxlen = 0;
foreach $pt (@pptok) {
if (defined($pt)) {
printf OUT " %-24s = %3d,\n", "PP_\U$pt\E", $n;
+ $maxlen = length($pt) if (length($pt) > $maxlen);
}
$n++;
}
@@ -139,6 +145,8 @@ if ($what eq 'h') {
printf OUT "#define PP_HAS_CASE(x) ((x) >= PP_%s)\n",
uc($pptok[$first_itoken]);
print OUT "#define PP_INSENSITIVE(x) ((x) & 1)\n";
+ # The +1 here is for the initial % sign
+ printf OUT "#define PP_TOKLEN_MAX %d\n", $maxlen+1;
print OUT "\n";
foreach $ct (@cctok) {
@@ -164,6 +172,36 @@ if ($what eq 'c') {
print OUT "/* Do not edit */\n";
print OUT "\n";
+ print OUT "#include \"compiler.h\"\n";
+ print OUT "#include \"nctype.h\"\n";
+ print OUT "#include \"nasmlib.h\"\n";
+ print OUT "#include \"hashtbl.h\"\n";
+ print OUT "#include \"preproc.h\"\n";
+ print OUT "\n";
+
+ # Note that this is global.
+ printf OUT "const char * const pp_directives[%d] = {\n", scalar(@pptok);
+ foreach $d (@pptok) {
+ if (defined($d) && $d !~ /[A-Z]/) {
+ print OUT " \"%$d\",\n";
+ } else {
+ print OUT " NULL,\n";
+ }
+ }
+ print OUT "};\n";
+
+ printf OUT "const uint8_t pp_directives_len[%d] = {\n", scalar(@pptok);
+ foreach $d (@pptok) {
+ printf OUT " %d,\n", defined($d) ? length($d)+1 : 0;
+ }
+ print OUT "};\n";
+
+ # Put a large value in unused hash 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 "\n#define INVALID_HASH_ENTRY (65535/3)\n";
+
my %tokens = ();
my @tokendata = ();
@@ -192,53 +230,75 @@ if ($what eq 'c') {
($n, $sv, $g) = @hashinfo;
die if ($n & ($n-1));
+ $n <<= 1;
- print OUT "#include \"compiler.h\"\n";
- print OUT "#include \"nctype.h\"\n";
- print OUT "#include \"nasmlib.h\"\n";
- print OUT "#include \"hashtbl.h\"\n";
- print OUT "#include \"preproc.h\"\n";
- print OUT "\n";
- # Note that this is global.
- printf OUT "const char * const pp_directives[%d] = {\n", scalar(@pptok);
- foreach $d (@pptok) {
- if (defined($d) && $d !~ /[A-Z]/) {
- print OUT " \"%$d\",\n";
- } else {
- print OUT " NULL,\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 hashdata[$n] = {\n";
+ for ($i = 0; $i < $n; $i++) {
+ my $h = ${$g}[$i];
+ print OUT " ", defined($h) ? $h : 'INVALID_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];
+ printf OUT " k1 = ((uint32_t)crc & 0x%x) + 0;\n", $n-2;
+ printf OUT " k2 = ((uint32_t)(crc >> 32) & 0x%x) + 1;\n", $n-2;
+ print OUT "\n";
+ print OUT " ix = hashdata[k1] + hashdata[k2];\n";
+ 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], token))\n";
+ print OUT " return PP_INVALID;\n";
+ 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};
}
- print OUT "};\n";
- printf OUT "const uint8_t pp_directives_len[%d] = {\n", scalar(@pptok);
- foreach $d (@pptok) {
- printf OUT " %d,\n", defined($d) ? length($d)+1 : 0;
+ @hashinfo = gen_perfect_hash(\%tasmtokens);
+ if (!@hashinfo) {
+ die "$0: no hash found\n";
}
- print OUT "};\n";
- print OUT "enum preproc_token pp_token_hash(const char *token)\n";
- print OUT "{\n";
+ # Paranoia...
+ verify_hash_table(\%tasmtokens, \@hashinfo);
- # 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 "\n#define UNUSED_HASH_ENTRY (65535/3)\n";
+ ($n, $sv, $g) = @hashinfo;
+ die if ($n & ($n-1));
+ $n <<= 1;
- 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 "\n\n/* TASM compatibility preprocessor token hash */\n";
- print OUT " static const int16_t hash2[$n] = {\n";
+ print OUT "enum preproc_token pp_tasm_token_hash(const char *token)\n";
+ print OUT "{\n";
+ print OUT " static const int16_t hashdata[$n] = {\n";
for ($i = 0; $i < $n; $i++) {
- my $h = ${$g}[$i*2+1];
- print OUT " ", defined($h) ? $h : 'UNUSED_HASH_ENTRY', ",\n";
+ my $h = ${$g}[$i];
+ print OUT " ", defined($h) ? $h : 'INVALID_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
@@ -248,15 +308,17 @@ if ($what eq 'c') {
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";
+ printf OUT " k1 = ((uint32_t)crc & 0x%x) + 0;\n", $n-2;
+ printf OUT " k2 = ((uint32_t)(crc >> 32) & 0x%x) + 1;\n", $n-2;
print OUT "\n";
- printf OUT " ix = hash1[k1 & 0x%x] + hash2[k2 & 0x%x];\n", $n-1, $n-1;
+ printf OUT " ix = hashdata[k1] + hashdata[k2];\n", $n-1, $n-1;
+ # Comparing to pptok here is correct, because this hash produces
+ # an enum preproc_token value directly.
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], token))\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";
@@ -269,9 +331,8 @@ if ($what eq 'c') {
if ($what eq 'ph') {
print OUT "# Automatically generated from $in by $0\n";
print OUT "# Do not edit\n";
- print OUT "\n";
- print OUT "%pptok_hash = (\n";
+ print OUT "\n\%pptok_hash = (\n";
$n = 0;
foreach $tok (@pptok) {
if (defined($tok)) {
@@ -280,5 +341,12 @@ if ($what eq 'ph') {
$n++;
}
print OUT ");\n";
- print OUT "1;\n";
+
+ print OUT "\n\@pptok_list = (\n";
+ foreach $tok (@pptok) {
+ print OUT " ", (defined($tok) ? "'\%$tok'" : 'undef'), ",\n";
+ }
+ print OUT ");\n";
+
+ print OUT "\n1;\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 a03e6aba..aeb73ff9 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -75,16 +75,32 @@
#include "tokens.h"
#include "tables.h"
#include "listing.h"
+#include "dbginfo.h"
/*
* Preprocessor execution options that can be controlled by %pragma or
* 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_MMACROS = 1, /* Collect mmacro information */
+ PDBG_SMACROS = 2, /* Collect smacro information */
+ PDBG_LIST_SMACROS = 4, /* Smacros to list file (list option 's') */
+ PDBG_INCLUDE = 8 /* Collect %include information */
+} ppdbg;
+
+/*
+ * Preprocessor options configured on the command line
+ */
+static enum preproc_opt ppopt;
typedef struct SMacro SMacro;
typedef struct MMacro MMacro;
@@ -99,7 +115,7 @@ typedef struct Cond Cond;
* This is the internal form which we break input lines up into.
* Typically stored in linked lists.
*
- * Note that `type' serves a double meaning: TOK_SMAC_START_PARAMS is
+ * Note that `type' serves a double meaning: TOKEN_SMAC_START_PARAMS is
* not necessarily used as-is, but is also used to encode the number
* and expansion type of substituted parameter. So in the definition
*
@@ -109,52 +125,27 @@ typedef struct Cond Cond;
* tok_smac_param(0) but the one representing `y' will be
* tok_smac_param(1); see the accessor functions below.
*
- * TOK_INTERNAL_STRING is a string which has been unquoted, but should
+ * TOKEN_INTERNAL_STR is a string which has been unquoted, but should
* be treated as if it was a quoted string. The code is free to change
- * one into the other at will. TOK_NAKED_STRING is a text token which
+ * one into the other at will. TOKEN_NAKED_STR is a text token which
* should be treated as a string, but which MUST NOT be turned into a
- * quoted string. TOK_INTERNAL_STRINGs can contain any character,
- * including NUL, but TOK_NAKED_STRING must be a valid C string.
+ * quoted string. TOKEN_INTERNAL_STRs can contain any character,
+ * including NUL, but TOKEN_NAKED_STR must be a valid C string.
*/
-enum pp_token_type {
- TOK_NONE = 0, TOK_WHITESPACE, TOK_COMMENT,
- TOK_CORRUPT, /* Token text modified in an unsafe manner, now bogus */
- TOK_BLOCK, /* Storage block pointer, not a real token */
- TOK_ID,
- TOK_PREPROC_ID, TOK_MMACRO_PARAM, TOK_LOCAL_SYMBOL,
- TOK_LOCAL_MACRO, TOK_ENVIRON, TOK_STRING,
- TOK_NUMBER, TOK_FLOAT, TOK_OTHER,
- TOK_INTERNAL_STRING, TOK_NAKED_STRING,
- TOK_PREPROC_Q, TOK_PREPROC_SQ, /* %?, %*? */
- TOK_PREPROC_QQ, TOK_PREPROC_SQQ, /* %??, %*?? */
- TOK_PASTE, /* %+ */
- TOK_COND_COMMA, /* %, */
- TOK_INDIRECT, /* %[...] */
- TOK_XDEF_PARAM, /* Used during %xdefine processing */
- TOK_SMAC_START_PARAMS, /* MUST BE LAST IN THE LIST!!! */
- TOK_MAX = INT_MAX /* Keep compiler from reducing the range */
-};
-static inline enum pp_token_type tok_smac_param(int param)
+static inline enum token_type tok_smac_param(int param)
{
- return TOK_SMAC_START_PARAMS + param;
+ return TOKEN_SMAC_START_PARAMS + param;
}
-static int smac_nparam(enum pp_token_type toktype)
+static int smac_nparam(enum token_type toktype)
{
- return toktype - TOK_SMAC_START_PARAMS;
+ return toktype - TOKEN_SMAC_START_PARAMS;
}
-static bool is_smac_param(enum pp_token_type toktype)
+static bool is_smac_param(enum token_type toktype)
{
- return toktype >= TOK_SMAC_START_PARAMS;
+ return toktype >= TOKEN_SMAC_START_PARAMS;
}
-#define PP_CONCAT_MASK(x) (1U << (x))
-
-struct tokseq_match {
- int mask_head;
- int mask_tail;
-};
-
/*
* This is tuned so struct Token should be 64 bytes on 64-bit
* systems and 32 bytes on 32-bit systems. It enables them
@@ -166,17 +157,17 @@ struct tokseq_match {
* if the length is passed through an interface with type "int",
* and is absurdly large anyway.
*
- * For the text mode, in pointer mode the pointer is stored at the end
- * of the union and the pad field is cleared. This allows short tokens
- * to be unconditionally tested for by only looking at the first text
- * bytes and not examining the type or len fields.
+ * Earlier versions of the source code incorrectly stated that
+ * examining the text string alone can be unconditionally valid. This
+ * is incorrect, as some token types strip parts of the string,
+ * e.g. indirect tokens.
*/
-#define INLINE_TEXT (7*sizeof(char *)-sizeof(enum pp_token_type)-sizeof(unsigned int)-1)
+#define INLINE_TEXT (7*sizeof(char *)-sizeof(enum token_type)-sizeof(unsigned int)-1)
#define MAX_TEXT (INT_MAX-2)
struct Token {
Token *next;
- enum pp_token_type type;
+ enum token_type type;
unsigned int len;
union {
char a[INLINE_TEXT+1];
@@ -297,6 +288,10 @@ struct MMacro {
int *paramlen;
uint64_t unique;
uint64_t condcnt; /* number of if blocks... */
+ struct { /* Debug information */
+ struct debug_macro_def *def; /* Definition */
+ struct debug_macro_inv *inv; /* Current invocation (if any) */
+ } dbg;
};
@@ -574,22 +569,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;
@@ -658,9 +637,9 @@ static Token *make_tok_num(Token *next, int64_t val);
static Token *make_tok_qstr(Token *next, const char *str);
static Token *make_tok_qstr_len(Token *next, const char *str, size_t len);
static Token *make_tok_char(Token *next, char op);
-static Token *new_Token(Token * next, enum pp_token_type type,
+static Token *new_Token(Token * next, enum token_type type,
const char *text, size_t txtlen);
-static Token *new_Token_free(Token * next, enum pp_token_type type,
+static Token *new_Token_free(Token * next, enum token_type type,
char *text, size_t txtlen);
static Token *dup_Token(Token *next, const Token *src);
static Token *new_White(Token *next);
@@ -669,18 +648,29 @@ static Token *steal_Token(Token *dst, Token *src);
static const struct use_package *
get_use_pkg(Token *t, const char *dname, const char **name);
static void mark_smac_params(Token *tline, const SMacro *tmpl,
- enum pp_token_type type);
+ enum token_type type);
+
+/* Safe extraction of token type */
+static inline enum token_type tok_type(const Token *x)
+{
+ return x ? x->type : TOKEN_EOS;
+}
/* Safe test for token type, false on x == NULL */
-static inline bool tok_type(const Token *x, enum pp_token_type t)
+static inline bool tok_is(const Token *x, enum token_type t)
+{
+ return tok_type(x) == t;
+}
+/* True if token is any other kind other that "c", but not NULL */
+static inline bool tok_isnt(const Token *x, enum token_type t)
{
- return x && x->type == t;
+ return x && x->type != t;
}
/* Whitespace token? */
static inline bool tok_white(const Token *x)
{
- return tok_type(x, TOK_WHITESPACE);
+ return tok_is(x, TOKEN_WHITESPACE);
}
/* Skip past any whitespace */
@@ -702,49 +692,40 @@ static Token *zap_white(Token *x)
}
/*
- * Single special character tests. The use of & rather than && is intentional; it
- * tells the compiler that it is safe to access text.a[1] unconditionally; hopefully
- * a smart compiler should turn it into a 16-bit memory reference.
+ * Unquote a token if it is a string, and set its type to
+ * TOKEN_INTERNAL_STR.
*/
-static inline bool tok_is(const Token *x, char c)
-{
- return x && ((x->text.a[0] == c) & !x->text.a[1]);
-}
-
-/* True if any other kind of token that "c", but not NULL */
-static inline bool tok_isnt(const Token *x, char c)
-{
- return x && !((x->text.a[0] == c) & !x->text.a[1]);
-}
/*
- * Unquote a token if it is a string, and set its type to
- * TOK_INTERNAL_STRING.
+ * Common version for any kind of quoted string; see asm/quote.c for
+ * information about the arguments.
*/
-static const char *unquote_token(Token *t)
+static const char *unquote_token_anystr(Token *t, uint32_t badctl, char qstart)
{
- if (t->type != TOK_STRING)
+ size_t nlen, olen;
+ char *p;
+
+ if (t->type != TOKEN_STR)
return tok_text(t);
- t->type = TOK_INTERNAL_STRING;
+ olen = t->len;
+ p = (olen > INLINE_TEXT) ? t->text.p.ptr : t->text.a;
+ t->len = nlen = nasm_unquote_anystr(p, NULL, badctl, qstart);
+ t->type = TOKEN_INTERNAL_STR;
- if (t->len > INLINE_TEXT) {
- char *p = t->text.p.ptr;
+ if (olen <= INLINE_TEXT || nlen > INLINE_TEXT)
+ return p;
- t->len = nasm_unquote(p, NULL);
+ nasm_zero(t->text.a);
+ memcpy(t->text.a, p, nlen);
+ nasm_free(p);
+ return t->text.a;
+}
- if (t->len <= INLINE_TEXT) {
- nasm_zero(t->text.a);
- memcpy(t->text.a, p, t->len);
- nasm_free(p);
- return t->text.a;
- } else {
- return p;
- }
- } else {
- t->len = nasm_unquote(t->text.a, NULL);
- return t->text.a;
- }
+/* Unquote any string, can produce any arbitrary binary output */
+static const char *unquote_token(Token *t)
+{
+ return unquote_token_anystr(t, 0, STR_NASM);
}
/*
@@ -753,39 +734,18 @@ static const char *unquote_token(Token *t)
*/
static const char *unquote_token_cstr(Token *t)
{
- if (t->type != TOK_STRING)
- return tok_text(t);
-
- t->type = TOK_INTERNAL_STRING;
-
- if (t->len > INLINE_TEXT) {
- char *p = t->text.p.ptr;
-
- t->len = nasm_unquote_cstr(p, NULL);
-
- if (t->len <= INLINE_TEXT) {
- nasm_zero(t->text.a);
- memcpy(t->text.a, p, t->len);
- nasm_free(p);
- return t->text.a;
- } else {
- return p;
- }
- } else {
- t->len = nasm_unquote_cstr(t->text.a, NULL);
- return t->text.a;
- }
+ return unquote_token_anystr(t, BADCTL, STR_NASM);
}
/*
- * Convert a TOK_INTERNAL_STRING token to a quoted
- * TOK_STRING tokens.
+ * Convert a TOKEN_INTERNAL_STR token to a quoted
+ * TOKEN_STR tokens.
*/
static Token *quote_any_token(Token *t);
static inline unused_func
Token *quote_token(Token *t)
{
- if (likely(!tok_is(t, TOK_INTERNAL_STRING)))
+ if (likely(!tok_is(t, TOKEN_INTERNAL_STR)))
return t;
return quote_any_token(t);
@@ -793,7 +753,7 @@ Token *quote_token(Token *t)
/*
* Convert *any* kind of token to a quoted
- * TOK_STRING token.
+ * TOKEN_STR token.
*/
static Token *quote_any_token(Token *t)
{
@@ -801,7 +761,7 @@ static Token *quote_any_token(Token *t)
char *p;
p = nasm_quote(tok_text(t), &len);
- t->type = TOK_STRING;
+ t->type = TOKEN_STR;
return set_text_free(t, p, len);
}
@@ -837,18 +797,18 @@ static const char *pp_getenv(const Token *t, bool warn)
return NULL;
switch (t->type) {
- case TOK_ENVIRON:
+ case TOKEN_ENVIRON:
txt += 2; /* Skip leading %! */
is_string = nasm_isquote(*txt);
break;
- case TOK_STRING:
+ case TOKEN_STR:
is_string = true;
break;
- case TOK_INTERNAL_STRING:
- case TOK_NAKED_STRING:
- case TOK_ID:
+ case TOKEN_INTERNAL_STR:
+ case TOKEN_NAKED_STR:
+ case TOKEN_ID:
is_string = false;
break;
@@ -885,76 +845,6 @@ static const char *pp_getenv(const Token *t, bool warn)
}
/*
- * 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 inline char *prepreproc(char *line)
-{
- if (unlikely(tasm_compatible_mode))
- return check_tasm_directive(line);
- else
- return line;
-}
-
-/*
* Free a linked list of tokens.
*/
static void free_tlist(Token * list)
@@ -1399,7 +1289,7 @@ static char *read_line(void)
*/
static Token *tokenize(const char *line)
{
- enum pp_token_type type;
+ enum token_type type;
Token *list = NULL;
Token *t, **tail = &list;
@@ -1475,7 +1365,7 @@ static Token *tokenize(const char *line)
if (*p)
p++;
else
- nasm_nonfatalf(ERR_PASS1, "unterminated %%! string");
+ nasm_nonfatal("unterminated %%! string");
} else {
/* %! without anything else... */
}
@@ -1500,107 +1390,108 @@ static Token *tokenize(const char *line)
/* Classify here, to handle %{...} correctly */
if (toklen < 2) {
- type = TOK_OTHER; /* % operator */
+ type = '%'; /* % operator */
} else {
char c0 = line[1];
switch (c0) {
case '+':
- type = (toklen == 2) ? TOK_PASTE : TOK_MMACRO_PARAM;
+ type = (toklen == 2) ? TOKEN_PASTE : TOKEN_MMACRO_PARAM;
break;
case '-':
- type = TOK_MMACRO_PARAM;
+ type = TOKEN_MMACRO_PARAM;
break;
case '?':
if (toklen == 2)
- type = TOK_PREPROC_Q;
+ type = TOKEN_PREPROC_Q;
else if (toklen == 3 && line[2] == '?')
- type = TOK_PREPROC_QQ;
+ type = TOKEN_PREPROC_QQ;
else
- type = TOK_PREPROC_ID;
+ type = TOKEN_PREPROC_ID;
break;
case '*':
- type = TOK_OTHER;
+ type = TOKEN_OTHER;
if (line[2] == '?') {
if (toklen == 3)
- type = TOK_PREPROC_SQ;
+ type = TOKEN_PREPROC_SQ;
else if (toklen == 4 && line[3] == '?')
- type = TOK_PREPROC_SQQ;
+ type = TOKEN_PREPROC_SQQ;
}
break;
case '!':
- type = (toklen == 2) ? TOK_OTHER : TOK_ENVIRON;
+ type = (toklen == 2) ? TOKEN_OTHER : TOKEN_ENVIRON;
break;
case '%':
- type = (toklen == 2) ? TOK_OTHER : TOK_LOCAL_SYMBOL;
+ type = (toklen == 2) ? TOKEN_SMOD : TOKEN_LOCAL_SYMBOL;
break;
case '$':
- type = (toklen == 2) ? TOK_OTHER : TOK_LOCAL_MACRO;
+ type = (toklen == 2) ? TOKEN_OTHER : TOKEN_LOCAL_MACRO;
break;
case '[':
line += 2; /* Skip %[ */
firstchar = *line; /* Don't clobber */
toklen -= 2;
- type = TOK_INDIRECT;
+ type = TOKEN_INDIRECT;
break;
case ',':
- type = (toklen == 2) ? TOK_COND_COMMA : TOK_PREPROC_ID;
+ type = (toklen == 2) ? TOKEN_COND_COMMA : TOKEN_PREPROC_ID;
break;
case '\'':
case '\"':
case '`':
/* %{'string'} */
- type = TOK_PREPROC_ID;
+ type = TOKEN_PREPROC_ID;
break;
case ':':
- type = TOK_MMACRO_PARAM; /* %{:..} */
+ type = TOKEN_MMACRO_PARAM; /* %{:..} */
break;
default:
if (nasm_isdigit(c0))
- type = TOK_MMACRO_PARAM;
+ type = TOKEN_MMACRO_PARAM;
else if (nasm_isidchar(c0) || toklen > 2)
- type = TOK_PREPROC_ID;
+ type = TOKEN_PREPROC_ID;
else
- type = TOK_OTHER;
+ type = TOKEN_OTHER;
break;
}
}
+ } else if (*p == '?' && !nasm_isidchar(p[1])) {
+ /* ? operator */
+ type = TOKEN_QMARK;
} else if (nasm_isidstart(*p) || (*p == '$' && nasm_isidstart(p[1]))) {
/*
- * An identifier. This includes the ? operator, which is
- * treated as a keyword, not as a special character
- * operator
+ * A regular identifier. This includes keywords, which are not
+ * special to the preprocessor.
*/
- type = TOK_ID;
+ type = TOKEN_ID;
while (nasm_isidchar(*++p))
;
} else if (nasm_isquote(*p)) {
/*
* A string token.
*/
- type = TOK_STRING;
+ type = TOKEN_STR;
p = nasm_skip_string(p);
if (*p) {
p++;
} else {
nasm_warn(WARN_OTHER, "unterminated string");
- /* Handling unterminated strings by UNV */
- /* type = -1; */
+ type = TOKEN_ERRSTR;
}
} else if (p[0] == '$' && p[1] == '$') {
- type = TOK_OTHER; /* TOKEN_BASE */
+ type = TOKEN_BASE;
p += 2;
} else if (nasm_isnumstart(*p)) {
bool is_hex = false;
@@ -1642,7 +1533,7 @@ static Token *tokenize(const char *line)
/*
* we need to deal with consequences of the legacy
* parser, like "1.nolist" being two tokens
- * (TOK_NUMBER, TOK_ID) here; at least give it
+ * (TOKEN_NUM, TOKEN_ID) here; at least give it
* a shot for now. In the future, we probably need
* a flex-based scanner with proper pattern matching
* to do it as well as it can be done. Nothing in
@@ -1666,32 +1557,28 @@ static Token *tokenize(const char *line)
p--; /* Point to first character beyond number */
if (p == line+1 && *line == '$') {
- type = TOK_OTHER; /* TOKEN_HERE */
+ type = TOKEN_HERE;
} else {
if (has_e && !is_hex) {
/* 1e13 is floating-point, but 1e13h is not */
is_float = true;
}
- type = is_float ? TOK_FLOAT : TOK_NUMBER;
+ type = is_float ? TOKEN_FLOAT : TOKEN_NUM;
}
} else if (nasm_isspace(*p)) {
- type = TOK_WHITESPACE;
+ firstchar = ' '; /* Always a single space */
+ type = TOKEN_WHITESPACE;
p = nasm_skip_spaces(p);
/*
* Whitespace just before end-of-line is discarded by
* pretending it's a comment; whitespace just before a
* comment gets lumped into the comment.
*/
- if (!*p || *p == ';') {
- type = TOK_COMMENT;
- while (*p)
- p++;
- }
+ if (!*p || *p == ';')
+ type = TOKEN_EOS;
} else if (*p == ';') {
- type = TOK_COMMENT;
- while (*p)
- p++;
+ type = TOKEN_EOS;
} else {
/*
* Anything else is an operator of some kind. We check
@@ -1700,14 +1587,18 @@ static Token *tokenize(const char *line)
* character operators (<<<, >>>, <=>) but anything
* else is a single-character operator.
*/
- type = TOK_OTHER;
+ type = (unsigned char)*p;
switch (*p++) {
case '>':
if (*p == '>') {
p++;
- if (*p == '>')
+ type = TOKEN_SHR;
+ if (*p == '>') {
+ type = TOKEN_SAR;
p++;
+ }
} else if (*p == '=') {
+ type = TOKEN_GE;
p++;
}
break;
@@ -1715,30 +1606,58 @@ static Token *tokenize(const char *line)
case '<':
if (*p == '<') {
p++;
+ type = TOKEN_SHR;
if (*p == '<')
p++;
} else if (*p == '=') {
p++;
- if (*p == '>')
+ type = TOKEN_LE;
+ if (*p == '>') {
p++;
+ type = TOKEN_LEG;
+ }
} else if (*p == '>') {
p++;
+ type = TOKEN_NE;
}
break;
case '!':
- if (*p == '=')
+ if (*p == '=') {
p++;
+ type = TOKEN_NE;
+ }
break;
case '/':
+ if (*p == '/') {
+ p++;
+ type = TOKEN_SDIV;
+ }
+ break;
case '=':
+ if (*p == '=')
+ p++; /* Still TOKEN_EQ == '=' though */
+ break;
case '&':
+ if (*p == '&') {
+ p++;
+ type = TOKEN_DBL_AND;
+ }
+ break;
+
case '|':
+ if (*p == '|') {
+ p++;
+ type = TOKEN_DBL_OR;
+ }
+ break;
+
case '^':
- /* These operators can be doubled but nothing else */
- if (*p == p[-1])
- p++;
+ if (*p == '^') {
+ p++;
+ type = TOKEN_DBL_XOR;
+ }
break;
default:
@@ -1746,16 +1665,15 @@ static Token *tokenize(const char *line)
}
}
- if (type == TOK_WHITESPACE) {
- *tail = t = new_White(NULL);
- tail = &t->next;
- } else if (type != TOK_COMMENT) {
- if (!ep)
- ep = p;
- *tail = t = new_Token(NULL, type, line, ep - line);
- *tok_text_buf(t) = firstchar; /* E.g. %{foo} -> {foo -> %foo */
- tail = &t->next;
- }
+ if (type == TOKEN_EOS)
+ break; /* done with the string... */
+
+ if (!ep)
+ ep = p;
+ *tail = t = new_Token(NULL, type, line, ep - line);
+ *tok_text_buf(t) = firstchar; /* E.g. %{foo} -> {foo -> %foo */
+ tail = &t->next;
+
line = p;
}
return list;
@@ -1789,7 +1707,7 @@ static Token *alloc_Token(void)
* block allocations and is not used for data.
*/
block[0].next = tokenblocks;
- block[0].type = TOK_BLOCK;
+ block[0].type = TOKEN_BLOCK;
tokenblocks = block;
/*
@@ -1816,6 +1734,7 @@ static Token *delete_Token(Token *t)
Token *next = t->next;
nasm_zero(*t);
+ t->type = TOKEN_FREE;
t->next = freeTokens;
freeTokens = t;
@@ -1859,7 +1778,7 @@ static inline void delete_Blocks(void)
* this function creates a new Token and passes a pointer to it
* back to the caller. It sets the type, text, and next pointer elements.
*/
-static Token *new_Token(Token * next, enum pp_token_type type,
+static Token *new_Token(Token * next, enum token_type type,
const char *text, size_t txtlen)
{
Token *t = alloc_Token();
@@ -1867,7 +1786,7 @@ static Token *new_Token(Token * next, enum pp_token_type type,
t->next = next;
t->type = type;
- if (type == TOK_WHITESPACE) {
+ if (type == TOKEN_WHITESPACE) {
t->len = 1;
t->text.a[0] = ' ';
} else {
@@ -1901,7 +1820,7 @@ static Token *new_Token(Token * next, enum pp_token_type type,
* either taken over or freed. This function MUST be called
* with valid txt and txtlen, unlike new_Token().
*/
-static Token *new_Token_free(Token * next, enum pp_token_type type,
+static Token *new_Token_free(Token * next, enum token_type type,
char *text, size_t txtlen)
{
Token *t = alloc_Token();
@@ -1940,7 +1859,7 @@ static Token *new_White(Token *next)
Token *t = alloc_Token();
t->next = next;
- t->type = TOK_WHITESPACE;
+ t->type = TOKEN_WHITESPACE;
t->len = 1;
t->text.a[0] = ' ';
@@ -1980,16 +1899,16 @@ static char *detoken(Token * tlist, bool expand_locals)
list_for_each(t, tlist) {
switch (t->type) {
- case TOK_ENVIRON:
+ case TOKEN_ENVIRON:
{
const char *v = pp_getenv(t, true);
set_text(t, v, tok_strlen(v));
- t->type = TOK_NAKED_STRING;
+ t->type = TOKEN_NAKED_STR;
break;
}
- case TOK_LOCAL_MACRO:
- case TOK_LOCAL_SYMBOL:
+ case TOKEN_LOCAL_MACRO:
+ case TOKEN_LOCAL_SYMBOL:
if (expand_locals) {
const char *q;
char *p;
@@ -1997,12 +1916,12 @@ static char *detoken(Token * tlist, bool expand_locals)
if (ctx) {
p = nasm_asprintf("..@%"PRIu64".%s", ctx->number, q);
set_text_free(t, p, nasm_last_string_len());
- t->type = TOK_ID;
+ t->type = TOKEN_ID;
}
}
break;
- case TOK_INDIRECT:
+ case TOKEN_INDIRECT:
/*
* This won't happen in when emitting to the assembler,
* but can happen when emitting output for some of the
@@ -2033,7 +1952,7 @@ static char *detoken(Token * tlist, bool expand_locals)
list_for_each(t, tlist) {
switch (t->type) {
- case TOK_INDIRECT:
+ case TOKEN_INDIRECT:
*p++ = '%';
*p++ = '[';
p = mempcpy(p, tok_text(t), t->len);
@@ -2077,31 +1996,20 @@ static int ppscan(void *private_data, struct tokenval *tokval)
pps->ntokens = 0;
return tokval->t_type = TOKEN_EOS;
}
- } while (tline->type == TOK_WHITESPACE || tline->type == TOK_COMMENT);
+ } while (tline->type == TOKEN_WHITESPACE);
txt = tok_text(tline);
tokval->t_charptr = (char *)txt; /* Fix this */
- if (txt[0] == '$') {
- if (!txt[1]) {
- return tokval->t_type = TOKEN_HERE;
- } else if (txt[1] == '$' && !txt[2]) {
- return tokval->t_type = TOKEN_BASE;
- } else if (tline->type == TOK_ID) {
- tokval->t_charptr++;
- return tokval->t_type = TOKEN_ID;
- }
- }
-
switch (tline->type) {
default:
- if (tline->len == 1)
- return tokval->t_type = txt[0];
- /* fall through */
- case TOK_ID:
+ return tokval->t_type = tline->type;
+
+ case TOKEN_ID:
+ /* This could be an assembler keyword */
return nasm_token_hash(txt, tokval);
- case TOK_NUMBER:
+ case TOKEN_NUM:
{
bool rn_error;
tokval->t_integer = readnum(txt, &rn_error);
@@ -2111,11 +2019,11 @@ static int ppscan(void *private_data, struct tokenval *tokval)
return tokval->t_type = TOKEN_NUM;
}
- case TOK_FLOAT:
- return tokval->t_type = TOKEN_FLOAT;
-
- case TOK_STRING:
+ case TOKEN_STR:
tokval->t_charptr = (char *)unquote_token(tline);
+ /* fall through */
+ case TOKEN_INTERNAL_STR:
+ case TOKEN_NAKED_STR:
tokval->t_inttwo = tline->len;
return tokval->t_type = TOKEN_STR;
}
@@ -2144,7 +2052,7 @@ static bool pp_get_boolean_option(Token *tline, bool defval)
if (!tline)
return true;
- if (tline->type == TOK_ID) {
+ if (tline->type == TOKEN_ID) {
size_t i;
const char *txt = tok_text(tline);
@@ -2245,10 +2153,11 @@ static Context *get_ctx(const char *name, const char **namep)
* the end of the path.
*
* Note: for INC_PROBE the function returns NULL at all times;
- * instead look for the
+ * instead look for a filename in *slpath.
*/
enum incopen_mode {
INC_NEEDED, /* File must exist */
+ INC_REQUIRED, /* File must exist, but only open once/pass */
INC_OPTIONAL, /* Missing is OK */
INC_PROBE /* Only an existence probe */
};
@@ -2293,41 +2202,88 @@ static FILE *inc_fopen_search(const char *file, char **slpath,
* Open a file, or test for the presence of one (depending on omode),
* considering the include path.
*/
+struct file_hash_entry {
+ const char *path;
+ struct file_hash_entry *full; /* Hash entry for the full path */
+ int64_t include_pass; /* Pass in which last included (for %require) */
+};
+
static FILE *inc_fopen(const char *file,
struct strlist *dhead,
const char **found_path,
enum incopen_mode omode,
enum file_flags fmode)
{
+ struct file_hash_entry **fhep;
+ struct file_hash_entry *fhe = NULL;
struct hash_insert hi;
- void **hp;
- char *path;
+ const char *path = NULL;
FILE *fp = NULL;
-
- hp = hash_find(&FileHash, file, &hi);
- if (hp) {
- path = *hp;
- if (path || omode != INC_NEEDED) {
- strlist_add(dhead, path ? path : file);
+ const int64_t pass = pass_count();
+ bool skip_open = (omode == INC_PROBE);
+
+ fhep = (struct file_hash_entry **)hash_find(&FileHash, file, &hi);
+ if (fhep) {
+ fhe = *fhep;
+ if (fhe) {
+ path = fhe->path;
+ skip_open |= (omode == INC_REQUIRED) &&
+ (fhe->full->include_pass >= pass);
}
} else {
/* Need to do the actual path search */
- fp = inc_fopen_search(file, &path, omode, fmode);
+ char *pptr;
+ fp = inc_fopen_search(file, &pptr, omode, fmode);
+ path = pptr;
/* Positive or negative result */
- hash_add(&hi, nasm_strdup(file), path);
+ if (path) {
+ nasm_new(fhe);
+ fhe->path = path;
+ fhe->full = fhe; /* It is *possible*... */
+ }
+ hash_add(&hi, nasm_strdup(file), fhe);
+
+ /*
+ * Add a hash entry for the canonical path if there isn't one
+ * already. Try to get the unique name from the OS best we can.
+ * Note that ->path and ->full->path can be different, and that
+ * is okay (we don't want to print out a full canonical path
+ * in messages, for example.)
+ */
+ if (path) {
+ char *fullpath = nasm_realpath(path);
+
+ if (!strcmp(file, fullpath)) {
+ nasm_free(fullpath);
+ } else {
+ struct file_hash_entry **fullp, *full;
+ fullp = (struct file_hash_entry **)
+ hash_find(&FileHash, fullpath, &hi);
+
+ if (fullp) {
+ full = *fullp;
+ nasm_free(fullpath);
+ } else {
+ nasm_new(full);
+ full->path = fullpath;
+ full->full = full;
+ hash_add(&hi, path, full);
+ }
+ fhe->full = full;
+ }
+ }
/*
* Add file to dependency path.
*/
- if (path || omode != INC_NEEDED)
- strlist_add(dhead, file);
+ strlist_add(dhead, path ? path : file);
}
if (path && !fp && omode != INC_PROBE)
fp = nasm_open_read(path, fmode);
- if (omode == INC_NEEDED && !fp) {
+ if (omode < INC_OPTIONAL && !fp) {
if (!path)
errno = ENOENT;
@@ -2335,6 +2291,9 @@ static FILE *inc_fopen(const char *file,
file, strerror(errno));
}
+ if (fp)
+ fhe->full->include_pass = pass;
+
if (found_path)
*found_path = path;
@@ -2384,7 +2343,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 {
@@ -2509,7 +2468,7 @@ static enum cond_state if_condition(Token * tline, enum preproc_token ct)
struct ppscan pps;
struct tokenval tokval;
expr *evalresult;
- enum pp_token_type needtype;
+ enum token_type needtype;
const char *dname = pp_directives[ct];
bool casesense = true;
enum preproc_token cond = PP_COND(ct);
@@ -2523,7 +2482,7 @@ static enum cond_state if_condition(Token * tline, enum preproc_token ct)
tline = skip_white(tline);
if (!tline)
break;
- if (tline->type != TOK_ID) {
+ if (tline->type != TOKEN_ID) {
nasm_nonfatal("`%s' expects context identifiers",
dname);
goto fail;
@@ -2545,8 +2504,8 @@ static enum cond_state if_condition(Token * tline, enum preproc_token ct)
j = false; /* have we matched yet? */
while (tline) {
tline = skip_white(tline);
- if (!tline || (tline->type != TOK_ID &&
- tline->type != TOK_LOCAL_MACRO)) {
+ if (!tline || (tline->type != TOKEN_ID &&
+ tline->type != TOKEN_LOCAL_MACRO)) {
nasm_nonfatal("`%s' expects macro identifiers",
dname);
goto fail;
@@ -2564,15 +2523,24 @@ 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? */
while (tline) {
tline = skip_white(tline);
- if (!tline || (tline->type != TOK_ID &&
- tline->type != TOK_STRING &&
- tline->type != TOK_INTERNAL_STRING &&
- tline->type != TOK_ENVIRON)) {
+ if (!tline || (tline->type != TOKEN_ID &&
+ tline->type != TOKEN_STR &&
+ tline->type != TOKEN_INTERNAL_STR &&
+ tline->type != TOKEN_ENVIRON)) {
nasm_nonfatal("`%s' expects environment variable names",
dname);
goto fail;
@@ -2607,11 +2575,11 @@ static enum cond_state if_condition(Token * tline, enum preproc_token ct)
dname);
goto fail;
}
- if (t->type == TOK_WHITESPACE) {
+ if (t->type == TOKEN_WHITESPACE) {
t = t->next;
continue;
}
- if (tt->type == TOK_WHITESPACE) {
+ if (tt->type == TOKEN_WHITESPACE) {
tt = tt->next;
continue;
}
@@ -2644,7 +2612,7 @@ static enum cond_state if_condition(Token * tline, enum preproc_token ct)
tline = skip_white(tline);
tline = expand_id(tline);
- if (!tok_type(tline, TOK_ID)) {
+ if (!tok_is(tline, TOKEN_ID)) {
nasm_nonfatal("`%s' expects a macro name", dname);
goto fail;
}
@@ -2656,7 +2624,7 @@ static enum cond_state if_condition(Token * tline, enum preproc_token ct)
tline = expand_smacro(tline->next);
tline = skip_white(tline);
if (!tline) {
- } else if (!tok_type(tline, TOK_NUMBER)) {
+ } else if (!tok_is(tline, TOKEN_NUM)) {
nasm_nonfatal("`%s' expects a parameter count or nothing",
dname);
} else {
@@ -2667,7 +2635,7 @@ static enum cond_state if_condition(Token * tline, enum preproc_token ct)
tline = tline->next->next;
if (tok_is(tline, '*'))
searching.nparam_max = INT_MAX;
- else if (!tok_type(tline, TOK_NUMBER))
+ else if (!tok_is(tline, TOKEN_NUM))
nasm_nonfatal("`%s' expects a parameter count after `-'",
dname);
else {
@@ -2702,23 +2670,23 @@ static enum cond_state if_condition(Token * tline, enum preproc_token ct)
}
case PP_IFID:
- needtype = TOK_ID;
+ needtype = TOKEN_ID;
goto iftype;
case PP_IFNUM:
- needtype = TOK_NUMBER;
+ needtype = TOKEN_NUM;
goto iftype;
case PP_IFSTR:
- needtype = TOK_STRING;
+ needtype = TOKEN_STR;
goto iftype;
iftype:
t = tline = expand_smacro(tline);
while (tok_white(t) ||
- (needtype == TOK_NUMBER && (tok_is(t, '-') | tok_is(t, '+'))))
+ (needtype == TOKEN_NUM && (tok_is(t, '-') | tok_is(t, '+'))))
t = t->next;
- j = tok_type(t, needtype);
+ j = tok_is(t, needtype);
break;
case PP_IFTOKEN:
@@ -2796,17 +2764,17 @@ smacro_expand_default(const SMacro *s, Token **params, int nparams)
}
/*
- * Emit a macro defintion or undef to the listing file, if
- * desired. This is similar to detoken(), but it handles the reverse
- * expansion list, does not expand %! or local variable tokens, and
- * does some special handling for macro parameters.
+ * Emit a macro defintion or undef to the listing file or debug format
+ * if desired. This is similar to detoken(), but it handles the
+ * reverse expansion list, does not expand %! or local variable
+ * tokens, and does some special handling for macro parameters.
*/
static void
list_smacro_def(enum preproc_token op, const Context *ctx, const SMacro *m)
{
Token *t;
size_t namelen, size;
- char *def, *p;
+ char *def, *p, *end_spec;
char *context_prefix = NULL;
size_t context_len;
@@ -2851,6 +2819,7 @@ list_smacro_def(enum preproc_token op, const Context *ctx, const SMacro *m)
}
*--p = ' ';
+ end_spec = p; /* Truncate here for macro def only */
if (m->nparam) {
int i;
@@ -2883,7 +2852,14 @@ list_smacro_def(enum preproc_token op, const Context *ctx, const SMacro *m)
nasm_free(context_prefix);
}
- nasm_listmsg("%s %s", pp_directives[op], p);
+ if (ppdbg & PDBG_LIST_SMACROS)
+ nasm_listmsg("%s %s", pp_directives[op], p);
+ if (ppdbg & PDBG_SMACROS) {
+ bool define = !(op == PP_UNDEF || op == PP_UNDEFALIAS);
+ if (!define)
+ *end_spec = '\0'; /* Remove the expansion (for list file only) */
+ dfmt->debug_smacros(define, p);
+ }
nasm_free(def);
}
@@ -2940,7 +2916,7 @@ static int parse_smacro_template(Token ***tpp, SMacro *tmpl)
err = done = false;
while (!done) {
- if (!t || !t->type) {
+ if (!t) {
if (name || flags)
nasm_nonfatal("`)' expected to terminate macro template");
else
@@ -2949,56 +2925,46 @@ static int parse_smacro_template(Token ***tpp, SMacro *tmpl)
}
switch (t->type) {
- case TOK_ID:
+ case TOKEN_ID:
if (name)
goto bad;
name = t;
break;
-
- case TOK_OTHER:
- if (t->len != 1)
- goto bad;
- switch (t->text.a[0]) {
- case '=':
- flags |= SPARM_EVAL;
- break;
- case '&':
- flags |= SPARM_STR;
- break;
- case '!':
- flags |= SPARM_NOSTRIP;
- break;
- case '+':
- flags |= SPARM_GREEDY;
- greedy = true;
- break;
- case ',':
- if (greedy)
- nasm_nonfatal("greedy parameter must be last");
- /* fall through */
- case ')':
- if (params) {
- if (name)
- steal_Token(&params[nparam].name, name);
- params[nparam].flags = flags;
- }
- nparam++;
- name = NULL;
- flags = 0;
- done = t->text.a[0] == ')';
- break;
- default:
- goto bad;
+ case '=':
+ flags |= SPARM_EVAL;
+ break;
+ case '&':
+ flags |= SPARM_STR;
+ break;
+ case '!':
+ flags |= SPARM_NOSTRIP;
+ break;
+ case '+':
+ flags |= SPARM_GREEDY;
+ greedy = true;
+ break;
+ case ',':
+ if (greedy)
+ nasm_nonfatal("greedy parameter must be last");
+ /* fall through */
+ case ')':
+ if (params) {
+ if (name)
+ steal_Token(&params[nparam].name, name);
+ params[nparam].flags = flags;
}
+ nparam++;
+ name = NULL;
+ flags = 0;
+ done = true;
break;
-
- case TOK_WHITESPACE:
+ case TOKEN_WHITESPACE:
break;
-
default:
bad:
if (!err) {
- nasm_nonfatal("garbage `%s' in macro parameter list", tok_text(t));
+ nasm_nonfatal("garbage `%s' in macro parameter list",
+ tok_text(t));
err = true;
}
break;
@@ -3009,7 +2975,7 @@ static int parse_smacro_template(Token ***tpp, SMacro *tmpl)
}
finish:
- while (t && t->type == TOK_WHITESPACE) {
+ while (t && t->type == TOKEN_WHITESPACE) {
tn = &t->next;
t = t->next;
}
@@ -3055,7 +3021,7 @@ static SMacro *define_smacro(const char *mname, bool casesense,
goto fail;
}
- if (!defining_alias && !ppopt.noaliases) {
+ if (!defining_alias && !ppconf.noaliases) {
/* It is an alias macro; follow the alias link */
SMacro *s;
@@ -3141,17 +3107,19 @@ static SMacro *define_smacro(const char *mname, bool casesense,
smac->name = nasm_strdup(mname);
smac->casesense = casesense;
- smac->expansion = expansion;
+ smac->expansion = reverse_tokens(expansion);
smac->expand = smacro_expand_default;
if (tmpl) {
smac->nparam = tmpl->nparam;
smac->params = tmpl->params;
smac->alias = tmpl->alias;
smac->greedy = tmpl->greedy;
- if (tmpl->expand)
- smac->expand = tmpl->expand;
+ if (tmpl->expand) {
+ smac->expand = tmpl->expand;
+ smac->expandpvt = tmpl->expandpvt;
+ }
}
- if (list_option('s')) {
+ if (ppdbg & (PDBG_SMACROS|PDBG_LIST_SMACROS)) {
list_smacro_def((smac->alias ? PP_DEFALIAS : PP_DEFINE)
+ !casesense, ctx, smac);
}
@@ -3185,7 +3153,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 {
@@ -3216,7 +3184,7 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
tline = tline->next;
tline = skip_white(tline);
tline = expand_id(tline);
- if (!tok_type(tline, TOK_ID)) {
+ if (!tok_is(tline, TOKEN_ID)) {
nasm_nonfatal("`%s' expects a macro name", directive);
return false;
}
@@ -3232,7 +3200,7 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
tline = expand_smacro(tline->next);
tline = skip_white(tline);
- if (!tok_type(tline, TOK_NUMBER))
+ if (!tok_is(tline, TOKEN_NUM))
nasm_nonfatal("`%s' expects a parameter count", directive);
else
def->nparam_min = def->nparam_max = read_param_count(tok_text(tline));
@@ -3240,7 +3208,7 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
tline = tline->next->next;
if (tok_is(tline, '*')) {
def->nparam_max = INT_MAX;
- } else if (!tok_type(tline, TOK_NUMBER)) {
+ } else if (!tok_is(tline, TOKEN_NUM)) {
nasm_nonfatal("`%s' expects a parameter count after `-'", directive);
} else {
def->nparam_max = read_param_count(tok_text(tline));
@@ -3254,7 +3222,7 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
tline = tline->next;
def->plus = true;
}
- if (tline && tok_type(tline->next, TOK_ID) &&
+ if (tline && tok_is(tline->next, TOKEN_ID) &&
tline->next->len == 7 &&
!nasm_stricmp(tline->next->text.a, ".nolist")) {
tline = tline->next;
@@ -3271,7 +3239,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,
@@ -3323,14 +3291,14 @@ static void do_pragma_preproc(Token *tline)
tline = tline->next;
tline = skip_white(tline);
- if (!tok_type(tline, TOK_ID))
+ if (!tok_is(tline, TOKEN_ID))
return;
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 */
}
@@ -3338,7 +3306,7 @@ static void do_pragma_preproc(Token *tline)
static bool is_macro_id(const Token *t)
{
- return tok_type(t, TOK_ID) || tok_type(t, TOK_LOCAL_MACRO);
+ return tok_is(t, TOKEN_ID) || tok_is(t, TOKEN_LOCAL_MACRO);
}
static const char *get_id(Token **tp, const char *dname)
@@ -3375,7 +3343,7 @@ get_use_pkg(Token *t, const char *dname, const char **name)
if (!t) {
nasm_nonfatal("`%s' expects a package name, got end of line", dname);
return NULL;
- } else if (t->type != TOK_ID && t->type != TOK_STRING) {
+ } else if (t->type != TOKEN_ID && t->type != TOKEN_STR) {
nasm_nonfatal("`%s' expects a package name, got `%s'",
dname, tok_text(t));
return NULL;
@@ -3394,13 +3362,13 @@ get_use_pkg(Token *t, const char *dname, const char **name)
/*
* Mark parameter tokens in an smacro definition. If the type argument
* is 0, create smac param tokens, otherwise use the type specified;
- * normally this is used for TOK_XDEF_PARAM, which is used to protect
+ * normally this is used for TOKEN_XDEF_PARAM, which is used to protect
* parameter tokens during expansion during %xdefine.
*
* tmpl may not be NULL here.
*/
static void mark_smac_params(Token *tline, const SMacro *tmpl,
- enum pp_token_type type)
+ enum token_type type)
{
const struct smac_param *params = tmpl->params;
int nparam = tmpl->nparam;
@@ -3408,7 +3376,7 @@ static void mark_smac_params(Token *tline, const SMacro *tmpl,
int i;
list_for_each(t, tline) {
- if (t->type != TOK_ID && t->type != TOK_XDEF_PARAM)
+ if (t->type != TOKEN_ID && t->type != TOKEN_XDEF_PARAM)
continue;
for (i = 0; i < nparam; i++) {
@@ -3438,6 +3406,138 @@ 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_is(tline, TOKEN_NUM)) {
+ 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_is(tline, TOKEN_NUM)) {
+ 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 == TOKEN_STR) {
+ const char *fname;
+ /*
+ * If this is a quoted string, ignore anything after
+ * it; this allows for compatiblity with gcc's
+ * additional flags options.
+ */
+
+ fname = unquote_token_anystr(tline, BADCTL,
+ dname[0] == '#' ? STR_C : STR_NASM);
+ src_set_fname(fname);
+ } else {
+ char *fname;
+ 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;
+}
+
+/*
+ * Used for the %arg and %local directives
+ */
+static void define_stack_smacro(const char *name, int offset)
+{
+ Token *tt;
+
+ tt = make_tok_char(NULL, ')');
+ tt = make_tok_num(tt, offset);
+ if (!tok_is(tt, '-'))
+ tt = make_tok_char(tt, '+');
+ tt = new_Token(tt, TOKEN_ID, StackPointer, 0);
+ tt = make_tok_char(tt, '(');
+
+ define_smacro(name, true, tt, NULL);
+}
+
+
+/*
+ * This implements the %assign directive: expand an smacro expression,
+ * then evaluate it, and assign the corresponding number to an smacro.
+ */
+static void assign_smacro(const char *mname, bool casesense,
+ Token *tline, const char *dname)
+{
+ struct ppscan pps;
+ expr *evalresult;
+ struct tokenval tokval;
+
+ tline = expand_smacro(tline);
+
+ pps.tptr = tline;
+ pps.ntokens = -1;
+ tokval.t_type = TOKEN_INVALID;
+ evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
+ free_tlist(tline);
+ if (!evalresult)
+ return;
+
+ if (tokval.t_type)
+ nasm_warn(WARN_OTHER, "trailing garbage after expression ignored");
+
+ if (!is_simple(evalresult)) {
+ nasm_nonfatal("non-constant value given to `%s'", dname);
+ } else {
+ tline = make_tok_num(NULL, reloc_value(evalresult));
+
+ /*
+ * We now have a macro name, an implicit parameter count of
+ * zero, and a numeric token to use as an expansion. Create
+ * and store an SMacro.
+ */
+ define_smacro(mname, casesense, tline, NULL);
+ }
+}
+
/**
* find and process preprocessor directive in passed line
* Find out if a line contains a preprocessor directive, and deal
@@ -3455,10 +3555,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;
@@ -3481,91 +3579,63 @@ static int do_directive(Token *tline, Token **output)
*output = NULL; /* No output generated */
origline = tline;
- if (tok_is(tline, '#')) {
- /* cpp-style line directive */
- if (!tok_white(tline->next))
- return NO_DIRECTIVE_FOUND;
- dname = tok_text(tline);
- goto pp_line;
- }
+ /* 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 TOKEN_PREPROC_ID:
+ dname = tok_text(tline);
+ /*
+ * For it to be a directive, the second character has to be an
+ * ASCII letter; this is a very quick and dirty test for that;
+ * all other cases will get rejected by the token hash.
+ */
+ if ((uint8_t)(dname[1] - 'A') > (uint8_t)('z' - 'A'))
+ 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 TOKEN_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) {
- 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;
+ 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) {
- if (dname[0] == '#') {
- /* cpp version: treat double quotes like NASM backquotes */
- char *txt = tok_text_buf(tline);
- if (txt[0] == '"') {
- txt[0] = '`';
- txt[tline->len - 1] = '`';
- }
- }
- src_set_fname(unquote_token(tline));
- /*
- * Anything after the string is ignored by design (for cpp
- * compatibility and future extensions.)
- */
- } 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--;
}
/*
@@ -3634,7 +3704,7 @@ static int do_directive(Token *tline, Token **output)
tline = tline->next;
t->next = NULL;
tline = zap_white(expand_smacro(tline));
- if (tok_type(tline, TOK_ID)) {
+ if (tok_is(tline, TOKEN_ID)) {
if (!nasm_stricmp(tok_text(tline), "preproc")) {
/* Preprocessor pragma */
do_pragma_preproc(tline);
@@ -3649,7 +3719,7 @@ static int do_directive(Token *tline, Token **output)
/* Prepend "[pragma " */
t = new_White(tline);
- t = new_Token(t, TOK_ID, "pragma", 6);
+ t = new_Token(t, TOKEN_ID, "pragma", 6);
t = make_tok_char(t, '[');
tline = t;
*output = tline;
@@ -3666,7 +3736,7 @@ static int do_directive(Token *tline, Token **output)
* %stacksize large.
*/
tline = skip_white(tline->next);
- if (!tline || tline->type != TOK_ID) {
+ if (!tline || tline->type != TOKEN_ID) {
nasm_nonfatal("`%s' missing size parameter", dname);
break;
}
@@ -3716,12 +3786,11 @@ static int do_directive(Token *tline, Token **output)
offset = ArgOffset;
do {
const char *arg;
- char directive[256];
int size = StackSize;
/* Find the argument name */
tline = skip_white(tline->next);
- if (!tline || tline->type != TOK_ID) {
+ if (!tline || tline->type != TOKEN_ID) {
nasm_nonfatal("`%s' missing argument parameter", dname);
goto done;
}
@@ -3734,7 +3803,7 @@ static int do_directive(Token *tline, Token **output)
goto done;
}
tline = tline->next;
- if (!tok_type(tline, TOK_ID)) {
+ if (!tok_is(tline, TOKEN_ID)) {
nasm_nonfatal("`%s' missing size type parameter", dname);
goto done;
}
@@ -3754,9 +3823,7 @@ static int do_directive(Token *tline, Token **output)
size = ALIGN(size, StackSize);
/* Now define the macro for the argument */
- snprintf(directive, sizeof(directive), "%%define %s (%s+%d)",
- arg, StackPointer, offset);
- do_directive(tokenize(directive), output);
+ define_stack_smacro(arg, offset);
offset += size;
/* Move to the next argument in the list */
@@ -3766,6 +3833,9 @@ static int do_directive(Token *tline, Token **output)
break;
case PP_LOCAL:
+ {
+ int total_size = 0;
+
/* TASM like LOCAL directive to define local variables for a
* function, in the following form:
*
@@ -3778,12 +3848,11 @@ static int do_directive(Token *tline, Token **output)
offset = LocalOffset;
do {
const char *local;
- char directive[256];
int size = StackSize;
/* Find the argument name */
tline = skip_white(tline->next);
- if (!tline || tline->type != TOK_ID) {
+ if (!tline || tline->type != TOKEN_ID) {
nasm_nonfatal("`%s' missing argument parameter", dname);
goto done;
}
@@ -3796,7 +3865,7 @@ static int do_directive(Token *tline, Token **output)
goto done;
}
tline = tline->next;
- if (!tok_type(tline, TOK_ID)) {
+ if (!tok_is(tline, TOKEN_ID)) {
nasm_nonfatal("`%s' missing size type parameter", dname);
goto done;
}
@@ -3818,21 +3887,24 @@ static int do_directive(Token *tline, Token **output)
offset += size; /* Negative offset, increment before */
/* Now define the macro for the argument */
- snprintf(directive, sizeof(directive), "%%define %s (%s-%d)",
- local, StackPointer, offset);
- do_directive(tokenize(directive), output);
+ define_stack_smacro(local, -offset);
- /* Now define the assign to setup the enter_c macro correctly */
- snprintf(directive, sizeof(directive),
- "%%assign %%$localsize %%$localsize+%d", size);
- do_directive(tokenize(directive), output);
+ /* How is this different from offset? */
+ total_size += size;
/* Move to the next argument in the list */
tline = skip_white(tline->next);
} while (tok_is(tline, ','));
+
+ /* Now define the assign to setup the enter_c macro correctly */
+ tt = make_tok_num(NULL, total_size);
+ tt = make_tok_char(tt, '+');
+ tt = new_Token(tt, TOKEN_LOCAL_MACRO, "%$localsize", 11);
+ assign_smacro("%$localsize", true, tt, dname);
+
LocalOffset = offset;
break;
-
+ }
case PP_CLEAR:
{
bool context = false;
@@ -3843,7 +3915,7 @@ static int do_directive(Token *tline, Token **output)
/* Emulate legacy behavior */
do_clear(CLEAR_DEFINE|CLEAR_MMACRO, false);
} else {
- while ((t = skip_white(t)) && t->type == TOK_ID) {
+ while ((t = skip_white(t)) && t->type == TOKEN_ID) {
const char *txt = tok_text(t);
if (!nasm_stricmp(txt, "all")) {
do_clear(CLEAR_ALL, context);
@@ -3888,8 +3960,8 @@ static int do_directive(Token *tline, Token **output)
case PP_DEPEND:
t = tline->next = expand_smacro(tline->next);
t = skip_white(t);
- if (!t || (t->type != TOK_STRING &&
- t->type != TOK_INTERNAL_STRING)) {
+ if (!t || (t->type != TOKEN_STR &&
+ t->type != TOKEN_INTERNAL_STR)) {
nasm_nonfatal("`%s' expects a file name", dname);
goto done;
}
@@ -3900,11 +3972,12 @@ static int do_directive(Token *tline, Token **output)
goto done;
case PP_INCLUDE:
+ case PP_REQUIRE:
t = tline->next = expand_smacro(tline->next);
t = skip_white(t);
- if (!t || (t->type != TOK_STRING &&
- t->type != TOK_INTERNAL_STRING)) {
+ if (!t || (t->type != TOKEN_STR &&
+ t->type != TOKEN_INTERNAL_STR)) {
nasm_nonfatal("`%s' expects a file name", dname);
goto done;
}
@@ -3915,20 +3988,27 @@ static int do_directive(Token *tline, Token **output)
inc->next = istk;
found_path = NULL;
inc->fp = inc_fopen(p, deplist, &found_path,
- (pp_mode == PP_DEPS)
- ? INC_OPTIONAL : INC_NEEDED, NF_TEXT);
+ (pp_mode == PP_DEPS) ? INC_OPTIONAL :
+ (op == PP_REQUIRE) ? INC_REQUIRED :
+ INC_NEEDED, NF_TEXT);
if (!inc->fp) {
- /* -MG given but file not found */
+ /* -MG given but file not found, or repeated %require */
nasm_free(inc);
} else {
- 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);
+ inc->nolist = istk->nolist;
+ inc->noline = istk->noline;
+ inc->where = istk->where;
+ inc->lineinc = 0;
istk = inc;
- lfmt->uplevel(LIST_INCLUDE, 0);
+ if (!istk->noline) {
+ src_set(0, found_path ? found_path : p);
+ istk->where = src_where();
+ istk->lineinc = 1;
+ if (ppdbg & PDBG_INCLUDE)
+ dfmt->debug_include(true, istk->next->where, istk->where);
+ }
+ if (!istk->nolist)
+ lfmt->uplevel(LIST_INCLUDE, 0);
}
break;
@@ -3952,12 +4032,15 @@ static int do_directive(Token *tline, Token **output)
stdmacpos = pkg->macros;
nasm_new(inc);
inc->next = istk;
- inc->nolist = istk->nolist + !list_option('b');
- inc->noline = istk->noline;
+ if (!list_option('b')) {
+ inc->nolist++;
+ inc->noline++;
+ }
+ istk = inc;
+ if (!istk->nolist)
+ lfmt->uplevel(LIST_INCLUDE, 0);
if (!inc->noline)
src_set(0, NULL);
- istk = inc;
- lfmt->uplevel(LIST_INCLUDE, 0);
}
break;
}
@@ -3968,7 +4051,7 @@ static int do_directive(Token *tline, Token **output)
tline = skip_white(tline);
tline = expand_id(tline);
if (tline) {
- if (!tok_type(tline, TOK_ID)) {
+ if (!tok_is(tline, TOKEN_ID)) {
nasm_nonfatal("`%s' expects a context identifier", dname);
goto done;
}
@@ -4028,7 +4111,7 @@ issue_error:
tline = skip_white(tline);
t = tline ? tline->next : NULL;
t = skip_white(t);
- if (tok_type(tline, TOK_STRING) && !t) {
+ if (tok_is(tline, TOKEN_STR) && !t) {
/* The line contains only a quoted string */
p = unquote_token(tline); /* Ignore NUL character truncation */
nasm_error(severity, "%s", p);
@@ -4288,7 +4371,7 @@ issue_error:
nolist = 0;
tline = skip_white(tline->next);
- if (tok_type(tline, TOK_ID) && tline->len == 7 &&
+ if (tok_is(tline, TOKEN_ID) && tline->len == 7 &&
!nasm_memicmp(tline->text.a, ".nolist", 7)) {
if (!list_option('f'))
nolist |= NL_LIST; /* ... but update line numbers */
@@ -4430,11 +4513,10 @@ issue_error:
if (op == PP_XDEFINE) {
/* Protect macro parameter tokens */
if (nparam)
- mark_smac_params(tline, &tmpl, TOK_XDEF_PARAM);
+ mark_smac_params(tline, &tmpl, TOKEN_XDEF_PARAM);
tline = expand_smacro(tline);
}
- /* NB: Does this still make sense? */
- macro_start = reverse_tokens(tline);
+ macro_start = tline;
}
/*
@@ -4490,7 +4572,7 @@ issue_error:
t = skip_white(tline);
/* t should now point to the string */
- if (!tok_type(t, TOK_STRING)) {
+ if (!tok_is(t, TOKEN_STR)) {
nasm_nonfatal("`%s' requires string as second parameter", dname);
free_tlist(tline);
goto done;
@@ -4501,7 +4583,7 @@ issue_error:
* are stored with the token stream reversed, so we have to
* reverse the output of tokenize().
*/
- macro_start = reverse_tokens(tokenize(unquote_token_cstr(t)));
+ macro_start = tokenize(unquote_token_cstr(t));
/*
* We now have a macro name, an implicit parameter count of
@@ -4524,8 +4606,8 @@ issue_error:
last->next = NULL;
t = skip_white(tline);
- if (!t || (t->type != TOK_STRING &&
- t->type != TOK_INTERNAL_STRING)) {
+ if (!t || (t->type != TOKEN_STR &&
+ t->type != TOKEN_INTERNAL_STR)) {
nasm_nonfatal("`%s' expects a file name", dname);
free_tlist(tline);
goto done;
@@ -4560,7 +4642,7 @@ issue_error:
t = skip_white(tline);
/* t should now point to the string */
- if (!tok_type(t, TOK_STRING)) {
+ if (!tok_is(t, TOKEN_STR)) {
nasm_nonfatal("`%s' requires string as second parameter", dname);
free_tlist(tline);
free_tlist(origline);
@@ -4591,13 +4673,13 @@ issue_error:
len = 0;
list_for_each(t, tline) {
switch (t->type) {
- case TOK_WHITESPACE:
+ case TOKEN_WHITESPACE:
break;
- case TOK_STRING:
+ case TOKEN_STR:
unquote_token(t);
len += t->len;
break;
- case TOK_OTHER:
+ case TOKEN_OTHER:
if (tok_is(t, ',')) /* permit comma separators */
break;
/* else fall through */
@@ -4611,7 +4693,7 @@ issue_error:
q = qbuf = nasm_malloc(len+1);
list_for_each(t, tline) {
- if (t->type == TOK_INTERNAL_STRING)
+ if (t->type == TOKEN_INTERNAL_STR)
q = mempcpy(q, tok_text(t), t->len);
}
*q = '\0';
@@ -4646,7 +4728,7 @@ issue_error:
t = skip_white(t);
/* t should now point to the string */
- if (!tok_type(t, TOK_STRING)) {
+ if (!tok_is(t, TOKEN_STR)) {
nasm_nonfatal("`%s' requires string as second parameter", dname);
free_tlist(tline);
goto done;
@@ -4715,40 +4797,15 @@ issue_error:
goto done;
last = tline;
- tline = expand_smacro(tline->next);
+ tline = tline->next;
last->next = NULL;
-
- pps.tptr = tline;
- pps.ntokens = -1;
- tokval.t_type = TOKEN_INVALID;
- evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
- free_tlist(tline);
- if (!evalresult)
- goto done;
-
- if (tokval.t_type)
- nasm_warn(WARN_OTHER, "trailing garbage after expression ignored");
-
- if (!is_simple(evalresult)) {
- nasm_nonfatal("non-constant value given to `%s'", dname);
- free_tlist(origline);
- return DIRECTIVE_FOUND;
- }
-
- macro_start = make_tok_num(NULL, reloc_value(evalresult));
-
- /*
- * We now have a macro name, an implicit parameter count of
- * zero, and a numeric token to use as an expansion. Create
- * and store an SMacro.
- */
- define_smacro(mname, casesense, macro_start, NULL);
- break;
+ assign_smacro(mname, casesense, tline, dname);
+ goto done;
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:
@@ -4779,7 +4836,7 @@ static int find_cc(Token * t)
return -1; /* Probably a %+ without a space */
t = skip_white(t);
- if (!tok_type(t, TOK_ID))
+ if (!tok_is(t, TOKEN_ID))
return -1;
tt = t->next;
tt = skip_white(tt);
@@ -4790,9 +4847,57 @@ static int find_cc(Token * t)
ARRAY_SIZE(conditions));
}
-static inline bool pp_concat_match(const Token *t, unsigned int mask)
+enum concat_flags {
+ CONCAT_ID = 0x01,
+ CONCAT_LOCAL_MACRO = 0x02,
+ CONCAT_ENVIRON = 0x04,
+ CONCAT_PREPROC_ID = 0x08,
+ CONCAT_NUM = 0x10,
+ CONCAT_FLOAT = 0x20,
+ CONCAT_OP = 0x40 /* Operators */
+};
+
+struct concat_mask {
+ enum concat_flags mask_head;
+ enum concat_flags mask_tail;
+};
+
+
+static inline bool pp_concat_match(const Token *t, enum concat_flags mask)
{
- return t && (PP_CONCAT_MASK(t->type) & mask);
+ enum concat_flags ctype = 0;
+
+ if (!t)
+ return false;
+
+ switch (t->type) {
+ case TOKEN_ID:
+ ctype = CONCAT_ID; /* Ought this include $ and $$? */
+ break;
+ case TOKEN_LOCAL_MACRO:
+ ctype = CONCAT_LOCAL_MACRO;
+ break;
+ case TOKEN_ENVIRON:
+ ctype = CONCAT_ENVIRON;
+ break;
+ case TOKEN_PREPROC_ID:
+ ctype = CONCAT_PREPROC_ID;
+ break;
+ case TOKEN_NUM:
+ case TOKEN_FLOAT:
+ ctype = CONCAT_NUM;
+ break;
+ case TOKEN_OTHER:
+ ctype = CONCAT_OP; /* For historical reasons */
+ break;
+ default:
+ if (t->type > TOKEN_WHITESPACE && t->type < TOKEN_MAX_OPERATOR)
+ ctype = CONCAT_OP;
+ else
+ ctype = 0;
+ }
+
+ return !!(ctype & mask);
}
/*
@@ -4802,7 +4907,7 @@ static inline bool pp_concat_match(const Token *t, unsigned int mask)
* The @m array can contain a series of token types which are
* executed as separate passes.
*/
-static bool paste_tokens(Token **head, const struct tokseq_match *m,
+static bool paste_tokens(Token **head, const struct concat_mask *m,
size_t mnum, bool handle_explicit)
{
Token *tok, *t, *next, **prev_next, **prev_nonspace, **nextp;
@@ -4825,19 +4930,19 @@ static bool paste_tokens(Token **head, const struct tokseq_match *m,
tok = *head;
prev_next = prev_nonspace = head;
- if (tok_white(tok) || tok_type(tok, TOK_PASTE))
+ if (tok_white(tok) || tok_is(tok, TOKEN_PASTE))
prev_nonspace = NULL;
while (tok && (next = tok->next)) {
bool did_paste = false;
switch (tok->type) {
- case TOK_WHITESPACE:
+ case TOKEN_WHITESPACE:
/* Zap redundant whitespaces */
tok->next = next = zap_white(next);
break;
- case TOK_PASTE:
+ case TOKEN_PASTE:
/* Explicit pasting */
if (!handle_explicit)
break;
@@ -4862,8 +4967,8 @@ static bool paste_tokens(Token **head, const struct tokseq_match *m,
* just drop whem in that case.
*/
while ((next = *nextp)) {
- if (next->type == TOK_PASTE || next->type == TOK_WHITESPACE)
- *nextp = delete_Token(next);
+ if (next->type == TOKEN_PASTE || next->type == TOKEN_WHITESPACE)
+ next = delete_Token(next);
else
break;
}
@@ -4942,7 +5047,7 @@ static bool paste_tokens(Token **head, const struct tokseq_match *m,
* ie A -> new-tokens -> B
*/
while ((tok = t->next)) {
- if (tok->type != TOK_WHITESPACE && tok->type != TOK_PASTE)
+ if (tok->type != TOKEN_WHITESPACE && tok->type != TOKEN_PASTE)
prev_nonspace = &t->next;
t = tok;
}
@@ -4957,10 +5062,10 @@ static bool paste_tokens(Token **head, const struct tokseq_match *m,
pasted = true;
} else {
prev_next = &tok->next;
- if (next && next->type != TOK_WHITESPACE && next->type != TOK_PASTE)
+ if (next && next->type != TOKEN_WHITESPACE &&
+ next->type != TOKEN_PASTE)
prev_nonspace = prev_next;
}
-
tok = next;
}
@@ -5056,7 +5161,7 @@ static Token *expand_mmac_params(Token * tline)
t->next = NULL;
switch (type) {
- case TOK_LOCAL_SYMBOL:
+ case TOKEN_LOCAL_SYMBOL:
change = true;
if (!mac) {
@@ -5064,10 +5169,10 @@ static Token *expand_mmac_params(Token * tline)
break;
}
- type = TOK_ID;
+ type = TOKEN_ID;
text = nasm_asprintf("..@%"PRIu64".%s", mac->unique, text+2);
break;
- case TOK_MMACRO_PARAM:
+ case TOKEN_MMACRO_PARAM:
{
Token *tt = NULL;
@@ -5092,7 +5197,7 @@ static Token *expand_mmac_params(Token * tline)
*/
case '0':
if (!text[2]) {
- type = TOK_NUMBER;
+ type = TOKEN_NUM;
text = nasm_asprintf("%d", mac->nparam);
break;
}
@@ -5139,7 +5244,7 @@ static Token *expand_mmac_params(Token * tline)
break;
}
- type = TOK_ID;
+ type = TOKEN_ID;
if (text[1] == '-') {
int ncc = inverse_ccs[cc];
if (unlikely(ncc == -1)) {
@@ -5161,9 +5266,9 @@ static Token *expand_mmac_params(Token * tline)
break;
}
- case TOK_PREPROC_Q:
+ case TOKEN_PREPROC_Q:
if (mac) {
- type = TOK_ID;
+ type = TOKEN_ID;
text = nasm_strdup(mac->iname);
change = true;
} else {
@@ -5171,9 +5276,9 @@ static Token *expand_mmac_params(Token * tline)
}
break;
- case TOK_PREPROC_QQ:
+ case TOKEN_PREPROC_QQ:
if (mac) {
- type = TOK_ID;
+ type = TOKEN_ID;
text = nasm_strdup(mac->name);
change = true;
} else {
@@ -5181,7 +5286,7 @@ static Token *expand_mmac_params(Token * tline)
}
break;
- case TOK_INDIRECT:
+ case TOKEN_INDIRECT:
{
Token *tt;
@@ -5225,18 +5330,14 @@ static Token *expand_mmac_params(Token * tline)
*tail = NULL;
if (changed) {
- const struct tokseq_match t[] = {
+ const struct concat_mask t[] = {
{
- PP_CONCAT_MASK(TOK_ID) |
- PP_CONCAT_MASK(TOK_FLOAT), /* head */
- PP_CONCAT_MASK(TOK_ID) |
- PP_CONCAT_MASK(TOK_NUMBER) |
- PP_CONCAT_MASK(TOK_FLOAT) |
- PP_CONCAT_MASK(TOK_OTHER) /* tail */
+ CONCAT_ID | CONCAT_FLOAT, /* head */
+ CONCAT_ID | CONCAT_NUM | CONCAT_FLOAT | CONCAT_OP /* tail */
},
{
- PP_CONCAT_MASK(TOK_NUMBER), /* head */
- PP_CONCAT_MASK(TOK_NUMBER) /* tail */
+ CONCAT_NUM, /* head */
+ CONCAT_NUM /* tail */
}
};
paste_tokens(&thead, t, ARRAY_SIZE(t), false);
@@ -5286,9 +5387,9 @@ static SMacro *expand_one_smacro(Token ***tpp)
smacro_deadman.triggered = true;
}
goto not_a_macro;
- } else if (tline->type == TOK_ID || tline->type == TOK_PREPROC_ID) {
+ } else if (tline->type == TOKEN_ID || tline->type == TOKEN_PREPROC_ID) {
head = (SMacro *)hash_findix(&smacros, mname);
- } else if (tline->type == TOK_LOCAL_MACRO) {
+ } else if (tline->type == TOKEN_LOCAL_MACRO) {
Context *ctx = get_ctx(mname, &mname);
head = ctx ? (SMacro *)hash_findix(&ctx->localmac, mname) : NULL;
} else {
@@ -5301,7 +5402,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;
@@ -5357,10 +5458,7 @@ static SMacro *expand_one_smacro(Token ***tpp)
goto not_a_macro;
}
- if (t->type != TOK_OTHER || t->len != 1)
- continue;
-
- switch (t->text.a[0]) {
+ switch (t->type) {
case ',':
if (!brackets && paren == 1)
nparam++;
@@ -5446,24 +5544,16 @@ static SMacro *expand_one_smacro(Token ***tpp)
while (paren) {
bool skip;
- char ch;
tline = tline->next;
if (!tline)
nasm_nonfatal("macro call expects terminating `)'");
- ch = 0;
skip = false;
-
switch (tline->type) {
- case TOK_OTHER:
- if (tline->len == 1)
- ch = tline->text.a[0];
- break;
-
- case TOK_WHITESPACE:
+ case TOKEN_WHITESPACE:
if (!(flags & SPARM_NOSTRIP)) {
if (brackets || *phead)
white++; /* Keep interior whitespace */
@@ -5471,11 +5561,6 @@ static SMacro *expand_one_smacro(Token ***tpp)
}
break;
- default:
- break;
- }
-
- switch (ch) {
case ',':
if (!brackets && paren == 1 && !(flags & SPARM_GREEDY)) {
i++;
@@ -5587,33 +5672,33 @@ static SMacro *expand_one_smacro(Token ***tpp)
/* Note: we own the expansion this returns. */
t = m->expand(m, params, nparam);
- tafter = tline->next; /* Skip past the macro call */
- tline->next = NULL; /* Truncate list at the macro call end */
+ tafter = tline->next; /* Skip past the macro call */
+ tline->next = NULL; /* Truncate list at the macro call end */
tline = tafter;
tup = NULL;
cond_comma = false;
while (t) {
- enum pp_token_type type = t->type;
+ enum token_type type = t->type;
Token *tnext = t->next;
switch (type) {
- case TOK_PREPROC_Q:
- case TOK_PREPROC_SQ:
+ case TOKEN_PREPROC_Q:
+ case TOKEN_PREPROC_SQ:
delete_Token(t);
t = dup_Token(tline, mstart);
break;
- case TOK_PREPROC_QQ:
- case TOK_PREPROC_SQQ:
+ case TOKEN_PREPROC_QQ:
+ case TOKEN_PREPROC_SQQ:
{
size_t mlen = strlen(m->name);
size_t len;
char *p, *from;
t->type = mstart->type;
- if (t->type == TOK_LOCAL_MACRO) {
+ if (t->type == TOKEN_LOCAL_MACRO) {
const char *psp; /* prefix start pointer */
const char *pep; /* prefix end pointer */
size_t plen;
@@ -5637,14 +5722,14 @@ static SMacro *expand_one_smacro(Token ***tpp)
break;
}
- case TOK_COND_COMMA:
+ case TOKEN_COND_COMMA:
delete_Token(t);
t = cond_comma ? make_tok_char(tline, ',') : NULL;
break;
- case TOK_ID:
- case TOK_PREPROC_ID:
- case TOK_LOCAL_MACRO:
+ case TOKEN_ID:
+ case TOKEN_PREPROC_ID:
+ case TOKEN_LOCAL_MACRO:
{
/*
* Chain this into the target line *before* expanding,
@@ -5676,7 +5761,7 @@ static SMacro *expand_one_smacro(Token ***tpp)
tline = t;
while (!cond_comma && t && t != endt) {
- cond_comma = t->type != TOK_WHITESPACE;
+ cond_comma = t->type != TOKEN_WHITESPACE;
t = t->next;
}
}
@@ -5755,17 +5840,13 @@ static Token *expand_smacro_noreset(Token *org_tline)
expanded = true;
while (true) {
- static const struct tokseq_match tmatch[] = {
+ static const struct concat_mask tmatch[] = {
{
- PP_CONCAT_MASK(TOK_ID) |
- PP_CONCAT_MASK(TOK_LOCAL_MACRO) |
- PP_CONCAT_MASK(TOK_ENVIRON) |
- PP_CONCAT_MASK(TOK_PREPROC_ID), /* head */
- PP_CONCAT_MASK(TOK_ID) |
- PP_CONCAT_MASK(TOK_LOCAL_MACRO) |
- PP_CONCAT_MASK(TOK_ENVIRON) |
- PP_CONCAT_MASK(TOK_PREPROC_ID) |
- PP_CONCAT_MASK(TOK_NUMBER) /* tail */
+ CONCAT_ID | CONCAT_LOCAL_MACRO |
+ CONCAT_ENVIRON | CONCAT_PREPROC_ID, /* head */
+ CONCAT_ID | CONCAT_LOCAL_MACRO |
+ CONCAT_ENVIRON | CONCAT_PREPROC_ID |
+ CONCAT_NUM /* tail */
}
};
Token **tail = &tline;
@@ -5784,9 +5865,9 @@ static Token *expand_smacro_noreset(Token *org_tline)
break; /* Done! */
/*
- * Now scan the entire line and look for successive TOK_IDs
+ * Now scan the entire line and look for successive TOKEN_IDs
* that resulted after expansion (they can't be produced by
- * tokenize()). The successive TOK_IDs should be concatenated.
+ * tokenize()). The successive TOKEN_IDs should be concatenated.
* Also we look for %+ tokens and concatenate the tokens
* before and after them (without white spaces in between).
*/
@@ -5843,8 +5924,10 @@ static Token *expand_id(Token * tline)
cur = tline;
while (cur->next &&
- (cur->next->type == TOK_ID || cur->next->type == TOK_PREPROC_ID ||
- cur->next->type == TOK_LOCAL_MACRO || cur->next->type == TOK_NUMBER))
+ (cur->next->type == TOKEN_ID ||
+ cur->next->type == TOKEN_PREPROC_ID ||
+ cur->next->type == TOKEN_LOCAL_MACRO ||
+ cur->next->type == TOKEN_NUM))
cur = cur->next;
/* If identifier consists of just one token, don't expand */
@@ -5961,7 +6044,7 @@ find_mmacro_in_list(MMacro *m, const char *finding,
* call, and return the MMacro structure called if so. Doesn't have
* to check for an initial label - that's taken care of in
* expand_mmacro - but must check numbers of parameters. Guaranteed
- * to be called with tline->type == TOK_ID, so the putative macro
+ * to be called with tline->type == TOKEN_ID, so the putative macro
* name is easy to find.
*/
static MMacro *is_mmacro(Token * tline, int *nparamp, Token ***paramsp)
@@ -6063,7 +6146,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) {
/*
@@ -6210,7 +6293,7 @@ static void list_mmacro_call(const MMacro *m)
list_for_each(t, m->params[i]) {
if (j++ >= m->paramlen[i])
break;
- size += (t->type == TOK_WHITESPACE) ? 1 : t->len;
+ size += (t->type == TOKEN_WHITESPACE) ? 1 : t->len;
}
}
@@ -6237,6 +6320,156 @@ static void list_mmacro_call(const MMacro *m)
}
/*
+ * Collect information about macro invocations for the benefit of
+ * the debugger. During execution we create a reverse list; before
+ * calling the backend reverse it to definition/invocation order just
+ * to be nicer. [XXX: not implemented yet]
+ */
+struct debug_macro_inv *debug_current_macro;
+
+/* Get/create a addr structure for a seg:inv combo */
+static struct debug_macro_addr *
+debug_macro_get_addr_inv(int32_t seg, struct debug_macro_inv *inv)
+{
+ struct debug_macro_addr *addr;
+ nasm_static_assert(offsetof(struct debug_macro_addr, tree) == 0);
+
+ if (likely(seg == inv->lastseg))
+ return inv->addr.last;
+
+ inv->lastseg = seg;
+ addr = (struct debug_macro_addr *)
+ rb_search_exact(inv->addr.tree, seg);
+ if (unlikely(!addr)) {
+ nasm_new(addr);
+ addr->tree.key = seg;
+ inv->addr.tree = rb_insert(inv->addr.tree, &addr->tree);
+ inv->naddr++;
+ if (inv->up)
+ addr->up = debug_macro_get_addr_inv(seg, inv->up);
+ }
+
+ return inv->addr.last = addr;
+}
+
+/* Get/create an addr structure for a seg in debug_current_macro */
+struct debug_macro_addr *debug_macro_get_addr(int32_t seg)
+{
+ return debug_macro_get_addr_inv(seg, debug_current_macro);
+}
+
+static struct debug_macro_info dmi;
+static struct debug_macro_inv_list *current_inv_list = &dmi.inv;
+
+static void debug_macro_start(MMacro *m, struct src_location where)
+{
+ struct debug_macro_def *def = m->dbg.def;
+ struct debug_macro_inv *inv;
+
+ nasm_assert(!m->dbg.inv);
+
+ /* First invocation? Need to create a def structure */
+ if (unlikely(!def)) {
+ nasm_new(def);
+ def->name = nasm_strdup(m->name);
+ def->where = m->where;
+
+ def->next = dmi.def.l;
+ dmi.def.l = def;
+ dmi.def.n++;
+
+ m->dbg.def = def;
+ }
+
+ nasm_new(inv);
+ inv->lastseg = NO_SEG;
+ inv->where = where;
+ inv->up = debug_current_macro;
+ inv->next = current_inv_list->l;
+ inv->def = def;
+ current_inv_list->l = inv;
+ current_inv_list->n++;
+ current_inv_list = &inv->down;
+
+ def->ninv++;
+ m->dbg.inv = inv;
+ debug_current_macro = inv;
+}
+
+static void debug_macro_end(MMacro *m)
+{
+ struct debug_macro_inv *inv = m->dbg.inv;
+
+ nasm_assert(inv == debug_current_macro);
+
+ list_reverse(inv->down.l);
+
+ m->dbg.inv = NULL;
+ inv = inv->up;
+
+ m = istk->mstk.mmac;
+ if (m) {
+ nasm_assert(inv == m->dbg.inv);
+ debug_current_macro = inv;
+ current_inv_list = &inv->down;
+ } else {
+ nasm_assert(!inv);
+ debug_current_macro = NULL;
+ current_inv_list = &dmi.inv;
+ }
+}
+
+static void free_debug_macro_addr_tree(struct rbtree *tree)
+{
+ struct rbtree *left, *right;
+ nasm_static_assert(offsetof(struct debug_macro_addr,tree) == 0);
+
+ if (!tree)
+ return;
+
+ left = rb_left(tree);
+ right = rb_right(tree);
+
+ nasm_free(tree);
+
+ free_debug_macro_addr_tree(left);
+ free_debug_macro_addr_tree(right);
+}
+
+static void free_debug_macro_inv_list(struct debug_macro_inv *inv)
+{
+ struct debug_macro_inv *itmp;
+
+ if (!inv)
+ return;
+
+ list_for_each_safe(inv, itmp, inv) {
+ free_debug_macro_inv_list(inv->down.l);
+ free_debug_macro_addr_tree(inv->addr.tree);
+ nasm_free(inv);
+ }
+}
+
+static void free_debug_macro_info(void)
+{
+ struct debug_macro_def *def, *dtmp;
+
+ list_for_each_safe(def, dtmp, dmi.def.l)
+ nasm_free(def);
+
+ free_debug_macro_inv_list(dmi.inv.l);
+
+ nasm_zero(dmi);
+}
+
+static void debug_macro_output(void)
+{
+ list_reverse(dmi.inv.l);
+ dfmt->debug_mmacros(&dmi);
+ free_debug_macro_info();
+}
+
+/*
* Expand the multi-line macro call made by the given line, if
* there is one to be expanded. If there is, push the expansion on
* istk->expansion and return 1. Otherwise return 0.
@@ -6255,8 +6488,7 @@ static int expand_mmacro(Token * tline)
t = tline;
t = skip_white(t);
- /* if (!tok_type(t, TOK_ID)) Lino 02/25/02 */
- if (!tok_type(t, TOK_ID) && !tok_type(t, TOK_LOCAL_MACRO))
+ if (!tok_is(t, TOKEN_ID) && !tok_is(t, TOKEN_LOCAL_MACRO))
return 0;
m = is_mmacro(t, &nparam, &params);
if (m) {
@@ -6279,7 +6511,7 @@ static int expand_mmacro(Token * tline)
if (tok_white(t))
last = t, t = t->next;
}
- if (!tok_type(t, TOK_ID) || !(m = is_mmacro(t, &nparam, &params)))
+ if (!tok_is(t, TOKEN_ID) || !(m = is_mmacro(t, &nparam, &params)))
return 0;
last->next = NULL;
mname = tok_text(t);
@@ -6325,28 +6557,26 @@ static int expand_mmacro(Token * tline)
continue;
}
- if (t->type == TOK_OTHER && t->len == 1) {
- switch (t->text.a[0]) {
- case ',':
- if (comma && !brace)
- goto endparam;
- break;
-
- case '{':
- brace++;
- break;
+ switch(t->type) {
+ case ',':
+ if (comma && !brace)
+ goto endparam;
+ break;
- case '}':
- brace--;
- if (braced && !brace) {
- paramlen[i] += white;
- goto endparam;
- }
- break;
+ case '{':
+ brace++;
+ break;
- default:
- break;
+ case '}':
+ brace--;
+ if (braced && !brace) {
+ paramlen[i] += white;
+ goto endparam;
}
+ break;
+
+ default:
+ break;
}
paramlen[i] += white + 1;
@@ -6441,10 +6671,13 @@ static int expand_mmacro(Token * tline)
istk->noline += !!(m->nolist & NL_LINE);
if (!istk->nolist) {
- lfmt->uplevel(LIST_MACRO, 0);
-
if (list_option('m'))
list_mmacro_call(m);
+
+ lfmt->uplevel(LIST_MACRO, 0);
+
+ if (ppdbg & PDBG_MMACROS)
+ debug_macro_start(m, src_where());
}
if (!istk->noline)
@@ -6458,7 +6691,7 @@ static int expand_mmacro(Token * tline)
* It will never be called with a severity level of ERR_FATAL or
* higher.
*/
-static bool pp_suppress_error(errflags severity)
+bool pp_suppress_error(errflags severity)
{
/*
* If we're in a dead branch of IF or something like it, ignore the error.
@@ -6479,11 +6712,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 *
@@ -6515,91 +6750,100 @@ stdmac_ptr(const SMacro *s, Token **params, int nparams)
switch (globalbits) {
case 16:
- return new_Token(NULL, TOK_ID, "word", 4);
+ return new_Token(NULL, TOKEN_ID, "word", 4);
case 32:
- return new_Token(NULL, TOK_ID, "dword", 5);
+ return new_Token(NULL, TOKEN_ID, "dword", 5);
case 64:
- return new_Token(NULL, TOK_ID, "qword", 5);
+ return new_Token(NULL, TOKEN_ID, "qword", 5);
default:
panic();
}
}
+static Token *
+stdmac_is(const SMacro *s, Token **params, int nparams)
+{
+ int retval;
+ struct Token *pline = params[0];
+
+ (void)nparams;
+
+ params[0] = NULL; /* Don't free this later */
+
+ retval = if_condition(pline, s->expandpvt.u) == COND_IF_TRUE;
+ return make_tok_num(NULL, retval);
+}
+
/* Add magic standard macros */
struct magic_macros {
const char *name;
int nparam;
ExpandSMacro func;
};
-static const struct magic_macros magic_macros[] =
-{
- { "__?FILE?__", 0, stdmac_file },
- { "__?LINE?__", 0, stdmac_line },
- { "__?BITS?__", 0, stdmac_bits },
- { "__?PTR?__", 0, stdmac_ptr },
- { NULL, 0, NULL }
-};
-
static void pp_add_magic_stdmac(void)
{
+ static const struct magic_macros magic_macros[] = {
+ { "__?FILE?__", 0, stdmac_file },
+ { "__?LINE?__", 0, stdmac_line },
+ { "__?BITS?__", 0, stdmac_bits },
+ { "__?PTR?__", 0, stdmac_ptr },
+ { NULL, 0, NULL }
+ };
const struct magic_macros *m;
SMacro tmpl;
+ enum preproc_token pt;
+ char name_buf[PP_TOKLEN_MAX+1];
+ /* Simple standard magic macros */
nasm_zero(tmpl);
-
for (m = magic_macros; m->name; m++) {
tmpl.nparam = m->nparam;
tmpl.expand = m->func;
define_smacro(m->name, true, NULL, &tmpl);
}
+
+ /* %is...() macro functions */
+ tmpl.nparam = 1;
+ tmpl.greedy = true;
+ tmpl.expand = stdmac_is;
+ name_buf[0] = '%';
+ name_buf[1] = 'i';
+ name_buf[2] = 's';
+ for (pt = PP_IF; pt < PP_IFN; pt++) {
+ if (pp_directives[pt]) {
+ nasm_new(tmpl.params);
+
+ tmpl.params[0].flags = SPARM_GREEDY;
+ strcpy(name_buf+3, pp_directives[pt]+3);
+ tmpl.expandpvt.u = pt;
+ define_smacro(name_buf, false, NULL, &tmpl);
+ }
+ }
}
-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);
-
- 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 = !list_option('b');
+ inc->nolist = inc->noline = !list_option('b');
+ inc->where = istk->where;
istk = inc;
- lfmt->uplevel(LIST_INCLUDE, 0);
+ if (!istk->nolist) {
+ lfmt->uplevel(LIST_INCLUDE, 0);
+ }
+ if (!istk->noline) {
+ src_set(0, NULL);
+ istk->where = src_where();
+ if (ppdbg & PDBG_INCLUDE)
+ dfmt->debug_include(true, istk->next->where, istk->where);
+ }
pp_add_magic_stdmac();
@@ -6645,8 +6889,67 @@ 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)
+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_mmacros)
+ ppdbg |= PDBG_MMACROS;
+ if (dfmt->debug_smacros)
+ ppdbg |= PDBG_SMACROS;
+ if (dfmt->debug_include)
+ ppdbg |= PDBG_INCLUDE;
+ }
+
+ if (list_option('s'))
+ ppdbg |= PDBG_LIST_SMACROS;
+ }
+
+ 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;
+
+ if (ppdbg & PDBG_INCLUDE) {
+ /* Let the debug format know the main file */
+ dfmt->debug_include(true, src_nowhere(), istk->where);
+ }
+
+ strlist_add(deplist, file);
+
+ do_predef = false;
+
+ if (!(ppopt & PP_TRIVIAL))
+ pp_reset_stdmac(mode);
+}
+
+void pp_init(enum preproc_opt opt)
{
+ ppopt = opt;
+ nasm_newn(use_loaded, use_package_count);
}
/*
@@ -6755,12 +7058,6 @@ 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) {
@@ -6769,6 +7066,14 @@ static Token *pp_tokline(void)
src_update(l->where);
}
+ if (fm->nolist & NL_LIST) {
+ istk->nolist--;
+ } else if (!istk->nolist) {
+ lfmt->downlevel(LIST_MACRO);
+ if ((ppdbg & PDBG_MMACROS) && fm->name)
+ debug_macro_end(fm);
+ }
+
istk->where = l->where;
/*
@@ -6808,7 +7113,6 @@ static Token *pp_tokline(void)
nasm_free(line);
}
} else if ((line = read_line())) {
- line = prepreproc(line);
tline = tokenize(line);
nasm_free(line);
} else {
@@ -6816,7 +7120,6 @@ 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);
@@ -6825,14 +7128,19 @@ static Token *pp_tokline(void)
nasm_fatal("expected `%%endif' before end of file");
}
- list_for_each(is, i->next) {
- if (is->fp) {
- lfmt->downlevel(LIST_INCLUDE);
- src_update(is->where);
- break;
- }
- }
istk = i->next;
+
+ if (!i->nolist)
+ lfmt->downlevel(LIST_INCLUDE);
+ if (!i->noline) {
+ struct src_location whereto
+ = istk ? istk->where : src_nowhere();
+ if (ppdbg & PDBG_INCLUDE)
+ dfmt->debug_include(false, whereto, i->where);
+ if (istk)
+ src_update(istk->where);
+ }
+
nasm_free(i);
return &tok_pop;
}
@@ -6884,7 +7192,8 @@ static Token *pp_tokline(void)
if (mmac) {
const Token *t;
list_for_each(t, tline) {
- if (!memcmp(t->text.a, "%00", 4))
+ if (t->type == TOKEN_PREPROC_ID &&
+ !memcmp(t->text.a, "%00", 4))
mmac->capture_label = true;
}
}
@@ -6914,7 +7223,7 @@ static Token *pp_tokline(void)
}
}
-static char *pp_getline(void)
+char *pp_getline(void)
{
char *line = NULL;
Token *tline;
@@ -6947,7 +7256,7 @@ static char *pp_getline(void)
return line;
}
-static void pp_cleanup_pass(void)
+void pp_cleanup_pass(void)
{
if (defining) {
if (defining->name) {
@@ -6968,14 +7277,21 @@ static void pp_cleanup_pass(void)
Include *i = istk;
istk = istk->next;
fclose(i->fp);
+ if (!istk && (ppdbg & PDBG_INCLUDE)) {
+ /* Signal closing the top-level input file */
+ dfmt->debug_include(false, src_nowhere(), i->where);
+ }
nasm_free(i);
}
while (cstk)
ctx_pop();
src_set_fname(NULL);
+
+ if (ppdbg & PDBG_MMACROS)
+ debug_macro_output();
}
-static void pp_cleanup_session(void)
+void pp_cleanup_session(void)
{
nasm_free(use_loaded);
free_llist(predef);
@@ -6984,19 +7300,19 @@ static void pp_cleanup_session(void)
ipath_list = NULL;
}
-static void pp_include_path(struct strlist *list)
+void pp_include_path(struct strlist *list)
{
ipath_list = list;
}
-static void pp_pre_include(char *fname)
+void pp_pre_include(char *fname)
{
Token *inc, *space, *name;
Line *l;
- name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0);
+ name = new_Token(NULL, TOKEN_INTERNAL_STR, fname, 0);
space = new_White(name);
- inc = new_Token(space, TOK_PREPROC_ID, "%include", 0);
+ inc = new_Token(space, TOKEN_PREPROC_ID, "%include", 0);
l = nasm_malloc(sizeof(Line));
l->next = predef;
@@ -7005,7 +7321,7 @@ static void pp_pre_include(char *fname)
predef = l;
}
-static void pp_pre_define(char *definition)
+void pp_pre_define(char *definition)
{
Token *def, *space;
Line *l;
@@ -7013,35 +7329,30 @@ static void pp_pre_define(char *definition)
equals = strchr(definition, '=');
space = new_White(NULL);
- def = new_Token(space, TOK_PREPROC_ID, "%define", 0);
+ def = new_Token(space, TOKEN_PREPROC_ID, "%define", 0);
if (equals)
*equals = ' ';
space->next = tokenize(definition);
if (equals)
*equals = '=';
- /* We can't predefine a TOK_LOCAL_MACRO for obvious reasons... */
- if (space->next->type != TOK_PREPROC_ID &&
- space->next->type != TOK_ID)
- nasm_warn(WARN_OTHER, "pre-defining non ID `%s\'\n", definition);
-
- l = nasm_malloc(sizeof(Line));
+ nasm_new(l);
l->next = predef;
l->first = def;
l->finishes = NULL;
predef = l;
}
-static void pp_pre_undefine(char *definition)
+void pp_pre_undefine(char *definition)
{
Token *def, *space;
Line *l;
space = new_White(NULL);
- def = new_Token(space, TOK_PREPROC_ID, "%undef", 0);
+ def = new_Token(space, TOKEN_PREPROC_ID, "%undef", 0);
space->next = tokenize(definition);
- l = nasm_malloc(sizeof(Line));
+ nasm_new(l);
l->next = predef;
l->first = def;
l->finishes = NULL;
@@ -7049,21 +7360,18 @@ static void pp_pre_undefine(char *definition)
}
/* Insert an early preprocessor command that doesn't need special handling */
-static void pp_pre_command(const char *what, char *string)
+void pp_pre_command(const char *what, char *string)
{
- char *cmd;
Token *def, *space;
Line *l;
def = tokenize(string);
if (what) {
space = new_White(def);
- cmd = nasm_strcat(what[0] == '%' ? "" : "%", what);
- def = new_Token(space, TOK_PREPROC_ID, cmd, nasm_last_string_len());
- nasm_free(cmd);
+ def = new_Token(space, TOKEN_PREPROC_ID, what, 0);
}
- l = nasm_malloc(sizeof(Line));
+ nasm_new(l);
l->next = predef;
l->first = def;
l->finishes = NULL;
@@ -7085,24 +7393,35 @@ static void pp_add_stdmac(macros_t *macros)
*mp = macros;
}
-static void pp_extra_stdmac(macros_t *macros)
+void pp_extra_stdmac(macros_t *macros)
{
extrastdmac = macros;
}
-/* Create a numeric token */
+/* Create a numeric token, with possible - token in front */
static Token *make_tok_num(Token *next, int64_t val)
{
char numbuf[32];
- int len = snprintf(numbuf, sizeof(numbuf), "%"PRId64"", val);
- return new_Token(next, TOK_NUMBER, numbuf, len);
+ int len;
+ uint64_t uval;
+ bool minus = val < 0;
+
+ uval = minus ? -val : val;
+
+ len = snprintf(numbuf, sizeof numbuf, "%"PRIu64, uval);
+ next = new_Token(next, TOKEN_NUM, numbuf, len);
+
+ if (minus)
+ next = make_tok_char(next, '-');
+
+ return next;
}
/* Create a quoted string token */
static Token *make_tok_qstr_len(Token *next, const char *str, size_t len)
{
char *p = nasm_quote(str, &len);
- return new_Token_free(next, TOK_STRING, p, len);
+ return new_Token_free(next, TOKEN_STR, p, len);
}
static Token *make_tok_qstr(Token *next, const char *str)
{
@@ -7112,7 +7431,7 @@ static Token *make_tok_qstr(Token *next, const char *str)
/* Create a single-character operator token */
static Token *make_tok_char(Token *next, char op)
{
- Token *t = new_Token(next, TOK_OTHER, NULL, 1);
+ Token *t = new_Token(next, op, NULL, 1);
t->text.a[0] = op;
return t;
}
@@ -7121,7 +7440,7 @@ static Token *make_tok_char(Token *next, char op)
* Descent the macro hierarchy and display the expansion after
* encountering an error message.
*/
-static void pp_error_list_macros(errflags severity)
+void pp_error_list_macros(errflags severity)
{
const MMacro *m;
@@ -7135,19 +7454,3 @@ static void pp_error_list_macros(errflags severity)
src_error_reset();
}
-
-const struct preproc_ops nasmpp = {
- pp_init,
- pp_reset,
- pp_getline,
- pp_cleanup_pass,
- pp_cleanup_session,
- pp_extra_stdmac,
- pp_pre_define,
- pp_pre_undefine,
- pp_pre_include,
- pp_pre_command,
- pp_include_path,
- pp_error_list_macros,
- pp_suppress_error
-};
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/asm/quote.c b/asm/quote.c
index 58bb5a10..301abed7 100644
--- a/asm/quote.c
+++ b/asm/quote.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2019 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.
*
@@ -291,10 +291,17 @@ char *nasm_quote_cstr(const char *str, size_t *lenp)
* corresponding to bits set in badctl; in that case, the output
* string, but not *ep, is truncated before the first invalid
* character.
+ *
+ * badctl is a bitmask of control characters (0-31) which are forbidden
+ * from appearing in the final output.
+ *
+ * The qstart character can be either '`' (NASM style) or '\"' (C style),
+ * to indicate the lead marker of a quoted string. If it is '\"', then
+ * '`' is not a special character at all.
*/
-static size_t nasm_unquote_common(char *str, char **ep,
- const uint32_t badctl)
+size_t nasm_unquote_anystr(char *str, char **ep, const uint32_t badctl,
+ const char qstart)
{
unsigned char bq;
const unsigned char *p;
@@ -319,15 +326,7 @@ static size_t nasm_unquote_common(char *str, char **ep,
if (!bq)
return 0;
- switch (bq) {
- case '\'':
- case '\"':
- /* '...' or "..." string */
- while ((c = *p++) && (c != bq))
- EMIT(c);
- break;
-
- case '`':
+ if (bq == (unsigned char)qstart) {
/* `...` string */
state = st_start;
@@ -335,18 +334,13 @@ static size_t nasm_unquote_common(char *str, char **ep,
c = *p++;
switch (state) {
case st_start:
- switch (c) {
- case '\\':
+ if (c == '\\') {
state = st_backslash;
- break;
- case '`':
- case '\0':
+ } else if ((c == '\0') | (c == bq)) {
state = st_done;
- break;
- default:
+ } else {
EMIT(c);
- break;
- }
+ }
break;
case st_backslash:
@@ -450,14 +444,19 @@ static size_t nasm_unquote_common(char *str, char **ep,
default:
panic();
}
- }
- break;
-
- default:
+ }
+ } else if (bq == '\'' || bq == '\"') {
+ /*
+ * '...' or "..." string, NASM legacy style (no escapes of
+ * * any kind, including collapsing double quote marks.)
+ * We obviously can't get here if qstart == '\"'.
+ */
+ while ((c = *p++) && (c != bq))
+ EMIT(c);
+ } else {
/* Not a quoted string, just return the input... */
while ((c = *p++))
EMIT(c);
- break;
}
/* Zero-terminate the output */
@@ -472,24 +471,30 @@ static size_t nasm_unquote_common(char *str, char **ep,
}
#undef EMIT
+/*
+ * Unquote any arbitrary string; may produce any bytes, including embedded
+ * control- and NUL characters.
+ */
size_t nasm_unquote(char *str, char **ep)
{
- return nasm_unquote_common(str, ep, 0);
+ return nasm_unquote_anystr(str, ep, 0, STR_NASM);
}
+
+/*
+ * Unquote a string indended to be used as a C string; most control
+ * characters are rejected, including whitespace characters that
+ * would imply line endings and so on.
+ */
size_t nasm_unquote_cstr(char *str, char **ep)
{
- /*
- * These are the only control characters permitted: BEL BS TAB ESC
- */
- const uint32_t okctl = (1 << '\a') | (1 << '\b') | (1 << '\t') | (1 << 27);
-
- return nasm_unquote_common(str, ep, ~okctl);
+ return nasm_unquote_anystr(str, ep, BADCTL, STR_NASM);
}
/*
* Find the end of a quoted string; returns the pointer to the terminating
* character (either the ending quote or the null character, if unterminated.)
* If the input is not a quoted string, return NULL.
+ * This applies to NASM style strings only.
*/
char *nasm_skip_string(const char *str)
{
@@ -537,7 +542,9 @@ char *nasm_skip_string(const char *str)
* Note: for the purpose of finding the end of the string,
* all successor states to st_backslash are functionally
* equivalent to st_start, since either a backslash or
- * a backquote will force a return to the st_start state.
+ * a backquote will force a return to the st_start state,
+ * and any possible multi-character state will terminate
+ * for any non-alphanumeric character.
*/
state = c ? st_start : st_done;
break;
diff --git a/asm/quote.h b/asm/quote.h
index 7259f7cd..d8226cdb 100644
--- a/asm/quote.h
+++ b/asm/quote.h
@@ -38,9 +38,24 @@
char *nasm_quote(const char *str, size_t *len);
char *nasm_quote_cstr(const char *str, size_t *len);
+size_t nasm_unquote_anystr(char *str, char **endptr,
+ uint32_t badctl, char qstart);
size_t nasm_unquote(char *str, char **endptr);
size_t nasm_unquote_cstr(char *str, char **endptr);
char *nasm_skip_string(const char *str);
+/* Arguments used with nasm_quote_anystr() */
+
+/*
+ * These are the only control characters when we produce a C string:
+ * BEL BS TAB ESC
+ */
+#define OKCTL ((1U << '\a') | (1U << '\b') | (1U << '\t') | (1U << 27))
+#define BADCTL (~(uint32_t)OKCTL)
+
+/* Initial quotation mark */
+#define STR_C '\"'
+#define STR_NASM '`'
+
#endif /* NASM_QUOTE_H */
diff --git a/asm/srcfile.h b/asm/srcfile.h
index ec9965d3..a1853548 100644
--- a/asm/srcfile.h
+++ b/asm/srcfile.h
@@ -44,6 +44,12 @@ struct src_location {
int32_t lineno;
};
+static inline const_func struct src_location src_nowhere(void)
+{
+ struct src_location no_where = { NULL, 0 };
+ return no_where;
+}
+
/*
* Comparing the *pointer value* of filenames is valid, because the
* filename hash system guarantees that each unique filename string is
diff --git a/asm/tokhash.pl b/asm/tokhash.pl
index 9303157b..566a3aa3 100755
--- a/asm/tokhash.pl
+++ b/asm/tokhash.pl
@@ -1,7 +1,7 @@
#!/usr/bin/perl
## --------------------------------------------------------------------------
##
-## 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.
##
@@ -201,6 +201,7 @@ if ($output eq 'h') {
($n, $sv, $g) = @hashinfo;
die if ($n & ($n-1));
+ $n <<= 1;
print "/*\n";
print " * This file is generated from insns.dat, regs.dat and token.dat\n";
@@ -234,19 +235,12 @@ if ($output eq 'h') {
# 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 "#define UNUSED_HASH_ENTRY (65535/3)\n";
+ print "#define INVALID_HASH_ENTRY (65535/3)\n";
- print " static const int16_t hash1[$n] = {\n";
+ printf " static const int16_t hashdata[%d] = {\n", $n;
for ($i = 0; $i < $n; $i++) {
- my $h = ${$g}[$i*2+0];
- print " ", defined($h) ? $h : 'UNUSED_HASH_ENTRY', ",\n";
- }
- print " };\n";
-
- print " static const int16_t hash2[$n] = {\n";
- for ($i = 0; $i < $n; $i++) {
- my $h = ${$g}[$i*2+1];
- print " ", defined($h) ? $h : 'UNUSED_HASH_ENTRY', ",\n";
+ my $h = ${$g}[$i];
+ print " ", defined($h) ? $h : 'INVALID_HASH_ENTRY', ",\n";
}
print " };\n";
@@ -275,10 +269,11 @@ if ($output eq 'h') {
print " crc = crc64_byte(crc, c);\n";
print " };\n";
print "\n";
- print " k1 = (uint32_t)crc;\n";
- print " k2 = (uint32_t)(crc >> 32);\n";
+ printf " k1 = ((uint32_t)crc & 0x%x) + 0;\n", $n-2;
+ printf " k2 = ((uint32_t)(crc >> 32) & 0x%x) + 1;\n", $n-2;
print "\n";
- printf " ix = hash1[k1 & 0x%x] + hash2[k2 & 0x%x];\n", $n-1, $n-1;
+ printf " ix = hashdata[k1] + hashdata[k2];\n",
+ $n-2, $n-2;
printf " if (ix >= %d)\n", scalar(@tokendata);
print " goto notfound;\n";
print "\n";