From 493c5b8861fc7a9a97b9d07833b6dee91f2987a2 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Wed, 23 Dec 2009 06:45:17 +0000 Subject: [PATCH] Add initial gas preprocessor, contributed by Alexei Svitkine. Support for include directive amongst other major key pieces. Does not currently support macros. Fixes #79. Contributed by: Alexei Svitkine svn path=/trunk/yasm/; revision=2243 --- COPYING | 1 + modules/parsers/gas/gas-parser.c | 3 +- modules/preprocs/CMakeLists.txt | 1 + modules/preprocs/Makefile.inc | 2 + modules/preprocs/gas/CMakeLists.txt | 4 + modules/preprocs/gas/Makefile.inc | 10 + modules/preprocs/gas/gas-eval.c | 443 ++++++++++++ modules/preprocs/gas/gas-eval.h | 120 +++ modules/preprocs/gas/gas-preproc.c | 921 ++++++++++++++++++++++++ modules/preprocs/gas/tests/Makefile.inc | 7 + po/POTFILES.in | 2 + 11 files changed, 1513 insertions(+), 1 deletion(-) create mode 100644 modules/preprocs/gas/CMakeLists.txt create mode 100644 modules/preprocs/gas/Makefile.inc create mode 100644 modules/preprocs/gas/gas-eval.c create mode 100644 modules/preprocs/gas/gas-eval.h create mode 100644 modules/preprocs/gas/gas-preproc.c create mode 100644 modules/preprocs/gas/tests/Makefile.inc diff --git a/COPYING b/COPYING index 6b8118d3..b28d40c9 100644 --- a/COPYING +++ b/COPYING @@ -10,6 +10,7 @@ Yasm developers and/or contributors include: Stephen Polkowski (x86 instruction patches) Henryk Richter (Mach-O object format) Ben Skeggs (patches, bug reports) + Alexei Svitkine (GAS preprocessor) Samuel Thibault (TASM parser and frontend) ----------------------------------- diff --git a/modules/parsers/gas/gas-parser.c b/modules/parsers/gas/gas-parser.c index 98231471..64a10c20 100644 --- a/modules/parsers/gas/gas-parser.c +++ b/modules/parsers/gas/gas-parser.c @@ -114,6 +114,7 @@ gas_parser_do_parse(yasm_object *object, yasm_preproc *pp, /* Define valid preprocessors to use with this parser */ static const char *gas_parser_preproc_keywords[] = { + "gas", "raw", "cpp", "nasm", @@ -133,7 +134,7 @@ yasm_parser_module yasm_gnu_LTX_parser = { "GNU AS (GAS)-compatible parser", "gnu", gas_parser_preproc_keywords, - "raw", + "gas", NULL, /* No standard macros */ gas_parser_do_parse }; diff --git a/modules/preprocs/CMakeLists.txt b/modules/preprocs/CMakeLists.txt index dccecbe5..59640272 100644 --- a/modules/preprocs/CMakeLists.txt +++ b/modules/preprocs/CMakeLists.txt @@ -1,3 +1,4 @@ INCLUDE(preprocs/nasm/CMakeLists.txt) INCLUDE(preprocs/raw/CMakeLists.txt) INCLUDE(preprocs/cpp/CMakeLists.txt) +INCLUDE(preprocs/gas/CMakeLists.txt) diff --git a/modules/preprocs/Makefile.inc b/modules/preprocs/Makefile.inc index aee9accd..fedcf75b 100644 --- a/modules/preprocs/Makefile.inc +++ b/modules/preprocs/Makefile.inc @@ -4,8 +4,10 @@ EXTRA_DIST += modules/preprocs/tasm/Makefile.inc EXTRA_DIST += modules/preprocs/nasm/Makefile.inc EXTRA_DIST += modules/preprocs/raw/Makefile.inc EXTRA_DIST += modules/preprocs/cpp/Makefile.inc +EXTRA_DIST += modules/preprocs/gas/Makefile.inc include modules/preprocs/tasm/Makefile.inc include modules/preprocs/nasm/Makefile.inc include modules/preprocs/raw/Makefile.inc include modules/preprocs/cpp/Makefile.inc +include modules/preprocs/gas/Makefile.inc diff --git a/modules/preprocs/gas/CMakeLists.txt b/modules/preprocs/gas/CMakeLists.txt new file mode 100644 index 00000000..e8d09148 --- /dev/null +++ b/modules/preprocs/gas/CMakeLists.txt @@ -0,0 +1,4 @@ +YASM_ADD_MODULE(preproc_gas + preprocs/gas/gas-preproc.c + preprocs/gas/gas-eval.c + ) diff --git a/modules/preprocs/gas/Makefile.inc b/modules/preprocs/gas/Makefile.inc new file mode 100644 index 00000000..a53077b6 --- /dev/null +++ b/modules/preprocs/gas/Makefile.inc @@ -0,0 +1,10 @@ +# $Id$ + +libyasm_a_SOURCES += modules/preprocs/gas/gas-preproc.c +libyasm_a_SOURCES += modules/preprocs/gas/gas-eval.c + +YASM_MODULES += preproc_gas + +EXTRA_DIST += modules/preprocs/gas/tests/Makefile.inc + +include modules/preprocs/gas/tests/Makefile.inc diff --git a/modules/preprocs/gas/gas-eval.c b/modules/preprocs/gas/gas-eval.c new file mode 100644 index 00000000..db70d7fd --- /dev/null +++ b/modules/preprocs/gas/gas-eval.c @@ -0,0 +1,443 @@ +/* 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 +#include +#include +#include +#include +#include +#include + +#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; + } + 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 (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/modules/preprocs/gas/gas-eval.h b/modules/preprocs/gas/gas-eval.h new file mode 100644 index 00000000..18dcc517 --- /dev/null +++ b/modules/preprocs/gas/gas-eval.h @@ -0,0 +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 diff --git a/modules/preprocs/gas/gas-preproc.c b/modules/preprocs/gas/gas-preproc.c new file mode 100644 index 00000000..729aeaec --- /dev/null +++ b/modules/preprocs/gas/gas-preproc.c @@ -0,0 +1,921 @@ +/* + * 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 +#include +/*@unused@*/ RCSID("$Id$"); + +#include +#include "gas-eval.h" + +#define FALSE 0 +#define TRUE 1 +#define BSIZE 512 + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +typedef struct buffered_line { + char *line; + 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 yasm_preproc_gas { + yasm_preproc_base preproc; /* base structure */ + + FILE *in; + char *in_filename; + + yasm_symtab *defines; + + int depth; + int skip_depth; + + const char *expr_string; + char *expr_symbol; + int expr_string_cursor; + + SLIST_HEAD(buffered_lines_head, buffered_line) buffered_lines; + SLIST_HEAD(included_files_head, included_file) included_files; + + yasm_linemap *cur_lm; + yasm_errwarns *errwarns; + int fatal_error; +} yasm_preproc_gas; + +yasm_preproc_module yasm_gas_LTX_preproc; + +/* 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, yasm_linemap_get_current(pp->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 char *read_line(yasm_preproc_gas *pp) +{ + char *buf; + + 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); + buf = bline->line; + yasm_xfree(bline); + if (!SLIST_EMPTY(&pp->included_files)) { + SLIST_FIRST(&pp->included_files)->lines_remaining--; + } + return buf; + } + + buf = read_line_from_file(pp, pp->in); + + return buf; +} + +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, yasm_linemap_get_current(pp->cur_lm)); + } + 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 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 value = 0; + do { + value = value*10 + (c - '0'); + next_char(pp); + c = get_char(pp); + } while (isdigit(c)); + 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; + + va_start(args, fmt); + yasm_error_set_va(YASM_ERROR_SYNTAX, N_(fmt), args); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + 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; + + if (!*arg1) { + return 0; + } + + tv.t_type = TOKEN_INVALID; + + pp->expr_symbol = NULL; + pp->expr_string = arg1; + pp->expr_string_cursor = 0; + 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); + + if (pp->expr_symbol) { + yasm_xfree(pp->expr_symbol); + pp->expr_symbol = NULL; + } + + 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->skip_depth) { + pp->skip_depth--; + } else if (pp->depth) { + pp->depth--; + } else { + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".endif\" without \".if\"")); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + return 0; + } + return 1; +} + +static int handle_else(yasm_preproc_gas *pp, int is_elseif) +{ + if (pp->skip_depth == 1) { + pp->skip_depth = 0; + pp->depth++; + } else if (!pp->depth) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("\".%s\" without \".if\""), is_elseif ? "elseif" : "else"); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + return 0; + } else if (!pp->skip_depth) { + 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, yasm_linemap_get_current(pp->cur_lm)); + 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, yasm_linemap_get_current(pp->cur_lm)); + 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, yasm_linemap_get_current(pp->cur_lm)); + 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, yasm_linemap_get_current(pp->cur_lm)); + 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, yasm_linemap_get_current(pp->cur_lm)); + 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, yasm_linemap_get_current(pp->cur_lm)); + 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; + 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 eval_set(yasm_preproc_gas *pp, int allow_redefine, const char *name, const char *value) +{ + if (!pp->skip_depth) { + yasm_intnum *num = yasm_intnum_create_int(eval_expr(pp, value)); + yasm_expr *expr = yasm_expr_create_ident(yasm_expr_int(num), 0); + yasm_symrec *rec = yasm_symtab_get(pp->defines, name); + if (rec) { + if (!allow_redefine) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("symbol \"%s\" is already defined"), name); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + return 0; + } + /* TODO */ + yasm_error_set(YASM_ERROR_SYNTAX, N_("redefining symbols not yet implimented"), name); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + return 0; + } else { + yasm_symtab_define_equ(pp->defines, name, expr, 0); + } + } + return 1; +} + +static int eval_rept(yasm_preproc_gas *pp, int unused, const char *arg1) +{ + long i, n = eval_expr(pp, arg1); + long num_lines = 0; + char *line = read_line(pp); + buffered_line *prev_bline = NULL; + SLIST_HEAD(buffered_lines_head, buffered_line) lines; + + SLIST_INIT(&lines); + + while (line) { + skip_whitespace2(&line); + if (!strncmp(line, ".endr", 4)) { + 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); + 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; + 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_error_set(YASM_ERROR_SYNTAX, N_("unexpected EOF in \".rept\" block")); + yasm_errwarn_propagate(pp->errwarns, yasm_linemap_get_current(pp->cur_lm)); + 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, yasm_linemap_get_current(pp->cur_lm)); + 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 int process_line(yasm_preproc_gas *pp, const char *line) +{ + size_t i; + 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}, + {"rept", 1, FN(eval_rept), 0}, + {"endr", 1, FN(eval_endr), 0}, + }; + + 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 && !strncmp("if", directives[i].name, 2)) { + pp->skip_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, yasm_linemap_get_current(pp->cur_lm)); + 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; + } + } + } + + return (pp->skip_depth == 0); +} + +/* 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(N_("Could not open input file")); + } + } 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(); + yasm_symtab_set_case_sensitive(pp->defines, 1); + pp->depth = 0; + pp->skip_depth = 0; + SLIST_INIT(&pp->buffered_lines); + SLIST_INIT(&pp->included_files); + pp->cur_lm = lm; + pp->errwarns = errwarns; + pp->fatal_error = 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->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); + } + 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; + + do { + if (line != NULL) { + yasm_xfree(line); + } + if (pp->fatal_error) { + return NULL; + } + line = read_line(pp); + if (line == NULL) { + return NULL; + } + done = process_line(pp, line); + } while (!done); + + 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 = { + "GAS 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/modules/preprocs/gas/tests/Makefile.inc b/modules/preprocs/gas/tests/Makefile.inc new file mode 100644 index 00000000..c2a07c2e --- /dev/null +++ b/modules/preprocs/gas/tests/Makefile.inc @@ -0,0 +1,7 @@ +# $Id$ + +#TESTS += modules/preprocs/gas/tests/rawpp_test.sh + +#EXTRA_DIST += modules/preprocs/gas/tests/rawpp_test.sh +#EXTRA_DIST += modules/preprocs/gas/tests/longline.asm +#EXTRA_DIST += modules/preprocs/gas/tests/longline.hex diff --git a/po/POTFILES.in b/po/POTFILES.in index 4cb66b12..bdea54fd 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -55,6 +55,8 @@ modules/parsers/gas/gas-token.re modules/parsers/nasm/nasm-parse.c modules/parsers/nasm/nasm-token.re modules/preprocs/cpp/cpp-preproc.c +modules/preprocs/gas/gas-preproc.c +modules/preprocs/gas/gas-eval.c modules/preprocs/nasm/nasm-preproc.c modules/preprocs/nasm/nasm-pp.c modules/preprocs/raw/raw-preproc.c -- 2.40.0