//***********************************************************************************************************
//**
//**	hp21asm - Symbol Table Module
//**
//**	2014 Nov: split from single file / bh
//**
//***********************************************************************************************************
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "sym.h"
#include "util.h"

extern void			List_err();
extern FILE*			ListFile;


//* END Refs
//***********************************************************************************************************
//* Internals

typedef struct
 {
	char			name[SYM_MAXLEN*2+1];
	int			value;
 }
	SYM;


static SYM			sym__tbl[SYM_TBLSIZE];  
static int			sym__cnt;
static char			sym__curScope[SYM_MAXLEN+1];


//* END Internals
//***********************************************************************************************************
//* Interface

//----------------------------------------------------

void
Sym_init()
 {
	sym__cnt = 0;

	sym__curScope[0] = 0;
 }


//----------------------------------------------------
// Insert symbol into symbol table

void
Sym_define( symbol, value, doInsert )
	char			*symbol;
	int 			value;
	int			doInsert;
 {
	char			scopedSymbol[SYM_MAXLEN*2+1];
	int			i;

	if( strlen(symbol) > SYM_MAXLEN )
	 {	List_err( "Symbol name too long" );
		return;
	 }

	if( symbol[0] == '_' )							// local symbol if it starts with '_'
		sprintf( scopedSymbol, "%s%s", sym__curScope, symbol );		// prefix current scope to local symbol
	else
	 {	strcpy( scopedSymbol, symbol );					// global, use it as is
		strcpy( sym__curScope, symbol );				// also make it the current scope
	 }

	if( !doInsert )								// during 2nd pass just update current scope
		return;

	for( i=0; i<sym__cnt; ++i )						// simple scan of the table
		if( streql(sym__tbl[i].name,scopedSymbol) )
		 {	List_err( "Duplicate symbol" );
			return;
		 }

	if( sym__cnt == SYM_TBLSIZE )						// space available?
	 {	List_err( "Symbol table is full!" );
		return;
	 }

	strcpy( sym__tbl[sym__cnt].name, scopedSymbol );			// append to table
	sym__tbl[sym__cnt].value = value;
	++sym__cnt;
 }


//----------------------------------------------------
// Lookup a symbol and return it's value

int
Sym_find( symbol )
	char			*symbol;
 {
	char			scopedSymbol[SYM_MAXLEN*3+1];			// *3 because symbol parse allowed dbl length, and now could scope it
	int			i;

	if( symbol[0] == '_' )
		sprintf( scopedSymbol, "%s%s", sym__curScope, symbol );
	else
		strcpy( scopedSymbol, symbol );

	for( i=0; i<sym__cnt; ++i )
		if( streql(sym__tbl[i].name,scopedSymbol) )
			return( sym__tbl[i].value );

	List_err( "Undefined symbol" );
	return( 0 );
 }


//----------------------------------------------------

void
Sym_list()
 {
	int			i;

	fprintf( ListFile, "\nSymbol List:\n" );

	for( i=0; i<sym__cnt; ++i )
		fprintf( ListFile, "%*s %06o\n", -(SYM_MAXLEN*2*2/3), sym__tbl[i].name, sym__tbl[i].value );

	fprintf( ListFile, "\n" );
 }


//----------------------------------------------------

int
Sym_validChr( c )
	char			c;
 {
	return( isalnum(c) || c=='.' || c=='_' );
 }


//* EOF
//***********************************************************************************************************
