199 lines
4.9 KiB
C
199 lines
4.9 KiB
C
/* $NetBSD: gsp_sym.c,v 1.10 2025/11/24 08:04:28 nia Exp $ */
|
|
/*
|
|
* GSP assembler - symbol table
|
|
*
|
|
* Copyright (c) 1993 Paul Mackerras.
|
|
* All rights reserved.
|
|
*
|
|
* 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 above copyright
|
|
* 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. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "gsp_ass.h"
|
|
|
|
#define NHASH 64 /* must be power of 2 */
|
|
|
|
symbol symbol_hash[NHASH];
|
|
|
|
void define_sym(char *, unsigned, unsigned, int);
|
|
|
|
symbol
|
|
lookup(char *id, bool makeit)
|
|
{
|
|
symbol ptr, p, *pp;
|
|
int h;
|
|
char *ip;
|
|
|
|
h = 0;
|
|
for( ip = id; *ip != 0; )
|
|
h = (h << 1) + *ip++;
|
|
h &= NHASH-1;
|
|
for( pp = &symbol_hash[h]; (p = *pp) != NULL; pp = &p->next )
|
|
if( (h = strcmp(id, p->name)) == 0 )
|
|
return p;
|
|
else if( h < 0 )
|
|
break;
|
|
if( !makeit )
|
|
return NULL;
|
|
ptr = malloc(sizeof(struct symbol) + strlen(id));
|
|
ptr->ndefn = 0;
|
|
ptr->flags = 0;
|
|
ptr->value = 0;
|
|
ptr->lineno = NOT_YET;
|
|
strcpy(ptr->name, id);
|
|
*pp = ptr;
|
|
ptr->next = p;
|
|
ptr->nlab = NULL;
|
|
return ptr;
|
|
}
|
|
|
|
void
|
|
define_sym(char *id, unsigned val, unsigned lno, int flags)
|
|
{
|
|
symbol ptr;
|
|
|
|
ptr = lookup(id, TRUE);
|
|
if( (ptr->flags & SET_LABEL) == 0 ){
|
|
if( ptr->ndefn >= 2 ){
|
|
perr("Multiply defined label %s", id);
|
|
if( (flags & SET_LABEL) != 0 )
|
|
return;
|
|
} else if( pass2 && ptr->value != val )
|
|
perr("Phase error on label %s (%#x -> %#x)",
|
|
id, ptr->value, val);
|
|
}
|
|
ptr->flags = flags;
|
|
ptr->ndefn += 1;
|
|
ptr->value = val;
|
|
ptr->lineno = lno;
|
|
}
|
|
|
|
void
|
|
set_label(char *id)
|
|
{
|
|
if( id != NULL ){
|
|
define_sym(id, pc, lineno, DEFINED);
|
|
if( pass2 )
|
|
do_list_pc();
|
|
}
|
|
}
|
|
|
|
void
|
|
do_asg(char *name, expr value, int flags)
|
|
{
|
|
int32_t val;
|
|
unsigned lno;
|
|
|
|
if( eval_expr(value, &val, &lno) )
|
|
flags |= DEFINED;
|
|
if( lno < lineno )
|
|
lno = lineno;
|
|
define_sym(name, val, lno, flags);
|
|
if( pass2 )
|
|
do_show_val(val);
|
|
}
|
|
|
|
void
|
|
set_numeric_label(int lnum)
|
|
{
|
|
symbol bp, fp;
|
|
struct numlab *nl;
|
|
char id[32];
|
|
|
|
/* define the backward reference symbol */
|
|
sprintf(id, "%dB", lnum);
|
|
bp = lookup(id, TRUE);
|
|
bp->flags = NUMERIC_LABEL | DEFINED;
|
|
bp->value = pc;
|
|
bp->lineno = lineno;
|
|
|
|
/* look up the forward reference symbol */
|
|
id[strlen(id) - 1] = 'F';
|
|
fp = lookup(id, TRUE);
|
|
|
|
if( !pass2 ){
|
|
/* Record a new numeric label and link it into the
|
|
chain. fp->nlab points to the head of the chain,
|
|
bp->nlab points to the tail. */
|
|
new(nl);
|
|
nl->value = pc;
|
|
nl->lineno = lineno;
|
|
nl->next = NULL;
|
|
if( bp->nlab == NULL )
|
|
fp->nlab = nl;
|
|
else
|
|
bp->nlab->next = nl;
|
|
bp->nlab = nl;
|
|
fp->flags = NUMERIC_LABEL;
|
|
} else {
|
|
/* Advance to the next numeric label entry in the chain
|
|
and update the value of the forward reference symbol. */
|
|
if( pc != fp->value )
|
|
perr("Phase error on numeric label %d (%#x -> %#x)",
|
|
lnum, fp->value, pc);
|
|
nl = fp->nlab;
|
|
nl = nl->next;
|
|
if( nl == NULL ){
|
|
/* no more labels of this number */
|
|
/* forward references are now undefined */
|
|
fp->flags &= ~DEFINED;
|
|
fp->lineno = NOT_YET;
|
|
fp->value = 0;
|
|
} else {
|
|
fp->lineno = nl->lineno;
|
|
fp->value = nl->value;
|
|
fp->nlab = nl;
|
|
}
|
|
do_list_pc();
|
|
}
|
|
}
|
|
|
|
/* At the beginning of pass 2, reset all of the numeric labels.
|
|
Backward references become undefined, forward references are defined
|
|
by the first instance of the label. */
|
|
void
|
|
reset_numeric_labels()
|
|
{
|
|
symbol p;
|
|
struct numlab *nl;
|
|
int h;
|
|
|
|
for( h = 0; h < NHASH; ++h ) {
|
|
for( p = symbol_hash[h]; p != NULL; p = p->next ) {
|
|
if( (p->flags & NUMERIC_LABEL) != 0 ) {
|
|
if( (p->flags & DEFINED) != 0 ) {
|
|
/* a backward reference */
|
|
p->flags &= ~DEFINED;
|
|
} else {
|
|
/* a forward reference */
|
|
p->flags |= DEFINED;
|
|
nl = p->nlab;
|
|
p->value = nl->value;
|
|
p->lineno = nl->lineno;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|