changeset 4238:a5a68c0afe56

[project @ 2002-12-25 21:04:33 by jwe]
author jwe
date Wed, 25 Dec 2002 21:04:34 +0000
parents 9c8034434982
children 90db7796adc2
files src/ChangeLog src/lex.h src/lex.l src/ov-usr-fcn.cc src/ov-usr-fcn.h src/parse.h src/parse.y src/symtab.cc src/symtab.h src/toplev.cc src/toplev.h src/variables.cc
diffstat 12 files changed, 339 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/ChangeLog	Wed Dec 25 21:04:34 2002 +0000
@@ -1,8 +1,74 @@
+2002-12-25  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* variables.cc (link_to_builtin_or_function): Maybe prepend parent
+	function name symbol name.
+
+	* parse.y (parent_function_name): New variable.
+	(fcn_name): New non-terminal.
+	(function2): Use it.
+	(parsed_fcn_name): Fold into fcn_name.
+	(function_end): Don't call check_for_garbage_after_fcn_def.
+	Set lexer_flags.parsing_nested_function on EOF.
+	* parse.h: Provide decl for parent_function_name.
+
+	* ov-usr-fcn.h (octave_user_function::mark_as_nested_function,
+	(octave_user_funciton::is_nested_function): New functions.
+	(octave_user_function::nested_function): New data member.
+	(octave_user_function::do_multi_index_op): Maybe protect and set
+	curr_parent_function pointer.
+	* parse.y (frob_function): Maybe mark as nested function.
+
+	* toplev.cc (curr_parent_function): New global variable.
+	* toplev.h: Provide decl.
+
+	* lex.l (check_for_garbage_after_fcn_def): Delete.
+	* lex.h: Delete decl.
+
+	* lex.l (prep_for_nested_function): New function.
+	(<NESTED_FUNCTION_START>): Use it here.
+	(is_keyword): And here.
+	(lookup_identifier): Maybe prepend parent function name.
+
+	* variables.cc (initialize_symbol_tables): Give names to the three
+	main symbol tables.
+	* symtab.cc (symbol_table::lookup, symbol_table::rename): Print
+	debugging info if Vdebug_symtab_lookups is nonzero.
+	(debug_symtab_lookups): New function.
+	(Vdebug_symtab_lookups): New static varaible.
+	(symbols_of_symtab): DEFVAR it.
+	* symtab.h (symbol_table::table_name): New member variable.
+	(symtab_count): New static member variable.
+	(symbol_table::symbol_table): Handle table name.
+
 2002-12-24  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
+	* parse.y (frob_function): Don't give nested functions the same
+	name as the function file.
+
+	* lex.h (lexical_feedback::parsing_nested_function): New data member.
+	* lex.l (lexical_feedback::init): Initialize it to false.
+	(<NESTED_FUNCTION_START>): Set lexer_flags.parsing_nested_function
+	to true.
+
+	* parse.y (symtab_context): Now a stack.  Change all uses.
+
+	* lex.l (NESTED_FUNCTION_START): New start state to handle
+	"function" keyword in a nested function context.
+	(prep_for_function): New function.
+	(is_keyword): Allow functions to be nested in function files.
+
+	* lex.l (is_keyword): Maybe ignore END tokens.
+	Increment and decrement end_tokens_expected as appropriate.
+	(handle_identifier): If is_keyword returns -1, return immediately.
+	({IDENT}{S}*): Do nothing if handle_identifier returns -1.
+
+	* parse.y (end_tokens_expected): New variable.
+	(parse_fcn_file): Protect and set it.
+
 	* parse.y (begin_obj_idx): Increment
 	lexer_flags.looking_at_object_index.
 	(postfix_expr): Decrement it as appropriate here.
+
 	* lex.h (lexical_feedback::looking_at_object_index): Now int.
 
 	* parse.y (postfix_expr): Reset	lexer_flags.looking_at_object_index
--- a/src/lex.h	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/lex.h	Wed Dec 25 21:04:34 2002 +0000
@@ -113,11 +113,6 @@
 // Delete a buffer (for unwind-prot).
 extern void delete_input_buffer (void *buf);
 
-// See if a function file has extra garbage after the end statement.
-// This needs to be defined in lex.l so that it can use yyinput() but
-// it must be called from parse.y.
-extern void check_for_garbage_after_fcn_def (void);
-
 // For communication between the lexer and parser.
 
 class
@@ -191,6 +186,9 @@
   // Should only matter if defining_func is also TRUE.
   bool parsed_function_name;
 
+  // TRUE means that we're parsing a nested function definition.
+  bool parsing_nested_function;
+
   // TRUE means we've seen something that means we must be past the
   // range part of a plot command.
   bool past_plot_range;
--- a/src/lex.l	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/lex.l	Wed Dec 25 21:04:34 2002 +0000
@@ -22,6 +22,7 @@
 
 %s COMMAND_START
 %s MATRIX_START
+%s NESTED_FUNCTION_START
 
 %{
 #ifdef HAVE_CONFIG_H
@@ -193,6 +194,8 @@
 static void do_comma_insert_check (void);
 static int is_plot_keyword (const std::string& s);
 static int is_keyword (const std::string& s);
+static void prep_for_function (void);
+static void prep_for_nested_function (void);
 static std::string plot_style_token (const std::string& s);
 static symbol_record *lookup_identifier (const std::string& s);
 static void grab_help_text (void);
@@ -238,6 +241,12 @@
 NUMBER	(({D}+\.?{D}*{EXPON}?)|(\.{D}+{EXPON}?)|(0[xX][0-9a-fA-F]+))
 %%
 
+<NESTED_FUNCTION_START>{} {
+    BEGIN 0;
+    prep_for_nested_function ();
+    return FCN;
+  }
+
 %{
 // Help and other command-style functions are a pain in the ass.  This
 // stuff needs to be simplified.  May require some changes in the
@@ -529,7 +538,10 @@
 %}
 
 {IDENT}{S}* {
-    return handle_identifier ();
+    int id_tok = handle_identifier ();
+
+    if (id_tok >= 0)
+      return id_tok;
   }
 
 %{
@@ -814,7 +826,10 @@
   error_state = 0;
   warning_state = 0;
   parser_end_of_input = false;
-  symtab_context = 0;
+  end_tokens_expected = 0;
+
+  while (! symtab_context.empty ())
+    symtab_context.pop ();
 
   // We do want a prompt by default.
   promptflag = 1;
@@ -1046,7 +1061,35 @@
     }
 }
 
-// Handle keywords.
+static void
+prep_for_function (void)
+{
+  end_tokens_expected++;
+
+  // Prepare for local symbols.
+
+  tmp_local_sym_tab = new symbol_table ();
+
+  promptflag--;
+
+  lexer_flags.defining_func = true;
+  lexer_flags.parsed_function_name = false;
+  lexer_flags.beginning_of_function = true;
+
+  if (! (reading_fcn_file || reading_script_file))
+    input_line_number = 1;
+}
+
+static void
+prep_for_nested_function (void)
+{
+  lexer_flags.parsing_nested_function = true;
+  prep_for_function ();
+  yylval.tok_val = new token (input_line_number, current_input_column);
+  token_stack.push (yylval.tok_val);
+}
+
+// Handle keywords.  Return -1 if the keyword should be ignored.
 
 static int
 is_keyword (const std::string& s)
@@ -1111,40 +1154,65 @@
 	  if (lexer_flags.looking_at_object_index)
 	    return 0;
 	  else
-	    yylval.tok_val = new token (token::simple_end, l, c);
+	    {
+	      if (reading_fcn_file && end_tokens_expected == 1)
+		return -1;
+	      else
+		{
+		  yylval.tok_val = new token (token::simple_end, l, c);
+		  end_tokens_expected--;
+		}
+	    }
 	  break;
 
 	case end_try_catch_kw:
+	  end_tokens_expected--;
 	  yylval.tok_val = new token (token::try_catch_end, l, c);
 	  break;
 
 	case end_unwind_protect_kw:
+	  end_tokens_expected--;
 	  yylval.tok_val = new token (token::unwind_protect_end, l, c);
 	  break;
 
 	case endfor_kw:
+	  end_tokens_expected--;
 	  yylval.tok_val = new token (token::for_end, l, c);
 	  break;
 
 	case endfunction_kw:
-	  yylval.tok_val = new token (token::function_end, l, c);
+	  {
+	    if (reading_fcn_file && end_tokens_expected == 1)
+	      return -1;
+	    else
+	      {
+		yylval.tok_val = new token (token::function_end, l, c);
+		end_tokens_expected--;
+	      }
+	  }
 	  break;
 
 	case endif_kw:
+	  end_tokens_expected--;
 	  yylval.tok_val = new token (token::if_end, l, c);
 	  break;
 
 	case endswitch_kw:
+	  end_tokens_expected--;
 	  yylval.tok_val = new token (token::switch_end, l, c);
 	  break;
 
 	case endwhile_kw:
+	  end_tokens_expected--;
 	  yylval.tok_val = new token (token::while_end, l, c);
 	  break;
 
-	case do_kw:
 	case for_kw:
 	case while_kw:
+	  end_tokens_expected++;
+	  // Fall through...
+
+	case do_kw:
 	  promptflag--;
 	  lexer_flags.looping++;
 	  break;
@@ -1153,6 +1221,7 @@
 	case try_kw:
 	case switch_kw:
 	case unwind_protect_kw:
+	  end_tokens_expected++;
 	  promptflag--;
 	  break;
 
@@ -1172,35 +1241,40 @@
 	  break;
 
 	case function_kw:
-	  if (lexer_flags.defining_func)
-	    {
-	      error ("function keyword invalid within a function body");
-
-	      if ((reading_fcn_file || reading_script_file)
-		  && ! curr_fcn_file_name.empty ())
-		error ("defining new function near line %d of file `%s.m'",
-		       input_line_number, curr_fcn_file_name.c_str ());
-	      else
-		error ("defining new function near line %d",
-		       input_line_number);
-
-	      return LEXICAL_ERROR;
-	    }
-	  else
-	    {
-	      // Prepare for local symbols.
-
-	      tmp_local_sym_tab = new symbol_table ();
-
-	      promptflag--;
-
-	      lexer_flags.defining_func = true;
-	      lexer_flags.parsed_function_name = false;
-	      lexer_flags.beginning_of_function = true;
-
-	      if (! (reading_fcn_file || reading_script_file))
-		input_line_number = 1;
-	    }
+	  {
+	    if (lexer_flags.defining_func)
+	      {
+		if (reading_fcn_file)
+		  {
+
+		    if (lexer_flags.parsing_nested_function)
+		      {
+			BEGIN NESTED_FUNCTION_START;
+			yylval.tok_val = new token (token::function_end, l, c);
+		      }
+		    else
+		      {
+			prep_for_nested_function ();
+			return FCN;
+		      }
+		  }
+		else
+		  {
+		    error ("nested functions not implemented in this context");
+
+		    if ((reading_fcn_file || reading_script_file)
+			&& ! curr_fcn_file_name.empty ())
+		      error ("near line %d of file `%s.m'",
+			     input_line_number, curr_fcn_file_name.c_str ());
+		    else
+		      error ("near line %d", input_line_number);
+
+		    return LEXICAL_ERROR;
+		  }
+	      }
+	    else
+	      prep_for_function ();
+	  }
 	  break;
 
         case magic_file_kw:
@@ -1248,7 +1322,13 @@
 static symbol_record *
 lookup_identifier (const std::string& name)
 {
-  return curr_sym_tab->lookup (name, true);
+  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
@@ -2243,7 +2323,8 @@
 }
 
 // Figure out exactly what kind of token to return when we have seen
-// an identifier.  Handles keywords.
+// an identifier.  Handles keywords.  Return -1 if the identifier
+// should be ignored.
 
 static int
 handle_identifier (void)
@@ -2295,7 +2376,9 @@
 
   if (kw_token)
     {
-      if (kw_token == STYLE)
+      if (kw_token < 0)
+	return kw_token;
+      else if (kw_token == STYLE)
 	{
 	  current_input_column += yyleng;
 	  lexer_flags.quote_is_transpose = false;
@@ -2536,6 +2619,7 @@
   beginning_of_function = false;
   defining_func = false;
   parsed_function_name = false;
+  parsing_nested_function = false;
 
   // Not parsing a function return or parameter list.
   looking_at_return_list = false;
--- a/src/ov-usr-fcn.cc	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/ov-usr-fcn.cc	Wed Dec 25 21:04:34 2002 +0000
@@ -82,7 +82,8 @@
     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), args_passed (), num_args_passed (0),
+    num_named_args (0), nested_function (false),
+    args_passed (), num_args_passed (0),
     curr_va_arg_number (0), vr_list (0), symtab_entry (0),
     argn_sr (0), nargin_sr (0), nargout_sr (0), varargin_sr (0)
 {
@@ -405,6 +406,12 @@
   unwind_protect_ptr (curr_function);
   curr_function = this;
 
+  if (! is_nested_function ())
+    {
+      unwind_protect_ptr (curr_parent_function);
+      curr_parent_function = this;
+    }
+
   // Save and restore args passed for recursive calls.
 
   save_args_passed (args);
--- a/src/ov-usr-fcn.h	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/ov-usr-fcn.h	Wed Dec 25 21:04:34 2002 +0000
@@ -120,6 +120,10 @@
   std::string function_name (void)
     { return fcn_name; }
 
+  void mark_as_nested_function (void) { nested_function = true; }
+
+  bool is_nested_function (void) const { return nested_function; }
+
   void save_args_passed (const octave_value_list& args)
     {
       if (call_depth > 1)
@@ -211,6 +215,9 @@
   // The number of arguments that have names.
   int num_named_args;
 
+  // TRUE means this is a nested function.
+  bool nested_function;
+
   // The values that were passed as arguments.
   octave_value_list args_passed;
 
--- a/src/parse.h	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/parse.h	Wed Dec 25 21:04:34 2002 +0000
@@ -73,11 +73,18 @@
 extern bool evaluating_function_body;
 
 // Keep track of symbol table information when parsing functions.
-extern symbol_table *symtab_context;
+extern std::stack<symbol_table*> symtab_context;
+
+// Name of parent function when parsing function files that might
+// contain nested functions.
+extern std::string parent_function_name;
 
 // TRUE means warn about function files that have time stamps in the future.
 extern bool Vwarn_future_time_stamp;
 
+// Keep a count of how many END tokens we expect.
+extern int end_tokens_expected;
+
 extern void
 parse_and_execute (FILE *f);
 
--- a/src/parse.y	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/parse.y	Wed Dec 25 21:04:34 2002 +0000
@@ -133,8 +133,15 @@
 // an eval() statement.
 bool evaluating_function_body = false;
 
+// Keep a count of how many END tokens we expect.
+int end_tokens_expected = 0;
+
 // Keep track of symbol table information when parsing functions.
-symbol_table *symtab_context = 0;
+std::stack<symbol_table*> symtab_context;
+
+// Name of parent function when parsing function files that might
+// contain nested functions.
+std::string parent_function_name;
 
 // Forward declarations for some functions defined at the bottom of
 // the file.
@@ -321,10 +328,10 @@
     { \
       global_command = 0; \
       yyerrok; \
-      if (symtab_context) \
+      if (! symtab_context.empty ()) \
         { \
-	  curr_sym_tab = symtab_context; \
-	  symtab_context = 0; \
+	  curr_sym_tab = symtab_context.top (); \
+	  symtab_context.pop (); \
         } \
       if (interactive || forced_interactive) \
 	YYACCEPT; \
@@ -420,7 +427,7 @@
 %type <tree_expression_type> title matrix cell
 %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
+%type <tree_identifier_type> identifier fcn_name
 %type <octave_user_function_type> function1 function2 function3
 %type <tree_index_expression_type> word_list_cmd
 %type <tree_colon_expression_type> colon_expr1
@@ -1097,12 +1104,7 @@
 // ===========================================
 
 save_symtab	: // empty
-		  {
-		    if (symtab_context)
-		      panic_impossible ();
-
-		    symtab_context = curr_sym_tab;
-		  }
+		  { symtab_context.push (curr_sym_tab); }
 		;
 		   
 function_symtab	: // empty
@@ -1117,10 +1119,6 @@
 		  { lexer_flags.looking_at_return_list = true; }
 		;
 
-parsed_fcn_name	: // empty
-		  { lexer_flags.parsed_function_name = true; }
-		;
-
 // ===========================
 // List of function parameters
 // ===========================
@@ -1229,8 +1227,8 @@
 // Function definition
 // ===================
 
-function_beg	: save_symtab FCN stash_comment function_symtab
-		  { $$ = $3; }
+function_beg	: save_symtab FCN function_symtab stash_comment
+		  { $$ = $4; }
 		;
 
 function	: function_beg function2
@@ -1257,9 +1255,24 @@
 		  { $$ = $3; }
 		;
 
-function2	: identifier local_symtab parsed_fcn_name function3
+fcn_name	: identifier local_symtab
 		  {
-		    if (! ($$ = frob_function ($1, $4)))
+		    std::string id_name = $1->name ();
+
+		    if (reading_fcn_file
+		        && ! lexer_flags.parsing_nested_function)
+		      parent_function_name = (curr_fcn_file_name == id_name)
+			? id_name : curr_fcn_file_name;
+
+		    lexer_flags.parsed_function_name = true;
+
+		    $$ = $1;
+		  }
+		;
+
+function2	: fcn_name function3
+		  {
+		    if (! ($$ = frob_function ($1, $2)))
 		      ABORT_PARSE;
 		  }
 		;
@@ -1276,16 +1289,13 @@
 
 function_end	: END
 		  {
-		    if (end_token_ok ($1, token::function_end))
-		      {
-			if (reading_fcn_file)
-			  check_for_garbage_after_fcn_def ();
-		      }
-		    else
+		    if (! end_token_ok ($1, token::function_end))
 		      ABORT_PARSE;
 		  }
 		| END_OF_INPUT
 		  {
+		    lexer_flags.parsing_nested_function = false;
+
 		    if (! (reading_fcn_file || reading_script_file
 			   || get_input_from_eval_string))
 		      YYABORT;
@@ -2525,7 +2535,8 @@
 
   if (reading_fcn_file)
     {
-      if (curr_fcn_file_name != id_name)
+      if (! lexer_flags.parsing_nested_function
+          && curr_fcn_file_name != id_name)
 	{
 	  if (Vwarn_function_name_clash)
 	    warning ("function name `%s' does not agree with function\
@@ -2569,7 +2580,12 @@
   symbol_record *sr = fbi_sym_tab->lookup (id_name);
 
   if (sr)
-    fcn->stash_symtab_ptr (sr);
+    {
+      fcn->stash_symtab_ptr (sr);
+
+      if (lexer_flags.parsing_nested_function)
+        fcn->mark_as_nested_function ();
+    }
   else
     panic_impossible ();
 
@@ -2613,11 +2629,11 @@
 static void
 recover_from_parsing_function (void)
 {
-  if (! symtab_context)
+  if (symtab_context.empty ())
     panic_impossible ();
 
-  curr_sym_tab = symtab_context;
-  symtab_context = 0;
+  curr_sym_tab = symtab_context.top ();
+  symtab_context.pop ();
 
   lexer_flags.defining_func = false;
   lexer_flags.beginning_of_function = false;
@@ -3238,13 +3254,17 @@
 
   unwind_protect_int (input_line_number);
   unwind_protect_int (current_input_column);
+  unwind_protect_int (end_tokens_expected);
   unwind_protect_bool (reading_fcn_file);
   unwind_protect_bool (line_editing);
+  unwind_protect_str (parent_function_name);
 
   input_line_number = 0;
   current_input_column = 1;
+  end_tokens_expected = 0;
   reading_fcn_file = true;
   line_editing = false;
+  parent_function_name = "";
 
   FILE *ffile = get_input_from_file (ff, 0);
 
--- a/src/symtab.cc	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/symtab.cc	Wed Dec 25 21:04:34 2002 +0000
@@ -47,11 +47,16 @@
 #include "utils.h"
 #include "variables.h"
 
+unsigned long int symbol_table::symtab_count = 0;
+
 // 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;
 
+// Nonzero means we print debugging info about symbol table lookups.
+static int Vdebug_symtab_lookups;
+
 octave_allocator
 symbol_record::symbol_def::allocator (sizeof (symbol_record::symbol_def));
 
@@ -462,6 +467,15 @@
 symbol_record *
 symbol_table::lookup (const std::string& nm, bool insert, bool warn)
 {
+  if (Vdebug_symtab_lookups)
+    {
+      std::cerr << (table_name.empty () ? "???" : table_name)
+		<< " symtab::lookup ["
+		<< (insert ? "I" : "-")
+		<< (warn ? "W" : "-")
+		<< "] \"" << nm << "\"\n";
+    }
+
   unsigned int index = hash (nm);
 
   symbol_record *ptr = table[index].next ();
@@ -491,6 +505,15 @@
 void
 symbol_table::rename (const std::string& old_name, const std::string& new_name)
 {
+  if (Vdebug_symtab_lookups)
+    {
+      std::cerr << (table_name.empty () ? "???" : table_name)
+		<< " symtab::rename "
+		<< "\"" << old_name << "\""
+		<< " to "
+		<< "\"" << new_name << "\"\n";
+    }
+
   unsigned int index = hash (old_name);
 
   symbol_record *prev = &table[index];
@@ -1072,6 +1095,14 @@
   return 0;
 }
 
+static int
+debug_symtab_lookups (void)
+{
+  Vdebug_symtab_lookups = check_preference ("debug_symtab_lookups");
+
+  return 0;
+}
+
 void
 symbols_of_symtab (void)
 {
@@ -1083,6 +1114,11 @@
 will cause Octave to print a warning, but allow the operation.\n\
 @end defvr");
 
+  DEFVAR (debug_symtab_lookups, false, debug_symtab_lookups,
+    "-*- texinfo -*-\n\
+@defvr debug_symtab_lookups\n\
+If the value of htis variable is nonzero, print debugging info when\n\
+searching for symbols in the symbol tables");
 }
 
 
--- a/src/symtab.h	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/symtab.h	Wed Dec 25 21:04:34 2002 +0000
@@ -32,6 +32,7 @@
 #include <string>
 #include <stack>
 
+#include "lo-sstream.h"
 #include "oct-alloc.h"
 #include "str-vec.h"
 
@@ -406,10 +407,20 @@
 {
 public:
 
-  symbol_table (unsigned int tab_size = 128)
-    : table_size (tab_size), table (new symbol_record [table_size])
+  symbol_table (unsigned int tab_size = 128,
+		const std::string& nm = std::string ())
+    : table_size (tab_size), table (new symbol_record [table_size]),
+      table_name (nm)
     {
       assert ((tab_size % 2) == 0);
+
+      if (table_name.empty ())
+	{
+	  OSSTREAM buf;
+	  buf << symtab_count++ << OSSTREAM_ENDS;
+	  table_name = OSSTREAM_STR (buf);
+	  OSSTREAM_FREEZE (buf);
+	}
     }
 
   ~symbol_table (void)
@@ -495,6 +506,10 @@
 
   symbol_record *table;
 
+  std::string table_name;
+
+  static unsigned long int symtab_count;
+
   unsigned int hash (const std::string& s);
 
   // No copying!
--- a/src/toplev.cc	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/toplev.cc	Wed Dec 25 21:04:34 2002 +0000
@@ -92,6 +92,9 @@
 // Pointer to function that is currently being evaluated.
 octave_user_function *curr_function = 0;
 
+// Pointer to parent function that is currently being evaluated.
+octave_user_function *curr_parent_function = 0;
+
 // Original value of TEXMFDBS environment variable.
 std::string octave_original_texmfdbs;
 
--- a/src/toplev.h	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/toplev.h	Wed Dec 25 21:04:34 2002 +0000
@@ -48,6 +48,9 @@
 // Pointer to function that is currently being evaluated.
 extern octave_user_function *curr_function;
 
+// Pointer to parent function that is currently being evaluated.
+extern octave_user_function *curr_parent_function;
+
 // Original value of TEXMFDBS environment variable.
 extern std::string octave_original_texmfdbs;
 
--- a/src/variables.cc	Wed Dec 25 03:14:38 2002 +0000
+++ b/src/variables.cc	Wed Dec 25 21:04:34 2002 +0000
@@ -86,13 +86,13 @@
 initialize_symbol_tables (void)
 {
   if (! fbi_sym_tab)
-    fbi_sym_tab = new symbol_table (2048);
+    fbi_sym_tab = new symbol_table (2048, "FBI");
 
   if (! global_sym_tab)
-    global_sym_tab = new symbol_table (2048);
+    global_sym_tab = new symbol_table (2048, "GLOBAL");
 
   if (! top_level_sym_tab)
-    top_level_sym_tab = new symbol_table (4096);
+    top_level_sym_tab = new symbol_table (4096, "TOP");
 
   curr_sym_tab = top_level_sym_tab;
 }
@@ -923,7 +923,19 @@
 void
 link_to_builtin_or_function (symbol_record *sr)
 {
-  symbol_record *tmp_sym = fbi_sym_tab->lookup (sr->name ());
+  std::string nm = sr->name ();
+
+  symbol_record *tmp_sym = 0;
+
+  if (curr_parent_function)
+    {
+      std::string parent = curr_parent_function->function_name ();
+
+      tmp_sym = fbi_sym_tab->lookup (parent + ":" + nm);
+    }
+
+  if (! tmp_sym)
+    tmp_sym = fbi_sym_tab->lookup (nm);
 
   if (tmp_sym
       && (tmp_sym->is_builtin_variable ()