OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [Open8 Tools/] [open8_src/] [open8_as/] [pass_1.c] - Rev 210

Go to most recent revision | Compare with Previous | Blame | View Log

 
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
 
#include "defines.h"
 
#include "include_file.h"
#include "parse.h"
#include "pass_1.h"
#include "pass_2.h"
#include "stack.h"
 
#define MAXADDRESS 0x10000
 
int org_defined = 1, background_defined = 0, background_size = 0;
int bank = 0, bank_defined = 0;
int rombanks = 0, rombanks_defined = 0, romtype = 0, max_address=0;
int rambanks = 0, rambanks_defined = 0;
int emptyfill, emptyfill_defined = 0;
int section_status = OFF, section_id = 1, line_count_status = ON;
int d, i, ind, inz, ifdef = 0, t, slots_amount = 1;
int memorymap_defined = 0;
int defaultslot_defined = 0, defaultslot, current_slot = 0;
int banksize_defined = 1, banksize = MAXADDRESS ;
int rombankmap_defined = 0, *banks = NULL, *bankaddress = NULL;
int bankheader_status = OFF;
int macro_active = 0;
int repeat_active = 0;
int smc_defined = 0;
int asciitable_defined = 0;
int block_status = 0;
unsigned char asciitable[256];
 
int unfolded_size;
char *unfolded_buffer = NULL;
FILE *fold_out;
 
extern struct stack *stacks_header_first, *stacks_header_last;
extern int stacks_inside, stacks_outside;
int stack_inserted;
 
extern int operand_hint;
 
char tmp[4096], emsg[256];
char *tmp_bf;
char cp[256];
 
unsigned char *rom_banks = NULL, *rom_banks_usage_table = NULL;
 
struct export_def *export_first = NULL, *export_last = NULL;
struct optcode *opt_tmp;
struct definition *defines = NULL, *tmp_def, *next_def;
struct macro_static *macros_first = NULL, *macros_last;
struct section_def *sections_first = NULL, *sections_last = NULL, *sec_tmp, *sec_next;
struct macro_runtime *macro_stack = NULL, *macro_runtime_current = NULL;
struct repeat_runtime *repeat_stack = NULL;
struct slot slots[256];
struct structure *structures_first = NULL;
struct filepointer *filepointers = NULL;
 
extern char *buffer, *unfolded_buffer, label[MAX_NAME_LENGTH], *include_dir, *full_name;
extern int size, unfolded_size, input_number_error_msg, verbose_mode, output_format, open_files;
extern int stack_id, latest_stack, ss, commandline_parsing, newline_beginning;
extern int extra_definitions, string_size, input_float_mode;
extern int include_dir_size, parse_floats, listfile_data, quiet;
extern FILE *file_out_ptr;
extern double flo;
extern char *final_name;
extern struct active_file_info *active_file_info_first, *active_file_info_last, *active_file_info_tmp;
extern struct file_name_info *file_name_info_first, *file_name_info_last, *file_name_info_tmp;
extern struct stack *stacks_first, *stacks_tmp, *stacks_last;
 
int opcode_n[256], opcode_p[256];
int macro_stack_size = 0, repeat_stack_size = 0;
 
int xbit_size = 0;
int accu_size = 8, index_size = 8;
 
 
#include "opcodes_v8urisc.c"
#include "opcodes_v8urisc_tables.c"
 
 
int strcaselesscmp(char *s1, char *s2) {
 
  if (s1 == NULL || s2 == NULL)
    return 0;
 
  while (*s1 != 0) {
    if (toupper((int)*s1) != toupper((int)*s2))
      return 1;
    s1++;
    s2++;
  }
 
  if (*s2 != 0)
    return 1;
 
  return 0;
}
 
 
int pass_1(void) {
 
  struct macro_runtime *mrc = NULL;
  struct macro_static *m = NULL;
  int o, p, q;
 
 
 
  if (verbose_mode == ON)
    printf("Pass 1...\n");
 
  /* mark all slots as empty */
  for (q = 0; q < 256; q++)
    slots[q].size = 0;
 
  /* except for the first - lay down some good defaults */
  slots[0].size = MAXADDRESS; /* default size */
 
  /* set up a default ROMBANKMAP */
  int b = 0, a = 0, bt = 0, bt_defined = 0, x, bs = 0, bs_defined = 0;
 
  //BANKSTOTAL
  o = 0; d = 1;
  banks = malloc(sizeof(int) * d);
  bankaddress = malloc(sizeof(int) * d);
  if (banks == NULL || bankaddress == NULL) {
    print_error("Out of memory while allocating ROM banks.\n", ERROR_DIR);
    return FAILED;
  }
  bt = d;
  bt_defined = 1;
  d=MAXADDRESS;
  bs = d;
  bs_defined = 1;
  d=1;
  for (x = 0; x < d; x++) {
    banks[o] = bs;
    bankaddress[o] = a;
    o++;
    b++;
    a += bs;
  }
  rombanks = b;
  rombanks_defined = 1;
  for (max_address = 0, q = 0; q < rombanks; q++)
    max_address += banks[q];
 
  if (rom_banks != NULL)
    free(rom_banks);
  if (rom_banks_usage_table != NULL)
    free(rom_banks_usage_table);
 
  rom_banks = malloc(sizeof(unsigned char) * max_address);
  rom_banks_usage_table = malloc(sizeof(unsigned char) * max_address);
  if (rom_banks == NULL || rom_banks_usage_table == NULL) {
    print_error("Out of memory while allocating ROM banks.\n", ERROR_DIR);
    return FAILED;
  }
 
  memset(rom_banks_usage_table, 0, sizeof(unsigned char) * max_address);
  rombankmap_defined = 1;
  bank=0;
  bank_defined=1;
 
 
 
 
 
 
  /* start from the very first character */
  i = 0;
 
  /* output the file id */
  fprintf(file_out_ptr, "f%d ", active_file_info_tmp->filename_id);
 
  /* BANK 0 SLOT 0 ORG 0 */
  if (output_format != OUTPUT_LIBRARY)
    fprintf(file_out_ptr, "B%d %d O%d", 0, 0, 0);
 
  while ((t = get_next_token()) == SUCCEEDED) {
    q = evaluate_token();
 
    if (q == SUCCEEDED)
      continue;
    else if (q == EVALUATE_TOKEN_EOP)
      return SUCCEEDED;
    else if (q == EVALUATE_TOKEN_NOT_IDENTIFIED) {
      /* check if it is of the form "LABEL:XYZ" */
      for (q = 0; q < ss; q++)
	if (tmp[q] == ':')
	  break;
 
      /* is it a macro */
      if (q == ss) {
	m = macros_first;
	while (m != NULL) {
	  if (strcmp(m->name, tmp) == 0)
	    break;
	  m = m->next;
	}
      }
 
      /* it is a label after all */
      if (q != ss || newline_beginning == ON) {
	tmp[q] = 0;
 
	/* reset the flag as there can be only one label / line */
	newline_beginning = OFF;
 
	if (output_format == OUTPUT_LIBRARY && section_status == OFF) {
	  print_error("All labels must be inside sections when compiling a library.\n", ERROR_LOG);
	  return FAILED;
	}
	if (org_defined == 0) {
	  sprintf(emsg, "\"%s\" needs a position in memory.\n", tmp);
	  print_error(emsg, ERROR_LOG);
	  return FAILED;
	}
	if (ss > MAX_NAME_LENGTH - 1) {
	  sprintf(emsg, "The label \"%s\" is too long. Max label length is %d bytes.\n", tmp, MAX_NAME_LENGTH - 1);
	  print_error(emsg, ERROR_NONE);
	  return FAILED;
	}
	if (bankheader_status == ON) {
	  print_error("BANKHEADER sections don't take labels.\n", ERROR_LOG);
	  return FAILED;
	}
 
	/* check out for \@-symbols */
	if (macro_active != 0) {
	  if (tmp[q - 2] == '\\' && tmp[q - 1] == '@')
	    sprintf(&tmp[q - 2], "%d%c", macro_runtime_current->macro->calls - 1, 0);
	}
 
	fprintf(file_out_ptr, "k%d L%s ", active_file_info_last->line_current, tmp);
 
	/* move to the end of the label */
	if (q != ss)
	  i -= ss - q - 1;
	else
	  i -= ss - q;
 
	continue;
      }
 
      if (m == NULL) {
	sprintf(emsg, "Unknown symbol \"%s\".\n", tmp);
	print_error(emsg, ERROR_ERR);
	return FAILED;
      }
 
      /* start running a macro... run until .ENDM */
      if (macro_active == macro_stack_size) {
 
	struct macro_runtime *mr;
 
 
	/* enlarge the macro stack */
	macro_stack_size = (macro_stack_size<<1)+2;
	mr = realloc(macro_stack, sizeof(struct macro_runtime) * macro_stack_size);
	if (mr == NULL) {
	  print_error("Out of memory error while enlarging macro stack buffer.\n", ERROR_ERR);
	  return FAILED;
	}
	macro_stack = mr;
      }
 
      mrc = &macro_stack[macro_active];
      mrc->argument_data = NULL;
 
      /* collect macro arguments */
      for (p = 0; 1; p++) {
	/* take away the white space */
	while (1) {
	  if (buffer[i] == ' ' || buffer[i] == ',')
	    i++;
	  else
	    break;
	}
 
	o = i;
	q = input_number();
	if (q == INPUT_NUMBER_EOL)
	  break;
 
	mrc->argument_data = realloc(mrc->argument_data, (p+1)*sizeof(struct macro_argument *));
	mrc->argument_data[p] = malloc(sizeof(struct macro_argument));
	if (mrc->argument_data == NULL || mrc->argument_data[p] == NULL) {
	  print_error("Out of memory error while collecting macro arguments.\n", ERROR_NONE);
	  return FAILED;
	}
 
	mrc->argument_data[p]->start = o;
	mrc->argument_data[p]->type = q;
 
	if (q == INPUT_NUMBER_ADDRESS_LABEL)
	  strcpy(mrc->argument_data[p]->string, label);
	else if (q == INPUT_NUMBER_STRING)
	  strcpy(mrc->argument_data[p]->string, label);
	else if (q == INPUT_NUMBER_STACK)
	  mrc->argument_data[p]->value = latest_stack;
	else if (q == SUCCEEDED)
	  mrc->argument_data[p]->value = d;
	else
	  return FAILED;
 
	/* do we have a name for this argument? */
	if (p < m->nargument_names) {
	  if (q == INPUT_NUMBER_ADDRESS_LABEL)
	    redefine(m->argument_names[p], 0.0, label, DEFINITION_TYPE_STRING, strlen(label));
	  else if (q == INPUT_NUMBER_STRING)
	    redefine(m->argument_names[p], 0.0, label, DEFINITION_TYPE_STRING, strlen(label));
	  else if (q == INPUT_NUMBER_STACK)
	    redefine(m->argument_names[p], (double)latest_stack, NULL, DEFINITION_TYPE_STACK, 0);
	  else if (q == SUCCEEDED)
	    redefine(m->argument_names[p], (double)d, NULL, DEFINITION_TYPE_VALUE, 0);
	}
      }
 
      macro_runtime_current = mrc;
      macro_active++;
      m->calls++;
      mrc->supplied_arguments = p;
 
      next_line();
 
      mrc->macro = m;
      mrc->macro_end = i;
      mrc->macro_end_line = active_file_info_last->line_current;
      mrc->macro_end_filename_id = active_file_info_last->filename_id;
 
      if ((extra_definitions == ON) && (active_file_info_last->filename_id != m->filename_id)) {
	redefine("WLA_FILENAME", 0.0, get_file_name(m->filename_id), DEFINITION_TYPE_STRING, strlen(get_file_name(m->filename_id)));
	redefine("wla_filename", 0.0, get_file_name(m->filename_id), DEFINITION_TYPE_STRING, strlen(get_file_name(m->filename_id)));
      }
 
      active_file_info_last->line_current = m->start_line;
      active_file_info_last->filename_id = m->filename_id;
      i = m->start;
 
      /* redefine NARGS */
      if (redefine("NARGS", (double)p, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	return FAILED;
      if (redefine("nargs", (double)p, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	return FAILED;
 
      continue;
    }
    else if (q == FAILED) {
      sprintf(emsg, "Couldn't parse \"%s\".\n", tmp);
      print_error(emsg, ERROR_ERR);
      return FAILED;
    }
    else {
      printf("PASS_1: Internal error, unknown return type %d.\n", q);
      return FAILED;
    }
  }
 
  return FAILED;
}
 
 
int evaluate_token(void) {
 
  int f, z = 0, x, y;
 
 
  /* is it a directive? */
  if (tmp[0] == '.')
    return parse_directive();
 
  /* is it a label? */
  if (tmp[ss - 1] == ':' && newline_beginning == ON) {
 
    tmp[ss - 1] = 0;
    newline_beginning = OFF;
 
    if (output_format == OUTPUT_LIBRARY && section_status == OFF) {
      print_error("All labels must be inside sections when compiling a library.\n", ERROR_LOG);
      return FAILED;
    }
    if (org_defined == 0) {
      sprintf(emsg, "\"%s\" needs a position in memory.\n", tmp);
      print_error(emsg, ERROR_LOG);
      return FAILED;
    }
    if (ss > MAX_NAME_LENGTH - 1) {
      sprintf(emsg, "The label \"%s\" is too long. Max label length is %d bytes.\n", tmp, MAX_NAME_LENGTH - 1);
      print_error(emsg, ERROR_NONE);
      return FAILED;
    }
    if (bankheader_status == ON) {
      print_error("BANKHEADER sections don't take labels.\n", ERROR_LOG);
      return FAILED;
    }
 
    /* check for \@-symbols */
    if (macro_active != 0) {
      if (tmp[ss - 3] == '\\' && tmp[ss - 2] == '@')
	sprintf(&tmp[ss - 3], "%d%c", macro_runtime_current->macro->calls - 1, 0);
    }
 
    fprintf(file_out_ptr, "k%d L%s ", active_file_info_last->line_current, tmp);
 
    return SUCCEEDED;
  }
 
  /* OPCODE? */
 
  ind = opcode_p[(unsigned int)tmp[0]];
  opt_tmp = &opt_table[ind];
 
  for (f = opcode_n[(unsigned int)tmp[0]]; f > 0; f--) {
 
    for (inz = 0, d = SUCCEEDED; inz < OP_SIZE_MAX; inz++) {
      if (tmp[inz] == 0 && opt_tmp->op[inz] == 0 && buffer[i] == 0x0A) {
	if (opt_tmp->type == 0)
	  fprintf(file_out_ptr, "d%d ", opt_tmp->hex);
	else
	  fprintf(file_out_ptr, "y%d ", opt_tmp->hex);
	return SUCCEEDED;
      }
      if (tmp[inz] == 0 && opt_tmp->op[inz] == ' ' && buffer[i] == ' ')
	break;
      if (opt_tmp->op[inz] != toupper((int)tmp[inz])) {
	d = FAILED;
	break;
      }
    }
 
    if (d == FAILED) {
      opt_tmp = &opt_table[++ind];
      continue;
    }
 
    /* beginning matches the input */
    x = inz + 1;
    inz = i + 1;
 
    /* no stack rollback */
    stack_inserted = STACK_NONE;
 
    switch (opt_tmp->type) {
 
#include "decode_v8urisc.c"
 
    }
 
    /* perform stack rollback? */
    if (stack_inserted != STACK_NONE) {
 
      struct stack *s;
 
 
      if (stack_inserted == STACK_OUTSIDE) {
	if (stacks_outside == 1) {
	  stacks_outside = 0;
	  delete_stack(stacks_first);
	  stacks_first = NULL;
	  stacks_last = NULL;
	}
	else {
	  s = stacks_first;
	  stacks_outside--;
 
	  for (y = 0; y < stacks_outside - 1; y++)
	    s = s->next;
 
	  delete_stack(s->next);
	  s->next = NULL;
	  stacks_last = s;
	}
      }
      else {
	if (stacks_inside == 1) {
	  stacks_inside = 0;
	  delete_stack(stacks_header_first);
	  stacks_header_first = NULL;
	  stacks_header_last = NULL;
	}
	else {
	  s = stacks_header_first;
	  stacks_inside--;
 
	  for (y = 0; y < stacks_inside - 1; y++)
	    s = s->next;
 
	  delete_stack(s->next);
	  s->next = NULL;
	  stacks_header_last = s;
	}
      }
    }
 
    opt_tmp = &opt_table[++ind];
  }
 
  /* allow error messages from input_numbers() */
  input_number_error_msg = YES;
 
  return EVALUATE_TOKEN_NOT_IDENTIFIED;
}
 
 
int redefine(char *name, double value, char *string, int type, int size) {
 
  struct definition *d;
 
 
  d = defines;
  while (d != NULL) {
    if (strcmp(d->alias, name) == 0)
      break;
    d = d->next;
  }
 
  /* it wasn't defined previously */
  if (d == NULL) {
    return add_a_new_definition(name, value, string, type, size);
  }
 
  d->type = type;
 
  if (type == DEFINITION_TYPE_VALUE)
    d->value = value;
  else if (type == DEFINITION_TYPE_STACK)
    d->value = value;
  else if (type == DEFINITION_TYPE_STRING) {
    memcpy(d->string, string, size);
    d->string[size] = 0;
    d->size = size;
  }
 
  return SUCCEEDED;
}
 
 
int undefine(char *name) {
 
  struct definition *d, *p;
 
 
  d = defines;
  p = NULL;
  while (d != NULL) {
    if (strcmp(name, d->alias) == 0) {
      if (p != NULL)
	p->next = d->next;
      else
	defines = d->next;
      free(d);
      return SUCCEEDED;
    }
    p = d;
    d = d->next;
  }
 
  return FAILED;
}
 
 
int add_a_new_definition(char *name, double value, char *string, int type, int size) {
 
  struct definition *d, *l;
 
 
  l = NULL;
  d = defines;
  while (d != NULL) {
    l = d;
    if (strcmp(name, d->alias) == 0) {
      sprintf(emsg, "\"%s\" was defined for the second time.\n", name);
      if (commandline_parsing == OFF)
	print_error(emsg, ERROR_DIR);
      else
	fprintf(stderr, "ADD_A_NEW_DEFINITION: %s", emsg);
      return FAILED;
    }
    d = d->next;
  }
 
  d = malloc(sizeof(struct definition));
  if (d == NULL) {
    sprintf(emsg, "Out of memory while trying to add a new definition (\"%s\").\n", name);
    if (commandline_parsing == OFF)
      print_error(emsg, ERROR_DIR);
    else
      fprintf(stderr, "ADD_A_NEW_DEFINITION: %s", emsg);
    return FAILED;
  }
 
  if (defines == NULL)
    defines = d;
  else
    l->next = d;
 
  strcpy(d->alias, name);
  d->next = NULL;
  d->type = type;
 
  if (type == DEFINITION_TYPE_VALUE)
    d->value = value;
  else if (type == DEFINITION_TYPE_STACK)
    d->value = value;
  else if (type == DEFINITION_TYPE_STRING) {
    memcpy(d->string, string, size);
    d->string[size] = 0;
    d->size = size;
  }
 
  return SUCCEEDED;
}
 
 
int localize_path(char *path) {
 
  int i;
 
 
  if (path == NULL)
    return FAILED;
 
  for (i = 0; path[i] != 0; i++) {
#if defined(AMIGA) || defined(UNIX)
    /* '\' -> '/' */
    if (path[i] == '\\')
      path[i] = '/';
#else
    /* '/' -> '\' */
    if (path[i] == '/')
      path[i] = '\\';
#endif
  }
 
  return SUCCEEDED;
}
 
 
void print_error(char *error, int i) {
 
  char error_dir[] = "DIRECTIVE_ERROR:";
  char error_unf[] = "UNFOLD_ALIASES:";
  char error_num[] = "INPUT_NUMBER:";
  char error_inc[] = "INCLUDE_FILE:";
  char error_inb[] = "INCBIN_FILE:";
  char error_inp[] = "INPUT_ERROR:";
  char error_log[] = "LOGIC_ERROR:";
  char error_stc[] = "STACK_CALCULATE:";
  char error_wrn[] = "WARNING:";
  char error_err[] = "ERROR:";
  char *t = NULL;
 
 
  switch (i) {
  case ERROR_LOG:
    t = error_log;
    break;
  case ERROR_UNF:
    t = error_unf;
    break;
  case ERROR_INC:
    t = error_inc;
    break;
  case ERROR_INB:
    t = error_inb;
    break;
  case ERROR_DIR:
    t = error_dir;
    break;
  case ERROR_INP:
    t = error_inp;
    break;
  case ERROR_NUM:
    t = error_num;
    break;
  case ERROR_STC:
    t = error_stc;
    break;
  case ERROR_WRN:
    t = error_wrn;
    break;
  case ERROR_ERR:
    t = error_err;
    break;
  case ERROR_NONE:
    fprintf(stderr, "%s:%d: %s", get_file_name(active_file_info_last->filename_id), active_file_info_last->line_current, error);
    return;
  }
 
  fprintf(stderr, "%s:%d: %s %s", get_file_name(active_file_info_last->filename_id), active_file_info_last->line_current, t, error);
  return;
}
 
 
void next_line(void) {
 
  newline_beginning = ON;
 
  if (line_count_status == OFF)
    return;
 
  /* output the file number for list file structure building */
  if (listfile_data == YES)
    fprintf(file_out_ptr, "k%d ", active_file_info_last->line_current);
 
  if (active_file_info_last != NULL)
    active_file_info_last->line_current++;
}
 
 
int parse_directive(void) {
 
  char bak[256];
  int o, q;
 
 
  /* ORG */
 
  if (strcmp(cp, "ORG") == 0) {
    if (output_format == OUTPUT_LIBRARY) {
      print_error("Library files don't take .ORG definitions.\n", ERROR_DIR);
      return FAILED;
    }
    if (bank_defined == 0) {
      print_error("No .BANK is defined.\n", ERROR_LOG);
      return FAILED;
    }
    if (section_status == ON) {
      print_error("You can't issue .ORG inside a .SECTION.\n", ERROR_DIR);
      return FAILED;
    }
 
    q = input_number();
 
    if (q == FAILED)
      return FAILED;
 
    if (q != SUCCEEDED) {
      print_error(".ORG needs a positive or zero integer value.\n", ERROR_DIR);
      return FAILED;
    }
 
    org_defined = 1;
    fprintf(file_out_ptr, "O%d ", d);
    return SUCCEEDED;
  }
 
  /* ORGA */
 
  if (strcmp(cp, "ORGA") == 0) {
    if (output_format == OUTPUT_LIBRARY) {
      print_error("Library files don't take .ORGA definitions.\n", ERROR_DIR);
      return FAILED;
    }
    if (bank_defined == 0) {
      print_error("No .BANK is defined.\n", ERROR_LOG);
      return FAILED;
    }
    if (section_status == ON) {
      print_error("You can't issue .ORGA inside a .SECTION.\n", ERROR_DIR);
      return FAILED;
    }
 
    q = input_number();
 
    if (q == FAILED)
      return FAILED;
 
    if (q != SUCCEEDED) {
      print_error(".ORGA needs a positive or zero integer value.\n", ERROR_DIR);
      return FAILED;
    }
 
    org_defined = 1;
 
    ind = slots[current_slot].address;
    if (d < ind || d > (ind + slots[current_slot].size)) {
      print_error(".ORGA is outside the current SLOT.\n", ERROR_DIR);
      return FAILED;
    }
 
    fprintf(file_out_ptr, "O%d ", d - ind);
 
    return SUCCEEDED;
  }
 
  /* SLOT */
 
  if (strcmp(cp, "SLOT") == 0) {
    if (output_format == OUTPUT_LIBRARY) {
      print_error("Library files don't take .SLOT definitions.\n", ERROR_DIR);
      return FAILED;
    }
    if (section_status == ON) {
      print_error("You can't issue .SLOT inside a .SECTION.\n", ERROR_DIR);
      return FAILED;
    }
 
    q = input_number();
 
    if (q == FAILED)
      return FAILED;
 
    if (q != SUCCEEDED) {
      print_error(".SLOT needs a positive or zero integer value.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (slots[d].size == 0) {
      sprintf(emsg, "There is no SLOT number %d.\n", d);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    fprintf(file_out_ptr, "B%d %d ", bank, d);
 
    current_slot = d;
 
    return SUCCEEDED;
  }
 
  /* BANK */
 
  if (strcmp(cp, "BANK") == 0) {
    if (output_format == OUTPUT_LIBRARY) {
      print_error("Library files don't take .BANK definitions.\n", ERROR_DIR);
      return FAILED;
    }
    if (section_status == ON) {
      sprintf(emsg, "Section \"%s\" is open. Do not try to change the bank.\n", sections_last->name);
      print_error(emsg, ERROR_LOG);
      return FAILED;
    }
    if (rombanks_defined == 0 && output_format != OUTPUT_LIBRARY) {
      print_error(".ROMBANKS is not yet defined.\n", ERROR_DIR);
      return FAILED;
    }
 
    q = input_number();
 
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED || d < 0) {
      print_error(".BANK number must be zero or positive.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (rombanks <= d && output_format != OUTPUT_LIBRARY) {
      sprintf(emsg, "ROM banks == %d, selected bank %d.\n", rombanks, d);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    bank = d;
    bank_defined = 1;
 
    if (compare_next_token("SLOT", 4) == SUCCEEDED) {
      skip_next_token();
 
      q = input_number();
 
      if (q == FAILED)
	return FAILED;
      if (q != SUCCEEDED || d > 255 || d < 0) {
	print_error("SLOT needs an unsigned 8bit value as an ID.\n", ERROR_DIR);
	return FAILED;
      }
 
      if (slots[d].size == 0) {
	sprintf(emsg, "There is no SLOT number %d.\n", d);
	print_error(emsg, ERROR_DIR);
	return FAILED;
      }
 
      if (output_format != OUTPUT_LIBRARY)
	fprintf(file_out_ptr, "B%d %d ", bank, d);
 
      ind = bank;
      inz = d;
      current_slot = d;
    }
    else if (output_format != OUTPUT_LIBRARY) {
      fprintf(file_out_ptr, "B%d %d ", d, defaultslot);
      ind = d;
      inz = defaultslot;
      current_slot = defaultslot;
    }
 
    if (slots[inz].size < banks[ind]) {
      sprintf(emsg, "SLOT %d's size %d < BANK %d's size %d.\n", inz, slots[inz].size, ind, banks[ind]);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
    if (slots[inz].size > banks[ind]) {
      sprintf(emsg, "SLOT %d's size %d > BANK %d's size %d, but the bank fits inside.\n", inz, slots[inz].size, ind, banks[ind]);
      print_error(emsg, ERROR_WRN);
    }
 
    return SUCCEEDED;
  }
 
  /* DB/BYT/BYTE? */
 
  if (strcmp(cp, "DB") == 0 || strcmp(cp, "BYT") == 0 || strcmp(cp, "BYTE") == 0) {
    strcpy(bak, cp);
 
    inz = input_number();
    for (ind = 0; inz == SUCCEEDED || inz == INPUT_NUMBER_STRING || inz == INPUT_NUMBER_ADDRESS_LABEL || inz == INPUT_NUMBER_STACK; ind++) {
      if (inz == INPUT_NUMBER_STRING) {
	for (o = 0; o < string_size; o++)
	  fprintf(file_out_ptr, "d%d ", (int)label[o]);
	inz = input_number();
	continue;
      }
 
      if (inz == SUCCEEDED && (d < -127 || d > 255)) {
	sprintf(emsg, ".%s expects 8bit data, %d is out of range!\n", bak, d);
	print_error(emsg, ERROR_DIR);
	return FAILED;
      }
 
      if (inz == SUCCEEDED)
	fprintf(file_out_ptr, "d%d ", d);
      else if (inz == INPUT_NUMBER_ADDRESS_LABEL)
	fprintf(file_out_ptr, "k%d Q%s ", active_file_info_last->line_current, label);
      else if (inz == INPUT_NUMBER_STACK)
	fprintf(file_out_ptr, "c%d ", latest_stack);
 
      inz = input_number();
    }
 
    if (inz == FAILED)
      return FAILED;
 
    if (inz == INPUT_NUMBER_EOL && ind == 0) {
      sprintf(emsg, ".%s needs data.\n", bak);
      print_error(emsg, ERROR_INP);
      return FAILED;
    }
 
    if (inz == INPUT_NUMBER_EOL)
      next_line();
 
    return SUCCEEDED;
  }
 
  /* ASCTABLE/ASCIITABLE? */
  if (strcmp(cp, "ASCTABLE") == 0 || strcmp(cp, "ASCIITABLE") == 0) {
 
    int astart, aend;
 
 
    strcpy(bak, cp);
 
    /* clear the table (to the default n->n -mapping) */
    for (o = 0; o < 256; o++)
      asciitable[o] = o;
 
    /* read the entries */
    while ((ind = get_next_token()) == SUCCEEDED) {
      if (strcaselesscmp(tmp, ".ENDA") == 0)
	break;
      else if (strcaselesscmp(tmp, "MAP") == 0) {
	q = input_number();
 
	while (q == INPUT_NUMBER_EOL) {
	  next_line();
	  q = input_number();
	}
 
	if (q == FAILED)
	  return FAILED;
	if (q == SUCCEEDED && (d < 0 || d > 255)) {
	  print_error("The entry must be a positive 8bit immediate value or one letter string.\n", ERROR_DIR);
	  return FAILED;
	}
	if (q == INPUT_NUMBER_STRING) {
	  if (string_size != 1) {
	    print_error("The entry must be a positive 8bit immediate value or one letter string.\n", ERROR_DIR);
	    return FAILED;
	  }
	  else {
	    d = label[0];
	    if (d < 0)
	      d += 256;
	  }
	}
 
	astart = d;
	aend = d+1;
 
	/* do we have a range? */
	if (compare_next_token("TO", 2) == SUCCEEDED) {
	  skip_next_token();
 
	  q = input_number();
 
	  if (q == FAILED)
	    return FAILED;
	  if (q == SUCCEEDED && (d < 0 || d > 255)) {
	    print_error("The entry must be a positive 8bit immediate value or one letter string.\n", ERROR_DIR);
	    return FAILED;
	  }
	  if (q == INPUT_NUMBER_STRING) {
	    if (string_size != 1) {
	      print_error("The entry must be a positive 8bit immediate value or one letter string.\n", ERROR_DIR);
	      return FAILED;
	    }
	    else {
	      d = label[0];
	      if (d < 0)
		d += 256;
	    }
	  }
 
	  aend = d+1;
	}
 
	if (aend <= astart) {
	  print_error("The end address of the mapping must be larger than the staring address.\n", ERROR_DIR);
	  return FAILED;
	}
 
	/* skip the "=" */
	if (compare_next_token("=", 1) != SUCCEEDED) {
	  ind = FAILED;
	  break;
	}
	skip_next_token();
 
	/* read the starting address */
	q = input_number();
 
	if (q == FAILED)
	  return FAILED;
	if (q == SUCCEEDED && (d < 0 || d > 255)) {
	  print_error("The entry must be a positive 8bit immediate value or one letter string.\n", ERROR_DIR);
	  return FAILED;
	}
	if (q != SUCCEEDED) {
	  print_error("The entry must be a positive 8bit immediate value.\n", ERROR_DIR);
	  return FAILED;
	}
 
	/* build the mapping */
	for (o = astart; o < aend; o++) {
	  if (d >= 256) {
	    print_error("The mapping overflows from the ASCII table!\n", ERROR_DIR);
	    return FAILED;
	  }
	  asciitable[o] = d++;
	}
      }
      else {
	ind = FAILED;
	break;
      }
    }
 
    if (ind != SUCCEEDED) {
      sprintf(emsg, "Error in .%s data structure.\n", bak);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    asciitable_defined = 1;
 
    return SUCCEEDED;
  }
 
  /* ASC? */
  if (strcmp(cp, "ASC") == 0) {
    strcpy(bak, cp);
 
    if (asciitable_defined == 0) {
      print_error("No .ASCIITABLE defined. Using the default n->n -mapping.\n", ERROR_WRN);
      for (o = 0; o < 256; o++)
	asciitable[o] = o;
    }
 
    while (1) {
      q = input_number();
      if (q == INPUT_NUMBER_EOL) {
	next_line();
	break;
      }
 
      if (!q == INPUT_NUMBER_STRING) {
	sprintf(emsg, ".%s needs string data.\n", bak);
	print_error(emsg, ERROR_INP);
	return FAILED;
      }
 
      /* remap the data */
      for (o = 0; o < string_size; o++) {
	ind = label[o];
	if (ind < 0)
	  ind += 256;
	ind = (int)asciitable[ind];
	fprintf(file_out_ptr, "d%d ", ind);
      }
    }
 
    return SUCCEEDED;
  }
 
  /* DW/WORD? */
 
  if (strcmp(cp, "DW") == 0 || strcmp(cp, "WORD") == 0) {
    strcpy(bak, cp);
 
    inz = input_number();
    for (ind = 0; inz == SUCCEEDED || inz == INPUT_NUMBER_ADDRESS_LABEL || inz == INPUT_NUMBER_STACK; ind++) {
      if (inz == SUCCEEDED && (d < -32768 || d > 65535)) {
	sprintf(emsg, ".%s expects 16bit data, %d is out of range!\n", bak, d);
	print_error(emsg, ERROR_DIR);
	return FAILED;
      }
 
      if (inz == SUCCEEDED)
	fprintf(file_out_ptr, "y%d", d);
      else if (inz == INPUT_NUMBER_ADDRESS_LABEL)
	fprintf(file_out_ptr, "k%d r%s ", active_file_info_last->line_current, label);
      else if (inz == INPUT_NUMBER_STACK)
	fprintf(file_out_ptr, "C%d ", latest_stack);
 
      inz = input_number();
    }
 
    if (inz == FAILED)
      return FAILED;
 
    if ((inz == INPUT_NUMBER_EOL || inz == INPUT_NUMBER_STRING) && ind == 0) {
      sprintf(emsg, ".%s needs data.\n", bak);
      print_error(emsg, ERROR_INP);
      return FAILED;
    }
 
    if (inz == INPUT_NUMBER_EOL)
      next_line();
 
    return SUCCEEDED;
  }
 
  /* DSTRUCT */
 
  if (strcmp(cp, "DSTRUCT") == 0) {
 
    struct structure_item *it;
    struct structure *s;
    char iname[256];
    int c, f;
 
 
    /* get instance name */
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != INPUT_NUMBER_ADDRESS_LABEL) {
      print_error(".DSTRUCT needs a name for the instance.\n", ERROR_INP);
      return FAILED;
    }
 
    strcpy(iname, label);
 
    if (compare_next_token("INSTANCEOF", 10) == SUCCEEDED)
      skip_next_token();
 
    /* get structure name */
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != INPUT_NUMBER_ADDRESS_LABEL) {
      print_error(".DSTRUCT needs a structure name.\n", ERROR_INP);
      return FAILED;
    }
 
    /* find the structure */
    s = structures_first;
    while (s != NULL) {
      if (strcmp(label, s->name) == 0)
	break;
      s = s->next;
    }
 
    if (s == NULL) {
      sprintf(emsg, "Reference to an unidentified structure \"%s\".\n", label);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (compare_next_token("DATA", 4) == SUCCEEDED)
      skip_next_token();
 
    fprintf(file_out_ptr, "k%d L%s ", active_file_info_last->line_current, iname);
 
    /* read the data */
    it = s->items;
    inz = input_number();
    for (ind = 0; it != NULL && (inz == SUCCEEDED || inz == INPUT_NUMBER_STRING || inz == INPUT_NUMBER_ADDRESS_LABEL || inz == INPUT_NUMBER_STACK); ind++) {
 
    fprintf(file_out_ptr, "k%d L%s.%s ", active_file_info_last->line_current, iname, it->name);
 
      /* take care of the strings */
      if (inz == INPUT_NUMBER_STRING) {
	if (it->size < string_size) {
	  sprintf(emsg, "String \"%s\" doesn't fit into the %d bytes of \"%s.%s\". Discarding the overflow.\n", label, it->size, s->name, it->name);
	  print_error(emsg, ERROR_WRN);
	  c = it->size;
	}
	else
	  c = string_size;
 
	/* copy the string */
	for (o = 0; o < c; o++)
	  fprintf(file_out_ptr, "d%d ", (int)label[o]);
      }
      /* take care of the rest */
      else {
	if (it->size == 1) {
	  if ((inz == SUCCEEDED) && (d < -127 || d > 255)) {
	    sprintf(emsg, "\"%s.%s\" expects 8bit data, %d is out of range!\n", s->name, it->name, d);
	    print_error(emsg, ERROR_DIR);
	    return FAILED;
	  }
 
	  if (inz == SUCCEEDED)
	    fprintf(file_out_ptr, "d%d ", d);
	  else if (inz == INPUT_NUMBER_ADDRESS_LABEL)
	    fprintf(file_out_ptr, "k%d Q%s ", active_file_info_last->line_current, label);
	  else if (inz == INPUT_NUMBER_STACK)
	    fprintf(file_out_ptr, "c%d ", latest_stack);
 
	  o = 1;
	}
	else {
	  if (inz == SUCCEEDED && (d < -32768 || d > 65535)) {
	    sprintf(emsg, "\"%s.%s\" expects 16bit data, %d is out of range!\n", s->name, it->name, d);
	    print_error(emsg, ERROR_DIR);
	    return FAILED;
	  }
 
	  if (inz == SUCCEEDED)
	    fprintf(file_out_ptr, "y%d", d);
	  else if (inz == INPUT_NUMBER_ADDRESS_LABEL)
	    fprintf(file_out_ptr, "k%d r%s ", active_file_info_last->line_current, label);
	  else if (inz == INPUT_NUMBER_STACK)
	    fprintf(file_out_ptr, "C%d ", latest_stack);
 
	  o = 2;
	}
      }
 
      /* fill the rest with emptyfill or zero */
      if (emptyfill_defined != 0)
	f = emptyfill;
      else
	f = 0;
 
      for (; o < it->size; o++)
	fprintf(file_out_ptr, "d%d ", f);
 
      it = it->next;
      inz = input_number();
    }
 
    if (it != NULL) {
      sprintf(emsg, "\"%s\" doesn't define all the members of \"%s\".\n", iname, s->name);
      print_error(emsg, ERROR_DIR);
      return FAILED;
 
    }
 
    if (inz == INPUT_NUMBER_EOL)
      next_line();
    else {
      sprintf(emsg, "Too much data for structure \"%s\".\n", s->name);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    return SUCCEEDED;
  }
 
  /* DS/DSB? */
 
  if (strcmp(cp, "DSB") == 0 || strcmp(cp, "DS") == 0) {
    strcpy(bak, cp);
 
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED) {
      sprintf(emsg, ".%s needs size.\n", bak);
      print_error(emsg, ERROR_INP);
      return FAILED;
    }
 
    if (d < 1 || d > 65535) {
      sprintf(emsg, ".%s expects a 16bit positive integer as size, %d is out of range!\n", bak, d);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    inz = d;
 
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (!(q == SUCCEEDED || q == INPUT_NUMBER_ADDRESS_LABEL || q == INPUT_NUMBER_STACK)) {
      sprintf(emsg, ".%s needs data.\n", bak);
      print_error(emsg, ERROR_INP);
      return FAILED;
    }
 
    if (q == SUCCEEDED && (d > 255 || d < -127)) {
      sprintf(emsg, ".%s expects 8bit data, %d is out of range!\n", bak, d);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (q == SUCCEEDED)
      fprintf(file_out_ptr, "x%d %d ", inz, d);
    else if (q == INPUT_NUMBER_ADDRESS_LABEL) {
      fprintf(file_out_ptr, "k%d ", active_file_info_last->line_current);
      for (q = 0; q < inz; q++)
	fprintf(file_out_ptr, "R%s ", label);
    }
    else if (q == INPUT_NUMBER_STACK) {
      for (q = 0; q < inz; q++)
	fprintf(file_out_ptr, "c%d ", latest_stack);
    }
 
    return SUCCEEDED;
  }
 
  /* DSW? */
 
  if (strcmp(cp, "DSW") == 0) {
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED) {
      print_error(".DSW needs size.\n", ERROR_INP);
      return FAILED;
    }
 
    if (d < 1 || d > 65535) {
      sprintf(emsg, ".DSW expects a 16bit positive integer as size, %d is out of range!\n", d);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    inz = d;
 
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (!(q == SUCCEEDED || q == INPUT_NUMBER_ADDRESS_LABEL || q == INPUT_NUMBER_STACK)) {
      print_error(".DSW needs data.\n", ERROR_INP);
      return FAILED;
    }
 
    if (q == SUCCEEDED && (d < -32768 || d > 65535)) {
      sprintf(emsg, ".DSW expects 16bit data, %d is out of range!\n", d);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (q == SUCCEEDED)
      fprintf(file_out_ptr, "X%d %d ", inz, d);
    else if (q == INPUT_NUMBER_ADDRESS_LABEL) {
      fprintf(file_out_ptr, "k%d ", active_file_info_last->line_current);
      for (q = 0; q < inz; q++)
	fprintf(file_out_ptr, "r%s ", label);
    }
    else if (q == INPUT_NUMBER_STACK) {
      for (q = 0; q < inz; q++)
	fprintf(file_out_ptr, "C%d ", latest_stack);
    }
 
    return SUCCEEDED;
  }
 
  /* INCDIR */
 
  if (strcmp(cp, "INCDIR") == 0) {
 
    char *c;
 
 
    if (get_next_token() != GET_NEXT_TOKEN_STRING) {
      print_error(".INCDIR needs a directory string.\n", ERROR_DIR);
      return FAILED;
    }
 
    q = ss;
 
    /* use the default dir? */
    if (q == 0) {
      if (include_dir != NULL)
	include_dir[0] = 0;
      return SUCCEEDED;
    }
 
    /* use the given dir */
    o = strlen(tmp) + 2;
    if (o > include_dir_size) {
      c = realloc(include_dir, o);
      if (c == NULL) {
	print_error("Out of memory error.\n", ERROR_DIR);
	return FAILED;
      }
      include_dir = c;
      include_dir_size = o;
    }
 
    /* convert the path string to local enviroment */
    localize_path(tmp);
 
    strcpy(include_dir, tmp);
 
    /* terminate the string with '/' */
#ifdef MSDOS
    if (include_dir[q - 1] != '\\') {
      include_dir[q] = '\\';
      include_dir[q + 1] = 0;
    }
#else
    if (include_dir[q - 1] != '/') {
      include_dir[q] = '/';
      include_dir[q + 1] = 0;
    }
#endif
 
    return SUCCEEDED;
  }
 
  /* INCLUDE */
 
  if (strcmp(cp, "INCLUDE") == 0) {
    o = input_number();
    if (o != INPUT_NUMBER_STRING) {
      print_error(".INCLUDE needs a file name string.\n", ERROR_DIR);
      return FAILED;
    }
    if (macro_active != 0) {
      print_error("You cannot include a file inside a MACRO.\n", ERROR_DIR);
      return FAILED;
    }
 
    /* convert the path to local enviroment */
    localize_path(label);
 
    if (include_file(label) == FAILED)
      return FAILED;
 
    fprintf(file_out_ptr, "f%d ", active_file_info_tmp->filename_id);
 
    return SUCCEEDED;
  }
 
  /* INCBIN */
 
  if (strcmp(cp, "INCBIN") == 0) {
 
    int s, r;
 
 
    if (org_defined == 0 && output_format != OUTPUT_LIBRARY) {
      print_error("Before you can .INCBIN data you'll need to use ORG.\n", ERROR_LOG);
      return FAILED;
    }
 
    o = input_number();
    if (o != INPUT_NUMBER_STRING) {
      print_error(".INCBIN needs a file name string.\n", ERROR_DIR);
      return FAILED;
    }
 
    /* convert the path string to local enviroment */
    localize_path(label);
 
    if (incbin_file(label, &ind, &inz, &s, &r) == FAILED)
      return FAILED;
 
    /* D [id] [swap] [skip] [size] */
    fprintf(file_out_ptr, "D%d %d %d %d ", ind, inz, s, r);
 
    return SUCCEEDED;
  }
 
  /* OUTNAME */
 
  if (strcmp(cp, "OUTNAME") == 0) {
 
    inz = input_number();
 
    if (inz != INPUT_NUMBER_STRING) {
      print_error(".OUTNAME needs a file name string.\n", ERROR_DIR);
      return FAILED;
    }
 
    strcpy(final_name, label);
    return SUCCEEDED;
  }
 
  /* STRUCT */
 
  if (strcmp(cp, "STRUCT") == 0) {
 
    struct structure_item *si, *ss, *sl = NULL;
    struct structure *st;
    char name[512];
    int ssi = 0;
 
 
    st = malloc(sizeof(struct structure));
    if (st == NULL) {
      print_error("Out of memory while allocating a new STRUCT.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    strcpy(st->name, tmp);
 
    st->next = structures_first;
    structures_first = st;
    st->items = NULL;
 
    while (1) {
      if (get_next_token() == FAILED)
	return FAILED;
 
      /* end of STRUCT? */
      if (strcaselesscmp(tmp, ".ENDST") == 0) {
	/* create the SIZEOF-definition */
	st->size = ssi;
	sprintf(name, "_sizeof_%s", st->name);
 
	if (add_a_new_definition(name, (double)ssi, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	  return FAILED;
 
	/* create the structure definitions */
	ssi = 0;
	ss = st->items;
	while (ss != NULL) {
	  sprintf(name, "%s.%s", st->name, ss->name);
	  if (add_a_new_definition(name, (double)ssi, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	    return FAILED;
	  ssi += ss->size;
	  ss = ss->next;
	}
 
	if (st->items == NULL) {
	  sprintf(emsg, "Structure \"%s\" is empty!\n", st->name);
	  print_error(emsg, ERROR_DIR);
	  return FAILED;
	}
 
	return SUCCEEDED;
      }
 
      if (tmp[strlen(tmp) - 1] == ':')
	tmp[strlen(tmp) - 1] = 0;
 
      /* check for duplicate labels */
      ss = st->items;
      while (ss != NULL) {
	if (strcmp(ss->name, tmp) == 0) {
	  sprintf(emsg, "Duplicate label \"%s\" inside .STRUCT \"%s\".\n", tmp, st->name);
	  print_error(emsg, ERROR_DIR);
	  return FAILED;
	}
	ss = ss->next;
      }
 
      si = malloc(sizeof(struct structure_item));
      if (si == NULL) {
	print_error("Out of memory while allocating a new STRUCT.\n", ERROR_DIR);
	return FAILED;
      }
      si->next = NULL;
      strcpy(si->name, tmp);
 
      if (st->items == NULL)
	st->items = si;
      if (sl != NULL)
	sl->next = si;
      sl = si;
 
      /* get the item type */
      if (get_next_token() == FAILED)
	return FAILED;
 
      if (strcaselesscmp(tmp, "DB") == 0 || strcaselesscmp(tmp, "BYT") == 0 || strcaselesscmp(tmp, "BYTE") == 0)
	si->size = 1;
      else if (strcaselesscmp(tmp, "DW") == 0 || strcaselesscmp(tmp, "WORD") == 0)
	si->size = 2;
      else if (strcaselesscmp(tmp, "DS") == 0 || strcaselesscmp(tmp, "DSB") == 0) {
	q = input_number();
	if (q == FAILED)
	  return FAILED;
	if (q != SUCCEEDED) {
	  print_error("DS/DSB needs size.\n", ERROR_DIR);
	  return FAILED;
	}
	si->size = d;
      }
      else if (strcaselesscmp(tmp, "DSW") == 0) {
	q = input_number();
	if (q == FAILED)
	  return FAILED;
	if (q != SUCCEEDED) {
	  print_error("DSW needs size.\n", ERROR_DIR);
	  return FAILED;
	}
	si->size = d*2;
      }
      else if (tmp[0] == '.')
	continue;
      else {
	sprintf(emsg, "Unexpected symbol \"%s\" in .STRUCT.\n", tmp);
	print_error(emsg, ERROR_DIR);
	return FAILED;
      }
      ssi += si->size;
    }
 
    return FAILED;
  }
 
  /* RAMSECTION */
 
  if (strcmp(cp, "RAMSECTION") == 0) {
 
    char namebak[256];
 
 
    if (output_format == OUTPUT_LIBRARY) {
      print_error("Libraries don't take RAMSECTIONs.\n", ERROR_DIR);
      return FAILED;
    }
    if (section_id > 255) {
      print_error("Out of section numbers. Please start a new file.\n", ERROR_DIR);
      return FAILED;
    }
    if (section_status == ON) {
      sprintf(emsg, "There is already an open section called \"%s\".", sections_last->name);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    sec_tmp = calloc(sizeof(struct section_def), 1);
    if (sec_tmp == NULL) {
      sprintf(emsg, "Out of memory while allocating room for a new RAMSECTION \"%s\".\n", tmp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    sec_tmp->listfile_items = 0;
    sec_tmp->listfile_ints = NULL;
    sec_tmp->listfile_cmds = NULL;
    sec_tmp->maxsize_status = OFF;
    sec_tmp->status = SECTION_STATUS_RAM;
    sec_tmp->alive = ON;
    sec_tmp->data = NULL;
    sec_tmp->filename_id = active_file_info_last->filename_id;
    sec_tmp->id = section_id;
    sec_tmp->alignment = 1;
    sec_tmp->advance_org = YES;
    section_id++;
 
    strcpy(sec_tmp->name, tmp);
    sec_tmp->next = NULL;
 
    /* look for duplicate sections */
    sec_next = sections_first;
    while (sec_next != NULL) {
      if (strcmp(sec_next->name, tmp) == 0) {
	sprintf(emsg, "SECTION \"%s\" was defined for the second time.\n", tmp);
	print_error(emsg, ERROR_DIR);
	free(sec_tmp);
	return FAILED;
      }
      sec_next = sec_next->next;
    }
 
    if (sections_first == NULL) {
      sections_first = sec_tmp;
      sections_last = sec_tmp;
    }
    else {
      sections_last->next = sec_tmp;
      sections_last = sec_tmp;
    }
 
    /* check for optional BANK */
    if (compare_next_token("BANK", 4) != SUCCEEDED)
      sec_tmp->bank = 0;
    else {
      skip_next_token();
 
      q = input_number();
 
      if (q == FAILED)
	return FAILED;
      if (q != SUCCEEDED || d < 0) {
	print_error("BANK number must be zero or positive.\n", ERROR_DIR);
	return FAILED;
      }
 
      if (rombanks <= d && output_format != OUTPUT_LIBRARY) {
	sprintf(emsg, "ROM banks == %d, selected bank %d.\n", rombanks, d);
	print_error(emsg, ERROR_DIR);
	return FAILED;
      }
 
      sec_tmp->bank = d;
    }
 
    if (compare_next_token("SLOT", 4) != SUCCEEDED) {
      if (get_next_token() == FAILED)
	return FAILED;
      sprintf(emsg, "Unknown symbol \"%s\".\n", tmp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    skip_next_token();
 
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED || d > 255 || d < 0) {
      print_error(".RAMSECTION needs an unsigned 8bit value as the SLOT number.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (slots[d].size == 0) {
      sprintf(emsg, "There is no SLOT number %d.\n", d);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    sec_tmp->slot = d;
    fprintf(file_out_ptr, "S%d ", sec_tmp->id);
 
    /* ram section - read labels */
    if (sec_tmp->status == SECTION_STATUS_RAM) {
      while ((t = get_next_token()) != FAILED) {
	if (strcaselesscmp(tmp, ".ENDS") == 0) {
	  fprintf(file_out_ptr, "s ");
	  section_status = OFF;
	  return SUCCEEDED;
	}
	if (tmp[strlen(tmp) - 1] == ':')
	  tmp[strlen(tmp) - 1] = 0;
	fprintf(file_out_ptr, "k%d L%s ", active_file_info_last->line_current, tmp);
	strcpy(namebak, tmp);
	if (get_next_token() == FAILED)
	  return FAILED;
	if (strcaselesscmp(tmp, "DB") == 0 || strcaselesscmp(tmp, "BYT") == 0 || strcaselesscmp(tmp, "BYTE") == 0)
	  fprintf(file_out_ptr, "d0 ");
	else if (strcaselesscmp(tmp, "DW") == 0 || strcaselesscmp(tmp, "WORD") == 0)
	  fprintf(file_out_ptr, "y0 ");
	else if (strcaselesscmp(tmp, "DS") == 0 || strcaselesscmp(tmp, "DSB") == 0) {
	  q = input_number();
	  if (q == FAILED)
	    return FAILED;
	  if (q != SUCCEEDED) {
	    print_error("DS/DSB needs size.\n", ERROR_DIR);
	    return FAILED;
	  }
	  fprintf(file_out_ptr, "x%d 0 ", d);
	}
	else if (strcaselesscmp(tmp, "DSW") == 0) {
	  q = input_number();
	  if (q == FAILED)
	    return FAILED;
	  if (q != SUCCEEDED) {
	    print_error("DSW needs size.\n", ERROR_DIR);
	    return FAILED;
	  }
	  fprintf(file_out_ptr, "x%d 0 ", d*2);
	}
	/* it's an instance of a structure! */
	else if (strcaselesscmp(tmp, "INSTANCEOF") == 0) {
 
	  struct structure_item *si;
	  struct structure *st;
	  int g;
 
 
	  if (get_next_token() == FAILED)
	    return FAILED;
 
	  st = structures_first;
	  while (st != NULL) {
	    if (strcmp(st->name, tmp) == 0)
	      break;
	    st = st->next;
	  }
 
	  if (st == NULL) {
	    sprintf(emsg, "No STRUCT named \"%s\" available.\n", tmp);
	    print_error(emsg, ERROR_DIR);
	    return FAILED;
	  }
 
	  /* amount of structures? */
	  inz = input_number();
	  if (inz == SUCCEEDED && d > 1)
	    fprintf(file_out_ptr, "k%d L%s.1 ", active_file_info_last->line_current, namebak);
 
	  /* generate labels */
	  si = st->items;
	  while (si != NULL) {
	    if (inz == SUCCEEDED && d > 1)
	      fprintf(file_out_ptr, "k%d L%s.%s L%s.1.%s x%d 0 ", active_file_info_last->line_current, namebak, si->name, namebak, si->name, si->size);
	    else
	      fprintf(file_out_ptr, "k%d L%s.%s x%d 0 ", active_file_info_last->line_current, namebak, si->name, si->size);
	    si = si->next;
	  }
 
	  if (inz == INPUT_NUMBER_EOL)
	    next_line();
	  else if (inz == SUCCEEDED) {
	    if (d < 1) {
	      print_error("The amount of structures must be greater than 0.\n", ERROR_DIR);
	      return FAILED;
	    }
 
	    g = 2;
	    while (d > 1) {
	      si = st->items;
	      fprintf(file_out_ptr, "k%d L%s.%d ", active_file_info_last->line_current, namebak, g);
	      while (si != NULL) {
		fprintf(file_out_ptr, "k%d L%s.%d.%s x%d 0 ", active_file_info_last->line_current, namebak, g, si->name, si->size);
		si = si->next;
	      }
	      g++;
	      d--;
	    }
	  }
	  else {
	    if (inz == INPUT_NUMBER_STRING)
	      sprintf(emsg, "Expected the amount of structures, got \"%s\" instead.\n", label);
	    else
	      sprintf(emsg, "Expected the amount of structures.\n");
	    print_error(emsg, ERROR_DIR);
	    return FAILED;
	  }
	}
	else if (tmp[0] == '.' && strcaselesscmp(tmp, ".ENDS") != 0)
	  continue;
	else {
	  sprintf(emsg, "Unexpected symbol \"%s\".\n", tmp);
	  print_error(emsg, ERROR_DIR);
	  return FAILED;
	}
      }
      return FAILED;
    }
 
    return SUCCEEDED;
  }
 
  /* SECTION */
 
  if (strcmp(cp, "SECTION") == 0) {
 
    int l, m;
 
 
    if (section_id > 255) {
      print_error("Out of section numbers. Please start a new file.\n", ERROR_DIR);
      return FAILED;
    }
    if (section_status == ON) {
      sprintf(emsg, "There is already an open section called \"%s\".", sections_last->name);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
    else if (output_format != OUTPUT_LIBRARY && bank_defined == 0) {
      print_error(".SECTION requires a predefined bank.\n", ERROR_DIR);
      return FAILED;
    }
    else if (output_format != OUTPUT_LIBRARY && org_defined == 0) {
      print_error(".SECTION requires a starting address for positioning.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    /* every library section starts @ the beginning of the bank */
    if (output_format == OUTPUT_LIBRARY)
      org_defined = 1;
 
    sec_tmp = calloc(sizeof(struct section_def), 1);
    if (sec_tmp == NULL) {
      sprintf(emsg, "Out of memory while allocating room for a new SECTION \"%s\".\n", tmp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    sec_tmp->listfile_items = 0;
    sec_tmp->listfile_ints = NULL;
    sec_tmp->listfile_cmds = NULL;
    sec_tmp->maxsize_status = OFF;
    sec_tmp->data = NULL;
    sec_tmp->alignment = 1;
    sec_tmp->advance_org = YES;
 
    /* check if the section size is supplied inside the name */
    l = strlen(tmp) - 1;
 
    for (; l >= 0 && tmp[l] != '_'; l--);
 
    if (tmp[l] == '_') {
      l++;
      if (tmp[l] == '$') {
	for (l++, m = 0; tmp[l] != 0; l++) {
	  if (tmp[l] >= '0' && tmp[l] <= '9')
	    m = (m << 4) + tmp[l] - '0';
	  else if (tmp[l] >= 'a' && tmp[l] <= 'f')
	    m = (m << 4) + tmp[l] - 'a' + 10;
	  else if (tmp[l] >= 'A' && tmp[l] <= 'F')
	    m = (m << 4) + tmp[l] - 'A' + 10;
	  else
	    break;
	}
 
	if (tmp[l] == 0) {
	  sec_tmp->maxsize_status = ON;
	  sec_tmp->maxsize = m;
	}
      }
      else if (tmp[l] >= '0' && tmp[l] <= '9') {
	for (m = 0; tmp[l] != 0; l++) {
	  if (tmp[l] >= '0' && tmp[l] <= '9')
	    m = (m * 10) + tmp[l] - '0';
	  else
	    break;
	}
 
	if (tmp[l] == 0) {
	  sec_tmp->maxsize_status = ON;
	  sec_tmp->maxsize = m;
	}
      }
    }
 
    if (strcmp(tmp, "BANKHEADER") == 0) {
      if (output_format == OUTPUT_LIBRARY) {
	print_error("Library files don't take bank header sections.\n", ERROR_DIR);
	return FAILED;
      }
      sec_next = sections_first;
      while (sec_next != NULL) {
	if (strcmp(sec_next->name, tmp) == 0 && sec_next->bank == bank) {
	  sprintf(emsg, "BANKHEADER section was defined for the second time for bank %d.\n", bank);
	  print_error(emsg, ERROR_DIR);
	  return FAILED;
	}
	sec_next = sec_next->next;
      }
    }
    else {
      sec_next = sections_first;
      while (sec_next != NULL) {
	if (strcmp(sec_next->name, tmp) == 0) {
	  sprintf(emsg, "SECTION \"%s\" was defined for the second time.\n", tmp);
	  print_error(emsg, ERROR_DIR);
	  free(sec_tmp);
	  return FAILED;
	}
	sec_next = sec_next->next;
      }
    }
 
    strcpy(sec_tmp->name, tmp);
    sec_tmp->next = NULL;
 
    if (sections_first == NULL) {
      sections_first = sec_tmp;
      sections_last = sec_tmp;
    }
    else {
      sections_last->next = sec_tmp;
      sections_last = sec_tmp;
    }
 
    /* the size of the section? */
    if (compare_next_token("SIZE", 4) == SUCCEEDED) {
      if (sec_tmp->maxsize_status == ON) {
	print_error("The size of the section has already been defined.\n", ERROR_DIR);
	return FAILED;
      }
 
      if (skip_next_token() == FAILED)
	return FAILED;
 
      inz = input_number();
      if (inz != SUCCEEDED) {
	print_error("Could not parse the size.\n", ERROR_DIR);
	return FAILED;
      }
 
      sec_tmp->maxsize_status = ON;
      sec_tmp->maxsize = d;
    }
 
    /* align the section? */
    if (compare_next_token("ALIGN", 5) == SUCCEEDED) {
      if (skip_next_token() == FAILED)
	return FAILED;
 
      inz = input_number();
      if (inz != SUCCEEDED) {
	print_error("Could not parse the section alignment.\n", ERROR_DIR);
	return FAILED;
      }
 
      sec_tmp->alignment = d;
    }
 
    /* the type of the section */
    if (compare_next_token("FORCE", 5) == SUCCEEDED) {
      if (output_format == OUTPUT_LIBRARY) {
	print_error("Libraries don't take FORCE sections.\n", ERROR_DIR);
	return FAILED;
      }
      sec_tmp->status = SECTION_STATUS_FORCE;
      if (skip_next_token() == FAILED)
	return FAILED;
    }
    else if (compare_next_token("FREE", 4) == SUCCEEDED) {
      sec_tmp->status = SECTION_STATUS_FREE;
      if (skip_next_token() == FAILED)
	return FAILED;
    }
    else if (compare_next_token("SUPERFREE", 9) == SUCCEEDED) {
      sec_tmp->status = SECTION_STATUS_SUPERFREE;
      if (skip_next_token() == FAILED)
	return FAILED;
    }
    else if (compare_next_token("SEMIFREE", 8) == SUCCEEDED) {
      if (output_format == OUTPUT_LIBRARY) {
	print_error("Libraries don't take SEMIFREE sections.\n", ERROR_DIR);
	return FAILED;
      }
      sec_tmp->status = SECTION_STATUS_SEMIFREE;
      if (skip_next_token() == FAILED)
	return FAILED;
    }
    else if (compare_next_token("OVERWRITE", 9) == SUCCEEDED) {
      if (output_format == OUTPUT_LIBRARY) {
	print_error("Libraries don't take OVERWRITE sections.\n", ERROR_DIR);
	return FAILED;
      }
      sec_tmp->status = SECTION_STATUS_OVERWRITE;
      if (skip_next_token() == FAILED)
	return FAILED;
    }
    else
      sec_tmp->status = SECTION_STATUS_FREE;
 
    /* return the org after the section? */
    if (compare_next_token("RETURNORG", 9) == SUCCEEDED) {
      if (skip_next_token() == FAILED)
	return FAILED;
 
      sec_tmp->advance_org = NO;
    }
 
    /* bankheader section? */
    if (strcmp(sec_tmp->name, "BANKHEADER") == 0) {
      sec_tmp->status = SECTION_STATUS_HEADER;
      bankheader_status = ON;
    }
 
    sec_tmp->id = section_id;
    sec_tmp->alive = ON;
    sec_tmp->filename_id = active_file_info_last->filename_id;
    sec_tmp->bank = bank;
    section_id++;
    section_status = ON;
    fprintf(file_out_ptr, "S%d ", sec_tmp->id);
 
    return SUCCEEDED;
  }
 
  /* ELSE */
 
  if (strcmp(cp, "ELSE") == 0) {
 
    int m, r;
 
 
    if (ifdef == 0) {
      print_error("There must be .IFxxx before .ELSE.\n", ERROR_DIR);
      return FAILED;
    }
 
    /* find the next compiling point */
    r = 1;
    m = macro_active;
    /* disable macro decoding */
    macro_active = 0;
    while (get_next_token() != FAILED) {
      if (tmp[0] == '.') {
	if (strcmp(cp, "ENDIF") == 0)
	  r--;
	if (strcmp(cp, "E") == 0)
	  break;
	if (strcmp(cp, "IFDEF") == 0 || strcmp(cp, "IFNDEF") == 0 || strcmp(cp, "IFGR") == 0 || strcmp(cp, "IFLE") == 0 || strcmp(cp, "IFEQ") == 0 ||
	    strcmp(cp, "IFNEQ") == 0 || strcmp(cp, "IFDEFM") == 0 || strcmp(cp, "IFNDEFM") == 0 || strcmp(cp, "IF") == 0 || strcmp(cp, "IFEXISTS") == 0 ||
	    strcmp(cp, "IFGREQ") == 0 || strcmp(cp, "IFLEEQ") == 0)
	  r++;
      }
      if (r == 0) {
	ifdef--;
	macro_active = m;
	return SUCCEEDED;
      }
    }
 
    print_error(".ELSE must end to .ENDIF.\n", ERROR_DIR);
    return FAILED;
  }
 
  /* ENDIF */
 
  if (strcmp(cp, "ENDIF") == 0) {
 
    if (ifdef == 0) {
      print_error(".ENDIF was given before any .IF directive.\n", ERROR_DIR);
      return FAILED;
    }
 
    ifdef--;
    return SUCCEEDED;
  }
 
  /* IFDEF */
 
  if (strcmp(cp, "IFDEF") == 0) {
 
    struct definition *d;
 
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    d = defines;
    while (d != NULL) {
      if (strcmp(tmp, d->alias) == 0) {
	ifdef++;
	return SUCCEEDED;
      }
      d = d->next;
    }
 
    return find_next_point("IFDEF");
  }
 
  /* IF */
 
  if (strcmp(cp, "IF") == 0) {
 
    char k[256];
    int y, o, s;
 
 
    q = input_number();
    if (q != SUCCEEDED && q != INPUT_NUMBER_STRING) {
      sprintf(emsg, ".IF needs immediate data.\n");
      print_error(emsg, ERROR_INP);
      return FAILED;
    }
 
    strncpy(k, label, 255);
    k[255] = 0;
    y = d;
    s = q;
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    if (strcmp(tmp, "<") == 0)
      o = 0;
    else if (strcmp(tmp, ">") == 0)
      o = 1;
    else if (strcmp(tmp, "==") == 0)
      o = 2;
    else if (strcmp(tmp, "!=") == 0)
      o = 3;
    else if (strcmp(tmp, ">=") == 0)
      o = 4;
    else if (strcmp(tmp, "<=") == 0)
      o = 5;
    else {
      print_error(".IF needs an operator. Supported operators are '<', '>', '>=', '<=', '!=' and '=='.\n", ERROR_INP);
      return FAILED;
    }
 
    q = input_number();
    if (q != SUCCEEDED && q != INPUT_NUMBER_STRING) {
      sprintf(emsg, ".IF needs immediate data.\n");
      print_error(emsg, ERROR_INP);
      return FAILED;
    }
 
    /* different types? */
    if (s != q) {
      print_error("Cannot compare strings with immediate values.\n", ERROR_INP);
      return FAILED;
    }
 
    /* values? */
    if (s == SUCCEEDED) {
      if ((o == 0 && y < d) || (o == 1 && y > d) || (o == 2 && y == d) || (o == 3 && y != d) || (o == 4 && y >= d) || (o == 5 && y <= d))
	q = SUCCEEDED;
      else
	q = FAILED;
    }
    /* strings? */
    else {
      if ((o == 0 && strcmp(k, label) < 0) || (o == 1 && strcmp(k, label) > 0) || (o == 2 && strcmp(k, label) == 0) || (o == 3 && strcmp(k, label) != 0) || (o == 4 && strcmp(k, label) >= 0) || (o == 5 && strcmp(k, label) <= 0))
	q = SUCCEEDED;
      else
	q = FAILED;
    }
 
    if (q == SUCCEEDED) {
      ifdef++;
      return SUCCEEDED;
    }
    else
      return find_next_point("IF");
  }
 
  /* IFGR/IFLE/IFEQ/IFNEQ/IFGREQ/IFLEEQ */
 
  if (strcmp(cp, "IFGR") == 0 || strcmp(cp, "IFLE") == 0 || strcmp(cp, "IFEQ") == 0 || strcmp(cp, "IFNEQ") == 0 || strcmp(cp, "IFGREQ") == 0 || strcmp(cp, "IFLEEQ") == 0) {
 
    char k[256];
    int y, o, s;
 
 
    strcpy(bak, cp);
 
    if (strcmp(&cp[2], "LE") == 0)
      o = 0;
    else if (strcmp(&cp[2], "GR") == 0)
      o = 1;
    else if (strcmp(&cp[2], "EQ") == 0)
      o = 2;
    else if (strcmp(&cp[2], "NEQ") == 0)
      o = 3;
    else if (strcmp(&cp[2], "GREQ") == 0)
      o = 4;
    else
      o = 5;
 
    q = input_number();
    if (q != SUCCEEDED && q != INPUT_NUMBER_STRING) {
      sprintf(emsg, ".%s needs immediate data.\n", bak);
      print_error(emsg, ERROR_INP);
      return FAILED;
    }
 
    strncpy(k, label, 255);
    k[255] = 0;
    y = d;
    s = q;
 
    q = input_number();
    if (q != SUCCEEDED && q != INPUT_NUMBER_STRING) {
      sprintf(emsg, ".%s needs immediate data.\n", bak);
      print_error(emsg, ERROR_INP);
      return FAILED;
    }
 
    /* different types? */
    if (s != q) {
      print_error("Cannot compare strings with immediate values.\n", ERROR_INP);
      return FAILED;
    }
 
    /* values? */
    if (s == SUCCEEDED) {
      if ((o == 0 && y < d) || (o == 1 && y > d) || (o == 2 && y == d) || (o == 3 && y != d) || (o == 4 && y >= d) || (o == 5 && y <= d))
	q = SUCCEEDED;
      else
	q = FAILED;
    }
    /* strings? */
    else {
      if ((o == 0 && strcmp(k, label) < 0) || (o == 1 && strcmp(k, label) > 0) || (o == 2 && strcmp(k, label) == 0) || (o == 3 && strcmp(k, label) != 0) || (o == 4 && strcmp(k, label) >= 0) || (o == 5 && strcmp(k, label) <= 0))
	q = SUCCEEDED;
      else
	q = FAILED;
    }
 
    if (q == SUCCEEDED) {
      ifdef++;
      return SUCCEEDED;
    }
    else {
      strcpy(k, cp);
      return find_next_point(k);
    }
  }
 
  /* IFEXISTS */
 
  if (strcmp(cp, "IFEXISTS") == 0) {
 
    FILE *f;
 
 
    inz = input_number();
 
    if (inz != INPUT_NUMBER_STRING) {
      print_error(".IFEXISTS needs a file name string.\n", ERROR_DIR);
      return FAILED;
    }
 
    f = fopen(label, "r");
    if (f == NULL)
      return find_next_point("IFEXISTS");
 
    fclose(f);
    ifdef++;
 
    return SUCCEEDED;
  }
 
  /* IFNDEF */
 
  if (strcmp(cp, "IFNDEF") == 0) {
 
    struct definition *d;
 
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    d = defines;
    while (d != NULL) {
      if (strcmp(tmp, d->alias) == 0) {
	strcpy(emsg, cp);
	return find_next_point(emsg);
      }
      d = d->next;
    }
 
    ifdef++;
    return SUCCEEDED;
  }
 
  /* IFDEFM/IFNDEFM */
 
  if (strcmp(cp, "IFDEFM") == 0 || strcmp(cp, "IFNDEFM") == 0) {
 
    int k, o;
    char e;
 
 
    strcpy(bak, cp);
 
    if (macro_active == 0) {
      sprintf(emsg, ".%s can be only used inside a macro.\n", bak);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (cp[2] == 'N')
      o = 0;
    else
      o = 1;
 
    for (; i < size; i++) {
 
      if (buffer[i] == 0x0A)
	break;
      else if (buffer[i] == '\\') {
	e = buffer[++i];
	if (e >= '0' && e <= '9') {
	  d = (e - '0') * 10;
	  for (k = 2; k < 8; k++, d *= 10) {
	    e = buffer[++i];
	    if (e >= '0' && e <= '9')
	      d += e - '0';
	    else
	      break;
	  }
 
	  d /= 10;
	  if ((o == 0 && macro_runtime_current->supplied_arguments < d) ||
	      (o == 1 && macro_runtime_current->supplied_arguments >= d)) {
	    ifdef++;
	    return SUCCEEDED;
	  }
	  else {
	    strcpy(emsg, cp);
	    return find_next_point(emsg);
	  }
	}
	break;
      }
    }
 
    sprintf(emsg, ".%s needs an argument.\n", bak);
    print_error(emsg, ERROR_DIR);
    return FAILED;
  }
 
  /* FOPEN */
 
  if (strcmp(cp, "FOPEN") == 0) {
 
    struct filepointer *f;
    char *c;
 
 
    o = input_number();
    if (o != INPUT_NUMBER_STRING) {
      print_error(".FOPEN needs a file name string.\n", ERROR_DIR);
      return FAILED;
    }
 
    /* convert the path to local enviroment */
    localize_path(label);
 
    c = malloc(strlen(label) + 1);
    if (c == NULL) {
      print_error("Out of memory error.\n", ERROR_DIR);
      return FAILED;
    }
    strcpy(c, label);
 
    /* get the file pointer name */
    if (get_next_token() == FAILED)
      return FAILED;
 
    /* is it defined already? */
    f = filepointers;
    while (f != NULL) {
      if (strcmp(tmp, f->name) == 0)
	break;
      f = f->next;
    }
 
    if (f != NULL) {
      /* it exists already! close the old handle and open the new one. */
      if (f->f != NULL) {
	fclose(f->f);
	f->f = NULL;
      }
      if (f->filename != NULL) {
	free(f->filename);
	f->filename = NULL;
      }
    }
    else {
      /* allocate a new filepointer */
      f = malloc(sizeof(struct filepointer));
      if (f == NULL) {
	print_error("Out of memory error.\n", ERROR_DIR);
	return FAILED;
      }
 
      f->f = NULL;
      f->filename = NULL;
      f->next = filepointers;
      filepointers = f;
    }
 
    f->filename = c;
    strcpy(f->name, tmp);
 
    /* open the file */
    f->f = fopen(f->filename, "rb");
    if (f->f == NULL) {
      sprintf(emsg, "Error opening file \"%s\" for reading.\n", f->filename);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    return SUCCEEDED;
  }
 
  /* FCLOSE */
 
  if (strcmp(cp, "FCLOSE") == 0) {
 
    struct filepointer *f, **t;
 
 
    /* get the file pointer name */
    if (get_next_token() == FAILED)
      return FAILED;
 
    f = filepointers;
    t = &filepointers;
    while (f != NULL) {
      if (strcmp(tmp, f->name) == 0)
	break;
      t = &(f->next);
      f = f->next;
    }
 
    if (f == NULL) {
      sprintf(emsg, "Couldn't find filepointer \"%s\".\n", tmp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    /* close the file pointer */
    if (f->f != NULL) {
      fclose(f->f);
      f->f = NULL;
    }
    *t = f->next;
 
    free(f->filename);
    free(f);
 
    return SUCCEEDED;
  }
 
  /* FSIZE */
 
  if (strcmp(cp, "FSIZE") == 0) {
 
    struct filepointer *f;
    long l, b;
 
 
    /* get the file pointer name */
    if (get_next_token() == FAILED)
      return FAILED;
 
    /* fetch the file pointer */
    f = filepointers;
    while (f != NULL) {
      if (strcmp(tmp, f->name) == 0)
	break;
      f = f->next;
    }
 
    if (f == NULL) {
      sprintf(emsg, "Couldn't find filepointer \"%s\".\n", tmp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    l = ftell(f->f);
    fseek(f->f, 0, SEEK_END);
    b = ftell(f->f);
    fseek(f->f, l, SEEK_SET);
 
    /* get the definition label */
    if (get_next_token() == FAILED)
      return FAILED;
 
    add_a_new_definition(tmp, (double)b, NULL, DEFINITION_TYPE_VALUE, 0);
 
    return SUCCEEDED;
  }
 
  /* FREAD */
 
  if (strcmp(cp, "FREAD") == 0) {
 
    struct filepointer *f;
    unsigned char c;
 
 
    /* get the file pointer name */
    if (get_next_token() == FAILED)
      return FAILED;
 
    f = filepointers;
    while (f != NULL) {
      if (strcmp(tmp, f->name) == 0)
	break;
      f = f->next;
    }
 
    if (f == NULL) {
      sprintf(emsg, "Couldn't find filepointer \"%s\".\n", tmp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    fscanf(f->f, "%c", &c);
 
    /* get the definition label */
    if (get_next_token() == FAILED)
      return FAILED;
 
    redefine(tmp, (double)c, NULL, DEFINITION_TYPE_VALUE, 0);
 
    return SUCCEEDED;
  }
 
  /* BLOCK */
 
  if (strcmp(cp, "BLOCK") == 0) {
    if ((ind = get_next_token()) == FAILED)
      return FAILED;
 
    if (ind != GET_NEXT_TOKEN_STRING) {
      print_error(".BLOCK requires a name string.\n", ERROR_DIR);
      return FAILED;
    }
 
    block_status++;
    fprintf(file_out_ptr, "g%s ", tmp);
 
    return SUCCEEDED;
  }
 
  /* ENDB */
 
  if (strcmp(cp, "ENDB") == 0) {
 
    if (block_status <= 0) {
      print_error("There is no open .BLOCK.\n", ERROR_DIR);
      return FAILED;
    }
 
    block_status--;
    fprintf(file_out_ptr, "G ");
 
    return SUCCEEDED;
  }
 
  /* SHIFT */
 
  if (strcmp(cp, "SHIFT") == 0) {
 
    struct macro_argument *ma;
    struct macro_runtime *rt;
    struct macro_static *st;
 
 
    if (macro_active == 0) {
      print_error(".SHIFT can only be used inside a MACRO.\n", ERROR_DIR);
      return FAILED;
    }
 
    rt = &macro_stack[macro_active - 1];
    st = rt->macro;
 
    if (st->nargument_names <= rt->supplied_arguments)
      o = st->nargument_names;
    else
      o = rt->supplied_arguments;
 
    /* free the argument definitions */
    for (q = 0; q < o; q++)
      undefine(st->argument_names[q]);
 
    /* free the first argument data */
    free(rt->argument_data[0]);
 
    /* shift the arguments one down */
    for (q = 0; q < rt->supplied_arguments - 1; q++)
      rt->argument_data[q] = rt->argument_data[q + 1];
 
    /* remove the last one */
    rt->argument_data[q] = NULL;
    rt->supplied_arguments--;
 
    if (st->nargument_names <= rt->supplied_arguments)
      o = st->nargument_names;
    else
      o = rt->supplied_arguments;
 
    /* redo the definitions if any */
    for (q = 0; q < o; q++) {
      ma = rt->argument_data[q];
      if (ma->type == SUCCEEDED)
	redefine(st->argument_names[q], (double)ma->value, NULL, DEFINITION_TYPE_VALUE, 0);
      else if (ma->type == INPUT_NUMBER_STACK)
	redefine(st->argument_names[q], (double)ma->value, NULL, DEFINITION_TYPE_STACK, 0);
      else if (ma->type == INPUT_NUMBER_ADDRESS_LABEL)
	redefine(st->argument_names[q], 0.0, ma->string, DEFINITION_TYPE_STRING, strlen(ma->string));
      else if (ma->type == INPUT_NUMBER_STRING)
	redefine(st->argument_names[q], 0.0, ma->string, DEFINITION_TYPE_STRING, strlen(ma->string));
    }
 
    /* redefine NARGS */
    if (redefine("NARGS", (double)rt->supplied_arguments, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
      return FAILED;
    if (redefine("nargs", (double)rt->supplied_arguments, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
      return FAILED;
 
    return SUCCEEDED;
  }
 
  /* ENDS */
 
  if (strcmp(cp, "ENDS") == 0) {
 
    if (section_status == OFF) {
      print_error("There is no open section.\n", ERROR_DIR);
      return FAILED;
    }
 
    section_status = OFF;
    bankheader_status = OFF;
    fprintf(file_out_ptr, "s ");
 
    return SUCCEEDED;
  }
 
  /* ROMBANKS */
 
  if (strcmp(cp, "ROMBANKS") == 0) {
 
    if (output_format == OUTPUT_LIBRARY) {
      print_error("Library files don't take .ROMBANKS.\n", ERROR_DIR);
      return FAILED;
    }
    if (banksize_defined == 0) {
      print_error("No .ROMBANKSIZE defined.\n", ERROR_DIR);
      return FAILED;
    }
 
    q = input_number();
 
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED || d < 1) {
      print_error(".ROMBANKS needs a positive integer value.\n", ERROR_DIR);
      return FAILED;
    }
 
    /* check that the old bank map (smaller) and the new one equal as much as they can */
    if (rombanks_defined != 0) {
      if (rombanks < d)
	inz = rombanks;
      else
	inz = d;
 
      for (ind = 0; ind < inz; ind++) {
	if (banks[ind] != banksize) {
	  print_error("The old and the new .ROMBANKMAP's don't match.\n", ERROR_DIR);
	  return FAILED;
	}
      }
 
      if (d <= rombanks)
	return SUCCEEDED;
 
      sprintf(emsg, "Upgrading from %d to %d ROM banks.\n", rombanks, d);
      print_error(emsg, ERROR_WRN);
    }
 
    rombanks = d;
    rombanks_defined = 1;
    max_address = d * banksize;
 
    if (rom_banks != NULL)
      free(rom_banks);
    if (rom_banks_usage_table != NULL)
      free(rom_banks_usage_table);
 
    rom_banks = malloc(sizeof(unsigned char) * max_address);
    rom_banks_usage_table = malloc(sizeof(unsigned char) * max_address);
    if (rom_banks == NULL || rom_banks_usage_table == NULL) {
      print_error("Out of memory while allocating ROM banks.\n", ERROR_DIR);
      return FAILED;
    }
 
    memset(rom_banks_usage_table, 0, sizeof(unsigned char) * max_address);
 
    if (banks != NULL)
      free(banks);
    if (bankaddress != NULL)
      free(bankaddress);
 
    banks = malloc(sizeof(int) * rombanks);
    bankaddress = malloc(sizeof(int) * rombanks);
    if (banks == NULL || bankaddress == NULL) {
      print_error("Out of memory while allocating ROM banks.\n", ERROR_DIR);
      return FAILED;
    }
 
    for (inz = 0, ind = 0; ind < d; ind++) {
      banks[ind] = banksize;
      bankaddress[ind] = inz;
      inz += banksize;
    }
 
    return SUCCEEDED;
  }
 
  /* ROMBANKMAP */
 
  if (strcmp(cp, "ROMBANKMAP") == 0) {
 
    int b = 0, a = 0, bt = 0, bt_defined = 0, x, bs = 0, bs_defined = 0;
 
 
    if (output_format == OUTPUT_LIBRARY) {
      print_error("Library files don't take .ROMBANKMAP.\n", ERROR_DIR);
      return FAILED;
    }
 
    /* ROMBANKMAP has been defined previously */
    if (rombankmap_defined != 0 || rombanks_defined != 0) {
      o = 0;
      while ((ind = get_next_token()) == SUCCEEDED) {
	if (strcaselesscmp(tmp, ".ENDRO") == 0) {
	  break;
	}
	else if (strcaselesscmp(tmp, "BANKSTOTAL") == 0) {
	  q = input_number();
 
	  if (q == FAILED)
	    return FAILED;
	  if (q != SUCCEEDED || d <= 0) {
	    print_error("BANKSTOTAL needs a positive value.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  if (rombanks < d) {
	    banks = realloc(banks, sizeof(int) * d);
	    bankaddress = realloc(bankaddress, sizeof(int) * d);
	    if (banks == NULL || bankaddress == NULL) {
	      print_error("Out of memory while allocating ROM banks.\n", ERROR_DIR);
	      return FAILED;
	    }
	  }
 
	  bt = d;
	  bt_defined = 1;
	}
	else if (strcaselesscmp(tmp, "BANKSIZE") == 0) {
	  if (bt_defined == 0) {
	    print_error("BANKSTOTAL needs to be defined prior to BANKSIZE.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  q = input_number();
 
	  if (q == FAILED)
	    return FAILED;
	  if (q != SUCCEEDED || d <= 0) {
	    print_error("BANKSIZE needs a positive value.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  bs = d;
	  bs_defined = 1;
	}
	else if (strcaselesscmp(tmp, "BANKS") == 0) {
	  if (bs_defined == 0) {
	    print_error("BANKSIZE needs to be defined prior to BANKS.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  q = input_number();
 
	  if (q == FAILED)
	    return FAILED;
	  if (q != SUCCEEDED || d <= 0) {
	    print_error("BANKS needs a positive value.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  for (x = 0; x < d; x++) {
	    if (b > bt) {
	      print_error("More BANKS than BANKSTOTAL suggests.\n", ERROR_DIR);
	      return FAILED;
	    }
 
	    /* new banks? */
	    if (x >= rombanks) {
	      banks[o] = bs;
	      bankaddress[o] = a;
	    }
	    /* compare old banks */
	    else if (banks[o] != bs) {
	      print_error("The old and the new ROMBANKMAPs don't match.\n", ERROR_DIR);
	      return FAILED;
	    }
 
	    o++;
	    b++;
	    a += bs;
	  }
	}
	else {
	  ind = FAILED;
	  break;
	}
      }
    }
    /* no ROMBANKMAP has been defined */
    else {
      o = 0;
      while ((ind = get_next_token()) == SUCCEEDED) {
	if (strcaselesscmp(tmp, ".ENDRO") == 0)
	  break;
	else if (strcaselesscmp(tmp, "BANKSTOTAL") == 0) {
	  q = input_number();
 
	  if (q == FAILED)
	    return FAILED;
	  if (q != SUCCEEDED || d <= 0) {
	    print_error("BANKSTOTAL needs a positive value.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  banks = malloc(sizeof(int) * d);
	  bankaddress = malloc(sizeof(int) * d);
	  if (banks == NULL || bankaddress == NULL) {
	    print_error("Out of memory while allocating ROM banks.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  bt = d;
	  bt_defined = 1;
	}
	else if (strcaselesscmp(tmp, "BANKSIZE") == 0) {
	  if (bt_defined == 0) {
	    print_error("BANKSTOTAL needs to be defined prior to BANKSIZE.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  q = input_number();
 
	  if (q == FAILED)
	    return FAILED;
	  if (q != SUCCEEDED || d <= 0) {
	    print_error("BANKSIZE needs a positive value.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  bs = d;
	  bs_defined = 1;
	}
	else if (strcaselesscmp(tmp, "BANKS") == 0) {
	  if (bs_defined == 0) {
	    print_error("BANKSIZE needs to be defined prior to BANKS.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  q = input_number();
 
	  if (q == FAILED)
	    return FAILED;
	  if (q != SUCCEEDED || d <= 0) {
	    print_error("BANKS needs a positive value.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  for (x = 0; x < d; x++) {
	    if (b > bt) {
	      print_error("More BANKS than BANKSTOTAL suggests.\n", ERROR_DIR);
	      return FAILED;
	    }
	    banks[o] = bs;
	    bankaddress[o] = a;
	    o++;
	    b++;
	    a += bs;
	  }
	}
	else {
	  ind = FAILED;
	  break;
	}
      }
    }
 
    if (ind != SUCCEEDED) {
      print_error("Error in .ROMBANKMAP data structure.\n", ERROR_DIR);
      return FAILED;
    }
 
    /* no banks definded? */
    if (bt == 0) {
      print_error("No ROM banks were defined inside the .ROMBANKMAP.\n", ERROR_DIR);
      return FAILED;	
    }
    if (bt != b) {
      print_error("Not all ROM banks were defined inside the .ROMBANKMAP.\n", ERROR_DIR);
      return FAILED;	
    }
 
    if (rombanks_defined != 0) {
      if (b > rombanks) {
	sprintf(emsg, "Upgrading from %d to %d ROM banks.\n", rombanks, b);
	print_error(emsg, ERROR_WRN);
      }
      else
	return SUCCEEDED;
    }
 
    rombanks = b;
    rombanks_defined = 1;
    for (max_address = 0, q = 0; q < rombanks; q++)
      max_address += banks[q];
 
    if (rom_banks != NULL)
      free(rom_banks);
    if (rom_banks_usage_table != NULL)
      free(rom_banks_usage_table);
 
    rom_banks = malloc(sizeof(unsigned char) * max_address);
    rom_banks_usage_table = malloc(sizeof(unsigned char) * max_address);
    if (rom_banks == NULL || rom_banks_usage_table == NULL) {
      print_error("Out of memory while allocating ROM banks.\n", ERROR_DIR);
      return FAILED;
    }
 
    memset(rom_banks_usage_table, 0, sizeof(unsigned char) * max_address);
    rombankmap_defined = 1;
 
    return SUCCEEDED;
  }
 
  /* MEMORYMAP */
 
  if (strcmp(cp, "MEMORYMAP") == 0) {
 
    int slotsize = 0, slotsize_defined = 0, s = 0;
    slots_amount=0;
 
 
    if (memorymap_defined == 1) {
      print_error(".MEMORYMAP can be defined only once.\n", ERROR_DIR);
      return FAILED;
    }
    if (output_format == OUTPUT_LIBRARY)
      print_error("Libraries don't need .MEMORYMAP.\n", ERROR_WRN);
 
    while ((ind = get_next_token()) == SUCCEEDED) {
      if (strcaselesscmp(tmp, ".ENDME") == 0) {
	if (defaultslot_defined == 0) {
	  print_error("No DEFAULTSLOT defined.\n", ERROR_DIR);
	  return FAILED;
	}
 
	if (slots[defaultslot].size == 0) {
	  sprintf(emsg, "Unknown DEFAULTSLOT %d.\n", defaultslot);
	  print_error(emsg, ERROR_DIR);
	  return FAILED;
	}
 
	break;
      }
      else if (strcaselesscmp(tmp, "SLOTSIZE") == 0) {
	q = input_number();
 
	if (q == FAILED)
	  return FAILED;
	if (q != SUCCEEDED) {
	  print_error("SLOTSIZE needs an immediate value.\n", ERROR_DIR);
	  return FAILED;
	}
 
	slotsize = d;
	slotsize_defined = 1;
      }
      else if (strcaselesscmp(tmp, "DEFAULTSLOT") == 0) {
	if (defaultslot_defined != 0) {
	  print_error("DEFAULTSLOT can be defined only once.\n", ERROR_DIR);
	  return FAILED;
	}
 
	q = input_number();
 
	if (q == FAILED)
	  return FAILED;
	if (q != SUCCEEDED || d > 255 || d < 0) {
	  print_error("DEFAULTSLOT needs an immediate value (0-255) as an ID.\n", ERROR_DIR);
	  return FAILED;
	}
 
	defaultslot_defined = 1;
	defaultslot = d;
      }
      else if (strcaselesscmp(tmp, "SLOT") == 0) {
	q = input_number();
 
	if (q == FAILED)
	  return FAILED;
	if (q != SUCCEEDED || d > 255 || d < 0) {
	  print_error("SLOT needs a positive value (0-255) as an ID.\n", ERROR_DIR);
	  return FAILED;
	}
 
	if (s != d) {
	  print_error("Error in SLOT's ID. ID's start from 0.\n", ERROR_DIR);
	  return FAILED;
	}
 
	o = d;
 
	/* skip "START" if present */
	if (compare_next_token("START", 5) == SUCCEEDED)
	  skip_next_token();
 
	q = input_number();
 
	if (q == FAILED)
	  return FAILED;
	if (q != SUCCEEDED || d < 0) {
	  print_error("The starting address has to be a non-negative value.\n", ERROR_DIR);
	  return FAILED;
	}
 
	slots[o].address = d;
 
	/* skip "SIZE" if present */
	if (compare_next_token("SIZE", 4) == SUCCEEDED)
	  skip_next_token();
 
	q = input_number();
	if (q == INPUT_NUMBER_EOL) {
	  if (slotsize_defined == 0) {
	    print_error("SLOTSIZE must be defined if you don't explicitly give the size.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  next_line();
 
	  d = slotsize;
	}
	else {
	  if (q == FAILED)
	    return FAILED;
	  if (q != SUCCEEDED) {
	    print_error("The size of the slot needs to be an immediate value.\n", ERROR_DIR);
	    return FAILED;
	  }
	}
 
	slots[o].size = d;
	slots_amount++;
	s++;
      }
      else {
	ind = FAILED;
	break;
      }
    }
 
    if (ind != SUCCEEDED) {
      print_error("Error in .MEMORYMAP data structure.\n", ERROR_DIR);
      return FAILED;
    }
 
    memorymap_defined=1;
 
    return SUCCEEDED;
  }
 
  /* UNBACKGROUND */
 
  if (strcmp(cp, "UNBACKGROUND") == 0) {
 
    int start, end;
 
 
    if (output_format != OUTPUT_OBJECT) {
      print_error(".UNBACKGROUND can only be used in OBJECT output mode.\n", ERROR_DIR);
      return FAILED;
    }
    if (background_defined == 0) {
      print_error("No .BACKGROUND specified.\n", ERROR_DIR);
      return FAILED;
    }
 
    /* get the starting address */
    q = input_number();
 
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED || q < 0) {
      print_error(".UNBACKGROUND needs the block's starting address.\n", ERROR_DIR);
      return FAILED;
    }
 
    start = d;
 
    /* get the ending address */
    q = input_number();
 
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED || q < 0) {
      print_error(".UNBACKGROUND needs the block's ending address.\n", ERROR_DIR);
      return FAILED;
    }
 
    end = d;
 
    if (end < start) {
      print_error("The block's ending address is smaller than the starting address!\n", ERROR_DIR);
      return FAILED;
    }
    if (start >= max_address) {
      sprintf(emsg, "The block's starting address $%x is beyond the ROM's ending address $%x.\n", start, max_address-1);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
    if (end >= max_address) {
      sprintf(emsg, "The block's ending address $%x is beyond the ROM's ending address $%x. Using the ROM's ending address instead.\n", end, max_address-1);
      end = max_address;
      print_error(emsg, ERROR_WRN);
    }
 
    /* clear the memory [start, end] */
    memset(rom_banks + start, 0, end - start + 1);
    memset(rom_banks_usage_table + start, 0, end - start + 1);
 
    return SUCCEEDED;
  }
 
  /* BACKGROUND */
 
  if (strcmp(cp, "BACKGROUND") == 0) {
 
    FILE *file_in_ptr;
 
 
    if (output_format != OUTPUT_OBJECT) {
      print_error(".BACKGROUND can only be used in OBJECT output mode.\n", ERROR_DIR);
      return FAILED;
    }
    if (background_defined == 1) {
      print_error("Only one .BACKGROUND can be specified.\n", ERROR_DIR);
      return FAILED;
    }
 
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != INPUT_NUMBER_STRING) {
      print_error(".BACKGROUND needs a file name string.\n", ERROR_DIR);
      return FAILED;
    }
 
#ifdef abba
    if (memorymap_defined == 0) {
	/* Set up some default values for the PV2 */
	slots[0].address = 0;
	slots[0].size = MAXADDRESS;
	slots_amount++;
    	memorymap_defined=1;
    }
#endif
 
    if (rombanks_defined == 0) {
      print_error("No .ROMBANKS defined.\n", ERROR_DIR);
      return FAILED;
    }
 
    create_full_name(include_dir, label);
 
    if ((file_in_ptr = fopen(full_name, "rb")) == NULL) {
      sprintf(emsg, "Error opening .BACKGROUND file \"%s\".\n", full_name);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    fseek(file_in_ptr, 0, SEEK_END);
    background_size = ftell(file_in_ptr);
    fseek(file_in_ptr, 0, SEEK_SET);
 
    if (max_address != background_size) {
      sprintf(emsg, ".BACKGROUND file \"%s\" size (%d) and ROM size (%d) don't match.\n", full_name,
	      background_size, max_address);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    memset(rom_banks_usage_table, 2, max_address);
    fread(rom_banks, 1, max_address, file_in_ptr);
 
    background_defined = 1;
    fclose(file_in_ptr);
 
    return SUCCEEDED;
  }
 
  /* EMPTYFILL */
 
  if (strcmp(cp, "EMPTYFILL") == 0) {
 
    if (output_format == OUTPUT_LIBRARY) {
      print_error("Library files don't take .EMPTYFILL.\n", ERROR_DIR);
      return FAILED;
    }
 
    q = input_number();
 
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED || d < -127 || d > 255) {
      print_error(".EMPTYFILL needs a 8bit value.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (emptyfill_defined != 0) {
      if (emptyfill != d) {
	print_error(".EMPTYFILL was defined for the second time.\n", ERROR_DIR);
	return FAILED;
      }
      return SUCCEEDED;
    }
 
    emptyfill = d;
    emptyfill_defined = 1;
 
    return SUCCEEDED;
  }
 
  /* DEFINE/DEF/EQU */
 
  if (strcmp(cp, "DEFINE") == 0 || strcmp(cp, "DEF") == 0 || strcmp(cp, "EQU") == 0) {
 
    double dou;
    char k[256];
    int j, size;
 
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    /* check the user doesn't try to define reserved labels */
    if (strcmp(tmp, "WLA_TIME") == 0 || strcmp(tmp, "wla_time") == 0 ||
	strcmp(tmp, "WLA_VERSION") == 0 || strcmp(tmp, "wla_version") == 0 ||
	strcmp(tmp, "WLA_FILENAME") == 0 || strcmp(tmp, "wla_filename") == 0 ||
	strcmp(tmp, "NARGS") == 0 || strcmp(tmp, "nargs") == 0 ||
	strcmp(tmp, "CADDR") == 0 || strcmp(tmp, "caddr") == 0) {
 
      sprintf(emsg, "\"%s\" is a reserved definition label and is not user definiable.\n", tmp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    /* skip "=", if present */
    if (compare_next_token("=", 1) == SUCCEEDED)
      skip_next_token();
 
    input_float_mode = ON;
    q = get_new_definition_data(&j, k, &size, &dou);
    input_float_mode = OFF;
    if (q == FAILED)
      return FAILED;
 
    if (!(q == INPUT_NUMBER_EOL || q == INPUT_NUMBER_FLOAT || q == SUCCEEDED || q == INPUT_NUMBER_STRING || q == INPUT_NUMBER_STACK)) {
      print_error("Could not parse the definition data.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (q == SUCCEEDED)
      add_a_new_definition(tmp, (double)j, NULL, DEFINITION_TYPE_VALUE, 0);
    else if (q == INPUT_NUMBER_FLOAT)
      add_a_new_definition(tmp, dou, NULL, DEFINITION_TYPE_VALUE, 0);
    else if (q == INPUT_NUMBER_STRING)
      add_a_new_definition(tmp, 0.0, k, DEFINITION_TYPE_STRING, size);
    else if (q == INPUT_NUMBER_STACK)
      add_a_new_definition(tmp, (double)j, NULL, DEFINITION_TYPE_STACK, 0);
    else if (q == INPUT_NUMBER_EOL) {
      add_a_new_definition(tmp, 0, NULL, DEFINITION_TYPE_VALUE, 0);
      next_line();
    }
 
    return SUCCEEDED;
  }
 
  /* INPUT */
 
  if (strcmp(cp, "INPUT") == 0) {
 
    char k[256];
    int j, v;
 
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    fgets(k, 254, stdin);
 
    for (j = 0; j < 254; j++) {
      if (k[j] == 0)
	break;
      if (k[j] == 0x0A) {
	k[j] = 0;
	break;
      }
      if (k[j] == 0x0D) {
	k[j] = 0;
	break;
      }
    }
 
    if (j == 254) {
      print_error("Error in .INPUT.\n", ERROR_DIR);
      return FAILED;
    }
 
    for (j = 0; j < 254; j++) {
      if (k[j] == 0) {
	print_error("No .INPUT?\n", ERROR_DIR);
	return FAILED;
      }
      if (!(k[j] == ' ' || k[j] == 0x09))
	break;
    }
 
    if (k[j] == '%') {
      v = 0;
      j++;
      for ( ; j < 254; j++) {
	if (k[j] == 0)
	  break;
	if (k[j] == '0' || k[j] == '1')
	  v = (v << 1) + k[j] - '0';
	else
	  break;
      }
      if (k[j] == 0) {
	redefine(tmp, (double)v, NULL, DEFINITION_TYPE_VALUE, 0);
	return SUCCEEDED;
      }
    }
    else if (k[j] == '$') {
      j++;
      v = 0;
      for ( ; j < 254; j++) {
	if (k[j] == 0)
	  break;
	if (k[j] >= '0' && k[j] <= '9')
	  v = (v << 4) + k[j] - '0';
	else if (k[j] >= 'a' && k[j] <= 'f')
	  v = (v << 4) + k[j] - 'a' + 10;
	else if (k[j] >= 'A' && k[j] <= 'F')
	  v = (v << 4) + k[j] - 'A' + 10;
	else
	  break;
      }
      if (k[j] == 0) {
	redefine(tmp, (double)v, NULL, DEFINITION_TYPE_VALUE, 0);
	return SUCCEEDED;
      }
    }
    else if (k[j] >= '0' && k[j] <= '9') {
      v = 0;
      for ( ; j < 254; j++) {
	if (k[j] == 0)
	  break;
	if (k[j] >= '0' && k[j] <= '9')
	  v = (v * 10) + k[j] - '0';
	else
	  break;
      }
      if (k[j] == 0) {
	redefine(tmp, (double)v, NULL, DEFINITION_TYPE_VALUE, 0);
	return SUCCEEDED;
      }
    }
 
    /* it's a string */
    redefine(tmp, 0.0, k, DEFINITION_TYPE_STRING, strlen(k));
 
    return SUCCEEDED;
  }
 
  /* REDEFINE/REDEF */
 
  if (strcmp(cp, "REDEFINE") == 0 || strcmp(cp, "REDEF") == 0) {
 
    double dou;
    char k[256];
    int j, size;
 
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    /* check the user doesn't try to define reserved labels */
    if (strcmp(tmp, "WLA_TIME") == 0 || strcmp(tmp, "wla_time") == 0 ||
	strcmp(tmp, "WLA_VERSION") == 0 || strcmp(tmp, "wla_version") == 0 ||
	strcmp(tmp, "WLA_FILENAME") == 0 || strcmp(tmp, "wla_filename") == 0 ||
	strcmp(tmp, "NARGS") == 0 || strcmp(tmp, "nargs") == 0 ||
	strcmp(tmp, "CADDR") == 0 || strcmp(tmp, "caddr") == 0) {
 
      sprintf(emsg, "\"%s\" is a reserved definition label and is not user definiable.\n", tmp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    /* skip "=", if present */
    if (compare_next_token("=", 1) == SUCCEEDED)
      skip_next_token();
 
    input_float_mode = ON;
    q = get_new_definition_data(&j, k, &size, &dou);
    input_float_mode = OFF;
    if (q == FAILED)
      return FAILED;
 
    if (!(q == INPUT_NUMBER_FLOAT || q == SUCCEEDED || q == INPUT_NUMBER_STRING || q == INPUT_NUMBER_STACK)) {
      print_error("Could not parse the definition data.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (q == SUCCEEDED)
      redefine(tmp, (double)j, NULL, DEFINITION_TYPE_VALUE, 0);
    else if (q == INPUT_NUMBER_FLOAT)
      redefine(tmp, dou, NULL, DEFINITION_TYPE_VALUE, 0);
    else if (q == INPUT_NUMBER_STRING)
      redefine(tmp, 0.0, k, DEFINITION_TYPE_STRING, size);
    else if (q == INPUT_NUMBER_STACK)
      redefine(tmp, (double)j, NULL, DEFINITION_TYPE_STACK, 0);
 
    return SUCCEEDED;
  }
 
  /* EXPORT */
 
  if (strcmp(cp, "EXPORT") == 0) {
    q = 0;
    while (1) {
      ind = input_next_string();
      if (ind == FAILED)
	return FAILED;
      if (ind == INPUT_NUMBER_EOL) {
	if (q != 0) {
	  next_line();
	  return SUCCEEDED;
	}
	print_error(".EXPORT requires definition name(s).\n", ERROR_DIR);
	return FAILED;
      }
 
      q++;
 
      if (export_a_definition(tmp) == FAILED)
	return FAILED;
    }
 
    return FAILED;
  }
 
  /* SYM/SYMBOL */
 
  if (strcmp(cp, "SYM") == 0 || strcmp(cp, "SYMBOL") == 0) {
    ind = input_next_string();
    if (ind != SUCCEEDED) {
      print_error(".SYM requires a symbol name.\n", ERROR_DIR);
      return FAILED;
    }
 
    fprintf(file_out_ptr, "Y%s ", tmp);
 
    return SUCCEEDED;
  }
 
  /* BR/BREAKPOINT */
 
  if (strcmp(cp, "BR") == 0 || strcmp(cp, "BREAKPOINT") == 0) {
    fprintf(file_out_ptr, "Z ");
    return SUCCEEDED;
  }
 
  /* ENUM */
 
  if (strcmp(cp, "ENUM") == 0) {
 
    char tmpname[MAX_NAME_LENGTH];
    int exp = NO, ord = 1, type;
 
 
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED) {
      print_error(".ENUM needs a starting address.\n", ERROR_DIR);
      return FAILED;
    }
 
    o = d;
 
    /* "ASC" or "DESC"? */
    if (compare_next_token("ASC", 3) == SUCCEEDED) {
      ord = 1;
      skip_next_token();
    }
    else if (compare_next_token("DESC", 4) == SUCCEEDED) {
      ord = -1;
      skip_next_token();
    }
 
    /* do we have "EXPORT" defined? */
    if (compare_next_token("EXPORT", 6) == SUCCEEDED) {
      skip_next_token();
      exp = YES;
    }
 
    while ((t = get_next_token()) != FAILED) {
      if (strcaselesscmp(tmp, ".ENDE") == 0)
	return SUCCEEDED;
      if (tmp[strlen(tmp) - 1] == ':')
	tmp[strlen(tmp) - 1] = 0;
      strcpy(tmpname, tmp);
 
      /* ASC? */
      if (ord == 1) {
	if (add_a_new_definition(tmpname, (double)o, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	  return FAILED;
	if (exp == YES)
	  if (export_a_definition(tmpname) == FAILED)
	    return FAILED;
      }
 
      /* get the size/type */
      if (get_next_token() == FAILED)
	return FAILED;
 
      type = 0;
 
      if (strcaselesscmp(tmp, "DB") == 0 || strcaselesscmp(tmp, "BYT") == 0 || strcaselesscmp(tmp, "BYTE") == 0)
	o += 1*ord;
      else if (strcaselesscmp(tmp, "DW") == 0 || strcaselesscmp(tmp, "WORD") == 0)
	o += 2*ord;
      else if (strcaselesscmp(tmp, "DS") == 0 || strcaselesscmp(tmp, "DSB") == 0) {
	strcpy(bak, tmp);
	q = input_number();
	if (q == FAILED)
	  return FAILED;
	if (q != SUCCEEDED) {
	  sprintf(emsg, ".%s needs size.\n", bak);
	  print_error(emsg, ERROR_DIR);
	  return FAILED;
	}
	o += d*ord;
      }
      else if (strcaselesscmp(tmp, "DSW") == 0) {
	q = input_number();
	if (q == FAILED)
	  return FAILED;
	if (q != SUCCEEDED) {
	  print_error("DSW needs size.\n", ERROR_DIR);
	  return FAILED;
	}
	o += d*2*ord;
      }
      /* it's an instance of a structure! */
      else if (strcaselesscmp(tmp, "INSTANCEOF") == 0) {
 
	struct structure_item *si;
	struct structure *st;
	int g;
 
 
	type = 1;
 
	if (get_next_token() == FAILED)
	  return FAILED;
 
	st = structures_first;
	while (st != NULL) {
	  if (strcmp(st->name, tmp) == 0)
	    break;
	  st = st->next;
	}
 
	if (st == NULL) {
	  sprintf(emsg, "No STRUCT named \"%s\" available.\n", tmp);
	  print_error(emsg, ERROR_DIR);
	  return FAILED;
	}
 
	/* generate labels (first the basic ones, without index number) */
	if (ord == -1) {
	  o -= st->size;
	  if (add_a_new_definition(tmpname, (double)o, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	    return FAILED;
	  if (exp == YES)
	    if (export_a_definition(tmpname) == FAILED)
	      return FAILED;
	}
 
	si = st->items;
	while (si != NULL) {
	  sprintf(tmp, "%s.%s%c", tmpname, si->name, 0);
	  if (add_a_new_definition(tmp, (double)o, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	    return FAILED;
	  if (exp == YES)
	    if (export_a_definition(tmp) == FAILED)
	      return FAILED;
	  o += si->size;
	  si = si->next;
	}
 
	if (ord == -1)
	  o -= st->size;
 
	/* the number of structures? */
	inz = input_number();
	if (inz == INPUT_NUMBER_EOL)
	  next_line();
	else if (inz == SUCCEEDED) {
	  if (d < 1) {
	    print_error("The number of structures must be greater than 0.\n", ERROR_DIR);
	    return FAILED;
	  }
 
	  /* generate labels (now with the index numbers) */
	  if (d > 1) {
	    g = 1;
 
	    if (ord == 1)
	      o -= st->size;
 
	    while (d > 0) {
	      si = st->items;
	      sprintf(tmp, "%s.%d%c", tmpname, g, 0);
	      if (add_a_new_definition(tmp, (double)o, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
		return FAILED;
	      if (exp == YES)
		if (export_a_definition(tmp) == FAILED)
		  return FAILED;
	      while (si != NULL) {
		sprintf(tmp, "%s.%d.%s%c", tmpname, g, si->name, 0);
		if (add_a_new_definition(tmp, (double)o, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
		  return FAILED;
		if (exp == YES)
		  if (export_a_definition(tmp) == FAILED)
		    return FAILED;
		o += si->size;
		si = si->next;
	      }
	      g++;
	      d--;
	      if (ord == -1) {
		if (d > 0)
		  o -= st->size*2;
		else
		  o -= st->size;
	      }
	    }
	  }
	}
	else {
	  if (inz == INPUT_NUMBER_STRING)
	    sprintf(emsg, "Expected the number of structures, got \"%s\" instead.\n", label);
	  else
	    sprintf(emsg, "Expected the number of structures.\n");
	  print_error(emsg, ERROR_DIR);
	  return FAILED;
	}
      }
      else if (tmp[0] == '.' && strcaselesscmp(tmp, ".ENDE") != 0)
	;
      else {
	sprintf(emsg, "Unexpected symbol \"%s\" in .ENUM.\n", tmp);
	print_error(emsg, ERROR_DIR);
	return FAILED;
      }
 
      /* DESC? */
      if (ord == -1 && type == 0) {
	if (add_a_new_definition(tmpname, (double)o, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	  return FAILED;
	if (exp == YES)
	  if (export_a_definition(tmpname) == FAILED)
	    return FAILED;
      }
    }
 
    return FAILED;
  }
 
 
  /* MACRO */
 
  if (strcmp(cp, "MACRO") == 0) {
 
    struct macro_static *m;
    int macro_start;
 
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    macro_start = active_file_info_last->line_current;
 
    m = macros_first;
    while (m != NULL) {
      if (strcmp(tmp, m->name) == 0) {
	sprintf(emsg, "MACRO \"%s\" was defined for the second time.\n", tmp);
	print_error(emsg, ERROR_DIR);
	return FAILED;
      }
      m = m->next;
    }
 
    m = malloc(sizeof(struct macro_static));
    if (m == NULL) {
      print_error("Out of memory while allocating room for a new MACRO.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (macros_first == NULL) {
      macros_first = m;
      macros_last = m;
    }
    else {
      macros_last->next = m;
      macros_last = m;
    }
 
    strcpy(m->name, tmp);
    m->next = NULL;
    m->calls = 0;
    m->filename_id = active_file_info_last->filename_id;
    m->argument_names = NULL;
 
    /* is ARGS defined? */
    q = 0;
    if (compare_next_token("ARGS", 4) == SUCCEEDED) {
      skip_next_token();
 
      while (1) {
	ind = input_next_string();
	if (ind == FAILED)
	  return FAILED;
	if (ind == INPUT_NUMBER_EOL) {
	  if (q != 0) {
	    next_line();
	    break;
	  }
	  sprintf(emsg, "MACRO \"%s\" is missing argument names?\n", m->name);
	  print_error(emsg, ERROR_DIR);
	  return FAILED;
	}
	q++;
 
	/* store the label */
	m->argument_names = realloc(m->argument_names, sizeof(char *)*q);
	if (m->argument_names == NULL) {
	  print_error("Out of memory error.\n", ERROR_NONE);
	  return FAILED;
	}
	m->argument_names[q-1] = malloc(strlen(tmp)+1);
	if (m->argument_names[q-1] == NULL) {
	  print_error("Out of memory error.\n", ERROR_NONE);
	  return FAILED;
	}
 
	strcpy(m->argument_names[q-1], tmp);
      }
    }
 
    m->nargument_names = q;
    m->start = i;
    m->start_line = active_file_info_last->line_current;
 
    /* go to the end of the macro */
    for (; i < size; i++) {
      if (buffer[i] == 0x0A) {
	next_line();
	continue;
      }
      else if ((strncmp(&buffer[i], ".E", 2) == 0) && (buffer[i + 2] == 0x0A || buffer[i + 2] == ' ')) {
	active_file_info_last->line_current = macro_start;
	sprintf(emsg, "MACRO \"%s\" wasn't terminated with .ENDM.\n", m->name);
	print_error(emsg, ERROR_DIR);
	return FAILED;
      }
      else if ((strncmp(&buffer[i], ".ENDM", 5) == 0 || strncmp(&buffer[i], ".endm", 5) == 0) && (buffer[i + 5] == 0x0A || buffer[i + 5] == ' ')) {
	i += 5;
	break;
      }
    }
 
    return SUCCEEDED;
  }
 
  /* REPT/REPEAT */
 
  if (strcmp(cp, "REPT") == 0 || strcmp(cp, "REPEAT") == 0) {
 
    char c[16];
 
 
    strcpy(c, cp);
 
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED) {
      sprintf(emsg, ".%s needs a count.\n", c);
      print_error(emsg, ERROR_INP);
      return FAILED;
    }
 
    if (d < 0) {
      sprintf(emsg, ".%s count value must be positive or zero.\n", c);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (d == 0) {
      int l, r, m;
 
      l = active_file_info_last->line_current;
      /* find the next compiling point */
      r = 1;
      m = macro_active;
      /* disable macro decoding */
      macro_active = 0;
      while (get_next_token() != FAILED) {
	if (tmp[0] == '.') {
	  if (strcmp(cp, "ENDR") == 0)
	    r--;
	  if (strcmp(cp, "E") == 0)
	    break;
	  if (strcmp(cp, "REPT") == 0 || strcmp(cp, "REPEAT") == 0)
	    r++;
	}
	if (r == 0) {
	  macro_active = m;
	  return SUCCEEDED;
	}
      }
 
      /* return the condition's line number */
      active_file_info_last->line_current = l;
      sprintf(emsg, ".%s must end to .ENDR.\n", c);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (repeat_active == repeat_stack_size) {
      struct repeat_runtime *rr;
 
      repeat_stack_size = (repeat_stack_size<<1)+2;
      rr = realloc(repeat_stack, sizeof(struct repeat_runtime) * repeat_stack_size);
      if (rr == NULL) {
	print_error("Out of memory error while enlarging repeat stack buffer.\n", ERROR_ERR);
	return FAILED;
      }
      repeat_stack = rr;
    }
 
    repeat_stack[repeat_active].start = i;
    repeat_stack[repeat_active].counter = d;
    repeat_stack[repeat_active].start_line = active_file_info_last->line_current;
 
    repeat_active++;
 
    return SUCCEEDED;
  }
 
  /* ENDR */
 
  if (strcmp(cp, "ENDR") == 0) {
 
    if (repeat_active == 0) {
      print_error("There is no open repetition.\n", ERROR_DIR);
      return FAILED;
    }
 
    repeat_stack[repeat_active - 1].counter--;
    if (repeat_stack[repeat_active - 1].counter == 0) {
      repeat_active--;
      return SUCCEEDED;
    }
 
    i = repeat_stack[repeat_active - 1].start;
    active_file_info_last->line_current = repeat_stack[repeat_active - 1].start_line;
 
    return SUCCEEDED;
  }
 
  /* E */
 
  if (strcmp(cp, "E") == 0) {
    if (active_file_info_last != NULL) {
      active_file_info_tmp = active_file_info_last;
      active_file_info_last = active_file_info_last->prev;
      free(active_file_info_tmp);
      if (active_file_info_last == NULL)
	active_file_info_first = NULL;
      else
	fprintf(file_out_ptr, "f%d ", active_file_info_last->filename_id);
    }
    fprintf(file_out_ptr, "E ");
    open_files--;
    if (open_files == 0)
      return EVALUATE_TOKEN_EOP;
 
    if (extra_definitions == ON) {
      redefine("WLA_FILENAME", 0.0, get_file_name(active_file_info_last->filename_id), DEFINITION_TYPE_STRING,
	       strlen(get_file_name(active_file_info_last->filename_id)));
      redefine("wla_filename", 0.0, get_file_name(active_file_info_last->filename_id), DEFINITION_TYPE_STRING,
	       strlen(get_file_name(active_file_info_last->filename_id)));
    }
 
    return SUCCEEDED;
  }
 
  /* M */
 
  if (strcmp(cp, "M") == 0) {
    if (line_count_status == OFF)
      line_count_status = ON;
    else
      line_count_status = OFF;
    return SUCCEEDED;
  }
 
  /* ROMBANKSIZE */
 
  if (strcmp(cp, "ROMBANKSIZE") == 0 || strcmp(cp, "BANKSIZE") == 0) {
    q = input_number();
 
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED || d < 0) {
      print_error(".ROMBANKSIZE needs a positive integer value.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (banksize_defined != 0) {
      if (banksize != d) {
	print_error(".ROMBANKSIZE was defined for the second time.\n", ERROR_DIR);
	return FAILED;
      }
      return SUCCEEDED;
    }
 
    banksize = d;
    banksize_defined = 1;
 
    return SUCCEEDED;
  }
 
  /* ENDM */
 
  if (strcmp(cp, "ENDM") == 0) {
    if (macro_active != 0) {
      macro_active--;
 
      /* free the arguments */
      if (macro_stack[macro_active].supplied_arguments > 0) {
	for (d = 0; d < macro_stack[macro_active].supplied_arguments; d++)
	  free(macro_stack[macro_active].argument_data[d]);
	free(macro_stack[macro_active].argument_data);
	macro_stack[macro_active].argument_data = NULL;
      }
 
      /* free the argument definitions */
      for (q = 0; q < macro_stack[macro_active].macro->nargument_names; q++)
	undefine(macro_stack[macro_active].macro->argument_names[q]);
 
      i = macro_stack[macro_active].macro_end;
 
      if ((extra_definitions == ON) && (active_file_info_last->filename_id != macro_stack[macro_active].macro_end_filename_id)) {
	redefine("WLA_FILENAME", 0.0, get_file_name(macro_stack[macro_active].macro_end_filename_id), DEFINITION_TYPE_STRING,
		 strlen(get_file_name(macro_stack[macro_active].macro_end_filename_id)));
	redefine("wla_filename", 0.0, get_file_name(macro_stack[macro_active].macro_end_filename_id), DEFINITION_TYPE_STRING,
		 strlen(get_file_name(macro_stack[macro_active].macro_end_filename_id)));
      }
 
      active_file_info_last->filename_id = macro_stack[macro_active].macro_end_filename_id;
      active_file_info_last->line_current = macro_stack[macro_active].macro_end_line;
 
      /* was this the last macro called? */
      if (macro_active == 0) {
	/* delete NARGS */
	undefine("NARGS");
	undefine("nargs");
 
	macro_runtime_current = NULL;
 
	return SUCCEEDED;
      }
 
      /* redefine NARGS */
      if (redefine("NARGS", (double)macro_stack[macro_active - 1].supplied_arguments, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	return FAILED;
      if (redefine("nargs", (double)macro_stack[macro_active - 1].supplied_arguments, NULL, DEFINITION_TYPE_VALUE, 0) == FAILED)
	return FAILED;
 
      macro_runtime_current = &macro_stack[macro_active - 1];
 
      return SUCCEEDED;
    }
 
    return EVALUATE_TOKEN_NOT_IDENTIFIED;
  }
 
 
  /* 8BIT */
 
  if (strcmp(cp, "8BIT") == 0) {
    xbit_size = 8;
    return SUCCEEDED;
  }
 
  /* 16BIT */
 
  if (strcmp(cp, "16BIT") == 0) {
    xbit_size = 16;
    return SUCCEEDED;
  }
 
 
  /* PRINTT */
 
  if (strcmp(cp, "PRINTT") == 0) {
 
    char t[256];
    int s, u;
 
 
    inz = input_number();
 
    if (inz != INPUT_NUMBER_STRING) {
      print_error(".PRINTT needs a string.\n", ERROR_DIR);
      return FAILED;
    }
 
    for (s = 0, u = 0; label[s] != 0;) {
      if (label[s] == '\\' && label[s + 1] == 'n') {
#ifdef MSDOS
	t[u++] = '\r';
	t[u++] = '\n';
#else
	t[u++] = '\n';
#endif
	s += 2;
      }
      else if (label[s] == '\\' && label[s + 1] == '\\') {
	t[u++] = '\\';
	s += 2;
      }
      else
	t[u++] = label[s++];
    }
 
    t[u] = 0;
    if (quiet == NO)
      printf("%s", t);
 
    return SUCCEEDED;
  }
 
  /* PRINTV */
 
  if (strcmp(cp, "PRINTV") == 0) {
 
    int m;
 
 
    if (get_next_token() == FAILED)
      return FAILED;
 
    if (strcaselesscmp(tmp, "HEX") == 0)
      m = 0;
    else if (strcaselesscmp(tmp, "DEC") == 0)
      m = 1;
    else {
      print_error(".PRINTV needs to know the format of the output, HEX or DEC.\n", ERROR_DIR);
      return FAILED;
    }
 
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED) {
      if (q == INPUT_NUMBER_ADDRESS_LABEL) {
	sprintf(emsg, "\"%s\" is not known.\n", label);
	print_error(emsg, ERROR_DIR);
      }
      print_error(".PRINTV can only print currently known values.\n", ERROR_DIR);
      return FAILED;
    }
 
    if (quiet == NO) {
      if (m == 0)
	printf("%x", d);
      else
	printf("%d", d);
    }
 
    return SUCCEEDED;
  }
 
  /* SEED */
 
  if (strcmp(cp, "SEED") == 0) {
 
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED) {
      print_error(".SEED needs a seed value for the randon number generator.\n", ERROR_DIR);
      return FAILED;
    }
 
    /* reseed the random number generator */
    srand(d);
 
    return SUCCEEDED;
  }
 
  /* DBRND/DWRND */
  if (strcmp(cp, "DBRND") == 0 || strcmp(cp, "DWRND") == 0) {
 
    int o, c, min, max, f;
 
 
    /* bytes or words? */
    if (cp[1] == 'W')
      o = 1;
    else
      o = 0;
 
    /* get the count */
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED) {
      sprintf(emsg, ".%s needs the amount of random numbers.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    c = d;
 
    if (c <= 0) {
      sprintf(emsg, ".%s needs that the amount of random numbers is > 0.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    /* get min */
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED) {
      sprintf(emsg, ".%s needs the min value.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    min = d;
 
    /* get max */
    q = input_number();
    if (q == FAILED)
      return FAILED;
    if (q != SUCCEEDED) {
      sprintf(emsg, ".%s needs the max value.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    max = d;
 
    if (min >= max) {
      sprintf(emsg, ".%s needs that min < max.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    /* generate the numbers */
    for (f = 0; f < c; f++) {
      d = (rand() % (max-min+1)) + min;
 
      if (o == 1) {
	if (d < -32768 || d > 65535) {
	  sprintf(emsg, ".%s: Expected a 16bit value, computed %d.\n", cp, d);
	  print_error(emsg, ERROR_NONE);
	  return FAILED;
	}
	fprintf(file_out_ptr, "y %d ", d);
      }
      else {
	if (d > 255 || d < -127) {
	  sprintf(emsg, ".%s: Expected a 8bit value, computed %d.\n", cp, d);
	  print_error(emsg, ERROR_NONE);
	  return FAILED;
	}
	fprintf(file_out_ptr, "d%d ", d);
      }
    }
 
    return SUCCEEDED;
  }
 
  /* DWSIN/DBSIN/DWCOS/DBCOS */
 
  if (strcmp(cp, "DWSIN") == 0 || strcmp(cp, "DBSIN") == 0 || strcmp(cp, "DWCOS") == 0 || strcmp(cp, "DBCOS") == 0) {
 
    double m, a, s, n;
    int p, c, o, f;
 
 
    if (cp[1] == 'W')
      o = 1;
    else
      o = 2;
    if (cp[2] == 'S')
      f = 1;
    else
      f = 2;
 
    input_float_mode = ON;
    p = input_number();
    input_float_mode = OFF;
    if (p != SUCCEEDED && p != INPUT_NUMBER_FLOAT) {
      sprintf(emsg, ".%s needs a value for starting angle.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (p == SUCCEEDED)
      a = d;
    else
      a = flo;
 
    if (input_number() != SUCCEEDED || d < 0) {
      sprintf(emsg, ".%s needs an non-negative integer value for additional angles.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    c = d;
 
    input_float_mode = ON;
    p = input_number();
    if (p != SUCCEEDED && p != INPUT_NUMBER_FLOAT) {
      sprintf(emsg, ".%s needs a value for angle step.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (p == SUCCEEDED)
      s = d;
    else
      s = flo;
 
    p = input_number();
    if (p != SUCCEEDED && p != INPUT_NUMBER_FLOAT) {
      sprintf(emsg, ".%s needs a value to multiply the result with.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (p == SUCCEEDED)
      m = d;
    else
      m = flo;
 
    p = input_number();
    input_float_mode = OFF;
    if (p != SUCCEEDED && p != INPUT_NUMBER_FLOAT) {
      sprintf(emsg, ".%s needs a value to add to the result.\n", cp);
      print_error(emsg, ERROR_DIR);
      return FAILED;
    }
 
    if (p == SUCCEEDED)
      n = d;
    else
      n = flo;
 
    for (c++; c > 0; c--) {
      while (a >= 360)
	a -= 360;
 
      if (f == 1)
	d = (int)((m * sin(a*M_PI/180)) + n);
      else
	d = (int)((m * cos(a*M_PI/180)) + n);
 
      if (o == 1) {
	if (d < -32768 || d > 65535) {
	  sprintf(emsg, ".%s: Expected a 16bit value, computed %d.\n", cp, d);
	  print_error(emsg, ERROR_NONE);
	  return FAILED;
	}
	fprintf(file_out_ptr, "y %d ", d);
      }
      else {
	if (d > 255 || d < -127) {
	  sprintf(emsg, ".%s: Expected a 8bit value, computed %d.\n", cp, d);
	  print_error(emsg, ERROR_NONE);
	  return FAILED;
	}
	fprintf(file_out_ptr, "d%d ", d);
      }
 
      a += s;
    }
 
    return SUCCEEDED;
  }
 
  /* FAIL */
 
  if (strcmp(cp, "FAIL") == 0) {
    print_error("HALT: .FAIL found.\n", ERROR_NONE);
 
    /* make a silent exit */
    exit(0);
  }
 
  /* UNDEF/UNDEFINE */
 
  if (strcmp(cp, "UNDEF") == 0 || strcmp(cp, "UNDEFINE") == 0) {
 
    char c[16];
 
 
    strcpy(c, cp);
 
    q = 0;
    while (1) {
      ind = input_next_string();
      if (ind == FAILED)
	return FAILED;
      if (ind == INPUT_NUMBER_EOL) {
	if (q != 0) {
	  next_line();
	  return SUCCEEDED;
	}
	sprintf(emsg, ".%s requires definition name(s).\n", c);
	print_error(emsg, ERROR_DIR);
	return FAILED;
      }
 
      q++;
 
      if (undefine(tmp) == FAILED) {
	sprintf(emsg, "Could not .%s \"%s\".\n", c, tmp);
	print_error(emsg, ERROR_WRN);
      }
    }
 
    return SUCCEEDED;
  }
 
  /* ASM */
 
  if (strcmp(cp, "ASM") == 0)
    return SUCCEEDED;
 
  /* ENDASM */
 
  if (strcmp(cp, "ENDASM") == 0) {
 
    int assem = 1, x;
 
 
    while (1) {
      x = i;
      q = get_next_token();
      if (q == GET_NEXT_TOKEN_STRING)
	continue;
 
      /* end of file? */
      if (strcmp(tmp, ".E") == 0) {
	i = x;
	return SUCCEEDED;
      }
      if (strcaselesscmp(tmp, ".ASM") == 0) {
	assem--;
	if (assem == 0)
	  return SUCCEEDED;
      }
      if (strcaselesscmp(tmp, ".ENDASM") == 0)
	assem++;
    }
  }
 
  sprintf(emsg, "Unknown directive \"%s\".\n", tmp);
  print_error(emsg, ERROR_NONE);
 
  return FAILED;
}
 
 
int find_next_point(char *n) {
 
  int r, m, l;
 
 
  l = active_file_info_last->line_current;
  /* find the next compiling point */
  r = 1;
  m = macro_active;
  /* disable macro decoding */
  macro_active = 0;
  while (get_next_token() != FAILED) {
    if (tmp[0] == '.') {
      if (strcmp(cp, "ENDIF") == 0)
	r--;
      if (strcmp(cp, "ELSE") == 0 && r == 1)
	r--;
      if (strcmp(cp, "E") == 0)
	break;
      if (strcmp(cp, "IFDEF") == 0 || strcmp(cp, "IFNDEF") == 0 || strcmp(cp, "IFGR") == 0 || strcmp(cp, "IFLE") == 0 ||
	  strcmp(cp, "IFEQ") == 0 || strcmp(cp, "IFNEQ") == 0 || strcmp(cp, "IFDEFM") == 0 || strcmp(cp, "IFNDEFM") == 0 ||
	  strcmp(cp, "IF") == 0 || strcmp(cp, "IFGREQ") == 0 || strcmp(cp, "IFLEEQ") == 0 || strcmp(cp, "IFEXISTS") == 0)
	r++;
    }
    if (r == 0) {
      if (strcmp(cp, "ELSE") == 0)
	ifdef++;
      macro_active = m;
      return SUCCEEDED;
    }
  }
 
  /* return the condition's line number */
  active_file_info_last->line_current = l;
  sprintf(emsg, ".%s must end to .ENDIF/.ELSE.\n", n);
  print_error(emsg, ERROR_DIR);
 
  return FAILED;
}
 
 
void delete_stack(struct stack *s) {
 
  if (s == NULL) {
    sprintf(emsg, "Deleting a non-existing computation stack. This can lead to problems.\n");
    print_error(emsg, ERROR_WRN);
    return;
  }
 
  free(s->stack);
  free(s);
}
 
 
int get_new_definition_data(int *b, char *c, int *size, double *data) {
 
  int a, x, n, s;
 
 
  x = input_number();
  a = x;
  n = 0;
  s = 0;
 
  if (x == INPUT_NUMBER_ADDRESS_LABEL) {
    /* address label -> stack */
    stack_create_label_stack(label);
    x = INPUT_NUMBER_STACK;
  }
 
  if (x == INPUT_NUMBER_STACK) {
    *b = stacks_tmp->id;
    stacks_tmp->position = STACK_POSITION_DEFINITION;
    x = input_number();
    if (x != INPUT_NUMBER_EOL) {
      print_error("A computation cannot be output as a string.\n", ERROR_DIR);
      return SUCCEEDED;
    }
    return INPUT_NUMBER_STACK;
  }
 
  while (x != INPUT_NUMBER_EOL) {
    /* the first fetch will conserve both classes */
    if (n == 0) {
      if (x == SUCCEEDED)
	*b = d;
      else if (x == INPUT_NUMBER_STRING) {
	strcpy(c, label);
	s = strlen(label);
      }
      else if (x == INPUT_NUMBER_FLOAT) {
	*data = flo;
	*b = flo;
      }
      else
	return x;
 
      n++;
      x = input_number();
      continue;
    }
    /* the next fetches will produce strings */
    else if (n == 1 && (a == SUCCEEDED || a == INPUT_NUMBER_FLOAT)) {
      if (*b > 255) {
	c[0] = (*b & 255);
	c[1] = (*b >> 8) & 255;
	c[2] = 0;
	s = 2;
      }
      else {
	c[0] = *b;
	c[1] = 0;
	s = 1;
      }
      a = INPUT_NUMBER_STRING;
    }
 
    /* transform floats to integers */
    if (x == INPUT_NUMBER_FLOAT) {
      d = flo;
      x = SUCCEEDED;
    }
 
    if (x == INPUT_NUMBER_STRING) {
      strcpy(&c[s], label);
      s += strlen(label);
    }
    else if (x == SUCCEEDED) {
      if (d > 255) {
	c[s] = (d & 255);
	c[s + 1] = (d >> 8) & 255;
	c[s + 2] = 0;
	s += 2;
      }
      else {
	c[s] = d;
	c[s + 1] = 0;
	s++;
      }
    }
    else
      return x;
 
    n++;
    x = input_number();
  }
 
  next_line();
 
  if (a == INPUT_NUMBER_STRING)
    c[s] = 0;
 
  *size = s;
 
  return a;
}
 
 
int export_a_definition(char *n) {
 
  struct export_def *e;
 
 
  /* don't export it twice or more often */
  e = export_first;
  while (e != NULL) {
    if (strcmp(e->name, n) == 0) {
      sprintf(emsg, "\"%s\" was .EXPORTed for the second time.\n", n);
      print_error(emsg, ERROR_WRN);
      return SUCCEEDED;
    }
    e = e->next;
  }
 
  e = malloc(sizeof(struct export_def));
  if (e == NULL) {
    sprintf(emsg, "Out of memory while allocating room for \".EXPORT %s\".\n", n);
    print_error(emsg, ERROR_DIR);
    return FAILED;
  }
 
  strcpy(e->name, n);
  e->next = NULL;
 
  if (export_first == NULL) {
    export_first = e;
    export_last = e;
  }
  else {
    export_last->next = e;
    export_last = e;
  }
 
  return SUCCEEDED;
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.