Files
Vasm/src/symbol.c

257 lines
5.7 KiB
C
Raw Normal View History

2023-04-25 14:36:25 -04:00
/*
* VASM VARCem Multi-Target Assembler.
* A simple table-driven assembler for several 8-bit target
* devices, like the 6502, 6800, 80x, Z80 et al series. The
* code originated from Bernd B<EFBFBD>ckmann's "asm6502" project.
*
* This file is part of the VARCem Project.
*
* Handle symbols.
*
* Version: @(#)symbol.c 1.0.3 2023/04/22
*
* Authors: Fred N. van Kempen, <waltje@varcem.com>
* Bernd B<EFBFBD>ckmann, <https://codeberg.org/boeckmann/asm6502>
*
* Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the entire
* above notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "global.h"
static symbol_t *symbols = NULL; // global symbol table
/* Create a new symbol, initialize to defaults. */
static symbol_t *
sym_new(const char *name)
{
symbol_t *sym;
sym = malloc(sizeof(symbol_t));
if (sym == NULL)
error(ERR_MEM, name);
memset(sym, 0x00, sizeof(symbol_t));
strcpy(sym->name, name);
return sym;
}
/* Return the first entry of the symbol table. */
symbol_t *
sym_table(void)
{
return symbols;
}
/* Delete all entries from a symbol table. */
void
sym_free(symbol_t **table)
{
symbol_t *sym, *next;
if (table == NULL)
table = &symbols;
sym = *table;
while (sym != NULL) {
if (sym->locals != NULL)
sym_free(&sym->locals);
next = sym->next;
free(sym);
sym = next;
}
*table = NULL;
}
/* Look up a symbol in one of the tables. */
symbol_t *
sym_lookup(const char *name, symbol_t **table)
{
symbol_t *ptr;
if (table == NULL)
table = &symbols;
for (ptr = *table; ptr != NULL; ptr = ptr->next) {
if (! strcmp(name, ptr->name))
return ptr;
}
return NULL;
}
char
sym_type(const symbol_t *sym)
{
switch (sym->kind) {
case KIND_LBL:
return 'L';
case KIND_VAR:
return 'V';
}
return '-';
}
symbol_t *
sym_aquire(const char *name, symbol_t **table)
{
symbol_t *ptr, *sym;
if (table == NULL)
table = &symbols;
sym = sym_lookup(name, table);
if (sym == NULL) {
sym = sym_new(name);
/* Insert symbol in alphabetical order. */
if ((*table == NULL) || (strcasecmp((*table)->name, name) > 0)) {
sym->next = *table;
*table = sym;
} else {
for (ptr = *table; ptr->next != NULL; ptr = ptr->next) {
if (strcasecmp(ptr->next->name, name) > 0)
break;
}
sym->next = ptr->next;
ptr->next = sym;
}
}
return sym;
}
symbol_t *
define_label(const char *id, uint16_t v, symbol_t *parent)
{
char nid[ID_LEN];
symbol_t *sym;
if (parent != NULL) {
if (*id == DOT_CHAR) {
/*
* This is a "dot label", meaning, its name
* has to be tacked on to the preceeding
* global label's name.
*/
if ((strlen(parent->name) + strlen(id)) >= ID_LEN)
error(ERR_IDLEN, id);
strcpy(nid, parent->name);
strcat(nid, id);
id = nid;
}
sym = sym_aquire(id, &parent->locals);
} else
sym = sym_aquire(id, NULL);
if (IS_VAR(sym) || (DEFINED(sym->value) && (sym->value.v != v)))
error(parent ? ERR_LOCAL_REDEF : ERR_REDEF, id);
sym->kind = KIND_LBL;
sym->filenr = filenames_idx;
sym->linenr = line;
sym->value.v = v;
sym->value.t = ((TYPE(sym->value) == TYPE_WORD)
? TYPE_WORD : NUM_TYPE(v)) | VALUE_DEFINED;
return sym;
}
void
define_variable(const char *id, value_t v)
{
symbol_t *sym;
sym = sym_aquire(id, NULL);
if (DEFINED(sym->value) && (sym->value.v != v.v))
error(ERR_REDEF, id);
sym->kind = KIND_VAR;
sym->filenr = filenames_idx;
sym->linenr = line;
/* if the type is already set do not change it */
sym->value.v = v.v;
if (TYPE(sym->value)) {
#if 0
if (NUM_TYPE(v.v) > TYPE(sym->value)) error(ERR_REDEF, id);
#endif
if (DEFINED(v))
SET_DEFINED(sym->value);
} else
sym->value.t = v.t;
/* If previously defined as label make it word sized. */
if (IS_LBL(sym))
SET_TYPE(sym->value, TYPE_WORD);
}
const char *
sym_print(const symbol_t *sym)
{
static char buff[32];
switch (TYPE(sym->value)) {
case TYPE_BYTE:
sprintf(buff, "%02X", sym->value.v & 0xff);
break;
case TYPE_WORD:
sprintf(buff, "%04X", sym->value.v & 0xffff);
break;
case TYPE_DWORD:
sprintf(buff, "%08X", sym->value.v);
break;
}
return buff;
}