changeset 7336:745a8299c2b5

[project @ 2007-12-28 20:56:55 by jwe]
author jwe
date Fri, 28 Dec 2007 20:56:58 +0000
parents 58f5fab3ebe5
children e70789e0cd92
files doc/ChangeLog doc/interpreter/io.txi doc/interpreter/var.txi src/ChangeLog src/DLD-FUNCTIONS/dispatch.cc src/Makefile.in src/debug.cc src/defun-dld.h src/defun-int.h src/defun.cc src/dynamic-ld.cc src/dynamic-ld.h src/error.cc src/file-io.cc src/help.cc src/help.h src/input.cc src/lex.h src/lex.l src/load-path.cc src/load-path.h src/load-save.cc src/load-save.h src/ls-hdf5.cc src/ls-mat-ascii.cc src/ls-mat4.cc src/ls-mat5.cc src/ls-oct-ascii.cc src/ls-oct-binary.cc src/mex.cc src/oct-lvalue.cc src/oct-lvalue.h src/octave.cc src/ov-base.cc src/ov-base.h src/ov-fcn-handle.cc src/ov-fcn-handle.h src/ov-fcn.h src/ov-struct.cc src/ov-struct.h src/ov-typeinfo.cc src/ov-typeinfo.h src/ov-usr-fcn.cc src/ov-usr-fcn.h src/ov.cc src/ov.h src/parse.h src/parse.y src/pt-arg-list.cc src/pt-arg-list.h src/pt-assign.cc src/pt-assign.h src/pt-binop.cc src/pt-binop.h src/pt-cell.cc src/pt-cell.h src/pt-cmd.cc src/pt-cmd.h src/pt-colon.cc src/pt-colon.h src/pt-const.cc src/pt-const.h src/pt-decl.cc src/pt-decl.h src/pt-except.cc src/pt-except.h src/pt-exp.h src/pt-fcn-handle.cc src/pt-fcn-handle.h src/pt-id.cc src/pt-id.h src/pt-idx.cc src/pt-idx.h src/pt-jump.cc src/pt-jump.h src/pt-loop.cc src/pt-loop.h src/pt-mat.cc src/pt-mat.h src/pt-misc.cc src/pt-misc.h src/pt-select.cc src/pt-select.h src/pt-stmt.cc src/pt-stmt.h src/pt-unop.cc src/pt-unop.h src/symtab.cc src/symtab.h src/token.cc src/token.h src/toplev.cc src/unwind-prot.h src/variables.cc src/variables.h src/version.h
diffstat 96 files changed, 6042 insertions(+), 5870 deletions(-) [+]
line wrap: on
line diff
--- a/doc/ChangeLog	Fri Feb 01 23:56:51 2008 -0500
+++ b/doc/ChangeLog	Fri Dec 28 20:56:58 2007 +0000
@@ -1,3 +1,12 @@
+2007-12-28  John W. Eaton  <jwe@octave.org>
+
+	Merge changes from object branch:
+
+	2007-06-20  John W. Eaton  <jwe@octave.org>
+
+	* interpreter/var.txi, interpreter/io.txi:
+	Eliminate print_answer_id_name.
+
 2007-12-21  John W. Eaton  <jwe@octave.org>
 
 	Version 3.0.0 released.
--- a/doc/interpreter/io.txi	Fri Feb 01 23:56:51 2008 -0500
+++ b/doc/interpreter/io.txi	Fri Dec 28 20:56:58 2007 +0000
@@ -69,8 +69,6 @@
 
 @DOCSTRING(format)
 
-@DOCSTRING(print_answer_id_name)
-
 @menu
 * Paging Screen Output::
 @end menu
--- a/doc/interpreter/var.txi	Fri Feb 01 23:56:51 2008 -0500
+++ b/doc/interpreter/var.txi	Fri Dec 28 20:56:58 2007 +0000
@@ -477,11 +477,6 @@
 
 Default value: 1.
 
-@item print_answer_id_name
-@xref{Terminal Output}.
-
-Default value: 1.
-
 @item print_empty_dimensions
 @xref{Empty Matrices}.
 
--- a/src/ChangeLog	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ChangeLog	Fri Dec 28 20:56:58 2007 +0000
@@ -1,3 +1,418 @@
+2007-12-28  John W. Eaton  <jwe@octave.org>
+
+	Merge changes from object branch:
+
+	2007-12-12  John W. Eaton  <jwe@octave.org>
+
+	* load-path.cc (load_path::dir_info::get_file_list,
+	load_path::move_method_map, load_path::remove_method_map,
+	load_path::do_find_fcn, load_path::do_find_private_fcn,
+	load_path::do_find_method, load_path::do_find_file,
+	load_path::do_find_first_of, load_path::do_find_all_first_of,
+	load_path::do_display, load_path::add_to_method_map, genpath,
+	execute_pkg_add_or_del): Use file_ops::concat.
+
+	2007-08-24  John W. Eaton  <jwe@octave.org>
+
+	* variables.cc (Fmislocked): return value for nargin == 0 case.
+
+	2007-07-27  John W. Eaton  <jwe@octave.org>
+
+	* pt-idx.cc (tree_index_expression::rvalue):
+	Pass substring of type to subsref when doing partial evaluation.
+	(tree_index_expression::lvalue): Likewise.
+
+	2007-06-29  John W. Eaton  <jwe@octave.org>
+
+	* ov-class.cc (is_built_in_class, set_class_relationship,
+	Fsuperiorto, Finferiorto): New functions.
+	(octave_class::in_class_method): New function.
+	(octave_class::subsref, octave_class:subsasgn): Use it.
+
+	2007-06-28  John W. Eaton  <jwe@octave.org>
+
+	* src/ov-class.cc (sanitize): New function.
+	(make_idx_args): Use it.
+
+	2007-06-28  John W. Eaton  <jwe@octave.org>
+
+	* src/ov-class.cc (octave_class::subsasgn): Expect and use only
+	one return value from feval of subsasgn method.
+
+	* ov.cc (octave_value::assign): Don't convert to struct if
+	indexing a class object with ".".
+
+	* pt-idx.cc (tree_index_expression::make_arg_struct):
+	Use Cell instead of octave_value_list for subscripts.
+
+	* ov-class.cc (make_idx_args): For "." index, subs field is
+	string, not cell.
+
+	2007-06-27  John W. Eaton  <jwe@octave.org>
+
+	* ov-fcn-handle.cc (octave_fcn_handle::save_ascii,
+	octave_fcn_handle::load_ascii, octave_fcn_handle::save_binary,
+	octave_fcn_handle::load_binary, octave_fcn_handle::save_hdf5,
+	octave_fcn_handle::load_hdf5): Adapt to new symbol table objects.
+
+	* symtab.h (symbol_table::all_variables,
+	symbol_table::do_all_variables): New arg, defined_only.
+
+	2007-06-26  John W. Eaton  <jwe@octave.org>
+
+	* ls-mat5.cc (read_mat5_binary_element): Adapt to new symbol table
+	objects.
+
+	* variables.cc (Vwhos_line_format): New static variable.
+	(Fwhos_line_format): New function.
+	(symbol_record_name_compare): Delete function.
+	(symbol_record_name_compare, whos_parameter): New structs.
+	(print_descriptor, dimensions_string_req_first_space,
+	dimensions_string_req_total_space, make_dimensions_string,
+	parse_whos_line_format, print_symbol_info_line): New static
+	functions, adapted from old symbol table class.
+	(do_who): Adapt to new symbol table objects.
+
+	* symtab.h (symbol_table::glob_variables): New functions.
+	(symbol_table::do_glob): New argument, vars_only.  Change all uses.
+
+	2007-06-22  John W. Eaton  <jwe@octave.org>
+
+	* symtab.cc (symbol_table::fcn_info::fcn_info_rep::help_for_dispatch):
+	New function.
+	* symtab.h: Provide decl.
+	(symbol_table::fcn_info::help_for_dispatch,
+	symbol_table::help_for_dispatch): New functions.
+
+	* help.cc (help_from_symbol_table): Call
+	symbol_table::help_for_dispatch instead of
+	extract_help_from_dispatch.
+
+	* help.cc (extract_help_from_dispatch): Delete.
+	* help.h: Delete decl.
+
+	2007-06-21  John W. Eaton  <jwe@octave.org>
+
+	* DLD-FUNCTIONS/dispatch.cc (class octave_dispatch): Delete class.
+	(builtin, any_arg_is_magic_colon, dispatch_record): Delete functions.
+	(Fbuiltin, Fdispatch): Adapt to new symbol table objects.
+
+	* symtab.cc (symbol_table::fcn_info::fcn_info_rep::print_dispatch):
+	New function.
+	* symtab.h: Provide decl.
+	(symbol_table::fcn_info::print_dispatch, symbol_table::print_dispatch):
+	New functions.
+
+	* symtab.h (symbol_table::fcn_info::fcn_info_rep::clear_dispatch,
+	symbol_table::fcn_info::clear_dispatch, symbol_table::clear_dispatch):
+	New functions.
+
+	* symtab.h (symbol_table::fcn_info::fcn_info_rep::get_dispatch,
+	symbol_table::fcn_info::get_dispatch, symbol_table::get_dispatch):
+	New functions.
+
+	* symtab.cc (symbol_table::fcn_info::fcn_info_rep::find):
+	Use leftmost class argument as dispatch type, or first argument if
+	there are no class arguments.
+
+	2007-06-20  John W. Eaton  <jwe@octave.org>
+
+	* ov-base.cc (Vprint_answer_id_name, Fprint_answer_id_name): Delete.
+	(octave_base_value::print_with_name): Always print name.
+
+	* ov-base.cc (Vsilent_functions): No longer static.
+	* ov-base.h: Provide decl.
+
+	* ov-class.cc (Fmethods): Define as command.
+
+	* ov-class.cc (octave_class::print): Simply call print_raw.
+
+	* ov-class.cc (octave_class::print_with_name): New function.
+	* ov-class.h: Provide decl.
+
+	2007-06-19  John W. Eaton  <jwe@octave.org>
+
+	* ov.cc (octave_value::do_unary_op, octave_value::do_binary_op):
+	Handle class methods.
+
+	* ov.cc (octave_value::unary_op_fcn_name,
+	octave_value::binary_op_fcn_name): New functions.
+	* ov.h: Provide decls.
+
+	* ov-typeinfo.cc (octave_value_typeinfo::register_unary_class_op,
+	octave_value_typeinfo::register_binary_class_op,
+	octave_value_typeinfo::do_register_unary_class_op,
+	octave_value_typeinfo::do_register_binary_class_op,
+	octave_value_typeinfo::do_lookup_unary_class_op,
+	octave_value_typeinfo::do_lookup_binary_class_op): New functions.
+	* ov-typeinfo.h: Provide decls.
+	
+	* ov-typeinfo.h (octave_value_typeinfo::unary_class_op_fcn,
+	octave_value_typeinfo::binary_class_op_fcn): New typedefs.
+	(octave_value_typeinfo::unary_class_ops,
+	octave_value_typeinfo::binary_class_ops): New data members.
+	(octave_value_typeinfo::octave_value_typeinfo): Initialize them.
+	(octave_value_typeinfo::lookup_unary_class_op,
+	octave_value_typeinfo::lookup_binary_class_op): New functions.
+
+	* OPERATORS/op-class.cc: New file.
+	* Makefile.in (OP_XSRC): Add it to the list.
+
+	* ov.cc (install_types): Call octave_class::register_type here.
+
+	* ov-class.h (octave_class): Implement by containing a map object
+	instead of deriving from octave_struct.
+	* ov-class.cc (octave_class::subsref, octave_class::subsasgn):
+	Don't use octave_class implementation as default action.
+
+	* ov.h, ov.cc (octave_value::octave_value (const Octave_map&, const
+	std::string&)): New constructor.
+
+	2007-06-18  John W. Eaton  <jwe@octave.org>
+
+	* ov-class.cc (octave_class::subsref, octave_class::subsasgn):
+	Handle dispatch to user-defined methods.
+
+	* parse.y (load_fcn_from_file): New arg, dispatch_type.
+	Change all uses.
+
+	* ov-fcn.h (octave_function::is_class_constructor,
+	octave_function::is_class_method, octave_function::dispatch_class):
+	New virtual functions.
+
+	* ov-usr-fcn.h (octave_user_function::dispatch_class,
+	octave_usr_function::stash_dispatch_class): New functions.
+	(octave_usr_fucntion::xdispatch_class): New data member.
+	* parse.y (frob_function): Call stash_dispatch_class here.
+
+	* ov-struct.cc (Ffieldnames): Also handle objects.
+
+	* ov-class.cc (Fmethods): New function.
+	* load-path.cc (load_path::do_methods): New function.
+	* load-path.h (load_path::methods): New function.
+
+	* ov.h (octave_value::is_object): New function.
+	* ov-base.h (octave_base_value::is_object): New virtual function.
+	* ov-class.h (octave_class::is_object): New function.
+	* ov-class.cc (Fisobject): New function.
+
+	2007-06-15  John W. Eaton  <jwe@octave.org>
+
+	* ov-class.cc (octave_class::print): Call display method if found.
+
+	* symtab.h (symbol_table::fcn_info::find_method): New function.
+	(symbol_table::find_method): New function.
+	(symbol_table::fcn_info::fcn_info_rep::find_method): Provide decl.
+	* symtab.cc (symbol_table::fcn_info::fcn_info_rep::find_method):
+	New function.
+	(symbol_table::fcn_info::fcn_info_rep::find): Use it.
+
+	2007-06-14  John W. Eaton  <jwe@octave.org>
+
+	* symtab.h (symbol_table::clear_mex_functions): Make it work.
+	(symbol_table::fcn_info::fcn_info_rep::clear_mex_function,
+	symbol_table::fcn_info::clear_mex_function): New functions.
+
+	2007-06-08  John W. Eaton  <jwe@octave.org>
+
+	* defun.cc (Falias): Delete.
+
+	* variables.cc (load_fcn_try_ctor): New function.
+	(lookup): call load_fcn_try_ctor instead of load_fcn_from_file.
+
+	* variables.cc, variables.h (at_top_level, lookup_by_name, lookup,
+	initialize_symbol_tables, fcn_out_of_date, symbol_out_of_date,
+	lookup_function, lookup_user_function, link_to_global_variable,
+	link_to_builtin_or_function, force_link_to_function, Fdocument,
+	is_local_variable, do_clear_all, do_clear_functions,
+	do_clear_globals, do_clear_variables, do_clear_function,
+	do_clear_global, do_clear_variable, do_clear_symbol,
+	do_clear_function_pattern, do_clear_global_pattern,
+	do_clear_variable_pattern, do_clear_symbol_pattern,
+	clear_function, clear_variable, clear_symbol):
+	Delete (some functionality moved to the new symtab.cc and some is
+	no longer needed).
+	(Fignore_function_time_stamp): Move to symtab.cc.
+
+	* lex.l (lookup_identifier): Delete.
+
+	* parse.y (is_function_file): New function.
+	(load_fcn_from_file): Return pointer to octave_function, not bool.
+
+	* ov-usr-fcn.h, ov-usr-fcn.cc (octave_user_function::argn_sr,
+	octave_user_function::nargin_sr, octave_user_function::nargout_sr,
+	octave_user_function::varargin_sr): Delete data members.
+	(octave_user_function::install_automatic_vars): Delete.
+	(octave_user_script::do_multi_index_op): New function.
+
+	* ov-fcn.h (octave_function::locked, octave_function::my_dir_name):
+	New data members.
+	(octave_function::dir_name, octave_function::stash_dir_name,
+	octave_function::lock, octave_function::unlock,
+	octave_function::islocked): New functions.
+
+	* of-fcn-handle.h, ov-fcn-handle.cc (octave_fcn_handle::subsref):
+	Call out_of_date_check here to simplify time stamp checking.
+	(octave_fcn_handle::reload_warning): Delete.
+
+	* ov.h (octave_value::is_user_script, octave_value::is_user_function):
+	New functions.
+	* ov-base.h (octave_base_value::is_user_script,
+	octave_base_value::is_user_function): New pure virtual functions.
+	* ov-fcn.h (octave_function::is_user_script,
+	octave_function::is_user_function): Delete.
+
+	* load-save.cc (install_loaded_variable): Greatly simplify.
+
+	* load-path.h, load-path.cc: Change private_fcn_file to private_file.
+	(load_path::private_fcn_map): New data member.
+	(load_path::do_add, load_path::do_remove, load_path::do_update):
+	Also manage private_file_map here.
+	(load_path::add_to_private_fcn_map): New function.
+	(load_path::remove_private_fcn_map): New function.
+	(load_path::do_find_private_fcn): Make it work.
+	(get_file_list): New function.
+	(load_path::do_display): Use it.  Display private map.
+	(load_path::find_method, load_path::find_fcn): Handle directory name.
+
+	* token.cc, token.h, toplev.cc, debug.cc, defun.cc, defun-dld.h,
+	defun-int.h, error.cc, help.cc, load-save.h, load-save.cc, mex.cc,
+	octave.cc, ov-fcn-handle.cc, ov-usr-fcn.cc, parse.h, parse.y,
+	lex.l, variables.cc: Adapt to new symbol table objects (my
+	apologies for the lack of detail).
+
+	* unwind-prot.h (unwind_protect::add): Set default value for ptr arg.
+
+	* pt-stmt.cc (tree_statement::eval): Rework method for deciding
+	whether to assign value to ans.
+
+	* pt-idx.cc (tree_index_expression::rvalue):
+	Looking up symbol may evaluaate first args now.
+
+	* pt-id.h, pt-id.cc (tree_identifier::document,
+	tree_identifier::is_defined, tree_identifier::define,
+	tree_identifier::is_function, tree_identifier::lookup,
+	tree_identifier::link_to_global): Delete.
+	(tree_identifier::do_lookup): Simplify.
+	(tree_identifier::rvalue): Looking up symbol can't execute script now.
+
+	* pt-misc.cc (tree_parameter_list::initialize_undefined,
+	tree_parameter_list::is_defined): Call is_variable for elt, not
+	is_defined.
+
+	* pt-fcn-handle.h (tree_anon_fcn_handle::fcn): Now pointer to
+	octave_user_function, not value.  Change all uses.
+
+	* pt-decl.h (tree_decl_command::initialized): Delete data member.
+	(tree_decl_elt::is_variable): New function.
+	* pt-decl.cc: Fix all uses of tree_decl_command::initialized.
+
+	* ls-hdf5.cc, ls-mat-ascii.cc, ls-mat4.cc, ls-mat5.cc,
+	ls-oct-ascii.cc, ls-oct-binary.cc, input.cc: Don't include symtab.h.
+
+	* dynamic-ld.h, dynamic-ld.cc (octave_dynamic_loader::load_oct,
+	octave_dynamic_loader::load_mex, octave_dynamic_loader::do_load_oct,
+	octave_dynamic_loader::do_load_mex): Adapt to new symbol table
+	objects.  Return pointer octave_function instead of bool.
+
+	* DLD-FUNCTIONS/dispatch.cc (Fbuiltin): Disable for now.
+	Disable code that works with old symbol tables.
+	(Fbuiltin): Simply call symbol_table::add_dispatch.
+
+	* pt-arg-list.cc, pt-arg-list.h, pt-assign.cc, pt-assign.h,
+	pt-binop.cc, pt-binop.h, pt-bp.h, pt-cell.cc, pt-cell.h,
+	pt-cmd.cc, pt-cmd.h, pt-colon.cc, pt-colon.h, pt-const.cc,
+	pt-const.h, pt-decl.cc, pt-decl.h, pt-except.cc, pt-except.h,
+	pt-exp.h, pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h,
+	pt-idx.cc, pt-idx.h, pt-jump.cc, pt-jump.h, pt-loop.cc, pt-loop.h,
+	pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h, pt-select.cc,
+	pt-select.h, pt-stmt.cc, pt-stmt.h, pt-unop.cc, pt-unop.h:
+	Adapt dup functions to use scope instead of symbol_table objects.
+
+	* TEMPLATE-INST/Array-sym.cc: Delete.
+	* Makefile.in (TI_XSRC): Remove it from the list.
+
+	* symtab.h, symtab.cc: Replace with new versions.
+
+	2007-05-16  John W. Eaton  <jwe@octave.org>
+
+	* oct-lvalue.cc, oct-lvalue.h (octave_lvalue::chg_fcn): Delete.
+	Fix all uses.
+
+	2007-05-15  John W. Eaton  <jwe@octave.org>
+
+	* load-path.cc (load_path::do_find_private_function): New function.
+	* load-path.h (load_path::do_find_private_function): Provide decl.
+        (load_path::find_private_function): New function.
+
+	2007-05-08  John W. Eaton  <jwe@octave.org>
+
+	* pt-idx.cc (tree_index_expression::rvalue): Handle dispatch here.
+
+	* pt-id.cc (tree_identifier::is_variable, tree_identifier::lookup):
+	New functions.
+	* pt-id.cc: Provide decls.
+
+	* parse.y (current_class_name): New global variable.
+	* parse.h: Provide decl.
+
+	* parse.y (load_fcn_from_file, parse_fcn_file):
+	New arg, dispatch_type.
+	(parse_fcn_file): Protect current_class_name and set it to
+	dispatch_type before parsing function.
+	(load_fcn_from_file): If dispatch_type is not empty, call
+	load_path::find_method instead of load_path::find_fcn.
+	* parse.h: Fix decls for extern functions.
+
+	* lex.h (lexical_feedback::parsing_class_method): New data member.
+	* lex.l (lexical_feedback::init): Initialize it.
+	(lookup_identifier): Check it and set sym_name accordingly.
+
+	* ov-usr-fcn.h (octave_user_function::mark_as_class_constructor,
+	octave_user_function::is_class_constructor,
+	octave_user_function::mark_as_class_method,
+	octave_user_function::is_class_method): New functions.
+	(octave_user_function::class_constructor,
+	octave_user_function::class_method): New data members.
+	* ov-usr-fcn.cc (octave_user_function::octave_user_function):
+	Initialize them.
+
+	* load-path.h, load-path.cc: Use typedefs to simplify template decls.
+	Use fcn consistently instead of function.
+	
+	2007-05-03  John W. Eaton  <jwe@octave.org>
+
+	* ov-class.cc (Fclass): Move here.
+	* ov-typeinfo.cc: From here.
+
+	* input.cc (octave_gets): Call load_path::update if user input
+	contains something other than one of the characters " \t\n\r".
+
+	* ov-class.cc, ov-class.h: New files.
+	* Makefile.in: Add them to the appropriate lists.
+
+	* load-path.cc (genpath): Skip directories beginning with "@".
+	(load_path::dir_info::get_file_list):  Don't return anything.
+	Call get_private_function_map here.
+	(load_path::dir_info::initialize): Not here.
+	(load_path::dir_info_::get_method_file_map): New function.
+	(load_path::method_map): New data member.
+	(load_path::do_clear): Also clear method_map.
+	(load_path::do_add): Also call add_to_method_map.
+	(load_path::do_update): Also clear method_map and call
+	(load_path::do_find_method): New function.
+	(load_path::do_add_to_method_map): New function.
+	(load_path::move_fcn_map, load_path::move_method_map): New functions.
+	(load_path::move): Use them.
+	(load_path::remove_fcn_map, load_path::remove_method_map):
+	New functions.
+	(load_path::remove): Use them.
+	* load-path.h: Provide/fix decls.
+	(load_path::find_method): New static function.
+
+	* Makefile.in (%.df : %.cc): Use mv instead of
+	$(simple-move-if-change-rule).
+
 2007-12-21  John W. Eaton  <jwe@octave.org>
 
 	Version 3.0.0 released.
--- a/src/DLD-FUNCTIONS/dispatch.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/DLD-FUNCTIONS/dispatch.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -28,6 +28,8 @@
 #include <map>
 #include <string>
 
+#include "Cell.h"
+#include "oct-map.h"
 #include "defun-dld.h"
 #include "ov.h"
 #include "ov-fcn.h"
@@ -37,257 +39,6 @@
 #include "symtab.h"
 #include "variables.h"
 
-// FIXME should be using a map from type_id->name, rather
-// than type_name->name
-
-template class std::map<std::string,std::string>;
-
-typedef std::map<std::string,std::string> Table;
-
-class
-octave_dispatch : public octave_function
-{
-public:
-
-  // FIXME need to handle doc strings of dispatched functions, for
-  // example, by appending "for <f>(<type>,...) see <name>" for each
-  // time dispatch(f,type,name) is called.
-  octave_dispatch (const std::string &nm)
-    : octave_function (nm, "Overloaded function"), tab (), base (nm),
-      has_alias (false)
-  { }
-
-  // FIXME if we get deleted, we should restore the original
-  // symbol_record from base before dying.
-  ~octave_dispatch (void) { }
-
-  bool is_builtin_function (void) const { return true; }
-
-  octave_function *function_value (bool) { return this; }
-
-  octave_value do_index_op (const octave_value_list&, bool = false)
-  {
-    error ("dispatch: do_index_op");
-    return octave_value ();
-  }
-
-  octave_value subsref (const std::string&,
-			const std::list<octave_value_list>&)
-  {
-    error ("dispatch: subsref (str, list)");
-    panic_impossible ();
-    return octave_value ();
-  }
-
-  octave_value_list subsref (const std::string& type,
-			     const std::list<octave_value_list>& idx,
-			     int nargout);
-
-  octave_value_list do_multi_index_op (int, const octave_value_list&);
-
-  void add (const std::string t, const std::string n);
-
-  void clear (const std::string t);
-
-  void print (std::ostream& os, bool pr_as_read=false) const;
-
-private:
-
-  Table tab;
-  std::string base;
-  bool has_alias;
-
-  octave_dispatch (void) 
-    : octave_function (), tab (), base (), has_alias (false) { }
-
-  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
-
-  DECLARE_OCTAVE_ALLOCATOR
-};
-
-DEFINE_OCTAVE_ALLOCATOR (octave_dispatch);
-
-DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_dispatch,
-				     "overloaded function", "function");
-
-void 
-octave_dispatch::add (const std::string t, const std::string n)
-{ 
-  if (tab.count (t) > 0 && tab[t] != n)
-    warning ("replacing %s(%s,...)->%s with %s",
-	     base.c_str (), t.c_str (), tab[t].c_str (), n.c_str ());
-
-  tab[t] = n;
-
-  if (t == "any")
-    has_alias = true;
-}
-
-void
-octave_dispatch::clear (const std::string t)
-{
-  tab.erase (t); 
-
-  if (t == "any")
-    has_alias = false;
-}
-
-octave_value_list
-octave_dispatch::subsref (const std::string& type,
-			  const std::list<octave_value_list>& idx,
-			  int nargout)
-{
-  octave_value_list retval;
-
-  switch (type[0])
-    {
-    case '(':
-      retval = do_multi_index_op (nargout, idx.front ());
-      break;
-
-    case '{':
-    case '.':
-      {
-	const std::string nm = type_name ();
-	error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
-      }
-      break;
-
-    default:
-      panic_impossible ();
-    }
-
-  if (idx.size () > 1)
-    retval = retval(0).next_subsref (type, idx);
-
-  return retval;
-}
-
-static octave_function*
-builtin (const std::string& base)
-{
-  octave_function *fcn = 0;
-
-  // Check if we are overriding a builtin function.  This is the
-  // case if builtin is protected.
-  symbol_record *builtin = fbi_sym_tab->lookup ("builtin:" + base, 0);
-
-  if (! builtin)
-    error ("builtin record has gone missing");
-
-  if (error_state)
-    return fcn;
-
-  if (builtin->is_read_only ())
-    {
-      // builtin is read only, so checking for updates is pointless
-      if (builtin->is_function ())
-        fcn = builtin->def().function_value ();
-      else
-	error ("builtin %s is not a function", base.c_str ());
-    }
-  else
-    {
-      // Check that builtin is up to date.
- 
-      // Don't try to fight octave's function name handling
-      // mechanism.  Instead, move dispatch record out of the way,
-      // and restore the builtin to its original name.
-      symbol_record *dispatch = fbi_sym_tab->lookup (base, 0);
-      if (! dispatch)
-	error ("dispatch record has gone missing");
-
-      dispatch->unprotect ();
-
-      fbi_sym_tab->rename (base, "dispatch:" + base);
-
-      fbi_sym_tab->rename ("builtin:" + base, base);
-
-      // check for updates to builtin function; ignore errors that
-      // appear (they interfere with renaming), and remove the updated
-      // name from the current symbol table.  FIXME check that
-      // updating a function updates it in all contexts --- it may be
-      // that it is updated only in the current symbol table, and not
-      // the caller.  I believe this won't be a problem because the
-      // caller will go through the same logic and end up with the
-      // newer version.
-      fcn = is_valid_function (base, "dispatch", 1);
-      int cache_error = error_state;
-      error_state = 0;
-      curr_sym_tab->clear_function (base);
-
-      // Move the builtin function out of the way and restore the
-      // dispatch fuction.
-      // FIXME what if builtin wants to protect itself?
-      symbol_record *found = fbi_sym_tab->lookup (base, 0);
-      bool readonly = found->is_read_only ();
-      found->unprotect ();
-      fbi_sym_tab->rename (base, "builtin:" + base);
-      fbi_sym_tab->rename ("dispatch:" + base, base);
-      if (readonly)
-	found->protect ();
-      dispatch->protect ();
-
-      // remember if there were any errors.
-      error_state = cache_error;
-    }
-
-  return fcn;
-}
-
-static bool
-any_arg_is_magic_colon (const octave_value_list& args)
-{
-  int nargin = args.length ();
-
-  for (int i = 0; i < nargin; i++)
-    if (args(i).is_magic_colon ())
-      return true;
-
-  return false;
-}
-
-octave_value_list
-octave_dispatch::do_multi_index_op (int nargout, const octave_value_list& args)
-{
-  octave_value_list retval;
-
-  if (error_state) return retval;
-
-  if (any_arg_is_magic_colon (args))
-    {
-      ::error ("invalid use of colon in function argument list");
-      return retval;
-    }
-
-  // If more than one argument, check if argument template matches any
-  // overloaded functions.  Also provide a catch-all '*' type to provide
-  // single level pseudo rename and replace functionality.
-  if (args.length () > 0 && tab.count (args(0).type_name ()) > 0)
-    retval = feval (tab[args(0).type_name()], args, nargout);
-  else if (has_alias)
-    retval = feval (tab["any"], args, nargout);
-  else
-    {
-      octave_function *fcn = builtin (base);
-      if (! error_state && fcn)
-        retval = fcn->do_multi_index_op (nargout, args);
-    }
-
-  return retval;
-}
-
-void 
-octave_dispatch::print (std::ostream& os, bool) const
-{
-  os << "Overloaded function " << base << std::endl;
-
-  for (Table::const_iterator it = tab.begin (); it != tab.end (); it++)
-    os << base << "(" << it->first << ",...)->" 
-       << it->second << "(" << it->first << ",...)"
-       << std::endl;
-}
-
 DEFUN_DLD (builtin, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Loadable Function} {[@dots{}]} builtin (@var{f}, @dots{})\n\
@@ -304,25 +55,18 @@
     {
       const std::string name (args(0).string_value ());
  
-      if (error_state)
-	return retval;
-
-      symbol_record *sr = lookup_by_name (name, 0);
-
-      if (sr && sr->is_function ())
+      if (! error_state)
 	{
-	  if (sr->def().type_id () == octave_dispatch::static_type_id ())
-	    {
-	      octave_function *fcn = builtin (name);
+	  octave_value fcn = symbol_table::find_function (name);
 
-	      if (!error_state && fcn)
-		retval = fcn->do_multi_index_op (nargout, args.splice (0, 1));
-	    }
+	  if (fcn.is_defined ())
+	    retval = feval (fcn.function_value (), args.splice (0, 1),
+			    nargout);
 	  else
-	    retval = feval (name, args.splice (0, 1), nargout);
+	    error ("builtin: lookup for symbol `%s' failed", name.c_str ());
 	}
       else
-	error ("builtin: lookup for symbol `%s' failed", name.c_str ());
+	error ("builtin: expecting function name as first argument");
     }
   else
     print_usage ();
@@ -330,102 +74,7 @@
   return retval;
 }
 
-static void
-dispatch_record (const std::string &f, const std::string &n, 
-		 const std::string &t)
-{
-  // find the base function in the symbol table, loading it if it
-  // is not already there; if it is already a dispatch, then bonus
-
-  symbol_record *sr = fbi_sym_tab->lookup (f, true);
-
-  if (sr->def().type_id () != octave_dispatch::static_type_id ())
-    {
-      // Preserve mark_as_command status
-      bool iscommand = sr->is_command ();
-
-      // Not an overloaded name, so if only display or clear then we are done
-      if (t.empty ())
-	return;
-
-      // sr is the base symbol; rename it to keep it safe.  When we need
-      // it we will rename it back again.
-      if (sr->is_read_only ()) 
-        {
-          sr->unprotect ();
-          fbi_sym_tab->rename (f, "builtin:" + f);
-  	  sr = fbi_sym_tab->lookup (f, true);
-          sr->protect ();
-	}
-      else 
-        fbi_sym_tab->rename (f, "builtin:" + f);
-
-      // It would be good to hide the builtin:XXX name, but since the
-      // new XXX name in the symbol table is set to BUILTIN_FUNCTION,
-      // things don't work quite the way we would like.
-      // sr->hide ();
-
-      // Problem:  when a function is first called a new record
-      // is created for it in the current symbol table, so calling
-      // dispatch on a function that has already been called, we
-      // should also clear it from all existing symbol tables.
-      // This is too much work, so we will only do it for the
-      // top level symbol table.  We can't use the clear_function() 
-      // method, because it won't clear builtin functions.  Instead 
-      // we check if the symbol is a function and clear it then.  This
-      // won't properly clear shadowed functions, or functions in
-      // other namespaces (such as the current, if called from a
-      // function).
-      symbol_record *local = top_level_sym_tab->lookup (f, false);
-      if (local && local->is_function ())
-	local->clear ();
-
-      // Build a new dispatch object based on the function definition
-      octave_dispatch *dispatch = new octave_dispatch (f);
-  
-      // Create a symbol record for the dispatch object.
-      sr = fbi_sym_tab->lookup (f, true);
-      sr->unprotect ();
-      sr->define (octave_value (dispatch), symbol_record::BUILTIN_FUNCTION); 
-      // std::cout << "iscommand('"<<f<<"')=" << iscommand << std::endl;
-      if (iscommand)
-	sr->mark_as_command();
-      sr->document ("\n\n@noindent\nOverloaded function:\n");
-      sr->make_eternal (); // FIXME why??
-      sr->mark_as_static ();
-      sr->protect ();
-    }
-
-  // clear/replace/extend the map with the new type-function pair
-  const octave_dispatch& rep
-    = dynamic_cast<const octave_dispatch&> (sr->def().get_rep ());
-
-  if (t.empty ())
-    // FIXME should return the list if nargout > 1
-    rep.print (octave_stdout);
-  else if (n.empty ())
-    {
-      // FIXME should we eliminate the dispatch function if
-      // there are no more elements?
-      // FIXME should clear the " $t:\w+" from the help string.
-      // FIXME -- seems bad to cast away const here...
-      octave_dispatch& xrep = const_cast<octave_dispatch&> (rep);
-
-      xrep.clear (t);
-    }
-  else
-    {
-      // FIXME -- seems bad to cast away const here...
-      octave_dispatch& xrep = const_cast<octave_dispatch&> (rep);
-
-      xrep.add (t, n);
-
-      if (! sr->help().empty ())
-	sr->document (sr->help() + "\n" + n + " (" + t + ", ...)\n");
-    }
-}
-
-DEFUN_DLD (dispatch, args, ,
+DEFUN_DLD (dispatch, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Loadable Function} {} dispatch (@var{f}, @var{r}, @var{type})\n\
 \n\
@@ -443,40 +92,89 @@
 @end deftypefn")
 {
   octave_value retval;
+
   int nargin = args.length ();
 
-  if (nargin < 1 || nargin > 3)
-    {
-      print_usage ();
-      return retval;
-    }
+  std::string f, r, t;
 
-  std::string f, t, n;
-  if (nargin > 0)
-    f = args(0).string_value ();
-
-  if (nargin == 2)
-    t = args(1).string_value ();
-  else if (nargin > 2)
+  if (nargin > 0 && nargin < 4)
     {
-      n = args(1).string_value ();
-      t = args(2).string_value ();
-    }
+      if (nargin > 0)
+	{
+	  f = args(0).string_value ();
+
+	  if (error_state)
+	    {
+	      error ("dispatch: expecting first argument to be function name");
+	      return retval;
+	    }
+	}
+
+      if (nargin > 1)
+	{
+	  r = args(1).string_value ();
 
-  if (error_state)
-    return retval;
-  
-  static bool register_type = true;
+	  if (error_state)
+	    {
+	      error ("dispatch: expecting second argument to be function name");
+	      return retval;
+	    }
+	}
+
+      if (nargin > 2)
+	{
+	  t = args(2).string_value ();
+
+	  if (error_state)
+	    {
+	      error ("dispatch: expecting third argument to be type name");
+	      return retval;
+	    }
+	}
 
-  // register dispatch function type if you have not already done so
-  if (register_type)
-    {
-      octave_dispatch::register_type ();
-      register_type = false;
-      fbi_sym_tab->lookup("dispatch")->mark_as_static ();
+      if (nargin == 1)
+	{
+	  if (nargout > 0)
+	    {
+	      symbol_table::fcn_info::dispatch_map_type dm
+		= symbol_table::get_dispatch (f);
+
+	      size_t len = dm.size ();
+
+	      Cell type_field (len, 1);
+	      Cell name_field (len, 1);
+
+	      symbol_table::fcn_info::dispatch_map_type::const_iterator p
+		= dm.begin ();
+
+	      for (size_t i = 0; i < len; i++)
+		{
+		  type_field(i) = p->first;
+		  name_field(i) = p->second;
+
+		  p++;
+		}
+
+	      Octave_map m;
+
+	      m.assign ("type", type_field);
+	      m.assign ("name", name_field);
+
+	      retval = m;
+	    }
+	  else
+	    symbol_table::print_dispatch (octave_stdout, f);
+	}
+      else if (nargin == 2)
+	{
+	  t = r;
+	  symbol_table::clear_dispatch (f, t);
+	}
+      else
+	symbol_table::add_dispatch (f, t, r);
     }
-
-  dispatch_record (f, n, t);
+  else
+    print_usage ();
 
   return retval;
 }
--- a/src/Makefile.in	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/Makefile.in	Fri Dec 28 20:56:58 2007 +0000
@@ -100,7 +100,7 @@
 	ov-streamoff.h ov-str-mat.h ov-bool-mat.h ov-bool.h \
 	ov-cell.h ov.h ov-fcn.h ov-builtin.h ov-dld-fcn.h \
 	ov-mapper.h ov-mex-fcn.h ov-usr-fcn.h ov-fcn-handle.h \
-	ov-fcn-inline.h ov-typeinfo.h ov-type-conv.h \
+	ov-fcn-inline.h ov-class.h ov-typeinfo.h ov-type-conv.h \
 	$(OV_INTTYPE_INC)
 
 OV_SPARSE_INCLUDES := \
@@ -129,7 +129,7 @@
 	$(PT_INCLUDES) \
 	$(OV_SPARSE_INCLUDES)
 
-TI_XSRC := Array-os.cc Array-sym.cc Array-tc.cc
+TI_XSRC := Array-os.cc Array-tc.cc
 
 TI_SRC := $(addprefix TEMPLATE-INST/, $(TI_XSRC))
 
@@ -144,8 +144,8 @@
 	op-sm-cs.cc op-sm-m.cc op-sm-s.cc op-sm-scm.cc op-sm-sm.cc \
 	op-s-scm.cc op-s-sm.cc
 
-OP_XSRC := op-b-b.cc op-b-bm.cc op-bm-b.cc op-bm-bm.cc \
-	op-cell.cc op-chm.cc op-cm-cm.cc op-cm-cs.cc op-cm-m.cc \
+OP_XSRC := op-b-b.cc op-b-bm.cc op-bm-b.cc op-bm-bm.cc op-cell.cc \
+	op-chm.cc op-class.cc op-cm-cm.cc op-cm-cs.cc op-cm-m.cc \
 	op-cm-s.cc op-cs-cm.cc op-cs-cs.cc op-cs-m.cc \
 	op-cs-s.cc op-list.cc op-m-cm.cc \
 	op-m-cs.cc op-m-m.cc op-m-s.cc op-range.cc op-s-cm.cc \
@@ -172,7 +172,7 @@
 	ov-colon.cc ov-bool-mat.cc ov-bool.cc ov-cell.cc \
 	ov.cc ov-fcn.cc ov-builtin.cc ov-dld-fcn.cc ov-mapper.cc \
 	ov-mex-fcn.cc ov-usr-fcn.cc ov-fcn-handle.cc ov-fcn-inline.cc \
-	ov-typeinfo.cc \
+	ov-class.cc ov-typeinfo.cc \
 	$(OV_INTTYPE_SRC) \
 	$(OV_SPARSE_SRC)
 
@@ -193,7 +193,7 @@
 	octave.cc zfstream.cc oct-strstrm.cc oct-lvalue.cc pager.cc \
 	parse.y pr-output.cc procstream.cc sighandlers.cc \
 	siglist.c sparse-xdiv.cc sparse-xpow.cc strfns.cc \
-	symtab.cc syscalls.cc sysdep.cc token.cc toplev.cc \
+	syscalls.cc symtab.cc sysdep.cc token.cc toplev.cc \
 	unwind-prot.cc utils.cc variables.cc xdiv.cc xpow.cc \
 	$(OV_SRC) \
 	$(PT_SRC)
--- a/src/debug.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/debug.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -70,23 +70,9 @@
     dbg_fcn = octave_call_stack::caller_user_function ();
   else
     {
-      symbol_record *ptr = curr_sym_tab->lookup (fname);
+      octave_value fcn = symbol_table::find_user_function (fname);
 
-      if (ptr && ptr->is_user_function ())
-	{
-	  octave_value tmp = ptr->def ();
-	  dbg_fcn = dynamic_cast<octave_user_function *> (tmp.function_value ());
-	}
-      else
-	{
-	  ptr = lookup_by_name (fname, false);
-
-	  if (ptr && ptr->is_user_function ())
-	    {
-	      octave_value tmp = ptr->def ();
-	      dbg_fcn = dynamic_cast<octave_user_function *> (tmp.function_value ());
-	    }
-	}
+      dbg_fcn = fcn.user_function_value ();
     }
 
   return dbg_fcn;
--- a/src/defun-dld.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/defun-dld.h	Fri Dec 28 20:56:58 2007 +0000
@@ -50,7 +50,7 @@
 // quoted string, and the internal name of the function must be passed
 // too (the convention is to use a prefix of "F", so "foo" becomes "Ffoo").
 
-#define DEFUNX_DLD(name, fname, fsname, args_name, nargout_name, doc) \
+#define DEFUNX_DLD(name, fname, fsname, gname, args_name, nargout_name, doc) \
   DEFUNX_DLD_INTERNAL (name, fname, args_name, nargout_name, false, doc)
 
 #else
@@ -60,9 +60,9 @@
   DEFINE_FUN_INSTALLER_FUN (name, doc) \
   DECLARE_FUN (name, args_name, nargout_name)
 
-#define DEFUNX_DLD(name, fname, fsname, args_name, nargout_name, doc) \
+#define DEFUNX_DLD(name, fname, fsname, gname, args_name, nargout_name, doc) \
   DECLARE_FUNX (fname, args_name, nargout_name); \
-  DEFINE_FUNX_INSTALLER_FUN (name, fname, fsname, doc) \
+  DEFINE_FUNX_INSTALLER_FUN (name, fname, fsname, gname, doc) \
   DECLARE_FUNX (fname, args_name, nargout_name)
 
 #endif
--- a/src/defun-int.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/defun-int.h	Fri Dec 28 20:56:58 2007 +0000
@@ -40,7 +40,7 @@
 extern OCTINTERP_API void check_version (const std::string& version, const std::string& fcn);
 
 extern OCTINTERP_API void
-install_builtin_mapper (octave_mapper *mf);
+install_builtin_mapper (octave_mapper *mf, const std::string& name);
 
 extern OCTINTERP_API void
 install_builtin_function (octave_builtin::fcn f, const std::string& name,
@@ -74,6 +74,8 @@
 
 typedef bool (*octave_dld_fcn_installer) (const octave_shlib&, bool relative);
 
+typedef octave_function * (*octave_dld_fcn_getter) (const octave_shlib&, bool relative);
+
 #define DEFINE_FUN_INSTALLER_FUN(name, doc) \
   DEFINE_FUN_INSTALLER_FUN2(name, doc, CXX_ABI)
 
@@ -81,15 +83,15 @@
   DEFINE_FUN_INSTALLER_FUN3(name, doc, cxx_abi)
 
 #define DEFINE_FUN_INSTALLER_FUN3(name, doc, cxx_abi) \
-  DEFINE_FUNX_INSTALLER_FUN3(#name, F ## name, FS ## name, doc, cxx_abi)
+  DEFINE_FUNX_INSTALLER_FUN3(#name, F ## name, FS ## name, G ## name, doc, cxx_abi)
 
-#define DEFINE_FUNX_INSTALLER_FUN(name, fname, fsname, doc) \
-  DEFINE_FUNX_INSTALLER_FUN2(name, fname, fsname, doc, CXX_ABI)
+#define DEFINE_FUNX_INSTALLER_FUN(name, fname, fsname, gname, doc) \
+  DEFINE_FUNX_INSTALLER_FUN2(name, fname, fsname, gname, doc, CXX_ABI)
 
-#define DEFINE_FUNX_INSTALLER_FUN2(name, fname, fsname, doc, cxx_abi) \
-  DEFINE_FUNX_INSTALLER_FUN3(name, fname, fsname, doc, cxx_abi)
+#define DEFINE_FUNX_INSTALLER_FUN2(name, fname, fsname, gname, doc, cxx_abi) \
+  DEFINE_FUNX_INSTALLER_FUN3(name, fname, fsname, gname, doc, cxx_abi)
 
-#define DEFINE_FUNX_INSTALLER_FUN3(name, fname, fsname, doc, cxx_abi) \
+#define DEFINE_FUNX_INSTALLER_FUN3(name, fname, fsname, gname, doc, cxx_abi) \
   extern "C" \
   OCTAVE_EXPORT \
   bool \
@@ -105,6 +107,28 @@
       install_dld_function (fname, name, shl, doc, false, relative); \
  \
     return retval; \
+  } \
+ \
+  extern "C" \
+  OCTAVE_EXPORT \
+  octave_function * \
+  gname ## _ ## cxx_abi (const octave_shlib& shl, bool relative) \
+  { \
+    octave_function *retval = 0; \
+ \
+    check_version (OCTAVE_API_VERSION, name); \
+ \
+    if (! error_state) \
+      { \
+	octave_dld_function *fcn = new octave_dld_function (fname, shl, name, doc); \
+ \
+        if (relative) \
+          fcn->mark_relative (); \
+ \
+        retval = fcn; \
+      } \
+ \
+    return retval; \
   }
 
 // MAKE_BUILTINS is defined to extract function names and related
@@ -193,8 +217,9 @@
 			      ch_map_flag, can_ret_cmplx_for_real, doc) \
   install_builtin_mapper \
     (new octave_mapper \
-     (ch_map, d_b_map, c_b_map, d_d_map, d_c_map, c_c_map, \
-      lo, hi, ch_map_flag, can_ret_cmplx_for_real, #name, doc))
+       (ch_map, d_b_map, c_b_map, d_d_map, d_c_map, c_c_map, \
+        lo, hi, ch_map_flag, can_ret_cmplx_for_real, #name, doc), \
+     #name)
 
 #endif /* ! MAKE_BUILTINS */
 
--- a/src/defun.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/defun.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -129,18 +129,9 @@
 // Install variables and functions in the symbol tables.
 
 void
-install_builtin_mapper (octave_mapper *mf)
+install_builtin_mapper (octave_mapper *mf, const std::string& name)
 {
-  symbol_record *sym_rec = fbi_sym_tab->lookup (mf->name (), true);
-
-  unsigned int t
-    = symbol_record::BUILTIN_FUNCTION | symbol_record::MAPPER_FUNCTION;
-
-  sym_rec->unprotect ();
-  sym_rec->define (mf, t);
-  sym_rec->document (mf->doc_string ());
-  sym_rec->make_eternal ();
-  sym_rec->protect ();
+  symbol_table::install_built_in_function (name, octave_value (mf));
 }
 
 void
@@ -148,18 +139,12 @@
 			  const std::string& doc, bool is_text_fcn,
 			  bool /* can_hide_function -- not yet implemented */)
 {
-  symbol_record *sym_rec = fbi_sym_tab->lookup (name, true);
+  octave_value fcn (new octave_builtin (f, name, doc));
 
-  unsigned int t = symbol_record::BUILTIN_FUNCTION;
+  symbol_table::install_built_in_function (name, fcn);
 
   if (is_text_fcn)
-    t |= symbol_record::COMMAND;
-
-  sym_rec->unprotect ();
-  sym_rec->define (new octave_builtin (f, name, doc), t);
-  sym_rec->document (doc);
-  sym_rec->make_eternal ();
-  sym_rec->protect ();
+    mark_as_command (name);
 }
 
 void
@@ -168,30 +153,17 @@
 		      const std::string& doc, bool is_text_fcn,
 		      bool relative)
 {
-  symbol_record *sym_rec = fbi_sym_tab->lookup (name, true);
-
-  unsigned int t = symbol_record::DLD_FUNCTION;
-
-  if (is_text_fcn)
-    t |= symbol_record::COMMAND;
-
-  sym_rec->unprotect ();
-
-  octave_dld_function *df = new octave_dld_function (f, shl, name, doc);
+  octave_dld_function *fcn = new octave_dld_function (f, shl, name, doc);
 
   if (relative)
-    df->mark_relative ();
+    fcn->mark_relative ();
 
-  sym_rec->define (df, t);
-  sym_rec->document (doc);
+  octave_value fval (fcn);
 
-  // Also insert the full name in the symbol table.  This way, we can
-  // properly cope with changes to LOAD_PATH.
+  symbol_table::install_built_in_function (name, fval);
 
-  symbol_record *full_sr = fbi_sym_tab->lookup (shl.file_name (), true);
-
-  full_sr->alias (sym_rec, true);
-  full_sr->hide ();
+  if (is_text_fcn)
+    mark_as_command (name);
 }
 
 void
@@ -199,89 +171,25 @@
 		      const octave_shlib& shl, bool is_text_fcn,
 		      bool relative)
 {
-  symbol_record *sym_rec = fbi_sym_tab->lookup (name, true);
-
-  unsigned int t = symbol_record::MEX_FUNCTION;
-
-  if (is_text_fcn)
-    t |= symbol_record::COMMAND;
-
-  sym_rec->unprotect ();
-
-  octave_mex_function *mf = new octave_mex_function (fptr, fmex, shl, name);
+  octave_mex_function *fcn = new octave_mex_function (fptr, fmex, shl, name);
 
   if (relative)
-    mf->mark_relative ();
+    fcn->mark_relative ();
 
-  sym_rec->define (mf, t);
+  octave_value fval (fcn);
 
-  // Also insert the full name in the symbol table.  This way, we can
-  // properly cope with changes to LOAD_PATH.
+  symbol_table::install_built_in_function (name, fval);
 
-  symbol_record *full_sr = fbi_sym_tab->lookup (shl.file_name (), true);
-
-  full_sr->alias (sym_rec, true);
-  full_sr->hide ();
+  if (is_text_fcn)
+    mark_as_command (name);
 }
 
 void
 alias_builtin (const std::string& alias, const std::string& name)
 {
-  symbol_record *sr_name = fbi_sym_tab->lookup (name);
-
-  if (! sr_name)
-    panic ("can't alias to undefined name!");
-
-  symbol_record *sr_alias = fbi_sym_tab->lookup (alias, true);
-
-  if (sr_alias)
-    sr_alias->alias (sr_name);
-  else
-    panic ("can't find symbol record for builtin function `%s'",
-	   alias.c_str ());
+  symbol_table::alias_built_in_function (alias, name);
 }
 
-#if 0
-// This is insufficient to really make it possible to define an alias
-// for function.  There are a number of subtle problems related to
-// automatically reloading functions.
-DEFUN (alias, args, ,
-  "alias (alias, name)")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 2)
-    {
-      string alias = args(0).string_value ();
-      string name = args(1).string_value ();
-
-      if (! error_state)
-	{
-	  symbol_record *sr_name = lookup_by_name (name, false);
-
-	  if (sr_name && sr_name->is_function ())
-	    {
-	      symbol_record *sr_alias = fbi_sym_tab->lookup (alias, true);
-
-	      if (sr_alias)
-		sr_alias->alias (sr_name);
-	      else
-		error ("alias: unable to insert `%s' in symbol table",
-		       alias.c_str ());
-	    }
-	  else
-	    error ("alias: function `%s' does not exist", name.c_str ());
-	}
-    }
-  else
-    print_usage ();
-
-  return retval;
-}
-#endif
-
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/dynamic-ld.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/dynamic-ld.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -35,6 +35,9 @@
 
 #include "defun.h"
 #include "dynamic-ld.h"
+#include "ov-fcn.h"
+#include "ov-dld-fcn.h"
+#include "ov-mex-fcn.h"
 #include "parse.h"
 #include "unwind-prot.h"
 #include "utils.h"
@@ -295,12 +298,7 @@
 {
   warning_with_id ("Octave:reload-forces-clear", "  %s", fcn_name.c_str ());
 
-  curr_sym_tab->clear (fcn_name);
-
-  if (curr_sym_tab != top_level_sym_tab)
-    top_level_sym_tab->clear (fcn_name);
-
-  fbi_sym_tab->clear (fcn_name);
+  symbol_table::clear_user_function (fcn_name);
 }
 
 static void
@@ -314,12 +312,12 @@
   octave_shlib_list::remove (oct_file, do_clear_function);
 }
 
-bool
+octave_function *
 octave_dynamic_loader::do_load_oct (const std::string& fcn_name,
 				    const std::string& file_name,
 				    bool relative)
 {
-  bool retval = false;
+  octave_function *retval = 0;
 
   octave_shlib oct_file;
 
@@ -330,7 +328,7 @@
   doing_load = true;
 
   void *function
-    = octave_shlib_list::search (fcn_name, oct_file, mangle_name);
+    = octave_shlib_list::search (fcn_name, oct_file, xmangle_name);
 
   if (! error_state)
     {
@@ -377,7 +375,7 @@
 
 		      octave_shlib_list::append (oct_file);
 
-		      function = oct_file.search (fcn_name, mangle_name);
+		      function = oct_file.search (fcn_name, xmangle_name);
 		    }
 		  else
 		    ::error ("%s is not a valid shared library",
@@ -389,8 +387,8 @@
 
   if (function)
     {
-      octave_dld_fcn_installer f
-	= FCN_PTR_CAST (octave_dld_fcn_installer, function);
+      octave_dld_fcn_getter f
+	= FCN_PTR_CAST (octave_dld_fcn_getter, function);
 
       retval = f (oct_file, relative);
 
@@ -404,12 +402,12 @@
   return retval;
 }
 
-bool
+octave_function *
 octave_dynamic_loader::do_load_mex (const std::string& fcn_name,
 				    const std::string& file_name,
 				    bool relative)
 {
-  bool retval = false;
+  octave_function *retval = 0;
 
   octave_shlib mex_file;
 
@@ -467,11 +465,7 @@
     }
 
   if (function)
-    {
-      install_mex_function (function, have_fmex, fcn_name, mex_file, relative);
-
-      retval = true;
-    }
+    retval = new octave_mex_function (function, have_fmex, mex_file, fcn_name);
   else
     ::error ("failed to install .mex file function `%s'", fcn_name.c_str ());
   
@@ -499,22 +493,22 @@
   return retval;
 }
 
-bool
+octave_function *
 octave_dynamic_loader::load_oct (const std::string& fcn_name,
-				 const std::string& file_name,
-				 bool relative)
+				  const std::string& file_name,
+				  bool relative)
 {
   return (instance_ok ())
-    ? instance->do_load_oct (fcn_name, file_name, relative) : false;
+    ? instance->do_load_oct (fcn_name, file_name, relative) : 0;
 }
 
-bool
+octave_function *
 octave_dynamic_loader::load_mex (const std::string& fcn_name,
-				 const std::string& file_name,
-				 bool relative)
+				  const std::string& file_name,
+				  bool relative)
 {
   return (instance_ok ())
-    ? instance->do_load_mex (fcn_name, file_name, relative) : false;
+    ? instance->do_load_mex (fcn_name, file_name, relative) : 0;
 }
 
 bool
@@ -537,6 +531,20 @@
   return retval;
 }
 
+std::string
+octave_dynamic_loader::xmangle_name (const std::string& name)
+{
+#if defined (CXX_PREPENDS_UNDERSCORE)
+  std::string retval ("_G");
+#else
+  std::string retval ("G");
+#endif
+  retval.append (name);
+  retval.append ("_");
+  retval.append (STRINGIFY (CXX_ABI));
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/dynamic-ld.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/dynamic-ld.h	Fri Dec 28 20:56:58 2007 +0000
@@ -28,6 +28,8 @@
 
 #include "oct-shlib.h"
 
+class octave_function;
+
 class
 octave_dynamic_loader
 {
@@ -39,13 +41,15 @@
 
   virtual ~octave_dynamic_loader (void) { }
 
-  static bool load_oct (const std::string& fcn_name,
-			const std::string& file_name = std::string (),
-			bool relative = false);
+  static octave_function *
+  load_oct (const std::string& fcn_name,
+	     const std::string& file_name = std::string (),
+	     bool relative = false);
 
-  static bool load_mex (const std::string& fcn_name,
-			const std::string& file_name = std::string (),
-			bool relative = false);
+  static octave_function *
+  load_mex (const std::string& fcn_name,
+	     const std::string& file_name = std::string (),
+	     bool relative = false);
 
   static bool remove (const std::string& fcn_name, octave_shlib& shl);
 
@@ -61,13 +65,15 @@
 
   static bool instance_ok (void);
 
-  bool do_load_oct (const std::string& fcn_name,
-		    const std::string& file_name = std::string (),
-		    bool relative = false);
+  octave_function *
+  do_load_oct (const std::string& fcn_name,
+		const std::string& file_name = std::string (),
+		bool relative = false);
 
-  bool do_load_mex (const std::string& fcn_name,
-		    const std::string& file_name = std::string (),
-		    bool relative = false);
+  octave_function *
+  do_load_mex (const std::string& fcn_name,
+		const std::string& file_name = std::string (),
+		bool relative = false);
 
   bool do_remove (const std::string& fcn_name, octave_shlib& shl);
 
@@ -76,6 +82,8 @@
 protected:
 
   static std::string mangle_name (const std::string& name);
+
+  static std::string xmangle_name (const std::string& name);
 };
 
 #endif
--- a/src/error.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/error.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -643,7 +643,7 @@
     }
   else if (warn_opt == 1)
     {
-      if (curr_sym_tab != top_level_sym_tab
+      if (symbol_table::at_top_level ()
 	  && Vbacktrace_on_warning
 	  && ! warning_state
 	  && ! discard_warning_messages)
--- a/src/file-io.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/file-io.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -44,6 +44,7 @@
 #include <cstdio>
 
 #include <iostream>
+#include <stack>
 #include <vector>
 
 #ifdef HAVE_UNISTD_H
--- a/src/help.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/help.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -61,6 +61,7 @@
 #include "parse.h"
 #include "pathsearch.h"
 #include "procstream.h"
+#include "pt-pr-code.h"
 #include "sighandlers.h"
 #include "symtab.h"
 #include "syswait.h"
@@ -563,18 +564,20 @@
   string_vector key = names (keyword_help ());
   int key_len = key.length ();
 
-  string_vector fbi = fbi_sym_tab->name_list ();
-  int fbi_len = fbi.length ();
+  string_vector bif = symbol_table::built_in_function_names ();
+  int bif_len = bif.length ();
 
-  string_vector glb = global_sym_tab->name_list ();
+  string_vector glb
+    = symbol_table::variable_names (symbol_table::global_scope ());
   int glb_len = glb.length ();
 
-  string_vector top = top_level_sym_tab->name_list ();
+  string_vector top
+    = symbol_table::variable_names (symbol_table::top_scope ());
   int top_len = top.length ();
 
   string_vector lcl;
-  if (top_level_sym_tab != curr_sym_tab)
-    lcl = curr_sym_tab->name_list ();
+  if (! symbol_table::at_top_level ())
+    lcl = symbol_table::variable_names ();
   int lcl_len = lcl.length ();
 
   string_vector ffl = load_path::fcn_names ();
@@ -583,7 +586,8 @@
   string_vector afl = autoloaded_functions ();
   int afl_len = afl.length ();
 
-  int total_len = key_len + fbi_len + glb_len + top_len + lcl_len + ffl_len + afl_len;
+  int total_len = key_len + bif_len + glb_len + top_len + lcl_len
+    + ffl_len + afl_len;
 
   string_vector list (total_len);
 
@@ -594,8 +598,8 @@
   for (i = 0; i < key_len; i++)
     list[j++] = key[i];
 
-  for (i = 0; i < fbi_len; i++)
-    list[j++] = fbi[i];
+  for (i = 0; i < bif_len; i++)
+    list[j++] = bif[i];
 
   for (i = 0; i < glb_len; i++)
     list[j++] = glb[i];
@@ -649,28 +653,19 @@
 }
 
 static void
-display_symtab_names (std::ostream& os, const string_vector& names,
+display_symtab_names (std::ostream& os, const std::list<std::string>& names,
 		      const std::string& desc)
 {
   if (! names.empty ())
     {
       os << "\n*** " << desc << ":\n\n";
-      names.list_in_columns (os);
+
+      string_vector sv (names);
+
+      sv.list_in_columns (os);
     }
 }
 
-#ifdef LIST_SYMBOLS
-#undef LIST_SYMBOLS
-#endif
-#define LIST_SYMBOLS(type, msg) \
-  do \
-    { \
-      string_vector names \
-	= fbi_sym_tab->name_list (string_vector (), true, type); \
-      display_symtab_names (octave_stdout, names, msg); \
-    } \
-  while (0)
-
 static void
 simple_help (void)
 {
@@ -684,18 +679,11 @@
   display_names_from_help_list (octave_stdout, keyword_help (),
 				"reserved words");
 
-  // FIXME -- is this distinction needed?
-
-  LIST_SYMBOLS (symbol_record::COMMAND, "commands");
-
-  LIST_SYMBOLS (symbol_record::MAPPER_FUNCTION, "mapper functions");
+  display_symtab_names (octave_stdout,
+			symbol_table::built_in_function_names (),
+			"built-in functions");
 
-  LIST_SYMBOLS (symbol_record::BUILTIN_FUNCTION, "general functions");
-
-  // Also need to list variables and currently compiled functions from
-  // the symbol table, if there are any.
-
-  // Also need to search octave_path for script files.
+  // FIXME -- list functions defined on command line?
 
   load_path::display (octave_stdout);
 
@@ -944,80 +932,34 @@
   return retval;
 }
 
-std::string
-extract_help_from_dispatch (const std::string& nm)
-{
-  std::string retval;
-
-  symbol_record *builtin = fbi_sym_tab->lookup ("builtin:" + nm, 0);
-
-  if (builtin)
-    {
-      // Check that builtin is up to date.
- 
-      // Don't try to fight octave's function name handling
-      // mechanism.  Instead, move dispatch record out of the way,
-      // and restore the builtin to its original name.
-      symbol_record *dispatch = fbi_sym_tab->lookup (nm, 0);
-
-      if (dispatch)
-	{
-	  dispatch->unprotect ();
-
-	  fbi_sym_tab->rename (nm, "dispatch:" + nm);
-	  fbi_sym_tab->rename ("builtin:" + nm, nm);
-
-	  // Check for updates to builtin function; ignore errors
-	  // that appear (they interfere with renaming), and remove
-	  // the updated name from the current symbol table.  FIXME --
-	  // check that updating a function updates it in all
-	  // contexts.  It may be that it is updated only in the 
-	  // current symbol table, and not the caller.  I believe this
-	  // won't be a problem because the caller will go through the
-	  // same logic and end up with the newer version.
-
-	  octave_function *f = is_valid_function (nm);
-
-	  if (f)
-	    retval = builtin->help ();
-
-	  curr_sym_tab->clear_function (nm);
-
-	  // Move the builtin function out of the way and restore the
-	  // dispatch fuction.  FIXME what if builtin wants to
-	  // protect itself?
-
-	  fbi_sym_tab->rename (nm, "builtin:" + nm);
-	  fbi_sym_tab->rename ("dispatch:" + nm, nm);
-
-	  dispatch->protect ();
-	}
-      else
-	error ("failed to find dispatch record for `builtin:%s'", nm.c_str ());
-    }
-
-  return retval;
-}
-
 static bool
 raw_help_from_symbol_table (const std::string& nm, std::string& h, 
 			    std::string& w, bool& symbol_found)
 {
   bool retval = false;
 
-  symbol_record *sym_rec = lookup_by_name (nm, 0);
+  octave_value val = symbol_table::find_function (nm);
 
-  if (sym_rec && sym_rec->is_defined ())
+  if (val.is_defined ())
     {
-      symbol_found = true;
+      octave_function *fcn = val.function_value ();
+
+      if (fcn)
+	{
+	  symbol_found = true;
 
-      h = sym_rec->help ();
+	  h = fcn->doc_string ();
+
+	  if (! h.empty ())
+	    {
+	      retval = true;
 
-      if (h.length () > 0)
-	{
-	  w = sym_rec->which ();
+	      w = fcn->fcn_file_name ();
 
-	  retval = true;
+	      if (w.empty ())
+		w = fcn->is_user_function ()
+		  ? "command-line function" : "built-in function";
+	    }
 	}
     }
 
@@ -1037,7 +979,7 @@
     {
       if (h.length () > 0)
 	{
-	  h = extract_help_from_dispatch (nm) + h;
+	  h += "\n\n@noindent\n" + symbol_table::help_for_dispatch (nm);
 
 	  display_help_text (os, h);
 
@@ -1193,36 +1135,82 @@
 }
 
 static void
+display_file (std::ostream& os, const std::string& name,
+	      const std::string& fname, const std::string& type,
+	      bool pr_type_info, bool quiet)
+{
+  std::ifstream fs (fname.c_str (), std::ios::in);
+
+  if (fs)
+    {
+      if (pr_type_info && ! quiet)
+	os << name << " is the " << type
+		   << " defined from: " << fname << "\n\n";
+
+      char ch;
+
+      while (fs.get (ch))
+	os << ch;
+    }
+  else
+    os << "unable to open `" << fname << "' for reading!\n";
+}
+
+static void
 do_type (std::ostream& os, const std::string& name, bool pr_type_info,
 	 bool quiet, bool pr_orig_txt)
 {
-  symbol_record *sym_rec = lookup_by_name (name, 0);
+  // FIXME -- should we bother with variables here (earlier versions
+  // of Octave displayed them)?
+
+  octave_value val = symbol_table::varval (name);
 
-  if (sym_rec && sym_rec->is_defined ())
-    sym_rec->type (os, pr_type_info, quiet, pr_orig_txt);
+  if (val.is_defined ())
+    {
+      if (pr_type_info && ! quiet)
+	os << name << " is a variable\n";
+
+      val.print_raw (os, pr_orig_txt);
+
+      if (pr_type_info)
+	os << "\n";
+    }
   else
     {
-      std::string ff = fcn_file_in_path (name);
+      val = symbol_table::find_function (name);
 
-      if (! ff.empty ())
+      if (val.is_defined ())
 	{
-	  std::ifstream fs (ff.c_str (), std::ios::in);
+	  octave_function *fcn = val.function_value ();
+
+	  std::string fn = fcn ? fcn->fcn_file_name () : std::string ();
 
-	  if (fs)
+	  if (pr_orig_txt && ! fn.empty ())
+	    display_file (os, name, fn, "function", pr_type_info, quiet);
+	  else
 	    {
 	      if (pr_type_info && ! quiet)
-		os << name << " is the script file: " << ff << "\n\n";
-
-	      char ch;
+		{
+		  std::string type
+		    = fcn->is_user_function () ? "command-line" : "built-in";
 
-	      while (fs.get (ch))
-		os << ch;
+		  os << name << " is a " << type << " function:\n\n";
+		}
+
+	      tree_print_code tpc (os, "", pr_orig_txt);
+
+	      fcn->accept (tpc);
 	    }
-	  else
-	    os << "unable to open `" << ff << "' for reading!\n";
 	}
       else
-	error ("type: `%s' undefined", name.c_str ());
+	{
+	  std::string fn = fcn_file_in_path (name);
+
+	  if (! fn.empty ())
+	    display_file (os, name, fn, "script", pr_type_info, quiet);
+	  else
+	    error ("type: `%s' undefined", name.c_str ());
+	}
     }
 }
 
@@ -1298,35 +1286,64 @@
 std::string
 do_which (const std::string& name)
 {
-  std::string retval;
+  octave_value val = symbol_table::find_function (name);
 
-  symbol_record *sym_rec = lookup_by_name (name, 0);
+  if (val.is_defined ())
+    {
+      octave_function *fcn = val.function_value ();
 
-  if (sym_rec && sym_rec->is_defined ())
-    retval = sym_rec->which ();
-  else
-    retval = fcn_file_in_path (name);
+      if (fcn)
+	{
+	  std::string fn = fcn->fcn_file_name ();
 
-  return retval;
+	  return fn.empty ()
+	    ? (fcn->is_user_function ()
+	       ? "command-line function" : "built-in function")
+	    : fn;
+	}
+    }
+
+  return fcn_file_in_path (name);
 }
 
 static void
 do_which (std::ostream& os, const std::string& name)
 {
-  symbol_record *sym_rec = lookup_by_name (name, 0);
+  std::string desc;
 
-  if (sym_rec && sym_rec->is_defined ())
-    sym_rec->which (os);
-  else
+  octave_value val = symbol_table::find_function (name);
+
+  if (val.is_defined ())
     {
-      std::string path = fcn_file_in_path (name);
+      octave_function *fcn = val.function_value ();
+
+      if (fcn)
+	{
+	  desc = fcn->fcn_file_name ();
 
-      if (! path.empty ())
-	os << "which: `" << name << "' is the script file\n"
-	   << path << "\n";
+	  if (desc.empty ())
+	    {
+	      if (fcn->is_user_function ())
+		desc = "is a command-line function";
+	      else
+		desc = "is a built-in function";
+	    }
+	  else
+	    desc = "is the function from the file " + desc;
+	}
+    }
+
+  if (desc.empty ())
+    {
+      std::string fn = fcn_file_in_path (name);
+
+      if (! fn.empty ())
+	desc = "is the script file " + fn;
       else
-	os << "which: `" << name << "' is undefined\n";
+	desc = "is undefined";
     }
+
+  os << "which: `" << name << "' " << desc << std::endl;
 }
 
 DEFCMD (which, args, nargout,
@@ -1764,6 +1781,7 @@
 @end deffn")
 {
   octave_value_list retval;
+
   int nargin = args.length ();
   bool first_sentence_only = true;
 
@@ -1897,9 +1915,11 @@
 	  ptr++;
 	}
 
+      string_vector names;
+
+#ifdef OLD_SYMTAB
       // Check the symbol record table
-      string_vector names
-	= fbi_sym_tab->name_list (string_vector (), true);
+      names = fbi_sym_tab->name_list (string_vector (), true);
 
       for (octave_idx_type i = 0; i < names.length (); i++)
 	{
@@ -1947,6 +1967,7 @@
 		}
 	    }
 	}
+#endif
 
       string_vector dirs = load_path::dirs ();
 
@@ -1973,6 +1994,7 @@
 		  else
 		    continue;
 
+#ifdef OLD_SYMTAB
 		  // Check if already in symbol table
 		  symbol_record *sr = fbi_sym_tab->lookup (name);
 
@@ -2037,6 +2059,7 @@
 			    }
 			}
 		    }
+#endif
 
 		  // Check if this function has autoloaded functions attached to it
 		  std::string file_name = load_path::find_fcn (name);
@@ -2049,6 +2072,7 @@
 			{
 			  std::string aname = autoload_fcns (k);
 
+#ifdef OLD_SYMTAB
 			  // Check if already in symbol table
 			  sr = fbi_sym_tab->lookup (aname);
 
@@ -2094,6 +2118,7 @@
 				    }
 				}
 			    }
+#endif
 			}
 		    }
 		}
--- a/src/help.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/help.h	Fri Dec 28 20:56:58 2007 +0000
@@ -31,8 +31,6 @@
 
 extern string_vector make_name_list (void);
 
-extern std::string extract_help_from_dispatch (const std::string&);
-
 extern void display_help_text (std::ostream&, const std::string&);
 
 extern void display_usage_text (std::ostream&, const std::string&);
--- a/src/input.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/input.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -66,7 +66,6 @@
 #include "pt-const.h"
 #include "pt-stmt.h"
 #include "sighandlers.h"
-#include "symtab.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
@@ -265,7 +264,7 @@
 
       // There is no need to update the load_path cache if there is no
       // user input.
-      if (! retval.empty ())
+      if (! retval.empty () && retval.find_first_not_of (" \t\n\r") != NPOS)
 	load_path::update ();
     }
   else
--- a/src/lex.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/lex.h	Fri Dec 28 20:56:58 2007 +0000
@@ -119,6 +119,9 @@
   //  -1 ==> Yes, but it is the last one because we have seen EOF.
   int parsing_nested_function;
 
+  // TRUE means we are parsing a class method.
+  bool parsing_class_method;
+
   // Return transpose or start a string?
   bool quote_is_transpose;
 
--- a/src/lex.l	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/lex.l	Fri Dec 28 20:56:58 2007 +0000
@@ -242,7 +242,6 @@
 static int is_keyword_token (const std::string& s);
 static void prep_for_function (void);
 static void prep_for_nested_function (void);
-static symbol_record *lookup_identifier (const std::string& s);
 static std::string grab_help_text (void);
 static bool match_any (char c, const char *s);
 static bool next_token_is_sep_op (void);
@@ -844,6 +843,8 @@
   while (! symtab_context.empty ())
     symtab_context.pop ();
 
+  symbol_table::reset_parent_scope ();
+
   // We do want a prompt by default.
   promptflag = 1;
 
@@ -959,10 +960,6 @@
 {
   end_tokens_expected++;
 
-  // Prepare for local symbols.
-
-  tmp_local_sym_tab = new symbol_table ();
-
   promptflag--;
 
   lexer_flags.defining_func = true;
@@ -1174,39 +1171,19 @@
   return 0;
 }
 
-// Try to find an identifier.  All binding to global or builtin
-// variables occurs when expressions are evaluated.
-
-static symbol_record *
-lookup_identifier (const std::string& name)
-{
-  std::string sym_name = name;
-
-  if (curr_sym_tab == fbi_sym_tab
-      && lexer_flags.parsing_nested_function)
-    sym_name = parent_function_name + ":" + sym_name;
-
-  return curr_sym_tab->lookup (sym_name, true);
-}
-
 static bool
 is_variable (const std::string& name)
 {
-  symbol_record *sr = curr_sym_tab->lookup (name);
-
-  return sr && sr->is_variable ();
+  return symbol_table::is_variable (name);
 }
 
 static void
 force_local_variable (const std::string& name)
 {
-  if (! is_variable (name))
-    curr_sym_tab->clear (name);
-
-  symbol_record *sr = curr_sym_tab->lookup (name, true);
-
-  if (sr)
-    sr->define (octave_value ());
+  octave_value& val = symbol_table::varref (name);
+
+  if (! val.is_defined ())
+    val = Matrix ();
 }
 
 // Grab the help text from an function file.
@@ -2307,19 +2284,6 @@
 
   yyunput (c1, yytext);
 
-  // Make sure we put the return values of a function in the symbol
-  // table that is local to the function.
-
-  // If we are defining a function and we have not seen the function
-  // name yet and the next token is `=', then this identifier must be
-  // the only return value for the function and it belongs in the
-  // local symbol table.
-
-  if (next_tok_is_eq
-      && lexer_flags.defining_func
-      && ! lexer_flags.parsed_function_name)
-    curr_sym_tab = tmp_local_sym_tab;
-
   // Kluge alert.
   //
   // If we are looking at a text style function, set up to gobble its
@@ -2357,9 +2321,13 @@
   if (tok == "end")
     tok = "__end__";    
 
-  yylval.tok_val = new token (lookup_identifier (tok),
-			      input_line_number,
-			      current_input_column);
+  yylval.tok_val = new token (&(symbol_table::insert (tok)),
+			      input_line_number, current_input_column);
+
+  // FIXME -- this forces a link for tok in the chain of variables for
+  // the current scope.  Probably this step should be done
+  // differently, maybe in symbol_table::insert?
+  symbol_table::varref (tok);
 
   token_stack.push (yylval.tok_val);
 
@@ -2399,6 +2367,7 @@
   defining_func = false;
   parsed_function_name = false;
   parsing_nested_function = 0;
+  parsing_class_method = false;
 
   // Not initiallly looking at a function handle.
   looking_at_function_handle = 0;
--- a/src/load-path.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/load-path.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -43,8 +43,8 @@
 #include "utils.h"
 
 load_path *load_path::instance = 0;
-load_path::hook_function_ptr load_path::add_hook = execute_pkg_add;
-load_path::hook_function_ptr load_path::remove_hook = execute_pkg_del;
+load_path::hook_fcn_ptr load_path::add_hook = execute_pkg_add;
+load_path::hook_fcn_ptr load_path::remove_hook = execute_pkg_del;
 std::string load_path::command_line_path;
 std::string load_path::sys_path;
 
@@ -81,17 +81,7 @@
     {
       dir_mtime = fs.mtime ();
 
-      bool has_private_subdir = get_file_list (dir_name);
-
-      if (! error_state)
-	{
-	  if (has_private_subdir)
-	    {
-	      std::string pdn = file_ops::concat (dir_name, "private");
-
-	      get_private_function_map (pdn);
-	    }
-	}
+      get_file_list (dir_name);
     }
   else
     {
@@ -100,11 +90,9 @@
     }
 }
 
-bool
+void
 load_path::dir_info::get_file_list (const std::string& d)
 {
-  bool has_private_subdir = false;
-
   dir_entry dir (d);
 
   if (dir)
@@ -131,8 +119,10 @@
 	    {
 	      if (fs.is_dir ())
 		{
-		  if (! has_private_subdir && fname == "private")
-		    has_private_subdir = true;
+		  if (fname == "private")
+		    get_private_file_map (full_name);
+		  else if (fname[0] == '@')
+		    get_method_file_map (full_name, fname.substr (1));
 		}
 	      else
 		{
@@ -164,13 +154,13 @@
       std::string msg = dir.error ();
       warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
     }
-
-  return has_private_subdir;
 }
 
-void
-load_path::dir_info::get_private_function_map (const std::string& d)
+load_path::dir_info::fcn_file_map_type
+get_fcn_files (const std::string& d)
 {
+  load_path::dir_info::fcn_file_map_type retval;
+
   dir_entry dir (d);
 
   if (dir)
@@ -204,7 +194,7 @@
 		  else if (ext == ".mex")
 		    t = load_path::MEX_FILE;
 
-		  private_function_map[base] |= t;
+		  retval[base] |= t;
 		}
 	    }
 	}
@@ -214,6 +204,21 @@
       std::string msg = dir.error ();
       warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
     }
+
+  return retval;
+}
+
+void
+load_path::dir_info::get_private_file_map (const std::string& d)
+{
+  private_file_map = get_fcn_files (d);
+}
+
+void
+load_path::dir_info::get_method_file_map (const std::string& d,
+					  const std::string& class_name)
+{
+  method_file_map[class_name] = get_fcn_files (d);
 }
 
 bool
@@ -234,6 +239,9 @@
   return retval;
 }
 
+// FIXME -- maybe we should also maintain a map to speed up this
+// method of access.
+
 load_path::const_dir_info_list_iterator
 load_path::find_dir_info (const std::string& dir_arg) const
 {
@@ -277,51 +285,81 @@
 }
 
 void
-load_path::move (dir_info_list_iterator i, bool at_end)
+load_path::move_fcn_map (const std::string& dir_name,
+			 const string_vector& fcn_files, bool at_end)
 {
-  if (dir_info_list.size () > 1)
+  octave_idx_type len = fcn_files.length ();
+
+  for (octave_idx_type k = 0; k < len; k++)
     {
-      dir_info di = *i;
-
-      dir_info_list.erase (i);
+      std::string fname = fcn_files[k];
 
-      if (at_end)
-	dir_info_list.push_back (di);
-      else
-	dir_info_list.push_front (di);
+      std::string ext;
+      std::string base = fname;
+
+      size_t pos = fname.rfind ('.');
 
-      std::string dir = di.dir_name;
+      if (pos != NPOS)
+	{
+	  base = fname.substr (0, pos);
+	  ext = fname.substr (pos);
+	}
 
-      string_vector fcn_files = di.fcn_files;
+      file_info_list_type& file_info_list = fcn_map[base];
 
-      octave_idx_type len = fcn_files.length ();
-
-      for (octave_idx_type k = 0; k < len; k++)
+      if (file_info_list.size () == 1)
+	continue;
+      else
 	{
-	  std::string fname = fcn_files[k];
+	  for (file_info_list_iterator p = file_info_list.begin ();
+	       p != file_info_list.end ();
+	       p++)
+	    {
+	      if (p->dir_name == dir_name)
+		{
+		  file_info fi = *p;
 
-	  std::string ext;
-	  std::string base = fname;
+		  file_info_list.erase (p);
+
+		  if (at_end)
+		    file_info_list.push_back (fi);
+		  else
+		    file_info_list.push_front (fi);
 
-	  size_t pos = fname.rfind ('.');
+		  break;
+		}
+	    }
+	}
+    }
+}
 
-	  if (pos != NPOS)
-	    {
-	      base = fname.substr (0, pos);
-	      ext = fname.substr (pos);
-	    }
+void
+load_path::move_method_map (const std::string& dir_name, bool at_end)
+{
+  for (method_map_iterator i = method_map.begin ();
+       i != method_map.end ();
+       i++)
+    {
+      std::string class_name = i->first;
 
-	  std::list<file_info>& file_info_list = fcn_map[base];
+      fcn_map_type& fm = i->second;
+
+      std::string full_dir_name
+	= file_ops::concat (dir_name, "@" + class_name);
+
+      for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++)
+	{
+	  file_info_list_type& file_info_list = q->second;
 
 	  if (file_info_list.size () == 1)
 	    continue;
 	  else
 	    {
-	      for (std::list<file_info>::iterator p = file_info_list.begin ();
-		   p != file_info_list.end ();
-		   p++)
+	      for (file_info_list_iterator p = file_info_list.begin ();
+	       p != file_info_list.end ();
+	       p++)
 		{
-		  if (p->dir_name == dir)
+		  if (p->dir_name == full_dir_name)
 		    {
 		      file_info fi = *p;
 
@@ -340,6 +378,30 @@
     }
 }
 
+void
+load_path::move (dir_info_list_iterator i, bool at_end)
+{
+  if (dir_info_list.size () > 1)
+    {
+      dir_info di = *i;
+
+      dir_info_list.erase (i);
+
+      if (at_end)
+	dir_info_list.push_back (di);
+      else
+	dir_info_list.push_front (di);
+
+      std::string dir_name = di.dir_name;
+
+      move_fcn_map (dir_name, di.fcn_files, at_end);
+
+      // No need to move elements of private function map.
+
+      move_method_map (dir_name, at_end);
+    }
+}
+
 static void
 maybe_add_path_elts (std::string& path, const std::string& dir)
 {
@@ -387,6 +449,8 @@
 {
   dir_info_list.clear ();
   fcn_map.clear ();
+  private_fcn_map.clear ();
+  method_map.clear ();
 
   do_append (".", false);
 }
@@ -503,6 +567,10 @@
 
 		  add_to_fcn_map (di, true);
 
+		  add_to_private_fcn_map (di);
+
+		  add_to_method_map (di, true);
+
 		  if (add_hook)
 		    add_hook (dir);
 		}
@@ -527,6 +595,96 @@
     panic_impossible ();
 }
 
+void
+load_path::remove_fcn_map (const std::string& dir,
+			   const string_vector& fcn_files)
+{
+  octave_idx_type len = fcn_files.length ();
+
+  for (octave_idx_type k = 0; k < len; k++)
+    {
+      std::string fname = fcn_files[k];
+
+      std::string ext;
+      std::string base = fname;
+
+      size_t pos = fname.rfind ('.');
+
+      if (pos != NPOS)
+	{
+	  base = fname.substr (0, pos);
+	  ext = fname.substr (pos);
+	}
+
+      file_info_list_type& file_info_list = fcn_map[base];
+
+      for (file_info_list_iterator p = file_info_list.begin ();
+	   p != file_info_list.end ();
+	   p++)
+	{
+	  if (p->dir_name == dir)
+	    {
+	      file_info_list.erase (p);
+
+	      if (file_info_list.empty ())
+		fcn_map.erase (fname);
+
+	      break;
+	    }
+	}
+    }
+}
+
+void
+load_path::remove_private_fcn_map (const std::string& dir)
+{
+  private_fcn_map_iterator p = private_fcn_map.find (dir);
+
+  if (p != private_fcn_map.end ())
+    private_fcn_map.erase (p);
+}
+
+void
+load_path::remove_method_map (const std::string& dir)
+{
+  for (method_map_iterator i = method_map.begin ();
+       i != method_map.end ();
+       i++)
+    {
+      std::string class_name = i->first;
+
+      fcn_map_type& fm = i->second;
+
+      std::string full_dir_name = file_ops::concat (dir, "@" + class_name);
+
+      for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++)
+	{
+	  file_info_list_type& file_info_list = q->second;
+
+	  if (file_info_list.size () == 1)
+	    continue;
+	  else
+	    {
+	      for (file_info_list_iterator p = file_info_list.begin ();
+	       p != file_info_list.end ();
+	       p++)
+		{
+		  if (p->dir_name == full_dir_name)
+		    {
+		      file_info_list.erase (p);
+
+		      // FIXME -- if there are no other elements, we
+		      // should remove this element of fm but calling
+		      // erase here would invalidate the iterator q.
+
+		      break;
+		    }
+		}
+	    }
+	}
+    }
+}
+
 bool
 load_path::do_remove (const std::string& dir_arg)
 {
@@ -558,40 +716,11 @@
 
 	      dir_info_list.erase (i);
 
-	      octave_idx_type len = fcn_files.length ();
-
-	      for (octave_idx_type k = 0; k < len; k++)
-		{
-		  std::string fname = fcn_files[k];
-
-		  std::string ext;
-		  std::string base = fname;
-
-		  size_t pos = fname.rfind ('.');
-
-		  if (pos != NPOS)
-		    {
-		      base = fname.substr (0, pos);
-		      ext = fname.substr (pos);
-		    }
+	      remove_fcn_map (dir, fcn_files);
 
-		  std::list<file_info>& file_info_list = fcn_map[base];
+	      remove_private_fcn_map (dir);
 
-		  for (std::list<file_info>::iterator p = file_info_list.begin ();
-		       p != file_info_list.end ();
-		       p++)
-		    {
-		      if (p->dir_name == dir)
-			{
-			  file_info_list.erase (p);
-
-			  if (file_info_list.empty ())
-			    fcn_map.erase (fname);
-
-			  break;
-			}
-		    }
-		}
+	      remove_method_map (dir);
 	    }
 	}
     }
@@ -608,6 +737,10 @@
 
   fcn_map.clear ();
 
+  private_fcn_map.clear ();
+
+  method_map.clear ();
+
   for (dir_info_list_iterator p = dir_info_list.begin ();
        p != dir_info_list.end ();
        p++)
@@ -617,21 +750,122 @@
       di.update ();
 
       add_to_fcn_map (di, true);
+
+      add_to_private_fcn_map (di);
+
+      add_to_method_map (di, true);
     }
 }
 
+bool
+load_path::check_file_type (std::string& fname, int type, int possible_types,
+			    const std::string& fcn, const char *who)
+{
+  bool retval = false;
+
+  if (type == load_path::OCT_FILE)
+    {
+      if ((type & possible_types) == load_path::OCT_FILE)
+	{
+	  fname += ".oct";
+	  retval = true;
+	}
+    }
+  else if (type == load_path::M_FILE)
+    {
+      if ((type & possible_types) == load_path::M_FILE)
+	{
+	  fname += ".m";
+	  retval = true;
+	}
+    }
+  else if (type == load_path::MEX_FILE)
+    {
+      if ((type & possible_types) == load_path::MEX_FILE)
+	{
+	  fname += ".mex";
+	  retval = true;
+	}
+    }
+  else if (type == (load_path::M_FILE | load_path::OCT_FILE))
+    {
+      if (possible_types & load_path::OCT_FILE)
+	{
+	  fname += ".oct";
+	  retval = true;
+	}
+      else if (possible_types & load_path::M_FILE)
+	{
+	  fname += ".m";
+	  retval = true;
+	}
+    }
+  else if (type == (load_path::M_FILE | load_path::MEX_FILE))
+    {
+      if (possible_types & load_path::MEX_FILE)
+	{
+	  fname += ".mex";
+	  retval = true;
+	}
+      else if (possible_types & load_path::M_FILE)
+	{
+	  fname += ".m";
+	  retval = true;
+	}
+    }
+  else if (type == (load_path::OCT_FILE | load_path::MEX_FILE))
+    {
+      if (possible_types & load_path::OCT_FILE)
+	{
+	  fname += ".oct";
+	  retval = true;
+	}
+      else if (possible_types & load_path::MEX_FILE)
+	{
+	  fname += ".mex";
+	  retval = true;
+	}
+    }
+  else if (type == (load_path::M_FILE | load_path::OCT_FILE
+		    | load_path::MEX_FILE))
+    {
+      if (possible_types & load_path::OCT_FILE)
+	{
+	  fname += ".oct";
+	  retval = true;
+	}
+      else if (possible_types & load_path::MEX_FILE)
+	{
+	  fname += ".mex";
+	  retval = true;
+	}
+      else if (possible_types & load_path::M_FILE)
+	{
+	  fname += ".m";
+	  retval = true;
+	}
+    }
+  else
+    error ("%s: %s: invalid type code = %d", who, fcn.c_str (), type);
+
+  return retval;
+} 
+
 std::string
-load_path::do_find_fcn (const std::string& fcn, int type) const
+load_path::do_find_fcn (const std::string& fcn, std::string& dir_name,
+			int type) const
 {
   std::string retval;
+  
+  //  update ();
 
-  update ();
+  dir_name = std::string ();
 
   const_fcn_map_iterator p = fcn_map.find (fcn);
 
   if (p != fcn_map.end ())
     {
-      const std::list<file_info>& file_info_list = p->second;
+      const file_info_list_type& file_info_list = p->second;
 
       for (const_file_info_list_iterator i = file_info_list.begin ();
 	   i != file_info_list.end ();
@@ -639,104 +873,123 @@
 	{
 	  const file_info& fi = *i;
 
-	  int t = fi.types;
-
 	  retval = file_ops::concat (fi.dir_name, fcn);
 
-	  if (type == load_path::OCT_FILE)
+	  if (check_file_type (retval, type, fi.types,
+			       fcn, "load_path::do_find_fcn"))
 	    {
-	      if ((type & t) == load_path::OCT_FILE)
-		{
-		  retval += ".oct";
-		  break;
-		}
-	    }
-	  else if (type == load_path::M_FILE)
-	    {
-	      if ((type & t) == load_path::M_FILE)
-		{
-		  retval += ".m";
-		  break;
-		}
+	      dir_name = fi.dir_name;
+	      break;
 	    }
-	  else if (type == load_path::MEX_FILE)
+	  else
+	    retval = std::string ();
+	}
+    }
+
+  return retval;
+}
+
+std::string
+load_path::do_find_private_fcn (const std::string& dir,
+				const std::string& fcn, int type) const
+{
+  std::string retval;
+
+  //  update ();
+
+  const_private_fcn_map_iterator q = private_fcn_map.find (dir);
+
+  if (q != private_fcn_map.end ())
+    {
+      const dir_info::fcn_file_map_type& m = q->second;
+
+      dir_info::const_fcn_file_map_iterator p = m.find (fcn);
+
+      if (p != m.end ())
+	{
+	  std::string fname
+	    = file_ops::concat (file_ops::concat (dir, "private"), fcn);
+
+	  if (check_file_type (fname, type, p->second, fcn,
+			       "load_path::find_private_fcn"))
+	    retval = fname;
+	}
+    }
+
+  return retval;
+}
+
+std::string
+load_path::do_find_method (const std::string& class_name,
+			   const std::string& meth,
+			   std::string& dir_name, int type) const
+{
+  std::string retval;
+
+  //  update ();
+
+  dir_name = std::string ();
+
+  const_method_map_iterator q = method_map.find (class_name);
+
+  if (q != method_map.end ())
+    {
+      const fcn_map_type& m = q->second;
+
+      const_fcn_map_iterator p = m.find (meth);
+
+      if (p != m.end ())
+	{
+	  const file_info_list_type& file_info_list = p->second;
+
+	  for (const_file_info_list_iterator i = file_info_list.begin ();
+	       i != file_info_list.end ();
+	       i++)
 	    {
-	      if ((type & t) == load_path::MEX_FILE)
+	      const file_info& fi = *i;
+
+	      retval = file_ops::concat (fi.dir_name, meth);
+
+	      bool found = check_file_type (retval, type, fi.types,
+					    meth, "load_path::do_find_method");
+
+	      if (found)
 		{
-		  retval += ".mex";
-		  break;
-		}
-	    }
-	  else if (type == (load_path::M_FILE | load_path::OCT_FILE))
-	    {
-	      if (t & load_path::OCT_FILE)
-		{
-		  retval += ".oct";
-		  break;
-		}
-	      else if (t & load_path::M_FILE)
-		{
-		  retval += ".m";
+		  dir_name = fi.dir_name;
 		  break;
 		}
-	    }
-	  else if (type == (load_path::M_FILE | load_path::MEX_FILE))
-	    {
-	      if (t & load_path::MEX_FILE)
-		{
-		  retval += ".mex";
-		  break;
-		}
-	      else if (t & load_path::M_FILE)
-		{
-		  retval += ".m";
-		  break;
-		}
+	      else
+		retval = std::string ();
 	    }
-	  else if (type == (load_path::OCT_FILE | load_path::MEX_FILE))
-	    {
-	      if (t & load_path::OCT_FILE)
-		{
-		  retval += ".oct";
-		  break;
-		}
-	      else if (t & load_path::MEX_FILE)
-		{
-		  retval += ".mex";
-		  break;
-		}
-	    }
-	  else if (type == (load_path::M_FILE | load_path::OCT_FILE
-			    | load_path::MEX_FILE))
-	    {
-	      if (t & load_path::OCT_FILE)
-		{
-		  retval += ".oct";
-		  break;
-		}
-	      else if (t & load_path::MEX_FILE)
-		{
-		  retval += ".mex";
-		  break;
-		}
-	      else if (t & load_path::M_FILE)
-		{
-		  retval += ".m";
-		  break;
-		}
-	    }
-	  else
-	    error ("load_path::do_find_fcn: %s: invalid type code = %d",
-		   fcn.c_str (), type);
- 
- 	  // Reset the return string, in case the above tesst fail.
- 	  retval = std::string ();
 	}
     }
 
   return retval;
 }
 
+std::list<std::string>
+load_path::do_methods (const std::string& class_name) const
+{
+  std::list<std::string> retval;
+
+  //  update ();
+
+  const_method_map_iterator q = method_map.find (class_name);
+
+  if (q != method_map.end ())
+    {
+      const fcn_map_type& m = q->second;
+
+      for (const_fcn_map_iterator p = m.begin (); p != m.end (); p++)
+	retval.push_back (p->first);
+    }
+
+  if (! retval.empty ())
+    retval.sort ();
+
+  return retval;
+}
+
 std::string
 load_path::do_find_file (const std::string& file) const
 {
@@ -987,6 +1240,80 @@
 }
 
 void
+print_types (std::ostream& os, int types)
+{
+  bool printed_type = false;
+
+  if (types & load_path::OCT_FILE)
+    {
+      os << "oct";
+      printed_type = true;
+    }
+
+  if (types & load_path::MEX_FILE)
+    {
+      if (printed_type)
+	os << "|";
+      os << "mex";
+      printed_type = true;
+    }
+
+  if (types & load_path::M_FILE)
+    {
+      if (printed_type)
+	os << "|";
+      os << "m";
+      printed_type = true;
+    }
+}
+
+void
+print_fcn_list (std::ostream& os,
+		const load_path::dir_info::fcn_file_map_type& lst)
+{
+  for (load_path::dir_info::const_fcn_file_map_iterator p = lst.begin ();
+       p != lst.end ();
+       p++)
+    {
+      os << "  " << p->first << " (";
+
+      print_types (os, p->second);
+
+      os << ")\n";
+    }
+}
+
+string_vector
+get_file_list (const load_path::dir_info::fcn_file_map_type& lst)
+{
+  octave_idx_type n = lst.size ();
+
+  string_vector retval (n);
+
+  octave_idx_type count = 0;
+
+  for (load_path::dir_info::const_fcn_file_map_iterator p = lst.begin ();
+       p != lst.end ();
+       p++)
+    {
+      std::string nm = p->first;
+
+      int types = p->second;
+
+      if (types & load_path::OCT_FILE)
+	nm += ".oct";
+      else if (types & load_path::MEX_FILE)
+	nm += ".mex";
+      else
+	nm += ".m";
+
+      retval[count++] = nm;
+    }
+
+  return retval;
+}
+
+void
 load_path::do_display (std::ostream& os) const
 {
   for (const_dir_info_list_iterator i = dir_info_list.begin ();
@@ -1002,53 +1329,32 @@
 	  fcn_files.list_in_columns (os);
 	}
 
-#if defined (DEBUG_LOAD_PATH)
-
-      const std::map<std::string, int>& private_function_map
-	= i->private_function_map;
+      const dir_info::method_file_map_type& method_file_map
+	= i->method_file_map;
 
-      if (private_function_map.size () > 0)
+      if (! method_file_map.empty ())
 	{
-	  os << "private:\n";
-
-	  for (std::map<std::string, int>::const_iterator p = private_function_map.begin ();
-	       p != private_function_map.end ();
+	  for (dir_info::const_method_file_map_iterator p = method_file_map.begin ();
+	       p != method_file_map.end ();
 	       p++)
 	    {
-	      os << "  " << p->first << " (";
-
-	      bool printed_type = false;
-
-	      int types = p->second;
+	      os << "\n*** methods in " << i->dir_name
+		 << "/@" << p->first << ":\n\n";
 
-	      if (types & load_path::OCT_FILE)
-		{
-		  os << "oct";
-		  printed_type = true;
-		}
+	      string_vector method_files = get_file_list (p->second);
 
-	      if (types & load_path::MEX_FILE)
-		{
-		  if (printed_type)
-		    os << "|";
-		  os << "mex";
-		  printed_type = true;
-		}
+	      method_files.list_in_columns (os);
+	    }
+	}
+    }
 
-	      if (types & load_path::M_FILE)
-		{
-		  if (printed_type)
-		    os << "|";
-		  os << "m";
-		  printed_type = true;
-		}
+  for (const_private_fcn_map_iterator i = private_fcn_map.begin ();
+       i != private_fcn_map.end (); i++)
+    {
+      os << "\n*** private functions in "
+	 << file_ops::concat (i->first, "private") << ":\n\n";
 
-	      os << ")\n";
-	    }
-
-	  os << "\n";
-	}
-#endif
+      print_fcn_list (os, i->second);
     }
 
 #if defined (DEBUG_LOAD_PATH)
@@ -1059,7 +1365,7 @@
     {
       os << i->first << ":\n";
 
-      const std::list<file_info>& file_info_list = i->second;
+      const file_info_list_type& file_info_list = i->second;
 
       for (const_file_info_list_iterator p = file_info_list.begin ();
 	   p != file_info_list.end ();
@@ -1067,34 +1373,41 @@
 	{
 	  os << "  " << p->dir_name << " (";
 
-	  bool printed_type = false;
-
-	  if (p->types & load_path::OCT_FILE)
-	    {
-	      os << "oct";
-	      printed_type = true;
-	    }
-
-	  if (p->types & load_path::MEX_FILE)
-	    {
-	      if (printed_type)
-		os << "|";
-	      os << "mex";
-	      printed_type = true;
-	    }
-
-	  if (p->types & load_path::M_FILE)
-	    {
-	      if (printed_type)
-		os << "|";
-	      os << "m";
-	      printed_type = true;
-	    }
+	  print_types (os, p->types);
 
 	  os << ")\n";
 	}
     }
 
+  for (const_method_map_iterator i = method_map.begin ();
+       i != method_map.end ();
+       i++)
+    {
+      os << "CLASS " << i->first << ":\n";
+
+      const fcn_map_type& fm = i->second;
+
+      for (const_fcn_map_iterator q = fm.begin ();
+	   q != fm.end ();
+	   q++)
+	{
+	  os << "  " << q->first << ":\n";
+
+	  const file_info_list_type& file_info_list = q->second;
+
+	  for (const_file_info_list_iterator p = file_info_list.begin ();
+	       p != file_info_list.end ();
+	       p++)
+	    {
+	      os << "  " << p->dir_name << " (";
+
+	      print_types (os, p->types);
+
+	      os << ")\n";
+	    }
+	}
+    }
+
   os << "\n";
 
 #endif
@@ -1124,7 +1437,7 @@
 	  ext = fname.substr (pos);
 	}
 
-      std::list<file_info>& file_info_list = fcn_map[base];
+      file_info_list_type& file_info_list = fcn_map[base];
 
       file_info_list_iterator p = file_info_list.begin ();
 
@@ -1162,6 +1475,78 @@
     }
 }
 
+void
+load_path::add_to_private_fcn_map (const dir_info& di) const
+{
+  dir_info::fcn_file_map_type private_file_map = di.private_file_map;
+
+  if (! private_file_map.empty ())
+    private_fcn_map[di.dir_name] = private_file_map;
+}
+
+void
+load_path::add_to_method_map (const dir_info& di, bool at_end) const
+{
+  std::string dir_name = di.dir_name;
+
+  // <CLASS_NAME, <FCN_NAME, TYPES>>
+  dir_info::method_file_map_type method_file_map = di.method_file_map;
+
+  for (dir_info::const_method_file_map_iterator q = method_file_map.begin ();
+       q != method_file_map.end ();
+       q++)
+    {
+      std::string class_name = q->first;
+
+      fcn_map_type& fm = method_map[class_name];
+
+      std::string full_dir_name
+	= file_ops::concat (dir_name, "@" + class_name);
+
+      // <FCN_NAME, TYPES>
+      const dir_info::fcn_file_map_type& m = q->second;
+
+      for (dir_info::const_fcn_file_map_iterator p = m.begin ();
+	   p != m.end ();
+	   p++)
+	{
+	  std::string base = p->first;
+
+	  int types = p->second;
+
+	  file_info_list_type& file_info_list = fm[base];
+
+	  file_info_list_iterator p2 = file_info_list.begin ();
+
+	  while (p2 != file_info_list.end ())
+	    {
+	      if (p2->dir_name == full_dir_name)
+		break;
+
+	      p2++;
+	    }
+
+	  if (p2 == file_info_list.end ())
+	    {
+	      file_info fi (full_dir_name, types);
+
+	      if (at_end)
+		file_info_list.push_back (fi);
+	      else
+		file_info_list.push_front (fi);
+	    }
+	  else
+	    {
+	      // FIXME -- is this possible?
+
+	      file_info& fi = *p2;
+
+	      fi.types = types;
+	    }
+	}
+    }
+}
+
 std::string
 genpath (const std::string& dirname, const string_vector& skip)
 {
@@ -1182,9 +1567,10 @@
 	  std::string elt = dirlist[i];
 
 	  // FIXME -- the caller should be able to specify the list of
-	  // directories to skip in addition to "." and "..".
+	  // directories to skip in addition to ".", "..", and
+	  // directories beginning with "@".
 
-	  bool skip_p = (elt == "." || elt == "..");
+	  bool skip_p = (elt == "." || elt == ".." || elt[0] == '@');
 
 	  if (! skip_p)
 	    {
--- a/src/load-path.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/load-path.h	Fri Dec 28 20:56:58 2007 +0000
@@ -37,11 +37,11 @@
 {
 protected:
 
-  load_path (void) : dir_info_list (), fcn_map () { }
+  load_path (void) : dir_info_list (), fcn_map (), method_map () { }
 
 public:
 
-  typedef void (*hook_function_ptr) (const std::string& dir);
+  typedef void (*hook_fcn_ptr) (const std::string& dir);
 
   ~load_path (void) { }
 
@@ -86,28 +86,68 @@
       instance->do_update ();
   }
 
+  static std::string find_method (const std::string& class_name,
+				  const std::string& meth,
+				  std::string& dir_name)
+  {
+    return instance_ok ()
+      ? instance->do_find_method (class_name, meth, dir_name) : std::string ();
+  }
+
+  static std::string find_method (const std::string& class_name,
+				  const std::string& meth)
+  {
+    std::string dir_name;
+    return find_method (class_name, meth, dir_name);
+  }
+
+  static std::list<std::string> methods (const std::string& class_name)
+  {
+    return instance_ok ()
+      ? instance->do_methods (class_name) : std::list<std::string> ();
+  }
+
+  static std::string find_fcn (const std::string& fcn, std::string& dir_name)
+  {
+    return instance_ok ()
+      ? instance->do_find_fcn (fcn, dir_name) : std::string ();
+  }
+
   static std::string find_fcn (const std::string& fcn)
   {
+    std::string dir_name;
+    return find_fcn (fcn, dir_name);
+  }
+
+  static std::string find_private_fcn (const std::string& dir,
+				       const std::string& fcn)
+  {
     return instance_ok ()
-      ? instance->do_find_fcn (fcn) : std::string ();
+      ? instance->do_find_private_fcn (dir, fcn) : std::string ();
   }
 
   static std::string find_fcn_file (const std::string& fcn)
   {
+    std::string dir_name;
+
     return instance_ok () ?
-      instance->do_find_fcn (fcn, M_FILE) : std::string ();
+      instance->do_find_fcn (fcn, dir_name, M_FILE) : std::string ();
   }
 
   static std::string find_oct_file (const std::string& fcn)
   {
+    std::string dir_name;
+
     return instance_ok () ?
-      instance->do_find_fcn (fcn, OCT_FILE) : std::string ();
+      instance->do_find_fcn (fcn, dir_name, OCT_FILE) : std::string ();
   }
 
   static std::string find_mex_file (const std::string& fcn)
   {
+    std::string dir_name;
+
     return instance_ok () ?
-      instance->do_find_fcn (fcn, MEX_FILE) : std::string ();
+      instance->do_find_fcn (fcn, dir_name, MEX_FILE) : std::string ();
   }
 
   static std::string find_file (const std::string& file)
@@ -160,9 +200,9 @@
       instance->do_display (os);
   }
 
-  static void set_add_hook (hook_function_ptr f) { add_hook = f; }
+  static void set_add_hook (hook_fcn_ptr f) { add_hook = f; }
 
-  static void set_remove_hook (hook_function_ptr f) { remove_hook = f; }
+  static void set_remove_hook (hook_fcn_ptr f) { remove_hook = f; }
 
   static void set_command_line_path (const std::string& p)
   {
@@ -187,13 +227,26 @@
   {
   public:
 
+    // <FCN_NAME, TYPE>
+    typedef std::map<std::string, int> fcn_file_map_type;
+
+    typedef fcn_file_map_type::const_iterator const_fcn_file_map_iterator;
+    typedef fcn_file_map_type::iterator fcn_file_map_iterator;
+
+    // <CLASS_NAME, <FCN_NAME, TYPE>>
+    typedef std::map<std::string, fcn_file_map_type> method_file_map_type;
+
+    typedef method_file_map_type::const_iterator const_method_file_map_iterator;
+    typedef method_file_map_type::iterator method_file_map_iterator;
+
     dir_info (const std::string& d) : dir_name (d) { initialize (); }
 
     dir_info (const dir_info& di)
       : dir_name (di.dir_name), is_relative (di.is_relative),
 	dir_mtime (di.dir_mtime), all_files (di.all_files),
 	fcn_files (di.fcn_files),
-	private_function_map (di.private_function_map) { }
+	private_file_map (di.private_file_map),
+	method_file_map (di.method_file_map) { }
 
     ~dir_info (void) { }
 
@@ -206,7 +259,8 @@
 	  dir_mtime = di.dir_mtime;
 	  all_files = di.all_files;
 	  fcn_files = di.fcn_files;
-	  private_function_map = di.private_function_map;
+	  private_file_map = di.private_file_map;
+	  method_file_map = di.method_file_map;
 	}
 
       return *this;
@@ -219,15 +273,21 @@
     octave_time dir_mtime;
     string_vector all_files;
     string_vector fcn_files;
-    std::map<std::string, int> private_function_map;
+    fcn_file_map_type private_file_map;
+    method_file_map_type method_file_map;
 
   private:
 
     void initialize (void);
 
-    bool get_file_list (const std::string& d);
+    void get_file_list (const std::string& d);
+
+    void get_private_file_map (const std::string& d);
 
-    void get_private_function_map (const std::string& d);
+    void get_method_file_map (const std::string& d,
+			      const std::string& class_name);
+
+    friend fcn_file_map_type get_fcn_files (const std::string& d);
   };
 
   class file_info
@@ -263,21 +323,53 @@
   // in each directory.
   //
   // Second, a map from file names (the union of all "public" files for all
-  // directories, but without filename exteinsions) to a list of
+  // directories, but without filename extensions) to a list of
   // corresponding information (directory name and file types).  This
   // way, we can quickly find shadowed file names and look up all
   // overloaded functions (in the "@" directories used to implement
   // classes).
 
-  mutable std::list<dir_info> dir_info_list;
+  typedef std::list<dir_info> dir_info_list_type;
+
+  typedef dir_info_list_type::const_iterator const_dir_info_list_iterator;
+  typedef dir_info_list_type::iterator dir_info_list_iterator;
+
+  typedef std::list<file_info> file_info_list_type;
+
+  typedef file_info_list_type::const_iterator const_file_info_list_iterator;
+  typedef file_info_list_type::iterator file_info_list_iterator;
+
+  // <FCN_NAME, FILE_INFO_LIST>
+  typedef std::map<std::string, file_info_list_type> fcn_map_type;
+
+  typedef fcn_map_type::const_iterator const_fcn_map_iterator;
+  typedef fcn_map_type::iterator fcn_map_iterator;
 
-  mutable std::map<std::string, std::list<file_info> > fcn_map;
+  // <DIR_NAME, <FCN_NAME, TYPE>>
+  typedef std::map<std::string, dir_info::fcn_file_map_type> private_fcn_map_type;
+
+  typedef private_fcn_map_type::const_iterator const_private_fcn_map_iterator;
+  typedef private_fcn_map_type::iterator private_fcn_map_iterator;
+
+  // <CLASS_NAME, <FCN_NAME, FILE_INFO_LIST>>
+  typedef std::map<std::string, fcn_map_type> method_map_type;
+
+  typedef method_map_type::const_iterator const_method_map_iterator;
+  typedef method_map_type::iterator method_map_iterator;
+
+  mutable dir_info_list_type dir_info_list;
+
+  mutable fcn_map_type fcn_map;
+
+  mutable private_fcn_map_type private_fcn_map;
+
+  mutable method_map_type method_map;
 
   static load_path *instance;
 
-  static hook_function_ptr add_hook;
+  static hook_fcn_ptr add_hook;
 
-  static hook_function_ptr remove_hook;
+  static hook_fcn_ptr remove_hook;
 
   static std::string command_line_path;
 
@@ -285,20 +377,16 @@
 
   static bool instance_ok (void);
 
-  typedef std::list<dir_info>::const_iterator const_dir_info_list_iterator;
-  typedef std::list<dir_info>::iterator dir_info_list_iterator;
-
-  typedef std::map<std::string, std::list<file_info> >::const_iterator const_fcn_map_iterator;
-  typedef std::map<std::string, std::list<file_info> >::iterator fcn_map_iterator;
-
-  typedef std::list<file_info>::const_iterator const_file_info_list_iterator;
-  typedef std::list<file_info>::iterator file_info_list_iterator;
-
   const_dir_info_list_iterator find_dir_info (const std::string& dir) const;
   dir_info_list_iterator find_dir_info (const std::string& dir);
 
   bool contains (const std::string& dir) const;
 
+  void move_fcn_map (const std::string& dir,
+		     const string_vector& fcn_files, bool at_end);
+
+  void move_method_map (const std::string& dir, bool at_end);
+
   void move (std::list<dir_info>::iterator i, bool at_end);
 
   void do_initialize (bool set_initial_path);
@@ -313,13 +401,35 @@
 
   void do_add (const std::string& dir, bool at_end, bool warn);
 
+  void remove_fcn_map (const std::string& dir, const string_vector& fcn_files);
+
+  void remove_private_fcn_map (const std::string& dir);
+
+  void remove_method_map (const std::string& dir);
+
   bool do_remove (const std::string& dir);
 
   void do_update (void) const;
 
+  static bool
+  check_file_type (std::string& fname, int type, int possible_types,
+		   const std::string& fcn, const char *who);
+
   std::string do_find_fcn (const std::string& fcn,
+			   std::string& dir_name,
 			   int type = M_FILE | OCT_FILE | MEX_FILE) const;
 
+  std::string do_find_private_fcn (const std::string& dir,
+				   const std::string& fcn,
+				   int type = M_FILE | OCT_FILE | MEX_FILE) const;
+
+  std::string do_find_method (const std::string& class_name,
+			      const std::string& meth,
+			      std::string& dir_name,
+			      int type = M_FILE | OCT_FILE | MEX_FILE) const;
+
+  std::list<std::string> do_methods (const std::string& class_name) const;
+
   std::string do_find_file (const std::string& file) const;
 
   std::string do_find_first_of (const string_vector& files) const;
@@ -336,11 +446,24 @@
 
   std::string do_path (void) const;
 
+  friend void print_types (std::ostream& os, int types);
+
+  friend string_vector get_file_list (const dir_info::fcn_file_map_type& lst);
+
+  friend void
+  print_fcn_list (std::ostream& os, const dir_info::fcn_file_map_type& lst);
+
   void do_display (std::ostream& os) const;
 
   std::string do_system_path (void) const { return sys_path; }
 
   void add_to_fcn_map (const dir_info& di, bool at_end) const;
+
+  void add_to_private_fcn_map (const dir_info& di) const;
+
+  void add_to_method_map (const dir_info& di, bool at_end) const;
+
+  friend dir_info::fcn_file_map_type get_fcn_files (const std::string& d);
 };
 
 extern std::string
--- a/src/load-save.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/load-save.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -132,149 +132,22 @@
     error ("%s: unable to open file `%s'", fcn.c_str (), file.c_str ());
 }
 
-// FIXME -- shouldn't this be implemented in terms of other
-// functions that are already available?
-
-// Install a variable with name NAME and the value specified TC in the
-// symbol table.  If FORCE is TRUE, replace any existing definition
-// for NAME.  If GLOBAL is TRUE, make the variable global.
-//
-// Assumes TC is defined.
+// Install a variable with name NAME and the value VAL in the
+// symbol table.  If GLOBAL is TRUE, make the variable global.
 
 static void
-install_loaded_variable (int force, const std::string& name,
+install_loaded_variable (const std::string& name,
 			 const octave_value& val,
-			 int global, const std::string& doc)
+			 bool global, const std::string& /*doc*/)
 {
-  // Is there already a symbol by this name?  If so, what is it?
-
-  symbol_record *lsr = curr_sym_tab->lookup (name);
-
-  bool is_undefined = true;
-  bool is_variable = false;
-  bool is_function = false;
-  bool is_global = false;
-
-  if (lsr)
-    {
-      is_undefined = ! lsr->is_defined ();
-      is_variable = lsr->is_variable ();
-      is_function = lsr->is_function ();
-      is_global = lsr->is_linked_to_global ();
-    }
-
-  symbol_record *sr = 0;
-
   if (global)
     {
-      if (is_global || is_undefined)
-	{
-	  if (force || is_undefined)
-	    {
-	      lsr = curr_sym_tab->lookup (name, true);
-	      link_to_global_variable (lsr);
-	      sr = lsr;
-	    }
-	  else
-	    {
-	      warning ("load: global variable name `%s' exists",
-		       name.c_str ());
-	      warning ("use `load -force' to overwrite");
-	    }
-	}
-      else if (is_function)
-	{
-	  if (force)
-	    {
-	      lsr = curr_sym_tab->lookup (name, true);
-	      link_to_global_variable (lsr);
-	      sr = lsr;
-	    }
-	  else
-	    {
-	      warning ("load: `%s' is currently a function in this scope",
-		       name.c_str ());
-	      warning ("`load -force' will load variable and hide function");
-	    }
-	}
-      else if (is_variable)
-	{
-	  if (force)
-	    {
-	      lsr = curr_sym_tab->lookup (name, true);
-	      link_to_global_variable (lsr);
-	      sr = lsr;
-	    }
-	  else
-	    {
-	      warning ("load: local variable name `%s' exists",
-		       name.c_str ());
-	      warning ("use `load -force' to overwrite");
-	    }
-	}
-      else
-	error ("load: unable to load data for unknown symbol type");
+      symbol_table::clear (name);
+      symbol_table::mark_global (name);
+      symbol_table::varref (name, symbol_table::global_scope ()) = val;
     }
   else
-    {
-      if (is_global)
-	{
-	  if (force || is_undefined)
-	    {
-	      lsr = curr_sym_tab->lookup (name, true);
-	      link_to_global_variable (lsr);
-	      sr = lsr;
-	    }
-	  else
-	    {
-	      warning ("load: global variable name `%s' exists",
-		       name.c_str ());
-	      warning ("use `load -force' to overwrite");
-	    }
-	}
-      else if (is_function)
-	{
-	  if (force)
-	    {
-	      lsr = curr_sym_tab->lookup (name, true);
-	      link_to_global_variable (lsr);
-	      sr = lsr;
-	    }
-	  else
-	    {
-	      warning ("load: `%s' is currently a function in this scope",
-		       name.c_str ());
-	      warning ("`load -force' will load variable and hide function");
-	    }
-	}
-      else if (is_variable || is_undefined)
-	{
-	  if (force || is_undefined)
-	    {
-	      lsr = curr_sym_tab->lookup (name, true);
-	      sr = lsr;
-	    }
-	  else
-	    {
-	      warning ("load: local variable name `%s' exists",
-		       name.c_str ());
-	      warning ("use `load -force' to overwrite");
-	    }
-	}
-      else
-	error ("load: unable to load data for unknown symbol type");
-    }
-
-  if (sr)
-    {
-      sr->define (val);
-      sr->document (doc);
-      return;
-    }
-  else
-    error ("load: unable to load variable `%s'", name.c_str ());
-
-  return;
+    symbol_table::varref (name) = val;
 }
 
 // Return TRUE if NAME matches one of the given globbing PATTERNS.
@@ -451,7 +324,7 @@
 }
 
 octave_value
-do_load (std::istream& stream, const std::string& orig_fname, bool force,
+do_load (std::istream& stream, const std::string& orig_fname,
 	 load_save_format format, oct_mach_info::float_format flt_fmt,
 	 bool list_only, bool swap, bool verbose,
 	 const string_vector& argv, int argv_idx, int argc, int nargout)
@@ -552,7 +425,7 @@
 			    retstruct.assign (name, tc);
 			}
 		      else
-			install_loaded_variable (force, name, tc, global, doc);
+			install_loaded_variable (name, tc, global, doc);
 		    }
 		}
 
@@ -766,7 +639,6 @@
 
   load_save_format format = LS_UNKNOWN;
 
-  bool force = true;
   bool list_only = false;
   bool verbose = false;
 
@@ -857,7 +729,7 @@
 	  // that we can get additional input?  I'm afraid that we
 	  // can't fix this using std::cin only.
 
-	  retval = do_load (std::cin, orig_fname, force, format, flt_fmt,
+	  retval = do_load (std::cin, orig_fname, format, flt_fmt,
 			    list_only, swap, verbose, argv, i, argc,
 			    nargout);
 	}
@@ -887,7 +759,7 @@
 
 	  if (hdf5_file.file_id >= 0)
 	    {
-	      retval = do_load (hdf5_file, orig_fname, force, format,
+	      retval = do_load (hdf5_file, orig_fname, format,
 				flt_fmt, list_only, swap, verbose,
 				argv, i, argc, nargout);
 
@@ -940,7 +812,7 @@
 			}
 		    }
 
-		  retval = do_load (file, orig_fname, force, format,
+		  retval = do_load (file, orig_fname, format,
 				    flt_fmt, list_only, swap, verbose,
 				argv, i, argc, nargout);
 
@@ -974,7 +846,7 @@
 			}
 		    }
 
-		  retval = do_load (file, orig_fname, force, format,
+		  retval = do_load (file, orig_fname, format,
 				    flt_fmt, list_only, swap, verbose,
 				    argv, i, argc, nargout);
 
@@ -1033,7 +905,7 @@
 static void
 do_save (std::ostream& os, const octave_value& tc,
 	 const std::string& name, const std::string& help,
-	 int global, load_save_format fmt, bool save_as_floats)
+	 bool global, load_save_format fmt, bool save_as_floats)
 {
   switch (fmt)
     {
@@ -1078,46 +950,42 @@
 // Save the info from SR on stream OS in the format specified by FMT.
 
 void
-do_save (std::ostream& os, symbol_record *sr, load_save_format fmt,
-	 bool save_as_floats)
+do_save (std::ostream& os, const symbol_table::symbol_record& sr,
+	 load_save_format fmt, bool save_as_floats)
 {
-  if (! sr->is_variable ())
-    {
-      error ("save: can only save variables, not functions");
-      return;
-    }
+  octave_value val = sr.varval ();
 
-  octave_value tc = sr->def ();
-
-  if (tc.is_defined ())
+  if (val.is_defined ())
     {
-      std::string name = sr->name ();
-      std::string help = sr->help ();
+      std::string name = sr.name ();
+      std::string help;
+      bool global = sr.is_global ();
 
-      int global = sr->is_linked_to_global ();
-
-      do_save (os, tc, name, help, global, fmt, save_as_floats);
+      do_save (os, val, name, help, global, fmt, save_as_floats);
     }
 }
 
 // Save variables with names matching PATTERN on stream OS in the
 // format specified by FMT.
 
-static int
+static size_t
 save_vars (std::ostream& os, const std::string& pattern,
 	   load_save_format fmt, bool save_as_floats)
 {
-  Array<symbol_record *> vars = curr_sym_tab->glob
-    (pattern, symbol_record::USER_VARIABLE, SYMTAB_ALL_SCOPES);
+  std::list<symbol_table::symbol_record> vars = symbol_table::glob (pattern);
+
+  size_t saved = 0;
 
-  int saved = vars.length ();
+  typedef std::list<symbol_table::symbol_record>::const_iterator const_vars_iterator;
 
-  for (int i = 0; i < saved; i++)
+  for (const_vars_iterator p = vars.begin (); p != vars.end (); p++)
     {
-      do_save (os, vars(i), fmt, save_as_floats);
+      do_save (os, *p, fmt, save_as_floats);
 
       if (error_state)
 	break;
+
+      saved++;
     }
 
   return saved;
@@ -1333,43 +1201,35 @@
 {
   write_header (os, fmt);
 
-  Array<symbol_record *> vars = curr_sym_tab->glob
-    ("*", symbol_record::USER_VARIABLE, SYMTAB_ALL_SCOPES);
-
-  int num_to_save = vars.length ();
+  std::list<symbol_table::symbol_record> vars = symbol_table::all_variables ();
 
   double save_mem_size = 0;
 
-  for (int i = 0; i < num_to_save; i++)
+  typedef std::list<symbol_table::symbol_record>::const_iterator const_vars_iterator;
+
+  for (const_vars_iterator p = vars.begin (); p != vars.end (); p++)
     {
-      symbol_record *sr = vars(i);
+      octave_value val = p->varval ();
 
-      if (sr->is_variable ())
+      if (val.is_defined ())
 	{
-	  octave_value tc = sr->def ();
-
-	  if (tc.is_defined ())
-	    {
-	      double tc_size = tc.byte_size () / 1024;
-
-	      // FIXME -- maybe we should try to throw out the
-	      // largest first...
+	  std::string name = p->name ();
+	  std::string help;
+	  bool global = p->is_global ();
 
-	      if (Voctave_core_file_limit < 0
-		  || save_mem_size + tc_size < Voctave_core_file_limit)
-		{
-		  save_mem_size += tc_size;
+	  double val_size = val.byte_size () / 1024;
 
-		  std::string name = sr->name ();
-		  std::string help = sr->help ();
+	  // FIXME -- maybe we should try to throw out the largest first...
 
-		  int global = sr->is_linked_to_global ();
-
-		  do_save (os, tc, name, help, global, fmt, save_as_floats);
+	  if (Voctave_core_file_limit < 0
+	      || save_mem_size + val_size < Voctave_core_file_limit)
+	    {
+	      save_mem_size += val_size;
 
-		  if (error_state)
-		    break;
-		}
+	      do_save (os, val, name, help, global, fmt, save_as_floats);
+
+	      if (error_state)
+		break;
 	    }
 	}
     }
--- a/src/load-save.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/load-save.h	Fri Dec 28 20:56:58 2007 +0000
@@ -59,8 +59,8 @@
 	 const string_vector& argv, int argv_idx, int argc, int nargout);
 
 extern void
-do_save (std::ostream& os, symbol_record *sr, load_save_format fmt,
-	 bool save_as_floats);
+do_save (std::ostream& os, const symbol_table::symbol_record& sr,
+	 load_save_format fmt, bool save_as_floats);
 
 extern void
 write_header (std::ostream& os, load_save_format format);
--- a/src/ls-hdf5.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ls-hdf5.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -61,7 +61,6 @@
 #include "ov-cell.h"
 #include "pager.h"
 #include "pt-exp.h"
-#include "symtab.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
--- a/src/ls-mat-ascii.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ls-mat-ascii.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -56,7 +56,6 @@
 #include "ov-cell.h"
 #include "pager.h"
 #include "pt-exp.h"
-#include "symtab.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
--- a/src/ls-mat4.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ls-mat4.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -55,7 +55,6 @@
 #include "ov-cell.h"
 #include "pager.h"
 #include "pt-exp.h"
-#include "symtab.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
--- a/src/ls-mat5.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ls-mat5.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -61,7 +61,6 @@
 #include "ov-fcn-inline.h"
 #include "pager.h"
 #include "pt-exp.h"
-#include "symtab.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
@@ -775,21 +774,18 @@
 
 		    if (fs.exists ())
 		      {
-			symbol_record *sr = fbi_sym_tab->lookup (str, true);
-		    
-			if (sr)
-			  {
-			    load_fcn_from_file (sr, false);
+			size_t xpos = str.find_last_of (file_ops::dir_sep_chars);
+
+			std::string dir_name = str.substr (0, xpos);
 
-			    tc = octave_value (new octave_fcn_handle 
-					       (sr->def (), fname));
+			octave_function *fcn
+			  = load_fcn_from_file (str, dir_name, "", fname);
+		    
+			if (fcn)
+			  {
+			    octave_value tmp (fcn);
 
-			    // The next two lines are needed to force the 
-			    // definition of the function back to the one 
-			    // that is on the user path.
-			    sr = fbi_sym_tab->lookup (fname, true);
-
-			    load_fcn_from_file (sr, false);
+			    tc = octave_value (new octave_fcn_handle (tmp, fname));
 			  }
 		      }
 		    else
@@ -806,21 +802,18 @@
 			str = octave_env::make_absolute 
 			  (p.find_first_of (names), octave_env::getcwd ());
 
-			symbol_record *sr = fbi_sym_tab->lookup (str, true);
+			size_t xpos = str.find_last_of (file_ops::dir_sep_chars);
 
-			if (sr)
-			  {
-			    load_fcn_from_file (sr, false);
+			std::string dir_name = str.substr (0, xpos);
 
-			    tc = octave_value (new octave_fcn_handle 
-					       (sr->def (), fname));
+			octave_function *fcn
+			  = load_fcn_from_file (str, dir_name, "", fname);
 
-			    // The next two lines are needed to force the 
-			    // definition of the function back to the one 
-			    // that is on the user path.
-			    sr = fbi_sym_tab->lookup (fname, true);
+			if (fcn)
+			  {
+			    octave_value tmp (fcn);
 
-			    load_fcn_from_file (sr, false);
+			    tc = octave_value (new octave_fcn_handle (tmp, fname));
 			  }
 			else
 			  {
@@ -832,18 +825,18 @@
 		  }
 		else
 		  {
-		    symbol_record *sr = fbi_sym_tab->lookup (fpath, true);
+		    size_t xpos = fpath.find_last_of (file_ops::dir_sep_chars);
 
-		    if (sr)
-		      {
-			load_fcn_from_file (sr, false);
+		    std::string dir_name = fpath.substr (0, xpos);
 
-			tc = octave_value (new octave_fcn_handle (sr->def (), 
-								  fname));
+		    octave_function *fcn
+		      = load_fcn_from_file (fpath, dir_name, "", fname);
 
-			sr = fbi_sym_tab->lookup (fname, true);
+		    if (fcn)
+		      {
+			octave_value tmp (fcn);
 
-			load_fcn_from_file (sr, false);
+			tc = octave_value (new octave_fcn_handle (tmp, fname));
 		      }
 		    else
 		      {
@@ -868,37 +861,28 @@
 	    m2 = m2.contents("MCOS")(0).map_value();
 	    tc2 = m2.contents("MCOS")(0).cell_value()(1 + off).cell_value()(1);
 	    m2 = tc2.map_value();
-	    symbol_table *local_sym_tab = 0;
+
+	    symbol_table::scope_id local_scope = symbol_table::alloc_scope ();
+
 	    if (m2.nfields() > 0)
 	      {
 		octave_value tmp;
-
-		local_sym_tab = new symbol_table (((m2.nfields() + 1) & ~1), 
-						  "LOCAL");
-	      
+      
 		for (Octave_map::iterator p0 = m2.begin() ; 
 		     p0 != m2.end(); p0++)
 		  {
 		    std::string key = m2.key(p0);
 		    octave_value val = m2.contents(p0)(0);
 
-		    symbol_record *sr = local_sym_tab->lookup (key, true);
-
-		    if (sr)
-		      sr->define (val);
-		    else
-		      {
-			error ("load: failed to load anonymous function handle");
-			goto skip_ahead;
-		      }
+		    symbol_table::varref (key, local_scope) = val;
                   }
 	      }
 	    
 	    unwind_protect::begin_frame ("anon_mat5_load");
-	    unwind_protect_ptr (curr_sym_tab);
+	    
+	    symbol_table::push_scope (local_scope);
 
-	    if (local_sym_tab)
-	      curr_sym_tab = local_sym_tab;
+	    unwind_protect::add (symbol_table::pop_scope);
 
 	    int parse_status;
 	    octave_value anon_fcn_handle = 
@@ -924,8 +908,7 @@
 
 	    unwind_protect::run_frame ("anon_mat5_load");
 
-	    if (local_sym_tab)
-	      delete local_sym_tab;	    
+	    symbol_table::erase_scope (local_scope);
 	  }
 	else
 	  {
--- a/src/ls-oct-ascii.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ls-oct-ascii.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -56,8 +56,6 @@
 #include "ov-cell.h"
 #include "pager.h"
 #include "pt-exp.h"
-#include "symtab.h"
-#include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
 #include "variables.h"
--- a/src/ls-oct-binary.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ls-oct-binary.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -55,7 +55,6 @@
 #include "ov-cell.h"
 #include "pager.h"
 #include "pt-exp.h"
-#include "symtab.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
--- a/src/mex.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/mex.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -3242,31 +3242,26 @@
 {
   mxArray *retval = 0;
 
-  // FIXME -- this should be in variable.cc, but the correct
-  // functionality is not exported.  Particularly, get_global_value()
-  // generates an error if the symbol is undefined.
-
-  symbol_record *sr = 0;
+  // FIXME -- should this be in variables.cc?
+
+  symbol_table::scope_id scope = -1;
 
   if (! strcmp (space, "global"))
-    sr = global_sym_tab->lookup (name);
+    scope = symbol_table::global_scope ();
   else if (! strcmp (space, "caller"))
-    sr = curr_sym_tab->lookup (name);
+    scope = symbol_table::current_caller_scope ();
   else if (! strcmp (space, "base"))
-    sr = top_level_sym_tab->lookup (name);
+    scope = symbol_table::top_scope ();
   else
     mexErrMsgTxt ("mexGetVariable: symbol table does not exist");
 
-  if (sr)
+  octave_value val = symbol_table::varval (name, scope);
+
+  if (val.is_defined ())
     {
-      octave_value sr_def = sr->def ();
-
-      if (sr_def.is_defined ())
-	{
-	  retval = mex_context->make_value (sr_def);
-
-	  retval->set_name (name);
-	}
+      retval = mex_context->make_value (val);
+
+      retval->set_name (name);
     }
 
   return retval;
@@ -3297,21 +3292,20 @@
     set_global_value (name, mxArray::as_octave_value (ptr));
   else
     {
-      // FIXME -- this belongs in variables.cc.
-
-      symbol_record *sr = 0;
-
-      if (! strcmp (space, "caller"))
-	sr = curr_sym_tab->lookup (name, true);
+      // FIXME -- should this be in variables.cc?
+
+      symbol_table::scope_id scope = -1;
+
+      if (! strcmp (space, "global"))
+	scope = symbol_table::global_scope ();
+      else if (! strcmp (space, "caller"))
+	scope = symbol_table::current_caller_scope ();
       else if (! strcmp (space, "base"))
-	sr = top_level_sym_tab->lookup (name, true);
+	scope = symbol_table::top_scope ();
       else
 	mexErrMsgTxt ("mexPutVariable: symbol table does not exist");
 
-      if (sr)
-	sr->define (mxArray::as_octave_value (ptr));
-      else
-	panic_impossible ();
+      symbol_table::varref (name, scope) = mxArray::as_octave_value (ptr);
     }
 
   return 0;
@@ -3390,7 +3384,7 @@
       else
 	mex_lock_count[fname]++;
 
-      mlock (fname);
+      mlock ();
     }
 }
 
--- a/src/oct-lvalue.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/oct-lvalue.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -37,7 +37,7 @@
 		    ? val->assign (op, rhs)
 		    : val->assign (op, type, idx, rhs));
 
-  if (! (error_state || (chg_fcn && chg_fcn () < 0)))
+  if (! error_state)
     *val = tmp;
 }
 
@@ -62,7 +62,7 @@
 		    ? val->do_non_const_unary_op (op)
 		    : val->do_non_const_unary_op (op, type, idx));
 
-  if (! (error_state || (chg_fcn && chg_fcn () < 0)))
+  if (! error_state)
     *val = tmp;
 }
 
--- a/src/oct-lvalue.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/oct-lvalue.h	Fri Dec 28 20:56:58 2007 +0000
@@ -31,7 +31,6 @@
 
 #include "oct-obj.h"
 #include "pt-idx.h"
-#include "symtab.h"
 
 // FIXME -- eliminate the following kluge?
 
@@ -43,13 +42,12 @@
 {
 public:
 
-  octave_lvalue (octave_value *v = &dummy_val,
-		 symbol_record::change_function f = 0)
-    : val (v), type (), idx (), chg_fcn (f), nel (1), index_set (false) { }
+  octave_lvalue (octave_value *v = &dummy_val)
+    : val (v), type (), idx (), nel (1), index_set (false) { }
 
   octave_lvalue (const octave_lvalue& vr)
-    : val (vr.val), type (vr.type), idx (vr.idx), chg_fcn (vr.chg_fcn),
-      nel (vr.nel), index_set (vr.index_set) { }
+    : val (vr.val), type (vr.type), idx (vr.idx), nel (vr.nel),
+      index_set (vr.index_set) { }
 
   octave_lvalue& operator = (const octave_lvalue& vr)
     {
@@ -58,7 +56,6 @@
 	  val = vr.val;
 	  type = vr.type;
 	  idx = vr.idx;
-	  chg_fcn = vr.chg_fcn;
 	  nel = vr.nel;
 	  index_set = vr.index_set;
 	}
@@ -100,8 +97,6 @@
 
   std::list<octave_value_list> idx;
 
-  symbol_record::change_function chg_fcn;
-
   octave_idx_type nel;
 
   bool index_set;
--- a/src/octave.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/octave.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -189,15 +189,13 @@
 static void
 intern_argv (int argc, char **argv)
 {
-  symbol_record *nargin_sr = top_level_sym_tab->lookup ("__nargin__", true);
+  symbol_table::varref (".nargin.", symbol_table::top_scope ()) = argc - 1;
 
-  nargin_sr->mark_as_static ();
-
-  nargin_sr->define (argc-1);
+  symbol_table::mark_hidden (".nargin.", symbol_table::top_scope ());
 
   if (argc > 1)
     {
-      octave_argv.resize (argc-1);
+      octave_argv.resize (argc - 1);
 
       // Skip program name in argv.
       int i = argc;
@@ -599,8 +597,6 @@
 
   initialize_file_io ();
 
-  initialize_symbol_tables ();
-
   install_types ();
 
   install_ops ();
--- a/src/ov-base.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-base.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -58,12 +58,9 @@
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_base_value,
 				     "<unknown type>", "unknown");
 
-// If TRUE, print the name along with the value.
-static bool Vprint_answer_id_name = true;
-
 // If TRUE, turn off printing of results in functions (as if a
 // semicolon has been appended to each statement).
-static bool Vsilent_functions = false;
+bool Vsilent_functions = false;
 
 // TRUE means to perform automatic sparse to real mutation if there
 // is memory to be saved
@@ -347,10 +344,7 @@
 {
   if (! (evaluating_function_body && Vsilent_functions))
     {
-      bool pad_after = false;
-
-      if (Vprint_answer_id_name)
-	pad_after = print_name_tag (output_buf, name);
+      bool pad_after = print_name_tag (output_buf, name);
 
       print (output_buf);
 
@@ -1111,17 +1105,6 @@
   INSTALL_WIDENOP (octave_base_value, octave_cell, cell_conv);
 }
 
-DEFUN (print_answer_id_name, args, nargout,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {@var{val} =} print_answer_id_name ()\n\
-@deftypefnx {Built-in Function} {@var{old_val} =} print_answer_id_name (@var{new_val})\n\
-Query or set the internal variable that controls whether variable\n\
-names are printed along with results produced by evaluating an expression.\n\
-@end deftypefn")
-{
-  return SET_INTERNAL_VARIABLE (print_answer_id_name);
-}
-
 DEFUN (silent_functions, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {@var{val} =} silent_functions ()\n\
--- a/src/ov-base.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-base.h	Fri Dec 28 20:56:58 2007 +0000
@@ -222,6 +222,8 @@
 
   virtual bool is_map (void) const { return false; }
 
+  virtual bool is_object (void) const { return false; }
+
   virtual bool is_streamoff (void) const { return false; }
 
   virtual bool is_cs_list (void) const { return false; }
@@ -288,6 +290,10 @@
 
   virtual bool is_function (void) const { return false; }
 
+  virtual bool is_user_script (void) const { return false; }
+
+  virtual bool is_user_function (void) const { return false; }
+
   virtual bool is_builtin_function (void) const { return false; }
 
   virtual bool is_dld_function (void) const { return false; }
@@ -487,6 +493,10 @@
   DECLARE_OV_BASE_TYPEID_FUNCTIONS_AND_DATA
 };
 
+// If TRUE, turn off printing of results in functions (as if a
+// semicolon has been appended to each statement).
+extern bool Vsilent_functions;
+
 // TRUE means to perform automatic sparse to real mutation if there
 // is memory to be saved
 extern bool Vsparse_auto_mutate;
--- a/src/ov-fcn-handle.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-fcn-handle.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -28,6 +28,8 @@
 #include <sstream>
 #include <vector>
 
+#include "file-ops.h"
+
 #include "defun.h"
 #include "error.h"
 #include "gripes.h"
@@ -63,18 +65,6 @@
 				     "function handle",
 				     "function_handle");
 
-void
-octave_fcn_handle::reload_warning (const std::string& fcn_type) const
-{
-  if (warn_reload)
-    {
-      warn_reload = false;
-
-      warning ("reloading %s functions referenced by function handles is not implemented",
-	       fcn_type.c_str ());
-    }
-}
-
 octave_value_list
 octave_fcn_handle::subsref (const std::string& type,
 			    const std::list<octave_value_list>& idx,
@@ -86,47 +76,22 @@
     {
     case '(':
       {
-	octave_function *f = function_value ();
-
-	if (f && f->time_checked () < Vlast_prompt_time)
-	  {
-	    std::string ff_nm = f->fcn_file_name ();
+	out_of_date_check (fcn);
 
-	    octave_time ottp = f->time_parsed ();
-	    time_t tp = ottp.unix_time ();
+	if (fcn.is_defined ())
+	  {
+	    octave_function *f = function_value ();
 
-	    if (ff_nm.empty ())
-	      {
-		// FIXME -- need to handle inline and
-		// command-line functions here.
-	      }
+	    if (f)
+	      retval = f->subsref (type, idx, nargout);
 	    else
-	      {
-		if (fcn_out_of_date (f, ff_nm, tp))
-		  {
-		    // FIXME -- there is currently no way to
-		    // parse a .m file or reload a .oct file that
-		    // leaves the fbi symbol table untouched.  We need
-		    // a function that will parse the file and return
-		    // a pointer to the new function definition
-		    // without altering the symbol table.
-
-		    if (f->is_nested_function ())
-		      reload_warning ("nested");
-		    else
-		      reload_warning ("functions");
-		  }
-	      }
+	      error ("invalid function handle");
 	  }
-
-	if (f)
-	  retval = f->subsref (type, idx, nargout);
 	else
 	  error ("invalid function handle");
       }
       break;
 
-
     case '{':
     case '.':
       {
@@ -167,21 +132,18 @@
 
       if (fs.exists ())
 	{
-	  symbol_record *sr = fbi_sym_tab->lookup (str, true);
-		    
-	  if (sr)
-	    {
-	      load_fcn_from_file (sr, false);
+	  size_t xpos = str.find_last_of (file_ops::dir_sep_chars);
 
-	      fcn = octave_value (new octave_fcn_handle (sr->def (), nm));
+	  std::string dir_name = str.substr (0, xpos);
 
-	      // The next two lines are needed to force the 
-	      // definition of the function back to the one 
-	      // that is on the user path.
-	      sr = fbi_sym_tab->lookup (nm, true);
+	  octave_function *xfcn
+	    = load_fcn_from_file (str, dir_name, "", nm);
 
-	      load_fcn_from_file (sr, false);
+	  if (xfcn)
+	    {
+	      octave_value tmp (xfcn);
 
+	      fcn = octave_value (new octave_fcn_handle (tmp, nm));
 	    }
 	  else
 	    {
@@ -202,20 +164,17 @@
 	  str = octave_env::make_absolute 
 	    (p.find_first_of (names), octave_env::getcwd ());
 
-	  symbol_record *sr = fbi_sym_tab->lookup (str, true);
+	  size_t xpos = str.find_last_of (file_ops::dir_sep_chars);
 
-	  if (sr)
-	    {
-	      load_fcn_from_file (sr, false);
+	  std::string dir_name = str.substr (0, xpos);
+
+	  octave_function *xfcn = load_fcn_from_file (str, dir_name, "", nm);
 
-	      fcn = octave_value (new octave_fcn_handle (sr->def (), nm));
+	  if (xfcn)
+	    {
+	      octave_value tmp (xfcn);
 
-	      // The next two lines are needed to force the 
-	      // definition of the function back to the one 
-	      // that is on the user path.
-	      sr = fbi_sym_tab->lookup (nm, true);
-
-	      load_fcn_from_file (sr, false);
+	      fcn = octave_value (new octave_fcn_handle (tmp, nm));
 	    }
 	  else
 	    {
@@ -228,17 +187,17 @@
     {
       if (fpath.length () > 0)
 	{
-	  symbol_record *sr = fbi_sym_tab->lookup (fpath, true);
+	  size_t xpos = fpath.find_last_of (file_ops::dir_sep_chars);
 
-	  if (sr)
-	    {
-	      load_fcn_from_file (sr, false);
+	  std::string dir_name = fpath.substr (0, xpos);
+
+	  octave_function *xfcn = load_fcn_from_file (fpath, dir_name, "", nm);
 
-	      fcn = octave_value (new octave_fcn_handle (sr->def (), nm));
+	  if (xfcn)
+	    {
+	      octave_value tmp (xfcn);
 
-	      sr = fbi_sym_tab->lookup (nm, true);
-
-	      load_fcn_from_file (sr, false);
+	      fcn = octave_value (new octave_fcn_handle (tmp, nm));
 	    }
 	  else
 	    {
@@ -248,7 +207,8 @@
 	}
       else
 	{
-	  fcn = lookup_function (nm);
+	  fcn = symbol_table::find_function (nm);
+
 	  if (! fcn.is_function ())
 	    {
 	      error ("function handle points to non-existent function");
@@ -270,30 +230,24 @@
       print_raw (os, true);
       os << "\n";
 
-      if (fcn.is_undefined())
+      if (fcn.is_undefined ())
 	return false;
 
       octave_user_function *f = fcn.user_function_value ();
 
-      Array<symbol_record *> vars = f->sym_tab()->symbol_list();
-      octave_idx_type varlen = vars.length();
+      std::list<symbol_table::symbol_record> vars
+	= symbol_table::all_variables (f->scope ());
 
-      // Exclude undefined values like __retval__
-      for (octave_idx_type i = 0; i < vars.length(); i++)
-	{
-	  if (! vars(i)->is_defined ())
-	    varlen--;
-	}
+      size_t varlen = vars.size ();
 
       if (varlen > 0)
 	{
 	  os << "# length: " << varlen << "\n";
 
-	  for (octave_idx_type i = 0; i < vars.length(); i++)
+	  for (std::list<symbol_table::symbol_record>::const_iterator p = vars.begin ();
+	       p != vars.end (); p++)
 	    {
-	      if (vars(i)->is_defined () &&
-		  ! save_ascii_data (os, vars(i)->def(), vars(i)->name(), 
-				     false, 0))
+	      if (! save_ascii_data (os, p->varval (), p->name (), false, 0))
 		return os;
 	    }
 	}
@@ -357,18 +311,13 @@
 	}
 
       pos = is.tellg ();
-      symbol_table *local_sym_tab = 0;
+
+      symbol_table::scope_id local_scope = symbol_table::alloc_scope ();
 
       if (extract_keyword (is, "length", len, true) && len >= 0)
 	{
 	  if (len > 0)
 	    {
-	      octave_idx_type nlen = len;
-	      if (nlen % 2)
-		nlen++;
-	      
-	      local_sym_tab = new symbol_table (((nlen + 1) & ~1) , "LOCAL");
-	      
 	      for (octave_idx_type i = 0; i < len; i++)
 		{
 		  octave_value t2;
@@ -383,16 +332,7 @@
 		      break;
 		    }
 
-		  symbol_record *sr = local_sym_tab->lookup (name, true);
-
-		  if (sr)
-		    sr->define (t2);
-		  else
-		    {
-		      error ("load: failed to load anonymous function handle");
-		      success = false;
-		      break;
-		    }
+		  symbol_table::varref (name, local_scope) = t2;
 		}
 	    }
 	}
@@ -405,10 +345,10 @@
       if (is && success)
 	{
 	  unwind_protect::begin_frame ("anon_ascii_load");
-	  unwind_protect_ptr (curr_sym_tab);
 
-	  if (local_sym_tab)
-	    curr_sym_tab = local_sym_tab;
+	  symbol_table::push_scope (local_scope);
+
+	  unwind_protect::add (symbol_table::pop_scope);
 
 	  int parse_status;
 	  octave_value anon_fcn_handle = 
@@ -431,8 +371,7 @@
       else
 	success = false;
 
-      if (local_sym_tab)
-	delete local_sym_tab;
+      symbol_table::erase_scope (local_scope);
     }
   else
     success = set_fcn (octaveroot, fpath);
@@ -473,20 +412,15 @@
     {
       std::ostringstream nmbuf;
 
-      if (fcn.is_undefined())
+      if (fcn.is_undefined ())
 	return false;
 
       octave_user_function *f = fcn.user_function_value ();
 
-      Array<symbol_record *> vars = f->sym_tab()->symbol_list();
-      octave_idx_type varlen = vars.length();
+      std::list<symbol_table::symbol_record> vars
+	= symbol_table::all_variables (f->scope ());
 
-      // Exclude undefined values like __retval__
-      for (octave_idx_type i = 0; i < vars.length(); i++)
-	{
-	  if (! vars(i)->is_defined ())
-	    varlen--;
-	}
+      size_t varlen = vars.size ();
 
       if (varlen > 0)
 	nmbuf << nm << " " << varlen;
@@ -507,10 +441,10 @@
 
       if (varlen > 0)
 	{
-	  for (octave_idx_type i = 0; i < vars.length(); i++)
+	  for (std::list<symbol_table::symbol_record>::const_iterator p = vars.begin ();
+	       p != vars.end (); p++)
 	    {
-	      if (vars(i)->is_defined () &&
-		  ! save_binary_data (os, vars(i)->def(), vars(i)->name(), 
+	      if (! save_binary_data (os, p->varval (), p->name (),
 				      "", 0, save_as_floats))
 		return os;
 	    }
@@ -528,6 +462,7 @@
       os.write (reinterpret_cast<char *> (&tmp), 4);
       os.write (buf_str.c_str (), buf_str.length ());
     }
+
   return true;
 }
 
@@ -536,6 +471,7 @@
 				oct_mach_info::float_format fmt)
 {
   bool success = true;
+
   int32_t tmp;
   if (! is.read (reinterpret_cast<char *> (&tmp), 4))
     return false;
@@ -568,15 +504,10 @@
       OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
       is.read (ctmp2, tmp);
 
-      symbol_table *local_sym_tab = 0;
+      symbol_table::scope_id local_scope = symbol_table::alloc_scope ();
+	      
       if (len > 0)
 	{
-	  octave_idx_type nlen = len;
-	  if (nlen % 2)
-	    nlen++;
-	      
-	  local_sym_tab = new symbol_table (nlen, "LOCAL");
-	      
 	  for (octave_idx_type i = 0; i < len; i++)
 	    {
 	      octave_value t2;
@@ -593,29 +524,17 @@
 		  break;
 		}
 
-	      symbol_record *sr = local_sym_tab->lookup (name, true);
-
-	      if (sr)
-		{
-		  sr->define (t2);
-		  sr->document (doc);
-		}
-	      else
-		{
-		  error ("load: failed to load anonymous function handle");
-		  success = false;
-		  break;
-		}
+	      symbol_table::varref (name, local_scope) = t2;
 	    }
 	}
 
       if (is && success)
 	{
 	  unwind_protect::begin_frame ("anon_binary_load");
-	  unwind_protect_ptr (curr_sym_tab);
 
-	  if (local_sym_tab)
-	    curr_sym_tab = local_sym_tab;
+	  symbol_table::push_scope (local_scope);
+
+	  unwind_protect::add (symbol_table::pop_scope);
 
 	  int parse_status;
 	  octave_value anon_fcn_handle = 
@@ -635,8 +554,7 @@
 	  unwind_protect::run_frame ("anon_binary_load");
 	}
 
-      if (local_sym_tab)
-	delete local_sym_tab;
+      symbol_table::erase_scope (local_scope);
     }
   else
     {
@@ -689,12 +607,14 @@
 octave_fcn_handle::save_hdf5 (hid_t loc_id, const char *name,
 			      bool save_as_floats)
 {
+  bool retval = true;
+
   hid_t group_hid = -1;
   group_hid = H5Gcreate (loc_id, name, 0);
-  if (group_hid < 0 ) return false;
+  if (group_hid < 0)
+    return false;
 
   hid_t space_hid = -1, data_hid = -1, type_hid = -1;;
-  bool retval = true;
 
   // attach the type of the variable
   type_hid = H5Tcopy (H5T_C_S1);
@@ -756,15 +676,11 @@
       H5Dclose (data_hid);
 
       octave_user_function *f = fcn.user_function_value ();
-      Array<symbol_record *> vars = f->sym_tab()->symbol_list();
-      octave_idx_type varlen = vars.length();
 
-      // Exclude undefined values like __retval__
-      for (octave_idx_type i = 0; i < vars.length(); i++)
-	{
-	  if (! vars(i)->is_defined ())
-	    varlen--;
-	}
+      std::list<symbol_table::symbol_record> vars
+	= symbol_table::all_variables (f->scope ());
+
+      size_t varlen = vars.size ();
 
       if (varlen > 0)
 	{
@@ -798,10 +714,10 @@
 	      return false;
 	    }
 
-	  for (octave_idx_type i = 0; i < vars.length(); i++)
+	  for (std::list<symbol_table::symbol_record>::const_iterator p = vars.begin ();
+	       p != vars.end (); p++)
 	    {
-	      if (vars(i)->is_defined () &&
-		  ! add_hdf5_data (data_hid, vars(i)->def(), vars(i)->name(), 
+	      if (! add_hdf5_data (data_hid, p->varval (), p->name (),
 				   "", false, save_as_floats))
 		break;
 	    }
@@ -883,13 +799,15 @@
 octave_fcn_handle::load_hdf5 (hid_t loc_id, const char *name,
 			      bool have_h5giterate_bug)
 {
+  bool success = true;
+
   hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id;
   hsize_t rank;
   int slen;
-  bool success = true;
 
   group_hid = H5Gopen (loc_id, name);
-  if (group_hid < 0 ) return false;
+  if (group_hid < 0)
+    return false;
 
   data_hid = H5Dopen (group_hid, "nm");
 
@@ -1017,7 +935,6 @@
       H5Tclose (st_id);
       H5Dclose (data_hid);
 
-      symbol_table *local_sym_tab = 0;
       octave_idx_type len = 0;
 
       // we have to pull some shenanigans here to make sure
@@ -1045,14 +962,10 @@
       // restore error reporting:
       H5Eset_auto (err_func, err_func_data);
 
+      symbol_table::scope_id local_scope = symbol_table::alloc_scope ();
+
       if (len > 0 && success)
 	{
-	  octave_idx_type nlen = len;
-	  if (nlen % 2)
-	    nlen++;
-	      
-	  local_sym_tab = new symbol_table (nlen, "LOCAL");
-	      
 #ifdef HAVE_H5GGET_NUM_OBJS
 	  hsize_t num_obj = 0;
 	  data_hid = H5Gopen (group_hid, "symbol table"); 
@@ -1083,16 +996,7 @@
 		  if (have_h5giterate_bug)
 		    current_item++;  // H5Giterate returns last index processed
 
-		  symbol_record *sr = local_sym_tab->lookup (dsub.name, true);
-
-		  if (sr)
-		    sr->define (dsub.tc);
-		  else
-		    {
-		      error ("load: failed to load anonymous function handle");
-		      success = false;
-		      break;
-		    }
+		  symbol_table::varref (dsub.name, local_scope) = dsub.tc;
 		}
 	    }
 	}
@@ -1100,10 +1004,10 @@
       if (success)
 	{
 	  unwind_protect::begin_frame ("anon_hdf5_load");
-	  unwind_protect_ptr (curr_sym_tab);
 
-	  if (local_sym_tab)
-	    curr_sym_tab = local_sym_tab;
+	  symbol_table::push_scope (local_scope);
+
+	  unwind_protect::add (symbol_table::pop_scope);
 
 	  int parse_status;
 	  octave_value anon_fcn_handle = 
@@ -1123,8 +1027,7 @@
 	  unwind_protect::run_frame ("anon_hdf5_load");
 	}
 
-      if (local_sym_tab)
-	delete local_sym_tab;
+      symbol_table::erase_scope (local_scope);
     }
   else
     {
@@ -1318,21 +1221,9 @@
 {
   octave_value retval;
 
-  octave_function *fcn = octave_call_stack::current ();
-
-  std::string parent_name = fcn ? fcn->name () : std::string ();
-
-  if (! parent_name.empty ())
-    {
-      size_t pos = parent_name.find (':');
+  octave_value f = symbol_table::find_function (nm);
 
-      if (pos != NPOS)
-	parent_name = parent_name.substr (0, pos);
-    }
-
-  octave_value f = lookup_function (nm, parent_name);
-
-  if (f.is_function ())
+  if (f.is_defined ())
     retval = octave_value (new octave_fcn_handle (f, nm));
   else
     error ("error creating function handle \"@%s\"", nm.c_str ());
@@ -1396,25 +1287,19 @@
 		      m.assign ("file", "");
 
 		      octave_user_function *fu = fh->user_function_value ();
-		      Array <symbol_record *> vars = 
-			fu->sym_tab ()->symbol_list ();
-		      octave_idx_type varlen = vars.length ();
 
-		      // Exclude undefined values like __retval__
-		      for (int i = 0; i < vars.length (); i++)
-			{
-			  if (! vars (i)->is_defined ())
-			    varlen--;
-			}
+		      std::list<symbol_table::symbol_record> vars
+			= symbol_table::all_variables (fu->scope ());
+
+		      size_t varlen = vars.size ();
 
 		      if (varlen > 0)
 			{
 			  Octave_map ws;
-			  for (octave_idx_type i = 0; i < vars.length (); i++)
+			  for (std::list<symbol_table::symbol_record>::const_iterator p = vars.begin ();
+			       p != vars.end (); p++)
 			    {
-			      if (vars (i)->is_defined ())
-				ws.assign (vars (i)->name (), 
-					   vars (i)->def ());
+			      ws.assign (p->name (), p->varval ());
 			    }
 
 			  m.assign ("workspace", ws);
--- a/src/ov-fcn-handle.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-fcn-handle.h	Fri Dec 28 20:56:58 2007 +0000
@@ -118,8 +118,6 @@
   // implemented.
   mutable bool warn_reload;
 
-  void reload_warning (const std::string& fcn_type) const;
-
 protected:
 
   // The function we are handling.
--- a/src/ov-fcn.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-fcn.h	Fri Dec 28 20:56:58 2007 +0000
@@ -33,6 +33,7 @@
 #include "oct-obj.h"
 #include "ov-base.h"
 #include "ov-typeinfo.h"
+#include "symtab.h"
 
 class tree_walker;
 
@@ -65,6 +66,8 @@
 
   virtual void mark_fcn_file_up_to_date (const octave_time&) { }
 
+  virtual symbol_table::scope_id scope (void) { return -1; }
+
   virtual octave_time time_parsed (void) const
     { return octave_time (static_cast<time_t> (0)); }
 
@@ -73,14 +76,26 @@
 
   virtual bool is_nested_function (void) const { return false; }
 
-  virtual bool is_user_script (void) const { return false; }
+  virtual bool is_class_constructor (void) const { return false; }
 
-  virtual bool is_user_function (void) const { return false; }
+  virtual bool is_class_method (void) const { return false; }
+
+  virtual std::string dispatch_class (void) const { return std::string (); }
 
   virtual bool takes_varargs (void) const { return false; }
 
   virtual bool takes_var_return (void) const { return false; }
 
+  std::string dir_name (void) const { return my_dir_name; }
+
+  void stash_dir_name (const std::string& dir) { my_dir_name = dir; }
+
+  void lock (void) { locked = true; }
+
+  void unlock (void) { locked = false; }
+
+  bool islocked (void) { return locked; }
+
   void mark_relative (void) { relative = true; }
 
   bool is_relative (void) const { return relative; }
@@ -104,9 +119,16 @@
   // TRUE if this function was found from a relative path element.
   bool relative;
 
+  // TRUE if this function is tagged so that it can't be cleared.
+  bool locked;
+
   // The name of this function.
   std::string my_name;
 
+  // The name of the directory in the path where we found this
+  // function.  May be relative.
+  std::string my_dir_name;
+
   // The help text for this function.
   std::string doc;
 
--- a/src/ov-struct.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-struct.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -772,10 +772,14 @@
 
   if (nargin == 1)
     {
-      if (args(0).is_map ())
+      octave_value arg = args(0);
+
+      if (arg.is_map () || arg.is_object ())
 	{
-	  Octave_map m = args(0).map_value ();
+	  Octave_map m = arg.map_value ();
+
 	  string_vector keys = m.keys ();
+
 	  if (keys.length () == 0)
 	    retval = Cell (0, 1);
 	  else
--- a/src/ov-struct.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-struct.h	Fri Dec 28 20:56:58 2007 +0000
@@ -142,11 +142,13 @@
 
   mxArray *as_mxArray (void) const;
 
-private:
+protected:
 
   // The associative array used to manage the structure data.
   Octave_map map;
 
+private:
+
   DECLARE_OCTAVE_ALLOCATOR
 
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
--- a/src/ov-typeinfo.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-typeinfo.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -93,6 +93,14 @@
 }
 
 bool
+octave_value_typeinfo::register_unary_class_op (octave_value::unary_op op,
+					        octave_value_typeinfo::unary_class_op_fcn f)
+{
+  return (instance_ok ())
+    ? instance->do_register_unary_class_op (op, f) : false;
+}
+
+bool
 octave_value_typeinfo::register_unary_op (octave_value::unary_op op,
 					   int t, octave_value_typeinfo::unary_op_fcn f)
 {
@@ -110,6 +118,14 @@
 }
 
 bool
+octave_value_typeinfo::register_binary_class_op (octave_value::binary_op op,
+						 octave_value_typeinfo::binary_class_op_fcn f)
+{
+  return (instance_ok ())
+    ? instance->do_register_binary_class_op (op, f) : false;
+}
+
+bool
 octave_value_typeinfo::register_binary_op (octave_value::binary_op op,
 					   int t1, int t2,
 					   octave_value_typeinfo::binary_op_fcn f)
@@ -225,6 +241,23 @@
 }
 
 bool
+octave_value_typeinfo::do_register_unary_class_op (octave_value::unary_op op,
+					           octave_value_typeinfo::unary_class_op_fcn f)
+{
+  if (lookup_unary_class_op (op))
+    {
+      std::string op_name = octave_value::unary_op_as_string (op);
+
+      warning ("duplicate unary operator `%s' for class dispatch",
+	       op_name.c_str ());
+    }
+
+  unary_class_ops.checkelem (static_cast<int> (op)) = f;
+
+  return false;
+}
+
+bool
 octave_value_typeinfo::do_register_unary_op (octave_value::unary_op op,
 					     int t, octave_value_typeinfo::unary_op_fcn f)
 {
@@ -261,6 +294,23 @@
 }
 
 bool
+octave_value_typeinfo::do_register_binary_class_op (octave_value::binary_op op,
+						    octave_value_typeinfo::binary_class_op_fcn f)
+{
+  if (lookup_binary_class_op (op))
+    {
+      std::string op_name = octave_value::binary_op_as_string (op);
+
+      warning ("duplicate binary operator `%s' for class dispatch",
+	       op_name.c_str ());
+    }
+
+  binary_class_ops.checkelem (static_cast<int> (op)) = f;
+
+  return false;
+}
+
+bool
 octave_value_typeinfo::do_register_binary_op (octave_value::binary_op op,
 					      int t1, int t2,
 					      octave_value_typeinfo::binary_op_fcn f)
@@ -407,6 +457,12 @@
   return retval;
 }
 
+octave_value_typeinfo::unary_class_op_fcn
+octave_value_typeinfo::do_lookup_unary_class_op (octave_value::unary_op op)
+{
+  return unary_class_ops.checkelem (static_cast<int> (op));
+}
+
 octave_value_typeinfo::unary_op_fcn
 octave_value_typeinfo::do_lookup_unary_op (octave_value::unary_op op, int t)
 {
@@ -420,6 +476,12 @@
   return non_const_unary_ops.checkelem (static_cast<int> (op), t);
 }
 
+octave_value_typeinfo::binary_class_op_fcn
+octave_value_typeinfo::do_lookup_binary_class_op (octave_value::binary_op op)
+{
+  return binary_class_ops.checkelem (static_cast<int> (op));
+}
+
 octave_value_typeinfo::binary_op_fcn
 octave_value_typeinfo::do_lookup_binary_op (octave_value::binary_op op,
 					    int t1, int t2)
@@ -499,25 +561,6 @@
   return retval;
 }
 
-DEFUN (class, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} class (@var{expr})\n\
-\n\
-Return the class of the expression @var{expr}, as a string.\n\
-@end deftypefn")
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1)
-    retval = args(0).class_name ();
-  else
-    print_usage ();
-
-  return retval;
-}
-
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-typeinfo.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-typeinfo.h	Fri Dec 28 20:56:58 2007 +0000
@@ -40,10 +40,15 @@
 {
 public:
 
+  typedef octave_value (*unary_class_op_fcn) (const octave_value&);
+
   typedef octave_value (*unary_op_fcn) (const octave_base_value&);
 
   typedef void (*non_const_unary_op_fcn) (octave_base_value&);
 
+  typedef octave_value (*binary_class_op_fcn)
+    (const octave_value&, const octave_value&);
+
   typedef octave_value (*binary_op_fcn)
     (const octave_base_value&, const octave_base_value&);
 
@@ -61,11 +66,17 @@
   static int register_type (const std::string&, const std::string&,
 			    const octave_value&);
 
+  static bool register_unary_class_op (octave_value::unary_op,
+				       unary_class_op_fcn);
+
   static bool register_unary_op (octave_value::unary_op, int, unary_op_fcn);
 
   static bool register_non_const_unary_op (octave_value::unary_op, int,
 					   non_const_unary_op_fcn);
 
+  static bool register_binary_class_op (octave_value::binary_op,
+					binary_class_op_fcn);
+
   static bool register_binary_op (octave_value::binary_op, int, int,
 				  binary_op_fcn);
 
@@ -91,6 +102,12 @@
     return instance->do_lookup_type (nm);
   }
 
+  static unary_class_op_fcn
+  lookup_unary_class_op (octave_value::unary_op op)
+  {
+    return instance->do_lookup_unary_class_op (op);
+  }
+
   static unary_op_fcn
   lookup_unary_op (octave_value::unary_op op, int t)
   {
@@ -103,6 +120,12 @@
     return instance->do_lookup_non_const_unary_op (op, t);
   }
 
+  static binary_class_op_fcn
+  lookup_binary_class_op (octave_value::binary_op op)
+  {
+    return instance->do_lookup_binary_class_op (op);
+  }
+
   static binary_op_fcn
   lookup_binary_op (octave_value::binary_op op, int t1, int t2)
   {
@@ -155,8 +178,10 @@
   octave_value_typeinfo (void)
     : num_types (0), types (init_tab_sz, std::string ()),
       vals (init_tab_sz),
+      unary_class_ops (octave_value::num_unary_ops, 0),
       unary_ops (octave_value::num_unary_ops, init_tab_sz, 0),
       non_const_unary_ops (octave_value::num_unary_ops, init_tab_sz, 0),
+      binary_class_ops (octave_value::num_binary_ops, 0),
       binary_ops (octave_value::num_binary_ops, init_tab_sz, init_tab_sz, 0),
       cat_ops (init_tab_sz, init_tab_sz, 0),
       assign_ops (octave_value::num_assign_ops, init_tab_sz, init_tab_sz, 0),
@@ -177,10 +202,14 @@
 
   Array<octave_value> vals;
 
+  Array<unary_class_op_fcn> unary_class_ops;
+
   Array2<unary_op_fcn> unary_ops;
 
   Array2<non_const_unary_op_fcn> non_const_unary_ops;
 
+  Array<binary_class_op_fcn> binary_class_ops;
+
   Array3<binary_op_fcn> binary_ops;
 
   Array2<cat_op_fcn> cat_ops;
@@ -198,11 +227,16 @@
   int do_register_type (const std::string&, const std::string&,
 			const octave_value&);
 
+  bool do_register_unary_class_op (octave_value::unary_op, unary_class_op_fcn);
+
   bool do_register_unary_op (octave_value::unary_op, int, unary_op_fcn);
 
   bool do_register_non_const_unary_op (octave_value::unary_op, int,
 				       non_const_unary_op_fcn);
 
+  bool do_register_binary_class_op (octave_value::binary_op,
+				    binary_class_op_fcn);
+
   bool do_register_binary_op (octave_value::binary_op, int, int,
 			      binary_op_fcn);
 
@@ -222,11 +256,15 @@
 
   octave_value do_lookup_type (const std::string& nm);
 
+  unary_class_op_fcn do_lookup_unary_class_op (octave_value::unary_op);
+
   unary_op_fcn do_lookup_unary_op (octave_value::unary_op, int);
 
   non_const_unary_op_fcn do_lookup_non_const_unary_op
     (octave_value::unary_op, int);
 
+  binary_class_op_fcn do_lookup_binary_class_op (octave_value::binary_op);
+
   binary_op_fcn do_lookup_binary_op (octave_value::binary_op, int, int);
 
   cat_op_fcn do_lookup_cat_op (int, int);
--- a/src/ov-usr-fcn.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-usr-fcn.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -51,6 +51,31 @@
 // Maximum nesting level for functions called recursively.
 static int Vmax_recursion_depth = 256;
 
+// Scripts.
+
+octave_value_list
+octave_user_script::do_multi_index_op (int nargout,
+				       const octave_value_list& args)
+{
+  octave_value_list retval;
+
+  if (! error_state)
+    {
+      if (args.length () == 0)
+	{
+	  // FIXME -- I think we need a way to protect against
+	  // recursion, but we can't use the same method as we use for
+	  // functions.
+
+	  source_file (file_name);
+	}
+      else
+	error ("invalid call to script");
+    }
+
+  return retval;
+}
+
 // User defined functions.
 
 DEFINE_OCTAVE_ALLOCATOR (octave_user_function);
@@ -69,17 +94,17 @@
 // extrinsic/intrinsic state?).
 
 octave_user_function::octave_user_function
-  (tree_parameter_list *pl, tree_parameter_list *rl,
-   tree_statement_list *cl, symbol_table *st)
+  (symbol_table::scope_id sid, tree_parameter_list *pl,
+   tree_parameter_list *rl, tree_statement_list *cl)
   : octave_function (std::string (), std::string ()),
     param_list (pl), ret_list (rl), cmd_list (cl),
-    local_sym_tab (st), lead_comm (), trail_comm (), file_name (),
+    lead_comm (), trail_comm (), file_name (),
     parent_name (), t_parsed (static_cast<time_t> (0)),
     t_checked (static_cast<time_t> (0)),
     system_fcn_file (false), call_depth (0), num_named_args (0),
-    nested_function (false), inline_function (false), args_passed (),
-    num_args_passed (0), symtab_entry (0), argn_sr (0),
-    nargin_sr (0), nargout_sr (0), varargin_sr (0)
+    nested_function (false), inline_function (false),
+    class_constructor (false), class_method (false), xdispatch_class (),
+    args_passed (), num_args_passed (0), local_scope (sid)
 {
   if (param_list)
     num_named_args = param_list->length ();
@@ -89,10 +114,11 @@
 {
   delete param_list;
   delete ret_list;
-  delete local_sym_tab;
   delete cmd_list;
   delete lead_comm;
   delete trail_comm;
+
+  symbol_table::erase_scope (local_scope);
 }
 
 octave_user_function *
@@ -163,22 +189,6 @@
   return retval;
 }
 
-// For unwind protect.
-
-static void
-pop_symbol_table_context (void *table)
-{
-  symbol_table *tmp = static_cast<symbol_table *> (table);
-  tmp->pop_context ();
-}
-
-static void
-clear_symbol_table (void *table)
-{
-  symbol_table *tmp = static_cast<symbol_table *> (table);
-  tmp->clear ();
-}
-
 static void
 clear_param_list (void *lst)
 {
@@ -197,13 +207,6 @@
     tmp->restore_args_passed ();
 }
 
-static void
-unprotect_function (void *sr_arg)
-{
-  symbol_record *sr = static_cast<symbol_record *> (sr_arg);
-  sr->unprotect ();
-}
-
 octave_value_list
 octave_user_function::subsref (const std::string& type,
 			       const std::list<octave_value_list>& idx,
@@ -269,32 +272,23 @@
       return retval;
     }
 
-  if (symtab_entry && ! symtab_entry->is_read_only ())
-    {
-      symtab_entry->protect ();
-      unwind_protect::add (unprotect_function, symtab_entry);
-    }
+  // Save old and set current symbol table context, for
+  // eval_undefined_error().
+
+  symbol_table::push_scope (local_scope);
+  unwind_protect::add (symbol_table::pop_scope);
 
   if (call_depth > 1)
     {
-      local_sym_tab->push_context ();
-      unwind_protect::add (pop_symbol_table_context, local_sym_tab);
-    }
-
-  install_automatic_vars ();
-
-  // Force symbols to be undefined again when this function exits.
+      symbol_table::push_context ();
 
-  unwind_protect::add (clear_symbol_table, local_sym_tab);
-
-  // Save old and set current symbol table context, for
-  // eval_undefined_error().
-
-  unwind_protect_ptr (curr_caller_sym_tab);
-  curr_caller_sym_tab = curr_sym_tab;
-
-  unwind_protect_ptr (curr_sym_tab);
-  curr_sym_tab = local_sym_tab;
+      unwind_protect::add (symbol_table::pop_context);
+    }
+  else
+    {
+      // Force symbols to be undefined again when this function exits.
+      unwind_protect::add (symbol_table::clear_variables);
+    }
 
   unwind_protect_ptr (curr_caller_statement);
   curr_caller_statement = curr_statement;
@@ -390,13 +384,11 @@
 
 	if (ret_list->takes_varargs ())
 	  {
-	    symbol_record *sr = local_sym_tab->lookup ("varargout");
+	    octave_value varargout_varval = symbol_table::varval ("varargout");
 
-	    if (sr && sr->is_variable ())
+	    if (varargout_varval.is_defined ())
 	      {
-		octave_value v = sr->def ();
-
-		varargout = v.cell_value ();
+		varargout = varargout_varval.cell_value ();
 
 		if (error_state)
 		  error ("expecting varargout to be a cell array object");
@@ -443,14 +435,13 @@
   tw.visit_octave_user_function (*this);
 }
 
+#if 0
 void
 octave_user_function::print_symtab_info (std::ostream& os) const
 {
-  if (local_sym_tab)
-    local_sym_tab->print_info (os);
-  else
-    warning ("%s: no symbol table info!", my_name.c_str ());
+  symbol_table::print_info (os, local_scope);
 }
+#endif
 
 void
 octave_user_function::print_code_function_header (void)
@@ -469,29 +460,18 @@
 }
 
 void
-octave_user_function::install_automatic_vars (void)
-{
-  if (local_sym_tab)
-    {
-      argn_sr = local_sym_tab->lookup ("argn", true);
-      nargin_sr = local_sym_tab->lookup ("__nargin__", true);
-      nargout_sr = local_sym_tab->lookup ("__nargout__", true);
-
-      if (takes_varargs ())
-	varargin_sr = local_sym_tab->lookup ("varargin", true);
-    }
-}
-
-void
 octave_user_function::bind_automatic_vars
   (const string_vector& arg_names, int nargin, int nargout,
    const octave_value_list& va_args)
 {
   if (! arg_names.empty ())
-    argn_sr->define (arg_names);
+    symbol_table::varref ("argn") = arg_names;
 
-  nargin_sr->define (nargin);
-  nargout_sr->define (nargout);
+  symbol_table::varref (".nargin.") = nargin;
+  symbol_table::varref (".nargout.") = nargout;
+
+  symbol_table::mark_hidden (".nargin.");
+  symbol_table::mark_hidden (".nargout.");
 
   if (takes_varargs ())
     {
@@ -502,7 +482,7 @@
       for (int i = 0; i < n; i++)
 	varargin(0,i) = va_args(i);
 
-      varargin_sr->define (varargin);
+      symbol_table::varref ("varargin") = varargin;
     }
 }
 
@@ -528,7 +508,7 @@
 
       if (! error_state)
 	{
-	  octave_value fcn_val = lookup_user_function (fname);
+	  octave_value fcn_val = symbol_table::find_user_function (fname);
 
 	  octave_user_function *fcn = fcn_val.user_function_value (true);
 
@@ -551,9 +531,10 @@
     }
   else if (nargin == 0)
     {
-      symbol_record *sr = curr_sym_tab->lookup ("__nargin__");
+      retval = symbol_table::varval (".nargin.");
 
-      retval = sr ? sr->def () : 0;
+      if (retval.is_undefined ())
+	retval = 0;
     }
   else
     print_usage ();
@@ -601,7 +582,7 @@
 
       if (! error_state)
 	{
-	  octave_value fcn_val = lookup_user_function (fname);
+	  octave_value fcn_val = symbol_table::find_user_function (fname);
 
 	  octave_user_function *fcn = fcn_val.user_function_value (true);
 
@@ -624,11 +605,12 @@
     }
   else if (nargin == 0)
     {
-      if (! at_top_level ())
+      if (! symbol_table::at_top_level ())
 	{
-	  symbol_record *sr = curr_sym_tab->lookup ("__nargout__");
+	  retval = symbol_table::varval (".nargout.");
 
-	  retval = sr ? sr->def () : 0;
+	  if (retval.is_undefined ())
+	    retval = 0;
 	}
       else
 	error ("nargout: invalid call at top level");
--- a/src/ov-usr-fcn.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov-usr-fcn.h	Fri Dec 28 20:56:58 2007 +0000
@@ -33,6 +33,7 @@
 #include "oct-obj.h"
 #include "ov-fcn.h"
 #include "ov-typeinfo.h"
+#include "symtab.h"
 
 class string_vector;
 
@@ -41,8 +42,6 @@
 class tree_statement_list;
 class tree_va_return_list;
 class tree_walker;
-class symbol_table;
-class symbol_record;
 
 // Scripts.
 
@@ -54,7 +53,7 @@
   octave_user_script (void) { }
 
   octave_user_script (const std::string& fnm, const std::string& nm,
-		      const std::string& ds)
+		      const std::string& ds = std::string ())
     : octave_function (nm, ds), file_name (fnm) { }
 
   ~octave_user_script (void) { }
@@ -68,9 +67,12 @@
 
   std::string fcn_file_name (void) const { return file_name; }
 
+  octave_value_list
+  do_multi_index_op (int nargout, const octave_value_list& args);
+
 private:
 
-  // The name of the file we parsed
+  // The name of the file to parse.
   std::string file_name;
 
   // No copying!
@@ -91,10 +93,10 @@
 {
 public:
 
-  octave_user_function (tree_parameter_list *pl = 0,
+  octave_user_function (symbol_table::scope_id sid = -1,
+			tree_parameter_list *pl = 0,
 			tree_parameter_list *rl = 0,
-			tree_statement_list *cl = 0,
-			symbol_table *st = 0);
+			tree_statement_list *cl = 0);
 
   ~octave_user_function (void);
 
@@ -122,12 +124,12 @@
       mark_fcn_file_up_to_date (t);
     }
 
-  void stash_symtab_ptr (symbol_record *sr) { symtab_entry = sr; }
-
   std::string fcn_file_name (void) const { return file_name; }
 
   std::string parent_fcn_name (void) const { return parent_name; }
 
+  symbol_table::scope_id scope (void) { return local_scope; }
+
   octave_time time_parsed (void) const { return t_parsed; }
 
   octave_time time_checked (void) const { return t_checked; }
@@ -154,6 +156,18 @@
 
   bool is_inline_function (void) const { return inline_function; }
 
+  void mark_as_class_constructor (void) { class_constructor = true; }
+
+  bool is_class_constructor (void) const { return class_constructor; }
+
+  void mark_as_class_method (void) { class_method = true; }
+
+  bool is_class_method (void) const { return class_method; }
+
+  void stash_dispatch_class (const std::string& nm) { xdispatch_class = nm; }
+
+  std::string dispatch_class (void) const { return xdispatch_class; }
+
   void save_args_passed (const octave_value_list& args)
     {
       if (call_depth > 1)
@@ -195,15 +209,15 @@
 
   tree_statement_list *body (void) { return cmd_list; }
 
-  symbol_table *sym_tab (void) { return local_sym_tab; }
-
   octave_comment_list *leading_comment (void) { return lead_comm; }
 
   octave_comment_list *trailing_comment (void) { return trail_comm; }
 
   void accept (tree_walker& tw);
 
+#if 0
   void print_symtab_info (std::ostream& os) const;
+#endif
 
 private:
 
@@ -217,9 +231,6 @@
   // The list of commands that make up the body of this function.
   tree_statement_list *cmd_list;
 
-  // The local symbol table for this function.
-  symbol_table *local_sym_tab;
-
   // The comments preceding the FUNCTION token.
   octave_comment_list *lead_comm;
 
@@ -256,6 +267,16 @@
   // TRUE means this is an inline function.
   bool inline_function;
 
+  // TRUE means this function is the constructor for class object.
+  bool class_constructor;
+
+  // TRUE means this function is a method for a class.
+  bool class_method;
+
+  // If this object is a class method or constructor, this is the name
+  // of the class to which the method belongs.
+  std::string xdispatch_class;
+
   // The values that were passed as arguments.
   octave_value_list args_passed;
 
@@ -265,27 +286,26 @@
   // The number of arguments passed in.
   int num_args_passed;
 
-  // The symbol record for this function.
-  symbol_record *symtab_entry;
+  symbol_table::scope_id local_scope;
 
+#if 0
   // The symbol record for argn in the local symbol table.
-  symbol_record *argn_sr;
+  octave_value& argn_varref;
 
   // The symbol record for nargin in the local symbol table.
-  symbol_record *nargin_sr;
+  octave_value& nargin_varref;
 
   // The symbol record for nargout in the local symbol table.
-  symbol_record *nargout_sr;
+  octave_value& nargout_varref;
 
   // The symbol record for varargin in the local symbol table.
-  symbol_record *varargin_sr;
+  octave_value& varargin_varref;
+#endif
 
   void print_code_function_header (void);
 
   void print_code_function_trailer (void);
 
-  void install_automatic_vars (void);
-
   void bind_automatic_vars (const string_vector& arg_names, int nargin,
 			    int nargout, const octave_value_list& va_args);
 
--- a/src/ov.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -55,6 +55,7 @@
 #include "ov-str-mat.h"
 #include "ov-range.h"
 #include "ov-struct.h"
+#include "ov-class.h"
 #include "ov-streamoff.h"
 #include "ov-list.h"
 #include "ov-cs-list.h"
@@ -73,6 +74,7 @@
 #include "pager.h"
 #include "parse.h"
 #include "pr-output.h"
+#include "symtab.h"
 #include "utils.h"
 #include "variables.h"
 
@@ -127,6 +129,40 @@
 }
 
 std::string
+octave_value::unary_op_fcn_name (unary_op op)
+{
+  std::string retval;
+
+  switch (op)
+    {
+    case op_not:
+      retval = "not";
+      break;
+
+    case op_uplus:
+      retval = "uplus";
+      break;
+
+    case op_uminus:
+      retval = "uminus";
+      break;
+
+    case op_transpose:
+      retval = "transpose";
+      break;
+
+    case op_hermitian:
+      retval = "ctranspose";
+      break;
+
+    default:
+      break;
+    }
+
+  return retval;
+}
+
+std::string
 octave_value::binary_op_as_string (binary_op op)
 {
   std::string retval;
@@ -225,6 +261,92 @@
 }
 
 std::string
+octave_value::binary_op_fcn_name (binary_op op)
+{
+  std::string retval;
+
+  switch (op)
+    {
+    case op_add:
+      retval = "plus";
+      break;
+
+    case op_sub:
+      retval = "minus";
+      break;
+
+    case op_mul:
+      retval = "mtimes";
+      break;
+
+    case op_div:
+      retval = "mrdivide";
+      break;
+
+    case op_pow:
+      retval = "mpower";
+      break;
+
+    case op_ldiv:
+      retval = "mldivide";
+      break;
+
+    case op_lt:
+      retval = "lt";
+      break;
+
+    case op_le:
+      retval = "le";
+      break;
+
+    case op_eq:
+      retval = "eq";
+      break;
+
+    case op_ge:
+      retval = "ge";
+      break;
+
+    case op_gt:
+      retval = "gt";
+      break;
+
+    case op_ne:
+      retval = "ne";
+      break;
+
+    case op_el_mul:
+      retval = "times";
+      break;
+
+    case op_el_div:
+      retval = "rdivide";
+      break;
+
+    case op_el_pow:
+      retval = "power";
+      break;
+
+    case op_el_ldiv:
+      retval = "ldivide";
+      break;
+
+    case op_el_and:
+      retval = "and";
+      break;
+
+    case op_el_or:
+      retval = "or";
+      break;
+
+    default:
+      break;
+    }
+
+  return retval;
+}
+
+std::string
 octave_value::assign_op_as_string (assign_op op)
 {
   std::string retval;
@@ -719,6 +841,11 @@
 {
 }
 
+octave_value::octave_value (const Octave_map& m, const std::string& id)
+  : rep (new octave_class (m, id))
+{
+}
+
 octave_value::octave_value (const streamoff_array& off)
   : rep (new octave_streamoff (off))
 {
@@ -741,6 +868,12 @@
 {
 }
 
+octave_value::octave_value (octave_base_value *new_rep, int xcount)
+  : rep (new_rep)
+{
+  rep->count = xcount;
+}
+
 octave_base_value *
 octave_value::clone (void) const
 {
@@ -886,7 +1019,7 @@
 
   if (! error_state)
     {
-      if (type[0] == '.' && ! is_map ())
+      if (type[0] == '.' && ! (is_map () || is_object ()))
 	{
 	  octave_value tmp = Octave_map ();
 	  retval = tmp.subsasgn (type, idx, t_rhs);
@@ -1369,68 +1502,86 @@
   int t1 = v1.type_id ();
   int t2 = v2.type_id ();
 
-  octave_value_typeinfo::binary_op_fcn f
-    = octave_value_typeinfo::lookup_binary_op (op, t1, t2);
+  if (t1 == octave_class::static_type_id ()
+      || t2 == octave_class::static_type_id ())
+    {
+      octave_value_typeinfo::binary_class_op_fcn f
+	= octave_value_typeinfo::lookup_binary_class_op (op);
 
-  if (f)
-    retval = f (*v1.rep, *v2.rep);
+      if (f)
+	retval = f (v1, v2);
+      else
+	gripe_binary_op (octave_value::binary_op_as_string (op),
+			 v1.class_name (), v2.class_name ());
+    }
   else
     {
-      octave_value tv1;
-      octave_base_value::type_conv_fcn cf1 = v1.numeric_conversion_function ();
+      // FIXME -- we need to handle overloading operators for built-in
+      // classes (double, char, int8, etc.)
 
-      if (cf1)
+      octave_value_typeinfo::binary_op_fcn f
+	= octave_value_typeinfo::lookup_binary_op (op, t1, t2);
+
+      if (f)
+	retval = f (*v1.rep, *v2.rep);
+      else
 	{
-	  octave_base_value *tmp = cf1 (*v1.rep);
+	  octave_value tv1;
+	  octave_base_value::type_conv_fcn cf1 = v1.numeric_conversion_function ();
+
+	  if (cf1)
+	    {
+	      octave_base_value *tmp = cf1 (*v1.rep);
 
-	  if (tmp)
-	    {
-	      tv1 = octave_value (tmp);
-	      t1 = tv1.type_id ();
+	      if (tmp)
+		{
+		  tv1 = octave_value (tmp);
+		  t1 = tv1.type_id ();
+		}
+	      else
+		{
+		  gripe_binary_op_conv (octave_value::binary_op_as_string (op));
+		  return retval;
+		}
 	    }
 	  else
+	    tv1 = v1;
+
+	  octave_value tv2;
+	  octave_base_value::type_conv_fcn cf2 = v2.numeric_conversion_function ();
+
+	  if (cf2)
 	    {
-	      gripe_binary_op_conv (octave_value::binary_op_as_string (op));
-	      return retval;
-	    }
-	}
-      else
-	tv1 = v1;
+	      octave_base_value *tmp = cf2 (*v2.rep);
 
-      octave_value tv2;
-      octave_base_value::type_conv_fcn cf2 = v2.numeric_conversion_function ();
-
-      if (cf2)
-	{
-	  octave_base_value *tmp = cf2 (*v2.rep);
-
-	  if (tmp)
-	    {
-	      tv2 = octave_value (tmp);
-	      t2 = tv2.type_id ();
+	      if (tmp)
+		{
+		  tv2 = octave_value (tmp);
+		  t2 = tv2.type_id ();
+		}
+	      else
+		{
+		  gripe_binary_op_conv (octave_value::binary_op_as_string (op));
+		  return retval;
+		}
 	    }
 	  else
+	    tv2 = v2;
+
+	  if (cf1 || cf2)
 	    {
-	      gripe_binary_op_conv (octave_value::binary_op_as_string (op));
-	      return retval;
+	      f = octave_value_typeinfo::lookup_binary_op (op, t1, t2);
+
+	      if (f)
+		retval = f (*tv1.rep, *tv2.rep);
+	      else
+		gripe_binary_op (octave_value::binary_op_as_string (op),
+				 v1.type_name (), v2.type_name ());
 	    }
-	}
-      else
-	tv2 = v2;
-
-      if (cf1 || cf2)
-	{
-	  f = octave_value_typeinfo::lookup_binary_op (op, t1, t2);
-
-	  if (f)
-	    retval = f (*tv1.rep, *tv2.rep);
 	  else
 	    gripe_binary_op (octave_value::binary_op_as_string (op),
 			     v1.type_name (), v2.type_name ());
 	}
-      else
-	gripe_binary_op (octave_value::binary_op_as_string (op),
-			 v1.type_name (), v2.type_name ());
     }
 
   return retval;
@@ -1560,39 +1711,57 @@
 
   int t = v.type_id ();
 
-  octave_value_typeinfo::unary_op_fcn f
-    = octave_value_typeinfo::lookup_unary_op (op, t);
+  if (t == octave_class::static_type_id ())
+    {
+      octave_value_typeinfo::unary_class_op_fcn f
+	= octave_value_typeinfo::lookup_unary_class_op (op);
 
-  if (f)
-    retval = f (*v.rep);
+      if (f)
+	retval = f (v);
+      else
+	gripe_unary_op (octave_value::unary_op_as_string (op),
+			v.class_name ());
+    }
   else
     {
-      octave_value tv;
-      octave_base_value::type_conv_fcn cf = v.numeric_conversion_function ();
+      // FIXME -- we need to handle overloading operators for built-in
+      // classes (double, char, int8, etc.)
+
+      octave_value_typeinfo::unary_op_fcn f
+	= octave_value_typeinfo::lookup_unary_op (op, t);
 
-      if (cf)
+      if (f)
+	retval = f (*v.rep);
+      else
 	{
-	  octave_base_value *tmp = cf (*v.rep);
+	  octave_value tv;
+	  octave_base_value::type_conv_fcn cf
+	    = v.numeric_conversion_function ();
 
-	  if (tmp)
+	  if (cf)
 	    {
-	      tv = octave_value (tmp);
-	      t = tv.type_id ();
+	      octave_base_value *tmp = cf (*v.rep);
 
-	      f = octave_value_typeinfo::lookup_unary_op (op, t);
+	      if (tmp)
+		{
+		  tv = octave_value (tmp);
+		  t = tv.type_id ();
+
+		  f = octave_value_typeinfo::lookup_unary_op (op, t);
 
-	      if (f)
-		retval = f (*tv.rep);
+		  if (f)
+		    retval = f (*tv.rep);
+		  else
+		    gripe_unary_op (octave_value::unary_op_as_string (op),
+				    v.type_name ());
+		}
 	      else
-		gripe_unary_op (octave_value::unary_op_as_string (op),
-				v.type_name ());
+		gripe_unary_op_conv (octave_value::unary_op_as_string (op));
 	    }
 	  else
-	    gripe_unary_op_conv (octave_value::unary_op_as_string (op));
+	    gripe_unary_op (octave_value::unary_op_as_string (op),
+			    v.type_name ());
 	}
-      else
-	gripe_unary_op (octave_value::unary_op_as_string (op),
-			v.type_name ());
     }
 
   return retval;
@@ -1882,6 +2051,7 @@
   octave_sparse_matrix::register_type ();
   octave_sparse_complex_matrix::register_type ();
   octave_struct::register_type ();
+  octave_class::register_type ();
   octave_list::register_type ();
   octave_cs_list::register_type ();
   octave_magic_colon::register_type ();
--- a/src/ov.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/ov.h	Fri Dec 28 20:56:58 2007 +0000
@@ -130,8 +130,10 @@
   };
 
   static std::string unary_op_as_string (unary_op);
+  static std::string unary_op_fcn_name (unary_op);
 
   static std::string binary_op_as_string (binary_op);
+  static std::string binary_op_fcn_name (binary_op);
 
   static std::string assign_op_as_string (assign_op);
 
@@ -225,11 +227,13 @@
   octave_value (double base, double limit, double inc);
   octave_value (const Range& r);
   octave_value (const Octave_map& m);
+  octave_value (const Octave_map& m, const std::string& id);
   octave_value (const streamoff_array& off);
   octave_value (const octave_value_list& m, bool is_cs_list = false);
   octave_value (octave_value::magic_colon);
 
   octave_value (octave_base_value *new_rep);
+  octave_value (octave_base_value *new_rep, int xcount);
 
   // Copy constructor.
 
@@ -442,6 +446,9 @@
   bool is_map (void) const
     { return rep->is_map (); }
 
+  bool is_object (void) const
+    { return rep->is_object (); }
+
   bool is_streamoff (void) const
     { return rep->is_streamoff (); }
 
@@ -550,6 +557,12 @@
   bool is_function (void) const
     { return rep->is_function (); }
 
+  bool is_user_script (void) const
+    { return rep->is_user_script (); }
+
+  bool is_user_function (void) const
+    { return rep->is_user_function (); }
+
   bool is_builtin_function (void) const
     { return rep->is_builtin_function (); }
 
--- a/src/parse.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/parse.h	Fri Dec 28 20:56:58 2007 +0000
@@ -38,14 +38,9 @@
 class tree_matrix;
 class tree_identifier;
 class octave_function;
-class symbol_record;
-class symbol_table;
 
 #include "oct-obj.h"
 
-// Temporary symbol table pointer used to cope with bogus function syntax.
-extern symbol_table *tmp_local_sym_tab;
-
 // Nonzero means print parser debugging info (-d).
 extern int octave_debug;
 
@@ -73,12 +68,16 @@
 extern bool evaluating_function_body;
 
 // Keep track of symbol table information when parsing functions.
-extern std::stack<symbol_table*> symtab_context;
+extern std::stack<symbol_table::scope_id> symtab_context;
 
 // Name of parent function when parsing function files that might
 // contain nested functions.
 extern std::string parent_function_name;
 
+// Name of the current class when we are parsing class methods or
+// constructors.
+extern std::string current_class_name;
+
 // Keep a count of how many END tokens we expect.
 extern int end_tokens_expected;
 
@@ -102,11 +101,12 @@
 
 extern OCTINTERP_API string_vector reverse_lookup_autoload (const std::string& nm);
 
-extern OCTINTERP_API bool
-load_fcn_from_file (const std::string& nm, bool exec_script);
-
-extern OCTINTERP_API bool
-load_fcn_from_file (symbol_record *sym_rec, bool exec_script);
+extern OCTINTERP_API octave_function *
+load_fcn_from_file (const std::string& file_name,
+		    const std::string& dir_name = std::string (),
+		    const std::string& dispatch_type = std::string (),
+		    const std::string& fcn_name = std::string (),
+		    bool autoload = false);
 
 extern OCTINTERP_API void
 source_file (const std::string& file_name,
--- a/src/parse.y	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/parse.y	Fri Dec 28 20:56:58 2007 +0000
@@ -75,9 +75,6 @@
 #include "utils.h"
 #include "variables.h"
 
-// Temporary symbol table pointer used to cope with bogus function syntax.
-symbol_table *tmp_local_sym_tab = 0;
-
 // The current input line number.
 int input_line_number = 0;
 
@@ -109,12 +106,16 @@
 int end_tokens_expected = 0;
 
 // Keep track of symbol table information when parsing functions.
-std::stack<symbol_table*> symtab_context;
+std::stack<symbol_table::scope_id> symtab_context;
 
 // Name of parent function when parsing function files that might
 // contain nested functions.
 std::string parent_function_name;
 
+// Name of the current class when we are parsing class methods or
+// constructors.
+std::string current_class_name;
+
 // TRUE means we are in the process of autoloading a function.
 static bool autoloading = false;
 
@@ -122,6 +123,10 @@
 // element.
 static bool fcn_file_from_relative_lookup = false;
 
+// If nonzero, this is a pointer to the function we just finished
+// parsing.
+static octave_function *curr_fcn_ptr = 0;
+
 // List of autoloads (function -> file mapping).
 static std::map<std::string, std::string> autoload_map;
 
@@ -263,12 +268,7 @@
 frob_function (const std::string& fname, octave_user_function *fcn);
 
 // Finish defining a function.
-static octave_user_function *
-finish_function (tree_identifier *id, octave_user_function *fcn,
-		 octave_comment_list *lc);
-
-// Finish defining a function a different way.
-static octave_user_function *
+static void
 finish_function (tree_parameter_list *ret_list,
 		 octave_user_function *fcn, octave_comment_list *lc);
 
@@ -316,7 +316,7 @@
       yyerrok; \
       if (! symtab_context.empty ()) \
         { \
-	  curr_sym_tab = symtab_context.top (); \
+	  symbol_table::set_scope (symtab_context.top ()); \
 	  symtab_context.pop (); \
         } \
       if (interactive || forced_interactive) \
@@ -415,7 +415,7 @@
 %type <tree_expression_type> primary_expr postfix_expr prefix_expr binary_expr
 %type <tree_expression_type> simple_expr colon_expr assign_expr expression
 %type <tree_identifier_type> identifier fcn_name
-%type <octave_user_function_type> function1 function2 function3
+%type <octave_user_function_type> function1 function2
 %type <tree_index_expression_type> word_list_cmd
 %type <tree_colon_expression_type> colon_expr1
 %type <tree_argument_list_type> arg_list word_list assign_lhs
@@ -435,7 +435,7 @@
 %type <tree_decl_command_type> declaration
 %type <tree_statement_type> statement
 %type <tree_statement_list_type> simple_list simple_list1 list list1
-%type <tree_statement_list_type> opt_list input1 function4
+%type <tree_statement_list_type> opt_list input1
 
 // Precedence and associativity.
 %left ';' ',' '\n'
@@ -554,8 +554,8 @@
 
 identifier	: NAME
 		  {
-		    $$ = new tree_identifier
-		      ($1->sym_rec (), $1->line (), $1->column ());
+		    symbol_table::symbol_record *sr = $1->sym_rec ();
+		    $$ = new tree_identifier (*sr, $1->line (), $1->column ());
 		  }
 		;
 
@@ -1098,16 +1098,14 @@
 // Some `subroutines' for function definitions
 // ===========================================
 
-save_symtab	: // empty
-		  { symtab_context.push (curr_sym_tab); }
-		;
-		   
-function_symtab	: // empty
-		  { curr_sym_tab = fbi_sym_tab; }
-		;
-
-local_symtab	: // empty
-		  { curr_sym_tab = tmp_local_sym_tab; }
+push_fcn_symtab	: // empty
+		  {
+		    symtab_context.push (symbol_table::current_scope ());
+		    symbol_table::set_scope (symbol_table::alloc_scope ());
+
+		    if (! lexer_flags.parsing_nested_function)
+		      symbol_table::set_parent_scope (symbol_table::current_scope ());
+		  }
 		;
 
 // ===========================
@@ -1120,12 +1118,8 @@
 
 		    if (lexer_flags.looking_at_function_handle)
 		      {
-		        symtab_context.push (curr_sym_tab);
-
-			tmp_local_sym_tab = new symbol_table ();
-
-			curr_sym_tab = tmp_local_sym_tab;
-
+		        symtab_context.push (symbol_table::current_scope ());
+			symbol_table::set_scope (symbol_table::alloc_scope ());
 			lexer_flags.looking_at_function_handle--;
 		      }
 		  }
@@ -1182,15 +1176,12 @@
 // List of function return value names
 // ===================================
 
-return_list_beg	: '[' local_symtab
-		;
-
-return_list	: return_list_beg return_list_end
+return_list	: '[' ']'
 		  {
 		    lexer_flags.looking_at_return_list = false;
 		    $$ = new tree_parameter_list ();
 		  }
-		| return_list_beg VARARGOUT return_list_end
+		| '[' VARARGOUT ']'
 		  {
 		    lexer_flags.looking_at_return_list = false;
 		    tree_parameter_list *tmp = new tree_parameter_list ();
@@ -1204,12 +1195,17 @@
 		    tmp->mark_varargs_only ();
 		    $$ = tmp;
 		  }
-		| return_list_beg return_list1 return_list_end
+		| return_list1
+		  {
+		    lexer_flags.looking_at_return_list = false;
+		    $$ = $1;
+		  }
+		| '[' return_list1 ']'
 		  {
 		    lexer_flags.looking_at_return_list = false;
 		    $$ = $2;
 		  }
-		| return_list_beg return_list1 ',' VARARGOUT return_list_end
+		| '[' return_list1 ',' VARARGOUT ']'
 		  {
 		    lexer_flags.looking_at_return_list = false;
 		    $2->mark_varargs ();
@@ -1226,42 +1222,29 @@
 		  }
 		;
 
-return_list_end	: function_symtab ']'
-		;
-
 // ===================
 // Function definition
 // ===================
 
-function_beg	: save_symtab FCN function_symtab stash_comment
-		  { $$ = $4; }
+function_beg	: push_fcn_symtab FCN stash_comment
+		  { $$ = $3; }
 		;
 
-function	: function_beg function2
+function	: function_beg function1
 		  {
 		    $2->stash_leading_comment ($1);
 		    recover_from_parsing_function ();
 		    $$ = 0;
 		  }
-		| function_beg identifier function1
+		| function_beg return_list '=' function1
 		  {
-		    finish_function ($2, $3, $1);
-		    recover_from_parsing_function ();
-		    $$ = 0;
-		  }
-		| function_beg return_list function1
-		  {
-		    finish_function ($2, $3, $1);
+		    finish_function ($2, $4, $1);
 		    recover_from_parsing_function ();
 		    $$ = 0;
 		  }
 		;
 
-function1	: function_symtab '=' function2
-		  { $$ = $3; }
-		;
-
-fcn_name	: identifier local_symtab
+fcn_name	: identifier
 		  {
 		    std::string id_name = $1->name ();
 
@@ -1276,7 +1259,7 @@
 		  }
 		;
 
-function2	: fcn_name function3
+function1	: fcn_name function2
 		  {
 		    std::string fname = $1->name ();
 
@@ -1287,14 +1270,10 @@
 		  }
 		;
 
-function3	: param_list function4
-		  { $$ = start_function ($1, $2); }
-		| function4
-		  { $$ = start_function (0, $1); }
-		;
-
-function4	: opt_sep opt_list function_end
-		  { $$ = $2; }
+function2	: param_list opt_sep opt_list function_end
+		  { $$ = start_function ($1, $3); }
+		| opt_sep opt_list function_end
+		  { $$ = start_function (0, $2); }
 		;
 
 function_end	: END
@@ -1772,24 +1751,45 @@
 
   tree_parameter_list *ret_list = 0;
 
-  symbol_table *fcn_sym_tab = curr_sym_tab;
+  symbol_table::scope_id fcn_scope = symbol_table::current_scope ();
 
   if (symtab_context.empty ())
     panic_impossible ();
 
-  curr_sym_tab = symtab_context.top ();
+  symbol_table::set_scope (symtab_context.top ());
 
   symtab_context.pop ();
 
   if (stmt && stmt->is_expression ())
-    stmt->set_print_flag (false);
+    {
+      symbol_table::symbol_record& sr = symbol_table::insert ("__retval__");
+
+      tree_expression *e = stmt->expression ();
+
+      tree_identifier *id = new tree_identifier (sr);
+
+      tree_simple_assignment *asn = new tree_simple_assignment (id, e);
+
+      stmt->set_expression (asn);
+
+      stmt->set_print_flag (false);
+
+      // FIXME -- would like to delete old_stmt here or
+      // replace expression inside it with the new expression we just
+      // created so we don't have to create a new statement at all.
+
+      id = new tree_identifier (sr);
+      tree_decl_elt *elt = new tree_decl_elt (id);
+
+      ret_list = new tree_parameter_list (elt);
+    }
 
   tree_statement_list *body = new tree_statement_list (stmt);
 
   body->mark_as_function_body ();
 
   tree_anon_fcn_handle *retval
-    = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_sym_tab, l, c);
+    = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_scope, l, c);
 
   return retval;
 }
@@ -2423,7 +2423,9 @@
   // We'll fill in the return list later.
 
   octave_user_function *fcn
-    = new octave_user_function (param_list, 0, body, curr_sym_tab);
+    = new octave_user_function (symbol_table::current_scope (),
+				param_list, 0, body);
+				
 
   if (fcn)
     {
@@ -2449,15 +2451,30 @@
 
   if (reading_fcn_file || autoloading)
     {
-      if (! (lexer_flags.parsing_nested_function || autoloading)
-          && curr_fcn_file_name != id_name)
+      if (! (autoloading
+	     || lexer_flags.parsing_nested_function
+	     || lexer_flags.parsing_class_method))
 	{
-	  warning_with_id
-	    ("Octave:function-name-clash",
-	     "function name `%s' does not agree with function file name `%s'",
-	     id_name.c_str (), curr_fcn_file_full_name.c_str ());
-
-	  id_name = curr_fcn_file_name;
+	  // FIXME -- should curr_fcn_file_name already be
+	  // preprocessed when we get here?  It seems to only be a
+	  // problem with relative file names.
+
+	  std::string nm = curr_fcn_file_name;
+
+	  size_t pos = nm.find_last_of (file_ops::dir_sep_chars);
+
+	  if (pos != NPOS)
+	    nm = curr_fcn_file_name.substr (pos+1);
+
+	  if (nm != id_name)
+	    {
+	      warning_with_id
+		("Octave:function-name-clash",
+		 "function name `%s' does not agree with function file name `%s'",
+		 id_name.c_str (), curr_fcn_file_full_name.c_str ());
+
+	      id_name = nm;
+	    }
 	}
 
       octave_time now;
@@ -2472,6 +2489,16 @@
       if (lexer_flags.parsing_nested_function)
         fcn->stash_parent_fcn_name (parent_function_name);
 
+      if (lexer_flags.parsing_class_method)
+	{
+	  if (current_class_name == id_name)
+	    fcn->mark_as_class_constructor ();
+	  else
+	    fcn->mark_as_class_method ();
+
+	  fcn->stash_dispatch_class (current_class_name);
+	}
+
       std::string nm = fcn->fcn_file_name ();
 
       file_stat fs (nm);
@@ -2490,105 +2517,47 @@
 
   fcn->stash_function_name (id_name);
 
-  // Enter the new function in fbi_sym_tab.  If there is already a
-  // variable of the same name in the current symbol table, we won't
-  // find the new function when we try to call it, so we need to clear
-  // the old symbol from the current symbol table.  Note that this
-  // means that for things like
-  //
-  //   function f () eval ("function g () 1, end"); end
-  //   g = 13;
-  //   f ();
-  //   g
-  //
-  // G will still refer to the variable G (with value 13) rather
-  // than the function G, until the variable G is cleared.
-
-  curr_sym_tab->clear (id_name);
-
-  if (! lexer_flags.parsing_nested_function
-      && symtab_context.top () == top_level_sym_tab)
+  if (! help_buf.empty ())
+    {
+      fcn->document (help_buf.top ());
+
+      help_buf.pop ();
+    }
+
+  if (lexer_flags.parsing_nested_function)
     {
-      symbol_record *sr = top_level_sym_tab->lookup (id_name);
-
-      // Only clear the existing name if it is already defined as a
-      // function.  If there is already a variable defined with the
-      // same name as a the current function, it will continue to
-      // shadow this name until the variable is cleared.  This means
-      // that for something like the following at the command line,
-      //
-      //   f = 13;
-      //   function f () 7, end
-      //   f
-      //
-      // F will still refer to the variable F (with value 13) rather
-      // than the function F, until the variable F is cleared.
-
-      if (sr && sr->is_function ())
-	top_level_sym_tab->clear (id_name);
-    }
-
-  symbol_record *sr = fbi_sym_tab->lookup (id_name, true);
-
-  if (sr)
-    {
-      fcn->stash_symtab_ptr (sr);
-
-      if (lexer_flags.parsing_nested_function)
-        {
-          fcn->mark_as_nested_function ();
-	  sr->hide ();
+      std::string nm = fcn->name ();
+
+      fcn->mark_as_nested_function ();
+
+      symbol_table::install_subfunction (nm, octave_value (fcn));
+
+      if (lexer_flags.parsing_nested_function < 0)
+	{
+	  lexer_flags.parsing_nested_function = 0;
+	  symbol_table::reset_parent_scope ();
 	}
     }
-  else
-    panic_impossible ();
-
-  sr->define (fcn, symbol_record::USER_FUNCTION);
-
-  if (! help_buf.empty ())
+  else if (! reading_fcn_file)
     {
-      sr->document (help_buf.top ());
-      help_buf.pop ();
+      std::string nm = fcn->name ();
+
+      symbol_table::install_cmdline_function (nm, octave_value (fcn));
+
+      // Make sure that any variable with the same name as the new
+      // function is cleared.
+
+      symbol_table::varref (nm) = octave_value ();
     }
-
-  // Also insert the full name in the symbol table.  This way, we can
-  // properly cope with changes to LOADPATH.
-
-  if (reading_fcn_file)
-    {
-      symbol_record *full_sr
-        = fbi_sym_tab->lookup (curr_fcn_file_full_name, true);
-
-      full_sr->alias (sr, true);
-      full_sr->hide ();
-    }
-
-  if (lexer_flags.parsing_nested_function < 0)
-    lexer_flags.parsing_nested_function = 0;
+  else
+    curr_fcn_ptr = fcn;
 
   return fcn;
 }
 
 // Finish defining a function.
 
-static octave_user_function *
-finish_function (tree_identifier *id, octave_user_function *fcn,
-		 octave_comment_list *lc)
-{
-  tree_decl_elt *tmp = new tree_decl_elt (id);
-
-  tree_parameter_list *tpl = new tree_parameter_list (tmp);
-
-  tpl->mark_as_formal_parameters ();
-
-  fcn->stash_leading_comment (lc);
-
-  return fcn->define_ret_list (tpl);
-}
-
-// Finish defining a function a different way.
-
-static octave_user_function *
+static void
 finish_function (tree_parameter_list *ret_list,
 		 octave_user_function *fcn, octave_comment_list *lc)
 {
@@ -2596,7 +2565,7 @@
 
   fcn->stash_leading_comment (lc);
 
-  return fcn->define_ret_list (ret_list);
+  fcn->define_ret_list (ret_list);
 }
 
 static void
@@ -2605,7 +2574,7 @@
   if (symtab_context.empty ())
     panic_impossible ();
 
-  curr_sym_tab = symtab_context.top ();
+  symbol_table::set_scope (symtab_context.top ());
   symtab_context.pop ();
 
   lexer_flags.defining_func = false;
@@ -2848,8 +2817,6 @@
   get_input_from_eval_string = false;
   parser_end_of_input = false;
 
-  unwind_protect_ptr (curr_sym_tab);
-
   int retval;
   do
     {
@@ -3205,6 +3172,23 @@
   return status;
 }
 
+static int
+is_function_file (const std::string& fname)
+{
+  int retval = 0;
+
+  FILE *fid = fopen (fname.c_str (), "r");
+
+  if (fid)
+    {
+      retval = is_function_file (fid);
+
+      fclose (fid);
+    }
+
+  return retval;
+}
+
 static void
 restore_command_history (void *)
 {
@@ -3217,13 +3201,15 @@
   command_editor::set_input_stream (static_cast<FILE *> (f));
 }
 
-static bool
-parse_fcn_file (const std::string& ff, bool exec_script,
-		bool force_script = false)
+typedef octave_function * octave_function_ptr;
+
+static octave_function *
+parse_fcn_file (const std::string& ff, const std::string& dispatch_type,
+		bool exec_script, bool force_script = false)
 {
   unwind_protect::begin_frame ("parse_fcn_file");
 
-  int script_file_executed = false;
+  octave_function *fcn_ptr = 0;
 
   // Open function file and parse.
 
@@ -3241,6 +3227,7 @@
   unwind_protect_bool (reading_fcn_file);
   unwind_protect_bool (line_editing);
   unwind_protect_str (parent_function_name);
+  unwind_protect_str (current_class_name);
 
   input_line_number = 0;
   current_input_column = 1;
@@ -3248,6 +3235,7 @@
   reading_fcn_file = true;
   line_editing = false;
   parent_function_name = "";
+  current_class_name = dispatch_type;
 
   FILE *ffile = get_input_from_file (ff, 0);
 
@@ -3287,7 +3275,8 @@
 
 	  switch_to_buffer (new_buf);
 
-	  unwind_protect_ptr (curr_sym_tab);
+	  unwind_protect_ptr (curr_fcn_ptr);
+	  curr_fcn_ptr = 0;
 
 	  reset_parser ();
 
@@ -3301,14 +3290,14 @@
 	  // FIXME -- this should not be necessary.
 	  gobble_leading_white_space (ffile, false, true, false, false);
 
+	  lexer_flags.parsing_class_method = ! dispatch_type.empty ();
+
 	  int status = yyparse ();
 
+	  fcn_ptr = curr_fcn_ptr;
+
 	  if (status != 0)
-	    {
-	      error ("parse error while reading function file %s",
-		     ff.c_str ());
-	      fbi_sym_tab->clear (curr_fcn_file_name);
-	    }
+	    error ("parse error while reading function file %s", ff.c_str ());
 	}
       else if (exec_script)
 	{
@@ -3334,8 +3323,6 @@
 	  unwind_protect::add (octave_call_stack::unwind_pop_script, 0);
 
 	  parse_and_execute (ffile);
-
-	  script_file_executed = true;
 	}
     }
   else
@@ -3343,7 +3330,7 @@
 
   unwind_protect::run_frame ("parse_fcn_file");
 
-  return script_file_executed;
+  return fcn_ptr;
 }
 
 std::string
@@ -3387,14 +3374,16 @@
   return names;
 }
 
-bool
-load_fcn_from_file (const std::string& nm_arg, bool exec_script)
+octave_function *
+load_fcn_from_file (const std::string& file_name, const std::string& dir_name,
+		    const std::string& dispatch_type,
+		    const std::string& fcn_name, bool autoload)
 {
+  octave_function *retval = 0;
+
   unwind_protect::begin_frame ("load_fcn_from_file");
 
-  bool script_file_executed = false;
-
-  std::string nm = nm_arg;
+  std::string nm = file_name;
 
   size_t nm_len = nm.length ();
 
@@ -3404,30 +3393,24 @@
 
   fcn_file_from_relative_lookup = false;
 
-  if (octave_env::absolute_pathname (nm)
-      && ((nm_len > 4 && nm.substr (nm_len-4) == ".oct")
-	  || (nm_len > 4 && nm.substr (nm_len-4) == ".mex")
-	  || (nm_len > 2 && nm.substr (nm_len-2) == ".m")))
+  file = nm;
+
+  if ((nm_len > 4 && nm.substr (nm_len-4) == ".oct")
+      || (nm_len > 4 && nm.substr (nm_len-4) == ".mex")
+      || (nm_len > 2 && nm.substr (nm_len-2) == ".m"))
     {
-      file = nm;
-
       nm = octave_env::base_pathname (file);
       nm = nm.substr (0, nm.find_last_of ('.'));
     }
-  else
+
+  if (autoload)
     {
-      file = lookup_autoload (nm);
-
-      if (! file.empty ())
-	{
-	  unwind_protect_bool (autoloading);
-
-	  autoloading = true;
-	  exec_script = true;
-	}
-      else
-        file = load_path::find_fcn (nm);
-
+      unwind_protect_bool (autoloading);
+      autoloading = true;
+    }
+
+  if (! file.empty ())
+    {
       fcn_file_from_relative_lookup = ! octave_env::absolute_pathname (file);
 
       file = octave_env::make_absolute (file, octave_env::getcwd ());
@@ -3437,47 +3420,37 @@
 
   if (len > 4 && file.substr (len-4, len-1) == ".oct")
     {
-      if (octave_dynamic_loader::load_oct (nm, file, fcn_file_from_relative_lookup))
-        force_link_to_function (nm);
+      if (autoload && ! fcn_name.empty ())
+	nm = fcn_name;
+
+      retval = octave_dynamic_loader::load_oct (nm, file, fcn_file_from_relative_lookup);
     }
   else if (len > 4 && file.substr (len-4, len-1) == ".mex")
-    {
-      if (octave_dynamic_loader::load_mex (nm, file, fcn_file_from_relative_lookup))
-        force_link_to_function (nm);
-    }
+    retval = octave_dynamic_loader::load_mex (nm, file, fcn_file_from_relative_lookup);
   else if (len > 2)
     {
-      // These are needed by yyparse.
-
-      unwind_protect_str (curr_fcn_file_name);
-      unwind_protect_str (curr_fcn_file_full_name);
-
-      curr_fcn_file_name = nm;
-      curr_fcn_file_full_name = file;
-
-      script_file_executed = parse_fcn_file (file, exec_script, autoloading);
-
-      if (! error_state)
+      if (is_function_file (file))
 	{
-	  if (autoloading)
-	    {
-	      script_file_executed = false;
-	      force_link_to_function (nm);
-	    }
-	  else if (! script_file_executed)
-	    force_link_to_function (nm);
+	  // These are needed by yyparse.
+
+	  unwind_protect_str (curr_fcn_file_name);
+	  unwind_protect_str (curr_fcn_file_full_name);
+
+	  curr_fcn_file_name = nm;
+	  curr_fcn_file_full_name = file;
+
+	  retval = parse_fcn_file (file, dispatch_type, false, autoloading);
 	}
+      else
+	retval = new octave_user_script (file, fcn_name);
     }
 
+  if (retval)
+    retval->stash_dir_name (dir_name);
+
   unwind_protect::run_frame ("load_fcn_from_file");
 
-  return script_file_executed;
-}
-
-bool
-load_fcn_from_file (symbol_record *sym_rec, bool exec_script)
-{
-  return load_fcn_from_file (sym_rec->name (), exec_script);
+  return retval;
 }
 
 DEFCMD (autoload, args, ,
@@ -3598,19 +3571,20 @@
 
   if (! context.empty ())
     {
-      unwind_protect_ptr (curr_sym_tab);
-
       if (context == "caller")
-	curr_sym_tab = curr_caller_sym_tab;
+	symbol_table::push_scope (symbol_table::current_caller_scope ());
       else if (context == "base")
-	curr_sym_tab = top_level_sym_tab;
+	symbol_table::push_scope (symbol_table::top_scope ());
       else
 	error ("source: context must be \"caller\" or \"base\"");
+
+      if (! error_state)
+	unwind_protect::add (symbol_table::pop_scope);
     }      
 
   if (! error_state)
     {
-      parse_fcn_file (file_full_name, true, true);
+      parse_fcn_file (file_full_name, "", true, true);
 
       if (error_state)
 	error ("source: error sourcing file `%s'",
@@ -3736,10 +3710,12 @@
 {
   octave_value_list retval;
 
-  octave_function *fcn = is_valid_function (name, "feval", 1);
-
-  if (fcn)
-    retval = fcn->do_multi_index_op (nargout, args);
+  octave_value fcn = symbol_table::find_function (name, args);
+
+  if (fcn.is_defined ())
+    retval = fcn.do_multi_index_op (nargout, args);
+  else
+    error ("feval: function `%s' not found", name.c_str ());
 
   return retval;
 }
@@ -3896,8 +3872,6 @@
 
   switch_to_buffer (new_buf);
 
-  unwind_protect_ptr (curr_sym_tab);
-
   do
     {
       reset_parser ();
@@ -4048,14 +4022,20 @@
 
       if (! error_state)
         {
-	  unwind_protect::begin_frame ("Fassignin");
-
-	  unwind_protect_ptr (curr_sym_tab);
+	  symbol_table::scope_id scope = -1;
 
 	  if (context == "caller")
-	    curr_sym_tab = curr_caller_sym_tab;
+	    {
+	      if (symbol_table::current_scope () == symbol_table::current_caller_scope ())
+		{
+		  error ("assignin: assignment in caller not implemented yet for direct recursion");
+		  return retval;
+		}
+	      else
+		scope = symbol_table::current_caller_scope ();
+	    }
 	  else if (context == "base")
-	    curr_sym_tab = top_level_sym_tab;
+	    scope = symbol_table::top_scope ();
 	  else
 	    error ("assignin: context must be \"caller\" or \"base\"");
 
@@ -4066,27 +4046,13 @@
 	      if (! error_state)
 		{
 		  if (valid_identifier (nm))
-		    {
-		      symbol_record *sr = curr_sym_tab->lookup (nm, true);
-
-		      if (sr)
-			{
-			  tree_identifier *id = new tree_identifier (sr);
-			  tree_constant *rhs = new tree_constant (args(2));
-		      
-			  tree_simple_assignment tsa (id, rhs);
-
-			  tsa.rvalue ();
-			}
-		    }
+		    symbol_table::varref (nm, scope) = args(2);
 		  else
 		    error ("assignin: invalid variable name");
 		}
 	      else
 		error ("assignin: expecting variable name as second argument");
 	    }
-
-	  unwind_protect::run_frame ("Fassignin");
 	}
       else
         error ("assignin: expecting string as first argument");
@@ -4117,17 +4083,25 @@
         {
 	  unwind_protect::begin_frame ("Fevalin");
 
-	  unwind_protect_ptr (curr_sym_tab);
-
 	  if (context == "caller")
-	    curr_sym_tab = curr_caller_sym_tab;
+	    {
+	      if (symbol_table::current_scope () == symbol_table::current_caller_scope ())
+		{
+		  error ("evalin: evaluation in caller not implemented yet for direct recursion");
+		  return retval;
+		}
+	      else
+		symbol_table::push_scope (symbol_table::current_caller_scope ());
+	    }
 	  else if (context == "base")
-	    curr_sym_tab = top_level_sym_tab;
+	    symbol_table::push_scope (symbol_table::top_scope ());
 	  else
 	    error ("evalin: context must be \"caller\" or \"base\"");
 
 	  if (! error_state)
 	    {
+	      unwind_protect::add (symbol_table::pop_scope);
+
 	      if (nargin > 2)
 	        {
 		  unwind_protect_int (buffer_error_messages);
--- a/src/pt-arg-list.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-arg-list.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -254,7 +254,7 @@
 }
 
 tree_argument_list *
-tree_argument_list::dup (symbol_table *sym_tab)
+tree_argument_list::dup (symbol_table::scope_id scope)
 {
   tree_argument_list *new_list = new tree_argument_list ();
 
@@ -265,7 +265,7 @@
     {
       tree_expression *elt = *p;
 
-      new_list->append (elt ? elt->dup (sym_tab) : 0);
+      new_list->append (elt ? elt->dup (scope) : 0);
     }
 
   return new_list;
--- a/src/pt-arg-list.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-arg-list.h	Fri Dec 28 20:56:58 2007 +0000
@@ -78,7 +78,7 @@
 
   string_vector get_arg_names (void) const;
 
-  tree_argument_list *dup (symbol_table *sym_tab);
+  tree_argument_list *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-assign.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-assign.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -279,11 +279,11 @@
 }
 
 tree_expression *
-tree_simple_assignment::dup (symbol_table *sym_tab)
+tree_simple_assignment::dup (symbol_table::scope_id scope)
 {
   tree_simple_assignment *new_sa
-    = new tree_simple_assignment (lhs ? lhs->dup (sym_tab) : 0,
-				  rhs ? rhs->dup (sym_tab) : 0,
+    = new tree_simple_assignment (lhs ? lhs->dup (scope) : 0,
+				  rhs ? rhs->dup (scope) : 0,
 				  preserve, etype);
 
   new_sa->copy_base (*this);
@@ -507,11 +507,11 @@
 }
 
 tree_expression *
-tree_multi_assignment::dup (symbol_table *sym_tab)
+tree_multi_assignment::dup (symbol_table::scope_id scope)
 {
   tree_multi_assignment *new_ma
-    = new tree_multi_assignment (lhs ? lhs->dup (sym_tab) : 0,
-				 rhs ? rhs->dup (sym_tab) : 0,
+    = new tree_multi_assignment (lhs ? lhs->dup (scope) : 0,
+				 rhs ? rhs->dup (scope) : 0,
 				 preserve, etype);
 
   new_ma->copy_base (*this);
--- a/src/pt-assign.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-assign.h	Fri Dec 28 20:56:58 2007 +0000
@@ -36,6 +36,7 @@
 
 #include "ov.h"
 #include "pt-exp.h"
+#include "symtab.h"
 
 // Simple assignment expressions.
 
@@ -72,7 +73,7 @@
 
   tree_expression *right_hand_side (void) { return rhs; }
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -142,7 +143,7 @@
 
   tree_expression *right_hand_side (void) { return rhs; }
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
   
--- a/src/pt-binop.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-binop.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -106,11 +106,11 @@
 }
 
 tree_expression *
-tree_binary_expression::dup (symbol_table *sym_tab)
+tree_binary_expression::dup (symbol_table::scope_id scope)
 {
   tree_binary_expression *new_be
-    = new tree_binary_expression (op_lhs ? op_lhs->dup (sym_tab) : 0,
-				  op_rhs ? op_rhs->dup (sym_tab) : 0,
+    = new tree_binary_expression (op_lhs ? op_lhs->dup (scope) : 0,
+				  op_rhs ? op_rhs->dup (scope) : 0,
 				  line (), column (), etype);
 
   new_be->copy_base (*this);
@@ -233,11 +233,11 @@
 }
 
 tree_expression *
-tree_boolean_expression::dup (symbol_table *sym_tab)
+tree_boolean_expression::dup (symbol_table::scope_id scope)
 {
   tree_boolean_expression *new_be
-    = new tree_boolean_expression (op_lhs ? op_lhs->dup (sym_tab) : 0,
-				   op_rhs ? op_rhs->dup (sym_tab) : 0,
+    = new tree_boolean_expression (op_lhs ? op_lhs->dup (scope) : 0,
+				   op_rhs ? op_rhs->dup (scope) : 0,
 				   line (), column (), etype);
 
   new_be->copy_base (*this);
--- a/src/pt-binop.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-binop.h	Fri Dec 28 20:56:58 2007 +0000
@@ -34,6 +34,7 @@
 
 #include "ov.h"
 #include "pt-exp.h"
+#include "symtab.h"
 
 // Binary expressions.
 
@@ -82,7 +83,7 @@
   tree_expression *lhs (void) { return op_lhs; }
   tree_expression *rhs (void) { return op_rhs; }
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -139,7 +140,7 @@
 
   type op_type (void) const { return etype; }
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
 private:
 
--- a/src/pt-cell.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-cell.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -102,7 +102,7 @@
 }
 
 tree_expression *
-tree_cell::dup (symbol_table *sym_tab)
+tree_cell::dup (symbol_table::scope_id scope)
 {
   tree_cell *new_cell = new tree_cell (0, line (), column ());
 
@@ -110,7 +110,7 @@
     {
       tree_argument_list *elt = *p;
 
-      new_cell->append (elt ? elt->dup (sym_tab) : 0);
+      new_cell->append (elt ? elt->dup (scope) : 0);
     }
 
   new_cell->copy_base (*this);
--- a/src/pt-cell.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-cell.h	Fri Dec 28 20:56:58 2007 +0000
@@ -33,6 +33,7 @@
 class tree_walker;
 
 #include "pt-mat.h"
+#include "symtab.h"
 
 // General cells.
 
@@ -52,7 +53,7 @@
 
   octave_value_list rvalue (int);
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-cmd.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-cmd.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -31,7 +31,7 @@
 // No-op.
 
 tree_command *
-tree_no_op_command::dup (symbol_table *sym_tab)
+tree_no_op_command::dup (symbol_table::scope_id)
 {
   return new tree_no_op_command (orig_cmd, line (), column ());
 }
--- a/src/pt-cmd.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-cmd.h	Fri Dec 28 20:56:58 2007 +0000
@@ -27,10 +27,10 @@
 #include <string>
 
 class tree_walker;
-class symbol_table;
 
 #include "pt.h"
 #include "pt-bp.h"
+#include "symtab.h"
 
 // A base class for commands.
 
@@ -46,7 +46,7 @@
 
   virtual void eval (void) = 0;
 
-  virtual tree_command *dup (symbol_table *) = 0;
+  virtual tree_command *dup (symbol_table::scope_id) = 0;
 
 private:
 
@@ -71,7 +71,7 @@
 
   void eval (void) { MAYBE_DO_BREAKPOINT; }
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-colon.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-colon.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -210,12 +210,12 @@
 }
 
 tree_expression *
-tree_colon_expression::dup (symbol_table *sym_tab)
+tree_colon_expression::dup (symbol_table::scope_id scope)
 {
   tree_colon_expression *new_ce
-    = new tree_colon_expression (op_base ? op_base->dup (sym_tab) : 0,
-				 op_limit ? op_limit->dup (sym_tab) : 0,
-				 op_increment ? op_increment->dup (sym_tab) : 0,
+    = new tree_colon_expression (op_base ? op_base->dup (scope) : 0,
+				 op_limit ? op_limit->dup (scope) : 0,
+				 op_increment ? op_increment->dup (scope) : 0,
 				 line (), column ());
 
   new_ce->copy_base (*new_ce);
--- a/src/pt-colon.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-colon.h	Fri Dec 28 20:56:58 2007 +0000
@@ -33,6 +33,7 @@
 class octave_lvalue;
 
 #include "pt-exp.h"
+#include "symtab.h"
 
 // Colon expressions.
 
@@ -91,7 +92,7 @@
   int line (void) const;
   int column (void) const;
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-const.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-const.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -71,7 +71,7 @@
 }
 
 tree_expression *
-tree_constant::dup (symbol_table *)
+tree_constant::dup (symbol_table::scope_id)
 {
   tree_constant *new_tc
     = new tree_constant (val, orig_text, line (), column ());
--- a/src/pt-const.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-const.h	Fri Dec 28 20:56:58 2007 +0000
@@ -29,14 +29,13 @@
 
 #include "oct-alloc.h"
 
-#include "pt-bp.h"
-#include "pt-exp.h"
-
 class octave_value_list;
-
 class tree_walker;
 
 #include "ov.h"
+#include "pt-bp.h"
+#include "pt-exp.h"
+#include "symtab.h"
 
 class
 tree_constant : public tree_expression
@@ -83,7 +82,7 @@
 
   octave_value_list rvalue (int nargout);
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-decl.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-decl.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -69,10 +69,10 @@
 }
 
 tree_decl_elt *
-tree_decl_elt::dup (symbol_table *sym_tab)
+tree_decl_elt::dup (symbol_table::scope_id scope)
 {
-  return new tree_decl_elt (id ? id->dup (sym_tab) : 0,
-			    expr ? expr->dup (sym_tab) : 0);
+  return new tree_decl_elt (id ? id->dup (scope) : 0,
+			    expr ? expr->dup (scope) : 0);
 }
 
 void
@@ -98,7 +98,7 @@
 }
 
 tree_decl_init_list *
-tree_decl_init_list::dup (symbol_table *sym_tab)
+tree_decl_init_list::dup (symbol_table::scope_id scope)
 {
   tree_decl_init_list *new_dil = new tree_decl_init_list ();
 
@@ -106,7 +106,7 @@
     {
       tree_decl_elt *elt = *p;
 
-      new_dil->append (elt ? elt->dup (sym_tab) : 0);
+      new_dil->append (elt ? elt->dup (scope) : 0);
     }
   
   return new_dil;
@@ -140,7 +140,7 @@
 
   if (id)
     {
-      id->link_to_global ();
+      id->mark_global ();
 
       if (! error_state)
 	{
@@ -169,11 +169,7 @@
   MAYBE_DO_BREAKPOINT;
 
   if (init_list)
-    {
-      init_list->eval (do_init);
-
-      initialized = true;
-    }
+    init_list->eval (do_init);
 
   if (error_state)
     ::error ("evaluating global command near line %d, column %d",
@@ -181,9 +177,9 @@
 }
 
 tree_command *
-tree_global_command::dup (symbol_table *sym_tab)
+tree_global_command::dup (symbol_table::scope_id scope)
 {
-  return new tree_global_command (init_list ? init_list->dup (sym_tab) : 0,
+  return new tree_global_command (init_list ? init_list->dup (scope) : 0,
 				  line (), column ());
 }
 
@@ -223,22 +219,18 @@
 
   // Static variables only need to be marked and initialized once.
 
-  if (init_list && ! initialized)
-    {
-      init_list->eval (do_init);
+  if (init_list)
+    init_list->eval (do_init);
 
-      initialized = true;
-
-      if (error_state)
-	::error ("evaluating static command near line %d, column %d",
-		 line (), column ());
-    }
+  if (error_state)
+    ::error ("evaluating static command near line %d, column %d",
+	     line (), column ());
 }
 
 tree_command *
-tree_static_command::dup (symbol_table *sym_tab)
+tree_static_command::dup (symbol_table::scope_id scope)
 {
-  return new tree_static_command (init_list ? init_list->dup (sym_tab) : 0,
+  return new tree_static_command (init_list ? init_list->dup (scope) : 0,
 				  line (), column ());
 }
 
--- a/src/pt-decl.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-decl.h	Fri Dec 28 20:56:58 2007 +0000
@@ -35,6 +35,7 @@
 #include "oct-lvalue.h"
 #include "pt-cmd.h"
 #include "pt-id.h"
+#include "symtab.h"
 
 // List of expressions that make up a declaration statement.
 
@@ -54,6 +55,8 @@
 
   bool is_defined (void) { return id ? id->is_defined () : false; }
 
+  bool is_variable (void) { return id ? id->is_variable () : false; }
+
   void mark_as_formal_parameter (void)
   {
     if (id)
@@ -75,7 +78,7 @@
 
   tree_expression *expression (void) { return expr; }
 
-  tree_decl_elt *dup (symbol_table *sym_tab);
+  tree_decl_elt *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -115,7 +118,7 @@
 
   void eval (tree_decl_elt::eval_fcn);
 
-  tree_decl_init_list *dup (symbol_table *sym_tab);
+  tree_decl_init_list *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -136,11 +139,11 @@
 public:
 
   tree_decl_command (const std::string& n, int l = -1, int c = -1)
-    : tree_command (l, c), cmd_name (n), initialized (false), init_list (0) { }
+    : tree_command (l, c), cmd_name (n), init_list (0) { }
 
   tree_decl_command (const std::string& n, tree_decl_init_list *t,
 		     int l = -1, int c = -1)
-    : tree_command (l, c), cmd_name (n), initialized (false), init_list (t) { }
+    : tree_command (l, c), cmd_name (n), init_list (t) { }
 
   ~tree_decl_command (void);
 
@@ -155,9 +158,6 @@
   // The name of this command -- global, static, etc.
   std::string cmd_name;
 
-  // TRUE if this command has been evaluated.
-  bool initialized;
-
   // The list of variables or initializers in this declaration command.
   tree_decl_init_list *init_list;
 
@@ -187,7 +187,7 @@
 
   void eval (void);
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
 private:
 
@@ -217,7 +217,7 @@
 
   void eval (void);
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
 private:
 
--- a/src/pt-except.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-except.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -127,10 +127,10 @@
 }
 
 tree_command *
-tree_try_catch_command::dup (symbol_table *sym_tab)
+tree_try_catch_command::dup (symbol_table::scope_id scope)
 {
-  return new tree_try_catch_command (try_code ? try_code->dup (sym_tab) : 0,
-				     catch_code ? catch_code->dup (sym_tab) : 0,
+  return new tree_try_catch_command (try_code ? try_code->dup (scope) : 0,
+				     catch_code ? catch_code->dup (scope) : 0,
 				     lead_comm ? lead_comm->dup () : 0,
 				     mid_comm ? mid_comm->dup () : 0,
 				     trail_comm ? trail_comm->dup () : 0,
@@ -243,11 +243,11 @@
 }
 
 tree_command *
-tree_unwind_protect_command::dup (symbol_table *sym_tab)
+tree_unwind_protect_command::dup (symbol_table::scope_id scope)
 {
   return new tree_unwind_protect_command
-    (unwind_protect_code ? unwind_protect_code->dup (sym_tab) : 0,
-     cleanup_code ? cleanup_code->dup (sym_tab) : 0,
+    (unwind_protect_code ? unwind_protect_code->dup (scope) : 0,
+     cleanup_code ? cleanup_code->dup (scope) : 0,
      lead_comm ? lead_comm->dup () : 0,
      mid_comm ? mid_comm->dup () : 0,
      trail_comm ? trail_comm->dup () : 0,
--- a/src/pt-except.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-except.h	Fri Dec 28 20:56:58 2007 +0000
@@ -30,6 +30,7 @@
 
 #include "comment-list.h"
 #include "pt-cmd.h"
+#include "symtab.h"
 
 // Simple exception handling.
 
@@ -64,7 +65,7 @@
 
   octave_comment_list *trailing_comment (void) { return trail_comm; }
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -126,7 +127,7 @@
 
   octave_comment_list *trailing_comment (void) { return trail_comm; }
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-exp.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-exp.h	Fri Dec 28 20:56:58 2007 +0000
@@ -28,9 +28,9 @@
 
 class octave_value;
 class octave_lvalue;
-class symbol_table;
 
 #include "pt.h"
+#include "symtab.h"
 
 // A base class for expressions.
 
@@ -47,7 +47,7 @@
 
   virtual bool has_magic_end (void) const = 0;
 
-  virtual tree_expression *dup (symbol_table *) = 0;
+  virtual tree_expression *dup (symbol_table::scope_id) = 0;
 
   virtual bool is_constant (void) const { return false; }
 
--- a/src/pt-fcn-handle.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-fcn-handle.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -71,7 +71,7 @@
 }
 
 tree_expression *
-tree_fcn_handle::dup (symbol_table *)
+tree_fcn_handle::dup (symbol_table::scope_id)
 {
   tree_fcn_handle *new_fh = new tree_fcn_handle (nm, line (), column ());
 
@@ -91,28 +91,21 @@
 {
   MAYBE_DO_BREAKPOINT;
 
-  tree_parameter_list *param_list = fcn.parameter_list ();
-  tree_parameter_list *ret_list = fcn.return_list ();
-  tree_statement_list *cmd_list = fcn.body ();
-  symbol_table *sym_tab = fcn.sym_tab ();
-
-  symbol_table *new_sym_tab = sym_tab ? sym_tab->dup () : 0;
+  tree_parameter_list *param_list = parameter_list ();
+  tree_parameter_list *ret_list = return_list ();
+  tree_statement_list *cmd_list = body ();
+  symbol_table::scope_id this_scope = scope ();
 
-  if (new_sym_tab)
-    new_sym_tab->inherit (curr_sym_tab);
-
-  tree_parameter_list *new_param_list
-    = param_list ? param_list->dup (new_sym_tab) : 0;
+  symbol_table::scope_id new_scope = symbol_table::dup_scope (this_scope);
 
-  tree_statement_list *new_cmd_list
-    = cmd_list ? cmd_list->dup (new_sym_tab) : 0;
-
-  tree_parameter_list *new_ret_list
-    = ret_list ? ret_list->dup (new_sym_tab) : 0;
+  if (new_scope > 0)
+    symbol_table::inherit (new_scope, symbol_table::current_scope ());
 
   octave_user_function *uf
-    = new octave_user_function (new_param_list, new_ret_list,
-				new_cmd_list, new_sym_tab);
+    = new octave_user_function (new_scope,
+				param_list ? param_list->dup (new_scope) : 0,
+				ret_list ? ret_list->dup (new_scope) : 0,
+				cmd_list ? cmd_list->dup (new_scope) : 0);
 
   octave_function *curr_fcn = octave_call_stack::current ();
 
@@ -142,23 +135,23 @@
 }
 
 tree_expression *
-tree_anon_fcn_handle::dup (symbol_table *st)
+tree_anon_fcn_handle::dup (symbol_table::scope_id parent_scope)
 {
-  tree_parameter_list *param_list = fcn.parameter_list ();
-  tree_parameter_list *ret_list = fcn.return_list ();
-  tree_statement_list *cmd_list = fcn.body ();
-  symbol_table *sym_tab = fcn.sym_tab ();
+  tree_parameter_list *param_list = parameter_list ();
+  tree_parameter_list *ret_list = return_list ();
+  tree_statement_list *cmd_list = body ();
+  symbol_table::scope_id this_scope = scope ();
 
-  symbol_table *new_sym_tab = sym_tab ? sym_tab->dup () : 0;
+  symbol_table::scope_id new_scope = symbol_table::dup_scope (this_scope);
 
-  if (new_sym_tab)
-    new_sym_tab->inherit (st);
+  if (new_scope > 0)
+    symbol_table::inherit (new_scope, parent_scope);
 
   tree_anon_fcn_handle *new_afh
-    = new tree_anon_fcn_handle (param_list ? param_list->dup (new_sym_tab) : 0,
-				ret_list ? ret_list->dup (new_sym_tab) : 0,
-				cmd_list ? cmd_list->dup (new_sym_tab) : 0,
-				new_sym_tab, line (), column ());
+    = new tree_anon_fcn_handle (param_list ? param_list->dup (new_scope) : 0,
+				ret_list ? ret_list->dup (new_scope) : 0,
+				cmd_list ? cmd_list->dup (new_scope) : 0,
+				new_scope, line (), column ());
 
   new_afh->copy_base (*this);
 
--- a/src/pt-fcn-handle.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-fcn-handle.h	Fri Dec 28 20:56:58 2007 +0000
@@ -30,6 +30,7 @@
 #include "pt-exp.h"
 #include "pt-misc.h"
 #include "pt-stmt.h"
+#include "symtab.h"
 
 class octave_value_list;
 
@@ -37,6 +38,7 @@
 
 #include "ov.h"
 #include "ov-usr-fcn.h"
+#include "symtab.h"
 
 class
 tree_fcn_handle : public tree_expression
@@ -67,7 +69,7 @@
 
   octave_value_list rvalue (int nargout);
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -89,14 +91,15 @@
 public:
 
   tree_anon_fcn_handle (int l = -1, int c = -1)
-    : tree_expression (l, c), fcn () { }
+    : tree_expression (l, c), fcn (0) { }
 
   tree_anon_fcn_handle (tree_parameter_list *pl, tree_parameter_list *rl,
-			tree_statement_list *cl, symbol_table *st,
+			tree_statement_list *cl, symbol_table::scope_id sid,
 			int l = -1, int c = -1)
-    : tree_expression (l, c), fcn (pl, rl, cl, st) { }
+    : tree_expression (l, c),
+      fcn (new octave_user_function (sid, pl, rl, cl)) { }
 
-  ~tree_anon_fcn_handle (void) { }
+  ~tree_anon_fcn_handle (void) { delete fcn; }
 
   bool has_magic_end (void) const { return false; }
 
@@ -106,18 +109,28 @@
 
   octave_value_list rvalue (int nargout);
 
-  tree_parameter_list *parameter_list (void) { return fcn.parameter_list (); }
+  tree_parameter_list *parameter_list (void)
+  {
+    return fcn ? fcn->parameter_list () : 0;
+  }
 
-  tree_statement_list *body (void) { return fcn.body (); }
+  tree_parameter_list *return_list (void)
+  {
+    return fcn ? fcn->return_list () : 0;
+  }
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_statement_list *body (void) { return fcn ? fcn->body () : 0; }
+
+  symbol_table::scope_id scope (void) { return fcn ? fcn->scope () : -1; }
+
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
 private:
 
   // The function.
-  octave_user_function fcn;
+  octave_user_function *fcn;
 
   // No copying!
 
--- a/src/pt-id.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-id.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -39,41 +39,6 @@
 
 // Symbols from the symbol table.
 
-std::string
-tree_identifier::name (void) const
-{
-  std::string retval;
-  if (sym)
-    retval = sym->name ();
-  return retval;
-}
-
-tree_identifier *
-tree_identifier::define (octave_function *f, unsigned int sym_type)
-{
-  int status = sym->define (f, sym_type);
-  return status ? this : 0;
-}
-
-void
-tree_identifier::document (const std::string& s)
-{
-  if (sym)
-    sym->document (s);
-}
-
-bool
-tree_identifier::is_defined (void)
-{
-  return (sym && sym->is_defined ());
-}
-
-bool
-tree_identifier::is_function (void)
-{
-  return (sym && sym->is_function ());
-}
-
 void
 tree_identifier::eval_undefined_error (void)
 {
@@ -87,65 +52,6 @@
 	     name ().c_str (), l, c);
 }
 
-// Try to find a definition for an identifier.  Here's how:
-//
-//   * If the identifier is already defined and is a function defined
-//     in an function file that has been modified since the last time 
-//     we parsed it, parse it again.
-//
-//   * If the identifier is not defined, try to find a builtin
-//     variable or an already compiled function with the same name.
-//
-//   * If the identifier is still undefined, try looking for an
-//     function file to parse.
-//
-//   * On systems that support dynamic linking, we prefer .oct files,
-//     then .mex files, then .m files.
-
-octave_value
-tree_identifier::do_lookup (bool& script_file_executed, bool exec_script)
-{
-  static octave_value foo;
-
-  script_file_executed = lookup (sym, exec_script);
-
-  return script_file_executed ? foo : sym->def ();
-}
-
-void
-tree_identifier::link_to_global (void)
-{
-  if (sym)
-    {
-      if (! sym->is_linked_to_global ())
-	{
-	  if (sym->is_defined () && sym->is_variable ())
-	    {
-	      std::string nm = sym->name ();
-
-	      warning ("value of local variable `%s' may have changed to match global",
-		       nm.c_str ());
-	    }
-
-	  link_to_global_variable (sym);
-	}
-    }
-}
-
-void
-tree_identifier::mark_as_static (void)
-{
-  if (sym)
-    sym->mark_as_static ();
-}
-
-void
-tree_identifier::mark_as_formal_parameter (void)
-{
-  if (sym)
-    sym->mark_as_formal_parameter ();
-}
-
 octave_value_list
 tree_identifier::rvalue (int nargout)
 {
@@ -156,42 +62,41 @@
   if (error_state)
     return retval;
 
-  bool script_file_executed = false;
+  octave_value_list evaluated_args;
+  bool args_evaluated;
 
-  octave_value val = do_lookup (script_file_executed);
+  octave_value val = sym.find (0, string_vector (), evaluated_args,
+			       args_evaluated);
 
-  if (! script_file_executed)
+  if (val.is_defined ())
     {
-      if (val.is_defined ())
+      // GAGME -- this would be cleaner if we required
+      // parens to indicate function calls.
+      //
+      // If this identifier refers to a function, we need to know
+      // whether it is indexed so that we can do the same thing
+      // for `f' and `f()'.  If the index is present, return the
+      // function object and let tree_index_expression::rvalue
+      // handle indexing.  Otherwise, arrange to call the function
+      // here, so that we don't return the function definition as
+      // a value.
+
+      if (val.is_function () && ! is_postfix_indexed ())
 	{
-	  // GAGME -- this would be cleaner if we required
-	  // parens to indicate function calls.
-	  //
-	  // If this identifier refers to a function, we need to know
-	  // whether it is indexed so that we can do the same thing
-	  // for `f' and `f()'.  If the index is present, return the
-	  // function object and let tree_index_expression::rvalue
-	  // handle indexing.  Otherwise, arrange to call the function
-	  // here, so that we don't return the function definition as
-	  // a value.
+	  octave_value_list tmp_args;
 
-	  if (val.is_function () && ! is_postfix_indexed ())
-	    {
-	      octave_value_list tmp_args;
-
-	      retval = val.do_multi_index_op (nargout, tmp_args);
-	    }
-	  else
-	    {
-	      if (print_result () && nargout == 0)
-		val.print_with_name (octave_stdout, name ());
-
-	      retval = val;
-	    }
+	  retval = val.do_multi_index_op (nargout, tmp_args);
 	}
       else
-	eval_undefined_error ();
+	{
+	  if (print_result () && nargout == 0)
+	    val.print_with_name (octave_stdout, name ());
+
+	  retval = val;
+	}
     }
+  else
+    eval_undefined_error ();
 
   return retval;
 }
@@ -214,15 +119,21 @@
 {
   MAYBE_DO_BREAKPOINT;
 
-  return sym->variable_reference ();
+  return octave_lvalue (&(sym.varref ()));
 }
 
 tree_identifier *
-tree_identifier::dup (symbol_table *sym_tab)
+tree_identifier::dup (symbol_table::scope_id scope)
 {
-  symbol_record *sr = (sym_tab && sym) ? sym_tab->lookup (sym->name ()) : 0;
+  // The new tree_identifier object contains a symbol_record
+  // entry from the duplicated scope.
 
-  tree_identifier *new_id = new tree_identifier (sr, line (), column ());
+  // FIXME -- is this the best way?
+  symbol_table::symbol_record new_sym
+    = symbol_table::find_symbol (sym.name (), scope);
+
+  tree_identifier *new_id
+    = new tree_identifier (new_sym, line (), column ());
 
   new_id->copy_base (*this);
 
--- a/src/pt-id.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-id.h	Fri Dec 28 20:56:58 2007 +0000
@@ -30,11 +30,11 @@
 class octave_value;
 class octave_value_list;
 class octave_function;
-class symbol_record;
 
 class tree_walker;
 
 #include "pt-exp.h"
+#include "symtab.h"
 
 // Symbols from the symbol table.
 
@@ -46,9 +46,9 @@
 public:
 
   tree_identifier (int l = -1, int c = -1)
-    : tree_expression (l, c), sym (0) { }
+    : tree_expression (l, c), sym () { }
 
-  tree_identifier (symbol_record *s, int l = -1, int c = -1)
+  tree_identifier (const symbol_table::symbol_record& s, int l = -1, int c = -1)
     : tree_expression (l, c), sym (s) { }
 
   ~tree_identifier (void) { }
@@ -57,24 +57,48 @@
 
   bool is_identifier (void) const { return true; }
 
-  std::string name (void) const;
+  std::string name (void) const { return sym.name (); }
 
-  tree_identifier *define (octave_function *f, unsigned int sym_type);
+  bool is_defined (void) { return sym.is_defined (); }
+
+  bool is_variable (void) { return sym.is_variable (); }
 
-  void document (const std::string& s);
-
-  bool is_defined (void);
-
-  bool is_function (void);
+  // Try to find a definition for an identifier.  Here's how:
+  //
+  //   * If the identifier is already defined and is a function defined
+  //     in an function file that has been modified since the last time 
+  //     we parsed it, parse it again.
+  //
+  //   * If the identifier is not defined, try to find a builtin
+  //     variable or an already compiled function with the same name.
+  //
+  //   * If the identifier is still undefined, try looking for an
+  //     function file to parse.
+  //
+  //   * On systems that support dynamic linking, we prefer .oct files,
+  //     then .mex files, then .m files.
 
   octave_value
-  do_lookup (bool& script_file_executed, bool exec_script = true);
-
-  void link_to_global (void);
+  do_lookup (bool& script_file_executed, bool exec_script = true)
+  {
+    // FIXME -- SYMTAB: what about executing script files?
+    octave_value_list evaluated_args;
+    bool args_evaluated;
+    return sym.find (0, string_vector (), evaluated_args, args_evaluated);
+  }
 
-  void mark_as_static (void);
+  octave_value
+  do_lookup (tree_argument_list *args, const string_vector& arg_names,
+	     octave_value_list& evaluated_args, bool& args_evaluated)
+  {
+    return sym.find (args, arg_names, evaluated_args, args_evaluated);
+  }
 
-  void mark_as_formal_parameter (void);
+  void mark_global (void) { sym.mark_global (); }
+
+  void mark_as_static (void) { sym.init_persistent (); }
+
+  void mark_as_formal_parameter (void) { sym.mark_formal (); }
 
   // We really need to know whether this symbol referst to a variable
   // or a function, but we may not know that yet.
@@ -89,14 +113,14 @@
 
   void eval_undefined_error (void);
 
-  tree_identifier *dup (symbol_table *sym_tab);
+  tree_identifier *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
 private:
 
   // The symbol record that this identifier references.
-  symbol_record *sym;
+  symbol_table::symbol_record sym;
 
   // No copying!
 
--- a/src/pt-idx.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-idx.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -34,6 +34,7 @@
 #include "pager.h"
 #include "pt-arg-list.h"
 #include "pt-bp.h"
+#include "pt-id.h"
 #include "pt-idx.h"
 #include "pt-walk.h"
 #include "utils.h"
@@ -219,9 +220,8 @@
 {
   int n = args.size ();
 
-  // FIXME -- why not just make these Cell objects?
-  octave_value_list subs_list (n, octave_value ());
-  octave_value_list type_list (n, octave_value ());
+  Cell type_field (n, 1);
+  Cell subs_field (n, 1);
 
   std::list<tree_argument_list *>::const_iterator p_args = args.begin ();
   std::list<string_vector>::const_iterator p_arg_nm = arg_nm.begin ();
@@ -234,16 +234,16 @@
       switch (type[i])
 	{
 	case '(':
-	  subs_list(i) = make_subs_cell (*p_args, *p_arg_nm);
+	  subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
 	  break;
 
 	case '{':
-	  subs_list(i) = make_subs_cell (*p_args, *p_arg_nm);
+	  subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
 	  break;
 
 	case '.':
 	  {
-	    subs_list(i) = get_struct_index (p_arg_nm, p_dyn_field);
+	    subs_field(i) = get_struct_index (p_arg_nm, p_dyn_field);
 
 	    if (error_state)
 	      eval_error ();
@@ -262,8 +262,8 @@
       p_dyn_field++;
     }
 
-  m.assign ("subs", Cell (subs_list));
-  m.assign ("type", Cell (type_list));
+  m.assign ("type", type_field);
+  m.assign ("subs", subs_field);
 
   return m;
 }
@@ -276,11 +276,38 @@
   if (error_state)
     return retval;
 
-  octave_value first_expr_val = expr->rvalue ();
-  octave_value tmp = first_expr_val;
+  octave_value first_expr_val;
+
+  octave_value_list first_args;
+
+  bool have_args = false;
+
+  if (expr->is_identifier () && type[0] == '(')
+    {
+      tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
+
+      if (! (id->is_variable () || args.empty ()))
+	{
+	  tree_argument_list *al = *(args.begin ());
+
+	  size_t n = al ? al->length () : 0;
+
+	  if (n > 0)
+	    {
+	      string_vector anm = *(arg_nm.begin ());
+
+	      first_expr_val = id->do_lookup  (al, anm, first_args, have_args);
+	    }
+	}
+    }
 
   if (! error_state)
     {
+      if (first_expr_val.is_undefined ())
+	first_expr_val = expr->rvalue ();
+
+      octave_value tmp = first_expr_val;
+
       std::list<octave_value_list> idx;
 
       int n = args.size ();
@@ -304,11 +331,11 @@
 		  // and we are looking at the argument list that
 		  // contains the second (or third, etc.) "end" token,
 		  // so we must evaluate everything up to the point of
-		  // that argument list so we pass the appropiate
+		  // that argument list so we can pass the appropriate
 		  // value to the built-in __end__ function.
 
 		  octave_value_list tmp_list
-		    = first_expr_val.subsref (type, idx, nargout);
+		    = first_expr_val.subsref (type.substr (0, i), idx, nargout);
 
 		  tmp = tmp_list(0);
 
@@ -320,7 +347,13 @@
 	  switch (type[i])
 	    {
 	    case '(':
-	      idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
+	      if (have_args)
+		{
+		  idx.push_back (first_args);
+		  have_args = false;
+		}
+	      else
+		idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
 	      break;
 
 	    case '{':
@@ -415,11 +448,11 @@
 		  // and we are looking at the argument list that
 		  // contains the second (or third, etc.) "end" token,
 		  // so we must evaluate everything up to the point of
-		  // that argument list so we pass the appropiate
+		  // that argument list so we pass the appropriate
 		  // value to the built-in __end__ function.
 
 		  octave_value_list tmp_list
-		    = first_retval_object.subsref (type, idx, 1);
+		    = first_retval_object.subsref (type.substr (0, i), idx, 1);
 
 		  tmp = tmp_list(0);
 
@@ -656,12 +689,12 @@
 }
 
 tree_index_expression *
-tree_index_expression::dup (symbol_table *sym_tab)
+tree_index_expression::dup (symbol_table::scope_id scope)
 {
   tree_index_expression *new_idx_expr
     = new tree_index_expression (line (), column ());
 
-  new_idx_expr->expr = expr ? expr->dup (sym_tab) : 0;
+  new_idx_expr->expr = expr ? expr->dup (scope) : 0;
 
   std::list<tree_argument_list *> new_args;
 
@@ -671,7 +704,7 @@
     {
       tree_argument_list *elt = *p;
 
-      new_args.push_back (elt ? elt->dup (sym_tab) : 0);
+      new_args.push_back (elt ? elt->dup (scope) : 0);
     }
 
   new_idx_expr->args = new_args;
@@ -688,7 +721,7 @@
     {
       tree_expression *elt = *p;
 
-      new_dyn_field.push_back (elt ? elt->dup (sym_tab) : 0);
+      new_dyn_field.push_back (elt ? elt->dup (scope) : 0);
     }
 
   new_idx_expr->dyn_field = new_dyn_field;
--- a/src/pt-idx.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-idx.h	Fri Dec 28 20:56:58 2007 +0000
@@ -38,6 +38,7 @@
 #include "str-vec.h"
 
 #include "pt-exp.h"
+#include "symtab.h"
 
 // Index expressions.
 
@@ -89,7 +90,7 @@
 
   void eval_error (void) const;
 
-  tree_index_expression *dup (symbol_table *sym_tab);
+  tree_index_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-jump.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-jump.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -49,7 +49,7 @@
 }
 
 tree_command *
-tree_break_command::dup (symbol_table *)
+tree_break_command::dup (symbol_table::scope_id)
 {
   return new tree_break_command (line (), column ());
 }
@@ -75,7 +75,7 @@
 }
 
 tree_command *
-tree_continue_command::dup (symbol_table *)
+tree_continue_command::dup (symbol_table::scope_id)
 {
   return new tree_continue_command (line (), column ());
 }
@@ -101,7 +101,7 @@
 }
 
 tree_command *
-tree_return_command::dup (symbol_table *)
+tree_return_command::dup (symbol_table::scope_id)
 {
   return new tree_return_command (line (), column ());
 }
--- a/src/pt-jump.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-jump.h	Fri Dec 28 20:56:58 2007 +0000
@@ -26,6 +26,7 @@
 class tree_walker;
 
 #include "pt-cmd.h"
+#include "symtab.h"
 
 // Break.
 
@@ -41,7 +42,7 @@
 
   void eval (void);
 
-  tree_command *dup (symbol_table *);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -70,7 +71,7 @@
 
   void eval (void);
 
-  tree_command *dup (symbol_table *);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -99,7 +100,7 @@
 
   void eval (void);
 
-  tree_command *dup (symbol_table *);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-loop.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-loop.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -126,10 +126,10 @@
 }
 
 tree_command *
-tree_while_command::dup (symbol_table *sym_tab)
+tree_while_command::dup (symbol_table::scope_id scope)
 {
-  return new tree_while_command (expr ? expr->dup (sym_tab) : 0,
-				 list ? list->dup (sym_tab) : 0,
+  return new tree_while_command (expr ? expr->dup (scope) : 0,
+				 list ? list->dup (scope) : 0,
 				 lead_comm ? lead_comm->dup () : 0,
 				 trail_comm ? trail_comm->dup (): 0,
 				 line (), column ());
@@ -189,10 +189,10 @@
 }
 
 tree_command *
-tree_do_until_command::dup (symbol_table *sym_tab)
+tree_do_until_command::dup (symbol_table::scope_id scope)
 {
-  return new tree_do_until_command (expr ? expr->dup (sym_tab) : 0,
-				    list ? list->dup (sym_tab) : 0,
+  return new tree_do_until_command (expr ? expr->dup (scope) : 0,
+				    list ? list->dup (scope) : 0,
 				    lead_comm ? lead_comm->dup () : 0,
 				    trail_comm ? trail_comm->dup (): 0,
 				    line (), column ());
@@ -487,11 +487,11 @@
 }
 
 tree_command *
-tree_simple_for_command::dup (symbol_table *sym_tab)
+tree_simple_for_command::dup (symbol_table::scope_id scope)
 {
-  return new tree_simple_for_command (lhs ? lhs->dup (sym_tab) : 0,
-				      expr ? expr->dup (sym_tab) : 0,
-				      list ? list->dup (sym_tab) : 0,
+  return new tree_simple_for_command (lhs ? lhs->dup (scope) : 0,
+				      expr ? expr->dup (scope) : 0,
+				      list ? list->dup (scope) : 0,
 				      lead_comm ? lead_comm->dup () : 0,
 				      trail_comm ? trail_comm->dup () : 0,
 				      line (), column ());
@@ -608,11 +608,11 @@
 }
 
 tree_command *
-tree_complex_for_command::dup (symbol_table *sym_tab)
+tree_complex_for_command::dup (symbol_table::scope_id scope)
 {
-  return new tree_complex_for_command (lhs ? lhs->dup (sym_tab) : 0,
-				      expr ? expr->dup (sym_tab) : 0,
-				      list ? list->dup (sym_tab) : 0,
+  return new tree_complex_for_command (lhs ? lhs->dup (scope) : 0,
+				      expr ? expr->dup (scope) : 0,
+				      list ? list->dup (scope) : 0,
 				      lead_comm ? lead_comm->dup () : 0,
 				      trail_comm ? trail_comm->dup () : 0,
 				      line (), column ());
--- a/src/pt-loop.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-loop.h	Fri Dec 28 20:56:58 2007 +0000
@@ -35,6 +35,7 @@
 
 #include "comment-list.h"
 #include "pt-cmd.h"
+#include "symtab.h"
 
 // TRUE means we are evaluating some kind of looping construct.
 extern bool evaluating_looping_command;
@@ -78,7 +79,7 @@
 
   octave_comment_list *trailing_comment (void) { return trail_comm; }
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -133,7 +134,7 @@
 
   void eval_error (void);
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -181,7 +182,7 @@
 
   octave_comment_list *trailing_comment (void) { return trail_comm; }
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -245,7 +246,7 @@
 
   octave_comment_list *trailing_comment (void) { return trail_comm; }
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-mat.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-mat.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -951,7 +951,7 @@
 }
 
 tree_expression *
-tree_matrix::dup (symbol_table *sym_tab)
+tree_matrix::dup (symbol_table::scope_id scope)
 {
   tree_matrix *new_matrix = new tree_matrix (0, line (), column ());
 
@@ -959,7 +959,7 @@
     {
       tree_argument_list *elt = *p;
 
-      new_matrix->append (elt ? elt->dup (sym_tab) : 0);
+      new_matrix->append (elt ? elt->dup (scope) : 0);
     }
 
   new_matrix->copy_base (*this);
--- a/src/pt-mat.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-mat.h	Fri Dec 28 20:56:58 2007 +0000
@@ -34,6 +34,7 @@
 
 #include "base-list.h"
 #include "pt-exp.h"
+#include "symtab.h"
 
 // General matrices.  This allows us to construct matrices from
 // other matrices, variables, and functions.
@@ -63,7 +64,7 @@
 
   octave_value_list rvalue (int nargout);
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-misc.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-misc.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -75,7 +75,7 @@
 
       tree_decl_elt *elt = *p;
 
-      if (! elt->is_defined ())
+      if (! elt->is_variable ())
 	{
 	  if (! warned)
 	    {
@@ -177,7 +177,7 @@
     {
       tree_decl_elt *elt = *p;
 
-      if (! elt->is_defined ())
+      if (! elt->is_variable ())
 	{
 	  status = false;
 	  break;
@@ -188,7 +188,7 @@
 }
 
 tree_parameter_list *
-tree_parameter_list::dup (symbol_table *sym_tab)
+tree_parameter_list::dup (symbol_table::scope_id scope)
 {
   tree_parameter_list *new_list = new tree_parameter_list ();
 
@@ -199,7 +199,7 @@
     {
       tree_decl_elt *elt = *p;
 
-      new_list->append (elt->dup (sym_tab));
+      new_list->append (elt->dup (scope));
     }
 
   return new_list;
@@ -224,7 +224,7 @@
 }
 
 tree_return_list *
-tree_return_list::dup (symbol_table *sym_tab)
+tree_return_list::dup (symbol_table::scope_id scope)
 {
   tree_return_list *new_list = new tree_return_list ();
 
@@ -232,7 +232,7 @@
     {
       tree_index_expression *elt = *p;
 
-      new_list->append (elt->dup (sym_tab));
+      new_list->append (elt->dup (scope));
     }
 
   return new_list;
--- a/src/pt-misc.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-misc.h	Fri Dec 28 20:56:58 2007 +0000
@@ -37,6 +37,7 @@
 
 #include "base-list.h"
 #include "pt-decl.h"
+#include "symtab.h"
 
 // Parameter lists.  Used to hold the list of input and output
 // parameters in a function definition.  Elements are identifiers
@@ -76,7 +77,7 @@
 
   octave_value_list convert_to_const_vector (const Cell& varargout);
 
-  tree_parameter_list *dup (symbol_table *sym_tab);
+  tree_parameter_list *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -105,7 +106,7 @@
 
   ~tree_return_list (void);
 
-  tree_return_list *dup (symbol_table *sym_tab);
+  tree_return_list *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-select.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-select.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -60,10 +60,10 @@
 }
 
 tree_if_clause *
-tree_if_clause::dup (symbol_table *sym_tab)
+tree_if_clause::dup (symbol_table::scope_id scope)
 {
-  return new tree_if_clause (expr ? expr->dup (sym_tab) : 0,
-			     list ? list->dup (sym_tab) : 0,
+  return new tree_if_clause (expr ? expr->dup (scope) : 0,
+			     list ? list->dup (scope) : 0,
 			     lead_comm ? lead_comm->dup () : 0);
 }
 
@@ -88,7 +88,7 @@
 }
 
 tree_if_command_list *
-tree_if_command_list::dup (symbol_table *sym_tab)
+tree_if_command_list::dup (symbol_table::scope_id scope)
 {
   tree_if_command_list *new_icl = new tree_if_command_list ();
 
@@ -96,7 +96,7 @@
     {
       tree_if_clause *elt = *p;
 
-      new_icl->append (elt ? elt->dup (sym_tab) : 0);
+      new_icl->append (elt ? elt->dup (scope) : 0);
     }
 
   return new_icl;
@@ -129,9 +129,9 @@
 }
 
 tree_command *
-tree_if_command::dup (symbol_table *sym_tab)
+tree_if_command::dup (symbol_table::scope_id scope)
 {
-  return new tree_if_command (list ? list->dup (sym_tab) : 0,
+  return new tree_if_command (list ? list->dup (scope) : 0,
 			      lead_comm ? lead_comm->dup () : 0,
 			      trail_comm ? trail_comm->dup () : 0,
 			      line (), column ());
@@ -243,10 +243,10 @@
 }
 
 tree_switch_case *
-tree_switch_case::dup (symbol_table *sym_tab)
+tree_switch_case::dup (symbol_table::scope_id scope)
 {
-  return new tree_switch_case (label ? label->dup (sym_tab) : 0,
-			       list ? list->dup (sym_tab) : 0,
+  return new tree_switch_case (label ? label->dup (scope) : 0,
+			       list ? list->dup (scope) : 0,
 			       lead_comm ? lead_comm->dup () : 0);
 }
 
@@ -271,7 +271,7 @@
 }
 
 tree_switch_case_list *
-tree_switch_case_list::dup (symbol_table *sym_tab)
+tree_switch_case_list::dup (symbol_table::scope_id scope)
 {
   tree_switch_case_list *new_scl = new tree_switch_case_list ();
 
@@ -279,7 +279,7 @@
     {
       tree_switch_case *elt = *p;
 
-      new_scl->append (elt ? elt->dup (sym_tab) : 0);
+      new_scl->append (elt ? elt->dup (scope) : 0);
     }
   
   return new_scl;
@@ -332,10 +332,10 @@
 }
 
 tree_command *
-tree_switch_command::dup (symbol_table *sym_tab)
+tree_switch_command::dup (symbol_table::scope_id scope)
 {
-  return new tree_switch_command (expr ? expr->dup (sym_tab) : 0,
-				  list ? list->dup (sym_tab) : 0,
+  return new tree_switch_command (expr ? expr->dup (scope) : 0,
+				  list ? list->dup (scope) : 0,
 				  lead_comm ? lead_comm->dup () : 0,
 				  trail_comm ? trail_comm->dup () : 0,
 				  line (), column ());
--- a/src/pt-select.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-select.h	Fri Dec 28 20:56:58 2007 +0000
@@ -32,6 +32,7 @@
 #include "base-list.h"
 #include "comment-list.h"
 #include "pt-cmd.h"
+#include "symtab.h"
 
 // If.
 
@@ -63,7 +64,7 @@
 
   octave_comment_list *leading_comment (void) { return lead_comm; }
 
-  tree_if_clause *dup (symbol_table *sym_tab);
+  tree_if_clause *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -106,7 +107,7 @@
 
   void eval (void);
 
-  tree_if_command_list *dup (symbol_table *sym_tab);
+  tree_if_command_list *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -141,7 +142,7 @@
 
   octave_comment_list *trailing_comment (void) { return trail_comm; }
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -196,7 +197,7 @@
 
   octave_comment_list *leading_comment (void) { return lead_comm; }
 
-  tree_switch_case *dup (symbol_table *sym_tab);
+  tree_switch_case *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -239,7 +240,7 @@
 
   void eval (const octave_value& val);
 
-  tree_switch_case_list *dup (symbol_table *sym_tab);
+  tree_switch_case_list *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -281,7 +282,7 @@
 
   octave_comment_list *trailing_comment (void) { return trail_comm; }
 
-  tree_command *dup (symbol_table *sym_tab);
+  tree_command *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-stmt.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-stmt.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -115,26 +115,19 @@
 
 	  bool do_bind_ans = false;
 
-	  bool script_file_executed = false;
-
 	  if (expr->is_identifier ())
 	    {
 	      tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
 
-	      id->do_lookup (script_file_executed, true);
-
-	      do_bind_ans = id->is_function ();
+	      do_bind_ans = (! id->is_variable ());
 	    }
 	  else
 	    do_bind_ans = (! expr->is_assignment_expression ());
 
-	  if (! script_file_executed)
-	    {
-	      retval = expr->rvalue (nargout);
+	  retval = expr->rvalue (nargout);
 
-	      if (do_bind_ans && ! (error_state || retval.empty ()))
-		bind_ans (retval(0), pf);
-	    }
+	  if (do_bind_ans && ! (error_state || retval.empty ()))
+	    bind_ans (retval(0), pf);
 	}
 
       unwind_protect::run ();
@@ -144,13 +137,13 @@
 }
 
 tree_statement *
-tree_statement::dup (symbol_table *sym_tab)
+tree_statement::dup (symbol_table::scope_id scope)
 {
   tree_statement *new_stmt = new tree_statement ();
 
-  new_stmt->cmd = cmd ? cmd->dup (sym_tab) : 0;
+  new_stmt->cmd = cmd ? cmd->dup (scope) : 0;
 
-  new_stmt->expr = expr ? expr->dup (sym_tab) : 0;
+  new_stmt->expr = expr ? expr->dup (scope) : 0;
 
   new_stmt->comm = comm ? comm->dup () : 0;
 
@@ -268,7 +261,7 @@
 }
 
 tree_statement_list *
-tree_statement_list::dup (symbol_table *sym_tab)
+tree_statement_list::dup (symbol_table::scope_id scope)
 {
   tree_statement_list *new_list = new tree_statement_list ();
 
@@ -278,7 +271,7 @@
     {
       tree_statement *elt = *p;
 
-      new_list->append (elt ? elt->dup (sym_tab) : 0);
+      new_list->append (elt ? elt->dup (scope) : 0);
     }
 
   return new_list;
--- a/src/pt-stmt.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-stmt.h	Fri Dec 28 20:56:58 2007 +0000
@@ -33,6 +33,7 @@
 
 #include "base-list.h"
 #include "comment-list.h"
+#include "symtab.h"
 
 // A statement is either a command to execute or an expression to
 // evaluate.
@@ -82,7 +83,7 @@
 
   void set_expression (tree_expression *e) { expr = e; }
 
-  tree_statement *dup (symbol_table *sym_tab);
+  tree_statement *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -141,7 +142,7 @@
 
   octave_value_list list_breakpoints (void);
 
-  tree_statement_list *dup (symbol_table *sym_tab);
+  tree_statement_list *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/pt-unop.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-unop.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -121,10 +121,10 @@
 }
 
 tree_expression *
-tree_prefix_expression::dup (symbol_table *sym_tab)
+tree_prefix_expression::dup (symbol_table::scope_id scope)
 {
   tree_prefix_expression *new_pe
-    = new tree_prefix_expression (op ? op->dup (sym_tab) : 0,
+    = new tree_prefix_expression (op ? op->dup (scope) : 0,
 				  line (), column (), etype);
 
   new_pe->copy_base (*this);
@@ -218,10 +218,10 @@
 }
 
 tree_expression *
-tree_postfix_expression::dup (symbol_table *sym_tab)
+tree_postfix_expression::dup (symbol_table::scope_id scope)
 {
   tree_postfix_expression *new_pe
-    = new tree_postfix_expression (op ? op->dup (sym_tab) : 0,
+    = new tree_postfix_expression (op ? op->dup (scope) : 0,
 				   line (), column (), etype);
 
   new_pe->copy_base (*this);
--- a/src/pt-unop.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/pt-unop.h	Fri Dec 28 20:56:58 2007 +0000
@@ -33,6 +33,7 @@
 class octave_lvalue;
 
 #include "pt-exp.h"
+#include "symtab.h"
 
 // Unary expressions.
 
@@ -103,7 +104,7 @@
 
   void eval_error (void);
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
@@ -141,7 +142,7 @@
 
   void eval_error (void);
 
-  tree_expression *dup (symbol_table *sym_tab);
+  tree_expression *dup (symbol_table::scope_id scope);
 
   void accept (tree_walker& tw);
 
--- a/src/symtab.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/symtab.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -2,7 +2,7 @@
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
               2002, 2003, 2004, 2005, 2006, 2007 John W. Eaton
-
+  
 This file is part of Octave.
 
 Octave is free software; you can redistribute it and/or modify it
@@ -25,1066 +25,167 @@
 #include <config.h>
 #endif
 
-#include <cassert>
-#include <cctype>
-#include <climits>
-#include <cstdio>
-
-#include <iomanip>
-#include <fstream>
-#include <sstream>
-
-#include "glob-match.h"
-#include "str-vec.h"
+#include "oct-env.h"
+#include "oct-time.h"
+#include "file-ops.h"
+#include "file-stat.h"
 
 #include "defun.h"
-#include "error.h"
-#include "oct-lvalue.h"
-#include "ov.h"
-#include "pt-pr-code.h"
+#include "dirfns.h"
+#include "input.h"
+#include "load-path.h"
 #include "symtab.h"
+#include "ov-fcn.h"
+#include "pager.h"
+#include "parse.h"
+#include "pt-arg-list.h"
+#include "toplev.h"
+#include "unwind-prot.h"
 #include "utils.h"
-#include "variables.h"
-#include "ov-usr-fcn.h"
-#include "toplev.h"
+
+symbol_table *symbol_table::instance = 0;
 
-#include "gripes.h"
-#include "lo-mappers.h"
+std::map<symbol_table::scope_id, symbol_table*> symbol_table::all_instances;
 
-#include "parse.h"
+std::map<std::string, symbol_table::fcn_info> symbol_table::fcn_table;
 
-unsigned long int symbol_table::symtab_count = 0;
+const symbol_table::scope_id symbol_table::xglobal_scope = 0;
+const symbol_table::scope_id symbol_table::xtop_scope = 1;
 
-// Should variables be allowed to hide functions of the same name?  A
-// positive value means yes.  A negative value means yes, but print a
-// warning message.  Zero means it should be considered an error.
-static int Vvariables_can_hide_functions = 1;
+symbol_table::scope_id symbol_table::xcurrent_scope = 1;
+symbol_table::scope_id symbol_table::xcurrent_caller_scope = -1;
 
-// Nonzero means we print debugging info about symbol table lookups.
-static bool Vdebug_symtab_lookups = false;
+symbol_table::scope_id symbol_table::xparent_scope = -1;
+
+std::deque<symbol_table::scope_id> symbol_table::scope_stack;
 
-// Defines layout for the whos/who -long command
-std::string Vwhos_line_format
-  = "  %p:4; %ln:6; %cs:16:6:8:1;  %rb:12;  %lc:-1;\n";
-
-octave_allocator
-symbol_record::symbol_def::allocator (sizeof (symbol_record::symbol_def));
+symbol_table::scope_id symbol_table::next_available_scope = 2;
+std::set<symbol_table::scope_id> symbol_table::scope_ids_in_use;
+std::set<symbol_table::scope_id> symbol_table::scope_ids_free_list;
 
-#define SYMBOL_DEF symbol_record::symbol_def
-
-std::string
-SYMBOL_DEF::type_as_string (void) const
-{
-  std::string retval = "<unknown type>";
+// Should Octave always check to see if function files have changed
+// since they were last compiled?
+static int Vignore_function_time_stamp = 1;
 
-  if (is_user_variable ())
-    retval = "user-defined variable";
-  else if (is_command ())
-    retval = "built-in command";
-  else if (is_mapper_function ())
-    retval = "built-in mapper function";
-  else if (is_user_function ())
-    retval = "user-defined function";
-  else if (is_builtin_function ())
-    retval = "built-in function";
-  else if (is_dld_function ())
-    retval = "dynamically-linked function";
-  else if (is_mex_function ())
-    retval = "dynamically-linked mex function";
+octave_value
+symbol_table::symbol_record::find (tree_argument_list *args,
+				   const string_vector& arg_names,
+				   octave_value_list& evaluated_args,
+				   bool& args_evaluated) const
+{
+  octave_value retval;
 
-  return retval;
+  if (is_global ())
+    return symbol_table::varref (name (), symbol_table::xglobal_scope);
+  else
+    {
+      octave_value val = varval ();
+
+      if (val.is_defined ())
+	return val;
+    }
+
+  return symbol_table::find_function (name (), args, arg_names,
+				      evaluated_args, args_evaluated);
 }
 
-void
-SYMBOL_DEF::type (std::ostream& os, const std::string& name, bool pr_type_info,
-		  bool quiet, bool pr_orig_txt)
-{
-  if (is_user_function ())
-    {
-      octave_function *defn = definition.function_value ();
-
-      std::string fn = defn ? defn->fcn_file_name () : std::string ();
-
-      if (pr_orig_txt && ! fn.empty ())
-	{
-	  std::ifstream fs (fn.c_str (), std::ios::in);
-
-	  if (fs)
-	    {
-	      if (pr_type_info && ! quiet)
-		os << name << " is the " << type_as_string ()
-		   << " defined from: " << fn << "\n\n";
-
-	      char ch;
-
-	      while (fs.get (ch))
-		os << ch;
-	    }
-	  else
-	    os << "unable to open `" << fn << "' for reading!\n";
-	}
-      else
-	{
-	  if (pr_type_info && ! quiet)
-	    os << name << " is a " << type_as_string () << ":\n\n";
-
-	  tree_print_code tpc (os, "", pr_orig_txt);
-
-	  defn->accept (tpc);
-	}
-    }
-  else if (is_user_variable ())
-    {
-      if (pr_type_info && ! quiet)
-	os << name << " is a " << type_as_string () << "\n";
-
-      definition.print_raw (os, true);
-
-      if (pr_type_info)
-	os << "\n";
-    }
-  else
-    os << name << " is a " << type_as_string () << "\n";
-}
-
-std::string
-SYMBOL_DEF::which (const std::string& name)
-{
-  std::string retval;
-
-  if (is_user_function () || is_dld_function () || is_mex_function ())
-    {
-      octave_function *defn = definition.function_value ();
-
-      if (defn)
-	retval = defn->fcn_file_name ();
-    }
-  else
-    retval = name + " is a " + type_as_string ();
+// Check the load path to see if file that defined this is still
+// visible.  If the file is no longer visible, then erase the
+// definition and move on.  If the file is visible, then we also
+// need to check to see whether the file has changed since the the
+// function was loaded/parsed.  However, this check should only
+// happen once per prompt (for files found from relative path
+// elements, we also check if the working directory has changed
+// since the last time the function was loaded/parsed).
+//
+// FIXME -- perhaps this should be done for all loaded functions when
+// the prompt is printed or the directory has changed, and then we
+// would not check for it when finding symbol definitions.
 
-  return retval;
-}
-
-void
-SYMBOL_DEF::which (std::ostream& os, const std::string& name)
-{
-  os << name;
-
-  if (is_user_function () || is_dld_function () || is_mex_function ())
-    {
-      octave_function *defn = definition.function_value ();
-
-      std::string fn = defn ? defn->fcn_file_name () : std::string ();
-
-      if (! fn.empty ())
-	{
-	  os << " is the " << type_as_string () << " from the file\n"
-	     << fn << "\n";
-
-	  return;
-	}
-    }
-
-  os << " is a " << type_as_string () << "\n";
-}
-
-void
-SYMBOL_DEF::document (const std::string& h)
-{
-  help_string = h;
-
-  if (is_function ())
-    {
-      octave_function *defn = definition.function_value ();
-
-      if (defn)
-	defn->document (h);
-    }
-}
-
-
-void
-SYMBOL_DEF::print_info (std::ostream& os, const std::string& prefix) const
-{
-  os << prefix << "symbol_def::count: " << count << "\n";
-
-  definition.print_info (os, prefix + "  ");
-}
-
-// Individual records in a symbol table.
-
-void
-symbol_record::rename (const std::string& new_name)
-{
-  if (! read_only_error ("rename"))
-    nm = new_name;
-}
-
-void
-symbol_record::define (const octave_value& v, unsigned int sym_type)
-{
-  if (! (is_variable () && read_only_error ("redefine")))
-    definition->define (v, sym_type);
-}
-
-bool
-symbol_record::define (octave_function *f, unsigned int sym_type)
+static inline bool
+out_of_date_check_internal (octave_value& function)
 {
   bool retval = false;
 
-  if (! read_only_error ("redefine"))
-    {
-      maybe_delete_def ();
-
-      octave_value tmp (f);
-
-      definition = new symbol_def (tmp, sym_type);
-
-      retval = true;
-    }
-
-  return retval;
-}
-
-void
-symbol_record::clear (void)
-{
-  if (is_defined ())
-    {
-      if (! (tagged_static || is_eternal ()))
-	{
-	  while (! aliases_to_clear.empty ())
-	    {
-	      symbol_record *sr = aliases_to_clear.top ();
-	      aliases_to_clear.pop ();
-	      sr->clear ();
-	    }
-
-	  maybe_delete_def ();
-
-	  definition = new symbol_def ();
-	}
-
-      if (linked_to_global)
-	linked_to_global = 0;
-    }
-}
-
-void
-symbol_record::alias (symbol_record *s, bool mark_to_clear)
-{
-  chg_fcn = s->chg_fcn;
-
-  maybe_delete_def ();
-
-  if (mark_to_clear)
-    s->push_alias_to_clear (this);
-
-  definition = s->definition;
-
-  definition->count++;
-}
-
-void
-symbol_record::mark_as_formal_parameter (void)
-{
-  if (is_linked_to_global ())
-    error ("can't mark global variable `%s' as function parameter",
-	   nm.c_str ());
-  else if (is_static ())
-    error ("can't mark static variable `%s' as function parameter",
-	   nm.c_str ());
-  else
-    formal_param = 1;
-}
-
-void
-symbol_record::mark_as_automatic_variable (void)
-{
-  if (is_linked_to_global ())
-    error ("can't mark global variable `%s' as automatic variable",
-	   nm.c_str ());
-  else if (is_static ())
-    error ("can't mark static variable `%s' as automatic variable",
-	   nm.c_str ());
-  else
-    automatic_variable = 1;
-}
+  octave_function *fcn = function.function_value (true);
 
-void
-symbol_record::mark_as_linked_to_global (void)
-{
-  if (is_formal_parameter ())
-    error ("can't make function parameter `%s' global", nm.c_str ());
-  else if (is_static ())
-    error ("can't make static variable `%s' global", nm.c_str ());
-  else
-    linked_to_global = 1;
-}
-
-void
-symbol_record::mark_as_static (void)
-{
-  if (is_linked_to_global ())
-    error ("can't make global variable `%s' static", nm.c_str ());
-  else if (is_formal_parameter ())
-    error ("can't make formal parameter `%s' static", nm.c_str ());
-  else
-    tagged_static = 1;
-}
-
-octave_value&
-symbol_record::variable_value (void)
-{
-  static octave_value foo;
-
-  return is_variable () ? def () : foo;
-}
-
-octave_lvalue
-symbol_record::variable_reference (void)
-{
-  if ((Vvariables_can_hide_functions <= 0 || ! can_hide_function)
-      && (is_function ()
-	  || (! is_defined () && is_valid_function (nm))))
-    {
-      if (Vvariables_can_hide_functions < 0 && can_hide_function)
-	warning ("variable `%s' hides function", nm.c_str ());
-      else
-	{
-	  error ("variable `%s' hides function", nm.c_str ());
-	  return octave_lvalue ();
-	}
-    }
-
-  if (is_function ())
-    clear ();
-
-  if (! is_defined ())
-    {
-      octave_value tmp;
-      define (tmp);
-    }
-
-  return octave_lvalue (&(def ()), chg_fcn);
-}
-
-void
-symbol_record::push_context (void)
-{
-  if (! is_static ())
-    {
-      context.push (definition);
-
-      definition = new symbol_def ();
-
-      global_link_context.push (static_cast<unsigned int> (linked_to_global));
-
-      linked_to_global = 0;
-    }
-}
-
-void
-symbol_record::pop_context (void)
-{
-  // It is possible for context to be empty if new symbols have been
-  // inserted in the symbol table during recursive calls.  This can
-  // happen as a result of calls to eval() and feval().
-
-  if (! context.empty ())
+  if (fcn)
     {
-      maybe_delete_def ();
-
-      definition = context.top ();
-      context.pop ();
-
-      linked_to_global = global_link_context.top ();
-      global_link_context.pop ();
-    }
-}
-
-// Calculate how much space needs to be reserved for the first part of
-// the dimensions string.  For example,
-//
-//   mat is a 12x3 matrix
-//            ^^  => 2 columns
+      // FIXME -- we need to handle nested functions properly here.
 
-int
-symbol_record::dimensions_string_req_first_space (int print_dims) const
-{
-  int first_param_space = 0;
-
-  // Calculating dimensions.
-
-  std::string dim_str = "";
-  std::stringstream ss;
-  dim_vector dimensions = dims ();
-  long dim = dimensions.length ();
-
-  first_param_space = (first_param_space >= 1 ? first_param_space : 1);
-
-  // Preparing dimension string.
-
-  if ((dim <= print_dims || print_dims < 0) && print_dims != 0)
-    {
-      // Dimensions string must be printed like this: 2x3x4x2.
+      if (! fcn->is_nested_function ())
+	{
+	  std::string ff = fcn->fcn_file_name ();
 
-      if (dim == 0 || dim == 1)
-	first_param_space = 1; // First parameter is 1.
-      else
-        {
-	  ss << dimensions (0);
-	 
-	  dim_str = ss.str ();
-	  first_param_space = dim_str.length ();
-	}
-    }
-  else
-    {
-      // Printing dimension string as: a-D.
-
-      ss << dim;
-
-      dim_str = ss.str ();
-      first_param_space = dim_str.length ();
-    }
+	  if (! ff.empty ())
+	    {
+	      octave_time tc = fcn->time_checked ();
 
-  return first_param_space;
-}
-
-// Calculate how much space needs to be reserved for the
-// dimensions string.  For example,
-//
-//   mat is a 12x3 matrix
-//            ^^^^ => 4 columns
-//
-// FIXME -- why not just use the dim_vector::str () method?
-
-int
-symbol_record::dimensions_string_req_total_space (int print_dims) const
-{
-  std::string dim_str = "";
-  std::stringstream ss;
-
-  ss << make_dimensions_string (print_dims);
-  dim_str = ss.str ();
-
-  return dim_str.length ();
-}
+	      bool relative = fcn->is_relative ();
 
-// Make the dimensions-string.  For example: mat is a 2x3 matrix.
-//                                                    ^^^
-//
-// FIXME -- why not just use the dim_vector::str () method?
-
-std::string
-symbol_record::make_dimensions_string (int print_dims) const
-{
-  // Calculating dimensions.
-
-  std::string dim_str = "";
-  std::stringstream ss;
-  dim_vector dimensions = dims ();
-  long dim = dimensions.length ();
-
-  // Preparing dimension string.
-
-  if ((dim <= print_dims || print_dims < 0) && print_dims != 0)
-    {
-      // Only printing the dimension string as: axbxc...
-
-      if (dim == 0)
-	ss << "1x1";
-      else
-        {
-	  for (int i = 0; i < dim; i++)
-	    {
-	      if (i == 0)
+	      if (tc < Vlast_prompt_time
+		  || (relative && tc < Vlast_chdir_time))
 		{
-		  if (dim == 1)
-		    {
-		      // Looks like this is not going to happen in
-		      // Octave, but ...
+		  octave_time ottp = fcn->time_parsed ();
+		  time_t tp = ottp.unix_time ();
 
-		      ss << "1x" << dimensions (i);
-		    }
-		  else
-		    ss << dimensions (i);
-		}
-	      else if (i < dim && dim != 1)
-		ss << "x" << dimensions (i);
-	    }
-	}
-    }
-  else
-    {
-      // Printing dimension string as: a-D.
-
-      ss << dim << "-D";
-    }
-
-  dim_str = ss.str ();
-
-  return dim_str;
-}
-
-// Print a line of information on a given symbol.
+		  std::string nm = fcn->name ();
 
-void
-symbol_record::print_symbol_info_line (std::ostream& os,
-				       std::list<whos_parameter>& params) const
-{
-  std::list<whos_parameter>::iterator i = params.begin ();
-  while (i != params.end ())
-    {
-      whos_parameter param = * i;
+		  int nm_len = nm.length ();
 
-      if (param.command != '\0')
-        {
-	  // Do the actual printing.
-
-	  switch (param.modifier)
-	    {
-	    case 'l':
-	      os << std::setiosflags (std::ios::left)
-		 << std::setw (param.parameter_length);
-	      break;
-
-	    case 'r':
-	      os << std::setiosflags (std::ios::right)
-		 << std::setw (param.parameter_length);
-	      break;
+		  std::string file;
+		  std::string dir_name;
 
-	    case 'c':
-	      if (param.command == 's')
-	        {
-		  int front = param.first_parameter_length
-		    - dimensions_string_req_first_space (param.dimensions);
-		  int back = param.parameter_length
-		    - dimensions_string_req_total_space (param.dimensions)
-		    - front;
-		  front = (front > 0) ? front : 0;
-		  back = (back > 0) ? back : 0;
-
-		  os << std::setiosflags (std::ios::left)
-		     << std::setw (front)
-		     << ""
-		     << std::resetiosflags (std::ios::left)
-		     << make_dimensions_string (param.dimensions)
-		     << std::setiosflags (std::ios::left)
-		     << std::setw (back)
-		     << ""
-		     << std::resetiosflags (std::ios::left);
-		}
-	      else
-	        {
-		  os << std::setiosflags (std::ios::left)
-		     << std::setw (param.parameter_length);
-		}
-	      break;
-
-	    default:
-	      error ("whos_line_format: modifier `%c' unknown",
-		     param.modifier);
-
-	      os << std::setiosflags (std::ios::right)
-		 << std::setw (param.parameter_length);
-	    }
-
-	  switch (param.command)
-	    {
-	    case 'b':
-	      os << byte_size ();
-	      break;
-
-	    case 'c':
-	      os << class_name ();
-	      break;
-
-	    case 'e':
-	      os << capacity ();
-	      break;
-
-	    case 'n':
-	      os << name ();
-	      break;
-
-	    case 'p':
-	      {
-		std::stringstream ss;
-		std::string str;
-
-		ss << (is_read_only () ? "r-" : "rw")
-		   << (is_static () || is_eternal () ? "-" : "d");
-		str = ss.str ();
-
-		os << str;
-	      }
-	      break;
-
-	    case 's':
-	      if (param.modifier != 'c')
-		os << make_dimensions_string (param.dimensions);
-	      break;
-
-	    case 't':
-	      os << type_name ();
-	      break;
-	    
-	    default:
-	      error ("whos_line_format: command `%c' unknown", param.command);
-	    }
+		  if (octave_env::absolute_pathname (nm)
+		      && ((nm_len > 4 && (nm.substr (nm_len-4) == ".oct"
+					  || nm.substr (nm_len-4) == ".mex"))
+			  || (nm_len > 2 && nm.substr (nm_len-4) == ".m")))
+		    file = nm;
+		  else
+		    // FIXME -- this lookup is not right since it doesn't
+		    // account for dispatch type.
+		    file = octave_env::make_absolute (load_path::find_fcn (nm, dir_name),
+						      octave_env::getcwd ());
 
-	  os << std::resetiosflags (std::ios::left)
-	     << std::resetiosflags (std::ios::right);
-	  i++;
-	}
-      else
-	{
-	  os << param.text;
-	  i++;
-	}
-    }
-}
-
-void
-symbol_record::print_info (std::ostream& os, const std::string& prefix) const
-{
-  os << prefix << "formal param:      " << formal_param << "\n"
-     << prefix << "linked to global:  " << linked_to_global << "\n"
-     << prefix << "tagged static:     " << tagged_static << "\n"
-     << prefix << "can hide function: " << can_hide_function << "\n"
-     << prefix << "visible:           " << visible << "\n";
-
-  if (definition)
-    definition->print_info (os, prefix);
-  else
-    os << prefix << "symbol " << name () << " is undefined\n";
-}
-
-bool
-symbol_record::read_only_error (const char *action)
-{
-  if (is_read_only ())
-    {
-      if (is_variable ())
-	::error ("can't %s read-only constant `%s'", action, nm.c_str ());
-      else if (is_function ())
-	::error ("can't %s read-only function `%s'", action, nm.c_str ());
-      else
-	::error ("can't %s read-only symbol `%s'", action, nm.c_str ());
+		  if (file.empty ())
+		    {
+		      // Can't see this function from current
+		      // directory, so we should clear it.
 
-      return true;
-    }
-  else
-    return false;
-}
-
-// A symbol table.
-
-symbol_table::~symbol_table (void)
-{
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
-	{
-	  symbol_record *tmp = ptr;
-
-	  ptr = ptr->next ();
-
-	  delete tmp;
-	}
-    }
-
-  delete [] table;
-}
-
-symbol_record *
-symbol_table::lookup (const std::string& nm, bool insert, bool warn)
-{
-  if (Vdebug_symtab_lookups)
-    {
-      std::cerr << (table_name.empty () ? std::string ("???") : table_name)
-		<< " symtab::lookup ["
-		<< (insert ? "I" : "-")
-		<< (warn ? "W" : "-")
-		<< "] \"" << nm << "\"\n";
-    }
-
-  unsigned int index = hash (nm);
-
-  symbol_record *ptr = table[index].next ();
+		      function = octave_value ();
+		    }
+		  else if (same_file (file, ff))
+		    {
+		      fcn->mark_fcn_file_up_to_date (octave_time ());
 
-  while (ptr)
-    {
-      if (ptr->name () == nm)
-	return ptr;
-
-      ptr = ptr->next ();
-    }
-
-  if (insert)
-    {
-      symbol_record *sr = new symbol_record (nm, table[index].next ());
-
-      table[index].chain (sr);
-
-      return sr;
-    }
-  else if (warn)
-    warning ("lookup: symbol `%s' not found", nm.c_str ());
-
-  return 0;
-}
-
-void
-symbol_table::rename (const std::string& old_name, const std::string& new_name)
-{
-  if (Vdebug_symtab_lookups)
-    {
-      std::cerr << (table_name.empty () ? std::string ("???") : table_name)
-		<< " symtab::rename "
-		<< "\"" << old_name << "\""
-		<< " to "
-		<< "\"" << new_name << "\"\n";
-    }
-
-  unsigned int index = hash (old_name);
+		      if (! (Vignore_function_time_stamp == 2
+			     || (Vignore_function_time_stamp
+				 && fcn->is_system_fcn_file ())))
+			{
+			  file_stat fs (ff);
 
-  symbol_record *prev = &table[index];
-  symbol_record *ptr = prev->next ();
-
-  while (ptr)
-    {
-      if (ptr->name () == old_name)
-	{
-	  ptr->rename (new_name);
-
-	  if (! error_state)
-	    {
-	      prev->chain (ptr->next ());
-
-	      index = hash (new_name);
-	      ptr->chain (table[index].next ());
-	      table[index].chain (ptr);
-
-	      return;
-	    }
-
-	  break;
-	}
-
-      prev = ptr;
-      ptr = ptr->next ();
-    }
-
-  error ("unable to rename `%s' to `%s'", old_name.c_str (),
-	 new_name.c_str ());
-}
-
-// FIXME -- it would be nice to eliminate a lot of the
-// following duplicate code.
-
-void
-symbol_table::clear (void)
-{
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
+			  if (fs)
+			    {
+			      if (fs.is_newer (tp))
+				{
+				  fcn = load_fcn_from_file (ff, dir_name);
 
-      while (ptr)
-	{
-	  if (ptr->is_user_function())
-	    {
-	      octave_user_function *fcn = ptr->def ().user_function_value ();
-	      std::string parent = (fcn ? fcn->parent_fcn_name () :
-				    std::string ());
-
-	      if (! parent.empty ())
-		{
-		  if (curr_parent_function &&
-		      parent == curr_parent_function->name ())
-		    {
-		      ptr = ptr->next ();
-		      continue;
-		    }			  
-
-		  symbol_record *parent_sr = fbi_sym_tab->lookup (parent);
-
-		  if (parent_sr && (parent_sr->is_static () ||
-				    parent_sr->is_eternal ()))
-		  {
-		    ptr = ptr->next ();
-		    continue;
-		  }
-		}
-	    }
-
-	  ptr->clear ();
-
-	  ptr = ptr->next ();
-	}
-    }
-}
-
-void
-symbol_table::clear_variables (void)
-{
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
+				  if (fcn)
+				    {
+				      retval = true;
 
-      while (ptr)
-	{
-	  if (ptr->is_user_variable ())
-	    ptr->clear ();
-
-	  ptr = ptr->next ();
-	}
-    }
-}
-
-// Really only clear functions that can be reloaded.
-
-void
-symbol_table::clear_functions (void)
-{
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
-	{
-	  if (ptr->is_user_function ()
-	      || ptr->is_dld_function ()
-	      || ptr->is_mex_function ())
-	    {
-
-	      if (ptr->is_user_function())
-		{
-		  octave_user_function *fcn = 
-		    ptr->def ().user_function_value ();
-		  std::string parent = (fcn ? fcn->parent_fcn_name () :
-					std::string ());
-
-		  if (! parent.empty ())
-		    {
-		      if (curr_parent_function &&
-			  parent == curr_parent_function->name ())
-			{
-			  ptr = ptr->next ();
-			  continue;
-			}			  
-
-		      symbol_record *parent_sr = fbi_sym_tab->lookup (parent);
-
-		      if (parent_sr && (parent_sr->is_static () ||
-					parent_sr->is_eternal ()))
-			{
-			  ptr = ptr->next ();
-			  continue;
+				      function = octave_value (fcn);
+				    }
+				  else
+				    function = octave_value ();
+				}				
+			    }
+			  else
+			    function = octave_value ();
 			}
 		    }
 		}
-
-	      ptr->clear ();
 	    }
-
-	  ptr = ptr->next ();
-	}
-    }
-}
-
-void
-symbol_table::clear_mex_functions (void)
-{
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
-	{
-	  if (ptr->is_mex_function ())
-	    ptr->clear ();
-
-	  ptr = ptr->next ();
-	}
-    }
-}
-
-void
-symbol_table::clear_globals (void)
-{
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
-	{
-	  if (ptr->is_user_variable () && ptr->is_linked_to_global ())
-	    ptr->clear ();
-
-	  ptr = ptr->next ();
-	}
-    }
-}
-
-bool
-symbol_table::clear (const std::string& nm)
-{
-  unsigned int index = hash (nm);
-
-  symbol_record *ptr = table[index].next ();
-
-  while (ptr)
-    {
-      if (ptr->name () == nm)
-	{
-	  if (ptr->is_user_function())
-	    {
-	      octave_user_function *fcn = 
-		ptr->def ().user_function_value ();
-	      std::string parent = (fcn ? fcn->parent_fcn_name () :
-				    std::string ());
-
-	      if (! parent.empty ())
-		{
-		  if (curr_parent_function &&
-		      parent == curr_parent_function->name ())
-		    return true;
-
-		  symbol_record *parent_sr = fbi_sym_tab->lookup (parent);
-		  
-		  if (parent_sr && (parent_sr->is_static () ||
-				    parent_sr->is_eternal ()))
-		    return true;
-		}
-	    }
-
-	  ptr->clear ();
-
-	  return true;
-	}
-      ptr = ptr->next ();
-    }
-
-  return false;
-}
-
-bool
-symbol_table::clear_variable (const std::string& nm)
-{
-  unsigned int index = hash (nm);
-
-  symbol_record *ptr = table[index].next ();
-
-  while (ptr)
-    {
-      if (ptr->name () == nm && ptr->is_user_variable ())
-	{
-	  ptr->clear ();
-	  return true;
-	}
-      ptr = ptr->next ();
-    }
-
-  return false;
-}
-
-bool
-symbol_table::clear_global (const std::string& nm)
-{
-  unsigned int index = hash (nm);
-
-  symbol_record *ptr = table[index].next ();
-
-  while (ptr)
-    {
-      if (ptr->name () == nm
-	  && ptr->is_user_variable ()
-	  && ptr->is_linked_to_global ())
-	{
-	  ptr->clear ();
-	  return true;
-	}
-      ptr = ptr->next ();
-    }
-
-  return false;
-}
-
-// Really only clear functions that can be reloaded.
-
-bool
-symbol_table::clear_function (const std::string& nm)
-{
-  unsigned int index = hash (nm);
-
-  symbol_record *ptr = table[index].next ();
-
-  while (ptr)
-    {
-      if (ptr->name () == nm
-	  && (ptr->is_user_function ()
-	      || ptr->is_dld_function ()
-	      || ptr->is_mex_function ()))
-	{
-	  if (ptr->is_user_function())
-	    {
-	      octave_user_function *fcn = 
-		ptr->def ().user_function_value ();
-	      std::string parent = (fcn ? fcn->parent_fcn_name () :
-				    std::string ());
-
-	      if (! parent.empty ())
-		{
-		  if (curr_parent_function &&
-		      parent == curr_parent_function->name ())
-		    return true;
-
-		  symbol_record *parent_sr = fbi_sym_tab->lookup (parent);
-		  
-		  if (parent_sr && (parent_sr->is_static () ||
-				    parent_sr->is_eternal ()))
-		    return true;
-		}
-	    }
-
-	  ptr->clear ();
-	  return true;
-	}
-      ptr = ptr->next ();
-    }
-
-  return false;
-}
-
-bool
-symbol_table::clear_variable_pattern (const std::string& pat)
-{
-  bool retval = false;
-
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
-	{
-	  if (ptr->is_user_variable ())
-	    {
-	      glob_match pattern (pat);
-
-	      if (pattern.match (ptr->name ()))
-		{
-		  ptr->clear ();
-
-		  retval = true;
-		}
-	    }
-
-	  ptr = ptr->next ();
 	}
     }
 
@@ -1092,915 +193,609 @@
 }
 
 bool
-symbol_table::clear_global_pattern (const std::string& pat)
+out_of_date_check (octave_value& function)
 {
-  bool retval = false;
+  return out_of_date_check_internal (function);
+}
 
-  for (unsigned int i = 0; i < table_size; i++)
+octave_value
+symbol_table::fcn_info::fcn_info_rep::load_private_function
+  (const std::string& dir_name)
+{
+  octave_value retval;
+
+  std::string file_name = load_path::find_private_fcn (dir_name, name);
+
+  if (! file_name.empty ())
     {
-      symbol_record *ptr = table[i].next ();
+      octave_function *fcn = load_fcn_from_file (file_name);
 
-      while (ptr)
+      if (fcn)
 	{
-	  if (ptr->is_user_variable () && ptr->is_linked_to_global ())
-	    {
-	      glob_match pattern (pat);
+	  retval = octave_value (fcn);
 
-	      if (pattern.match (ptr->name ()))
-		{
-		  ptr->clear ();
-
-		  retval = true;
-		}
-	    }
-
-	  ptr = ptr->next ();
+	  private_functions[dir_name] = retval;
 	}
     }
 
   return retval;
 }
 
-// Really only clear functions that can be reloaded.
-
-bool
-symbol_table::clear_function_pattern (const std::string& pat)
+octave_value
+symbol_table::fcn_info::fcn_info_rep::load_class_constructor (void)
 {
-  bool retval = false;
+  octave_value retval;
+
+  std::string dir_name;
 
-  for (unsigned int i = 0; i < table_size; i++)
+  std::string file_name = load_path::find_method (name, name, dir_name);
+
+  if (! file_name.empty ())
     {
-      symbol_record *ptr = table[i].next ();
+      octave_function *fcn = load_fcn_from_file (file_name, dir_name, name);
 
-      while (ptr)
+      if (fcn)
 	{
-	  if (ptr->is_user_function ()
-	      || ptr->is_dld_function ()
-	      || ptr->is_mex_function ())
-	    {
-	      glob_match pattern (pat);
+	  retval = octave_value (fcn);
+
+	  class_constructors[name] = retval;
+	}
+    }
+
+  return retval;
+}
+
+octave_value
+symbol_table::fcn_info::fcn_info_rep::load_class_method
+  (const std::string& dispatch_type)
+{
+  octave_value retval;
 
-	      if (pattern.match (ptr->name ()))
-		{
-		  ptr->clear ();
+  std::string dir_name;
+
+  std::string file_name = load_path::find_method (dispatch_type, name, dir_name);
 
-		  retval = true;
-		}
-	    }
+  if (! file_name.empty ())
+    {
+      octave_function *fcn = load_fcn_from_file (file_name, dir_name,
+						 dispatch_type);
 
-	  ptr = ptr->next ();
+      if (fcn)
+	{
+	  retval = octave_value (fcn);
+
+	  class_methods[dispatch_type] = retval;
 	}
     }
 
   return retval;
 }
 
-int
-symbol_table::size (void) const
+void
+symbol_table::fcn_info::fcn_info_rep::print_dispatch (std::ostream& os) const
 {
-  int count = 0;
+  if (dispatch_map.empty ())
+    os << "dispatch: " << name << " is not overloaded" << std::endl;
+  else
+    {
+      os << "Overloaded function " << name << ":\n\n";
+
+      for (const_dispatch_map_iterator p = dispatch_map.begin ();
+	   p != dispatch_map.end (); p++)
+	os << "  " << name << " (" << p->first << ", ...) -> " 
+	   << p->second << " (" << p->first << ", ...)\n";
 
-  for (unsigned int i = 0; i < table_size; i++)
+      os << std::endl;
+    }
+}
+
+std::string
+symbol_table::fcn_info::fcn_info_rep::help_for_dispatch (void) const
+{
+  std::string retval;
+
+  if (! dispatch_map.empty ())
     {
-      symbol_record *ptr = table[i].next ();
+      retval = "Overloaded function:\n\n";
+
+      for (const_dispatch_map_iterator p = dispatch_map.begin ();
+	   p != dispatch_map.end (); p++)
+	retval += "  " + p->second + " (" + p->first + ", ...)\n\n";
+    }
+
+  return retval;
+}
+
+// Find the definition of NAME according to the following precedence
+// list:
+//
+//   variable
+//   subfunction
+//   private function
+//   class constructor
+//   class method
+//   legacy dispatch
+//   command-line function
+//   autoload function
+//   function on the path
+//   built-in function
 
-      while (ptr)
+// Notes:
+//
+// FIXME -- we need to evaluate the argument list to determine the
+// dispatch type.  The method used here works (pass in the args, pass
+// out the evaluated args and a flag saying whether the evaluation was
+// needed), but it seems a bit inelegant.  We do need to save the
+// evaluated args in some way to avoid evaluating them multiple times.
+//  Maybe evaluated args could be attached to the tree_argument_list
+// object?  Then the argument list could be evaluated outside of this
+// function and we could elimnate the arg_names, evaluated_args, and
+// args_evaluated arguments.  We would still want to avoid computing
+// the dispatch type unless it is needed, so the args should be passed
+// rather than the dispatch type.  But the arguments will need to be
+// evaluated no matter what, so evaluating them beforehand should be
+// OK.  If the evaluated arguments are attached to args, then we would
+// need to determine the appropriate place(s) to clear them (for
+// example, before returning from tree_index_expression::rvalue).
+
+octave_value
+symbol_table::fcn_info::fcn_info_rep::find
+  (tree_argument_list *args, const string_vector& arg_names,
+   octave_value_list& evaluated_args, bool& args_evaluated,
+   scope_id scope)
+{
+  static bool deja_vu = false;
+
+  // Subfunction.  I think it only makes sense to check for
+  // subfunctions if we are currently executing a function defined
+  // from a .m file.
+
+  scope_val_iterator r = subfunctions.find (scope);
+
+  if (r != subfunctions.end ())
+    {
+      // FIXME -- out-of-date check here.
+
+      return r->second;
+    }
+  else if (curr_parent_function)
+    {
+      scope_id pscope = curr_parent_function->scope ();
+
+      r = subfunctions.find (pscope);
+
+      if (r != subfunctions.end ())
 	{
-	  count++;
-	  ptr = ptr->next ();
+	  // FIXME -- out-of-date check here.
+
+	  return r->second;
 	}
     }
 
-  return count;
-}
+  // Private function.
 
-static bool
-matches_patterns (const std::string& name, const string_vector& pats)
-{
-  int npats = pats.length ();
+  octave_function *curr_fcn = octave_call_stack::current ();
 
-  if (npats == 0)
-    return true;
-
-  glob_match pattern (pats);
-
-  return pattern.match (name);
-}
+  if (curr_fcn)
+    {
+      std::string dir_name = curr_fcn->dir_name ();
 
-Array<symbol_record *>
-symbol_table::subsymbol_list (const string_vector& pats,
-			      unsigned int type, unsigned int scope) const
-{
-  int count = 0;
-
-  int n = size ();
+      if (! dir_name.empty ())
+	{
+	  str_val_iterator q = private_functions.find (dir_name);
 
-  Array<symbol_record *> subsymbols (dim_vector (n, 1));
-  int pats_length = pats.length ();
-
-  if (n == 0)
-    return subsymbols;
-
-  // Look for separators like .({
-  for (int j = 0; j < pats_length; j++)
-    {
-      std::string var_name = pats (j);
+	  if (q == private_functions.end ())
+	    {
+	      octave_value val = load_private_function (dir_name);
 
-      size_t pos = var_name.find_first_of (".({");
-
-      if ((pos != NPOS) && (pos > 0))
-        {
-	  std::string first_name = var_name.substr(0,pos);
-
-	  for (unsigned int i = 0; i < table_size; i++)
+	      if (val.is_defined ())
+		return val;
+	    }
+	  else
 	    {
-	      symbol_record *ptr = table[i].next ();
-
-	      while (ptr)
-	        {
-		  assert (count < n);
-
-		  unsigned int my_scope = ptr->is_linked_to_global () + 1; // Tricky...
+	      octave_value& fval = q->second;
 
-		  unsigned int my_type = ptr->type ();
-
-		  std::string my_name = ptr->name ();
+	      if (fval.is_defined ())
+		out_of_date_check_internal (fval);
 
-		  if ((type & my_type) && (scope & my_scope) && (first_name == my_name))
-		    {
-		      symbol_record *sym_ptr = new symbol_record ();
-		      octave_value value;
-		      int parse_status;
-	 
-		      value = eval_string (var_name, true, parse_status);
-	 
-		      sym_ptr->define (value);
-		      sym_ptr->rename (var_name);
-		      subsymbols(count++) = sym_ptr;
-		    }
+	      if (fval.is_defined ())
+		return fval;
+	      else
+		{
+		  octave_value val = load_private_function (dir_name);
 
-		  ptr = ptr->next ();
+		  if (val.is_defined ())
+		    return val;
 		}
 	    }
 	}
     }
 
-  subsymbols.resize (dim_vector (count, 1));
+  // Class constructors.  The class name and function name are the same.
 
-  return subsymbols;
-}
+  str_val_iterator q = class_constructors.find (name);
 
-Array<symbol_record *>
-symbol_table::symbol_list (const string_vector& pats,
-			   unsigned int type, unsigned int scope) const
-{
-  int count = 0;
+  if (q == class_constructors.end ())
+    {
+      octave_value val = load_class_constructor ();
 
-  int n = size ();
-
-  Array<symbol_record *> symbols (dim_vector (n, 1));
-
-  if (n == 0)
-    return symbols;
-
-  for (unsigned int i = 0; i < table_size; i++)
+      if (val.is_defined ())
+	return val;
+    }
+  else
     {
-      symbol_record *ptr = table[i].next ();
+      octave_value& fval = q->second;
 
-      while (ptr)
-	{
-	  if (ptr->is_visible ())
-	    {
-	      assert (count < n);
-
-	      unsigned int my_scope = ptr->is_linked_to_global () + 1; // Tricky...
+      if (fval.is_defined ())
+	out_of_date_check_internal (fval);
 
-	      unsigned int my_type = ptr->type ();
-
-	      std::string my_name = ptr->name ();
+      if (fval.is_defined ())
+	return fval;
+      else
+	{
+	  octave_value val = load_class_constructor ();
 
-	      if ((type & my_type) && (scope & my_scope) && (matches_patterns (my_name, pats)))
-		symbols(count++) = ptr;
-	    }
-
-	  ptr = ptr->next ();
+	  if (val.is_defined ())
+	    return val;
 	}
     }
 
-  symbols.resize (dim_vector (count, 1));
+  // Class methods.
 
-  return symbols;
-}
+  if (args_evaluated || (args && args->length () > 0))
+    {
+      if (! args_evaluated)
+	evaluated_args = args->convert_to_const_vector ();
 
-string_vector
-symbol_table::name_list (const string_vector& pats, bool sort,
-			 unsigned int type, unsigned int scope) const
-{
-  Array<symbol_record *> symbols = symbol_list (pats, type, scope);
+      if (! error_state)
+	{
+	  int n = evaluated_args.length ();
+
+	  if (n > 0 && ! args_evaluated)
+	    evaluated_args.stash_name_tags (arg_names);
+
+	  args_evaluated = true;
+
+	  // FIXME -- need to handle precedence.
 
-  string_vector names;
+	  std::string dispatch_type = evaluated_args(0).class_name ();
 
-  int n = symbols.length ();
+	  for (int i = 1; i < n; i++)
+	    {
+	      octave_value arg = evaluated_args(i);
 
-  if (n > 0)
-    {
-      names.resize (n);
+	      if (arg.is_object ())
+		{
+		  dispatch_type = arg.class_name ();
+		  break;
+		}
+	    }
 
-      for (int i = 0; i < n; i++)
-	names[i] = symbols(i)->name ();
+	  octave_value fcn = find_method (dispatch_type);
+
+	  if (fcn.is_defined ())
+	    return fcn;
+	}
+      else
+	return octave_value ();
     }
 
-  if (sort)
-    names.qsort ();
+  // Legacy dispatch.  We just check args_evaluated here because the
+  // actual evaluation will have happened already when searching for
+  // class methods.
+
+  if (args_evaluated && ! dispatch_map.empty ())
+    {
+      std::string dispatch_type = evaluated_args(0).type_name ();
+
+      std::string fname;
+
+      dispatch_map_iterator p = dispatch_map.find (dispatch_type);
+
+      if (p == dispatch_map.end ())
+	p = dispatch_map.find ("any");
 
-  return names;
-}
+      if (p != dispatch_map.end ())
+	{
+	  fname = p->second;
+
+	  octave_value fcn
+	    = symbol_table::find_function (fname, evaluated_args, scope);
+
+	  if (fcn.is_defined ())
+	    return fcn;
+	}
+    }
+
+  // Command-line function.
+
+  if (cmdline_function.is_defined ())
+    return cmdline_function;
+
+  // Autoload?
 
-static int
-maybe_list_cmp_fcn (const void *a_arg, const void *b_arg)
-{
-  const symbol_record *a = *(static_cast<symbol_record *const*> (a_arg));
-  const symbol_record *b = *(static_cast<symbol_record *const*> (b_arg));
+  octave_value fcn = find_autoload ();
+
+  if (fcn.is_defined ())
+    return fcn;
+
+  // Function on the path.
+
+  fcn = find_user_function ();
+
+  if (fcn.is_defined ())
+    return fcn;
+
+  // Built-in function.
+
+  if (built_in_function.is_defined ())
+    return built_in_function;
 
-  std::string a_nm = a->name ();
-  std::string b_nm = b->name ();
+  // At this point, we failed to find anything.  It is possible that
+  // the user created a file on the fly since the last prompt or
+  // chdir, so try updating the load path and searching again.
+
+  octave_value retval;
 
-  return a_nm.compare (b_nm);
+  if (! deja_vu)
+    {
+      load_path::update ();
+
+      deja_vu = true;
+
+      retval = find (args, arg_names, evaluated_args, args_evaluated, scope);
+    }
+
+  deja_vu = false;
+
+  return retval;
 }
 
-void
-symbol_table::print_descriptor (std::ostream& os,
-				std::list<whos_parameter> params) const
+octave_value
+symbol_table::fcn_info::fcn_info_rep::find_method (const std::string& dispatch_type)
 {
-  // This method prints a line of information on a given symbol
-  std::list<whos_parameter>::iterator i = params.begin ();
-  std::ostringstream param_buf;
-
-  while (i != params.end ())
-    {
-      whos_parameter param = * i;
+  octave_value retval;
 
-      if (param.command != '\0')
-        {
-	  // Do the actual printing
-	  switch (param.modifier)
-	    {
-	    case 'l':
-	      os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
-	      param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
-	      break;
+  str_val_iterator q = class_methods.find (dispatch_type);
 
-	    case 'r':
-	      os << std::setiosflags (std::ios::right) << std::setw (param.parameter_length);
-	      param_buf << std::setiosflags (std::ios::right) << std::setw (param.parameter_length);
-	      break;
-
-	    case 'c':
-	      if (param.command != 's')
-	        {
-		  os << std::setiosflags (std::ios::left)
-		     << std::setw (param.parameter_length);
-		  param_buf << std::setiosflags (std::ios::left)
-			    << std::setw (param.parameter_length);
-		}
-	      break;
+  if (q == class_methods.end ())
+    {
+      octave_value val = load_class_method (dispatch_type);
 
-	    default:
-	      os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
-	      param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
-	    }
+      if (val.is_defined ())
+	return val;
+    }
+  else
+    {
+      octave_value& fval = q->second;
 
-	  if (param.command == 's' && param.modifier == 'c')
-	    {
-	      int a, b;
-	     
-	      if (param.modifier == 'c')
-	        {
-		  a = param.first_parameter_length - param.balance;
-		  a = (a < 0 ? 0 : a);
-		  b = param.parameter_length - a - param.text . length ();
-		  b = (b < 0 ? 0 : b);
-		  os << std::setiosflags (std::ios::left) << std::setw (a)
-		     << "" << std::resetiosflags (std::ios::left) << param.text
-		     << std::setiosflags (std::ios::left)
-		     << std::setw (b) << ""
-		     << std::resetiosflags (std::ios::left);
-		  param_buf << std::setiosflags (std::ios::left) << std::setw (a)
-		     << "" << std::resetiosflags (std::ios::left) << param.line
-		     << std::setiosflags (std::ios::left)
-		     << std::setw (b) << ""
-		     << std::resetiosflags (std::ios::left);
-		}
-	    }
-	  else
-	    {
-	      os << param.text;
-	      param_buf << param.line;
-	    }
-	  os << std::resetiosflags (std::ios::left)
-	     << std::resetiosflags (std::ios::right);
-	  param_buf << std::resetiosflags (std::ios::left)
-		    << std::resetiosflags (std::ios::right);
-	  i++;
-	}
+      if (fval.is_defined ())
+	out_of_date_check_internal (fval);
+
+      if (fval.is_defined ())
+	return fval;
       else
 	{
-	  os << param.text;
-	  param_buf << param.line;
-	  i++;
+	  octave_value val = load_class_method (dispatch_type);
+
+	  if (val.is_defined ())
+	    return val;
 	}
     }
 
-  os << param_buf.str ();
+  return retval;
 }
 
-std::list<whos_parameter>
-symbol_table::parse_whos_line_format (Array<symbol_record *>& symbols) const
+octave_value
+symbol_table::fcn_info::fcn_info_rep::find_autoload (void)
 {
-  // This method parses the string whos_line_format, and returns
-  // a parameter list, containing all information needed to print
-  // the given attributtes of the symbols
-  int idx;
-  size_t format_len = Vwhos_line_format.length ();
-  char garbage;
-  std::list<whos_parameter> params;
-
-  size_t bytes1;
-  int elements1;
+  octave_value retval;
 
-  int len = symbols.length ();
-
-  std::string param_string = "bcenpst";
-  Array<int> param_length (dim_vector (param_string.length (), 1));
-  Array<std::string> param_names (dim_vector (param_string.length (), 1));
-  size_t pos_b, pos_c, pos_e, pos_n, pos_p, pos_s, pos_t;
+  // Autoloaded function.
 
-  pos_b = param_string.find ('b'); // Bytes
-  pos_c = param_string.find ('c'); // Class
-  pos_e = param_string.find ('e'); // Elements
-  pos_n = param_string.find ('n'); // Name
-  pos_p = param_string.find ('p'); // Protected
-  pos_s = param_string.find ('s'); // Size
-  pos_t = param_string.find ('t'); // Type
+  if (autoload_function.is_defined ())
+    out_of_date_check_internal (autoload_function);
 
-  param_names(pos_b) = "Bytes";
-  param_names(pos_c) = "Class";
-  param_names(pos_e) = "Elements";
-  param_names(pos_n) = "Name";
-  param_names(pos_p) = "Prot";
-  param_names(pos_s) = "Size";
-  param_names(pos_t) = "Type";
+  if (! autoload_function.is_defined ())
+    {
+      std::string file_name = lookup_autoload (name);
 
-  for (size_t i = 0; i < param_string.length (); i++)
-    param_length(i) = param_names(i) . length ();
-
-  // Calculating necessary spacing for name column,
-  // bytes column, elements column and class column
-  for (int i = 0; i < static_cast<int> (len); i++)
-    {
-      std::stringstream ss1, ss2;
-      std::string str;
+      if (! file_name.empty ())
+	{
+	  size_t pos = file_name.find_last_of (file_ops::dir_sep_chars);
 
-      str = symbols(i)->name ();
-      param_length(pos_n) = ((str.length ()
-			      > static_cast<size_t> (param_length(pos_n)))
-			     ? str.length () : param_length(pos_n));
-
-      str = symbols(i)->type_name ();
-      param_length(pos_t) = ((str.length ()
-			      > static_cast<size_t> (param_length(pos_t)))
-			     ? str.length () : param_length(pos_t));
+	  std::string dir_name = file_name.substr (0, pos);
 
-      elements1 = symbols(i)->capacity ();
-      ss1 << elements1;
-      str = ss1.str ();
-      param_length(pos_e) = ((str.length ()
-			      > static_cast<size_t> (param_length(pos_e)))
-			     ? str.length () : param_length(pos_e));
+	  octave_function *fcn = load_fcn_from_file (file_name, dir_name,
+						     "", name, true);
 
-      bytes1 = symbols(i)->byte_size ();
-      ss2 << bytes1;
-      str = ss2.str ();
-      param_length(pos_b) = ((str.length ()
-			      > static_cast<size_t> (param_length(pos_b)))
-			     ? str.length () : param_length (pos_b));
+	  if (fcn)
+	    autoload_function = octave_value (fcn);
+	}
     }
 
-  idx = 0;
-  while (static_cast<size_t> (idx) < format_len)
-    {
-      whos_parameter param;
-      param.command = '\0';
-
-      if (Vwhos_line_format[idx] == '%')
-        {
-	  bool error_encountered = false;
-	  param.modifier = 'r';
-	  param.parameter_length = 0;
-	  param.dimensions = 8;
-
-	  int a = 0, b = -1, c = 8, balance = 1;
-	  unsigned int items;
-	  size_t pos;
-	  std::string cmd;
-
-	  // Parse one command from whos_line_format
-	  cmd = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
-	  pos = cmd.find (';');
-	  if (pos != NPOS)
-	    cmd = cmd.substr (0, pos+1);
-	  else
-	    error ("parameter without ; in whos_line_format");
-
-	  idx += cmd.length ();
-
-	  // FIXME -- use iostream functions instead of sscanf!
+  return autoload_function;
+}
 
-	  if (cmd.find_first_of ("crl") != 1)
-	    items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d:%d;",
-			    &garbage, &param.command, &a, &b, &c, &balance);
-	  else
-	    items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d:%d;",
-			    &garbage, &param.modifier, &param.command,
-			    &a, &b, &c, &balance) - 1;
-	 
-	  if (items < 2)
-	    {
-	      error ("whos_line_format: parameter structure without command in whos_line_format");
-	      error_encountered = true;
-	    }
+octave_value
+symbol_table::fcn_info::fcn_info_rep::find_user_function (void)
+{
+  // Function on the path.
 
-	  // Insert data into parameter
-	  param.first_parameter_length = 0;
-	  pos = param_string.find (param.command);
-	  if (pos != NPOS)
-	    {
-	      param.parameter_length = param_length(pos);
-	      param.text = param_names(pos);
-	      param.line.assign (param_names(pos).length (), '=');
-
-	      param.parameter_length = (a > param.parameter_length
-					? a : param.parameter_length);
-	      if (param.command == 's' && param.modifier == 'c' && b > 0)
-		param.first_parameter_length = b;
-	    }
-	  else
-	    {
-	      error ("whos_line_format: '%c' is not a command",
-		     param.command);
-	      error_encountered = true;
-	    }
+  if (function_on_path.is_defined ())
+    out_of_date_check_internal (function_on_path);
 
-	  if (param.command == 's')
-	    {
-	      // Have to calculate space needed for printing matrix dimensions
-	      // Space needed for Size column is hard to determine in prior,
-	      // because it depends on dimensions to be shown. That is why it is
-	      // recalculated for each Size-command
-	      int j, first, rest = 0, total;
-	      param.dimensions = c;
-	      first = param.first_parameter_length;
-	      total = param.parameter_length;
-	     
-	      for (j = 0; j < len; j++)
-		{
-		  int first1 = symbols(j)->dimensions_string_req_first_space (param.dimensions);
-		  int total1 = symbols(j)->dimensions_string_req_total_space (param.dimensions);
-		  int rest1 = total1 - first1;
-		  rest = (rest1 > rest ? rest1 : rest);
-		  first = (first1 > first ? first1 : first);
-		  total = (total1 > total ? total1 : total);
-		}
+  if (! function_on_path.is_defined ())
+    {
+      std::string dir_name;
 
-	      if (param.modifier == 'c')
-	        {
-		  if (first < balance)
-		    first += balance - first;
-		  if (rest + balance < param.parameter_length)
-		    rest += param.parameter_length - rest - balance;
+      std::string file_name = load_path::find_fcn (name, dir_name);
 
-		  param.parameter_length = first + rest;
-		  param.first_parameter_length = first;
-		  param.balance = balance;
-		}
-	      else
-	        {
-		  param.parameter_length = total;
-		  param.first_parameter_length = 0;
-		}
-	    }
-	  else if (param.modifier == 'c')
-	    {
-	      error ("whos_line_format: modifier 'c' not available for command '%c'",
-		     param.command);
-	      error_encountered = true;
-	    }
+      if (! file_name.empty ())
+	{
+	  octave_function *fcn = load_fcn_from_file (file_name, dir_name);
 
-	  // What happens if whos_line_format contains negative numbers
-	  // at param_length positions?
-	  param.balance = (b < 0 ? 0 : param.balance);
-	  param.first_parameter_length = (b < 0 ? 0 :
-					  param.first_parameter_length);
-	  param.parameter_length = (a < 0
-				    ? 0
-				    : (param.parameter_length
-				       < param_length(pos_s)
-				       ? param_length(pos_s)
-				       : param.parameter_length));
-
-	  // Parameter will not be pushed into parameter list if ...
-	  if (! error_encountered)
-	    params.push_back (param);
-	}
-      else
-        {
-	  // Text string, to be printed as it is ...
-	  std::string text;
-	  size_t pos;
-	  text = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
-	  pos = text.find ('%');
-	  if (pos != NPOS)
-	    text = text.substr (0, pos);
-
-	  // Push parameter into list ...
-	  idx += text.length ();
-	  param.text=text;
-	  param.line.assign (text.length(), ' ');
-	  params.push_back (param);
+	  if (fcn)
+	    function_on_path = octave_value (fcn);
 	}
     }
 
-  return params;
+  return function_on_path;
+}
+
+octave_value
+symbol_table::fcn_info::find (tree_argument_list *args,
+			      const string_vector& arg_names,
+			      octave_value_list& evaluated_args,
+			      bool& args_evaluated, scope_id scope)
+{
+  return rep->find (args, arg_names, evaluated_args, args_evaluated, scope);
+}
+
+octave_value
+symbol_table::find (const std::string& name, tree_argument_list *args,
+		    const string_vector& arg_names,
+		    octave_value_list& evaluated_args, bool& args_evaluated,
+		    symbol_table::scope_id scope, bool skip_variables)
+{
+  symbol_table *inst = get_instance (scope);
+
+  return inst
+    ? inst->do_find (name, args, arg_names, evaluated_args,
+		       args_evaluated, scope, skip_variables)
+    : octave_value ();
+}
+
+octave_value
+symbol_table::find_function (const std::string& name, tree_argument_list *args,
+			     const string_vector& arg_names,
+			     octave_value_list& evaluated_args,
+			     bool& args_evaluated, scope_id scope)
+{
+  return find (name, args, arg_names, evaluated_args, args_evaluated,
+	       scope, true);
 }
 
-int
-symbol_table::maybe_list (const char *header, const string_vector& argv,
-			  std::ostream& os, bool show_verbose,
-			  unsigned type, unsigned scope)
+octave_value
+symbol_table::do_find (const std::string& name, tree_argument_list *args,
+		       const string_vector& arg_names,
+		       octave_value_list& evaluated_args,
+		       bool& args_evaluated, scope_id scope,
+		       bool skip_variables)
 {
-  // This method prints information for sets of symbols, but only one
-  // set at a time (like, for instance: all variables, or all
-  // built-in-functions).
+  octave_value retval;
 
-  // This method invokes print_symbol_info_line to print info on every
-  // symbol.
+  // Variable.
 
-  int status = 0;
-
-  if (show_verbose)
+  if (! skip_variables)
     {
-      // FIXME Should separate argv to lists with and without dots.
-      Array<symbol_record *> xsymbols = symbol_list (argv, type, scope);
-      Array<symbol_record *> xsubsymbols = subsymbol_list (argv, type, scope);
+      table_iterator p = table.find (name);
 
-      int sym_len = xsymbols.length (), subsym_len = xsubsymbols.length (),
-	len = sym_len + subsym_len;
- 
-      Array<symbol_record *> symbols (dim_vector (len, 1));
+      if (p != table.end ())
+	{
+	  symbol_record& sr = p->second;
 
-      if (len > 0)
-	{
-	  size_t bytes = 0;
-	  size_t elements = 0;
-
-	  int i;
+	  // FIXME -- should we be using something other than varref here?
 
-	  std::list<whos_parameter> params;
-
-	  // Joining symbolic tables.
-	  for (i = 0; i < sym_len; i++)
-	    symbols(i) = xsymbols(i);
-
-	  for (i = 0; i < subsym_len; i++)
-	    symbols(i+sym_len) = xsubsymbols(i);
-
-	  os << "\n" << header << "\n\n";
-
-	  symbols.qsort (maybe_list_cmp_fcn);
-
-	  params = parse_whos_line_format (symbols);
-
-	  print_descriptor (os, params);
+	  if (sr.is_global ())
+	    return symbol_table::varref (name, xglobal_scope);
+	  else
+	    {
+	      octave_value& val = sr.varref ();
 
-	  os << "\n";
+	      if (val.is_defined ())
+		return val;
+	    }
+	}
+    }
 
-	  for (int j = 0; j < len; j++)
-	    {
-	      symbols(j)->print_symbol_info_line (os, params);
-	      elements += symbols(j)->capacity ();
-	      bytes += symbols(j)->byte_size ();
-	    }
+  fcn_table_iterator p = fcn_table.find (name);
 
-	  os << "\nTotal is "
-	     << elements << (elements == 1 ? " element" : " elements")
-	     << " using "
-	     << bytes << (bytes == 1 ? " byte" : " bytes")
-	     << "\n";
+  if (p != fcn_table.end ())
+    {
+      evaluated_args = octave_value_list ();
+      args_evaluated = false;
 
-	  status = 1;
-	}
+      return p->second.find (args, arg_names, evaluated_args, args_evaluated,
+			     scope);
     }
   else
     {
-      string_vector symbols = name_list (argv, 1, type, scope);
+      fcn_info finfo (name);
+
+      octave_value fcn = finfo.find (args, arg_names, evaluated_args,
+				     args_evaluated, scope);
 
-      if (! symbols.empty ())
-	{
-	  os << "\n" << header << "\n\n";
+      if (fcn.is_defined ())
+	fcn_table[name] = finfo;
 
-	  symbols.list_in_columns (os);
-
-	  status = 1;
-	}
+      return fcn;
     }
 
-  return status;
-}
-
-Array<symbol_record *>
-symbol_table::glob (const std::string& pat, unsigned int type,
-		    unsigned int scope) const
-{
-  int count = 0;
-
-  int n = size ();
-
-  Array<symbol_record *> symbols (dim_vector (n, 1));
-
-  if (n == 0)
-    return symbols;
-
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
-	{
-	  assert (count < n);
-
-	  unsigned int my_scope = ptr->is_linked_to_global () + 1; // Tricky...
-
-	  unsigned int my_type = ptr->type ();
-
-	  glob_match pattern (pat);
-
-	  if ((type & my_type) && (scope & my_scope)
-	      && pattern.match (ptr->name ()))
-	    {
-	      symbols(count++) = ptr;
-	    }
-
-	  ptr = ptr->next ();
-	}
-    }
-
-  symbols.resize (dim_vector (count, 1));
-
-  return symbols;
+  return retval;
 }
 
-void
-symbol_table::push_context (void)
+DEFUN (ignore_function_time_stamp, args, nargout,
+    "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {@var{val} =} ignore_function_time_stamp ()\n\
+@deftypefnx {Built-in Function} {@var{old_val} =} ignore_function_time_stamp (@var{new_val})\n\
+Query or set the internal variable that controls whether Octave checks\n\
+the time stamp on files each time it looks up functions defined in\n\
+function files.  If the internal variable is set to @code{\"system\"},\n\
+Octave will not automatically recompile function files in subdirectories of\n\
+@file{@var{octave-home}/lib/@var{version}} if they have changed since\n\
+they were last compiled, but will recompile other function files in the\n\
+search path if they change.  If set to @code{\"all\"}, Octave will not\n\
+recompile any function files unless their definitions are removed with\n\
+@code{clear}.  If set to \"none\", Octave will always check time stamps\n\
+on files to determine whether functions defined in function files\n\
+need to recompiled.\n\
+@end deftypefn")
 {
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
-	{
-	  ptr->push_context ();
-	  ptr = ptr->next ();
-	}
-    }
-}
-
-void
-symbol_table::pop_context (void)
-{
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
-	{
-	  ptr->pop_context ();
-	  ptr = ptr->next ();
-	}
-    }
-}
+  octave_value retval;
 
-// Create a new symbol table with the same entries.  Only the symbol
-// names and some attributes are copied, not values.
-
-symbol_table *
-symbol_table::dup (void)
-{
-  symbol_table *new_sym_tab = new symbol_table (table_size);
-
-  for (unsigned int i = 0; i < table_size; i++)
+  if (nargout > 0)
     {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
+      switch (Vignore_function_time_stamp)
 	{
-	  std::string nm = ptr->name ();
+	case 1:
+	  retval = "system";
+	  break;
 
-	  symbol_record *sr = new_sym_tab->lookup (nm, true);
-
-	  if (sr)
-	    {
-	      if (ptr->is_formal_parameter ())
-		sr->mark_as_formal_parameter ();
+	case 2:
+	  retval = "all";
+	  break;
 
-	      if (ptr->is_automatic_variable ())
-		sr->mark_as_automatic_variable ();
-
-	      if (ptr->is_static ())
-		sr->mark_as_static ();
-	    }
-
-	  ptr = ptr->next ();
+	default:
+	  retval = "none";
+	  break;
 	}
     }
 
-  return new_sym_tab;
-}
-
-void
-symbol_table::inherit (symbol_table *parent_sym_tab)
-{
-  for (unsigned int i = 0; i < table_size; i++)
-    {
-      symbol_record *ptr = table[i].next ();
-
-      while (ptr)
-	{
-	  std::string nm = ptr->name ();
-
-	  if (! (nm == "__retval__"
-		 || ptr->is_automatic_variable ()
-		 || ptr->is_formal_parameter ()))
-	    {
-	      symbol_record *sr = parent_sym_tab->lookup (nm);
+  int nargin = args.length ();
 
-	      if (sr)
-		{
-		  ptr->define (sr->variable_value ());
-
-		  ptr->mark_as_static ();
-		}
-	    }
-
-	  ptr = ptr->next ();
-	}
-    }
-}
-
-void
-symbol_table::print_info (std::ostream& os) const
-{
-  int count = 0;
-  int empty_chains = 0;
-  int max_chain_length = 0;
-  int min_chain_length = INT_MAX;
-
-  for (unsigned int i = 0; i < table_size; i++)
+  if (nargin == 1)
     {
-      int num_this_chain = 0;
-
-      symbol_record *ptr = table[i].next ();
-
-      if (ptr)
-	os << "chain number " << i << ":\n";
-      else
-	{
-	  empty_chains++;
-	  min_chain_length = 0;
-	}
-
-      while (ptr)
-	{
-	  num_this_chain++;
-
-	  os << "  " << ptr->name () << "\n";
-
-	  ptr->print_info (os, "    ");
-
-	  ptr = ptr->next ();
-	}
-
-      count += num_this_chain;
-
-      if (num_this_chain > max_chain_length)
-	max_chain_length = num_this_chain;
-
-      if (num_this_chain < min_chain_length)
-	min_chain_length = num_this_chain;
-
-      if (num_this_chain > 0)
-	os << "\n";
-    }
-
-  os << "max chain length: " << max_chain_length << "\n";
-  os << "min chain length: " << min_chain_length << "\n";
-  os << "empty chains:     " << empty_chains << "\n";
-  os << "total chains:     " << table_size << "\n";
-  os << "total symbols:    " << count << "\n";
-}
-
-// Chris Torek's fave hash function.
+      std::string sval = args(0).string_value ();
 
-unsigned int
-symbol_table::hash (const std::string& str)
-{
-  unsigned int h = 0;
-
-  for (unsigned int i = 0; i < str.length (); i++)
-    h = h * 33 + str[i];
-
-  return h & (table_size - 1);
-}
-
-DEFUN (debug_symtab_lookups, args, nargout,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {@var{val} =} debug_symtab_lookups ()\n\
-@deftypefnx {Built-in Function} {@var{old_val} =} debug_symtab_lookups (@var{new_val})\n\
-Query or set the internal variable that controls whether debugging\n\
-information is printed when searching for symbols in the symbol tables.\n\
-@end deftypefn")
-{
-  return SET_INTERNAL_VARIABLE (debug_symtab_lookups);
-}
+      if (! error_state)
+	{
+	  if (sval == "all")
+	    Vignore_function_time_stamp = 2;
+	  else if (sval == "system")
+	    Vignore_function_time_stamp = 1;
+	  else if (sval == "none")
+	    Vignore_function_time_stamp = 0;
+	  else
+	    error ("ignore_function_time_stamp: expecting argument to be \"all\", \"system\", or \"none\"");
+	}
+      else
+	error ("ignore_function_time_stamp: expecting argument to be character string");
+    }
+  else if (nargin > 1)
+    print_usage ();
 
-DEFUN (whos_line_format, args, nargout,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {@var{val} =} whos_line_format ()\n\
-@deftypefnx {Built-in Function} {@var{old_val} =} whos_line_format (@var{new_val})\n\
-Query or set the format string used by the @code{whos}.\n\
-\n\
-The following escape sequences may be used in the format:\n\
-@table @code\n\
-@item %b\n\
-Prints number of bytes occupied by variables.\n\
-@item %c\n\
-Prints class names of variables.\n\
-@item %e\n\
-Prints elements held by variables.\n\
-@item %n\n\
-Prints variable names.\n\
-@item %p\n\
-Prints protection attributes of variables.\n\
-@item %s\n\
-Prints dimensions of variables.\n\
-@item %t\n\
-Prints type names of variables.\n\
-@end table\n\
-\n\
-Every command may also have a modifier:\n\
-@table @code\n\
-@item l\n\
-Left alignment.\n\
-@item r\n\
-Right alignment (this is the default).\n\
-@item c\n\
-Centered (may only be applied to command %s).\n\
-@end table\n\
-\n\
-A command is composed like this:\n\
-\n\
-@example\n\
-%[modifier]<command>[:size_of_parameter[:center-specific[\n\
-       :print_dims[:balance]]]];\n\
-@end example\n\
-\n\
-Command and modifier is already explained. Size_of_parameter\n\
-tells how many columns the parameter will need for printing.\n\
-print_dims tells how many dimensions to print. If number of\n\
-dimensions exceeds print_dims, dimensions will be printed like\n\
-x-D.\n\
-center-specific and print_dims may only be applied to command\n\
-%s. A negative value for print_dims will cause Octave to print all\n\
-dimensions whatsoever.\n\
-balance specifies the offset for printing of the dimensions string.\n\
-\n\
-The default format is \"  %p:4; %ln:6; %cs:16:6:8:1;  %rb:12;  %lc:-1;\\n\".\n\
-@end deftypefn")
-{
-  return SET_INTERNAL_VARIABLE (whos_line_format);
-}
-
-DEFUN (variables_can_hide_functions, args, nargout,
-    "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {@var{val} =} variables_can_hide_functions ()\n\
-@deftypefnx {Built-in Function} {@var{old_val} =} variables_can_hide_functions (@var{new_val})\n\
-Query or set the internal variable that controls whether assignments\n\
-to variables may hide previously defined functions of the same name.\n\
-If set to a nonzero value allows hiding, zero causes Octave to\n\
-generate an error, and a negative value cause Octave to print a\n\
-warning, but allow the operation.\n\
-@end deftypefn")
-{
-  return SET_INTERNAL_VARIABLE (variables_can_hide_functions);
+  return retval;
 }
 
 /*
--- a/src/symtab.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/symtab.h	Fri Dec 28 20:56:58 2007 +0000
@@ -2,7 +2,7 @@
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2002, 2003,
               2004, 2005, 2006, 2007 John W. Eaton
-
+  
 This file is part of Octave.
 
 Octave is free software; you can redistribute it and/or modify it
@@ -24,474 +24,19 @@
 #if !defined (octave_symtab_h)
 #define octave_symtab_h 1
 
-#include <cassert>
-
-#include <string>
+#include <deque>
+#include <list>
+#include <map>
+#include <set>
 #include <stack>
-#include <sstream>
-
-#include "oct-alloc.h"
-#include "str-vec.h"
-
-#include "ov.h"
-
-class octave_lvalue;
-
-class string_vector;
-
-class symbol_record;
-class symbol_table;
-
-struct
-whos_parameter
-{
-  char command;
-  char modifier;
-  int parameter_length;
-  int first_parameter_length;
-  int dimensions;
-  int balance;
-  std::string text;
-  std::string line;
-};
-
-// Individual records in a symbol table.
-
-class
-OCTINTERP_API
-symbol_record
-{
-public:
-
-  // If you add or delete an entry here, you'll also need to change
-  // the width parameter in the declaration for symbol_type below...
-
-  enum TYPE
-    {
-      UNKNOWN = 0,
-      USER_FUNCTION = 1,
-      USER_VARIABLE = 2,
-      DLD_FUNCTION = 4,
-      BUILTIN_FUNCTION = 8,
-      COMMAND = 16,
-      RAWCOMMAND = 32,
-      MAPPER_FUNCTION = 64,
-      MEX_FUNCTION = 128
-    };
-
-private:
-
-  // Variables or functions.
-
-  class symbol_def
-  {
-  public:
-
-    symbol_def (const octave_value& val = octave_value (),
-		unsigned int sym_type = 0)
-      : symbol_type (sym_type), read_only (0), help_string (),
-	definition (val), count (1) { }
-
-    ~symbol_def (void) { }
-
-    bool is_variable (void) const
-      { return (symbol_type & symbol_record::USER_VARIABLE); }
-
-    // It's not necessary to check for COMMAND and MAPPER_FUNCTION
-    // here.  Those tags are just used as additional qualifiers for
-    // the other types of functions.
-
-    bool is_function (void) const
-      {
-	return (symbol_type & symbol_record::USER_FUNCTION
-		|| symbol_type & symbol_record::DLD_FUNCTION
-		|| symbol_type & symbol_record::MEX_FUNCTION
-		|| symbol_type & symbol_record::BUILTIN_FUNCTION);
-      }
-
-    bool is_user_variable (void) const
-      { return (symbol_type & symbol_record::USER_VARIABLE); }
-
-    // Don't use |= here to avoid error with AIX compiler.
-    void mark_as_command (void)
-      { symbol_type = symbol_type | symbol_record::COMMAND; }
-
-    void unmark_command (void)
-      { symbol_type &= ~symbol_record::COMMAND; }
-
-    bool is_command (void) const
-      { return (symbol_type & symbol_record::COMMAND); }
-
-    void mark_as_rawcommand (void)
-      { symbol_type |= (symbol_record::COMMAND
-			| symbol_record::RAWCOMMAND); }
-
-    void unmark_rawcommand (void)
-      { symbol_type &= ~symbol_record::RAWCOMMAND; }
-
-    bool is_rawcommand (void) const
-      { return (symbol_type & symbol_record::RAWCOMMAND); }      
-
-    bool is_mapper_function (void) const
-      { return (symbol_type & symbol_record::MAPPER_FUNCTION); }
-
-    bool is_user_function (void) const
-      { return (symbol_type & symbol_record::USER_FUNCTION); }
-
-    bool is_builtin_function (void) const
-      { return (symbol_type & symbol_record::BUILTIN_FUNCTION); }
-
-    bool is_dld_function (void) const
-      { return (symbol_type & symbol_record::DLD_FUNCTION); }
-
-    bool is_mex_function (void) const
-      { return (symbol_type & symbol_record::MEX_FUNCTION); }
-
-    // FIXME
-    bool is_map_element (const std::string& /* elts */) const
-      { return false; }
-
-    bool is_defined (void) const
-      { return definition.is_defined (); }
-
-    bool is_read_only (void) const
-      { return read_only; }
-
-    bool is_matrix_type (void) const 
-      { return definition.is_matrix_type (); }
-
-    bool is_sparse_type (void) const
-      { return definition.is_sparse_type (); }
-
-    bool is_complex_type (void) const
-      { return definition.is_complex_type (); }
-
-    std::string class_name (void) const
-      { return definition.class_name (); }
-
-    Matrix size (void) const
-      { return definition.size (); }
-
-    size_t byte_size (void) const
-      { return definition.byte_size (); };
-
-    octave_idx_type numel (void) const
-      { return definition.numel (); };
-
-    octave_idx_type capacity (void) const
-      { return definition.capacity (); };
-
-    dim_vector dims (void) const 
-      { return definition.dims (); }
-
-    octave_idx_type rows (void) const { return definition.rows (); }
-    octave_idx_type columns (void) const { return definition.columns (); }
-
-    std::string type_name (void) const { return definition.type_name (); }
-
-    std::string type_as_string (void) const;
-
-    void type (std::ostream& os, const std::string& name, bool pr_type_info,
-	       bool quiet, bool pr_orig_txt);
-
-    std::string which (const std::string& name);
-
-    void which (std::ostream& os, const std::string& name);
-
-    void define (const octave_value& val, unsigned int sym_type)
-      {
-	definition = val;
-	symbol_type = sym_type;
-      }
-
-    void protect (void) { read_only = 1; }
-
-    void unprotect (void) { read_only = 0; }
-
-    octave_value& def (void) { return definition; }
-
-    std::string help (void) const { return help_string; }
-
-    void document (const std::string& h);
-
-    unsigned int type (void) { return symbol_type; }
-
-    void *operator new (size_t size)
-      { return allocator.alloc (size); }
-
-    void operator delete (void *p, size_t size)
-      { allocator.free (p, size); }
-
-    static octave_allocator allocator;
-
-    // The type of this symbol (see the enum above).
-    unsigned int symbol_type : 9;
-
-    // Nonzero means this variable cannot be given a new value.
-    unsigned int read_only : 1;
-
-    // The doc string associated with this variable.
-    std::string help_string;
-
-    // The value of this definition.  See ov.h and related files.
-    octave_value definition;
-
-    // Reference count.
-    int count;
-
-    void print_info (std::ostream& os,
-		     const std::string& prefix = std::string ()) const;
-
-    // No copying!
-
-    symbol_def (const symbol_def& sd);
-
-    symbol_def& operator = (const symbol_def& sd);
-  };
-
-public:
-
-  typedef int (*change_function) (void);
+#include <string>
 
-  symbol_record (void)
-    : formal_param (false), automatic_variable (false),
-      linked_to_global (false), tagged_static (false),
-      can_hide_function (true), visible (true), eternal (false),
-      nm (), chg_fcn (0), definition (new symbol_def ()), next_elem (0) { }
-
-  // FIXME -- kluge alert!  We obviously need a better way of
-  // handling allow_shadow!
-
-  symbol_record (const std::string& n, symbol_record *nxt)
-    : formal_param (false), automatic_variable (false),
-      linked_to_global (false), tagged_static (false),
-      can_hide_function (n != "__end__"), visible (true),
-      eternal (false), nm (n), chg_fcn (0),
-      definition (new symbol_def ()), next_elem (nxt) { }
-
-  ~symbol_record (void)
-    {
-      if (--definition->count <= 0)
-	delete definition;
-    }
-
-  std::string name (void) const { return nm; }
-
-  std::string help (void) const { return definition->help (); }
-
-  octave_value& def (void) { return definition->def (); }
-
-  void rename (const std::string& new_name);
-
-  bool is_function (void) const
-    { return definition->is_function (); }
-
-  void mark_as_command (void)
-    { definition->mark_as_command (); }
-
-  void unmark_command (void)
-    { definition->unmark_command (); }
-
-  bool is_command (void) const
-    { return definition->is_command (); }
-
-  void mark_as_rawcommand (void)
-    { definition->mark_as_rawcommand (); }
-
-  void unmark_rawcommand (void)
-    { definition->unmark_rawcommand (); }
-
-  bool is_rawcommand (void) const
-    { return definition->is_rawcommand (); }    
-
-  bool is_mapper_function (void) const
-    { return definition->is_mapper_function (); }
-
-  bool is_user_function (void) const
-    { return definition->is_user_function (); }
-
-  bool is_builtin_function (void) const
-    { return definition->is_builtin_function (); }
-
-  bool is_dld_function (void) const
-    { return definition->is_dld_function (); }
-
-  bool is_mex_function (void) const
-    { return definition->is_mex_function (); }
-
-  bool is_variable (void) const
-    { return definition->is_variable (); }
-
-  bool is_user_variable (void) const
-    { return definition->is_user_variable (); }
-
-  bool is_map_element (const std::string& elts) const
-    { return definition->is_map_element (elts); }
-
-  unsigned int type (void) const { return definition->type (); }
-
-  bool is_defined (void) const { return definition->is_defined (); }
-
-  bool is_read_only (void) const { return definition->is_read_only (); }
-
-  bool is_eternal (void) const { return eternal; }
-
-  void protect (void) { definition->protect (); }
-
-  void unprotect (void) { definition->unprotect (); }
-
-  void make_eternal (void) { eternal = 1; }
-
-  void hide (void) { visible = false; }
-  void show (void) { visible = true; }
-  bool is_visible (void) const { return visible; }
-
-  void set_change_function (change_function f) { chg_fcn = f; }
-
-  void define (const octave_value& v, unsigned int sym_type = USER_VARIABLE);
-
-  bool define (octave_function *f, unsigned int sym_type);
-
-  void document (const std::string& h) { definition->document (h); }
-
-  void clear (void);
-
-  void alias (symbol_record *s, bool mark_to_clear = false);
-
-  void mark_as_formal_parameter (void);
-  bool is_formal_parameter (void) const { return formal_param; }
-
-  void mark_as_automatic_variable (void);
-  bool is_automatic_variable (void) const { return automatic_variable; }
-
-  void mark_as_linked_to_global (void);
-  bool is_linked_to_global (void) const { return linked_to_global; }
-
-  void mark_as_static (void);
-  bool is_static (void) const { return tagged_static; }
-  void unmark_static (void) { tagged_static = false; }
+#include "glob-match.h"
 
-  bool is_matrix_type (void) const 
-    { return definition->is_matrix_type (); }
-
-  bool is_sparse_type (void) const
-    { return definition->is_sparse_type (); }
-
-  bool is_complex_type (void) const
-    { return definition->is_complex_type (); }
-
-  std::string class_name (void) const
-    { return definition->class_name (); }
-
-  Matrix size (void) const
-    { return definition->size (); }
-
-  size_t byte_size (void) const
-    { return definition->byte_size (); };
-
-  octave_idx_type numel (void) const
-    { return definition->numel (); };
-
-  octave_idx_type capacity (void) const
-    { return definition->capacity (); };
-
-  dim_vector dims (void) const { return definition->dims (); }
-
-  int dimensions_string_req_first_space (int print_dims) const;
-
-  int dimensions_string_req_total_space (int print_dims) const;
-
-  std::string make_dimensions_string (int print_dims) const;
-
-  octave_idx_type rows (void) const { return definition->rows (); }
-  octave_idx_type columns (void) const { return definition->columns (); }
-
-  std::string type_name (void) const { return definition->type_name (); }
-
-  std::string type_as_string (void) const
-    { return definition->type_as_string (); }
-
-  void type (std::ostream& os, bool pr_type_info, bool quiet, bool pr_orig_txt)
-    { definition->type (os, name (), pr_type_info, quiet, pr_orig_txt); }
-
-  std::string which (void) { return definition->which (name ()); }
-
-  void which (std::ostream& os) { definition->which (os, name ()); }
-
-  octave_value& variable_value (void);
-  octave_lvalue variable_reference (void);
-
-  symbol_record *next (void) const { return next_elem; }
-
-  void chain (symbol_record *s) { next_elem = s; }
-
-  void push_context (void);
-
-  void pop_context (void);
-
-  void print_symbol_info_line (std::ostream& os,
-			       std::list<whos_parameter>& params) const;
+class tree_argument_list;
 
-  void print_info (std::ostream& os,
-		   const std::string& prefix = std::string ()) const;
-
-private:
-
-  unsigned int formal_param : 1;
-  unsigned int automatic_variable : 1;
-  unsigned int linked_to_global : 1;
-  unsigned int tagged_static : 1;
-  unsigned int can_hide_function : 1;
-  unsigned int visible : 1;
-  unsigned int eternal : 1;
-
-  std::string nm;
-  change_function chg_fcn;
-  symbol_def *definition;
-  symbol_record *next_elem;
-
-  // This should maybe be one stack with a structure containing all the
-  // items we need to save for recursive calls...
-  std::stack <symbol_def *> context;
-  std::stack <unsigned int> global_link_context;
-
-  std::stack <symbol_record *> aliases_to_clear;
-
-  void push_alias_to_clear (symbol_record *s)
-    { aliases_to_clear.push (s); }
-
-  bool read_only_error (const char *action);
-
-  void maybe_delete_def (void)
-    {
-      if (--definition->count <= 0)
-        delete definition;
-    }
-
-  // No copying!
-
-  symbol_record (const symbol_record& s);
-
-  symbol_record& operator = (const symbol_record& s);
-};
-
-// A symbol table.
-
-#define SYMTAB_LOCAL_SCOPE 1
-#define SYMTAB_GLOBAL_SCOPE 2
-
-#define SYMTAB_ALL_SCOPES (SYMTAB_LOCAL_SCOPE | SYMTAB_GLOBAL_SCOPE)
-
-#define SYMTAB_ALL_TYPES (symbol_record::USER_FUNCTION \
-			  | symbol_record::USER_VARIABLE \
-			  | symbol_record::DLD_FUNCTION \
-			  | symbol_record::BUILTIN_FUNCTION \
-			  | symbol_record::COMMAND \
-  			  | symbol_record::RAWCOMMAND \
-			  | symbol_record::MAPPER_FUNCTION \
-			  | symbol_record::MEX_FUNCTION)
-
-#define SYMTAB_VARIABLES (symbol_record::USER_VARIABLE)
+#include "oct-obj.h"
+#include "ov.h"
 
 class
 OCTINTERP_API
@@ -499,135 +44,1737 @@
 {
 public:
 
-  symbol_table (unsigned int tab_size = 64,
-		const std::string& nm = std::string ())
-    : table_size (tab_size), table (new symbol_record [table_size]),
-      table_name (nm)
+  typedef int scope_id;
+
+  class
+  symbol_record
+  {
+  public:
+
+    // generic variable
+    static const unsigned int local = 1;
+
+    // varargin, argn, .nargin., .nargout.
+    // (FIXME -- is this really used now?)
+    static const unsigned int automatic = 2;
+
+    // formal parameter
+    static const unsigned int formal = 4;
+
+    // not listed or cleared (.nargin., .nargout.)
+    static const unsigned int hidden = 8;
+
+    // inherited from parent scope; not cleared at function exit
+    static const unsigned int inherited = 16;
+
+    // global (redirects to global scope)
+    static const unsigned int global = 32;
+
+    // not cleared at function exit
+    static const unsigned int persistent = 64;
+
+  private:
+
+    class
+    symbol_record_rep
     {
-      assert ((tab_size % 2) == 0);
+    public:
+
+      symbol_record_rep (const std::string& nm, const octave_value& v,
+			 unsigned int sc)
+	: name (nm), value_stack (), storage_class (sc), count (1)
+      {
+	value_stack.push (v);
+      }
+
+      octave_value& varref (void) { return value_stack.top (); }
+
+      octave_value varval (void) const { return value_stack.top (); }
+
+      void push_context (void) { value_stack.push (octave_value ()); }
+
+      void pop_context (void) { value_stack.pop (); }
+
+      void clear (void)
+      {
+	if (! (is_hidden () || is_inherited ()))
+	  {
+	    if (is_global ())
+	      unmark_global ();
+
+	    if (is_persistent ())
+	      {
+		symbol_table::persistent_varref (name) = varval ();
+		unmark_persistent ();
+	      }
+
+	    varref () = octave_value ();
+	  }
+      }
+
+      bool is_defined (void) const { return varval ().is_defined (); }
+
+      bool is_variable (void) const
+      {
+	return (storage_class != local || is_defined ());
+      }
+
+      bool is_local (void) const { return storage_class & local; }
+      bool is_automatic (void) const { return storage_class & automatic; }
+      bool is_formal (void) const { return storage_class & formal; }
+      bool is_hidden (void) const { return storage_class & hidden; }
+      bool is_inherited (void) const { return storage_class & inherited; }
+      bool is_global (void) const { return storage_class & global; }
+      bool is_persistent (void) const { return storage_class & persistent; }
+
+      void mark_local (void) { storage_class |= local; }
+      void mark_automatic (void) { storage_class |= automatic; }
+      void mark_formal (void) { storage_class |= formal; }
+      void mark_hidden (void) { storage_class |= hidden; }
+      void mark_inherited (void) { storage_class |= inherited; }
+      void mark_global (void)
+      {
+	if (is_persistent ())
+	  error ("can't make persistent variable %s global", name.c_str ());
+	else
+	  storage_class |= global;
+      }
+      void mark_persistent (void)
+      {
+	if (is_global ())
+	  error ("can't make global variable %s persistent", name.c_str ());
+	else
+	  storage_class |= persistent;
+      }
+
+      void unmark_local (void) { storage_class &= ~local; }
+      void unmark_automatic (void) { storage_class &= ~automatic; }
+      void unmark_formal (void) { storage_class &= ~formal; }
+      void unmark_hidden (void) { storage_class &= ~hidden; }
+      void unmark_inherited (void) { storage_class &= ~inherited; }
+      void unmark_global (void) { storage_class &= ~global; }
+      void unmark_persistent (void) { storage_class &= ~persistent; }
+
+      void init_persistent (void)
+      {
+	if (! is_defined ())
+	  {
+	    mark_persistent ();
+
+	    varref () = symbol_table::persistent_varval (name);
+	  }
+	// FIXME -- this causes trouble with recursive calls.
+	// else
+	//   error ("unable to declare existing variable persistent");
+      }
+
+      void erase_persistent (void)
+      {
+	unmark_persistent ();
+	symbol_table::erase_persistent (name);
+      }
+
+      symbol_record_rep *dup (void)
+      {
+	return new symbol_record_rep (name, varval (), storage_class);
+      }
+
+      std::string name;
+
+      std::stack<octave_value> value_stack;
+
+      unsigned int storage_class;
+
+      size_t count;
+
+    private:
+
+      // No copying!
+
+      symbol_record_rep (const symbol_record_rep& ov);
+
+      symbol_record_rep& operator = (const symbol_record_rep&);
+    };
+
+  public:
+
+    symbol_record (const std::string& nm = std::string (),
+		   const octave_value& v = octave_value (),
+		   unsigned int sc = local)
+      : rep (new symbol_record_rep (nm, v, sc)) { }
+
+    symbol_record (const symbol_record& sr)
+      : rep (sr.rep)
+    { 
+      rep->count++;
+    }
+
+    symbol_record& operator = (const symbol_record& sr)
+    {
+      if (this != &sr)
+	{
+	  rep = sr.rep;
+	  rep->count++;
+	}
+
+      return *this;
+    }
+
+    ~symbol_record (void)
+    {
+      if (--rep->count == 0)
+	delete rep;
+    }
+
+    symbol_record dup (void) const { return symbol_record (rep->dup ()); }
+
+    std::string name (void) const { return rep->name; }
+
+    octave_value
+    find (tree_argument_list *args, const string_vector& arg_names,
+	  octave_value_list& evaluated_args, bool& args_evaluated) const;
+
+    octave_value& varref (void)
+    {
+      return is_global ()
+	? symbol_table::varref (name (), symbol_table::global_scope ())
+	: rep->varref ();
+    }
+
+    octave_value varval (void) const
+    {
+      return is_global ()
+	? symbol_table::varval (name (), symbol_table::global_scope ())
+	: rep->varval ();
+    }
+
+    void push_context (void)
+    {
+      if (! (is_persistent () || is_global ()))
+	rep->push_context ();
+    }
+
+    void pop_context (void)
+    {
+      if (! (is_persistent () || is_global ()))
+	rep->pop_context ();
+    }
+
+    void clear (void) { rep->clear (); }
+
+    bool is_defined (void) const { return rep->is_defined (); }
+    bool is_variable (void) const { return rep->is_variable (); }
+
+    bool is_local (void) const { return rep->is_local (); }
+    bool is_automatic (void) const { return rep->is_automatic (); }
+    bool is_formal (void) const { return rep->is_formal (); }
+    bool is_global (void) const { return rep->is_global (); }
+    bool is_hidden (void) const { return rep->is_hidden (); }
+    bool is_inherited (void) const { return rep->is_inherited (); }
+    bool is_persistent (void) const { return rep->is_persistent (); }
+
+    void mark_local (void) { rep->mark_local (); }
+    void mark_automatic (void) { rep->mark_automatic (); }
+    void mark_formal (void) { rep->mark_formal (); }
+    void mark_hidden (void) { rep->mark_hidden (); }
+    void mark_inherited (void) { rep->mark_inherited (); }
+    void mark_global (void) { rep->mark_global (); }
+    void mark_persistent (void) { rep->mark_persistent (); }
+
+    void unmark_local (void) { rep->unmark_local (); }
+    void unmark_automatic (void) { rep->unmark_automatic (); }
+    void unmark_formal (void) { rep->unmark_formal (); }
+    void unmark_hidden (void) { rep->unmark_hidden (); }
+    void unmark_inherited (void) { rep->unmark_inherited (); }
+    void unmark_global (void) { rep->unmark_global (); }
+    void unmark_persistent (void) { rep->unmark_persistent (); }
+
+    void init_persistent (void) { rep->init_persistent (); }
+
+    void erase_persistent (void) { rep->erase_persistent (); }
+
+    unsigned int xstorage_class (void) const { return rep->storage_class; }
+
+  private:
+
+    symbol_record_rep *rep;
+
+    symbol_record (symbol_record_rep *new_rep) : rep (new_rep) { }
+  };
+
+  class
+  fcn_info
+  {
+  public:
+
+    typedef std::map<std::string, std::string> dispatch_map_type;
+
+    typedef std::map<scope_id, octave_value>::const_iterator const_scope_val_iterator;
+    typedef std::map<scope_id, octave_value>::iterator scope_val_iterator;
 
-      if (table_name.empty ())
+    typedef std::map<std::string, octave_value>::const_iterator const_str_val_iterator;
+    typedef std::map<std::string, octave_value>::iterator str_val_iterator;
+
+    typedef dispatch_map_type::const_iterator const_dispatch_map_iterator;
+    typedef dispatch_map_type::iterator dispatch_map_iterator;
+
+  private:
+
+    class
+    fcn_info_rep
+    {
+    public:
+
+      fcn_info_rep (const std::string& nm)
+	: name (nm), subfunctions (), private_functions (),
+	  class_constructors (), class_methods (), cmdline_function (),
+	  autoload_function (), function_on_path (), built_in_function (),
+	  count (1) { }
+
+      octave_value load_private_function (const std::string& dir_name);
+
+      octave_value load_class_constructor (void);
+
+      octave_value load_class_method (const std::string& dispatch_type);
+
+      octave_value
+      find (tree_argument_list *args, const string_vector& arg_names,
+	    octave_value_list& evaluated_args, bool& args_evaluated,
+	    scope_id scope);
+
+      octave_value find_method (const std::string& dispatch_type);
+
+      octave_value find_autoload (void);
+
+      octave_value find_user_function (void);
+
+      bool is_user_function_defined (void) const
+      {
+	return function_on_path.is_defined ();
+      }
+
+      octave_value find_function (scope_id scope)
+      {
+	octave_value_list args;
+
+	return find_function (args, scope);
+      }
+
+      octave_value find_function (const octave_value_list& args,
+				  scope_id scope)
+      {
+	string_vector arg_names;
+	octave_value_list evaluated_args = args;
+	bool args_evaluated;
+
+	return find (0, arg_names, evaluated_args, args_evaluated, scope);
+      }
+
+      void install_cmdline_function (const octave_value& f)
+      {
+	cmdline_function = f;
+      }
+
+      void install_subfunction (const octave_value& f, scope_id scope)
+      {
+	subfunctions[scope] = f;
+      }
+
+      void install_user_function (const octave_value& f)
+      {
+	function_on_path = f;
+      }
+
+      void install_built_in_function (const octave_value& f)
+      {
+	built_in_function = f;
+      }
+
+      void clear (void)
+      {
+	subfunctions.clear ();
+	private_functions.clear ();
+	class_constructors.clear ();
+	class_methods.clear ();
+	cmdline_function = octave_value ();
+	autoload_function = octave_value ();
+	function_on_path = octave_value ();
+      }
+
+      // FIXME -- should this also clear the cmdline and other "user
+      // defined" functions?
+      void clear_user_function (void)
+      {
+	function_on_path = octave_value ();
+      }
+
+      void clear_mex_function (void)
+      {
+	if (function_on_path.is_mex_function ())
+	  function_on_path = octave_value ();
+      }
+
+      void add_dispatch (const std::string& type, const std::string& fname)
+      {
+	dispatch_map[type] = fname;
+      }
+
+      void clear_dispatch (const std::string& type)
+      {
+	dispatch_map_iterator p = dispatch_map.find (type);
+
+	if (p != dispatch_map.end ())
+	  dispatch_map.erase (p);
+      }
+
+      void print_dispatch (std::ostream& os) const;
+
+      std::string help_for_dispatch (void) const;
+
+      dispatch_map_type get_dispatch (void) const { return dispatch_map; }
+
+      std::string name;
+
+      // Scope id to function object.
+      std::map<scope_id, octave_value> subfunctions;
+
+      // Directory name to function object.
+      std::map<std::string, octave_value> private_functions;
+
+      // Class name to function object.
+      std::map<std::string, octave_value> class_constructors;
+
+      // Dispatch type to function object.
+      std::map<std::string, octave_value> class_methods;
+
+      // Legacy dispatch map (dispatch type name to function name).
+      dispatch_map_type dispatch_map;
+
+      octave_value cmdline_function;
+
+      octave_value autoload_function;
+
+      octave_value function_on_path;
+
+      octave_value built_in_function;
+
+      size_t count;
+
+    private:
+
+      // No copying!
+
+      fcn_info_rep (const fcn_info_rep&);
+
+      fcn_info_rep& operator = (const fcn_info_rep&);
+    };
+
+  public:
+
+    fcn_info (const std::string& nm = std::string ())
+      : rep (new fcn_info_rep (nm)) { }
+
+    fcn_info (const fcn_info& ov) : rep (ov.rep)
+    { 
+      rep->count++;
+    }
+
+    fcn_info& operator = (const fcn_info& ov)
+    {
+      if (this != &ov)
 	{
-	  std::ostringstream buf;
-	  buf << symtab_count++;
-	  table_name = buf.str ();
+	  rep = ov.rep;
+	  rep->count++;
 	}
+
+      return *this;
+    }
+
+    ~fcn_info (void)
+    {
+      if (--rep->count == 0)
+	delete rep;
+    }
+
+    octave_value
+    find (tree_argument_list *args, const string_vector& arg_names,
+	  octave_value_list& evaluated_args, bool& args_evaluated,
+	  scope_id scope);
+
+    octave_value find_method (const std::string& dispatch_type) const
+    {
+      return rep->find_method (dispatch_type);
+    }
+
+    octave_value find_built_in_function (void) const
+    {
+      return rep->built_in_function;
+    }
+
+    octave_value find_autoload (void)
+    {
+      return rep->find_autoload ();
+    }
+
+    octave_value find_user_function (void)
+    {
+      return rep->find_user_function ();
+    }
+
+    bool is_user_function_defined (void) const
+    {
+      return rep->is_user_function_defined ();
+    }
+
+    octave_value find_function (scope_id scope)
+    {
+      return rep->find_function (scope);
+    }
+
+    octave_value find_function (const octave_value_list& args,
+				scope_id scope)
+    {
+      return rep->find_function (args, scope);
+    }
+
+    void install_cmdline_function (const octave_value& f)
+    {
+      rep->install_cmdline_function (f);
+    }
+
+    void install_subfunction (const octave_value& f, scope_id scope)
+    {
+      rep->install_subfunction (f, scope);
+    }
+
+    void install_user_function (const octave_value& f)
+    {
+      rep->install_user_function (f);
+    }
+
+    void install_built_in_function (const octave_value& f)
+    {
+      rep->install_built_in_function (f);
+    }
+
+    void clear (void) { rep->clear (); }
+    
+    void clear_user_function (void) { rep->clear_user_function (); }
+    
+    void clear_mex_function (void) { rep->clear_mex_function (); }
+    
+    void add_dispatch (const std::string& type, const std::string& fname)
+    {
+      rep->add_dispatch (type, fname);
+    }
+
+    void clear_dispatch (const std::string& type)
+    {
+      rep->clear_dispatch (type);
+    }
+
+    void print_dispatch (std::ostream& os) const
+    {
+      rep->print_dispatch (os);
+    }
+
+    std::string help_for_dispatch (void) const { return rep->help_for_dispatch (); }
+
+    dispatch_map_type get_dispatch (void) const
+    {
+      return rep->get_dispatch ();
     }
 
-  ~symbol_table (void);
+  private:
+
+    fcn_info_rep *rep;
+  };
+
+  static scope_id global_scope (void) { return xglobal_scope; }
+  static scope_id top_scope (void) { return xtop_scope; }
+
+  static scope_id current_scope (void) { return xcurrent_scope; }
+  static scope_id current_caller_scope (void) { return xcurrent_caller_scope; }
+
+  // We use parent_scope to handle parsing subfunctions.
+  static scope_id parent_scope (void) { return xparent_scope; }
+
+  static scope_id alloc_scope (void)
+  {
+    scope_id retval;
+
+    scope_ids_free_list_iterator p = scope_ids_free_list.begin ();
+
+    if (p != scope_ids_free_list.end ())
+      {
+	retval = *p;
+	scope_ids_free_list.erase (p);
+      }
+    else
+      retval = next_available_scope++;
+
+    scope_ids_in_use.insert (retval);
+
+    return retval;
+  }
+
+  static void set_scope (scope_id scope)
+  {
+    if (scope == xglobal_scope)
+      error ("can't set scope to global");
+    else if (scope != xcurrent_scope)
+      {
+	all_instances_iterator p = all_instances.find (scope);
+
+	if (p == all_instances.end ())
+	  {
+	    instance = new symbol_table ();
 
-  symbol_record *lookup (const std::string& nm, bool insert = false,
-			 bool warn = false);
+	    all_instances[scope] = instance;
+	  }
+	else
+	  instance = p->second;
+
+	xcurrent_scope = scope;
+      }
+  }
+
+  static void push_scope (scope_id scope)
+  {
+    if (scope_stack.empty ())
+      scope_stack.push_front (xtop_scope);
+
+    xcurrent_caller_scope = xcurrent_scope;
+
+    set_scope (scope);
+
+    scope_stack.push_front (scope);
+  }
+
+  static void pop_scope (void)
+  {
+    scope_stack.pop_front ();
 
-  void rename (const std::string& old_name, const std::string& new_name);
+    set_scope (scope_stack[0]);
+
+    xcurrent_caller_scope = scope_stack[1];
+  }
+
+  static void pop_scope (void *) { pop_scope (); }
+
+  static void reset_scope (void)
+  {
+    scope_stack.clear ();
+
+    scope_stack.push_front (xtop_scope);
 
-  void clear (void);
+    set_scope (xtop_scope);
+
+    xcurrent_caller_scope = -1;
+  }
+
+  static void set_parent_scope (scope_id scope)
+  {
+    xparent_scope = scope;
+  }
+
+  static void reset_parent_scope (void)
+  {
+    set_parent_scope (-1);
+  }
 
-  void clear_variables (void);
-  void clear_functions (void);
-  void clear_mex_functions (void);
-  void clear_globals (void);
+  static void erase_scope (scope_id scope = xcurrent_scope)
+  {
+    all_instances_iterator p = all_instances.find (scope);
+
+    if (p != all_instances.end ())
+      all_instances.erase (p);
+
+    // free_scope (scope);
+  }
+
+  static scope_id dup_scope (scope_id scope = xcurrent_scope)
+  {
+    scope_id retval = -1;
+
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      {
+	scope_id new_scope = alloc_scope ();
+
+	symbol_table *new_symbol_table = new symbol_table ();
+
+	if (new_symbol_table)
+	  {
+	    all_instances[new_scope] = new_symbol_table;
+
+	    inst->do_dup_scope (*new_symbol_table);
+
+	    retval = new_scope;
+	  }
+      }
+
+    return retval;
+  }
+
+#if 0
+  static void print_scope (const std::string& tag, scope_id scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      {
+	std::cerr << "printing " << tag << ", scope: " << scope
+		  << ", inst: " << inst << std::endl;
+
+	inst->do_print_scope (std::cerr);
+      }
+  }
 
-  bool clear (const std::string& nm);
+  void do_print_scope (std::ostream& os) const
+  {
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	symbol_record sr = p->second;
+
+	octave_value val = sr.varval ();
+
+	if (val.is_defined ())
+	  sr.varval ().print_with_name (os, sr.name ());
+	else
+	  os << sr.name () << " is not defined" << std::endl;
+      }
+  }
+#endif
+
+  static symbol_record find_symbol (const std::string& name,
+				    scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_find_symbol (name) : symbol_record ();
+  }
 
-  bool clear_variable (const std::string& nm);
-  bool clear_function (const std::string& nm);
-  bool clear_global (const std::string& nm);
+  static void inherit (scope_id scope, scope_id donor_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_inherit (donor_scope);
+  }
+
+  static bool at_top_level (void) { return xcurrent_scope == xtop_scope; }
+
+  // Find a value corresponding to the given name in the table.
+  static octave_value
+  find (const std::string& name, tree_argument_list *args,
+	const string_vector& arg_names,
+	octave_value_list& evaluated_args, bool& args_evaluated,
+	scope_id scope = xcurrent_scope, bool skip_variables = false);
+
+  // Insert a new name in the table.
+  static symbol_record&
+  insert (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    static symbol_record foobar;
+
+    symbol_table *inst = get_instance (scope);
 
-  bool clear_variable_pattern (const std::string& pat);
-  bool clear_function_pattern (const std::string& pat);
-  bool clear_global_pattern (const std::string& pat);
+    return inst ? inst->do_insert (name) : foobar;
+  }
+
+  static octave_value&
+  varref (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    static octave_value foobar;
+
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_varref (name) : foobar;
+  }
+
+  static octave_value
+  varval (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_varval (name) : octave_value ();
+  }
+
+  static octave_value&
+  persistent_varref (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    static octave_value foobar;
+
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_persistent_varref (name) : foobar;
+  }
+
+  static octave_value
+  persistent_varval (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_persistent_varval (name) : octave_value ();
+  }
+
+  static void
+  erase_persistent (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_erase_persistent (name);
+  }
 
-  int size (void) const;
+  static bool
+  is_variable (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_is_variable (name) : false;
+  }
+
+  static bool
+  is_built_in_function_name (const std::string& name)
+  {
+    octave_value val = find_built_in_function (name);
+
+    return val.is_defined ();
+  }
+
+  static octave_value
+  find_method (const std::string& name, const std::string& dispatch_type)
+  {
+    const_fcn_table_iterator p = fcn_table.find (name);
 
-  Array<symbol_record *>
-  subsymbol_list (const string_vector& pats = string_vector (),
-		  unsigned int type = SYMTAB_ALL_TYPES,
-		  unsigned int scope = SYMTAB_ALL_SCOPES) const;
+    if (p != fcn_table.end ())
+      return p->second.find_method (dispatch_type);
+    else
+      {
+	fcn_info finfo (name);
+
+	octave_value fcn = finfo.find_method (dispatch_type);
+
+	if (fcn.is_defined ())
+	  fcn_table[name] = finfo;
+
+	return fcn;
+      }
+  }
+
+  static octave_value
+  find_built_in_function (const std::string& name)
+  {
+    const_fcn_table_iterator p = fcn_table.find (name);
+
+    return (p != fcn_table.end ())
+      ? p->second.find_built_in_function () : octave_value ();
+  }
+
+  static octave_value
+  find_autoload (const std::string& name)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
 
-  Array<symbol_record *>
-  symbol_list (const string_vector& pats = string_vector (),
-	       unsigned int type = SYMTAB_ALL_TYPES,
-	       unsigned int scope = SYMTAB_ALL_SCOPES) const;
+    return (p != fcn_table.end ())
+      ? p->second.find_autoload () : octave_value ();
+  }
+
+  static octave_value
+  find_function (const std::string& name, tree_argument_list *args,
+		 const string_vector& arg_names,
+		 octave_value_list& evaluated_args, bool& args_evaluated,
+		 scope_id scope = xcurrent_scope);
+
+  static octave_value
+  find_user_function (const std::string& name)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    return (p != fcn_table.end ())
+      ? p->second.find_user_function () : octave_value ();
+  }
+
+  static octave_value
+  find_function (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    octave_value_list evaluated_args;
+
+    return find_function (name, evaluated_args, scope);
+  }
+
+  static octave_value
+  find_function (const std::string& name, const octave_value_list& args,
+		 scope_id scope = xcurrent_scope)
+  {
+    string_vector arg_names;
+    octave_value_list evaluated_args = args;
+    bool args_evaluated = ! args.empty ();
+
+    return find_function (name, 0, arg_names, evaluated_args,
+			  args_evaluated, scope);
+  }
+
+  static void install_cmdline_function (const std::string& name,
+					const octave_value& fcn)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
 
+	finfo.install_cmdline_function (fcn);
+      }
+    else
+      {
+	fcn_info finfo (name);
 
-  string_vector
-  name_list (const string_vector& pats = string_vector (),
-	     bool sort = false, unsigned int type = SYMTAB_ALL_TYPES,
-	     unsigned int scope = SYMTAB_ALL_SCOPES) const;
+	finfo.install_cmdline_function (fcn);
+
+	fcn_table[name] = finfo;
+      }
+  }
+
+  static void install_subfunction (const std::string& name,
+				   const octave_value& fcn,
+				   scope_id scope = xparent_scope)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.install_subfunction (fcn, scope);
+      }
+    else
+      {
+	fcn_info finfo (name);
+
+	finfo.install_subfunction (fcn, scope);
+
+	fcn_table[name] = finfo;
+      }
+  }
+
+  static void install_user_function (const std::string& name,
+				     const octave_value& fcn)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.install_user_function (fcn);
+      }
+    else
+      {
+	fcn_info finfo (name);
+
+	finfo.install_user_function (fcn);
+
+	fcn_table[name] = finfo;
+      }
+  }
 
-  string_vector
-  user_function_name_list (void) const
-    {
-      return name_list
-	(string_vector (), false,
-	 symbol_record::USER_FUNCTION|symbol_record::DLD_FUNCTION|symbol_record::MEX_FUNCTION,
-	 SYMTAB_ALL_SCOPES);
-    }
+  static void install_built_in_function (const std::string& name,
+					 const octave_value& fcn)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.install_built_in_function (fcn);
+      }
+    else
+      {
+	fcn_info finfo (name);
+
+	finfo.install_built_in_function (fcn);
+
+	fcn_table[name] = finfo;
+      }
+  }
+
+  static void clear (const std::string& name, scope_id scope = xcurrent_scope)
+  {
+    clear_variable (name, scope);
+  }
+
+  static void clear_all (void)
+  {
+    clear_variables ();
+
+    clear_functions ();
+  }
+
+  static void clear_variables (scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_clear_variables ();
+  }
+
+  // For unwind_protect.
+  static void clear_variables (void *) { clear_variables (); }
+
+  static void clear_functions (void)
+  {
+    for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)
+      p->second.clear ();
+  }
+
+  static void clear_function (const std::string& name)
+  {
+    clear_user_function (name);
+  }
+
+  static void clear_global (const std::string& name,
+			    scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_clear_global (name);
+  }
+
+  static void clear_variable (const std::string& name,
+			      scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_clear_variable (name);
+  }
+
+  static void clear_symbol (const std::string& name)
+  {
+    // FIXME -- are we supposed to do both here?
+
+    clear_variable (name);
+    clear_function (name);
+  }
+
+  static void clear_function_pattern (const std::string& pat)
+  {
+    glob_match pattern (pat);
+
+    for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)
+      {
+	if (pattern.match (p->first))
+	  p->second.clear_user_function ();
+      }
+  }
+
+  static void clear_global_pattern (const std::string& pat,
+				    scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
 
-  string_vector
-  global_variable_name_list (void) const
-    {
-      return name_list
-	(string_vector (), false, SYMTAB_VARIABLES, SYMTAB_GLOBAL_SCOPE);
-    }
+    if (inst)
+      inst->do_clear_global_pattern (pat);
+  }
+
+  static void clear_variable_pattern (const std::string& pat,
+				      scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_clear_variable_pattern (pat);
+  }
+
+  static void clear_symbol_pattern (const std::string& pat)
+  {
+    // FIXME -- are we supposed to do both here?
+
+    clear_variable_pattern (pat);
+    clear_function_pattern (pat);
+  }
+
+  static void clear_user_function (const std::string& name)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.clear_user_function ();
+      }
+    // FIXME -- is this necessary, or even useful?
+    // else
+    //   error ("clear: no such function `%s'", name.c_str ());
+  }
+
+  static void clear_mex_functions (void)
+  {
+    for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.clear_mex_function ();
+      }
+  }
+
+  static void alias_built_in_function (const std::string& alias,
+				       const std::string& name)
+  {
+    octave_value fcn = find_built_in_function (name);
+
+    if (fcn.is_defined ())
+      {
+	fcn_info finfo (alias);
+
+	finfo.install_built_in_function (fcn);
+
+	fcn_table[alias] = finfo;
+      }
+    else
+      panic ("alias: `%s' is undefined", name.c_str ());
+  }
+
+  static void add_dispatch (const std::string& name, const std::string& type,
+			    const std::string& fname)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.add_dispatch (type, fname);
+      }
+    else
+      {
+	fcn_info finfo (name);
+
+	finfo.add_dispatch (type, fname);
+
+	fcn_table[name] = finfo;
+      }
+  }
+
+  static void clear_dispatch (const std::string& name, const std::string& type)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.clear_dispatch (type);
+      }
+  }
+
+  static void print_dispatch (std::ostream& os, const std::string& name)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
 
-  string_vector
-  variable_name_list (void) const
-    {
-      return name_list
-	(string_vector (), false, SYMTAB_VARIABLES, SYMTAB_LOCAL_SCOPE);
-    }
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.print_dispatch (os);
+      }
+  }
+
+  static fcn_info::dispatch_map_type get_dispatch (const std::string& name)
+  {
+    fcn_info::dispatch_map_type retval;
+
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	retval = finfo.get_dispatch ();
+      }
+
+    return retval;
+  }
+
+  static std::string help_for_dispatch (const std::string& name)
+  {
+    std::string retval;
+
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	retval = finfo.help_for_dispatch ();
+      }
+
+    return retval;
+  }
+
+  static void push_context (scope_id scope = xcurrent_scope)
+  {
+    if (scope == xglobal_scope || scope == xtop_scope)
+      error ("invalid call to xymtab::push_context");
+    else
+      {
+	symbol_table *inst = get_instance (scope);
+
+	if (inst)
+	  inst->do_push_context ();
+      }
+  }
+
+  static void pop_context (scope_id scope = xcurrent_scope)
+  {
+    if (scope == xglobal_scope || scope == xtop_scope)
+      error ("invalid call to xymtab::push_context");
+    else
+      {
+	symbol_table *inst = get_instance (scope);
+
+	if (inst)
+	  inst->do_pop_context ();
+      }
+  }
+
+  // For unwind_protect.
+  static void pop_context (void *) { pop_context (); }
+
+  static void mark_hidden (const std::string& name,
+			   scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_mark_hidden (name);
+  }
+
+  static void mark_global (const std::string& name,
+			   scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    if (inst)
+      inst->do_mark_global (name);
+  }
+
+  static std::list<symbol_record>
+  all_variables (scope_id scope = xcurrent_scope, bool defined_only = true)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst
+      ? inst->do_all_variables (defined_only) : std::list<symbol_record> ();
+  }
 
-  int maybe_list (const char *header, const string_vector& argv,
-		  std::ostream& os, bool show_verbose,
-		  unsigned type, unsigned scope);
-  
-  Array<symbol_record *> glob (const std::string& pat = std::string ("*"),
-			       unsigned int type = SYMTAB_ALL_TYPES,
-			       unsigned int scope = SYMTAB_ALL_SCOPES) const;
+  static std::list<symbol_record>
+  glob (const std::string& pattern, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_glob (pattern) : std::list<symbol_record> ();
+  }
+
+  static std::list<symbol_record>
+  glob_variables (const std::string& pattern, scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_glob (pattern, true) : std::list<symbol_record> ();
+  }
+
+  static std::list<symbol_record>
+  glob_variables (const string_vector& patterns,
+		  scope_id scope = xcurrent_scope)
+  {
+    std::list<symbol_record> retval;
+
+    size_t len = patterns.length ();
 
-  void push_context (void);
+    for (size_t i = 0; i < len; i++)
+      {
+	std::list<symbol_record> tmp = glob_variables (patterns[i], scope);
+
+	retval.insert (retval.begin (), tmp.begin (), tmp.end ());
+      }
+
+    return retval;
+  }
+
+  static std::list<std::string> user_function_names (void)
+  {
+    std::list<std::string> retval;
+
+    for (fcn_table_iterator p = fcn_table.begin ();
+	 p != fcn_table.end (); p++)
+      {
+	if (p->second.is_user_function_defined ())
+	  retval.push_back (p->first);
+      }
+
+    if (! retval.empty ())
+      retval.sort ();
+
+    return retval;
+  }
 
-  void pop_context (void);
+  static std::list<std::string>
+  variable_names (scope_id scope = xcurrent_scope)
+  {
+    symbol_table *inst = get_instance (scope);
+
+    return inst ? inst->do_variable_names () : std::list<std::string> ();
+  }
+
+  static std::list<std::string> built_in_function_names (void)
+  {
+    std::list<std::string> retval;
+
+    for (const_fcn_table_iterator p = fcn_table.begin ();
+	 p != fcn_table.end (); p++)
+      {
+	octave_value fcn = p->second.find_built_in_function ();
+
+	if (fcn.is_defined ())
+	  retval.push_back (p->first);
+      }
+
+    if (! retval.empty ())
+      retval.sort ();
 
-  // Create a new symbol table with the same entries.  Only the symbol
-  // names and some attributes are copied, not values.
-  symbol_table *dup (void);
+    return retval;
+  }
+
+  static bool is_local_variable (const std::string& name,
+				 scope_id scope = xcurrent_scope)
+  {
+    if (scope == xglobal_scope)
+      return false;
+    else
+      {
+	symbol_table *inst = get_instance (scope);
 
-  // Inherit some values from the parent_sym_tab.
-  void inherit (symbol_table *parent_sym_tab);
+	return inst ? inst->do_is_local_variable (name) : false;
+      }
+  }
 
-  void print_info (std::ostream& os) const;
+  static bool is_global (const std::string& name,
+			 scope_id scope = xcurrent_scope)
+  {
+    if (scope == xglobal_scope)
+      return true;
+    else
+      {
+	symbol_table *inst = get_instance (scope);
+
+	return inst ? inst->do_is_global (name) : false;
+      }
+  }
 
 private:
 
-  unsigned int table_size;
+  typedef std::map<std::string, symbol_record>::const_iterator const_table_iterator;
+  typedef std::map<std::string, symbol_record>::iterator table_iterator;
+
+  typedef std::map<std::string, octave_value>::const_iterator const_persistent_table_iterator;
+  typedef std::map<std::string, octave_value>::iterator persistent_table_iterator;
+
+  typedef std::map<scope_id, symbol_table*>::const_iterator all_instances_const_iterator;
+  typedef std::map<scope_id, symbol_table*>::iterator all_instances_iterator;
+
+  typedef std::map<std::string, fcn_info>::const_iterator const_fcn_table_iterator;
+  typedef std::map<std::string, fcn_info>::iterator fcn_table_iterator;
+
+  typedef std::set<scope_id>::const_iterator scope_ids_free_list_const_iterator;
+  typedef std::set<scope_id>::iterator scope_ids_free_list_iterator;
+
+  typedef std::set<scope_id>::const_iterator scope_ids_in_use_const_iterator;
+  typedef std::set<scope_id>::iterator scope_ids_in_use_iterator;
+
+  // Map from symbol names to symbol info.
+  std::map<std::string, symbol_record> table;
+
+  // Map from names of persistent variables to values.
+  std::map<std::string, octave_value> persistent_table;
+
+  // Pointer to symbol table for current scope (variables only).
+  static symbol_table *instance;
 
-  symbol_record *table;
+  // Map from scope id to symbol table instances.
+  static std::map<scope_id, symbol_table*> all_instances;
+
+  // Map from function names to function info (subfunctions, private
+  // functions, class constructors, class methods, etc.)
+  static std::map<std::string, fcn_info> fcn_table;
+
+  static const scope_id xglobal_scope;
+  static const scope_id xtop_scope;
+
+  static scope_id xcurrent_scope;
+  static scope_id xcurrent_caller_scope;
+
+  // We use parent_scope to handle parsing subfunctions.
+  static scope_id xparent_scope;
+
+  static std::deque<scope_id> scope_stack;
+
+  // The next available scope ID.
+  static scope_id next_available_scope;
+
+  // The set of scope IDs that are currently allocated.
+  static std::set<scope_id> scope_ids_in_use;
+
+  // The set of scope IDs that are currently available.
+  static std::set<scope_id> scope_ids_free_list;
+
+  symbol_table (void) : table () { }
+
+  ~symbol_table (void) { }
 
-  std::string table_name;
+  static void free_scope (scope_id scope)
+  {
+    if (scope == xglobal_scope || scope == xtop_scope)
+      error ("can't free global or top-level scopes!");
+    else
+      {
+	scope_ids_in_use_iterator p = scope_ids_in_use.find (scope);
+
+	if (p != scope_ids_in_use.end ())
+	  {
+	    scope_ids_in_use.erase (p);
+	    scope_ids_free_list.insert (*p);
+	  }
+	else
+	  error ("scope id = %ld not found!", scope);
+      }
+  }
+
+  static symbol_table *get_instance (scope_id scope)
+  {
+    symbol_table *retval = 0;
+
+    if (scope == xcurrent_scope)
+      {
+	if (! instance)
+	  {
+	    instance = new symbol_table ();
 
-  static unsigned long int symtab_count;
+	    all_instances[scope] = instance;
+	  }
+
+	if (! instance)
+	  error ("unable to create symbol_table object!");
+
+	retval = instance;
+      }
+    else
+      {
+	all_instances_iterator p = all_instances.find (scope);
+
+	if (p == all_instances.end ())
+	  {
+	    retval = new symbol_table ();
+
+	    all_instances[scope] = retval;
+	  }
+	else
+	  retval = p->second;
+      }
+
+    return retval;
+  }
+
+  void insert_symbol_record (const symbol_record& sr)
+  {
+    table[sr.name ()] = sr;
+  }
 
   void
-  print_descriptor (std::ostream& os, 
-		    std::list<whos_parameter> params) const;
+  do_dup_scope (symbol_table& new_symbol_table) const
+  {
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      new_symbol_table.insert_symbol_record (p->second.dup ());
+  }
+
+  symbol_record do_find_symbol (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    if (p == table.end ())
+      return do_insert (name);
+    else
+      return p->second;
+  }
+
+  void do_inherit (scope_id donor_scope)
+  {
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	symbol_record& sr = p->second;
+
+	std::string nm = sr.name ();
+
+	if (! (sr.is_automatic () || sr.is_formal () || nm == "__retval__"))
+	  {
+	    octave_value val = symbol_table::varval (nm, donor_scope);
+
+	    if (val.is_defined ())
+	      {
+		sr.varref () = val;
+
+		sr.mark_inherited ();
+	      }
+	  }
+      }
+  }
+
+  octave_value
+  do_find (const std::string& name, tree_argument_list *args,
+	   const string_vector& arg_names,
+	   octave_value_list& evaluated_args, bool& args_evaluated,
+	   scope_id scope, bool skip_variables);
+
+  symbol_record& do_insert (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    return p == table.end ()
+      ? (table[name] = symbol_record (name)) : p->second;
+  }
+
+  octave_value& do_varref (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    if (p == table.end ())
+      {
+	symbol_record& sr = do_insert (name);
+
+	return sr.varref ();
+      }
+    else
+      return p->second.varref ();
+  }
 
-  std::list<whos_parameter>
-  parse_whos_line_format (Array<symbol_record *>& symbols) const;
+  octave_value do_varval (const std::string& name) const
+  {
+    const_table_iterator p = table.find (name);
+
+    return (p != table.end ()) ? p->second.varval () : octave_value ();
+  }
+
+  octave_value& do_persistent_varref (const std::string& name)
+  {
+    persistent_table_iterator p = persistent_table.find (name);
+
+    return (p == persistent_table.end ())
+      ? persistent_table[name] : p->second;
+  }
+
+  octave_value do_persistent_varval (const std::string& name)
+  {
+    const_persistent_table_iterator p = persistent_table.find (name);
+
+    return (p != persistent_table.end ()) ? p->second : octave_value ();
+  }
+
+  void do_erase_persistent (const std::string& name)
+  {
+    persistent_table_iterator p = persistent_table.find (name);
+
+    if (p != persistent_table.end ())
+      persistent_table.erase (p);
+  }
+
+  bool do_is_variable (const std::string& name) const
+  {
+    bool retval = false;
+
+    const_table_iterator p = table.find (name);
+
+    if (p != table.end ())
+      {
+	const symbol_record& sr = p->second;
+
+	retval = sr.is_variable ();
+      }
+
+    return retval;
+  }
+
+  void do_push_context (void)
+  {
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      p->second.push_context ();
+  }
+
+  void do_pop_context (void)
+  {
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      p->second.pop_context ();
+  }
+
+  void do_clear_variables (void)
+  {
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      p->second.clear ();
+  }
+
+  void do_clear_global (const std::string& name)
+  {
+    table_iterator p = table.find (name);
 
-  unsigned int hash (const std::string& s);
+    if (p != table.end ())
+      {
+	symbol_record& sr = p->second;
+
+	if (sr.is_global ())
+	  {
+	    symbol_table::clear_variable (p->first, xglobal_scope);
+
+	    sr.unmark_global ();
+	  }
+      }
+  }
+
+  void do_clear_variable (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    if (p != table.end ())
+      p->second.clear ();
+  }
+
+  void do_clear_global_pattern (const std::string& pat)
+  {
+    glob_match pattern (pat);
+
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	symbol_record& sr = p->second;
 
-  // No copying!
+	if (sr.is_global ())
+	  {
+	    if (pattern.match (sr.name ()))
+	      {
+		symbol_table::clear_variable (p->first, xglobal_scope);
+
+		sr.unmark_global ();
+	      }
+	  }
+      }
+  }
+
+  void do_clear_variable_pattern (const std::string& pat)
+  {
+    glob_match pattern (pat);
+
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	symbol_record& sr = p->second;
+
+	if (sr.is_defined () || sr.is_global ())
+	  {
+	    if (pattern.match (sr.name ()))
+	      sr.clear ();
+	  }
+      }
+  }
+
+  void do_mark_hidden (const std::string& name)
+  {
+    table_iterator p = table.find (name);
+
+    if (p != table.end ())
+      p->second.mark_hidden ();
+  }
+
+  void do_mark_global (const std::string& name)
+  {
+    table_iterator p = table.find (name);
 
-  symbol_table (const symbol_table&);
+    if (p != table.end ())
+      p->second.mark_global ();
+  }
+
+  std::list<symbol_record> do_all_variables (bool defined_only) const
+  {
+    std::list<symbol_record> retval;
+
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	const symbol_record& sr = p->second;
+
+	if (defined_only && ! sr.is_defined ())
+	  continue;
+
+	retval.push_back (sr);
+      }
+
+    return retval;
+  }
+
+  std::list<symbol_record> do_glob (const std::string& pattern,
+				    bool vars_only = false) const
+  {
+    std::list<symbol_record> retval;
+
+    glob_match pat (pattern);
+
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	if (pat.match (p->first))
+	  {
+	    const symbol_record& sr = p->second;
 
-  symbol_table& operator = (const symbol_table&);
+	    if (vars_only && ! sr.is_variable ())
+	      continue;
+
+	    retval.push_back (sr);
+	  }
+      }
+
+    return retval;
+  }
+
+  std::list<std::string> do_variable_names (void)
+  {
+    std::list<std::string> retval;
+
+    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+      retval.push_back (p->first);
+
+    retval.sort ();
+
+    return retval;
+  }
+
+  bool do_is_local_variable (const std::string& name) const
+  {
+    const_table_iterator p = table.find (name);
+
+    return (p != table.end ()
+	    && ! p->second.is_global ()
+	    && p->second.is_defined ());
+  }
+
+  bool do_is_global (const std::string& name) const
+  {
+    const_table_iterator p = table.find (name);
+
+    return p != table.end () && p->second.is_global ();
+  }
 };
 
-// Defines layout for the whos/who -long command.
-extern std::string Vwhos_line_format;
+extern bool out_of_date_check (octave_value& function);
 
 #endif
 
--- a/src/token.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/token.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -73,7 +73,7 @@
   pt = t;
 }
 
-token::token (symbol_record *s, int l, int c)
+token::token (symbol_table::symbol_record *s, int l, int c)
 {
   line_num = l;
   column_num = c;
@@ -115,7 +115,7 @@
   return pt;
 }
 
-symbol_record *
+symbol_table::symbol_record *
 token::sym_rec (void)
 {
   assert (type_tag == sym_rec_token);
--- a/src/token.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/token.h	Fri Dec 28 20:56:58 2007 +0000
@@ -26,7 +26,7 @@
 
 #include <string>
 
-class symbol_record;
+class symbol_table::symbol_record;
 
 class
 token
@@ -68,7 +68,7 @@
 	 int l = -1, int c = -1);
   token (end_tok_type t, int l = -1, int c = -1);
   token (plot_tok_type t, int l = -1, int c = -1);
-  token (symbol_record *s, int l = -1, int c = -1);
+  token (symbol_table::symbol_record *s, int l = -1, int c = -1);
 
   ~token (void);
 
@@ -79,7 +79,7 @@
   double number (void);
   end_tok_type ettype (void);
   plot_tok_type pttype (void);
-  symbol_record *sym_rec (void);
+  symbol_table::symbol_record *sym_rec (void);
 
   std::string text_rep (void);
 
@@ -100,7 +100,7 @@
       double num;
       end_tok_type et;
       plot_tok_type pt;
-      symbol_record *sr;
+      symbol_table::symbol_record *sr;
     };
   std::string orig_text;
 };
--- a/src/toplev.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/toplev.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -209,7 +209,7 @@
     {
       try
 	{
-	  curr_sym_tab = top_level_sym_tab;
+	  symbol_table::reset_scope ();
 
 	  reset_error_handler ();
 
--- a/src/unwind-prot.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/unwind-prot.h	Fri Dec 28 20:56:58 2007 +0000
@@ -81,7 +81,7 @@
 {
 public:
 
-  static void add (unwind_elem::cleanup_func fptr, void *ptr);
+  static void add (unwind_elem::cleanup_func fptr, void *ptr = 0);
 
   static void run (void);
 
--- a/src/variables.cc	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/variables.cc	Fri Dec 28 20:56:58 2007 +0000
@@ -28,6 +28,7 @@
 #include <cstdio>
 #include <cstring>
 
+#include <iomanip>
 #include <set>
 #include <string>
 
@@ -63,51 +64,32 @@
 // since they were last compiled?
 static int Vignore_function_time_stamp = 1;
 
-// Symbol table for symbols at the top level.
-symbol_table *top_level_sym_tab = 0;
-
-// Symbol table for the current scope.
-symbol_table *curr_sym_tab = 0;
-
-// Symbol table for the current caller scope.
-symbol_table *curr_caller_sym_tab = 0;
-
-// Symbol table for global symbols.
-symbol_table *global_sym_tab = 0;
-
-// Symbol table for functions and built-in symbols.
-symbol_table *fbi_sym_tab = 0;
-
-bool
-at_top_level (void)
-{
-  return (curr_sym_tab == top_level_sym_tab);
-}
-
-// Initialization.
-
-// Create the initial symbol tables and set the current scope at the
-// top level.
-
-void
-initialize_symbol_tables (void)
-{
-  if (! fbi_sym_tab)
-    fbi_sym_tab = new symbol_table (2048, "FBI");
-
-  if (! global_sym_tab)
-    global_sym_tab = new symbol_table (2048, "GLOBAL");
-
-  if (! top_level_sym_tab)
-    top_level_sym_tab = new symbol_table (4096, "TOP");
-
-  curr_caller_sym_tab = curr_sym_tab = top_level_sym_tab;
-}
+// Defines layout for the whos/who -long command
+static std::string Vwhos_line_format
+  = "  %a:4; %ln:6; %cs:16:6:8:1;  %rb:12;  %lc:-1;\n";
 
 void
 clear_mex_functions (void)
 {
-  fbi_sym_tab->clear_mex_functions ();
+  symbol_table::clear_mex_functions ();
+}
+
+void
+clear_function (const std::string& nm)
+{
+  symbol_table::clear_function (nm);
+}
+
+void
+clear_variable (const std::string& nm)
+{
+  symbol_table::clear_variable (nm);
+}
+
+void
+clear_symbol (const std::string& nm)
+{
+  symbol_table::clear_symbol (nm);
 }
 
 // Attributes of variables and functions.
@@ -116,13 +98,7 @@
 
 static std::set <std::string> command_set;
 
-static inline bool
-is_marked_as_command (const std::string& s)
-{
-  return command_set.find (s) != command_set.end ();
-}
-
-static inline void
+void
 mark_as_command (const std::string& s)
 {
   command_set.insert (s);
@@ -132,11 +108,6 @@
 unmark_command (const std::string& s)
 {
   command_set.erase (s);
-
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-
-  if (sr)
-    sr->unmark_command ();
 }
 
 DEFCMD (mark_as_command, args, ,
@@ -148,7 +119,7 @@
 {
   octave_value_list retval;
 
-  if (at_top_level ())
+  if (symbol_table::at_top_level ())
     {
       int nargin = args.length ();
 
@@ -182,7 +153,7 @@
 {
   octave_value_list retval;
 
-  if (at_top_level ())
+  if (symbol_table::at_top_level ())
     {
       int nargin = args.length ();
 
@@ -210,26 +181,10 @@
 bool
 is_command_name (const std::string& s)
 {
-  bool retval = false;
-
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-
-  if (sr)
-    {
-      if (sr->is_command ())
-	retval = true;
-      else if (is_marked_as_command (s))
-	{
-	  sr->mark_as_command ();
-	  retval = true;
-	}
-    }
-  else
-    retval = is_marked_as_command (s);
-
-  return retval;
+  return command_set.find (s) != command_set.end ();
 }
 
+
 DEFCMD (iscommand, args, ,
 "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} iscommand (@var{name})\n\
@@ -274,12 +229,6 @@
 
 static std::set <std::string> rawcommand_set;
 
-bool
-is_marked_as_rawcommand (const std::string& s)
-{
-  return rawcommand_set.find (s) != rawcommand_set.end ();
-}
-
 void
 mark_as_rawcommand (const std::string& s)
 {
@@ -291,11 +240,6 @@
 unmark_rawcommand (const std::string& s)
 {
   rawcommand_set.erase (s);
-
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-
-  if (sr)
-    sr->unmark_rawcommand ();
 }
 
 DEFCMD (mark_as_rawcommand, args, ,
@@ -314,7 +258,7 @@
 {
   octave_value_list retval;
 
-  if (at_top_level ())
+  if (symbol_table::at_top_level ())
     {
       int nargin = args.length ();
 
@@ -350,7 +294,7 @@
 {
   octave_value_list retval;
 
-  if (at_top_level ())
+  if (symbol_table::at_top_level ())
     {
       int nargin = args.length ();
 
@@ -378,24 +322,7 @@
 bool
 is_rawcommand_name (const std::string& s)
 {
-  bool retval = false;
-
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-
-  if (sr)
-    {
-      if (sr->is_rawcommand ())
-	retval = true;
-      else if (is_marked_as_rawcommand (s))
-	{
-	  sr->mark_as_rawcommand ();
-	  retval = true;
-	}
-    }
-  else
-    retval = is_marked_as_rawcommand (s);
-
-  return retval;
+  return rawcommand_set.find (s) != rawcommand_set.end ();
 }
 
 DEFCMD (israwcommand, args, ,
@@ -439,33 +366,6 @@
   return retval;
 }
 
-// Is this a built-in function?
-
-bool
-is_builtin_function_name (const std::string& s)
-{
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-  return (sr && sr->is_builtin_function ());
-}
-
-// Is this a mapper function?
-
-bool
-is_mapper_function_name (const std::string& s)
-{
-  symbol_record *sr = fbi_sym_tab->lookup (s);
-  return (sr && sr->is_mapper_function ());
-}
-
-// Is this function globally in this scope?
-
-bool
-is_globally_visible (const std::string& name)
-{
-  symbol_record *sr = curr_sym_tab->lookup (name);
-  return (sr && sr->is_linked_to_global ());
-}
-
 // Is this octave_value a valid function?
 
 octave_function *
@@ -474,28 +374,17 @@
 {
   octave_function *ans = 0;
 
-  symbol_record *sr = 0;
-
   if (! fcn_name.empty ())
     {
-      sr = fbi_sym_tab->lookup (fcn_name, true);
-
-      lookup (sr, false);
+      octave_value val = symbol_table::find_function (fcn_name);
+
+      if (val.is_defined ())
+	ans = val.function_value (true);
     }
 
-  if (sr)
-    {
-      octave_value tmp = sr->def ();
-      ans = tmp.function_value (true);
-    }
-
-  if (! sr || ! ans || ! sr->is_function ())
-    {
-      if (warn)
-	error ("%s: the symbol `%s' is not valid as a function",
-	       warn_for.c_str (), fcn_name.c_str ());
-      ans = 0;
-    }
+  if (! ans && warn)
+    error ("%s: the symbol `%s' is not valid as a function",
+	   warn_for.c_str (), fcn_name.c_str ());
 
   return ans;
 }
@@ -613,12 +502,9 @@
 
   if (! name.empty ())
     {
-      symbol_record *sr = curr_sym_tab->lookup (name);
-
-      if (! sr)
-	sr = fbi_sym_tab->lookup (name);
-
-      retval = (sr  && sr->is_variable ());
+      octave_value val = symbol_table::varval (name);
+
+      retval = val.is_defined ();
     }
 
   return retval;
@@ -733,11 +619,7 @@
       return retval;
     }
 
-  symbol_record *sr = curr_sym_tab->lookup (name);
-
-  retval = (sr && sr->is_linked_to_global ());
-
-  return retval;
+  return symbol_table::is_global (name);
 }
 
 DEFUN (isglobal, args, ,
@@ -787,20 +669,21 @@
   // name that is visible in the current scope will be in the local
   // symbol table.
 
-  symbol_record *sr = curr_sym_tab->lookup (symbol_name);
-
-  if (! (sr && sr->is_defined ()))
-    sr = fbi_sym_tab->lookup (symbol_name);
-
-  if (sr && sr->is_defined ())
+  octave_value_list evaluated_args;
+  bool args_evaluated;
+
+  octave_value val = symbol_table::find (symbol_name, 0, string_vector (),
+					 evaluated_args, args_evaluated);
+
+  if (val.is_defined ())
     {
       bool not_a_struct = struct_elts.empty ();
-      bool var_ok = not_a_struct || sr->is_map_element (struct_elts);
+      bool var_ok = not_a_struct /* || val.is_map_element (struct_elts) */;
 
       if (! retval
 	  && var_ok
 	  && (type == "any" || type == "var")
-	  && sr->is_user_variable ())
+	  && val.is_constant ())
 	{
 	  retval = 1;
 	}
@@ -808,7 +691,7 @@
       if (! retval
 	  && (type == "any" || type == "builtin"))
 	{
-	  if (not_a_struct && sr->is_builtin_function ())
+	  if (not_a_struct && val.is_builtin_function ())
 	    {
 	      retval = 5;
 	    }
@@ -817,13 +700,12 @@
       if (! retval
 	  && not_a_struct
 	  && (type == "any" || type == "file")
-	  && (sr->is_user_function () || sr->is_dld_function ()))
+	  && (val.is_user_function () || val.is_dld_function ()))
 	{
-	  octave_value t = sr->def ();
-	  octave_function *f = t.function_value (true);
+	  octave_function *f = val.function_value (true);
 	  std::string s = f ? f->fcn_file_name () : std::string ();
 
-	  retval = s.empty () ? 103 : (sr->is_user_function () ? 2 : 3);
+	  retval = s.empty () ? 103 : (val.is_user_function () ? 2 : 3);
 	}
     }
 
@@ -962,289 +844,29 @@
   return retval;
 }
 
-bool
-fcn_out_of_date (octave_function *fcn, const std::string& ff, time_t tp)
-{
-  bool retval = false;
-
-  fcn->mark_fcn_file_up_to_date (octave_time ());
-
-  if (! (Vignore_function_time_stamp == 2
-	 || (Vignore_function_time_stamp && fcn->is_system_fcn_file ())))
-    {
-      file_stat fs (ff);
-
-      if (fs && fs.is_newer (tp))
-	retval = true;
-    }
-
-  return retval;
-}
-
-// Is there a corresponding function file that is newer than the
-// symbol definition?
-
-static bool
-symbol_out_of_date (symbol_record *sr)
-{
-  bool retval = false;
-
-  if (sr)
-    {
-      octave_value ans = sr->def ();
-
-      octave_function *fcn = ans.function_value (true);
-
-      if (fcn)
-	{
-	  std::string ff = fcn->fcn_file_name ();
-
-	  if (! ff.empty ())
-	    {
-	      octave_time tc = fcn->time_checked ();
-
-	      bool relative = fcn->is_relative ();
-
-	      if (tc < Vlast_prompt_time
-		  || (relative && tc < Vlast_chdir_time))
-		{
-		  octave_time ottp = fcn->time_parsed ();
-		  time_t tp = ottp.unix_time ();
-
-		  std::string nm = fcn->is_nested_function ()
-		    ? fcn->parent_fcn_name () : fcn->name ();
-
-		  // FIXME -- the following code is repeated
-		  // in load_fcn_from_file in parse.y.
-
-		  int nm_len = nm.length ();
-
-		  std::string file;
-
-		  if (octave_env::absolute_pathname (nm)
-		      && ((nm_len > 4 && (nm.substr (nm_len-4) == ".oct"
-					  || nm.substr (nm_len-4) == ".mex"))
-			  || (nm_len > 2 && nm.substr (nm_len-4) == ".m")))
-		    {
-		      file = nm;
-		    }
-		  else
-		    {
-		      file = lookup_autoload (nm);
-
-		      if (file.empty ())
-			file = load_path::find_fcn (nm);
-
-		      file = octave_env::make_absolute (file, octave_env::getcwd ());
-		    }
-
-		  if (file.empty ())
-		    {
-		      // Can't see this function now, so we should
-		      // clear it.
-
-		      sr->clear ();
-
-		      retval = true;
-		    }
-		  else if (same_file (file, ff))
-		    {
-		      retval = fcn_out_of_date (fcn, ff, tp);
-		    }
-		  else
-		    {
-		      // Check the full function name.  Maybe we already
-		      // parsed it.
-
-		      symbol_record *full_sr = fbi_sym_tab->lookup (file);
-
-		      if (full_sr)
-			{
-			  octave_value v = full_sr->def ();
-
-			  if (v.is_function ())
-			    {
-			      // OK, swap the aliases around.
-
-			      // FIXME -- this is a bit
-			      // tricky, so maybe some refactoring is
-			      // in order here too...
-
-			      symbol_record *short_sr = fbi_sym_tab->lookup (nm);
-
-			      if (short_sr)
-				short_sr->alias (full_sr);
-
-			      // Make local symbol table entry point
-			      // to correct global function too.
-
-			      sr->alias (full_sr);
-
-			      fcn = v.function_value ();
-
-			      retval = fcn_out_of_date (fcn, file, tp);
-			    }
-			  else
-			    retval = true;
-			}
-		      else
-			retval = true;
-		    }
-		}
-	    }
-	}
-    }
-
-  return retval;
-}
-
-bool
-lookup (symbol_record *sym_rec, bool exec_script)
-{
-  bool script_executed = false;
-
-  if (! sym_rec->is_linked_to_global ())
-    {
-      if (sym_rec->is_defined ())
-	{
-	  if (sym_rec->is_function () && symbol_out_of_date (sym_rec))
-	    script_executed = load_fcn_from_file (sym_rec, exec_script);
-	}
-      else if (! sym_rec->is_formal_parameter ())
-	{
-	  link_to_builtin_or_function (sym_rec);
-
-	  if (! sym_rec->is_defined ())
-	    script_executed = load_fcn_from_file (sym_rec, exec_script);
-	  else if (sym_rec->is_function () && symbol_out_of_date (sym_rec))
-	    script_executed = load_fcn_from_file (sym_rec, exec_script);
-	}
-    }
-
-  return script_executed;
-}
-
-// Get the symbol record for the given name that is visible in the
-// current scope.  Reread any function definitions that appear to be
-// out of date.  If a function is available in a file but is not
-// currently loaded, this will load it and insert the name in the
-// current symbol table.
-
-symbol_record *
-lookup_by_name (const std::string& nm, bool exec_script)
-{
-  symbol_record *sym_rec = curr_sym_tab->lookup (nm, true);
-
-  lookup (sym_rec, exec_script);
-
-  return sym_rec;
-}
-
-octave_value
-lookup_function (const std::string& nm, const std::string& parent)
-{
-  octave_value retval;
-
-  symbol_record *sr = 0;
-
-  if (! parent.empty ())
-    sr = fbi_sym_tab->lookup (parent + ":" + nm);
-
-  if (! sr || ! sr->is_function ())
-    {
-      if (curr_parent_function)
-	sr = fbi_sym_tab->lookup (curr_parent_function->name () + ":" + nm);
-
-      if (! sr || ! sr->is_function ())
-	sr = fbi_sym_tab->lookup (nm, true);
-
-      if (sr && ! sr->is_function ())
-	load_fcn_from_file (sr, false);
-    }
-
-  if (sr)
-    {
-      octave_value v = sr->def ();
-
-      if (v.is_function ())
-	retval = v;
-    }
-
-  return retval;
-}
-
-octave_value
-lookup_user_function (const std::string& nm)
-{
-  octave_value retval;
-
-  symbol_record *sr = 0;
-
-  if (curr_parent_function)
-    {
-      std::string parent = curr_parent_function->name ();
-
-      sr = fbi_sym_tab->lookup (parent + ":" + nm);
-    }
-
-  if (! sr || ! sr->is_user_function ())
-    {
-      sr = fbi_sym_tab->lookup (nm, true);
-
-      if (sr && ! sr->is_user_function ())
-	load_fcn_from_file (sr, false);
-    }
-
-  if (sr)
-    retval = sr->def ();
-
-  return retval;
-}
-
 octave_value
 lookup_function_handle (const std::string& nm)
 {
-  octave_value retval;
-
-  symbol_record *sr = curr_sym_tab->lookup (nm, true);
-
-  if (sr && sr->def ().is_function_handle ())
-    retval = sr->def ();
-
-  return retval;
+  octave_value val = symbol_table::varval (nm);
+
+  return val.is_function_handle () ? val : octave_value ();
 }
 
 octave_value
 get_global_value (const std::string& nm, bool silent)
 {
-  octave_value retval;
-
-  symbol_record *sr = global_sym_tab->lookup (nm);
-
-  if (sr)
-    {
-      octave_value sr_def = sr->def ();
-
-      if (sr_def.is_defined ())
-	retval = sr_def;
-      else if (! silent)
-	error ("get_global_by_name: undefined symbol `%s'", nm.c_str ());
-    }
-  else if (! silent)
-    error ("get_global_by_name: unknown symbol `%s'", nm.c_str ());
-
-  return retval;
+  octave_value val = symbol_table::varval (nm, symbol_table::global_scope ());
+
+  if (val.is_undefined () && ! silent)
+    error ("get_global_by_name: undefined symbol `%s'", nm.c_str ());
+
+  return val;
 }
 
 void
 set_global_value (const std::string& nm, const octave_value& val)
 {
-  symbol_record *sr = global_sym_tab->lookup (nm, true);
-
-  if (sr)
-    sr->define (val);
-  else
-    panic_impossible ();
+  symbol_table::varref (nm, symbol_table::global_scope ()) = val;
 }
 
 // Variable values.
@@ -1415,174 +1037,609 @@
   return retval;
 }
 
-// Global stuff and links to builtin variables and functions.
-
-// Make the definition of the symbol record sr be the same as the
-// definition of the global variable of the same name, creating it if
-// it doesn't already exist.
-
-void
-link_to_global_variable (symbol_record *sr)
+struct
+symbol_record_name_compare
+{
+  bool operator () (const symbol_table::symbol_record& a,
+		    const symbol_table::symbol_record& b)
+  {
+    std::string a_nm = a.name ();
+    std::string b_nm = b.name ();
+
+    return a_nm.compare (b_nm);
+  }
+};
+
+struct
+whos_parameter
 {
-  if (! sr->is_linked_to_global ())
+  char command;
+  char modifier;
+  int parameter_length;
+  int first_parameter_length;
+  int dimensions;
+  int balance;
+  std::string text;
+  std::string line;
+};
+
+static void
+print_descriptor (std::ostream& os, std::list<whos_parameter> params)
+{
+  // This method prints a line of information on a given symbol
+  std::list<whos_parameter>::iterator i = params.begin ();
+  std::ostringstream param_buf;
+
+  while (i != params.end ())
     {
-      sr->mark_as_linked_to_global ();
-
-      if (! error_state)
+      whos_parameter param = *i;
+
+      if (param.command != '\0')
+        {
+	  // Do the actual printing
+	  switch (param.modifier)
+	    {
+	    case 'l':
+	      os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
+	      param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
+	      break;
+
+	    case 'r':
+	      os << std::setiosflags (std::ios::right) << std::setw (param.parameter_length);
+	      param_buf << std::setiosflags (std::ios::right) << std::setw (param.parameter_length);
+	      break;
+
+	    case 'c':
+	      if (param.command != 's')
+	        {
+		  os << std::setiosflags (std::ios::left)
+		     << std::setw (param.parameter_length);
+		  param_buf << std::setiosflags (std::ios::left)
+			    << std::setw (param.parameter_length);
+		}
+	      break;
+
+	    default:
+	      os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
+	      param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
+	    }
+
+	  if (param.command == 's' && param.modifier == 'c')
+	    {
+	      int a, b;
+	     
+	      if (param.modifier == 'c')
+	        {
+		  a = param.first_parameter_length - param.balance;
+		  a = (a < 0 ? 0 : a);
+		  b = param.parameter_length - a - param.text . length ();
+		  b = (b < 0 ? 0 : b);
+		  os << std::setiosflags (std::ios::left) << std::setw (a)
+		     << "" << std::resetiosflags (std::ios::left) << param.text
+		     << std::setiosflags (std::ios::left)
+		     << std::setw (b) << ""
+		     << std::resetiosflags (std::ios::left);
+		  param_buf << std::setiosflags (std::ios::left) << std::setw (a)
+		     << "" << std::resetiosflags (std::ios::left) << param.line
+		     << std::setiosflags (std::ios::left)
+		     << std::setw (b) << ""
+		     << std::resetiosflags (std::ios::left);
+		}
+	    }
+	  else
+	    {
+	      os << param.text;
+	      param_buf << param.line;
+	    }
+	  os << std::resetiosflags (std::ios::left)
+	     << std::resetiosflags (std::ios::right);
+	  param_buf << std::resetiosflags (std::ios::left)
+		    << std::resetiosflags (std::ios::right);
+	  i++;
+	}
+      else
 	{
-	  std::string nm = sr->name ();
-
-	  symbol_record *gsr = global_sym_tab->lookup (nm, true);
-
-	  // Make sure this symbol is a variable.
-
-	  if (! gsr->is_user_variable ())
-	    gsr->define (octave_value ());
-
-	  sr->alias (gsr);
+	  os << param.text;
+	  param_buf << param.line;
+	  i++;
 	}
     }
+
+  os << param_buf.str ();
 }
 
-// Make the definition of the symbol record sr be the same as the
-// definition of the builtin variable of the same name.
-
-// Make the definition of the symbol record sr be the same as the
-// definition of the builtin function, or user function of the same
-// name, provided that the name has not been used as a formal parameter.
-
-void
-link_to_builtin_or_function (symbol_record *sr)
-{
-  std::string nm = sr->name ();
-
-  symbol_record *tmp_sym = 0;
-
-  octave_function *fcn = octave_call_stack::current ();
-
-  std::string parent = fcn ? fcn->parent_fcn_name () : std::string ();
-
-  if (! parent.empty ())
-    tmp_sym = fbi_sym_tab->lookup (parent + ":" + nm);
-
-  if (! tmp_sym && curr_parent_function)
-    tmp_sym = fbi_sym_tab->lookup (curr_parent_function->name () + ":" + nm);
-
-  if (! tmp_sym)
-    tmp_sym = fbi_sym_tab->lookup (nm);
-
-  if (tmp_sym
-      && tmp_sym->is_function ()
-      && ! tmp_sym->is_formal_parameter ())
-    sr->alias (tmp_sym);
-}
-
-// Force a link to a function in the current symbol table.  This is
-// used just after defining a function to avoid different behavior
-// depending on whether or not the function has been evaluated after
-// being defined.
+// Calculate how much space needs to be reserved for the first part of
+// the dimensions string.  For example,
 //
-// Return without doing anything if there isn't a function with the
-// given name defined in the global symbol table.
-
-void
-force_link_to_function (const std::string& id_name)
-{
-  symbol_record *fsr = fbi_sym_tab->lookup (id_name, true);
-  if (fsr->is_function ())
-    {
-      curr_sym_tab->clear (id_name);
-      symbol_record *csr = curr_sym_tab->lookup (id_name, true);
-      csr->alias (fsr);
-    }
-}
-
-DEFUN (document, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} document (@var{symbol}, @var{text})\n\
-Set the documentation string for @var{symbol} to @var{text}.\n\
-@end deftypefn")
+//   mat is a 12x3 matrix
+//            ^^  => 2 columns
+
+static int
+dimensions_string_req_first_space (const dim_vector& dims, int print_dims)
 {
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 2)
+  int first_param_space = 0;
+
+  // Calculating dimensions.
+
+  std::string dim_str = "";
+  std::stringstream ss;
+  long dim = dims.length ();
+
+  first_param_space = (first_param_space >= 1 ? first_param_space : 1);
+
+  // Preparing dimension string.
+
+  if ((dim <= print_dims || print_dims < 0) && print_dims != 0)
+    {
+      // Dimensions string must be printed like this: 2x3x4x2.
+
+      if (dim == 0 || dim == 1)
+	first_param_space = 1; // First parameter is 1.
+      else
+        {
+	  ss << dims (0);
+	 
+	  dim_str = ss.str ();
+	  first_param_space = dim_str.length ();
+	}
+    }
+  else
     {
-      std::string name = args(0).string_value ();
-
-      if (! error_state)
-	{
-	  std::string help = args(1).string_value ();
-
-	  if (! error_state)
+      // Printing dimension string as: a-D.
+
+      ss << dim;
+
+      dim_str = ss.str ();
+      first_param_space = dim_str.length ();
+    }
+
+  return first_param_space;
+}
+
+// Make the dimensions-string.  For example: mat is a 2x3 matrix.
+//                                                    ^^^
+//
+// FIXME -- why not just use the dim_vector::str () method?
+
+std::string
+make_dimensions_string (const dim_vector& dims, int print_dims)
+{
+  // Calculating dimensions.
+
+  std::string dim_str = "";
+  std::stringstream ss;
+  long dim = dims.length ();
+
+  // Preparing dimension string.
+
+  if ((dim <= print_dims || print_dims < 0) && print_dims != 0)
+    {
+      // Only printing the dimension string as: axbxc...
+
+      if (dim == 0)
+	ss << "1x1";
+      else
+        {
+	  for (int i = 0; i < dim; i++)
 	    {
-	      if (is_command_name (name)
-		  || is_mapper_function_name (name)
-		  || is_builtin_function_name (name))
-		error ("document: can't redefine help for built-in functions");
-	      else
+	      if (i == 0)
 		{
-		  symbol_record *sym_rec = curr_sym_tab->lookup (name);
-
-		  if (sym_rec)
-		    sym_rec->document (help);
+		  if (dim == 1)
+		    {
+		      // Looks like this is not going to happen in
+		      // Octave, but ...
+
+		      ss << "1x" << dims (i);
+		    }
 		  else
-		    error ("document: no such symbol `%s'", name.c_str ());
+		    ss << dims (i);
 		}
+	      else if (i < dim && dim != 1)
+		ss << "x" << dims (i);
 	    }
 	}
     }
   else
-    print_usage ();
-
-  return retval;
+    {
+      // Printing dimension string as: a-D.
+
+      ss << dim << "-D";
+    }
+
+  dim_str = ss.str ();
+
+  return dim_str;
 }
 
-// FIXME -- this function is duplicated in symtab.cc with the
-// name maybe_list_cmp_fcn.
+// Calculate how much space needs to be reserved for the
+// dimensions string.  For example,
+//
+//   mat is a 12x3 matrix
+//            ^^^^ => 4 columns
+//
+// FIXME -- why not just use the dim_vector::str () method?
 
 static int
-symbol_record_name_compare (const void *a_arg, const void *b_arg)
+dimensions_string_req_total_space (const dim_vector& dims, int print_dims)
+{
+  std::string dim_str = "";
+  std::stringstream ss;
+
+  ss << make_dimensions_string (dims, print_dims);
+  dim_str = ss.str ();
+
+  return dim_str.length ();
+}
+
+static std::list<whos_parameter>
+parse_whos_line_format (const std::list<symbol_table::symbol_record>& symbols)
 {
-  const symbol_record *a = *(static_cast<symbol_record *const*> (a_arg));
-  const symbol_record *b = *(static_cast<symbol_record *const*> (b_arg));
-
-  std::string a_nm = a->name ();
-  std::string b_nm = b->name ();
-
-  return a_nm.compare (b_nm);
+  // This method parses the string whos_line_format, and returns
+  // a parameter list, containing all information needed to print
+  // the given attributtes of the symbols
+  int idx;
+  size_t format_len = Vwhos_line_format.length ();
+  char garbage;
+  std::list<whos_parameter> params;
+
+  size_t bytes1;
+  int elements1;
+
+  std::string param_string = "abcenst";
+  Array<int> param_length (dim_vector (param_string.length (), 1));
+  Array<std::string> param_names (dim_vector (param_string.length (), 1));
+  size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
+
+  pos_a = param_string.find ('a'); // Attributes
+  pos_b = param_string.find ('b'); // Bytes
+  pos_c = param_string.find ('c'); // Class
+  pos_e = param_string.find ('e'); // Elements
+  pos_n = param_string.find ('n'); // Name
+  pos_s = param_string.find ('s'); // Size
+  pos_t = param_string.find ('t'); // Type
+
+  param_names(pos_a) = "Attr";
+  param_names(pos_b) = "Bytes";
+  param_names(pos_c) = "Class";
+  param_names(pos_e) = "Elements";
+  param_names(pos_n) = "Name";
+  param_names(pos_s) = "Size";
+  param_names(pos_t) = "Type";
+
+  for (size_t i = 0; i < param_string.length (); i++)
+    param_length(i) = param_names(i) . length ();
+
+  // Calculating necessary spacing for name column,
+  // bytes column, elements column and class column
+
+  for (std::list<symbol_table::symbol_record>::const_iterator p = symbols.begin ();
+       p != symbols.end (); p++)
+    {
+      std::stringstream ss1, ss2;
+      std::string str;
+
+      str = p->name ();
+      param_length(pos_n) = ((str.length ()
+			      > static_cast<size_t> (param_length(pos_n)))
+			     ? str.length () : param_length(pos_n));
+
+      octave_value val = p->varval ();
+
+      str = val.type_name ();
+      param_length(pos_t) = ((str.length ()
+			      > static_cast<size_t> (param_length(pos_t)))
+			     ? str.length () : param_length(pos_t));
+
+      elements1 = val.capacity ();
+      ss1 << elements1;
+      str = ss1.str ();
+      param_length(pos_e) = ((str.length ()
+			      > static_cast<size_t> (param_length(pos_e)))
+			     ? str.length () : param_length(pos_e));
+
+      bytes1 = val.byte_size ();
+      ss2 << bytes1;
+      str = ss2.str ();
+      param_length(pos_b) = ((str.length ()
+			      > static_cast<size_t> (param_length(pos_b)))
+			     ? str.length () : param_length (pos_b));
+    }
+
+  idx = 0;
+  while (static_cast<size_t> (idx) < format_len)
+    {
+      whos_parameter param;
+      param.command = '\0';
+
+      if (Vwhos_line_format[idx] == '%')
+        {
+	  bool error_encountered = false;
+	  param.modifier = 'r';
+	  param.parameter_length = 0;
+	  param.dimensions = 8;
+
+	  int a = 0, b = -1, c = 8, balance = 1;
+	  unsigned int items;
+	  size_t pos;
+	  std::string cmd;
+
+	  // Parse one command from whos_line_format
+	  cmd = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
+	  pos = cmd.find (';');
+	  if (pos != NPOS)
+	    cmd = cmd.substr (0, pos+1);
+	  else
+	    error ("parameter without ; in whos_line_format");
+
+	  idx += cmd.length ();
+
+	  // FIXME -- use iostream functions instead of sscanf!
+
+	  if (cmd.find_first_of ("crl") != 1)
+	    items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d:%d;",
+			    &garbage, &param.command, &a, &b, &c, &balance);
+	  else
+	    items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d:%d;",
+			    &garbage, &param.modifier, &param.command,
+			    &a, &b, &c, &balance) - 1;
+	 
+	  if (items < 2)
+	    {
+	      error ("whos_line_format: parameter structure without command in whos_line_format");
+	      error_encountered = true;
+	    }
+
+	  // Insert data into parameter
+	  param.first_parameter_length = 0;
+	  pos = param_string.find (param.command);
+	  if (pos != NPOS)
+	    {
+	      param.parameter_length = param_length(pos);
+	      param.text = param_names(pos);
+	      param.line.assign (param_names(pos).length (), '=');
+
+	      param.parameter_length = (a > param.parameter_length
+					? a : param.parameter_length);
+	      if (param.command == 's' && param.modifier == 'c' && b > 0)
+		param.first_parameter_length = b;
+	    }
+	  else
+	    {
+	      error ("whos_line_format: '%c' is not a command",
+		     param.command);
+	      error_encountered = true;
+	    }
+
+	  if (param.command == 's')
+	    {
+	      // Have to calculate space needed for printing matrix dimensions
+	      // Space needed for Size column is hard to determine in prior,
+	      // because it depends on dimensions to be shown. That is why it is
+	      // recalculated for each Size-command
+	      int first, rest = 0, total;
+	      param.dimensions = c;
+	      first = param.first_parameter_length;
+	      total = param.parameter_length;
+
+	      for (std::list<symbol_table::symbol_record>::const_iterator p = symbols.begin ();
+		   p != symbols.end (); p++)
+		{
+		  octave_value val = p->varval ();
+		  dim_vector dims = val.dims ();
+		  int first1 = dimensions_string_req_first_space (dims, param.dimensions);
+		  int total1 = dimensions_string_req_total_space (dims, param.dimensions);
+		  int rest1 = total1 - first1;
+		  rest = (rest1 > rest ? rest1 : rest);
+		  first = (first1 > first ? first1 : first);
+		  total = (total1 > total ? total1 : total);
+		}
+
+	      if (param.modifier == 'c')
+	        {
+		  if (first < balance)
+		    first += balance - first;
+		  if (rest + balance < param.parameter_length)
+		    rest += param.parameter_length - rest - balance;
+
+		  param.parameter_length = first + rest;
+		  param.first_parameter_length = first;
+		  param.balance = balance;
+		}
+	      else
+	        {
+		  param.parameter_length = total;
+		  param.first_parameter_length = 0;
+		}
+	    }
+	  else if (param.modifier == 'c')
+	    {
+	      error ("whos_line_format: modifier 'c' not available for command '%c'",
+		     param.command);
+	      error_encountered = true;
+	    }
+
+	  // What happens if whos_line_format contains negative numbers
+	  // at param_length positions?
+	  param.balance = (b < 0 ? 0 : param.balance);
+	  param.first_parameter_length = (b < 0 ? 0 :
+					  param.first_parameter_length);
+	  param.parameter_length = (a < 0
+				    ? 0
+				    : (param.parameter_length
+				       < param_length(pos_s)
+				       ? param_length(pos_s)
+				       : param.parameter_length));
+
+	  // Parameter will not be pushed into parameter list if ...
+	  if (! error_encountered)
+	    params.push_back (param);
+	}
+      else
+        {
+	  // Text string, to be printed as it is ...
+	  std::string text;
+	  size_t pos;
+	  text = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
+	  pos = text.find ('%');
+	  if (pos != NPOS)
+	    text = text.substr (0, pos);
+
+	  // Push parameter into list ...
+	  idx += text.length ();
+	  param.text=text;
+	  param.line.assign (text.length(), ' ');
+	  params.push_back (param);
+	}
+    }
+
+  return params;
+}
+
+void
+print_symbol_info_line (std::ostream& os,
+			const symbol_table::symbol_record& sr,
+			std::list<whos_parameter>& params)
+{
+  octave_value val = sr.varval ();
+  dim_vector dims = val.dims ();
+
+  std::list<whos_parameter>::iterator i = params.begin ();
+
+  while (i != params.end ())
+    {
+      whos_parameter param = *i;
+
+      if (param.command != '\0')
+        {
+	  // Do the actual printing.
+
+	  switch (param.modifier)
+	    {
+	    case 'l':
+	      os << std::setiosflags (std::ios::left)
+		 << std::setw (param.parameter_length);
+	      break;
+
+	    case 'r':
+	      os << std::setiosflags (std::ios::right)
+		 << std::setw (param.parameter_length);
+	      break;
+
+	    case 'c':
+	      if (param.command == 's')
+	        {
+		  int front = param.first_parameter_length
+		    - dimensions_string_req_first_space (dims, param.dimensions);
+		  int back = param.parameter_length
+		    - dimensions_string_req_total_space (dims, param.dimensions)
+		    - front;
+		  front = (front > 0) ? front : 0;
+		  back = (back > 0) ? back : 0;
+
+		  os << std::setiosflags (std::ios::left)
+		     << std::setw (front)
+		     << ""
+		     << std::resetiosflags (std::ios::left)
+		     << make_dimensions_string (dims, param.dimensions)
+		     << std::setiosflags (std::ios::left)
+		     << std::setw (back)
+		     << ""
+		     << std::resetiosflags (std::ios::left);
+		}
+	      else
+	        {
+		  os << std::setiosflags (std::ios::left)
+		     << std::setw (param.parameter_length);
+		}
+	      break;
+
+	    default:
+	      error ("whos_line_format: modifier `%c' unknown",
+		     param.modifier);
+
+	      os << std::setiosflags (std::ios::right)
+		 << std::setw (param.parameter_length);
+	    }
+
+	  switch (param.command)
+	    {
+	    case 'a':
+	      {
+		char tmp[5];
+
+		tmp[0] = (sr.is_automatic () ? 'a' : ' ');
+		tmp[1] = (sr.is_formal () ? 'f' : ' ');
+		tmp[2] = (sr.is_global () ? 'g' : ' ');
+		tmp[3] = (sr.is_persistent () ? 'p' : ' ');
+		tmp[4] = 0;
+
+		os << tmp;
+	      }
+	      break;
+
+	    case 'b':
+	      os << val.byte_size ();
+	      break;
+
+	    case 'c':
+	      os << val.class_name ();
+	      break;
+
+	    case 'e':
+	      os << val.capacity ();
+	      break;
+
+	    case 'n':
+	      os << sr.name ();
+	      break;
+
+	    case 's':
+	      if (param.modifier != 'c')
+		os << make_dimensions_string (dims, param.dimensions);
+	      break;
+
+	    case 't':
+	      os << val.type_name ();
+	      break;
+	    
+	    default:
+	      error ("whos_line_format: command `%c' unknown", param.command);
+	    }
+
+	  os << std::resetiosflags (std::ios::left)
+	     << std::resetiosflags (std::ios::right);
+	  i++;
+        }
+      else
+	{
+	  os << param.text;
+	  i++;
+	}
+    }
 }
 
 static octave_value
-do_who (int argc, const string_vector& argv, int return_list)
+do_who (int argc, const string_vector& argv, bool return_list,
+	bool verbose = false)
 {
   octave_value retval;
 
-  bool show_builtins = false;
-  bool show_functions = false;
-  bool show_variables = false;
-  bool show_verbose = false;
-
   std::string my_name = argv[0];
 
+  bool global_only = false;
+
   int i;
   for (i = 1; i < argc; i++)
     {
-      if (argv[i] == "-all" || argv[i] == "-a")
+      if (argv[i] == "-regexp" || argv[i] == "-file")
 	{
-	  show_builtins = true;
-	  show_functions = true;
-	  show_variables = true;
+	  error ("%s: `%s' option not implemented", my_name.c_str (),
+		 argv[i].c_str ());
+
+	  return retval;
 	}
-      else if (argv[i] == "-builtins" || argv[i] == "-b")
-	show_builtins = true;
-      else if (argv[i] == "-functions" || argv[i] == "-f")
-	show_functions = true;
-      else if (argv[i] == "-long" || argv[i] == "-l")
-	show_verbose = true;
-      else if (argv[i] == "-variables" || argv[i] == "-v")
-	show_variables = true;
+      else if (argv[i] == "global")
+	global_only = true;
       else if (argv[i][0] == '-')
 	warning ("%s: unrecognized option `%s'", my_name.c_str (),
 		 argv[i].c_str ());
@@ -1590,99 +1647,27 @@
 	break;
     }
 
-  // If no options were specified to select the type of symbol to
-  // display, then set defaults.
-
-  if (! (show_builtins || show_functions || show_variables))
+  int npats = argc - i;
+  string_vector pats (npats > 0 ? npats : 1);
+  if (npats > 0)
     {
-      show_functions = at_top_level ();
-      show_variables = true;
+      for (int j = 0; j < npats; j++)
+	pats[j] = argv[i+j];
     }
-
-  int npats = argc - i;
-  string_vector pats (npats);
-  for (int j = 0; j < npats; j++)
-    pats[j] = argv[i+j];
-
-  // If the user specified -l and nothing else, show variables.  If
-  // evaluating this at the top level, also show functions.
-
-  if (show_verbose && ! (show_builtins || show_functions || show_variables))
-    {
-      show_functions = at_top_level ();
-      show_variables = 1;
-    }
+  else
+    pats[0] = "*";
+    
+  symbol_table::scope_id scope = global_only
+    ? symbol_table::global_scope () : symbol_table::current_scope ();
+
+  std::list<symbol_table::symbol_record> symbols
+    = symbol_table::glob_variables (pats, scope);
+
+  size_t symbols_len = symbols.size ();
 
   if (return_list)
     {
-      // FIXME -- maybe symbol_list should return a std::list
-      // object instead of an Array.
-
-      dim_vector dv (0, 0);
-
-      Array<symbol_record *> s3 (dv);
-      Array<symbol_record *> s4 (dv);
-      Array<symbol_record *> s5 (dv);
-      Array<symbol_record *> s6 (dv);
-      Array<symbol_record *> s7 (dv);
-      Array<symbol_record *> s8 (dv);
-
-      if (show_builtins)
-	{
-	  s3 = fbi_sym_tab->symbol_list (pats, symbol_record::BUILTIN_FUNCTION,
-					 SYMTAB_ALL_SCOPES);
-	}
-
-      if (show_functions)
-	{
-	  s4 = fbi_sym_tab->symbol_list (pats, symbol_record::DLD_FUNCTION,
-					 SYMTAB_ALL_SCOPES);
-
-	  s5 = fbi_sym_tab->symbol_list (pats, symbol_record::USER_FUNCTION,
-					 SYMTAB_ALL_SCOPES);
-
-	  s6 = fbi_sym_tab->symbol_list (pats, symbol_record::MEX_FUNCTION,
-					 SYMTAB_ALL_SCOPES);
-	}
-
-      if (show_variables)
-	{
-	  s7 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE,
-					  SYMTAB_LOCAL_SCOPE);
-
-	  s8 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE,
-					  SYMTAB_GLOBAL_SCOPE);
-	}
-
-      octave_idx_type s3_len = s3.length ();
-      octave_idx_type s4_len = s4.length ();
-      octave_idx_type s5_len = s5.length ();
-      octave_idx_type s6_len = s6.length ();
-      octave_idx_type s7_len = s7.length ();
-      octave_idx_type s8_len = s8.length ();
-
-      octave_idx_type symbols_len
-	= s3_len + s4_len + s5_len + s6_len + s7_len + s8_len;
-
-      Array<symbol_record *> symbols (dim_vector (symbols_len, 1));
-
-      octave_idx_type k = 0;
-
-      symbols.insert (s3, k, 0);
-      k += s3_len;
-      symbols.insert (s4, k, 0);
-      k += s4_len;
-      symbols.insert (s5, k, 0);
-      k += s5_len;
-      symbols.insert (s6, k, 0);
-      k += s6_len;
-      symbols.insert (s7, k, 0);
-      k += s7_len;
-      symbols.insert (s8, k, 0);
-
-      symbols.qsort (symbol_record_name_compare);
-
-      if (show_verbose)
+      if (verbose)
 	{
 	  Array<octave_value> name_info (symbols_len, 1);
 	  Array<octave_value> size_info (symbols_len, 1);
@@ -1693,9 +1678,12 @@
 	  Array<octave_value> complex_info (symbols_len, 1);
 	  Array<octave_value> nesting_info (symbols_len, 1);
 
-	  for (octave_idx_type j = 0; j < symbols_len; j++)
+	  std::list<symbol_table::symbol_record>::const_iterator p
+	    = symbols.begin ();
+
+	  for (size_t j = 0; j < symbols_len; j++)
 	    {
-	      symbol_record *sr = symbols(j);
+	      const symbol_table::symbol_record& sr = *p++;
 
 	      Octave_map ni;
 
@@ -1708,13 +1696,16 @@
 	      ni.assign ("function", caller_function_name);
 	      ni.assign ("level", 1);
 
-	      name_info(j) = sr->name ();
-	      size_info(j) = sr->size ();
-	      bytes_info(j) = sr->byte_size ();
-	      class_info(j) = sr->class_name ();
-	      global_info(j) = sr->is_linked_to_global ();
-	      sparse_info(j) = sr->is_sparse_type ();
-	      complex_info(j) = sr->is_complex_type ();
+	      name_info(j) = sr.name ();
+	      global_info(j) = sr.is_global ();
+
+	      octave_value val = sr.varval ();
+
+	      size_info(j) = val.size ();
+	      bytes_info(j) = val.byte_size ();
+	      class_info(j) = val.class_name ();
+	      sparse_info(j) = val.is_sparse_type ();
+	      complex_info(j) = val.is_complex_type ();
 	      nesting_info(j) = ni;
 	    }
 
@@ -1739,56 +1730,70 @@
 	    {
 	      names.resize (symbols_len);
 
-	      for (octave_idx_type j = 0; j < symbols_len; j++)
-		names[j] = symbols(j)->name ();
+	      std::list<symbol_table::symbol_record>::const_iterator p
+		= symbols.begin ();
+
+	      for (size_t j = 0; j < symbols_len; j++)
+		{
+		  names[j] = p->name ();
+		  p++;
+		}
 	    }
 
 	  retval = Cell (names);
 	}
     }
-  else
+  else if (symbols_len > 0)
     {
-      int pad_after = 0;
-
-      if (show_builtins)
-	{
-	  pad_after += fbi_sym_tab->maybe_list
-	    ("*** built-in functions:", pats, octave_stdout,
-	     show_verbose, symbol_record::BUILTIN_FUNCTION, SYMTAB_ALL_SCOPES);
-	}
-
-      if (show_functions)
+      if (global_only)
+	octave_stdout << "Global variables:\n\n";
+      else
+	octave_stdout << "Variables in the current scope:\n\n";
+
+      if (verbose)
 	{
-	  pad_after += fbi_sym_tab->maybe_list
-	    ("*** dynamically linked functions:", pats,
-	     octave_stdout, show_verbose, symbol_record::DLD_FUNCTION,
-	     SYMTAB_ALL_SCOPES);
-
-	  pad_after += fbi_sym_tab->maybe_list
-	    ("*** currently compiled functions:", pats,
-	     octave_stdout, show_verbose, symbol_record::USER_FUNCTION,
-	     SYMTAB_ALL_SCOPES);
-
-	  pad_after += fbi_sym_tab->maybe_list
-	    ("*** mex functions:", pats,
-	     octave_stdout, show_verbose, symbol_record::MEX_FUNCTION,
-	     SYMTAB_ALL_SCOPES);
+	  size_t bytes = 0;
+	  size_t elements = 0;
+
+	  std::list<whos_parameter> params;
+
+	  params = parse_whos_line_format (symbols);
+
+	  print_descriptor (octave_stdout, params);
+
+	  octave_stdout << "\n";
+
+	  for (std::list<symbol_table::symbol_record>::const_iterator p = symbols.begin ();
+	       p != symbols.end (); p++)
+	    {
+	      print_symbol_info_line (octave_stdout, *p, params);
+	      octave_value val = p->varval ();
+	      elements += val.capacity ();
+	      bytes += val.byte_size ();
+	    }
+
+	  octave_stdout << "\nTotal is " << elements
+			<< (elements == 1 ? " element" : " elements")
+			<< " using " << bytes
+			<< (bytes == 1 ? " byte" : " bytes") << "\n";
 	}
-
-      if (show_variables)
+      else
 	{
-	  pad_after += curr_sym_tab->maybe_list
-	    ("*** local user variables:", pats, octave_stdout,
-	     show_verbose, symbol_record::USER_VARIABLE, SYMTAB_LOCAL_SCOPE);
-
-	  pad_after += curr_sym_tab->maybe_list
-	    ("*** globally visible user variables:", pats,
-	     octave_stdout, show_verbose, symbol_record::USER_VARIABLE,
-	     SYMTAB_GLOBAL_SCOPE);
+	  string_vector names (symbols_len);
+
+	  std::list<symbol_table::symbol_record>::const_iterator p
+	    = symbols.begin ();
+
+	  for (size_t j = 0; j < symbols_len; j++)
+	    {
+	      names[j] = p->name ();
+	      p++;
+	    }
+
+	  names.list_in_columns (octave_stdout);
 	}
 
-      if (pad_after)
-	octave_stdout << "\n";
+      octave_stdout << "\n";
     }
 
   return retval;
@@ -1840,10 +1845,8 @@
 
       string_vector argv = args.make_argv ("who");
 
-      if (error_state)
-	return retval;
-
-      retval = do_who (argc, argv, nargout == 1);
+      if (! error_state)
+	retval = do_who (argc, argv, nargout == 1);
     }
   else
     print_usage ();
@@ -1861,23 +1864,12 @@
 
   if (nargout < 2)
     {
-      int nargin = args.length ();
-
-      octave_value_list tmp_args;
-
-      for (int i = nargin; i > 0; i--)
-	tmp_args(i) = args(i-1);
-
-      tmp_args(0) = "-long";
-
-      int argc = tmp_args.length () + 1;
-
-      string_vector argv = tmp_args.make_argv ("whos");
-
-      if (error_state)
-	return retval;
-
-      retval = do_who (argc, argv, nargout == 1);
+      int argc = args.length () + 1;
+
+      string_vector argv = args.make_argv ("whos");
+
+      if (! error_state)
+	retval = do_who (argc, argv, nargout == 1, true);
     }
   else
     print_usage ();
@@ -1890,14 +1882,14 @@
 void
 bind_ans (const octave_value& val, bool print)
 {
-  symbol_record *sr = curr_sym_tab->lookup ("ans", true);
+  static std::string ans = "ans";
 
   if (val.is_defined ())
     {
-      sr->define (val);
+      symbol_table::varref (ans) = val;
 
       if (print)
-	val.print_with_name (octave_stdout, "ans");
+	val.print_with_name (octave_stdout, ans);
     }
 }
 
@@ -1912,61 +1904,59 @@
 }
 
 void 
-mlock (const std::string& nm)
+mlock (void)
 {
-  symbol_record *sr = fbi_sym_tab->lookup (nm, true);
-
-  if (sr)
-    sr->mark_as_static ();
+  octave_function *fcn = octave_call_stack::caller ();
+
+  if (fcn)
+    fcn->lock ();
+  else
+    error ("mlock: invalid use outside a function");
 }
 
 void 
 munlock (const std::string& nm)
 {
-  symbol_record *sr = fbi_sym_tab->lookup (nm);
-
-  if (sr && sr->is_static ())
-    sr->unmark_static ();
-  else
-    error ("munlock: %s is not locked", nm.c_str ());
+  octave_value val = symbol_table::find_function (nm);
+
+  if (val.is_defined ())
+    {
+      octave_function *fcn = val.function_value ();
+
+      if (fcn)
+	fcn->unlock ();
+    }
 }
 
 bool
 mislocked (const std::string& nm)
 {
-  symbol_record *sr = fbi_sym_tab->lookup (nm);
-
-  return (sr && sr->is_static ());
+  bool retval = false;
+
+  octave_value val = symbol_table::find_function (nm);
+
+  if (val.is_defined ())
+    {
+      octave_function *fcn = val.function_value ();
+
+      if (fcn)
+	retval = fcn->islocked ();
+    }
+
+  return retval;
 }
 
 DEFCMD (mlock, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} mlock (@var{name})\n\
-Lock the named function into memory.  If no function is named\n\
-then lock in the current function.\n\
+Lock the current function into memory so that it can't be cleared.\n\
 @seealso{munlock, mislocked, persistent}\n\
 @end deftypefn")
 {
   octave_value_list retval;
 
-  if (args.length () == 1)
-    {
-      std::string name = args(0).string_value ();
-
-      if (! error_state)
-	mlock (name);
-      else
-	error ("mlock: expecting argument to be a function name");
-    }
-  else if (args.length () == 0)
-    {
-      octave_user_function *fcn = octave_call_stack::caller_user_function ();
-
-      if (fcn)
-        mlock (fcn->name ());
-      else
-        error ("mlock: invalid use outside a function");
-    }
+  if (args.length () == 0)
+    mlock ();
   else
     print_usage ();
 
@@ -1994,10 +1984,10 @@
     }
   else if (args.length () == 0)
     {
-      octave_user_function *fcn = octave_call_stack::caller_user_function ();
+      octave_function *fcn = octave_call_stack::caller ();
 
       if (fcn)
-        munlock (fcn->name ());
+        fcn->unlock ();
       else
         error ("munlock: invalid use outside a function");
     }
@@ -2029,10 +2019,10 @@
     }
   else if (args.length () == 0)
     {
-      octave_user_function *fcn = octave_call_stack::caller_user_function ();
+      octave_function *fcn = octave_call_stack::caller ();
 
       if (fcn)
-        retval = mislocked (fcn->name ());
+        retval = fcn->islocked ();
       else
         error ("mislocked: invalid use outside a function");
     }
@@ -2069,14 +2059,6 @@
   return retval;
 }
 
-static inline bool
-is_local_variable (const std::string& nm)
-{
-  symbol_record *sr = curr_sym_tab->lookup (nm);
-
-  return (sr && sr->is_variable ());
-}
-
 static inline void
 maybe_warn_exclusive (bool exclusive)
 {
@@ -2084,136 +2066,17 @@
     warning ("clear: ignoring --exclusive option");
 }
 
-static inline void
-do_clear_all (void)
-{
-  curr_sym_tab->clear ();
-  fbi_sym_tab->clear_functions ();
-  global_sym_tab->clear ();
-}
-
-static inline void
-do_clear_functions (void)
-{
-  curr_sym_tab->clear_functions ();
-  fbi_sym_tab->clear_functions ();
-}
-
-static inline void
-do_clear_globals (void)
-{
-  curr_sym_tab->clear_globals ();
-  global_sym_tab->clear ();
-}
-
-static inline void
-do_clear_variables (void)
-{
-  curr_sym_tab->clear ();
-}
-
-static inline bool
-do_clear_function (const std::string& nm)
-{
-  bool b1 = curr_sym_tab->clear_function (nm);
-
-  bool b2 = fbi_sym_tab->clear_function (nm);
-
-  return b1 || b2;
-}
-
-static inline bool
-do_clear_global (const std::string& nm)
-{
-  bool b1 = curr_sym_tab->clear_global (nm);
-
-  bool b2 = global_sym_tab->clear_variable (nm);
-
-  return b1 || b2;
-}
-
-static inline bool
-do_clear_variable (const std::string& nm)
-{
-  return curr_sym_tab->clear_variable (nm);
-}
-
-static inline bool
-do_clear_symbol (const std::string& nm)
-{
-  bool cleared = curr_sym_tab->clear_variable (nm);
-
-  if (! cleared)
-    cleared = do_clear_function (nm);
-
-  return cleared;
-}
-
-static inline bool
-do_clear_function_pattern (const std::string& pat)
-{
-  bool b1 = curr_sym_tab->clear_function_pattern (pat);
-
-  bool b2 = fbi_sym_tab->clear_function_pattern (pat);
-
-  return b1 || b2;
-}
-
-static inline bool
-do_clear_global_pattern (const std::string& pat)
-{
-  bool b1 = curr_sym_tab->clear_global_pattern (pat);
-
-  bool b2 = global_sym_tab->clear_variable_pattern (pat);
-
-  return b1 || b2;
-}
-
-static inline bool
-do_clear_variable_pattern (const std::string& pat)
-{
-  return curr_sym_tab->clear_variable_pattern (pat);
-}
-
-static inline bool
-do_clear_symbol_pattern (const std::string& pat)
-{
-  // FIXME -- if we have a variable v1 and a function v2 and
-  // someone says clear v*, we will clear the variable but not the
-  // function.  Is that really what should happen?  (I think it is
-  // what Matlab does.)
-
-  bool cleared = curr_sym_tab->clear_variable_pattern (pat);
-
-  if (! cleared)
-    cleared = do_clear_function_pattern (pat);
-
-  return cleared;
-}
-
-static inline void
+static void
 do_clear_functions (const string_vector& argv, int argc, int idx,
 		    bool exclusive = false)
 {
   if (idx == argc)
-    do_clear_functions ();
+    symbol_table::clear_functions ();
   else
     {
       if (exclusive)
 	{
-	  string_vector lfcns = curr_sym_tab->user_function_name_list ();
-
-	  int lcount = lfcns.length ();
-
-	  for (int i = 0; i < lcount; i++)
-	    {
-	      std::string nm = lfcns[i];
-
-	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_function (nm);
-	    }
-
-	  string_vector fcns = fbi_sym_tab->user_function_name_list ();
+	  string_vector fcns = symbol_table::user_function_names ();
 
 	  int fcount = fcns.length ();
 
@@ -2222,40 +2085,29 @@
 	      std::string nm = fcns[i];
 
 	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_function (nm);
+		symbol_table::clear_function (nm);
 	    }
 	}
       else
 	{
 	  while (idx < argc)
-	    do_clear_function_pattern (argv[idx++]);
+	    symbol_table::clear_function_pattern (argv[idx++]);
 	}
     }
 }
 
-static inline void
+static void
 do_clear_globals (const string_vector& argv, int argc, int idx,
 		  bool exclusive = false)
 {
   if (idx == argc)
-    do_clear_globals ();
+    symbol_table::clear_variables(symbol_table::global_scope ());
   else
     {
       if (exclusive)
 	{
-	  string_vector lvars = curr_sym_tab->global_variable_name_list ();
-
-	  int lcount = lvars.length ();
-
-	  for (int i = 0; i < lcount; i++)
-	    {
-	      std::string nm = lvars[i];
-
-	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_global (nm);
-	    }
-
-	  string_vector gvars = global_sym_tab->global_variable_name_list ();
+	  string_vector gvars
+	    = symbol_table::variable_names (symbol_table::global_scope ());
 
 	  int gcount = gvars.length ();
 
@@ -2264,28 +2116,28 @@
 	      std::string nm = gvars[i];
 
 	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_global (nm);
+		symbol_table::clear_global (nm);
 	    }
 	}
       else
 	{
 	  while (idx < argc)
-	    do_clear_global_pattern (argv[idx++]);
+	    symbol_table::clear_global_pattern (argv[idx++]);
 	}
     }
 }
 
-static inline void
+static void
 do_clear_variables (const string_vector& argv, int argc, int idx,
 		    bool exclusive = false)
 {
   if (idx == argc)
-    do_clear_variables ();
+    symbol_table::clear_variables ();
   else
     {
       if (exclusive)
 	{
-	  string_vector lvars = curr_sym_tab->variable_name_list ();
+	  string_vector lvars = symbol_table::variable_names ();
 
 	  int lcount = lvars.length ();
 
@@ -2294,23 +2146,23 @@
 	      std::string nm = lvars[i];
 
 	      if (! name_matches_any_pattern (nm, argv, argc, idx))
-		do_clear_variable (nm);
+		symbol_table::clear_variable (nm);
 	    }
 	}
       else
 	{
 	  while (idx < argc)
-	    do_clear_variable_pattern (argv[idx++]);
+	    symbol_table::clear_variable_pattern (argv[idx++]);
 	}
     }
 }
 
-static inline void
+static void
 do_clear_symbols (const string_vector& argv, int argc, int idx,
 		  bool exclusive = false)
 {
   if (idx == argc)
-    do_clear_variables ();
+    symbol_table::clear_variables ();
   else
     {
       if (exclusive)
@@ -2326,7 +2178,7 @@
       else
 	{
 	  while (idx < argc)
-	    do_clear_symbol_pattern (argv[idx++]);
+	    symbol_table::clear_symbol_pattern (argv[idx++]);
 	}
     }
 }
@@ -2338,25 +2190,29 @@
 
   for (; idx < argc; idx++)
     {
-      if (argv[idx] == "all" && ! is_local_variable ("all"))
+      if (argv[idx] == "all"
+	  && ! symbol_table::is_local_variable ("all"))
 	{
-	  do_clear_all ();
+	  symbol_table::clear_all ();
 	}
-      else if (argv[idx] == "functions" && ! is_local_variable ("functions"))
+      else if (argv[idx] == "functions"
+	       && ! symbol_table::is_local_variable ("functions"))
 	{
 	  do_clear_functions (argv, argc, ++idx);
 	}
-      else if (argv[idx] == "global" && ! is_local_variable ("global"))
+      else if (argv[idx] == "global"
+	       && ! symbol_table::is_local_variable ("global"))
 	{
 	  do_clear_globals (argv, argc, ++idx);
 	}
-      else if (argv[idx] == "variables" && ! is_local_variable ("variables"))
+      else if (argv[idx] == "variables"
+	       && ! symbol_table::is_local_variable ("variables"))
 	{
-	  do_clear_variables ();
+	  symbol_table::clear_variables ();
 	}
       else
 	{
-	  do_clear_symbol_pattern (argv[idx]);
+	  symbol_table::clear_symbol_pattern (argv[idx]);
 	}
     }
 }
@@ -2372,24 +2228,6 @@
     } \
   while (0)
 
-bool
-clear_function (const std::string& nm)
-{
-  return do_clear_function (nm);
-}
-
-bool
-clear_variable (const std::string& nm)
-{
-  return do_clear_variable (nm);
-}
-
-bool
-clear_symbol (const std::string& nm)
-{
-  return do_clear_symbol (nm);
-}
-
 DEFCMD (clear, args, ,
   "-*- texinfo -*-\n\
 @deffn {Command} clear [-x] pattern @dots{}\n\
@@ -2443,7 +2281,7 @@
     {
       if (argc == 1)
 	{
-	  do_clear_variables ();
+	  symbol_table::clear_variables ();
 	}
       else
 	{
@@ -2511,9 +2349,7 @@
 			warning
 			  ("clear: ignoring extra arguments after -all");
 
-		      curr_sym_tab->clear ();
-		      fbi_sym_tab->clear_functions ();
-		      global_sym_tab->clear ();
+		      symbol_table::clear_all ();
 		    }
 		  else if (clear_functions)
 		    {
@@ -2547,40 +2383,9 @@
 {
   octave_value_list retval;
 
-  int nargin = args.length ();
-
-  if (nargin == 1)
-    {
-      std::string arg = args(0).string_value ();
-
-      if (arg == "fbi")
-	fbi_sym_tab->print_info (octave_stdout);
-      else if (arg == "global")
-	global_sym_tab->print_info (octave_stdout);
-      else if (arg == "top-level")
-	top_level_sym_tab->print_info (octave_stdout);
-      else
-	{
-	  symbol_record *fsr = fbi_sym_tab->lookup (arg, true);
-
-	  if (fsr && fsr->is_user_function ())
-	    {
-	      octave_value tmp = fsr->def ();
-	      const octave_base_value& rep = tmp.get_rep ();
-	      
-	      const octave_user_function& fcn
-		= dynamic_cast<const octave_user_function&> (rep);
-
-	      fcn.print_symtab_info (octave_stdout);
-	    }
-	  else
-	    error ("no user-defined function named %s", arg.c_str ());
-	}
-    }
-  else if (nargin == 0)
-    curr_sym_tab->print_info (octave_stdout);
-  else
-    print_usage ();
+  // FIXME -- what should this function do now?  Print a summary for
+  // each scope?  Print the entire symbol table?  Accept a scope
+  // argument?
 
   return retval;
 }
@@ -2593,92 +2398,67 @@
 {
   octave_value_list retval;
 
-  int nargin = args.length ();
-
-  if (nargin == 1)
-    {
-      std::string symbol_name = args(0).string_value ();
-
-      if (! error_state)
-	{
-	  symbol_record *sr = curr_sym_tab->lookup (symbol_name);
-
-	  if (sr)
-	    sr->print_info (octave_stdout);
-	  else
-	    error ("__print_symbol_info__: symbol %s not found",
-		   symbol_name.c_str ());
-	}
-      else
-	print_usage ();
-    }
-  else
-    print_usage ();
+  // FIXME -- what should this function do now?
 
   return retval;
 }
 
-DEFUN (ignore_function_time_stamp, args, nargout,
-    "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {@var{val} =} ignore_function_time_stamp ()\n\
-@deftypefnx {Built-in Function} {@var{old_val} =} ignore_function_time_stamp (@var{new_val})\n\
-Query or set the internal variable that controls whether Octave checks\n\
-the time stamp on files each time it looks up functions defined in\n\
-function files.  If the internal variable is set to @code{\"system\"},\n\
-Octave will not automatically recompile function files in subdirectories of\n\
-@file{@var{octave-home}/lib/@var{version}} if they have changed since\n\
-they were last compiled, but will recompile other function files in the\n\
-search path if they change.  If set to @code{\"all\"}, Octave will not\n\
-recompile any function files unless their definitions are removed with\n\
-@code{clear}.  If set to \"none\", Octave will always check time stamps\n\
-on files to determine whether functions defined in function files\n\
-need to be recompiled.\n\
+DEFUN (whos_line_format, args, nargout,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {@var{val} =} whos_line_format ()\n\
+@deftypefnx {Built-in Function} {@var{old_val} =} whos_line_format (@var{new_val})\n\
+Query or set the format string used by the @code{whos}.\n\
+\n\
+The following escape sequences may be used in the format:\n\
+@table @code\n\
+@item %a\n\
+Prints attributes of variables (g=global, p=persistent,\n\
+f=formal parameter, a=automatic variable).\n\
+@item %b\n\
+Prints number of bytes occupied by variables.\n\
+@item %c\n\
+Prints class names of variables.\n\
+@item %e\n\
+Prints elements held by variables.\n\
+@item %n\n\
+Prints variable names.\n\
+@item %s\n\
+Prints dimensions of variables.\n\
+@item %t\n\
+Prints type names of variables.\n\
+@end table\n\
+\n\
+Every command may also have a modifier:\n\
+@table @code\n\
+@item l\n\
+Left alignment.\n\
+@item r\n\
+Right alignment (this is the default).\n\
+@item c\n\
+Centered (may only be applied to command %s).\n\
+@end table\n\
+\n\
+A command is composed like this:\n\
+\n\
+@example\n\
+%[modifier]<command>[:size_of_parameter[:center-specific[\n\
+       :print_dims[:balance]]]];\n\
+@end example\n\
+\n\
+Command and modifier is already explained. Size_of_parameter\n\
+tells how many columns the parameter will need for printing.\n\
+print_dims tells how many dimensions to print. If number of\n\
+dimensions exceeds print_dims, dimensions will be printed like\n\
+x-D.\n\
+center-specific and print_dims may only be applied to command\n\
+%s. A negative value for print_dims will cause Octave to print all\n\
+dimensions whatsoever.\n\
+balance specifies the offset for printing of the dimensions string.\n\
+\n\
+The default format is \"  %a:4; %ln:6; %cs:16:6:8:1;  %rb:12;  %lc:-1;\\n\".\n\
 @end deftypefn")
 {
-  octave_value retval;
-
-  if (nargout > 0)
-    {
-      switch (Vignore_function_time_stamp)
-	{
-	case 1:
-	  retval = "system";
-	  break;
-
-	case 2:
-	  retval = "all";
-	  break;
-
-	default:
-	  retval = "none";
-	  break;
-	}
-    }
-
-  int nargin = args.length ();
-
-  if (nargin == 1)
-    {
-      std::string sval = args(0).string_value ();
-
-      if (! error_state)
-	{
-	  if (sval == "all")
-	    Vignore_function_time_stamp = 2;
-	  else if (sval == "system")
-	    Vignore_function_time_stamp = 1;
-	  else if (sval == "none")
-	    Vignore_function_time_stamp = 0;
-	  else
-	    error ("ignore_function_time_stamp: expecting argument to be \"all\", \"system\", or \"none\"");
-	}
-      else
-	error ("ignore_function_time_stamp: expecting argument to be character string");
-    }
-  else if (nargin > 1)
-    print_usage ();
-
-  return retval;
+  return SET_INTERNAL_VARIABLE (whos_line_format);
 }
 
 /*
--- a/src/variables.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/variables.h	Fri Dec 28 20:56:58 2007 +0000
@@ -26,8 +26,6 @@
 
 class octave_function;
 class octave_user_function;
-class symbol_record;
-class symbol_table;
 
 class tree_identifier;
 class octave_value;
@@ -45,11 +43,9 @@
 #include "ov-builtin.h"
 #include "symtab.h"
 
-extern OCTINTERP_API bool at_top_level (void);
-
-extern OCTINTERP_API void initialize_symbol_tables (void);
 extern OCTINTERP_API void clear_mex_functions (void);
 
+extern OCTINTERP_API void mark_as_command (const std::string&);
 extern OCTINTERP_API bool is_command_name (const std::string&);
 
 // The next three are here temporarily...
@@ -58,9 +54,6 @@
 extern OCTINTERP_API void unmark_rawcommand (const std::string& s);
 
 extern OCTINTERP_API bool is_rawcommand_name (const std::string&);
-extern OCTINTERP_API bool is_mapper_function_name (const std::string&);
-extern OCTINTERP_API bool is_builtin_function_name (const std::string&);
-extern OCTINTERP_API bool is_globally_visible (const std::string&);
 
 extern OCTINTERP_API octave_function *
 is_valid_function (const octave_value&, const std::string& = std::string (),
@@ -91,20 +84,6 @@
 extern OCTINTERP_API std::string
 unique_symbol_name (const std::string& basename);
 
-extern OCTINTERP_API bool
-fcn_out_of_date (octave_function *fcn, const std::string& ff, time_t tp);
-
-extern OCTINTERP_API bool lookup (symbol_record *s, bool exec_script = true);
-
-extern OCTINTERP_API symbol_record *
-lookup_by_name (const std::string& nm, bool exec_script = true);
-
-extern OCTINTERP_API octave_value
-lookup_function (const std::string& nm,
-		 const std::string& parent = std::string ());
-
-extern OCTINTERP_API octave_value lookup_user_function (const std::string& nm);
-
 extern OCTINTERP_API octave_value lookup_function_handle (const std::string& nm);
 
 extern OCTINTERP_API octave_value
@@ -147,38 +126,18 @@
 extern OCTINTERP_API int builtin_real_scalar_variable (const std::string&, double&);
 extern OCTINTERP_API octave_value builtin_any_variable (const std::string&);
 
-extern OCTINTERP_API void link_to_global_variable (symbol_record *sr);
-extern OCTINTERP_API void link_to_builtin_or_function (symbol_record *sr);
-
-extern OCTINTERP_API void force_link_to_function (const std::string&);
-
 extern OCTINTERP_API void bind_ans (const octave_value& val, bool print);
 
 extern OCTINTERP_API void
 bind_internal_variable (const std::string& fname, const octave_value& val);
 
-extern OCTINTERP_API void mlock (const std::string&);
+extern OCTINTERP_API void mlock (void);
 extern OCTINTERP_API void munlock (const std::string&);
 extern OCTINTERP_API bool mislocked (const std::string&);
 
-extern OCTINTERP_API bool clear_function (const std::string& nm);
-extern OCTINTERP_API bool clear_variable (const std::string& nm);
-extern OCTINTERP_API bool clear_symbol (const std::string& nm);
-
-// Symbol table for symbols at the top level.
-extern OCTINTERP_API symbol_table *top_level_sym_tab;
-
-// Symbol table for the current scope.
-extern OCTINTERP_API symbol_table *curr_sym_tab;
-
-// Symbol table for the current caller scope.
-extern OCTINTERP_API symbol_table *curr_caller_sym_tab;
-
-// Symbol table for global symbols.
-extern OCTINTERP_API symbol_table *global_sym_tab;
-
-// Symbol table for functions and built-in symbols.
-extern OCTINTERP_API symbol_table *fbi_sym_tab;
+extern OCTINTERP_API void clear_function (const std::string& nm);
+extern OCTINTERP_API void clear_variable (const std::string& nm);
+extern OCTINTERP_API void clear_symbol (const std::string& nm);
 
 #endif
 
--- a/src/version.h	Fri Feb 01 23:56:51 2008 -0500
+++ b/src/version.h	Fri Dec 28 20:56:58 2007 +0000
@@ -24,9 +24,9 @@
 #if !defined (octave_version_h)
 #define octave_version_h 1
 
-#define OCTAVE_VERSION "3.0.0"
+#define OCTAVE_VERSION "3.0.0+"
 
-#define OCTAVE_API_VERSION "api-v32"
+#define OCTAVE_API_VERSION "api-v32+"
 
 #define OCTAVE_RELEASE_DATE "2007-12-21"