Mercurial > hg > octave-nkf
changeset 7787:6b521b1e3631
Add dbquit and make dbstep compatible. Use parser in debug mode to handle multi-line input
author | David Bateman <dbateman@free.fr> |
---|---|
date | Tue, 13 May 2008 21:12:12 +0200 |
parents | 37ff0c21c17d |
children | 45f5faba05a2 |
files | PROJECTS doc/ChangeLog doc/interpreter/debug.txi doc/interpreter/octave.texi src/ChangeLog src/debug.cc src/input.cc src/input.h src/parse.y src/pt-bp.h src/pt.cc src/pt.h src/toplev.cc src/toplev.h |
diffstat | 14 files changed, 377 insertions(+), 183 deletions(-) [+] |
line wrap: on
line diff
--- a/PROJECTS +++ b/PROJECTS @@ -174,15 +174,6 @@ * Allow customization of the debug prompt. - * For the keyboard function, parse return (or quit) more - intelligently so that something like - - debug> x = 1; return - - will work as expected. - - * Handle multi-line input at the keyboard/debug prompt correctly. - * Fix the parser so that if (expr) 'this is a string' end
--- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,10 @@ +2008-05-20 David Bateman <dbateman@free.fr> + + * interpreter/debug.txi: Uodate documentation for multiline + input. Add documentation for dbcont, dbquit, dbstep, dbstqck, dbup + and dbdown functions. + * interpreter/octave.texi: Upodate index for debugging functions. + 2008-05-03 Rafael Laboissiere <rafael@debian.org> * interpreter/expr.txi, interpreter/tips.txi: Use ischar instead of
--- a/doc/interpreter/debug.txi +++ b/doc/interpreter/debug.txi @@ -27,25 +27,14 @@ errors. The normal commandline editing and history functions are available in -debug mode. However, one limitation on the debug mode is that -commands entered at the debug prompt are evaluated as strings, rather -than being handled by the Octave parser. This means that all commands in -debug mode must be contained on a single line. That is, it is alright to -write - -@example -debug> for i = 1:n, foo(i); endfor -@end example - -@noindent -in debug mode. However, writing the above in three lines will not be -correctly evaluated. To leave the debug mode, you should simply type -either @code{quit}, @code{exit}, @code{return} or @code{dbcont}. +debug mode. @menu * Entering Debug Mode:: +* Leaving Debug Mode:: * Breakpoints:: * Debug Mode:: +* Call Stack:: @end menu @node Entering Debug Mode @@ -65,6 +54,22 @@ @DOCSTRING(debug_on_error) +@node Leaving Debug Mode +@section Leavinging Debug Mode + +To leave the debug mode, you should simply type either @code{dbcont} +or @code{return}. + +@DOCSTRING(dbcont} + +To quit debug mode and return directly to the prompt @code{dbquit} +should be used instead + +@DOCSTRING(dbquit) + +Finally, typing @code{exit} or @code{quit} at the debug prompt will +result in Octave terminating normally. + @node Breakpoints @section Breakpoints @@ -132,8 +137,17 @@ @DOCSTRING(dbtype) Debug mode equally allows single line stepping through a function using -the commands @code{dbstep} and @code{dbnext}. These differ slightly in -the way they treat the next executable line if the next line itself is a -function defined in an m-file. The @code{dbnext} command will execute -the next line, while staying in the existing function being debugged. -The @code{dbstep} command will step in to the new function. +the commands @code{dbstep}. + +@c leave dbnext undocumented + +@DOCSTRING(dbstep) + +@node Call Stack +@section Call Stack + +@DOCSTRING(dbstack) + +@DOCSTRING(dbup) + +@DOCSTRING(dbdown)
--- a/doc/interpreter/octave.texi +++ b/doc/interpreter/octave.texi @@ -353,8 +353,10 @@ Debugging * Entering Debug Mode:: +* Leaving Debug Mode:: * Breakpoints:: * Debug Mode:: +* Call Stack:: Input and Output
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,46 @@ +2008-05-20 David Bateman <dbateman@free.fr> + + * debug.cc (Fdbstop): If no line specified assume line 1. + (Fdbstep, Fdbcont, Fdbnext): Move debugging functions + to normal commands. + (Fdbquit): New command to quit debugging mode and return to the + prompt. + (Fdbstep): Modify the dbstep command for compatibility. + * input.cc (Vdebugging_current_line): Store current line being + debugged for use in DEFCMD versions of debug commands. + (match_sans_spaces_semi): Delete. + (static void get_debug_input (const std;string&)): New function to + parse input in debug mode using standard Octave parser. + (static octave_value_list get_user_input (const + octave_value_list&, int)): Remove debugging specialization. + * input.h (Vdebugging_current_line): Store current line being + debugged for use in DEFCMD versions of debug commands. + * parse.y (make_return_command): Special handling in debug mode. + * pt-bp.h (MAYBE_DO_BREAKPOINT): Support break in n lines needed + to support "dbstep N". + * pt.cc (tree::break_next): Convert to a down counter to support + break in N lines. Breakpoint occure when tree::break_next is zero. + * toplev.cc (octave_user_script * + octave_call_stack::do_caller_user_script (difference_type) const): + Support skipping the first N functions to support "dbstep out". + (octave_user_function * octave_call_stack::do_caller_user_function + (difference_type) const): Ditto. + (octave_user_code * octave_call_stack::do_caller_user_code + (difference_type) const): Ditto. + * toplev.h (octave_user_script * + octave_call_stack::do_caller_user_script (difference_type) const): + Add difference_type argument. + (octave_user_function * octave_call_stack::do_caller_user_function + (difference_type) const): Ditto. + (octave_user_code * octave_call_stack::do_caller_user_code + (difference_type) const): Ditto. + (static octave_user_script *caller_script (difference_type)): + Ditto. + (static octave_user_function *caller_user_function + (difference_type q)): Ditto. + (static octave_user_code *caller_user_code (difference_type q)): + Ditto. + 2008-05-20 Kim Hansen <kimhanse@gmail.com> * load-path.cc (load_path::do_initialize):
--- a/src/debug.cc +++ b/src/debug.cc @@ -380,6 +380,9 @@ parse_dbfunction_params ("dbstop", args, symbol_name, lines); + if (lines.size () == 0) + lines[0] = 1; + if (! error_state) retval = bp_table::add_breakpoint (symbol_name, lines); @@ -833,6 +836,155 @@ return retval; } +DEFCMD (dbstep, args, , + "-*- texinfo -*-\n\ +@deftypefn {Command} {} dbstep @var{n}\n\ +@deftypefnx {Command} {} dbstep in\n\ +@deftypefnx {Command} {} dbstep out\n\ +In debugging mode, execute the next @var{n} lines of code. If @var{n} is\n\ +omitted execute the next line of code. If the next line of code is itself\n\ +defined in terms of an m-file remain in the existing function.\n\ +\n\ +Using @code{dbstep in} will cause execution of the next line to step into\n\ +any m-files defined on the next line. Using @code{dbstep out} with cause\n\ +execution to continue until the current function returns.\n\ +@seealso{dbcont, dbquit}\n\ +@end deftypefn") +{ + if (Vdebugging) + { + int nargin = args.length (); + + if (nargin > 1) + print_usage (); + else if (nargin == 1 && args(0).is_string ()) + { + std::string arg = args(0).string_value (); + + if (! error_state) + { + if (arg == "in") + { + Vdebugging = false; + + tree::break_next = 0; + + tree::last_line = 0; + + tree::break_function = octave_call_stack::caller_user_code (); + } + else if (arg == "out") + { + Vdebugging = false; + + tree::break_next = 0; + + tree::last_line = -1; + + // Next to skip 2 here. One for the oct-file dbstep and + // another for the function we actually want to step out of. + tree::break_function = octave_call_stack::caller_user_code (2); + } + else + { + int n = atoi (arg.c_str ()); + + Vdebugging = false; + + if (n < 0) + tree::break_next = 0; + else + tree::break_next = n; + + tree::last_line = Vdebugging_current_line; + + tree::break_function = octave_call_stack::caller_user_code (); + } + } + } + else + { + Vdebugging = false; + + tree::break_next = 0; + + tree::last_line = Vdebugging_current_line; + + tree::break_function = octave_call_stack::caller_user_code (); + } + } + else + error ("dbstep: can only be called in debug mode"); + + return octave_value_list (); +} + +DEFCMD (dbcont, args, , + "-*- texinfo -*-\n\ +@deftypefn {Command} {} dbcont ()\n\ +In debugging mode, quit debugging mode and continue execution.\n\ +@seealso{dbstep, dbstep}\n\ +@end deftypefn") +{ + if (Vdebugging) + if (args.length() == 0) + Vdebugging = false; + else + print_usage (); + else + error ("dbcont: can only be called in debug mode"); + + return octave_value_list (); +} + +DEFCMD (dbquit, args, , + "-*- texinfo -*-\n\ +@deftypefn {Command} {} dbquit ()\n\ +In debugging mode, quit debugging mode and return to the top level.\n\ +@seealso{dbstep, dbcont}\n\ +@end deftypefn") +{ + if (Vdebugging) + if (args.length() == 0) + octave_throw_interrupt_exception (); + else + print_usage (); + else + error ("dbquit: can only be called in debug mode"); + + return octave_value_list (); +} + +DEFCMD (dbnext, args, , + "-*- texinfo -*-\n\ +@deftypefn {Command} {} dbquit ()\n\ +In debugging mode, execute the next line of code without stepping in to\n\ +functions. This is synonymous with @code{dbstep}.\n\ +@seealso{dbstep, dbcont, dbquit}\n\ +@end deftypefn") +{ + if (Vdebugging) + { + if (args.length() == 0) + { + Vdebugging = false; + + tree::break_next = 0; + + tree::last_line = Vdebugging_current_line; + + tree::break_function = octave_call_stack::caller_user_code (); + } + else + print_usage (); + } + else + error ("dbnext: can only be called in debug mode"); + + return octave_value_list (); +} + + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/input.cc +++ b/src/input.cc @@ -147,6 +147,9 @@ // TRUE if we are in debugging mode. bool Vdebugging = false; +// The current line that we are debugging +int Vdebugging_current_line = -1; + // TRUE if we are running in the Emacs GUD mode. static bool Vgud_mode = false; @@ -566,21 +569,78 @@ command_editor::set_quoting_function (quoting_filename); } -static bool -match_sans_spaces_semi (const std::string& standard, const std::string& test) +static void +get_debug_input (const std::string& prompt) { - size_t beg = test.find_first_not_of (" \t"); + octave_user_code *caller = octave_call_stack::caller_user_code (); + std::string nm; + + if (caller) + { + nm = caller->fcn_file_name (); + + if (nm.empty ()) + nm = caller->name (); + + Vdebugging_current_line = octave_call_stack::current_line (); + } + else + Vdebugging_current_line = -1; - if (beg != NPOS) + std::ostringstream buf; + + if (! nm.empty ()) { - size_t end = test.find_last_not_of ("; \t"); + if (Vgud_mode) + { + static char ctrl_z = 'Z' & 0x1f; - size_t len = end == NPOS ? NPOS : end - beg + 1; + buf << ctrl_z << ctrl_z << nm << ":" << Vdebugging_current_line; + } + else + { + buf << "stopped in " << nm; - return (test.substr (beg, len) == standard); + if (Vdebugging_current_line > 0) + buf << " at line " << Vdebugging_current_line; + } } - return false; + std::string msg = buf.str (); + + if (! msg.empty ()) + message (Vgud_mode ? 0 : "keyboard", msg.c_str ()); + + unwind_protect::begin_frame ("get_debug_input"); + + unwind_protect_str (VPS1); + VPS1 = prompt; + + while (Vdebugging) + { + reset_error_handler (); + + reset_parser (); + + // This is the same as yyparse in parse.y. + int retval = octave_parse (); + + if (retval == 0 && global_command) + { + global_command->eval (); + + delete global_command; + + global_command = 0; + + OCTAVE_QUIT; + + if (octave_completion_matches_called) + octave_completion_matches_called = false; + } + } + + unwind_protect::run_frame ("get_debug_input"); } // If the user simply hits return, this will produce an empty matrix. @@ -597,63 +657,14 @@ if (nargin == 2) read_as_string++; - std::string nm; - int line = -1; - - if (Vdebugging) - { - octave_user_code *caller = octave_call_stack::caller_user_code (); - - if (caller) - { - nm = caller->fcn_file_name (); - - if (nm.empty ()) - nm = caller->name (); - - line = octave_call_stack::current_line (); - } - } - - std::ostringstream buf; - - if (! nm.empty ()) - { - if (Vgud_mode) - { - static char ctrl_z = 'Z' & 0x1f; + std::string prompt = args(0).string_value (); - buf << ctrl_z << ctrl_z << nm << ":" << line; - } - else - { - buf << "stopped in " << nm; - - if (line > 0) - buf << " at line " << line; - } + if (error_state) + { + error ("input: unrecognized argument"); + return retval; } - std::string msg = buf.str (); - - if (! msg.empty ()) - message (Vgud_mode ? 0 : "keyboard", msg.c_str ()); - - std::string prompt = "debug> "; - - if (nargin > 0) - { - prompt = args(0).string_value (); - - if (error_state) - { - error ("input: unrecognized argument"); - return retval; - } - } - - again: - flush_octave_stdout (); octave_diary << prompt; @@ -673,43 +684,7 @@ octave_diary << "\n"; if (len < 1) - { - if (Vdebugging) - goto again; - else - return read_as_string ? octave_value ("") : octave_value (Matrix ()); - } - - if (Vdebugging) - { - if (match_sans_spaces_semi ("exit", input_buf) - || match_sans_spaces_semi ("quit", input_buf) - || match_sans_spaces_semi ("return", input_buf) - || match_sans_spaces_semi ("dbcont", input_buf)) - { - return retval; - } - else if (match_sans_spaces_semi ("dbstep", input_buf)) - { - tree::break_next = true; - - tree::last_line = 0; - - tree::break_function = octave_call_stack::current (); - - return retval; - } - else if (match_sans_spaces_semi ("dbnext", input_buf)) - { - tree::break_next = true; - - tree::last_line = octave_call_stack::current_line (); - - tree::break_function = octave_call_stack::current (); - - return retval; - } - } + return read_as_string ? octave_value ("") : octave_value (Matrix ()); if (read_as_string) { @@ -723,9 +698,7 @@ { int parse_status = 0; - bool silent = ! Vdebugging; - - retval = eval_string (input_buf, silent, parse_status, nargout); + retval = eval_string (input_buf, true, parse_status, nargout); if (! Vdebugging && retval.length () == 0) retval(0) = Matrix (); @@ -734,19 +707,6 @@ else error ("input: reading user-input failed!"); - if (Vdebugging) - { - // Clear error_state so that if errors were encountered while - // evaluating user input, extra error messages will not be - // printed after we return. - - reset_error_handler (); - - retval = octave_value_list (); - - goto again; - } - return retval; } @@ -895,9 +855,12 @@ Vsaving_history = true; Vdebugging = true; - octave_value_list tmp = get_user_input (args, 0); + std::string prompt = "debug> "; + if (nargin > 0) + prompt = args(0).string_value (); - retval = tmp(0); + if (! error_state) + get_debug_input (prompt); unwind_protect::run_frame ("do_keyboard");
--- a/src/input.h +++ b/src/input.h @@ -91,6 +91,9 @@ // TRUE if we are in debugging mode. extern bool Vdebugging; +// The current line that we are debugging +extern int Vdebugging_current_line; + extern std::string gnu_readline (const std::string& s, bool force_readline = false); extern void initialize_command_input (void);
--- a/src/parse.y +++ b/src/parse.y @@ -2216,11 +2216,20 @@ int l = return_tok->line (); int c = return_tok->column (); - if (lexer_flags.defining_func || reading_script_file - || evaluating_function_body) - retval = new tree_return_command (l, c); + if (Vdebugging) + { + Vdebugging = false; + + retval = new tree_no_op_command ("return", l, c); + } else - retval = new tree_no_op_command ("return", l, c); + { + if (lexer_flags.defining_func || reading_script_file + || evaluating_function_body) + retval = new tree_return_command (l, c); + else + retval = new tree_no_op_command ("return", l, c); + } return retval; }
--- a/src/pt-bp.h +++ b/src/pt-bp.h @@ -166,31 +166,40 @@ octave_function *xfcn = octave_call_stack::current (); \ \ if (octave_debug_on_interrupt_state \ - || (tree::break_next && tree::last_line == 0) \ - || (tree::break_next \ + || (tree::break_next >= 0 && tree::last_line == 0) \ + || (tree::break_next >= 0 \ && xfcn == tree::break_function \ && tree::last_line != line ()) \ || is_breakpoint ()) \ { \ - octave_debug_on_interrupt_state = false; \ + if (!octave_debug_on_interrupt_state && tree::break_next > 0) \ + { \ + tree::break_next--; \ + if (tree::last_line > 0) \ + tree::last_line = line(); \ + } \ + else \ + { \ + octave_debug_on_interrupt_state = false; \ \ - tree::break_next = false; \ - \ - if (xfcn) \ - octave_stdout << xfcn->name () << ": "; \ + tree::break_next = -1; \ \ - octave_stdout << "line " << line () << ", " \ - << "column " << column () \ - << std::endl; \ + if (xfcn) \ + octave_stdout << xfcn->name () << ": "; \ + \ + octave_stdout << "line " << line () << ", " \ + << "column " << column () \ + << std::endl; \ \ - tree_print_code tpc (octave_stdout); \ - this->accept (tpc); \ + tree_print_code tpc (octave_stdout); \ + this->accept (tpc); \ + \ + octave_stdout << std::endl; \ \ - octave_stdout << std::endl; \ + tree::break_statement = this; \ \ - tree::break_statement = this; \ - \ - do_keyboard (); \ + do_keyboard (); \ + } \ } \ } \ while (0)
--- a/src/pt.cc +++ b/src/pt.cc @@ -33,8 +33,8 @@ #include "pt.h" #include "pt-pr-code.h" -// If true, stop executing at the next possible point. -bool tree::break_next = false; +// If zero, stop executing at the next possible point. +int tree::break_next = -1; // The line where dbnext was executed. int tree::last_line = 0;
--- a/src/pt.h +++ b/src/pt.h @@ -66,7 +66,7 @@ { return break_point; } // If true, stop executing at the next possible point. - static bool break_next; + static int break_next; // The line where dbnext was executed. static int last_line;
--- a/src/toplev.cc +++ b/src/toplev.cc @@ -112,11 +112,11 @@ } octave_user_script * -octave_call_stack::do_caller_user_script (void) const +octave_call_stack::do_caller_user_script (difference_type q) const { octave_user_script *retval = 0; - for (const_iterator p = cs.begin (); p != cs.end (); p++) + for (const_iterator p = cs.begin () + q; p != cs.end (); p++) { const call_stack_elt& elt = *p; @@ -133,11 +133,11 @@ } octave_user_function * -octave_call_stack::do_caller_user_function (void) const +octave_call_stack::do_caller_user_function (difference_type q) const { octave_user_function *retval = 0; - for (const_iterator p = cs.begin (); p != cs.end (); p++) + for (const_iterator p = cs.begin () + q; p != cs.end (); p++) { const call_stack_elt& elt = *p; @@ -154,11 +154,11 @@ } octave_user_code * -octave_call_stack::do_caller_user_code (void) const +octave_call_stack::do_caller_user_code (difference_type q) const { octave_user_code *retval = 0; - for (const_iterator p = cs.begin (); p != cs.end (); p++) + for (const_iterator p = cs.begin () + q; p != cs.end (); p++) { const call_stack_elt& elt = *p;
--- a/src/toplev.h +++ b/src/toplev.h @@ -94,6 +94,7 @@ typedef std::deque<call_stack_elt>::iterator iterator; typedef std::deque<call_stack_elt>::const_iterator const_iterator; + typedef std::deque<call_stack_elt>::difference_type difference_type; static bool instance_ok (void) { @@ -149,21 +150,21 @@ } // First script on the stack. - static octave_user_script *caller_script (void) + static octave_user_script *caller_script (difference_type q = 0) { - return instance_ok () ? instance->do_caller_user_script () : 0; + return instance_ok () ? instance->do_caller_user_script (q) : 0; } // First user-defined function on the stack. - static octave_user_function *caller_user_function (void) + static octave_user_function *caller_user_function (difference_type q = 0) { - return instance_ok () ? instance->do_caller_user_function () : 0; + return instance_ok () ? instance->do_caller_user_function (q) : 0; } // First user-defined function on the stack. - static octave_user_code *caller_user_code (void) + static octave_user_code *caller_user_code (difference_type q = 0) { - return instance_ok () ? instance->do_caller_user_code () : 0; + return instance_ok () ? instance->do_caller_user_code (q) : 0; } static void @@ -251,11 +252,11 @@ return retval; } - octave_user_script *do_caller_user_script (void) const; + octave_user_script *do_caller_user_script (difference_type q = 0) const; - octave_user_function *do_caller_user_function (void) const; + octave_user_function *do_caller_user_function (difference_type q = 0) const; - octave_user_code *do_caller_user_code (void) const; + octave_user_code *do_caller_user_code (difference_type q = 0) const; void do_push (octave_function *f, symbol_table::scope_id scope, symbol_table::context_id context)