/* 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-8 | 0
|