--- /dev/null
+/* $IdPath: yasm/modules/preprocs/yapp/yapp-preproc.c,v 1.23 2003/03/17 00:03:02 peter Exp $
+ * YAPP preprocessor (mimics NASM's preprocessor)
+ *
+ * Copyright (C) 2001 Michael Urman
+ *
+ * This file is part of YASM.
+ *
+ * YASM is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * YASM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <util.h>
+/*@unused@*/ RCSID("$IdPath: yasm/modules/preprocs/yapp/yapp-preproc.c,v 1.23 2003/03/17 00:03:02 peter Exp $");
+
+#define YASM_LIB_INTERNAL
+#include <libyasm.h>
+
+#include "yapp-preproc.h"
+#include "yapp-token.h"
+
+#define ydebug(x) /* printf x */
+
+static int is_interactive;
+static int saved_length;
+
+static HAMT *macro_table;
+
+static YAPP_Output current_output;
+YYSTYPE yapp_preproc_lval;
+
+/*@dependent@*/ yasm_linemgr *yapp_preproc_linemgr;
+
+int isatty(int);
+
+/* Build source and macro representations */
+static SLIST_HEAD(source_head, source_s) source_head, macro_head, param_head;
+static struct source_s {
+ SLIST_ENTRY(source_s) next;
+ YAPP_Token token;
+} *src, *source_tail, *macro_tail, *param_tail;
+typedef struct source_s source;
+
+/* don't forget what the nesting level says */
+static SLIST_HEAD(output_head, output_s) output_head;
+static struct output_s {
+ SLIST_ENTRY(output_s) next;
+ YAPP_Output out;
+} output, *out;
+
+/*****************************************************************************/
+/* macro support - to be moved to a separate file later (?) */
+/*****************************************************************************/
+typedef struct YAPP_Macro_s {
+ struct source_head macro_head;
+ struct source_head param_head;
+ enum {
+ YAPP_MACRO = 0,
+ YAPP_DEFINE
+ } type;
+ int args;
+ int fillargs;
+ int expanding;
+} YAPP_Macro;
+
+YAPP_Macro *
+yapp_macro_insert (char *name, int argc, int fillargs);
+
+void
+yapp_macro_error_exists (YAPP_Macro *v);
+
+void
+yapp_macro_error_sameargname (YAPP_Macro *v);
+
+YAPP_Macro *
+yapp_define_insert (char *name, int argc, int fillargs);
+
+void
+yapp_macro_delete (YAPP_Macro *ym);
+
+static YAPP_Macro *
+yapp_macro_get (const char *key);
+
+struct source_head *
+yapp_define_param_get (HAMT *hamt, const char *key);
+
+static void
+replay_saved_tokens(char *ident,
+ struct source_head *from_head,
+ struct source_head *to_head,
+ source **to_tail);
+
+YAPP_Macro *
+yapp_macro_insert (char *name, int argc, int fillargs)
+{
+ YAPP_Macro *ym = yasm_xmalloc(sizeof(YAPP_Macro));
+ ym->type = YAPP_MACRO;
+ ym->args = argc;
+ ym->fillargs = fillargs;
+
+ memcpy(&ym->macro_head, ¯o_head, sizeof(macro_head));
+
+ SLIST_INIT(¯o_head);
+ macro_tail = SLIST_FIRST(¯o_head);
+ return ym;
+}
+
+void
+yapp_macro_error_exists (YAPP_Macro *v)
+{
+ if (v) yasm__error(cur_lindex, N_("Redefining macro of the same name %d:%d"), v->type, v->args);
+}
+
+void
+yapp_macro_error_sameargname (YAPP_Macro *v)
+{
+ if (v) yasm__error(cur_lindex, N_("Duplicate argument names in macro"));
+}
+
+YAPP_Macro *
+yapp_define_insert (char *name, int argc, int fillargs)
+{
+ int zero = 0;
+ char *mungename = name;
+ YAPP_Macro *ym;
+
+ ym = yapp_macro_get(name);
+ if (ym) {
+ if ((argc >= 0 && ym->args < 0)
+ || (argc < 0 && ym->args >= 0))
+ {
+ yasm__warning(YASM_WARN_PREPROC, cur_lindex, N_("Attempted %%define both with and without parameters"));
+ return NULL;
+ }
+ }
+ else if (argc >= 0)
+ {
+ /* insert placeholder for paramlisted defines */
+ ym = yasm_xmalloc(sizeof(YAPP_Macro));
+ ym->type = YAPP_DEFINE;
+ ym->args = argc;
+ ym->fillargs = fillargs;
+ ym->expanding = 0;
+ HAMT_insert(macro_table, name, (void *)ym, &zero, (void (*)(void *))yapp_macro_error_exists);
+ }
+
+ /* now for the real one */
+ ym = yasm_xmalloc(sizeof(YAPP_Macro));
+ ym->type = YAPP_DEFINE;
+ ym->args = argc;
+ ym->fillargs = fillargs;
+ ym->expanding = 0;
+
+ if (argc>=0) {
+ mungename = yasm_xmalloc(strlen(name)+8);
+ sprintf(mungename, "%s(%d)", name, argc);
+ }
+
+ ydebug(("YAPP: +Inserting macro %s\n", mungename));
+
+ memcpy(&ym->macro_head, ¯o_head, sizeof(macro_head));
+ memcpy(&ym->param_head, ¶m_head, sizeof(param_head));
+
+ HAMT_insert(macro_table, mungename, (void *)ym, &zero, (void (*)(void *))yapp_macro_error_exists);
+
+ SLIST_INIT(¯o_head);
+ SLIST_INIT(¶m_head);
+
+ macro_tail = SLIST_FIRST(¯o_head);
+ param_tail = SLIST_FIRST(¶m_head);
+
+ return ym;
+}
+
+void
+yapp_macro_delete (YAPP_Macro *ym)
+{
+ while (!SLIST_EMPTY(&ym->macro_head)) {
+ source *s = SLIST_FIRST(&ym->macro_head);
+ yasm_xfree(s);
+ SLIST_REMOVE_HEAD(&ym->macro_head, next);
+ }
+ yasm_xfree(ym);
+}
+
+static YAPP_Macro *
+yapp_macro_get (const char *key)
+{
+ return (YAPP_Macro *)HAMT_search(macro_table, key);
+}
+
+struct source_head *
+yapp_define_param_get (HAMT *hamt, const char *key)
+{
+ return (struct source_head *)HAMT_search(hamt, key);
+}
+
+/*****************************************************************************/
+
+void
+append_processed_token(source *tok, struct source_head *to_head, source **to_tail);
+
+void
+append_token(int token, struct source_head *to_head, source **to_tail);
+
+int
+append_to_return(struct source_head *to_head, source **to_tail);
+
+int
+eat_through_return(struct source_head *to_head, source **to_tail);
+
+int
+yapp_get_ident(const char *synlvl);
+
+void
+copy_token(YAPP_Token *tok, struct source_head *to_head, source **to_tail);
+
+void
+expand_macro(char *name,
+ struct source_head *from_head,
+ struct source_head *to_head,
+ source **to_tail);
+
+void
+expand_token_list(struct source_head *paramexp, struct source_head *to_head, source **to_tail);
+
+static void
+yapp_preproc_initialize(FILE *f, const char *in_filename, yasm_linemgr *lm)
+{
+ is_interactive = f ? (isatty(fileno(f)) > 0) : 0;
+ yapp_preproc_linemgr = lm;
+ yapp_preproc_current_file = yasm__xstrdup(in_filename);
+ yapp_preproc_line_number = 1;
+ yapp_lex_initialize(f);
+ SLIST_INIT(&output_head);
+ SLIST_INIT(&source_head);
+ SLIST_INIT(¯o_head);
+ SLIST_INIT(¶m_head);
+ out = yasm_xmalloc(sizeof(output));
+ out->out = current_output = YAPP_OUTPUT;
+ SLIST_INSERT_HEAD(&output_head, out, next);
+
+ macro_table = HAMT_new(yasm_internal_error_);
+
+ source_tail = SLIST_FIRST(&source_head);
+ macro_tail = SLIST_FIRST(¯o_head);
+ param_tail = SLIST_FIRST(¶m_head);
+
+ append_token(LINE, &source_head, &source_tail);
+}
+
+static void
+yapp_preproc_cleanup(void)
+{
+ /* TODO: clean up */
+}
+
+/* Generate a new level of if* context
+ * if val is true, this module of the current level will be output IFF the
+ * surrounding one is.
+ */
+static void
+push_if(int val)
+{
+ out = yasm_xmalloc(sizeof(output));
+ out->out = current_output;
+ SLIST_INSERT_HEAD(&output_head, out, next);
+
+ switch (current_output)
+ {
+ case YAPP_OUTPUT:
+ current_output = val ? YAPP_OUTPUT : YAPP_NO_OUTPUT;
+ break;
+
+ case YAPP_NO_OUTPUT:
+ case YAPP_OLD_OUTPUT:
+ case YAPP_BLOCKED_OUTPUT:
+ current_output = YAPP_BLOCKED_OUTPUT;
+ break;
+ }
+ if (current_output != YAPP_OUTPUT) set_inhibit();
+
+}
+
+/* Generate a new module in the current if* context
+ * if val is true and this level hasn't had a true, it will be output if the
+ * surrounding level is.
+ */
+static void
+push_else(int val)
+{
+ switch (current_output)
+ {
+ /* if it was NO, turn to output IFF val is true */
+ case YAPP_NO_OUTPUT:
+ current_output = val ? YAPP_OUTPUT : YAPP_NO_OUTPUT;
+ break;
+
+ /* if it was yes, make it OLD */
+ case YAPP_OUTPUT:
+ current_output = YAPP_OLD_OUTPUT;
+ break;
+
+ /* leave OLD as OLD, BLOCKED as BLOCKED */
+ case YAPP_OLD_OUTPUT:
+ case YAPP_BLOCKED_OUTPUT:
+ break;
+ }
+ if (current_output != YAPP_OUTPUT) set_inhibit();
+}
+
+/* Clear the curent if* context level */
+static void
+pop_if(void)
+{
+ out = SLIST_FIRST(&output_head);
+ current_output = out->out;
+ SLIST_REMOVE_HEAD(&output_head, next);
+ yasm_xfree(out);
+ if (current_output != YAPP_OUTPUT) set_inhibit();
+}
+
+/* undefine a symbol */
+static void
+yapp_undef(const char *key)
+{
+ int zero = 0;
+ HAMT_insert(macro_table, key, NULL, &zero, (void (*)(void *))yapp_macro_delete);
+}
+
+/* Is a symbol known to YAPP? */
+static int
+yapp_defined(const char *key)
+{
+ return yapp_macro_get(key) != NULL;
+}
+
+void
+append_processed_token(source *tok, struct source_head *to_head, source **to_tail)
+{
+ ydebug(("YAPP: appended token \"%s\"\n", tok->token.str));
+ if (*to_tail) {
+ SLIST_INSERT_AFTER(*to_tail, tok, next);
+ }
+ else {
+ SLIST_INSERT_HEAD(to_head, tok, next);
+ }
+ *to_tail = tok;
+ if (to_head == &source_head)
+ saved_length += strlen(tok->token.str);
+}
+
+void
+append_token(int token, struct source_head *to_head, source **to_tail)
+{
+ if (current_output != YAPP_OUTPUT) {
+ ydebug(("YAPP: append_token while not YAPP_OUTPUT\n"));
+ return;
+ }
+
+ /* attempt to condense LINES together or newlines onto LINES */
+ if ((*to_tail) && (*to_tail)->token.type == LINE
+ && (token == '\n' || token == LINE))
+ {
+ yasm_xfree ((*to_tail)->token.str);
+ (*to_tail)->token.str = yasm_xmalloc(23+strlen(yapp_preproc_current_file));
+ sprintf((*to_tail)->token.str, "%%line %d+1 %s\n", yapp_preproc_line_number, yapp_preproc_current_file);
+ }
+ else {
+ src = yasm_xmalloc(sizeof(source));
+ src->token.type = token;
+ switch (token)
+ {
+ case INTNUM:
+ src->token.str = yasm__xstrdup(yapp_preproc_lval.int_str_val.str);
+ src->token.val.int_val = yapp_preproc_lval.int_str_val.val;
+ break;
+
+ case FLTNUM:
+ src->token.str = yasm__xstrdup(yapp_preproc_lval.double_str_val.str);
+ src->token.val.double_val = yapp_preproc_lval.double_str_val.val;
+ break;
+
+ case STRING:
+ case WHITESPACE:
+ src->token.str = yasm__xstrdup(yapp_preproc_lval.str_val);
+ break;
+
+ case IDENT:
+ src->token.str = yasm__xstrdup(yapp_preproc_lval.str_val);
+ break;
+
+ case '+': case '-': case '*': case '/': case '%': case ',': case '\n':
+ case '[': case ']': case '(': case ')':
+ src->token.str = yasm_xmalloc(2);
+ src->token.str[0] = (char)token;
+ src->token.str[1] = '\0';
+ break;
+
+ case LINE:
+ /* TODO: consider removing any trailing newline or LINE tokens */
+ src->token.str = yasm_xmalloc(23+strlen(yapp_preproc_current_file));
+ sprintf(src->token.str, "%%line %d+1 %s\n", yapp_preproc_line_number, yapp_preproc_current_file);
+ break;
+
+ default:
+ yasm_xfree(src);
+ return;
+ }
+ append_processed_token(src, to_head, to_tail);
+ }
+}
+
+static void
+replay_saved_tokens(char *ident,
+ struct source_head *from_head,
+ struct source_head *to_head,
+ source **to_tail)
+{
+ source *item, *after;
+ ydebug(("-No, %s didn't match any macro we have\n", ident));
+ /* this means a macro expansion failed. stick its name and all the saved
+ * tokens into the output stream */
+ yapp_preproc_lval.str_val = ident;
+ append_token(IDENT, to_head, to_tail);
+
+ item = SLIST_FIRST(from_head);
+ while (item) {
+ after = SLIST_NEXT(item, next);
+ SLIST_INSERT_AFTER(*to_tail, item, next);
+ *to_tail = item;
+ saved_length += strlen(item->token.str);
+ item = after;
+ }
+ SLIST_INIT(from_head);
+}
+
+int
+append_to_return(struct source_head *to_head, source **to_tail)
+{
+ int token = yapp_preproc_lex();
+ while (token != '\n') {
+ ydebug(("YAPP: ATR: '%c' \"%s\"\n", token, yapp_preproc_lval.str_val));
+ if (token == 0)
+ return 0;
+ append_token(token, to_head, to_tail);
+ token = yapp_preproc_lex();
+ }
+ return '\n';
+}
+
+int
+eat_through_return(struct source_head *to_head, source **to_tail)
+{
+ int token;
+ while ((token = yapp_preproc_lex()) != '\n') {
+ if (token == 0)
+ return 0;
+ yasm__error(cur_lindex, N_("Skipping possibly valid %%define stuff"));
+ }
+ append_token('\n', to_head, to_tail);
+ return '\n';
+}
+
+int
+yapp_get_ident(const char *synlvl)
+{
+ int token = yapp_preproc_lex();
+ if (token == WHITESPACE)
+ token = yapp_preproc_lex();
+ if (token != IDENT) {
+ yasm__error(cur_lindex, N_("Identifier expected after %%%s"), synlvl);
+ }
+ return token;
+}
+
+void
+copy_token(YAPP_Token *tok, struct source_head *to_head, source **to_tail)
+{
+ src = yasm_xmalloc(sizeof(source));
+ src->token.type = tok->type;
+ src->token.str = yasm__xstrdup(tok->str);
+
+ append_processed_token(src, to_head, to_tail);
+}
+
+void
+expand_macro(char *name,
+ struct source_head *from_head,
+ struct source_head *to_head,
+ source **to_tail)
+{
+ struct source_head replay_head, arg_head;
+ source *replay_tail, *arg_tail;
+
+ YAPP_Macro *ym = yapp_macro_get(name);
+
+ ydebug(("YAPP: +Expand macro %s...\n", name));
+
+ if (ym->expanding) yasm_internal_error(N_("Recursively expanding a macro!"));
+
+ if (ym->type == YAPP_DEFINE) {
+ if (ym->args == -1) {
+ /* no parens to deal with */
+ ym->expanding = 1;
+ expand_token_list(&ym->macro_head, to_head, to_tail);
+ ym->expanding = 0;
+ }
+ else
+ {
+ char *mungename;
+ int token;
+ int argc=0;
+ int parennest=0;
+ HAMT *param_table;
+ source *replay, *param;
+
+ ydebug(("YAPP: +Expanding multi-arg macro %s...\n", name));
+
+ /* Build up both a parameter reference list and a token buffer,
+ * because we won't know until we've reached the closing paren if
+ * we can actuall expand the macro or not. bleah. */
+ /* worse, we can't build the parameter list until we know the
+ * parameter names, which we can't look up until we know the
+ * number of arguments. sigh */
+ /* HMM */
+ SLIST_INIT(&replay_head);
+ replay_tail = SLIST_FIRST(&replay_head);
+
+ /* find out what we got */
+ if (from_head) {
+ yasm_internal_error(N_("Expanding macro with non-null from_head ugh\n"));
+ }
+ token = yapp_preproc_lex();
+ append_token(token, &replay_head, &replay_tail);
+ /* allow one whitespace */
+ if (token == WHITESPACE) {
+ ydebug(("Ignoring WS between macro and paren\n"));
+ token = yapp_preproc_lex();
+ append_token(token, &replay_head, &replay_tail);
+ }
+ if (token != '(') {
+ ydebug(("YAPP: -Didn't get to left paren; instead got '%c' \"%s\"\n", token, yapp_preproc_lval.str_val));
+ replay_saved_tokens(name, &replay_head, to_head, to_tail);
+ return;
+ }
+
+ /* at this point, we've got the left paren. time to get annoyed */
+ while (token != ')') {
+ token = yapp_preproc_lex();
+ append_token(token, &replay_head, &replay_tail);
+ /* TODO: handle { } for commas? or is that just macros? */
+ switch (token) {
+ case '(':
+ parennest++;
+ break;
+
+ case ')':
+ if (parennest) {
+ parennest--;
+ token = ',';
+ }
+ else {
+ argc++;
+ }
+ break;
+
+ case ',':
+ if (!parennest)
+ argc++;
+ break;
+
+ case WHITESPACE: case IDENT: case INTNUM: case FLTNUM: case STRING:
+ case '+': case '-': case '*': case '/':
+ break;
+
+ default:
+ if (token < 256)
+ yasm_internal_error(N_("Unexpected character token in parameter expansion"));
+ else
+ yasm__error(cur_lindex, N_("Cannot handle preprocessor items inside possible macro invocation"));
+ }
+ }
+
+ /* Now we have the argument count; let's see if it exists */
+ mungename = yasm_xmalloc(strlen(name)+8);
+ sprintf(mungename, "%s(%d)", name, argc);
+ ym = yapp_macro_get(mungename);
+ if (!ym)
+ {
+ ydebug(("YAPP: -Didn't find macro %s\n", mungename));
+ replay_saved_tokens(name, &replay_head, to_head, to_tail);
+ yasm_xfree(mungename);
+ return;
+ }
+ ydebug(("YAPP: +Found macro %s\n", mungename));
+
+ ym->expanding = 1;
+
+ /* so the macro exists. build a HAMT parameter table */
+ param_table = HAMT_new(yasm_internal_error_);
+ /* fill the entries by walking the replay buffer and create
+ * "macros". coincidentally, clear the replay buffer. */
+
+ /* get to the opening paren */
+ replay = SLIST_FIRST(&replay_head);
+ while (replay->token.type != '(') {
+ ydebug(("YAPP: Ignoring replay token '%c' \"%s\"\n", replay->token.type, replay->token.str));
+ SLIST_REMOVE_HEAD(&replay_head, next);
+ yasm_xfree(replay->token.str);
+ yasm_xfree(replay);
+ replay = SLIST_FIRST(&replay_head);
+ }
+ ydebug(("YAPP: Ignoring replay token '%c' \"%s\"\n", replay->token.type, replay->token.str));
+
+ /* free the open paren */
+ SLIST_REMOVE_HEAD(&replay_head, next);
+ yasm_xfree(replay->token.str);
+ yasm_xfree(replay);
+
+ param = SLIST_FIRST(&ym->param_head);
+
+ SLIST_INIT(&arg_head);
+ arg_tail = SLIST_FIRST(&arg_head);
+
+ replay = SLIST_FIRST(&replay_head);
+ SLIST_REMOVE_HEAD(&replay_head, next);
+ while (parennest || replay) {
+ if (replay->token.type == '(') {
+ parennest++;
+ append_processed_token(replay, &arg_head, &arg_tail);
+ ydebug(("YAPP: +add arg token '%c'\n", replay->token.type));
+ }
+ else if (parennest && replay->token.type == ')') {
+ parennest--;
+ append_processed_token(replay, &arg_head, &arg_tail);
+ ydebug(("YAPP: +add arg token '%c'\n", replay->token.type));
+ }
+ else if ((!parennest) && (replay->token.type == ','
+ || replay->token.type == ')'))
+ {
+ int zero=0;
+ struct source_head *argmacro = yasm_xmalloc(sizeof(struct source_head));
+ memcpy(argmacro, &arg_head, sizeof(struct source_head));
+ SLIST_INIT(&arg_head);
+ arg_tail = SLIST_FIRST(&arg_head);
+
+ /* don't save the comma */
+ yasm_xfree(replay->token.str);
+ yasm_xfree(replay);
+
+ HAMT_insert(param_table,
+ param->token.str,
+ (void *)argmacro,
+ &zero,
+ (void (*)(void *))yapp_macro_error_sameargname);
+ param = SLIST_NEXT(param, next);
+ }
+ else if (replay->token.type == IDENT
+ && yapp_defined(replay->token.str))
+ {
+ ydebug(("YAPP: +add arg macro '%c' \"%s\"\n", replay->token.type, replay->token.str));
+ expand_macro(replay->token.str, &replay_head, &arg_head, &arg_tail);
+ }
+ else if (arg_tail || replay->token.type != WHITESPACE) {
+ ydebug(("YAPP: +else add arg token '%c' \"%s\"\n", replay->token.type, replay->token.str));
+ append_processed_token(replay, &arg_head, &arg_tail);
+ }
+ replay = SLIST_FIRST(&replay_head);
+ if (replay) SLIST_REMOVE_HEAD(&replay_head, next);
+ }
+ if (replay) {
+ yasm_xfree(replay->token.str);
+ yasm_xfree(replay);
+ }
+ else if (param) {
+ yasm_internal_error(N_("Got to end of arglist before end of replay!"));
+ }
+ replay = SLIST_FIRST(&replay_head);
+ if (replay || param)
+ yasm_internal_error(N_("Count and distribution of define args mismatched!"));
+
+ /* the param_table is set up without errors, so expansion is ready
+ * to go */
+ SLIST_FOREACH (replay, &ym->macro_head, next) {
+ if (replay->token.type == IDENT) {
+
+ /* check local args first */
+ struct source_head *paramexp =
+ yapp_define_param_get(param_table, replay->token.str);
+
+ if (paramexp) {
+ expand_token_list(paramexp, to_head, to_tail);
+ }
+ else {
+ /* otherwise, check macros */
+ YAPP_Macro *imacro = yapp_macro_get(replay->token.str);
+ if (imacro != NULL && !imacro->expanding) {
+ expand_macro(replay->token.str, NULL, to_head, to_tail);
+ }
+ else {
+ /* otherwise it's just a vanilla ident */
+ copy_token(&replay->token, to_head, to_tail);
+ }
+ }
+ }
+ else {
+ copy_token(&replay->token, to_head, to_tail);
+ }
+ }
+ ym->expanding = 0;
+ }
+ }
+ else
+ yasm_internal_error(N_("Invoking Macros not yet supported"));
+
+ ym->expanding = 0;
+}
+
+void
+expand_token_list(struct source_head *paramexp, struct source_head *to_head, source **to_tail)
+{
+ source *item;
+ SLIST_FOREACH (item, paramexp, next) {
+ if (item->token.type == IDENT) {
+ YAPP_Macro *imacro = yapp_macro_get(item->token.str);
+ if (imacro != NULL && !imacro->expanding) {
+ expand_macro(item->token.str, NULL, to_head, to_tail);
+ }
+ else {
+ copy_token(&item->token, to_head, to_tail);
+ }
+ }
+ else {
+ copy_token(&item->token, to_head, to_tail);
+ }
+ }
+}
+
+static size_t
+yapp_preproc_input(char *buf, size_t max_size)
+{
+ static YAPP_State state = YAPP_STATE_INITIAL;
+ size_t n = 0;
+ int token;
+ int need_line_directive = 0;
+
+ while ((size_t)saved_length < max_size && state != YAPP_STATE_EOF)
+ {
+ token = yapp_preproc_lex();
+
+ switch (state) {
+ case YAPP_STATE_INITIAL:
+ switch (token)
+ {
+ char *s;
+ default:
+ append_token(token, &source_head, &source_tail);
+ /*if (append_to_return()==0) state=YAPP_STATE_EOF;*/
+ ydebug(("YAPP: default: '%c' \"%s\"\n", token, yapp_preproc_lval.str_val));
+ /*yasm__error(cur_lindex, N_("YAPP got an unhandled token."));*/
+ break;
+
+ case IDENT:
+ ydebug(("YAPP: ident: \"%s\"\n", yapp_preproc_lval.str_val));
+ if (yapp_defined(yapp_preproc_lval.str_val)) {
+ expand_macro(yapp_preproc_lval.str_val, NULL, &source_head, &source_tail);
+ }
+ else {
+ append_token(token, &source_head, &source_tail);
+ }
+ break;
+
+ case 0:
+ state = YAPP_STATE_EOF;
+ break;
+
+ case '\n':
+ append_token(token, &source_head, &source_tail);
+ break;
+
+ case CLEAR:
+ HAMT_delete(macro_table, (void (*)(void *))yapp_macro_delete);
+ macro_table = HAMT_new(yasm_internal_error_);
+ break;
+
+ case DEFINE:
+ ydebug(("YAPP: define: "));
+ token = yapp_get_ident("define");
+ ydebug((" \"%s\"\n", yapp_preproc_lval.str_val));
+ s = yasm__xstrdup(yapp_preproc_lval.str_val);
+
+ /* three cases: newline or stuff or left paren */
+ token = yapp_preproc_lex();
+ if (token == '\n') {
+ /* no args or content - just insert it */
+ yapp_define_insert(s, -1, 0);
+ append_token('\n', &source_head, &source_tail);
+ }
+ else if (token == WHITESPACE) {
+ /* no parens */
+ if(append_to_return(¯o_head, ¯o_tail)==0) state=YAPP_STATE_EOF;
+ else {
+ yapp_define_insert(s, -1, 0);
+ }
+ append_token('\n', &source_head, &source_tail);
+ }
+ else if (token == '(') {
+ /* get all params of the parameter list */
+ /* ensure they alternate IDENT and ',' */
+ int param_count = 0;
+ int last_token = ',';
+
+ ydebug((" *Getting arglist for define %s\n", s));
+
+ while ((token = yapp_preproc_lex())!=')') {
+ ydebug(("YAPP: +read token '%c' \"%s\" for macro %s\n", token, yapp_preproc_lval.str_val, s));
+ if (token == WHITESPACE) {
+ token = last_token;
+ }
+ else if (last_token == ',' && token == IDENT) {
+ append_token(token, ¶m_head, ¶m_tail);
+ param_count++;
+ }
+ else if (token == 0) {
+ state = YAPP_STATE_EOF;
+ break;
+ }
+ else if (last_token == ',' || token != ',')
+ yasm__error(cur_lindex, N_("Unexpected token in %%define parameters"));
+ last_token = token;
+ }
+ if (token == ')') {
+ /* after paramlist and ')' */
+ /* everything is what it's defined to be */
+ token = yapp_preproc_lex();
+ if (token != WHITESPACE) append_token(token, ¯o_head, ¯o_tail);
+ if (append_to_return(¯o_head, ¯o_tail)==0) state=YAPP_STATE_EOF;
+ else {
+ ydebug(("YAPP: Inserting define macro %s (%d)\n", s, param_count));
+ yapp_define_insert(s, param_count, 0);
+ }
+ }
+ append_token('\n', &source_head, &source_tail);
+ }
+ else {
+ yasm_internal_error(N_("%%define ... failed miserably - neither \\n, WS, or ( followed ident"));
+ }
+ break;
+
+ case UNDEF:
+ token = yapp_get_ident("undef");
+ yapp_undef(yapp_preproc_lval.str_val);
+ state = YAPP_STATE_NEED_EOL;
+ break;
+
+ case IFDEF:
+ token = yapp_get_ident("ifdef");
+ push_if(yapp_defined(yapp_preproc_lval.str_val));
+ state = YAPP_STATE_NEED_EOL;
+ break;
+
+ case IFNDEF:
+ token = yapp_get_ident("ifndef");
+ push_if(!yapp_defined(yapp_preproc_lval.str_val));
+ state = YAPP_STATE_NEED_EOL;
+ break;
+
+ case ELSE:
+ push_else(1);
+ if (current_output == YAPP_OUTPUT) need_line_directive = 1;
+ state = YAPP_STATE_NEED_EOL;
+ break;
+
+ case ELIFDEF:
+ token = yapp_get_ident("elifdef");
+ push_else(yapp_defined(yapp_preproc_lval.str_val));
+ if (current_output == YAPP_OUTPUT) need_line_directive = 1;
+ state = YAPP_STATE_NEED_EOL;
+ break;
+
+ case ELIFNDEF:
+ token = yapp_get_ident("elifndef");
+ push_else(!yapp_defined(yapp_preproc_lval.str_val));
+ if (current_output == YAPP_OUTPUT) need_line_directive = 1;
+ state = YAPP_STATE_NEED_EOL;
+ break;
+
+ case ENDIF:
+ /* there's got to be another way to do this: */
+ /* only set if going from non-output to output */
+ if (current_output != YAPP_OUTPUT) need_line_directive = 1;
+ pop_if();
+ if (current_output != YAPP_OUTPUT) need_line_directive = 0;
+ state = YAPP_STATE_NEED_EOL;
+ break;
+
+ case INCLUDE:
+ case LINE:
+ need_line_directive = 1;
+ break;
+ }
+ if (state == YAPP_STATE_NEED_EOL)
+ {
+ if (eat_through_return(&source_head, &source_tail)==0) state=YAPP_STATE_EOF;
+ else state=YAPP_STATE_INITIAL;
+ }
+ break;
+ default:
+ yasm__error(cur_lindex, N_("YAPP got into a bad state"));
+ }
+ if (need_line_directive) {
+ append_token(LINE, &source_head, &source_tail);
+ need_line_directive = 0;
+ }
+ }
+
+ /* convert saved stuff into output. we either have enough, or are EOF */
+ while (n < max_size && saved_length)
+ {
+ src = SLIST_FIRST(&source_head);
+ if (max_size - n >= strlen(src->token.str)) {
+ strcpy(buf+n, src->token.str);
+ n += strlen(src->token.str);
+
+ saved_length -= strlen(src->token.str);
+ SLIST_REMOVE_HEAD(&source_head, next);
+ yasm_xfree(src->token.str);
+ yasm_xfree(src);
+ }
+ }
+
+ return n;
+}
+
+/* Define preproc structure -- see preproc.h for details */
+yasm_preproc yasm_yapp_LTX_preproc = {
+ "YAPP preprocessing (NASM style)",
+ "yapp",
+ yapp_preproc_initialize,
+ yapp_preproc_cleanup,
+ yapp_preproc_input
+};
--- /dev/null
+/* $IdPath$
+ * YAPP lexer
+ *
+ * Copyright (C) 2001 Michael Urman
+ *
+ * This file is part of YASM.
+ *
+ * YASM is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * YASM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+%{
+#define YASM_LIB_INTERNAL
+#include "libyasm.h"
+/*@unused@*/ RCSID("$IdPath$");
+
+#include <errno.h>
+
+#include "modules/preprocs/yapp/yapp-preproc.h"
+#include "modules/preprocs/yapp/yapp-token.h"
+
+
+#define yylval yapp_preproc_lval
+
+#define malloc yasm_xmalloc
+#define realloc yasm_xrealloc
+
+/* starting size of string buffer */
+#define STRBUF_ALLOC_SIZE 128
+
+/* string buffer used when parsing strings/character constants */
+static char *strbuf = (char *)NULL;
+
+/* length of strbuf (including terminating NULL character) */
+static size_t strbuf_size = 0;
+
+/* include file mumbo jumbo */
+static SLIST_HEAD(include_head, include_s) includes_head;
+struct include_s {
+ SLIST_ENTRY(include_s) next;
+ YY_BUFFER_STATE include_state;
+ char *filename;
+ int line_number;
+};
+typedef struct include_s include;
+
+char *yapp_preproc_current_file;
+int yapp_preproc_line_number;
+
+%}
+%option noyywrap
+%option nounput
+%option case-insensitive
+%option prefix="yapp_preproc_"
+%option outfile="lex.yy.c"
+
+%x D
+%x incl
+%x line
+%x inhibit
+
+DIGIT [0-9]
+BINDIGIT [01]
+OCTDIGIT [0-7]
+HEXDIGIT [0-9a-f]
+WS [ \t]
+DIR %[ \t]*
+
+%%
+
+ /* standard decimal integer */
+{DIGIT}+ {
+ yylval.int_str_val.val = strtoul(yytext, (char **)NULL, 10);
+ yylval.int_str_val.str = yytext;
+ return INTNUM;
+}
+
+ /* 10010011b - binary number */
+{BINDIGIT}+b {
+ yylval.int_str_val.val = strtoul(yytext, (char **)NULL, 2);
+ yylval.int_str_val.str = yytext;
+ return INTNUM;
+}
+
+ /* 777q - octal number */
+{OCTDIGIT}+q {
+ yylval.int_str_val.val = strtoul(yytext, (char **)NULL, 8);
+ yylval.int_str_val.str = yytext;
+ return INTNUM;
+}
+
+ /* 0AAh form of hexidecimal number */
+0{HEXDIGIT}+h {
+ yylval.int_str_val.val = strtoul(yytext+1, (char **)NULL, 16);
+ yylval.int_str_val.str = yytext;
+ return INTNUM;
+}
+
+ /* $0AA and 0xAA forms of hexidecimal number */
+(\$0|0x){HEXDIGIT}+ {
+ yylval.int_str_val.val = strtoul(yytext+2, (char **)NULL, 16);
+ yylval.int_str_val.str = yytext;
+ return INTNUM;
+}
+
+ /* floating point value */
+{DIGIT}+\.{DIGIT}*(e[-+]?{DIGIT}+)? {
+ yylval.double_str_val.val = strtod(yytext, (char **)NULL);
+ yylval.double_str_val.str = yytext;
+ return FLTNUM;
+}
+
+ /* string/character constant values */
+["'] {
+ int inch;
+ size_t count;
+ char endch = yytext[0];
+
+ strbuf = yasm_xmalloc(STRBUF_ALLOC_SIZE);
+
+ strbuf_size = STRBUF_ALLOC_SIZE;
+ inch = input();
+ count = 0;
+ while(inch != EOF && inch != endch && inch != '\n') {
+ strbuf[count++] = inch;
+ if(count >= strbuf_size) {
+ strbuf = yasm_xrealloc(strbuf, strbuf_size + STRBUF_ALLOC_SIZE);
+ strbuf_size += STRBUF_ALLOC_SIZE;
+ }
+ inch = input();
+ }
+
+ if(inch == '\n')
+ yasm__error(cur_lindex, N_("unterminated string"));
+ else if(inch == EOF)
+ yasm__error(cur_lindex, N_("unexpected end of file in string"));
+
+ strbuf[count] = '\0';
+
+ yylval.str_val = strbuf;
+ return STRING;
+}
+
+ /* identifiers */
+\.\.[a-z0-9_$#@~.?]+ |
+\.[a-z0-9_$#@~?][a-z0-9_$#@~.?]* |
+[a-z_?][a-z0-9_$#@~.?]* {
+ yylval.str_val = yasm__xstrdup(yytext);
+ return IDENT;
+}
+
+ /* includes - based on flex manual handling of include files */
+<inhibit>{DIR}include[^\n]* ;
+{DIR}include BEGIN(incl);
+ /* note the " handling here is a hack that doesn't accept useful
+ * things (like spaces, or quotes). fix it later */
+<incl>[ \t"]* /* eat whitespace */
+<incl>[^ \t\n"]* { /* have the filename */
+ include *inc;
+ FILE *incfile;
+ inc = yasm_xmalloc(sizeof(include));
+ inc->include_state = YY_CURRENT_BUFFER;
+
+ /* FIXME: handle includes that aren't relative */
+ incfile = fopen (yytext, "r");
+ if(!incfile) {
+ yasm__error(cur_lindex, N_("include file `%s': %s"),
+ yytext, strerror(errno));
+ yasm_xfree(inc);
+ }
+ else {
+ yyin = incfile;
+ inc->filename = yapp_preproc_current_file;
+ inc->line_number = yapp_preproc_line_number;
+ SLIST_INSERT_HEAD(&includes_head, inc, next);
+
+ yapp_preproc_line_number = 1;
+ yapp_preproc_current_file = yasm__xstrdup(yytext);
+ BEGIN(INITIAL);
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ }
+ return INCLUDE;
+}
+
+ /* end includes - note that it's not in <incl> at the time */
+<<EOF>> {
+ if(SLIST_EMPTY(&includes_head)) {
+ yyterminate();
+ }
+ else {
+ include *inc;
+ inc = SLIST_FIRST(&includes_head);
+ yy_delete_buffer (YY_CURRENT_BUFFER);
+ yy_switch_to_buffer (inc->include_state);
+ yasm_xfree(yapp_preproc_current_file);
+ yapp_preproc_current_file = inc->filename;
+ yapp_preproc_line_number = inc->line_number + 1;
+ SLIST_REMOVE_HEAD(&includes_head, next);
+ yasm_xfree(inc);
+
+ BEGIN(incl);
+ return INCLUDE;
+ }
+}
+
+<incl>["]{WS}*\n BEGIN(INITIAL);
+
+
+ /* directive: % directive [args] */
+<inhibit>{DIR}clear[^\n] ;
+{DIR}clear return CLEAR;
+
+<inhibit>{DIR}line[^\n] ;
+{DIR}line BEGIN(line);
+<line>{DIGIT}+ yapp_preproc_line_number = strtoul(yytext, (char **)NULL, 10);
+<line>{DIGIT}+{WS}*\n {
+ yapp_preproc_line_number = strtoul(yytext, (char **)NULL, 10);
+ BEGIN(INITIAL);
+ return LINE;
+}
+<line>{WS}+["] ; /* eat space before file */
+<line>[^ \t\n"]* { /* have the filename */
+ yasm_xfree(yapp_preproc_current_file);
+ yapp_preproc_current_file = yasm__xstrdup(yytext);
+}
+<line>["]{WS}*\n {
+ BEGIN(INITIAL);
+ return LINE;
+}
+
+{DIR}define return DEFINE;
+{DIR}undef return UNDEF;
+{DIR}assign return ASSIGN;
+{DIR}macro return MACRO;
+{DIR}endmacro return ENDMACRO;
+{DIR}rotate return ROTATE;
+<inhibit>{DIR}define[^\n]* ;
+<inhibit>{DIR}undef[^\n]* ;
+<inhibit>{DIR}assign[^\n]* ;
+<inhibit>{DIR}macro[^\n]* ;
+<inhibit>{DIR}endmacro[^\n]* ;
+<inhibit>{DIR}rotate[^\n]* ;
+
+ /* preprocessor loops */
+{DIR}rep return REP;
+{DIR}exitrep return EXITREP;
+{DIR}endrep return ENDREP;
+<inhibit>{DIR}rep[^\n]* ;
+<inhibit>{DIR}exitrep[^\n]* ;
+<inhibit>{DIR}endrep[^\n]* ;
+
+{DIR}if return IF;
+{DIR}elif return ELIF;
+{DIR}else return ELSE;
+{DIR}endif return ENDIF;
+<inhibit>{DIR}if { BEGIN(INITIAL); return IF; }
+<inhibit>{DIR}elif { BEGIN(INITIAL); return ELIF; }
+<inhibit>{DIR}else { BEGIN(INITIAL); return ELSE; }
+<inhibit>{DIR}endif { BEGIN(INITIAL); return ENDIF; }
+
+ /* test defines */
+{DIR}ifdef return IFDEF;
+{DIR}elifdef return ELIFDEF;
+{DIR}ifndef return IFNDEF;
+{DIR}elifndef return ELIFNDEF;
+<inhibit>{DIR}ifdef { BEGIN(INITIAL); return IFDEF; }
+<inhibit>{DIR}elifdef { BEGIN(INITIAL); return ELIFDEF; }
+<inhibit>{DIR}ifndef { BEGIN(INITIAL); return IFNDEF; }
+<inhibit>{DIR}elifndef { BEGIN(INITIAL); return ELIFNDEF; }
+
+ /* test context stack */
+{DIR}ifctx return IFCTX;
+{DIR}elifctx return ELIFCTX;
+<inhibit>{DIR}ifctx { BEGIN(INITIAL); return IFCTX; }
+<inhibit>{DIR}elifctx { BEGIN(INITIAL); return ELIFCTX; }
+
+ /* test exact identity */
+{DIR}ifidn return IFIDN;
+{DIR}elifidn return ELIFIDN;
+{DIR}ifidni return IFIDNI;
+{DIR}elifidni return ELIFIDNI;
+<inhibit>{DIR}ifidn { BEGIN(INITIAL); return IFIDN; }
+<inhibit>{DIR}elifidn { BEGIN(INITIAL); return ELIFIDN; }
+<inhibit>{DIR}ifidni { BEGIN(INITIAL); return IFIDNI; }
+<inhibit>{DIR}elifidni { BEGIN(INITIAL); return ELIFIDNI; }
+
+ /* test token types */
+{DIR}ifid return IFID;
+{DIR}elifid return ELIFID;
+{DIR}ifnum return IFNUM;
+{DIR}elifnum return ELIFNUM;
+{DIR}ifstr return IFSTR;
+{DIR}elifstr return ELIFSTR;
+<inhibit>{DIR}ifid { BEGIN(INITIAL); return IFID; }
+<inhibit>{DIR}elifid { BEGIN(INITIAL); return ELIFID; }
+<inhibit>{DIR}ifnum { BEGIN(INITIAL); return IFNUM; }
+<inhibit>{DIR}elifnum { BEGIN(INITIAL); return ELIFNUM; }
+<inhibit>{DIR}ifstr { BEGIN(INITIAL); return IFSTR; }
+<inhibit>{DIR}elifstr { BEGIN(INITIAL); return ELIFSTR; }
+
+ /* error reporting */
+<inhibit>{DIR}error[^\n]* ;
+{DIR}error[ ]+.* { yylval.str_val = yytext; return ERROR; }
+
+ /* context stack management */
+{DIR}push return PUSH;
+{DIR}pop return POP;
+{DIR}repl return REPL;
+<inhibit>{DIR}push[^\n]* ;
+<inhibit>{DIR}pop[^\n]* ;
+<inhibit>{DIR}repl[^\n]* ;
+
+<inhibit>[^%\n]*\n { yapp_preproc_line_number++; return '\n'; }
+
+;.*\n { yapp_preproc_line_number++; return '\n'; }
+
+{WS}+ { yylval.str_val = yytext; return WHITESPACE; }
+
+{WS}*\n { yapp_preproc_line_number++; return '\n'; }
+
+
+[][+*/,()-] { return yytext[0]; }
+
+<inhibit>. {
+ yasm__warning(YASM_WARN_PREPROC, cur_lindex, N_("Unhandled character in <inhibit> `%s'"), yasm__conv_unprint(yytext[0]));
+}
+
+. {
+ yasm__warning(YASM_WARN_PREPROC, cur_lindex, N_("ignoring unrecognized character `%s'"),
+ yasm__conv_unprint(yytext[0]));
+}
+
+%%
+
+void
+yapp_lex_initialize(FILE *f)
+{
+ SLIST_INIT(&includes_head);
+ yyin = f;
+}
+
+void set_inhibit(void)
+{
+ BEGIN(inhibit);
+}