/* symtab.cpp */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include "symtab.h"
#include "exception.h"

void SymTab::loadSymTab (const char *source)
{
char *symfile = new char [strlen (source) + 1];
char *end = symfile + strlen (source) -4;
static char inbuf [1024];
SymFunIdx *curFun;
FILE *f;

	strcpy (symfile, source);
	if (*end  != '.') {	// Verify if there is the dot at the right place
		delete symfile;
		throw (new Exception ("Uncorrect s19 name (%s)", source));
	}
	strcpy (end, ".cdb");
	f = fopen (symfile, "r");
	if (!f) {
		throw (new Exception ("Can't find symbol file (%s)", symfile));
	}

	while (!feof (f)) {
		SymNode *tmpSymbol, *fndSymbol;
		if (fgets (inbuf, 1023, f)) {
			switch (inbuf [0]) {
				case 'S' :	// Symbol records
				case 'F' :	// Function records (uguali ai Symbol, ma con due campi in piu che non mi interessano)
					//	<S><:>{G | F<Filename> | L { <function> | ``-null-`` } }<$><Name><$><Level><$><Block><(><TypeRecord><)><,><AddressSpace><,><OnStack><,><Stack><,><[><Reg><,>{<Reg><,>}<]> 
					tmpSymbol = new SymNode (symbols, inbuf);
					if (symIdx.findEq (tmpSymbol)) {	// Esiste gia
						delete tmpSymbol;
					} else {
						symbols = tmpSymbol;
						symIdx.add (symbols);
						if (tmpSymbol->getVarType () == FUNCTION) {
							functions = new SymFunIdx (functions, tmpSymbol);
#ifdef TREEDEBUG
							printf ("Aggiunta funzione "); tmpSymbol->debPrint ();
#endif
						}
					}
					break;
				case 'L' :	// Linker records
					switch (inbuf [2]) {	// Subtypes of linker record
						case 'A' :	// ASM line record				<L><:><A><$><Filename><$><Line><:><EndAddress> 
						case 'C' :	// C line record				<L><:><C><$><Filename><$><Line><$><Level><$><Block><:><EndAddress>
							if (inbuf [2] == 'A') {
								asmSyms = -1;
							} else {
								cSyms = -1;
							}
						case 'G' :	// Global						<L><:><G><$><name><$><level><$><block><:><address> 
						case 'F' :	// File (Static)				<L><:>F<filename><$><name><$><level><$><block><:><address> 
						case 'L' :	// Local (Function)				<L><:>L<function><$><name><$><level><$><block><:><address> 
							tmpSymbol = new SymNode (symbols, inbuf);
							if (tmpSymbol -> hasIdx (SYMIDX)) {
								fndSymbol = symIdx.findEq (tmpSymbol);
							}  else {
								fndSymbol = NULL;
							}
							if (fndSymbol) {
								fndSymbol->merge (tmpSymbol);
								delete tmpSymbol;
								tmpSymbol = fndSymbol;
							} else {
								symbols = tmpSymbol;
								symIdx.add (symbols);
							}
							lineIdx.add (tmpSymbol);
							addrIdx.add (tmpSymbol);
							break;
						case 'X' :	// Linker Symbol End Address
							switch (inbuf [3]) {
								case 'G' :	// Global				<L><:><X><G><$><name><$><level><$><block><:><Address> 
								case 'F' :	// File (static)		<L><:><X>F<filename><$><name><$><level><$><block><:><Address> 
								case 'L' :	// Local (funcition)	<L><:><X>L<functionName><$><name><$><level><$><block><:><Address>
									tmpSymbol = new SymNode (symbols, inbuf);
									fndSymbol = symIdx.findEq (tmpSymbol);
									if (fndSymbol) {
										fndSymbol->merge (tmpSymbol);
										delete tmpSymbol;
									}
									break; 
								default:
									break;
							}
							break;
						default:
							break;
					}
					break;
			}
		}
	}
	/* Completa la tabella delle funzioni */
	for (curFun = functions; curFun; curFun = curFun->getNext ()) {
	SymNode *start = getSymFromAddr (curFun->getStartAd (), CLINE);
	SymNode *end = getSymFromAddr (curFun->getEndAd (), CLINE);
		curFun->addLines (start, end);
	}
	
	delete (symfile);
	fclose (f);
	
#ifdef TREEDEBUG
	// symIdx.debPrint ();
	
	SymFunIdx *t = functions;
	while (t) {
		t->debPrint ();
		t = t -> getNext ();
	}
    printf ("Fine scansione e aggiunta simboli\n");
#endif
}

/*
Funzione main da File blink.c L=0 B=0 Lin 37 a File blink.c L=2 B=2 Lin 55 Ok
Funzione getSym da File blink.c L=2 B=2 Lin 57 a File blink.c L=1 B=1 Lin 60 Ok
Funzione symPlay da File blink.c L=1 B=1 Lin 62 a File blink.c L=1 B=1 Lin 69 Ok
Funzione dummy_isr da File blink.c L=1 B=1 Lin 73 a File blink.c L=1 B=1 Lin 75 Ok

Funzione delay da File delay.c L=0 B=0 Lin 6 a File delay.c L=1 B=1 Lin 12 Ok
Funzione delay_asm da File delay.c L=1 B=1 Lin 14 a File delay.c L=1 B=1 Lin 21 Ok

 */

SymNode *SymTab::getSymFromAddr (int addr, symType t)
{
SymNode ref;
    ref.setAddress (addr);
    ref.setType (t);
	return addrIdx.findEq (&ref);
}

SymNode *SymTab::getSymFromLine (const char *file, int line)
{
SymNode ref;
char *sym = new char [strlen (file) + 1];
	strcpy (sym,file);
	ref.setFile (sym);
    ref.setLine (line);
	return lineIdx.findEq (&ref);
}

SymNode *SymTab::getSymFromSym (const char *name, const char *file, int line)
{
SymNode ref;
SymNode *function = getFunction (file, line);
char *sym = new char [strlen (name) + 1];
	strcpy (sym,name);

#ifdef TREEDEBUG
    printf ("Cerco '%s' - File %s Linea %d\n",sym, file, line);
#endif
	if (function) {	// the symbol is referebced inside a funcion: add file and funcrion name
	char *fileName = new char [strlen (file) + 1];
	char *funName = new char [strlen (function->getSym()) + 1];
		strcpy (fileName,file);
		strcpy (funName,function->getSym());
		ref.setFileAndFun (fileName, funName);
		// Serches for the level and block, based on the line
    	ref.setLine (line);
		function = lineIdx.findLt (&ref);
		if (function) {
#ifdef TREEDEBUG
			printf ("Linea - "); function->debPrint ();
#endif
			ref.setBlockAndLevel (function);
		}
	}
	ref.setSym (sym);
#ifdef TREEDEBUG
    printf ("Richiesta - "); ref.debPrint();
#endif
	function = symIdx.findEq (&ref);
#ifdef TREEDEBUG
    if (function) {
        printf ("Trovato - "); function -> debPrint();
    }
#endif
	return function;
//	return symIdx.findEq (&ref);
}

SymNode *SymTab::getFunction (const char *file, int line)
{
SymFunIdx *curFun;
	for (curFun = functions; curFun; curFun = curFun -> getNext ()) {
		if (curFun -> isFun (file, line)) {
			return curFun -> getFunction ();
		}
	}
	return NULL;
}


void SymTab::clean ()
{
	lineIdx.clean ();
	addrIdx.clean ();
	while (symbols) {
		SymNode *t;
		t = symbols;
		symbols = t -> getNext ();
		delete t;
	}
	while (functions) {
	SymFunIdx *t = functions;
		functions = functions -> getNext ();
		delete t;
	}
}


