Source file: /~heha/hs/gputils64-210929.zip/gputils/labelset.cpp

/* Label list handler.
   Copyright 2014	Molnár Károly
   Copyright 2016	Molnár Károly
*/

#include "stdhdr.h"

#include "libgputils.h"
#include "labelset.h"

void _cdecl yyerror(const char *Text, ...) {
  va_list ap;
  char    buf[BUFSIZ];

  snprintf(buf, sizeof(buf), "Error: %s\n", Text);
  va_start(ap, Text);
  vfprintf(stderr, buf, ap);
  va_end(ap);
}

static const char *section_names[SECT_SPEC_MAX_NUM] = { "CODE", "DATA", "EEDATA" };

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

void lset_init(lset_section_root_t *Root, const char *File_name) {
  if (!Root) return;
  Root->file_name      = GP_Strdup(File_name);
  Root->is_data        = 0;
  Root->section_number = 0;
  Root->section_global = NULL;
  Root->section_first  = NULL;
  Root->section_actual = NULL;
  Root->section_last   = NULL;
  Root->sections[SECT_SPEC_CODE]   = NULL;
  Root->sections[SECT_SPEC_DATA]   = NULL;
  Root->sections[SECT_SPEC_EEDATA] = NULL;
}

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

void lset_symbol_t::list() const{
  const char *type;

  type = (attr & CSYM_DATA) ? " (DATA)" : "";

  if (attr & CSYM_END) {
    printf("  [line %4i]: \"%s\" = %li:%li%s\n", line_number, name,
           start, end, type);
  }
  else {
    printf("  [line %4i]: \"%s\" = %li%s\n", line_number, name,
           start, type);
  }
}

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

void lset_section_t::lset_symbol_list_all(bool Use_table) const{
  unsigned i;
  ;

  if (!symbol_number) return;
  lset_symbol_t *sym = symbol_first;
  if (!sym) return;

  if (Use_table && symbol_table) {
    i = 0;
    
    do {
      symbol_table[i]->list();
      ++i;
    }
    while (i < symbol_number);
  }else{
    do {
      sym->list();
      sym = sym->next;
    }
    while (sym);
  }
}

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

lset_symbol_t*lset_symbol_find(const lset_section_t *Section, const char *Name) {
  lset_symbol_t *sym;

  if (!Section || !Name ||
      !Section->symbol_number || !(sym = Section->symbol_first)) return NULL;
  do {
    if (!strcmp(sym->name, Name)) break;
    sym = sym->next;
  }
  while (sym);

  return sym;
}

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

lset_symbol_t*lset_symbol_find_addr(const lset_section_t *Section, long Start_addr, long End_addr, int Use_table) {
  int            i_min;
  int            i_mid;
  int            i_max;
  long           sym_end;
  long           tmp;
  lset_symbol_t *sym;

  if ((Section == NULL) || (Section->symbol_number == 0)) {
    return NULL;
  }

  if (End_addr < 0) {
    End_addr = Start_addr;
  }
  else {
    if (Start_addr > End_addr) {
      tmp = Start_addr;
      Start_addr = End_addr;
      End_addr = tmp;
    }
  }

  if (Use_table) {
    if (!Section->symbol_table) return NULL;

    i_min = 0;
    i_max = Section->symbol_number - 1;
    while (i_max >= i_min) {
      i_mid   = i_min + ((i_max - i_min) >> 1);
      sym     = Section->symbol_table[i_mid];
      sym_end = (sym->attr & CSYM_END) ? sym->end : sym->start;

      if (sym_end < End_addr) {
        i_min = i_mid + 1;
      }
      else if (sym->start > Start_addr) {
        i_max = i_mid - 1;
      }
      else return sym;
    }
  }
  else {
    if (!(sym = Section->symbol_first)) return NULL;

    do {
      sym_end = (sym->attr & CSYM_END) ? sym->end : sym->start;

      if (((sym->start <= Start_addr) && (Start_addr <= sym->end)) ||
          ((sym->start <= End_addr)   && (End_addr   <= sym->end)) ||
          ((Start_addr <= sym->start) && (sym->start <= End_addr)) ||
          ((Start_addr <= sym->end)   && (sym->end   <= End_addr))) {
        /* Partial or complete overlap. */
        return sym;
      }

      sym = sym->next;
    }
    while (sym);
  }

  return NULL;
}

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

lset_symbol_t *
lset_symbol_new(lset_section_t *Section, const char *Name, long Start, long End, unsigned Attr,
                int Line_number)
{
  lset_symbol_t *sym;

  if (lset_symbol_find(Section, Name)) {
    yyerror("In line %i, already existing symbol: %s", Line_number, Name);
    exit(1);
  }

  if ((Attr & (CSYM_START | CSYM_END)) == (CSYM_START | CSYM_END)) {
    if (Start == End) {
      yyerror("In line %i, the \"start\" value (%li) equal the \"end\" value (%li) in the \"%s\" symbol!",
              Line_number, Start, End, Name);
      exit(1);
    }
    else if (Start > End) {
      yyerror("In line %i, the \"start\" value (%li) greater than the \"end\" value (%li) in the \"%s\" symbol!",
              Line_number, Start, End, Name);
      exit(1);
    }
  }

  if (!Section) {
    yyerror("No existing section!");
    exit(1);
  }

  if (Section->symbol_number >= DSYMBOL_MAX) {
    yyerror("Out of memory.");
    exit(1);
  }

  sym = new lset_symbol_t;
  memset(sym,0,sizeof*sym);

  if (!Section->symbol_first) Section->symbol_first = sym;

  if (Section->symbol_last) {
    Section->symbol_last->next = sym;
    sym->prev = Section->symbol_last;
  }

  Section->symbol_last   = sym;
  Section->symbol_actual = sym;
  ++Section->symbol_number;

  sym->name        = GP_Strdup(Name);
  sym->start       = Start;
  sym->end         = End;
  sym->attr        = Attr;
  sym->line_number = Line_number;
  return sym;
}

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

static int _cdecl _symbol_cmp(const void *P0, const void *P1) {
  const lset_symbol_t &sym0   = **(const lset_symbol_t **)P0;
  const lset_symbol_t &sym1   = **(const lset_symbol_t **)P1;
  long                 start0 = sym0.start;
  long                 start1 = sym1.start;

  if (start0 < start1) return -1;
  if (start0 > start1) return 1;
  return 0;
}

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

void lset_symbol_make_table(lset_section_t *Section) {
  if (!Section || !Section->symbol_number) return;
  lset_symbol_t *sym = Section->symbol_first;
  if (!sym) return;
  if (Section->symbol_table) delete[] Section->symbol_table;

  Section->symbol_table = new lset_symbol_t*[Section->symbol_number];
  memset(Section->symbol_table,0,sizeof*Section->symbol_table*Section->symbol_number);

  unsigned i = 0;
  do {
    Section->symbol_table[i] = sym;
    ++i;
    sym = sym->next;
  }while ((sym) && (i < Section->symbol_number));

  if (i != Section->symbol_number) {
    yyerror("Wrong the number of symbols: %u != %u", i != Section->symbol_number);
    exit(1);
  }

  qsort(Section->symbol_table, Section->symbol_number, sizeof(lset_symbol_t *), _symbol_cmp);
}

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

static void _check_bounds(const lset_section_t *Section, const lset_symbol_t *Symbol) {
  unsigned         i;
  unsigned         k;
  const lset_symbol_t *sym;

  i = 0;
  do {
    sym = Section->symbol_table[i];
    ++i;

    if (sym != Symbol) {
      k  = (sym->attr    & CSYM_END) ? 2 : 0;
      k |= (Symbol->attr & CSYM_END) ? 1 : 0;

      switch (k) {
        case 0:
        default: {
	  if (sym->start == Symbol->start) {
            yyerror("Two symbols there is at same address: ([line %i]: \"%s\"{%li}) == ([line %i]: \"%s\"{%li})",
                    sym->line_number, sym->name, sym->start,
                    Symbol->line_number, Symbol->name, Symbol->start);
            exit(1);
          }
          break;
        }

        case 1: {
          /* The Symbol is a range. */
          if (Symbol->start <= sym->start && sym->start <= Symbol->end) {
            yyerror("There is a symbol the area of an other symbol: ([line %i]: \"%s\"{%li:%li}) == ([line %i]: \"%s\"{%li})",
                    Symbol->line_number, Symbol->name, Symbol->start, Symbol->end,
                    sym->line_number, sym->name, sym->start);
            exit(1);
          }
          break;
        }

        case 2: {
          /* The sym is a range. */
          if (sym->start <= Symbol->start && Symbol->start <= sym->end) {
            yyerror("There is a symbol the area of an other symbol: ([line %i]: \"%s\"{%li:%li}) == ([line %i]: \"%s\"{%li})",
                    sym->line_number, sym->name, sym->start, sym->end,
                    Symbol->line_number, Symbol->name, Symbol->start);
            exit(1);
          }
          break;
        }

        case 3: {
          /* The sym and the Symbol is a range. */
          if ((sym->start <= Symbol->start && Symbol->start <= sym->end)
	   || (sym->start <= Symbol->end   && Symbol->end   <= sym->end)
	   || (Symbol->start <= sym->start && sym->start <= Symbol->end)
	   || (Symbol->start <= sym->end   && sym->end   <= Symbol->end)) {
            yyerror("Overlap there is areas of this symbols: ([line %i]: \"%s\"{%li:%li}) -- ([line %i]: \"%s\"{%li:%li})",
                    sym->line_number, sym->name, sym->start, sym->end,
                    Symbol->line_number, Symbol->name, Symbol->start, Symbol->end);
            exit(1);
          }
          break;
        }
      }
    }
  } while (i < Section->symbol_number);
}

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

void
lset_symbol_check_bounds(const lset_section_t *Section)
{
  unsigned i;

  if ((Section == NULL) || (Section->symbol_number == 0) || (Section->symbol_table == NULL)) {
    return;
  }

  i = 0;
  do {
    _check_bounds(Section, Section->symbol_table[i]);
    ++i;
  } while (i < Section->symbol_number);
}

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

void
lset_symbol_check_absolute_limits(const lset_section_t *Section, long Min, long Max)
{
  unsigned         i;
  const lset_symbol_t *sym;

  if ((Section == NULL) || (Section->symbol_number == 0) || (Section->symbol_table == NULL)) {
    return;
  }

  i = 0;
  do {
    sym = Section->symbol_table[i];
    ++i;

    if (sym->attr & CSYM_END) {
      if (sym->start < Min) {
        yyerror("The starting address of area of the symbol is less than the minimum value: ([line %i]: \"%s\"{%li}) < %li",
                sym->line_number, sym->name, sym->start, Min);
        exit(1);
      }
      else if (sym->start > Max) {
        yyerror("The starting address of area of the symbol is greater than the minimum value: ([line %i]: \"%s\"{%li}) > %li",
                sym->line_number, sym->name, sym->start, Max);
        exit(1);
      }
      else if (sym->end < Min) {
        yyerror("The ultimate address of area of the symbol is less than the maximum value: ([line %i]: \"%s\"{%li}) < %li",
                sym->line_number, sym->name, sym->end, Min);
        exit(1);
      }
      else if (sym->end > Max) {
        yyerror("The ultimate address of area of the symbol is greater than the maximum value: ([line %i]: \"%s\"{%li}) > %li",
                sym->line_number, sym->name, sym->end, Max);
        exit(1);
      }
    }
    else {
      if (sym->start < Min) {
        yyerror("The address of symbol is less than the minimum value: ([line %i]: \"%s\"{%li}) < %li",
                sym->line_number, sym->name, sym->start, Min);
        exit(1);
      }
      else if (sym->start > Max) {
        yyerror("The address of symbol is greater than the maximum value: ([line %i]: \"%s\"{%li}) > %li",
                sym->line_number, sym->name, sym->start, Max);
        exit(1);
      }
    }
  }
  while (i < Section->symbol_number);
}

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

void
lset_symbol_check_align(const lset_section_t *Section, long Align)
{
  unsigned         i;
  long                 aligned;
  const lset_symbol_t *sym;

  if ((Section == NULL) || (Section->symbol_number == 0) || (Section->symbol_table == NULL)) {
    return;
  }

  i = 0;
  do {
    sym = Section->symbol_table[i];
    ++i;

    if (sym->attr & CSYM_END) {
      if ((sym->start % Align) != 0) {
        yyerror("The starting address of area of symbol not aligned: ([line %i]: \"%s\"{%li}) != %li",
                sym->line_number, sym->name, sym->start, (sym->start / Align) * Align);
        exit(1);
      }

      aligned = ((sym->end / Align) * Align) + Align - 1;

      if (sym->end != aligned) {
        yyerror("The ultimate address of area of the symbol not aligned: ([line %i]: \"%s\"{%li}) != %li",
                sym->line_number, sym->name, sym->end, aligned);
        exit(1);
      }
    }
    else {
      if ((sym->start % Align) != 0) {
        yyerror("The address of symbol not aligned: ([line %i]: \"%s\"{%li}) != %li",
                sym->line_number, sym->name, sym->start, (sym->start / Align) * Align);
        exit(1);
      }
    }
  }
  while (i < Section->symbol_number);
}

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

void
lset_symbol_free_all(lset_section_t *Section)
{
  lset_symbol_t *sym;
  lset_symbol_t *s;

  if (Section == NULL) {
    return;
  }

  if (Section->symbol_number > 0) {
    if ((sym = Section->symbol_first)) {
      do {
        s = sym->next;
        free(sym->name);
        free(sym);
        sym = s;
      }
      while (sym);
    }

    Section->symbol_number = 0;
  }

  Section->symbol_first  = NULL;
  Section->symbol_actual = NULL;
  Section->symbol_last   = NULL;

  if (Section->symbol_table) {
    free(Section->symbol_table);
    Section->symbol_table = NULL;
  }
}

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

void
lset_section_list(const lset_section_root_t *Root)
{
  const lset_section_t *sect;

  if ((Root == NULL) || (Root->section_number == 0) || ((sect = Root->section_first) == NULL)) {
    return;
  }

  do {
    printf("\"%s\"\n", sect->name);
    sect = sect->next;
  }
  while (sect);
}

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

void lset_section_root_t::lset_section_full_list(bool Use_table) const{
  const lset_section_t *sect = section_global;

  if (sect) {
    printf("\"%s\"\n", sect->name);
    sect->lset_symbol_list_all(Use_table);
  }

  if (!section_number) return;
  sect = section_first;
  if (!sect) return;

  do {
    printf("\"%s\"\n", sect->name);
    sect->lset_symbol_list_all(Use_table);
    sect = sect->next;
  }
  while (sect);
}

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

lset_section_t* lset_section_find(const lset_section_root_t *Root, const char *Name) {
  lset_section_t *sect;

  if ((Root == NULL) || (Root->section_number == 0) || ((sect = Root->section_first) == NULL)) {
    return NULL;
  }

  do {
    if (strcmp(sect->name, Name) == 0) {
      break;
    }

    sect = sect->next;
  }
  while (sect);

  return sect;
}

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

lset_section_t* lset_section_make_global(lset_section_root_t *Root) {
  lset_section_t *sect;

  if (!Root) return NULL;
  if (Root->section_global) return Root->section_global;

  sect = new lset_section_t;
  memset(sect,0,sizeof*sect);

  Root->section_global = sect;
  sect->name = GP_Strdup(SECT_NAME_GLOBAL);
  return sect;
}

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

static bool _find_section_name(const char *Name) {
  unsigned i;

  for (i = 0; i < ARRAY_SIZE(section_names); ++i) {
    if (strcmp(Name, section_names[i]) == 0) {
      return true;
    }
  }

  return false;
}

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

static unsigned _print_section_names(char *Text, unsigned MaxLen) {
  unsigned  i;
  unsigned  len;
  const char   *fmt;

  len = 0;
  for (i = 0; i < ARRAY_SIZE(section_names); ++i) {
    switch (i) {
      case (ARRAY_SIZE(section_names) - 1): {
        fmt = "%s";
        break;
      }

      case (ARRAY_SIZE(section_names) - 2): {
        fmt = "%s or ";
        break;
      }

      default: {
        fmt = "%s, ";
      }
    }

    len += snprintf(&Text[len], MaxLen - len, fmt, section_names[i]);
  }

  return len;
}

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

lset_section_t* lset_section_new(lset_section_root_t *Root, const char *Name, int Line_number) {
  if (!Root || Root->section_number >= DSECTION_MAX || !Name) return NULL;

  if (strcmp(Name, SECT_NAME_GLOBAL) == 0) {
    yyerror("In line %i, the section name is reserved: %s", Line_number, Name);
    exit(1);
  }

  if (! _find_section_name(Name)) {
    char buf[BUFSIZ];
    _print_section_names(buf, sizeof buf);
    yyerror("In line %i, the name of section (%s) only can be: %s", Line_number, Name, buf);
    exit(1);
  }

  if (lset_section_find(Root, Name)) return NULL;

  lset_section_t*sect = new lset_section_t;
  if (!sect) return NULL;
  memset(sect,0,sizeof*sect);

  if (!Root->section_first) Root->section_first = sect;

  if (Root->section_last) {
    Root->section_last->next = sect;
    sect->prev = Root->section_last;
  }

  Root->section_last   = sect;
  Root->section_actual = sect;
  ++Root->section_number;

  sect->name = GP_Strdup(Name);
  sect->line_number = Line_number;
  return sect;
}

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

void lset_section_make_symbol_tables(lset_section_root_t *Root) {
  if (!Root) return;
  lset_section_t*sect = Root->section_global;
  if (sect) lset_symbol_make_table(sect);

  if (Root->section_number > 0) {
    if ((sect = Root->section_first)) {
      do {
        lset_section_t*s = sect->next;
        lset_symbol_make_table(sect);
        sect = s;
      }
      while (sect);
    }
  }
}

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

void lset_section_check_bounds(const lset_section_root_t *Root) {
  if (!Root) return;
  if (Root->section_number > 0) {
    const lset_section_t *sect = Root->section_first;
    if (sect) do {
      lset_symbol_check_bounds(sect);
      sect = sect->next;
    }while (sect);
  }
}

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

void
lset_sections_choose(lset_section_root_t *Root)
{
  unsigned i;

  if (Root == NULL) {
    return;
  }

  for (i = 0; i < ARRAY_SIZE(section_names); ++i) {
    Root->sections[i] = lset_section_find(Root, section_names[i]);
  }
}

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

static void
_delete_section(lset_section_t *Section)
{
  lset_symbol_free_all(Section);
  free(Section->name);
  free(Section);
}

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

void lset_delete(lset_section_root_t *Root) {
  lset_section_t *sect;
  lset_section_t *s;

  if (Root == NULL) {
    return;
  }

  if ((sect = Root->section_global)) {
    _delete_section(sect);
    Root->section_global = NULL;
  }

  if (Root->section_number > 0) {
    if ((sect = Root->section_first)) {
      do {
        s = sect->next;
        _delete_section(sect);
        sect = s;
      }
      while (sect);
    }

    Root->section_number = 0;
  }

  if (Root->file_name) {
    free(Root->file_name);
    Root->file_name = NULL;
  }

  Root->is_data        = 0;
  Root->section_first  = NULL;
  Root->section_actual = NULL;
  Root->section_last   = NULL;
  Root->sections[SECT_SPEC_CODE]   = NULL;
  Root->sections[SECT_SPEC_DATA]   = NULL;
  Root->sections[SECT_SPEC_EEDATA] = NULL;
}
Detected encoding: UTF-80