diff options
author | somov <somov@yandex-team.ru> | 2022-02-10 16:45:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:49 +0300 |
commit | 7489e4682331202b9c7d863c0898eb83d7b12c2b (patch) | |
tree | 9142afc54d335ea52910662635b898e79e192e49 /contrib/tools/yasm/modules/preprocs | |
parent | a5950576e397b1909261050b8c7da16db58f10b1 (diff) | |
download | ydb-7489e4682331202b9c7d863c0898eb83d7b12c2b.tar.gz |
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/tools/yasm/modules/preprocs')
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/cpp/cpp-preproc.c | 804 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/gas/gas-eval.c | 886 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/gas/gas-eval.h | 240 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/gas/gas-preproc.c | 2814 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/nasm/genversion.c | 162 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.c | 880 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.h | 36 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.c | 10618 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.h | 44 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/nasm/nasm-preproc.c | 682 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/nasm/nasm.h | 566 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/nasm/nasmlib.c | 402 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/nasm/nasmlib.h | 120 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/raw/raw-preproc.c | 336 |
14 files changed, 9295 insertions, 9295 deletions
diff --git a/contrib/tools/yasm/modules/preprocs/cpp/cpp-preproc.c b/contrib/tools/yasm/modules/preprocs/cpp/cpp-preproc.c index ec294268cc..663f726cc7 100644 --- a/contrib/tools/yasm/modules/preprocs/cpp/cpp-preproc.c +++ b/contrib/tools/yasm/modules/preprocs/cpp/cpp-preproc.c @@ -1,402 +1,402 @@ -/* - * Invoke an external C preprocessor - * - * Copyright (C) 2007 Paul Barker - * Copyright (C) 2001-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. - */ - -#include <util.h> -#include <libyasm.h> - -/* TODO: Use autoconf to get the limit on the command line length. */ -#define CMDLINE_SIZE 32770 - -#define BSIZE 512 - -/* Pre-declare the preprocessor module object. */ -yasm_preproc_module yasm_cpp_LTX_preproc; - -/******************************************************************************* - Structures. -*******************************************************************************/ - -/* An entry in a list of arguments to pass to cpp. */ -typedef struct cpp_arg_entry { - TAILQ_ENTRY(cpp_arg_entry) entry; - - /* - The operator (eg "-I") and the parameter (eg "include/"). op is expected - to point to a string literal, whereas param is expected to be a copy of - the parameter which is free'd when no-longer needed (in - cpp_preproc_destroy()). - */ - const char *op; - char *param; -} cpp_arg_entry; - -typedef struct yasm_preproc_cpp { - yasm_preproc_base preproc; /* base structure */ - - /* List of arguments to pass to cpp. */ - TAILQ_HEAD(cpp_arg_head, cpp_arg_entry) cpp_args; - - char *filename; - FILE *f, *f_deps; - yasm_linemap *cur_lm; - yasm_errwarns *errwarns; - - int flags; -} yasm_preproc_cpp; - -/* Flag values for yasm_preproc_cpp->flags. */ -#define CPP_HAS_BEEN_INVOKED 0x01 -#define CPP_HAS_GENERATED_DEPS 0x02 - -/******************************************************************************* - Internal functions and helpers. -*******************************************************************************/ - -/* - Append a string to the command line, ensuring that we don't overflow the - buffer. -*/ -#define APPEND(s) do { \ - size_t _len = strlen(s); \ - if (p + _len >= limit) \ - yasm__fatal(N_("command line too long!")); \ - strcpy(p, s); \ - p += _len; \ -} while (0) - -/* - Put all the options together into a command line that can be used to invoke - cpp. -*/ -static char * -cpp_build_cmdline(yasm_preproc_cpp *pp, const char *extra) -{ - char *cmdline, *p, *limit; - cpp_arg_entry *arg; - - /* Initialize command line. */ - cmdline = p = yasm_xmalloc(strlen(CPP_PROG)+CMDLINE_SIZE); - limit = p + CMDLINE_SIZE; - strcpy(p, CPP_PROG); - p += strlen(CPP_PROG); - - arg = TAILQ_FIRST(&pp->cpp_args); - - /* Append arguments from the list. */ - while ( arg ) { - APPEND(" "); - APPEND(arg->op); - APPEND(" "); - APPEND(arg->param); - - arg = TAILQ_NEXT(arg, entry); - } - - /* Append extra arguments. */ - if (extra) { - APPEND(" "); - APPEND(extra); - } - /* Append final arguments. */ - APPEND(" -x assembler-with-cpp "); - APPEND(pp->filename); - - return cmdline; -} - -/* Invoke the c preprocessor. */ -static void -cpp_invoke(yasm_preproc_cpp *pp) -{ - char *cmdline; - - cmdline = cpp_build_cmdline(pp, NULL); - -#ifdef HAVE_POPEN - pp->f = popen(cmdline, "r"); - if (!pp->f) - yasm__fatal( N_("Failed to execute preprocessor") ); -#else - yasm__fatal( N_("Cannot execute preprocessor, no popen available") ); -#endif - - yasm_xfree(cmdline); -} - -/* Free memory used by the list of arguments. */ -static void -cpp_destroy_args(yasm_preproc_cpp *pp) -{ - cpp_arg_entry *arg; - - while ( (arg = TAILQ_FIRST(&pp->cpp_args)) ) { - TAILQ_REMOVE(&pp->cpp_args, arg, entry); - yasm_xfree(arg->param); - yasm_xfree(arg); - } -} - -/* Invoke the c preprocessor to generate dependency info. */ -static void -cpp_generate_deps(yasm_preproc_cpp *pp) -{ - char *cmdline; - - cmdline = cpp_build_cmdline(pp, "-M"); - -#ifdef HAVE_POPEN - pp->f_deps = popen(cmdline, "r"); - if (!pp->f_deps) - yasm__fatal( N_("Failed to execute preprocessor") ); -#else - yasm__fatal( N_("Cannot execute preprocessor, no popen available") ); -#endif - - yasm_xfree(cmdline); -} - -/******************************************************************************* - Interface functions. -*******************************************************************************/ -static yasm_preproc * -cpp_preproc_create(const char *in, yasm_symtab *symtab, yasm_linemap *lm, - yasm_errwarns *errwarns) -{ - yasm_preproc_cpp *pp = yasm_xmalloc(sizeof(yasm_preproc_cpp)); - void * iter; - const char * inc_dir; - - pp->preproc.module = &yasm_cpp_LTX_preproc; - pp->f = pp->f_deps = NULL; - pp->cur_lm = lm; - pp->errwarns = errwarns; - pp->flags = 0; - pp->filename = yasm__xstrdup(in); - - TAILQ_INIT(&pp->cpp_args); - - /* Iterate through the list of include dirs. */ - iter = NULL; - while ((inc_dir = yasm_get_include_dir(&iter)) != NULL) { - cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); - arg->op = "-I"; - arg->param = yasm__xstrdup(inc_dir); - - TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); - } - - return (yasm_preproc *)pp; -} - -static void -cpp_preproc_destroy(yasm_preproc *preproc) -{ - yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; - - if (pp->f) { -#ifdef HAVE_POPEN - if (pclose(pp->f) != 0) - yasm__fatal( N_("Preprocessor exited with failure") ); -#endif - } - - cpp_destroy_args(pp); - - yasm_xfree(pp->filename); - yasm_xfree(pp); -} - -static char * -cpp_preproc_get_line(yasm_preproc *preproc) -{ - yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; - int bufsize = BSIZE; - char *buf, *p; - - if (! (pp->flags & CPP_HAS_BEEN_INVOKED) ) { - pp->flags |= CPP_HAS_BEEN_INVOKED; - - cpp_invoke(pp); - } - - /* - Once the preprocessor has been run, we're just dealing with a normal - file. - */ - - /* Loop to ensure entire line is read (don't want to limit line length). */ - buf = yasm_xmalloc((size_t)bufsize); - p = buf; - for (;;) { - if (!fgets(p, bufsize-(p-buf), pp->f)) { - if (ferror(pp->f)) { - yasm_error_set(YASM_ERROR_IO, - N_("error when reading from file")); - yasm_errwarn_propagate(pp->errwarns, - yasm_linemap_get_current(pp->cur_lm)); - } - break; - } - p += strlen(p); - if (p > buf && p[-1] == '\n') - break; - if ((p-buf) >= bufsize) { - /* Increase size of buffer */ - char *oldbuf = buf; - bufsize *= 2; - buf = yasm_xrealloc(buf, (size_t)bufsize); - p = buf + (p-oldbuf); - } - } - - if (p == buf) { - /* No data; must be at EOF */ - yasm_xfree(buf); - return NULL; - } - - /* Strip the line ending */ - buf[strcspn(buf, "\r\n")] = '\0'; - - return buf; -} - -static size_t -cpp_preproc_get_included_file(yasm_preproc *preproc, char *buf, - size_t max_size) -{ - char *p = buf; - int ch = '\0'; - size_t n = 0; - yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; - - if (! (pp->flags & CPP_HAS_GENERATED_DEPS) ) { - pp->flags |= CPP_HAS_GENERATED_DEPS; - - cpp_generate_deps(pp); - - /* Skip target name and first dependency. */ - while (ch != ':') - ch = fgetc(pp->f_deps); - - fgetc(pp->f_deps); /* Discard space after colon. */ - - while (ch != ' ' && ch != EOF) - ch = fgetc(pp->f_deps); - - if (ch == EOF) - return 0; - } - - while (n < max_size) { - ch = fgetc(pp->f_deps); - - if (ch == ' ' || ch == EOF) { - *p = '\0'; - return n; - } - - /* Eat any silly characters. */ - if (ch < ' ') - continue; - - *p++ = ch; - n++; - } - - /* Ensure the buffer is null-terminated. */ - *(p - 1) = '\0'; - return n; -} - -static void -cpp_preproc_add_include_file(yasm_preproc *preproc, const char *filename) -{ - yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; - - cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); - arg->op = "-include"; - arg->param = yasm__xstrdup(filename); - - TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); -} - -static void -cpp_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) -{ - yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; - - cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); - arg->op = "-D"; - arg->param = yasm__xstrdup(macronameval); - - TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); -} - -static void -cpp_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) -{ - yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; - - cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); - arg->op = "-U"; - arg->param = yasm__xstrdup(macroname); - - TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); -} - -static void -cpp_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) -{ - /* Handle a builtin as if it were a predefine. */ - cpp_preproc_predefine_macro(preproc, macronameval); -} - -static void -cpp_preproc_add_standard(yasm_preproc *preproc, const char **macros) -{ - /* TODO */ -} - -/******************************************************************************* - Preprocessor module object. -*******************************************************************************/ - -yasm_preproc_module yasm_cpp_LTX_preproc = { - "Run input through external C preprocessor", - "cpp", - cpp_preproc_create, - cpp_preproc_destroy, - cpp_preproc_get_line, - cpp_preproc_get_included_file, - cpp_preproc_add_include_file, - cpp_preproc_predefine_macro, - cpp_preproc_undefine_macro, - cpp_preproc_define_builtin, - cpp_preproc_add_standard -}; +/* + * Invoke an external C preprocessor + * + * Copyright (C) 2007 Paul Barker + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. + */ + +#include <util.h> +#include <libyasm.h> + +/* TODO: Use autoconf to get the limit on the command line length. */ +#define CMDLINE_SIZE 32770 + +#define BSIZE 512 + +/* Pre-declare the preprocessor module object. */ +yasm_preproc_module yasm_cpp_LTX_preproc; + +/******************************************************************************* + Structures. +*******************************************************************************/ + +/* An entry in a list of arguments to pass to cpp. */ +typedef struct cpp_arg_entry { + TAILQ_ENTRY(cpp_arg_entry) entry; + + /* + The operator (eg "-I") and the parameter (eg "include/"). op is expected + to point to a string literal, whereas param is expected to be a copy of + the parameter which is free'd when no-longer needed (in + cpp_preproc_destroy()). + */ + const char *op; + char *param; +} cpp_arg_entry; + +typedef struct yasm_preproc_cpp { + yasm_preproc_base preproc; /* base structure */ + + /* List of arguments to pass to cpp. */ + TAILQ_HEAD(cpp_arg_head, cpp_arg_entry) cpp_args; + + char *filename; + FILE *f, *f_deps; + yasm_linemap *cur_lm; + yasm_errwarns *errwarns; + + int flags; +} yasm_preproc_cpp; + +/* Flag values for yasm_preproc_cpp->flags. */ +#define CPP_HAS_BEEN_INVOKED 0x01 +#define CPP_HAS_GENERATED_DEPS 0x02 + +/******************************************************************************* + Internal functions and helpers. +*******************************************************************************/ + +/* + Append a string to the command line, ensuring that we don't overflow the + buffer. +*/ +#define APPEND(s) do { \ + size_t _len = strlen(s); \ + if (p + _len >= limit) \ + yasm__fatal(N_("command line too long!")); \ + strcpy(p, s); \ + p += _len; \ +} while (0) + +/* + Put all the options together into a command line that can be used to invoke + cpp. +*/ +static char * +cpp_build_cmdline(yasm_preproc_cpp *pp, const char *extra) +{ + char *cmdline, *p, *limit; + cpp_arg_entry *arg; + + /* Initialize command line. */ + cmdline = p = yasm_xmalloc(strlen(CPP_PROG)+CMDLINE_SIZE); + limit = p + CMDLINE_SIZE; + strcpy(p, CPP_PROG); + p += strlen(CPP_PROG); + + arg = TAILQ_FIRST(&pp->cpp_args); + + /* Append arguments from the list. */ + while ( arg ) { + APPEND(" "); + APPEND(arg->op); + APPEND(" "); + APPEND(arg->param); + + arg = TAILQ_NEXT(arg, entry); + } + + /* Append extra arguments. */ + if (extra) { + APPEND(" "); + APPEND(extra); + } + /* Append final arguments. */ + APPEND(" -x assembler-with-cpp "); + APPEND(pp->filename); + + return cmdline; +} + +/* Invoke the c preprocessor. */ +static void +cpp_invoke(yasm_preproc_cpp *pp) +{ + char *cmdline; + + cmdline = cpp_build_cmdline(pp, NULL); + +#ifdef HAVE_POPEN + pp->f = popen(cmdline, "r"); + if (!pp->f) + yasm__fatal( N_("Failed to execute preprocessor") ); +#else + yasm__fatal( N_("Cannot execute preprocessor, no popen available") ); +#endif + + yasm_xfree(cmdline); +} + +/* Free memory used by the list of arguments. */ +static void +cpp_destroy_args(yasm_preproc_cpp *pp) +{ + cpp_arg_entry *arg; + + while ( (arg = TAILQ_FIRST(&pp->cpp_args)) ) { + TAILQ_REMOVE(&pp->cpp_args, arg, entry); + yasm_xfree(arg->param); + yasm_xfree(arg); + } +} + +/* Invoke the c preprocessor to generate dependency info. */ +static void +cpp_generate_deps(yasm_preproc_cpp *pp) +{ + char *cmdline; + + cmdline = cpp_build_cmdline(pp, "-M"); + +#ifdef HAVE_POPEN + pp->f_deps = popen(cmdline, "r"); + if (!pp->f_deps) + yasm__fatal( N_("Failed to execute preprocessor") ); +#else + yasm__fatal( N_("Cannot execute preprocessor, no popen available") ); +#endif + + yasm_xfree(cmdline); +} + +/******************************************************************************* + Interface functions. +*******************************************************************************/ +static yasm_preproc * +cpp_preproc_create(const char *in, yasm_symtab *symtab, yasm_linemap *lm, + yasm_errwarns *errwarns) +{ + yasm_preproc_cpp *pp = yasm_xmalloc(sizeof(yasm_preproc_cpp)); + void * iter; + const char * inc_dir; + + pp->preproc.module = &yasm_cpp_LTX_preproc; + pp->f = pp->f_deps = NULL; + pp->cur_lm = lm; + pp->errwarns = errwarns; + pp->flags = 0; + pp->filename = yasm__xstrdup(in); + + TAILQ_INIT(&pp->cpp_args); + + /* Iterate through the list of include dirs. */ + iter = NULL; + while ((inc_dir = yasm_get_include_dir(&iter)) != NULL) { + cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); + arg->op = "-I"; + arg->param = yasm__xstrdup(inc_dir); + + TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); + } + + return (yasm_preproc *)pp; +} + +static void +cpp_preproc_destroy(yasm_preproc *preproc) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + if (pp->f) { +#ifdef HAVE_POPEN + if (pclose(pp->f) != 0) + yasm__fatal( N_("Preprocessor exited with failure") ); +#endif + } + + cpp_destroy_args(pp); + + yasm_xfree(pp->filename); + yasm_xfree(pp); +} + +static char * +cpp_preproc_get_line(yasm_preproc *preproc) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + int bufsize = BSIZE; + char *buf, *p; + + if (! (pp->flags & CPP_HAS_BEEN_INVOKED) ) { + pp->flags |= CPP_HAS_BEEN_INVOKED; + + cpp_invoke(pp); + } + + /* + Once the preprocessor has been run, we're just dealing with a normal + file. + */ + + /* Loop to ensure entire line is read (don't want to limit line length). */ + buf = yasm_xmalloc((size_t)bufsize); + p = buf; + for (;;) { + if (!fgets(p, bufsize-(p-buf), pp->f)) { + if (ferror(pp->f)) { + yasm_error_set(YASM_ERROR_IO, + N_("error when reading from file")); + yasm_errwarn_propagate(pp->errwarns, + yasm_linemap_get_current(pp->cur_lm)); + } + break; + } + p += strlen(p); + if (p > buf && p[-1] == '\n') + break; + if ((p-buf) >= bufsize) { + /* Increase size of buffer */ + char *oldbuf = buf; + bufsize *= 2; + buf = yasm_xrealloc(buf, (size_t)bufsize); + p = buf + (p-oldbuf); + } + } + + if (p == buf) { + /* No data; must be at EOF */ + yasm_xfree(buf); + return NULL; + } + + /* Strip the line ending */ + buf[strcspn(buf, "\r\n")] = '\0'; + + return buf; +} + +static size_t +cpp_preproc_get_included_file(yasm_preproc *preproc, char *buf, + size_t max_size) +{ + char *p = buf; + int ch = '\0'; + size_t n = 0; + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + if (! (pp->flags & CPP_HAS_GENERATED_DEPS) ) { + pp->flags |= CPP_HAS_GENERATED_DEPS; + + cpp_generate_deps(pp); + + /* Skip target name and first dependency. */ + while (ch != ':') + ch = fgetc(pp->f_deps); + + fgetc(pp->f_deps); /* Discard space after colon. */ + + while (ch != ' ' && ch != EOF) + ch = fgetc(pp->f_deps); + + if (ch == EOF) + return 0; + } + + while (n < max_size) { + ch = fgetc(pp->f_deps); + + if (ch == ' ' || ch == EOF) { + *p = '\0'; + return n; + } + + /* Eat any silly characters. */ + if (ch < ' ') + continue; + + *p++ = ch; + n++; + } + + /* Ensure the buffer is null-terminated. */ + *(p - 1) = '\0'; + return n; +} + +static void +cpp_preproc_add_include_file(yasm_preproc *preproc, const char *filename) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); + arg->op = "-include"; + arg->param = yasm__xstrdup(filename); + + TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); +} + +static void +cpp_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); + arg->op = "-D"; + arg->param = yasm__xstrdup(macronameval); + + TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); +} + +static void +cpp_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) +{ + yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc; + + cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry)); + arg->op = "-U"; + arg->param = yasm__xstrdup(macroname); + + TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry); +} + +static void +cpp_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) +{ + /* Handle a builtin as if it were a predefine. */ + cpp_preproc_predefine_macro(preproc, macronameval); +} + +static void +cpp_preproc_add_standard(yasm_preproc *preproc, const char **macros) +{ + /* TODO */ +} + +/******************************************************************************* + Preprocessor module object. +*******************************************************************************/ + +yasm_preproc_module yasm_cpp_LTX_preproc = { + "Run input through external C preprocessor", + "cpp", + cpp_preproc_create, + cpp_preproc_destroy, + cpp_preproc_get_line, + cpp_preproc_get_included_file, + cpp_preproc_add_include_file, + cpp_preproc_predefine_macro, + cpp_preproc_undefine_macro, + cpp_preproc_define_builtin, + cpp_preproc_add_standard +}; diff --git a/contrib/tools/yasm/modules/preprocs/gas/gas-eval.c b/contrib/tools/yasm/modules/preprocs/gas/gas-eval.c index 1f274c52e8..3625c7a9be 100644 --- a/contrib/tools/yasm/modules/preprocs/gas/gas-eval.c +++ b/contrib/tools/yasm/modules/preprocs/gas/gas-eval.c @@ -1,444 +1,444 @@ -/* eval.c expression evaluator for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * initial version 27/iii/95 by Simon Tatham - */ -#include <util.h> -#include <libyasm-stdint.h> -#include <libyasm/coretype.h> -#include <libyasm/intnum.h> -#include <libyasm/expr.h> -#include <libyasm/symrec.h> -#include <ctype.h> - -#include "gas-eval.h" - -/* The assembler symbol table. */ -static yasm_symtab *symtab; - -static scanner scan; /* Address of scanner routine */ -static efunc error; /* Address of error reporting routine */ - -static struct tokenval *tokval; /* The current token */ -static int i; /* The t_type of tokval */ - -static void *scpriv; -static void *epriv; - -/* - * Recursive-descent parser. Called with a single boolean operand, - * which is TRUE if the evaluation is critical (i.e. unresolved - * symbols are an error condition). Must update the global `i' to - * reflect the token after the parsed string. May return NULL. - * - * evaluate() should report its own errors: on return it is assumed - * that if NULL has been returned, the error has already been - * reported. - */ - -/* - * Grammar parsed is: - * - * expr : bexpr [ WRT expr6 ] - * bexpr : rexp0 or expr0 depending on relative-mode setting - * rexp0 : rexp1 [ {||} rexp1...] - * rexp1 : rexp2 [ {^^} rexp2...] - * rexp2 : rexp3 [ {&&} rexp3...] - * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ] - * expr0 : expr1 [ {|} expr1...] - * expr1 : expr2 [ {^} expr2...] - * expr2 : expr3 [ {&} expr3...] - * expr3 : expr4 [ {<<,>>} expr4...] - * expr4 : expr5 [ {+,-} expr5...] - * expr5 : expr6 [ {*,/,%,//,%%} expr6...] - * expr6 : { ~,+,-,SEG } expr6 - * | (bexpr) - * | symbol - * | $ - * | number - */ - -static yasm_expr *rexp0(void), *rexp1(void), *rexp2(void), *rexp3(void); - -static yasm_expr *expr0(void), *expr1(void), *expr2(void), *expr3(void); -static yasm_expr *expr4(void), *expr5(void), *expr6(void); - -static yasm_expr *(*bexpr)(void); - -static yasm_expr *rexp0(void) -{ - yasm_expr *e, *f; - - e = rexp1(); - if (!e) - return NULL; - - while (i == TOKEN_DBL_OR) - { - i = scan(scpriv, tokval); - f = rexp1(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_LOR, f, 0); +/* eval.c expression evaluator for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 27/iii/95 by Simon Tatham + */ +#include <util.h> +#include <libyasm-stdint.h> +#include <libyasm/coretype.h> +#include <libyasm/intnum.h> +#include <libyasm/expr.h> +#include <libyasm/symrec.h> +#include <ctype.h> + +#include "gas-eval.h" + +/* The assembler symbol table. */ +static yasm_symtab *symtab; + +static scanner scan; /* Address of scanner routine */ +static efunc error; /* Address of error reporting routine */ + +static struct tokenval *tokval; /* The current token */ +static int i; /* The t_type of tokval */ + +static void *scpriv; +static void *epriv; + +/* + * Recursive-descent parser. Called with a single boolean operand, + * which is TRUE if the evaluation is critical (i.e. unresolved + * symbols are an error condition). Must update the global `i' to + * reflect the token after the parsed string. May return NULL. + * + * evaluate() should report its own errors: on return it is assumed + * that if NULL has been returned, the error has already been + * reported. + */ + +/* + * Grammar parsed is: + * + * expr : bexpr [ WRT expr6 ] + * bexpr : rexp0 or expr0 depending on relative-mode setting + * rexp0 : rexp1 [ {||} rexp1...] + * rexp1 : rexp2 [ {^^} rexp2...] + * rexp2 : rexp3 [ {&&} rexp3...] + * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ] + * expr0 : expr1 [ {|} expr1...] + * expr1 : expr2 [ {^} expr2...] + * expr2 : expr3 [ {&} expr3...] + * expr3 : expr4 [ {<<,>>} expr4...] + * expr4 : expr5 [ {+,-} expr5...] + * expr5 : expr6 [ {*,/,%,//,%%} expr6...] + * expr6 : { ~,+,-,SEG } expr6 + * | (bexpr) + * | symbol + * | $ + * | number + */ + +static yasm_expr *rexp0(void), *rexp1(void), *rexp2(void), *rexp3(void); + +static yasm_expr *expr0(void), *expr1(void), *expr2(void), *expr3(void); +static yasm_expr *expr4(void), *expr5(void), *expr6(void); + +static yasm_expr *(*bexpr)(void); + +static yasm_expr *rexp0(void) +{ + yasm_expr *e, *f; + + e = rexp1(); + if (!e) + return NULL; + + while (i == TOKEN_DBL_OR) + { + i = scan(scpriv, tokval); + f = rexp1(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LOR, f, 0); + } + return e; +} + +static yasm_expr *rexp1(void) +{ + yasm_expr *e, *f; + + e = rexp2(); + if (!e) + return NULL; + + while (i == TOKEN_DBL_XOR) + { + i = scan(scpriv, tokval); + f = rexp2(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LXOR, f, 0); + } + return e; +} + +static yasm_expr *rexp2(void) +{ + yasm_expr *e, *f; + + e = rexp3(); + if (!e) + return NULL; + while (i == TOKEN_DBL_AND) + { + i = scan(scpriv, tokval); + f = rexp3(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LAND, f, 0); + } + return e; +} + +static yasm_expr *rexp3(void) +{ + yasm_expr *e, *f; + + e = expr0(); + if (!e) + return NULL; + + while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || + i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) + { + int j = i; + i = scan(scpriv, tokval); + f = expr0(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (j) + { + case TOKEN_EQ: + e = yasm_expr_create_tree(e, YASM_EXPR_EQ, f, 0); + break; + case TOKEN_LT: + e = yasm_expr_create_tree(e, YASM_EXPR_LT, f, 0); + break; + case TOKEN_GT: + e = yasm_expr_create_tree(e, YASM_EXPR_GT, f, 0); + break; + case TOKEN_NE: + e = yasm_expr_create_tree(e, YASM_EXPR_NE, f, 0); + break; + case TOKEN_LE: + e = yasm_expr_create_tree(e, YASM_EXPR_LE, f, 0); + break; + case TOKEN_GE: + e = yasm_expr_create_tree(e, YASM_EXPR_GE, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr0(void) +{ + yasm_expr *e, *f; + + e = expr1(); + if (!e) + return NULL; + + while (i == '|') + { + i = scan(scpriv, tokval); + f = expr1(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_OR, f, 0); + } + return e; +} + +static yasm_expr *expr1(void) +{ + yasm_expr *e, *f; + + e = expr2(); + if (!e) + return NULL; + + while (i == '^') { + i = scan(scpriv, tokval); + f = expr2(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_XOR, f, 0); + } + return e; +} + +static yasm_expr *expr2(void) +{ + yasm_expr *e, *f; + + e = expr3(); + if (!e) + return NULL; + + while (i == '&') { + i = scan(scpriv, tokval); + f = expr3(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_AND, f, 0); + } + return e; +} + +static yasm_expr *expr3(void) +{ + yasm_expr *e, *f; + + e = expr4(); + if (!e) + return NULL; + + while (i == TOKEN_SHL || i == TOKEN_SHR) + { + int j = i; + i = scan(scpriv, tokval); + f = expr4(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (j) { + case TOKEN_SHL: + e = yasm_expr_create_tree(e, YASM_EXPR_SHL, f, 0); + break; + case TOKEN_SHR: + e = yasm_expr_create_tree(e, YASM_EXPR_SHR, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr4(void) +{ + yasm_expr *e, *f; + + e = expr5(); + if (!e) + return NULL; + while (i == '+' || i == '-') + { + int j = i; + i = scan(scpriv, tokval); + f = expr5(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + switch (j) { + case '+': + e = yasm_expr_create_tree(e, YASM_EXPR_ADD, f, 0); + break; + case '-': + e = yasm_expr_create_tree(e, YASM_EXPR_SUB, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr5(void) +{ + yasm_expr *e, *f; + + e = expr6(); + if (!e) + return NULL; + while (i == '*' || i == '/' || i == '%' || + i == TOKEN_SDIV || i == TOKEN_SMOD) + { + int j = i; + i = scan(scpriv, tokval); + f = expr6(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + switch (j) { + case '*': + e = yasm_expr_create_tree(e, YASM_EXPR_MUL, f, 0); + break; + case '/': + e = yasm_expr_create_tree(e, YASM_EXPR_DIV, f, 0); + break; + case '%': + e = yasm_expr_create_tree(e, YASM_EXPR_MOD, f, 0); + break; + case TOKEN_SDIV: + e = yasm_expr_create_tree(e, YASM_EXPR_SIGNDIV, f, 0); + break; + case TOKEN_SMOD: + e = yasm_expr_create_tree(e, YASM_EXPR_SIGNMOD, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr6(void) +{ + yasm_expr *e = NULL; + + if (i == '-') { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + return yasm_expr_create_branch(YASM_EXPR_NEG, e, 0); + } else if (i == '+') { + i = scan(scpriv, tokval); + return expr6(); + } else if (i == '~') { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + return yasm_expr_create_branch(YASM_EXPR_NOT, e, 0); + } else if (i == TOKEN_SEG) { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + error(epriv, ERR_NONFATAL, "%s not supported", "SEG"); + return e; + } else if (i == '(') { + i = scan(scpriv, tokval); + e = bexpr(); + if (!e) + return NULL; + if (i != ')') { + error(epriv, ERR_NONFATAL, "expecting `)'"); + return NULL; + } + i = scan(scpriv, tokval); + return e; } - return e; -} - -static yasm_expr *rexp1(void) -{ - yasm_expr *e, *f; - - e = rexp2(); - if (!e) - return NULL; - - while (i == TOKEN_DBL_XOR) - { - i = scan(scpriv, tokval); - f = rexp2(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_LXOR, f, 0); - } - return e; -} - -static yasm_expr *rexp2(void) -{ - yasm_expr *e, *f; - - e = rexp3(); - if (!e) - return NULL; - while (i == TOKEN_DBL_AND) - { - i = scan(scpriv, tokval); - f = rexp3(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_LAND, f, 0); - } - return e; -} - -static yasm_expr *rexp3(void) -{ - yasm_expr *e, *f; - - e = expr0(); - if (!e) - return NULL; - - while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || - i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) - { - int j = i; - i = scan(scpriv, tokval); - f = expr0(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - switch (j) - { - case TOKEN_EQ: - e = yasm_expr_create_tree(e, YASM_EXPR_EQ, f, 0); - break; - case TOKEN_LT: - e = yasm_expr_create_tree(e, YASM_EXPR_LT, f, 0); - break; - case TOKEN_GT: - e = yasm_expr_create_tree(e, YASM_EXPR_GT, f, 0); - break; - case TOKEN_NE: - e = yasm_expr_create_tree(e, YASM_EXPR_NE, f, 0); - break; - case TOKEN_LE: - e = yasm_expr_create_tree(e, YASM_EXPR_LE, f, 0); - break; - case TOKEN_GE: - e = yasm_expr_create_tree(e, YASM_EXPR_GE, f, 0); - break; - } - } - return e; -} - -static yasm_expr *expr0(void) -{ - yasm_expr *e, *f; - - e = expr1(); - if (!e) - return NULL; - - while (i == '|') - { - i = scan(scpriv, tokval); - f = expr1(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_OR, f, 0); - } - return e; -} - -static yasm_expr *expr1(void) -{ - yasm_expr *e, *f; - - e = expr2(); - if (!e) - return NULL; - - while (i == '^') { - i = scan(scpriv, tokval); - f = expr2(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_XOR, f, 0); - } - return e; -} - -static yasm_expr *expr2(void) -{ - yasm_expr *e, *f; - - e = expr3(); - if (!e) - return NULL; - - while (i == '&') { - i = scan(scpriv, tokval); - f = expr3(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_AND, f, 0); - } - return e; -} - -static yasm_expr *expr3(void) -{ - yasm_expr *e, *f; - - e = expr4(); - if (!e) - return NULL; - - while (i == TOKEN_SHL || i == TOKEN_SHR) - { - int j = i; - i = scan(scpriv, tokval); - f = expr4(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - switch (j) { - case TOKEN_SHL: - e = yasm_expr_create_tree(e, YASM_EXPR_SHL, f, 0); - break; - case TOKEN_SHR: - e = yasm_expr_create_tree(e, YASM_EXPR_SHR, f, 0); - break; - } - } - return e; -} - -static yasm_expr *expr4(void) -{ - yasm_expr *e, *f; - - e = expr5(); - if (!e) - return NULL; - while (i == '+' || i == '-') - { - int j = i; - i = scan(scpriv, tokval); - f = expr5(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - switch (j) { - case '+': - e = yasm_expr_create_tree(e, YASM_EXPR_ADD, f, 0); - break; - case '-': - e = yasm_expr_create_tree(e, YASM_EXPR_SUB, f, 0); - break; - } - } - return e; -} - -static yasm_expr *expr5(void) -{ - yasm_expr *e, *f; - - e = expr6(); - if (!e) - return NULL; - while (i == '*' || i == '/' || i == '%' || - i == TOKEN_SDIV || i == TOKEN_SMOD) - { - int j = i; - i = scan(scpriv, tokval); - f = expr6(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - switch (j) { - case '*': - e = yasm_expr_create_tree(e, YASM_EXPR_MUL, f, 0); - break; - case '/': - e = yasm_expr_create_tree(e, YASM_EXPR_DIV, f, 0); - break; - case '%': - e = yasm_expr_create_tree(e, YASM_EXPR_MOD, f, 0); - break; - case TOKEN_SDIV: - e = yasm_expr_create_tree(e, YASM_EXPR_SIGNDIV, f, 0); - break; - case TOKEN_SMOD: - e = yasm_expr_create_tree(e, YASM_EXPR_SIGNMOD, f, 0); - break; - } - } - return e; -} - -static yasm_expr *expr6(void) -{ - yasm_expr *e = NULL; - - if (i == '-') { - i = scan(scpriv, tokval); - e = expr6(); - if (!e) - return NULL; - return yasm_expr_create_branch(YASM_EXPR_NEG, e, 0); - } else if (i == '+') { - i = scan(scpriv, tokval); - return expr6(); - } else if (i == '~') { - i = scan(scpriv, tokval); - e = expr6(); - if (!e) - return NULL; - return yasm_expr_create_branch(YASM_EXPR_NOT, e, 0); - } else if (i == TOKEN_SEG) { - i = scan(scpriv, tokval); - e = expr6(); - if (!e) - return NULL; - error(epriv, ERR_NONFATAL, "%s not supported", "SEG"); - return e; - } else if (i == '(') { - i = scan(scpriv, tokval); - e = bexpr(); - if (!e) - return NULL; - if (i != ')') { - error(epriv, ERR_NONFATAL, "expecting `)'"); - return NULL; - } - i = scan(scpriv, tokval); - return e; - } - else if (i == TOKEN_NUM || i == TOKEN_ID || - i == TOKEN_HERE || i == TOKEN_BASE) - { - switch (i) { - case TOKEN_NUM: - e = yasm_expr_create_ident(yasm_expr_int(tokval->t_integer), 0); - tokval->t_integer = NULL; - break; - case TOKEN_ID: - if (symtab) { - yasm_symrec *sym = - yasm_symtab_get(symtab, tokval->t_charptr); - if (sym) { - e = yasm_expr_create_ident(yasm_expr_sym(sym), 0); - } else { - error(epriv, ERR_NONFATAL, - "undefined symbol `%s' in preprocessor", - tokval->t_charptr); - e = yasm_expr_create_ident(yasm_expr_int( - yasm_intnum_create_int(1)), 0); - } - break; - } - /*fallthrough*/ - case TOKEN_HERE: - case TOKEN_BASE: - error(epriv, ERR_NONFATAL, - "cannot reference symbol `%s' in preprocessor", - (i == TOKEN_ID ? tokval->t_charptr : - i == TOKEN_HERE ? "$" : "$$")); - e = yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_int(1)), - 0); - break; - } - i = scan(scpriv, tokval); - return e; - } else { - error(epriv, ERR_NONFATAL, "expression syntax error"); - return NULL; - } -} - -yasm_expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, - void *eprivate, int critical, efunc report_error, - yasm_symtab *st) -{ - if (critical & CRITICAL) { - critical &= ~CRITICAL; - bexpr = rexp0; - } else - bexpr = expr0; - - scan = sc; - scpriv = scprivate; - tokval = tv; - error = report_error; - epriv = eprivate; - symtab = st; - - if (tokval->t_type == TOKEN_INVALID) - i = scan(scpriv, tokval); - else - i = tokval->t_type; - - return bexpr (); -} + else if (i == TOKEN_NUM || i == TOKEN_ID || + i == TOKEN_HERE || i == TOKEN_BASE) + { + switch (i) { + case TOKEN_NUM: + e = yasm_expr_create_ident(yasm_expr_int(tokval->t_integer), 0); + tokval->t_integer = NULL; + break; + case TOKEN_ID: + if (symtab) { + yasm_symrec *sym = + yasm_symtab_get(symtab, tokval->t_charptr); + if (sym) { + e = yasm_expr_create_ident(yasm_expr_sym(sym), 0); + } else { + error(epriv, ERR_NONFATAL, + "undefined symbol `%s' in preprocessor", + tokval->t_charptr); + e = yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_int(1)), 0); + } + break; + } + /*fallthrough*/ + case TOKEN_HERE: + case TOKEN_BASE: + error(epriv, ERR_NONFATAL, + "cannot reference symbol `%s' in preprocessor", + (i == TOKEN_ID ? tokval->t_charptr : + i == TOKEN_HERE ? "$" : "$$")); + e = yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_int(1)), + 0); + break; + } + i = scan(scpriv, tokval); + return e; + } else { + error(epriv, ERR_NONFATAL, "expression syntax error"); + return NULL; + } +} + +yasm_expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, + void *eprivate, int critical, efunc report_error, + yasm_symtab *st) +{ + if (critical & CRITICAL) { + critical &= ~CRITICAL; + bexpr = rexp0; + } else + bexpr = expr0; + + scan = sc; + scpriv = scprivate; + tokval = tv; + error = report_error; + epriv = eprivate; + symtab = st; + + if (tokval->t_type == TOKEN_INVALID) + i = scan(scpriv, tokval); + else + i = tokval->t_type; + + return bexpr (); +} diff --git a/contrib/tools/yasm/modules/preprocs/gas/gas-eval.h b/contrib/tools/yasm/modules/preprocs/gas/gas-eval.h index 10b2d0c7cc..18dcc517a9 100644 --- a/contrib/tools/yasm/modules/preprocs/gas/gas-eval.h +++ b/contrib/tools/yasm/modules/preprocs/gas/gas-eval.h @@ -1,120 +1,120 @@ -/* eval.h header file for eval.c - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#ifndef YASM_EVAL_H -#define YASM_EVAL_H - -/* - * ------------------------- - * Error reporting functions - * ------------------------- - */ - -/* - * An error reporting function should look like this. - */ -typedef void (*efunc) (void *private_data, int severity, const char *fmt, ...); - -/* - * These are the error severity codes which get passed as the first - * argument to an efunc. - */ - -#define ERR_DEBUG 0x00000008 /* put out debugging message */ -#define ERR_WARNING 0x00000000 /* warn only: no further action */ -#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ -#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ -#define ERR_PANIC 0x00000003 /* internal error: panic instantly - * and dump core for reference */ -#define ERR_MASK 0x0000000F /* mask off the above codes */ -#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ -#define ERR_USAGE 0x00000020 /* print a usage message */ -#define ERR_PASS1 0x00000040 /* only print this error on pass one */ - -/* - * These codes define specific types of suppressible warning. - */ - -#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ -#define ERR_WARN_SHR 8 /* how far to shift right */ - -#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ -#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ -#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and - * alone on line) */ -#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ -#define ERR_WARN_GNUELF 0x00000500 /* using GNU ELF extensions */ -#define ERR_WARN_MAX 5 /* the highest numbered one */ - -/* - * The expression evaluator must be passed a scanner function; a - * standard scanner is provided as part of nasmlib.c. The - * preprocessor will use a different one. Scanners, and the - * token-value structures they return, look like this. - * - * The return value from the scanner is always a copy of the - * `t_type' field in the structure. - */ -struct tokenval { - int t_type; - yasm_intnum *t_integer, *t_inttwo; - char *t_charptr; -}; -typedef int (*scanner) (void *private_data, struct tokenval *tv); - -/* - * Token types returned by the scanner, in addition to ordinary - * ASCII character values, and zero for end-of-string. - */ -enum { /* token types, other than chars */ - TOKEN_INVALID = -1, /* a placeholder value */ - TOKEN_EOS = 0, /* end of string */ - TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */ - TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */ - TOKEN_ERRNUM, /* numeric constant with error in */ - TOKEN_HERE, TOKEN_BASE, /* $ and $$ */ - TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */ - TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ - TOKEN_SHL, TOKEN_SHR, /* << and >> */ - TOKEN_SDIV, TOKEN_SMOD, /* // and %% */ - TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */ - TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */ - TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */ - TOKEN_FLOAT /* floating-point constant */ -}; - -/* - * The actual expression evaluator function looks like this. When - * called, it expects the first token of its expression to already - * be in `*tv'; if it is not, set tv->t_type to TOKEN_INVALID and - * it will start by calling the scanner. - * - * `critical' is non-zero if the expression may not contain forward - * references. The evaluator will report its own error if this - * occurs; if `critical' is 1, the error will be "symbol not - * defined before use", whereas if `critical' is 2, the error will - * be "symbol undefined". - * - * If `critical' has bit 8 set (in addition to its main value: 0x101 - * and 0x102 correspond to 1 and 2) then an extended expression - * syntax is recognised, in which relational operators such as =, < - * and >= are accepted, as well as low-precedence logical operators - * &&, ^^ and ||. - */ -#define CRITICAL 0x100 -typedef yasm_expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, - int critical, efunc error, yasm_symtab *symtab); - -/* - * The evaluator itself. - */ -yasm_expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, - void *eprivate, int critical, efunc report_error, - yasm_symtab *symtab); - -#endif +/* eval.h header file for eval.c + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef YASM_EVAL_H +#define YASM_EVAL_H + +/* + * ------------------------- + * Error reporting functions + * ------------------------- + */ + +/* + * An error reporting function should look like this. + */ +typedef void (*efunc) (void *private_data, int severity, const char *fmt, ...); + +/* + * These are the error severity codes which get passed as the first + * argument to an efunc. + */ + +#define ERR_DEBUG 0x00000008 /* put out debugging message */ +#define ERR_WARNING 0x00000000 /* warn only: no further action */ +#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ +#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ +#define ERR_PANIC 0x00000003 /* internal error: panic instantly + * and dump core for reference */ +#define ERR_MASK 0x0000000F /* mask off the above codes */ +#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ +#define ERR_USAGE 0x00000020 /* print a usage message */ +#define ERR_PASS1 0x00000040 /* only print this error on pass one */ + +/* + * These codes define specific types of suppressible warning. + */ + +#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ +#define ERR_WARN_SHR 8 /* how far to shift right */ + +#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ +#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ +#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and + * alone on line) */ +#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ +#define ERR_WARN_GNUELF 0x00000500 /* using GNU ELF extensions */ +#define ERR_WARN_MAX 5 /* the highest numbered one */ + +/* + * The expression evaluator must be passed a scanner function; a + * standard scanner is provided as part of nasmlib.c. The + * preprocessor will use a different one. Scanners, and the + * token-value structures they return, look like this. + * + * The return value from the scanner is always a copy of the + * `t_type' field in the structure. + */ +struct tokenval { + int t_type; + yasm_intnum *t_integer, *t_inttwo; + char *t_charptr; +}; +typedef int (*scanner) (void *private_data, struct tokenval *tv); + +/* + * Token types returned by the scanner, in addition to ordinary + * ASCII character values, and zero for end-of-string. + */ +enum { /* token types, other than chars */ + TOKEN_INVALID = -1, /* a placeholder value */ + TOKEN_EOS = 0, /* end of string */ + TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */ + TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */ + TOKEN_ERRNUM, /* numeric constant with error in */ + TOKEN_HERE, TOKEN_BASE, /* $ and $$ */ + TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */ + TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ + TOKEN_SHL, TOKEN_SHR, /* << and >> */ + TOKEN_SDIV, TOKEN_SMOD, /* // and %% */ + TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */ + TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */ + TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */ + TOKEN_FLOAT /* floating-point constant */ +}; + +/* + * The actual expression evaluator function looks like this. When + * called, it expects the first token of its expression to already + * be in `*tv'; if it is not, set tv->t_type to TOKEN_INVALID and + * it will start by calling the scanner. + * + * `critical' is non-zero if the expression may not contain forward + * references. The evaluator will report its own error if this + * occurs; if `critical' is 1, the error will be "symbol not + * defined before use", whereas if `critical' is 2, the error will + * be "symbol undefined". + * + * If `critical' has bit 8 set (in addition to its main value: 0x101 + * and 0x102 correspond to 1 and 2) then an extended expression + * syntax is recognised, in which relational operators such as =, < + * and >= are accepted, as well as low-precedence logical operators + * &&, ^^ and ||. + */ +#define CRITICAL 0x100 +typedef yasm_expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, + int critical, efunc error, yasm_symtab *symtab); + +/* + * The evaluator itself. + */ +yasm_expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, + void *eprivate, int critical, efunc report_error, + yasm_symtab *symtab); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/gas/gas-preproc.c b/contrib/tools/yasm/modules/preprocs/gas/gas-preproc.c index ecb24225fe..60c9e4f0cd 100644 --- a/contrib/tools/yasm/modules/preprocs/gas/gas-preproc.c +++ b/contrib/tools/yasm/modules/preprocs/gas/gas-preproc.c @@ -1,1409 +1,1409 @@ -/* - * GAS preprocessor (emulates GNU Assembler's preprocessor) - * - * Copyright (C) 2009 Alexei Svitkine - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. - */ -#include <util.h> -#include <ctype.h> - -#include <libyasm.h> -#include "modules/preprocs/gas/gas-eval.h" - -#define FALSE 0 -#define TRUE 1 -#define BSIZE 512 - -#ifndef MAXPATHLEN -#define MAXPATHLEN 1024 -#endif - -typedef struct buffered_line { - char *line; - int line_number; - SLIST_ENTRY(buffered_line) next; -} buffered_line; - -typedef struct included_file { - char *filename; - int lines_remaining; - SLIST_ENTRY(included_file) next; -} included_file; - -typedef struct macro_entry { - char *name; - int num_params; - char **params; - int num_lines; - char **lines; - STAILQ_ENTRY(macro_entry) next; -} macro_entry; - -typedef struct deferred_define { - char *name; - char *value; - SLIST_ENTRY(deferred_define) next; -} deferred_define; - -typedef struct expr_state { - const char *string; - char *symbol; - int string_cursor; -} expr_state; - -typedef struct yasm_preproc_gas { - yasm_preproc_base preproc; /* base structure */ - - FILE *in; - char *in_filename; - - yasm_symtab *defines; - SLIST_HEAD(deferred_defines_head, deferred_define) deferred_defines; - - int depth; - int skip_depth; - - int in_comment; - - expr_state expr; - - SLIST_HEAD(buffered_lines_head, buffered_line) buffered_lines; - SLIST_HEAD(included_files_head, included_file) included_files; - STAILQ_HEAD(macros_head, macro_entry) macros; - - int in_line_number; - int next_line_number; - int current_line_number; /* virtual (output) line number */ - - yasm_linemap *cur_lm; - yasm_errwarns *errwarns; - int fatal_error; - int detect_errors_only; -} yasm_preproc_gas; - -yasm_preproc_module yasm_gas_LTX_preproc; - -/* Forward declarations. */ - -static int substitute_values(yasm_preproc_gas *pp, char **line_ptr); - -/* String helpers. */ - -static const char *starts_with(const char *big, const char *little) -{ - while (*little) { - if (*little++ != *big++) { - return NULL; - } - } - return big; -} - -static void skip_whitespace(const char **line) -{ - while (isspace(**line)) { - (*line)++; - } -} - -static void skip_whitespace2(char **line) -{ - while (isspace(**line)) { - (*line)++; - } -} - -static const char *matches(const char *line, const char *directive) -{ - skip_whitespace(&line); - - if (*line == '.') { - line = starts_with(line + 1, directive); - if (line && (!*line || isspace(*line))) { - skip_whitespace(&line); - return line; - } - } - - return NULL; -} - -static int unquote(const char *arg, char *to, size_t to_size, char q, char expected, const char **remainder) -{ - const char *quote; - const char *end; - size_t len; - - skip_whitespace(&arg); - if (*arg != q) { - return -1; - } - - arg++; - - end = arg; - do { - quote = strchr(end, q); - if (!quote) { - return -2; - } - end = quote + 1; - } while (*(quote - 1) == '\\'); - - skip_whitespace(&end); - if (*end != expected) { - return -3; - } - - if (remainder) { - *remainder = end + 1; - } - - len = (size_t) (quote - arg); - if (len >= to_size) { - return -4; - } - - strncpy(to, arg, len); - to[len] = '\0'; - - return (int) len; -} - -/* Line-reading. */ - -static char *read_line_from_file(yasm_preproc_gas *pp, FILE *file) -{ - int bufsize = BSIZE; - char *buf; - char *p; - - buf = yasm_xmalloc((size_t)bufsize); - - /* Loop to ensure entire line is read (don't want to limit line length). */ - p = buf; - for (;;) { - if (!fgets(p, bufsize - (p - buf), file)) { - if (ferror(file)) { - yasm_error_set(YASM_ERROR_IO, N_("error when reading from file")); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); +/* + * GAS preprocessor (emulates GNU Assembler's preprocessor) + * + * Copyright (C) 2009 Alexei Svitkine + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. + */ +#include <util.h> +#include <ctype.h> + +#include <libyasm.h> +#include "modules/preprocs/gas/gas-eval.h" + +#define FALSE 0 +#define TRUE 1 +#define BSIZE 512 + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +typedef struct buffered_line { + char *line; + int line_number; + SLIST_ENTRY(buffered_line) next; +} buffered_line; + +typedef struct included_file { + char *filename; + int lines_remaining; + SLIST_ENTRY(included_file) next; +} included_file; + +typedef struct macro_entry { + char *name; + int num_params; + char **params; + int num_lines; + char **lines; + STAILQ_ENTRY(macro_entry) next; +} macro_entry; + +typedef struct deferred_define { + char *name; + char *value; + SLIST_ENTRY(deferred_define) next; +} deferred_define; + +typedef struct expr_state { + const char *string; + char *symbol; + int string_cursor; +} expr_state; + +typedef struct yasm_preproc_gas { + yasm_preproc_base preproc; /* base structure */ + + FILE *in; + char *in_filename; + + yasm_symtab *defines; + SLIST_HEAD(deferred_defines_head, deferred_define) deferred_defines; + + int depth; + int skip_depth; + + int in_comment; + + expr_state expr; + + SLIST_HEAD(buffered_lines_head, buffered_line) buffered_lines; + SLIST_HEAD(included_files_head, included_file) included_files; + STAILQ_HEAD(macros_head, macro_entry) macros; + + int in_line_number; + int next_line_number; + int current_line_number; /* virtual (output) line number */ + + yasm_linemap *cur_lm; + yasm_errwarns *errwarns; + int fatal_error; + int detect_errors_only; +} yasm_preproc_gas; + +yasm_preproc_module yasm_gas_LTX_preproc; + +/* Forward declarations. */ + +static int substitute_values(yasm_preproc_gas *pp, char **line_ptr); + +/* String helpers. */ + +static const char *starts_with(const char *big, const char *little) +{ + while (*little) { + if (*little++ != *big++) { + return NULL; + } + } + return big; +} + +static void skip_whitespace(const char **line) +{ + while (isspace(**line)) { + (*line)++; + } +} + +static void skip_whitespace2(char **line) +{ + while (isspace(**line)) { + (*line)++; + } +} + +static const char *matches(const char *line, const char *directive) +{ + skip_whitespace(&line); + + if (*line == '.') { + line = starts_with(line + 1, directive); + if (line && (!*line || isspace(*line))) { + skip_whitespace(&line); + return line; + } + } + + return NULL; +} + +static int unquote(const char *arg, char *to, size_t to_size, char q, char expected, const char **remainder) +{ + const char *quote; + const char *end; + size_t len; + + skip_whitespace(&arg); + if (*arg != q) { + return -1; + } + + arg++; + + end = arg; + do { + quote = strchr(end, q); + if (!quote) { + return -2; + } + end = quote + 1; + } while (*(quote - 1) == '\\'); + + skip_whitespace(&end); + if (*end != expected) { + return -3; + } + + if (remainder) { + *remainder = end + 1; + } + + len = (size_t) (quote - arg); + if (len >= to_size) { + return -4; + } + + strncpy(to, arg, len); + to[len] = '\0'; + + return (int) len; +} + +/* Line-reading. */ + +static char *read_line_from_file(yasm_preproc_gas *pp, FILE *file) +{ + int bufsize = BSIZE; + char *buf; + char *p; + + buf = yasm_xmalloc((size_t)bufsize); + + /* Loop to ensure entire line is read (don't want to limit line length). */ + p = buf; + for (;;) { + if (!fgets(p, bufsize - (p - buf), file)) { + if (ferror(file)) { + yasm_error_set(YASM_ERROR_IO, N_("error when reading from file")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + } + break; + } + p += strlen(p); + if (p > buf && p[-1] == '\n') { + break; + } + if ((p - buf) + 1 >= bufsize) { + /* Increase size of buffer */ + char *oldbuf = buf; + bufsize *= 2; + buf = yasm_xrealloc(buf, (size_t) bufsize); + p = buf + (p - oldbuf); + } + } + + if (p == buf) { + /* No data; must be at EOF */ + yasm_xfree(buf); + return NULL; + } + + /* Strip the line ending */ + buf[strcspn(buf, "\r\n")] = '\0'; + return buf; +} + +static char *read_line(yasm_preproc_gas *pp) +{ + char *line; + + if (!SLIST_EMPTY(&pp->included_files)) { + included_file *inc_file = SLIST_FIRST(&pp->included_files); + if (inc_file->lines_remaining <= 0) { + SLIST_REMOVE_HEAD(&pp->included_files, next); + yasm_xfree(inc_file->filename); + yasm_xfree(inc_file); + } + } + + if (!SLIST_EMPTY(&pp->buffered_lines)) { + buffered_line *bline = SLIST_FIRST(&pp->buffered_lines); + SLIST_REMOVE_HEAD(&pp->buffered_lines, next); + line = bline->line; + if (bline->line_number != -1) { + pp->next_line_number = bline->line_number; + } + yasm_xfree(bline); + if (!SLIST_EMPTY(&pp->included_files)) { + SLIST_FIRST(&pp->included_files)->lines_remaining--; + } + return line; + } + + line = read_line_from_file(pp, pp->in); + if (line) { + pp->in_line_number++; + pp->next_line_number = pp->in_line_number; + } + + return line; +} + +static const char *get_arg(yasm_preproc_gas *pp, const char *src, char *dest, size_t dest_size) +{ + const char *comma = strchr(src, ','); + if (comma) { + size_t len = (size_t) (comma - src); + if (len >= dest_size) { + len = dest_size - 1; + } + strncpy(dest, src, len); + dest[len] = '\0'; + comma++; + skip_whitespace(&comma); + } else { + yasm_error_set(YASM_ERROR_SYNTAX, N_("expected comma")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + } + return comma; +} + +/* GAS expression evaluation. */ + +static char get_char(yasm_preproc_gas *pp) +{ + return pp->expr.string[pp->expr.string_cursor]; +} + +static const char *get_str(yasm_preproc_gas *pp) +{ + return pp->expr.string + pp->expr.string_cursor; +} + +static void next_char(yasm_preproc_gas *pp) +{ + pp->expr.string_cursor++; +} + +static int ishex(char c) +{ + c = tolower(c); + return isdigit(c) || (c >= 'a' && c <= 'f'); +} + +static void gas_scan_init(yasm_preproc_gas *pp, struct tokenval *tokval, const char *arg1) +{ + pp->expr.symbol = NULL; + pp->expr.string = arg1; + pp->expr.string_cursor = 0; + memset(tokval, 0, sizeof(struct tokenval)); + tokval->t_type = TOKEN_INVALID; +} + +static void gas_scan_cleanup(yasm_preproc_gas *pp, struct tokenval *tokval) +{ + if (tokval->t_integer) { + yasm_intnum_destroy(tokval->t_integer); + tokval->t_integer = NULL; + } + if (pp->expr.symbol) { + yasm_xfree(pp->expr.symbol); + pp->expr.symbol = NULL; + } +} + +static int gas_scan(void *preproc, struct tokenval *tokval) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; + char c = get_char(pp); + const char *str; + + tokval->t_charptr = NULL; + + if (c == '\0') { + return tokval->t_type = TOKEN_EOS; + } + + if (isspace(c)) { + do { + next_char(pp); + c = get_char(pp); + } while (isspace(c)); + } + + if (isdigit(c)) { + int char_index = 0; + int value = 0; + + do { + value = value*10 + (c - '0'); + char_index++; + next_char(pp); + c = get_char(pp); + if (char_index == 1 && c == 'x' && value == 0) { + next_char(pp); + c = get_char(pp); + /* Hex notation. */ + while (ishex(c)) { + if (isdigit(c)) { + value = (value << 4) | (c - '0'); + } else { + value = (value << 4) | (tolower(c) - 'a' + 0xa); + } + next_char(pp); + c = get_char(pp); + } + break; + } + } while (isdigit(c)); + + if (tokval->t_integer) { + yasm_intnum_destroy(tokval->t_integer); + } + tokval->t_integer = yasm_intnum_create_int(value); + return tokval->t_type = TOKEN_NUM; + } + + tokval->t_type = TOKEN_INVALID; + str = get_str(pp); + + { + /* It should be tested whether GAS supports all of these or if there are missing ones. */ + unsigned i; + struct { + const char *op; + int token; + } ops[] = { + { "<<", TOKEN_SHL }, + { ">>", TOKEN_SHR }, + { "//", TOKEN_SDIV }, + { "%%", TOKEN_SMOD }, + { "==", TOKEN_EQ }, + { "!=", TOKEN_NE }, + { "<>", TOKEN_NE }, + { "<>", TOKEN_NE }, + { "<=", TOKEN_LE }, + { ">=", TOKEN_GE }, + { "&&", TOKEN_DBL_AND }, + { "^^", TOKEN_DBL_XOR }, + { "||", TOKEN_DBL_OR } + }; + for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) { + if (!strcmp(str, ops[i].op)) { + tokval->t_type = ops[i].token; + break; + } + } + } + + if (tokval->t_type != TOKEN_INVALID) { + next_char(pp); + next_char(pp); + } else { + str = get_str(pp); + + next_char(pp); + tokval->t_type = c; + + /* Is it a symbol? If so we need to make it a TOKEN_ID. */ + if (isalpha(c) || c == '_' || c == '.') { + int symbol_length = 1; + + c = get_char(pp); + while (isalnum(c) || c == '$' || c == '_') { + symbol_length++; + next_char(pp); + c = get_char(pp); + } + + pp->expr.symbol = yasm_xrealloc(pp->expr.symbol, symbol_length + 1); + memcpy(pp->expr.symbol, str, symbol_length); + pp->expr.symbol[symbol_length] = '\0'; + + tokval->t_type = TOKEN_ID; + tokval->t_charptr = pp->expr.symbol; + } + } + + return tokval->t_type; +} + +static void gas_err(void *private_data, int severity, const char *fmt, ...) +{ + va_list args; + yasm_preproc_gas *pp = private_data; + + if (!pp->detect_errors_only) { + va_start(args, fmt); + yasm_error_set_va(YASM_ERROR_SYNTAX, N_(fmt), args); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + va_end(args); + } + + pp->fatal_error = 1; +} + +static long eval_expr(yasm_preproc_gas *pp, const char *arg1) +{ + struct tokenval tv; + yasm_expr *expr; + yasm_intnum *intn; + long value; + expr_state prev_state; + + if (!*arg1) { + return 0; + } + + prev_state = pp->expr; + gas_scan_init(pp, &tv, arg1); + expr = evaluate(gas_scan, pp, &tv, pp, CRITICAL, gas_err, pp->defines); + intn = yasm_expr_get_intnum(&expr, 0); + value = yasm_intnum_get_int(intn); + yasm_expr_destroy(expr); + gas_scan_cleanup(pp, &tv); + pp->expr = prev_state; + + return value; +} + +/* If-directive helpers. */ + +static int handle_if(yasm_preproc_gas *pp, int is_true) +{ + assert(pp->depth >= 0); + assert(pp->skip_depth == 0); + if (is_true) { + pp->depth++; + } else { + pp->skip_depth = 1; + } + return 1; +} + +static int handle_endif(yasm_preproc_gas *pp) +{ + if (pp->depth) { + pp->depth--; + } else { + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endif\" without \".if\"")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + return 1; +} + +static int handle_else(yasm_preproc_gas *pp, int is_elseif) +{ + if (!pp->depth) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".%s\" without \".if\""), is_elseif ? "elseif" : "else"); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } else { + pp->skip_depth = 1; + } + return 1; +} + +/* Directive-handling functions. */ + +static int eval_if(yasm_preproc_gas *pp, int negate, const char *arg1) +{ + long value; + if (!*arg1) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("expression is required in \".if\" statement")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + value = eval_expr(pp, arg1); + handle_if(pp, (negate ? !value : !!value)); + return 1; +} + +static int eval_else(yasm_preproc_gas *pp, int unused) +{ + return handle_else(pp, 0); +} + +static int eval_endif(yasm_preproc_gas *pp, int unused) +{ + return handle_endif(pp); +} + +static int eval_elseif(yasm_preproc_gas *pp, int unused, const char *arg1) +{ + if (!*arg1) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("expression is required in \".elseif\" statement")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + if (!handle_else(pp, 1)) { + return 0; + } + return eval_if(pp, 0, arg1); +} + +static int eval_ifb(yasm_preproc_gas *pp, int negate, const char *arg1) +{ + int is_blank = !*arg1; + return handle_if(pp, (negate ? !is_blank : is_blank)); +} + +static int eval_ifc(yasm_preproc_gas *pp, int negate, const char *args) +{ + char arg1[512], arg2[512]; + const char *remainder; + int len = unquote(args, arg1, sizeof(arg1), '\'', ',', &remainder); + if (len >= 0) { + len = unquote(remainder, arg2, sizeof(arg2), '\'', '\0', NULL); + if (len >= 0) { + int result = !strcmp(arg1, arg2); + return handle_if(pp, (negate ? !result : result)); + } + } else { + /* first argument was not single-quoted, assume non-quoted mode */ + remainder = get_arg(pp, args, arg1, sizeof(arg1)); + if (remainder) { + int result = !strcmp(arg1, remainder); + return handle_if(pp, (negate ? !result : result)); + } + } + yasm_error_set(YASM_ERROR_SYNTAX, N_("\"%s\" expects two single-quoted or unquoted arguments"), negate ? ".ifnc" : ".ifc"); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; +} + +static int eval_ifeqs(yasm_preproc_gas *pp, int negate, const char *args) +{ + char arg1[512], arg2[512]; + const char *remainder; + int len = unquote(args, arg1, sizeof(arg1), '"', ',', &remainder); + if (len >= 0) { + len = unquote(remainder, arg2, sizeof(arg2), '"', '\0', NULL); + if (len >= 0) { + int result = !strcmp(arg1, arg2); + return handle_if(pp, (negate ? !result : result)); + } + } + yasm_error_set(YASM_ERROR_SYNTAX, N_("\"%s\" expects two double-quoted arguments"), negate ? ".ifnes" : ".ifeqs"); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 1; +} + +static int eval_ifdef(yasm_preproc_gas *pp, int negate, const char *name) +{ + yasm_symrec *rec = yasm_symtab_get(pp->defines, name); + int result = (rec != NULL); + return handle_if(pp, (negate ? !result : result)); +} + +static int eval_ifge(yasm_preproc_gas *pp, int negate, const char *arg1) +{ + long value = eval_expr(pp, arg1); + int result = (value >= 0); + return handle_if(pp, (negate ? !result : result)); +} + +static int eval_ifgt(yasm_preproc_gas *pp, int negate, const char *arg1) +{ + long value = eval_expr(pp, arg1); + int result = (value > 0); + return handle_if(pp, (negate ? !result : result)); +} + +static int eval_include(yasm_preproc_gas *pp, int unused, const char *arg1) +{ + char *current_filename; + char filename[MAXPATHLEN]; + char *line; + int num_lines; + FILE *file; + buffered_line *prev_bline; + included_file *inc_file; + + if (unquote(arg1, filename, sizeof(filename), '"', '\0', NULL) < 0) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("string expected")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + + if (SLIST_EMPTY(&pp->included_files)) { + current_filename = pp->in_filename; + } else { + current_filename = SLIST_FIRST(&pp->included_files)->filename; + } + file = yasm_fopen_include(filename, current_filename, "r", NULL); + if (!file) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("unable to open included file \"%s\""), filename); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + + num_lines = 0; + prev_bline = NULL; + line = read_line_from_file(pp, file); + while (line) { + buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); + bline->line = line; + bline->line_number = -1; + if (prev_bline) { + SLIST_INSERT_AFTER(prev_bline, bline, next); + } else { + SLIST_INSERT_HEAD(&pp->buffered_lines, bline, next); + } + prev_bline = bline; + line = read_line_from_file(pp, file); + num_lines++; + } + + inc_file = yasm_xmalloc(sizeof(included_file)); + inc_file->filename = yasm__xstrdup(filename); + inc_file->lines_remaining = num_lines; + SLIST_INSERT_HEAD(&pp->included_files, inc_file, next); + return 1; +} + +static int try_eval_expr(yasm_preproc_gas *pp, const char *value, long *result) +{ + int success; + + pp->detect_errors_only = 1; + *result = eval_expr(pp, value); + success = !pp->fatal_error; + pp->fatal_error = 0; + pp->detect_errors_only = 0; + + return success; +} + +static int remove_define(yasm_preproc_gas *pp, const char *name, int allow_redefine) +{ + yasm_symrec *rec = yasm_symtab_get(pp->defines, name); + if (rec) { + const yasm_symtab_iter *entry; + yasm_symtab *new_defines; + + if (!allow_redefine) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("symbol \"%s\" is already defined"), name); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; + } + + new_defines = yasm_symtab_create(); + + for (entry = yasm_symtab_first(pp->defines); entry; entry = yasm_symtab_next(entry)) { + yasm_symrec *entry_rec = yasm_symtab_iter_value(entry); + const char *rec_name = yasm_symrec_get_name(entry_rec); + if (strcmp(rec_name, name)) { + yasm_intnum *num = yasm_intnum_create_int(eval_expr(pp, rec_name)); + yasm_expr *expr = yasm_expr_create_ident(yasm_expr_int(num), 0); + yasm_symtab_define_equ(new_defines, rec_name, expr, 0); } - break; - } - p += strlen(p); - if (p > buf && p[-1] == '\n') { - break; - } - if ((p - buf) + 1 >= bufsize) { - /* Increase size of buffer */ - char *oldbuf = buf; - bufsize *= 2; - buf = yasm_xrealloc(buf, (size_t) bufsize); - p = buf + (p - oldbuf); - } - } - - if (p == buf) { - /* No data; must be at EOF */ - yasm_xfree(buf); - return NULL; - } - - /* Strip the line ending */ - buf[strcspn(buf, "\r\n")] = '\0'; - return buf; -} - -static char *read_line(yasm_preproc_gas *pp) -{ - char *line; - - if (!SLIST_EMPTY(&pp->included_files)) { - included_file *inc_file = SLIST_FIRST(&pp->included_files); - if (inc_file->lines_remaining <= 0) { - SLIST_REMOVE_HEAD(&pp->included_files, next); - yasm_xfree(inc_file->filename); - yasm_xfree(inc_file); - } - } - - if (!SLIST_EMPTY(&pp->buffered_lines)) { - buffered_line *bline = SLIST_FIRST(&pp->buffered_lines); - SLIST_REMOVE_HEAD(&pp->buffered_lines, next); - line = bline->line; - if (bline->line_number != -1) { - pp->next_line_number = bline->line_number; - } - yasm_xfree(bline); - if (!SLIST_EMPTY(&pp->included_files)) { - SLIST_FIRST(&pp->included_files)->lines_remaining--; - } - return line; - } - - line = read_line_from_file(pp, pp->in); - if (line) { - pp->in_line_number++; - pp->next_line_number = pp->in_line_number; - } - - return line; -} - -static const char *get_arg(yasm_preproc_gas *pp, const char *src, char *dest, size_t dest_size) -{ - const char *comma = strchr(src, ','); - if (comma) { - size_t len = (size_t) (comma - src); - if (len >= dest_size) { - len = dest_size - 1; - } - strncpy(dest, src, len); - dest[len] = '\0'; - comma++; - skip_whitespace(&comma); - } else { - yasm_error_set(YASM_ERROR_SYNTAX, N_("expected comma")); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - } - return comma; -} - -/* GAS expression evaluation. */ - -static char get_char(yasm_preproc_gas *pp) -{ - return pp->expr.string[pp->expr.string_cursor]; -} - -static const char *get_str(yasm_preproc_gas *pp) -{ - return pp->expr.string + pp->expr.string_cursor; -} - -static void next_char(yasm_preproc_gas *pp) -{ - pp->expr.string_cursor++; -} - -static int ishex(char c) -{ - c = tolower(c); - return isdigit(c) || (c >= 'a' && c <= 'f'); -} - -static void gas_scan_init(yasm_preproc_gas *pp, struct tokenval *tokval, const char *arg1) -{ - pp->expr.symbol = NULL; - pp->expr.string = arg1; - pp->expr.string_cursor = 0; - memset(tokval, 0, sizeof(struct tokenval)); - tokval->t_type = TOKEN_INVALID; -} - -static void gas_scan_cleanup(yasm_preproc_gas *pp, struct tokenval *tokval) -{ - if (tokval->t_integer) { - yasm_intnum_destroy(tokval->t_integer); - tokval->t_integer = NULL; - } - if (pp->expr.symbol) { - yasm_xfree(pp->expr.symbol); - pp->expr.symbol = NULL; - } -} - -static int gas_scan(void *preproc, struct tokenval *tokval) -{ - yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; - char c = get_char(pp); - const char *str; - - tokval->t_charptr = NULL; - - if (c == '\0') { - return tokval->t_type = TOKEN_EOS; - } - - if (isspace(c)) { - do { - next_char(pp); - c = get_char(pp); - } while (isspace(c)); - } - - if (isdigit(c)) { - int char_index = 0; - int value = 0; - - do { - value = value*10 + (c - '0'); - char_index++; - next_char(pp); - c = get_char(pp); - if (char_index == 1 && c == 'x' && value == 0) { - next_char(pp); - c = get_char(pp); - /* Hex notation. */ - while (ishex(c)) { - if (isdigit(c)) { - value = (value << 4) | (c - '0'); - } else { - value = (value << 4) | (tolower(c) - 'a' + 0xa); - } - next_char(pp); - c = get_char(pp); - } - break; - } - } while (isdigit(c)); - - if (tokval->t_integer) { - yasm_intnum_destroy(tokval->t_integer); - } - tokval->t_integer = yasm_intnum_create_int(value); - return tokval->t_type = TOKEN_NUM; - } - - tokval->t_type = TOKEN_INVALID; - str = get_str(pp); - - { - /* It should be tested whether GAS supports all of these or if there are missing ones. */ - unsigned i; - struct { - const char *op; - int token; - } ops[] = { - { "<<", TOKEN_SHL }, - { ">>", TOKEN_SHR }, - { "//", TOKEN_SDIV }, - { "%%", TOKEN_SMOD }, - { "==", TOKEN_EQ }, - { "!=", TOKEN_NE }, - { "<>", TOKEN_NE }, - { "<>", TOKEN_NE }, - { "<=", TOKEN_LE }, - { ">=", TOKEN_GE }, - { "&&", TOKEN_DBL_AND }, - { "^^", TOKEN_DBL_XOR }, - { "||", TOKEN_DBL_OR } - }; - for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) { - if (!strcmp(str, ops[i].op)) { - tokval->t_type = ops[i].token; - break; - } - } - } - - if (tokval->t_type != TOKEN_INVALID) { - next_char(pp); - next_char(pp); - } else { - str = get_str(pp); - - next_char(pp); - tokval->t_type = c; - - /* Is it a symbol? If so we need to make it a TOKEN_ID. */ - if (isalpha(c) || c == '_' || c == '.') { - int symbol_length = 1; - - c = get_char(pp); - while (isalnum(c) || c == '$' || c == '_') { - symbol_length++; - next_char(pp); - c = get_char(pp); - } - - pp->expr.symbol = yasm_xrealloc(pp->expr.symbol, symbol_length + 1); - memcpy(pp->expr.symbol, str, symbol_length); - pp->expr.symbol[symbol_length] = '\0'; - - tokval->t_type = TOKEN_ID; - tokval->t_charptr = pp->expr.symbol; - } - } - - return tokval->t_type; -} - -static void gas_err(void *private_data, int severity, const char *fmt, ...) -{ - va_list args; - yasm_preproc_gas *pp = private_data; - - if (!pp->detect_errors_only) { - va_start(args, fmt); - yasm_error_set_va(YASM_ERROR_SYNTAX, N_(fmt), args); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - va_end(args); - } - - pp->fatal_error = 1; -} - -static long eval_expr(yasm_preproc_gas *pp, const char *arg1) -{ - struct tokenval tv; - yasm_expr *expr; - yasm_intnum *intn; - long value; - expr_state prev_state; - - if (!*arg1) { - return 0; - } - - prev_state = pp->expr; - gas_scan_init(pp, &tv, arg1); - expr = evaluate(gas_scan, pp, &tv, pp, CRITICAL, gas_err, pp->defines); - intn = yasm_expr_get_intnum(&expr, 0); - value = yasm_intnum_get_int(intn); - yasm_expr_destroy(expr); - gas_scan_cleanup(pp, &tv); - pp->expr = prev_state; - - return value; -} - -/* If-directive helpers. */ - -static int handle_if(yasm_preproc_gas *pp, int is_true) -{ - assert(pp->depth >= 0); - assert(pp->skip_depth == 0); - if (is_true) { - pp->depth++; - } else { - pp->skip_depth = 1; - } - return 1; -} - -static int handle_endif(yasm_preproc_gas *pp) -{ - if (pp->depth) { - pp->depth--; - } else { - yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endif\" without \".if\"")); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 0; - } - return 1; -} - -static int handle_else(yasm_preproc_gas *pp, int is_elseif) -{ - if (!pp->depth) { - yasm_error_set(YASM_ERROR_SYNTAX, N_("\".%s\" without \".if\""), is_elseif ? "elseif" : "else"); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 0; - } else { - pp->skip_depth = 1; - } - return 1; -} - -/* Directive-handling functions. */ - -static int eval_if(yasm_preproc_gas *pp, int negate, const char *arg1) -{ - long value; - if (!*arg1) { - yasm_error_set(YASM_ERROR_SYNTAX, N_("expression is required in \".if\" statement")); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 0; - } - value = eval_expr(pp, arg1); - handle_if(pp, (negate ? !value : !!value)); - return 1; -} - -static int eval_else(yasm_preproc_gas *pp, int unused) -{ - return handle_else(pp, 0); -} - -static int eval_endif(yasm_preproc_gas *pp, int unused) -{ - return handle_endif(pp); -} - -static int eval_elseif(yasm_preproc_gas *pp, int unused, const char *arg1) -{ - if (!*arg1) { - yasm_error_set(YASM_ERROR_SYNTAX, N_("expression is required in \".elseif\" statement")); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 0; - } - if (!handle_else(pp, 1)) { - return 0; - } - return eval_if(pp, 0, arg1); -} - -static int eval_ifb(yasm_preproc_gas *pp, int negate, const char *arg1) -{ - int is_blank = !*arg1; - return handle_if(pp, (negate ? !is_blank : is_blank)); -} - -static int eval_ifc(yasm_preproc_gas *pp, int negate, const char *args) -{ - char arg1[512], arg2[512]; - const char *remainder; - int len = unquote(args, arg1, sizeof(arg1), '\'', ',', &remainder); - if (len >= 0) { - len = unquote(remainder, arg2, sizeof(arg2), '\'', '\0', NULL); - if (len >= 0) { - int result = !strcmp(arg1, arg2); - return handle_if(pp, (negate ? !result : result)); - } - } else { - /* first argument was not single-quoted, assume non-quoted mode */ - remainder = get_arg(pp, args, arg1, sizeof(arg1)); - if (remainder) { - int result = !strcmp(arg1, remainder); - return handle_if(pp, (negate ? !result : result)); - } - } - yasm_error_set(YASM_ERROR_SYNTAX, N_("\"%s\" expects two single-quoted or unquoted arguments"), negate ? ".ifnc" : ".ifc"); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 0; -} - -static int eval_ifeqs(yasm_preproc_gas *pp, int negate, const char *args) -{ - char arg1[512], arg2[512]; - const char *remainder; - int len = unquote(args, arg1, sizeof(arg1), '"', ',', &remainder); - if (len >= 0) { - len = unquote(remainder, arg2, sizeof(arg2), '"', '\0', NULL); - if (len >= 0) { - int result = !strcmp(arg1, arg2); - return handle_if(pp, (negate ? !result : result)); - } - } - yasm_error_set(YASM_ERROR_SYNTAX, N_("\"%s\" expects two double-quoted arguments"), negate ? ".ifnes" : ".ifeqs"); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 1; -} - -static int eval_ifdef(yasm_preproc_gas *pp, int negate, const char *name) -{ - yasm_symrec *rec = yasm_symtab_get(pp->defines, name); - int result = (rec != NULL); - return handle_if(pp, (negate ? !result : result)); -} - -static int eval_ifge(yasm_preproc_gas *pp, int negate, const char *arg1) -{ - long value = eval_expr(pp, arg1); - int result = (value >= 0); - return handle_if(pp, (negate ? !result : result)); -} - -static int eval_ifgt(yasm_preproc_gas *pp, int negate, const char *arg1) -{ - long value = eval_expr(pp, arg1); - int result = (value > 0); - return handle_if(pp, (negate ? !result : result)); -} - -static int eval_include(yasm_preproc_gas *pp, int unused, const char *arg1) -{ - char *current_filename; - char filename[MAXPATHLEN]; - char *line; - int num_lines; - FILE *file; - buffered_line *prev_bline; - included_file *inc_file; - - if (unquote(arg1, filename, sizeof(filename), '"', '\0', NULL) < 0) { - yasm_error_set(YASM_ERROR_SYNTAX, N_("string expected")); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 0; - } - - if (SLIST_EMPTY(&pp->included_files)) { - current_filename = pp->in_filename; - } else { - current_filename = SLIST_FIRST(&pp->included_files)->filename; - } - file = yasm_fopen_include(filename, current_filename, "r", NULL); - if (!file) { - yasm_error_set(YASM_ERROR_SYNTAX, N_("unable to open included file \"%s\""), filename); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 0; - } - - num_lines = 0; - prev_bline = NULL; - line = read_line_from_file(pp, file); - while (line) { - buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); - bline->line = line; - bline->line_number = -1; - if (prev_bline) { - SLIST_INSERT_AFTER(prev_bline, bline, next); - } else { - SLIST_INSERT_HEAD(&pp->buffered_lines, bline, next); - } - prev_bline = bline; - line = read_line_from_file(pp, file); - num_lines++; - } - - inc_file = yasm_xmalloc(sizeof(included_file)); - inc_file->filename = yasm__xstrdup(filename); - inc_file->lines_remaining = num_lines; - SLIST_INSERT_HEAD(&pp->included_files, inc_file, next); - return 1; -} - -static int try_eval_expr(yasm_preproc_gas *pp, const char *value, long *result) -{ - int success; - - pp->detect_errors_only = 1; - *result = eval_expr(pp, value); - success = !pp->fatal_error; - pp->fatal_error = 0; - pp->detect_errors_only = 0; - - return success; -} - -static int remove_define(yasm_preproc_gas *pp, const char *name, int allow_redefine) -{ - yasm_symrec *rec = yasm_symtab_get(pp->defines, name); - if (rec) { - const yasm_symtab_iter *entry; - yasm_symtab *new_defines; - - if (!allow_redefine) { - yasm_error_set(YASM_ERROR_SYNTAX, N_("symbol \"%s\" is already defined"), name); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 0; - } - - new_defines = yasm_symtab_create(); - - for (entry = yasm_symtab_first(pp->defines); entry; entry = yasm_symtab_next(entry)) { - yasm_symrec *entry_rec = yasm_symtab_iter_value(entry); - const char *rec_name = yasm_symrec_get_name(entry_rec); - if (strcmp(rec_name, name)) { - yasm_intnum *num = yasm_intnum_create_int(eval_expr(pp, rec_name)); - yasm_expr *expr = yasm_expr_create_ident(yasm_expr_int(num), 0); - yasm_symtab_define_equ(new_defines, rec_name, expr, 0); - } - } - - yasm_symtab_destroy(pp->defines); - pp->defines = new_defines; - } - return (rec != NULL); -} - -static void add_define(yasm_preproc_gas *pp, const char *name, long value, int allow_redefine, int substitute) -{ - deferred_define *def, *prev_def, *temp_def; - yasm_intnum *num; - yasm_expr *expr; - - remove_define(pp, name, allow_redefine); - - /* Add the new define. */ - num = yasm_intnum_create_int(value); - expr = yasm_expr_create_ident(yasm_expr_int(num), 0); - yasm_symtab_define_equ(pp->defines, name, expr, 0); - - /* Perform substitution on any deferred defines. */ - if (substitute) { - prev_def = NULL; - temp_def = NULL; - SLIST_FOREACH_SAFE(def, &pp->deferred_defines, next, temp_def) { - if (substitute_values(pp, &def->value)) { - /* Value was updated - check if it can be added to the symtab. */ - if (try_eval_expr(pp, def->value, &value)) { - add_define(pp, def->name, value, FALSE, FALSE); - if (prev_def) { - SLIST_NEXT(prev_def, next) = SLIST_NEXT(def, next); - } else { - SLIST_FIRST(&pp->deferred_defines) = SLIST_NEXT(def, next); - } - yasm_xfree(def->name); - yasm_xfree(def->value); - yasm_xfree(def); - continue; - } - } - prev_def = def; - } - } -} - -static int eval_set(yasm_preproc_gas *pp, int allow_redefine, const char *name, const char *value) -{ - if (!pp->skip_depth) { - long result; - - if (!try_eval_expr(pp, value, &result)) { - deferred_define *def; - remove_define(pp, name, allow_redefine); - def = yasm_xmalloc(sizeof(deferred_define)); - def->name = yasm__xstrdup(name); - def->value = yasm__xstrdup(value); - substitute_values(pp, &def->value); - SLIST_INSERT_HEAD(&pp->deferred_defines, def, next); - } else { - add_define(pp, name, result, allow_redefine, TRUE); - } - } - return 1; -} - -static int eval_macro(yasm_preproc_gas *pp, int unused, char *args) -{ - char *end; - char *line; - long nesting = 1; - macro_entry *macro = yasm_xmalloc(sizeof(macro_entry)); - - memset(macro, 0, sizeof(macro_entry)); - - end = args; - while (*end && !isspace(*end)) { - end++; - } - macro->name = yasm_xmalloc(end - args + 1); - memcpy(macro->name, args, end - args); - macro->name[end - args] = '\0'; - - skip_whitespace2(&end); - while (*end) { - args = end; - while (*end && !isspace(*end) && *end != ',') { - end++; - } - macro->num_params++; - macro->params = yasm_xrealloc(macro->params, macro->num_params*sizeof(char *)); - macro->params[macro->num_params - 1] = yasm_xmalloc(end - args + 1); - memcpy(macro->params[macro->num_params - 1], args, end - args); - macro->params[macro->num_params - 1][end - args] = '\0'; - skip_whitespace2(&end); - if (*end == ',') { - end++; - skip_whitespace2(&end); - } - } - - STAILQ_INSERT_TAIL(&pp->macros, macro, next); - - line = read_line(pp); - while (line) { - char *line2 = line; - skip_whitespace2(&line2); - if (starts_with(line2, ".macro")) { - nesting++; - } else if (starts_with(line, ".endm") && --nesting == 0) { - return 1; - } - macro->num_lines++; - macro->lines = yasm_xrealloc(macro->lines, macro->num_lines*sizeof(char *)); - macro->lines[macro->num_lines - 1] = line; - line = read_line(pp); - } - - yasm_error_set(YASM_ERROR_SYNTAX, N_("unexpected EOF in \".macro\" block")); - yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); - return 0; -} - -static int eval_endm(yasm_preproc_gas *pp, int unused) -{ - yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endm\" without \".macro\"")); - yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); - return 0; -} - -static void get_param_value(macro_entry *macro, int param_index, const char *args, const char **value, int *length) -{ - int arg_index = 0; - const char *default_value = NULL; - const char *end, *eq = strstr(macro->params[param_index], "="); - - if (eq) { - default_value = eq + 1; - } - - skip_whitespace(&args); - end = args; - while (*end) { - args = end; - while (*end && !isspace(*end) && *end != ',') { - end++; - } - if (arg_index == param_index) { - if (end == args && default_value) { - *value = default_value; - *length = strlen(default_value); - } else { - *value = args; - *length = end - args; - } - return; - } - arg_index++; - skip_whitespace(&end); - if (*end == ',') { - end++; - skip_whitespace(&end); - } - } - - *value = default_value; - *length = (default_value ? strlen(default_value) : 0); -} - -static void expand_macro(yasm_preproc_gas *pp, macro_entry *macro, const char *args) -{ - int i, j; - buffered_line *prev_bline = NULL; - - for (i = 0; i < macro->num_lines; i++) { - buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); - struct tokenval tokval; - int prev_was_backslash = FALSE; - int line_length = strlen(macro->lines[i]); - char *work = yasm__xstrdup(macro->lines[i]); - expr_state prev_state = pp->expr; - - gas_scan_init(pp, &tokval, work); - while (gas_scan(pp, &tokval) != TOKEN_EOS) { - if (prev_was_backslash) { - if (tokval.t_type == TOKEN_ID) { - for (j = 0; j < macro->num_params; j++) { - char *end = strstr(macro->params[j], "="); - int len = (end ? (size_t)(end - macro->params[j]) - : strlen(macro->params[j])); - if (!strncmp(tokval.t_charptr, macro->params[j], len) - && tokval.t_charptr[len] == '\0') { - /* now, find matching argument. */ - const char *value; - char *line = work + (pp->expr.string - work); - int cursor = pp->expr.string_cursor; - int value_length, delta; - - get_param_value(macro, j, args, &value, &value_length); - - len++; /* leading slash */ - delta = value_length - len; - line_length += delta; - if (delta > 0) { - line = yasm_xrealloc(line, line_length + 1); - } - memmove(line + cursor - len + value_length, line + cursor, strlen(line + cursor) + 1); - memcpy(line + cursor - len, value, value_length); - pp->expr.string = work = line; - pp->expr.string_cursor += delta; - if (pp->expr.symbol) { - yasm_xfree(pp->expr.symbol); - pp->expr.symbol = NULL; - } - } - } - } - prev_was_backslash = FALSE; - } else if (tokval.t_type == '\\') { - prev_was_backslash = TRUE; - } - } - gas_scan_cleanup(pp, &tokval); - - bline->line = work + (pp->expr.string - work); - bline->line_number = -1; - pp->expr = prev_state; - - if (prev_bline) { - SLIST_INSERT_AFTER(prev_bline, bline, next); - } else { - SLIST_INSERT_HEAD(&pp->buffered_lines, bline, next); - } - prev_bline = bline; - } -} - -static int eval_rept(yasm_preproc_gas *pp, int unused, const char *arg1) -{ - long i, n = eval_expr(pp, arg1); - long num_lines = 0; - long nesting = 1; - char *line = read_line(pp); - buffered_line *prev_bline = NULL; - SLIST_HEAD(buffered_lines_head, buffered_line) lines; - int rept_start_file_line_number = pp->next_line_number - 1; - int rept_start_output_line_number = pp->current_line_number; - - SLIST_INIT(&lines); - - while (line) { - skip_whitespace2(&line); - if (starts_with(line, ".rept")) { - nesting++; - } else if (starts_with(line, ".endr") && --nesting == 0) { - for (i = 0; i < n; i++) { - buffered_line *current_line; - prev_bline = NULL; - SLIST_FOREACH(current_line, &lines, next) { - buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); - bline->line = yasm__xstrdup(current_line->line); - bline->line_number = current_line->line_number; - if (prev_bline) { - SLIST_INSERT_AFTER(prev_bline, bline, next); - } else { - SLIST_INSERT_HEAD(&pp->buffered_lines, bline, next); - } - prev_bline = bline; - } - } - if (!SLIST_EMPTY(&pp->included_files)) { - included_file *inc_file = SLIST_FIRST(&pp->included_files); - inc_file->lines_remaining += n * num_lines; - } - while (!SLIST_EMPTY(&lines)) { - buffered_line *bline = SLIST_FIRST(&lines); - SLIST_REMOVE_HEAD(&lines, next); - yasm_xfree(bline->line); - yasm_xfree(bline); - } - yasm_xfree(line); - return 1; - } - if (n > 0) { - buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); - bline->line = line; - bline->line_number = pp->next_line_number; - if (prev_bline) { - SLIST_INSERT_AFTER(prev_bline, bline, next); - } else { - SLIST_INSERT_HEAD(&lines, bline, next); - } - prev_bline = bline; - } else { - yasm_xfree(line); - } - line = read_line(pp); - num_lines++; - } - yasm_linemap_set(pp->cur_lm, pp->in_filename, rept_start_output_line_number, rept_start_file_line_number, 0); - yasm_error_set(YASM_ERROR_SYNTAX, N_("rept without matching endr")); - yasm_errwarn_propagate(pp->errwarns, rept_start_output_line_number); - return 0; -} - -static int eval_endr(yasm_preproc_gas *pp, int unused) -{ - yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endr\" without \".rept\"")); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - return 0; -} - -/* Top-level line processing. */ - -typedef int (*pp_fn0_t)(yasm_preproc_gas *pp, int param); -typedef int (*pp_fn1_t)(yasm_preproc_gas *pp, int param, const char *arg1); -typedef int (*pp_fn2_t)(yasm_preproc_gas *pp, int param, const char *arg1, const char *arg2); - -#define FN(f) ((pp_fn0_t) &(f)) - -static void kill_comments(yasm_preproc_gas *pp, char *line) -{ - int next = 2; - char *cstart; - - skip_whitespace2(&line); - if (*line == '#' || !strncmp(line, "//", 2)) { - *line = '\0'; - return; - } - - if (pp->in_comment) { - cstart = line; - next = 0; - } else { - cstart = strstr(line, "/*"); - next = 2; - } - - while (cstart) { - char *cend = strstr(cstart + next, "*/"); - - if (!cend) { - *cstart = '\0'; - pp->in_comment = TRUE; - return; - } - - memmove(cstart, cend + 2, strlen(cend + 2) + 1); - pp->in_comment = FALSE; - cstart = strstr(cstart, "/*"); - next = 2; - } -} - -static int substitute_values(yasm_preproc_gas *pp, char **line_ptr) -{ - int changed = 0; - char *line = *line_ptr; - int line_length = strlen(line); - struct tokenval tokval; - expr_state prev_state = pp->expr; - - gas_scan_init(pp, &tokval, line); - while (gas_scan(pp, &tokval) != TOKEN_EOS) { - if (tokval.t_type == TOKEN_ID) { - yasm_symrec *rec = yasm_symtab_get(pp->defines, tokval.t_charptr); - if (rec) { - int cursor = pp->expr.string_cursor; - int len = strlen(tokval.t_charptr); - char value[64]; - int value_length = sprintf(value, "%ld", eval_expr(pp, tokval.t_charptr)); - int delta = value_length - len; - - line_length += delta; - if (delta > 0) { - line = yasm_xrealloc(line, line_length + 1); - } - memmove(line + cursor - len + value_length, line + cursor, strlen(line + cursor) + 1); - memcpy(line + cursor - len, value, value_length); - pp->expr.string = line; - pp->expr.string_cursor = cursor + delta; - changed = 1; - } - yasm_xfree(pp->expr.symbol); - pp->expr.symbol = NULL; - } - } - gas_scan_cleanup(pp, &tokval); - pp->expr = prev_state; - - if (changed) { - *line_ptr = line; - } - - return changed; -} - -static int process_line(yasm_preproc_gas *pp, char **line_ptr) -{ - macro_entry *macro; - size_t i; - char *line = *line_ptr; - struct { - const char *name; - int nargs; - pp_fn0_t fn; - int param; - } directives[] = { - {"else", 0, FN(eval_else), 0}, - {"elseif", 1, FN(eval_elseif), 0}, - {"endif", 0, FN(eval_endif), 0}, - {"if", 1, FN(eval_if), 0}, - {"ifb", 1, FN(eval_ifb), 0}, - {"ifc", 1, FN(eval_ifc), 0}, - {"ifdef", 1, FN(eval_ifdef), 0}, - {"ifeq", 1, FN(eval_if), 1}, - {"ifeqs", 1, FN(eval_ifeqs), 0}, - {"ifge", 1, FN(eval_ifge), 0}, - {"ifgt", 1, FN(eval_ifgt), 0}, - {"ifle", 1, FN(eval_ifgt), 1}, - {"iflt", 1, FN(eval_ifge), 1}, - {"ifnb", 1, FN(eval_ifb), 1}, - {"ifnc", 1, FN(eval_ifc), 1}, - {"ifndef", 1, FN(eval_ifdef), 1}, - {"ifnotdef", 1, FN(eval_ifdef), 1}, - {"ifne", 1, FN(eval_if), 0}, - {"ifnes", 1, FN(eval_ifeqs), 1}, - {"include", 1, FN(eval_include), 0}, - {"set", 2, FN(eval_set), 1}, - {"equ", 2, FN(eval_set), 1}, - {"equiv", 2, FN(eval_set), 0}, - {"macro", 1, FN(eval_macro), 0}, - {"endm", 0, FN(eval_endm), 0}, - {"rept", 1, FN(eval_rept), 0}, - {"endr", 1, FN(eval_endr), 0}, - }; - - kill_comments(pp, line); - skip_whitespace2(&line); - if (*line == '\0') { - return FALSE; - } - - /* See if this is a macro call. */ - STAILQ_FOREACH(macro, &pp->macros, next) { - const char *remainder = starts_with(line, macro->name); - if (remainder && (!*remainder || isspace(*remainder))) { - skip_whitespace2(&line); - expand_macro(pp, macro, remainder); - return FALSE; - } - } - - for (i = 0; i < sizeof(directives)/sizeof(directives[0]); i++) { - char buf1[1024]; - const char *remainder = matches(line, directives[i].name); - - if (remainder) { - if (pp->skip_depth) { - if (!strncmp("if", directives[i].name, 2)) { - pp->skip_depth++; - } else if (!strcmp("endif", directives[i].name)) { - pp->skip_depth--; - } else if (!strcmp("else", directives[i].name)) { - if (pp->skip_depth == 1) { - pp->skip_depth = 0; - pp->depth++; - } - } - return FALSE; - } else if (directives[i].nargs == 0) { - pp_fn0_t fn = (pp_fn0_t) directives[i].fn; - pp->fatal_error = !fn(pp, directives[i].param); - return FALSE; - } else if (directives[i].nargs == 1) { - pp_fn1_t fn = (pp_fn1_t) directives[i].fn; - skip_whitespace(&remainder); - pp->fatal_error = !fn(pp, directives[i].param, remainder); - return FALSE; - } else if (directives[i].nargs == 2) { - remainder = get_arg(pp, remainder, buf1, sizeof(buf1)); - if (!remainder || !*remainder || !*buf1) { - yasm_error_set(YASM_ERROR_SYNTAX, N_("\".%s\" expects two arguments"), directives[i].name); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - pp->fatal_error = 1; - } else { - pp_fn2_t fn = (pp_fn2_t) directives[i].fn; - pp->fatal_error = !fn(pp, directives[i].param, buf1, remainder); - } - return FALSE; - } - } - } - - if (pp->skip_depth == 0) { - substitute_values(pp, line_ptr); - return TRUE; - } - - return FALSE; -} - -/* Functions exported by the preprocessor. */ - -static yasm_preproc * -gas_preproc_create(const char *in_filename, yasm_symtab *symtab, - yasm_linemap *lm, yasm_errwarns *errwarns) -{ - FILE *f; - yasm_preproc_gas *pp = yasm_xmalloc(sizeof(yasm_preproc_gas)); - - if (strcmp(in_filename, "-") != 0) { - f = fopen(in_filename, "r"); - if (!f) { + } + + yasm_symtab_destroy(pp->defines); + pp->defines = new_defines; + } + return (rec != NULL); +} + +static void add_define(yasm_preproc_gas *pp, const char *name, long value, int allow_redefine, int substitute) +{ + deferred_define *def, *prev_def, *temp_def; + yasm_intnum *num; + yasm_expr *expr; + + remove_define(pp, name, allow_redefine); + + /* Add the new define. */ + num = yasm_intnum_create_int(value); + expr = yasm_expr_create_ident(yasm_expr_int(num), 0); + yasm_symtab_define_equ(pp->defines, name, expr, 0); + + /* Perform substitution on any deferred defines. */ + if (substitute) { + prev_def = NULL; + temp_def = NULL; + SLIST_FOREACH_SAFE(def, &pp->deferred_defines, next, temp_def) { + if (substitute_values(pp, &def->value)) { + /* Value was updated - check if it can be added to the symtab. */ + if (try_eval_expr(pp, def->value, &value)) { + add_define(pp, def->name, value, FALSE, FALSE); + if (prev_def) { + SLIST_NEXT(prev_def, next) = SLIST_NEXT(def, next); + } else { + SLIST_FIRST(&pp->deferred_defines) = SLIST_NEXT(def, next); + } + yasm_xfree(def->name); + yasm_xfree(def->value); + yasm_xfree(def); + continue; + } + } + prev_def = def; + } + } +} + +static int eval_set(yasm_preproc_gas *pp, int allow_redefine, const char *name, const char *value) +{ + if (!pp->skip_depth) { + long result; + + if (!try_eval_expr(pp, value, &result)) { + deferred_define *def; + remove_define(pp, name, allow_redefine); + def = yasm_xmalloc(sizeof(deferred_define)); + def->name = yasm__xstrdup(name); + def->value = yasm__xstrdup(value); + substitute_values(pp, &def->value); + SLIST_INSERT_HEAD(&pp->deferred_defines, def, next); + } else { + add_define(pp, name, result, allow_redefine, TRUE); + } + } + return 1; +} + +static int eval_macro(yasm_preproc_gas *pp, int unused, char *args) +{ + char *end; + char *line; + long nesting = 1; + macro_entry *macro = yasm_xmalloc(sizeof(macro_entry)); + + memset(macro, 0, sizeof(macro_entry)); + + end = args; + while (*end && !isspace(*end)) { + end++; + } + macro->name = yasm_xmalloc(end - args + 1); + memcpy(macro->name, args, end - args); + macro->name[end - args] = '\0'; + + skip_whitespace2(&end); + while (*end) { + args = end; + while (*end && !isspace(*end) && *end != ',') { + end++; + } + macro->num_params++; + macro->params = yasm_xrealloc(macro->params, macro->num_params*sizeof(char *)); + macro->params[macro->num_params - 1] = yasm_xmalloc(end - args + 1); + memcpy(macro->params[macro->num_params - 1], args, end - args); + macro->params[macro->num_params - 1][end - args] = '\0'; + skip_whitespace2(&end); + if (*end == ',') { + end++; + skip_whitespace2(&end); + } + } + + STAILQ_INSERT_TAIL(&pp->macros, macro, next); + + line = read_line(pp); + while (line) { + char *line2 = line; + skip_whitespace2(&line2); + if (starts_with(line2, ".macro")) { + nesting++; + } else if (starts_with(line, ".endm") && --nesting == 0) { + return 1; + } + macro->num_lines++; + macro->lines = yasm_xrealloc(macro->lines, macro->num_lines*sizeof(char *)); + macro->lines[macro->num_lines - 1] = line; + line = read_line(pp); + } + + yasm_error_set(YASM_ERROR_SYNTAX, N_("unexpected EOF in \".macro\" block")); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + return 0; +} + +static int eval_endm(yasm_preproc_gas *pp, int unused) +{ + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endm\" without \".macro\"")); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + return 0; +} + +static void get_param_value(macro_entry *macro, int param_index, const char *args, const char **value, int *length) +{ + int arg_index = 0; + const char *default_value = NULL; + const char *end, *eq = strstr(macro->params[param_index], "="); + + if (eq) { + default_value = eq + 1; + } + + skip_whitespace(&args); + end = args; + while (*end) { + args = end; + while (*end && !isspace(*end) && *end != ',') { + end++; + } + if (arg_index == param_index) { + if (end == args && default_value) { + *value = default_value; + *length = strlen(default_value); + } else { + *value = args; + *length = end - args; + } + return; + } + arg_index++; + skip_whitespace(&end); + if (*end == ',') { + end++; + skip_whitespace(&end); + } + } + + *value = default_value; + *length = (default_value ? strlen(default_value) : 0); +} + +static void expand_macro(yasm_preproc_gas *pp, macro_entry *macro, const char *args) +{ + int i, j; + buffered_line *prev_bline = NULL; + + for (i = 0; i < macro->num_lines; i++) { + buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); + struct tokenval tokval; + int prev_was_backslash = FALSE; + int line_length = strlen(macro->lines[i]); + char *work = yasm__xstrdup(macro->lines[i]); + expr_state prev_state = pp->expr; + + gas_scan_init(pp, &tokval, work); + while (gas_scan(pp, &tokval) != TOKEN_EOS) { + if (prev_was_backslash) { + if (tokval.t_type == TOKEN_ID) { + for (j = 0; j < macro->num_params; j++) { + char *end = strstr(macro->params[j], "="); + int len = (end ? (size_t)(end - macro->params[j]) + : strlen(macro->params[j])); + if (!strncmp(tokval.t_charptr, macro->params[j], len) + && tokval.t_charptr[len] == '\0') { + /* now, find matching argument. */ + const char *value; + char *line = work + (pp->expr.string - work); + int cursor = pp->expr.string_cursor; + int value_length, delta; + + get_param_value(macro, j, args, &value, &value_length); + + len++; /* leading slash */ + delta = value_length - len; + line_length += delta; + if (delta > 0) { + line = yasm_xrealloc(line, line_length + 1); + } + memmove(line + cursor - len + value_length, line + cursor, strlen(line + cursor) + 1); + memcpy(line + cursor - len, value, value_length); + pp->expr.string = work = line; + pp->expr.string_cursor += delta; + if (pp->expr.symbol) { + yasm_xfree(pp->expr.symbol); + pp->expr.symbol = NULL; + } + } + } + } + prev_was_backslash = FALSE; + } else if (tokval.t_type == '\\') { + prev_was_backslash = TRUE; + } + } + gas_scan_cleanup(pp, &tokval); + + bline->line = work + (pp->expr.string - work); + bline->line_number = -1; + pp->expr = prev_state; + + if (prev_bline) { + SLIST_INSERT_AFTER(prev_bline, bline, next); + } else { + SLIST_INSERT_HEAD(&pp->buffered_lines, bline, next); + } + prev_bline = bline; + } +} + +static int eval_rept(yasm_preproc_gas *pp, int unused, const char *arg1) +{ + long i, n = eval_expr(pp, arg1); + long num_lines = 0; + long nesting = 1; + char *line = read_line(pp); + buffered_line *prev_bline = NULL; + SLIST_HEAD(buffered_lines_head, buffered_line) lines; + int rept_start_file_line_number = pp->next_line_number - 1; + int rept_start_output_line_number = pp->current_line_number; + + SLIST_INIT(&lines); + + while (line) { + skip_whitespace2(&line); + if (starts_with(line, ".rept")) { + nesting++; + } else if (starts_with(line, ".endr") && --nesting == 0) { + for (i = 0; i < n; i++) { + buffered_line *current_line; + prev_bline = NULL; + SLIST_FOREACH(current_line, &lines, next) { + buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); + bline->line = yasm__xstrdup(current_line->line); + bline->line_number = current_line->line_number; + if (prev_bline) { + SLIST_INSERT_AFTER(prev_bline, bline, next); + } else { + SLIST_INSERT_HEAD(&pp->buffered_lines, bline, next); + } + prev_bline = bline; + } + } + if (!SLIST_EMPTY(&pp->included_files)) { + included_file *inc_file = SLIST_FIRST(&pp->included_files); + inc_file->lines_remaining += n * num_lines; + } + while (!SLIST_EMPTY(&lines)) { + buffered_line *bline = SLIST_FIRST(&lines); + SLIST_REMOVE_HEAD(&lines, next); + yasm_xfree(bline->line); + yasm_xfree(bline); + } + yasm_xfree(line); + return 1; + } + if (n > 0) { + buffered_line *bline = yasm_xmalloc(sizeof(buffered_line)); + bline->line = line; + bline->line_number = pp->next_line_number; + if (prev_bline) { + SLIST_INSERT_AFTER(prev_bline, bline, next); + } else { + SLIST_INSERT_HEAD(&lines, bline, next); + } + prev_bline = bline; + } else { + yasm_xfree(line); + } + line = read_line(pp); + num_lines++; + } + yasm_linemap_set(pp->cur_lm, pp->in_filename, rept_start_output_line_number, rept_start_file_line_number, 0); + yasm_error_set(YASM_ERROR_SYNTAX, N_("rept without matching endr")); + yasm_errwarn_propagate(pp->errwarns, rept_start_output_line_number); + return 0; +} + +static int eval_endr(yasm_preproc_gas *pp, int unused) +{ + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endr\" without \".rept\"")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + return 0; +} + +/* Top-level line processing. */ + +typedef int (*pp_fn0_t)(yasm_preproc_gas *pp, int param); +typedef int (*pp_fn1_t)(yasm_preproc_gas *pp, int param, const char *arg1); +typedef int (*pp_fn2_t)(yasm_preproc_gas *pp, int param, const char *arg1, const char *arg2); + +#define FN(f) ((pp_fn0_t) &(f)) + +static void kill_comments(yasm_preproc_gas *pp, char *line) +{ + int next = 2; + char *cstart; + + skip_whitespace2(&line); + if (*line == '#' || !strncmp(line, "//", 2)) { + *line = '\0'; + return; + } + + if (pp->in_comment) { + cstart = line; + next = 0; + } else { + cstart = strstr(line, "/*"); + next = 2; + } + + while (cstart) { + char *cend = strstr(cstart + next, "*/"); + + if (!cend) { + *cstart = '\0'; + pp->in_comment = TRUE; + return; + } + + memmove(cstart, cend + 2, strlen(cend + 2) + 1); + pp->in_comment = FALSE; + cstart = strstr(cstart, "/*"); + next = 2; + } +} + +static int substitute_values(yasm_preproc_gas *pp, char **line_ptr) +{ + int changed = 0; + char *line = *line_ptr; + int line_length = strlen(line); + struct tokenval tokval; + expr_state prev_state = pp->expr; + + gas_scan_init(pp, &tokval, line); + while (gas_scan(pp, &tokval) != TOKEN_EOS) { + if (tokval.t_type == TOKEN_ID) { + yasm_symrec *rec = yasm_symtab_get(pp->defines, tokval.t_charptr); + if (rec) { + int cursor = pp->expr.string_cursor; + int len = strlen(tokval.t_charptr); + char value[64]; + int value_length = sprintf(value, "%ld", eval_expr(pp, tokval.t_charptr)); + int delta = value_length - len; + + line_length += delta; + if (delta > 0) { + line = yasm_xrealloc(line, line_length + 1); + } + memmove(line + cursor - len + value_length, line + cursor, strlen(line + cursor) + 1); + memcpy(line + cursor - len, value, value_length); + pp->expr.string = line; + pp->expr.string_cursor = cursor + delta; + changed = 1; + } + yasm_xfree(pp->expr.symbol); + pp->expr.symbol = NULL; + } + } + gas_scan_cleanup(pp, &tokval); + pp->expr = prev_state; + + if (changed) { + *line_ptr = line; + } + + return changed; +} + +static int process_line(yasm_preproc_gas *pp, char **line_ptr) +{ + macro_entry *macro; + size_t i; + char *line = *line_ptr; + struct { + const char *name; + int nargs; + pp_fn0_t fn; + int param; + } directives[] = { + {"else", 0, FN(eval_else), 0}, + {"elseif", 1, FN(eval_elseif), 0}, + {"endif", 0, FN(eval_endif), 0}, + {"if", 1, FN(eval_if), 0}, + {"ifb", 1, FN(eval_ifb), 0}, + {"ifc", 1, FN(eval_ifc), 0}, + {"ifdef", 1, FN(eval_ifdef), 0}, + {"ifeq", 1, FN(eval_if), 1}, + {"ifeqs", 1, FN(eval_ifeqs), 0}, + {"ifge", 1, FN(eval_ifge), 0}, + {"ifgt", 1, FN(eval_ifgt), 0}, + {"ifle", 1, FN(eval_ifgt), 1}, + {"iflt", 1, FN(eval_ifge), 1}, + {"ifnb", 1, FN(eval_ifb), 1}, + {"ifnc", 1, FN(eval_ifc), 1}, + {"ifndef", 1, FN(eval_ifdef), 1}, + {"ifnotdef", 1, FN(eval_ifdef), 1}, + {"ifne", 1, FN(eval_if), 0}, + {"ifnes", 1, FN(eval_ifeqs), 1}, + {"include", 1, FN(eval_include), 0}, + {"set", 2, FN(eval_set), 1}, + {"equ", 2, FN(eval_set), 1}, + {"equiv", 2, FN(eval_set), 0}, + {"macro", 1, FN(eval_macro), 0}, + {"endm", 0, FN(eval_endm), 0}, + {"rept", 1, FN(eval_rept), 0}, + {"endr", 1, FN(eval_endr), 0}, + }; + + kill_comments(pp, line); + skip_whitespace2(&line); + if (*line == '\0') { + return FALSE; + } + + /* See if this is a macro call. */ + STAILQ_FOREACH(macro, &pp->macros, next) { + const char *remainder = starts_with(line, macro->name); + if (remainder && (!*remainder || isspace(*remainder))) { + skip_whitespace2(&line); + expand_macro(pp, macro, remainder); + return FALSE; + } + } + + for (i = 0; i < sizeof(directives)/sizeof(directives[0]); i++) { + char buf1[1024]; + const char *remainder = matches(line, directives[i].name); + + if (remainder) { + if (pp->skip_depth) { + if (!strncmp("if", directives[i].name, 2)) { + pp->skip_depth++; + } else if (!strcmp("endif", directives[i].name)) { + pp->skip_depth--; + } else if (!strcmp("else", directives[i].name)) { + if (pp->skip_depth == 1) { + pp->skip_depth = 0; + pp->depth++; + } + } + return FALSE; + } else if (directives[i].nargs == 0) { + pp_fn0_t fn = (pp_fn0_t) directives[i].fn; + pp->fatal_error = !fn(pp, directives[i].param); + return FALSE; + } else if (directives[i].nargs == 1) { + pp_fn1_t fn = (pp_fn1_t) directives[i].fn; + skip_whitespace(&remainder); + pp->fatal_error = !fn(pp, directives[i].param, remainder); + return FALSE; + } else if (directives[i].nargs == 2) { + remainder = get_arg(pp, remainder, buf1, sizeof(buf1)); + if (!remainder || !*remainder || !*buf1) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".%s\" expects two arguments"), directives[i].name); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + pp->fatal_error = 1; + } else { + pp_fn2_t fn = (pp_fn2_t) directives[i].fn; + pp->fatal_error = !fn(pp, directives[i].param, buf1, remainder); + } + return FALSE; + } + } + } + + if (pp->skip_depth == 0) { + substitute_values(pp, line_ptr); + return TRUE; + } + + return FALSE; +} + +/* Functions exported by the preprocessor. */ + +static yasm_preproc * +gas_preproc_create(const char *in_filename, yasm_symtab *symtab, + yasm_linemap *lm, yasm_errwarns *errwarns) +{ + FILE *f; + yasm_preproc_gas *pp = yasm_xmalloc(sizeof(yasm_preproc_gas)); + + if (strcmp(in_filename, "-") != 0) { + f = fopen(in_filename, "r"); + if (!f) { yasm__fatal_missing_input_file(N_("Could not open input file"), in_filename); - } - } else { - f = stdin; - } - - pp->preproc.module = &yasm_gas_LTX_preproc; - pp->in = f; - pp->in_filename = yasm__xstrdup(in_filename); - pp->defines = yasm_symtab_create(); - SLIST_INIT(&pp->deferred_defines); - yasm_symtab_set_case_sensitive(pp->defines, 1); - pp->depth = 0; - pp->skip_depth = 0; - pp->in_comment = FALSE; - SLIST_INIT(&pp->buffered_lines); - SLIST_INIT(&pp->included_files); - STAILQ_INIT(&pp->macros); - pp->in_line_number = 0; - pp->next_line_number = 0; - pp->current_line_number = 0; - pp->cur_lm = lm; - pp->errwarns = errwarns; - pp->fatal_error = 0; - pp->detect_errors_only = 0; - - return (yasm_preproc *) pp; -} - -static void -gas_preproc_destroy(yasm_preproc *preproc) -{ - yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; - yasm_xfree(pp->in_filename); - yasm_symtab_destroy(pp->defines); - while (!SLIST_EMPTY(&pp->deferred_defines)) { - deferred_define *def = SLIST_FIRST(&pp->deferred_defines); - SLIST_REMOVE_HEAD(&pp->deferred_defines, next); - yasm_xfree(def->name); - yasm_xfree(def->value); - yasm_xfree(def); - } - while (!SLIST_EMPTY(&pp->buffered_lines)) { - buffered_line *bline = SLIST_FIRST(&pp->buffered_lines); - SLIST_REMOVE_HEAD(&pp->buffered_lines, next); - yasm_xfree(bline->line); - yasm_xfree(bline); - } - while (!SLIST_EMPTY(&pp->included_files)) { - included_file *inc_file = SLIST_FIRST(&pp->included_files); - SLIST_REMOVE_HEAD(&pp->included_files, next); - yasm_xfree(inc_file->filename); - yasm_xfree(inc_file); - } - while (!STAILQ_EMPTY(&pp->macros)) { - int i; - macro_entry *macro = STAILQ_FIRST(&pp->macros); - STAILQ_REMOVE_HEAD(&pp->macros, next); - yasm_xfree(macro->name); - for (i = 0; i < macro->num_params; i++) - yasm_xfree(macro->params[i]); - yasm_xfree(macro->params); - for (i = 0; i < macro->num_lines; i++) - yasm_xfree(macro->lines[i]); - yasm_xfree(macro->lines); - yasm_xfree(macro); - } - yasm_xfree(preproc); -} - -static char * -gas_preproc_get_line(yasm_preproc *preproc) -{ - yasm_preproc_gas *pp = (yasm_preproc_gas *)preproc; - int done = FALSE; - char *line = NULL; - - pp->current_line_number++; - - do { - if (line != NULL) { - yasm_xfree(line); - } - if (pp->fatal_error) { - return NULL; - } - line = read_line(pp); - if (line == NULL) { - if (pp->in_comment) { - yasm_linemap_set(pp->cur_lm, pp->in_filename, pp->current_line_number, pp->next_line_number, 0); - yasm_warn_set(YASM_WARN_GENERAL, N_("end of file in comment")); - yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); - pp->in_comment = FALSE; - } - return NULL; - } - done = process_line(pp, &line); - } while (!done); - - yasm_linemap_set(pp->cur_lm, pp->in_filename, pp->current_line_number, pp->next_line_number, 0); - - return line; -} - -static size_t -gas_preproc_get_included_file(yasm_preproc *preproc, char *buf, - size_t max_size) -{ - /* TODO */ - return 0; -} - -static void -gas_preproc_add_include_file(yasm_preproc *preproc, const char *filename) -{ - yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; - eval_include(pp, 0, filename); -} - -static void -gas_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) -{ - yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; - const char *eq = strstr(macronameval, "="); - char *name, *value; - if (eq) { - value = yasm__xstrdup(eq + 1); - name = yasm_xmalloc(eq - macronameval + 1); - memcpy(name, macronameval, eq - macronameval); - name[eq - macronameval] = '\0'; - } else { - name = yasm__xstrdup(macronameval); - value = yasm__xstrdup(""); - } - eval_set(pp, 1, name, value); - yasm_xfree(name); - yasm_xfree(value); -} - -static void -gas_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) -{ - /* TODO */ -} - -static void -gas_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) -{ - /* TODO */ -} - -static void -gas_preproc_add_standard(yasm_preproc *preproc, const char **macros) -{ - /* TODO */ -} - - -/* Define preproc structure -- see preproc.h for details */ -yasm_preproc_module yasm_gas_LTX_preproc = { - "GNU AS (GAS)-compatible preprocessor", - "gas", - gas_preproc_create, - gas_preproc_destroy, - gas_preproc_get_line, - gas_preproc_get_included_file, - gas_preproc_add_include_file, - gas_preproc_predefine_macro, - gas_preproc_undefine_macro, - gas_preproc_define_builtin, - gas_preproc_add_standard -}; + } + } else { + f = stdin; + } + + pp->preproc.module = &yasm_gas_LTX_preproc; + pp->in = f; + pp->in_filename = yasm__xstrdup(in_filename); + pp->defines = yasm_symtab_create(); + SLIST_INIT(&pp->deferred_defines); + yasm_symtab_set_case_sensitive(pp->defines, 1); + pp->depth = 0; + pp->skip_depth = 0; + pp->in_comment = FALSE; + SLIST_INIT(&pp->buffered_lines); + SLIST_INIT(&pp->included_files); + STAILQ_INIT(&pp->macros); + pp->in_line_number = 0; + pp->next_line_number = 0; + pp->current_line_number = 0; + pp->cur_lm = lm; + pp->errwarns = errwarns; + pp->fatal_error = 0; + pp->detect_errors_only = 0; + + return (yasm_preproc *) pp; +} + +static void +gas_preproc_destroy(yasm_preproc *preproc) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; + yasm_xfree(pp->in_filename); + yasm_symtab_destroy(pp->defines); + while (!SLIST_EMPTY(&pp->deferred_defines)) { + deferred_define *def = SLIST_FIRST(&pp->deferred_defines); + SLIST_REMOVE_HEAD(&pp->deferred_defines, next); + yasm_xfree(def->name); + yasm_xfree(def->value); + yasm_xfree(def); + } + while (!SLIST_EMPTY(&pp->buffered_lines)) { + buffered_line *bline = SLIST_FIRST(&pp->buffered_lines); + SLIST_REMOVE_HEAD(&pp->buffered_lines, next); + yasm_xfree(bline->line); + yasm_xfree(bline); + } + while (!SLIST_EMPTY(&pp->included_files)) { + included_file *inc_file = SLIST_FIRST(&pp->included_files); + SLIST_REMOVE_HEAD(&pp->included_files, next); + yasm_xfree(inc_file->filename); + yasm_xfree(inc_file); + } + while (!STAILQ_EMPTY(&pp->macros)) { + int i; + macro_entry *macro = STAILQ_FIRST(&pp->macros); + STAILQ_REMOVE_HEAD(&pp->macros, next); + yasm_xfree(macro->name); + for (i = 0; i < macro->num_params; i++) + yasm_xfree(macro->params[i]); + yasm_xfree(macro->params); + for (i = 0; i < macro->num_lines; i++) + yasm_xfree(macro->lines[i]); + yasm_xfree(macro->lines); + yasm_xfree(macro); + } + yasm_xfree(preproc); +} + +static char * +gas_preproc_get_line(yasm_preproc *preproc) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *)preproc; + int done = FALSE; + char *line = NULL; + + pp->current_line_number++; + + do { + if (line != NULL) { + yasm_xfree(line); + } + if (pp->fatal_error) { + return NULL; + } + line = read_line(pp); + if (line == NULL) { + if (pp->in_comment) { + yasm_linemap_set(pp->cur_lm, pp->in_filename, pp->current_line_number, pp->next_line_number, 0); + yasm_warn_set(YASM_WARN_GENERAL, N_("end of file in comment")); + yasm_errwarn_propagate(pp->errwarns, pp->current_line_number); + pp->in_comment = FALSE; + } + return NULL; + } + done = process_line(pp, &line); + } while (!done); + + yasm_linemap_set(pp->cur_lm, pp->in_filename, pp->current_line_number, pp->next_line_number, 0); + + return line; +} + +static size_t +gas_preproc_get_included_file(yasm_preproc *preproc, char *buf, + size_t max_size) +{ + /* TODO */ + return 0; +} + +static void +gas_preproc_add_include_file(yasm_preproc *preproc, const char *filename) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; + eval_include(pp, 0, filename); +} + +static void +gas_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) +{ + yasm_preproc_gas *pp = (yasm_preproc_gas *) preproc; + const char *eq = strstr(macronameval, "="); + char *name, *value; + if (eq) { + value = yasm__xstrdup(eq + 1); + name = yasm_xmalloc(eq - macronameval + 1); + memcpy(name, macronameval, eq - macronameval); + name[eq - macronameval] = '\0'; + } else { + name = yasm__xstrdup(macronameval); + value = yasm__xstrdup(""); + } + eval_set(pp, 1, name, value); + yasm_xfree(name); + yasm_xfree(value); +} + +static void +gas_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) +{ + /* TODO */ +} + +static void +gas_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) +{ + /* TODO */ +} + +static void +gas_preproc_add_standard(yasm_preproc *preproc, const char **macros) +{ + /* TODO */ +} + + +/* Define preproc structure -- see preproc.h for details */ +yasm_preproc_module yasm_gas_LTX_preproc = { + "GNU AS (GAS)-compatible preprocessor", + "gas", + gas_preproc_create, + gas_preproc_destroy, + gas_preproc_get_line, + gas_preproc_get_included_file, + gas_preproc_add_include_file, + gas_preproc_predefine_macro, + gas_preproc_undefine_macro, + gas_preproc_define_builtin, + gas_preproc_add_standard +}; diff --git a/contrib/tools/yasm/modules/preprocs/nasm/genversion.c b/contrib/tools/yasm/modules/preprocs/nasm/genversion.c index 0c509c0924..164b4d6b51 100644 --- a/contrib/tools/yasm/modules/preprocs/nasm/genversion.c +++ b/contrib/tools/yasm/modules/preprocs/nasm/genversion.c @@ -1,81 +1,81 @@ -/* - * - * Generate version.mac - * - * Copyright (C) 2006-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. - */ -#include "config.h" /* for PACKAGE_VERSION */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> - -int -main(int argc, char *argv[]) -{ - FILE *out; - int major, minor, subminor, patchlevel, matched; - - if (argc != 2) { - fprintf(stderr, "Usage: %s <outfile>\n", argv[0]); - return EXIT_FAILURE; - } - - matched = sscanf(PACKAGE_VERSION, "%d.%d.%d.%d", &major, &minor, &subminor, - &patchlevel); - - if (matched == 3) - patchlevel = 0; - else if (matched != 4) { - fprintf(stderr, "Version tokenizing error\n"); - return EXIT_FAILURE; - } - - out = fopen(argv[1], "wt"); - - if (!out) { - fprintf(stderr, "Could not open `%s'.\n", argv[1]); - return EXIT_FAILURE; - } - - fprintf(out, "; This file auto-generated by genversion.c" - " - don't edit it\n"); - - fprintf(out, "%%define __YASM_MAJOR__ %d\n", major); - fprintf(out, "%%define __YASM_MINOR__ %d\n", minor); - fprintf(out, "%%define __YASM_SUBMINOR__ %d\n", subminor); - fprintf(out, "%%define __YASM_BUILD__ %d\n", patchlevel); - fprintf(out, "%%define __YASM_PATCHLEVEL__ %d\n", patchlevel); - - /* Version id (hex number) */ - fprintf(out, "%%define __YASM_VERSION_ID__ 0%02x%02x%02x%02xh\n", major, - minor, subminor, patchlevel); - - /* Version string */ - fprintf(out, "%%define __YASM_VER__ \"%s\"\n", PACKAGE_VERSION); - fclose(out); - - return EXIT_SUCCESS; -} +/* + * + * Generate version.mac + * + * Copyright (C) 2006-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. + */ +#include "config.h" /* for PACKAGE_VERSION */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +int +main(int argc, char *argv[]) +{ + FILE *out; + int major, minor, subminor, patchlevel, matched; + + if (argc != 2) { + fprintf(stderr, "Usage: %s <outfile>\n", argv[0]); + return EXIT_FAILURE; + } + + matched = sscanf(PACKAGE_VERSION, "%d.%d.%d.%d", &major, &minor, &subminor, + &patchlevel); + + if (matched == 3) + patchlevel = 0; + else if (matched != 4) { + fprintf(stderr, "Version tokenizing error\n"); + return EXIT_FAILURE; + } + + out = fopen(argv[1], "wt"); + + if (!out) { + fprintf(stderr, "Could not open `%s'.\n", argv[1]); + return EXIT_FAILURE; + } + + fprintf(out, "; This file auto-generated by genversion.c" + " - don't edit it\n"); + + fprintf(out, "%%define __YASM_MAJOR__ %d\n", major); + fprintf(out, "%%define __YASM_MINOR__ %d\n", minor); + fprintf(out, "%%define __YASM_SUBMINOR__ %d\n", subminor); + fprintf(out, "%%define __YASM_BUILD__ %d\n", patchlevel); + fprintf(out, "%%define __YASM_PATCHLEVEL__ %d\n", patchlevel); + + /* Version id (hex number) */ + fprintf(out, "%%define __YASM_VERSION_ID__ 0%02x%02x%02x%02xh\n", major, + minor, subminor, patchlevel); + + /* Version string */ + fprintf(out, "%%define __YASM_VER__ \"%s\"\n", PACKAGE_VERSION); + fclose(out); + + return EXIT_SUCCESS; +} diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.c b/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.c index 859cad841a..e249484cd5 100644 --- a/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.c +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.c @@ -1,441 +1,441 @@ -/* eval.c expression evaluator for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * initial version 27/iii/95 by Simon Tatham - */ -#include <util.h> -#include <libyasm-stdint.h> -#include <libyasm/coretype.h> -#include <libyasm/intnum.h> -#include <libyasm/expr.h> -#include <libyasm/symrec.h> -#include <ctype.h> - -#include "nasm.h" -#include "nasmlib.h" -#include "nasm-eval.h" - -/* The assembler symbol table. */ -extern yasm_symtab *nasm_symtab; - -static scanner scan; /* Address of scanner routine */ -static efunc error; /* Address of error reporting routine */ - -static struct tokenval *tokval; /* The current token */ -static int i; /* The t_type of tokval */ - -static void *scpriv; - -/* - * Recursive-descent parser. Called with a single boolean operand, - * which is TRUE if the evaluation is critical (i.e. unresolved - * symbols are an error condition). Must update the global `i' to - * reflect the token after the parsed string. May return NULL. - * - * evaluate() should report its own errors: on return it is assumed - * that if NULL has been returned, the error has already been - * reported. - */ - -/* - * Grammar parsed is: - * - * expr : bexpr [ WRT expr6 ] - * bexpr : rexp0 or expr0 depending on relative-mode setting - * rexp0 : rexp1 [ {||} rexp1...] - * rexp1 : rexp2 [ {^^} rexp2...] - * rexp2 : rexp3 [ {&&} rexp3...] - * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ] - * expr0 : expr1 [ {|} expr1...] - * expr1 : expr2 [ {^} expr2...] - * expr2 : expr3 [ {&} expr3...] - * expr3 : expr4 [ {<<,>>} expr4...] - * expr4 : expr5 [ {+,-} expr5...] - * expr5 : expr6 [ {*,/,%,//,%%} expr6...] - * expr6 : { ~,+,-,SEG } expr6 - * | (bexpr) - * | symbol - * | $ - * | number - */ - -static yasm_expr *rexp0(void), *rexp1(void), *rexp2(void), *rexp3(void); - -static yasm_expr *expr0(void), *expr1(void), *expr2(void), *expr3(void); -static yasm_expr *expr4(void), *expr5(void), *expr6(void); - -static yasm_expr *(*bexpr)(void); - -static yasm_expr *rexp0(void) -{ - yasm_expr *e, *f; - - e = rexp1(); - if (!e) - return NULL; - - while (i == TOKEN_DBL_OR) - { - i = scan(scpriv, tokval); - f = rexp1(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_LOR, f, 0); +/* eval.c expression evaluator for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 27/iii/95 by Simon Tatham + */ +#include <util.h> +#include <libyasm-stdint.h> +#include <libyasm/coretype.h> +#include <libyasm/intnum.h> +#include <libyasm/expr.h> +#include <libyasm/symrec.h> +#include <ctype.h> + +#include "nasm.h" +#include "nasmlib.h" +#include "nasm-eval.h" + +/* The assembler symbol table. */ +extern yasm_symtab *nasm_symtab; + +static scanner scan; /* Address of scanner routine */ +static efunc error; /* Address of error reporting routine */ + +static struct tokenval *tokval; /* The current token */ +static int i; /* The t_type of tokval */ + +static void *scpriv; + +/* + * Recursive-descent parser. Called with a single boolean operand, + * which is TRUE if the evaluation is critical (i.e. unresolved + * symbols are an error condition). Must update the global `i' to + * reflect the token after the parsed string. May return NULL. + * + * evaluate() should report its own errors: on return it is assumed + * that if NULL has been returned, the error has already been + * reported. + */ + +/* + * Grammar parsed is: + * + * expr : bexpr [ WRT expr6 ] + * bexpr : rexp0 or expr0 depending on relative-mode setting + * rexp0 : rexp1 [ {||} rexp1...] + * rexp1 : rexp2 [ {^^} rexp2...] + * rexp2 : rexp3 [ {&&} rexp3...] + * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ] + * expr0 : expr1 [ {|} expr1...] + * expr1 : expr2 [ {^} expr2...] + * expr2 : expr3 [ {&} expr3...] + * expr3 : expr4 [ {<<,>>} expr4...] + * expr4 : expr5 [ {+,-} expr5...] + * expr5 : expr6 [ {*,/,%,//,%%} expr6...] + * expr6 : { ~,+,-,SEG } expr6 + * | (bexpr) + * | symbol + * | $ + * | number + */ + +static yasm_expr *rexp0(void), *rexp1(void), *rexp2(void), *rexp3(void); + +static yasm_expr *expr0(void), *expr1(void), *expr2(void), *expr3(void); +static yasm_expr *expr4(void), *expr5(void), *expr6(void); + +static yasm_expr *(*bexpr)(void); + +static yasm_expr *rexp0(void) +{ + yasm_expr *e, *f; + + e = rexp1(); + if (!e) + return NULL; + + while (i == TOKEN_DBL_OR) + { + i = scan(scpriv, tokval); + f = rexp1(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LOR, f, 0); + } + return e; +} + +static yasm_expr *rexp1(void) +{ + yasm_expr *e, *f; + + e = rexp2(); + if (!e) + return NULL; + + while (i == TOKEN_DBL_XOR) + { + i = scan(scpriv, tokval); + f = rexp2(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LXOR, f, 0); + } + return e; +} + +static yasm_expr *rexp2(void) +{ + yasm_expr *e, *f; + + e = rexp3(); + if (!e) + return NULL; + while (i == TOKEN_DBL_AND) + { + i = scan(scpriv, tokval); + f = rexp3(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_LAND, f, 0); + } + return e; +} + +static yasm_expr *rexp3(void) +{ + yasm_expr *e, *f; + + e = expr0(); + if (!e) + return NULL; + + while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || + i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) + { + int j = i; + i = scan(scpriv, tokval); + f = expr0(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (j) + { + case TOKEN_EQ: + e = yasm_expr_create_tree(e, YASM_EXPR_EQ, f, 0); + break; + case TOKEN_LT: + e = yasm_expr_create_tree(e, YASM_EXPR_LT, f, 0); + break; + case TOKEN_GT: + e = yasm_expr_create_tree(e, YASM_EXPR_GT, f, 0); + break; + case TOKEN_NE: + e = yasm_expr_create_tree(e, YASM_EXPR_NE, f, 0); + break; + case TOKEN_LE: + e = yasm_expr_create_tree(e, YASM_EXPR_LE, f, 0); + break; + case TOKEN_GE: + e = yasm_expr_create_tree(e, YASM_EXPR_GE, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr0(void) +{ + yasm_expr *e, *f; + + e = expr1(); + if (!e) + return NULL; + + while (i == '|') + { + i = scan(scpriv, tokval); + f = expr1(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_OR, f, 0); + } + return e; +} + +static yasm_expr *expr1(void) +{ + yasm_expr *e, *f; + + e = expr2(); + if (!e) + return NULL; + + while (i == '^') { + i = scan(scpriv, tokval); + f = expr2(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_XOR, f, 0); + } + return e; +} + +static yasm_expr *expr2(void) +{ + yasm_expr *e, *f; + + e = expr3(); + if (!e) + return NULL; + + while (i == '&') { + i = scan(scpriv, tokval); + f = expr3(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + e = yasm_expr_create_tree(e, YASM_EXPR_AND, f, 0); + } + return e; +} + +static yasm_expr *expr3(void) +{ + yasm_expr *e, *f; + + e = expr4(); + if (!e) + return NULL; + + while (i == TOKEN_SHL || i == TOKEN_SHR) + { + int j = i; + i = scan(scpriv, tokval); + f = expr4(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + + switch (j) { + case TOKEN_SHL: + e = yasm_expr_create_tree(e, YASM_EXPR_SHL, f, 0); + break; + case TOKEN_SHR: + e = yasm_expr_create_tree(e, YASM_EXPR_SHR, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr4(void) +{ + yasm_expr *e, *f; + + e = expr5(); + if (!e) + return NULL; + while (i == '+' || i == '-') + { + int j = i; + i = scan(scpriv, tokval); + f = expr5(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + switch (j) { + case '+': + e = yasm_expr_create_tree(e, YASM_EXPR_ADD, f, 0); + break; + case '-': + e = yasm_expr_create_tree(e, YASM_EXPR_SUB, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr5(void) +{ + yasm_expr *e, *f; + + e = expr6(); + if (!e) + return NULL; + while (i == '*' || i == '/' || i == '%' || + i == TOKEN_SDIV || i == TOKEN_SMOD) + { + int j = i; + i = scan(scpriv, tokval); + f = expr6(); + if (!f) { + yasm_expr_destroy(e); + return NULL; + } + switch (j) { + case '*': + e = yasm_expr_create_tree(e, YASM_EXPR_MUL, f, 0); + break; + case '/': + e = yasm_expr_create_tree(e, YASM_EXPR_DIV, f, 0); + break; + case '%': + e = yasm_expr_create_tree(e, YASM_EXPR_MOD, f, 0); + break; + case TOKEN_SDIV: + e = yasm_expr_create_tree(e, YASM_EXPR_SIGNDIV, f, 0); + break; + case TOKEN_SMOD: + e = yasm_expr_create_tree(e, YASM_EXPR_SIGNMOD, f, 0); + break; + } + } + return e; +} + +static yasm_expr *expr6(void) +{ + yasm_expr *e = NULL; + + if (i == '-') { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + return yasm_expr_create_branch(YASM_EXPR_NEG, e, 0); + } else if (i == '+') { + i = scan(scpriv, tokval); + return expr6(); + } else if (i == '~') { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + return yasm_expr_create_branch(YASM_EXPR_NOT, e, 0); + } else if (i == TOKEN_SEG) { + i = scan(scpriv, tokval); + e = expr6(); + if (!e) + return NULL; + error(ERR_NONFATAL, "%s not supported", "SEG"); + return e; + } else if (i == '(') { + i = scan(scpriv, tokval); + e = bexpr(); + if (!e) + return NULL; + if (i != ')') { + error(ERR_NONFATAL, "expecting `)'"); + return NULL; + } + i = scan(scpriv, tokval); + return e; } - return e; -} - -static yasm_expr *rexp1(void) -{ - yasm_expr *e, *f; - - e = rexp2(); - if (!e) - return NULL; - - while (i == TOKEN_DBL_XOR) - { - i = scan(scpriv, tokval); - f = rexp2(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_LXOR, f, 0); - } - return e; -} - -static yasm_expr *rexp2(void) -{ - yasm_expr *e, *f; - - e = rexp3(); - if (!e) - return NULL; - while (i == TOKEN_DBL_AND) - { - i = scan(scpriv, tokval); - f = rexp3(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_LAND, f, 0); - } - return e; -} - -static yasm_expr *rexp3(void) -{ - yasm_expr *e, *f; - - e = expr0(); - if (!e) - return NULL; - - while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || - i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) - { - int j = i; - i = scan(scpriv, tokval); - f = expr0(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - switch (j) - { - case TOKEN_EQ: - e = yasm_expr_create_tree(e, YASM_EXPR_EQ, f, 0); - break; - case TOKEN_LT: - e = yasm_expr_create_tree(e, YASM_EXPR_LT, f, 0); - break; - case TOKEN_GT: - e = yasm_expr_create_tree(e, YASM_EXPR_GT, f, 0); - break; - case TOKEN_NE: - e = yasm_expr_create_tree(e, YASM_EXPR_NE, f, 0); - break; - case TOKEN_LE: - e = yasm_expr_create_tree(e, YASM_EXPR_LE, f, 0); - break; - case TOKEN_GE: - e = yasm_expr_create_tree(e, YASM_EXPR_GE, f, 0); - break; - } - } - return e; -} - -static yasm_expr *expr0(void) -{ - yasm_expr *e, *f; - - e = expr1(); - if (!e) - return NULL; - - while (i == '|') - { - i = scan(scpriv, tokval); - f = expr1(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_OR, f, 0); - } - return e; -} - -static yasm_expr *expr1(void) -{ - yasm_expr *e, *f; - - e = expr2(); - if (!e) - return NULL; - - while (i == '^') { - i = scan(scpriv, tokval); - f = expr2(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_XOR, f, 0); - } - return e; -} - -static yasm_expr *expr2(void) -{ - yasm_expr *e, *f; - - e = expr3(); - if (!e) - return NULL; - - while (i == '&') { - i = scan(scpriv, tokval); - f = expr3(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - e = yasm_expr_create_tree(e, YASM_EXPR_AND, f, 0); - } - return e; -} - -static yasm_expr *expr3(void) -{ - yasm_expr *e, *f; - - e = expr4(); - if (!e) - return NULL; - - while (i == TOKEN_SHL || i == TOKEN_SHR) - { - int j = i; - i = scan(scpriv, tokval); - f = expr4(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - - switch (j) { - case TOKEN_SHL: - e = yasm_expr_create_tree(e, YASM_EXPR_SHL, f, 0); - break; - case TOKEN_SHR: - e = yasm_expr_create_tree(e, YASM_EXPR_SHR, f, 0); - break; - } - } - return e; -} - -static yasm_expr *expr4(void) -{ - yasm_expr *e, *f; - - e = expr5(); - if (!e) - return NULL; - while (i == '+' || i == '-') - { - int j = i; - i = scan(scpriv, tokval); - f = expr5(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - switch (j) { - case '+': - e = yasm_expr_create_tree(e, YASM_EXPR_ADD, f, 0); - break; - case '-': - e = yasm_expr_create_tree(e, YASM_EXPR_SUB, f, 0); - break; - } - } - return e; -} - -static yasm_expr *expr5(void) -{ - yasm_expr *e, *f; - - e = expr6(); - if (!e) - return NULL; - while (i == '*' || i == '/' || i == '%' || - i == TOKEN_SDIV || i == TOKEN_SMOD) - { - int j = i; - i = scan(scpriv, tokval); - f = expr6(); - if (!f) { - yasm_expr_destroy(e); - return NULL; - } - switch (j) { - case '*': - e = yasm_expr_create_tree(e, YASM_EXPR_MUL, f, 0); - break; - case '/': - e = yasm_expr_create_tree(e, YASM_EXPR_DIV, f, 0); - break; - case '%': - e = yasm_expr_create_tree(e, YASM_EXPR_MOD, f, 0); - break; - case TOKEN_SDIV: - e = yasm_expr_create_tree(e, YASM_EXPR_SIGNDIV, f, 0); - break; - case TOKEN_SMOD: - e = yasm_expr_create_tree(e, YASM_EXPR_SIGNMOD, f, 0); - break; - } - } - return e; -} - -static yasm_expr *expr6(void) -{ - yasm_expr *e = NULL; - - if (i == '-') { - i = scan(scpriv, tokval); - e = expr6(); - if (!e) - return NULL; - return yasm_expr_create_branch(YASM_EXPR_NEG, e, 0); - } else if (i == '+') { - i = scan(scpriv, tokval); - return expr6(); - } else if (i == '~') { - i = scan(scpriv, tokval); - e = expr6(); - if (!e) - return NULL; - return yasm_expr_create_branch(YASM_EXPR_NOT, e, 0); - } else if (i == TOKEN_SEG) { - i = scan(scpriv, tokval); - e = expr6(); - if (!e) - return NULL; - error(ERR_NONFATAL, "%s not supported", "SEG"); - return e; - } else if (i == '(') { - i = scan(scpriv, tokval); - e = bexpr(); - if (!e) - return NULL; - if (i != ')') { - error(ERR_NONFATAL, "expecting `)'"); - return NULL; - } - i = scan(scpriv, tokval); - return e; - } - else if (i == TOKEN_NUM || i == TOKEN_ID || - i == TOKEN_HERE || i == TOKEN_BASE) - { - switch (i) { - case TOKEN_NUM: - e = yasm_expr_create_ident(yasm_expr_int(tokval->t_integer), 0); - break; - case TOKEN_ID: - if (nasm_symtab) { - yasm_symrec *sym = - yasm_symtab_get(nasm_symtab, tokval->t_charptr); - if (sym) { - e = yasm_expr_create_ident(yasm_expr_sym(sym), 0); - } else { - error(ERR_NONFATAL, - "undefined symbol `%s' in preprocessor", - tokval->t_charptr); - e = yasm_expr_create_ident(yasm_expr_int( - yasm_intnum_create_int(1)), 0); - } - break; - } - /*fallthrough*/ - case TOKEN_HERE: - case TOKEN_BASE: - error(ERR_NONFATAL, - "cannot reference symbol `%s' in preprocessor", - (i == TOKEN_ID ? tokval->t_charptr : - i == TOKEN_HERE ? "$" : "$$")); - e = yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_int(1)), - 0); - break; - } - i = scan(scpriv, tokval); - return e; - } else { - error(ERR_NONFATAL, "expression syntax error"); - return NULL; - } -} - -yasm_expr *nasm_evaluate (scanner sc, void *scprivate, struct tokenval *tv, - int critical, efunc report_error) -{ - if (critical & CRITICAL) { - critical &= ~CRITICAL; - bexpr = rexp0; - } else - bexpr = expr0; - - scan = sc; - scpriv = scprivate; - tokval = tv; - error = report_error; - - if (tokval->t_type == TOKEN_INVALID) - i = scan(scpriv, tokval); - else - i = tokval->t_type; - - return bexpr (); -} + else if (i == TOKEN_NUM || i == TOKEN_ID || + i == TOKEN_HERE || i == TOKEN_BASE) + { + switch (i) { + case TOKEN_NUM: + e = yasm_expr_create_ident(yasm_expr_int(tokval->t_integer), 0); + break; + case TOKEN_ID: + if (nasm_symtab) { + yasm_symrec *sym = + yasm_symtab_get(nasm_symtab, tokval->t_charptr); + if (sym) { + e = yasm_expr_create_ident(yasm_expr_sym(sym), 0); + } else { + error(ERR_NONFATAL, + "undefined symbol `%s' in preprocessor", + tokval->t_charptr); + e = yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_int(1)), 0); + } + break; + } + /*fallthrough*/ + case TOKEN_HERE: + case TOKEN_BASE: + error(ERR_NONFATAL, + "cannot reference symbol `%s' in preprocessor", + (i == TOKEN_ID ? tokval->t_charptr : + i == TOKEN_HERE ? "$" : "$$")); + e = yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_int(1)), + 0); + break; + } + i = scan(scpriv, tokval); + return e; + } else { + error(ERR_NONFATAL, "expression syntax error"); + return NULL; + } +} + +yasm_expr *nasm_evaluate (scanner sc, void *scprivate, struct tokenval *tv, + int critical, efunc report_error) +{ + if (critical & CRITICAL) { + critical &= ~CRITICAL; + bexpr = rexp0; + } else + bexpr = expr0; + + scan = sc; + scpriv = scprivate; + tokval = tv; + error = report_error; + + if (tokval->t_type == TOKEN_INVALID) + i = scan(scpriv, tokval); + else + i = tokval->t_type; + + return bexpr (); +} diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.h b/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.h index a02c8d83e6..f06937c5cc 100644 --- a/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.h +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-eval.h @@ -1,18 +1,18 @@ -/* eval.h header file for eval.c - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#ifndef NASM_EVAL_H -#define NASM_EVAL_H - -/* - * The evaluator itself. - */ -yasm_expr *nasm_evaluate (scanner sc, void *scprivate, struct tokenval *tv, - int critical, efunc report_error); - -#endif +/* eval.h header file for eval.c + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef NASM_EVAL_H +#define NASM_EVAL_H + +/* + * The evaluator itself. + */ +yasm_expr *nasm_evaluate (scanner sc, void *scprivate, struct tokenval *tv, + int critical, efunc report_error); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.c b/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.c index e530f728a6..27a8cc6c93 100644 --- a/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.c +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.c @@ -1,5317 +1,5317 @@ -/* -*- mode: c; c-file-style: "bsd" -*- */ -/* preproc.c macro preprocessor for the Netwide Assembler +/* -*- mode: c; c-file-style: "bsd" -*- */ +/* preproc.c macro preprocessor for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 18/iii/97 by Simon Tatham + */ + +/* Typical flow of text through preproc + * + * pp_getline gets tokenised lines, either + * + * from a macro expansion + * + * or + * { + * read_line gets raw text from stdmacpos, or predef, or current input file + * tokenise converts to tokens + * } + * + * expand_mmac_params is used to expand %1 etc., unless a macro is being + * defined or a false conditional is being processed + * (%0, %1, %+1, %-1, %%foo + * + * do_directive checks for directives + * + * expand_smacro is used to expand single line macros + * + * expand_mmacro is used to expand multi-line macros + * + * detoken is used to convert the line back to text + */ +#include <util.h> +#include <libyasm-stdint.h> +#include <libyasm/coretype.h> +#include <libyasm/intnum.h> +#include <libyasm/expr.h> +#include <libyasm/file.h> +#include <stdarg.h> +#include <ctype.h> +#include <limits.h> + +#include "nasm.h" +#include "nasmlib.h" +#include "nasm-pp.h" + +typedef struct SMacro SMacro; +typedef struct MMacro MMacro; +typedef struct Context Context; +typedef struct Token Token; +typedef struct Blocks Blocks; +typedef struct Line Line; +typedef struct Include Include; +typedef struct Cond Cond; + +/* + * Store the definition of a single-line macro. + */ +struct SMacro +{ + SMacro *next; + char *name; + int level; + int casesense; + int nparam; + int in_progress; + Token *expansion; +}; + +/* + * Store the definition of a multi-line macro. This is also used to + * store the interiors of `%rep...%endrep' blocks, which are + * effectively self-re-invoking multi-line macros which simply + * don't have a name or bother to appear in the hash tables. %rep + * blocks are signified by having a NULL `name' field. + * + * In a MMacro describing a `%rep' block, the `in_progress' field + * isn't merely boolean, but gives the number of repeats left to + * run. + * + * The `next' field is used for storing MMacros in hash tables; the + * `next_active' field is for stacking them on istk entries. + * + * When a MMacro is being expanded, `params', `iline', `nparam', + * `paramlen', `rotate' and `unique' are local to the invocation. + */ +struct MMacro +{ + MMacro *next; + char *name; + int casesense; + long nparam_min, nparam_max; + int plus; /* is the last parameter greedy? */ + int nolist; /* is this macro listing-inhibited? */ + int in_progress; + Token *dlist; /* All defaults as one list */ + Token **defaults; /* Parameter default pointers */ + int ndefs; /* number of default parameters */ + Line *expansion; + + MMacro *next_active; + MMacro *rep_nest; /* used for nesting %rep */ + Token **params; /* actual parameters */ + Token *iline; /* invocation line */ + long nparam, rotate, *paramlen; + unsigned long unique; + int lineno; /* Current line number on expansion */ +}; + +/* + * The context stack is composed of a linked list of these. + */ +struct Context +{ + Context *next; + SMacro *localmac; + char *name; + unsigned long number; +}; + +/* + * 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_PARAM is not + * necessarily used as-is, but is intended to denote the number of + * the substituted parameter. So in the definition + * + * %define a(x,y) ( (x) & ~(y) ) * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. + * the token representing `x' will have its type changed to + * TOK_SMAC_PARAM, but the one representing `y' will be + * TOK_SMAC_PARAM+1. + * + * TOK_INTERNAL_STRING is a dirty hack: it's a single string token + * which doesn't need quotes around it. Used in the pre-include + * mechanism as an alternative to trying to find a sensible type of + * quote to use on the filename we were passed. + */ +struct Token +{ + Token *next; + char *text; + SMacro *mac; /* associated macro for TOK_SMAC_END */ + int type; +}; +enum +{ + TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING, + TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_SMAC_PARAM, + TOK_INTERNAL_STRING +}; + +/* + * Multi-line macro definitions are stored as a linked list of + * these, which is essentially a container to allow several linked + * lists of Tokens. * - * initial version 18/iii/97 by Simon Tatham - */ - -/* Typical flow of text through preproc - * - * pp_getline gets tokenised lines, either - * - * from a macro expansion - * - * or - * { - * read_line gets raw text from stdmacpos, or predef, or current input file - * tokenise converts to tokens - * } - * - * expand_mmac_params is used to expand %1 etc., unless a macro is being - * defined or a false conditional is being processed - * (%0, %1, %+1, %-1, %%foo - * - * do_directive checks for directives - * - * expand_smacro is used to expand single line macros - * - * expand_mmacro is used to expand multi-line macros - * - * detoken is used to convert the line back to text - */ -#include <util.h> -#include <libyasm-stdint.h> -#include <libyasm/coretype.h> -#include <libyasm/intnum.h> -#include <libyasm/expr.h> -#include <libyasm/file.h> -#include <stdarg.h> -#include <ctype.h> -#include <limits.h> - -#include "nasm.h" -#include "nasmlib.h" -#include "nasm-pp.h" - -typedef struct SMacro SMacro; -typedef struct MMacro MMacro; -typedef struct Context Context; -typedef struct Token Token; -typedef struct Blocks Blocks; -typedef struct Line Line; -typedef struct Include Include; -typedef struct Cond Cond; - -/* - * Store the definition of a single-line macro. - */ -struct SMacro -{ - SMacro *next; - char *name; - int level; - int casesense; - int nparam; - int in_progress; - Token *expansion; -}; - -/* - * Store the definition of a multi-line macro. This is also used to - * store the interiors of `%rep...%endrep' blocks, which are - * effectively self-re-invoking multi-line macros which simply - * don't have a name or bother to appear in the hash tables. %rep - * blocks are signified by having a NULL `name' field. - * - * In a MMacro describing a `%rep' block, the `in_progress' field - * isn't merely boolean, but gives the number of repeats left to - * run. - * - * The `next' field is used for storing MMacros in hash tables; the - * `next_active' field is for stacking them on istk entries. - * - * When a MMacro is being expanded, `params', `iline', `nparam', - * `paramlen', `rotate' and `unique' are local to the invocation. - */ -struct MMacro -{ - MMacro *next; - char *name; - int casesense; - long nparam_min, nparam_max; - int plus; /* is the last parameter greedy? */ - int nolist; /* is this macro listing-inhibited? */ - int in_progress; - Token *dlist; /* All defaults as one list */ - Token **defaults; /* Parameter default pointers */ - int ndefs; /* number of default parameters */ - Line *expansion; - - MMacro *next_active; - MMacro *rep_nest; /* used for nesting %rep */ - Token **params; /* actual parameters */ - Token *iline; /* invocation line */ - long nparam, rotate, *paramlen; - unsigned long unique; - int lineno; /* Current line number on expansion */ -}; - -/* - * The context stack is composed of a linked list of these. - */ -struct Context -{ - Context *next; - SMacro *localmac; - char *name; - unsigned long number; -}; - -/* - * 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_PARAM is not - * necessarily used as-is, but is intended to denote the number of - * the substituted parameter. So in the definition - * - * %define a(x,y) ( (x) & ~(y) ) - * - * the token representing `x' will have its type changed to - * TOK_SMAC_PARAM, but the one representing `y' will be - * TOK_SMAC_PARAM+1. - * - * TOK_INTERNAL_STRING is a dirty hack: it's a single string token - * which doesn't need quotes around it. Used in the pre-include - * mechanism as an alternative to trying to find a sensible type of - * quote to use on the filename we were passed. - */ -struct Token -{ - Token *next; - char *text; - SMacro *mac; /* associated macro for TOK_SMAC_END */ - int type; -}; -enum -{ - TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING, - TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_SMAC_PARAM, - TOK_INTERNAL_STRING -}; - -/* - * Multi-line macro definitions are stored as a linked list of - * these, which is essentially a container to allow several linked - * lists of Tokens. - * - * Note that in this module, linked lists are treated as stacks - * wherever possible. For this reason, Lines are _pushed_ on to the - * `expansion' field in MMacro structures, so that the linked list, - * if walked, would give the macro lines in reverse order; this - * means that we can walk the list when expanding a macro, and thus - * push the lines on to the `expansion' field in _istk_ in reverse - * order (so that when popped back off they are in the right - * order). It may seem cockeyed, and it relies on my design having - * an even number of steps in, but it works... - * - * Some of these structures, rather than being actual lines, are - * markers delimiting the end of the expansion of a given macro. - * This is for use in the cycle-tracking and %rep-handling code. - * Such structures have `finishes' non-NULL, and `first' NULL. All - * others have `finishes' NULL, but `first' may still be NULL if - * the line is blank. - */ -struct Line -{ - Line *next; - MMacro *finishes; - Token *first; -}; - -/* - * To handle an arbitrary level of file inclusion, we maintain a - * stack (ie linked list) of these things. - */ -struct Include -{ - Include *next; - FILE *fp; - Cond *conds; - Line *expansion; - char *fname; - int lineno, lineinc; - MMacro *mstk; /* stack of active macros/reps */ -}; - -/* - * Conditional assembly: we maintain a separate stack of these for - * each level of file inclusion. (The only reason we keep the - * stacks separate is to ensure that a stray `%endif' in a file - * included from within the true branch of a `%if' won't terminate - * it and cause confusion: instead, rightly, it'll cause an error.) - */ -struct Cond -{ - Cond *next; - int state; -}; -enum -{ - /* - * These states are for use just after %if or %elif: IF_TRUE - * means the condition has evaluated to truth so we are - * currently emitting, whereas IF_FALSE means we are not - * currently emitting but will start doing so if a %else comes - * up. In these states, all directives are admissible: %elif, - * %else and %endif. (And of course %if.) - */ - COND_IF_TRUE, COND_IF_FALSE, - /* - * These states come up after a %else: ELSE_TRUE means we're - * emitting, and ELSE_FALSE means we're not. In ELSE_* states, - * any %elif or %else will cause an error. - */ - COND_ELSE_TRUE, COND_ELSE_FALSE, - /* - * This state means that we're not emitting now, and also that - * nothing until %endif will be emitted at all. It's for use in - * two circumstances: (i) when we've had our moment of emission - * and have now started seeing %elifs, and (ii) when the - * condition construct in question is contained within a - * non-emitting branch of a larger condition construct. - */ - COND_NEVER -}; -#define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE ) - -/* - * These defines are used as the possible return values for do_directive - */ -#define NO_DIRECTIVE_FOUND 0 -#define DIRECTIVE_FOUND 1 - -/* - * Condition codes. Note that we use c_ prefix not C_ because C_ is - * used in nasm.h for the "real" condition codes. At _this_ level, - * we treat CXZ and ECXZ as condition codes, albeit non-invertible - * ones, so we need a different enum... - */ -static const char *conditions[] = { - "a", "ae", "b", "be", "c", "cxz", "e", "ecxz", "g", "ge", "l", "le", - "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", - "np", "ns", "nz", "o", "p", "pe", "po", "s", "z" -}; -enum -{ - c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE, - c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO, - c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_S, c_Z -}; -static int inverse_ccs[] = { - c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE, - c_A, c_AE, c_B, c_BE, c_C, c_E, c_G, c_GE, c_L, c_LE, c_O, c_P, c_S, - c_Z, c_NO, c_NP, c_PO, c_PE, c_NS, c_NZ -}; - -/* - * Directive names. - */ -static const char *directives[] = { - "%arg", - "%assign", "%clear", "%define", "%elif", "%elifctx", "%elifdef", - "%elifid", "%elifidn", "%elifidni", "%elifmacro", "%elifnctx", "%elifndef", - "%elifnid", "%elifnidn", "%elifnidni", "%elifnmacro", "%elifnnum", "%elifnstr", - "%elifnum", "%elifstr", "%else", "%endif", "%endm", "%endmacro", - "%endrep", "%endscope", "%error", "%exitrep", "%iassign", "%idefine", "%if", - "%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifmacro", "%ifnctx", - "%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnmacro", "%ifnnum", - "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", - "%ixdefine", "%line", - "%local", - "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", - "%scope", "%stacksize", - "%strlen", "%substr", "%undef", "%xdefine" -}; -enum -{ - PP_ARG, - PP_ASSIGN, PP_CLEAR, PP_DEFINE, PP_ELIF, PP_ELIFCTX, PP_ELIFDEF, - PP_ELIFID, PP_ELIFIDN, PP_ELIFIDNI, PP_ELIFMACRO, PP_ELIFNCTX, PP_ELIFNDEF, - PP_ELIFNID, PP_ELIFNIDN, PP_ELIFNIDNI, PP_ELIFNMACRO, PP_ELIFNNUM, PP_ELIFNSTR, - PP_ELIFNUM, PP_ELIFSTR, PP_ELSE, PP_ENDIF, PP_ENDM, PP_ENDMACRO, - PP_ENDREP, PP_ENDSCOPE, PP_ERROR, PP_EXITREP, PP_IASSIGN, PP_IDEFINE, PP_IF, - PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFMACRO, PP_IFNCTX, - PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNMACRO, PP_IFNNUM, - PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, - PP_IXDEFINE, PP_LINE, - PP_LOCAL, - PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, - PP_SCOPE, PP_STACKSIZE, - PP_STRLEN, PP_SUBSTR, PP_UNDEF, PP_XDEFINE -}; - -/* If this is a an IF, ELIF, ELSE or ENDIF keyword */ -static int is_condition(int arg) -{ - return ((arg >= PP_ELIF) && (arg <= PP_ENDIF)) || - ((arg >= PP_IF) && (arg <= PP_IFSTR)); -} - -/* 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. - */ - -#ifndef MAX -# define MAX(a,b) ( ((a) > (b)) ? (a) : (b)) -#endif - -enum -{ - TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI, - TM_IFNDEF, TM_INCLUDE, TM_LOCAL, - TM_REPT, TM_IRP, TM_MACRO, - TM_STRUC, TM_SEGMENT -}; - -static const char *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; -static int LocalOffset = 4; -static int Level = 0; - - -static Context *cstk; -static Include *istk; - -static FILE *first_fp = NULL; - -static efunc _error; /* Pointer to client-provided error reporting function */ -static evalfunc evaluate; - -static int pass; /* HACK: pass 0 = generate dependencies only */ - -static unsigned long unique; /* unique identifier numbers */ - -static Line *builtindef = NULL; -static Line *stddef = NULL; -static Line *predef = NULL; -static int first_line = 1; - -static ListGen *list; - -/* - * The number of hash values we use for the macro lookup tables. - * FIXME: We should *really* be able to configure this at run time, - * or even have the hash table automatically expanding when necessary. - */ -#define NHASH 4096 - -/* - * The current set of multi-line macros we have defined. - */ -static MMacro *mmacros[NHASH]; - -/* - * The current set of single-line macros we have defined. - */ -static SMacro *smacros[NHASH]; - -/* - * The multi-line macro we are currently defining, or the %rep - * block we are currently reading, if any. - */ -static MMacro *defining; - -/* - * The number of macro parameters to allocate space for at a time. - */ -#define PARAM_DELTA 16 - -/* - * Macros to make NASM ignore some TASM directives before the first include - * directive. - */ -static const char *tasm_compat_macros[] = -{ - "%idefine IDEAL", - "%idefine JUMPS", - "%idefine END", - "%idefine P8086 CPU 8086", - "%idefine P186 CPU 186", - "%idefine P286 CPU 286", - "%idefine P286N CPU 286", - "%idefine P286P CPU 286 Priv", - "%idefine P386 CPU 386", - "%idefine P386N CPU 386", - "%idefine P386P CPU 386 Priv", - "%idefine P486 CPU 486", - "%idefine P586 CPU 586", - "%idefine .8086 CPU 8086", - "%idefine .186 CPU 186", - "%idefine .286 CPU 286", - "%idefine .286C CPU 286", - "%idefine .286P CPU 286", - "%idefine .386 CPU 386", - "%idefine .386C CPU 386", - "%idefine .386P CPU 386", - "%idefine .486 CPU 486", - "%idefine .486C CPU 486", - "%idefine .486P CPU 486", - "%idefine .586 CPU 586", - "%idefine .586C CPU 586", - "%idefine .586P CPU 586", - "", - "%imacro TITLE 1", - "%endm", - "%imacro NAME 1", - "%endm", - "", - "%imacro EXTRN 1-*.nolist", - "%rep %0", - "[extern %1]", - "%rotate 1", - "%endrep", - "%endmacro", - "", - "%imacro PUBLIC 1-*.nolist", - "%rep %0", - "[global %1]", - "%rotate 1", - "%endrep", - "%endmacro", - "", - "; this is not needed", - "%idefine PTR", - NULL -}; - -static int nested_mac_count, nested_rep_count; - -/* - * Tokens are allocated in blocks to improve speed - */ -#define TOKEN_BLOCKSIZE 4096 -static Token *freeTokens = NULL; -struct Blocks { - Blocks *next; - void *chunk; -}; - -static Blocks blocks = { NULL, NULL }; - -/* - * Forward declarations. - */ -static Token *expand_mmac_params(Token * tline); -static Token *expand_smacro(Token * tline); -static Token *expand_id(Token * tline); -static Context *get_ctx(char *name, int all_contexts); -static void make_tok_num(Token * tok, yasm_intnum *val); -static void error(int severity, const char *fmt, ...); -static void *new_Block(size_t size); -static void delete_Blocks(void); -static Token *new_Token(Token * next, int type, const char *text, - size_t txtlen); -static Token *delete_Token(Token * t); -static Token *tokenise(char *line); - -/* - * Macros for safe checking of token pointers, avoid *(NULL) - */ -#define tok_type_(x,t) ((x) && (x)->type == (t)) -#define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next -#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v))) -#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v)))) - -/* Handle TASM specific directives, which do not contain a % in - * front of them. We do it here because I could not find any other - * place to do it for the moment, and it is a hack (ideally it would - * be nice to be able to use the NASM pre-processor to do it). - */ - -typedef struct TMEndItem { - int type; - void *data; - struct TMEndItem *next; -} TMEndItem; - -static TMEndItem *EndmStack = NULL, *EndsStack = NULL; - -char **TMParameters; - -struct TStrucField { - char *name; - char *type; - struct TStrucField *next; -}; -struct TStruc { - char *name; - struct TStrucField *fields, *lastField; - struct TStruc *next; -}; -static struct TStruc *TStrucs = NULL; -static int inTstruc = 0; - -struct TSegmentAssume { - char *segreg; - char *segment; -}; -struct TSegmentAssume *TAssumes; - -const char *tasm_get_segment_register(const char *segment) -{ - struct TSegmentAssume *assume; - if (!TAssumes) - return NULL; - for (assume = TAssumes; assume->segreg; assume++) { - if (!strcmp(assume->segment, segment)) - break; - } - return assume->segreg; -} - -static char * -check_tasm_directive(char *line) -{ - int i, j, k, m; - size_t len, len2; - char *p, *oldline, oldchar, *q, oldchar2; - TMEndItem *end; - - p = line; - - /* Skip whitespace */ - while (isspace(*p) && *p != 0 && *p != ';') - p++; - - /* Ignore nasm directives */ - if (*p == '%') - return line; - - /* Binary search for the directive name */ - len = 0; - while (!isspace(p[len]) && p[len] != 0 && p[len] != ';') - len++; - if (!len) - return line; - - oldchar = p[len]; - p[len] = 0; - i = -1; - j = elements(tasm_directives); - 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; - if (k == TM_IFDIFI) - { - /* NASM does not recognise IFDIFI, so we convert it to - * %ifdef BOGUS. This is not used in NASM comaptible - * code, but does need to parse for the TASM macro - * package. - */ - line = nasm_malloc(13); - strcpy(line, "%ifdef BOGUS"); - } - else if (k == TM_INCLUDE) - { - /* add double quotes around file name */ - p += 7 + 1; - while (isspace(*p) && *p) - p++; - len = strlen(p); - line = nasm_malloc(1 + 7 + 1 + 1 + len + 1 + 1); - sprintf(line, "%%include \"%s\"", p); - } - else - { - line = nasm_malloc(len + 2); - line[0] = '%'; - memcpy(line + 1, p, len + 1); - } - nasm_free(oldline); - return line; - } - else if (m < 0) - { - j = k; - } - else - i = k; - } - - /* Not a simple directive */ - - if (!nasm_stricmp(p, "endm")) { - /* handle end of endm directive */ - char **parameter; - end = EndmStack; - /* undef parameters */ - if (!end) { - error(ERR_FATAL, "ENDM: not in an endm context"); - return line; - } - EndmStack = EndmStack->next; - nasm_free(line); - switch (end->type) { - case TM_MACRO: - len = 0; - for (parameter = end->data; *parameter; parameter++) - len += 6 + 1 + strlen(*parameter) + 1; - len += 5 + 1; - line = nasm_malloc(len); - p = line; - for (parameter = end->data; *parameter; parameter++) { - p += sprintf(p, "%%undef %s\n", *parameter); - nasm_free(*parameter); - } - nasm_free(end->data); - nasm_free(end); - sprintf(p, "%%endm"); - return line; - case TM_REPT: - nasm_free(end); - return nasm_strdup("%endrep"); - case TM_IRP: { - char **data; - const char *irp_format = - "%%undef %s\n" - "%%rotate 1\n" - "%%endrep\n" - "%%endm\n" - "irp %s\n" - "%%undef irp"; - data = end->data; - line = nasm_malloc(strlen(irp_format) - 4 + strlen(data[0]) - + strlen(data[1])); - sprintf(line, irp_format, data[0], data[1]); - nasm_free(data[0]); - nasm_free(data[1]); - nasm_free(data); - return line; - } - default: - error(ERR_FATAL, "ENDM: bogus endm context type %d\n",end->type); - return NULL; - } - } else if (!nasm_stricmp(p, "end")) { - nasm_free(line); - return nasm_strdup(""); - } else if (!nasm_stricmp(p, "rept")) { - /* handle repeat directive */ - end = nasm_malloc(sizeof(*end)); - end->type = TM_REPT; - end->next = EndmStack; - EndmStack = end; - memcpy(p, "%rep", 4); - p[len] = oldchar; - return line; - } else if (!nasm_stricmp(p, "locals")) { - tasm_locals = 1; - nasm_free(line); - return nasm_strdup(""); - } - - if (!oldchar) - return line; - - /* handle two-words directives */ - q = p + len + 1; - /* Skip whitespaces */ - while (isspace(*q) && *q) - q++; - - len2 = 0; - while (!isspace(q[len2]) && q[len2]!=',' && q[len2] != 0) - len2++; - oldchar2 = q[len2]; - q[len2] = '\0'; - - if (!nasm_stricmp(p, "irp")) { - /* handle indefinite repeat directive */ - const char *irp_format = - "%%imacro irp 0-*\n" - "%%rep %%0\n" - "%%define %s %%1\n"; - char **data; - - data = malloc(2*sizeof(char*)); - oldline = line; - line = nasm_malloc(strlen(irp_format) - 2 + len2 + 1); - sprintf(line,irp_format,q); - data[0] = nasm_strdup(q); - - if (!oldchar2) - error(ERR_FATAL, "%s: expected <values>", q + len2); - p = strchr(q + len2 + 1, '<'); - if (!p) - error(ERR_FATAL, "%s: expected <values>", q + len2); - p++; - q = strchr(p, '>'); - data[1] = nasm_strndup(p, q - p); - - end = nasm_malloc(sizeof(*end)); - end->type = TM_IRP; - end->next = EndmStack; - end->data = data; - EndmStack = end; - - nasm_free(oldline); - return line; - } else if (!nasm_stricmp(q, "macro")) { - char *name = p; - /* handle MACRO */ - /* count parameters */ - j = 1; - i = 0; - TMParameters = nasm_malloc(j*sizeof(*TMParameters)); - len = 0; - p = q + len2 + 1; - /* Skip whitespaces */ - while (isspace(*p) && *p) - p++; - while (*p) { - /* Get parameter name */ - for (q = p; !isspace(*q) && *q != ',' && *q; q++); - len2 = q-p; - if (len2 == 0) - error(ERR_FATAL, "'%s': expected parameter name", p); - TMParameters[i] = nasm_malloc(len2 + 1); - memcpy(TMParameters[i], p, len2); - TMParameters[i][len2] = '\0'; - len += len2; - i++; - if (i + 1 > j) { - j *= 2; - TMParameters = nasm_realloc(TMParameters, - j*sizeof(*TMParameters)); - } - if (i == 1000) - error(ERR_FATAL, "too many parameters for macro %s", name); - p = q; - while (isspace(*p) && *p) - p++; - if (!*p) - break; - if (*p != ',') - error(ERR_FATAL, "expected comma"); - p++; - while (isspace(*p) && *p) - p++; - } - TMParameters[i] = NULL; - TMParameters = nasm_realloc(TMParameters, - (i+1)*sizeof(*TMParameters)); - len += 1 + 6 + 1 + strlen(name) + 1 + 3; /* macro definition */ - len += i * (1 + 9 + 1 + 1 + 1 + 3 + 2); /* macro parameter definition */ - oldline = line; - p = line = nasm_malloc(len + 1); - p += sprintf(p, "%%imacro %s 0-*", name); - nasm_free(oldline); - for (j = 0; TMParameters[j]; j++) { - p += sprintf(p, "\n%%idefine %s %%{%-u}", TMParameters[j], j + 1); - } - end = nasm_malloc(sizeof(*end)); - end->type = TM_MACRO; - end->next = EndmStack; - end->data = TMParameters; - EndmStack = end; - return line; - } else if (!nasm_stricmp(q, "proc")) { - /* handle PROC */ - oldline = line; - line = nasm_malloc(2 + len + 1); - sprintf(line, "..%s",p); - nasm_free(oldline); - return line; - } else if (!nasm_stricmp(q, "struc")) { - /* handle struc */ - struct TStruc *struc; - if (inTstruc) { - error(ERR_FATAL, "STRUC: already in a struc context"); - return line; - } - oldline = line; - line = nasm_malloc(5 + 1 + len + 1); - sprintf(line, "struc %s", p); - struc = malloc(sizeof(*struc)); - struc->name = nasm_strdup(p); - struc->fields = NULL; - struc->lastField = NULL; - struc->next = TStrucs; - TStrucs = struc; - inTstruc = 1; - nasm_free(oldline); - end = nasm_malloc(sizeof(*end)); - end->type = TM_STRUC; - end->next = EndsStack; - EndsStack = end; - return line; - } else if (!nasm_stricmp(q, "segment")) { - /* handle SEGMENT */ - oldline = line; - line = nasm_strdup(oldchar2?q+len2+1:""); - if (tasm_segment) { - error(ERR_FATAL, "SEGMENT: already in a segment context"); - return line; - } - tasm_segment = nasm_strdup(p); - nasm_free(oldline); - end = nasm_malloc(sizeof(*end)); - end->type = TM_SEGMENT; - end->next = EndsStack; - EndsStack = end; - return line; - } else if (!nasm_stricmp(p, "ends") || !nasm_stricmp(q, "ends")) { - /* handle end of ends directive */ - end = EndsStack; - /* undef parameters */ - if (!end) { - error(ERR_FATAL, "ENDS: not in an ends context"); - return line; - } - EndsStack = EndsStack->next; - nasm_free(line); - switch (end->type) { - case TM_STRUC: - inTstruc = 0; - return nasm_strdup("endstruc"); - case TM_SEGMENT: - /* XXX: yes, we leak memory here, but that permits labels - * to avoid strduping... */ - tasm_segment = NULL; - return nasm_strdup(""); - default: - error(ERR_FATAL, "ENDS: bogus ends context type %d",end->type); - return NULL; - } - } else if (!nasm_stricmp(p, "endp") || !nasm_stricmp(q, "endp")) { - nasm_free(line); - return nasm_strdup(""); - } else if (!nasm_stricmp(p, "assume")) { - struct TSegmentAssume *assume; - /* handle ASSUME */ - if (!TAssumes) { - TAssumes = nasm_malloc(sizeof(*TAssumes)); - TAssumes[0].segreg = NULL; - } - i = 0; - q[len2] = oldchar2; - /* Skip whitespaces */ - while (isspace(*q) && *q) - q++; - while (*q && *q != ';') { - p = q; - for (; *q && *q != ';' && *q != ':' && !isspace(*q); q++); - if (!*q || *q == ';') - break; - /* segment register name */ - for (assume = TAssumes; assume->segreg; assume++) - if (strlen(assume->segreg) == (size_t)(q-p) && - !yasm__strncasecmp(assume->segreg, p, q-p)) - break; - if (!assume->segreg) { - i = assume - TAssumes + 1; - TAssumes = nasm_realloc(TAssumes, (i+1)*sizeof(*TAssumes)); - assume = TAssumes + i - 1; - assume->segreg = nasm_strndup(p, q-p); - assume[1].segreg = NULL; - } - for (; *q && *q != ';' && *q != ':' && isspace(*q); q++); - if (*q != ':') - error(ERR_FATAL, "expected `:' instead of `%c'", *q); - for (q++; *q && isspace(*q); q++); - - /* segment name */ - p = q; - for (; *q && *q != ';' && *q != ',' && !isspace(*q); q++); - assume->segment = nasm_strndup(p, q-p); - for (; *q && isspace(*q); q++); - if (*q && *q != ';' && *q != ',') - error(ERR_FATAL, "expected `,' instead of `%c'", *q); - - if (*q && *q != ';') - q++; - for (; *q && isspace(*q); q++); - } - TAssumes[i].segreg = NULL; - TAssumes = nasm_realloc(TAssumes, (i+1)*sizeof(*TAssumes)); - nasm_free(line); - return nasm_strdup(""); - } else if (inTstruc) { - struct TStrucField *field; - /* TODO: handle unnamed data */ - field = nasm_malloc(sizeof(*field)); - field->name = nasm_strdup(p); - /* TODO: type struc ! */ - field->type = nasm_strdup(q); - field->next = NULL; - if (!TStrucs->fields) - TStrucs->fields = field; - else if (TStrucs->lastField) - TStrucs->lastField->next = field; - TStrucs->lastField = field; - if (!oldchar2) { - error(ERR_FATAL, "Expected struc field initializer after %s %s", p, q); - return line; - } - oldline = line; - line = nasm_malloc(1 + len + 1 + len2 + 1 + strlen(q+len2+1) + 1); - sprintf(line, ".%s %s %s", p, q, q+len2+1); - nasm_free(oldline); - return line; - } - { - struct TStruc *struc; - for (struc = TStrucs; struc; struc = struc->next) { - if (!yasm__strcasecmp(q, struc->name)) { - char *r = q + len2 + 1, *s, *t, tasm_param[6]; - struct TStrucField *field = struc->fields; - int size, n; - if (!oldchar2) { - error(ERR_FATAL, "Expected struc field initializer after %s %s", p, q); - return line; - } - r = strchr(r, '<'); - if (!r) { - error(ERR_FATAL, "Expected < for struc field initializer in %s %s %s", p, q, r); - return line; - } - t = strchr(r + 1, '>'); - if (!t) { - error(ERR_FATAL, "Expected > for struc field initializer in %s %s %s", p, q, r); - return line; - } - *t = 0; - oldline = line; - size = len + len2 + 128; - line = nasm_malloc(size); - if (defining) - for (n=0;TMParameters[n];n++) - if (!strcmp(TMParameters[n],p)) { - sprintf(tasm_param,"%%{%d}",n+1); - p = tasm_param; - break; - } - n = sprintf(line, "%s: istruc %s\n", p, q); - /* use initialisers */ - while ((s = strchr(r + 1, ','))) { - if (!field) { - error(ERR_FATAL, "Too many initializers in structure %s %s", p, q); - return oldline; - } - *s = 0; - m = strlen(p) + 1 + strlen(field->name)*2 + 8 + - strlen(field->type) + 1 + strlen(r+1) + 2; - size += m; - line = nasm_realloc(line, size); - sprintf(line + n, "%s.%s: at .%s, %s %s\n", - p, field->name, field->name, field->type, r + 1); - n += m-1; - r = s; - field = field->next; - } - /* complete with last initializer and '?' */ - while(field) { - m = strlen(p) + 1 + strlen(field->name)*2 + 8 + - strlen(field->type) + 1 + (r ? strlen(r+1) : 1) + 2; - size += m; - line = nasm_realloc(line, size); - sprintf(line + n, "%s.%s: at .%s, %s %s\n", p, field->name, - field->name, field->type, r ? r + 1: "?"); - n += m-1; - r = NULL; - field = field->next; - } - line = nasm_realloc(line, n + 5); - sprintf(line + n, "iend"); - nasm_free(oldline); - return line; - } - } - } - - q[len2] = oldchar2; - p[len] = oldchar; - - return line; -} - -static Token * tasm_join_tokens(Token *tline) -{ - Token *t, *prev, *next; - for (prev = NULL, t = tline; t; prev = t, t = next) { - next = t->next; - if (t->type == TOK_OTHER && !strcmp(t->text,"&")) { - if (!prev) - error(ERR_FATAL, "no token before &"); - else if (!next) - error(ERR_FATAL, "no token after &"); - else if (prev->type != next->type) - error(ERR_FATAL, "can't handle different types of token around &"); - else if (!prev->text || !next->text) - error(ERR_FATAL, "can't handle empty token around &"); - else { - int lenp = strlen(prev->text); - int lenn = strlen(next->text); - prev->text = nasm_realloc(prev->text, lenp + lenn + 1); - strncpy(prev->text + lenp, next->text, lenn + 1); - (void) delete_Token(t); - prev->next = delete_Token(next); - t = prev; - next = t->next; - } - } - } - return tline; -} - -/* - * The pre-preprocessing stage... This function translates line - * number indications as they emerge from GNU cpp (`# lineno "file" - * flags') into NASM preprocessor line number indications (`%line - * lineno file'). - */ -static char * -prepreproc(char *line) -{ - int lineno; - size_t fnlen; - char *fname, *oldline; - char *c, *d, *ret; - Line *l, **lp; - - if (line[0] == '#' && line[1] == ' ') - { - oldline = line; - fname = oldline + 2; - lineno = atoi(fname); - fname += strspn(fname, "0123456789 "); - if (*fname == '"') - fname++; - fnlen = strcspn(fname, "\""); - line = nasm_malloc(20 + fnlen); - sprintf(line, "%%line %d %.*s", lineno, (int)fnlen, fname); - nasm_free(oldline); - } - if (tasm_compatible_mode) - line = check_tasm_directive(line); - - if (!(c = strchr(line, '\n'))) - return line; - - /* Turn multiline macros into several lines */ - *c = '\0'; - ret = nasm_strdup(line); - - lp = &istk->expansion; - do { - d = strchr(c+1, '\n'); - if (d) - *d = '\0'; - l = malloc(sizeof(*l)); - l -> first = tokenise(c+1); - l -> finishes = NULL; - l -> next = *lp; - *lp = l; - c = d; - lp = &l -> next; - } while (c); - nasm_free(line); - return ret; -} - -/* - * The hash function for macro lookups. Note that due to some - * macros having case-insensitive names, the hash function must be - * invariant under case changes. We implement this by applying a - * perfectly normal hash function to the uppercase of the string. - */ -static int -hash(char *s) -{ - unsigned int h = 0; - unsigned int i = 0; - /* - * Powers of three, mod 31. - */ - static const int multipliers[] = { - 1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, - 30, 28, 22, 4, 12, 5, 15, 14, 11, 2, 6, 18, 23, 7, 21 - }; - - - while (*s) - { - h += multipliers[i] * (unsigned char) (toupper(*s)); - s++; - if (++i >= elements(multipliers)) - i = 0; - } - h %= NHASH; - return h; -} - -/* - * Free a linked list of tokens. - */ -static void -free_tlist(Token * list_) -{ - while (list_) - { - list_ = delete_Token(list_); - } -} - -/* - * Free a linked list of lines. - */ -static void -free_llist(Line * list_) -{ - Line *l; - while (list_) - { - l = list_; - list_ = list_->next; - free_tlist(l->first); - nasm_free(l); - } -} - -/* - * Free an MMacro - */ -static void -free_mmacro(MMacro * m) -{ - nasm_free(m->name); - free_tlist(m->dlist); - nasm_free(m->defaults); - free_llist(m->expansion); - nasm_free(m); -} - -/* - * Pop the context stack. - */ -static void -ctx_pop(void) -{ - Context *c = cstk; - SMacro *smac, *s; - - cstk = cstk->next; - smac = c->localmac; - while (smac) - { - s = smac; - smac = smac->next; - nasm_free(s->name); - free_tlist(s->expansion); - nasm_free(s); - } - nasm_free(c->name); - nasm_free(c); -} - -#define BUF_DELTA 512 + * Note that in this module, linked lists are treated as stacks + * wherever possible. For this reason, Lines are _pushed_ on to the + * `expansion' field in MMacro structures, so that the linked list, + * if walked, would give the macro lines in reverse order; this + * means that we can walk the list when expanding a macro, and thus + * push the lines on to the `expansion' field in _istk_ in reverse + * order (so that when popped back off they are in the right + * order). It may seem cockeyed, and it relies on my design having + * an even number of steps in, but it works... + * + * Some of these structures, rather than being actual lines, are + * markers delimiting the end of the expansion of a given macro. + * This is for use in the cycle-tracking and %rep-handling code. + * Such structures have `finishes' non-NULL, and `first' NULL. All + * others have `finishes' NULL, but `first' may still be NULL if + * the line is blank. + */ +struct Line +{ + Line *next; + MMacro *finishes; + Token *first; +}; + +/* + * To handle an arbitrary level of file inclusion, we maintain a + * stack (ie linked list) of these things. + */ +struct Include +{ + Include *next; + FILE *fp; + Cond *conds; + Line *expansion; + char *fname; + int lineno, lineinc; + MMacro *mstk; /* stack of active macros/reps */ +}; + +/* + * Conditional assembly: we maintain a separate stack of these for + * each level of file inclusion. (The only reason we keep the + * stacks separate is to ensure that a stray `%endif' in a file + * included from within the true branch of a `%if' won't terminate + * it and cause confusion: instead, rightly, it'll cause an error.) + */ +struct Cond +{ + Cond *next; + int state; +}; +enum +{ + /* + * These states are for use just after %if or %elif: IF_TRUE + * means the condition has evaluated to truth so we are + * currently emitting, whereas IF_FALSE means we are not + * currently emitting but will start doing so if a %else comes + * up. In these states, all directives are admissible: %elif, + * %else and %endif. (And of course %if.) + */ + COND_IF_TRUE, COND_IF_FALSE, + /* + * These states come up after a %else: ELSE_TRUE means we're + * emitting, and ELSE_FALSE means we're not. In ELSE_* states, + * any %elif or %else will cause an error. + */ + COND_ELSE_TRUE, COND_ELSE_FALSE, + /* + * This state means that we're not emitting now, and also that + * nothing until %endif will be emitted at all. It's for use in + * two circumstances: (i) when we've had our moment of emission + * and have now started seeing %elifs, and (ii) when the + * condition construct in question is contained within a + * non-emitting branch of a larger condition construct. + */ + COND_NEVER +}; +#define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE ) + /* - * Read a line from the top file in istk, handling multiple CR/LFs - * at the end of the line read, and handling spurious ^Zs. Will - * return lines from the standard macro set if this has not already - * been done. - */ -static char * -read_line(void) -{ - char *buffer, *p, *q; - int bufsize, continued_count; - - bufsize = BUF_DELTA; - buffer = nasm_malloc(BUF_DELTA); - p = buffer; - continued_count = 0; - while (1) - { - q = fgets(p, bufsize - (int)(p - buffer), istk->fp); - if (!q) - break; - p += strlen(p); - if (p > buffer && p[-1] == '\n') - { - /* Convert backslash-CRLF line continuation sequences into - nothing at all (for DOS and Windows) */ - if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) { - p -= 3; - *p = 0; - continued_count++; - } - /* Also convert backslash-LF line continuation sequences into - nothing at all (for Unix) */ - else if (((p - 1) > buffer) && (p[-2] == '\\')) { - p -= 2; - *p = 0; - continued_count++; - } - else { - break; - } - } - if (p - buffer > bufsize - 10) - { - long offset = (long)(p - buffer); - bufsize += BUF_DELTA; - buffer = nasm_realloc(buffer, (size_t)bufsize); - p = buffer + offset; /* prevent stale-pointer problems */ - } - } - - if (!q && p == buffer) - { - nasm_free(buffer); - return NULL; - } - - nasm_src_set_linnum(nasm_src_get_linnum() + istk->lineinc + (continued_count * istk->lineinc)); - - /* - * Play safe: remove CRs as well as LFs, if any of either are - * present at the end of the line. - */ - while (--p >= buffer && (*p == '\n' || *p == '\r')) - *p = '\0'; - - /* - * Handle spurious ^Z, which may be inserted into source files - * by some file transfer utilities. - */ - buffer[strcspn(buffer, "\032")] = '\0'; - - list->line(LIST_READ, buffer); - - return buffer; -} - -/* - * Tokenise a line of text. This is a very simple process since we - * don't need to parse the value out of e.g. numeric tokens: we - * simply split one string into many. - */ -static Token * -tokenise(char *line) -{ - char *p = line; - int type; - Token *list_ = NULL; - Token *t, **tail = &list_; - - while (*line) - { - p = line; - if (*p == '%') - { - p++; - if ( isdigit(*p) || - ((*p == '-' || *p == '+') && isdigit(p[1])) || - ((*p == '+') && (isspace(p[1]) || !p[1]))) - { - do - { - p++; - } - while (isdigit(*p)); - type = TOK_PREPROC_ID; - } - else if (*p == '{') - { - p++; - while (*p && *p != '}') - { - p[-1] = *p; - p++; - } - p[-1] = '\0'; - if (*p) - p++; - type = TOK_PREPROC_ID; - } - else if (isidchar(*p) || - ((*p == '!' || *p == '%' || *p == '$') && - isidchar(p[1]))) - { - do - { - p++; - } - while (isidchar(*p)); - type = TOK_PREPROC_ID; - } - else - { - type = TOK_OTHER; - if (*p == '%') - p++; - } - } - else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) - { - type = TOK_ID; - p++; - while (*p && isidchar(*p)) - p++; - } - else if (*p == '\'' || *p == '"') - { - /* - * A string token. - */ - char c = *p; - p++; - type = TOK_STRING; - while (*p && *p != c) - p++; - - if (*p) - { - p++; - } - else - { - error(ERR_WARNING, "unterminated string"); - type = -1; - } - } - else if (isnumstart(*p)) - { - /* - * A number token. - */ - type = TOK_NUMBER; - p++; - while (*p && isnumchar(*p)) - p++; - } - else if (isspace(*p)) - { - type = TOK_WHITESPACE; - p++; - while (*p && isspace(*p)) - 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++; - } - } - else if (*p == ';') - { - type = TOK_COMMENT; - while (*p) - p++; - } - else - { - /* - * Anything else is an operator of some kind. We check - * for all the double-character operators (>>, <<, //, - * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything - * else is a single-character operator. - */ - type = TOK_OTHER; - if ((p[0] == '>' && p[1] == '>') || - (p[0] == '<' && p[1] == '<') || - (p[0] == '/' && p[1] == '/') || - (p[0] == '<' && p[1] == '=') || - (p[0] == '>' && p[1] == '=') || - (p[0] == '=' && p[1] == '=') || - (p[0] == '!' && p[1] == '=') || - (p[0] == '<' && p[1] == '>') || - (p[0] == '&' && p[1] == '&') || - (p[0] == '|' && p[1] == '|') || - (p[0] == '^' && p[1] == '^')) - { - p++; - } - p++; - } - - /* Handle unterminated string */ - if (type == -1) - { - *tail = t = new_Token(NULL, TOK_STRING, line, (size_t)(p-line)+1); - t->text[p-line] = *line; - tail = &t->next; - } - else if (type != TOK_COMMENT) - { - *tail = t = new_Token(NULL, type, line, (size_t)(p - line)); - tail = &t->next; - } - line = p; - } - return list_; -} - -/* - * this function allocates a new managed block of memory and - * returns a pointer to the block. The managed blocks are - * deleted only all at once by the delete_Blocks function. - */ -static void * -new_Block(size_t size) -{ - Blocks *b = &blocks; - - /* first, get to the end of the linked list */ - while (b->next) - b = b->next; - /* now allocate the requested chunk */ - b->chunk = nasm_malloc(size); - - /* now allocate a new block for the next request */ - b->next = nasm_malloc(sizeof(Blocks)); - /* and initialize the contents of the new block */ - b->next->next = NULL; - b->next->chunk = NULL; - return b->chunk; -} - -/* - * this function deletes all managed blocks of memory - */ -static void -delete_Blocks(void) -{ - Blocks *a,*b = &blocks; - - /* - * keep in mind that the first block, pointed to by blocks - * is a static and not dynamically allocated, so we don't - * free it. - */ - while (b) - { - if (b->chunk) - nasm_free(b->chunk); - a = b; - b = b->next; - if (a != &blocks) - nasm_free(a); - } -} - -/* - * this function creates a new Token and passes a pointer to it - * back to the caller. It sets the type and text elements, and - * also the mac and next elements to NULL. - */ -static Token * -new_Token(Token * next, int type, const char *text, size_t txtlen) -{ - Token *t; - int i; - - if (freeTokens == NULL) - { - freeTokens = (Token *)new_Block(TOKEN_BLOCKSIZE * sizeof(Token)); - for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++) - freeTokens[i].next = &freeTokens[i + 1]; - freeTokens[i].next = NULL; - } - t = freeTokens; - freeTokens = t->next; - t->next = next; - t->mac = NULL; - t->type = type; - if (type == TOK_WHITESPACE || text == NULL) - { - t->text = NULL; - } - else - { - if (txtlen == 0) - txtlen = strlen(text); - t->text = nasm_malloc(1 + txtlen); - strncpy(t->text, text, txtlen); - t->text[txtlen] = '\0'; - } - return t; -} - -static Token * -delete_Token(Token * t) -{ - Token *next = t->next; - nasm_free(t->text); - t->next = freeTokens; - freeTokens = t; - return next; -} - -/* - * Convert a line of tokens back into text. - * If expand_locals is not zero, identifiers of the form "%$*xxx" - * will be transformed into ..@ctxnum.xxx - */ -static char * -detoken(Token * tlist, int expand_locals) -{ - Token *t; - size_t len; - char *line, *p; - - len = 0; - for (t = tlist; t; t = t->next) - { - if (t->type == TOK_PREPROC_ID && t->text[1] == '!') - { - char *p2 = getenv(t->text + 2); - nasm_free(t->text); - if (p2) - t->text = nasm_strdup(p2); - else - t->text = NULL; - } - /* Expand local macros here and not during preprocessing */ - if (expand_locals && - t->type == TOK_PREPROC_ID && t->text && - t->text[0] == '%' && t->text[1] == '$') - { - Context *ctx = get_ctx(t->text, FALSE); - if (ctx) - { - char buffer[40]; - char *p2, *q = t->text + 2; - - q += strspn(q, "$"); - sprintf(buffer, "..@%lu.", ctx->number); - p2 = nasm_strcat(buffer, q); - nasm_free(t->text); - t->text = p2; - } - } - if (t->type == TOK_WHITESPACE) - { - len++; - } - else if (t->text) - { - len += strlen(t->text); - } - } - p = line = nasm_malloc(len + 1); - for (t = tlist; t; t = t->next) - { - if (t->type == TOK_WHITESPACE) - { - *p = ' '; - p++; - *p = '\0'; - } - else if (t->text) - { - strcpy(p, t->text); - p += strlen(p); - } - } - *p = '\0'; - return line; -} - -/* - * A scanner, suitable for use by the expression evaluator, which - * operates on a line of Tokens. Expects a pointer to a pointer to - * the first token in the line to be passed in as its private_data - * field. - */ -static int -ppscan(void *private_data, struct tokenval *tokval) -{ - Token **tlineptr = private_data; - Token *tline; - - do - { - tline = *tlineptr; - *tlineptr = tline ? tline->next : NULL; - } - while (tline && (tline->type == TOK_WHITESPACE || - tline->type == TOK_COMMENT)); - - if (!tline) - return tokval->t_type = TOKEN_EOS; - - if (tline->text[0] == '$' && !tline->text[1]) - return tokval->t_type = TOKEN_HERE; - if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2]) - return tokval->t_type = TOKEN_BASE; - - if (tline->type == TOK_ID) - { - tokval->t_charptr = tline->text; - if (tline->text[0] == '$') - { - tokval->t_charptr++; - return tokval->t_type = TOKEN_ID; - } - + * These defines are used as the possible return values for do_directive + */ +#define NO_DIRECTIVE_FOUND 0 +#define DIRECTIVE_FOUND 1 + +/* + * Condition codes. Note that we use c_ prefix not C_ because C_ is + * used in nasm.h for the "real" condition codes. At _this_ level, + * we treat CXZ and ECXZ as condition codes, albeit non-invertible + * ones, so we need a different enum... + */ +static const char *conditions[] = { + "a", "ae", "b", "be", "c", "cxz", "e", "ecxz", "g", "ge", "l", "le", + "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", + "np", "ns", "nz", "o", "p", "pe", "po", "s", "z" +}; +enum +{ + c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE, + c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO, + c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_S, c_Z +}; +static int inverse_ccs[] = { + c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE, + c_A, c_AE, c_B, c_BE, c_C, c_E, c_G, c_GE, c_L, c_LE, c_O, c_P, c_S, + c_Z, c_NO, c_NP, c_PO, c_PE, c_NS, c_NZ +}; + +/* + * Directive names. + */ +static const char *directives[] = { + "%arg", + "%assign", "%clear", "%define", "%elif", "%elifctx", "%elifdef", + "%elifid", "%elifidn", "%elifidni", "%elifmacro", "%elifnctx", "%elifndef", + "%elifnid", "%elifnidn", "%elifnidni", "%elifnmacro", "%elifnnum", "%elifnstr", + "%elifnum", "%elifstr", "%else", "%endif", "%endm", "%endmacro", + "%endrep", "%endscope", "%error", "%exitrep", "%iassign", "%idefine", "%if", + "%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifmacro", "%ifnctx", + "%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnmacro", "%ifnnum", + "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", + "%ixdefine", "%line", + "%local", + "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", + "%scope", "%stacksize", + "%strlen", "%substr", "%undef", "%xdefine" +}; +enum +{ + PP_ARG, + PP_ASSIGN, PP_CLEAR, PP_DEFINE, PP_ELIF, PP_ELIFCTX, PP_ELIFDEF, + PP_ELIFID, PP_ELIFIDN, PP_ELIFIDNI, PP_ELIFMACRO, PP_ELIFNCTX, PP_ELIFNDEF, + PP_ELIFNID, PP_ELIFNIDN, PP_ELIFNIDNI, PP_ELIFNMACRO, PP_ELIFNNUM, PP_ELIFNSTR, + PP_ELIFNUM, PP_ELIFSTR, PP_ELSE, PP_ENDIF, PP_ENDM, PP_ENDMACRO, + PP_ENDREP, PP_ENDSCOPE, PP_ERROR, PP_EXITREP, PP_IASSIGN, PP_IDEFINE, PP_IF, + PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFMACRO, PP_IFNCTX, + PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNMACRO, PP_IFNNUM, + PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, + PP_IXDEFINE, PP_LINE, + PP_LOCAL, + PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, + PP_SCOPE, PP_STACKSIZE, + PP_STRLEN, PP_SUBSTR, PP_UNDEF, PP_XDEFINE +}; + +/* If this is a an IF, ELIF, ELSE or ENDIF keyword */ +static int is_condition(int arg) +{ + return ((arg >= PP_ELIF) && (arg <= PP_ENDIF)) || + ((arg >= PP_IF) && (arg <= PP_IFSTR)); +} + +/* 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. + */ + +#ifndef MAX +# define MAX(a,b) ( ((a) > (b)) ? (a) : (b)) +#endif + +enum +{ + TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI, + TM_IFNDEF, TM_INCLUDE, TM_LOCAL, + TM_REPT, TM_IRP, TM_MACRO, + TM_STRUC, TM_SEGMENT +}; + +static const char *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; +static int LocalOffset = 4; +static int Level = 0; + + +static Context *cstk; +static Include *istk; + +static FILE *first_fp = NULL; + +static efunc _error; /* Pointer to client-provided error reporting function */ +static evalfunc evaluate; + +static int pass; /* HACK: pass 0 = generate dependencies only */ + +static unsigned long unique; /* unique identifier numbers */ + +static Line *builtindef = NULL; +static Line *stddef = NULL; +static Line *predef = NULL; +static int first_line = 1; + +static ListGen *list; + +/* + * The number of hash values we use for the macro lookup tables. + * FIXME: We should *really* be able to configure this at run time, + * or even have the hash table automatically expanding when necessary. + */ +#define NHASH 4096 + +/* + * The current set of multi-line macros we have defined. + */ +static MMacro *mmacros[NHASH]; + +/* + * The current set of single-line macros we have defined. + */ +static SMacro *smacros[NHASH]; + +/* + * The multi-line macro we are currently defining, or the %rep + * block we are currently reading, if any. + */ +static MMacro *defining; + +/* + * The number of macro parameters to allocate space for at a time. + */ +#define PARAM_DELTA 16 + +/* + * Macros to make NASM ignore some TASM directives before the first include + * directive. + */ +static const char *tasm_compat_macros[] = +{ + "%idefine IDEAL", + "%idefine JUMPS", + "%idefine END", + "%idefine P8086 CPU 8086", + "%idefine P186 CPU 186", + "%idefine P286 CPU 286", + "%idefine P286N CPU 286", + "%idefine P286P CPU 286 Priv", + "%idefine P386 CPU 386", + "%idefine P386N CPU 386", + "%idefine P386P CPU 386 Priv", + "%idefine P486 CPU 486", + "%idefine P586 CPU 586", + "%idefine .8086 CPU 8086", + "%idefine .186 CPU 186", + "%idefine .286 CPU 286", + "%idefine .286C CPU 286", + "%idefine .286P CPU 286", + "%idefine .386 CPU 386", + "%idefine .386C CPU 386", + "%idefine .386P CPU 386", + "%idefine .486 CPU 486", + "%idefine .486C CPU 486", + "%idefine .486P CPU 486", + "%idefine .586 CPU 586", + "%idefine .586C CPU 586", + "%idefine .586P CPU 586", + "", + "%imacro TITLE 1", + "%endm", + "%imacro NAME 1", + "%endm", + "", + "%imacro EXTRN 1-*.nolist", + "%rep %0", + "[extern %1]", + "%rotate 1", + "%endrep", + "%endmacro", + "", + "%imacro PUBLIC 1-*.nolist", + "%rep %0", + "[global %1]", + "%rotate 1", + "%endrep", + "%endmacro", + "", + "; this is not needed", + "%idefine PTR", + NULL +}; + +static int nested_mac_count, nested_rep_count; + +/* + * Tokens are allocated in blocks to improve speed + */ +#define TOKEN_BLOCKSIZE 4096 +static Token *freeTokens = NULL; +struct Blocks { + Blocks *next; + void *chunk; +}; + +static Blocks blocks = { NULL, NULL }; + +/* + * Forward declarations. + */ +static Token *expand_mmac_params(Token * tline); +static Token *expand_smacro(Token * tline); +static Token *expand_id(Token * tline); +static Context *get_ctx(char *name, int all_contexts); +static void make_tok_num(Token * tok, yasm_intnum *val); +static void error(int severity, const char *fmt, ...); +static void *new_Block(size_t size); +static void delete_Blocks(void); +static Token *new_Token(Token * next, int type, const char *text, + size_t txtlen); +static Token *delete_Token(Token * t); +static Token *tokenise(char *line); + +/* + * Macros for safe checking of token pointers, avoid *(NULL) + */ +#define tok_type_(x,t) ((x) && (x)->type == (t)) +#define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next +#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v))) +#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v)))) + +/* Handle TASM specific directives, which do not contain a % in + * front of them. We do it here because I could not find any other + * place to do it for the moment, and it is a hack (ideally it would + * be nice to be able to use the NASM pre-processor to do it). + */ + +typedef struct TMEndItem { + int type; + void *data; + struct TMEndItem *next; +} TMEndItem; + +static TMEndItem *EndmStack = NULL, *EndsStack = NULL; + +char **TMParameters; + +struct TStrucField { + char *name; + char *type; + struct TStrucField *next; +}; +struct TStruc { + char *name; + struct TStrucField *fields, *lastField; + struct TStruc *next; +}; +static struct TStruc *TStrucs = NULL; +static int inTstruc = 0; + +struct TSegmentAssume { + char *segreg; + char *segment; +}; +struct TSegmentAssume *TAssumes; + +const char *tasm_get_segment_register(const char *segment) +{ + struct TSegmentAssume *assume; + if (!TAssumes) + return NULL; + for (assume = TAssumes; assume->segreg; assume++) { + if (!strcmp(assume->segment, segment)) + break; + } + return assume->segreg; +} + +static char * +check_tasm_directive(char *line) +{ + int i, j, k, m; + size_t len, len2; + char *p, *oldline, oldchar, *q, oldchar2; + TMEndItem *end; + + p = line; + + /* Skip whitespace */ + while (isspace(*p) && *p != 0 && *p != ';') + p++; + + /* Ignore nasm directives */ + if (*p == '%') + return line; + + /* Binary search for the directive name */ + len = 0; + while (!isspace(p[len]) && p[len] != 0 && p[len] != ';') + len++; + if (!len) + return line; + + oldchar = p[len]; + p[len] = 0; + i = -1; + j = elements(tasm_directives); + 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; + if (k == TM_IFDIFI) + { + /* NASM does not recognise IFDIFI, so we convert it to + * %ifdef BOGUS. This is not used in NASM comaptible + * code, but does need to parse for the TASM macro + * package. + */ + line = nasm_malloc(13); + strcpy(line, "%ifdef BOGUS"); + } + else if (k == TM_INCLUDE) + { + /* add double quotes around file name */ + p += 7 + 1; + while (isspace(*p) && *p) + p++; + len = strlen(p); + line = nasm_malloc(1 + 7 + 1 + 1 + len + 1 + 1); + sprintf(line, "%%include \"%s\"", p); + } + else + { + line = nasm_malloc(len + 2); + line[0] = '%'; + memcpy(line + 1, p, len + 1); + } + nasm_free(oldline); + return line; + } + else if (m < 0) + { + j = k; + } + else + i = k; + } + + /* Not a simple directive */ + + if (!nasm_stricmp(p, "endm")) { + /* handle end of endm directive */ + char **parameter; + end = EndmStack; + /* undef parameters */ + if (!end) { + error(ERR_FATAL, "ENDM: not in an endm context"); + return line; + } + EndmStack = EndmStack->next; + nasm_free(line); + switch (end->type) { + case TM_MACRO: + len = 0; + for (parameter = end->data; *parameter; parameter++) + len += 6 + 1 + strlen(*parameter) + 1; + len += 5 + 1; + line = nasm_malloc(len); + p = line; + for (parameter = end->data; *parameter; parameter++) { + p += sprintf(p, "%%undef %s\n", *parameter); + nasm_free(*parameter); + } + nasm_free(end->data); + nasm_free(end); + sprintf(p, "%%endm"); + return line; + case TM_REPT: + nasm_free(end); + return nasm_strdup("%endrep"); + case TM_IRP: { + char **data; + const char *irp_format = + "%%undef %s\n" + "%%rotate 1\n" + "%%endrep\n" + "%%endm\n" + "irp %s\n" + "%%undef irp"; + data = end->data; + line = nasm_malloc(strlen(irp_format) - 4 + strlen(data[0]) + + strlen(data[1])); + sprintf(line, irp_format, data[0], data[1]); + nasm_free(data[0]); + nasm_free(data[1]); + nasm_free(data); + return line; + } + default: + error(ERR_FATAL, "ENDM: bogus endm context type %d\n",end->type); + return NULL; + } + } else if (!nasm_stricmp(p, "end")) { + nasm_free(line); + return nasm_strdup(""); + } else if (!nasm_stricmp(p, "rept")) { + /* handle repeat directive */ + end = nasm_malloc(sizeof(*end)); + end->type = TM_REPT; + end->next = EndmStack; + EndmStack = end; + memcpy(p, "%rep", 4); + p[len] = oldchar; + return line; + } else if (!nasm_stricmp(p, "locals")) { + tasm_locals = 1; + nasm_free(line); + return nasm_strdup(""); + } + + if (!oldchar) + return line; + + /* handle two-words directives */ + q = p + len + 1; + /* Skip whitespaces */ + while (isspace(*q) && *q) + q++; + + len2 = 0; + while (!isspace(q[len2]) && q[len2]!=',' && q[len2] != 0) + len2++; + oldchar2 = q[len2]; + q[len2] = '\0'; + + if (!nasm_stricmp(p, "irp")) { + /* handle indefinite repeat directive */ + const char *irp_format = + "%%imacro irp 0-*\n" + "%%rep %%0\n" + "%%define %s %%1\n"; + char **data; + + data = malloc(2*sizeof(char*)); + oldline = line; + line = nasm_malloc(strlen(irp_format) - 2 + len2 + 1); + sprintf(line,irp_format,q); + data[0] = nasm_strdup(q); + + if (!oldchar2) + error(ERR_FATAL, "%s: expected <values>", q + len2); + p = strchr(q + len2 + 1, '<'); + if (!p) + error(ERR_FATAL, "%s: expected <values>", q + len2); + p++; + q = strchr(p, '>'); + data[1] = nasm_strndup(p, q - p); + + end = nasm_malloc(sizeof(*end)); + end->type = TM_IRP; + end->next = EndmStack; + end->data = data; + EndmStack = end; + + nasm_free(oldline); + return line; + } else if (!nasm_stricmp(q, "macro")) { + char *name = p; + /* handle MACRO */ + /* count parameters */ + j = 1; + i = 0; + TMParameters = nasm_malloc(j*sizeof(*TMParameters)); + len = 0; + p = q + len2 + 1; + /* Skip whitespaces */ + while (isspace(*p) && *p) + p++; + while (*p) { + /* Get parameter name */ + for (q = p; !isspace(*q) && *q != ',' && *q; q++); + len2 = q-p; + if (len2 == 0) + error(ERR_FATAL, "'%s': expected parameter name", p); + TMParameters[i] = nasm_malloc(len2 + 1); + memcpy(TMParameters[i], p, len2); + TMParameters[i][len2] = '\0'; + len += len2; + i++; + if (i + 1 > j) { + j *= 2; + TMParameters = nasm_realloc(TMParameters, + j*sizeof(*TMParameters)); + } + if (i == 1000) + error(ERR_FATAL, "too many parameters for macro %s", name); + p = q; + while (isspace(*p) && *p) + p++; + if (!*p) + break; + if (*p != ',') + error(ERR_FATAL, "expected comma"); + p++; + while (isspace(*p) && *p) + p++; + } + TMParameters[i] = NULL; + TMParameters = nasm_realloc(TMParameters, + (i+1)*sizeof(*TMParameters)); + len += 1 + 6 + 1 + strlen(name) + 1 + 3; /* macro definition */ + len += i * (1 + 9 + 1 + 1 + 1 + 3 + 2); /* macro parameter definition */ + oldline = line; + p = line = nasm_malloc(len + 1); + p += sprintf(p, "%%imacro %s 0-*", name); + nasm_free(oldline); + for (j = 0; TMParameters[j]; j++) { + p += sprintf(p, "\n%%idefine %s %%{%-u}", TMParameters[j], j + 1); + } + end = nasm_malloc(sizeof(*end)); + end->type = TM_MACRO; + end->next = EndmStack; + end->data = TMParameters; + EndmStack = end; + return line; + } else if (!nasm_stricmp(q, "proc")) { + /* handle PROC */ + oldline = line; + line = nasm_malloc(2 + len + 1); + sprintf(line, "..%s",p); + nasm_free(oldline); + return line; + } else if (!nasm_stricmp(q, "struc")) { + /* handle struc */ + struct TStruc *struc; + if (inTstruc) { + error(ERR_FATAL, "STRUC: already in a struc context"); + return line; + } + oldline = line; + line = nasm_malloc(5 + 1 + len + 1); + sprintf(line, "struc %s", p); + struc = malloc(sizeof(*struc)); + struc->name = nasm_strdup(p); + struc->fields = NULL; + struc->lastField = NULL; + struc->next = TStrucs; + TStrucs = struc; + inTstruc = 1; + nasm_free(oldline); + end = nasm_malloc(sizeof(*end)); + end->type = TM_STRUC; + end->next = EndsStack; + EndsStack = end; + return line; + } else if (!nasm_stricmp(q, "segment")) { + /* handle SEGMENT */ + oldline = line; + line = nasm_strdup(oldchar2?q+len2+1:""); + if (tasm_segment) { + error(ERR_FATAL, "SEGMENT: already in a segment context"); + return line; + } + tasm_segment = nasm_strdup(p); + nasm_free(oldline); + end = nasm_malloc(sizeof(*end)); + end->type = TM_SEGMENT; + end->next = EndsStack; + EndsStack = end; + return line; + } else if (!nasm_stricmp(p, "ends") || !nasm_stricmp(q, "ends")) { + /* handle end of ends directive */ + end = EndsStack; + /* undef parameters */ + if (!end) { + error(ERR_FATAL, "ENDS: not in an ends context"); + return line; + } + EndsStack = EndsStack->next; + nasm_free(line); + switch (end->type) { + case TM_STRUC: + inTstruc = 0; + return nasm_strdup("endstruc"); + case TM_SEGMENT: + /* XXX: yes, we leak memory here, but that permits labels + * to avoid strduping... */ + tasm_segment = NULL; + return nasm_strdup(""); + default: + error(ERR_FATAL, "ENDS: bogus ends context type %d",end->type); + return NULL; + } + } else if (!nasm_stricmp(p, "endp") || !nasm_stricmp(q, "endp")) { + nasm_free(line); + return nasm_strdup(""); + } else if (!nasm_stricmp(p, "assume")) { + struct TSegmentAssume *assume; + /* handle ASSUME */ + if (!TAssumes) { + TAssumes = nasm_malloc(sizeof(*TAssumes)); + TAssumes[0].segreg = NULL; + } + i = 0; + q[len2] = oldchar2; + /* Skip whitespaces */ + while (isspace(*q) && *q) + q++; + while (*q && *q != ';') { + p = q; + for (; *q && *q != ';' && *q != ':' && !isspace(*q); q++); + if (!*q || *q == ';') + break; + /* segment register name */ + for (assume = TAssumes; assume->segreg; assume++) + if (strlen(assume->segreg) == (size_t)(q-p) && + !yasm__strncasecmp(assume->segreg, p, q-p)) + break; + if (!assume->segreg) { + i = assume - TAssumes + 1; + TAssumes = nasm_realloc(TAssumes, (i+1)*sizeof(*TAssumes)); + assume = TAssumes + i - 1; + assume->segreg = nasm_strndup(p, q-p); + assume[1].segreg = NULL; + } + for (; *q && *q != ';' && *q != ':' && isspace(*q); q++); + if (*q != ':') + error(ERR_FATAL, "expected `:' instead of `%c'", *q); + for (q++; *q && isspace(*q); q++); + + /* segment name */ + p = q; + for (; *q && *q != ';' && *q != ',' && !isspace(*q); q++); + assume->segment = nasm_strndup(p, q-p); + for (; *q && isspace(*q); q++); + if (*q && *q != ';' && *q != ',') + error(ERR_FATAL, "expected `,' instead of `%c'", *q); + + if (*q && *q != ';') + q++; + for (; *q && isspace(*q); q++); + } + TAssumes[i].segreg = NULL; + TAssumes = nasm_realloc(TAssumes, (i+1)*sizeof(*TAssumes)); + nasm_free(line); + return nasm_strdup(""); + } else if (inTstruc) { + struct TStrucField *field; + /* TODO: handle unnamed data */ + field = nasm_malloc(sizeof(*field)); + field->name = nasm_strdup(p); + /* TODO: type struc ! */ + field->type = nasm_strdup(q); + field->next = NULL; + if (!TStrucs->fields) + TStrucs->fields = field; + else if (TStrucs->lastField) + TStrucs->lastField->next = field; + TStrucs->lastField = field; + if (!oldchar2) { + error(ERR_FATAL, "Expected struc field initializer after %s %s", p, q); + return line; + } + oldline = line; + line = nasm_malloc(1 + len + 1 + len2 + 1 + strlen(q+len2+1) + 1); + sprintf(line, ".%s %s %s", p, q, q+len2+1); + nasm_free(oldline); + return line; + } + { + struct TStruc *struc; + for (struc = TStrucs; struc; struc = struc->next) { + if (!yasm__strcasecmp(q, struc->name)) { + char *r = q + len2 + 1, *s, *t, tasm_param[6]; + struct TStrucField *field = struc->fields; + int size, n; + if (!oldchar2) { + error(ERR_FATAL, "Expected struc field initializer after %s %s", p, q); + return line; + } + r = strchr(r, '<'); + if (!r) { + error(ERR_FATAL, "Expected < for struc field initializer in %s %s %s", p, q, r); + return line; + } + t = strchr(r + 1, '>'); + if (!t) { + error(ERR_FATAL, "Expected > for struc field initializer in %s %s %s", p, q, r); + return line; + } + *t = 0; + oldline = line; + size = len + len2 + 128; + line = nasm_malloc(size); + if (defining) + for (n=0;TMParameters[n];n++) + if (!strcmp(TMParameters[n],p)) { + sprintf(tasm_param,"%%{%d}",n+1); + p = tasm_param; + break; + } + n = sprintf(line, "%s: istruc %s\n", p, q); + /* use initialisers */ + while ((s = strchr(r + 1, ','))) { + if (!field) { + error(ERR_FATAL, "Too many initializers in structure %s %s", p, q); + return oldline; + } + *s = 0; + m = strlen(p) + 1 + strlen(field->name)*2 + 8 + + strlen(field->type) + 1 + strlen(r+1) + 2; + size += m; + line = nasm_realloc(line, size); + sprintf(line + n, "%s.%s: at .%s, %s %s\n", + p, field->name, field->name, field->type, r + 1); + n += m-1; + r = s; + field = field->next; + } + /* complete with last initializer and '?' */ + while(field) { + m = strlen(p) + 1 + strlen(field->name)*2 + 8 + + strlen(field->type) + 1 + (r ? strlen(r+1) : 1) + 2; + size += m; + line = nasm_realloc(line, size); + sprintf(line + n, "%s.%s: at .%s, %s %s\n", p, field->name, + field->name, field->type, r ? r + 1: "?"); + n += m-1; + r = NULL; + field = field->next; + } + line = nasm_realloc(line, n + 5); + sprintf(line + n, "iend"); + nasm_free(oldline); + return line; + } + } + } + + q[len2] = oldchar2; + p[len] = oldchar; + + return line; +} + +static Token * tasm_join_tokens(Token *tline) +{ + Token *t, *prev, *next; + for (prev = NULL, t = tline; t; prev = t, t = next) { + next = t->next; + if (t->type == TOK_OTHER && !strcmp(t->text,"&")) { + if (!prev) + error(ERR_FATAL, "no token before &"); + else if (!next) + error(ERR_FATAL, "no token after &"); + else if (prev->type != next->type) + error(ERR_FATAL, "can't handle different types of token around &"); + else if (!prev->text || !next->text) + error(ERR_FATAL, "can't handle empty token around &"); + else { + int lenp = strlen(prev->text); + int lenn = strlen(next->text); + prev->text = nasm_realloc(prev->text, lenp + lenn + 1); + strncpy(prev->text + lenp, next->text, lenn + 1); + (void) delete_Token(t); + prev->next = delete_Token(next); + t = prev; + next = t->next; + } + } + } + return tline; +} + +/* + * The pre-preprocessing stage... This function translates line + * number indications as they emerge from GNU cpp (`# lineno "file" + * flags') into NASM preprocessor line number indications (`%line + * lineno file'). + */ +static char * +prepreproc(char *line) +{ + int lineno; + size_t fnlen; + char *fname, *oldline; + char *c, *d, *ret; + Line *l, **lp; + + if (line[0] == '#' && line[1] == ' ') + { + oldline = line; + fname = oldline + 2; + lineno = atoi(fname); + fname += strspn(fname, "0123456789 "); + if (*fname == '"') + fname++; + fnlen = strcspn(fname, "\""); + line = nasm_malloc(20 + fnlen); + sprintf(line, "%%line %d %.*s", lineno, (int)fnlen, fname); + nasm_free(oldline); + } + if (tasm_compatible_mode) + line = check_tasm_directive(line); + + if (!(c = strchr(line, '\n'))) + return line; + + /* Turn multiline macros into several lines */ + *c = '\0'; + ret = nasm_strdup(line); + + lp = &istk->expansion; + do { + d = strchr(c+1, '\n'); + if (d) + *d = '\0'; + l = malloc(sizeof(*l)); + l -> first = tokenise(c+1); + l -> finishes = NULL; + l -> next = *lp; + *lp = l; + c = d; + lp = &l -> next; + } while (c); + nasm_free(line); + return ret; +} + +/* + * The hash function for macro lookups. Note that due to some + * macros having case-insensitive names, the hash function must be + * invariant under case changes. We implement this by applying a + * perfectly normal hash function to the uppercase of the string. + */ +static int +hash(char *s) +{ + unsigned int h = 0; + unsigned int i = 0; + /* + * Powers of three, mod 31. + */ + static const int multipliers[] = { + 1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, + 30, 28, 22, 4, 12, 5, 15, 14, 11, 2, 6, 18, 23, 7, 21 + }; + + + while (*s) + { + h += multipliers[i] * (unsigned char) (toupper(*s)); + s++; + if (++i >= elements(multipliers)) + i = 0; + } + h %= NHASH; + return h; +} + +/* + * Free a linked list of tokens. + */ +static void +free_tlist(Token * list_) +{ + while (list_) + { + list_ = delete_Token(list_); + } +} + +/* + * Free a linked list of lines. + */ +static void +free_llist(Line * list_) +{ + Line *l; + while (list_) + { + l = list_; + list_ = list_->next; + free_tlist(l->first); + nasm_free(l); + } +} + +/* + * Free an MMacro + */ +static void +free_mmacro(MMacro * m) +{ + nasm_free(m->name); + free_tlist(m->dlist); + nasm_free(m->defaults); + free_llist(m->expansion); + nasm_free(m); +} + +/* + * Pop the context stack. + */ +static void +ctx_pop(void) +{ + Context *c = cstk; + SMacro *smac, *s; + + cstk = cstk->next; + smac = c->localmac; + while (smac) + { + s = smac; + smac = smac->next; + nasm_free(s->name); + free_tlist(s->expansion); + nasm_free(s); + } + nasm_free(c->name); + nasm_free(c); +} + +#define BUF_DELTA 512 +/* + * Read a line from the top file in istk, handling multiple CR/LFs + * at the end of the line read, and handling spurious ^Zs. Will + * return lines from the standard macro set if this has not already + * been done. + */ +static char * +read_line(void) +{ + char *buffer, *p, *q; + int bufsize, continued_count; + + bufsize = BUF_DELTA; + buffer = nasm_malloc(BUF_DELTA); + p = buffer; + continued_count = 0; + while (1) + { + q = fgets(p, bufsize - (int)(p - buffer), istk->fp); + if (!q) + break; + p += strlen(p); + if (p > buffer && p[-1] == '\n') + { + /* Convert backslash-CRLF line continuation sequences into + nothing at all (for DOS and Windows) */ + if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) { + p -= 3; + *p = 0; + continued_count++; + } + /* Also convert backslash-LF line continuation sequences into + nothing at all (for Unix) */ + else if (((p - 1) > buffer) && (p[-2] == '\\')) { + p -= 2; + *p = 0; + continued_count++; + } + else { + break; + } + } + if (p - buffer > bufsize - 10) + { + long offset = (long)(p - buffer); + bufsize += BUF_DELTA; + buffer = nasm_realloc(buffer, (size_t)bufsize); + p = buffer + offset; /* prevent stale-pointer problems */ + } + } + + if (!q && p == buffer) + { + nasm_free(buffer); + return NULL; + } + + nasm_src_set_linnum(nasm_src_get_linnum() + istk->lineinc + (continued_count * istk->lineinc)); + + /* + * Play safe: remove CRs as well as LFs, if any of either are + * present at the end of the line. + */ + while (--p >= buffer && (*p == '\n' || *p == '\r')) + *p = '\0'; + + /* + * Handle spurious ^Z, which may be inserted into source files + * by some file transfer utilities. + */ + buffer[strcspn(buffer, "\032")] = '\0'; + + list->line(LIST_READ, buffer); + + return buffer; +} + +/* + * Tokenise a line of text. This is a very simple process since we + * don't need to parse the value out of e.g. numeric tokens: we + * simply split one string into many. + */ +static Token * +tokenise(char *line) +{ + char *p = line; + int type; + Token *list_ = NULL; + Token *t, **tail = &list_; + + while (*line) + { + p = line; + if (*p == '%') + { + p++; + if ( isdigit(*p) || + ((*p == '-' || *p == '+') && isdigit(p[1])) || + ((*p == '+') && (isspace(p[1]) || !p[1]))) + { + do + { + p++; + } + while (isdigit(*p)); + type = TOK_PREPROC_ID; + } + else if (*p == '{') + { + p++; + while (*p && *p != '}') + { + p[-1] = *p; + p++; + } + p[-1] = '\0'; + if (*p) + p++; + type = TOK_PREPROC_ID; + } + else if (isidchar(*p) || + ((*p == '!' || *p == '%' || *p == '$') && + isidchar(p[1]))) + { + do + { + p++; + } + while (isidchar(*p)); + type = TOK_PREPROC_ID; + } + else + { + type = TOK_OTHER; + if (*p == '%') + p++; + } + } + else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) + { + type = TOK_ID; + p++; + while (*p && isidchar(*p)) + p++; + } + else if (*p == '\'' || *p == '"') + { + /* + * A string token. + */ + char c = *p; + p++; + type = TOK_STRING; + while (*p && *p != c) + p++; + + if (*p) + { + p++; + } + else + { + error(ERR_WARNING, "unterminated string"); + type = -1; + } + } + else if (isnumstart(*p)) + { + /* + * A number token. + */ + type = TOK_NUMBER; + p++; + while (*p && isnumchar(*p)) + p++; + } + else if (isspace(*p)) + { + type = TOK_WHITESPACE; + p++; + while (*p && isspace(*p)) + 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++; + } + } + else if (*p == ';') + { + type = TOK_COMMENT; + while (*p) + p++; + } + else + { + /* + * Anything else is an operator of some kind. We check + * for all the double-character operators (>>, <<, //, + * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything + * else is a single-character operator. + */ + type = TOK_OTHER; + if ((p[0] == '>' && p[1] == '>') || + (p[0] == '<' && p[1] == '<') || + (p[0] == '/' && p[1] == '/') || + (p[0] == '<' && p[1] == '=') || + (p[0] == '>' && p[1] == '=') || + (p[0] == '=' && p[1] == '=') || + (p[0] == '!' && p[1] == '=') || + (p[0] == '<' && p[1] == '>') || + (p[0] == '&' && p[1] == '&') || + (p[0] == '|' && p[1] == '|') || + (p[0] == '^' && p[1] == '^')) + { + p++; + } + p++; + } + + /* Handle unterminated string */ + if (type == -1) + { + *tail = t = new_Token(NULL, TOK_STRING, line, (size_t)(p-line)+1); + t->text[p-line] = *line; + tail = &t->next; + } + else if (type != TOK_COMMENT) + { + *tail = t = new_Token(NULL, type, line, (size_t)(p - line)); + tail = &t->next; + } + line = p; + } + return list_; +} + +/* + * this function allocates a new managed block of memory and + * returns a pointer to the block. The managed blocks are + * deleted only all at once by the delete_Blocks function. + */ +static void * +new_Block(size_t size) +{ + Blocks *b = &blocks; + + /* first, get to the end of the linked list */ + while (b->next) + b = b->next; + /* now allocate the requested chunk */ + b->chunk = nasm_malloc(size); + + /* now allocate a new block for the next request */ + b->next = nasm_malloc(sizeof(Blocks)); + /* and initialize the contents of the new block */ + b->next->next = NULL; + b->next->chunk = NULL; + return b->chunk; +} + +/* + * this function deletes all managed blocks of memory + */ +static void +delete_Blocks(void) +{ + Blocks *a,*b = &blocks; + /* - * This is the only special case we actually need to worry - * about in this restricted context. - */ - if (!nasm_stricmp(tline->text, "seg")) - return tokval->t_type = TOKEN_SEG; - - return tokval->t_type = TOKEN_ID; - } - - if (tline->type == TOK_NUMBER) - { - int rn_error; - - tokval->t_integer = nasm_readnum(tline->text, &rn_error); - if (rn_error) - return tokval->t_type = TOKEN_ERRNUM; - tokval->t_charptr = NULL; - return tokval->t_type = TOKEN_NUM; - } - - if (tline->type == TOK_STRING) - { - int rn_warn; - char q, *r; - size_t l; - - r = tline->text; - q = *r++; - l = strlen(r); - - if (l == 0 || r[l - 1] != q) - return tokval->t_type = TOKEN_ERRNUM; - tokval->t_integer = nasm_readstrnum(r, l - 1, &rn_warn); - if (rn_warn) - error(ERR_WARNING | ERR_PASS1, "character constant too long"); - tokval->t_charptr = NULL; - return tokval->t_type = TOKEN_NUM; - } - - if (tline->type == TOK_OTHER) - { - if (!strcmp(tline->text, "<<")) - return tokval->t_type = TOKEN_SHL; - if (!strcmp(tline->text, ">>")) - return tokval->t_type = TOKEN_SHR; - if (!strcmp(tline->text, "//")) - return tokval->t_type = TOKEN_SDIV; - if (!strcmp(tline->text, "%%")) - return tokval->t_type = TOKEN_SMOD; - if (!strcmp(tline->text, "==")) - return tokval->t_type = TOKEN_EQ; - if (!strcmp(tline->text, "<>")) - return tokval->t_type = TOKEN_NE; - if (!strcmp(tline->text, "!=")) - return tokval->t_type = TOKEN_NE; - if (!strcmp(tline->text, "<=")) - return tokval->t_type = TOKEN_LE; - if (!strcmp(tline->text, ">=")) - return tokval->t_type = TOKEN_GE; - if (!strcmp(tline->text, "&&")) - return tokval->t_type = TOKEN_DBL_AND; - if (!strcmp(tline->text, "^^")) - return tokval->t_type = TOKEN_DBL_XOR; - if (!strcmp(tline->text, "||")) - return tokval->t_type = TOKEN_DBL_OR; - } - - /* - * We have no other options: just return the first character of - * the token text. - */ - return tokval->t_type = tline->text[0]; -} - -/* - * Compare a string to the name of an existing macro; this is a - * simple wrapper which calls either strcmp or nasm_stricmp - * depending on the value of the `casesense' parameter. - */ -static int -mstrcmp(char *p, char *q, int casesense) -{ - return casesense ? strcmp(p, q) : nasm_stricmp(p, q); -} - -/* - * Return the Context structure associated with a %$ token. Return - * NULL, having _already_ reported an error condition, if the - * context stack isn't deep enough for the supplied number of $ - * signs. - * If all_contexts == TRUE, contexts that enclose current are - * also scanned for such smacro, until it is found; if not - - * only the context that directly results from the number of $'s - * in variable's name. - */ -static Context * -get_ctx(char *name, int all_contexts) -{ - Context *ctx; - SMacro *m; - size_t i; - - if (!name || name[0] != '%' || name[1] != '$') - return NULL; - - if (!cstk) - { - error(ERR_NONFATAL, "`%s': context stack is empty", name); - return NULL; - } - - for (i = strspn(name + 2, "$"), ctx = cstk; (i > 0) && ctx; i--) - { - ctx = ctx->next; -/* i--; Lino - 02/25/02 */ - } - if (!ctx) - { - error(ERR_NONFATAL, "`%s': context stack is only" - " %d level%s deep", name, i - 1, (i == 2 ? "" : "s")); - return NULL; - } - if (!all_contexts) - return ctx; - - do - { - /* Search for this smacro in found context */ - m = ctx->localmac; - while (m) - { - if (!mstrcmp(m->name, name, m->casesense)) - return ctx; - m = m->next; - } - ctx = ctx->next; - } - while (ctx); - return NULL; -} - -/* - * Open an include file. This routine must always return a valid - * file pointer if it returns - it's responsible for throwing an - * ERR_FATAL and bombing out completely if not. It should also try - * the include path one by one until it finds the file or reaches - * the end of the path. - */ -static FILE * -inc_fopen(char *file, char **newname) -{ - FILE *fp; - char *combine = NULL, *c; - char *pb, *p1, *p2, *file2 = NULL; - - /* Try to expand all %ENVVAR% in filename. Warn, and leave %string% - * intact, if ENVVAR is not set in the environment. - */ - pb = file; - p1 = pb; - for (;;) { - char *env; - while (*p1 != '\0' && *p1 != '%') - p1++; - if (*p1 == '\0') - break; - p2 = p1+1; - while (*p2 != '\0' && *p2 != '%') - p2++; - if (*p2 == '\0') - break; - /* Okay, we have a %...%, with p1 pointing to the first %, and p2 - * pointing to the second %. - */ - *p2 = '\0'; - env = getenv(p1+1); - if (!env) { - /* warn, restore %, and continue looking */ - error(ERR_WARNING, "environment variable `%s' does not exist", - p1+1); - *p2 = '%'; - p1 = p2+1; - continue; - } - /* need to expand */ - if (!file2) { - file2 = nasm_malloc(strlen(file)+strlen(env)+1); - file2[0] = '\0'; - } else - file2 = nasm_realloc(file2, strlen(file2)+strlen(env)+1); - *p1 = '\0'; - strcat(file2, pb); - strcat(file2, env); - pb = p2+1; - p1 = pb; - } - /* add tail end; string is long enough that we don't need to realloc */ - if (file2) - strcat(file2, pb); - - fp = yasm_fopen_include(file2 ? file2 : file, nasm_src_get_fname(), "r", - &combine); - if (!fp && tasm_compatible_mode) - { - char *thefile = file2 ? file2 : file; - /* try a few case combinations */ - do { - for (c = thefile; *c; c++) - *c = toupper(*c); - fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); - if (fp) break; - *thefile = tolower(*thefile); - fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); - if (fp) break; - for (c = thefile; *c; c++) - *c = tolower(*c); - fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); - if (fp) break; - *thefile = toupper(*thefile); - fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); - if (fp) break; - } while (0); - } - if (!fp) - error(ERR_FATAL, "unable to open include file `%s'", - file2 ? file2 : file); - nasm_preproc_add_dep(combine); - - if (file2) - nasm_free(file2); - - *newname = combine; - return fp; -} - -/* - * Determine if we should warn on defining a single-line macro of - * name `name', with `nparam' parameters. If nparam is 0 or -1, will - * return TRUE if _any_ single-line macro of that name is defined. - * Otherwise, will return TRUE if a single-line macro with either - * `nparam' or no parameters is defined. - * - * If a macro with precisely the right number of parameters is - * defined, or nparam is -1, the address of the definition structure - * will be returned in `defn'; otherwise NULL will be returned. If `defn' - * is NULL, no action will be taken regarding its contents, and no - * error will occur. - * - * Note that this is also called with nparam zero to resolve - * `ifdef'. + * keep in mind that the first block, pointed to by blocks + * is a static and not dynamically allocated, so we don't + * free it. + */ + while (b) + { + if (b->chunk) + nasm_free(b->chunk); + a = b; + b = b->next; + if (a != &blocks) + nasm_free(a); + } +} + +/* + * this function creates a new Token and passes a pointer to it + * back to the caller. It sets the type and text elements, and + * also the mac and next elements to NULL. + */ +static Token * +new_Token(Token * next, int type, const char *text, size_t txtlen) +{ + Token *t; + int i; + + if (freeTokens == NULL) + { + freeTokens = (Token *)new_Block(TOKEN_BLOCKSIZE * sizeof(Token)); + for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++) + freeTokens[i].next = &freeTokens[i + 1]; + freeTokens[i].next = NULL; + } + t = freeTokens; + freeTokens = t->next; + t->next = next; + t->mac = NULL; + t->type = type; + if (type == TOK_WHITESPACE || text == NULL) + { + t->text = NULL; + } + else + { + if (txtlen == 0) + txtlen = strlen(text); + t->text = nasm_malloc(1 + txtlen); + strncpy(t->text, text, txtlen); + t->text[txtlen] = '\0'; + } + return t; +} + +static Token * +delete_Token(Token * t) +{ + Token *next = t->next; + nasm_free(t->text); + t->next = freeTokens; + freeTokens = t; + return next; +} + +/* + * Convert a line of tokens back into text. + * If expand_locals is not zero, identifiers of the form "%$*xxx" + * will be transformed into ..@ctxnum.xxx + */ +static char * +detoken(Token * tlist, int expand_locals) +{ + Token *t; + size_t len; + char *line, *p; + + len = 0; + for (t = tlist; t; t = t->next) + { + if (t->type == TOK_PREPROC_ID && t->text[1] == '!') + { + char *p2 = getenv(t->text + 2); + nasm_free(t->text); + if (p2) + t->text = nasm_strdup(p2); + else + t->text = NULL; + } + /* Expand local macros here and not during preprocessing */ + if (expand_locals && + t->type == TOK_PREPROC_ID && t->text && + t->text[0] == '%' && t->text[1] == '$') + { + Context *ctx = get_ctx(t->text, FALSE); + if (ctx) + { + char buffer[40]; + char *p2, *q = t->text + 2; + + q += strspn(q, "$"); + sprintf(buffer, "..@%lu.", ctx->number); + p2 = nasm_strcat(buffer, q); + nasm_free(t->text); + t->text = p2; + } + } + if (t->type == TOK_WHITESPACE) + { + len++; + } + else if (t->text) + { + len += strlen(t->text); + } + } + p = line = nasm_malloc(len + 1); + for (t = tlist; t; t = t->next) + { + if (t->type == TOK_WHITESPACE) + { + *p = ' '; + p++; + *p = '\0'; + } + else if (t->text) + { + strcpy(p, t->text); + p += strlen(p); + } + } + *p = '\0'; + return line; +} + +/* + * A scanner, suitable for use by the expression evaluator, which + * operates on a line of Tokens. Expects a pointer to a pointer to + * the first token in the line to be passed in as its private_data + * field. + */ +static int +ppscan(void *private_data, struct tokenval *tokval) +{ + Token **tlineptr = private_data; + Token *tline; + + do + { + tline = *tlineptr; + *tlineptr = tline ? tline->next : NULL; + } + while (tline && (tline->type == TOK_WHITESPACE || + tline->type == TOK_COMMENT)); + + if (!tline) + return tokval->t_type = TOKEN_EOS; + + if (tline->text[0] == '$' && !tline->text[1]) + return tokval->t_type = TOKEN_HERE; + if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2]) + return tokval->t_type = TOKEN_BASE; + + if (tline->type == TOK_ID) + { + tokval->t_charptr = tline->text; + if (tline->text[0] == '$') + { + tokval->t_charptr++; + return tokval->t_type = TOKEN_ID; + } + + /* + * This is the only special case we actually need to worry + * about in this restricted context. + */ + if (!nasm_stricmp(tline->text, "seg")) + return tokval->t_type = TOKEN_SEG; + + return tokval->t_type = TOKEN_ID; + } + + if (tline->type == TOK_NUMBER) + { + int rn_error; + + tokval->t_integer = nasm_readnum(tline->text, &rn_error); + if (rn_error) + return tokval->t_type = TOKEN_ERRNUM; + tokval->t_charptr = NULL; + return tokval->t_type = TOKEN_NUM; + } + + if (tline->type == TOK_STRING) + { + int rn_warn; + char q, *r; + size_t l; + + r = tline->text; + q = *r++; + l = strlen(r); + + if (l == 0 || r[l - 1] != q) + return tokval->t_type = TOKEN_ERRNUM; + tokval->t_integer = nasm_readstrnum(r, l - 1, &rn_warn); + if (rn_warn) + error(ERR_WARNING | ERR_PASS1, "character constant too long"); + tokval->t_charptr = NULL; + return tokval->t_type = TOKEN_NUM; + } + + if (tline->type == TOK_OTHER) + { + if (!strcmp(tline->text, "<<")) + return tokval->t_type = TOKEN_SHL; + if (!strcmp(tline->text, ">>")) + return tokval->t_type = TOKEN_SHR; + if (!strcmp(tline->text, "//")) + return tokval->t_type = TOKEN_SDIV; + if (!strcmp(tline->text, "%%")) + return tokval->t_type = TOKEN_SMOD; + if (!strcmp(tline->text, "==")) + return tokval->t_type = TOKEN_EQ; + if (!strcmp(tline->text, "<>")) + return tokval->t_type = TOKEN_NE; + if (!strcmp(tline->text, "!=")) + return tokval->t_type = TOKEN_NE; + if (!strcmp(tline->text, "<=")) + return tokval->t_type = TOKEN_LE; + if (!strcmp(tline->text, ">=")) + return tokval->t_type = TOKEN_GE; + if (!strcmp(tline->text, "&&")) + return tokval->t_type = TOKEN_DBL_AND; + if (!strcmp(tline->text, "^^")) + return tokval->t_type = TOKEN_DBL_XOR; + if (!strcmp(tline->text, "||")) + return tokval->t_type = TOKEN_DBL_OR; + } + + /* + * We have no other options: just return the first character of + * the token text. + */ + return tokval->t_type = tline->text[0]; +} + +/* + * Compare a string to the name of an existing macro; this is a + * simple wrapper which calls either strcmp or nasm_stricmp + * depending on the value of the `casesense' parameter. + */ +static int +mstrcmp(char *p, char *q, int casesense) +{ + return casesense ? strcmp(p, q) : nasm_stricmp(p, q); +} + +/* + * Return the Context structure associated with a %$ token. Return + * NULL, having _already_ reported an error condition, if the + * context stack isn't deep enough for the supplied number of $ + * signs. + * If all_contexts == TRUE, contexts that enclose current are + * also scanned for such smacro, until it is found; if not - + * only the context that directly results from the number of $'s + * in variable's name. + */ +static Context * +get_ctx(char *name, int all_contexts) +{ + Context *ctx; + SMacro *m; + size_t i; + + if (!name || name[0] != '%' || name[1] != '$') + return NULL; + + if (!cstk) + { + error(ERR_NONFATAL, "`%s': context stack is empty", name); + return NULL; + } + + for (i = strspn(name + 2, "$"), ctx = cstk; (i > 0) && ctx; i--) + { + ctx = ctx->next; +/* i--; Lino - 02/25/02 */ + } + if (!ctx) + { + error(ERR_NONFATAL, "`%s': context stack is only" + " %d level%s deep", name, i - 1, (i == 2 ? "" : "s")); + return NULL; + } + if (!all_contexts) + return ctx; + + do + { + /* Search for this smacro in found context */ + m = ctx->localmac; + while (m) + { + if (!mstrcmp(m->name, name, m->casesense)) + return ctx; + m = m->next; + } + ctx = ctx->next; + } + while (ctx); + return NULL; +} + +/* + * Open an include file. This routine must always return a valid + * file pointer if it returns - it's responsible for throwing an + * ERR_FATAL and bombing out completely if not. It should also try + * the include path one by one until it finds the file or reaches + * the end of the path. + */ +static FILE * +inc_fopen(char *file, char **newname) +{ + FILE *fp; + char *combine = NULL, *c; + char *pb, *p1, *p2, *file2 = NULL; + + /* Try to expand all %ENVVAR% in filename. Warn, and leave %string% + * intact, if ENVVAR is not set in the environment. + */ + pb = file; + p1 = pb; + for (;;) { + char *env; + while (*p1 != '\0' && *p1 != '%') + p1++; + if (*p1 == '\0') + break; + p2 = p1+1; + while (*p2 != '\0' && *p2 != '%') + p2++; + if (*p2 == '\0') + break; + /* Okay, we have a %...%, with p1 pointing to the first %, and p2 + * pointing to the second %. + */ + *p2 = '\0'; + env = getenv(p1+1); + if (!env) { + /* warn, restore %, and continue looking */ + error(ERR_WARNING, "environment variable `%s' does not exist", + p1+1); + *p2 = '%'; + p1 = p2+1; + continue; + } + /* need to expand */ + if (!file2) { + file2 = nasm_malloc(strlen(file)+strlen(env)+1); + file2[0] = '\0'; + } else + file2 = nasm_realloc(file2, strlen(file2)+strlen(env)+1); + *p1 = '\0'; + strcat(file2, pb); + strcat(file2, env); + pb = p2+1; + p1 = pb; + } + /* add tail end; string is long enough that we don't need to realloc */ + if (file2) + strcat(file2, pb); + + fp = yasm_fopen_include(file2 ? file2 : file, nasm_src_get_fname(), "r", + &combine); + if (!fp && tasm_compatible_mode) + { + char *thefile = file2 ? file2 : file; + /* try a few case combinations */ + do { + for (c = thefile; *c; c++) + *c = toupper(*c); + fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); + if (fp) break; + *thefile = tolower(*thefile); + fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); + if (fp) break; + for (c = thefile; *c; c++) + *c = tolower(*c); + fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); + if (fp) break; + *thefile = toupper(*thefile); + fp = yasm_fopen_include(thefile, nasm_src_get_fname(), "r", &combine); + if (fp) break; + } while (0); + } + if (!fp) + error(ERR_FATAL, "unable to open include file `%s'", + file2 ? file2 : file); + nasm_preproc_add_dep(combine); + + if (file2) + nasm_free(file2); + + *newname = combine; + return fp; +} + +/* + * Determine if we should warn on defining a single-line macro of + * name `name', with `nparam' parameters. If nparam is 0 or -1, will + * return TRUE if _any_ single-line macro of that name is defined. + * Otherwise, will return TRUE if a single-line macro with either + * `nparam' or no parameters is defined. + * + * If a macro with precisely the right number of parameters is + * defined, or nparam is -1, the address of the definition structure + * will be returned in `defn'; otherwise NULL will be returned. If `defn' + * is NULL, no action will be taken regarding its contents, and no + * error will occur. + * + * Note that this is also called with nparam zero to resolve + * `ifdef'. + * + * If you already know which context macro belongs to, you can pass + * the context pointer as first parameter; if you won't but name begins + * with %$ the context will be automatically computed. If all_contexts + * is true, macro will be searched in outer contexts as well. + */ +static int +smacro_defined(Context * ctx, char *name, int nparam, SMacro ** defn, + int nocase) +{ + SMacro *m; + int highest_level = -1; + + if (ctx) + m = ctx->localmac; + else if (name[0] == '%' && name[1] == '$') + { + if (cstk) + ctx = get_ctx(name, FALSE); + if (!ctx) + return FALSE; /* got to return _something_ */ + m = ctx->localmac; + } + else + m = smacros[hash(name)]; + + while (m) + { + if (!mstrcmp(m->name, name, m->casesense && nocase) && + (nparam <= 0 || m->nparam == 0 || nparam == m->nparam) && (highest_level < 0 || m->level > highest_level)) + { + highest_level = m->level; + if (defn) + { + if (nparam == m->nparam || nparam == -1) + *defn = m; + else + *defn = NULL; + } + } + m = m->next; + } + + return highest_level >= 0; +} + +/* + * Count and mark off the parameters in a multi-line macro call. + * This is called both from within the multi-line macro expansion + * code, and also to mark off the default parameters when provided + * in a %macro definition line. + */ +static void +count_mmac_params(Token * t, int *nparam, Token *** params) +{ + int paramsize, brace; + + *nparam = paramsize = 0; + *params = NULL; + while (t) + { + if (*nparam+1 >= paramsize) + { + paramsize += PARAM_DELTA; + *params = nasm_realloc(*params, sizeof(**params) * paramsize); + } + skip_white_(t); + brace = FALSE; + if (tok_is_(t, "{")) + brace = TRUE; + (*params)[(*nparam)++] = t; + while (tok_isnt_(t, brace ? "}" : ",")) + t = t->next; + if (t) + { /* got a comma/brace */ + t = t->next; + if (brace) + { + /* + * Now we've found the closing brace, look further + * for the comma. + */ + skip_white_(t); + if (tok_isnt_(t, ",")) + { + error(ERR_NONFATAL, + "braces do not enclose all of macro parameter"); + while (tok_isnt_(t, ",")) + t = t->next; + } + if (t) + t = t->next; /* eat the comma */ + } + } + } +} + +/* + * Determine whether one of the various `if' conditions is true or + * not. + * + * We must free the tline we get passed. + */ +static int +if_condition(Token * tline, int i) +{ + int j, casesense; + Token *t, *tt, **tptr, *origline; + struct tokenval tokval; + yasm_expr *evalresult; + yasm_intnum *intn; + + origline = tline; + + switch (i) + { + case PP_IFCTX: + case PP_ELIFCTX: + case PP_IFNCTX: + case PP_ELIFNCTX: + j = FALSE; /* have we matched yet? */ + while (cstk && tline) + { + skip_white_(tline); + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%s' expects context identifiers", + directives[i]); + free_tlist(origline); + return -1; + } + if (!nasm_stricmp(tline->text, cstk->name)) + j = TRUE; + tline = tline->next; + } + if (i == PP_IFNCTX || i == PP_ELIFNCTX) + j = !j; + free_tlist(origline); + return j; + + case PP_IFDEF: + case PP_ELIFDEF: + case PP_IFNDEF: + case PP_ELIFNDEF: + j = FALSE; /* have we matched yet? */ + while (tline) + { + skip_white_(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%s' expects macro identifiers", + directives[i]); + free_tlist(origline); + return -1; + } + if (smacro_defined(NULL, tline->text, 0, NULL, 1)) + j = TRUE; + tline = tline->next; + } + if (i == PP_IFNDEF || i == PP_ELIFNDEF) + j = !j; + free_tlist(origline); + return j; + + case PP_IFIDN: + case PP_ELIFIDN: + case PP_IFNIDN: + case PP_ELIFNIDN: + case PP_IFIDNI: + case PP_ELIFIDNI: + case PP_IFNIDNI: + case PP_ELIFNIDNI: + tline = expand_smacro(tline); + t = tt = tline; + while (tok_isnt_(tt, ",")) + tt = tt->next; + if (!tt) + { + error(ERR_NONFATAL, + "`%s' expects two comma-separated arguments", + directives[i]); + free_tlist(tline); + return -1; + } + tt = tt->next; + casesense = (i == PP_IFIDN || i == PP_ELIFIDN || + i == PP_IFNIDN || i == PP_ELIFNIDN); + j = TRUE; /* assume equality unless proved not */ + while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) + { + if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) + { + error(ERR_NONFATAL, "`%s': more than one comma on line", + directives[i]); + free_tlist(tline); + return -1; + } + if (t->type == TOK_WHITESPACE) + { + t = t->next; + continue; + } + if (tt->type == TOK_WHITESPACE) + { + tt = tt->next; + continue; + } + if (tt->type != t->type) + { + j = FALSE; /* found mismatching tokens */ + break; + } + /* Unify surrounding quotes for strings */ + if (t->type == TOK_STRING) + { + tt->text[0] = t->text[0]; + tt->text[strlen(tt->text) - 1] = t->text[0]; + } + if (mstrcmp(tt->text, t->text, casesense) != 0) + { + j = FALSE; /* found mismatching tokens */ + break; + } + + t = t->next; + tt = tt->next; + } + if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt) + j = FALSE; /* trailing gunk on one end or other */ + if (i == PP_IFNIDN || i == PP_ELIFNIDN || + i == PP_IFNIDNI || i == PP_ELIFNIDNI) + j = !j; + free_tlist(tline); + return j; + + case PP_IFMACRO: + case PP_ELIFMACRO: + case PP_IFNMACRO: + case PP_ELIFNMACRO: + { + int found = 0; + MMacro searching, *mmac; + + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) + { + error(ERR_NONFATAL, + "`%s' expects a macro name", + directives[i]); + return -1; + } + searching.name = nasm_strdup(tline->text); + searching.casesense = (i == PP_MACRO); + searching.plus = FALSE; + searching.nolist = FALSE; + searching.in_progress = FALSE; + searching.rep_nest = NULL; + searching.nparam_min = 0; + searching.nparam_max = INT_MAX; + tline = expand_smacro(tline->next); + skip_white_(tline); + if (!tline) + { + } else if (!tok_type_(tline, TOK_NUMBER)) + { + error(ERR_NONFATAL, + "`%s' expects a parameter count or nothing", + directives[i]); + } + else + { + intn = nasm_readnum(tline->text, &j); + searching.nparam_min = searching.nparam_max = + yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + } + if (tline && tok_is_(tline->next, "-")) + { + tline = tline->next->next; + if (tok_is_(tline, "*")) + searching.nparam_max = INT_MAX; + else if (!tok_type_(tline, TOK_NUMBER)) + error(ERR_NONFATAL, + "`%s' expects a parameter count after `-'", + directives[i]); + else + { + intn = nasm_readnum(tline->text, &j); + searching.nparam_max = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + if (searching.nparam_min > searching.nparam_max) + error(ERR_NONFATAL, + "minimum parameter count exceeds maximum"); + } + } + if (tline && tok_is_(tline->next, "+")) + { + tline = tline->next; + searching.plus = TRUE; + } + mmac = mmacros[hash(searching.name)]; + while (mmac) + { + if (!strcmp(mmac->name, searching.name) && + (mmac->nparam_min <= searching.nparam_max + || searching.plus) + && (searching.nparam_min <= mmac->nparam_max + || mmac->plus)) + { + found = TRUE; + break; + } + mmac = mmac->next; + } + nasm_free(searching.name); + free_tlist(origline); + if (i == PP_IFNMACRO || i == PP_ELIFNMACRO) + found = !found; + return found; + } + + case PP_IFID: + case PP_ELIFID: + case PP_IFNID: + case PP_ELIFNID: + case PP_IFNUM: + case PP_ELIFNUM: + case PP_IFNNUM: + case PP_ELIFNNUM: + case PP_IFSTR: + case PP_ELIFSTR: + case PP_IFNSTR: + case PP_ELIFNSTR: + tline = expand_smacro(tline); + t = tline; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + j = FALSE; /* placate optimiser */ + if (t) + switch (i) + { + case PP_IFID: + case PP_ELIFID: + case PP_IFNID: + case PP_ELIFNID: + j = (t->type == TOK_ID); + break; + case PP_IFNUM: + case PP_ELIFNUM: + case PP_IFNNUM: + case PP_ELIFNNUM: + j = (t->type == TOK_NUMBER); + break; + case PP_IFSTR: + case PP_ELIFSTR: + case PP_IFNSTR: + case PP_ELIFNSTR: + j = (t->type == TOK_STRING); + break; + } + if (i == PP_IFNID || i == PP_ELIFNID || + i == PP_IFNNUM || i == PP_ELIFNNUM || + i == PP_IFNSTR || i == PP_ELIFNSTR) + j = !j; + free_tlist(tline); + return j; + + case PP_IF: + case PP_ELIF: + t = tline = expand_smacro(tline); + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass | CRITICAL, + error); + free_tlist(tline); + if (!evalresult) + return -1; + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, + "non-constant value given to `%s'", directives[i]); + yasm_expr_destroy(evalresult); + return -1; + } + j = !yasm_intnum_is_zero(intn); + yasm_expr_destroy(evalresult); + return j; + + default: + error(ERR_FATAL, + "preprocessor directive `%s' not yet implemented", + directives[i]); + free_tlist(origline); + return -1; /* yeah, right */ + } +} + +/* + * Expand macros in a string. Used in %error and %include directives. + * First tokenise the string, apply "expand_smacro" and then de-tokenise back. + * The returned variable should ALWAYS be freed after usage. + */ +static void +expand_macros_in_string(char **p) +{ + Token *line = tokenise(*p); + line = expand_smacro(line); + *p = detoken(line, FALSE); +} + +/** + * find and process preprocessor directive in passed line + * Find out if a line contains a preprocessor directive, and deal + * with it if so. * - * If you already know which context macro belongs to, you can pass - * the context pointer as first parameter; if you won't but name begins - * with %$ the context will be automatically computed. If all_contexts - * is true, macro will be searched in outer contexts as well. - */ -static int -smacro_defined(Context * ctx, char *name, int nparam, SMacro ** defn, - int nocase) -{ - SMacro *m; - int highest_level = -1; - - if (ctx) - m = ctx->localmac; - else if (name[0] == '%' && name[1] == '$') - { - if (cstk) - ctx = get_ctx(name, FALSE); - if (!ctx) - return FALSE; /* got to return _something_ */ - m = ctx->localmac; - } - else - m = smacros[hash(name)]; - - while (m) - { - if (!mstrcmp(m->name, name, m->casesense && nocase) && - (nparam <= 0 || m->nparam == 0 || nparam == m->nparam) && (highest_level < 0 || m->level > highest_level)) - { - highest_level = m->level; - if (defn) - { - if (nparam == m->nparam || nparam == -1) - *defn = m; - else - *defn = NULL; - } - } - m = m->next; - } - - return highest_level >= 0; -} - -/* - * Count and mark off the parameters in a multi-line macro call. - * This is called both from within the multi-line macro expansion - * code, and also to mark off the default parameters when provided - * in a %macro definition line. - */ -static void -count_mmac_params(Token * t, int *nparam, Token *** params) -{ - int paramsize, brace; - - *nparam = paramsize = 0; - *params = NULL; - while (t) - { - if (*nparam+1 >= paramsize) - { - paramsize += PARAM_DELTA; - *params = nasm_realloc(*params, sizeof(**params) * paramsize); - } - skip_white_(t); - brace = FALSE; - if (tok_is_(t, "{")) - brace = TRUE; - (*params)[(*nparam)++] = t; - while (tok_isnt_(t, brace ? "}" : ",")) - t = t->next; - if (t) - { /* got a comma/brace */ - t = t->next; - if (brace) - { - /* - * Now we've found the closing brace, look further - * for the comma. - */ - skip_white_(t); - if (tok_isnt_(t, ",")) - { - error(ERR_NONFATAL, - "braces do not enclose all of macro parameter"); - while (tok_isnt_(t, ",")) - t = t->next; - } - if (t) - t = t->next; /* eat the comma */ - } - } - } -} - -/* - * Determine whether one of the various `if' conditions is true or - * not. + * If a directive _is_ found, it is the responsibility of this routine + * (and not the caller) to free_tlist() the line. + * + * @param tline a pointer to the current tokeninzed line linked list + * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND * - * We must free the tline we get passed. - */ -static int -if_condition(Token * tline, int i) -{ - int j, casesense; - Token *t, *tt, **tptr, *origline; - struct tokenval tokval; - yasm_expr *evalresult; - yasm_intnum *intn; - - origline = tline; - - switch (i) - { - case PP_IFCTX: - case PP_ELIFCTX: - case PP_IFNCTX: - case PP_ELIFNCTX: - j = FALSE; /* have we matched yet? */ - while (cstk && tline) - { - skip_white_(tline); - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%s' expects context identifiers", - directives[i]); - free_tlist(origline); - return -1; - } - if (!nasm_stricmp(tline->text, cstk->name)) - j = TRUE; - tline = tline->next; - } - if (i == PP_IFNCTX || i == PP_ELIFNCTX) - j = !j; - free_tlist(origline); - return j; - - case PP_IFDEF: - case PP_ELIFDEF: - case PP_IFNDEF: - case PP_ELIFNDEF: - j = FALSE; /* have we matched yet? */ - while (tline) - { - skip_white_(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%s' expects macro identifiers", - directives[i]); - free_tlist(origline); - return -1; - } - if (smacro_defined(NULL, tline->text, 0, NULL, 1)) - j = TRUE; - tline = tline->next; - } - if (i == PP_IFNDEF || i == PP_ELIFNDEF) - j = !j; - free_tlist(origline); - return j; - - case PP_IFIDN: - case PP_ELIFIDN: - case PP_IFNIDN: - case PP_ELIFNIDN: - case PP_IFIDNI: - case PP_ELIFIDNI: - case PP_IFNIDNI: - case PP_ELIFNIDNI: - tline = expand_smacro(tline); - t = tt = tline; - while (tok_isnt_(tt, ",")) - tt = tt->next; - if (!tt) - { - error(ERR_NONFATAL, - "`%s' expects two comma-separated arguments", - directives[i]); - free_tlist(tline); - return -1; - } - tt = tt->next; - casesense = (i == PP_IFIDN || i == PP_ELIFIDN || - i == PP_IFNIDN || i == PP_ELIFNIDN); - j = TRUE; /* assume equality unless proved not */ - while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) - { - if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) - { - error(ERR_NONFATAL, "`%s': more than one comma on line", - directives[i]); - free_tlist(tline); - return -1; - } - if (t->type == TOK_WHITESPACE) - { - t = t->next; - continue; - } - if (tt->type == TOK_WHITESPACE) - { - tt = tt->next; - continue; - } - if (tt->type != t->type) - { - j = FALSE; /* found mismatching tokens */ - break; - } - /* Unify surrounding quotes for strings */ - if (t->type == TOK_STRING) - { - tt->text[0] = t->text[0]; - tt->text[strlen(tt->text) - 1] = t->text[0]; - } - if (mstrcmp(tt->text, t->text, casesense) != 0) - { - j = FALSE; /* found mismatching tokens */ - break; - } - - t = t->next; - tt = tt->next; - } - if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt) - j = FALSE; /* trailing gunk on one end or other */ - if (i == PP_IFNIDN || i == PP_ELIFNIDN || - i == PP_IFNIDNI || i == PP_ELIFNIDNI) - j = !j; - free_tlist(tline); - return j; - - case PP_IFMACRO: - case PP_ELIFMACRO: - case PP_IFNMACRO: - case PP_ELIFNMACRO: - { - int found = 0; - MMacro searching, *mmac; - - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tok_type_(tline, TOK_ID)) - { - error(ERR_NONFATAL, - "`%s' expects a macro name", - directives[i]); - return -1; - } - searching.name = nasm_strdup(tline->text); - searching.casesense = (i == PP_MACRO); - searching.plus = FALSE; - searching.nolist = FALSE; - searching.in_progress = FALSE; - searching.rep_nest = NULL; - searching.nparam_min = 0; - searching.nparam_max = INT_MAX; - tline = expand_smacro(tline->next); - skip_white_(tline); - if (!tline) - { - } else if (!tok_type_(tline, TOK_NUMBER)) - { - error(ERR_NONFATAL, - "`%s' expects a parameter count or nothing", - directives[i]); - } - else - { - intn = nasm_readnum(tline->text, &j); - searching.nparam_min = searching.nparam_max = - yasm_intnum_get_int(intn); - yasm_intnum_destroy(intn); - if (j) - error(ERR_NONFATAL, - "unable to parse parameter count `%s'", - tline->text); - } - if (tline && tok_is_(tline->next, "-")) - { - tline = tline->next->next; - if (tok_is_(tline, "*")) - searching.nparam_max = INT_MAX; - else if (!tok_type_(tline, TOK_NUMBER)) - error(ERR_NONFATAL, - "`%s' expects a parameter count after `-'", - directives[i]); - else - { - intn = nasm_readnum(tline->text, &j); - searching.nparam_max = yasm_intnum_get_int(intn); - yasm_intnum_destroy(intn); - if (j) - error(ERR_NONFATAL, - "unable to parse parameter count `%s'", - tline->text); - if (searching.nparam_min > searching.nparam_max) - error(ERR_NONFATAL, - "minimum parameter count exceeds maximum"); - } - } - if (tline && tok_is_(tline->next, "+")) - { - tline = tline->next; - searching.plus = TRUE; - } - mmac = mmacros[hash(searching.name)]; - while (mmac) - { - if (!strcmp(mmac->name, searching.name) && - (mmac->nparam_min <= searching.nparam_max - || searching.plus) - && (searching.nparam_min <= mmac->nparam_max - || mmac->plus)) - { - found = TRUE; - break; - } - mmac = mmac->next; - } - nasm_free(searching.name); - free_tlist(origline); - if (i == PP_IFNMACRO || i == PP_ELIFNMACRO) - found = !found; - return found; - } - - case PP_IFID: - case PP_ELIFID: - case PP_IFNID: - case PP_ELIFNID: - case PP_IFNUM: - case PP_ELIFNUM: - case PP_IFNNUM: - case PP_ELIFNNUM: - case PP_IFSTR: - case PP_ELIFSTR: - case PP_IFNSTR: - case PP_ELIFNSTR: - tline = expand_smacro(tline); - t = tline; - while (tok_type_(t, TOK_WHITESPACE)) - t = t->next; - j = FALSE; /* placate optimiser */ - if (t) - switch (i) - { - case PP_IFID: - case PP_ELIFID: - case PP_IFNID: - case PP_ELIFNID: - j = (t->type == TOK_ID); - break; - case PP_IFNUM: - case PP_ELIFNUM: - case PP_IFNNUM: - case PP_ELIFNNUM: - j = (t->type == TOK_NUMBER); - break; - case PP_IFSTR: - case PP_ELIFSTR: - case PP_IFNSTR: - case PP_ELIFNSTR: - j = (t->type == TOK_STRING); - break; - } - if (i == PP_IFNID || i == PP_ELIFNID || - i == PP_IFNNUM || i == PP_ELIFNNUM || - i == PP_IFNSTR || i == PP_ELIFNSTR) - j = !j; - free_tlist(tline); - return j; - - case PP_IF: - case PP_ELIF: - t = tline = expand_smacro(tline); - tptr = &t; - tokval.t_type = TOKEN_INVALID; - evalresult = evaluate(ppscan, tptr, &tokval, pass | CRITICAL, - error); - free_tlist(tline); - if (!evalresult) - return -1; - if (tokval.t_type) - error(ERR_WARNING, - "trailing garbage after expression ignored"); - intn = yasm_expr_get_intnum(&evalresult, 0); - if (!intn) - { - error(ERR_NONFATAL, - "non-constant value given to `%s'", directives[i]); - yasm_expr_destroy(evalresult); - return -1; - } - j = !yasm_intnum_is_zero(intn); - yasm_expr_destroy(evalresult); - return j; - - default: - error(ERR_FATAL, - "preprocessor directive `%s' not yet implemented", - directives[i]); - free_tlist(origline); - return -1; /* yeah, right */ - } -} - -/* - * Expand macros in a string. Used in %error and %include directives. - * First tokenise the string, apply "expand_smacro" and then de-tokenise back. - * The returned variable should ALWAYS be freed after usage. - */ -static void -expand_macros_in_string(char **p) -{ - Token *line = tokenise(*p); - line = expand_smacro(line); - *p = detoken(line, FALSE); -} - -/** - * find and process preprocessor directive in passed line - * Find out if a line contains a preprocessor directive, and deal - * with it if so. - * - * If a directive _is_ found, it is the responsibility of this routine - * (and not the caller) to free_tlist() the line. - * - * @param tline a pointer to the current tokeninzed line linked list - * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND - * - */ -static int -do_directive(Token * tline) -{ - int i, j, k, m, nparam, nolist; - int offset; - char *p, *mname, *newname; - Include *inc; - Context *ctx; - Cond *cond; - SMacro *smac, **smhead; - MMacro *mmac; - Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline; - Line *l; - struct tokenval tokval; - yasm_expr *evalresult; - MMacro *tmp_defining; /* Used when manipulating rep_nest */ - yasm_intnum *intn; - - origline = tline; - - skip_white_(tline); - if (!tok_type_(tline, TOK_PREPROC_ID) || - (tline->text[1] == '%' || tline->text[1] == '$' - || tline->text[1] == '!')) - return NO_DIRECTIVE_FOUND; - - i = -1; - j = elements(directives); - while (j - i > 1) - { - k = (j + i) / 2; - m = nasm_stricmp(tline->text, directives[k]); - if (m == 0) { - if (tasm_compatible_mode) { - i = k; - j = -2; - } else if (k != PP_ARG && k != PP_LOCAL && k != PP_STACKSIZE) { - i = k; - j = -2; - } - break; - } - else if (m < 0) { - j = k; - } - else - i = k; - } - - /* - * If we're in a non-emitting branch of a condition construct, - * or walking to the end of an already terminated %rep block, - * we should ignore all directives except for condition - * directives. - */ - if (((istk->conds && !emitting(istk->conds->state)) || - (istk->mstk && !istk->mstk->in_progress)) && - !is_condition(i)) - { - return NO_DIRECTIVE_FOUND; - } - - /* - * If we're defining a macro or reading a %rep block, we should - * ignore all directives except for %macro/%imacro (which - * generate an error), %endm/%endmacro, and (only if we're in a - * %rep block) %endrep. If we're in a %rep block, another %rep - * causes an error, so should be let through. - */ - if (defining && i != PP_MACRO && i != PP_IMACRO && - i != PP_ENDMACRO && i != PP_ENDM && - (defining->name || (i != PP_ENDREP && i != PP_REP))) - { - return NO_DIRECTIVE_FOUND; - } - - if (defining) { - if (i == PP_MACRO || i == PP_IMACRO) { - nested_mac_count++; - return NO_DIRECTIVE_FOUND; - } else if (nested_mac_count > 0) { - if (i == PP_ENDMACRO) { - nested_mac_count--; - return NO_DIRECTIVE_FOUND; - } - } - if (!defining->name) { - if (i == PP_REP) { - nested_rep_count++; - return NO_DIRECTIVE_FOUND; - } else if (nested_rep_count > 0) { - if (i == PP_ENDREP) { - nested_rep_count--; - return NO_DIRECTIVE_FOUND; - } - } - } - } - - if (j != -2) - { - error(ERR_NONFATAL, "unknown preprocessor directive `%s'", - tline->text); - return NO_DIRECTIVE_FOUND; /* didn't get it */ - } - - switch (i) - { - case PP_STACKSIZE: - /* Directive to tell NASM what the default stack size is. The - * default is for a 16-bit stack, and this can be overriden with - * %stacksize large. - * the following form: - * - * ARG arg1:WORD, arg2:DWORD, arg4:QWORD - */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, "`%%stacksize' missing size parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - if (nasm_stricmp(tline->text, "flat") == 0) - { - /* All subsequent ARG directives are for a 32-bit stack */ - StackSize = 4; - StackPointer = "ebp"; - ArgOffset = 8; - LocalOffset = 4; - } - else if (nasm_stricmp(tline->text, "large") == 0) - { - /* All subsequent ARG directives are for a 16-bit stack, - * far function call. - */ - StackSize = 2; - StackPointer = "bp"; - ArgOffset = 4; - LocalOffset = 2; - } - else if (nasm_stricmp(tline->text, "small") == 0) - { - /* All subsequent ARG directives are for a 16-bit stack, - * far function call. We don't support near functions. - */ - StackSize = 2; - StackPointer = "bp"; - ArgOffset = 6; - LocalOffset = 2; - } - else - { - error(ERR_NONFATAL, "`%%stacksize' invalid size type"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_ARG: - /* TASM like ARG directive to define arguments to functions, in - * the following form: - * - * ARG arg1:WORD, arg2:DWORD, arg4:QWORD - */ - offset = ArgOffset; - do - { - char *arg, directive[256]; - int size = StackSize; - - /* Find the argument name */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, "`%%arg' missing argument parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - arg = tline->text; - - /* Find the argument size type */ - tline = tline->next; - if (!tline || tline->type != TOK_OTHER - || tline->text[0] != ':') - { - error(ERR_NONFATAL, - "Syntax error processing `%%arg' directive"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%%arg' missing size type parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - /* Allow macro expansion of type parameter */ - tt = tokenise(tline->text); - tt = expand_smacro(tt); - if (nasm_stricmp(tt->text, "byte") == 0) - { - size = MAX(StackSize, 1); - } - else if (nasm_stricmp(tt->text, "word") == 0) - { - size = MAX(StackSize, 2); - } - else if (nasm_stricmp(tt->text, "dword") == 0) - { - size = MAX(StackSize, 4); - } - else if (nasm_stricmp(tt->text, "qword") == 0) - { - size = MAX(StackSize, 8); - } - else if (nasm_stricmp(tt->text, "tword") == 0) - { - size = MAX(StackSize, 10); - } - else - { - error(ERR_NONFATAL, - "Invalid size type for `%%arg' missing directive"); - free_tlist(tt); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - free_tlist(tt); - - /* Now define the macro for the argument */ - sprintf(directive, "%%define %s (%s+%d)", arg, StackPointer, - offset); - do_directive(tokenise(directive)); - offset += size; - - /* Move to the next argument in the list */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - } - while (tline && tline->type == TOK_OTHER - && tline->text[0] == ','); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_LOCAL: - /* TASM like LOCAL directive to define local variables for a - * function, in the following form: - * - * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize - * - * The '= LocalSize' at the end is ignored by NASM, but is - * required by TASM to define the local parameter size (and used - * by the TASM macro package). - */ - offset = LocalOffset; - do - { - char *local, directive[256]; - int size = StackSize; - - /* Find the argument name */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%%local' missing argument parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - local = tline->text; - - /* Find the argument size type */ - tline = tline->next; - if (!tline || tline->type != TOK_OTHER - || tline->text[0] != ':') - { - error(ERR_NONFATAL, - "Syntax error processing `%%local' directive"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%%local' missing size type parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - /* Allow macro expansion of type parameter */ - tt = tokenise(tline->text); - tt = expand_smacro(tt); - if (nasm_stricmp(tt->text, "byte") == 0) - { - size = MAX(StackSize, 1); - } - else if (nasm_stricmp(tt->text, "word") == 0) - { - size = MAX(StackSize, 2); - } - else if (nasm_stricmp(tt->text, "dword") == 0) - { - size = MAX(StackSize, 4); - } - else if (nasm_stricmp(tt->text, "qword") == 0) - { - size = MAX(StackSize, 8); - } - else if (nasm_stricmp(tt->text, "tword") == 0) - { - size = MAX(StackSize, 10); - } - else - { - error(ERR_NONFATAL, - "Invalid size type for `%%local' missing directive"); - free_tlist(tt); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - free_tlist(tt); - - /* Now define the macro for the argument */ - sprintf(directive, "%%define %s (%s-%d)", local, StackPointer, - offset); - do_directive(tokenise(directive)); - offset += size; - - /* Now define the assign to setup the enter_c macro correctly */ - sprintf(directive, "%%assign %%$localsize %%$localsize+%d", - size); - do_directive(tokenise(directive)); - - /* Move to the next argument in the list */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - } - while (tline && tline->type == TOK_OTHER - && tline->text[0] == ','); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_CLEAR: - if (tline->next) - error(ERR_WARNING, - "trailing garbage after `%%clear' ignored"); - for (j = 0; j < NHASH; j++) - { - while (mmacros[j]) - { - MMacro *m2 = mmacros[j]; - mmacros[j] = m2->next; - free_mmacro(m2); - } - while (smacros[j]) - { - SMacro *s = smacros[j]; - smacros[j] = smacros[j]->next; - nasm_free(s->name); - free_tlist(s->expansion); - nasm_free(s); - } - } - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_INCLUDE: - tline = tline->next; - skip_white_(tline); - if (!tline || (tline->type != TOK_STRING && - tline->type != TOK_INTERNAL_STRING)) - { - error(ERR_NONFATAL, "`%%include' expects a file name"); - free_tlist(origline); - return DIRECTIVE_FOUND; /* but we did _something_ */ - } - if (tline->next) - error(ERR_WARNING, - "trailing garbage after `%%include' ignored"); - if (tline->type != TOK_INTERNAL_STRING) - { - p = tline->text + 1; /* point past the quote to the name */ - p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ + */ +static int +do_directive(Token * tline) +{ + int i, j, k, m, nparam, nolist; + int offset; + char *p, *mname, *newname; + Include *inc; + Context *ctx; + Cond *cond; + SMacro *smac, **smhead; + MMacro *mmac; + Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline; + Line *l; + struct tokenval tokval; + yasm_expr *evalresult; + MMacro *tmp_defining; /* Used when manipulating rep_nest */ + yasm_intnum *intn; + + origline = tline; + + skip_white_(tline); + if (!tok_type_(tline, TOK_PREPROC_ID) || + (tline->text[1] == '%' || tline->text[1] == '$' + || tline->text[1] == '!')) + return NO_DIRECTIVE_FOUND; + + i = -1; + j = elements(directives); + while (j - i > 1) + { + k = (j + i) / 2; + m = nasm_stricmp(tline->text, directives[k]); + if (m == 0) { + if (tasm_compatible_mode) { + i = k; + j = -2; + } else if (k != PP_ARG && k != PP_LOCAL && k != PP_STACKSIZE) { + i = k; + j = -2; + } + break; + } + else if (m < 0) { + j = k; + } + else + i = k; + } + + /* + * If we're in a non-emitting branch of a condition construct, + * or walking to the end of an already terminated %rep block, + * we should ignore all directives except for condition + * directives. + */ + if (((istk->conds && !emitting(istk->conds->state)) || + (istk->mstk && !istk->mstk->in_progress)) && + !is_condition(i)) + { + return NO_DIRECTIVE_FOUND; + } + + /* + * If we're defining a macro or reading a %rep block, we should + * ignore all directives except for %macro/%imacro (which + * generate an error), %endm/%endmacro, and (only if we're in a + * %rep block) %endrep. If we're in a %rep block, another %rep + * causes an error, so should be let through. + */ + if (defining && i != PP_MACRO && i != PP_IMACRO && + i != PP_ENDMACRO && i != PP_ENDM && + (defining->name || (i != PP_ENDREP && i != PP_REP))) + { + return NO_DIRECTIVE_FOUND; + } + + if (defining) { + if (i == PP_MACRO || i == PP_IMACRO) { + nested_mac_count++; + return NO_DIRECTIVE_FOUND; + } else if (nested_mac_count > 0) { + if (i == PP_ENDMACRO) { + nested_mac_count--; + return NO_DIRECTIVE_FOUND; + } + } + if (!defining->name) { + if (i == PP_REP) { + nested_rep_count++; + return NO_DIRECTIVE_FOUND; + } else if (nested_rep_count > 0) { + if (i == PP_ENDREP) { + nested_rep_count--; + return NO_DIRECTIVE_FOUND; + } + } + } + } + + if (j != -2) + { + error(ERR_NONFATAL, "unknown preprocessor directive `%s'", + tline->text); + return NO_DIRECTIVE_FOUND; /* didn't get it */ + } + + switch (i) + { + case PP_STACKSIZE: + /* Directive to tell NASM what the default stack size is. The + * default is for a 16-bit stack, and this can be overriden with + * %stacksize large. + * the following form: + * + * ARG arg1:WORD, arg2:DWORD, arg4:QWORD + */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, "`%%stacksize' missing size parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (nasm_stricmp(tline->text, "flat") == 0) + { + /* All subsequent ARG directives are for a 32-bit stack */ + StackSize = 4; + StackPointer = "ebp"; + ArgOffset = 8; + LocalOffset = 4; + } + else if (nasm_stricmp(tline->text, "large") == 0) + { + /* All subsequent ARG directives are for a 16-bit stack, + * far function call. + */ + StackSize = 2; + StackPointer = "bp"; + ArgOffset = 4; + LocalOffset = 2; + } + else if (nasm_stricmp(tline->text, "small") == 0) + { + /* All subsequent ARG directives are for a 16-bit stack, + * far function call. We don't support near functions. + */ + StackSize = 2; + StackPointer = "bp"; + ArgOffset = 6; + LocalOffset = 2; + } + else + { + error(ERR_NONFATAL, "`%%stacksize' invalid size type"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ARG: + /* TASM like ARG directive to define arguments to functions, in + * the following form: + * + * ARG arg1:WORD, arg2:DWORD, arg4:QWORD + */ + offset = ArgOffset; + do + { + char *arg, directive[256]; + int size = StackSize; + + /* Find the argument name */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, "`%%arg' missing argument parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + arg = tline->text; + + /* Find the argument size type */ + tline = tline->next; + if (!tline || tline->type != TOK_OTHER + || tline->text[0] != ':') + { + error(ERR_NONFATAL, + "Syntax error processing `%%arg' directive"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%%arg' missing size type parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + /* Allow macro expansion of type parameter */ + tt = tokenise(tline->text); + tt = expand_smacro(tt); + if (nasm_stricmp(tt->text, "byte") == 0) + { + size = MAX(StackSize, 1); + } + else if (nasm_stricmp(tt->text, "word") == 0) + { + size = MAX(StackSize, 2); + } + else if (nasm_stricmp(tt->text, "dword") == 0) + { + size = MAX(StackSize, 4); + } + else if (nasm_stricmp(tt->text, "qword") == 0) + { + size = MAX(StackSize, 8); + } + else if (nasm_stricmp(tt->text, "tword") == 0) + { + size = MAX(StackSize, 10); + } + else + { + error(ERR_NONFATAL, + "Invalid size type for `%%arg' missing directive"); + free_tlist(tt); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + free_tlist(tt); + + /* Now define the macro for the argument */ + sprintf(directive, "%%define %s (%s+%d)", arg, StackPointer, + offset); + do_directive(tokenise(directive)); + offset += size; + + /* Move to the next argument in the list */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + } + while (tline && tline->type == TOK_OTHER + && tline->text[0] == ','); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_LOCAL: + /* TASM like LOCAL directive to define local variables for a + * function, in the following form: + * + * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize + * + * The '= LocalSize' at the end is ignored by NASM, but is + * required by TASM to define the local parameter size (and used + * by the TASM macro package). + */ + offset = LocalOffset; + do + { + char *local, directive[256]; + int size = StackSize; + + /* Find the argument name */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%%local' missing argument parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + local = tline->text; + + /* Find the argument size type */ + tline = tline->next; + if (!tline || tline->type != TOK_OTHER + || tline->text[0] != ':') + { + error(ERR_NONFATAL, + "Syntax error processing `%%local' directive"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + tline = tline->next; + if (!tline || tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%%local' missing size type parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + /* Allow macro expansion of type parameter */ + tt = tokenise(tline->text); + tt = expand_smacro(tt); + if (nasm_stricmp(tt->text, "byte") == 0) + { + size = MAX(StackSize, 1); + } + else if (nasm_stricmp(tt->text, "word") == 0) + { + size = MAX(StackSize, 2); + } + else if (nasm_stricmp(tt->text, "dword") == 0) + { + size = MAX(StackSize, 4); + } + else if (nasm_stricmp(tt->text, "qword") == 0) + { + size = MAX(StackSize, 8); + } + else if (nasm_stricmp(tt->text, "tword") == 0) + { + size = MAX(StackSize, 10); + } + else + { + error(ERR_NONFATAL, + "Invalid size type for `%%local' missing directive"); + free_tlist(tt); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + free_tlist(tt); + + /* Now define the macro for the argument */ + sprintf(directive, "%%define %s (%s-%d)", local, StackPointer, + offset); + do_directive(tokenise(directive)); + offset += size; + + /* Now define the assign to setup the enter_c macro correctly */ + sprintf(directive, "%%assign %%$localsize %%$localsize+%d", + size); + do_directive(tokenise(directive)); + + /* Move to the next argument in the list */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + } + while (tline && tline->type == TOK_OTHER + && tline->text[0] == ','); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_CLEAR: + if (tline->next) + error(ERR_WARNING, + "trailing garbage after `%%clear' ignored"); + for (j = 0; j < NHASH; j++) + { + while (mmacros[j]) + { + MMacro *m2 = mmacros[j]; + mmacros[j] = m2->next; + free_mmacro(m2); + } + while (smacros[j]) + { + SMacro *s = smacros[j]; + smacros[j] = smacros[j]->next; + nasm_free(s->name); + free_tlist(s->expansion); + nasm_free(s); + } + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_INCLUDE: + tline = tline->next; + skip_white_(tline); + if (!tline || (tline->type != TOK_STRING && + tline->type != TOK_INTERNAL_STRING)) + { + error(ERR_NONFATAL, "`%%include' expects a file name"); + free_tlist(origline); + return DIRECTIVE_FOUND; /* but we did _something_ */ + } + if (tline->next) + error(ERR_WARNING, + "trailing garbage after `%%include' ignored"); + if (tline->type != TOK_INTERNAL_STRING) + { + p = tline->text + 1; /* point past the quote to the name */ + p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ + } + else + p = tline->text; /* internal_string is easier */ + expand_macros_in_string(&p); + inc = nasm_malloc(sizeof(Include)); + inc->next = istk; + inc->conds = NULL; + inc->fp = inc_fopen(p, &newname); + inc->fname = nasm_src_set_fname(newname); + inc->lineno = nasm_src_set_linnum(0); + inc->lineinc = 1; + inc->expansion = NULL; + inc->mstk = NULL; + istk = inc; + list->uplevel(LIST_INCLUDE); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_PUSH: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) + { + error(ERR_NONFATAL, "`%%push' expects a context identifier"); + free_tlist(origline); + return DIRECTIVE_FOUND; /* but we did _something_ */ + } + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%push' ignored"); + ctx = nasm_malloc(sizeof(Context)); + ctx->next = cstk; + ctx->localmac = NULL; + ctx->name = nasm_strdup(tline->text); + ctx->number = unique++; + cstk = ctx; + free_tlist(origline); + break; + + case PP_REPL: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) + { + error(ERR_NONFATAL, "`%%repl' expects a context identifier"); + free_tlist(origline); + return DIRECTIVE_FOUND; /* but we did _something_ */ + } + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%repl' ignored"); + if (!cstk) + error(ERR_NONFATAL, "`%%repl': context stack is empty"); + else + { + nasm_free(cstk->name); + cstk->name = nasm_strdup(tline->text); + } + free_tlist(origline); + break; + + case PP_POP: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%pop' ignored"); + if (!cstk) + error(ERR_NONFATAL, + "`%%pop': context stack is already empty"); + else + ctx_pop(); + free_tlist(origline); + break; + + case PP_SCOPE: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%scope' ignored"); + Level++; + free_tlist(origline); + break; + + case PP_ENDSCOPE: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%endscope' ignored"); + if (!Level) + error(ERR_NONFATAL, + "`%%endscope': already popped all levels"); + else + { + for (k = 0; k < NHASH; k++) + { + SMacro **smlast = &smacros[k]; + smac = smacros[k]; + while (smac) + { + if (smac->level < Level) + { + smlast = &smac->next; + smac = smac->next; + } + else + { + *smlast = smac->next; + nasm_free(smac->name); + free_tlist(smac->expansion); + nasm_free(smac); + smac = *smlast; + } + } + } + for (ctx = cstk; ctx; ctx = ctx->next) + { + SMacro **smlast = &ctx->localmac; + smac = ctx->localmac; + while (smac) + { + if (smac->level < Level) + { + smlast = &smac->next; + smac = smac->next; + } + else + { + *smlast = smac->next; + nasm_free(smac->name); + free_tlist(smac->expansion); + nasm_free(smac); + smac = *smlast; + } + } + } + Level--; + } + free_tlist(origline); + break; + + case PP_ERROR: + tline->next = expand_smacro(tline->next); + tline = tline->next; + skip_white_(tline); + if (tok_type_(tline, TOK_STRING)) + { + p = tline->text + 1; /* point past the quote to the name */ + p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ + expand_macros_in_string(&p); + error(ERR_NONFATAL, "%s", p); + nasm_free(p); + } + else + { + p = detoken(tline, FALSE); + error(ERR_WARNING, "%s", p); + nasm_free(p); + } + free_tlist(origline); + break; + + case PP_IF: + case PP_IFCTX: + case PP_IFDEF: + case PP_IFID: + case PP_IFIDN: + case PP_IFIDNI: + case PP_IFMACRO: + case PP_IFNCTX: + case PP_IFNDEF: + case PP_IFNID: + case PP_IFNIDN: + case PP_IFNIDNI: + case PP_IFNMACRO: + case PP_IFNNUM: + case PP_IFNSTR: + case PP_IFNUM: + case PP_IFSTR: + if (istk->conds && !emitting(istk->conds->state)) + j = COND_NEVER; + else + { + j = if_condition(tline->next, i); + tline->next = NULL; /* it got freed */ + j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; + } + free_tlist(origline); + cond = nasm_malloc(sizeof(Cond)); + cond->next = istk->conds; + cond->state = j; + istk->conds = cond; + return DIRECTIVE_FOUND; + + case PP_ELIF: + case PP_ELIFCTX: + case PP_ELIFDEF: + case PP_ELIFID: + case PP_ELIFIDN: + case PP_ELIFIDNI: + case PP_ELIFMACRO: + case PP_ELIFNCTX: + case PP_ELIFNDEF: + case PP_ELIFNID: + case PP_ELIFNIDN: + case PP_ELIFNIDNI: + case PP_ELIFNMACRO: + case PP_ELIFNNUM: + case PP_ELIFNSTR: + case PP_ELIFNUM: + case PP_ELIFSTR: + if (!istk->conds) + error(ERR_FATAL, "`%s': no matching `%%if'", directives[i]); + if (emitting(istk->conds->state) + || istk->conds->state == COND_NEVER) + istk->conds->state = COND_NEVER; + else + { + /* + * IMPORTANT: In the case of %if, we will already have + * called expand_mmac_params(); however, if we're + * processing an %elif we must have been in a + * non-emitting mode, which would have inhibited + * the normal invocation of expand_mmac_params(). Therefore, + * we have to do it explicitly here. + */ + j = if_condition(expand_mmac_params(tline->next), i); + tline->next = NULL; /* it got freed */ + istk->conds->state = + j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ELSE: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%else' ignored"); + if (!istk->conds) + error(ERR_FATAL, "`%%else': no matching `%%if'"); + if (emitting(istk->conds->state) + || istk->conds->state == COND_NEVER) + istk->conds->state = COND_ELSE_FALSE; + else + istk->conds->state = COND_ELSE_TRUE; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ENDIF: + if (tline->next) + error(ERR_WARNING, + "trailing garbage after `%%endif' ignored"); + if (!istk->conds) + error(ERR_FATAL, "`%%endif': no matching `%%if'"); + cond = istk->conds; + istk->conds = cond->next; + nasm_free(cond); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_MACRO: + case PP_IMACRO: + if (defining) + error(ERR_FATAL, + "`%%%smacro': already defining a macro", + (i == PP_IMACRO ? "i" : "")); + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) + { + error(ERR_NONFATAL, + "`%%%smacro' expects a macro name", + (i == PP_IMACRO ? "i" : "")); + return DIRECTIVE_FOUND; + } + defining = nasm_malloc(sizeof(MMacro)); + defining->name = nasm_strdup(tline->text); + defining->casesense = (i == PP_MACRO); + defining->plus = FALSE; + defining->nolist = FALSE; + defining->in_progress = FALSE; + defining->rep_nest = NULL; + tline = expand_smacro(tline->next); + skip_white_(tline); + if (!tok_type_(tline, TOK_NUMBER)) + { + error(ERR_NONFATAL, + "`%%%smacro' expects a parameter count", + (i == PP_IMACRO ? "i" : "")); + defining->nparam_min = defining->nparam_max = 0; + } + else + { + intn = nasm_readnum(tline->text, &j); + defining->nparam_min = defining->nparam_max = + yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + } + if (tline && tok_is_(tline->next, "-")) + { + tline = tline->next->next; + if (tok_is_(tline, "*")) + defining->nparam_max = INT_MAX; + else if (!tok_type_(tline, TOK_NUMBER)) + error(ERR_NONFATAL, + "`%%%smacro' expects a parameter count after `-'", + (i == PP_IMACRO ? "i" : "")); + else + { + intn = nasm_readnum(tline->text, &j); + defining->nparam_max = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + if (defining->nparam_min > defining->nparam_max) + error(ERR_NONFATAL, + "minimum parameter count exceeds maximum"); + } + } + if (tline && tok_is_(tline->next, "+")) + { + tline = tline->next; + defining->plus = TRUE; + } + if (tline && tok_type_(tline->next, TOK_ID) && + !nasm_stricmp(tline->next->text, ".nolist")) + { + tline = tline->next; + defining->nolist = TRUE; + } + mmac = mmacros[hash(defining->name)]; + while (mmac) + { + if (!strcmp(mmac->name, defining->name) && + (mmac->nparam_min <= defining->nparam_max + || defining->plus) + && (defining->nparam_min <= mmac->nparam_max + || mmac->plus)) + { + error(ERR_WARNING, + "redefining multi-line macro `%s'", + defining->name); + break; + } + mmac = mmac->next; + } + /* + * Handle default parameters. + */ + if (tline && tline->next) + { + defining->dlist = tline->next; + tline->next = NULL; + count_mmac_params(defining->dlist, &defining->ndefs, + &defining->defaults); + } + else + { + defining->dlist = NULL; + defining->defaults = NULL; + } + defining->expansion = NULL; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ENDM: + case PP_ENDMACRO: + if (!defining) + { + error(ERR_NONFATAL, "`%s': not defining a macro", + tline->text); + return DIRECTIVE_FOUND; + } + k = hash(defining->name); + defining->next = mmacros[k]; + mmacros[k] = defining; + defining = NULL; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ROTATE: + if (tline->next && tline->next->type == TOK_WHITESPACE) + tline = tline->next; + if (tline->next == NULL) + { + free_tlist(origline); + error(ERR_NONFATAL, "`%%rotate' missing rotate count"); + return DIRECTIVE_FOUND; + } + t = expand_smacro(tline->next); + tline->next = NULL; + free_tlist(origline); + tline = t; + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass, error); + free_tlist(tline); + if (!evalresult) + return DIRECTIVE_FOUND; + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, "non-constant value given to `%%rotate'"); + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + } + mmac = istk->mstk; + while (mmac && !mmac->name) /* avoid mistaking %reps for macros */ + mmac = mmac->next_active; + if (!mmac) + { + error(ERR_NONFATAL, + "`%%rotate' invoked outside a macro call"); } - else - p = tline->text; /* internal_string is easier */ - expand_macros_in_string(&p); - inc = nasm_malloc(sizeof(Include)); - inc->next = istk; - inc->conds = NULL; - inc->fp = inc_fopen(p, &newname); - inc->fname = nasm_src_set_fname(newname); - inc->lineno = nasm_src_set_linnum(0); - inc->lineinc = 1; - inc->expansion = NULL; - inc->mstk = NULL; - istk = inc; - list->uplevel(LIST_INCLUDE); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_PUSH: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tok_type_(tline, TOK_ID)) - { - error(ERR_NONFATAL, "`%%push' expects a context identifier"); - free_tlist(origline); - return DIRECTIVE_FOUND; /* but we did _something_ */ - } - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%push' ignored"); - ctx = nasm_malloc(sizeof(Context)); - ctx->next = cstk; - ctx->localmac = NULL; - ctx->name = nasm_strdup(tline->text); - ctx->number = unique++; - cstk = ctx; - free_tlist(origline); - break; - - case PP_REPL: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tok_type_(tline, TOK_ID)) - { - error(ERR_NONFATAL, "`%%repl' expects a context identifier"); - free_tlist(origline); - return DIRECTIVE_FOUND; /* but we did _something_ */ - } - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%repl' ignored"); - if (!cstk) - error(ERR_NONFATAL, "`%%repl': context stack is empty"); - else - { - nasm_free(cstk->name); - cstk->name = nasm_strdup(tline->text); - } - free_tlist(origline); - break; - - case PP_POP: - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%pop' ignored"); - if (!cstk) - error(ERR_NONFATAL, - "`%%pop': context stack is already empty"); - else - ctx_pop(); - free_tlist(origline); - break; - - case PP_SCOPE: - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%scope' ignored"); - Level++; - free_tlist(origline); - break; - - case PP_ENDSCOPE: - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%endscope' ignored"); - if (!Level) - error(ERR_NONFATAL, - "`%%endscope': already popped all levels"); - else - { - for (k = 0; k < NHASH; k++) - { - SMacro **smlast = &smacros[k]; - smac = smacros[k]; - while (smac) - { - if (smac->level < Level) - { - smlast = &smac->next; - smac = smac->next; - } - else - { - *smlast = smac->next; - nasm_free(smac->name); - free_tlist(smac->expansion); - nasm_free(smac); - smac = *smlast; - } - } - } - for (ctx = cstk; ctx; ctx = ctx->next) - { - SMacro **smlast = &ctx->localmac; - smac = ctx->localmac; - while (smac) - { - if (smac->level < Level) - { - smlast = &smac->next; - smac = smac->next; - } - else - { - *smlast = smac->next; - nasm_free(smac->name); - free_tlist(smac->expansion); - nasm_free(smac); - smac = *smlast; - } - } - } - Level--; - } - free_tlist(origline); - break; - - case PP_ERROR: - tline->next = expand_smacro(tline->next); - tline = tline->next; - skip_white_(tline); - if (tok_type_(tline, TOK_STRING)) - { - p = tline->text + 1; /* point past the quote to the name */ - p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ - expand_macros_in_string(&p); - error(ERR_NONFATAL, "%s", p); - nasm_free(p); - } - else - { - p = detoken(tline, FALSE); - error(ERR_WARNING, "%s", p); - nasm_free(p); - } - free_tlist(origline); - break; - - case PP_IF: - case PP_IFCTX: - case PP_IFDEF: - case PP_IFID: - case PP_IFIDN: - case PP_IFIDNI: - case PP_IFMACRO: - case PP_IFNCTX: - case PP_IFNDEF: - case PP_IFNID: - case PP_IFNIDN: - case PP_IFNIDNI: - case PP_IFNMACRO: - case PP_IFNNUM: - case PP_IFNSTR: - case PP_IFNUM: - case PP_IFSTR: - if (istk->conds && !emitting(istk->conds->state)) - j = COND_NEVER; - else - { - j = if_condition(tline->next, i); - tline->next = NULL; /* it got freed */ - j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; - } - free_tlist(origline); - cond = nasm_malloc(sizeof(Cond)); - cond->next = istk->conds; - cond->state = j; - istk->conds = cond; - return DIRECTIVE_FOUND; - - case PP_ELIF: - case PP_ELIFCTX: - case PP_ELIFDEF: - case PP_ELIFID: - case PP_ELIFIDN: - case PP_ELIFIDNI: - case PP_ELIFMACRO: - case PP_ELIFNCTX: - case PP_ELIFNDEF: - case PP_ELIFNID: - case PP_ELIFNIDN: - case PP_ELIFNIDNI: - case PP_ELIFNMACRO: - case PP_ELIFNNUM: - case PP_ELIFNSTR: - case PP_ELIFNUM: - case PP_ELIFSTR: - if (!istk->conds) - error(ERR_FATAL, "`%s': no matching `%%if'", directives[i]); - if (emitting(istk->conds->state) - || istk->conds->state == COND_NEVER) - istk->conds->state = COND_NEVER; - else - { - /* - * IMPORTANT: In the case of %if, we will already have - * called expand_mmac_params(); however, if we're - * processing an %elif we must have been in a - * non-emitting mode, which would have inhibited - * the normal invocation of expand_mmac_params(). Therefore, - * we have to do it explicitly here. - */ - j = if_condition(expand_mmac_params(tline->next), i); - tline->next = NULL; /* it got freed */ - istk->conds->state = - j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; - } - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_ELSE: - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%else' ignored"); - if (!istk->conds) - error(ERR_FATAL, "`%%else': no matching `%%if'"); - if (emitting(istk->conds->state) - || istk->conds->state == COND_NEVER) - istk->conds->state = COND_ELSE_FALSE; - else - istk->conds->state = COND_ELSE_TRUE; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_ENDIF: - if (tline->next) - error(ERR_WARNING, - "trailing garbage after `%%endif' ignored"); - if (!istk->conds) - error(ERR_FATAL, "`%%endif': no matching `%%if'"); - cond = istk->conds; - istk->conds = cond->next; - nasm_free(cond); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_MACRO: - case PP_IMACRO: - if (defining) - error(ERR_FATAL, - "`%%%smacro': already defining a macro", - (i == PP_IMACRO ? "i" : "")); - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tok_type_(tline, TOK_ID)) - { - error(ERR_NONFATAL, - "`%%%smacro' expects a macro name", - (i == PP_IMACRO ? "i" : "")); - return DIRECTIVE_FOUND; - } - defining = nasm_malloc(sizeof(MMacro)); - defining->name = nasm_strdup(tline->text); - defining->casesense = (i == PP_MACRO); - defining->plus = FALSE; - defining->nolist = FALSE; - defining->in_progress = FALSE; - defining->rep_nest = NULL; - tline = expand_smacro(tline->next); - skip_white_(tline); - if (!tok_type_(tline, TOK_NUMBER)) - { - error(ERR_NONFATAL, - "`%%%smacro' expects a parameter count", - (i == PP_IMACRO ? "i" : "")); - defining->nparam_min = defining->nparam_max = 0; - } - else - { - intn = nasm_readnum(tline->text, &j); - defining->nparam_min = defining->nparam_max = - yasm_intnum_get_int(intn); - yasm_intnum_destroy(intn); - if (j) - error(ERR_NONFATAL, - "unable to parse parameter count `%s'", - tline->text); - } - if (tline && tok_is_(tline->next, "-")) - { - tline = tline->next->next; - if (tok_is_(tline, "*")) - defining->nparam_max = INT_MAX; - else if (!tok_type_(tline, TOK_NUMBER)) - error(ERR_NONFATAL, - "`%%%smacro' expects a parameter count after `-'", - (i == PP_IMACRO ? "i" : "")); - else - { - intn = nasm_readnum(tline->text, &j); - defining->nparam_max = yasm_intnum_get_int(intn); - yasm_intnum_destroy(intn); - if (j) - error(ERR_NONFATAL, - "unable to parse parameter count `%s'", - tline->text); - if (defining->nparam_min > defining->nparam_max) - error(ERR_NONFATAL, - "minimum parameter count exceeds maximum"); - } - } - if (tline && tok_is_(tline->next, "+")) - { - tline = tline->next; - defining->plus = TRUE; - } - if (tline && tok_type_(tline->next, TOK_ID) && - !nasm_stricmp(tline->next->text, ".nolist")) - { - tline = tline->next; - defining->nolist = TRUE; - } - mmac = mmacros[hash(defining->name)]; - while (mmac) - { - if (!strcmp(mmac->name, defining->name) && - (mmac->nparam_min <= defining->nparam_max - || defining->plus) - && (defining->nparam_min <= mmac->nparam_max - || mmac->plus)) - { - error(ERR_WARNING, - "redefining multi-line macro `%s'", - defining->name); - break; - } - mmac = mmac->next; - } - /* - * Handle default parameters. - */ - if (tline && tline->next) - { - defining->dlist = tline->next; - tline->next = NULL; - count_mmac_params(defining->dlist, &defining->ndefs, - &defining->defaults); - } - else - { - defining->dlist = NULL; - defining->defaults = NULL; - } - defining->expansion = NULL; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_ENDM: - case PP_ENDMACRO: - if (!defining) - { - error(ERR_NONFATAL, "`%s': not defining a macro", - tline->text); - return DIRECTIVE_FOUND; - } - k = hash(defining->name); - defining->next = mmacros[k]; - mmacros[k] = defining; - defining = NULL; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_ROTATE: - if (tline->next && tline->next->type == TOK_WHITESPACE) - tline = tline->next; - if (tline->next == NULL) - { - free_tlist(origline); - error(ERR_NONFATAL, "`%%rotate' missing rotate count"); - return DIRECTIVE_FOUND; - } - t = expand_smacro(tline->next); - tline->next = NULL; - free_tlist(origline); - tline = t; - tptr = &t; - tokval.t_type = TOKEN_INVALID; - evalresult = evaluate(ppscan, tptr, &tokval, pass, error); - free_tlist(tline); - if (!evalresult) - return DIRECTIVE_FOUND; - if (tokval.t_type) - error(ERR_WARNING, - "trailing garbage after expression ignored"); - intn = yasm_expr_get_intnum(&evalresult, 0); - if (!intn) - { - error(ERR_NONFATAL, "non-constant value given to `%%rotate'"); - yasm_expr_destroy(evalresult); - return DIRECTIVE_FOUND; - } - mmac = istk->mstk; - while (mmac && !mmac->name) /* avoid mistaking %reps for macros */ - mmac = mmac->next_active; - if (!mmac) - { - error(ERR_NONFATAL, - "`%%rotate' invoked outside a macro call"); - } - else if (mmac->nparam == 0) - { - error(ERR_NONFATAL, - "`%%rotate' invoked within macro without parameters"); - } - else - { - mmac->rotate = mmac->rotate + yasm_intnum_get_int(intn); - - if (mmac->rotate < 0) - mmac->rotate = - mmac->nparam - (-mmac->rotate) % mmac->nparam; - mmac->rotate %= mmac->nparam; - } - yasm_expr_destroy(evalresult); - return DIRECTIVE_FOUND; - - case PP_REP: - nolist = FALSE; - do { - tline = tline->next; - } while (tok_type_(tline, TOK_WHITESPACE)); - - if (tok_type_(tline, TOK_ID) && - nasm_stricmp(tline->text, ".nolist") == 0) - { - nolist = TRUE; - do { - tline = tline->next; - } while (tok_type_(tline, TOK_WHITESPACE)); - } - - if (tline) - { - t = expand_smacro(tline); - tptr = &t; - tokval.t_type = TOKEN_INVALID; - evalresult = evaluate(ppscan, tptr, &tokval, pass, error); - if (!evalresult) - { - free_tlist(origline); - return DIRECTIVE_FOUND; - } - if (tokval.t_type) - error(ERR_WARNING, - "trailing garbage after expression ignored"); - intn = yasm_expr_get_intnum(&evalresult, 0); - if (!intn) - { - error(ERR_NONFATAL, "non-constant value given to `%%rep'"); - yasm_expr_destroy(evalresult); - return DIRECTIVE_FOUND; - } - i = (int)yasm_intnum_get_int(intn) + 1; - yasm_expr_destroy(evalresult); - } - else - { - error(ERR_NONFATAL, "`%%rep' expects a repeat count"); - i = 0; - } - free_tlist(origline); - - tmp_defining = defining; - defining = nasm_malloc(sizeof(MMacro)); - defining->name = NULL; /* flags this macro as a %rep block */ - defining->casesense = 0; - defining->plus = FALSE; - defining->nolist = nolist; - defining->in_progress = i; - defining->nparam_min = defining->nparam_max = 0; - defining->defaults = NULL; - defining->dlist = NULL; - defining->expansion = NULL; - defining->next_active = istk->mstk; - defining->rep_nest = tmp_defining; - return DIRECTIVE_FOUND; - - case PP_ENDREP: - if (!defining || defining->name) - { - error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'"); - return DIRECTIVE_FOUND; - } - - /* - * Now we have a "macro" defined - although it has no name - * and we won't be entering it in the hash tables - we must - * push a macro-end marker for it on to istk->expansion. - * After that, it will take care of propagating itself (a - * macro-end marker line for a macro which is really a %rep - * block will cause the macro to be re-expanded, complete - * with another macro-end marker to ensure the process - * continues) until the whole expansion is forcibly removed - * from istk->expansion by a %exitrep. - */ - l = nasm_malloc(sizeof(Line)); - l->next = istk->expansion; - l->finishes = defining; - l->first = NULL; - istk->expansion = l; - - istk->mstk = defining; - - list->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); - tmp_defining = defining; - defining = defining->rep_nest; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_EXITREP: - /* - * We must search along istk->expansion until we hit a - * macro-end marker for a macro with no name. Then we set - * its `in_progress' flag to 0. - */ - for (l = istk->expansion; l; l = l->next) - if (l->finishes && !l->finishes->name) - break; - - if (l) - l->finishes->in_progress = 0; - else - error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block"); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_XDEFINE: - case PP_IXDEFINE: - case PP_DEFINE: - case PP_IDEFINE: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%%%s%sdefine' expects a macro identifier", - ((i == PP_IDEFINE || i == PP_IXDEFINE) ? "i" : ""), - ((i == PP_XDEFINE || i == PP_IXDEFINE) ? "x" : "")); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - mname = tline->text; - last = tline; - param_start = tline = tline->next; - nparam = 0; - - /* Expand the macro definition now for %xdefine and %ixdefine */ - if ((i == PP_XDEFINE) || (i == PP_IXDEFINE)) - tline = expand_smacro(tline); - - if (tok_is_(tline, "(")) - { - /* - * This macro has parameters. - */ - - tline = tline->next; - while (1) - { - skip_white_(tline); - if (!tline) - { - error(ERR_NONFATAL, "parameter identifier expected"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - if (tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%s': parameter identifier expected", - tline->text); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - tline->type = TOK_SMAC_PARAM + nparam++; - tline = tline->next; - skip_white_(tline); - if (tok_is_(tline, ",")) - { - tline = tline->next; - continue; - } - if (!tok_is_(tline, ")")) - { - error(ERR_NONFATAL, - "`)' expected to terminate macro template"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - break; - } - last = tline; - tline = tline->next; - } - if (tok_type_(tline, TOK_WHITESPACE)) - last = tline, tline = tline->next; - macro_start = NULL; - last->next = NULL; - t = tline; - while (t) - { - if (t->type == TOK_ID) - { - for (tt = param_start; tt; tt = tt->next) - if (tt->type >= TOK_SMAC_PARAM && - !strcmp(tt->text, t->text)) - t->type = tt->type; - } - tt = t->next; - t->next = macro_start; - macro_start = t; - t = tt; - } - /* - * Good. We now have a macro name, a parameter count, and a - * token list (in reverse order) for an expansion. We ought - * to be OK just to create an SMacro, store it, and let - * free_tlist have the rest of the line (which we have - * carefully re-terminated after chopping off the expansion - * from the end). - */ - if (smacro_defined(ctx, mname, nparam, &smac, i == PP_DEFINE)) - { - if (!smac) - { - error(ERR_WARNING, - "single-line macro `%s' defined both with and" - " without parameters", mname); - free_tlist(origline); - free_tlist(macro_start); - return DIRECTIVE_FOUND; - } - else if (smac->level == Level) - { - /* - * We're redefining in the same level, so we have to - * take over an existing SMacro structure. This means - * freeing what was already in it. - */ - nasm_free(smac->name); - free_tlist(smac->expansion); - } - else - { - smac = nasm_malloc(sizeof(SMacro)); - smac->next = *smhead; - *smhead = smac; - } - } - else - { - smac = nasm_malloc(sizeof(SMacro)); - smac->next = *smhead; - *smhead = smac; - } - smac->name = nasm_strdup(mname); - smac->casesense = ((i == PP_DEFINE) || (i == PP_XDEFINE)); - smac->nparam = nparam; - smac->level = Level; - smac->expansion = macro_start; - smac->in_progress = FALSE; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_UNDEF: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, "`%%undef' expects a macro identifier"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - if (tline->next) - { - error(ERR_WARNING, - "trailing garbage after macro name ignored"); - } - - /* Find the context that symbol belongs to */ - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - - mname = tline->text; - - /* - * We now have a macro name... go hunt for it. - */ - while (smacro_defined(ctx, mname, -1, &smac, 1)) - { - /* Defined, so we need to find its predecessor and nuke it */ - SMacro **s; - for (s = smhead; *s && *s != smac; s = &(*s)->next); - if (*s) - { - *s = smac->next; - nasm_free(smac->name); - free_tlist(smac->expansion); - nasm_free(smac); - } - } - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_STRLEN: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%%strlen' expects a macro identifier as first parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - mname = tline->text; - last = tline; - tline = expand_smacro(tline->next); - last->next = NULL; - - t = tline; - while (tok_type_(t, TOK_WHITESPACE)) - t = t->next; - /* t should now point to the string */ - if (t->type != TOK_STRING) - { - error(ERR_NONFATAL, - "`%%strlen` requires string as second parameter"); - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - macro_start = nasm_malloc(sizeof(*macro_start)); - macro_start->next = NULL; - make_tok_num(macro_start, - yasm_intnum_create_uint((unsigned long)(strlen(t->text) - 2))); - macro_start->mac = NULL; - - /* - * 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. - */ - if (smacro_defined(ctx, mname, 0, &smac, i == PP_STRLEN)) - { - if (!smac) - error(ERR_WARNING, - "single-line macro `%s' defined both with and" - " without parameters", mname); - else - { - /* - * We're redefining, so we have to take over an - * existing SMacro structure. This means freeing - * what was already in it. - */ - nasm_free(smac->name); - free_tlist(smac->expansion); - } - } - else - { - smac = nasm_malloc(sizeof(SMacro)); - smac->next = *smhead; - *smhead = smac; - } - smac->name = nasm_strdup(mname); - smac->casesense = (i == PP_STRLEN); - smac->nparam = 0; - smac->level = 0; - smac->expansion = macro_start; - smac->in_progress = FALSE; - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_SUBSTR: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%%substr' expects a macro identifier as first parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - mname = tline->text; - last = tline; - tline = expand_smacro(tline->next); - last->next = NULL; - - t = tline->next; - while (tok_type_(t, TOK_WHITESPACE)) - t = t->next; - - /* t should now point to the string */ - if (t->type != TOK_STRING) - { - error(ERR_NONFATAL, - "`%%substr` requires string as second parameter"); - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - tt = t->next; - tptr = &tt; - tokval.t_type = TOKEN_INVALID; - evalresult = evaluate(ppscan, tptr, &tokval, pass, error); - if (!evalresult) - { - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - intn = yasm_expr_get_intnum(&evalresult, 0); - if (!intn) - { - error(ERR_NONFATAL, "non-constant value given to `%%substr`"); - free_tlist(tline); - free_tlist(origline); - yasm_expr_destroy(evalresult); - return DIRECTIVE_FOUND; - } - - macro_start = nasm_malloc(sizeof(*macro_start)); - macro_start->next = NULL; - macro_start->text = nasm_strdup("'''"); - if (yasm_intnum_sign(intn) == 1 - && yasm_intnum_get_uint(intn) < strlen(t->text) - 1) - { - macro_start->text[1] = t->text[yasm_intnum_get_uint(intn)]; - } - else - { - macro_start->text[2] = '\0'; - } - yasm_expr_destroy(evalresult); - macro_start->type = TOK_STRING; - macro_start->mac = NULL; - - /* - * 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. - */ - if (smacro_defined(ctx, mname, 0, &smac, i == PP_SUBSTR)) - { - if (!smac) - error(ERR_WARNING, - "single-line macro `%s' defined both with and" - " without parameters", mname); - else - { + else if (mmac->nparam == 0) + { + error(ERR_NONFATAL, + "`%%rotate' invoked within macro without parameters"); + } + else + { + mmac->rotate = mmac->rotate + yasm_intnum_get_int(intn); + + if (mmac->rotate < 0) + mmac->rotate = + mmac->nparam - (-mmac->rotate) % mmac->nparam; + mmac->rotate %= mmac->nparam; + } + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + + case PP_REP: + nolist = FALSE; + do { + tline = tline->next; + } while (tok_type_(tline, TOK_WHITESPACE)); + + if (tok_type_(tline, TOK_ID) && + nasm_stricmp(tline->text, ".nolist") == 0) + { + nolist = TRUE; + do { + tline = tline->next; + } while (tok_type_(tline, TOK_WHITESPACE)); + } + + if (tline) + { + t = expand_smacro(tline); + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass, error); + if (!evalresult) + { + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, "non-constant value given to `%%rep'"); + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + } + i = (int)yasm_intnum_get_int(intn) + 1; + yasm_expr_destroy(evalresult); + } + else + { + error(ERR_NONFATAL, "`%%rep' expects a repeat count"); + i = 0; + } + free_tlist(origline); + + tmp_defining = defining; + defining = nasm_malloc(sizeof(MMacro)); + defining->name = NULL; /* flags this macro as a %rep block */ + defining->casesense = 0; + defining->plus = FALSE; + defining->nolist = nolist; + defining->in_progress = i; + defining->nparam_min = defining->nparam_max = 0; + defining->defaults = NULL; + defining->dlist = NULL; + defining->expansion = NULL; + defining->next_active = istk->mstk; + defining->rep_nest = tmp_defining; + return DIRECTIVE_FOUND; + + case PP_ENDREP: + if (!defining || defining->name) + { + error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'"); + return DIRECTIVE_FOUND; + } + + /* + * Now we have a "macro" defined - although it has no name + * and we won't be entering it in the hash tables - we must + * push a macro-end marker for it on to istk->expansion. + * After that, it will take care of propagating itself (a + * macro-end marker line for a macro which is really a %rep + * block will cause the macro to be re-expanded, complete + * with another macro-end marker to ensure the process + * continues) until the whole expansion is forcibly removed + * from istk->expansion by a %exitrep. + */ + l = nasm_malloc(sizeof(Line)); + l->next = istk->expansion; + l->finishes = defining; + l->first = NULL; + istk->expansion = l; + + istk->mstk = defining; + + list->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); + tmp_defining = defining; + defining = defining->rep_nest; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_EXITREP: + /* + * We must search along istk->expansion until we hit a + * macro-end marker for a macro with no name. Then we set + * its `in_progress' flag to 0. + */ + for (l = istk->expansion; l; l = l->next) + if (l->finishes && !l->finishes->name) + break; + + if (l) + l->finishes->in_progress = 0; + else + error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block"); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_XDEFINE: + case PP_IXDEFINE: + case PP_DEFINE: + case PP_IDEFINE: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%%%s%sdefine' expects a macro identifier", + ((i == PP_IDEFINE || i == PP_IXDEFINE) ? "i" : ""), + ((i == PP_XDEFINE || i == PP_IXDEFINE) ? "x" : "")); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + param_start = tline = tline->next; + nparam = 0; + + /* Expand the macro definition now for %xdefine and %ixdefine */ + if ((i == PP_XDEFINE) || (i == PP_IXDEFINE)) + tline = expand_smacro(tline); + + if (tok_is_(tline, "(")) + { + /* + * This macro has parameters. + */ + + tline = tline->next; + while (1) + { + skip_white_(tline); + if (!tline) + { + error(ERR_NONFATAL, "parameter identifier expected"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (tline->type != TOK_ID) + { + error(ERR_NONFATAL, + "`%s': parameter identifier expected", + tline->text); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + tline->type = TOK_SMAC_PARAM + nparam++; + tline = tline->next; + skip_white_(tline); + if (tok_is_(tline, ",")) + { + tline = tline->next; + continue; + } + if (!tok_is_(tline, ")")) + { + error(ERR_NONFATAL, + "`)' expected to terminate macro template"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + break; + } + last = tline; + tline = tline->next; + } + if (tok_type_(tline, TOK_WHITESPACE)) + last = tline, tline = tline->next; + macro_start = NULL; + last->next = NULL; + t = tline; + while (t) + { + if (t->type == TOK_ID) + { + for (tt = param_start; tt; tt = tt->next) + if (tt->type >= TOK_SMAC_PARAM && + !strcmp(tt->text, t->text)) + t->type = tt->type; + } + tt = t->next; + t->next = macro_start; + macro_start = t; + t = tt; + } + /* + * Good. We now have a macro name, a parameter count, and a + * token list (in reverse order) for an expansion. We ought + * to be OK just to create an SMacro, store it, and let + * free_tlist have the rest of the line (which we have + * carefully re-terminated after chopping off the expansion + * from the end). + */ + if (smacro_defined(ctx, mname, nparam, &smac, i == PP_DEFINE)) + { + if (!smac) + { + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + free_tlist(origline); + free_tlist(macro_start); + return DIRECTIVE_FOUND; + } + else if (smac->level == Level) + { + /* + * We're redefining in the same level, so we have to + * take over an existing SMacro structure. This means + * freeing what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = ((i == PP_DEFINE) || (i == PP_XDEFINE)); + smac->nparam = nparam; + smac->level = Level; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_UNDEF: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, "`%%undef' expects a macro identifier"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (tline->next) + { + error(ERR_WARNING, + "trailing garbage after macro name ignored"); + } + + /* Find the context that symbol belongs to */ + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + + mname = tline->text; + + /* + * We now have a macro name... go hunt for it. + */ + while (smacro_defined(ctx, mname, -1, &smac, 1)) + { + /* Defined, so we need to find its predecessor and nuke it */ + SMacro **s; + for (s = smhead; *s && *s != smac; s = &(*s)->next); + if (*s) + { + *s = smac->next; + nasm_free(smac->name); + free_tlist(smac->expansion); + nasm_free(smac); + } + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_STRLEN: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%%strlen' expects a macro identifier as first parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + t = tline; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + /* t should now point to the string */ + if (t->type != TOK_STRING) + { + error(ERR_NONFATAL, + "`%%strlen` requires string as second parameter"); + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + make_tok_num(macro_start, + yasm_intnum_create_uint((unsigned long)(strlen(t->text) - 2))); + macro_start->mac = NULL; + + /* + * 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. + */ + if (smacro_defined(ctx, mname, 0, &smac, i == PP_STRLEN)) + { + if (!smac) + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else + { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_STRLEN); + smac->nparam = 0; + smac->level = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_SUBSTR: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%%substr' expects a macro identifier as first parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + t = tline->next; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + + /* t should now point to the string */ + if (t->type != TOK_STRING) + { + error(ERR_NONFATAL, + "`%%substr` requires string as second parameter"); + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + tt = t->next; + tptr = &tt; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass, error); + if (!evalresult) + { + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, "non-constant value given to `%%substr`"); + free_tlist(tline); + free_tlist(origline); + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + macro_start->text = nasm_strdup("'''"); + if (yasm_intnum_sign(intn) == 1 + && yasm_intnum_get_uint(intn) < strlen(t->text) - 1) + { + macro_start->text[1] = t->text[yasm_intnum_get_uint(intn)]; + } + else + { + macro_start->text[2] = '\0'; + } + yasm_expr_destroy(evalresult); + macro_start->type = TOK_STRING; + macro_start->mac = NULL; + + /* + * 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. + */ + if (smacro_defined(ctx, mname, 0, &smac, i == PP_SUBSTR)) + { + if (!smac) + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else + { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_SUBSTR); + smac->nparam = 0; + smac->level = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + + + case PP_ASSIGN: + case PP_IASSIGN: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) + { + error(ERR_NONFATAL, + "`%%%sassign' expects a macro identifier", + (i == PP_IASSIGN ? "i" : "")); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + t = tline; + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, pass, error); + free_tlist(tline); + if (!evalresult) + { + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + + intn = yasm_expr_get_intnum(&evalresult, 0); + if (!intn) + { + error(ERR_NONFATAL, + "non-constant value given to `%%%sassign'", + (i == PP_IASSIGN ? "i" : "")); + free_tlist(origline); + yasm_expr_destroy(evalresult); + return DIRECTIVE_FOUND; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + make_tok_num(macro_start, yasm_intnum_copy(intn)); + yasm_expr_destroy(evalresult); + macro_start->mac = NULL; + + /* + * 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. + */ + if (smacro_defined(ctx, mname, 0, &smac, i == PP_ASSIGN)) + { + if (!smac) + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else + { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } + else + { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_ASSIGN); + smac->nparam = 0; + smac->level = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_LINE: + /* + * Syntax is `%line nnn[+mmm] [filename]' + */ + tline = tline->next; + skip_white_(tline); + if (!tok_type_(tline, TOK_NUMBER)) + { + error(ERR_NONFATAL, "`%%line' expects line number"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + intn = nasm_readnum(tline->text, &j); + k = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + m = 1; + tline = tline->next; + if (tok_is_(tline, "+")) + { + tline = tline->next; + if (!tok_type_(tline, TOK_NUMBER)) + { + error(ERR_NONFATAL, "`%%line' expects line increment"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + intn = nasm_readnum(tline->text, &j); + m = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + tline = tline->next; + } + skip_white_(tline); + nasm_src_set_linnum(k); + istk->lineinc = m; + if (tline) + { + nasm_free(nasm_src_set_fname(detoken(tline, FALSE))); + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + default: + error(ERR_FATAL, + "preprocessor directive `%s' not yet implemented", + directives[i]); + break; + } + return DIRECTIVE_FOUND; +} + +/* + * Ensure that a macro parameter contains a condition code and + * nothing else. Return the condition code index if so, or -1 + * otherwise. + */ +static int +find_cc(Token * t) +{ + Token *tt; + int i, j, k, m; + + skip_white_(t); + if (t->type != TOK_ID) + return -1; + tt = t->next; + skip_white_(tt); + if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ","))) + return -1; + + i = -1; + j = elements(conditions); + while (j - i > 1) + { + k = (j + i) / 2; + m = nasm_stricmp(t->text, conditions[k]); + if (m == 0) + { + i = k; + j = -2; + break; + } + else if (m < 0) + { + j = k; + } + else + i = k; + } + if (j != -2) + return -1; + return i; +} + +/* + * Expand MMacro-local things: parameter references (%0, %n, %+n, + * %-n) and MMacro-local identifiers (%%foo). + */ +static Token * +expand_mmac_params(Token * tline) +{ + Token *t, *tt, **tail, *thead; + + tail = &thead; + thead = NULL; + + while (tline) + { + if (tline->type == TOK_PREPROC_ID && + (((tline->text[1] == '+' || tline->text[1] == '-') + && tline->text[2]) || tline->text[1] == '%' + || (tline->text[1] >= '0' && tline->text[1] <= '9'))) + { + char *text = NULL; + int type = 0, cc; /* type = 0 to placate optimisers */ + char tmpbuf[30]; + char *second_text = NULL; + int n, i; + MMacro *mac; + + t = tline; + tline = tline->next; + + second_text = strchr(t->text, ':'); + + mac = istk->mstk; + while (mac && !mac->name) /* avoid mistaking %reps for macros */ + mac = mac->next_active; + if (!mac) + error(ERR_NONFATAL, "`%s': not in a macro call", t->text); + else + { + if (second_text) + { + int end = atoi(second_text+1)-1; + int is_fst = 1; + int k; + n = atoi(t->text + 1)-1; + if (end < 0) + end += mac->nparam; + + for (k = n; k <= end; k++) + { + if (k >= mac->nparam) + tt = NULL; + else + { + if (mac->nparam > 1) + k = (k + mac->rotate) % mac->nparam; + tt = mac->params[k]; + } + if (tt) + { + if (!is_fst && mac->paramlen[k]) + { + *tail = new_Token(NULL, TOK_OTHER, ",", 0); + tail = &(*tail)->next; + } + if (mac->paramlen[k]) + is_fst = 0; + for (i = 0; i < mac->paramlen[k]; i++) + { + *tail = + new_Token(NULL, tt->type, tt->text, + 0); + tail = &(*tail)->next; + tt = tt->next; + } + } + text = NULL; /* we've done it here */ + } + } + else + { + switch (t->text[1]) + { + /* + * We have to make a substitution of one of the + * forms %1, %-1, %+1, %%foo, %0. + */ + case '0': + type = TOK_NUMBER; + sprintf(tmpbuf, "%ld", mac->nparam); + text = nasm_strdup(tmpbuf); + break; + case '%': + type = TOK_ID; + sprintf(tmpbuf, "..@%lu.", mac->unique); + text = nasm_strcat(tmpbuf, t->text + 2); + break; + case '-': + n = atoi(t->text + 2) - 1; + if (n >= mac->nparam) + tt = NULL; + else + { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + cc = find_cc(tt); + if (cc == -1) + { + error(ERR_NONFATAL, + "macro parameter %d is not a condition code", + n + 1); + text = NULL; + } + else + { + type = TOK_ID; + if (inverse_ccs[cc] == -1) + { + error(ERR_NONFATAL, + "condition code `%s' is not invertible", + conditions[cc]); + text = NULL; + } + else + text = + nasm_strdup(conditions[inverse_ccs + [cc]]); + } + break; + case '+': + n = atoi(t->text + 2) - 1; + if (n >= mac->nparam) + tt = NULL; + else + { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + cc = find_cc(tt); + if (cc == -1) + { + error(ERR_NONFATAL, + "macro parameter %d is not a condition code", + n + 1); + text = NULL; + } + else + { + type = TOK_ID; + text = nasm_strdup(conditions[cc]); + } + break; + default: + n = atoi(t->text + 1) - 1; + if (n >= mac->nparam) + tt = NULL; + else + { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + if (tt) + { + for (i = 0; i < mac->paramlen[n]; i++) + { + *tail = + new_Token(NULL, tt->type, tt->text, + 0); + tail = &(*tail)->next; + tt = tt->next; + } + } + text = NULL; /* we've done it here */ + break; + } + } + } + + if (!text) + { + delete_Token(t); + } + else + { + *tail = t; + tail = &t->next; + t->type = type; + nasm_free(t->text); + t->text = text; + t->mac = NULL; + } + continue; + } + else + { + t = *tail = tline; + tline = tline->next; + t->mac = NULL; + tail = &t->next; + } + } + *tail = NULL; + t = thead; + for (; t && (tt = t->next) != NULL; t = t->next) + switch (t->type) + { + case TOK_WHITESPACE: + if (tt->type == TOK_WHITESPACE) + { + t->next = delete_Token(tt); + } + break; + case TOK_ID: + if (tt->type == TOK_ID || tt->type == TOK_NUMBER) + { + char *tmp = nasm_strcat(t->text, tt->text); + nasm_free(t->text); + t->text = tmp; + t->next = delete_Token(tt); + } + break; + case TOK_NUMBER: + if (tt->type == TOK_NUMBER) + { + char *tmp = nasm_strcat(t->text, tt->text); + nasm_free(t->text); + t->text = tmp; + t->next = delete_Token(tt); + } + break; + } + + return thead; +} + +/* + * Expand all single-line macro calls made in the given line. + * Return the expanded version of the line. The original is deemed + * to be destroyed in the process. (In reality we'll just move + * Tokens from input to output a lot of the time, rather than + * actually bothering to destroy and replicate.) + */ +static Token * +expand_smacro(Token * tline) +{ + Token *t, *tt, *mstart, **tail, *thead; + SMacro *head = NULL, *m; + Token **params; + int *paramsize; + int nparam, sparam, brackets, rescan; + Token *org_tline = tline; + Context *ctx; + char *mname; + + /* + * Trick: we should avoid changing the start token pointer since it can + * be contained in "next" field of other token. Because of this + * we allocate a copy of first token and work with it; at the end of + * routine we copy it back + */ + if (org_tline) + { + tline = + new_Token(org_tline->next, org_tline->type, org_tline->text, + 0); + tline->mac = org_tline->mac; + nasm_free(org_tline->text); + org_tline->text = NULL; + } + + again: + tail = &thead; + thead = NULL; + + while (tline) + { /* main token loop */ + if ((mname = tline->text)) + { + /* if this token is a local macro, look in local context */ + if (tline->type == TOK_ID || tline->type == TOK_PREPROC_ID) + ctx = get_ctx(mname, TRUE); + else + ctx = NULL; + if (!ctx) + head = smacros[hash(mname)]; + else + head = ctx->localmac; + /* + * We've hit an identifier. As in is_mmacro below, we first + * check whether the identifier is a single-line macro at + * all, then think about checking for parameters if + * necessary. + */ + for (m = head; m; m = m->next) + if (!mstrcmp(m->name, mname, m->casesense)) + break; + if (m) + { + mstart = tline; + params = NULL; + paramsize = NULL; + if (m->nparam == 0) + { + /* + * Simple case: the macro is parameterless. Discard the + * one token that the macro call took, and push the + * expansion back on the to-do stack. + */ + if (!m->expansion) + { + if (!strcmp("__FILE__", m->name)) + { + long num = 0; + nasm_src_get(&num, &(tline->text)); + nasm_quote(&(tline->text)); + tline->type = TOK_STRING; + continue; + } + if (!strcmp("__LINE__", m->name)) + { + nasm_free(tline->text); + make_tok_num(tline, yasm_intnum_create_int(nasm_src_get_linnum())); + continue; + } + tline = delete_Token(tline); + continue; + } + } + else + { + /* + * Complicated case: at least one macro with this name + * exists and takes parameters. We must find the + * parameters in the call, count them, find the SMacro + * that corresponds to that form of the macro call, and + * substitute for the parameters when we expand. What a + * pain. + */ + /*tline = tline->next; + skip_white_(tline);*/ + do { + t = tline->next; + while (tok_type_(t, TOK_SMAC_END)) + { + t->mac->in_progress = FALSE; + t->text = NULL; + t = tline->next = delete_Token(t); + } + tline = t; + } while (tok_type_(tline, TOK_WHITESPACE)); + if (!tok_is_(tline, "(")) + { + /* + * This macro wasn't called with parameters: ignore + * the call. (Behaviour borrowed from gnu cpp.) + */ + tline = mstart; + m = NULL; + } + else + { + int paren = 0; + int white = 0; + brackets = 0; + nparam = 0; + sparam = PARAM_DELTA; + params = nasm_malloc(sparam * sizeof(Token *)); + params[0] = tline->next; + paramsize = nasm_malloc(sparam * sizeof(int)); + paramsize[0] = 0; + while (TRUE) + { /* parameter loop */ + /* + * For some unusual expansions + * which concatenates function call + */ + t = tline->next; + while (tok_type_(t, TOK_SMAC_END)) + { + t->mac->in_progress = FALSE; + t->text = NULL; + t = tline->next = delete_Token(t); + } + tline = t; + + if (!tline) + { + error(ERR_NONFATAL, + "macro call expects terminating `)'"); + break; + } + if (tline->type == TOK_WHITESPACE + && brackets <= 0) + { + if (paramsize[nparam]) + white++; + else + params[nparam] = tline->next; + continue; /* parameter loop */ + } + if (tline->type == TOK_OTHER + && tline->text[1] == 0) + { + char ch = tline->text[0]; + if (ch == ',' && !paren && brackets <= 0) + { + if (++nparam >= sparam) + { + sparam += PARAM_DELTA; + params = nasm_realloc(params, + sparam * sizeof(Token *)); + paramsize = nasm_realloc(paramsize, + sparam * sizeof(int)); + } + params[nparam] = tline->next; + paramsize[nparam] = 0; + white = 0; + continue; /* parameter loop */ + } + if (ch == '{' && + (brackets > 0 || (brackets == 0 && + !paramsize[nparam]))) + { + if (!(brackets++)) + { + params[nparam] = tline->next; + continue; /* parameter loop */ + } + } + if (ch == '}' && brackets > 0) + if (--brackets == 0) + { + brackets = -1; + continue; /* parameter loop */ + } + if (ch == '(' && !brackets) + paren++; + if (ch == ')' && brackets <= 0) + if (--paren < 0) + break; + } + if (brackets < 0) + { + brackets = 0; + error(ERR_NONFATAL, "braces do not " + "enclose all of macro parameter"); + } + paramsize[nparam] += white + 1; + white = 0; + } /* parameter loop */ + nparam++; + while (m && (m->nparam != nparam || + mstrcmp(m->name, mname, + m->casesense))) + m = m->next; + if (!m) + error(ERR_WARNING | ERR_WARN_MNP, + "macro `%s' exists, " + "but not taking %d parameters", + mstart->text, nparam); + } + } + if (m && m->in_progress) + m = NULL; + if (!m) /* in progess or didn't find '(' or wrong nparam */ + { /* - * We're redefining, so we have to take over an - * existing SMacro structure. This means freeing - * what was already in it. - */ - nasm_free(smac->name); - free_tlist(smac->expansion); - } - } - else - { - smac = nasm_malloc(sizeof(SMacro)); - smac->next = *smhead; - *smhead = smac; - } - smac->name = nasm_strdup(mname); - smac->casesense = (i == PP_SUBSTR); - smac->nparam = 0; - smac->level = 0; - smac->expansion = macro_start; - smac->in_progress = FALSE; - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - - - case PP_ASSIGN: - case PP_IASSIGN: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%%%sassign' expects a macro identifier", - (i == PP_IASSIGN ? "i" : "")); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - mname = tline->text; - last = tline; - tline = expand_smacro(tline->next); - last->next = NULL; - - t = tline; - tptr = &t; - tokval.t_type = TOKEN_INVALID; - evalresult = evaluate(ppscan, tptr, &tokval, pass, error); - free_tlist(tline); - if (!evalresult) - { - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - if (tokval.t_type) - error(ERR_WARNING, - "trailing garbage after expression ignored"); - - intn = yasm_expr_get_intnum(&evalresult, 0); - if (!intn) - { - error(ERR_NONFATAL, - "non-constant value given to `%%%sassign'", - (i == PP_IASSIGN ? "i" : "")); - free_tlist(origline); - yasm_expr_destroy(evalresult); - return DIRECTIVE_FOUND; - } - - macro_start = nasm_malloc(sizeof(*macro_start)); - macro_start->next = NULL; - make_tok_num(macro_start, yasm_intnum_copy(intn)); - yasm_expr_destroy(evalresult); - macro_start->mac = NULL; - - /* - * 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. - */ - if (smacro_defined(ctx, mname, 0, &smac, i == PP_ASSIGN)) - { - if (!smac) - error(ERR_WARNING, - "single-line macro `%s' defined both with and" - " without parameters", mname); - else - { - /* - * We're redefining, so we have to take over an - * existing SMacro structure. This means freeing - * what was already in it. - */ - nasm_free(smac->name); - free_tlist(smac->expansion); - } - } - else - { - smac = nasm_malloc(sizeof(SMacro)); - smac->next = *smhead; - *smhead = smac; - } - smac->name = nasm_strdup(mname); - smac->casesense = (i == PP_ASSIGN); - smac->nparam = 0; - smac->level = 0; - smac->expansion = macro_start; - smac->in_progress = FALSE; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_LINE: - /* - * Syntax is `%line nnn[+mmm] [filename]' - */ - tline = tline->next; - skip_white_(tline); - if (!tok_type_(tline, TOK_NUMBER)) - { - error(ERR_NONFATAL, "`%%line' expects line number"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - intn = nasm_readnum(tline->text, &j); - k = yasm_intnum_get_int(intn); - yasm_intnum_destroy(intn); - m = 1; - tline = tline->next; - if (tok_is_(tline, "+")) - { - tline = tline->next; - if (!tok_type_(tline, TOK_NUMBER)) - { - error(ERR_NONFATAL, "`%%line' expects line increment"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - intn = nasm_readnum(tline->text, &j); - m = yasm_intnum_get_int(intn); - yasm_intnum_destroy(intn); - tline = tline->next; - } - skip_white_(tline); - nasm_src_set_linnum(k); - istk->lineinc = m; - if (tline) - { - nasm_free(nasm_src_set_fname(detoken(tline, FALSE))); - } - free_tlist(origline); - return DIRECTIVE_FOUND; - - default: - error(ERR_FATAL, - "preprocessor directive `%s' not yet implemented", - directives[i]); - break; - } - return DIRECTIVE_FOUND; -} - -/* - * Ensure that a macro parameter contains a condition code and - * nothing else. Return the condition code index if so, or -1 - * otherwise. - */ -static int -find_cc(Token * t) -{ - Token *tt; - int i, j, k, m; - - skip_white_(t); - if (t->type != TOK_ID) - return -1; - tt = t->next; - skip_white_(tt); - if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ","))) - return -1; - - i = -1; - j = elements(conditions); - while (j - i > 1) - { - k = (j + i) / 2; - m = nasm_stricmp(t->text, conditions[k]); - if (m == 0) - { - i = k; - j = -2; - break; - } - else if (m < 0) - { - j = k; - } - else - i = k; - } - if (j != -2) - return -1; - return i; -} - -/* - * Expand MMacro-local things: parameter references (%0, %n, %+n, - * %-n) and MMacro-local identifiers (%%foo). - */ -static Token * -expand_mmac_params(Token * tline) -{ - Token *t, *tt, **tail, *thead; - - tail = &thead; - thead = NULL; - - while (tline) - { - if (tline->type == TOK_PREPROC_ID && - (((tline->text[1] == '+' || tline->text[1] == '-') - && tline->text[2]) || tline->text[1] == '%' - || (tline->text[1] >= '0' && tline->text[1] <= '9'))) - { - char *text = NULL; - int type = 0, cc; /* type = 0 to placate optimisers */ - char tmpbuf[30]; - char *second_text = NULL; - int n, i; - MMacro *mac; - - t = tline; - tline = tline->next; - - second_text = strchr(t->text, ':'); - - mac = istk->mstk; - while (mac && !mac->name) /* avoid mistaking %reps for macros */ - mac = mac->next_active; - if (!mac) - error(ERR_NONFATAL, "`%s': not in a macro call", t->text); - else - { - if (second_text) - { - int end = atoi(second_text+1)-1; - int is_fst = 1; - int k; - n = atoi(t->text + 1)-1; - if (end < 0) - end += mac->nparam; - - for (k = n; k <= end; k++) - { - if (k >= mac->nparam) - tt = NULL; - else - { - if (mac->nparam > 1) - k = (k + mac->rotate) % mac->nparam; - tt = mac->params[k]; - } - if (tt) - { - if (!is_fst && mac->paramlen[k]) - { - *tail = new_Token(NULL, TOK_OTHER, ",", 0); - tail = &(*tail)->next; - } - if (mac->paramlen[k]) - is_fst = 0; - for (i = 0; i < mac->paramlen[k]; i++) - { - *tail = - new_Token(NULL, tt->type, tt->text, - 0); - tail = &(*tail)->next; - tt = tt->next; - } - } - text = NULL; /* we've done it here */ - } - } - else - { - switch (t->text[1]) - { - /* - * We have to make a substitution of one of the - * forms %1, %-1, %+1, %%foo, %0. - */ - case '0': - type = TOK_NUMBER; - sprintf(tmpbuf, "%ld", mac->nparam); - text = nasm_strdup(tmpbuf); - break; - case '%': - type = TOK_ID; - sprintf(tmpbuf, "..@%lu.", mac->unique); - text = nasm_strcat(tmpbuf, t->text + 2); - break; - case '-': - n = atoi(t->text + 2) - 1; - if (n >= mac->nparam) - tt = NULL; - else - { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; - } - cc = find_cc(tt); - if (cc == -1) - { - error(ERR_NONFATAL, - "macro parameter %d is not a condition code", - n + 1); - text = NULL; - } - else - { - type = TOK_ID; - if (inverse_ccs[cc] == -1) - { - error(ERR_NONFATAL, - "condition code `%s' is not invertible", - conditions[cc]); - text = NULL; - } - else - text = - nasm_strdup(conditions[inverse_ccs - [cc]]); - } - break; - case '+': - n = atoi(t->text + 2) - 1; - if (n >= mac->nparam) - tt = NULL; - else - { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; - } - cc = find_cc(tt); - if (cc == -1) - { - error(ERR_NONFATAL, - "macro parameter %d is not a condition code", - n + 1); - text = NULL; - } - else - { - type = TOK_ID; - text = nasm_strdup(conditions[cc]); - } - break; - default: - n = atoi(t->text + 1) - 1; - if (n >= mac->nparam) - tt = NULL; - else - { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; - } - if (tt) - { - for (i = 0; i < mac->paramlen[n]; i++) - { - *tail = - new_Token(NULL, tt->type, tt->text, - 0); - tail = &(*tail)->next; - tt = tt->next; - } - } - text = NULL; /* we've done it here */ - break; - } - } - } - - if (!text) - { - delete_Token(t); - } - else - { - *tail = t; - tail = &t->next; - t->type = type; - nasm_free(t->text); - t->text = text; - t->mac = NULL; - } - continue; - } - else - { - t = *tail = tline; - tline = tline->next; - t->mac = NULL; - tail = &t->next; - } - } - *tail = NULL; - t = thead; - for (; t && (tt = t->next) != NULL; t = t->next) - switch (t->type) - { - case TOK_WHITESPACE: - if (tt->type == TOK_WHITESPACE) - { - t->next = delete_Token(tt); - } - break; - case TOK_ID: - if (tt->type == TOK_ID || tt->type == TOK_NUMBER) - { - char *tmp = nasm_strcat(t->text, tt->text); - nasm_free(t->text); - t->text = tmp; - t->next = delete_Token(tt); - } - break; - case TOK_NUMBER: - if (tt->type == TOK_NUMBER) - { - char *tmp = nasm_strcat(t->text, tt->text); - nasm_free(t->text); - t->text = tmp; - t->next = delete_Token(tt); - } - break; - } - - return thead; -} - -/* - * Expand all single-line macro calls made in the given line. - * Return the expanded version of the line. The original is deemed - * to be destroyed in the process. (In reality we'll just move - * Tokens from input to output a lot of the time, rather than - * actually bothering to destroy and replicate.) - */ -static Token * -expand_smacro(Token * tline) -{ - Token *t, *tt, *mstart, **tail, *thead; - SMacro *head = NULL, *m; - Token **params; - int *paramsize; - int nparam, sparam, brackets, rescan; - Token *org_tline = tline; - Context *ctx; - char *mname; - - /* - * Trick: we should avoid changing the start token pointer since it can - * be contained in "next" field of other token. Because of this - * we allocate a copy of first token and work with it; at the end of - * routine we copy it back - */ - if (org_tline) - { - tline = - new_Token(org_tline->next, org_tline->type, org_tline->text, - 0); - tline->mac = org_tline->mac; - nasm_free(org_tline->text); - org_tline->text = NULL; - } - - again: - tail = &thead; - thead = NULL; - - while (tline) - { /* main token loop */ - if ((mname = tline->text)) - { - /* if this token is a local macro, look in local context */ - if (tline->type == TOK_ID || tline->type == TOK_PREPROC_ID) - ctx = get_ctx(mname, TRUE); - else - ctx = NULL; - if (!ctx) - head = smacros[hash(mname)]; - else - head = ctx->localmac; - /* - * We've hit an identifier. As in is_mmacro below, we first - * check whether the identifier is a single-line macro at - * all, then think about checking for parameters if - * necessary. - */ - for (m = head; m; m = m->next) - if (!mstrcmp(m->name, mname, m->casesense)) - break; - if (m) - { - mstart = tline; - params = NULL; - paramsize = NULL; - if (m->nparam == 0) - { - /* - * Simple case: the macro is parameterless. Discard the - * one token that the macro call took, and push the - * expansion back on the to-do stack. - */ - if (!m->expansion) - { - if (!strcmp("__FILE__", m->name)) - { - long num = 0; - nasm_src_get(&num, &(tline->text)); - nasm_quote(&(tline->text)); - tline->type = TOK_STRING; - continue; - } - if (!strcmp("__LINE__", m->name)) - { - nasm_free(tline->text); - make_tok_num(tline, yasm_intnum_create_int(nasm_src_get_linnum())); - continue; - } - tline = delete_Token(tline); - continue; - } - } - else - { - /* - * Complicated case: at least one macro with this name - * exists and takes parameters. We must find the - * parameters in the call, count them, find the SMacro - * that corresponds to that form of the macro call, and - * substitute for the parameters when we expand. What a - * pain. - */ - /*tline = tline->next; - skip_white_(tline);*/ - do { - t = tline->next; - while (tok_type_(t, TOK_SMAC_END)) - { - t->mac->in_progress = FALSE; - t->text = NULL; - t = tline->next = delete_Token(t); - } - tline = t; - } while (tok_type_(tline, TOK_WHITESPACE)); - if (!tok_is_(tline, "(")) - { - /* - * This macro wasn't called with parameters: ignore - * the call. (Behaviour borrowed from gnu cpp.) - */ - tline = mstart; - m = NULL; - } - else - { - int paren = 0; - int white = 0; - brackets = 0; - nparam = 0; - sparam = PARAM_DELTA; - params = nasm_malloc(sparam * sizeof(Token *)); - params[0] = tline->next; - paramsize = nasm_malloc(sparam * sizeof(int)); - paramsize[0] = 0; - while (TRUE) - { /* parameter loop */ - /* - * For some unusual expansions - * which concatenates function call - */ - t = tline->next; - while (tok_type_(t, TOK_SMAC_END)) - { - t->mac->in_progress = FALSE; - t->text = NULL; - t = tline->next = delete_Token(t); - } - tline = t; - - if (!tline) - { - error(ERR_NONFATAL, - "macro call expects terminating `)'"); - break; - } - if (tline->type == TOK_WHITESPACE - && brackets <= 0) - { - if (paramsize[nparam]) - white++; - else - params[nparam] = tline->next; - continue; /* parameter loop */ - } - if (tline->type == TOK_OTHER - && tline->text[1] == 0) - { - char ch = tline->text[0]; - if (ch == ',' && !paren && brackets <= 0) - { - if (++nparam >= sparam) - { - sparam += PARAM_DELTA; - params = nasm_realloc(params, - sparam * sizeof(Token *)); - paramsize = nasm_realloc(paramsize, - sparam * sizeof(int)); - } - params[nparam] = tline->next; - paramsize[nparam] = 0; - white = 0; - continue; /* parameter loop */ - } - if (ch == '{' && - (brackets > 0 || (brackets == 0 && - !paramsize[nparam]))) - { - if (!(brackets++)) - { - params[nparam] = tline->next; - continue; /* parameter loop */ - } - } - if (ch == '}' && brackets > 0) - if (--brackets == 0) - { - brackets = -1; - continue; /* parameter loop */ - } - if (ch == '(' && !brackets) - paren++; - if (ch == ')' && brackets <= 0) - if (--paren < 0) - break; - } - if (brackets < 0) - { - brackets = 0; - error(ERR_NONFATAL, "braces do not " - "enclose all of macro parameter"); - } - paramsize[nparam] += white + 1; - white = 0; - } /* parameter loop */ - nparam++; - while (m && (m->nparam != nparam || - mstrcmp(m->name, mname, - m->casesense))) - m = m->next; - if (!m) - error(ERR_WARNING | ERR_WARN_MNP, - "macro `%s' exists, " - "but not taking %d parameters", - mstart->text, nparam); - } - } - if (m && m->in_progress) - m = NULL; - if (!m) /* in progess or didn't find '(' or wrong nparam */ - { - /* - * Design question: should we handle !tline, which - * indicates missing ')' here, or expand those - * macros anyway, which requires the (t) test a few - * lines down? - */ - nasm_free(params); - nasm_free(paramsize); - tline = mstart; - } - else - { - /* - * Expand the macro: we are placed on the last token of the - * call, so that we can easily split the call from the - * following tokens. We also start by pushing an SMAC_END - * token for the cycle removal. - */ - t = tline; - if (t) - { - tline = t->next; - t->next = NULL; - } - tt = new_Token(tline, TOK_SMAC_END, NULL, 0); - tt->mac = m; - m->in_progress = TRUE; - tline = tt; - for (t = m->expansion; t; t = t->next) - { - if (t->type >= TOK_SMAC_PARAM) - { - Token *pcopy = tline, **ptail = &pcopy; - Token *ttt, *pt; - int i; - - ttt = params[t->type - TOK_SMAC_PARAM]; - for (i = paramsize[t->type - TOK_SMAC_PARAM]; - --i >= 0;) - { - pt = *ptail = - new_Token(tline, ttt->type, ttt->text, - 0); - ptail = &pt->next; - ttt = ttt->next; - } - tline = pcopy; - } - else - { - tt = new_Token(tline, t->type, t->text, 0); - tline = tt; - } - } - - /* - * Having done that, get rid of the macro call, and clean - * up the parameters. - */ - nasm_free(params); - nasm_free(paramsize); - free_tlist(mstart); - continue; /* main token loop */ - } - } - } - - if (tline->type == TOK_SMAC_END) - { - tline->mac->in_progress = FALSE; - tline = delete_Token(tline); - } - else - { - t = *tail = tline; - tline = tline->next; - t->mac = NULL; - t->next = NULL; - tail = &t->next; - } - } - - /* - * Now scan the entire line and look for successive TOK_IDs that resulted - * after expansion (they can't be produced by tokenise()). The successive - * TOK_IDs should be concatenated. - * Also we look for %+ tokens and concatenate the tokens before and after - * them (without white spaces in between). - */ - t = thead; - rescan = 0; - while (t) - { - while (t && t->type != TOK_ID && t->type != TOK_PREPROC_ID) - t = t->next; - if (!t || !t->next) - break; - if (t->next->type == TOK_ID || - t->next->type == TOK_PREPROC_ID || - t->next->type == TOK_NUMBER) - { - char *p = nasm_strcat(t->text, t->next->text); - nasm_free(t->text); - t->next = delete_Token(t->next); - t->text = p; - rescan = 1; - } - else if (t->next->type == TOK_WHITESPACE && t->next->next && - t->next->next->type == TOK_PREPROC_ID && - strcmp(t->next->next->text, "%+") == 0) - { - /* free the next whitespace, the %+ token and next whitespace */ - int i; - for (i = 1; i <= 3; i++) - { - if (!t->next || (i != 2 && t->next->type != TOK_WHITESPACE)) - break; - t->next = delete_Token(t->next); - } /* endfor */ - } - else - t = t->next; - } - /* If we concatenaded something, re-scan the line for macros */ - if (rescan) - { - tline = thead; - goto again; - } - - if (org_tline) - { - if (thead) - { - *org_tline = *thead; - /* since we just gave text to org_line, don't free it */ - thead->text = NULL; - delete_Token(thead); - } - else - { - /* the expression expanded to empty line; - we can't return NULL for some reasons - we just set the line to a single WHITESPACE token. */ - memset(org_tline, 0, sizeof(*org_tline)); - org_tline->text = NULL; - org_tline->type = TOK_WHITESPACE; - } - thead = org_tline; - } - - return thead; -} - -/* - * Similar to expand_smacro but used exclusively with macro identifiers - * right before they are fetched in. The reason is that there can be - * identifiers consisting of several subparts. We consider that if there - * are more than one element forming the name, user wants a expansion, - * otherwise it will be left as-is. Example: - * - * %define %$abc cde - * - * the identifier %$abc will be left as-is so that the handler for %define - * will suck it and define the corresponding value. Other case: - * - * %define _%$abc cde - * - * In this case user wants name to be expanded *before* %define starts - * working, so we'll expand %$abc into something (if it has a value; - * otherwise it will be left as-is) then concatenate all successive - * PP_IDs into one. - */ -static Token * -expand_id(Token * tline) -{ - Token *cur, *oldnext = NULL; - - if (!tline || !tline->next) - return tline; - - cur = tline; - while (cur->next && - (cur->next->type == TOK_ID || - cur->next->type == TOK_PREPROC_ID || cur->next->type == TOK_NUMBER)) - cur = cur->next; - - /* If identifier consists of just one token, don't expand */ - if (cur == tline) - return tline; - - if (cur) - { - oldnext = cur->next; /* Detach the tail past identifier */ - cur->next = NULL; /* so that expand_smacro stops here */ - } - - tline = expand_smacro(tline); - - if (cur) - { - /* expand_smacro possibly changhed tline; re-scan for EOL */ - cur = tline; - while (cur && cur->next) - cur = cur->next; - if (cur) - cur->next = oldnext; - } - - return tline; -} - -/* - * Determine whether the given line constitutes a multi-line macro - * 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 - * name is easy to find. - */ -static MMacro * -is_mmacro(Token * tline, Token *** params_array) -{ - MMacro *head, *m; - Token **params; - int nparam; - - head = mmacros[hash(tline->text)]; - - /* - * Efficiency: first we see if any macro exists with the given - * name. If not, we can return NULL immediately. _Then_ we - * count the parameters, and then we look further along the - * list if necessary to find the proper MMacro. - */ - for (m = head; m; m = m->next) - if (!mstrcmp(m->name, tline->text, m->casesense)) - break; - if (!m) - return NULL; - - /* - * OK, we have a potential macro. Count and demarcate the - * parameters. - */ - count_mmac_params(tline->next, &nparam, ¶ms); - - /* - * So we know how many parameters we've got. Find the MMacro - * structure that handles this number. - */ - while (m) - { - if (m->nparam_min <= nparam && (m->plus || nparam <= m->nparam_max)) - { - /* - * This one is right. Just check if cycle removal - * prohibits us using it before we actually celebrate... - */ - if (m->in_progress) - { -#if 0 - error(ERR_NONFATAL, - "self-reference in multi-line macro `%s'", m->name); -#endif - nasm_free(params); - return NULL; - } - /* - * It's right, and we can use it. Add its default - * parameters to the end of our list if necessary. - */ - if (m->defaults && nparam < m->nparam_min + m->ndefs) - { - params = - nasm_realloc(params, - ((m->nparam_min + m->ndefs + 1) * sizeof(*params))); - while (nparam < m->nparam_min + m->ndefs) - { - params[nparam] = m->defaults[nparam - m->nparam_min]; - nparam++; - } - } - /* - * If we've gone over the maximum parameter count (and - * we're in Plus mode), ignore parameters beyond - * nparam_max. - */ - if (m->plus && nparam > m->nparam_max) - nparam = m->nparam_max; - /* - * Then terminate the parameter list, and leave. - */ - if (!params) - { /* need this special case */ - params = nasm_malloc(sizeof(*params)); - nparam = 0; - } - params[nparam] = NULL; - *params_array = params; - return m; - } - /* - * This one wasn't right: look for the next one with the - * same name. - */ - for (m = m->next; m; m = m->next) - if (!mstrcmp(m->name, tline->text, m->casesense)) - break; - } - - /* - * After all that, we didn't find one with the right number of - * parameters. Issue a warning, and fail to expand the macro. - */ - error(ERR_WARNING | ERR_WARN_MNP, - "macro `%s' exists, but not taking %d parameters", - tline->text, nparam); - nasm_free(params); - return NULL; -} - -/* - * 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. - */ -static int -expand_mmacro(Token * tline) -{ - Token *startline = tline; - Token *label = NULL; - int dont_prepend = 0; - Token **params, *t, *tt; - MMacro *m; - Line *l, *ll; - int i, nparam; - long *paramlen; - - t = tline; - skip_white_(t); -/* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */ - if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID)) - return 0; - m = is_mmacro(t, ¶ms); - if (!m) - { - Token *last; - /* - * We have an id which isn't a macro call. We'll assume - * it might be a label; we'll also check to see if a - * colon follows it. Then, if there's another id after - * that lot, we'll check it again for macro-hood. - */ - label = last = t; - t = t->next; - if (tok_type_(t, TOK_WHITESPACE)) - last = t, t = t->next; - if (tok_is_(t, ":")) - { - dont_prepend = 1; - last = t, t = t->next; - if (tok_type_(t, TOK_WHITESPACE)) - last = t, t = t->next; - } - if (!tok_type_(t, TOK_ID) || (m = is_mmacro(t, ¶ms)) == NULL) - return 0; - last->next = NULL; - tline = t; - } - - /* - * Fix up the parameters: this involves stripping leading and - * trailing whitespace, then stripping braces if they are - * present. - */ - for (nparam = 0; params[nparam]; nparam++) - ; - paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL; - - for (i = 0; params[i]; i++) - { - int brace = FALSE; - int comma = (!m->plus || i < nparam - 1); - - t = params[i]; - skip_white_(t); - if (tok_is_(t, "{")) - t = t->next, brace = TRUE, comma = FALSE; - params[i] = t; - paramlen[i] = 0; - while (t) - { - if (comma && t->type == TOK_OTHER && !strcmp(t->text, ",")) - break; /* ... because we have hit a comma */ - if (comma && t->type == TOK_WHITESPACE && tok_is_(t->next, ",")) - break; /* ... or a space then a comma */ - if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}")) - break; /* ... or a brace */ - t = t->next; - paramlen[i]++; - } - } - - /* - * OK, we have a MMacro structure together with a set of - * parameters. We must now go through the expansion and push - * copies of each Line on to istk->expansion. Substitution of - * parameter tokens and macro-local tokens doesn't get done - * until the single-line macro substitution process; this is - * because delaying them allows us to change the semantics - * later through %rotate. - * - * First, push an end marker on to istk->expansion, mark this - * macro as in progress, and set up its invocation-specific - * variables. - */ - ll = nasm_malloc(sizeof(Line)); - ll->next = istk->expansion; - ll->finishes = m; - ll->first = NULL; - istk->expansion = ll; - - m->in_progress = TRUE; - m->params = params; - m->iline = tline; - m->nparam = nparam; - m->rotate = 0; - m->paramlen = paramlen; - m->unique = unique++; - m->lineno = 0; - - m->next_active = istk->mstk; - istk->mstk = m; - - for (l = m->expansion; l; l = l->next) - { - Token **tail; - - ll = nasm_malloc(sizeof(Line)); - ll->finishes = NULL; - ll->next = istk->expansion; - istk->expansion = ll; - tail = &ll->first; - - for (t = l->first; t; t = t->next) - { - Token *x = t; - if (t->type == TOK_PREPROC_ID && - t->text[1] == '0' && t->text[2] == '0') - { - dont_prepend = -1; - x = label; - if (!x) - continue; - } - tt = *tail = new_Token(NULL, x->type, x->text, 0); - tail = &tt->next; - } - *tail = NULL; - } - - /* - * If we had a label, push it on as the first line of - * the macro expansion. - */ - if (label) - { - if (dont_prepend < 0) - free_tlist(startline); - else - { - ll = nasm_malloc(sizeof(Line)); - ll->finishes = NULL; - ll->next = istk->expansion; - istk->expansion = ll; - ll->first = startline; - if (!dont_prepend) - { - while (label->next) - label = label->next; - label->next = tt = new_Token(NULL, TOK_OTHER, ":", 0); - } - } - } - - list->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); - - return 1; -} - -/* - * Since preprocessor always operates only on the line that didn't - * arrive yet, we should always use ERR_OFFBY1. Also since user - * won't want to see same error twice (preprocessing is done once - * per pass) we will want to show errors only during pass one. - */ -static void -error(int severity, const char *fmt, ...) -{ - va_list arg; - char buff[1024]; - - /* If we're in a dead branch of IF or something like it, ignore the error */ - if (istk && istk->conds && !emitting(istk->conds->state)) - return; - - va_start(arg, fmt); -#ifdef HAVE_VSNPRINTF - vsnprintf(buff, sizeof(buff), fmt, arg); -#else - vsprintf(buff, fmt, arg); -#endif - va_end(arg); - - if (istk && istk->mstk && istk->mstk->name) - _error(severity | ERR_PASS1, "(%s:%d) %s", istk->mstk->name, - istk->mstk->lineno, buff); - else - _error(severity | ERR_PASS1, "%s", buff); -} - -static void -pp_reset(FILE *f, const char *file, int apass, efunc errfunc, evalfunc eval, - ListGen * listgen) -{ - int h; - - first_fp = f; - _error = errfunc; - cstk = NULL; - istk = nasm_malloc(sizeof(Include)); - istk->next = NULL; - istk->conds = NULL; - istk->expansion = NULL; - istk->mstk = NULL; - istk->fp = f; - istk->fname = NULL; - nasm_free(nasm_src_set_fname(nasm_strdup(file))); - nasm_src_set_linnum(0); - istk->lineinc = 1; - defining = NULL; - nested_mac_count = 0; - nested_rep_count = 0; - for (h = 0; h < NHASH; h++) - { - mmacros[h] = NULL; - smacros[h] = NULL; - } - unique = 0; - if (tasm_compatible_mode) { - pp_extra_stdmac(tasm_compat_macros); - } - list = listgen; - evaluate = eval; - pass = apass; - first_line = 1; -} - -/* - * Nasty hack: here we push the contents of `predef' on - * to the top-level expansion stack, since this is the - * most convenient way to implement the pre-include and - * pre-define features. - */ -static void -poke_predef(Line *predef_lines) -{ - Line *pd, *l; - Token *head, **tail, *t; - - for (pd = predef_lines; pd; pd = pd->next) - { - head = NULL; - tail = &head; - for (t = pd->first; t; t = t->next) - { - *tail = new_Token(NULL, t->type, t->text, 0); - tail = &(*tail)->next; - } - l = nasm_malloc(sizeof(Line)); - l->next = istk->expansion; - l->first = head; - l->finishes = FALSE; - istk->expansion = l; - } -} - -static char * -pp_getline(void) -{ - char *line; - Token *tline; - - while (1) - { - /* - * Fetch a tokenised line, either from the macro-expansion - * buffer or from the input file. - */ - tline = NULL; - - if (first_line) - { - /* Reverse order */ - poke_predef(predef); - poke_predef(stddef); - poke_predef(builtindef); - first_line = 0; - } - - if (!istk) - return NULL; - while (istk->expansion && istk->expansion->finishes) - { - Line *l = istk->expansion; - if (!l->finishes->name && l->finishes->in_progress > 1) - { - Line *ll; - - /* - * This is a macro-end marker for a macro with no - * name, which means it's not really a macro at all - * but a %rep block, and the `in_progress' field is - * more than 1, meaning that we still need to - * repeat. (1 means the natural last repetition; 0 - * means termination by %exitrep.) We have - * therefore expanded up to the %endrep, and must - * push the whole block on to the expansion buffer - * again. We don't bother to remove the macro-end - * marker: we'd only have to generate another one - * if we did. - */ - l->finishes->in_progress--; - for (l = l->finishes->expansion; l; l = l->next) - { - Token *t, *tt, **tail; - - ll = nasm_malloc(sizeof(Line)); - ll->next = istk->expansion; - ll->finishes = NULL; - ll->first = NULL; - tail = &ll->first; - - for (t = l->first; t; t = t->next) - { - if (t->text || t->type == TOK_WHITESPACE) - { - tt = *tail = new_Token(NULL, t->type, t->text, 0); - tail = &tt->next; - } - } - - istk->expansion = ll; - } - } - else - { - /* - * Check whether a `%rep' was started and not ended - * within this macro expansion. This can happen and - * should be detected. It's a fatal error because - * I'm too confused to work out how to recover - * sensibly from it. - */ - if (defining) - { - if (defining->name) - error(ERR_PANIC, "defining with name in expansion"); - else if (istk->mstk->name) - error(ERR_FATAL, "`%%rep' without `%%endrep' within" - " expansion of macro `%s'", istk->mstk->name); - } - - /* - * FIXME: investigate the relationship at this point between - * istk->mstk and l->finishes - */ - { - MMacro *m = istk->mstk; - istk->mstk = m->next_active; - if (m->name) - { - /* - * This was a real macro call, not a %rep, and - * therefore the parameter information needs to - * be freed. - */ - nasm_free(m->params); - free_tlist(m->iline); - nasm_free(m->paramlen); - l->finishes->in_progress = FALSE; - } - else - free_mmacro(m); - } - istk->expansion = l->next; - nasm_free(l); - list->downlevel(LIST_MACRO); - } - } - while (1) - { /* until we get a line we can use */ - - if (istk->expansion) - { /* from a macro expansion */ - char *p; - Line *l = istk->expansion; - if (istk->mstk) - istk->mstk->lineno++; - tline = l->first; - istk->expansion = l->next; - nasm_free(l); - p = detoken(tline, FALSE); - list->line(LIST_MACRO, p); - nasm_free(p); - break; - } - line = read_line(); - if (line) - { /* from the current input file */ - line = prepreproc(line); - tline = tokenise(line); - nasm_free(line); - break; - } - /* - * The current file has ended; work down the istk - */ - { - Include *i = istk; - if (i->fp != first_fp) - fclose(i->fp); - if (i->conds) - error(ERR_FATAL, "expected `%%endif' before end of file"); - /* only set line and file name if there's a next node */ - if (i->next) - { - nasm_src_set_linnum(i->lineno); - nasm_free(nasm_src_set_fname(nasm_strdup(i->fname))); - } - istk = i->next; - list->downlevel(LIST_INCLUDE); - nasm_free(i); - if (!istk) - return NULL; - if (istk->expansion && istk->expansion->finishes) - break; - } - } - - /* - * We must expand MMacro parameters and MMacro-local labels - * _before_ we plunge into directive processing, to cope - * with things like `%define something %1' such as STRUC - * uses. Unless we're _defining_ a MMacro, in which case - * those tokens should be left alone to go into the - * definition; and unless we're in a non-emitting - * condition, in which case we don't want to meddle with - * anything. - */ - if (!defining && !(istk->conds && !emitting(istk->conds->state))) - tline = expand_mmac_params(tline); - - /* - * Check the line to see if it's a preprocessor directive. - */ - if (do_directive(tline) == DIRECTIVE_FOUND) - { - continue; - } - else if (defining) - { - /* - * We're defining a multi-line macro. We emit nothing - * at all, and just - * shove the tokenised line on to the macro definition. - */ - Line *l = nasm_malloc(sizeof(Line)); - l->next = defining->expansion; - l->first = tline; - l->finishes = FALSE; - defining->expansion = l; - continue; - } - else if (istk->conds && !emitting(istk->conds->state)) - { - /* - * We're in a non-emitting branch of a condition block. - * Emit nothing at all, not even a blank line: when we - * emerge from the condition we'll give a line-number - * directive so we keep our place correctly. - */ - free_tlist(tline); - continue; - } - else if (istk->mstk && !istk->mstk->in_progress) - { - /* - * We're in a %rep block which has been terminated, so - * we're walking through to the %endrep without - * emitting anything. Emit nothing at all, not even a - * blank line: when we emerge from the %rep block we'll - * give a line-number directive so we keep our place - * correctly. - */ - free_tlist(tline); - continue; - } - else - { - tline = expand_smacro(tline); - if (!expand_mmacro(tline)) - { - /* - * De-tokenise the line again, and emit it. - */ - if (tasm_compatible_mode) - tline = tasm_join_tokens(tline); - - line = detoken(tline, TRUE); - free_tlist(tline); - break; - } - else - { - continue; /* expand_mmacro calls free_tlist */ - } - } - } - - return line; -} - -static void -pp_cleanup(int pass_) -{ - int h; - - if (pass_ == 1) - { - if (defining) - { - error(ERR_NONFATAL, "end of file while still defining macro `%s'", - defining->name); - free_mmacro(defining); - } - return; - } - while (cstk) - ctx_pop(); - for (h = 0; h < NHASH; h++) - { - while (mmacros[h]) - { - MMacro *m = mmacros[h]; - mmacros[h] = mmacros[h]->next; - free_mmacro(m); - } - while (smacros[h]) - { - SMacro *s = smacros[h]; - smacros[h] = smacros[h]->next; - nasm_free(s->name); - free_tlist(s->expansion); - nasm_free(s); - } - } - while (istk) - { - Include *i = istk; - istk = istk->next; - if (i->fp != first_fp) - fclose(i->fp); - nasm_free(i->fname); - nasm_free(i); - } - while (cstk) - ctx_pop(); - if (pass_ == 0) - { - free_llist(builtindef); - free_llist(stddef); - free_llist(predef); - builtindef = NULL; - stddef = NULL; - predef = NULL; - freeTokens = NULL; - delete_Blocks(); - blocks.next = NULL; - blocks.chunk = NULL; - } -} - -void -pp_pre_include(const char *fname) -{ - Token *inc, *space, *name; - Line *l; - - name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0); - space = new_Token(name, TOK_WHITESPACE, NULL, 0); - inc = new_Token(space, TOK_PREPROC_ID, "%include", 0); - - l = nasm_malloc(sizeof(Line)); - l->next = predef; - l->first = inc; - l->finishes = FALSE; - predef = l; -} - -void -pp_pre_define(char *definition) -{ - Token *def, *space; - Line *l; - char *equals; - - equals = strchr(definition, '='); - space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); - def = new_Token(space, TOK_PREPROC_ID, "%define", 0); - if (equals) - *equals = ' '; - space->next = tokenise(definition); - if (equals) - *equals = '='; - - l = nasm_malloc(sizeof(Line)); - l->next = predef; - l->first = def; - l->finishes = FALSE; - predef = l; -} - -void -pp_pre_undefine(char *definition) -{ - Token *def, *space; - Line *l; - - space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); - def = new_Token(space, TOK_PREPROC_ID, "%undef", 0); - space->next = tokenise(definition); - - l = nasm_malloc(sizeof(Line)); - l->next = predef; - l->first = def; - l->finishes = FALSE; - predef = l; -} - -void -pp_builtin_define(char *definition) -{ - Token *def, *space; - Line *l; - char *equals; - - equals = strchr(definition, '='); - space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); - def = new_Token(space, TOK_PREPROC_ID, "%define", 0); - if (equals) - *equals = ' '; - space->next = tokenise(definition); - if (equals) - *equals = '='; - - l = nasm_malloc(sizeof(Line)); - l->next = builtindef; - l->first = def; - l->finishes = FALSE; - builtindef = l; -} - -void -pp_extra_stdmac(const char **macros) -{ - const char **lp; - - for (lp=macros; *lp; lp++) - { - char *macro; - Token *t; - Line *l; - - macro = nasm_strdup(*lp); - t = tokenise(macro); - nasm_free(macro); - - l = nasm_malloc(sizeof(Line)); - l->next = stddef; - l->first = t; - l->finishes = FALSE; - stddef = l; - } -} - -static void -make_tok_num(Token * tok, yasm_intnum *val) -{ - tok->text = yasm_intnum_get_str(val); - tok->type = TOK_NUMBER; - yasm_intnum_destroy(val); -} - -Preproc nasmpp = { - pp_reset, - pp_getline, - pp_cleanup -}; + * Design question: should we handle !tline, which + * indicates missing ')' here, or expand those + * macros anyway, which requires the (t) test a few + * lines down? + */ + nasm_free(params); + nasm_free(paramsize); + tline = mstart; + } + else + { + /* + * Expand the macro: we are placed on the last token of the + * call, so that we can easily split the call from the + * following tokens. We also start by pushing an SMAC_END + * token for the cycle removal. + */ + t = tline; + if (t) + { + tline = t->next; + t->next = NULL; + } + tt = new_Token(tline, TOK_SMAC_END, NULL, 0); + tt->mac = m; + m->in_progress = TRUE; + tline = tt; + for (t = m->expansion; t; t = t->next) + { + if (t->type >= TOK_SMAC_PARAM) + { + Token *pcopy = tline, **ptail = &pcopy; + Token *ttt, *pt; + int i; + + ttt = params[t->type - TOK_SMAC_PARAM]; + for (i = paramsize[t->type - TOK_SMAC_PARAM]; + --i >= 0;) + { + pt = *ptail = + new_Token(tline, ttt->type, ttt->text, + 0); + ptail = &pt->next; + ttt = ttt->next; + } + tline = pcopy; + } + else + { + tt = new_Token(tline, t->type, t->text, 0); + tline = tt; + } + } + + /* + * Having done that, get rid of the macro call, and clean + * up the parameters. + */ + nasm_free(params); + nasm_free(paramsize); + free_tlist(mstart); + continue; /* main token loop */ + } + } + } + + if (tline->type == TOK_SMAC_END) + { + tline->mac->in_progress = FALSE; + tline = delete_Token(tline); + } + else + { + t = *tail = tline; + tline = tline->next; + t->mac = NULL; + t->next = NULL; + tail = &t->next; + } + } + + /* + * Now scan the entire line and look for successive TOK_IDs that resulted + * after expansion (they can't be produced by tokenise()). The successive + * TOK_IDs should be concatenated. + * Also we look for %+ tokens and concatenate the tokens before and after + * them (without white spaces in between). + */ + t = thead; + rescan = 0; + while (t) + { + while (t && t->type != TOK_ID && t->type != TOK_PREPROC_ID) + t = t->next; + if (!t || !t->next) + break; + if (t->next->type == TOK_ID || + t->next->type == TOK_PREPROC_ID || + t->next->type == TOK_NUMBER) + { + char *p = nasm_strcat(t->text, t->next->text); + nasm_free(t->text); + t->next = delete_Token(t->next); + t->text = p; + rescan = 1; + } + else if (t->next->type == TOK_WHITESPACE && t->next->next && + t->next->next->type == TOK_PREPROC_ID && + strcmp(t->next->next->text, "%+") == 0) + { + /* free the next whitespace, the %+ token and next whitespace */ + int i; + for (i = 1; i <= 3; i++) + { + if (!t->next || (i != 2 && t->next->type != TOK_WHITESPACE)) + break; + t->next = delete_Token(t->next); + } /* endfor */ + } + else + t = t->next; + } + /* If we concatenaded something, re-scan the line for macros */ + if (rescan) + { + tline = thead; + goto again; + } + + if (org_tline) + { + if (thead) + { + *org_tline = *thead; + /* since we just gave text to org_line, don't free it */ + thead->text = NULL; + delete_Token(thead); + } + else + { + /* the expression expanded to empty line; + we can't return NULL for some reasons + we just set the line to a single WHITESPACE token. */ + memset(org_tline, 0, sizeof(*org_tline)); + org_tline->text = NULL; + org_tline->type = TOK_WHITESPACE; + } + thead = org_tline; + } + + return thead; +} + +/* + * Similar to expand_smacro but used exclusively with macro identifiers + * right before they are fetched in. The reason is that there can be + * identifiers consisting of several subparts. We consider that if there + * are more than one element forming the name, user wants a expansion, + * otherwise it will be left as-is. Example: + * + * %define %$abc cde + * + * the identifier %$abc will be left as-is so that the handler for %define + * will suck it and define the corresponding value. Other case: + * + * %define _%$abc cde + * + * In this case user wants name to be expanded *before* %define starts + * working, so we'll expand %$abc into something (if it has a value; + * otherwise it will be left as-is) then concatenate all successive + * PP_IDs into one. + */ +static Token * +expand_id(Token * tline) +{ + Token *cur, *oldnext = NULL; + + if (!tline || !tline->next) + return tline; + + cur = tline; + while (cur->next && + (cur->next->type == TOK_ID || + cur->next->type == TOK_PREPROC_ID || cur->next->type == TOK_NUMBER)) + cur = cur->next; + + /* If identifier consists of just one token, don't expand */ + if (cur == tline) + return tline; + + if (cur) + { + oldnext = cur->next; /* Detach the tail past identifier */ + cur->next = NULL; /* so that expand_smacro stops here */ + } + + tline = expand_smacro(tline); + + if (cur) + { + /* expand_smacro possibly changhed tline; re-scan for EOL */ + cur = tline; + while (cur && cur->next) + cur = cur->next; + if (cur) + cur->next = oldnext; + } + + return tline; +} + +/* + * Determine whether the given line constitutes a multi-line macro + * 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 + * name is easy to find. + */ +static MMacro * +is_mmacro(Token * tline, Token *** params_array) +{ + MMacro *head, *m; + Token **params; + int nparam; + + head = mmacros[hash(tline->text)]; + + /* + * Efficiency: first we see if any macro exists with the given + * name. If not, we can return NULL immediately. _Then_ we + * count the parameters, and then we look further along the + * list if necessary to find the proper MMacro. + */ + for (m = head; m; m = m->next) + if (!mstrcmp(m->name, tline->text, m->casesense)) + break; + if (!m) + return NULL; + + /* + * OK, we have a potential macro. Count and demarcate the + * parameters. + */ + count_mmac_params(tline->next, &nparam, ¶ms); + + /* + * So we know how many parameters we've got. Find the MMacro + * structure that handles this number. + */ + while (m) + { + if (m->nparam_min <= nparam && (m->plus || nparam <= m->nparam_max)) + { + /* + * This one is right. Just check if cycle removal + * prohibits us using it before we actually celebrate... + */ + if (m->in_progress) + { +#if 0 + error(ERR_NONFATAL, + "self-reference in multi-line macro `%s'", m->name); +#endif + nasm_free(params); + return NULL; + } + /* + * It's right, and we can use it. Add its default + * parameters to the end of our list if necessary. + */ + if (m->defaults && nparam < m->nparam_min + m->ndefs) + { + params = + nasm_realloc(params, + ((m->nparam_min + m->ndefs + 1) * sizeof(*params))); + while (nparam < m->nparam_min + m->ndefs) + { + params[nparam] = m->defaults[nparam - m->nparam_min]; + nparam++; + } + } + /* + * If we've gone over the maximum parameter count (and + * we're in Plus mode), ignore parameters beyond + * nparam_max. + */ + if (m->plus && nparam > m->nparam_max) + nparam = m->nparam_max; + /* + * Then terminate the parameter list, and leave. + */ + if (!params) + { /* need this special case */ + params = nasm_malloc(sizeof(*params)); + nparam = 0; + } + params[nparam] = NULL; + *params_array = params; + return m; + } + /* + * This one wasn't right: look for the next one with the + * same name. + */ + for (m = m->next; m; m = m->next) + if (!mstrcmp(m->name, tline->text, m->casesense)) + break; + } + + /* + * After all that, we didn't find one with the right number of + * parameters. Issue a warning, and fail to expand the macro. + */ + error(ERR_WARNING | ERR_WARN_MNP, + "macro `%s' exists, but not taking %d parameters", + tline->text, nparam); + nasm_free(params); + return NULL; +} + +/* + * 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. + */ +static int +expand_mmacro(Token * tline) +{ + Token *startline = tline; + Token *label = NULL; + int dont_prepend = 0; + Token **params, *t, *tt; + MMacro *m; + Line *l, *ll; + int i, nparam; + long *paramlen; + + t = tline; + skip_white_(t); +/* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */ + if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID)) + return 0; + m = is_mmacro(t, ¶ms); + if (!m) + { + Token *last; + /* + * We have an id which isn't a macro call. We'll assume + * it might be a label; we'll also check to see if a + * colon follows it. Then, if there's another id after + * that lot, we'll check it again for macro-hood. + */ + label = last = t; + t = t->next; + if (tok_type_(t, TOK_WHITESPACE)) + last = t, t = t->next; + if (tok_is_(t, ":")) + { + dont_prepend = 1; + last = t, t = t->next; + if (tok_type_(t, TOK_WHITESPACE)) + last = t, t = t->next; + } + if (!tok_type_(t, TOK_ID) || (m = is_mmacro(t, ¶ms)) == NULL) + return 0; + last->next = NULL; + tline = t; + } + + /* + * Fix up the parameters: this involves stripping leading and + * trailing whitespace, then stripping braces if they are + * present. + */ + for (nparam = 0; params[nparam]; nparam++) + ; + paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL; + + for (i = 0; params[i]; i++) + { + int brace = FALSE; + int comma = (!m->plus || i < nparam - 1); + + t = params[i]; + skip_white_(t); + if (tok_is_(t, "{")) + t = t->next, brace = TRUE, comma = FALSE; + params[i] = t; + paramlen[i] = 0; + while (t) + { + if (comma && t->type == TOK_OTHER && !strcmp(t->text, ",")) + break; /* ... because we have hit a comma */ + if (comma && t->type == TOK_WHITESPACE && tok_is_(t->next, ",")) + break; /* ... or a space then a comma */ + if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}")) + break; /* ... or a brace */ + t = t->next; + paramlen[i]++; + } + } + + /* + * OK, we have a MMacro structure together with a set of + * parameters. We must now go through the expansion and push + * copies of each Line on to istk->expansion. Substitution of + * parameter tokens and macro-local tokens doesn't get done + * until the single-line macro substitution process; this is + * because delaying them allows us to change the semantics + * later through %rotate. + * + * First, push an end marker on to istk->expansion, mark this + * macro as in progress, and set up its invocation-specific + * variables. + */ + ll = nasm_malloc(sizeof(Line)); + ll->next = istk->expansion; + ll->finishes = m; + ll->first = NULL; + istk->expansion = ll; + + m->in_progress = TRUE; + m->params = params; + m->iline = tline; + m->nparam = nparam; + m->rotate = 0; + m->paramlen = paramlen; + m->unique = unique++; + m->lineno = 0; + + m->next_active = istk->mstk; + istk->mstk = m; + + for (l = m->expansion; l; l = l->next) + { + Token **tail; + + ll = nasm_malloc(sizeof(Line)); + ll->finishes = NULL; + ll->next = istk->expansion; + istk->expansion = ll; + tail = &ll->first; + + for (t = l->first; t; t = t->next) + { + Token *x = t; + if (t->type == TOK_PREPROC_ID && + t->text[1] == '0' && t->text[2] == '0') + { + dont_prepend = -1; + x = label; + if (!x) + continue; + } + tt = *tail = new_Token(NULL, x->type, x->text, 0); + tail = &tt->next; + } + *tail = NULL; + } + + /* + * If we had a label, push it on as the first line of + * the macro expansion. + */ + if (label) + { + if (dont_prepend < 0) + free_tlist(startline); + else + { + ll = nasm_malloc(sizeof(Line)); + ll->finishes = NULL; + ll->next = istk->expansion; + istk->expansion = ll; + ll->first = startline; + if (!dont_prepend) + { + while (label->next) + label = label->next; + label->next = tt = new_Token(NULL, TOK_OTHER, ":", 0); + } + } + } + + list->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); + + return 1; +} + +/* + * Since preprocessor always operates only on the line that didn't + * arrive yet, we should always use ERR_OFFBY1. Also since user + * won't want to see same error twice (preprocessing is done once + * per pass) we will want to show errors only during pass one. + */ +static void +error(int severity, const char *fmt, ...) +{ + va_list arg; + char buff[1024]; + + /* If we're in a dead branch of IF or something like it, ignore the error */ + if (istk && istk->conds && !emitting(istk->conds->state)) + return; + + va_start(arg, fmt); +#ifdef HAVE_VSNPRINTF + vsnprintf(buff, sizeof(buff), fmt, arg); +#else + vsprintf(buff, fmt, arg); +#endif + va_end(arg); + + if (istk && istk->mstk && istk->mstk->name) + _error(severity | ERR_PASS1, "(%s:%d) %s", istk->mstk->name, + istk->mstk->lineno, buff); + else + _error(severity | ERR_PASS1, "%s", buff); +} + +static void +pp_reset(FILE *f, const char *file, int apass, efunc errfunc, evalfunc eval, + ListGen * listgen) +{ + int h; + + first_fp = f; + _error = errfunc; + cstk = NULL; + istk = nasm_malloc(sizeof(Include)); + istk->next = NULL; + istk->conds = NULL; + istk->expansion = NULL; + istk->mstk = NULL; + istk->fp = f; + istk->fname = NULL; + nasm_free(nasm_src_set_fname(nasm_strdup(file))); + nasm_src_set_linnum(0); + istk->lineinc = 1; + defining = NULL; + nested_mac_count = 0; + nested_rep_count = 0; + for (h = 0; h < NHASH; h++) + { + mmacros[h] = NULL; + smacros[h] = NULL; + } + unique = 0; + if (tasm_compatible_mode) { + pp_extra_stdmac(tasm_compat_macros); + } + list = listgen; + evaluate = eval; + pass = apass; + first_line = 1; +} + +/* + * Nasty hack: here we push the contents of `predef' on + * to the top-level expansion stack, since this is the + * most convenient way to implement the pre-include and + * pre-define features. + */ +static void +poke_predef(Line *predef_lines) +{ + Line *pd, *l; + Token *head, **tail, *t; + + for (pd = predef_lines; pd; pd = pd->next) + { + head = NULL; + tail = &head; + for (t = pd->first; t; t = t->next) + { + *tail = new_Token(NULL, t->type, t->text, 0); + tail = &(*tail)->next; + } + l = nasm_malloc(sizeof(Line)); + l->next = istk->expansion; + l->first = head; + l->finishes = FALSE; + istk->expansion = l; + } +} + +static char * +pp_getline(void) +{ + char *line; + Token *tline; + + while (1) + { + /* + * Fetch a tokenised line, either from the macro-expansion + * buffer or from the input file. + */ + tline = NULL; + + if (first_line) + { + /* Reverse order */ + poke_predef(predef); + poke_predef(stddef); + poke_predef(builtindef); + first_line = 0; + } + + if (!istk) + return NULL; + while (istk->expansion && istk->expansion->finishes) + { + Line *l = istk->expansion; + if (!l->finishes->name && l->finishes->in_progress > 1) + { + Line *ll; + + /* + * This is a macro-end marker for a macro with no + * name, which means it's not really a macro at all + * but a %rep block, and the `in_progress' field is + * more than 1, meaning that we still need to + * repeat. (1 means the natural last repetition; 0 + * means termination by %exitrep.) We have + * therefore expanded up to the %endrep, and must + * push the whole block on to the expansion buffer + * again. We don't bother to remove the macro-end + * marker: we'd only have to generate another one + * if we did. + */ + l->finishes->in_progress--; + for (l = l->finishes->expansion; l; l = l->next) + { + Token *t, *tt, **tail; + + ll = nasm_malloc(sizeof(Line)); + ll->next = istk->expansion; + ll->finishes = NULL; + ll->first = NULL; + tail = &ll->first; + + for (t = l->first; t; t = t->next) + { + if (t->text || t->type == TOK_WHITESPACE) + { + tt = *tail = new_Token(NULL, t->type, t->text, 0); + tail = &tt->next; + } + } + + istk->expansion = ll; + } + } + else + { + /* + * Check whether a `%rep' was started and not ended + * within this macro expansion. This can happen and + * should be detected. It's a fatal error because + * I'm too confused to work out how to recover + * sensibly from it. + */ + if (defining) + { + if (defining->name) + error(ERR_PANIC, "defining with name in expansion"); + else if (istk->mstk->name) + error(ERR_FATAL, "`%%rep' without `%%endrep' within" + " expansion of macro `%s'", istk->mstk->name); + } + + /* + * FIXME: investigate the relationship at this point between + * istk->mstk and l->finishes + */ + { + MMacro *m = istk->mstk; + istk->mstk = m->next_active; + if (m->name) + { + /* + * This was a real macro call, not a %rep, and + * therefore the parameter information needs to + * be freed. + */ + nasm_free(m->params); + free_tlist(m->iline); + nasm_free(m->paramlen); + l->finishes->in_progress = FALSE; + } + else + free_mmacro(m); + } + istk->expansion = l->next; + nasm_free(l); + list->downlevel(LIST_MACRO); + } + } + while (1) + { /* until we get a line we can use */ + + if (istk->expansion) + { /* from a macro expansion */ + char *p; + Line *l = istk->expansion; + if (istk->mstk) + istk->mstk->lineno++; + tline = l->first; + istk->expansion = l->next; + nasm_free(l); + p = detoken(tline, FALSE); + list->line(LIST_MACRO, p); + nasm_free(p); + break; + } + line = read_line(); + if (line) + { /* from the current input file */ + line = prepreproc(line); + tline = tokenise(line); + nasm_free(line); + break; + } + /* + * The current file has ended; work down the istk + */ + { + Include *i = istk; + if (i->fp != first_fp) + fclose(i->fp); + if (i->conds) + error(ERR_FATAL, "expected `%%endif' before end of file"); + /* only set line and file name if there's a next node */ + if (i->next) + { + nasm_src_set_linnum(i->lineno); + nasm_free(nasm_src_set_fname(nasm_strdup(i->fname))); + } + istk = i->next; + list->downlevel(LIST_INCLUDE); + nasm_free(i); + if (!istk) + return NULL; + if (istk->expansion && istk->expansion->finishes) + break; + } + } + + /* + * We must expand MMacro parameters and MMacro-local labels + * _before_ we plunge into directive processing, to cope + * with things like `%define something %1' such as STRUC + * uses. Unless we're _defining_ a MMacro, in which case + * those tokens should be left alone to go into the + * definition; and unless we're in a non-emitting + * condition, in which case we don't want to meddle with + * anything. + */ + if (!defining && !(istk->conds && !emitting(istk->conds->state))) + tline = expand_mmac_params(tline); + + /* + * Check the line to see if it's a preprocessor directive. + */ + if (do_directive(tline) == DIRECTIVE_FOUND) + { + continue; + } + else if (defining) + { + /* + * We're defining a multi-line macro. We emit nothing + * at all, and just + * shove the tokenised line on to the macro definition. + */ + Line *l = nasm_malloc(sizeof(Line)); + l->next = defining->expansion; + l->first = tline; + l->finishes = FALSE; + defining->expansion = l; + continue; + } + else if (istk->conds && !emitting(istk->conds->state)) + { + /* + * We're in a non-emitting branch of a condition block. + * Emit nothing at all, not even a blank line: when we + * emerge from the condition we'll give a line-number + * directive so we keep our place correctly. + */ + free_tlist(tline); + continue; + } + else if (istk->mstk && !istk->mstk->in_progress) + { + /* + * We're in a %rep block which has been terminated, so + * we're walking through to the %endrep without + * emitting anything. Emit nothing at all, not even a + * blank line: when we emerge from the %rep block we'll + * give a line-number directive so we keep our place + * correctly. + */ + free_tlist(tline); + continue; + } + else + { + tline = expand_smacro(tline); + if (!expand_mmacro(tline)) + { + /* + * De-tokenise the line again, and emit it. + */ + if (tasm_compatible_mode) + tline = tasm_join_tokens(tline); + + line = detoken(tline, TRUE); + free_tlist(tline); + break; + } + else + { + continue; /* expand_mmacro calls free_tlist */ + } + } + } + + return line; +} + +static void +pp_cleanup(int pass_) +{ + int h; + + if (pass_ == 1) + { + if (defining) + { + error(ERR_NONFATAL, "end of file while still defining macro `%s'", + defining->name); + free_mmacro(defining); + } + return; + } + while (cstk) + ctx_pop(); + for (h = 0; h < NHASH; h++) + { + while (mmacros[h]) + { + MMacro *m = mmacros[h]; + mmacros[h] = mmacros[h]->next; + free_mmacro(m); + } + while (smacros[h]) + { + SMacro *s = smacros[h]; + smacros[h] = smacros[h]->next; + nasm_free(s->name); + free_tlist(s->expansion); + nasm_free(s); + } + } + while (istk) + { + Include *i = istk; + istk = istk->next; + if (i->fp != first_fp) + fclose(i->fp); + nasm_free(i->fname); + nasm_free(i); + } + while (cstk) + ctx_pop(); + if (pass_ == 0) + { + free_llist(builtindef); + free_llist(stddef); + free_llist(predef); + builtindef = NULL; + stddef = NULL; + predef = NULL; + freeTokens = NULL; + delete_Blocks(); + blocks.next = NULL; + blocks.chunk = NULL; + } +} + +void +pp_pre_include(const char *fname) +{ + Token *inc, *space, *name; + Line *l; + + name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0); + space = new_Token(name, TOK_WHITESPACE, NULL, 0); + inc = new_Token(space, TOK_PREPROC_ID, "%include", 0); + + l = nasm_malloc(sizeof(Line)); + l->next = predef; + l->first = inc; + l->finishes = FALSE; + predef = l; +} + +void +pp_pre_define(char *definition) +{ + Token *def, *space; + Line *l; + char *equals; + + equals = strchr(definition, '='); + space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); + def = new_Token(space, TOK_PREPROC_ID, "%define", 0); + if (equals) + *equals = ' '; + space->next = tokenise(definition); + if (equals) + *equals = '='; + + l = nasm_malloc(sizeof(Line)); + l->next = predef; + l->first = def; + l->finishes = FALSE; + predef = l; +} + +void +pp_pre_undefine(char *definition) +{ + Token *def, *space; + Line *l; + + space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); + def = new_Token(space, TOK_PREPROC_ID, "%undef", 0); + space->next = tokenise(definition); + + l = nasm_malloc(sizeof(Line)); + l->next = predef; + l->first = def; + l->finishes = FALSE; + predef = l; +} + +void +pp_builtin_define(char *definition) +{ + Token *def, *space; + Line *l; + char *equals; + + equals = strchr(definition, '='); + space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); + def = new_Token(space, TOK_PREPROC_ID, "%define", 0); + if (equals) + *equals = ' '; + space->next = tokenise(definition); + if (equals) + *equals = '='; + + l = nasm_malloc(sizeof(Line)); + l->next = builtindef; + l->first = def; + l->finishes = FALSE; + builtindef = l; +} + +void +pp_extra_stdmac(const char **macros) +{ + const char **lp; + + for (lp=macros; *lp; lp++) + { + char *macro; + Token *t; + Line *l; + + macro = nasm_strdup(*lp); + t = tokenise(macro); + nasm_free(macro); + + l = nasm_malloc(sizeof(Line)); + l->next = stddef; + l->first = t; + l->finishes = FALSE; + stddef = l; + } +} + +static void +make_tok_num(Token * tok, yasm_intnum *val) +{ + tok->text = yasm_intnum_get_str(val); + tok->type = TOK_NUMBER; + yasm_intnum_destroy(val); +} + +Preproc nasmpp = { + pp_reset, + pp_getline, + pp_cleanup +}; diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.h b/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.h index 0905edfb5b..a1990206f2 100644 --- a/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.h +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-pp.h @@ -1,22 +1,22 @@ -/* preproc.h header file for preproc.c - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#ifndef YASM_NASM_PREPROC_H -#define YASM_NASM_PREPROC_H - -void pp_pre_include (const char *); -void pp_pre_define (char *); -void pp_pre_undefine (char *); -void pp_builtin_define (char *); -void pp_extra_stdmac (const char **); - -extern Preproc nasmpp; - -void nasm_preproc_add_dep(char *); - -#endif +/* preproc.h header file for preproc.c + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef YASM_NASM_PREPROC_H +#define YASM_NASM_PREPROC_H + +void pp_pre_include (const char *); +void pp_pre_define (char *); +void pp_pre_undefine (char *); +void pp_builtin_define (char *); +void pp_extra_stdmac (const char **); + +extern Preproc nasmpp; + +void nasm_preproc_add_dep(char *); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm-preproc.c b/contrib/tools/yasm/modules/preprocs/nasm/nasm-preproc.c index 6653be73b6..566dd8004b 100644 --- a/contrib/tools/yasm/modules/preprocs/nasm/nasm-preproc.c +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm-preproc.c @@ -1,342 +1,342 @@ -/* - * Imported NASM preprocessor - glue code - * - * Copyright (C) 2002-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. - */ -#include <util.h> - -#include <libyasm.h> - -#include "nasm.h" -#include "nasmlib.h" -#include "nasm-pp.h" -#include "nasm-eval.h" - -typedef struct yasm_preproc_nasm { - yasm_preproc_base preproc; /* Base structure */ - - FILE *in; - char *line; - char *file_name; - long prior_linnum; - int lineinc; -} yasm_preproc_nasm; -yasm_symtab *nasm_symtab; -static yasm_linemap *cur_lm; -static yasm_errwarns *cur_errwarns; -int tasm_compatible_mode = 0; -int tasm_locals; -const char *tasm_segment; - -#include "nasm-version.c" - -typedef struct preproc_dep { - STAILQ_ENTRY(preproc_dep) link; - char *name; -} preproc_dep; - -static STAILQ_HEAD(preproc_dep_head, preproc_dep) *preproc_deps; -static int done_dep_preproc; - -yasm_preproc_module yasm_nasm_LTX_preproc; - -static void -nil_listgen_init(char *p, efunc e) -{ -} - -static void -nil_listgen_cleanup(void) -{ -} - -static void -nil_listgen_output(long v, const void *d, unsigned long v2) -{ -} - -static void -nil_listgen_line(int v, char *p) -{ -} - -static void -nil_listgen_uplevel(int v) -{ -} - -static void -nil_listgen_downlevel(int v) -{ -} - -static ListGen nil_list = { - nil_listgen_init, - nil_listgen_cleanup, - nil_listgen_output, - nil_listgen_line, - nil_listgen_uplevel, - nil_listgen_downlevel -}; - - -static void -nasm_efunc(int severity, const char *fmt, ...) -{ - va_list va; - - va_start(va, fmt); - switch (severity & ERR_MASK) { - case ERR_WARNING: - yasm_warn_set_va(YASM_WARN_PREPROC, fmt, va); - break; - case ERR_NONFATAL: - yasm_error_set_va(YASM_ERROR_GENERAL, fmt, va); - break; - case ERR_FATAL: - yasm_fatal(fmt, va); - /*@notreached@*/ - break; - case ERR_PANIC: - yasm_internal_error(fmt); /* FIXME */ - break; - case ERR_DEBUG: - break; - } - va_end(va); - yasm_errwarn_propagate(cur_errwarns, - yasm_linemap_poke(cur_lm, nasm_src_get_fname(), - (unsigned long)nasm_src_get_linnum())); -} - -static yasm_preproc * -nasm_preproc_create(const char *in_filename, yasm_symtab *symtab, - yasm_linemap *lm, yasm_errwarns *errwarns) -{ - FILE *f; - yasm_preproc_nasm *preproc_nasm = yasm_xmalloc(sizeof(yasm_preproc_nasm)); - - preproc_nasm->preproc.module = &yasm_nasm_LTX_preproc; - - if (strcmp(in_filename, "-") != 0) { - f = fopen(in_filename, "r"); - if (!f) +/* + * Imported NASM preprocessor - glue code + * + * Copyright (C) 2002-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. + */ +#include <util.h> + +#include <libyasm.h> + +#include "nasm.h" +#include "nasmlib.h" +#include "nasm-pp.h" +#include "nasm-eval.h" + +typedef struct yasm_preproc_nasm { + yasm_preproc_base preproc; /* Base structure */ + + FILE *in; + char *line; + char *file_name; + long prior_linnum; + int lineinc; +} yasm_preproc_nasm; +yasm_symtab *nasm_symtab; +static yasm_linemap *cur_lm; +static yasm_errwarns *cur_errwarns; +int tasm_compatible_mode = 0; +int tasm_locals; +const char *tasm_segment; + +#include "nasm-version.c" + +typedef struct preproc_dep { + STAILQ_ENTRY(preproc_dep) link; + char *name; +} preproc_dep; + +static STAILQ_HEAD(preproc_dep_head, preproc_dep) *preproc_deps; +static int done_dep_preproc; + +yasm_preproc_module yasm_nasm_LTX_preproc; + +static void +nil_listgen_init(char *p, efunc e) +{ +} + +static void +nil_listgen_cleanup(void) +{ +} + +static void +nil_listgen_output(long v, const void *d, unsigned long v2) +{ +} + +static void +nil_listgen_line(int v, char *p) +{ +} + +static void +nil_listgen_uplevel(int v) +{ +} + +static void +nil_listgen_downlevel(int v) +{ +} + +static ListGen nil_list = { + nil_listgen_init, + nil_listgen_cleanup, + nil_listgen_output, + nil_listgen_line, + nil_listgen_uplevel, + nil_listgen_downlevel +}; + + +static void +nasm_efunc(int severity, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + switch (severity & ERR_MASK) { + case ERR_WARNING: + yasm_warn_set_va(YASM_WARN_PREPROC, fmt, va); + break; + case ERR_NONFATAL: + yasm_error_set_va(YASM_ERROR_GENERAL, fmt, va); + break; + case ERR_FATAL: + yasm_fatal(fmt, va); + /*@notreached@*/ + break; + case ERR_PANIC: + yasm_internal_error(fmt); /* FIXME */ + break; + case ERR_DEBUG: + break; + } + va_end(va); + yasm_errwarn_propagate(cur_errwarns, + yasm_linemap_poke(cur_lm, nasm_src_get_fname(), + (unsigned long)nasm_src_get_linnum())); +} + +static yasm_preproc * +nasm_preproc_create(const char *in_filename, yasm_symtab *symtab, + yasm_linemap *lm, yasm_errwarns *errwarns) +{ + FILE *f; + yasm_preproc_nasm *preproc_nasm = yasm_xmalloc(sizeof(yasm_preproc_nasm)); + + preproc_nasm->preproc.module = &yasm_nasm_LTX_preproc; + + if (strcmp(in_filename, "-") != 0) { + f = fopen(in_filename, "r"); + if (!f) yasm__fatal_missing_input_file( N_("Could not open input file"), in_filename ); - } - else - f = stdin; - - preproc_nasm->in = f; - nasm_symtab = symtab; - cur_lm = lm; - cur_errwarns = errwarns; - preproc_deps = NULL; - done_dep_preproc = 0; - preproc_nasm->line = NULL; - preproc_nasm->file_name = NULL; - preproc_nasm->prior_linnum = 0; - preproc_nasm->lineinc = 0; - nasmpp.reset(f, in_filename, 2, nasm_efunc, nasm_evaluate, &nil_list); - - pp_extra_stdmac(nasm_version_mac); - - return (yasm_preproc *)preproc_nasm; -} - -static void -nasm_preproc_destroy(yasm_preproc *preproc) -{ - yasm_preproc_nasm *preproc_nasm = (yasm_preproc_nasm *)preproc; - nasmpp.cleanup(0); - if (preproc_nasm->line) - yasm_xfree(preproc_nasm->line); - if (preproc_nasm->file_name) - yasm_xfree(preproc_nasm->file_name); - yasm_xfree(preproc); - if (preproc_deps) - yasm_xfree(preproc_deps); -} - -static char * -nasm_preproc_get_line(yasm_preproc *preproc) -{ - yasm_preproc_nasm *preproc_nasm = (yasm_preproc_nasm *)preproc; - long linnum; - int altline; - char *line; - - if (preproc_nasm->line) { - char *retval = preproc_nasm->line; - preproc_nasm->line = NULL; - return retval; - } - - line = nasmpp.getline(); - if (!line) - { - nasmpp.cleanup(1); - return NULL; /* EOF */ - } - - linnum = preproc_nasm->prior_linnum += preproc_nasm->lineinc; - altline = nasm_src_get(&linnum, &preproc_nasm->file_name); - if (altline != 0) { - preproc_nasm->lineinc = - (altline != -1 || preproc_nasm->lineinc != 1); - preproc_nasm->line = line; - line = yasm_xmalloc(40+strlen(preproc_nasm->file_name)); - sprintf(line, "%%line %ld+%d %s", linnum, - preproc_nasm->lineinc, preproc_nasm->file_name); - preproc_nasm->prior_linnum = linnum; - } - - return line; -} - -void -nasm_preproc_add_dep(char *name) -{ - preproc_dep *dep; - - /* If not processing dependencies, simply return */ - if (!preproc_deps) - return; - - /* Save in preproc_deps */ - dep = yasm_xmalloc(sizeof(preproc_dep)); - dep->name = yasm__xstrdup(name); - STAILQ_INSERT_TAIL(preproc_deps, dep, link); -} - -static size_t -nasm_preproc_get_included_file(yasm_preproc *preproc, /*@out@*/ char *buf, - size_t max_size) -{ - if (!preproc_deps) { - preproc_deps = yasm_xmalloc(sizeof(struct preproc_dep_head)); - STAILQ_INIT(preproc_deps); - } - - for (;;) { - char *line; - - /* Pull first dep out of preproc_deps and return it if there is one */ - if (!STAILQ_EMPTY(preproc_deps)) { - char *name; - preproc_dep *dep = STAILQ_FIRST(preproc_deps); - STAILQ_REMOVE_HEAD(preproc_deps, link); - name = dep->name; - yasm_xfree(dep); - strncpy(buf, name, max_size); - buf[max_size-1] = '\0'; - yasm_xfree(name); - return strlen(buf); - } - - /* No more preprocessing to do */ - if (done_dep_preproc) { - return 0; - } - - /* Preprocess some more, throwing away the result */ - line = nasmpp.getline(); - if (line) - yasm_xfree(line); - else - done_dep_preproc = 1; - } -} - -static void -nasm_preproc_add_include_file(yasm_preproc *preproc, const char *filename) -{ - pp_pre_include(filename); -} - -static void -nasm_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) -{ - char *mnv = yasm__xstrdup(macronameval); - pp_pre_define(mnv); - yasm_xfree(mnv); -} - -static void -nasm_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) -{ - char *mn = yasm__xstrdup(macroname); - pp_pre_undefine(mn); - yasm_xfree(mn); -} - -static void -nasm_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) -{ - char *mnv = yasm__xstrdup(macronameval); - pp_builtin_define(mnv); - yasm_xfree(mnv); -} - -static void -nasm_preproc_add_standard(yasm_preproc *preproc, const char **macros) -{ - pp_extra_stdmac(macros); -} - -/* Define preproc structure -- see preproc.h for details */ -yasm_preproc_module yasm_nasm_LTX_preproc = { - "Real NASM Preprocessor", - "nasm", - nasm_preproc_create, - nasm_preproc_destroy, - nasm_preproc_get_line, - nasm_preproc_get_included_file, - nasm_preproc_add_include_file, - nasm_preproc_predefine_macro, - nasm_preproc_undefine_macro, - nasm_preproc_define_builtin, - nasm_preproc_add_standard -}; - -static yasm_preproc * -tasm_preproc_create(const char *in_filename, yasm_symtab *symtab, - yasm_linemap *lm, yasm_errwarns *errwarns) -{ - tasm_compatible_mode = 1; - return nasm_preproc_create(in_filename, symtab, lm, errwarns); -} - -yasm_preproc_module yasm_tasm_LTX_preproc = { - "Real TASM Preprocessor", - "tasm", - tasm_preproc_create, - nasm_preproc_destroy, - nasm_preproc_get_line, - nasm_preproc_get_included_file, - nasm_preproc_add_include_file, - nasm_preproc_predefine_macro, - nasm_preproc_undefine_macro, - nasm_preproc_define_builtin, - nasm_preproc_add_standard -}; + } + else + f = stdin; + + preproc_nasm->in = f; + nasm_symtab = symtab; + cur_lm = lm; + cur_errwarns = errwarns; + preproc_deps = NULL; + done_dep_preproc = 0; + preproc_nasm->line = NULL; + preproc_nasm->file_name = NULL; + preproc_nasm->prior_linnum = 0; + preproc_nasm->lineinc = 0; + nasmpp.reset(f, in_filename, 2, nasm_efunc, nasm_evaluate, &nil_list); + + pp_extra_stdmac(nasm_version_mac); + + return (yasm_preproc *)preproc_nasm; +} + +static void +nasm_preproc_destroy(yasm_preproc *preproc) +{ + yasm_preproc_nasm *preproc_nasm = (yasm_preproc_nasm *)preproc; + nasmpp.cleanup(0); + if (preproc_nasm->line) + yasm_xfree(preproc_nasm->line); + if (preproc_nasm->file_name) + yasm_xfree(preproc_nasm->file_name); + yasm_xfree(preproc); + if (preproc_deps) + yasm_xfree(preproc_deps); +} + +static char * +nasm_preproc_get_line(yasm_preproc *preproc) +{ + yasm_preproc_nasm *preproc_nasm = (yasm_preproc_nasm *)preproc; + long linnum; + int altline; + char *line; + + if (preproc_nasm->line) { + char *retval = preproc_nasm->line; + preproc_nasm->line = NULL; + return retval; + } + + line = nasmpp.getline(); + if (!line) + { + nasmpp.cleanup(1); + return NULL; /* EOF */ + } + + linnum = preproc_nasm->prior_linnum += preproc_nasm->lineinc; + altline = nasm_src_get(&linnum, &preproc_nasm->file_name); + if (altline != 0) { + preproc_nasm->lineinc = + (altline != -1 || preproc_nasm->lineinc != 1); + preproc_nasm->line = line; + line = yasm_xmalloc(40+strlen(preproc_nasm->file_name)); + sprintf(line, "%%line %ld+%d %s", linnum, + preproc_nasm->lineinc, preproc_nasm->file_name); + preproc_nasm->prior_linnum = linnum; + } + + return line; +} + +void +nasm_preproc_add_dep(char *name) +{ + preproc_dep *dep; + + /* If not processing dependencies, simply return */ + if (!preproc_deps) + return; + + /* Save in preproc_deps */ + dep = yasm_xmalloc(sizeof(preproc_dep)); + dep->name = yasm__xstrdup(name); + STAILQ_INSERT_TAIL(preproc_deps, dep, link); +} + +static size_t +nasm_preproc_get_included_file(yasm_preproc *preproc, /*@out@*/ char *buf, + size_t max_size) +{ + if (!preproc_deps) { + preproc_deps = yasm_xmalloc(sizeof(struct preproc_dep_head)); + STAILQ_INIT(preproc_deps); + } + + for (;;) { + char *line; + + /* Pull first dep out of preproc_deps and return it if there is one */ + if (!STAILQ_EMPTY(preproc_deps)) { + char *name; + preproc_dep *dep = STAILQ_FIRST(preproc_deps); + STAILQ_REMOVE_HEAD(preproc_deps, link); + name = dep->name; + yasm_xfree(dep); + strncpy(buf, name, max_size); + buf[max_size-1] = '\0'; + yasm_xfree(name); + return strlen(buf); + } + + /* No more preprocessing to do */ + if (done_dep_preproc) { + return 0; + } + + /* Preprocess some more, throwing away the result */ + line = nasmpp.getline(); + if (line) + yasm_xfree(line); + else + done_dep_preproc = 1; + } +} + +static void +nasm_preproc_add_include_file(yasm_preproc *preproc, const char *filename) +{ + pp_pre_include(filename); +} + +static void +nasm_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) +{ + char *mnv = yasm__xstrdup(macronameval); + pp_pre_define(mnv); + yasm_xfree(mnv); +} + +static void +nasm_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) +{ + char *mn = yasm__xstrdup(macroname); + pp_pre_undefine(mn); + yasm_xfree(mn); +} + +static void +nasm_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) +{ + char *mnv = yasm__xstrdup(macronameval); + pp_builtin_define(mnv); + yasm_xfree(mnv); +} + +static void +nasm_preproc_add_standard(yasm_preproc *preproc, const char **macros) +{ + pp_extra_stdmac(macros); +} + +/* Define preproc structure -- see preproc.h for details */ +yasm_preproc_module yasm_nasm_LTX_preproc = { + "Real NASM Preprocessor", + "nasm", + nasm_preproc_create, + nasm_preproc_destroy, + nasm_preproc_get_line, + nasm_preproc_get_included_file, + nasm_preproc_add_include_file, + nasm_preproc_predefine_macro, + nasm_preproc_undefine_macro, + nasm_preproc_define_builtin, + nasm_preproc_add_standard +}; + +static yasm_preproc * +tasm_preproc_create(const char *in_filename, yasm_symtab *symtab, + yasm_linemap *lm, yasm_errwarns *errwarns) +{ + tasm_compatible_mode = 1; + return nasm_preproc_create(in_filename, symtab, lm, errwarns); +} + +yasm_preproc_module yasm_tasm_LTX_preproc = { + "Real TASM Preprocessor", + "tasm", + tasm_preproc_create, + nasm_preproc_destroy, + nasm_preproc_get_line, + nasm_preproc_get_included_file, + nasm_preproc_add_include_file, + nasm_preproc_predefine_macro, + nasm_preproc_undefine_macro, + nasm_preproc_define_builtin, + nasm_preproc_add_standard +}; diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasm.h b/contrib/tools/yasm/modules/preprocs/nasm/nasm.h index 990118f983..b3382ffe92 100644 --- a/contrib/tools/yasm/modules/preprocs/nasm/nasm.h +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasm.h @@ -1,283 +1,283 @@ -/* nasm.h main header file for the Netwide Assembler: inter-module interface - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * initial version: 27/iii/95 by Simon Tatham - */ -#ifndef YASM_NASM_H -#define YASM_NASM_H - -#ifndef NULL -#define NULL 0 -#endif - -#ifndef FALSE -#define FALSE 0 /* comes in handy */ -#endif -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FILENAME_MAX -#define FILENAME_MAX 256 -#endif - -#ifndef PREFIX_MAX -#define PREFIX_MAX 10 -#endif - -#ifndef POSTFIX_MAX -#define POSTFIX_MAX 10 -#endif - -#define IDLEN_MAX 4096 - -/* - * ------------------------- - * Error reporting functions - * ------------------------- - */ - -/* - * An error reporting function should look like this. - */ -typedef void (*efunc) (int severity, const char *fmt, ...); - -/* - * These are the error severity codes which get passed as the first - * argument to an efunc. - */ - -#define ERR_DEBUG 0x00000008 /* put out debugging message */ -#define ERR_WARNING 0x00000000 /* warn only: no further action */ -#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ -#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ -#define ERR_PANIC 0x00000003 /* internal error: panic instantly - * and dump core for reference */ -#define ERR_MASK 0x0000000F /* mask off the above codes */ -#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ -#define ERR_USAGE 0x00000020 /* print a usage message */ -#define ERR_PASS1 0x00000040 /* only print this error on pass one */ - -/* - * These codes define specific types of suppressible warning. - */ - -#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ -#define ERR_WARN_SHR 8 /* how far to shift right */ - -#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ -#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ -#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and - * alone on line) */ -#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ -#define ERR_WARN_GNUELF 0x00000500 /* using GNU ELF extensions */ -#define ERR_WARN_MAX 5 /* the highest numbered one */ - -/* - * ----------------------- - * Other function typedefs - * ----------------------- - */ - -/* - * List-file generators should look like this: - */ -typedef struct { - /* - * Called to initialise the listing file generator. Before this - * is called, the other routines will silently do nothing when - * called. The `char *' parameter is the file name to write the - * listing to. - */ - void (*init) (char *, efunc); - - /* - * Called to clear stuff up and close the listing file. - */ - void (*cleanup) (void); - - /* - * Called to output binary data. Parameters are: the offset; - * the data; the data type. Data types are similar to the - * output-format interface, only OUT_ADDRESS will _always_ be - * displayed as if it's relocatable, so ensure that any non- - * relocatable address has been converted to OUT_RAWDATA by - * then. Note that OUT_RAWDATA+0 is a valid data type, and is a - * dummy call used to give the listing generator an offset to - * work with when doing things like uplevel(LIST_TIMES) or - * uplevel(LIST_INCBIN). - */ - void (*output) (long, const void *, unsigned long); - - /* - * Called to send a text line to the listing generator. The - * `int' parameter is LIST_READ or LIST_MACRO depending on - * whether the line came directly from an input file or is the - * result of a multi-line macro expansion. - */ - void (*line) (int, char *); - - /* - * Called to change one of the various levelled mechanisms in - * the listing generator. LIST_INCLUDE and LIST_MACRO can be - * used to increase the nesting level of include files and - * macro expansions; LIST_TIMES and LIST_INCBIN switch on the - * two binary-output-suppression mechanisms for large-scale - * pseudo-instructions. - * - * LIST_MACRO_NOLIST is synonymous with LIST_MACRO except that - * it indicates the beginning of the expansion of a `nolist' - * macro, so anything under that level won't be expanded unless - * it includes another file. - */ - void (*uplevel) (int); - - /* - * Reverse the effects of uplevel. - */ - void (*downlevel) (int); -} ListGen; - -/* - * The expression evaluator must be passed a scanner function; a - * standard scanner is provided as part of nasmlib.c. The - * preprocessor will use a different one. Scanners, and the - * token-value structures they return, look like this. - * - * The return value from the scanner is always a copy of the - * `t_type' field in the structure. - */ -struct tokenval { - int t_type; - yasm_intnum *t_integer, *t_inttwo; - char *t_charptr; -}; -typedef int (*scanner) (void *private_data, struct tokenval *tv); - -/* - * Token types returned by the scanner, in addition to ordinary - * ASCII character values, and zero for end-of-string. - */ -enum { /* token types, other than chars */ - TOKEN_INVALID = -1, /* a placeholder value */ - TOKEN_EOS = 0, /* end of string */ - TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */ - TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */ - TOKEN_ERRNUM, /* numeric constant with error in */ - TOKEN_HERE, TOKEN_BASE, /* $ and $$ */ - TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */ - TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ - TOKEN_SHL, TOKEN_SHR, /* << and >> */ - TOKEN_SDIV, TOKEN_SMOD, /* // and %% */ - TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */ - TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */ - TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */ - TOKEN_FLOAT /* floating-point constant */ -}; - -/* - * The actual expression evaluator function looks like this. When - * called, it expects the first token of its expression to already - * be in `*tv'; if it is not, set tv->t_type to TOKEN_INVALID and - * it will start by calling the scanner. - * - * `critical' is non-zero if the expression may not contain forward - * references. The evaluator will report its own error if this - * occurs; if `critical' is 1, the error will be "symbol not - * defined before use", whereas if `critical' is 2, the error will - * be "symbol undefined". - * - * If `critical' has bit 8 set (in addition to its main value: 0x101 - * and 0x102 correspond to 1 and 2) then an extended expression - * syntax is recognised, in which relational operators such as =, < - * and >= are accepted, as well as low-precedence logical operators - * &&, ^^ and ||. - */ -#define CRITICAL 0x100 -typedef yasm_expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, - int critical, efunc error); - -/* - * Preprocessors ought to look like this: - */ -typedef struct { - /* - * Called at the start of a pass; given a file name, the number - * of the pass, an error reporting function, an evaluator - * function, and a listing generator to talk to. - */ - void (*reset) (FILE *, const char *, int, efunc, evalfunc, ListGen *); - - /* - * Called to fetch a line of preprocessed source. The line - * returned has been malloc'ed, and so should be freed after - * use. - */ - char *(*getline) (void); - - /* - * Called at the end of a pass. - */ - void (*cleanup) (int); -} Preproc; - -/* - * ---------------------------------------------------------------- - * Some lexical properties of the NASM source language, included - * here because they are shared between the parser and preprocessor - * ---------------------------------------------------------------- - */ - -/* - * isidstart matches any character that may start an identifier, and isidchar - * matches any character that may appear at places other than the start of an - * identifier. E.g. a period may only appear at the start of an identifier - * (for local labels), whereas a number may appear anywhere *but* at the - * start. - */ - -#define isidstart(c) ( isalpha(c) || (c)=='_' || (c)=='.' || (c)=='?' \ - || (c)=='@' ) -#define isidchar(c) ( isidstart(c) || isdigit(c) || (c)=='$' || (c)=='#' \ - || (c)=='~' ) - -/* Ditto for numeric constants. */ - -#define isnumstart(c) ( isdigit(c) || (c)=='$' ) -#define isnumchar(c) ( isalnum(c) ) - -/* This returns the numeric value of a given 'digit'. */ - -#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') - -/* - * Data-type flags that get passed to listing-file routines. - */ -enum { - LIST_READ, LIST_MACRO, LIST_MACRO_NOLIST, LIST_INCLUDE, - LIST_INCBIN, LIST_TIMES -}; - -/* - * ----- - * Other - * ----- - */ - -/* - * This is a useful #define which I keep meaning to use more often: - * the number of elements of a statically defined array. - */ - -#define elements(x) ( sizeof(x) / sizeof(*(x)) ) - -extern int tasm_compatible_mode; -extern int tasm_locals; -extern const char *tasm_segment; -const char *tasm_get_segment_register(const char *segment); - -#endif +/* nasm.h main header file for the Netwide Assembler: inter-module interface + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version: 27/iii/95 by Simon Tatham + */ +#ifndef YASM_NASM_H +#define YASM_NASM_H + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef FALSE +#define FALSE 0 /* comes in handy */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FILENAME_MAX +#define FILENAME_MAX 256 +#endif + +#ifndef PREFIX_MAX +#define PREFIX_MAX 10 +#endif + +#ifndef POSTFIX_MAX +#define POSTFIX_MAX 10 +#endif + +#define IDLEN_MAX 4096 + +/* + * ------------------------- + * Error reporting functions + * ------------------------- + */ + +/* + * An error reporting function should look like this. + */ +typedef void (*efunc) (int severity, const char *fmt, ...); + +/* + * These are the error severity codes which get passed as the first + * argument to an efunc. + */ + +#define ERR_DEBUG 0x00000008 /* put out debugging message */ +#define ERR_WARNING 0x00000000 /* warn only: no further action */ +#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ +#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ +#define ERR_PANIC 0x00000003 /* internal error: panic instantly + * and dump core for reference */ +#define ERR_MASK 0x0000000F /* mask off the above codes */ +#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ +#define ERR_USAGE 0x00000020 /* print a usage message */ +#define ERR_PASS1 0x00000040 /* only print this error on pass one */ + +/* + * These codes define specific types of suppressible warning. + */ + +#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ +#define ERR_WARN_SHR 8 /* how far to shift right */ + +#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ +#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ +#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and + * alone on line) */ +#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ +#define ERR_WARN_GNUELF 0x00000500 /* using GNU ELF extensions */ +#define ERR_WARN_MAX 5 /* the highest numbered one */ + +/* + * ----------------------- + * Other function typedefs + * ----------------------- + */ + +/* + * List-file generators should look like this: + */ +typedef struct { + /* + * Called to initialise the listing file generator. Before this + * is called, the other routines will silently do nothing when + * called. The `char *' parameter is the file name to write the + * listing to. + */ + void (*init) (char *, efunc); + + /* + * Called to clear stuff up and close the listing file. + */ + void (*cleanup) (void); + + /* + * Called to output binary data. Parameters are: the offset; + * the data; the data type. Data types are similar to the + * output-format interface, only OUT_ADDRESS will _always_ be + * displayed as if it's relocatable, so ensure that any non- + * relocatable address has been converted to OUT_RAWDATA by + * then. Note that OUT_RAWDATA+0 is a valid data type, and is a + * dummy call used to give the listing generator an offset to + * work with when doing things like uplevel(LIST_TIMES) or + * uplevel(LIST_INCBIN). + */ + void (*output) (long, const void *, unsigned long); + + /* + * Called to send a text line to the listing generator. The + * `int' parameter is LIST_READ or LIST_MACRO depending on + * whether the line came directly from an input file or is the + * result of a multi-line macro expansion. + */ + void (*line) (int, char *); + + /* + * Called to change one of the various levelled mechanisms in + * the listing generator. LIST_INCLUDE and LIST_MACRO can be + * used to increase the nesting level of include files and + * macro expansions; LIST_TIMES and LIST_INCBIN switch on the + * two binary-output-suppression mechanisms for large-scale + * pseudo-instructions. + * + * LIST_MACRO_NOLIST is synonymous with LIST_MACRO except that + * it indicates the beginning of the expansion of a `nolist' + * macro, so anything under that level won't be expanded unless + * it includes another file. + */ + void (*uplevel) (int); + + /* + * Reverse the effects of uplevel. + */ + void (*downlevel) (int); +} ListGen; + +/* + * The expression evaluator must be passed a scanner function; a + * standard scanner is provided as part of nasmlib.c. The + * preprocessor will use a different one. Scanners, and the + * token-value structures they return, look like this. + * + * The return value from the scanner is always a copy of the + * `t_type' field in the structure. + */ +struct tokenval { + int t_type; + yasm_intnum *t_integer, *t_inttwo; + char *t_charptr; +}; +typedef int (*scanner) (void *private_data, struct tokenval *tv); + +/* + * Token types returned by the scanner, in addition to ordinary + * ASCII character values, and zero for end-of-string. + */ +enum { /* token types, other than chars */ + TOKEN_INVALID = -1, /* a placeholder value */ + TOKEN_EOS = 0, /* end of string */ + TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */ + TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */ + TOKEN_ERRNUM, /* numeric constant with error in */ + TOKEN_HERE, TOKEN_BASE, /* $ and $$ */ + TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */ + TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ + TOKEN_SHL, TOKEN_SHR, /* << and >> */ + TOKEN_SDIV, TOKEN_SMOD, /* // and %% */ + TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */ + TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */ + TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */ + TOKEN_FLOAT /* floating-point constant */ +}; + +/* + * The actual expression evaluator function looks like this. When + * called, it expects the first token of its expression to already + * be in `*tv'; if it is not, set tv->t_type to TOKEN_INVALID and + * it will start by calling the scanner. + * + * `critical' is non-zero if the expression may not contain forward + * references. The evaluator will report its own error if this + * occurs; if `critical' is 1, the error will be "symbol not + * defined before use", whereas if `critical' is 2, the error will + * be "symbol undefined". + * + * If `critical' has bit 8 set (in addition to its main value: 0x101 + * and 0x102 correspond to 1 and 2) then an extended expression + * syntax is recognised, in which relational operators such as =, < + * and >= are accepted, as well as low-precedence logical operators + * &&, ^^ and ||. + */ +#define CRITICAL 0x100 +typedef yasm_expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, + int critical, efunc error); + +/* + * Preprocessors ought to look like this: + */ +typedef struct { + /* + * Called at the start of a pass; given a file name, the number + * of the pass, an error reporting function, an evaluator + * function, and a listing generator to talk to. + */ + void (*reset) (FILE *, const char *, int, efunc, evalfunc, ListGen *); + + /* + * Called to fetch a line of preprocessed source. The line + * returned has been malloc'ed, and so should be freed after + * use. + */ + char *(*getline) (void); + + /* + * Called at the end of a pass. + */ + void (*cleanup) (int); +} Preproc; + +/* + * ---------------------------------------------------------------- + * Some lexical properties of the NASM source language, included + * here because they are shared between the parser and preprocessor + * ---------------------------------------------------------------- + */ + +/* + * isidstart matches any character that may start an identifier, and isidchar + * matches any character that may appear at places other than the start of an + * identifier. E.g. a period may only appear at the start of an identifier + * (for local labels), whereas a number may appear anywhere *but* at the + * start. + */ + +#define isidstart(c) ( isalpha(c) || (c)=='_' || (c)=='.' || (c)=='?' \ + || (c)=='@' ) +#define isidchar(c) ( isidstart(c) || isdigit(c) || (c)=='$' || (c)=='#' \ + || (c)=='~' ) + +/* Ditto for numeric constants. */ + +#define isnumstart(c) ( isdigit(c) || (c)=='$' ) +#define isnumchar(c) ( isalnum(c) ) + +/* This returns the numeric value of a given 'digit'. */ + +#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') + +/* + * Data-type flags that get passed to listing-file routines. + */ +enum { + LIST_READ, LIST_MACRO, LIST_MACRO_NOLIST, LIST_INCLUDE, + LIST_INCBIN, LIST_TIMES +}; + +/* + * ----- + * Other + * ----- + */ + +/* + * This is a useful #define which I keep meaning to use more often: + * the number of elements of a statically defined array. + */ + +#define elements(x) ( sizeof(x) / sizeof(*(x)) ) + +extern int tasm_compatible_mode; +extern int tasm_locals; +extern const char *tasm_segment; +const char *tasm_get_segment_register(const char *segment); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.c b/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.c index de1f64f9c4..2ced911780 100644 --- a/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.c +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.c @@ -1,201 +1,201 @@ -/* nasmlib.c library routines for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ -#include <util.h> -#include <libyasm/coretype.h> -#include <libyasm/intnum.h> -#include <ctype.h> - -#include "nasm.h" -#include "nasmlib.h" -/*#include "insns.h"*/ /* For MAX_KEYWORD */ - -#define lib_isnumchar(c) ( isalnum(c) || (c) == '$') -#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') - -yasm_intnum *nasm_readnum (char *str, int *error) -{ - char *r = str, *q, *p; - long radix; - yasm_intnum *intn; - char save; - int digit; - int sign = 0; - - *error = FALSE; - - while (isspace(*r)) r++; /* find start of number */ - - /* - * If the number came from make_tok_num (as a result of an %assign), it - * might have a '-' built into it (rather than in a preceeding token). - */ - if (*r == '-') - { - r++; - sign = 1; - } - - q = r; - - while (lib_isnumchar(*q)) q++; /* find end of number */ - - /* - * If it begins 0x, 0X or $, or ends in H, it's in hex. if it - * ends in Q, it's octal. if it ends in B, it's binary. - * Otherwise, it's ordinary decimal. - */ - if (*r=='0' && (r[1]=='x' || r[1]=='X')) - radix = 16, r += 2; - else if (*r=='$') - radix = 16, r++; - else if (q[-1]=='H' || q[-1]=='h') - radix = 16 , q--; - else if (q[-1]=='Q' || q[-1]=='q' || q[-1]=='O' || q[-1]=='o') - radix = 8 , q--; - else if (q[-1]=='B' || q[-1]=='b') - radix = 2 , q--; - else - radix = 10; - - /* - * If this number has been found for us by something other than - * the ordinary scanners, then it might be malformed by having - * nothing between the prefix and the suffix. Check this case - * now. - */ - if (r >= q) { - *error = TRUE; - return yasm_intnum_create_uint(0); - } - - /* Check for valid number of that radix */ - p = r; - while (*p && p < q) { - if (*p<'0' || (*p>'9' && *p<'A') || (digit = numvalue(*p)) >= radix) - { - *error = TRUE; - return yasm_intnum_create_uint(0); - } - p++; - } - - /* Use intnum to actually do the conversion */ - save = *q; - *q = '\0'; - switch (radix) { - case 2: - intn = yasm_intnum_create_bin(r); - break; - case 8: - intn = yasm_intnum_create_oct(r); - break; - case 10: - intn = yasm_intnum_create_dec(r); - break; - case 16: - intn = yasm_intnum_create_hex(r); - break; - default: - *error = TRUE; - intn = yasm_intnum_create_uint(0); - break; - } - *q = save; - - if (sign) - yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); - return intn; -} - -yasm_intnum *nasm_readstrnum (char *str, size_t length, int *warn) -{ - char save; - yasm_intnum *intn; - - *warn = FALSE; - - save = str[length]; - str[length] = '\0'; - intn = yasm_intnum_create_charconst_nasm(str); - str[length] = save; - - return intn; -} - -static char *file_name = NULL; -static long line_number = 0; - -char *nasm_src_set_fname(char *newname) -{ - char *oldname = file_name; - file_name = newname; - return oldname; -} - -char *nasm_src_get_fname(void) -{ - return file_name; -} - -long nasm_src_set_linnum(long newline) -{ - long oldline = line_number; - line_number = newline; - return oldline; -} - -long nasm_src_get_linnum(void) -{ - return line_number; -} - -int nasm_src_get(long *xline, char **xname) -{ - if (!file_name || !*xname || strcmp(*xname, file_name)) - { - nasm_free(*xname); - *xname = file_name ? nasm_strdup(file_name) : NULL; - *xline = line_number; - return -2; - } - if (*xline != line_number) - { - long tmp = line_number - *xline; - *xline = line_number; - return tmp; - } - return 0; -} - -void nasm_quote(char **str) -{ - size_t ln=strlen(*str); - char q=(*str)[0]; - char *p; - if (ln>1 && (*str)[ln-1]==q && (q=='"' || q=='\'')) - return; - q = '"'; - if (strchr(*str,q)) - q = '\''; - p = nasm_malloc(ln+3); - strcpy(p+1, *str); - nasm_free(*str); - p[ln+1] = p[0] = q; - p[ln+2] = 0; - *str = p; -} - -char *nasm_strcat(const char *one, const char *two) -{ - char *rslt; - size_t l1=strlen(one); - rslt = nasm_malloc(l1+strlen(two)+1); - strcpy(rslt, one); - strcpy(rslt+l1, two); - return rslt; -} +/* nasmlib.c library routines for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ +#include <util.h> +#include <libyasm/coretype.h> +#include <libyasm/intnum.h> +#include <ctype.h> + +#include "nasm.h" +#include "nasmlib.h" +/*#include "insns.h"*/ /* For MAX_KEYWORD */ + +#define lib_isnumchar(c) ( isalnum(c) || (c) == '$') +#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') + +yasm_intnum *nasm_readnum (char *str, int *error) +{ + char *r = str, *q, *p; + long radix; + yasm_intnum *intn; + char save; + int digit; + int sign = 0; + + *error = FALSE; + + while (isspace(*r)) r++; /* find start of number */ + + /* + * If the number came from make_tok_num (as a result of an %assign), it + * might have a '-' built into it (rather than in a preceeding token). + */ + if (*r == '-') + { + r++; + sign = 1; + } + + q = r; + + while (lib_isnumchar(*q)) q++; /* find end of number */ + + /* + * If it begins 0x, 0X or $, or ends in H, it's in hex. if it + * ends in Q, it's octal. if it ends in B, it's binary. + * Otherwise, it's ordinary decimal. + */ + if (*r=='0' && (r[1]=='x' || r[1]=='X')) + radix = 16, r += 2; + else if (*r=='$') + radix = 16, r++; + else if (q[-1]=='H' || q[-1]=='h') + radix = 16 , q--; + else if (q[-1]=='Q' || q[-1]=='q' || q[-1]=='O' || q[-1]=='o') + radix = 8 , q--; + else if (q[-1]=='B' || q[-1]=='b') + radix = 2 , q--; + else + radix = 10; + + /* + * If this number has been found for us by something other than + * the ordinary scanners, then it might be malformed by having + * nothing between the prefix and the suffix. Check this case + * now. + */ + if (r >= q) { + *error = TRUE; + return yasm_intnum_create_uint(0); + } + + /* Check for valid number of that radix */ + p = r; + while (*p && p < q) { + if (*p<'0' || (*p>'9' && *p<'A') || (digit = numvalue(*p)) >= radix) + { + *error = TRUE; + return yasm_intnum_create_uint(0); + } + p++; + } + + /* Use intnum to actually do the conversion */ + save = *q; + *q = '\0'; + switch (radix) { + case 2: + intn = yasm_intnum_create_bin(r); + break; + case 8: + intn = yasm_intnum_create_oct(r); + break; + case 10: + intn = yasm_intnum_create_dec(r); + break; + case 16: + intn = yasm_intnum_create_hex(r); + break; + default: + *error = TRUE; + intn = yasm_intnum_create_uint(0); + break; + } + *q = save; + + if (sign) + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + return intn; +} + +yasm_intnum *nasm_readstrnum (char *str, size_t length, int *warn) +{ + char save; + yasm_intnum *intn; + + *warn = FALSE; + + save = str[length]; + str[length] = '\0'; + intn = yasm_intnum_create_charconst_nasm(str); + str[length] = save; + + return intn; +} + +static char *file_name = NULL; +static long line_number = 0; + +char *nasm_src_set_fname(char *newname) +{ + char *oldname = file_name; + file_name = newname; + return oldname; +} + +char *nasm_src_get_fname(void) +{ + return file_name; +} + +long nasm_src_set_linnum(long newline) +{ + long oldline = line_number; + line_number = newline; + return oldline; +} + +long nasm_src_get_linnum(void) +{ + return line_number; +} + +int nasm_src_get(long *xline, char **xname) +{ + if (!file_name || !*xname || strcmp(*xname, file_name)) + { + nasm_free(*xname); + *xname = file_name ? nasm_strdup(file_name) : NULL; + *xline = line_number; + return -2; + } + if (*xline != line_number) + { + long tmp = line_number - *xline; + *xline = line_number; + return tmp; + } + return 0; +} + +void nasm_quote(char **str) +{ + size_t ln=strlen(*str); + char q=(*str)[0]; + char *p; + if (ln>1 && (*str)[ln-1]==q && (q=='"' || q=='\'')) + return; + q = '"'; + if (strchr(*str,q)) + q = '\''; + p = nasm_malloc(ln+3); + strcpy(p+1, *str); + nasm_free(*str); + p[ln+1] = p[0] = q; + p[ln+2] = 0; + *str = p; +} + +char *nasm_strcat(const char *one, const char *two) +{ + char *rslt; + size_t l1=strlen(one); + rslt = nasm_malloc(l1+strlen(two)+1); + strcpy(rslt, one); + strcpy(rslt+l1, two); + return rslt; +} diff --git a/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.h b/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.h index 735a54e159..c26c0668b5 100644 --- a/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.h +++ b/contrib/tools/yasm/modules/preprocs/nasm/nasmlib.h @@ -1,60 +1,60 @@ -/* nasmlib.h header file for nasmlib.c - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#ifndef YASM_NASMLIB_H -#define YASM_NASMLIB_H - -/* - * Wrappers around malloc, realloc and free. nasm_malloc will - * fatal-error and die rather than return NULL; nasm_realloc will - * do likewise, and will also guarantee to work right on being - * passed a NULL pointer; nasm_free will do nothing if it is passed - * a NULL pointer. - */ -#define nasm_malloc yasm_xmalloc -#define nasm_realloc yasm_xrealloc -#ifdef WITH_DMALLOC -#define nasm_free(p) do { if (p) yasm_xfree(p); } while(0) -#else -#define nasm_free(p) yasm_xfree(p) -#endif -#define nasm_strdup yasm__xstrdup -#define nasm_strndup yasm__xstrndup -#define nasm_stricmp yasm__strcasecmp -#define nasm_strnicmp yasm__strncasecmp - -/* - * Convert a string into a number, using NASM number rules. Sets - * `*error' to TRUE if an error occurs, and FALSE otherwise. - */ -yasm_intnum *nasm_readnum(char *str, int *error); - -/* - * Convert a character constant into a number. Sets - * `*warn' to TRUE if an overflow occurs, and FALSE otherwise. - * str points to and length covers the middle of the string, - * without the quotes. - */ -yasm_intnum *nasm_readstrnum(char *str, size_t length, int *warn); - -char *nasm_src_set_fname(char *newname); -char *nasm_src_get_fname(void); -long nasm_src_set_linnum(long newline); -long nasm_src_get_linnum(void); -/* - * src_get may be used if you simply want to know the source file and line. - * It is also used if you maintain private status about the source location - * It return 0 if the information was the same as the last time you - * checked, -1 if the name changed and (new-old) if just the line changed. - */ -int nasm_src_get(long *xline, char **xname); - -void nasm_quote(char **str); -char *nasm_strcat(const char *one, const char *two); - -#endif +/* nasmlib.h header file for nasmlib.c + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef YASM_NASMLIB_H +#define YASM_NASMLIB_H + +/* + * Wrappers around malloc, realloc and free. nasm_malloc will + * fatal-error and die rather than return NULL; nasm_realloc will + * do likewise, and will also guarantee to work right on being + * passed a NULL pointer; nasm_free will do nothing if it is passed + * a NULL pointer. + */ +#define nasm_malloc yasm_xmalloc +#define nasm_realloc yasm_xrealloc +#ifdef WITH_DMALLOC +#define nasm_free(p) do { if (p) yasm_xfree(p); } while(0) +#else +#define nasm_free(p) yasm_xfree(p) +#endif +#define nasm_strdup yasm__xstrdup +#define nasm_strndup yasm__xstrndup +#define nasm_stricmp yasm__strcasecmp +#define nasm_strnicmp yasm__strncasecmp + +/* + * Convert a string into a number, using NASM number rules. Sets + * `*error' to TRUE if an error occurs, and FALSE otherwise. + */ +yasm_intnum *nasm_readnum(char *str, int *error); + +/* + * Convert a character constant into a number. Sets + * `*warn' to TRUE if an overflow occurs, and FALSE otherwise. + * str points to and length covers the middle of the string, + * without the quotes. + */ +yasm_intnum *nasm_readstrnum(char *str, size_t length, int *warn); + +char *nasm_src_set_fname(char *newname); +char *nasm_src_get_fname(void); +long nasm_src_set_linnum(long newline); +long nasm_src_get_linnum(void); +/* + * src_get may be used if you simply want to know the source file and line. + * It is also used if you maintain private status about the source location + * It return 0 if the information was the same as the last time you + * checked, -1 if the name changed and (new-old) if just the line changed. + */ +int nasm_src_get(long *xline, char **xname); + +void nasm_quote(char **str); +char *nasm_strcat(const char *one, const char *two); + +#endif diff --git a/contrib/tools/yasm/modules/preprocs/raw/raw-preproc.c b/contrib/tools/yasm/modules/preprocs/raw/raw-preproc.c index f20fbc0f6a..9745b242fe 100644 --- a/contrib/tools/yasm/modules/preprocs/raw/raw-preproc.c +++ b/contrib/tools/yasm/modules/preprocs/raw/raw-preproc.c @@ -1,169 +1,169 @@ -/* - * Raw preprocessor (preforms NO preprocessing) - * - * Copyright (C) 2001-2007 Peter Johnson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. - */ -#include <util.h> - -#include <libyasm.h> - - -#define BSIZE 512 - -typedef struct yasm_preproc_raw { - yasm_preproc_base preproc; /* base structure */ - - FILE *in; - yasm_linemap *cur_lm; - yasm_errwarns *errwarns; -} yasm_preproc_raw; - -yasm_preproc_module yasm_raw_LTX_preproc; - -static yasm_preproc * -raw_preproc_create(const char *in_filename, yasm_symtab *symtab, - yasm_linemap *lm, yasm_errwarns *errwarns) -{ - FILE *f; - yasm_preproc_raw *preproc_raw = yasm_xmalloc(sizeof(yasm_preproc_raw)); - - if (strcmp(in_filename, "-") != 0) { - f = fopen(in_filename, "r"); - if (!f) +/* + * Raw preprocessor (preforms NO preprocessing) + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. + */ +#include <util.h> + +#include <libyasm.h> + + +#define BSIZE 512 + +typedef struct yasm_preproc_raw { + yasm_preproc_base preproc; /* base structure */ + + FILE *in; + yasm_linemap *cur_lm; + yasm_errwarns *errwarns; +} yasm_preproc_raw; + +yasm_preproc_module yasm_raw_LTX_preproc; + +static yasm_preproc * +raw_preproc_create(const char *in_filename, yasm_symtab *symtab, + yasm_linemap *lm, yasm_errwarns *errwarns) +{ + FILE *f; + yasm_preproc_raw *preproc_raw = yasm_xmalloc(sizeof(yasm_preproc_raw)); + + if (strcmp(in_filename, "-") != 0) { + f = fopen(in_filename, "r"); + if (!f) yasm__fatal_missing_input_file( N_("Could not open input file"), in_filename ); - } - else - f = stdin; - - preproc_raw->preproc.module = &yasm_raw_LTX_preproc; - preproc_raw->in = f; - preproc_raw->cur_lm = lm; - preproc_raw->errwarns = errwarns; - - return (yasm_preproc *)preproc_raw; -} - -static void -raw_preproc_destroy(yasm_preproc *preproc) -{ - yasm_xfree(preproc); -} - -static char * -raw_preproc_get_line(yasm_preproc *preproc) -{ - yasm_preproc_raw *preproc_raw = (yasm_preproc_raw *)preproc; - int bufsize = BSIZE; - char *buf = yasm_xmalloc((size_t)bufsize); - char *p; - - /* Loop to ensure entire line is read (don't want to limit line length). */ - p = buf; - for (;;) { - if (!fgets(p, bufsize-(p-buf), preproc_raw->in)) { - if (ferror(preproc_raw->in)) { - yasm_error_set(YASM_ERROR_IO, - N_("error when reading from file")); - yasm_errwarn_propagate(preproc_raw->errwarns, - yasm_linemap_get_current(preproc_raw->cur_lm)); - } - break; - } - p += strlen(p); - if (p > buf && p[-1] == '\n') - break; - if ((p-buf)+1 >= bufsize) { - /* Increase size of buffer */ - char *oldbuf = buf; - bufsize *= 2; - buf = yasm_xrealloc(buf, (size_t)bufsize); - p = buf + (p-oldbuf); - } - } - - if (p == buf) { - /* No data; must be at EOF */ - yasm_xfree(buf); - return NULL; - } - - /* Strip the line ending */ - buf[strcspn(buf, "\r\n")] = '\0'; - - return buf; -} - -static size_t -raw_preproc_get_included_file(yasm_preproc *preproc, char *buf, - size_t max_size) -{ - /* no included files */ - return 0; -} - -static void -raw_preproc_add_include_file(yasm_preproc *preproc, const char *filename) -{ - /* no pre-include files */ -} - -static void -raw_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) -{ - /* no pre-defining macros */ -} - -static void -raw_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) -{ - /* no undefining macros */ -} - -static void -raw_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) -{ - /* no builtin defines */ -} - -static void -raw_preproc_add_standard(yasm_preproc *preproc, const char **macros) -{ - /* no standard macros */ -} - - -/* Define preproc structure -- see preproc.h for details */ -yasm_preproc_module yasm_raw_LTX_preproc = { - "Disable preprocessing", - "raw", - raw_preproc_create, - raw_preproc_destroy, - raw_preproc_get_line, - raw_preproc_get_included_file, - raw_preproc_add_include_file, - raw_preproc_predefine_macro, - raw_preproc_undefine_macro, - raw_preproc_define_builtin, - raw_preproc_add_standard -}; + } + else + f = stdin; + + preproc_raw->preproc.module = &yasm_raw_LTX_preproc; + preproc_raw->in = f; + preproc_raw->cur_lm = lm; + preproc_raw->errwarns = errwarns; + + return (yasm_preproc *)preproc_raw; +} + +static void +raw_preproc_destroy(yasm_preproc *preproc) +{ + yasm_xfree(preproc); +} + +static char * +raw_preproc_get_line(yasm_preproc *preproc) +{ + yasm_preproc_raw *preproc_raw = (yasm_preproc_raw *)preproc; + int bufsize = BSIZE; + char *buf = yasm_xmalloc((size_t)bufsize); + char *p; + + /* Loop to ensure entire line is read (don't want to limit line length). */ + p = buf; + for (;;) { + if (!fgets(p, bufsize-(p-buf), preproc_raw->in)) { + if (ferror(preproc_raw->in)) { + yasm_error_set(YASM_ERROR_IO, + N_("error when reading from file")); + yasm_errwarn_propagate(preproc_raw->errwarns, + yasm_linemap_get_current(preproc_raw->cur_lm)); + } + break; + } + p += strlen(p); + if (p > buf && p[-1] == '\n') + break; + if ((p-buf)+1 >= bufsize) { + /* Increase size of buffer */ + char *oldbuf = buf; + bufsize *= 2; + buf = yasm_xrealloc(buf, (size_t)bufsize); + p = buf + (p-oldbuf); + } + } + + if (p == buf) { + /* No data; must be at EOF */ + yasm_xfree(buf); + return NULL; + } + + /* Strip the line ending */ + buf[strcspn(buf, "\r\n")] = '\0'; + + return buf; +} + +static size_t +raw_preproc_get_included_file(yasm_preproc *preproc, char *buf, + size_t max_size) +{ + /* no included files */ + return 0; +} + +static void +raw_preproc_add_include_file(yasm_preproc *preproc, const char *filename) +{ + /* no pre-include files */ +} + +static void +raw_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval) +{ + /* no pre-defining macros */ +} + +static void +raw_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname) +{ + /* no undefining macros */ +} + +static void +raw_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval) +{ + /* no builtin defines */ +} + +static void +raw_preproc_add_standard(yasm_preproc *preproc, const char **macros) +{ + /* no standard macros */ +} + + +/* Define preproc structure -- see preproc.h for details */ +yasm_preproc_module yasm_raw_LTX_preproc = { + "Disable preprocessing", + "raw", + raw_preproc_create, + raw_preproc_destroy, + raw_preproc_get_line, + raw_preproc_get_included_file, + raw_preproc_add_include_file, + raw_preproc_predefine_macro, + raw_preproc_undefine_macro, + raw_preproc_define_builtin, + raw_preproc_add_standard +}; |