diff --git a/tools/qfcc/include/Makefile.am b/tools/qfcc/include/Makefile.am index 638eb598c..96ac59aa4 100644 --- a/tools/qfcc/include/Makefile.am +++ b/tools/qfcc/include/Makefile.am @@ -3,4 +3,4 @@ AUTOMAKE_OPTIONS= foreign EXTRA_DIST= class.h cpp.h debug.h def.h emit.h expr.h function.h \ idstuff.h immediate.h linker.h method.h obj_file.h opcodes.h \ options.h qfcc.h qfprogs.h reloc.h strpool.h struct.h switch.h \ - type.h + symtab.h type.h diff --git a/tools/qfcc/include/symtab.h b/tools/qfcc/include/symtab.h new file mode 100644 index 000000000..dada07926 --- /dev/null +++ b/tools/qfcc/include/symtab.h @@ -0,0 +1,199 @@ +/* + symtab.h + + Symbol table management + + Copyright (C) 2011 Bill Currie + + Author: Bill Currie + Date: 2011/01/04 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifndef __symtab_h +#define __symtab_h + +/** \defgroup qfcc_symtab Symbol Table Management + \ingroup qfcc +*/ +//@{ +// +typedef enum { + sym_type, + sym_def, + sym_enum, + sym_class, +} sym_type_e; + +typedef struct symbol_s { + struct symbol_s *next; ///< chain of symbols in symbol table + const char *name; ///< symbol name + sym_type_e type; ///< symbol type (typedef, var, struct...) + union { + struct type_s *type; + struct def_s *def; + struct enumval_s *enm; + struct class_s *class; + } s; +} symbol_t; + +typedef enum { + stab_global, ///< global (many symbols) + stab_local, ///< local (few symbols: func, struct) + stab_union, ///< offset always 0 +} stab_type_e; + +typedef struct symtab_s { + struct symtab_s *parent; ///< points to parent table + struct symtab_s *next; ///< next in global collection of symtabs + stab_type_e type; ///< type of symbol table + struct hashtab_s *tab; ///< symbols defined in this table + symbol_t *symbols; ///< chain of symbols in this table + symbol_t **symtail; ///< keep chain in declaration order +} symtab_t; + +/** Create a new, empty symbol table. + + The symbol tables support scoping via their \c parent pointer. This + supports both code block scoping and ivar inheritance. + + \param parent Pointer to parent scope symbol table. + \param type The type of symbol table. Currently governs expected size. + \return The new, empty symbol table. +*/ +symtab_t *new_symtab (symtab_t *parent, stab_type_e type); + +/** Lookup a name in the symbol table. + + The entire symbol table chain (symtab_t::parent) starting at symtab + will be checked for \a name. + + \param symtab The symbol table to search for \a name. If \a name is + not in the symbol table, the tables's parent, if it + exists, will be checked, and then its parent, until the + end of the chain. + \param name The name to look up in the symbol table chain. +*/ +symbol_t *symtab_lookup (symtab_t *symtab, const char *name); + +/** Add a named type (\c typedef) to the symbol table. + + Duplicate names will not be inserted (an error), but only the given + symbol table is checked for duplicate names, not the ancestor chain. + + \param symtab The symbol table to which the named type will be added. + \param name The name of the type to be added to the symbol table. + \param type The type to be added to the symbol table. + \return The new symbol representing the named type or null if + an error occurred. +*/ +symbol_t *symtab_add_type (symtab_t *symtab, const char *name, + struct type_s *type); + +/** Add a def to the symbol table. + + Duplicate names will not be inserted (an error), but only the given + symbol table is checked for duplicate names, not the ancestor chain. + + \param symtab The symbol table to which the def will be added. + \param name The name of the def to be added to the symbol table. + \param def The def to be added to the symbol table. + \return The new symbol representing the def or null if an + error occurred. +*/ +symbol_t *symtab_add_def (symtab_t *symtab, const char *name, + struct def_s *def); + +/** Add an enum to the symbol table. + + Duplicate names will not be inserted (an error), but only the given + symbol table is checked for duplicate names, not the ancestor chain. + + \param symtab The symbol table to which the enum will be added. + \param name The name of the enum to be added to the symbol table. + \param enm The enum to be added to the symbol table. + \return The new symbol representing the enum or null if an + error occurred. +*/ +symbol_t *symtab_add_enum (symtab_t *symtab, const char *name, + struct enumval_s *enm); + +/** Add a class to the symbol table. + + Duplicate names will not be inserted (an error), but only the given + symbol table is checked for duplicate names, not the ancestor chain. + + \param symtab The symbol table to which the class will be added. + \param name The name of the class to be added to the symbol table. + \param class The class to be added to the symbol table. + \return The new symbol representing the class or null if an + error occurred. +*/ +symbol_t *symtab_add_class (symtab_t *symtab, const char *name, + struct class_s *class); + +/** Create a new single symbol table from the given symbol table chain. + + Create a new symbol table and add all of the symbols from the given + symbol table chain to the new symbol table. However, in order to + preserve scoping rules, duplicate names in ancestor tables will not be + added to the new table. + + The new symbol table will be "local". + + The intended use is for creating the ivar scope for methods. + + \param symtab The symbol table chain to be copied. + \param parent The parent symbol table of the new symbol table, or + null. + \return The new symbol table. + + \dot + digraph symtab_flat_copy { + layout=fdp; + parent; + subgraph clusterI { + node [shape=record]; + root [label="{

parent|integer\ x;|integer\ y;|float\ z;}"]; + base [label="{

parent|float\ w;|float\ x;}"]; + cur [label="{

parent|float\ y;}"]; + cur:p -> base; + base:p -> root; + } + subgraph clusterO { + node [shape=record]; + out [label="{

parent|float\ z;|float\ w;|float\ x;|float\ y;}"]; + } + symtab; + return; + symtab -> cur; + clusterI -> clusterO [len=1]; + out:p -> parent; + return -> out; + } + \enddot +*/ +symtab_t *symtab_flat_copy (symtab_t *symtab, symtab_t *parent); + +//@} + +#endif//__symtab_h diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index 312ebf2b3..67c47eea6 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -52,7 +52,8 @@ EXTRA_PROGRAMS= qfcc qfprogs qfcc_SOURCES= \ class.c constfold.c cpp.c debug.c def.c emit.c expr.c function.c \ idstuff.c immediate.c linker.c method.c obj_file.c opcodes.c options.c \ - qc-lex.l qc-parse.y qfcc.c reloc.c strpool.c struct.c switch.c type.c + qc-lex.l qc-parse.y qfcc.c reloc.c strpool.c struct.c switch.c symtab.c \ + type.c qfcc_LDADD= $(QFCC_LIBS) qfcc_DEPENDENCIES= $(QFCC_DEPS) diff --git a/tools/qfcc/source/symtab.c b/tools/qfcc/source/symtab.c new file mode 100644 index 000000000..a5a1b3b02 --- /dev/null +++ b/tools/qfcc/source/symtab.c @@ -0,0 +1,155 @@ +#include +#include + +#include "QF/hash.h" + +#include "class.h" +#include "def.h" +#include "qfcc.h" +#include "symtab.h" +#include "type.h" + +static symtab_t *free_symtabs; +static symbol_t *free_symbols; + +static const char * +sym_getkey (void *k, void *unused) +{ + return ((symbol_t *) k)->name; +} + +symtab_t * +new_symtab (symtab_t *parent, stab_type_e type) +{ + symtab_t *symtab; + int tabsize = 63; + + ALLOC (16, symtab_t, symtabs, symtab); + + symtab->parent = parent; + symtab->type = type; + if (symtab->type == stab_global) + tabsize = 1023; + symtab->tab = Hash_NewTable (tabsize, sym_getkey, 0, 0); + symtab->symtail = &symtab->symbols; + return symtab; +} + +symbol_t * +symtab_lookup (symtab_t *symtab, const char *name) +{ + symbol_t *symbol; + while (symtab) { + if ((symbol = Hash_Find (symtab->tab, name))) + return symbol; + symtab = symtab->parent; + } + return 0; +} + +static symbol_t * +new_symbol (void) +{ + symbol_t *symbol; + ALLOC (256, symbol_t, symbols, symbol); + return symbol; +} + +static void +add_symbol (symtab_t *symtab, symbol_t *symbol) +{ + Hash_Add (symtab->tab, symbol); + symbol->next = *symtab->symtail; + *symtab->symtail = symbol; + symtab->symtail = &symbol->next; +} + +symbol_t * +symtab_add_type (symtab_t *symtab, const char *name, type_t *type) +{ + symbol_t *symbol; + if ((symbol = Hash_Find (symtab->tab, name))) { + // duplicate symbol + } + symbol = new_symbol (); + symbol->name = name; + symbol->type = sym_type; + symbol->s.type = type; + add_symbol (symtab, symbol); + return symbol; +} + +symbol_t * +symtab_add_def (symtab_t *symtab, const char *name, def_t *def) +{ + symbol_t *symbol; + if ((symbol = Hash_Find (symtab->tab, name))) { + // duplicate symbol + } + symbol = new_symbol (); + symbol->name = name; + symbol->type = sym_def; + symbol->s.def = def; + add_symbol (symtab, symbol); + return symbol; +} + +symbol_t * +symtab_add_enum (symtab_t *symtab, const char *name, struct enumval_s *enm) +{ + symbol_t *symbol; + if ((symbol = Hash_Find (symtab->tab, name))) { + // duplicate symbol + } + symbol = new_symbol (); + symbol->name = name; + symbol->type = sym_enum; + symbol->s.enm = enm; + add_symbol (symtab, symbol); + return symbol; +} + +symbol_t * +symtab_add_class (symtab_t *symtab, const char *name, class_t *class) +{ + symbol_t *symbol; + if ((symbol = Hash_Find (symtab->tab, name))) { + // duplicate symbol + } + symbol = new_symbol (); + symbol->name = name; + symbol->type = sym_class; + symbol->s.class = class; + add_symbol (symtab, symbol); + return symbol; +} + +symtab_t * +symtab_flat_copy (symtab_t *symtab, symtab_t *parent) +{ + symtab_t *newtab; + symbol_t *newsym; + symbol_t *symbol; + + newtab = new_symtab (parent, stab_local); + while (symtab) { + for (symbol = symtab->symbols; symbol; symbol = symbol->next) { + if (Hash_Find (newtab->tab, symbol->name)) + continue; + newsym = new_symbol (); + *newsym = *symbol; + add_symbol (newtab, newsym); + } + symtab = symtab->parent; + // Set the tail pointer so symbols in ancestor tables come before + // those in decendent tables. + newtab->symtail = &newtab->symbols; + } + // Reset the tail pointer so any symbols added to newtab come after + // those copied from the input symbol table chain. + for (symbol = newtab->symbols; symbol && symbol->next; + symbol = symbol->next) + ; + newtab->symtail = symbol ? &symbol->next : &newtab->symbols; + return newtab; +}