Quelltext /~heha/hs/gputils64-210929.zip/gpasm/macro.cpp

/* Implements macros
   Copyright 2002-2005	Craig Franklin
*/

#include "stdhdr.h"

#include "libgputils.h"
#include "gpasm.h"
#include "directive.h"
#include "evaluate.h"
#include "gpmsg.h"
#include "macro.h"
#include "parse.h"
#include "preprocess.h"
#include "lst.h"
#include <vector>

/* The symbol table is pushed at each macro call. This makes local symbols
   possible. Each symbol table is created once on pass 1. On pass two the
   old symbol table is reloaded so forward references to the local symbols
   are possible. */

struct macro_table_t {
  symbol_table_t *table;
  int            line_number;      /* sanity check, better not change */
  macro_table_t(symbol_table_t*t,int n):table(t),line_number(n) {}
};

static std::vector<macro_table_t> macro_table_list;
static int macro_table_ptr;	// tracer for second pass

/*------------------------------------------------------------------------------------------------*/

static void _add_macro_table(symbol_table_t *Table) {
  macro_table_t m(Table,state.src_list.last->line_number);
  macro_table_list.push_back(m);
}

/*------------------------------------------------------------------------------------------------*/

/* Create a new defines table and place the macro parms in it. */

void macro_setup(macro_head_t *Head, int Arity, const pnode_t *Parms) {
  const pnode_t *pFrom;
  const pnode_t *pFromH;
  const pnode_t *pTo;
  const pnode_t *pToH;
  symbol_t      *sym;

  if (eval_enforce_arity(Arity, eval_list_length(Head->parms))) {
    /* push table for the marco parms */
    state.stMacroParams = gp_sym_push_table(state.stMacroParams, state.case_insensitive);

    /* Now add the macro's declared parameter list to the new defines table. */
    if (Arity > 0) {
      pTo = Parms;

      for (pFrom = Head->parms; pFrom != NULL; pFrom = PnListTail(pFrom)) {
        pToH   = PnListHead(pTo);
        pFromH = PnListHead(pFrom);
        assert(PnIsSymbol(pFromH));
        assert(PnIsSymbol(pToH));

        sym = gp_sym_add_symbol(state.stMacroParams, PnSymbol(pFromH));
        gp_sym_annotate_symbol(sym, mk_list(mk_string(GP_Strdup(PnSymbol(pToH))), NULL));
        pTo = PnListTail(pTo);
      }
    }

    state.next_state        = STATE_MACRO;
    state.next_buffer.macro = Head;
    state.lst.line.linetype = gpasm_state::Lst::Line::LTY_NONE;
  }
}

/*------------------------------------------------------------------------------------------------*/

symbol_table_t* macro_push_symbol_table(symbol_table_t *Table) {
  symbol_table_t *pnew = NULL;

  if (state.pass == 1) {
    pnew = gp_sym_push_table(Table, state.case_insensitive);
    _add_macro_table(pnew);
  }else{
    if (macro_table_ptr==macro_table_list.size()) {
      gpmsg(GPE_UNKNOWN, "An error occurred during a macro execution on pass %i.", state.pass);
      exit(1);
    }
    macro_table_t &el=macro_table_list[macro_table_ptr];

    if (el.line_number != (int)state.src_list.last->line_number) {
    /* The user must have conditionally assembled a macro using a forward
       reference to a label. This is a very bad practice. It means that
       a macro wasn't executed on the first pass, but it was on the second.
       Probably errors will be generated. Forward references to local
       symbols probably won't be correct. */
      pnew = gp_sym_push_table(Table, state.case_insensitive);
      gpmsg0(GPW_UNKNOWN, "Macro not executed on pass 1.");
    }else{
      assert(macro_table_ptr);
      pnew = el.table;
      gp_sym_set_guest_table(pnew, Table);
      macro_table_ptr++; /* setup for next macro */
    }
  }

  return pnew;
}

/*------------------------------------------------------------------------------------------------*/

void macro_list(macro_body_t *Body) {
  source_context_t *ctx;
  unsigned      old_line_number;

  ctx             = state.src_list.last;
  old_line_number = ctx->line_number;
  /* Never executed: List the macro body. */
  state.lst.line.linetype = gpasm_state::Lst::Line::LTY_DIR;
  ctx->line_number        = state.while_head->line_number;
  while (Body) {
    ++(ctx->line_number);
    lst_format_line(Body->src_line, 0);
    Body = Body->next;
  }

  ctx->line_number = old_line_number;
}
Vorgefundene Kodierung: UTF-80