Mercurial > hg > octave-nkf
changeset 7752:40c428ea3408
initial implementation of dbup and dbdown
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sun, 04 May 2008 03:42:19 -0400 |
parents | 7c020c067a60 |
children | e76a4a6e3c47 |
files | scripts/ChangeLog scripts/miscellaneous/Makefile.in scripts/miscellaneous/dbstack.m src/ChangeLog src/debug.cc src/help.cc src/input.cc src/input.h src/load-save.cc src/mex.cc src/octave.cc src/ov-usr-fcn.cc src/ov-usr-fcn.h src/pt-id.cc src/pt-id.h src/pt-stmt.cc src/symtab.cc src/symtab.h src/toplev.cc src/toplev.h src/unwind-prot.cc src/unwind-prot.h src/variables.cc |
diffstat | 23 files changed, 850 insertions(+), 332 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,8 @@ +2008-05-04 John W. Eaton <jwe@octave.org> + + * miscellaneous/dbstack.m: Delete. + * miscellaneous/Makefile.in (SOURCES): Remove it from the list. + 2008-05-01 David Bateman <dbateman@free.fr> * plot/plot.m: Remove documentation of 'L' option. @@ -26,7 +31,7 @@ 2008-04-25 John W. Eaton <jwe@octave.org> * miscellaneous/dbstack.m: New function. - * miscellaneous/Makefile.in: Add it to the list. + * miscellaneous/Makefile.in (SOURCES): Add it to the list. 2008-04-21 David Bateman <dbateman@free.fr>
--- a/scripts/miscellaneous/Makefile.in +++ b/scripts/miscellaneous/Makefile.in @@ -35,7 +35,7 @@ SOURCES = ans.m bincoeff.m bug_report.m bunzip2.m cast.m comma.m \ compare_versions.m computer.m copyfile.m \ - dbstack.m delete.m dir.m doc.m dos.m dump_prefs.m edit.m \ + delete.m dir.m doc.m dos.m dump_prefs.m edit.m \ fileattrib.m fileparts.m flops.m fullfile.m getfield.m gunzip.m gzip.m \ info.m inputname.m ismac.m ispc.m isunix.m license.m list_primes.m ls.m \ ls_command.m menu.m mex.m mexext.m mkoctfile.m movefile.m \
deleted file mode 100644 --- a/scripts/miscellaneous/dbstack.m +++ /dev/null @@ -1,56 +0,0 @@ -## Copyright (C) 2008 John W. Eaton -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {[@var{stack}, @var{idx}]} dbstack (@var{n}) -## Print or return current stack information. With optional argument -## @var{n}, omit the @var{n} innermost stack frames. -## @seealso{dbclear, dbstatus, dbstop} -## @end deftypefn - -## Author: jwe - -function [stack, idx] = dbstack (n = 0) - - if (n < 0 || round (n) != n) - error ("dbstack: expecting N to be a non-negative integer"); - endif - - ## Add one here to skip the dbstack stack frame. - [t_stack, t_idx] = __dbstack__ (n+1); - - if (nargout == 0) - nframes = numel (t_stack); - if (nframes > 0) - puts ("Stopped in:\n\n"); - for i = 1:nframes - if (i == t_idx) - puts ("--> "); - else - puts (" "); - endif - f = t_stack(i); - printf ("%s at line %d column %d\n", f.name, f.line, f.column); - endfor - endif - else - stack = t_stack; - idx = t_idx; - endif - -endfunction
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,158 @@ +2008-05-04 John W. Eaton <jwe@octave.org> + + * variables.cc (get_global_value): Use symbol_table::global_varval + instead of passing scope to symbol_table::varval. + (set_global_value): Use symbol_table::global_varref + instead of passing scope to symbol_table::varref. + (do_who): Use symbol_table::glob_global_variables + instead of passing scope to symbol_table::glob_variables. + (do_clear_globals): + Use symbol_table::global_variable_names and + symbol_table::clear_global instead of passing scope to + symbol_table::clear_variables. + Use symbol_table::global_variable_names instead of passing scope + to symbol_table::variable_names. + + * unwind-prot.cc (unwind_protect::save_size_t): New function. + (saved_variable::restore_value): Handle size_t values. + (saved_variable::saved_variable): New size_t constructor. + (saved_variable::size_type): New var_type enum value. + (saved_variable::ptr_to_size_t, saved_variable::size_t_value): + New union elements. + * unwind-prot.h (unwind_protect::save_size_t): Provide decl + (unwind_protect_size_t): New macro. + + * toplev.cc (octave_call_stack::do_goto_frame, + octave_call_stack::do_goto_frame_relative): New functions. + (octave_call_stack::do_backtrace): Also return scope and context ids. + * toplev.h (octave_call_stack::do_goto_frame, + octave_call_stack::do_goto_frame_relative): Provide decls. + (octave_call_stack::curr_frame): New data member. + (octave_call_stack::octave_call_stack): Initialize it. + (octave_call_stack::call_stack_elt::scope, + (octave_call_stack::call_stack_elt::context): New data members., + (octave_call_stack::current_frame, + (octave_call_stack::do_current_frame + octave_call_stack::do_goto_frame, + octave_call_stack::do_goto_frame_relative): New functions. + (octave_call_stack::push, octave_call_stack::do_push): + New args, scope and context. + (octave_call_stack::do_push, octave_call_stack::do_pop): Update + curr_frame if debugging. + + * symtab.cc (symbol_table::global_table): New map for global values. + (symbol_table::xcurrent_context): New variable for context info. + * symtab.h: Provide decls. + (symbol_table::global_varref, symbol_table::global_varval, + symbol_table::current_context, + symbol_table::set_scope_and_context, + symbol_table::glob_global_variables, + symbol_table::global_variable_names, + symbol_table::top_leve_variable_names): + New functions. + (symbol_table::context_id, const_global_table_iterator, + global_table_iterator): New typedefs. + (symbol_table::xcurrent_context_this_table): New variable. + (symbol_table::symbol_table): Initialize it. + (symbol_table::set_scope): Use it. + (symbol_table::symbol_record::find, symbol_table::do_find): + Use symbol_table::global_varref instead of passing scope to + symbol_table::varref. + (symbol_table::symbol_record::symbol_record_rep::value_stack): + Now a std::deque instead of a std::stack. + (symbol_table::symbol_record::symbol_record_rep::push_context, + symbol_table::symbol_record::symbol_record_rep::pop_context): + Don't push or pop persistent of global variables. + (symbol_table::symbol_record::symbol_record_rep::varval, + Handle context here. Call symbol_table::global_varval instead of + passing scope to symbol_table::varval. + (symbol_table::symbol_record::symbol_record_rep::varref): + Handle context here. Call symbol_table::global_varref instead of + passing scope to symbol_table::varref. + (symbol_table::symbol_record::varref, + symbol_table::symbol_record::varval): No need to handle global + values specially here. + (symbol_table::symbol_record::push_context + symbol_table::symbol_record::pop_context: No need to handle global + or persistent values specially here. + (symbol_table::get_instance): Don't return global scope. + (symbol_table::do_push_context, symbol_table::do_pop_context): + Increment/decrement xcurrent_context. + (symbol_table::do_clear_global, symbol_table::do_clear_global_pattern): + Use global_table instead of separate scope. + + * symtab.h, symtab.cc (symbol_table::fcn_info::fcn_info_rep::find, + symbol_table::fcn_info::fcn_info_rep::find_function, + symbol_table::fcn_info::find, symbol_table::fcn_info::find_function, + symbol_table::find, symbol_table::find_function, + symbol_table::do_find, symbol_table::insert, symbol_table::varref, + symbol_table::varval, symbol_table::persistent_varref, + symbol_table::persistent_varval, symbol_table::erase_persistent, + symbol_table::is_variable, symbol_table::clear, + symbol_table::clear_variables, symbol_table::clear_global, + symbol_table::clear_variable, symbol_table::clear_global_pattern, + symbol_table::clear_variable_pattern, symbol_table::push_context, + symbol_table::pop_context, symbol_table::mark_hidden, + symbol_table::mark_global, symbol_table::glob, + symbol_table::glob_variables, symbol_table::variable_names, + symbol_table::is_local_variable, symbol_table::is_global): + Eliminate scope arg. Change all uses. + (symbol_table::erase_scope, symbol_table::dup_scope): + Require scope arg. + + * pt-stmt.cc (tree_statement::eval): Don't update statement info + in octave_call_stack if debugging. + + * pt-id.h (tree_identifier::xsym): New function. + (tree_identifier::rvalue, tree_identifier::lvalue, + tree_identifier::dup, tree_identifier::is_defined, + tree_identifier::is_variable, tree_identifier::mark_global, + tree_identifier::mark_as_static, tree_identifier::do_lookup, + tree_identifier::mark_as_formal_parameter): + Use xsym to access symbol. + (tree_identifier::scope): New data member. + (tree_identifier::tree_identifier): Initialize it. + + * ov-usr-fcn.cc (octave_user_script::octave_user_script, + octave_user_function::octave_user_function): + Initialize call_depth to -1. + (octave_user_script::do_multi_index_op): Fix comparison of + call_depth with Vmax_recursion_depth. + (octave_user_function::do_multi_index_op): + Compare call depth > 0, instead of > 1. + * ov-usr-fcn.h (octave_user_function::save_args_passed): + Compare call depth > 0, instead of > 1. + + * input.cc (Vdebugging): New variable. + (get_user_input): Eliminate DEBUG argument. Use global Vdebugging + variable instead. Change all callers. + (saved_frame): New static variable. + (restore_frame): New function. + (do_keyboard): Unwind-protect Vdebugging here and set it to TRUE. + Save current frame. Use unwind_protect to restore it. + (Fkeyboard): Save current frame. Use unwind_protect to restore it. + Move up the call stack one frame before calling do_keyboard. + * input.h (Vdebugging): Provide decl. + + * mex.cc (mexGetVariable): Handle global vars with get_global_value. + (mexPutVariable): Likewise, with set_global_value. + + * octave.cc (intern_argv): Assert that we are at the top level. + Don't pass scope to symbol_table::varref or symbol_table::mark_hidden. + + * load-save.cc (install_loaded_variable): Use + symbol_table::global_varref instead of passing global scope to + symbol_table::varref. + + * help.cc (make_name_list): Call symbol_table::global_variable_names + and symbol_table::top_level_variable_names instead of passing + scope to symbol_table::variable_names. + + * debug.cc (do_dbupdown, Fdbup, Fdbdown): New functions. + (current_stack_frame): Delete static variable. + (Fdbstack): Rename from F__dbstack__. Implement all of dbstack + here instead of partially in dbstack.m. + 2008-05-03 John W. Eaton <jwe@octave.org> * pt-arg-list.cc (F__end__): If there are more dimensions than
--- a/src/debug.cc +++ b/src/debug.cc @@ -57,9 +57,6 @@ // Initialize the singleton object bp_table *bp_table::instance = 0; -// FIXME -- dbup and dbdown will need to modify this variable. -static int current_stack_frame = 1; - // Return a pointer to the user-defined function FNAME. If FNAME is // empty, search backward for the first user-defined function in the // current call stack. @@ -362,7 +359,7 @@ DEFCMD (dbstop, args, , "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {rline =} dbstop (@var{func}, @var{line}, @dots{})\n\ +@deftypefn {Loadable Function} {@var{rline} =} dbstop (@var{func}, @var{line}, @dots{})\n\ Set a breakpoint in a function\n\ @table @code\n\ @item func\n\ @@ -695,10 +692,12 @@ return retval; } -DEFUN (__dbstack__, args, , +DEFCMD (dbstack, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{stack}, @var{idx}]} __dbstack__ (@var{n})\n\ -Undocumented internal function.\n\ +@deftypefn {Loadable Function} {[@var{stack}, @var{idx}]} dbstack (@var{n})\n\ +Print or return current stack information. With optional argument\n\ +@var{n}, omit the @var{n} innermost stack frames.\n\ +@seealso{dbclear, dbstatus, dbstop}\n\ @end deftypefn") { octave_value_list retval; @@ -706,15 +705,130 @@ int n = 0; if (args.length () == 1) - n = args(0).int_value (); + { + octave_value arg = args(0); + + if (arg.is_string ()) + { + std::string s_arg = arg.string_value (); + + n = atoi (s_arg.c_str ()); + } + else + n = args(0).int_value (); + } if (! error_state) { - retval(1) = current_stack_frame; + if (n >= 0) + { + size_t curr_frame = octave_call_stack::current_frame (); + + // Skip dbstack stack frame. + if (! Vdebugging) + curr_frame++; + + // Adjust so that this is the index of where we are in the array + // that is returned in retval(0). + size_t idx = curr_frame - n; + + // Add one here to skip the __dbstack__ stack frame. + Octave_map stk = octave_call_stack::backtrace (curr_frame + n); + + if (nargout == 0) + { + octave_idx_type nframes = stk.numel (); + + if (nframes > 0) + { + octave_stdout << "Stopped in:\n\n"; + + Cell names = stk.contents ("name"); + Cell lines = stk.contents ("line"); + Cell columns = stk.contents ("column"); + + for (octave_idx_type i = 0; i < nframes; i++) + { + octave_value name = names(i); + octave_value line = lines(i); + octave_value column = columns(i); + + octave_stdout << (i == idx - 1 ? "--> " : " ") + << name.string_value () + << " at line " << line.int_value () + << " column " << column.int_value () + << std::endl; + } + } + } + else + { + retval(1) = idx; + retval(0) = stk; + } + } + else + error ("dbstack: expecting N to be a nonnegative integer"); + } + + return retval; +} - // Add one here to skip the __dbstack__ stack frame. - retval(0) = octave_call_stack::backtrace (n+1); +static void +do_dbupdown (const octave_value_list& args, const std::string& who) +{ + int n = 1; + + if (args.length () == 1) + { + octave_value arg = args(0); + + if (arg.is_string ()) + { + std::string s_arg = arg.string_value (); + + n = atoi (s_arg.c_str ()); + } + else + n = args(0).int_value (); + } + + if (! error_state) + { + if (who == "dbdown") + n = -n; + + if (! octave_call_stack::goto_frame_relative (n, true)) + error ("%s: invalid stack frame", who.c_str ()); } +} + +DEFCMD (dbup, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} dbup (@var{n})\n\ +In debugging mode, move up the execution stack @var{n} frames.\n\ +If @var{n} is omitted, move up one frame.\n\ +@seealso{dbstack}\n\ +@end deftypefn") +{ + octave_value retval; + + do_dbupdown (args, "dbup"); + + return retval; +} + +DEFCMD (dbdown, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} dbdown (@var{n})\n\ +In debugging mode, move down the execution stack @var{n} frames.\n\ +If @var{n} is omitted, move down one frame.\n\ +@seealso{dbstack}\n\ +@end deftypefn") +{ + octave_value retval; + + do_dbupdown (args, "dbdown"); return retval; }
--- a/src/help.cc +++ b/src/help.cc @@ -567,12 +567,12 @@ string_vector bif = symbol_table::built_in_function_names (); int bif_len = bif.length (); - string_vector glb - = symbol_table::variable_names (symbol_table::global_scope ()); + // FIXME -- is this really necessary here? + string_vector glb = symbol_table::global_variable_names (); int glb_len = glb.length (); - string_vector top - = symbol_table::variable_names (symbol_table::top_scope ()); + // FIXME -- is this really necessary here? + string_vector top = symbol_table::top_level_variable_names (); int top_len = top.length (); string_vector lcl;
--- a/src/input.cc +++ b/src/input.cc @@ -67,6 +67,7 @@ #include "pt-stmt.h" #include "sighandlers.h" #include "sysdep.h" +#include "toplev.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h" @@ -143,6 +144,9 @@ // the next user prompt. bool Vdrawnow_requested = false; +// TRUE if we are in debugging mode. +bool Vdebugging = false; + // TRUE if we are running in the Emacs GUD mode. static bool Vgud_mode = false; @@ -582,7 +586,7 @@ // If the user simply hits return, this will produce an empty matrix. static octave_value_list -get_user_input (const octave_value_list& args, bool debug, int nargout) +get_user_input (const octave_value_list& args, int nargout) { octave_value_list retval; @@ -596,7 +600,7 @@ std::string nm; int line = -1; - if (debug) + if (Vdebugging) { octave_user_code *caller = octave_call_stack::caller_user_code (); @@ -670,13 +674,13 @@ if (len < 1) { - if (debug) + if (Vdebugging) goto again; else return read_as_string ? octave_value ("") : octave_value (Matrix ()); } - if (debug) + if (Vdebugging) { if (match_sans_spaces_semi ("exit", input_buf) || match_sans_spaces_semi ("quit", input_buf) @@ -719,18 +723,18 @@ { int parse_status = 0; - bool silent = ! debug; + bool silent = ! Vdebugging; retval = eval_string (input_buf, silent, parse_status, nargout); - if (! debug && retval.length () == 0) + if (! Vdebugging && retval.length () == 0) retval(0) = Matrix (); } } else error ("input: reading user-input failed!"); - if (debug) + if (Vdebugging) { // Clear error_state so that if errors were encountered while // evaluating user input, extra error messages will not be @@ -787,7 +791,7 @@ int nargin = args.length (); if (nargin == 1 || nargin == 2) - retval = get_user_input (args, false, nargout); + retval = get_user_input (args, nargout); else print_usage (); @@ -855,6 +859,14 @@ command_history::ignore_entries (! Vsaving_history); } +static size_t saved_frame = 0; + +static void +restore_frame (void *) +{ + octave_call_stack::goto_frame (saved_frame); +} + octave_value do_keyboard (const octave_value_list& args) { @@ -874,10 +886,16 @@ unwind_protect::add (restore_command_history, 0); unwind_protect_bool (Vsaving_history); + unwind_protect_bool (Vdebugging); + + saved_frame = octave_call_stack::current_frame (); + unwind_protect::add (restore_frame); + unwind_protect_size_t (saved_frame); Vsaving_history = true; + Vdebugging = true; - octave_value_list tmp = get_user_input (args, true, 0); + octave_value_list tmp = get_user_input (args, 0); retval = tmp(0); @@ -906,7 +924,18 @@ int nargin = args.length (); if (nargin == 0 || nargin == 1) - do_keyboard (args); + { + saved_frame = octave_call_stack::current_frame (); + unwind_protect::add (restore_frame); + unwind_protect_size_t (saved_frame); + + // Skip the frame assigned to the keyboard function. + octave_call_stack::goto_frame (1); + + do_keyboard (args); + + unwind_protect::run (); + } else print_usage ();
--- a/src/input.h +++ b/src/input.h @@ -88,6 +88,9 @@ // the next user prompt. extern OCTINTERP_API bool Vdrawnow_requested; +// TRUE if we are in debugging mode. +extern bool Vdebugging; + extern std::string gnu_readline (const std::string& s, bool force_readline = false); extern void initialize_command_input (void);
--- a/src/load-save.cc +++ b/src/load-save.cc @@ -144,7 +144,7 @@ { symbol_table::clear (name); symbol_table::mark_global (name); - symbol_table::varref (name, symbol_table::global_scope ()) = val; + symbol_table::global_varref (name) = val; } else symbol_table::varref (name) = val;
--- a/src/mex.cc +++ b/src/mex.cc @@ -3262,18 +3262,23 @@ // FIXME -- should this be in variables.cc? - symbol_table::scope_id scope = -1; + octave_value val; 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")) - scope = symbol_table::top_scope (); + val = get_global_value (name); else - mexErrMsgTxt ("mexGetVariable: symbol table does not exist"); - - octave_value val = symbol_table::varval (name, scope); + { + symbol_table::scope_id scope = -1; + + if (! strcmp (space, "caller")) + scope = symbol_table::current_caller_scope (); + else if (! strcmp (space, "base")) + scope = symbol_table::top_scope (); + else + mexErrMsgTxt ("mexGetVariable: symbol table does not exist"); + + val = symbol_table::varval (name, scope); + } if (val.is_defined ()) { @@ -3314,9 +3319,7 @@ symbol_table::scope_id scope = -1; - if (! strcmp (space, "global")) - scope = symbol_table::global_scope (); - else if (! strcmp (space, "caller")) + if (! strcmp (space, "caller")) scope = symbol_table::current_caller_scope (); else if (! strcmp (space, "base")) scope = symbol_table::top_scope ();
--- a/src/octave.cc +++ b/src/octave.cc @@ -189,9 +189,11 @@ static void intern_argv (int argc, char **argv) { - symbol_table::varref (".nargin.", symbol_table::top_scope ()) = argc - 1; + assert (symbol_table::at_top_level ()); - symbol_table::mark_hidden (".nargin.", symbol_table::top_scope ()); + symbol_table::varref (".nargin.") = argc - 1; + + symbol_table::mark_hidden (".nargin."); if (argc > 1) {
--- a/src/ov-usr-fcn.cc +++ b/src/ov-usr-fcn.cc @@ -63,7 +63,7 @@ : octave_user_code (), cmd_list (0), file_name (), t_parsed (static_cast<time_t> (0)), t_checked (static_cast<time_t> (0)), - call_depth (0) + call_depth (-1) { } octave_user_script::octave_user_script (const std::string& fnm, @@ -73,7 +73,7 @@ : octave_user_code (nm, ds), cmd_list (cmds), file_name (fnm), t_parsed (static_cast<time_t> (0)), t_checked (static_cast<time_t> (0)), - call_depth (0) + call_depth (-1) { if (cmd_list) cmd_list->mark_as_script_body (); @@ -85,7 +85,7 @@ : octave_user_code (nm, ds), cmd_list (0), file_name (fnm), t_parsed (static_cast<time_t> (0)), t_checked (static_cast<time_t> (0)), - call_depth (0) + call_depth (-1) { } octave_user_script::~octave_user_script (void) @@ -121,7 +121,7 @@ unwind_protect_int (call_depth); call_depth++; - if (call_depth <= Vmax_recursion_depth) + if (call_depth < Vmax_recursion_depth) { octave_call_stack::push (this); @@ -202,7 +202,7 @@ 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), + system_fcn_file (false), call_depth (-1), num_named_args (param_list ? param_list->length () : 0), nested_function (false), inline_function (false), class_constructor (false), class_method (false), xdispatch_class (), @@ -367,7 +367,7 @@ unwind_protect_int (call_depth); call_depth++; - if (call_depth > Vmax_recursion_depth) + if (call_depth >= Vmax_recursion_depth) { ::error ("max_recursion_limit exceeded"); unwind_protect::run_frame ("user_func_eval"); @@ -377,10 +377,12 @@ // Save old and set current symbol table context, for // eval_undefined_error(). + octave_call_stack::push (this, local_scope, call_depth); + symbol_table::push_scope (local_scope); unwind_protect::add (symbol_table::pop_scope); - if (call_depth > 1) + if (call_depth > 0) { symbol_table::push_context (); @@ -392,8 +394,6 @@ unwind_protect::add (symbol_table::clear_variables); } - octave_call_stack::push (this); - unwind_protect::add (octave_call_stack::unwind_pop, 0); if (! (is_nested_function () || is_inline_function ()))
--- a/src/ov-usr-fcn.h +++ b/src/ov-usr-fcn.h @@ -251,7 +251,7 @@ void save_args_passed (const octave_value_list& args) { - if (call_depth > 1) + if (call_depth > 0) saved_args.push (args_passed); args_passed = args;
--- a/src/pt-id.cc +++ b/src/pt-id.cc @@ -65,8 +65,8 @@ octave_value_list evaluated_args; bool args_evaluated; - octave_value val = sym.find (0, string_vector (), evaluated_args, - args_evaluated); + octave_value val = xsym().find (0, string_vector (), evaluated_args, + args_evaluated); if (val.is_defined ()) { @@ -119,7 +119,7 @@ { MAYBE_DO_BREAKPOINT; - return octave_lvalue (&(sym.varref ())); + return octave_lvalue (&(xsym().varref ())); } tree_identifier * @@ -130,7 +130,7 @@ // FIXME -- is this the best way? symbol_table::symbol_record new_sym - = symbol_table::find_symbol (sym.name (), scope); + = symbol_table::find_symbol (xsym().name (), scope); tree_identifier *new_id = new tree_identifier (new_sym, line (), column ());
--- a/src/pt-id.h +++ b/src/pt-id.h @@ -47,10 +47,15 @@ public: tree_identifier (int l = -1, int c = -1) - : tree_expression (l, c), sym () { } + : tree_expression (l, c), sym (), scope (-1) { } - tree_identifier (const symbol_table::symbol_record& s, int l = -1, int c = -1) - : tree_expression (l, c), sym (s) { } + tree_identifier (const symbol_table::symbol_record& s, + int l = -1, int c = -1, + symbol_table::scope_id sc = symbol_table::current_scope ()) + : tree_expression (l, c), sym (s), scope (sc) + { + symbol_table::scope_id curr_scope = symbol_table::current_scope (); + } ~tree_identifier (void) { } @@ -58,11 +63,13 @@ bool is_identifier (void) const { return true; } + // The name doesn't change with scope, so use sym instead of + // accessing it through sym so that this function may remain const. std::string name (void) const { return sym.name (); } - bool is_defined (void) { return sym.is_defined (); } + bool is_defined (void) { return xsym().is_defined (); } - bool is_variable (void) { return sym.is_variable (); } + bool is_variable (void) { return xsym().is_variable (); } // Try to find a definition for an identifier. Here's how: // @@ -85,14 +92,14 @@ { MAYBE_DO_BREAKPOINT; - return sym.find (args, arg_names, evaluated_args, args_evaluated); + return xsym().find (args, arg_names, evaluated_args, args_evaluated); } - void mark_global (void) { sym.mark_global (); } + void mark_global (void) { xsym().mark_global (); } - void mark_as_static (void) { sym.init_persistent (); } + void mark_as_static (void) { xsym().init_persistent (); } - void mark_as_formal_parameter (void) { sym.mark_formal (); } + void mark_as_formal_parameter (void) { xsym().mark_formal (); } // We really need to know whether this symbol referst to a variable // or a function, but we may not know that yet. @@ -116,6 +123,24 @@ // The symbol record that this identifier references. symbol_table::symbol_record sym; + symbol_table::scope_id scope; + + // A script may be executed in multiple scopes. If the last one was + // different from the one we are in now, update sym to be from the + // new scope. + symbol_table::symbol_record& xsym (void) + { + symbol_table::scope_id curr_scope = symbol_table::current_scope (); + + if (scope != curr_scope) + { + scope = curr_scope; + sym = symbol_table::insert (sym.name ()); + } + + return sym; + } + // No copying! tree_identifier (const tree_identifier&);
--- a/src/pt-stmt.cc +++ b/src/pt-stmt.cc @@ -88,7 +88,7 @@ if (cmd || expr) { - if (in_function_or_script_body) + if (! (symbol_table::at_top_level () || Vdebugging)) octave_call_stack::set_statement (this); maybe_echo_code (in_function_or_script_body);
--- a/src/symtab.cc +++ b/src/symtab.cc @@ -47,6 +47,8 @@ std::map<symbol_table::scope_id, symbol_table*> symbol_table::all_instances; +std::map<std::string, octave_value> symbol_table::global_table; + std::map<std::string, symbol_table::fcn_info> symbol_table::fcn_table; const symbol_table::scope_id symbol_table::xglobal_scope = 0; @@ -63,6 +65,8 @@ std::set<symbol_table::scope_id> symbol_table::scope_ids_in_use; std::set<symbol_table::scope_id> symbol_table::scope_ids_free_list; +symbol_table::context_id symbol_table::xcurrent_context = 0; + // Should Octave always check to see if function files have changed // since they were last compiled? static int Vignore_function_time_stamp = 1; @@ -76,7 +80,7 @@ octave_value retval; if (is_global ()) - return symbol_table::varref (name (), symbol_table::xglobal_scope); + return symbol_table::global_varref (name ()); else { octave_value val = varval (); @@ -366,8 +370,7 @@ 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) + octave_value_list& evaluated_args, bool& args_evaluated) { static bool deja_vu = false; @@ -375,7 +378,7 @@ // subfunctions if we are currently executing a function defined // from a .m file. - scope_val_iterator r = subfunctions.find (scope); + scope_val_iterator r = subfunctions.find (xcurrent_scope); if (r != subfunctions.end ()) { @@ -525,7 +528,7 @@ fname = p->second; octave_value fcn - = symbol_table::find_function (fname, evaluated_args, scope); + = symbol_table::find_function (fname, evaluated_args); if (fcn.is_defined ()) return fcn; @@ -568,7 +571,7 @@ deja_vu = true; - retval = find (args, arg_names, evaluated_args, args_evaluated, scope); + retval = find (args, arg_names, evaluated_args, args_evaluated); } deja_vu = false; @@ -672,22 +675,22 @@ 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) + bool& args_evaluated) { - return rep->find (args, arg_names, evaluated_args, args_evaluated, scope); + return rep->find (args, arg_names, evaluated_args, args_evaluated); } 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) + bool skip_variables) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); return inst ? inst->do_find (name, args, arg_names, evaluated_args, - args_evaluated, scope, skip_variables) + args_evaluated, skip_variables) : octave_value (); } @@ -695,18 +698,16 @@ 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) + bool& args_evaluated) { - return find (name, args, arg_names, evaluated_args, args_evaluated, - scope, true); + return find (name, args, arg_names, evaluated_args, args_evaluated, true); } 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) + bool& args_evaluated, bool skip_variables) { octave_value retval; @@ -723,7 +724,7 @@ // FIXME -- should we be using something other than varref here? if (sr.is_global ()) - return symbol_table::varref (name, xglobal_scope); + return symbol_table::global_varref (name); else { octave_value& val = sr.varref (); @@ -741,15 +742,14 @@ evaluated_args = octave_value_list (); args_evaluated = false; - return p->second.find (args, arg_names, evaluated_args, args_evaluated, - scope); + return p->second.find (args, arg_names, evaluated_args, args_evaluated); } else { fcn_info finfo (name); octave_value fcn = finfo.find (args, arg_names, evaluated_args, - args_evaluated, scope); + args_evaluated); if (fcn.is_defined ()) fcn_table[name] = finfo;
--- a/src/symtab.h +++ b/src/symtab.h @@ -28,7 +28,6 @@ #include <list> #include <map> #include <set> -#include <stack> #include <string> #include "glob-match.h" @@ -45,6 +44,7 @@ public: typedef int scope_id; + typedef size_t context_id; class symbol_record @@ -84,19 +84,71 @@ unsigned int sc) : name (nm), value_stack (), storage_class (sc), count (1) { - value_stack.push (v); + value_stack.push_back (v); + } + + octave_value& varref (void) + { + if (is_global ()) + return symbol_table::global_varref (name); + else if (is_persistent ()) + return symbol_table::persistent_varref (name); + else + { + context_id n = value_stack.size (); + while (n++ <= symbol_table::xcurrent_context) + value_stack.push_back (octave_value ()); + + return value_stack[symbol_table::xcurrent_context]; + } } - octave_value& varref (void) { return value_stack.top (); } + octave_value varval (void) const + { + if (is_global ()) + return symbol_table::global_varval (name); + else if (is_persistent ()) + return symbol_table::persistent_varval (name); + else + { + if (symbol_table::xcurrent_context < value_stack.size ()) + return value_stack[symbol_table::xcurrent_context]; + else + return octave_value (); + } + } - octave_value varval (void) const { return value_stack.top (); } + void push_context (void) + { + if (! (is_persistent () || is_global ())) + value_stack.push_back (octave_value ()); + } - void push_context (void) { value_stack.push (octave_value ()); } + // If pop_context returns 0, we are out of values and this element + // of the symbol table should be deleted. This can happen for + // functions like + // + // function foo (n) + // if (n > 0) + // foo (n-1); + // else + // eval ("x = 1"); + // endif + // endfunction + // + // Here, X should only exist in the final stack frame. size_t pop_context (void) { - value_stack.pop (); - return value_stack.size (); + size_t retval = 1; + + if (! (is_persistent () || is_global ())) + { + value_stack.pop_back (); + retval = value_stack.size (); + } + + return retval; } void clear (void) @@ -185,7 +237,7 @@ std::string name; - std::stack<octave_value> value_stack; + std::deque<octave_value> value_stack; unsigned int storage_class; @@ -238,44 +290,13 @@ 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& varref (void) { return rep->varref (); } - octave_value varval (void) const - { - return is_global () - ? symbol_table::varval (name (), symbol_table::global_scope ()) - : rep->varval (); - } + octave_value varval (void) const { return rep->varval (); } - void push_context (void) - { - if (! (is_persistent () || is_global ())) - rep->push_context (); - } + void push_context (void) { rep->push_context (); } - // If pop_context returns 0, we are out of values and this element - // of the symbol table should be deleted. This can happen for - // functions like - // - // function foo (n) - // if (n > 0) - // foo (n-1); - // else - // eval ("x = 1"); - // endif - // endfunction - // - // Here, X should only exist in the final stack frame. - - size_t pop_context (void) - { - return (is_persistent () || is_global ()) ? 1 : rep->pop_context (); - } + size_t pop_context (void) { return rep->pop_context (); } void clear (void) { rep->clear (); } @@ -356,8 +377,7 @@ 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_list& evaluated_args, bool& args_evaluated); octave_value find_method (const std::string& dispatch_type); @@ -370,21 +390,20 @@ return function_on_path.is_defined (); } - octave_value find_function (scope_id scope) + octave_value find_function (void) { octave_value_list args; - return find_function (args, scope); + return find_function (args); } - octave_value find_function (const octave_value_list& args, - scope_id scope) + octave_value find_function (const octave_value_list& args) { string_vector arg_names; octave_value_list evaluated_args = args; bool args_evaluated; - return find (0, arg_names, evaluated_args, args_evaluated, scope); + return find (0, arg_names, evaluated_args, args_evaluated); } void install_cmdline_function (const octave_value& f) @@ -543,8 +562,7 @@ 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_list& evaluated_args, bool& args_evaluated); octave_value find_method (const std::string& dispatch_type) const { @@ -571,15 +589,14 @@ return rep->is_user_function_defined (); } - octave_value find_function (scope_id scope) + octave_value find_function (void) { - return rep->find_function (scope); + return rep->find_function (); } - octave_value find_function (const octave_value_list& args, - scope_id scope) + octave_value find_function (const octave_value_list& args) { - return rep->find_function (args, scope); + return rep->find_function (args); } void install_cmdline_function (const octave_value& f) @@ -641,6 +658,8 @@ static scope_id current_scope (void) { return xcurrent_scope; } static scope_id current_caller_scope (void) { return xcurrent_caller_scope; } + static context_id current_context (void) { return xcurrent_context; } + // We use parent_scope to handle parsing subfunctions. static scope_id parent_scope (void) { return xparent_scope; } @@ -681,6 +700,32 @@ instance = p->second; xcurrent_scope = scope; + xcurrent_context = instance->xcurrent_context_this_table; + } + } + + static void set_scope_and_context (scope_id scope, context_id context) + { + 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 ()) + error ("scope not found!"); + else + { + instance = p->second; + + xcurrent_scope = scope; + } + } + + if (! error_state) + xcurrent_context = context; } } @@ -728,8 +773,10 @@ set_parent_scope (-1); } - static void erase_scope (scope_id scope = xcurrent_scope) + static void erase_scope (scope_id scope) { + assert (scope != xglobal_scope); + all_instances_iterator p = all_instances.find (scope); if (p != all_instances.end ()) @@ -738,7 +785,7 @@ // free_scope (scope); } - static scope_id dup_scope (scope_id scope = xcurrent_scope) + static scope_id dup_scope (scope_id scope) { scope_id retval = -1; @@ -764,17 +811,12 @@ } #if 0 - static void print_scope (const std::string& tag, scope_id scope) + static void print_scope (const std::string& tag) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) - { - std::cerr << "printing " << tag << ", scope: " << scope - << ", inst: " << inst << std::endl; - - inst->do_print_scope (std::cerr); - } + inst->do_print_scope (std::cerr); } void do_print_scope (std::ostream& os) const @@ -793,8 +835,8 @@ } #endif - static symbol_record find_symbol (const std::string& name, - scope_id scope = xcurrent_scope) + static symbol_record + find_symbol (const std::string& name, scope_id scope = xcurrent_scope) { symbol_table *inst = get_instance (scope); @@ -816,21 +858,20 @@ 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); + 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& insert (const std::string& name) { static symbol_record foobar; - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); return inst ? inst->do_insert (name) : foobar; } - static octave_value& - varref (const std::string& name, scope_id scope = xcurrent_scope) + static octave_value& varref (const std::string& name, + scope_id scope = xcurrent_scope) { static octave_value foobar; @@ -839,8 +880,8 @@ return inst ? inst->do_varref (name) : foobar; } - static octave_value - varval (const std::string& name, scope_id scope = xcurrent_scope) + static octave_value varval (const std::string& name, + scope_id scope = xcurrent_scope) { symbol_table *inst = get_instance (scope); @@ -848,36 +889,48 @@ } static octave_value& - persistent_varref (const std::string& name, scope_id scope = xcurrent_scope) + global_varref (const std::string& name) + { + global_table_iterator p = global_table.find (name); + + return (p == global_table.end ()) ? global_table[name] : p->second; + } + + static octave_value + global_varval (const std::string& name) + { + const_global_table_iterator p = global_table.find (name); + + return (p != global_table.end ()) ? p->second : octave_value (); + } + + static octave_value& persistent_varref (const std::string& name) { static octave_value foobar; - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); return inst ? inst->do_persistent_varref (name) : foobar; } - static octave_value - persistent_varval (const std::string& name, scope_id scope = xcurrent_scope) + static octave_value persistent_varval (const std::string& name) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); return inst ? inst->do_persistent_varval (name) : octave_value (); } - static void - erase_persistent (const std::string& name, scope_id scope = xcurrent_scope) + static void erase_persistent (const std::string& name) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_erase_persistent (name); } - static bool - is_variable (const std::string& name, scope_id scope = xcurrent_scope) + static bool is_variable (const std::string& name) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); return inst ? inst->do_is_variable (name) : false; } @@ -931,11 +984,9 @@ 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); + octave_value_list& evaluated_args, bool& args_evaluated); - static octave_value - find_user_function (const std::string& name) + static octave_value find_user_function (const std::string& name) { fcn_table_iterator p = fcn_table.find (name); @@ -943,24 +994,21 @@ ? p->second.find_user_function () : octave_value (); } - static octave_value - find_function (const std::string& name, scope_id scope = xcurrent_scope) + static octave_value find_function (const std::string& name) { octave_value_list evaluated_args; - return find_function (name, evaluated_args, scope); + return find_function (name, evaluated_args); } static octave_value - find_function (const std::string& name, const octave_value_list& args, - scope_id scope = xcurrent_scope) + find_function (const std::string& name, const octave_value_list& args) { 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); + return find_function (name, 0, arg_names, evaluated_args, args_evaluated); } static void install_cmdline_function (const std::string& name, @@ -1048,9 +1096,9 @@ } } - static void clear (const std::string& name, scope_id scope = xcurrent_scope) + static void clear (const std::string& name) { - clear_variable (name, scope); + clear_variable (name); } static void clear_all (void) @@ -1060,9 +1108,9 @@ clear_functions (); } - static void clear_variables (scope_id scope = xcurrent_scope) + static void clear_variables (void) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_clear_variables (); @@ -1082,19 +1130,17 @@ clear_user_function (name); } - static void clear_global (const std::string& name, - scope_id scope = xcurrent_scope) + static void clear_global (const std::string& name) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_clear_global (name); } - static void clear_variable (const std::string& name, - scope_id scope = xcurrent_scope) + static void clear_variable (const std::string& name) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_clear_variable (name); @@ -1119,19 +1165,17 @@ } } - static void clear_global_pattern (const std::string& pat, - scope_id scope = xcurrent_scope) + static void clear_global_pattern (const std::string& pat) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_clear_global_pattern (pat); } - static void clear_variable_pattern (const std::string& pat, - scope_id scope = xcurrent_scope) + static void clear_variable_pattern (const std::string& pat) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_clear_variable_pattern (pat); @@ -1264,26 +1308,26 @@ return retval; } - static void push_context (scope_id scope = xcurrent_scope) + static void push_context (void) { - if (scope == xglobal_scope || scope == xtop_scope) + if (xcurrent_scope == xglobal_scope || xcurrent_scope == xtop_scope) error ("invalid call to xymtab::push_context"); else { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_push_context (); } } - static void pop_context (scope_id scope = xcurrent_scope) + static void pop_context (void) { - if (scope == xglobal_scope || scope == xtop_scope) - error ("invalid call to xymtab::push_context"); + if (xcurrent_scope == xglobal_scope || xcurrent_scope == xtop_scope) + error ("invalid call to xymtab::pop_context"); else { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_pop_context (); @@ -1293,19 +1337,17 @@ // For unwind_protect. static void pop_context (void *) { pop_context (); } - static void mark_hidden (const std::string& name, - scope_id scope = xcurrent_scope) + static void mark_hidden (const std::string& name) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_mark_hidden (name); } - static void mark_global (const std::string& name, - scope_id scope = xcurrent_scope) + static void mark_global (const std::string& name) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); if (inst) inst->do_mark_global (name); @@ -1320,25 +1362,43 @@ ? inst->do_all_variables (defined_only) : std::list<symbol_record> (); } - static std::list<symbol_record> - glob (const std::string& pattern, scope_id scope = xcurrent_scope) + static std::list<symbol_record> glob (const std::string& pattern) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_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) + static std::list<symbol_record> glob_variables (const std::string& pattern) { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_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) + glob_global_variables (const std::string& pattern) + { + std::list<symbol_record> retval; + + glob_match pat (pattern); + + for (const_global_table_iterator p = global_table.begin (); + p != global_table.end (); p++) + { + // We generate a list of symbol_record objects so that + // the results from glob_variables and glob_global_variables + // may be handled the same way. + + if (pat.match (p->first)) + retval.push_back (symbol_record (p->first, p->second, + symbol_record::global)); + } + + return retval; + } + + static std::list<symbol_record> glob_variables (const string_vector& patterns) { std::list<symbol_record> retval; @@ -1346,7 +1406,7 @@ for (size_t i = 0; i < len; i++) { - std::list<symbol_record> tmp = glob_variables (patterns[i], scope); + std::list<symbol_record> tmp = glob_variables (patterns[i]); retval.insert (retval.begin (), tmp.begin (), tmp.end ()); } @@ -1371,10 +1431,29 @@ return retval; } - static std::list<std::string> - variable_names (scope_id scope = xcurrent_scope) + static std::list<std::string> global_variable_names (void) { - symbol_table *inst = get_instance (scope); + std::list<std::string> retval; + + for (const_global_table_iterator p = global_table.begin (); + p != global_table.end (); p++) + retval.push_back (p->first); + + retval.sort (); + + return retval; + } + + static std::list<std::string> top_level_variable_names (void) + { + symbol_table *inst = get_instance (xtop_scope); + + return inst ? inst->do_variable_names () : std::list<std::string> (); + } + + static std::list<std::string> variable_names (void) + { + symbol_table *inst = get_instance (xcurrent_scope); return inst ? inst->do_variable_names () : std::list<std::string> (); } @@ -1398,27 +1477,25 @@ return retval; } - static bool is_local_variable (const std::string& name, - scope_id scope = xcurrent_scope) + static bool is_local_variable (const std::string& name) { - if (scope == xglobal_scope) + if (xcurrent_scope == xglobal_scope) return false; else { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); return inst ? inst->do_is_local_variable (name) : false; } } - static bool is_global (const std::string& name, - scope_id scope = xcurrent_scope) + static bool is_global (const std::string& name) { - if (scope == xglobal_scope) + if (xcurrent_scope == xglobal_scope) return true; else { - symbol_table *inst = get_instance (scope); + symbol_table *inst = get_instance (xcurrent_scope); return inst ? inst->do_is_global (name) : false; } @@ -1429,6 +1506,9 @@ 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_global_table_iterator; + typedef std::map<std::string, octave_value>::iterator global_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; @@ -1447,6 +1527,9 @@ // Map from symbol names to symbol info. std::map<std::string, symbol_record> table; + // Map from names of global variables to values. + static std::map<std::string, octave_value> global_table; + // Map from names of persistent variables to values. std::map<std::string, octave_value> persistent_table; @@ -1469,6 +1552,10 @@ // We use parent_scope to handle parsing subfunctions. static scope_id xparent_scope; + // Used to handle recursive calls. + context_id xcurrent_context_this_table; + static context_id xcurrent_context; + static std::deque<scope_id> scope_stack; // The next available scope ID. @@ -1480,7 +1567,7 @@ // 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) : table (), xcurrent_context_this_table () { } ~symbol_table (void) { } @@ -1506,32 +1593,35 @@ { symbol_table *retval = 0; - if (scope == xcurrent_scope) + if (scope != xglobal_scope) { - if (! instance) + if (scope == xcurrent_scope) { - instance = new symbol_table (); - - all_instances[scope] = instance; - } - - if (! instance) - error ("unable to create symbol_table object!"); + if (! instance) + { + instance = new symbol_table (); - retval = instance; - } - else - { - all_instances_iterator p = all_instances.find (scope); + all_instances[scope] = instance; + } - if (p == all_instances.end ()) - { - retval = new symbol_table (); + if (! instance) + error ("unable to create symbol_table object!"); - all_instances[scope] = retval; + retval = instance; } else - retval = p->second; + { + 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; @@ -1585,7 +1675,7 @@ 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); + bool skip_variables); symbol_record& do_insert (const std::string& name) { @@ -1657,12 +1747,16 @@ void do_push_context (void) { + xcurrent_context = ++xcurrent_context_this_table; + for (table_iterator p = table.begin (); p != table.end (); p++) p->second.push_context (); } void do_pop_context (void) { + xcurrent_context = --xcurrent_context_this_table; + for (table_iterator p = table.begin (); p != table.end (); ) { if (p->second.pop_context () == 0) @@ -1688,7 +1782,10 @@ if (sr.is_global ()) { - symbol_table::clear_variable (p->first, xglobal_scope); + global_table_iterator q = global_table.find (name); + + if (q != global_table.end ()) + global_table.erase (q); sr.unmark_global (); } @@ -1715,7 +1812,10 @@ { if (pattern.match (sr.name ())) { - symbol_table::clear_variable (p->first, xglobal_scope); + global_table_iterator q = global_table.find (sr.name ()); + + if (q != global_table.end ()) + global_table.erase (q); sr.unmark_global (); }
--- a/src/toplev.cc +++ b/src/toplev.cc @@ -181,19 +181,23 @@ int nframes = cs.size () - n; - if (nframes > 0) + if (n >= 0 && nframes > 0) { - Cell keys (4, 1); + Cell keys (6, 1); keys(0) = "file"; keys(1) = "name"; keys(2) = "line"; keys(3) = "column"; + keys(4) = "scope"; + keys(5) = "context"; Cell file (nframes, 1); Cell name (nframes, 1); Cell line (nframes, 1); Cell column (nframes, 1); + Cell scope (nframes, 1); + Cell context (nframes, 1); octave_idx_type k = 0; @@ -201,6 +205,9 @@ { const call_stack_elt& elt = *p; + scope(k) = elt.scope; + context(k) = elt.context; + octave_function *f = elt.fcn; if (f) @@ -236,11 +243,68 @@ retval.assign ("name", name); retval.assign ("line", line); retval.assign ("column", column); + retval.assign ("scope", scope); + retval.assign ("context", context); } return retval; } +bool +octave_call_stack::do_goto_frame (size_t n, bool verbose) +{ + bool retval = false; + + if (n < cs.size ()) + { + retval = true; + + curr_frame = n; + + const call_stack_elt& elt = cs[n]; + + symbol_table::set_scope_and_context (elt.scope, elt.context); + + if (verbose) + { + octave_function *f = elt.fcn; + std::string nm = f ? f->name () : std::string ("<unknown>"); + + tree_statement *s = elt.stmt; + int l = -1; + int c = -1; + if (s) + { + l = s->line (); + c = s->column (); + } + + octave_stdout << "stopped in " << nm + << " at line " << l << " column " << c + << " (" << elt.scope << "[" << elt.context << "])" + << std::endl; + } + } + + return retval; +} + +bool +octave_call_stack::do_goto_frame_relative (int n, bool verbose) +{ + bool retval = false; + + size_t sz = cs.size (); + + if (n == 0) + retval = true; + else if ((n > 0 && static_cast<size_t> (n) < sz - curr_frame) + || (n < 0 && static_cast<size_t> (-n) < curr_frame)) + retval = goto_frame (curr_frame + n, verbose); + + return retval; +} + void recover_from_exception (void) {
--- a/src/toplev.h +++ b/src/toplev.h @@ -37,6 +37,7 @@ class tree_statement_list; class charMatrix; +#include "input.h" #include "oct-map.h" extern OCTINTERP_API void @@ -75,15 +76,19 @@ struct call_stack_elt { - call_stack_elt (octave_function *f) : fcn (f), stmt (0) { } + call_stack_elt (octave_function *f, symbol_table::scope_id s, + symbol_table::context_id c) + : fcn (f), stmt (0), scope (s), context (c) { } octave_function *fcn; tree_statement *stmt; + symbol_table::scope_id scope; + symbol_table::context_id context; }; protected: - octave_call_stack (void) : cs () { } + octave_call_stack (void) : cs (), curr_frame (0) { } public: @@ -131,6 +136,11 @@ return element (1); } + static size_t current_frame (void) + { + return instance_ok () ? instance->do_current_frame () : 0; + } + // Function at location N on the call stack (N == 0 is current), may // be built-in. static octave_function *element (size_t n) @@ -156,10 +166,13 @@ return instance_ok () ? instance->do_caller_user_code () : 0; } - static void push (octave_function *f) + static void + push (octave_function *f, + symbol_table::scope_id scope = symbol_table::current_scope (), + symbol_table::context_id context = 0) { if (instance_ok ()) - instance->do_push (f); + instance->do_push (f, scope, context); } static octave_function *top (void) @@ -178,6 +191,17 @@ instance->do_set_statement (s); } + static bool goto_frame (size_t n = 0, bool verbose = false) + { + return instance_ok () ? instance->do_goto_frame (n, verbose) : false; + } + + static bool goto_frame_relative (int n, bool verbose = false) + { + return instance_ok () + ? instance->do_goto_frame_relative (n, verbose) : false; + } + static Octave_map backtrace (int n = 0) { return instance_ok () ? instance->do_backtrace (n) : Octave_map (); @@ -204,12 +228,16 @@ // The current call stack. std::deque<call_stack_elt> cs; + size_t curr_frame; + static octave_call_stack *instance; int do_current_line (void) const; int do_current_column (void) const; + size_t do_current_frame (void) { return curr_frame; } + octave_function *do_element (size_t n) { octave_function *retval = 0; @@ -229,9 +257,13 @@ octave_user_code *do_caller_user_code (void) const; - void do_push (octave_function *f) + void do_push (octave_function *f, symbol_table::scope_id scope, + symbol_table::context_id context) { - cs.push_front (call_stack_elt (f)); + if (Vdebugging) + curr_frame++; + + cs.push_front (call_stack_elt (f, scope, context)); } octave_function *do_top (void) const @@ -271,10 +303,19 @@ Octave_map do_backtrace (int n) const; + bool do_goto_frame (size_t n, bool verbose); + + bool do_goto_frame_relative (int n, bool verbose); + void do_pop (void) { if (! cs.empty ()) - cs.pop_front (); + { + if (Vdebugging) + curr_frame--; + + cs.pop_front (); + } } void do_clear (void) { cs.clear (); }
--- a/src/unwind-prot.cc +++ b/src/unwind-prot.cc @@ -45,6 +45,7 @@ { boolean, integer, + size_type, string_type, generic_ptr, generic @@ -56,6 +57,8 @@ saved_variable (int *p, int v); + saved_variable (size_t *p, size_t v); + saved_variable (std::string *p, const std::string& v); saved_variable (void **p, void *v); @@ -72,6 +75,7 @@ { bool *ptr_to_bool; int *ptr_to_int; + size_t *ptr_to_size_t; void *gen_ptr; void **ptr_to_gen_ptr; }; @@ -80,6 +84,7 @@ { bool bool_value; int int_value; + size_t size_t_value; std::string *str_value; void *gen_ptr_value; }; @@ -113,6 +118,14 @@ size = sizeof (int); // Is this necessary? } +saved_variable::saved_variable (size_t *p, size_t v) +{ + type_tag = size_type; + ptr_to_size_t = p; + size_t_value = v; + size = sizeof (size_t); // Is this necessary? +} + saved_variable::saved_variable (std::string *p, const std::string& v) { type_tag = string_type; @@ -160,6 +173,10 @@ *ptr_to_int = int_value; break; + case size_type: + *ptr_to_size_t = size_t_value; + break; + case string_type: (static_cast<std::string *> (gen_ptr)) -> assign (*str_value); break; @@ -290,6 +307,13 @@ } void +unwind_protect::save_size_t (size_t *ptr, size_t value) +{ + saved_variable *s = new saved_variable (ptr, value); + add (saved_variable::restore, s); +} + +void unwind_protect::save_str (std::string *ptr, const std::string& value) { saved_variable *s = new saved_variable (ptr, value);
--- a/src/unwind-prot.h +++ b/src/unwind-prot.h @@ -103,6 +103,8 @@ static void save_int (int *ptr, int value); + static void save_size_t (size_t *ptr, size_t value); + static void save_str (std::string *ptr, const std::string& value); static void save_ptr (void **ptr, void *value); @@ -120,6 +122,9 @@ #define unwind_protect_int(i) \ unwind_protect::save_int (&(i), (i)) +#define unwind_protect_size_t(i) \ + unwind_protect::save_size_t (&(i), (i)) + #define unwind_protect_str(s) \ unwind_protect::save_str (&(s), (s))
--- a/src/variables.cc +++ b/src/variables.cc @@ -856,7 +856,7 @@ octave_value get_global_value (const std::string& nm, bool silent) { - octave_value val = symbol_table::varval (nm, symbol_table::global_scope ()); + octave_value val = symbol_table::global_varval (nm); if (val.is_undefined () && ! silent) error ("get_global_by_name: undefined symbol `%s'", nm.c_str ()); @@ -867,7 +867,7 @@ void set_global_value (const std::string& nm, const octave_value& val) { - symbol_table::varref (nm, symbol_table::global_scope ()) = val; + symbol_table::global_varref (nm) = val; } // Variable values. @@ -1671,9 +1671,6 @@ pats[0] = "*"; } - symbol_table::scope_id scope = global_only - ? symbol_table::global_scope () : symbol_table::current_scope (); - symbol_info_list symbol_stats; std::list<std::string> symbol_names; @@ -1718,8 +1715,9 @@ } else { - std::list<symbol_table::symbol_record> tmp - = symbol_table::glob_variables (pats[j], scope); + std::list<symbol_table::symbol_record> tmp = global_only + ? symbol_table::glob_global_variables (pats[j]) + : symbol_table::glob_variables (pats[j]); for (std::list<symbol_table::symbol_record>::const_iterator p = tmp.begin (); p != tmp.end (); p++) @@ -2080,13 +2078,19 @@ bool exclusive = false) { if (idx == argc) - symbol_table::clear_variables(symbol_table::global_scope ()); + { + string_vector gvars = symbol_table::global_variable_names (); + + int gcount = gvars.length (); + + for (int i = 0; i < gcount; i++) + symbol_table::clear_global (gvars[i]); + } else { if (exclusive) { - string_vector gvars - = symbol_table::variable_names (symbol_table::global_scope ()); + string_vector gvars = symbol_table::global_variable_names (); int gcount = gvars.length ();