Mercurial > octave
diff src/symtab.cc @ 1:78fd87e624cb
[project @ 1993-08-08 01:13:40 by jwe]
Initial revision
author | jwe |
---|---|
date | Sun, 08 Aug 1993 01:13:40 +0000 |
parents | |
children | e4acc68c9c60 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/symtab.cc Sun Aug 08 01:13:40 1993 +0000 @@ -0,0 +1,855 @@ +// Symbol table classes. -*- C++ -*- +/* + +Copyright (C) 1992, 1993 John W. Eaton + +This file is part of Octave. + +Octave 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, or (at your option) any +later version. + +Octave 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 Octave; see the file COPYING. If not, write to the Free +Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifdef __GNUG__ +#pragma implementation +#endif + +// Don't even think about moving the tree.h include to symtab.h... + +#include "symtab.h" +#include "error.h" +#include "variables.h" +#include "utils.h" +#include "tree.h" +#include "tree-const.h" + +/* + * Variables and functions. + */ +symbol_def::symbol_def (void) +{ + help_string = (char *) NULL; + type = unknown_type; + lifespan = temporary; + sym_class = read_write; + definition = (tree *) NULL; +} + +symbol_def::symbol_def (tree_constant *t) +{ + help_string = (char *) NULL; + type = variable; + lifespan = temporary; + sym_class = read_write; + definition = t; +} + +symbol_def::symbol_def (tree_builtin *t) +{ + help_string = (char *) NULL; + type = builtin_function; + lifespan = temporary; + sym_class = read_write; + definition = t; +} + +symbol_def::symbol_def (tree_function *t) +{ + help_string = (char *) NULL; + type = user_function; + lifespan = temporary; + sym_class = read_write; + definition = t; +} + +symbol_def::~symbol_def (void) +{ + delete [] help_string; + delete definition; +} + +void +symbol_def::define (tree_constant *t) +{ + definition = t; + type = variable; +} + +void +symbol_def::define (tree_builtin *t) +{ + definition = t; + type = builtin_function; +} + +void +symbol_def::define (tree_function *t) +{ + definition = t; + type = user_function; +} + +tree * +symbol_def::def (void) +{ + return definition; +} + +char * +symbol_def::help (void) +{ + return help_string; +} + +void +symbol_def::document (char *h) +{ + delete [] help_string; + help_string = strsave (h); +} + +int +symbol_def::save (ostream& os, int mark_as_global) +{ + return definition->save (os, mark_as_global); +} + +/* + * Individual records in a symbol table. + */ +symbol_record::symbol_record (void) +{ + nm = (char *) NULL; + formal_param = 0; + var = (symbol_def *) NULL; + fcn = (symbol_def *) NULL; + sv_fcn = (sv_Function) NULL; + next_elem = (symbol_record *) NULL; +} + +symbol_record::symbol_record (char *n) +{ + nm = strsave (n); + formal_param = 0; + var = (symbol_def *) NULL; + fcn = (symbol_def *) NULL; + sv_fcn = (sv_Function) NULL; + next_elem = (symbol_record *) NULL; +} + +symbol_record::symbol_record (char *n, symbol_record *nxt) +{ + nm = strsave (n); + formal_param = 0; + var = (symbol_def *) NULL; + fcn = (symbol_def *) NULL; + sv_fcn = (sv_Function) NULL; + next_elem = nxt; +} + +symbol_record::~symbol_record (void) +{ + delete [] nm; + + if (var != (symbol_def *) NULL && --var->count <= 0) + delete var; + + if (fcn != (symbol_def *) NULL && --fcn->count <= 0) + delete fcn; +} + +char * +symbol_record::name (void) +{ + return nm; +} + +char * +symbol_record::help (void) +{ + if (var != (symbol_def *) NULL) + return var->help (); + else if (fcn != (symbol_def *) NULL) + return fcn->help (); + else + return (char *) NULL; +} + +tree * +symbol_record::def (void) +{ + if (var != (symbol_def *) NULL) + return var->def (); + else if (fcn != (symbol_def *) NULL) + return fcn->def (); + else + return (tree *) NULL; +} + +int +symbol_record::is_function (void) +{ + return (var == (symbol_def *) NULL && fcn != (symbol_def *) NULL); +} + +int +symbol_record::is_variable (void) +{ + return (var != (symbol_def *) NULL); +} + +int +symbol_record::is_defined (void) +{ + return (var != (symbol_def *) NULL || fcn != (symbol_def *) NULL); +} + +void +symbol_record::set_sv_function (sv_Function f) +{ + sv_fcn = f; +} + +int +symbol_record::var_read_only (void) +{ + if (var != (symbol_def *) NULL + && var->sym_class == symbol_def::read_only) + { + error ("can't assign to read only symbol `%s'", nm); + return 1; + } + else + return 0; +} + +int +symbol_record::read_only (void) +{ + if ((var != (symbol_def *) NULL + && var->sym_class == symbol_def::read_only) + || (fcn != (symbol_def *) NULL + && fcn->sym_class == symbol_def::read_only)) + { + error ("can't assign to read only symbol `%s'", nm); + return 1; + } + else + return 0; +} + +int +symbol_record::define (tree_constant *t) +{ + if (var_read_only ()) + return 0; + + tree_constant *saved_def = NULL_TREE_CONST; + + if (var != (symbol_def *) NULL) + { + saved_def = (tree_constant *) var->def (); // XXX FIXME XXX + var->define (t); + } + else + { + var = new symbol_def (t); + var->count = 1; + } + + if (sv_fcn != (sv_Function) NULL && sv_fcn () < 0) + { + var->define (saved_def); + delete t; + return 0; + } + + delete saved_def; + + return 1; +} + +int +symbol_record::define (tree_builtin *t) +{ + if (read_only ()) + return 0; + + if (var != (symbol_def *) NULL) + { + if (--var->count <= 0) + delete var; + var = (symbol_def *) NULL; + } + + if (fcn != (symbol_def *) NULL) + fcn->define (t); + else + { + fcn = new symbol_def (t); + fcn->count = 1; + } + + return 1; +} + +int +symbol_record::define (tree_function *t) +{ + if (read_only ()) + return 0; + + if (var != (symbol_def *) NULL) + { + if (--var->count <= 0) + delete var; + var = (symbol_def *) NULL; + } + + if (fcn != (symbol_def *) NULL) + fcn->define (t); + else + { + fcn = new symbol_def (t); + fcn->count = 1; + } + + return 1; +} + +int +symbol_record::define_as_fcn (tree_constant *t) +{ + if (read_only ()) + return 0; + + if (var != (symbol_def *) NULL) + { + if (--var->count <= 0) + delete var; + var = (symbol_def *) NULL; + } + + if (fcn != (symbol_def *) NULL) + fcn->define (t); + else + { + fcn = new symbol_def (t); + fcn->count = 1; + } + + return 1; +} + +void +symbol_record::document (char *h) +{ + if (var != (symbol_def *) NULL) + var->document (h); + else if (fcn != (symbol_def *) NULL) + fcn->document (h); + else + warning ("couldn't document undefined variable `%s'", nm); +} + +void +symbol_record::protect (void) +{ + if (var != (symbol_def *) NULL) + var->sym_class = symbol_def::read_only; + else if (fcn != (symbol_def *) NULL) + fcn->sym_class = symbol_def::read_only; + else + warning ("couldn't protect undefined variable `%s'", nm); +} + +void +symbol_record::unprotect (void) +{ + if (var != (symbol_def *) NULL) + var->sym_class = symbol_def::read_write; + else if (fcn != (symbol_def *) NULL) + fcn->sym_class = symbol_def::read_write; +} + +void +symbol_record::make_eternal (void) +{ + if (var != (symbol_def *) NULL) + var->lifespan = symbol_def::eternal; + else if (fcn != (symbol_def *) NULL) + fcn->lifespan = symbol_def::eternal; + else + warning ("couldn't give eternal life to the variable `%s'", nm); +} + +int +symbol_record::save (ostream& os, int mark_as_global = 0) +{ + int status = 0; + + if (var != (symbol_def *) NULL && var->def () != (tree *) NULL) + { +// For now, eternal implies builtin. + if (var->lifespan != symbol_def::eternal) + { +// Should we also save the help string? Maybe someday. + os << "# name: " << nm << "\n"; + status = var->save (os, mark_as_global); + } + } + else if (fcn != (symbol_def *) NULL) + message ("save", "sorry, can't save functions yet"); + else + message ("save", "can't save undefined symbols!"); + + return status; +} + +void +symbol_record::clear_visible (void) +{ + if (var != (symbol_def *) NULL && var->lifespan != symbol_def::eternal) + { + if (--var->count <= 0) + delete var; + var = (symbol_def *) NULL; + } + else if (fcn != (symbol_def *) NULL && fcn->lifespan != symbol_def::eternal) + { + if (--fcn->count <= 0) + delete fcn; + fcn = (symbol_def *) NULL; + } +} + +void +symbol_record::clear_all (void) +{ + if (var != (symbol_def *) NULL && var->lifespan != symbol_def::eternal) + { + if (--var->count <= 0) + delete var; + var = (symbol_def *) NULL; + } + + if (fcn != (symbol_def *) NULL && fcn->lifespan != symbol_def::eternal) + { + if (--fcn->count <= 0) + delete fcn; + fcn = (symbol_def *) NULL; + } +} + +void +symbol_record::undefine (void) +{ + if (var != (symbol_def *) NULL) + { + if (--var->count <= 0) + delete var; + var = (symbol_def *) NULL; + } + + if (fcn != (symbol_def *) NULL) + { + if (--fcn->count <= 0) + delete fcn; + fcn = (symbol_def *) NULL; + } +} + +void +symbol_record::mark_as_formal_parameter (void) +{ + formal_param = 1; +} + +int +symbol_record::is_formal_parameter (void) +{ + return formal_param; +} + +void +symbol_record::alias (symbol_record *s, int force = 0) +{ + sv_fcn = s->sv_fcn; // Maybe this should go in the var symbol_def? + + formal_param = s->formal_param; // Hmm. + + if (force && s->var == (symbol_def *) NULL + && s->fcn == (symbol_def *) NULL) + { + s->var = new symbol_def (); + var = s->var; + var->count = 2; // Yes, this is correct. + return; + } + + if (s->var != (symbol_def *) NULL) + { + var = s->var; + var->count++; + } + else if (s->fcn != (symbol_def *) NULL) + { + fcn = s->fcn; + fcn->count++; + } +} + +symbol_record * +symbol_record::next (void) +{ + return next_elem; +} + +/* + * A symbol table. + */ + +symbol_table::symbol_table (void) +{ +} + +symbol_record * +symbol_table::lookup (char *nm, int insert = 0, int warn = 0) +{ + int index = hash (nm) & HASH_MASK; + + symbol_record *ptr = table[index].next (); + + while (ptr != (symbol_record *) NULL) + { + if (strcmp (ptr->name (), nm) == 0) + return ptr; + ptr = ptr->next (); + } + + if (insert) + { + symbol_record *new_sym; + new_sym = new symbol_record (nm, table[index].next ()); + table[index].next_elem = new_sym; + return new_sym; + } + else if (warn) + message ("lookup", "symbol`%s' not found", nm); + + return (symbol_record *) NULL; +} + +void +symbol_table::clear (void) +{ + for (int i = 0; i < HASH_TABLE_SIZE; i++) + { + symbol_record *prev = &table[i]; + symbol_record *curr = prev->next (); + + while (curr != (symbol_record *) NULL) + { + curr->clear_all (); + +// This record might have been read only. If so, we shouldn't delete +// it from the table. + if (curr->is_defined ()) + { + prev = curr; + curr = curr->next (); + } + else + { + prev->next_elem = curr->next (); + symbol_record *tmp = curr; + curr = curr->next (); + delete tmp; + } + } + } +} + +int +symbol_table::clear (char *nm) +{ + int index = hash (nm) & HASH_MASK; + + symbol_record *prev = &table[index]; + symbol_record *curr = prev->next (); + + while (curr != (symbol_record *) NULL) + { + if (strcmp (curr->name (), nm) == 0) + { + curr->clear_visible (); + + if (! curr->is_defined ()) + { + prev->next_elem = curr->next (); + symbol_record *tmp = curr; + curr = curr->next (); + delete tmp; + } + + return 1; + } + prev = curr; + curr = curr->next (); + } + + return 0; +} + +void +symbol_table::undefine (void) +{ + for (int i = 0; i < HASH_TABLE_SIZE; i++) + { + symbol_record *ptr = table[i].next (); + + while (ptr != (symbol_record *) NULL) + { + ptr->undefine (); + ptr = ptr->next (); + } + } +} + +// Ugh. + +void +symbol_table::bind_globals (void) +{ + assert (this != global_sym_tab); + + for (int i = 0; i < HASH_TABLE_SIZE; i++) + { + symbol_record *ptr = table[i].next (); + + while (ptr != (symbol_record *) NULL && ! ptr->formal_param) + { + char *nm = ptr->name (); + symbol_record *sr = global_sym_tab->lookup (nm, 0, 0); + if (sr != (symbol_record *) NULL) + ptr->alias (sr, 1); + ptr = ptr->next (); + } + } +} + +int +symbol_table::save (ostream& os, int mark_as_global = 0) +{ + int status = 0; + for (char **names = sorted_var_list (); *names != (char *) NULL; names++) + { + if (save (os, *names, mark_as_global)) + status++; + } + return status; +} + +int +symbol_table::save (ostream& os, char *name, int mark_as_global = 0) +{ + int status = 0; + symbol_record *sr = lookup (name, 0, 0); + if (sr != (symbol_record *) NULL) + status = sr->save (os, mark_as_global); + return status; +} + +int +symbol_table::size (void) +{ + int count = 0; + for (int i = 0; i < HASH_TABLE_SIZE; i++) + { + symbol_record *ptr = table[i].next (); + while (ptr != (symbol_record *) NULL) + { + count++; + ptr = ptr->next (); + } + } + return count; +} + +char ** +symbol_table::list (void) +{ + int count; + return list (count); +} + +char ** +symbol_table::var_list (void) +{ + int count; + return var_list (count); +} + +char ** +symbol_table::fcn_list (void) +{ + int count; + return fcn_list (count); +} + +char ** +symbol_table::list (int& count) +{ + int n = size (); + if (n == 0) + return (char **) NULL; + + char **symbols = new char * [n+1]; + count = 0; + for (int i = 0; i < HASH_TABLE_SIZE; i++) + { + symbol_record *ptr = table[i].next (); + while (ptr != (symbol_record *) NULL) + { + assert (count < n); + symbols[count++] = strsave (ptr->name ()); + ptr = ptr->next (); + } + } + symbols[count] = (char *) NULL; + return symbols; +} + +char ** +symbol_table::var_list (int& count) +{ + int n = size (); + if (n == 0) + return (char **) NULL; + + char **symbols = new char * [n+1]; + count = 0; + for (int i = 0; i < HASH_TABLE_SIZE; i++) + { + symbol_record *ptr = table[i].next (); + while (ptr != (symbol_record *) NULL) + { + assert (count < n); + if (ptr->is_variable ()) + symbols[count++] = strsave (ptr->name ()); + ptr = ptr->next (); + } + } + symbols[count] = (char *) NULL; + return symbols; +} + +char ** +symbol_table::fcn_list (int& count) +{ + int n = size (); + if (n == 0) + return (char **) NULL; + + char **symbols = new char * [n+1]; + count = 0; + for (int i = 0; i < HASH_TABLE_SIZE; i++) + { + symbol_record *ptr = table[i].next (); + while (ptr != (symbol_record *) NULL) + { + assert (count < n); + if (ptr->is_function ()) + symbols[count++] = strsave (ptr->name ()); + ptr = ptr->next (); + } + } + symbols[count] = (char *) NULL; + return symbols; +} + +static inline int +pstrcmp (char **a, char **b) +{ + return strcmp (*a, *b); +} + +char ** +symbol_table::sorted_list (void) +{ + int count = 0; + return sorted_list (count); +} + +char ** +symbol_table::sorted_var_list (void) +{ + int count = 0; + return sorted_var_list (count); +} + +char ** +symbol_table::sorted_fcn_list (void) +{ + int count = 0; + return sorted_fcn_list (count); +} + +char ** +symbol_table::sorted_list (int& count) +{ + char **symbols = list (count); + if (symbols != (char **) NULL) + qsort ((void **) symbols, count, sizeof (char *), + (int (*)(void*, void*)) pstrcmp); + return symbols; +} + +char ** +symbol_table::sorted_var_list (int& count) +{ + char **symbols = var_list (count); + if (symbols != (char **) NULL) + qsort ((void **) symbols, count, sizeof (char *), + (int (*)(void*, void*)) pstrcmp); + return symbols; +} + +char ** +symbol_table::sorted_fcn_list (int& count) +{ + char **symbols = fcn_list (count); + if (symbols != (char **) NULL) + qsort ((void **) symbols, count, sizeof (char *), + (int (*)(void*, void*)) pstrcmp); + return symbols; +} + +// Chris Torek's fave hash function. + +unsigned int +symbol_table::hash (const char *str) +{ + unsigned h = 0; + while (*str) + h = h * 33 + *str++; + return h; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; page-delimiter: "^/\\*" *** +;;; End: *** +*/