scyther/src/symbol.c

273 lines
4.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include "symbol.h"
#include "debug.h"
#include "memory.h"
/*
Symbol processor.
Stores symbols for the lexical scanner. Can later print them.
Implementation uses a hashtable, the size of which is defined in
symbols.h.
*/
/* accessible for externals */
int globalError; //!< If >0, stdout output goes to stderr (for e.g. terms)
/* external declarations */
extern int yylineno;
/* global declarations */
//! Symbol hash table.
Symbol symbtab[HASHSIZE];
//! List of available (freed) symbol blocks.
Symbol symb_list;
//! List of all allocated symbol blocks.
Symbol symb_alloc;
/* main code */
//! Open symbols code.
void
symbolsInit (void)
{
int i;
for (i = 0; i < HASHSIZE; i++)
symbtab[i] = NULL;
symb_list = NULL;
symb_alloc = NULL;
globalError = 0;
}
//! Close symbols code.
void
symbolsDone (void)
{
Symbol s;
while (symb_alloc != NULL)
{
s = symb_alloc;
symb_alloc = s->allocnext;
memFree (s, sizeof (struct symbol));
}
}
//! Create a memory block for a symbol.
/**
* Internal memory management is used.
*@return A pointer to a memory block of size struct.
*/
Symbol
get_symb (void)
{
Symbol t;
if (symb_list != NULL)
{
t = symb_list;
symb_list = symb_list->next;
}
else
{
t = (Symbol) memAlloc (sizeof (struct symbol));
t->allocnext = symb_alloc;
symb_alloc = t;
}
t->keylevel = INT_MAX;
return t;
}
//! Declare a symbol to be freed.
void
free_symb (const Symbol s)
{
if (s == NULL)
return;
s->next = symb_list;
symb_list = s;
}
//! Return the index in the hash table for the string.
int
hash (const char *s)
{
int hv = 0;
int i;
for (i = 0; s[i] != EOS; i++)
{
int v = (hv >> 28) ^ (s[i] & 0xf);
hv = (hv << 4) | v;
}
hv = hv & 0x7fffffff;
return hv % HASHSIZE;
}
//! Insert a string into the hash table.
void
insert (const Symbol s)
{
int hv;
if (s == NULL)
return; /* illegal insertion of empty stuff */
hv = hash (s->text);
s->next = symbtab[hv];
symbtab[hv] = s;
}
//! Find a string in the hash table.
Symbol
lookup (const char *s)
{
int hv;
Symbol t;
if (s == NULL)
return NULL;
hv = hash (s);
t = symbtab[hv];
while (t != NULL)
{
if (strcmp (t->text, s) == 0)
break;
else
t = t->next;
}
return t;
}
//! Print a symbol.
void
symbolPrint (const Symbol s)
{
if (s == NULL)
return;
/* TODO maybe action depending on type? */
eprintf ("%s", s->text);
}
//! Print all symbols
void
symbolPrintAll (void)
{
int i, count;
eprintf ("List of all symbols\n");
count = 0;
for (i = 0; i < HASHSIZE; i++)
{
Symbol sym;
sym = symbtab[i];
if (sym != NULL)
{
eprintf ("H%i:\t", i);
while (sym != NULL)
{
count++;
eprintf ("[%s]\t", sym->text);
sym = sym->next;
}
eprintf ("\n");
}
}
eprintf ("Total:\t%i\n", count);
}
//! Insert a string into the symbol table, if it wasn't there yet.
/**
* Also sets line numbers and type.
*\sa T_SYSCONST
*/
Symbol
symbolSysConst (const char *str)
{
Symbol symb;
symb = lookup (str);
if (symb == NULL)
{
symb = get_symb ();
symb->lineno = yylineno;
symb->type = T_SYSCONST;
symb->text = str;
insert (symb);
}
return symb;
}
//! Fix all the unset keylevels
void
symbol_fix_keylevels (void)
{
int i;
for (i = 0; i < HASHSIZE; i++)
{
Symbol sym;
sym = symbtab[i];
while (sym != NULL)
{
#ifdef DEBUG
if (DEBUGL (5))
{
eprintf ("Symbol ");
symbolPrint (sym);
}
#endif
if (sym->keylevel == INT_MAX)
{
// Nothing currently, this simply does not originate on a strand.
#ifdef DEBUG
if (DEBUGL (5))
{
eprintf (" doesn't have a keylevel yet.\n");
}
#endif
}
#ifdef DEBUG
else
{
if (DEBUGL (5))
{
eprintf (" has keylevel %i\n", sym->keylevel);
}
}
#endif
sym = sym->next;
}
}
}
//! Print out according to globalError
/**
* Input is comparable to printf, only depends on globalError. This should be used by any function trying to do output.
*\sa globalError
*/
void
eprintf (char *fmt, ...)
{
va_list args;
va_start (args, fmt);
if (globalError == 0)
vfprintf (stdout, fmt, args);
else
vfprintf (stderr, fmt, args);
va_end (args);
}