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/gas/gas-preproc.c | |
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/gas/gas-preproc.c')
-rw-r--r-- | contrib/tools/yasm/modules/preprocs/gas/gas-preproc.c | 2814 |
1 files changed, 1407 insertions, 1407 deletions
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 +}; |