# HG changeset patch # User John W. Eaton # Date 1468348087 14400 # Node ID dd992fd74fce76612b95d37618a035a8abbe6ba6 # Parent 93ed9396f2c3b52c6be155514026011ed02effed put parser, lexer, and evaluator in namespace; interpreter now owns evaluator * oct-parse.in.yy, parse.h: Move parser classes to octave namespace. * lex.ll, lex.h: Move lexer classes to octave namespace. * pt-eval.h, pt-eval.cc: Move evaluator class to octave namespace. Don't define global current evaluator pointer here. * debug.cc, error.cc, input.cc, input.h, ls-mat-ascii.cc, pt-jit.cc, sighandlers.cc, utils.cc, variables.cc, ov-usr-fcn.cc, pt-assign.cc, pt-exp.h, pt-id.cc: Update for namespaces. * interpreter.cc, interpreter.h (current_evaluator): New global var. (interpreter::m_evaluator): New data member. (interpreter::~interpreter): Delete evaluator. diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/debug.cc --- a/libinterp/corefcn/debug.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/debug.cc Tue Jul 12 14:28:07 2016 -0400 @@ -623,7 +623,7 @@ { if (cond.length () > 0) { - octave_parser parser (cond + " ;"); // ; to reject partial expr like "y==" + octave::parser parser (cond + " ;"); // ; to reject partial expr like "y==" parser.reset (); int parse_status = parser.run (); if (parse_status) @@ -753,7 +753,7 @@ } } - tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; + octave::tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; return retval; } @@ -851,7 +851,7 @@ } } - tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; + octave::tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; return retval; } @@ -884,7 +884,7 @@ error ("remove_all_breakpoint_in_file: " "unable to find function %s\n", fname.c_str ()); - tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; + octave::tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; return retval; } @@ -901,7 +901,7 @@ remove_all_breakpoints_in_file (*it); } - tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; + octave::tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; } std::string @@ -2096,14 +2096,14 @@ Vdebugging = false; Vtrack_line_num = true; - tree_evaluator::dbstep_flag = -1; + octave::tree_evaluator::dbstep_flag = -1; } else if (arg == "out") { Vdebugging = false; Vtrack_line_num = true; - tree_evaluator::dbstep_flag = -2; + octave::tree_evaluator::dbstep_flag = -2; } else { @@ -2115,7 +2115,7 @@ Vdebugging = false; Vtrack_line_num = true; - tree_evaluator::dbstep_flag = n; + octave::tree_evaluator::dbstep_flag = n; } } else @@ -2123,7 +2123,7 @@ Vdebugging = false; Vtrack_line_num = true; - tree_evaluator::dbstep_flag = 1; + octave::tree_evaluator::dbstep_flag = 1; } return ovl (); @@ -2147,7 +2147,7 @@ Vdebugging = false; Vtrack_line_num = true; - tree_evaluator::reset_debug_state (); + octave::tree_evaluator::reset_debug_state (); return ovl (); } @@ -2168,7 +2168,7 @@ Vdebugging = false; - tree_evaluator::reset_debug_state (); + octave::tree_evaluator::reset_debug_state (); octave_throw_interrupt_exception (); @@ -2207,7 +2207,7 @@ if (nargin == 1) state = args(0).bool_value (); - tree_evaluator::quiet_breakpoint_flag = state; + octave::tree_evaluator::quiet_breakpoint_flag = state; return ovl (); } diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/error.cc --- a/libinterp/corefcn/error.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/error.cc Tue Jul 12 14:28:07 2016 -0400 @@ -325,9 +325,9 @@ frame.protect_var (Vdebug_on_error); Vdebug_on_error = false; - tree_evaluator::debug_mode = true; + octave::tree_evaluator::debug_mode = true; - tree_evaluator::current_frame = octave_call_stack::current_frame (); + octave::tree_evaluator::current_frame = octave_call_stack::current_frame (); if (show_stack_trace) { @@ -731,9 +731,9 @@ frame.protect_var (Vdebug_on_warning); Vdebug_on_warning = false; - tree_evaluator::debug_mode = true; + octave::tree_evaluator::debug_mode = true; - tree_evaluator::current_frame = octave_call_stack::current_frame (); + octave::tree_evaluator::current_frame = octave_call_stack::current_frame (); do_keyboard (octave_value_list ()); } diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/input.cc --- a/libinterp/corefcn/input.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/input.cc Tue Jul 12 14:28:07 2016 -0400 @@ -586,8 +586,8 @@ { octave::unwind_protect frame; - bool silent = tree_evaluator::quiet_breakpoint_flag; - tree_evaluator::quiet_breakpoint_flag = false; + bool silent = octave::tree_evaluator::quiet_breakpoint_flag; + octave::tree_evaluator::quiet_breakpoint_flag = false; octave_user_code *caller = octave_call_stack::caller_user_code (); std::string nm; @@ -681,7 +681,7 @@ app->forced_interactive (true); } - octave_parser curr_parser; + octave::parser curr_parser; while (Vdebugging) { @@ -701,7 +701,7 @@ { if (retval == 0 && curr_parser.stmt_list) { - curr_parser.stmt_list->accept (*current_evaluator); + curr_parser.stmt_list->accept (*octave::current_evaluator); if (octave_completion_matches_called) octave_completion_matches_called = false; @@ -993,10 +993,10 @@ // Skip the frame assigned to the keyboard function. octave_call_stack::goto_frame_relative (0); - tree_evaluator::debug_mode = true; - tree_evaluator::quiet_breakpoint_flag = false; + octave::tree_evaluator::debug_mode = true; + octave::tree_evaluator::quiet_breakpoint_flag = false; - tree_evaluator::current_frame = octave_call_stack::current_frame (); + octave::tree_evaluator::current_frame = octave_call_stack::current_frame (); do_keyboard (args); diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/input.h --- a/libinterp/corefcn/input.h Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/input.h Tue Jul 12 14:28:07 2016 -0400 @@ -36,7 +36,10 @@ #include "pager.h" class octave_value; -class octave_base_lexer; +namespace octave +{ + class base_lexer; +} extern OCTINTERP_API FILE *get_input_from_stdin (void); @@ -89,7 +92,7 @@ friend class octave_input_reader; - octave_base_reader (octave_base_lexer *lxr) + octave_base_reader (octave::base_lexer *lxr) : count (1), pflag (0), lexer (lxr) { } @@ -138,7 +141,7 @@ int pflag; - octave_base_lexer *lexer; + octave::base_lexer *lexer; void do_input_echo (const std::string&) const; @@ -150,7 +153,7 @@ { public: - octave_terminal_reader (octave_base_lexer *lxr = 0) + octave_terminal_reader (octave::base_lexer *lxr = 0) : octave_base_reader (lxr) { } @@ -170,7 +173,7 @@ { public: - octave_file_reader (FILE *f_arg, octave_base_lexer *lxr = 0) + octave_file_reader (FILE *f_arg, octave::base_lexer *lxr = 0) : octave_base_reader (lxr), file (f_arg) { } std::string get_input (bool& eof); @@ -192,7 +195,7 @@ public: octave_eval_string_reader (const std::string& str, - octave_base_lexer *lxr = 0) + octave::base_lexer *lxr = 0) : octave_base_reader (lxr), eval_string (str) { } @@ -213,15 +216,15 @@ octave_input_reader { public: - octave_input_reader (octave_base_lexer *lxr = 0) + octave_input_reader (octave::base_lexer *lxr = 0) : rep (new octave_terminal_reader (lxr)) { } - octave_input_reader (FILE *file, octave_base_lexer *lxr = 0) + octave_input_reader (FILE *file, octave::base_lexer *lxr = 0) : rep (new octave_file_reader (file, lxr)) { } - octave_input_reader (const std::string& str, octave_base_lexer *lxr = 0) + octave_input_reader (const std::string& str, octave::base_lexer *lxr = 0) : rep (new octave_eval_string_reader (str, lxr)) { } diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/interpreter.cc --- a/libinterp/corefcn/interpreter.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/interpreter.cc Tue Jul 12 14:28:07 2016 -0400 @@ -526,10 +526,15 @@ namespace octave { + tree_evaluator *current_evaluator = 0; + interpreter::interpreter (application *app_context, bool embedded) - : m_app_context (app_context), m_embedded (embedded), - m_interactive (false), m_quitting_gracefully (false) + : m_app_context (app_context), m_evaluator (new tree_evaluator (this)), + m_embedded (embedded), m_interactive (false), + m_quitting_gracefully (false) { + current_evaluator = m_evaluator; + cmdline_options options = m_app_context->options (); // Matlab uses "C" locale for LC_NUMERIC class regardless of local setting @@ -645,6 +650,13 @@ initialize_history (options.read_history_file ()); } + interpreter::~interpreter (void) + { + current_evaluator = 0; + + delete m_evaluator; + } + int interpreter::execute (void) { cmdline_options options = m_app_context->options (); @@ -858,11 +870,11 @@ // The big loop. - octave_lexer *lxr = (octave::application::interactive () - ? new octave_lexer () - : new octave_lexer (stdin)); + octave::lexer *lxr = (octave::application::interactive () + ? new octave::lexer () + : new octave::lexer (stdin)); - octave_parser parser (*lxr); + octave::parser parser (*lxr); int retval = 0; do @@ -874,7 +886,7 @@ parser.reset (); if (symbol_table::at_top_level ()) - tree_evaluator::reset_debug_state (); + octave::tree_evaluator::reset_debug_state (); retval = parser.run (); diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/interpreter.h --- a/libinterp/corefcn/interpreter.h Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/interpreter.h Tue Jul 12 14:28:07 2016 -0400 @@ -30,6 +30,8 @@ #include "quit.h" #include "str-vec.h" +#include "pt-eval.h" + typedef void (*octave_exit_func) (int); extern OCTINTERP_API octave_exit_func octave_exit; @@ -85,6 +87,8 @@ namespace octave { + extern tree_evaluator *current_evaluator; + // The application object contains a pointer to the current // interpreter and the interpreter contains a pointer back to the // application context so we need a forward declaration for one (or @@ -98,7 +102,7 @@ interpreter (application *app_context = 0, bool embedded = false); - ~interpreter (void) { } + ~interpreter (void); int execute (void); @@ -123,6 +127,8 @@ application *m_app_context; + tree_evaluator *m_evaluator; + bool m_embedded; // TRUE means this is an interactive interpreter (forced or not). diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/ls-mat-ascii.cc --- a/libinterp/corefcn/ls-mat-ascii.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/ls-mat-ascii.cc Tue Jul 12 14:28:07 2016 -0400 @@ -255,7 +255,7 @@ varname[i] = '_'; } - if (is_keyword (varname) || ! isalpha (varname[0])) + if (octave::is_keyword (varname) || ! isalpha (varname[0])) varname.insert (0, "X"); if (! valid_identifier (varname)) diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/pt-jit.cc --- a/libinterp/corefcn/pt-jit.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/pt-jit.cc Tue Jul 12 14:28:07 2016 -0400 @@ -780,7 +780,7 @@ visit (cmd); else { - // stolen from tree_evaluator::visit_statement + // stolen from octave::tree_evaluator::visit_statement bool do_bind_ans = false; if (expr->is_identifier ()) diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/sighandlers.cc --- a/libinterp/corefcn/sighandlers.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/sighandlers.cc Tue Jul 12 14:28:07 2016 -0400 @@ -490,7 +490,7 @@ { if (! octave_debug_on_interrupt_state) { - tree_evaluator::debug_mode = true; + octave::tree_evaluator::debug_mode = true; octave_debug_on_interrupt_state = true; return; @@ -499,7 +499,7 @@ { // Clear the flag and do normal interrupt stuff. - tree_evaluator::debug_mode + octave::tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; octave_debug_on_interrupt_state = false; } diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/utils.cc --- a/libinterp/corefcn/utils.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/utils.cc Tue Jul 12 14:28:07 2016 -0400 @@ -105,7 +105,7 @@ { std::string varname = args(0).string_value (); - retval = valid_identifier (varname) && ! is_keyword (varname); + retval = valid_identifier (varname) && ! octave::is_keyword (varname); } return retval; diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/corefcn/variables.cc --- a/libinterp/corefcn/variables.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/corefcn/variables.cc Tue Jul 12 14:28:07 2016 -0400 @@ -380,7 +380,7 @@ int symbol_exist (const std::string& name, const std::string& type) { - if (is_keyword (name)) + if (octave::is_keyword (name)) return 0; bool search_any = type == "any"; diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/octave-value/ov-usr-fcn.cc --- a/libinterp/octave-value/ov-usr-fcn.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/octave-value/ov-usr-fcn.cc Tue Jul 12 14:28:07 2016 -0400 @@ -141,15 +141,16 @@ frame.add_fcn (octave_call_stack::pop); + // Update line number even if debugging. frame.protect_var (Vtrack_line_num); - Vtrack_line_num = true; // update line no. even if debugging + Vtrack_line_num = true; - frame.protect_var (tree_evaluator::statement_context); - tree_evaluator::statement_context = tree_evaluator::script; + frame.protect_var (octave::tree_evaluator::statement_context); + octave::tree_evaluator::statement_context = octave::tree_evaluator::script; BEGIN_PROFILER_BLOCK (octave_user_script) - cmd_list->accept (*current_evaluator); + cmd_list->accept (*octave::current_evaluator); END_PROFILER_BLOCK @@ -583,8 +584,8 @@ // Evaluate the commands that make up the function. - frame.protect_var (tree_evaluator::statement_context); - tree_evaluator::statement_context = tree_evaluator::function; + frame.protect_var (octave::tree_evaluator::statement_context); + octave::tree_evaluator::statement_context = octave::tree_evaluator::function; BEGIN_PROFILER_BLOCK (octave_user_function) @@ -598,7 +599,7 @@ : expr->rvalue (nargout)); } else - cmd_list->accept (*current_evaluator); + cmd_list->accept (*octave::current_evaluator); END_PROFILER_BLOCK diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/parse-tree/lex.h --- a/libinterp/parse-tree/lex.h Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/lex.h Tue Jul 12 14:28:07 2016 -0400 @@ -35,791 +35,820 @@ #include "input.h" #include "token.h" -// Is the given string a keyword? -extern bool is_keyword (const std::string& s); - -// For communication between the lexer and parser. +namespace octave +{ + class interpreter; -class -lexical_feedback -{ -public: + // Is the given string a keyword? + extern bool is_keyword (const std::string& s); - // Track symbol table information when parsing functions. + // For communication between the lexer and parser. - class symbol_table_context + class + lexical_feedback { public: - symbol_table_context (void) : frame_stack () { } + // Track symbol table information when parsing functions. - void clear (void) + class symbol_table_context { - while (! frame_stack.empty ()) - frame_stack.pop (); - } + public: - bool empty (void) const { return frame_stack.empty (); } + symbol_table_context (void) : frame_stack () { } - void pop (void) - { - if (empty ()) - panic_impossible (); + void clear (void) + { + while (! frame_stack.empty ()) + frame_stack.pop (); + } - frame_stack.pop (); - } - - void push (symbol_table::scope_id scope = symbol_table::current_scope ()) - { - frame_stack.push (scope); - } + bool empty (void) const { return frame_stack.empty (); } - symbol_table::scope_id curr_scope (void) const - { - return empty () ? symbol_table::current_scope () : frame_stack.top (); - } + void pop (void) + { + if (empty ()) + panic_impossible (); - private: - - std::stack frame_stack; - }; + frame_stack.pop (); + } - // Track nesting of square brackets, curly braces, and parentheses. - - class bbp_nesting_level - { - private: + void push (symbol_table::scope_id scope = symbol_table::current_scope ()) + { + frame_stack.push (scope); + } - enum bracket_type - { - BRACKET = 1, - BRACE = 2, - PAREN = 3, - ANON_FCN_BODY = 4 + symbol_table::scope_id curr_scope (void) const + { + return empty () ? symbol_table::current_scope () : frame_stack.top (); + } + + private: + + std::stack frame_stack; }; - public: + // Track nesting of square brackets, curly braces, and parentheses. + + class bbp_nesting_level + { + private: - bbp_nesting_level (void) : context () { } + enum bracket_type + { + BRACKET = 1, + BRACE = 2, + PAREN = 3, + ANON_FCN_BODY = 4 + }; + + public: + + bbp_nesting_level (void) : context () { } + + bbp_nesting_level (const bbp_nesting_level& nl) : context (nl.context) { } - bbp_nesting_level (const bbp_nesting_level& nl) : context (nl.context) { } + bbp_nesting_level& operator = (const bbp_nesting_level& nl) + { + if (&nl != this) + context = nl.context; + + return *this; + } + + ~bbp_nesting_level (void) { } - bbp_nesting_level& operator = (const bbp_nesting_level& nl) - { - if (&nl != this) - context = nl.context; + void reset (void) + { + while (! context.empty ()) + context.pop (); + } + + void bracket (void) { context.push (BRACKET); } + + bool is_bracket (void) + { + return ! context.empty () && context.top () == BRACKET; + } + + void brace (void) { context.push (BRACE); } - return *this; - } + bool is_brace (void) + { + return ! context.empty () && context.top () == BRACE; + } + + void paren (void) { context.push (PAREN); } + + bool is_paren (void) + { + return ! context.empty () && context.top () == PAREN; + } - ~bbp_nesting_level (void) { } + void anon_fcn_body (void) { context.push (ANON_FCN_BODY); } + + bool is_anon_fcn_body (void) + { + return ! context.empty () && context.top () == ANON_FCN_BODY; + } + + bool is_bracket_or_brace (void) + { + return (! context.empty () + && (context.top () == BRACKET || context.top () == BRACE)); + } - void reset (void) + bool none (void) { return context.empty (); } + + void remove (void) + { + if (! context.empty ()) + context.pop (); + } + + void clear (void) + { + while (! context.empty ()) + context.pop (); + } + + private: + + std::stack context; + }; + + class token_cache { - while (! context.empty ()) - context.pop (); - } + public: - void bracket (void) { context.push (BRACKET); } + // Store an "unlimited" number of tokens. + token_cache (size_t sz_arg = std::numeric_limits::max ()) + : buffer (), sz (sz_arg) + { } - bool is_bracket (void) - { - return ! context.empty () && context.top () == BRACKET; - } + void push (token *tok) + { + if (buffer.size () == sz) + pop (); + + buffer.push_front (tok); + } + + void pop (void) + { + if (! empty ()) + { + delete buffer.back (); + buffer.pop_back (); + } + } + + // Direct access. + token *at (size_t n) + { + return empty () ? 0 : buffer.at (n); + } - void brace (void) { context.push (BRACE); } + const token *at (size_t n) const + { + return empty () ? 0 : buffer.at (n); + } + + // Most recently pushed. + token *front (void) + { + return empty () ? 0 : buffer.front (); + } - bool is_brace (void) - { - return ! context.empty () && context.top () == BRACE; - } + const token *front (void) const + { + return empty () ? 0 : buffer.front (); + } + + token *back (void) + { + return empty () ? 0 : buffer.back (); + } + + const token *back (void) const + { + return empty () ? 0 : buffer.back (); + } - void paren (void) { context.push (PAREN); } + // Number of elements currently in the buffer, max of sz. + size_t size (void) const { return buffer.size (); } + + bool empty (void) const { return buffer.empty (); } + + void clear (void) + { + while (! empty ()) + pop (); + } + + private: + + std::deque buffer; + + size_t sz; + + // No copying! + + token_cache (const token_cache&); + + token_cache& operator = (const token_cache&); + }; - bool is_paren (void) + lexical_feedback (void) + : end_of_input (false), at_beginning_of_statement (true), + looking_at_anon_fcn_args (false), looking_at_return_list (false), + looking_at_parameter_list (false), looking_at_decl_list (false), + looking_at_initializer_expression (false), + looking_at_matrix_or_assign_lhs (false), + looking_for_object_index (false), + looking_at_indirect_ref (false), parsing_class_method (false), + parsing_classdef (false), maybe_classdef_get_set_method (false), + parsing_classdef_get_method (false), + parsing_classdef_set_method (false), + quote_is_transpose (false), force_script (false), + reading_fcn_file (false), reading_script_file (false), + reading_classdef_file (false), + input_line_number (1), current_input_column (1), + bracketflag (0), braceflag (0), + looping (0), defining_func (0), looking_at_function_handle (0), + block_comment_nesting_level (0), command_arg_paren_count (0), + token_count (0), current_input_line (), comment_text (), + help_text (), string_text (), string_line (0), string_column (0), + fcn_file_name (), fcn_file_full_name (), looking_at_object_index (), + parsed_function_name (), pending_local_variables (), + symtab_context (), nesting_level (), tokens () { - return ! context.empty () && context.top () == PAREN; - } - - void anon_fcn_body (void) { context.push (ANON_FCN_BODY); } - - bool is_anon_fcn_body (void) - { - return ! context.empty () && context.top () == ANON_FCN_BODY; + init (); } - bool is_bracket_or_brace (void) - { - return (! context.empty () - && (context.top () == BRACKET || context.top () == BRACE)); - } + ~lexical_feedback (void); + + void init (void); + + void reset (void); + + int previous_token_value (void) const; + + bool previous_token_value_is (int tok_val) const; + + void mark_previous_token_trailing_space (void); + + bool space_follows_previous_token (void) const; + + bool previous_token_is_binop (void) const; + + bool previous_token_is_keyword (void) const; + + bool previous_token_may_be_command (void) const; + + void maybe_mark_previous_token_as_variable (void); + + void mark_as_variable (const std::string& nm); + void mark_as_variables (const std::list& lst); + + // true means that we have encountered eof on the input stream. + bool end_of_input; + + // true means we are at the beginning of a statement, where a + // command name is possible. + bool at_beginning_of_statement; + + // true means we are parsing an anonymous function argument list. + bool looking_at_anon_fcn_args; + + // true means we're parsing the return list for a function. + bool looking_at_return_list; + + // true means we're parsing the parameter list for a function. + bool looking_at_parameter_list; - bool none (void) { return context.empty (); } + // true means we're parsing a declaration list (global or + // persistent). + bool looking_at_decl_list; + + // true means we are looking at the initializer expression for a + // parameter list element. + bool looking_at_initializer_expression; + + // true means we're parsing a matrix or the left hand side of + // multi-value assignment statement. + bool looking_at_matrix_or_assign_lhs; + + // object index not possible until we've seen something. + bool looking_for_object_index; + + // true means we're looking at an indirect reference to a + // structure element. + bool looking_at_indirect_ref; + + // true means we are parsing a class method in function or classdef file. + bool parsing_class_method; + + // true means we are parsing a classdef file + bool parsing_classdef; + + // true means we are parsing a class method declaration line in a + // classdef file and can accept a property get or set method name. + // for example, "get.propertyname" is recognized as a function name. + bool maybe_classdef_get_set_method; + + // TRUE means we are parsing a classdef get.method. + bool parsing_classdef_get_method; + + // TRUE means we are parsing a classdef set.method. + bool parsing_classdef_set_method; + + // return transpose or start a string? + bool quote_is_transpose; + + // TRUE means treat the current file as a script even if the first + // token is "function" or "classdef". + bool force_script; - void remove (void) - { - if (! context.empty ()) - context.pop (); - } + // TRUE means we're parsing a function file. + bool reading_fcn_file; + + // TRUE means we're parsing a script file. + bool reading_script_file; + + // TRUE means we're parsing a classdef file. + bool reading_classdef_file; + + // the current input line number. + int input_line_number; + + // the column of the current token. + int current_input_column; + + // square bracket level count. + int bracketflag; + + // curly brace level count. + int braceflag; + + // true means we're in the middle of defining a loop. + int looping; + + // nonzero means we're in the middle of defining a function. + int defining_func; + + // nonzero means we are parsing a function handle. + int looking_at_function_handle; + + // nestng level for blcok comments. + int block_comment_nesting_level; + + // Parenthesis count for command argument parsing. + int command_arg_paren_count; + + // Count of tokens recognized by this lexer since initialized or + // since the last reset. + size_t token_count; - void clear (void) - { - while (! context.empty ()) - context.pop (); - } + // The current line of input. + std::string current_input_line; + + // The current comment text. + std::string comment_text; + + // The current help text. + std::string help_text; + + // The current character string text. + std::string string_text; + + // The position of the beginning of the current character string. + int string_line; + int string_column; + + // Simple name of function file we are reading. + std::string fcn_file_name; + + // Full name of file we are reading. + std::string fcn_file_full_name; + + // if the front of the list is true, the closest paren, brace, or + // bracket nesting is an index for an object. + std::list looking_at_object_index; + + // if the top of the stack is true, then we've already seen the name + // of the current function. should only matter if + // current_function_level > 0 + std::stack parsed_function_name; + + // set of identifiers that might be local variable names. + std::set pending_local_variables; + + // Track current symbol table scope and context. + symbol_table_context symtab_context; + + // is the closest nesting level a square bracket, squiggly brace, + // a paren, or an anonymous function body? + bbp_nesting_level nesting_level; + + // Tokens generated by the lexer. + token_cache tokens; private: - std::stack context; - }; - - class token_cache - { - public: - - // Store an "unlimited" number of tokens. - token_cache (size_t sz_arg = std::numeric_limits::max ()) - : buffer (), sz (sz_arg) - { } - - void push (token *tok) - { - if (buffer.size () == sz) - pop (); - - buffer.push_front (tok); - } - - void pop (void) - { - if (! empty ()) - { - delete buffer.back (); - buffer.pop_back (); - } - } - - // Direct access. - token *at (size_t n) - { - return empty () ? 0 : buffer.at (n); - } - - const token *at (size_t n) const - { - return empty () ? 0 : buffer.at (n); - } - - // Most recently pushed. - token *front (void) - { - return empty () ? 0 : buffer.front (); - } - - const token *front (void) const - { - return empty () ? 0 : buffer.front (); - } - - token *back (void) - { - return empty () ? 0 : buffer.back (); - } - - const token *back (void) const - { - return empty () ? 0 : buffer.back (); - } - - // Number of elements currently in the buffer, max of sz. - size_t size (void) const { return buffer.size (); } - - bool empty (void) const { return buffer.empty (); } - - void clear (void) - { - while (! empty ()) - pop (); - } - - private: - - std::deque buffer; - - size_t sz; - // No copying! - token_cache (const token_cache&); + lexical_feedback (const lexical_feedback&); - token_cache& operator = (const token_cache&); + lexical_feedback& operator = (const lexical_feedback&); }; - lexical_feedback (void) - : end_of_input (false), at_beginning_of_statement (true), - looking_at_anon_fcn_args (false), looking_at_return_list (false), - looking_at_parameter_list (false), looking_at_decl_list (false), - looking_at_initializer_expression (false), - looking_at_matrix_or_assign_lhs (false), - looking_for_object_index (false), - looking_at_indirect_ref (false), parsing_class_method (false), - parsing_classdef (false), maybe_classdef_get_set_method (false), - parsing_classdef_get_method (false), - parsing_classdef_set_method (false), - quote_is_transpose (false), force_script (false), - reading_fcn_file (false), reading_script_file (false), - reading_classdef_file (false), - input_line_number (1), current_input_column (1), - bracketflag (0), braceflag (0), - looping (0), defining_func (0), looking_at_function_handle (0), - block_comment_nesting_level (0), command_arg_paren_count (0), - token_count (0), current_input_line (), comment_text (), - help_text (), string_text (), string_line (0), string_column (0), - fcn_file_name (), fcn_file_full_name (), looking_at_object_index (), - parsed_function_name (), pending_local_variables (), - symtab_context (), nesting_level (), tokens () - { - init (); - } - - ~lexical_feedback (void); - - void init (void); - - void reset (void); - - int previous_token_value (void) const; - - bool previous_token_value_is (int tok_val) const; - - void mark_previous_token_trailing_space (void); - - bool space_follows_previous_token (void) const; - - bool previous_token_is_binop (void) const; - - bool previous_token_is_keyword (void) const; - - bool previous_token_may_be_command (void) const; - - void maybe_mark_previous_token_as_variable (void); - - void mark_as_variable (const std::string& nm); - void mark_as_variables (const std::list& lst); - - // true means that we have encountered eof on the input stream. - bool end_of_input; - - // true means we are at the beginning of a statement, where a - // command name is possible. - bool at_beginning_of_statement; - - // true means we are parsing an anonymous function argument list. - bool looking_at_anon_fcn_args; - - // true means we're parsing the return list for a function. - bool looking_at_return_list; - - // true means we're parsing the parameter list for a function. - bool looking_at_parameter_list; - - // true means we're parsing a declaration list (global or - // persistent). - bool looking_at_decl_list; - - // true means we are looking at the initializer expression for a - // parameter list element. - bool looking_at_initializer_expression; - - // true means we're parsing a matrix or the left hand side of - // multi-value assignment statement. - bool looking_at_matrix_or_assign_lhs; - - // object index not possible until we've seen something. - bool looking_for_object_index; - - // true means we're looking at an indirect reference to a - // structure element. - bool looking_at_indirect_ref; - - // true means we are parsing a class method in function or classdef file. - bool parsing_class_method; - - // true means we are parsing a classdef file - bool parsing_classdef; - - // true means we are parsing a class method declaration line in a - // classdef file and can accept a property get or set method name. - // for example, "get.propertyname" is recognized as a function name. - bool maybe_classdef_get_set_method; - - // TRUE means we are parsing a classdef get.method. - bool parsing_classdef_get_method; - - // TRUE means we are parsing a classdef set.method. - bool parsing_classdef_set_method; - - // return transpose or start a string? - bool quote_is_transpose; + // base_lexer inherits from lexical_feedback because we will + // eventually have several different constructors and it is easier to + // intialize if everything is grouped in a parent class rather than + // listing all the members in the base_lexer class. - // TRUE means treat the current file as a script even if the first - // token is "function" or "classdef". - bool force_script; - - // TRUE means we're parsing a function file. - bool reading_fcn_file; - - // TRUE means we're parsing a script file. - bool reading_script_file; - - // TRUE means we're parsing a classdef file. - bool reading_classdef_file; - - // the current input line number. - int input_line_number; - - // the column of the current token. - int current_input_column; - - // square bracket level count. - int bracketflag; - - // curly brace level count. - int braceflag; - - // true means we're in the middle of defining a loop. - int looping; - - // nonzero means we're in the middle of defining a function. - int defining_func; - - // nonzero means we are parsing a function handle. - int looking_at_function_handle; - - // nestng level for blcok comments. - int block_comment_nesting_level; - - // Parenthesis count for command argument parsing. - int command_arg_paren_count; - - // Count of tokens recognized by this lexer since initialized or - // since the last reset. - size_t token_count; - - // The current line of input. - std::string current_input_line; - - // The current comment text. - std::string comment_text; - - // The current help text. - std::string help_text; - - // The current character string text. - std::string string_text; - - // The position of the beginning of the current character string. - int string_line; - int string_column; - - // Simple name of function file we are reading. - std::string fcn_file_name; - - // Full name of file we are reading. - std::string fcn_file_full_name; - - // if the front of the list is true, the closest paren, brace, or - // bracket nesting is an index for an object. - std::list looking_at_object_index; - - // if the top of the stack is true, then we've already seen the name - // of the current function. should only matter if - // current_function_level > 0 - std::stack parsed_function_name; - - // set of identifiers that might be local variable names. - std::set pending_local_variables; - - // Track current symbol table scope and context. - symbol_table_context symtab_context; - - // is the closest nesting level a square bracket, squiggly brace, - // a paren, or an anonymous function body? - bbp_nesting_level nesting_level; - - // Tokens generated by the lexer. - token_cache tokens; - -private: - - // No copying! - - lexical_feedback (const lexical_feedback&); - - lexical_feedback& operator = (const lexical_feedback&); -}; - -// octave_base_lexer inherits from lexical_feedback because we will -// eventually have several different constructors and it is easier to -// intialize if everything is grouped in a parent class rather than -// listing all the members in the octave_base_lexer class. - -class -octave_base_lexer : public lexical_feedback -{ -public: - - // Handle buffering of input for lexer. - - class input_buffer + class + base_lexer : public lexical_feedback { public: - input_buffer (void) - : buffer (), pos (0), chars_left (0), eof (false) - { } + // Handle buffering of input for lexer. + + class input_buffer + { + public: + + input_buffer (void) + : buffer (), pos (0), chars_left (0), eof (false) + { } + + void fill (const std::string& input, bool eof_arg); + + // Copy at most max_size characters to buf. + int copy_chunk (char *buf, size_t max_size); + + bool empty (void) const { return chars_left == 0; } + + bool at_eof (void) const { return eof; } + + private: + + std::string buffer; + const char *pos; + size_t chars_left; + bool eof; + }; + + // Collect comment text. + + class + comment_buffer + { + public: + + comment_buffer (void) : comment_list (0) { } + + ~comment_buffer (void) { delete comment_list; } + + void append (const std::string& s, octave_comment_elt::comment_type t) + { + if (! comment_list) + comment_list = new octave_comment_list (); + + comment_list->append (s, t); + } + + // Caller is expected to delete the returned value. + + octave_comment_list *get_comment (void) + { + octave_comment_list *retval = comment_list; + + comment_list = 0; + + return retval; + } - void fill (const std::string& input, bool eof_arg); + void reset (void) + { + delete comment_list; + + comment_list = 0; + } + + private: + + octave_comment_list *comment_list; + }; + + base_lexer (interpreter *interp_context = 0) + : lexical_feedback (), scanner (0), input_buf (), comment_buf (), + m_interp_context (interp_context) + { + init (); + } + + virtual ~base_lexer (void); + + void init (void); + + virtual bool is_push_lexer (void) const { return false; } + + virtual void reset (void); + + void prep_for_file (void); - // Copy at most max_size characters to buf. - int copy_chunk (char *buf, size_t max_size); + void begin_string (int state); + + virtual int fill_flex_buffer (char *buf, unsigned int max_size) = 0; + + bool at_end_of_buffer (void) const { return input_buf.empty (); } + + bool at_end_of_file (void) const { return input_buf.at_eof (); } + + int handle_end_of_input (void); + + char *flex_yytext (void); + + int flex_yyleng (void); + + int text_yyinput (void); + + void xunput (char c, char *buf); + + void xunput (char c); + + bool looking_at_space (void); + + bool inside_any_object_index (void); + + bool is_variable (const std::string& name, symbol_table::scope_id scope); + + int is_keyword_token (const std::string& s); + + bool fq_identifier_contains_keyword (const std::string& s); + + bool whitespace_is_significant (void); - bool empty (void) const { return chars_left == 0; } + void handle_number (void); + + void handle_continuation (void); + + void finish_comment (octave_comment_elt::comment_type typ); + + octave_comment_list *get_comment (void) { return comment_buf.get_comment (); } + + int handle_close_bracket (int bracket_type); + + bool looks_like_command_arg (void); + + int handle_superclass_identifier (void); + + int handle_meta_identifier (void); + + int handle_fq_identifier (void); + + int handle_identifier (void); + + void maybe_warn_separator_insert (char sep); + + void warn_single_quote_string (void); + + void warn_language_extension (const std::string& msg); + + void maybe_warn_language_extension_comment (char c); - bool at_eof (void) const { return eof; } + void warn_language_extension_continuation (void); + + void warn_language_extension_operator (const std::string& op); + + void push_token (token *); + + token *current_token (void); + + void display_token (int tok); + + void fatal_error (const char *msg); + + void lexer_debug (const char *pattern); + + // Internal state of the flex-generated lexer. + void *scanner; + + // Object that reads and buffers input. + input_buffer input_buf; + + // Object that collects comment text. + comment_buffer comment_buf; + + // Interpreter that contains us, if any. + interpreter *m_interp_context; + + virtual void increment_promptflag (void) = 0; + + virtual void decrement_promptflag (void) = 0; - private: + virtual int promptflag (void) const = 0; + + virtual int promptflag (int) = 0; + + virtual std::string input_source (void) const { return "unknown"; } + + virtual bool input_from_terminal (void) const { return false; } + + virtual bool input_from_file (void) const { return false; } + + virtual bool input_from_eval_string (void) const { return false; } + + void push_start_state (int state); + + void pop_start_state (void); + + void clear_start_state (void); + + int start_state (void) const { return start_state_stack.top (); } + + void display_start_state (void) const; + + int handle_op (const char *pattern, int tok, bool bos = false); + + int handle_language_extension_op (const char *pattern, int tok, + bool bos = false); + + bool maybe_unput_comma_before_unary_op (int tok); - std::string buffer; - const char *pos; - size_t chars_left; - bool eof; + int handle_unary_op (int tok, bool bos = false); + + int handle_language_extension_unary_op (int tok, bool bos = false); + + int handle_assign_op (const char *pattern, int tok); + + int handle_language_extension_assign_op (const char *pattern, int tok); + + int handle_op_internal (int tok, bool bos, bool compat); + + int handle_token (const std::string& name, int tok); + + int handle_token (int tok, token *tok_val = 0); + + int count_token (int tok); + + int count_token_internal (int tok); + + int show_token (int tok); + + void enable_fq_identifier (void); + + protected: + + std::stack start_state_stack; + + // No copying! + + base_lexer (const base_lexer&); + + base_lexer& operator = (const base_lexer&); }; - // Collect comment text. - class - comment_buffer + lexer : public base_lexer { public: - comment_buffer (void) : comment_list (0) { } - - ~comment_buffer (void) { delete comment_list; } - - void append (const std::string& s, octave_comment_elt::comment_type t) - { - if (! comment_list) - comment_list = new octave_comment_list (); + lexer (interpreter *interp_context = 0) + : base_lexer (interp_context), input_reader (this) + { } - comment_list->append (s, t); - } - - // Caller is expected to delete the returned value. + lexer (FILE *file, interpreter *interp_context = 0) + : base_lexer (interp_context), input_reader (file, this) + { } - octave_comment_list *get_comment (void) - { - octave_comment_list *retval = comment_list; - - comment_list = 0; - - return retval; - } + lexer (const std::string& eval_string, + interpreter *interp_context = 0) + : base_lexer (interp_context), input_reader (eval_string, this) + { } void reset (void) { - delete comment_list; + input_reader.reset (); + + base_lexer::reset (); + } + + void increment_promptflag (void) { input_reader.increment_promptflag (); } - comment_list = 0; + void decrement_promptflag (void) { input_reader.decrement_promptflag (); } + + int promptflag (void) const { return input_reader.promptflag (); } + + int promptflag (int n) { return input_reader.promptflag (n); } + + std::string input_source (void) const + { + return input_reader.input_source (); } - private: + bool input_from_terminal (void) const + { + return input_reader.input_from_terminal (); + } + + bool input_from_file (void) const + { + return input_reader.input_from_file (); + } - octave_comment_list *comment_list; + bool input_from_eval_string (void) const + { + return input_reader.input_from_eval_string (); + } + + int fill_flex_buffer (char *buf, unsigned int max_size); + + octave_input_reader input_reader; + + protected: + + // No copying! + + lexer (const lexer&); + + lexer& operator = (const lexer&); }; - octave_base_lexer (void) - : lexical_feedback (), scanner (0), input_buf (), comment_buf () + class + push_lexer : public base_lexer { - init (); - } - - virtual ~octave_base_lexer (void); - - void init (void); - - virtual bool is_push_lexer (void) const { return false; } - - virtual void reset (void); - - void prep_for_file (void); - - void begin_string (int state); - - virtual int fill_flex_buffer (char *buf, unsigned int max_size) = 0; - - bool at_end_of_buffer (void) const { return input_buf.empty (); } - - bool at_end_of_file (void) const { return input_buf.at_eof (); } - - int handle_end_of_input (void); - - char *flex_yytext (void); - - int flex_yyleng (void); - - int text_yyinput (void); - - void xunput (char c, char *buf); + public: - void xunput (char c); - - bool looking_at_space (void); - - bool inside_any_object_index (void); - - bool is_variable (const std::string& name, symbol_table::scope_id scope); - - int is_keyword_token (const std::string& s); - - bool fq_identifier_contains_keyword (const std::string& s); - - bool whitespace_is_significant (void); - - void handle_number (void); - - void handle_continuation (void); + push_lexer (interpreter *interp_context = 0) + : base_lexer (interp_context), pflag (1) + { + append_input ("", false); + } - void finish_comment (octave_comment_elt::comment_type typ); - - octave_comment_list *get_comment (void) { return comment_buf.get_comment (); } - - int handle_close_bracket (int bracket_type); - - bool looks_like_command_arg (void); - - int handle_superclass_identifier (void); - - int handle_meta_identifier (void); - - int handle_fq_identifier (void); - - int handle_identifier (void); - - void maybe_warn_separator_insert (char sep); + push_lexer (const std::string& input, + interpreter *interp_context = 0) + : base_lexer (interp_context), pflag (1) + { + append_input (input, false); + } - void warn_single_quote_string (void); - - void warn_language_extension (const std::string& msg); - - void maybe_warn_language_extension_comment (char c); - - void warn_language_extension_continuation (void); - - void warn_language_extension_operator (const std::string& op); - - void push_token (token *); - - token *current_token (void); - - void display_token (int tok); - - void fatal_error (const char *msg); - - void lexer_debug (const char *pattern); - - // Internal state of the flex-generated lexer. - void *scanner; - - // Object that reads and buffers input. - input_buffer input_buf; - - // Object that collects comment text. - comment_buffer comment_buf; - - virtual void increment_promptflag (void) = 0; - - virtual void decrement_promptflag (void) = 0; - - virtual int promptflag (void) const = 0; + push_lexer (bool eof, interpreter *interp_context = 0) + : base_lexer (interp_context), pflag (1) + { + append_input ("", eof); + } - virtual int promptflag (int) = 0; - - virtual std::string input_source (void) const { return "unknown"; } - - virtual bool input_from_terminal (void) const { return false; } - - virtual bool input_from_file (void) const { return false; } - - virtual bool input_from_eval_string (void) const { return false; } - - void push_start_state (int state); - - void pop_start_state (void); - - void clear_start_state (void); - - int start_state (void) const { return start_state_stack.top (); } + push_lexer (const std::string& input, bool eof, + interpreter *interp_context = 0) + : base_lexer (interp_context), pflag (1) + { + append_input (input, eof); + } - void display_start_state (void) const; - - int handle_op (const char *pattern, int tok, bool bos = false); - - int handle_language_extension_op (const char *pattern, int tok, - bool bos = false); - - bool maybe_unput_comma_before_unary_op (int tok); + bool is_push_lexer (void) const { return true; } - int handle_unary_op (int tok, bool bos = false); - - int handle_language_extension_unary_op (int tok, bool bos = false); - - int handle_assign_op (const char *pattern, int tok); - - int handle_language_extension_assign_op (const char *pattern, int tok); - - int handle_op_internal (int tok, bool bos, bool compat); + void reset (void) + { + promptflag (1); - int handle_token (const std::string& name, int tok); - - int handle_token (int tok, token *tok_val = 0); - - int count_token (int tok); - - int count_token_internal (int tok); - - int show_token (int tok); - - void enable_fq_identifier (void); - -protected: - - std::stack start_state_stack; - - // No copying! - - octave_base_lexer (const octave_base_lexer&); - - octave_base_lexer& operator = (const octave_base_lexer&); -}; - -class -octave_lexer : public octave_base_lexer -{ -public: - - octave_lexer (void) - : octave_base_lexer (), input_reader (this) - { } + base_lexer::reset (); + } - octave_lexer (FILE *file) - : octave_base_lexer (), input_reader (file, this) - { } - - octave_lexer (const std::string& eval_string) - : octave_base_lexer (), input_reader (eval_string, this) - { } - - void reset (void) - { - input_reader.reset (); - - octave_base_lexer::reset (); - } - - void increment_promptflag (void) { input_reader.increment_promptflag (); } - - void decrement_promptflag (void) { input_reader.decrement_promptflag (); } + void append_input (const std::string& input, bool eof) + { + input_buf.fill (input, eof); + } - int promptflag (void) const { return input_reader.promptflag (); } - - int promptflag (int n) { return input_reader.promptflag (n); } - - std::string input_source (void) const - { - return input_reader.input_source (); - } + void increment_promptflag (void) { pflag++; } - bool input_from_terminal (void) const - { - return input_reader.input_from_terminal (); - } + void decrement_promptflag (void) { pflag--; } - bool input_from_file (void) const - { - return input_reader.input_from_file (); - } + int promptflag (void) const { return pflag; } - bool input_from_eval_string (void) const - { - return input_reader.input_from_eval_string (); - } - - int fill_flex_buffer (char *buf, unsigned int max_size); - - octave_input_reader input_reader; - -protected: - - // No copying! - - octave_lexer (const octave_lexer&); - - octave_lexer& operator = (const octave_lexer&); -}; + int promptflag (int n) + { + int retval = pflag; + pflag = n; + return retval; + } -class -octave_push_lexer : public octave_base_lexer -{ -public: + std::string input_source (void) const { return "push buffer"; } - octave_push_lexer (const std::string& input = "", - bool eof = false) - : octave_base_lexer (), pflag (1) - { - append_input (input, eof); - } - - bool is_push_lexer (void) const { return true; } - - void reset (void) - { - promptflag (1); + int fill_flex_buffer (char *buf, unsigned int max_size); - octave_base_lexer::reset (); - } + protected: - void append_input (const std::string& input, bool eof) - { - input_buf.fill (input, eof); - } + int pflag; - void increment_promptflag (void) { pflag++; } - - void decrement_promptflag (void) { pflag--; } - - int promptflag (void) const { return pflag; } + // No copying! - int promptflag (int n) - { - int retval = pflag; - pflag = n; - return retval; - } - - std::string input_source (void) const { return "push buffer"; } - - int fill_flex_buffer (char *buf, unsigned int max_size); + push_lexer (const push_lexer&); -protected: - - int pflag; - - // No copying! - - octave_push_lexer (const octave_push_lexer&); - - octave_push_lexer& operator = (const octave_push_lexer&); -}; + push_lexer& operator = (const push_lexer&); + }; +} #endif diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/parse-tree/lex.ll --- a/libinterp/parse-tree/lex.ll Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/lex.ll Tue Jul 12 14:28:07 2016 -0400 @@ -139,7 +139,7 @@ #error lex.l requires flex version 2.5.4 or later #endif -#define YY_EXTRA_TYPE octave_base_lexer * +#define YY_EXTRA_TYPE octave::base_lexer * #define curr_lexer yyextra // Arrange to get input via readline. @@ -1959,21 +1959,24 @@ } } -bool -is_keyword (const std::string& s) +namespace octave { - // Parsing function names like "set.property_name" inside - // classdef-style class definitions is simplified by handling the - // "set" and "get" portions of the names using the same mechanism as - // is used for keywords. However, they are not really keywords in - // the language, so omit them from the list of possible keywords. - // Likewise for "enumeration", "events", "methods", and - // "properties". - - return (octave_kw_hash::in_word_set (s.c_str (), s.length ()) != 0 - && ! (s == "set" || s == "get" - || s == "enumeration" || s == "events" - || s == "methods" || s == "properties")); + bool + is_keyword (const std::string& s) + { + // Parsing function names like "set.property_name" inside + // classdef-style class definitions is simplified by handling the + // "set" and "get" portions of the names using the same mechanism + // as is used for keywords. However, they are not really keywords + // in the language, so omit them from the list of possible + // keywords. Likewise for "enumeration", "events", "methods", and + // "properties". + + return (octave_kw_hash::in_word_set (s.c_str (), s.length ()) != 0 + && ! (s == "set" || s == "get" + || s == "enumeration" || s == "events" + || s == "methods" || s == "properties")); + } } DEFUN (iskeyword, args, , @@ -2017,7 +2020,7 @@ else { std::string name = args(0).xstring_value ("iskeyword: NAME must be a string"); - retval = is_keyword (name); + retval = octave::is_keyword (name); } return retval; @@ -2074,152 +2077,155 @@ return retval; } -lexical_feedback::~lexical_feedback (void) -{ - tokens.clear (); -} - -void -lexical_feedback::init (void) -{ - // The closest paren, brace, or bracket nesting is not an object - // index. - looking_at_object_index.push_front (false); -} - -void -lexical_feedback::reset (void) -{ - end_of_input = false; - at_beginning_of_statement = true; - looking_at_anon_fcn_args = false; - looking_at_return_list = false; - looking_at_parameter_list = false; - looking_at_decl_list = false; - looking_at_initializer_expression = false; - looking_at_matrix_or_assign_lhs = false; - looking_for_object_index = false; - looking_at_indirect_ref = false; - parsing_class_method = false; - parsing_classdef = false; - maybe_classdef_get_set_method = false; - parsing_classdef_get_method = false; - parsing_classdef_set_method = false; - quote_is_transpose = false; - force_script = false; - reading_fcn_file = false; - reading_script_file = false; - reading_classdef_file = false; - input_line_number = 1; - current_input_column = 1; - bracketflag = 0; - braceflag = 0; - looping = 0; - defining_func = 0; - looking_at_function_handle = 0; - block_comment_nesting_level = 0; - command_arg_paren_count = 0; - token_count = 0; - current_input_line = ""; - comment_text = ""; - help_text = ""; - string_text = ""; - string_line = 0; - string_column = 0; - fcn_file_name = ""; - fcn_file_full_name = ""; - looking_at_object_index.clear (); - looking_at_object_index.push_front (false); - - while (! parsed_function_name.empty ()) - parsed_function_name.pop (); - - pending_local_variables.clear (); - symtab_context.clear (); - nesting_level.reset (); - tokens.clear (); -} - -int -lexical_feedback::previous_token_value (void) const +namespace octave { - const token *tok = tokens.front (); - return tok ? tok->token_value () : 0; -} - -bool -lexical_feedback::previous_token_value_is (int tok_val) const -{ - const token *tok = tokens.front (); - return tok ? tok->token_value_is (tok_val) : false; -} - -void -lexical_feedback::mark_previous_token_trailing_space (void) -{ - token *tok = tokens.front (); - if (tok && ! previous_token_value_is ('\n')) - tok->mark_trailing_space (); -} - -bool -lexical_feedback::space_follows_previous_token (void) const -{ - const token *tok = tokens.front (); - return tok ? tok->space_follows_token () : false; -} - -bool -lexical_feedback::previous_token_is_binop (void) const -{ - int tok = previous_token_value (); - - return (tok == '+' || tok == '-' || tok == '@' - || tok == ',' || tok == ';' || tok == '*' || tok == '/' - || tok == ':' || tok == '=' || tok == ADD_EQ - || tok == AND_EQ || tok == DIV_EQ || tok == EDIV - || tok == EDIV_EQ || tok == ELEFTDIV || tok == ELEFTDIV_EQ - || tok == EMINUS || tok == EMUL || tok == EMUL_EQ - || tok == EPOW || tok == EPOW_EQ || tok == EXPR_AND - || tok == EXPR_AND_AND || tok == EXPR_EQ || tok == EXPR_GE - || tok == EXPR_GT || tok == EXPR_LE || tok == EXPR_LT - || tok == EXPR_NE || tok == EXPR_NOT || tok == EXPR_OR - || tok == EXPR_OR_OR || tok == LEFTDIV || tok == LEFTDIV_EQ - || tok == MUL_EQ || tok == OR_EQ || tok == POW - || tok == POW_EQ || tok == SUB_EQ); -} - -bool -lexical_feedback::previous_token_is_keyword (void) const -{ - const token *tok = tokens.front (); - return tok ? tok->is_keyword () : false; -} - -bool -lexical_feedback::previous_token_may_be_command (void) const -{ - const token *tok = tokens.front (); - return tok ? tok->may_be_command () : false; -} - -void -lexical_feedback::maybe_mark_previous_token_as_variable (void) -{ - token *tok = tokens.front (); - - if (tok && tok->is_symbol ()) - pending_local_variables.insert (tok->symbol_name ()); -} - -void -lexical_feedback::mark_as_variables (const std::list& lst) -{ - for (std::list::const_iterator p = lst.begin (); - p != lst.end (); p++) - { - pending_local_variables.insert (*p); - } + lexical_feedback::~lexical_feedback (void) + { + tokens.clear (); + } + + void + lexical_feedback::init (void) + { + // The closest paren, brace, or bracket nesting is not an object + // index. + looking_at_object_index.push_front (false); + } + + void + lexical_feedback::reset (void) + { + end_of_input = false; + at_beginning_of_statement = true; + looking_at_anon_fcn_args = false; + looking_at_return_list = false; + looking_at_parameter_list = false; + looking_at_decl_list = false; + looking_at_initializer_expression = false; + looking_at_matrix_or_assign_lhs = false; + looking_for_object_index = false; + looking_at_indirect_ref = false; + parsing_class_method = false; + parsing_classdef = false; + maybe_classdef_get_set_method = false; + parsing_classdef_get_method = false; + parsing_classdef_set_method = false; + quote_is_transpose = false; + force_script = false; + reading_fcn_file = false; + reading_script_file = false; + reading_classdef_file = false; + input_line_number = 1; + current_input_column = 1; + bracketflag = 0; + braceflag = 0; + looping = 0; + defining_func = 0; + looking_at_function_handle = 0; + block_comment_nesting_level = 0; + command_arg_paren_count = 0; + token_count = 0; + current_input_line = ""; + comment_text = ""; + help_text = ""; + string_text = ""; + string_line = 0; + string_column = 0; + fcn_file_name = ""; + fcn_file_full_name = ""; + looking_at_object_index.clear (); + looking_at_object_index.push_front (false); + + while (! parsed_function_name.empty ()) + parsed_function_name.pop (); + + pending_local_variables.clear (); + symtab_context.clear (); + nesting_level.reset (); + tokens.clear (); + } + + int + lexical_feedback::previous_token_value (void) const + { + const token *tok = tokens.front (); + return tok ? tok->token_value () : 0; + } + + bool + lexical_feedback::previous_token_value_is (int tok_val) const + { + const token *tok = tokens.front (); + return tok ? tok->token_value_is (tok_val) : false; + } + + void + lexical_feedback::mark_previous_token_trailing_space (void) + { + token *tok = tokens.front (); + if (tok && ! previous_token_value_is ('\n')) + tok->mark_trailing_space (); + } + + bool + lexical_feedback::space_follows_previous_token (void) const + { + const token *tok = tokens.front (); + return tok ? tok->space_follows_token () : false; + } + + bool + lexical_feedback::previous_token_is_binop (void) const + { + int tok = previous_token_value (); + + return (tok == '+' || tok == '-' || tok == '@' + || tok == ',' || tok == ';' || tok == '*' || tok == '/' + || tok == ':' || tok == '=' || tok == ADD_EQ + || tok == AND_EQ || tok == DIV_EQ || tok == EDIV + || tok == EDIV_EQ || tok == ELEFTDIV || tok == ELEFTDIV_EQ + || tok == EMINUS || tok == EMUL || tok == EMUL_EQ + || tok == EPOW || tok == EPOW_EQ || tok == EXPR_AND + || tok == EXPR_AND_AND || tok == EXPR_EQ || tok == EXPR_GE + || tok == EXPR_GT || tok == EXPR_LE || tok == EXPR_LT + || tok == EXPR_NE || tok == EXPR_NOT || tok == EXPR_OR + || tok == EXPR_OR_OR || tok == LEFTDIV || tok == LEFTDIV_EQ + || tok == MUL_EQ || tok == OR_EQ || tok == POW + || tok == POW_EQ || tok == SUB_EQ); + } + + bool + lexical_feedback::previous_token_is_keyword (void) const + { + const token *tok = tokens.front (); + return tok ? tok->is_keyword () : false; + } + + bool + lexical_feedback::previous_token_may_be_command (void) const + { + const token *tok = tokens.front (); + return tok ? tok->may_be_command () : false; + } + + void + lexical_feedback::maybe_mark_previous_token_as_variable (void) + { + token *tok = tokens.front (); + + if (tok && tok->is_symbol ()) + pending_local_variables.insert (tok->symbol_name ()); + } + + void + lexical_feedback::mark_as_variables (const std::list& lst) + { + for (std::list::const_iterator p = lst.begin (); + p != lst.end (); p++) + { + pending_local_variables.insert (*p); + } + } } static bool @@ -2237,508 +2243,511 @@ return retval; } -void -octave_base_lexer::input_buffer::fill (const std::string& input, bool eof_arg) -{ - buffer = input; - chars_left = buffer.length (); - pos = buffer.c_str (); - eof = eof_arg; -} - -int -octave_base_lexer::input_buffer::copy_chunk (char *buf, size_t max_size) -{ - static const char * const eol = "\n"; - - size_t len = max_size > chars_left ? chars_left : max_size; - assert (len > 0); - - memcpy (buf, pos, len); - - chars_left -= len; - pos += len; - - // Make sure input ends with a new line character. - if (chars_left == 0 && buf[len-1] != '\n') - { - if (len < max_size) - { - // There is enough room to plug the newline character in - // the buffer. - buf[len++] = '\n'; - } - else - { - // There isn't enough room to plug the newline character - // in the buffer so arrange to have it returned on the next - // call to octave_base_lexer::read. - pos = eol; - chars_left = 1; - } - } - - return len; -} - -octave_base_lexer::~octave_base_lexer (void) -{ - yylex_destroy (scanner); -} - -void -octave_base_lexer::init (void) -{ - yylex_init (&scanner); - - // Make octave_base_lexer object available through yyextra in - // flex-generated lexer. - yyset_extra (this, scanner); - - clear_start_state (); -} - -// Inside Flex-generated functions, yyg is the scanner cast to its real -// type. Some flex macros that we use in octave_base_lexer member functions -// (for example, BEGIN) use yyg. If we could perform the actions of -// these macros with functions instead, we could eliminate the -// OCTAVE_YYG macro. - -#define OCTAVE_YYG \ - struct yyguts_t *yyg = static_cast (scanner) - -void -octave_base_lexer::reset (void) -{ - // Start off on the right foot. - clear_start_state (); - - symtab_context.clear (); - - // We do want a prompt by default. - promptflag (1); - - // Only ask for input from stdin if we are expecting interactive - // input. - - if (octave::application::interactive () - && ! (reading_fcn_file - || reading_classdef_file - || reading_script_file - || input_from_eval_string ())) - yyrestart (stdin, scanner); - - lexical_feedback::reset (); - - comment_buf.reset (); -} - -void -octave_base_lexer::prep_for_file (void) -{ - reading_script_file = true; - - push_start_state (INPUT_FILE_START); -} - -void -octave_base_lexer::begin_string (int state) -{ - string_line = input_line_number; - string_column = current_input_column; - - push_start_state (state); -} - -int -octave_base_lexer::handle_end_of_input (void) -{ - lexer_debug ("<>"); - - if (block_comment_nesting_level != 0) - { - warning ("block comment open at end of input"); - - if ((reading_fcn_file || reading_script_file || reading_classdef_file) - && ! fcn_file_name.empty ()) - warning ("near line %d of file '%s.m'", - input_line_number, fcn_file_name.c_str ()); - } - - return handle_token (END_OF_INPUT); -} - -char * -octave_base_lexer::flex_yytext (void) -{ - return yyget_text (scanner); -} - -int -octave_base_lexer::flex_yyleng (void) -{ - return yyget_leng (scanner); -} - -int -octave_base_lexer::text_yyinput (void) -{ - int c = yyinput (scanner); - - if (lexer_debug_flag) - { - std::cerr << "I: "; - display_character (c); - std::cerr << std::endl; - } - - // Convert CRLF into just LF and single CR into LF. - - if (c == '\r') - { - c = yyinput (scanner); - - if (lexer_debug_flag) - { - std::cerr << "I: "; - display_character (c); - std::cerr << std::endl; - } - - if (c != '\n') - { - xunput (c); - c = '\n'; - } - } - - return c; -} - -void -octave_base_lexer::xunput (char c, char *buf) -{ - if (c != EOF) - { - if (lexer_debug_flag) - { - std::cerr << "U: "; - display_character (c); - std::cerr << std::endl; - } - - yyunput (c, buf, scanner); - } -} - -void -octave_base_lexer::xunput (char c) -{ - char *yytxt = flex_yytext (); - - xunput (c, yytxt); -} - -bool -octave_base_lexer::looking_at_space (void) -{ - int c = text_yyinput (); - xunput (c); - return (c == ' ' || c == '\t'); -} - -bool -octave_base_lexer::inside_any_object_index (void) -{ - bool retval = false; - - for (std::list::const_iterator i = looking_at_object_index.begin (); - i != looking_at_object_index.end (); i++) - { - if (*i) - { - retval = true; - break; - } - } - - return retval; -} - -bool -octave_base_lexer::is_variable (const std::string& name, - symbol_table::scope_id scope) -{ - return (symbol_table::is_variable (name, scope) - || (pending_local_variables.find (name) - != pending_local_variables.end ())); -} - -// Handle keywords. Return -1 if the keyword should be ignored. - -int -octave_base_lexer::is_keyword_token (const std::string& s) +namespace octave { - int l = input_line_number; - int c = current_input_column; - - int len = s.length (); - - const octave_kw *kw = octave_kw_hash::in_word_set (s.c_str (), len); - - if (kw) - { - bool previous_at_bos = at_beginning_of_statement; - - // May be reset to true for some token types. - at_beginning_of_statement = false; - - token *tok_val = 0; - - switch (kw->kw_id) - { - case break_kw: - case catch_kw: - case continue_kw: - case else_kw: - case otherwise_kw: - case return_kw: - case unwind_protect_cleanup_kw: - at_beginning_of_statement = true; - break; - - case persistent_kw: - case global_kw: - looking_at_decl_list = true; - break; - - case case_kw: - case elseif_kw: - case until_kw: - break; - - case end_kw: - if (inside_any_object_index () - || (defining_func - && ! (looking_at_return_list - || parsed_function_name.top ()))) + void + base_lexer::input_buffer::fill (const std::string& input, bool eof_arg) + { + buffer = input; + chars_left = buffer.length (); + pos = buffer.c_str (); + eof = eof_arg; + } + + int + base_lexer::input_buffer::copy_chunk (char *buf, size_t max_size) + { + static const char * const eol = "\n"; + + size_t len = max_size > chars_left ? chars_left : max_size; + assert (len > 0); + + memcpy (buf, pos, len); + + chars_left -= len; + pos += len; + + // Make sure input ends with a new line character. + if (chars_left == 0 && buf[len-1] != '\n') + { + if (len < max_size) + { + // There is enough room to plug the newline character in + // the buffer. + buf[len++] = '\n'; + } + else + { + // There isn't enough room to plug the newline character + // in the buffer so arrange to have it returned on the next + // call to base_lexer::read. + pos = eol; + chars_left = 1; + } + } + + return len; + } + + base_lexer::~base_lexer (void) + { + yylex_destroy (scanner); + } + + void + base_lexer::init (void) + { + yylex_init (&scanner); + + // Make base_lexer object available through yyextra in + // flex-generated lexer. + yyset_extra (this, scanner); + + clear_start_state (); + } + + // Inside Flex-generated functions, yyg is the scanner cast to its real + // type. Some flex macros that we use in base_lexer member functions + // (for example, BEGIN) use yyg. If we could perform the actions of + // these macros with functions instead, we could eliminate the + // OCTAVE_YYG macro. + +#define OCTAVE_YYG \ + struct yyguts_t *yyg = static_cast (scanner) + + void + base_lexer::reset (void) + { + // Start off on the right foot. + clear_start_state (); + + symtab_context.clear (); + + // We do want a prompt by default. + promptflag (1); + + // Only ask for input from stdin if we are expecting interactive + // input. + + if (octave::application::interactive () + && ! (reading_fcn_file + || reading_classdef_file + || reading_script_file + || input_from_eval_string ())) + yyrestart (stdin, scanner); + + lexical_feedback::reset (); + + comment_buf.reset (); + } + + void + base_lexer::prep_for_file (void) + { + reading_script_file = true; + + push_start_state (INPUT_FILE_START); + } + + void + base_lexer::begin_string (int state) + { + string_line = input_line_number; + string_column = current_input_column; + + push_start_state (state); + } + + int + base_lexer::handle_end_of_input (void) + { + lexer_debug ("<>"); + + if (block_comment_nesting_level != 0) + { + warning ("block comment open at end of input"); + + if ((reading_fcn_file || reading_script_file || reading_classdef_file) + && ! fcn_file_name.empty ()) + warning ("near line %d of file '%s.m'", + input_line_number, fcn_file_name.c_str ()); + } + + return handle_token (END_OF_INPUT); + } + + char * + base_lexer::flex_yytext (void) + { + return yyget_text (scanner); + } + + int + base_lexer::flex_yyleng (void) + { + return yyget_leng (scanner); + } + + int + base_lexer::text_yyinput (void) + { + int c = yyinput (scanner); + + if (lexer_debug_flag) + { + std::cerr << "I: "; + display_character (c); + std::cerr << std::endl; + } + + // Convert CRLF into just LF and single CR into LF. + + if (c == '\r') + { + c = yyinput (scanner); + + if (lexer_debug_flag) + { + std::cerr << "I: "; + display_character (c); + std::cerr << std::endl; + } + + if (c != '\n') + { + xunput (c); + c = '\n'; + } + } + + return c; + } + + void + base_lexer::xunput (char c, char *buf) + { + if (c != EOF) + { + if (lexer_debug_flag) + { + std::cerr << "U: "; + display_character (c); + std::cerr << std::endl; + } + + yyunput (c, buf, scanner); + } + } + + void + base_lexer::xunput (char c) + { + char *yytxt = flex_yytext (); + + xunput (c, yytxt); + } + + bool + base_lexer::looking_at_space (void) + { + int c = text_yyinput (); + xunput (c); + return (c == ' ' || c == '\t'); + } + + bool + base_lexer::inside_any_object_index (void) + { + bool retval = false; + + for (std::list::const_iterator i = looking_at_object_index.begin (); + i != looking_at_object_index.end (); i++) + { + if (*i) + { + retval = true; + break; + } + } + + return retval; + } + + bool + base_lexer::is_variable (const std::string& name, + symbol_table::scope_id scope) + { + return (symbol_table::is_variable (name, scope) + || (pending_local_variables.find (name) + != pending_local_variables.end ())); + } + + // Handle keywords. Return -1 if the keyword should be ignored. + + int + base_lexer::is_keyword_token (const std::string& s) + { + int l = input_line_number; + int c = current_input_column; + + int len = s.length (); + + const octave_kw *kw = octave_kw_hash::in_word_set (s.c_str (), len); + + if (kw) + { + bool previous_at_bos = at_beginning_of_statement; + + // May be reset to true for some token types. + at_beginning_of_statement = false; + + token *tok_val = 0; + + switch (kw->kw_id) + { + case break_kw: + case catch_kw: + case continue_kw: + case else_kw: + case otherwise_kw: + case return_kw: + case unwind_protect_cleanup_kw: + at_beginning_of_statement = true; + break; + + case persistent_kw: + case global_kw: + looking_at_decl_list = true; + break; + + case case_kw: + case elseif_kw: + case until_kw: + break; + + case end_kw: + if (inside_any_object_index () + || (defining_func + && ! (looking_at_return_list + || parsed_function_name.top ()))) + { + at_beginning_of_statement = previous_at_bos; + return 0; + } + + tok_val = new token (end_kw, token::simple_end, l, c); + at_beginning_of_statement = true; + break; + + case end_try_catch_kw: + tok_val = new token (end_try_catch_kw, token::try_catch_end, l, c); + at_beginning_of_statement = true; + break; + + case end_unwind_protect_kw: + tok_val = new token (end_unwind_protect_kw, + token::unwind_protect_end, l, c); + at_beginning_of_statement = true; + break; + + case endfor_kw: + tok_val = new token (endfor_kw, token::for_end, l, c); + at_beginning_of_statement = true; + break; + + case endfunction_kw: + tok_val = new token (endfunction_kw, token::function_end, l, c); + at_beginning_of_statement = true; + break; + + case endif_kw: + tok_val = new token (endif_kw, token::if_end, l, c); + at_beginning_of_statement = true; + break; + + case endparfor_kw: + tok_val = new token (endparfor_kw, token::parfor_end, l, c); + at_beginning_of_statement = true; + break; + + case endswitch_kw: + tok_val = new token (endswitch_kw, token::switch_end, l, c); + at_beginning_of_statement = true; + break; + + case endwhile_kw: + tok_val = new token (endwhile_kw, token::while_end, l, c); + at_beginning_of_statement = true; + break; + + case endclassdef_kw: + tok_val = new token (endclassdef_kw, token::classdef_end, l, c); + at_beginning_of_statement = true; + break; + + case endenumeration_kw: + tok_val = new token (endenumeration_kw, token::enumeration_end, l, c); + at_beginning_of_statement = true; + break; + + case endevents_kw: + tok_val = new token (endevents_kw, token::events_end, l, c); + at_beginning_of_statement = true; + break; + + case endmethods_kw: + tok_val = new token (endmethods_kw, token::methods_end, l, c); + at_beginning_of_statement = true; + break; + + case endproperties_kw: + tok_val = new token (endproperties_kw, token::properties_end, l, c); + at_beginning_of_statement = true; + break; + + + case for_kw: + case parfor_kw: + case while_kw: + decrement_promptflag (); + looping++; + break; + + case do_kw: + at_beginning_of_statement = true; + decrement_promptflag (); + looping++; + break; + + case try_kw: + case unwind_protect_kw: + at_beginning_of_statement = true; + decrement_promptflag (); + break; + + case if_kw: + case switch_kw: + decrement_promptflag (); + break; + + case get_kw: + case set_kw: + // 'get' and 'set' are keywords in classdef method + // declarations. + if (! maybe_classdef_get_set_method) + { + at_beginning_of_statement = previous_at_bos; + return 0; + } + break; + + case enumeration_kw: + case events_kw: + case methods_kw: + case properties_kw: + // 'properties', 'methods' and 'events' are keywords for + // classdef blocks. + if (! parsing_classdef) + { + at_beginning_of_statement = previous_at_bos; + return 0; + } + // fall through ... + + case classdef_kw: + // 'classdef' is always a keyword. + decrement_promptflag (); + + if (! force_script && token_count == 0 && input_from_file ()) + { + reading_classdef_file = true; + reading_script_file = false; + } + break; + + case function_kw: + decrement_promptflag (); + + defining_func++; + parsed_function_name.push (false); + + if (! force_script && token_count == 0 && input_from_file ()) + { + reading_fcn_file = true; + reading_script_file = false; + } + + if (! (reading_fcn_file || reading_script_file + || reading_classdef_file)) + input_line_number = 1; + break; + + case magic_file_kw: { - at_beginning_of_statement = previous_at_bos; - return 0; + if ((reading_fcn_file || reading_script_file + || reading_classdef_file) + && ! fcn_file_full_name.empty ()) + tok_val = new token (magic_file_kw, fcn_file_full_name, l, c); + else + tok_val = new token (magic_file_kw, "stdin", l, c); } - - tok_val = new token (end_kw, token::simple_end, l, c); - at_beginning_of_statement = true; - break; - - case end_try_catch_kw: - tok_val = new token (end_try_catch_kw, token::try_catch_end, l, c); - at_beginning_of_statement = true; - break; - - case end_unwind_protect_kw: - tok_val = new token (end_unwind_protect_kw, - token::unwind_protect_end, l, c); - at_beginning_of_statement = true; - break; - - case endfor_kw: - tok_val = new token (endfor_kw, token::for_end, l, c); - at_beginning_of_statement = true; - break; - - case endfunction_kw: - tok_val = new token (endfunction_kw, token::function_end, l, c); - at_beginning_of_statement = true; - break; - - case endif_kw: - tok_val = new token (endif_kw, token::if_end, l, c); - at_beginning_of_statement = true; - break; - - case endparfor_kw: - tok_val = new token (endparfor_kw, token::parfor_end, l, c); - at_beginning_of_statement = true; - break; - - case endswitch_kw: - tok_val = new token (endswitch_kw, token::switch_end, l, c); - at_beginning_of_statement = true; - break; - - case endwhile_kw: - tok_val = new token (endwhile_kw, token::while_end, l, c); - at_beginning_of_statement = true; - break; - - case endclassdef_kw: - tok_val = new token (endclassdef_kw, token::classdef_end, l, c); - at_beginning_of_statement = true; - break; - - case endenumeration_kw: - tok_val = new token (endenumeration_kw, token::enumeration_end, l, c); - at_beginning_of_statement = true; - break; - - case endevents_kw: - tok_val = new token (endevents_kw, token::events_end, l, c); - at_beginning_of_statement = true; - break; - - case endmethods_kw: - tok_val = new token (endmethods_kw, token::methods_end, l, c); - at_beginning_of_statement = true; - break; - - case endproperties_kw: - tok_val = new token (endproperties_kw, token::properties_end, l, c); - at_beginning_of_statement = true; - break; - - - case for_kw: - case parfor_kw: - case while_kw: - decrement_promptflag (); - looping++; - break; - - case do_kw: - at_beginning_of_statement = true; - decrement_promptflag (); - looping++; - break; - - case try_kw: - case unwind_protect_kw: - at_beginning_of_statement = true; - decrement_promptflag (); - break; - - case if_kw: - case switch_kw: - decrement_promptflag (); - break; - - case get_kw: - case set_kw: - // 'get' and 'set' are keywords in classdef method - // declarations. - if (! maybe_classdef_get_set_method) - { - at_beginning_of_statement = previous_at_bos; - return 0; - } - break; - - case enumeration_kw: - case events_kw: - case methods_kw: - case properties_kw: - // 'properties', 'methods' and 'events' are keywords for - // classdef blocks. - if (! parsing_classdef) - { - at_beginning_of_statement = previous_at_bos; - return 0; - } - // fall through ... - - case classdef_kw: - // 'classdef' is always a keyword. - decrement_promptflag (); - - if (! force_script && token_count == 0 && input_from_file ()) - { - reading_classdef_file = true; - reading_script_file = false; - } - break; - - case function_kw: - decrement_promptflag (); - - defining_func++; - parsed_function_name.push (false); - - if (! force_script && token_count == 0 && input_from_file ()) - { - reading_fcn_file = true; - reading_script_file = false; - } - - if (! (reading_fcn_file || reading_script_file - || reading_classdef_file)) - input_line_number = 1; - break; - - case magic_file_kw: + break; + + case magic_line_kw: + tok_val = new token (magic_line_kw, static_cast (l), + "", l, c); + break; + + default: + panic_impossible (); + } + + if (! tok_val) + tok_val = new token (kw->tok, true, l, c); + + push_token (tok_val); + + return kw->tok; + } + + return 0; + } + + bool + base_lexer::fq_identifier_contains_keyword (const std::string& s) + { + size_t p1 = 0; + size_t p2; + + std::string s_part; + + do + { + p2 = s.find ('.', p1); + + if (p2 != std::string::npos) { - if ((reading_fcn_file || reading_script_file - || reading_classdef_file) - && ! fcn_file_full_name.empty ()) - tok_val = new token (magic_file_kw, fcn_file_full_name, l, c); - else - tok_val = new token (magic_file_kw, "stdin", l, c); + s_part = s.substr (p1, p2 - p1); + p1 = p2 + 1; } - break; - - case magic_line_kw: - tok_val = new token (magic_line_kw, static_cast (l), - "", l, c); - break; - - default: - panic_impossible (); - } - - if (! tok_val) - tok_val = new token (kw->tok, true, l, c); - - push_token (tok_val); - - return kw->tok; - } - - return 0; -} - -bool -octave_base_lexer::fq_identifier_contains_keyword (const std::string& s) -{ - size_t p1 = 0; - size_t p2; - - std::string s_part; - - do - { - p2 = s.find ('.', p1); - - if (p2 != std::string::npos) - { - s_part = s.substr (p1, p2 - p1); - p1 = p2 + 1; - } - else - s_part = s.substr (p1); - - if (is_keyword_token (s_part)) - return true; - } - while (p2 != std::string::npos); - - return false; -} - -bool -octave_base_lexer::whitespace_is_significant (void) -{ - return (nesting_level.is_bracket () - || (nesting_level.is_brace () - && ! looking_at_object_index.front ())); + else + s_part = s.substr (p1); + + if (is_keyword_token (s_part)) + return true; + } + while (p2 != std::string::npos); + + return false; + } + + bool + base_lexer::whitespace_is_significant (void) + { + return (nesting_level.is_bracket () + || (nesting_level.is_brace () + && ! looking_at_object_index.front ())); + } } static inline bool @@ -2753,852 +2762,854 @@ return (len > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')); } -void -octave_base_lexer::handle_number (void) -{ - double value = 0.0; - int nread = 0; - - char *yytxt = flex_yytext (); - - // Strip any underscores - char *tmptxt = strsave (yytxt); - char *rptr = tmptxt; - char *wptr = tmptxt; - while (*rptr) - { - *wptr = *rptr++; - wptr += (*wptr != '_'); - } - *wptr = '\0'; - - if (looks_like_hex (tmptxt, strlen (tmptxt))) - { - uintmax_t long_int_value; - - nread = sscanf (tmptxt, "%jx", &long_int_value); - - value = static_cast (long_int_value); - } - else if (looks_like_bin (tmptxt, strlen (tmptxt))) - { - uintmax_t long_int_value = 0; - - for (size_t i = 0; i < strlen (tmptxt); i++) - { - long_int_value <<= 1; - long_int_value += static_cast (tmptxt[i] == '1'); - } - - value = static_cast (long_int_value); - - nread = 1; // Just to pass the assert stmt below - } - else - { - char *idx = strpbrk (tmptxt, "Dd"); - - if (idx) - *idx = 'e'; - - nread = sscanf (tmptxt, "%lf", &value); - } - - delete [] tmptxt; - - // If yytext doesn't contain a valid number, we are in deep doo doo. - - assert (nread == 1); - - looking_for_object_index = false; - at_beginning_of_statement = false; - - push_token (new token (NUM, value, yytxt, input_line_number, - current_input_column)); - - current_input_column += flex_yyleng (); -} - -void -octave_base_lexer::handle_continuation (void) -{ - char *yytxt = flex_yytext (); - int yylng = flex_yyleng (); - - int offset = 1; - if (yytxt[0] == '\\') - warn_language_extension_continuation (); - else - offset = 3; - - bool have_space = false; - while (offset < yylng) - { - char c = yytxt[offset]; - if (c == ' ' || c == '\t') - { - have_space = true; - offset++; - } - else - break; - } - - if (have_space) - mark_previous_token_trailing_space (); - - bool have_comment = false; - while (offset < yylng) - { - char c = yytxt[offset]; - if (c == '#' || c == '%') - { - have_comment = true; - offset++; - } - else - break; - } - - if (have_comment) - { - comment_text = &yytxt[offset]; - - // finish_comment sets at_beginning_of_statement to true but - // that's not be correct if we are handling a continued - // statement. Preserve the current state. - - bool saved_bos = at_beginning_of_statement; - - finish_comment (octave_comment_elt::end_of_line); - - at_beginning_of_statement = saved_bos; - } - - decrement_promptflag (); - input_line_number++; - current_input_column = 1; -} - -void -octave_base_lexer::finish_comment (octave_comment_elt::comment_type typ) -{ - bool copyright = looks_like_copyright (comment_text); - - if (nesting_level.none () && help_text.empty () - && ! comment_text.empty () && ! copyright) - help_text = comment_text; - - if (copyright) - typ = octave_comment_elt::copyright; - - comment_buf.append (comment_text, typ); - - comment_text = ""; - - at_beginning_of_statement = true; -} - -int -octave_base_lexer::handle_close_bracket (int bracket_type) -{ - int retval = bracket_type; - - if (! nesting_level.none ()) - { - nesting_level.remove (); - - if (bracket_type == ']') - bracketflag--; - else if (bracket_type == '}') - braceflag--; - else - panic_impossible (); - } - - pop_start_state (); - - return retval; -} - -bool -octave_base_lexer::looks_like_command_arg (void) -{ - bool space_before = space_follows_previous_token (); - bool space_after = looking_at_space (); - - return (space_before && ! space_after - && previous_token_may_be_command ()); -} - -int -octave_base_lexer::handle_superclass_identifier (void) -{ - std::string meth = flex_yytext (); - - size_t pos = meth.find ("@"); - std::string cls = meth.substr (pos + 1); - meth = meth.substr (0, pos); - - bool kw_token = (is_keyword_token (meth) - || fq_identifier_contains_keyword (cls)); - - if (kw_token) - { - token *tok - = new token (LEXICAL_ERROR, - "method, class, and package names may not be keywords", - input_line_number, current_input_column); - - push_token (tok); - - return count_token_internal (LEXICAL_ERROR); - } - - push_token (new token (SUPERCLASSREF, meth, cls, - input_line_number, current_input_column)); - - current_input_column += flex_yyleng (); - - return SUPERCLASSREF; -} - -int -octave_base_lexer::handle_meta_identifier (void) -{ - std::string cls = std::string(flex_yytext ()).substr (1); - - if (fq_identifier_contains_keyword (cls)) - { - token *tok = new token (LEXICAL_ERROR, - "class and package names may not be keywords", - input_line_number, current_input_column); - push_token (tok); - - return count_token_internal (LEXICAL_ERROR); - } - - push_token (new token (METAQUERY, cls, input_line_number, - current_input_column)); - - current_input_column += flex_yyleng (); - - return METAQUERY; -} - -int -octave_base_lexer::handle_fq_identifier (void) -{ - std::string fq_id = flex_yytext (); - - if (fq_identifier_contains_keyword (fq_id)) - { - token *tok - = new token (LEXICAL_ERROR, - "function, method, class, and package names may not be keywords", - input_line_number, current_input_column); - - push_token (tok); - - return count_token_internal (LEXICAL_ERROR); - } - - push_token (new token (FQ_IDENT, fq_id, input_line_number, - current_input_column)); - - current_input_column += flex_yyleng (); - - return FQ_IDENT; -} - -// Figure out exactly what kind of token to return when we have seen -// an identifier. Handles keywords. Return -1 if the identifier -// should be ignored. - -int -octave_base_lexer::handle_identifier (void) -{ - std::string ident = flex_yytext (); - - // If we are expecting a structure element, avoid recognizing - // keywords and other special names and return STRUCT_ELT, which is - // a string that is also a valid identifier. - - if (looking_at_indirect_ref) - { - push_token (new token (STRUCT_ELT, ident, input_line_number, - current_input_column)); - - looking_for_object_index = true; - - current_input_column += flex_yyleng (); - - return STRUCT_ELT; - } - - // If ident is a keyword token, then is_keyword_token will set - // at_beginning_of_statement. For example, if tok is an IF - // token, then at_beginning_of_statement will be false. - - int kw_token = is_keyword_token (ident); - - if (looking_at_function_handle) - { - if (kw_token) - { - token *tok - = new token (LEXICAL_ERROR, - "function handles may not refer to keywords", - input_line_number, current_input_column); - - push_token (tok); - - return count_token_internal (LEXICAL_ERROR); - } - else - { - push_token (new token (FCN_HANDLE, ident, input_line_number, - current_input_column)); - - current_input_column += flex_yyleng (); - looking_for_object_index = true; - - at_beginning_of_statement = false; - - return FCN_HANDLE; - } - } - - // If we have a regular keyword, return it. - // Keywords can be followed by identifiers. - - if (kw_token) - { - if (kw_token >= 0) - { - current_input_column += flex_yyleng (); - looking_for_object_index = false; - } - - // The call to is_keyword_token set at_beginning_of_statement. - - return kw_token; - } - - // Find the token in the symbol table. - - symbol_table::scope_id sid = symtab_context.curr_scope (); - - token *tok = new token (NAME, &(symbol_table::insert (ident, sid)), - input_line_number, current_input_column); - - // The following symbols are handled specially so that things like - // - // pi +1 - // - // are parsed as an addition expression instead of as a command-style - // function call with the argument "+1". - - if (at_beginning_of_statement - && (! (is_variable (ident, sid) - || ident == "e" || ident == "pi" - || ident == "I" || ident == "i" - || ident == "J" || ident == "j" - || ident == "Inf" || ident == "inf" - || ident == "NaN" || ident == "nan"))) - tok->mark_may_be_command (); - - push_token (tok); - - current_input_column += flex_yyleng (); - - // The magic end index can't be indexed. - - if (ident != "end") - looking_for_object_index = true; - - at_beginning_of_statement = false; - - return NAME; -} - -void -octave_base_lexer::maybe_warn_separator_insert (char sep) -{ - std::string nm = fcn_file_full_name; - - if (nm.empty ()) - warning_with_id ("Octave:separator-insert", - "potential auto-insertion of '%c' near line %d", - sep, input_line_number); - else - warning_with_id ("Octave:separator-insert", - "potential auto-insertion of '%c' near line %d of file %s", - sep, input_line_number, nm.c_str ()); -} - -void -octave_base_lexer::warn_single_quote_string (void) -{ - std::string nm = fcn_file_full_name; - - if (nm.empty ()) - warning_with_id ("Octave:single-quote-string", - "single quote delimited string near line %d", - input_line_number); - else - warning_with_id ("Octave:single-quote-string", - "single quote delimited string near line %d of file %s", - input_line_number, nm.c_str ()); -} - -void -octave_base_lexer::warn_language_extension (const std::string& msg) -{ - std::string nm = fcn_file_full_name; - - if (nm.empty ()) - warning_with_id ("Octave:language-extension", - "Octave language extension used: %s", - msg.c_str ()); - else - warning_with_id ("Octave:language-extension", - "Octave language extension used: %s near line %d offile %s", - msg.c_str (), input_line_number, nm.c_str ()); -} - -void -octave_base_lexer::maybe_warn_language_extension_comment (char c) -{ - if (c == '#') - warn_language_extension ("# used as comment character"); -} - -void -octave_base_lexer::warn_language_extension_continuation (void) +namespace octave { - warn_language_extension ("\\ used as line continuation marker"); -} - -void -octave_base_lexer::warn_language_extension_operator (const std::string& op) -{ - std::string t = op; - int n = t.length (); - if (t[n-1] == '\n') - t.resize (n-1); - warn_language_extension (t + " used as operator"); -} - -void -octave_base_lexer::push_token (token *tok) -{ - YYSTYPE *lval = yyget_lval (scanner); - lval->tok_val = tok; - tokens.push (tok); -} - -token * -octave_base_lexer::current_token (void) -{ - YYSTYPE *lval = yyget_lval (scanner); - return lval->tok_val; -} - -void -octave_base_lexer::display_token (int tok) -{ - switch (tok) - { - case '=': std::cerr << "'='\n"; break; - case ':': std::cerr << "':'\n"; break; - case '-': std::cerr << "'-'\n"; break; - case '+': std::cerr << "'+'\n"; break; - case '*': std::cerr << "'*'\n"; break; - case '/': std::cerr << "'/'\n"; break; - case ADD_EQ: std::cerr << "ADD_EQ\n"; break; - case SUB_EQ: std::cerr << "SUB_EQ\n"; break; - case MUL_EQ: std::cerr << "MUL_EQ\n"; break; - case DIV_EQ: std::cerr << "DIV_EQ\n"; break; - case LEFTDIV_EQ: std::cerr << "LEFTDIV_EQ\n"; break; - case POW_EQ: std::cerr << "POW_EQ\n"; break; - case EMUL_EQ: std::cerr << "EMUL_EQ\n"; break; - case EDIV_EQ: std::cerr << "EDIV_EQ\n"; break; - case ELEFTDIV_EQ: std::cerr << "ELEFTDIV_EQ\n"; break; - case EPOW_EQ: std::cerr << "EPOW_EQ\n"; break; - case AND_EQ: std::cerr << "AND_EQ\n"; break; - case OR_EQ: std::cerr << "OR_EQ\n"; break; - case EXPR_AND_AND: std::cerr << "EXPR_AND_AND\n"; break; - case EXPR_OR_OR: std::cerr << "EXPR_OR_OR\n"; break; - case EXPR_AND: std::cerr << "EXPR_AND\n"; break; - case EXPR_OR: std::cerr << "EXPR_OR\n"; break; - case EXPR_NOT: std::cerr << "EXPR_NOT\n"; break; - case EXPR_LT: std::cerr << "EXPR_LT\n"; break; - case EXPR_LE: std::cerr << "EXPR_LE\n"; break; - case EXPR_EQ: std::cerr << "EXPR_EQ\n"; break; - case EXPR_NE: std::cerr << "EXPR_NE\n"; break; - case EXPR_GE: std::cerr << "EXPR_GE\n"; break; - case EXPR_GT: std::cerr << "EXPR_GT\n"; break; - case LEFTDIV: std::cerr << "LEFTDIV\n"; break; - case EMUL: std::cerr << "EMUL\n"; break; - case EDIV: std::cerr << "EDIV\n"; break; - case ELEFTDIV: std::cerr << "ELEFTDIV\n"; break; - case EPLUS: std::cerr << "EPLUS\n"; break; - case EMINUS: std::cerr << "EMINUS\n"; break; - case HERMITIAN: std::cerr << "HERMITIAN\n"; break; - case TRANSPOSE: std::cerr << "TRANSPOSE\n"; break; - case PLUS_PLUS: std::cerr << "PLUS_PLUS\n"; break; - case MINUS_MINUS: std::cerr << "MINUS_MINUS\n"; break; - case POW: std::cerr << "POW\n"; break; - case EPOW: std::cerr << "EPOW\n"; break; - - case NUM: - case IMAG_NUM: + void + base_lexer::handle_number (void) + { + double value = 0.0; + int nread = 0; + + char *yytxt = flex_yytext (); + + // Strip any underscores + char *tmptxt = strsave (yytxt); + char *rptr = tmptxt; + char *wptr = tmptxt; + while (*rptr) + { + *wptr = *rptr++; + wptr += (*wptr != '_'); + } + *wptr = '\0'; + + if (looks_like_hex (tmptxt, strlen (tmptxt))) + { + uintmax_t long_int_value; + + nread = sscanf (tmptxt, "%jx", &long_int_value); + + value = static_cast (long_int_value); + } + else if (looks_like_bin (tmptxt, strlen (tmptxt))) + { + uintmax_t long_int_value = 0; + + for (size_t i = 0; i < strlen (tmptxt); i++) + { + long_int_value <<= 1; + long_int_value += static_cast (tmptxt[i] == '1'); + } + + value = static_cast (long_int_value); + + nread = 1; // Just to pass the assert stmt below + } + else + { + char *idx = strpbrk (tmptxt, "Dd"); + + if (idx) + *idx = 'e'; + + nread = sscanf (tmptxt, "%lf", &value); + } + + delete [] tmptxt; + + // If yytext doesn't contain a valid number, we are in deep doo doo. + + assert (nread == 1); + + looking_for_object_index = false; + at_beginning_of_statement = false; + + push_token (new token (NUM, value, yytxt, input_line_number, + current_input_column)); + + current_input_column += flex_yyleng (); + } + + void + base_lexer::handle_continuation (void) + { + char *yytxt = flex_yytext (); + int yylng = flex_yyleng (); + + int offset = 1; + if (yytxt[0] == '\\') + warn_language_extension_continuation (); + else + offset = 3; + + bool have_space = false; + while (offset < yylng) + { + char c = yytxt[offset]; + if (c == ' ' || c == '\t') + { + have_space = true; + offset++; + } + else + break; + } + + if (have_space) + mark_previous_token_trailing_space (); + + bool have_comment = false; + while (offset < yylng) + { + char c = yytxt[offset]; + if (c == '#' || c == '%') + { + have_comment = true; + offset++; + } + else + break; + } + + if (have_comment) + { + comment_text = &yytxt[offset]; + + // finish_comment sets at_beginning_of_statement to true but + // that's not be correct if we are handling a continued + // statement. Preserve the current state. + + bool saved_bos = at_beginning_of_statement; + + finish_comment (octave_comment_elt::end_of_line); + + at_beginning_of_statement = saved_bos; + } + + decrement_promptflag (); + input_line_number++; + current_input_column = 1; + } + + void + base_lexer::finish_comment (octave_comment_elt::comment_type typ) + { + bool copyright = looks_like_copyright (comment_text); + + if (nesting_level.none () && help_text.empty () + && ! comment_text.empty () && ! copyright) + help_text = comment_text; + + if (copyright) + typ = octave_comment_elt::copyright; + + comment_buf.append (comment_text, typ); + + comment_text = ""; + + at_beginning_of_statement = true; + } + + int + base_lexer::handle_close_bracket (int bracket_type) + { + int retval = bracket_type; + + if (! nesting_level.none ()) { - token *tok_val = current_token (); - std::cerr << (tok == NUM ? "NUM" : "IMAG_NUM") - << " [" << tok_val->number () << "]\n"; + nesting_level.remove (); + + if (bracket_type == ']') + bracketflag--; + else if (bracket_type == '}') + braceflag--; + else + panic_impossible (); } - break; - - case STRUCT_ELT: + + pop_start_state (); + + return retval; + } + + bool + base_lexer::looks_like_command_arg (void) + { + bool space_before = space_follows_previous_token (); + bool space_after = looking_at_space (); + + return (space_before && ! space_after + && previous_token_may_be_command ()); + } + + int + base_lexer::handle_superclass_identifier (void) + { + std::string meth = flex_yytext (); + + size_t pos = meth.find ("@"); + std::string cls = meth.substr (pos + 1); + meth = meth.substr (0, pos); + + bool kw_token = (is_keyword_token (meth) + || fq_identifier_contains_keyword (cls)); + + if (kw_token) { - token *tok_val = current_token (); - std::cerr << "STRUCT_ELT [" << tok_val->text () << "]\n"; + token *tok + = new token (LEXICAL_ERROR, + "method, class, and package names may not be keywords", + input_line_number, current_input_column); + + push_token (tok); + + return count_token_internal (LEXICAL_ERROR); + } + + push_token (new token (SUPERCLASSREF, meth, cls, + input_line_number, current_input_column)); + + current_input_column += flex_yyleng (); + + return SUPERCLASSREF; + } + + int + base_lexer::handle_meta_identifier (void) + { + std::string cls = std::string(flex_yytext ()).substr (1); + + if (fq_identifier_contains_keyword (cls)) + { + token *tok = new token (LEXICAL_ERROR, + "class and package names may not be keywords", + input_line_number, current_input_column); + push_token (tok); + + return count_token_internal (LEXICAL_ERROR); } - break; - - case NAME: + + push_token (new token (METAQUERY, cls, input_line_number, + current_input_column)); + + current_input_column += flex_yyleng (); + + return METAQUERY; + } + + int + base_lexer::handle_fq_identifier (void) + { + std::string fq_id = flex_yytext (); + + if (fq_identifier_contains_keyword (fq_id)) + { + token *tok + = new token (LEXICAL_ERROR, + "function, method, class, and package names may not be keywords", + input_line_number, current_input_column); + + push_token (tok); + + return count_token_internal (LEXICAL_ERROR); + } + + push_token (new token (FQ_IDENT, fq_id, input_line_number, + current_input_column)); + + current_input_column += flex_yyleng (); + + return FQ_IDENT; + } + + // Figure out exactly what kind of token to return when we have seen + // an identifier. Handles keywords. Return -1 if the identifier + // should be ignored. + + int + base_lexer::handle_identifier (void) + { + std::string ident = flex_yytext (); + + // If we are expecting a structure element, avoid recognizing + // keywords and other special names and return STRUCT_ELT, which is + // a string that is also a valid identifier. + + if (looking_at_indirect_ref) { - token *tok_val = current_token (); - symbol_table::symbol_record *sr = tok_val->sym_rec (); - std::cerr << "NAME"; - if (sr) - std::cerr << " [" << sr->name () << "]"; - std::cerr << "\n"; + push_token (new token (STRUCT_ELT, ident, input_line_number, + current_input_column)); + + looking_for_object_index = true; + + current_input_column += flex_yyleng (); + + return STRUCT_ELT; + } + + // If ident is a keyword token, then is_keyword_token will set + // at_beginning_of_statement. For example, if tok is an IF + // token, then at_beginning_of_statement will be false. + + int kw_token = is_keyword_token (ident); + + if (looking_at_function_handle) + { + if (kw_token) + { + token *tok + = new token (LEXICAL_ERROR, + "function handles may not refer to keywords", + input_line_number, current_input_column); + + push_token (tok); + + return count_token_internal (LEXICAL_ERROR); + } + else + { + push_token (new token (FCN_HANDLE, ident, input_line_number, + current_input_column)); + + current_input_column += flex_yyleng (); + looking_for_object_index = true; + + at_beginning_of_statement = false; + + return FCN_HANDLE; + } + } + + // If we have a regular keyword, return it. + // Keywords can be followed by identifiers. + + if (kw_token) + { + if (kw_token >= 0) + { + current_input_column += flex_yyleng (); + looking_for_object_index = false; + } + + // The call to is_keyword_token set at_beginning_of_statement. + + return kw_token; } - break; - - case END: std::cerr << "END\n"; break; - - case DQ_STRING: - case SQ_STRING: - { - token *tok_val = current_token (); - - std::cerr << (tok == DQ_STRING ? "DQ_STRING" : "SQ_STRING") - << " [" << tok_val->text () << "]\n"; - } - break; - - case FOR: std::cerr << "FOR\n"; break; - case WHILE: std::cerr << "WHILE\n"; break; - case DO: std::cerr << "DO\n"; break; - case UNTIL: std::cerr << "UNTIL\n"; break; - case IF: std::cerr << "IF\n"; break; - case ELSEIF: std::cerr << "ELSEIF\n"; break; - case ELSE: std::cerr << "ELSE\n"; break; - case SWITCH: std::cerr << "SWITCH\n"; break; - case CASE: std::cerr << "CASE\n"; break; - case OTHERWISE: std::cerr << "OTHERWISE\n"; break; - case BREAK: std::cerr << "BREAK\n"; break; - case CONTINUE: std::cerr << "CONTINUE\n"; break; - case FUNC_RET: std::cerr << "FUNC_RET\n"; break; - case UNWIND: std::cerr << "UNWIND\n"; break; - case CLEANUP: std::cerr << "CLEANUP\n"; break; - case TRY: std::cerr << "TRY\n"; break; - case CATCH: std::cerr << "CATCH\n"; break; - case GLOBAL: std::cerr << "GLOBAL\n"; break; - case PERSISTENT: std::cerr << "PERSISTENT\n"; break; - case FCN_HANDLE: std::cerr << "FCN_HANDLE\n"; break; - case END_OF_INPUT: std::cerr << "END_OF_INPUT\n\n"; break; - case LEXICAL_ERROR: std::cerr << "LEXICAL_ERROR\n\n"; break; - case FCN: std::cerr << "FCN\n"; break; - case INPUT_FILE: std::cerr << "INPUT_FILE\n"; break; - case SUPERCLASSREF: std::cerr << "SUPERCLASSREF\n"; break; - case METAQUERY: std::cerr << "METAQUERY\n"; break; - case GET: std::cerr << "GET\n"; break; - case SET: std::cerr << "SET\n"; break; - case PROPERTIES: std::cerr << "PROPERTIES\n"; break; - case METHODS: std::cerr << "METHODS\n"; break; - case EVENTS: std::cerr << "EVENTS\n"; break; - case CLASSDEF: std::cerr << "CLASSDEF\n"; break; - case '\n': std::cerr << "\\n\n"; break; - case '\r': std::cerr << "\\r\n"; break; - case '\t': std::cerr << "TAB\n"; break; - default: + + // Find the token in the symbol table. + + symbol_table::scope_id sid = symtab_context.curr_scope (); + + token *tok = new token (NAME, &(symbol_table::insert (ident, sid)), + input_line_number, current_input_column); + + // The following symbols are handled specially so that things like + // + // pi +1 + // + // are parsed as an addition expression instead of as a command-style + // function call with the argument "+1". + + if (at_beginning_of_statement + && (! (is_variable (ident, sid) + || ident == "e" || ident == "pi" + || ident == "I" || ident == "i" + || ident == "J" || ident == "j" + || ident == "Inf" || ident == "inf" + || ident == "NaN" || ident == "nan"))) + tok->mark_may_be_command (); + + push_token (tok); + + current_input_column += flex_yyleng (); + + // The magic end index can't be indexed. + + if (ident != "end") + looking_for_object_index = true; + + at_beginning_of_statement = false; + + return NAME; + } + + void + base_lexer::maybe_warn_separator_insert (char sep) + { + std::string nm = fcn_file_full_name; + + if (nm.empty ()) + warning_with_id ("Octave:separator-insert", + "potential auto-insertion of '%c' near line %d", + sep, input_line_number); + else + warning_with_id ("Octave:separator-insert", + "potential auto-insertion of '%c' near line %d of file %s", + sep, input_line_number, nm.c_str ()); + } + + void + base_lexer::warn_single_quote_string (void) + { + std::string nm = fcn_file_full_name; + + if (nm.empty ()) + warning_with_id ("Octave:single-quote-string", + "single quote delimited string near line %d", + input_line_number); + else + warning_with_id ("Octave:single-quote-string", + "single quote delimited string near line %d of file %s", + input_line_number, nm.c_str ()); + } + + void + base_lexer::warn_language_extension (const std::string& msg) + { + std::string nm = fcn_file_full_name; + + if (nm.empty ()) + warning_with_id ("Octave:language-extension", + "Octave language extension used: %s", + msg.c_str ()); + else + warning_with_id ("Octave:language-extension", + "Octave language extension used: %s near line %d offile %s", + msg.c_str (), input_line_number, nm.c_str ()); + } + + void + base_lexer::maybe_warn_language_extension_comment (char c) + { + if (c == '#') + warn_language_extension ("# used as comment character"); + } + + void + base_lexer::warn_language_extension_continuation (void) + { + warn_language_extension ("\\ used as line continuation marker"); + } + + void + base_lexer::warn_language_extension_operator (const std::string& op) + { + std::string t = op; + int n = t.length (); + if (t[n-1] == '\n') + t.resize (n-1); + warn_language_extension (t + " used as operator"); + } + + void + base_lexer::push_token (token *tok) + { + YYSTYPE *lval = yyget_lval (scanner); + lval->tok_val = tok; + tokens.push (tok); + } + + token * + base_lexer::current_token (void) + { + YYSTYPE *lval = yyget_lval (scanner); + return lval->tok_val; + } + + void + base_lexer::display_token (int tok) + { + switch (tok) { - if (tok < 256 && tok > 31) - std::cerr << static_cast (tok) << "\n"; - else - std::cerr << "UNKNOWN(" << tok << ")\n"; + case '=': std::cerr << "'='\n"; break; + case ':': std::cerr << "':'\n"; break; + case '-': std::cerr << "'-'\n"; break; + case '+': std::cerr << "'+'\n"; break; + case '*': std::cerr << "'*'\n"; break; + case '/': std::cerr << "'/'\n"; break; + case ADD_EQ: std::cerr << "ADD_EQ\n"; break; + case SUB_EQ: std::cerr << "SUB_EQ\n"; break; + case MUL_EQ: std::cerr << "MUL_EQ\n"; break; + case DIV_EQ: std::cerr << "DIV_EQ\n"; break; + case LEFTDIV_EQ: std::cerr << "LEFTDIV_EQ\n"; break; + case POW_EQ: std::cerr << "POW_EQ\n"; break; + case EMUL_EQ: std::cerr << "EMUL_EQ\n"; break; + case EDIV_EQ: std::cerr << "EDIV_EQ\n"; break; + case ELEFTDIV_EQ: std::cerr << "ELEFTDIV_EQ\n"; break; + case EPOW_EQ: std::cerr << "EPOW_EQ\n"; break; + case AND_EQ: std::cerr << "AND_EQ\n"; break; + case OR_EQ: std::cerr << "OR_EQ\n"; break; + case EXPR_AND_AND: std::cerr << "EXPR_AND_AND\n"; break; + case EXPR_OR_OR: std::cerr << "EXPR_OR_OR\n"; break; + case EXPR_AND: std::cerr << "EXPR_AND\n"; break; + case EXPR_OR: std::cerr << "EXPR_OR\n"; break; + case EXPR_NOT: std::cerr << "EXPR_NOT\n"; break; + case EXPR_LT: std::cerr << "EXPR_LT\n"; break; + case EXPR_LE: std::cerr << "EXPR_LE\n"; break; + case EXPR_EQ: std::cerr << "EXPR_EQ\n"; break; + case EXPR_NE: std::cerr << "EXPR_NE\n"; break; + case EXPR_GE: std::cerr << "EXPR_GE\n"; break; + case EXPR_GT: std::cerr << "EXPR_GT\n"; break; + case LEFTDIV: std::cerr << "LEFTDIV\n"; break; + case EMUL: std::cerr << "EMUL\n"; break; + case EDIV: std::cerr << "EDIV\n"; break; + case ELEFTDIV: std::cerr << "ELEFTDIV\n"; break; + case EPLUS: std::cerr << "EPLUS\n"; break; + case EMINUS: std::cerr << "EMINUS\n"; break; + case HERMITIAN: std::cerr << "HERMITIAN\n"; break; + case TRANSPOSE: std::cerr << "TRANSPOSE\n"; break; + case PLUS_PLUS: std::cerr << "PLUS_PLUS\n"; break; + case MINUS_MINUS: std::cerr << "MINUS_MINUS\n"; break; + case POW: std::cerr << "POW\n"; break; + case EPOW: std::cerr << "EPOW\n"; break; + + case NUM: + case IMAG_NUM: + { + token *tok_val = current_token (); + std::cerr << (tok == NUM ? "NUM" : "IMAG_NUM") + << " [" << tok_val->number () << "]\n"; + } + break; + + case STRUCT_ELT: + { + token *tok_val = current_token (); + std::cerr << "STRUCT_ELT [" << tok_val->text () << "]\n"; + } + break; + + case NAME: + { + token *tok_val = current_token (); + symbol_table::symbol_record *sr = tok_val->sym_rec (); + std::cerr << "NAME"; + if (sr) + std::cerr << " [" << sr->name () << "]"; + std::cerr << "\n"; + } + break; + + case END: std::cerr << "END\n"; break; + + case DQ_STRING: + case SQ_STRING: + { + token *tok_val = current_token (); + + std::cerr << (tok == DQ_STRING ? "DQ_STRING" : "SQ_STRING") + << " [" << tok_val->text () << "]\n"; + } + break; + + case FOR: std::cerr << "FOR\n"; break; + case WHILE: std::cerr << "WHILE\n"; break; + case DO: std::cerr << "DO\n"; break; + case UNTIL: std::cerr << "UNTIL\n"; break; + case IF: std::cerr << "IF\n"; break; + case ELSEIF: std::cerr << "ELSEIF\n"; break; + case ELSE: std::cerr << "ELSE\n"; break; + case SWITCH: std::cerr << "SWITCH\n"; break; + case CASE: std::cerr << "CASE\n"; break; + case OTHERWISE: std::cerr << "OTHERWISE\n"; break; + case BREAK: std::cerr << "BREAK\n"; break; + case CONTINUE: std::cerr << "CONTINUE\n"; break; + case FUNC_RET: std::cerr << "FUNC_RET\n"; break; + case UNWIND: std::cerr << "UNWIND\n"; break; + case CLEANUP: std::cerr << "CLEANUP\n"; break; + case TRY: std::cerr << "TRY\n"; break; + case CATCH: std::cerr << "CATCH\n"; break; + case GLOBAL: std::cerr << "GLOBAL\n"; break; + case PERSISTENT: std::cerr << "PERSISTENT\n"; break; + case FCN_HANDLE: std::cerr << "FCN_HANDLE\n"; break; + case END_OF_INPUT: std::cerr << "END_OF_INPUT\n\n"; break; + case LEXICAL_ERROR: std::cerr << "LEXICAL_ERROR\n\n"; break; + case FCN: std::cerr << "FCN\n"; break; + case INPUT_FILE: std::cerr << "INPUT_FILE\n"; break; + case SUPERCLASSREF: std::cerr << "SUPERCLASSREF\n"; break; + case METAQUERY: std::cerr << "METAQUERY\n"; break; + case GET: std::cerr << "GET\n"; break; + case SET: std::cerr << "SET\n"; break; + case PROPERTIES: std::cerr << "PROPERTIES\n"; break; + case METHODS: std::cerr << "METHODS\n"; break; + case EVENTS: std::cerr << "EVENTS\n"; break; + case CLASSDEF: std::cerr << "CLASSDEF\n"; break; + case '\n': std::cerr << "\\n\n"; break; + case '\r': std::cerr << "\\r\n"; break; + case '\t': std::cerr << "TAB\n"; break; + default: + { + if (tok < 256 && tok > 31) + std::cerr << static_cast (tok) << "\n"; + else + std::cerr << "UNKNOWN(" << tok << ")\n"; + } + break; + } + } + + void + base_lexer::fatal_error (const char *msg) + { + error ("fatal lexer error: %s", msg); + } + + void + base_lexer::lexer_debug (const char *pattern) + { + if (lexer_debug_flag) + { + std::cerr << std::endl; + + display_start_state (); + + std::cerr << "P: " << pattern << std::endl; + std::cerr << "T: " << flex_yytext () << std::endl; } - break; - } -} - -void -octave_base_lexer::fatal_error (const char *msg) -{ - error ("fatal lexer error: %s", msg); -} - -void -octave_base_lexer::lexer_debug (const char *pattern) -{ - if (lexer_debug_flag) - { - std::cerr << std::endl; - - display_start_state (); - - std::cerr << "P: " << pattern << std::endl; - std::cerr << "T: " << flex_yytext () << std::endl; - } -} - -void -octave_base_lexer::push_start_state (int state) -{ - OCTAVE_YYG; - - start_state_stack.push (state); - - BEGIN (start_state ()); -} - -void -octave_base_lexer::pop_start_state (void) -{ - OCTAVE_YYG; - - start_state_stack.pop (); - - BEGIN (start_state ()); -} - -void -octave_base_lexer::clear_start_state (void) -{ - while (! start_state_stack.empty ()) + } + + void + base_lexer::push_start_state (int state) + { + OCTAVE_YYG; + + start_state_stack.push (state); + + BEGIN (start_state ()); + } + + void + base_lexer::pop_start_state (void) + { + OCTAVE_YYG; + start_state_stack.pop (); - push_start_state (INITIAL); + BEGIN (start_state ()); + } + + void + base_lexer::clear_start_state (void) + { + while (! start_state_stack.empty ()) + start_state_stack.pop (); + + push_start_state (INITIAL); + } + + void + base_lexer::display_start_state (void) const + { + std::cerr << "S: "; + + switch (start_state ()) + { + case INITIAL: + std::cerr << "INITIAL" << std::endl; + break; + + case COMMAND_START: + std::cerr << "COMMAND_START" << std::endl; + break; + + case MATRIX_START: + std::cerr << "MATRIX_START" << std::endl; + break; + + case INPUT_FILE_START: + std::cerr << "INPUT_FILE_BEGIN" << std::endl; + break; + + case BLOCK_COMMENT_START: + std::cerr << "BLOCK_COMMENT_START" << std::endl; + break; + + case LINE_COMMENT_START: + std::cerr << "LINE_COMMENT_START" << std::endl; + break; + + case DQ_STRING_START: + std::cerr << "DQ_STRING_START" << std::endl; + break; + + case SQ_STRING_START: + std::cerr << "SQ_STRING_START" << std::endl; + break; + + default: + std::cerr << "UNKNOWN START STATE!" << std::endl; + break; + } + } + + int + base_lexer::handle_op (const char *pattern, int tok, bool bos) + { + lexer_debug (pattern); + + return handle_op_internal (tok, bos, true); + } + + int + base_lexer::handle_language_extension_op (const char *pattern, int tok, + bool bos) + { + lexer_debug (pattern); + + return handle_op_internal (tok, bos, false); + } + + bool + base_lexer::maybe_unput_comma_before_unary_op (int tok) + { + int prev_tok = previous_token_value (); + + bool unput_comma = false; + + if (whitespace_is_significant () && space_follows_previous_token ()) + { + int c = text_yyinput (); + xunput (c); + + bool space_after = (c == ' ' || c == '\t'); + + if (! (prev_tok == '[' || prev_tok == '{' + || previous_token_is_binop () + || ((tok == '+' || tok == '-') && space_after))) + unput_comma = true; + } + + return unput_comma; + } + + int + base_lexer::handle_unary_op (int tok, bool bos) + { + return maybe_unput_comma_before_unary_op (tok) + ? -1 : handle_op_internal (tok, bos, true); + } + + int + base_lexer::handle_language_extension_unary_op (int tok, bool bos) + { + return maybe_unput_comma_before_unary_op (tok) + ? -1 : handle_op_internal (tok, bos, false); + } + + int + base_lexer::handle_op_internal (int tok, bool bos, bool compat) + { + if (! compat) + warn_language_extension_operator (flex_yytext ()); + + push_token (new token (tok, input_line_number, current_input_column)); + + current_input_column += flex_yyleng (); + looking_for_object_index = false; + at_beginning_of_statement = bos; + + return count_token_internal (tok); + } + + int + base_lexer::handle_token (const std::string& name, int tok) + { + token *tok_val = new token (tok, name, input_line_number, + current_input_column); + + return handle_token (tok, tok_val); + } + + int + base_lexer::handle_token (int tok, token *tok_val) + { + if (! tok_val) + tok_val = new token (tok, input_line_number, current_input_column); + + push_token (tok_val); + + current_input_column += flex_yyleng (); + + return count_token_internal (tok); + } + + int + base_lexer::count_token (int tok) + { + token *tok_val = new token (tok, input_line_number, current_input_column); + + push_token (tok_val); + + return count_token_internal (tok); + } + + int + base_lexer::count_token_internal (int tok) + { + if (tok != '\n') + { + Vtoken_count++; + token_count++; + } + + return show_token (tok); + } + + int + base_lexer::show_token (int tok) + { + if (Vdisplay_tokens) + display_token (tok); + + if (lexer_debug_flag) + { + std::cerr << "R: "; + display_token (tok); + std::cerr << std::endl; + } + + return tok; + } + + void + base_lexer::enable_fq_identifier (void) + { + push_start_state (FQ_IDENT_START); + } + + int + lexer::fill_flex_buffer (char *buf, unsigned max_size) + { + int status = 0; + + if (input_buf.empty ()) + { + bool eof = false; + current_input_line = input_reader.get_input (eof); + input_buf.fill (current_input_line, eof); + } + + if (! input_buf.empty ()) + status = input_buf.copy_chunk (buf, max_size); + else + status = YY_NULL; + + return status; + } + + int + push_lexer::fill_flex_buffer (char *buf, unsigned max_size) + { + int status = 0; + + if (input_buf.empty () && ! input_buf.at_eof ()) + input_buf.fill (std::string (1, static_cast (1)), false); + + if (! input_buf.empty ()) + status = input_buf.copy_chunk (buf, max_size); + else + status = YY_NULL; + + return status; + } } - -void -octave_base_lexer::display_start_state (void) const -{ - std::cerr << "S: "; - - switch (start_state ()) - { - case INITIAL: - std::cerr << "INITIAL" << std::endl; - break; - - case COMMAND_START: - std::cerr << "COMMAND_START" << std::endl; - break; - - case MATRIX_START: - std::cerr << "MATRIX_START" << std::endl; - break; - - case INPUT_FILE_START: - std::cerr << "INPUT_FILE_BEGIN" << std::endl; - break; - - case BLOCK_COMMENT_START: - std::cerr << "BLOCK_COMMENT_START" << std::endl; - break; - - case LINE_COMMENT_START: - std::cerr << "LINE_COMMENT_START" << std::endl; - break; - - case DQ_STRING_START: - std::cerr << "DQ_STRING_START" << std::endl; - break; - - case SQ_STRING_START: - std::cerr << "SQ_STRING_START" << std::endl; - break; - - default: - std::cerr << "UNKNOWN START STATE!" << std::endl; - break; - } -} - -int -octave_base_lexer::handle_op (const char *pattern, int tok, bool bos) -{ - lexer_debug (pattern); - - return handle_op_internal (tok, bos, true); -} - -int -octave_base_lexer::handle_language_extension_op (const char *pattern, int tok, - bool bos) -{ - lexer_debug (pattern); - - return handle_op_internal (tok, bos, false); -} - -bool -octave_base_lexer::maybe_unput_comma_before_unary_op (int tok) -{ - int prev_tok = previous_token_value (); - - bool unput_comma = false; - - if (whitespace_is_significant () && space_follows_previous_token ()) - { - int c = text_yyinput (); - xunput (c); - - bool space_after = (c == ' ' || c == '\t'); - - if (! (prev_tok == '[' || prev_tok == '{' - || previous_token_is_binop () - || ((tok == '+' || tok == '-') && space_after))) - unput_comma = true; - } - - return unput_comma; -} - -int -octave_base_lexer::handle_unary_op (int tok, bool bos) -{ - return maybe_unput_comma_before_unary_op (tok) - ? -1 : handle_op_internal (tok, bos, true); -} - -int -octave_base_lexer::handle_language_extension_unary_op (int tok, bool bos) -{ - return maybe_unput_comma_before_unary_op (tok) - ? -1 : handle_op_internal (tok, bos, false); -} - -int -octave_base_lexer::handle_op_internal (int tok, bool bos, bool compat) -{ - if (! compat) - warn_language_extension_operator (flex_yytext ()); - - push_token (new token (tok, input_line_number, current_input_column)); - - current_input_column += flex_yyleng (); - looking_for_object_index = false; - at_beginning_of_statement = bos; - - return count_token_internal (tok); -} - -int -octave_base_lexer::handle_token (const std::string& name, int tok) -{ - token *tok_val = new token (tok, name, input_line_number, - current_input_column); - - return handle_token (tok, tok_val); -} - -int -octave_base_lexer::handle_token (int tok, token *tok_val) -{ - if (! tok_val) - tok_val = new token (tok, input_line_number, current_input_column); - - push_token (tok_val); - - current_input_column += flex_yyleng (); - - return count_token_internal (tok); -} - -int -octave_base_lexer::count_token (int tok) -{ - token *tok_val = new token (tok, input_line_number, current_input_column); - - push_token (tok_val); - - return count_token_internal (tok); -} - -int -octave_base_lexer::count_token_internal (int tok) -{ - if (tok != '\n') - { - Vtoken_count++; - token_count++; - } - - return show_token (tok); -} - -int -octave_base_lexer::show_token (int tok) -{ - if (Vdisplay_tokens) - display_token (tok); - - if (lexer_debug_flag) - { - std::cerr << "R: "; - display_token (tok); - std::cerr << std::endl; - } - - return tok; -} - -void -octave_base_lexer::enable_fq_identifier (void) -{ - push_start_state (FQ_IDENT_START); -} - -int -octave_lexer::fill_flex_buffer (char *buf, unsigned max_size) -{ - int status = 0; - - if (input_buf.empty ()) - { - bool eof = false; - current_input_line = input_reader.get_input (eof); - input_buf.fill (current_input_line, eof); - } - - if (! input_buf.empty ()) - status = input_buf.copy_chunk (buf, max_size); - else - status = YY_NULL; - - return status; -} - -int -octave_push_lexer::fill_flex_buffer (char *buf, unsigned max_size) -{ - int status = 0; - - if (input_buf.empty () && ! input_buf.at_eof ()) - input_buf.fill (std::string (1, static_cast (1)), false); - - if (! input_buf.empty ()) - status = input_buf.copy_chunk (buf, max_size); - else - status = YY_NULL; - - return status; -} - diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/parse-tree/oct-parse.in.yy --- a/libinterp/parse-tree/oct-parse.in.yy Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/oct-parse.in.yy Tue Jul 12 14:28:07 2016 -0400 @@ -88,7 +88,7 @@ // Global access to currently active lexer. // FIXME: to be removed after more parser+lexer refactoring. -octave_base_lexer *LEXER = 0; +octave::base_lexer *LEXER = 0; // TRUE means we printed messages about reading startup files. bool reading_startup_message_printed = false; @@ -99,7 +99,7 @@ // Forward declarations for some functions defined at the bottom of // the file. -static void yyerror (octave_base_parser& parser, const char *s); +static void yyerror (octave::base_parser& parser, const char *s); #define lexer parser.lexer #define scanner lexer.scanner @@ -134,7 +134,7 @@ %define api.pure %PUSH_PULL_DECL% -%parse-param { octave_base_parser& parser } +%parse-param { octave::base_parser& parser } %lex-param { void *scanner } %union @@ -1400,7 +1400,7 @@ // after parsing the function. Any function // definitions found in the file have already // been stored in the symbol table or in - // octave_base_parser::primary_fcn_ptr. + // base_parser::primary_fcn_ptr. delete $3; } @@ -2010,60 +2010,63 @@ #undef lexer static void -yyerror (octave_base_parser& parser, const char *s) +yyerror (octave::base_parser& parser, const char *s) { parser.bison_error (s); } -octave_base_parser::octave_base_parser (octave_base_lexer& lxr) - : endfunction_found (false), autoloading (false), - fcn_file_from_relative_lookup (false), parsing_subfunctions (false), - max_fcn_depth (0), curr_fcn_depth (0), primary_fcn_scope (-1), - curr_class_name (), curr_package_name (), function_scopes (), - primary_fcn_ptr (0), subfunction_names (), classdef_object (0), - stmt_list (0), lexer (lxr), parser_state (yypstate_new ()) -{ } - -octave_base_parser::~octave_base_parser (void) +namespace octave { - delete stmt_list; - - delete &lexer; - - // FIXME: Deleting the internal Bison parser state structure does - // not clean up any partial parse trees in the event of an interrupt or - // error. It's not clear how to safely do that with the C language - // parser that Bison generates. The C++ language parser that Bison - // generates would do it for us automatically whenever an exception - // is thrown while parsing input, but there is currently no C++ - // interface for a push parser. - - yypstate_delete (static_cast (parser_state)); -} - -void -octave_base_parser::reset (void) -{ - endfunction_found = false; - autoloading = false; - fcn_file_from_relative_lookup = false; - parsing_subfunctions = false; - max_fcn_depth = 0; - curr_fcn_depth = 0; - primary_fcn_scope = -1; - curr_class_name = ""; - curr_package_name = ""; - function_scopes.clear (); - primary_fcn_ptr = 0; - subfunction_names.clear (); - - delete stmt_list; - stmt_list = 0; - - lexer.reset (); - - yypstate_delete (static_cast (parser_state)); - parser_state = yypstate_new (); + base_parser::base_parser (base_lexer& lxr) + : endfunction_found (false), autoloading (false), + fcn_file_from_relative_lookup (false), parsing_subfunctions (false), + max_fcn_depth (0), curr_fcn_depth (0), primary_fcn_scope (-1), + curr_class_name (), curr_package_name (), function_scopes (), + primary_fcn_ptr (0), subfunction_names (), classdef_object (0), + stmt_list (0), lexer (lxr), parser_state (yypstate_new ()) + { } + + base_parser::~base_parser (void) + { + delete stmt_list; + + delete &lexer; + + // FIXME: Deleting the internal Bison parser state structure does + // not clean up any partial parse trees in the event of an interrupt or + // error. It's not clear how to safely do that with the C language + // parser that Bison generates. The C++ language parser that Bison + // generates would do it for us automatically whenever an exception + // is thrown while parsing input, but there is currently no C++ + // interface for a push parser. + + yypstate_delete (static_cast (parser_state)); + } + + void + base_parser::reset (void) + { + endfunction_found = false; + autoloading = false; + fcn_file_from_relative_lookup = false; + parsing_subfunctions = false; + max_fcn_depth = 0; + curr_fcn_depth = 0; + primary_fcn_scope = -1; + curr_class_name = ""; + curr_package_name = ""; + function_scopes.clear (); + primary_fcn_ptr = 0; + subfunction_names.clear (); + + delete stmt_list; + stmt_list = 0; + + lexer.reset (); + + yypstate_delete (static_cast (parser_state)); + parser_state = yypstate_new (); + } } // Error mesages for mismatched end tokens. @@ -2139,1015 +2142,1230 @@ return retval; } -void -octave_base_parser::end_token_error (token *tok, token::end_tok_type expected) -{ - std::string msg = ("'" + end_token_as_string (expected) - + "' command matched by '" - + end_token_as_string (tok->ettype ()) + "'"); - - bison_error (msg, tok->line (), tok->column ()); -} - - -// Check to see that end tokens are properly matched. - -bool -octave_base_parser::end_token_ok (token *tok, token::end_tok_type expected) -{ - token::end_tok_type ettype = tok->ettype (); - - return ettype == expected || ettype == token::simple_end; -} - -// Maybe print a warning if an assignment expression is used as the -// test in a logical expression. - -void -octave_base_parser::maybe_warn_assign_as_truth_value (tree_expression *expr) -{ - if (expr->is_assignment_expression () - && expr->paren_count () < 2) - { - if (lexer.fcn_file_full_name.empty ()) - warning_with_id - ("Octave:assign-as-truth-value", - "suggest parenthesis around assignment used as truth value"); - else - warning_with_id - ("Octave:assign-as-truth-value", - "suggest parenthesis around assignment used as truth value near line %d, column %d in file '%s'", - expr->line (), expr->column (), lexer.fcn_file_full_name.c_str ()); - } -} - -// Maybe print a warning about switch labels that aren't constants. - -void -octave_base_parser::maybe_warn_variable_switch_label (tree_expression *expr) -{ - if (! expr->is_constant ()) - { - if (lexer.fcn_file_full_name.empty ()) - warning_with_id ("Octave:variable-switch-label", - "variable switch label"); - else - warning_with_id - ("Octave:variable-switch-label", - "variable switch label near line %d, column %d in file '%s'", - expr->line (), expr->column (), lexer.fcn_file_full_name.c_str ()); - } -} - -// Finish building a range. - -tree_expression * -octave_base_parser::finish_colon_expression (tree_colon_expression *e) -{ - tree_expression *retval = e; - - octave::unwind_protect frame; - - frame.protect_var (discard_error_messages); - frame.protect_var (discard_warning_messages); - - discard_error_messages = true; - discard_warning_messages = true; - - tree_expression *base = e->base (); - tree_expression *limit = e->limit (); - tree_expression *incr = e->increment (); - - if (base) - { - if (limit) - { - if (base->is_constant () && limit->is_constant () - && (! incr || (incr && incr->is_constant ()))) - { - try - { - octave_value tmp = e->rvalue1 (); - - tree_constant *tc_retval - = new tree_constant (tmp, base->line (), base->column ()); - - std::ostringstream buf; - - tree_print_code tpc (buf); - - e->accept (tpc); - - tc_retval->stash_original_text (buf.str ()); - - delete e; - - retval = tc_retval; - } - catch (const octave_execution_exception&) - { - recover_from_exception (); - } - } - } - else - { - e->preserve_base (); - delete e; - - retval = base; - } - } - - return retval; -} - -// Make a constant. - -tree_constant * -octave_base_parser::make_constant (int op, token *tok_val) -{ - int l = tok_val->line (); - int c = tok_val->column (); - - tree_constant *retval = 0; - - switch (op) - { - case NUM: - { - octave_value tmp (tok_val->number ()); - retval = new tree_constant (tmp, l, c); - retval->stash_original_text (tok_val->text_rep ()); - } - break; - - case IMAG_NUM: - { - octave_value tmp (Complex (0.0, tok_val->number ())); - retval = new tree_constant (tmp, l, c); - retval->stash_original_text (tok_val->text_rep ()); - } - break; - - case DQ_STRING: - case SQ_STRING: - { - std::string txt = tok_val->text (); - - char delim = op == DQ_STRING ? '"' : '\''; - octave_value tmp (txt, delim); - - if (txt.empty ()) - { - if (op == DQ_STRING) - tmp = octave_null_str::instance; - else - tmp = octave_null_sq_str::instance; - } - - retval = new tree_constant (tmp, l, c); - - if (op == DQ_STRING) - txt = undo_string_escapes (txt); - - // FIXME: maybe this should also be handled by - // tok_val->text_rep () for character strings? - retval->stash_original_text (delim + txt + delim); - } - break; - - default: - panic_impossible (); - break; - } - - return retval; -} - -// Make a function handle. - -tree_fcn_handle * -octave_base_parser::make_fcn_handle (token *tok_val) -{ - int l = tok_val->line (); - int c = tok_val->column (); - - tree_fcn_handle *retval = new tree_fcn_handle (tok_val->text (), l, c); - - return retval; -} - -// Make an anonymous function handle. - -tree_anon_fcn_handle * -octave_base_parser::make_anon_fcn_handle (tree_parameter_list *param_list, - tree_statement *stmt) -{ - // FIXME: need to get these from the location of the @ symbol. - int l = lexer.input_line_number; - int c = lexer.current_input_column; - - tree_parameter_list *ret_list = 0; - - symbol_table::scope_id fcn_scope = lexer.symtab_context.curr_scope (); - - lexer.symtab_context.pop (); - - stmt->set_print_flag (false); - - tree_statement_list *body = new tree_statement_list (stmt); - - body->mark_as_anon_function_body (); - - tree_anon_fcn_handle *retval - = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_scope, l, c); - // FIXME: Stash the filename. This does not work and produces - // errors when executed. - //retval->stash_file_name (lexer.fcn_file_name); - - return retval; -} - -// Build a binary expression. - -tree_expression * -octave_base_parser::make_binary_op (int op, tree_expression *op1, - token *tok_val, tree_expression *op2) +namespace octave { - octave_value::binary_op t = octave_value::unknown_binary_op; - - switch (op) - { - case POW: - t = octave_value::op_pow; - break; - - case EPOW: - t = octave_value::op_el_pow; - break; - - case '+': - t = octave_value::op_add; - break; - - case '-': - t = octave_value::op_sub; - break; - - case '*': - t = octave_value::op_mul; - break; - - case '/': - t = octave_value::op_div; - break; - - case EMUL: - t = octave_value::op_el_mul; - break; - - case EDIV: - t = octave_value::op_el_div; - break; - - case LEFTDIV: - t = octave_value::op_ldiv; - break; - - case ELEFTDIV: - t = octave_value::op_el_ldiv; - break; - - case EXPR_LT: - t = octave_value::op_lt; - break; - - case EXPR_LE: - t = octave_value::op_le; - break; - - case EXPR_EQ: - t = octave_value::op_eq; - break; - - case EXPR_GE: - t = octave_value::op_ge; - break; - - case EXPR_GT: - t = octave_value::op_gt; - break; - - case EXPR_NE: - t = octave_value::op_ne; - break; - - case EXPR_AND: - t = octave_value::op_el_and; - break; - - case EXPR_OR: - t = octave_value::op_el_or; - break; - - default: - panic_impossible (); - break; - } - - int l = tok_val->line (); - int c = tok_val->column (); - - return maybe_compound_binary_expression (op1, op2, l, c, t); -} - -// Build a boolean expression. - -tree_expression * -octave_base_parser::make_boolean_op (int op, tree_expression *op1, - token *tok_val, tree_expression *op2) -{ - tree_boolean_expression::type t; - - switch (op) - { - case EXPR_AND_AND: - t = tree_boolean_expression::bool_and; - break; - - case EXPR_OR_OR: - t = tree_boolean_expression::bool_or; - break; - - default: - panic_impossible (); - break; - } - - int l = tok_val->line (); - int c = tok_val->column (); - - return new tree_boolean_expression (op1, op2, l, c, t); -} - -// Build a prefix expression. - -tree_expression * -octave_base_parser::make_prefix_op (int op, tree_expression *op1, - token *tok_val) -{ - octave_value::unary_op t = octave_value::unknown_unary_op; - - switch (op) - { - case EXPR_NOT: - t = octave_value::op_not; - break; - - case '+': - t = octave_value::op_uplus; - break; - - case '-': - t = octave_value::op_uminus; - break; - - case PLUS_PLUS: - t = octave_value::op_incr; - break; - - case MINUS_MINUS: - t = octave_value::op_decr; - break; - - default: - panic_impossible (); - break; - } - - int l = tok_val->line (); - int c = tok_val->column (); - - return new tree_prefix_expression (op1, l, c, t); -} - -// Build a postfix expression. - -tree_expression * -octave_base_parser::make_postfix_op (int op, tree_expression *op1, - token *tok_val) -{ - octave_value::unary_op t = octave_value::unknown_unary_op; - - switch (op) - { - case HERMITIAN: - t = octave_value::op_hermitian; - break; - - case TRANSPOSE: - t = octave_value::op_transpose; - break; - - case PLUS_PLUS: - t = octave_value::op_incr; - break; - - case MINUS_MINUS: - t = octave_value::op_decr; - break; - - default: - panic_impossible (); - break; - } - - int l = tok_val->line (); - int c = tok_val->column (); - - return new tree_postfix_expression (op1, l, c, t); -} - -// Build an unwind-protect command. - -tree_command * -octave_base_parser::make_unwind_command (token *unwind_tok, - tree_statement_list *body, - tree_statement_list *cleanup_stmts, - token *end_tok, - octave_comment_list *lc, - octave_comment_list *mc) -{ - tree_command *retval = 0; - - if (end_token_ok (end_tok, token::unwind_protect_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - int l = unwind_tok->line (); - int c = unwind_tok->column (); - - retval = new tree_unwind_protect_command (body, cleanup_stmts, - lc, mc, tc, l, c); - } - else - { - delete body; - delete cleanup_stmts; - - end_token_error (end_tok, token::unwind_protect_end); - } - - return retval; -} - -// Build a try-catch command. - -tree_command * -octave_base_parser::make_try_command (token *try_tok, + void + base_parser::end_token_error (token *tok, token::end_tok_type expected) + { + std::string msg = ("'" + end_token_as_string (expected) + + "' command matched by '" + + end_token_as_string (tok->ettype ()) + "'"); + + bison_error (msg, tok->line (), tok->column ()); + } + + // Check to see that end tokens are properly matched. + + bool + base_parser::end_token_ok (token *tok, token::end_tok_type expected) + { + token::end_tok_type ettype = tok->ettype (); + + return ettype == expected || ettype == token::simple_end; + } + + // Maybe print a warning if an assignment expression is used as the + // test in a logical expression. + + void + base_parser::maybe_warn_assign_as_truth_value (tree_expression *expr) + { + if (expr->is_assignment_expression () + && expr->paren_count () < 2) + { + if (lexer.fcn_file_full_name.empty ()) + warning_with_id + ("Octave:assign-as-truth-value", + "suggest parenthesis around assignment used as truth value"); + else + warning_with_id + ("Octave:assign-as-truth-value", + "suggest parenthesis around assignment used as truth value near line %d, column %d in file '%s'", + expr->line (), expr->column (), lexer.fcn_file_full_name.c_str ()); + } + } + + // Maybe print a warning about switch labels that aren't constants. + + void + base_parser::maybe_warn_variable_switch_label (tree_expression *expr) + { + if (! expr->is_constant ()) + { + if (lexer.fcn_file_full_name.empty ()) + warning_with_id ("Octave:variable-switch-label", + "variable switch label"); + else + warning_with_id + ("Octave:variable-switch-label", + "variable switch label near line %d, column %d in file '%s'", + expr->line (), expr->column (), lexer.fcn_file_full_name.c_str ()); + } + } + + // Finish building a range. + + tree_expression * + base_parser::finish_colon_expression (tree_colon_expression *e) + { + tree_expression *retval = e; + + octave::unwind_protect frame; + + frame.protect_var (discard_error_messages); + frame.protect_var (discard_warning_messages); + + discard_error_messages = true; + discard_warning_messages = true; + + tree_expression *base = e->base (); + tree_expression *limit = e->limit (); + tree_expression *incr = e->increment (); + + if (base) + { + if (limit) + { + if (base->is_constant () && limit->is_constant () + && (! incr || (incr && incr->is_constant ()))) + { + try + { + octave_value tmp = e->rvalue1 (); + + tree_constant *tc_retval + = new tree_constant (tmp, base->line (), base->column ()); + + std::ostringstream buf; + + tree_print_code tpc (buf); + + e->accept (tpc); + + tc_retval->stash_original_text (buf.str ()); + + delete e; + + retval = tc_retval; + } + catch (const octave_execution_exception&) + { + recover_from_exception (); + } + } + } + else + { + e->preserve_base (); + delete e; + + retval = base; + } + } + + return retval; + } + + // Make a constant. + + tree_constant * + base_parser::make_constant (int op, token *tok_val) + { + int l = tok_val->line (); + int c = tok_val->column (); + + tree_constant *retval = 0; + + switch (op) + { + case NUM: + { + octave_value tmp (tok_val->number ()); + retval = new tree_constant (tmp, l, c); + retval->stash_original_text (tok_val->text_rep ()); + } + break; + + case IMAG_NUM: + { + octave_value tmp (Complex (0.0, tok_val->number ())); + retval = new tree_constant (tmp, l, c); + retval->stash_original_text (tok_val->text_rep ()); + } + break; + + case DQ_STRING: + case SQ_STRING: + { + std::string txt = tok_val->text (); + + char delim = op == DQ_STRING ? '"' : '\''; + octave_value tmp (txt, delim); + + if (txt.empty ()) + { + if (op == DQ_STRING) + tmp = octave_null_str::instance; + else + tmp = octave_null_sq_str::instance; + } + + retval = new tree_constant (tmp, l, c); + + if (op == DQ_STRING) + txt = undo_string_escapes (txt); + + // FIXME: maybe this should also be handled by + // tok_val->text_rep () for character strings? + retval->stash_original_text (delim + txt + delim); + } + break; + + default: + panic_impossible (); + break; + } + + return retval; + } + + // Make a function handle. + + tree_fcn_handle * + base_parser::make_fcn_handle (token *tok_val) + { + int l = tok_val->line (); + int c = tok_val->column (); + + tree_fcn_handle *retval = new tree_fcn_handle (tok_val->text (), l, c); + + return retval; + } + + // Make an anonymous function handle. + + tree_anon_fcn_handle * + base_parser::make_anon_fcn_handle (tree_parameter_list *param_list, + tree_statement *stmt) + { + // FIXME: need to get these from the location of the @ symbol. + int l = lexer.input_line_number; + int c = lexer.current_input_column; + + tree_parameter_list *ret_list = 0; + + symbol_table::scope_id fcn_scope = lexer.symtab_context.curr_scope (); + + lexer.symtab_context.pop (); + + stmt->set_print_flag (false); + + tree_statement_list *body = new tree_statement_list (stmt); + + body->mark_as_anon_function_body (); + + tree_anon_fcn_handle *retval + = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_scope, l, c); + // FIXME: Stash the filename. This does not work and produces + // errors when executed. + //retval->stash_file_name (lexer.fcn_file_name); + + return retval; + } + + // Build a binary expression. + + tree_expression * + base_parser::make_binary_op (int op, tree_expression *op1, + token *tok_val, tree_expression *op2) + { + octave_value::binary_op t = octave_value::unknown_binary_op; + + switch (op) + { + case POW: + t = octave_value::op_pow; + break; + + case EPOW: + t = octave_value::op_el_pow; + break; + + case '+': + t = octave_value::op_add; + break; + + case '-': + t = octave_value::op_sub; + break; + + case '*': + t = octave_value::op_mul; + break; + + case '/': + t = octave_value::op_div; + break; + + case EMUL: + t = octave_value::op_el_mul; + break; + + case EDIV: + t = octave_value::op_el_div; + break; + + case LEFTDIV: + t = octave_value::op_ldiv; + break; + + case ELEFTDIV: + t = octave_value::op_el_ldiv; + break; + + case EXPR_LT: + t = octave_value::op_lt; + break; + + case EXPR_LE: + t = octave_value::op_le; + break; + + case EXPR_EQ: + t = octave_value::op_eq; + break; + + case EXPR_GE: + t = octave_value::op_ge; + break; + + case EXPR_GT: + t = octave_value::op_gt; + break; + + case EXPR_NE: + t = octave_value::op_ne; + break; + + case EXPR_AND: + t = octave_value::op_el_and; + break; + + case EXPR_OR: + t = octave_value::op_el_or; + break; + + default: + panic_impossible (); + break; + } + + int l = tok_val->line (); + int c = tok_val->column (); + + return maybe_compound_binary_expression (op1, op2, l, c, t); + } + + // Build a boolean expression. + + tree_expression * + base_parser::make_boolean_op (int op, tree_expression *op1, + token *tok_val, tree_expression *op2) + { + tree_boolean_expression::type t; + + switch (op) + { + case EXPR_AND_AND: + t = tree_boolean_expression::bool_and; + break; + + case EXPR_OR_OR: + t = tree_boolean_expression::bool_or; + break; + + default: + panic_impossible (); + break; + } + + int l = tok_val->line (); + int c = tok_val->column (); + + return new tree_boolean_expression (op1, op2, l, c, t); + } + + // Build a prefix expression. + + tree_expression * + base_parser::make_prefix_op (int op, tree_expression *op1, token *tok_val) + { + octave_value::unary_op t = octave_value::unknown_unary_op; + + switch (op) + { + case EXPR_NOT: + t = octave_value::op_not; + break; + + case '+': + t = octave_value::op_uplus; + break; + + case '-': + t = octave_value::op_uminus; + break; + + case PLUS_PLUS: + t = octave_value::op_incr; + break; + + case MINUS_MINUS: + t = octave_value::op_decr; + break; + + default: + panic_impossible (); + break; + } + + int l = tok_val->line (); + int c = tok_val->column (); + + return new tree_prefix_expression (op1, l, c, t); + } + + // Build a postfix expression. + + tree_expression * + base_parser::make_postfix_op (int op, tree_expression *op1, token *tok_val) + { + octave_value::unary_op t = octave_value::unknown_unary_op; + + switch (op) + { + case HERMITIAN: + t = octave_value::op_hermitian; + break; + + case TRANSPOSE: + t = octave_value::op_transpose; + break; + + case PLUS_PLUS: + t = octave_value::op_incr; + break; + + case MINUS_MINUS: + t = octave_value::op_decr; + break; + + default: + panic_impossible (); + break; + } + + int l = tok_val->line (); + int c = tok_val->column (); + + return new tree_postfix_expression (op1, l, c, t); + } + + // Build an unwind-protect command. + + tree_command * + base_parser::make_unwind_command (token *unwind_tok, + tree_statement_list *body, + tree_statement_list *cleanup_stmts, + token *end_tok, + octave_comment_list *lc, + octave_comment_list *mc) + { + tree_command *retval = 0; + + if (end_token_ok (end_tok, token::unwind_protect_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = unwind_tok->line (); + int c = unwind_tok->column (); + + retval = new tree_unwind_protect_command (body, cleanup_stmts, + lc, mc, tc, l, c); + } + else + { + delete body; + delete cleanup_stmts; + + end_token_error (end_tok, token::unwind_protect_end); + } + + return retval; + } + + // Build a try-catch command. + + tree_command * + base_parser::make_try_command (token *try_tok, + tree_statement_list *body, + char catch_sep, + tree_statement_list *cleanup_stmts, + token *end_tok, + octave_comment_list *lc, + octave_comment_list *mc) + { + tree_command *retval = 0; + + if (end_token_ok (end_tok, token::try_catch_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = try_tok->line (); + int c = try_tok->column (); + + tree_identifier *id = 0; + + if (! catch_sep && cleanup_stmts && ! cleanup_stmts->empty ()) + { + tree_statement *stmt = cleanup_stmts->front (); + + if (stmt) + { + tree_expression *expr = stmt->expression (); + + if (expr && expr->is_identifier ()) + { + id = dynamic_cast (expr); + + cleanup_stmts->pop_front (); + + stmt->set_expression (0); + delete stmt; + } + } + } + + retval = new tree_try_catch_command (body, cleanup_stmts, id, + lc, mc, tc, l, c); + } + else + { + delete body; + delete cleanup_stmts; + + end_token_error (end_tok, token::try_catch_end); + } + + return retval; + } + + // Build a while command. + + tree_command * + base_parser::make_while_command (token *while_tok, + tree_expression *expr, + tree_statement_list *body, + token *end_tok, + octave_comment_list *lc) + { + tree_command *retval = 0; + + maybe_warn_assign_as_truth_value (expr); + + if (end_token_ok (end_tok, token::while_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + lexer.looping--; + + int l = while_tok->line (); + int c = while_tok->column (); + + retval = new tree_while_command (expr, body, lc, tc, l, c); + } + else + { + delete expr; + delete body; + + end_token_error (end_tok, token::while_end); + } + + return retval; + } + + // Build a do-until command. + + tree_command * + base_parser::make_do_until_command (token *until_tok, tree_statement_list *body, - char catch_sep, - tree_statement_list *cleanup_stmts, - token *end_tok, - octave_comment_list *lc, - octave_comment_list *mc) -{ - tree_command *retval = 0; - - if (end_token_ok (end_tok, token::try_catch_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - int l = try_tok->line (); - int c = try_tok->column (); - - tree_identifier *id = 0; - - if (! catch_sep && cleanup_stmts && ! cleanup_stmts->empty ()) - { - tree_statement *stmt = cleanup_stmts->front (); - - if (stmt) - { - tree_expression *expr = stmt->expression (); - - if (expr && expr->is_identifier ()) - { - id = dynamic_cast (expr); - - cleanup_stmts->pop_front (); - - stmt->set_expression (0); - delete stmt; - } - } - } - - retval = new tree_try_catch_command (body, cleanup_stmts, id, - lc, mc, tc, l, c); - } - else - { - delete body; - delete cleanup_stmts; - - end_token_error (end_tok, token::try_catch_end); - } - - return retval; -} - -// Build a while command. - -tree_command * -octave_base_parser::make_while_command (token *while_tok, - tree_expression *expr, - tree_statement_list *body, - token *end_tok, - octave_comment_list *lc) -{ - tree_command *retval = 0; - - maybe_warn_assign_as_truth_value (expr); - - if (end_token_ok (end_tok, token::while_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - lexer.looping--; - - int l = while_tok->line (); - int c = while_tok->column (); - - retval = new tree_while_command (expr, body, lc, tc, l, c); - } - else - { - delete expr; - delete body; - - end_token_error (end_tok, token::while_end); - } - - return retval; -} - -// Build a do-until command. - -tree_command * -octave_base_parser::make_do_until_command (token *until_tok, - tree_statement_list *body, - tree_expression *expr, - octave_comment_list *lc) -{ - maybe_warn_assign_as_truth_value (expr); - - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - lexer.looping--; - - int l = until_tok->line (); - int c = until_tok->column (); - - return new tree_do_until_command (expr, body, lc, tc, l, c); -} - -// Build a for command. - -tree_command * -octave_base_parser::make_for_command (int tok_id, token *for_tok, - tree_argument_list *lhs, tree_expression *expr, - tree_expression *maxproc, - tree_statement_list *body, + octave_comment_list *lc) + { + maybe_warn_assign_as_truth_value (expr); + + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + lexer.looping--; + + int l = until_tok->line (); + int c = until_tok->column (); + + return new tree_do_until_command (expr, body, lc, tc, l, c); + } + + // Build a for command. + + tree_command * + base_parser::make_for_command (int tok_id, token *for_tok, + tree_argument_list *lhs, + tree_expression *expr, + tree_expression *maxproc, + tree_statement_list *body, + token *end_tok, + octave_comment_list *lc) + { + tree_command *retval = 0; + + bool parfor = tok_id == PARFOR; + + if (end_token_ok (end_tok, parfor ? token::parfor_end : token::for_end)) + { + expr->mark_as_for_cmd_expr (); + + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + lexer.looping--; + + int l = for_tok->line (); + int c = for_tok->column (); + + if (lhs->length () == 1) + { + tree_expression *tmp = lhs->remove_front (); + + retval = new tree_simple_for_command (parfor, tmp, expr, maxproc, + body, lc, tc, l, c); + + delete lhs; + } + else + { + if (parfor) + { + delete lhs; + delete expr; + delete maxproc; + delete body; + + bison_error ("invalid syntax for parfor statement"); + } + else + retval = new tree_complex_for_command (lhs, expr, body, + lc, tc, l, c); + } + } + else + { + delete lhs; + delete expr; + delete maxproc; + delete body; + + end_token_error (end_tok, parfor ? token::parfor_end : token::for_end); + } + + return retval; + } + + // Build a break command. + + tree_command * + base_parser::make_break_command (token *break_tok) + { + int l = break_tok->line (); + int c = break_tok->column (); + + return new tree_break_command (l, c); + } + + // Build a continue command. + + tree_command * + base_parser::make_continue_command (token *continue_tok) + { + int l = continue_tok->line (); + int c = continue_tok->column (); + + return new tree_continue_command (l, c); + } + + // Build a return command. + + tree_command * + base_parser::make_return_command (token *return_tok) + { + int l = return_tok->line (); + int c = return_tok->column (); + + return new tree_return_command (l, c); + } + + // Start an if command. + + tree_if_command_list * + base_parser::start_if_command (tree_expression *expr, + tree_statement_list *list) + { + maybe_warn_assign_as_truth_value (expr); + + tree_if_clause *t = new tree_if_clause (expr, list); + + return new tree_if_command_list (t); + } + + // Finish an if command. + + tree_if_command * + base_parser::finish_if_command (token *if_tok, + tree_if_command_list *list, + token *end_tok, + octave_comment_list *lc) + { + tree_if_command *retval = 0; + + if (end_token_ok (end_tok, token::if_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = if_tok->line (); + int c = if_tok->column (); + + if (list && ! list->empty ()) + { + tree_if_clause *elt = list->front (); + + if (elt) + { + elt->line (l); + elt->column (c); + } + } + + retval = new tree_if_command (list, lc, tc, l, c); + } + else + { + delete list; + + end_token_error (end_tok, token::if_end); + } + + return retval; + } + + // Build an elseif clause. + + tree_if_clause * + base_parser::make_elseif_clause (token *elseif_tok, + tree_expression *expr, + tree_statement_list *list, + octave_comment_list *lc) + { + maybe_warn_assign_as_truth_value (expr); + + int l = elseif_tok->line (); + int c = elseif_tok->column (); + + return new tree_if_clause (expr, list, lc, l, c); + } + + // Finish a switch command. + + tree_switch_command * + base_parser::finish_switch_command (token *switch_tok, + tree_expression *expr, + tree_switch_case_list *list, token *end_tok, octave_comment_list *lc) -{ - tree_command *retval = 0; - - bool parfor = tok_id == PARFOR; - - if (end_token_ok (end_tok, parfor ? token::parfor_end : token::for_end)) - { - expr->mark_as_for_cmd_expr (); - - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - lexer.looping--; - - int l = for_tok->line (); - int c = for_tok->column (); - - if (lhs->length () == 1) - { - tree_expression *tmp = lhs->remove_front (); - - retval = new tree_simple_for_command (parfor, tmp, expr, maxproc, - body, lc, tc, l, c); - - delete lhs; - } - else - { - if (parfor) - { - delete lhs; - delete expr; - delete maxproc; - delete body; - - bison_error ("invalid syntax for parfor statement"); - } - else - retval = new tree_complex_for_command (lhs, expr, body, - lc, tc, l, c); - } - } - else - { - delete lhs; - delete expr; - delete maxproc; - delete body; - - end_token_error (end_tok, parfor ? token::parfor_end : token::for_end); - } - - return retval; -} - -// Build a break command. - -tree_command * -octave_base_parser::make_break_command (token *break_tok) -{ - int l = break_tok->line (); - int c = break_tok->column (); - - return new tree_break_command (l, c); -} - -// Build a continue command. - -tree_command * -octave_base_parser::make_continue_command (token *continue_tok) -{ - int l = continue_tok->line (); - int c = continue_tok->column (); - - return new tree_continue_command (l, c); -} - -// Build a return command. - -tree_command * -octave_base_parser::make_return_command (token *return_tok) -{ - int l = return_tok->line (); - int c = return_tok->column (); - - return new tree_return_command (l, c); -} - -// Start an if command. - -tree_if_command_list * -octave_base_parser::start_if_command (tree_expression *expr, - tree_statement_list *list) -{ - maybe_warn_assign_as_truth_value (expr); - - tree_if_clause *t = new tree_if_clause (expr, list); - - return new tree_if_command_list (t); -} - -// Finish an if command. - -tree_if_command * -octave_base_parser::finish_if_command (token *if_tok, - tree_if_command_list *list, - token *end_tok, - octave_comment_list *lc) -{ - tree_if_command *retval = 0; - - if (end_token_ok (end_tok, token::if_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - int l = if_tok->line (); - int c = if_tok->column (); - - if (list && ! list->empty ()) - { - tree_if_clause *elt = list->front (); - - if (elt) - { - elt->line (l); - elt->column (c); - } - } - - retval = new tree_if_command (list, lc, tc, l, c); - } - else - { - delete list; - - end_token_error (end_tok, token::if_end); - } - - return retval; -} - -// Build an elseif clause. - -tree_if_clause * -octave_base_parser::make_elseif_clause (token *elseif_tok, - tree_expression *expr, - tree_statement_list *list, - octave_comment_list *lc) -{ - maybe_warn_assign_as_truth_value (expr); - - int l = elseif_tok->line (); - int c = elseif_tok->column (); - - return new tree_if_clause (expr, list, lc, l, c); -} - -// Finish a switch command. - -tree_switch_command * -octave_base_parser::finish_switch_command (token *switch_tok, - tree_expression *expr, - tree_switch_case_list *list, - token *end_tok, - octave_comment_list *lc) -{ - tree_switch_command *retval = 0; - - if (end_token_ok (end_tok, token::switch_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - int l = switch_tok->line (); - int c = switch_tok->column (); - - if (list && ! list->empty ()) - { - tree_switch_case *elt = list->front (); - - if (elt) - { - elt->line (l); - elt->column (c); - } - } - - retval = new tree_switch_command (expr, list, lc, tc, l, c); - } - else - { - delete expr; - delete list; - - end_token_error (end_tok, token::switch_end); - } - - return retval; -} - -// Build a switch case. - -tree_switch_case * -octave_base_parser::make_switch_case (token *case_tok, - tree_expression *expr, - tree_statement_list *list, - octave_comment_list *lc) -{ - maybe_warn_variable_switch_label (expr); - - int l = case_tok->line (); - int c = case_tok->column (); - - return new tree_switch_case (expr, list, lc, l, c); -} - -// Build an assignment to a variable. - -tree_expression * -octave_base_parser::make_assign_op (int op, tree_argument_list *lhs, - token *eq_tok, tree_expression *rhs) -{ - octave_value::assign_op t = octave_value::unknown_assign_op; - - switch (op) - { - case '=': - t = octave_value::op_asn_eq; - break; - - case ADD_EQ: - t = octave_value::op_add_eq; - break; - - case SUB_EQ: - t = octave_value::op_sub_eq; - break; - - case MUL_EQ: - t = octave_value::op_mul_eq; - break; - - case DIV_EQ: - t = octave_value::op_div_eq; - break; - - case LEFTDIV_EQ: - t = octave_value::op_ldiv_eq; - break; - - case POW_EQ: - t = octave_value::op_pow_eq; - break; - - case EMUL_EQ: - t = octave_value::op_el_mul_eq; - break; - - case EDIV_EQ: - t = octave_value::op_el_div_eq; - break; - - case ELEFTDIV_EQ: - t = octave_value::op_el_ldiv_eq; - break; - - case EPOW_EQ: - t = octave_value::op_el_pow_eq; - break; - - case AND_EQ: - t = octave_value::op_el_and_eq; - break; - - case OR_EQ: - t = octave_value::op_el_or_eq; - break; - - default: - panic_impossible (); - break; - } - - int l = eq_tok->line (); - int c = eq_tok->column (); - - if (! lhs->is_simple_assign_lhs () && t != octave_value::op_asn_eq) - { - // Multiple assignments like [x,y] OP= rhs are only valid for - // '=', not '+=', etc. - - delete lhs; - delete rhs; - - bison_error ("computed multiple assignment not allowed", l, c); - - return 0; - } - - if (lhs->is_simple_assign_lhs ()) - { - // We are looking at a simple assignment statement like x = rhs; - - tree_expression *tmp = lhs->remove_front (); - - if ((tmp->is_identifier () || tmp->is_index_expression ()) - && is_keyword (tmp->name ())) - { - std::string kw = tmp->name (); - - delete tmp; - delete lhs; - delete rhs; - - bison_error ("invalid assignment to keyword \"" + kw + "\"", l, c); - - return 0; - } - - delete lhs; - - return new tree_simple_assignment (tmp, rhs, false, l, c, t); - } - else - { - std::list names = lhs->variable_names (); - - for (std::list::const_iterator it = names.begin (); - it != names.end (); it++) - { - std::string kw = *it; - - if (is_keyword (kw)) - { - delete lhs; - delete rhs; - - bison_error ("invalid assignment to keyword \"" + kw + "\"", - l, c); - - return 0; - } - } - - return new tree_multi_assignment (lhs, rhs, false, l, c); - } -} - -// Define a script. - -void -octave_base_parser::make_script (tree_statement_list *cmds, - tree_statement *end_script) -{ - if (! cmds) - cmds = new tree_statement_list (); - - cmds->append (end_script); - - octave_user_script *script - = new octave_user_script (lexer.fcn_file_full_name, - lexer.fcn_file_name, - cmds, lexer.help_text); - - lexer.help_text = ""; - - octave::sys::time now; - - script->stash_fcn_file_time (now); - - primary_fcn_ptr = script; -} - -// Begin defining a function. - -octave_user_function * -octave_base_parser::start_function (tree_parameter_list *param_list, - tree_statement_list *body, - tree_statement *end_fcn_stmt) -{ - // We'll fill in the return list later. - - if (! body) - body = new tree_statement_list (); - - body->append (end_fcn_stmt); - - octave_user_function *fcn - = new octave_user_function (lexer.symtab_context.curr_scope (), - param_list, 0, body); - - if (fcn) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - fcn->stash_trailing_comment (tc); - fcn->stash_fcn_end_location (end_fcn_stmt->line (), - end_fcn_stmt->column ()); - } - - return fcn; -} - -tree_statement * -octave_base_parser::make_end (const std::string& type, bool eof, int l, int c) -{ - return make_statement (new tree_no_op_command (type, eof, l, c)); -} - -// Do most of the work for defining a function. - -octave_user_function * -octave_base_parser::frob_function (const std::string& fname, - octave_user_function *fcn) -{ - std::string id_name = fname; - - // If input is coming from a file, issue a warning if the name of - // the file does not match the name of the function stated in the - // file. Matlab doesn't provide a diagnostic (it ignores the stated - // name). - if (! autoloading && lexer.reading_fcn_file - && curr_fcn_depth == 1 && ! parsing_subfunctions) + { + tree_switch_command *retval = 0; + + if (end_token_ok (end_tok, token::switch_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = switch_tok->line (); + int c = switch_tok->column (); + + if (list && ! list->empty ()) + { + tree_switch_case *elt = list->front (); + + if (elt) + { + elt->line (l); + elt->column (c); + } + } + + retval = new tree_switch_command (expr, list, lc, tc, l, c); + } + else + { + delete expr; + delete list; + + end_token_error (end_tok, token::switch_end); + } + + return retval; + } + + // Build a switch case. + + tree_switch_case * + base_parser::make_switch_case (token *case_tok, + tree_expression *expr, + tree_statement_list *list, + octave_comment_list *lc) + { + maybe_warn_variable_switch_label (expr); + + int l = case_tok->line (); + int c = case_tok->column (); + + return new tree_switch_case (expr, list, lc, l, c); + } + + // Build an assignment to a variable. + + tree_expression * + base_parser::make_assign_op (int op, tree_argument_list *lhs, + token *eq_tok, tree_expression *rhs) + { + octave_value::assign_op t = octave_value::unknown_assign_op; + + switch (op) + { + case '=': + t = octave_value::op_asn_eq; + break; + + case ADD_EQ: + t = octave_value::op_add_eq; + break; + + case SUB_EQ: + t = octave_value::op_sub_eq; + break; + + case MUL_EQ: + t = octave_value::op_mul_eq; + break; + + case DIV_EQ: + t = octave_value::op_div_eq; + break; + + case LEFTDIV_EQ: + t = octave_value::op_ldiv_eq; + break; + + case POW_EQ: + t = octave_value::op_pow_eq; + break; + + case EMUL_EQ: + t = octave_value::op_el_mul_eq; + break; + + case EDIV_EQ: + t = octave_value::op_el_div_eq; + break; + + case ELEFTDIV_EQ: + t = octave_value::op_el_ldiv_eq; + break; + + case EPOW_EQ: + t = octave_value::op_el_pow_eq; + break; + + case AND_EQ: + t = octave_value::op_el_and_eq; + break; + + case OR_EQ: + t = octave_value::op_el_or_eq; + break; + + default: + panic_impossible (); + break; + } + + int l = eq_tok->line (); + int c = eq_tok->column (); + + if (! lhs->is_simple_assign_lhs () && t != octave_value::op_asn_eq) + { + // Multiple assignments like [x,y] OP= rhs are only valid for + // '=', not '+=', etc. + + delete lhs; + delete rhs; + + bison_error ("computed multiple assignment not allowed", l, c); + + return 0; + } + + if (lhs->is_simple_assign_lhs ()) + { + // We are looking at a simple assignment statement like x = rhs; + + tree_expression *tmp = lhs->remove_front (); + + if ((tmp->is_identifier () || tmp->is_index_expression ()) + && is_keyword (tmp->name ())) + { + std::string kw = tmp->name (); + + delete tmp; + delete lhs; + delete rhs; + + bison_error ("invalid assignment to keyword \"" + kw + "\"", l, c); + + return 0; + } + + delete lhs; + + return new tree_simple_assignment (tmp, rhs, false, l, c, t); + } + else + { + std::list names = lhs->variable_names (); + + for (std::list::const_iterator it = names.begin (); + it != names.end (); it++) + { + std::string kw = *it; + + if (is_keyword (kw)) + { + delete lhs; + delete rhs; + + bison_error ("invalid assignment to keyword \"" + kw + "\"", + l, c); + + return 0; + } + } + + return new tree_multi_assignment (lhs, rhs, false, l, c); + } + } + + // Define a script. + + void + base_parser::make_script (tree_statement_list *cmds, + tree_statement *end_script) + { + if (! cmds) + cmds = new tree_statement_list (); + + cmds->append (end_script); + + octave_user_script *script + = new octave_user_script (lexer.fcn_file_full_name, + lexer.fcn_file_name, + cmds, lexer.help_text); + + lexer.help_text = ""; + + octave::sys::time now; + + script->stash_fcn_file_time (now); + + primary_fcn_ptr = script; + } + + // Begin defining a function. + + octave_user_function * + base_parser::start_function (tree_parameter_list *param_list, + tree_statement_list *body, + tree_statement *end_fcn_stmt) { - // FIXME: should lexer.fcn_file_name already be - // preprocessed when we get here? It seems to only be a - // problem with relative filenames. + // We'll fill in the return list later. + + if (! body) + body = new tree_statement_list (); + + body->append (end_fcn_stmt); + + octave_user_function *fcn + = new octave_user_function (lexer.symtab_context.curr_scope (), + param_list, 0, body); + + if (fcn) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + fcn->stash_trailing_comment (tc); + fcn->stash_fcn_end_location (end_fcn_stmt->line (), + end_fcn_stmt->column ()); + } + + return fcn; + } + + tree_statement * + base_parser::make_end (const std::string& type, bool eof, int l, int c) + { + return make_statement (new tree_no_op_command (type, eof, l, c)); + } + + // Do most of the work for defining a function. + + octave_user_function * + base_parser::frob_function (const std::string& fname, + octave_user_function *fcn) + { + std::string id_name = fname; + + // If input is coming from a file, issue a warning if the name of + // the file does not match the name of the function stated in the + // file. Matlab doesn't provide a diagnostic (it ignores the stated + // name). + if (! autoloading && lexer.reading_fcn_file + && curr_fcn_depth == 1 && ! parsing_subfunctions) + { + // FIXME: should lexer.fcn_file_name already be + // preprocessed when we get here? It seems to only be a + // problem with relative filenames. + + std::string nm = lexer.fcn_file_name; + + size_t pos = nm.find_last_of (octave::sys::file_ops::dir_sep_chars ()); + + if (pos != std::string::npos) + nm = lexer.fcn_file_name.substr (pos+1); + + if (nm != id_name) + { + warning_with_id + ("Octave:function-name-clash", + "function name '%s' does not agree with function filename '%s'", + id_name.c_str (), lexer.fcn_file_full_name.c_str ()); + + id_name = nm; + } + } + + if (lexer.reading_fcn_file || lexer.reading_classdef_file || autoloading) + { + octave::sys::time now; + + fcn->stash_fcn_file_name (lexer.fcn_file_full_name); + fcn->stash_fcn_file_time (now); + fcn->mark_as_system_fcn_file (); + + if (fcn_file_from_relative_lookup) + fcn->mark_relative (); + + if (curr_fcn_depth > 1 || parsing_subfunctions) + { + fcn->stash_parent_fcn_name (lexer.fcn_file_name); + + if (curr_fcn_depth > 1) + fcn->stash_parent_fcn_scope (function_scopes[function_scopes.size ()-2]); + else + fcn->stash_parent_fcn_scope (primary_fcn_scope); + } + + if (lexer.parsing_class_method) + { + if (curr_class_name == id_name) + fcn->mark_as_class_constructor (); + else + fcn->mark_as_class_method (); + + fcn->stash_dispatch_class (curr_class_name); + } + + std::string nm = fcn->fcn_file_name (); + + octave::sys::file_stat fs (nm); + + if (fs && fs.is_newer (now)) + warning_with_id ("Octave:future-time-stamp", + "time stamp for '%s' is in the future", nm.c_str ()); + } + else if (! input_from_tmp_history_file + && ! lexer.force_script + && lexer.reading_script_file + && lexer.fcn_file_name == id_name) + { + warning ("function '%s' defined within script file '%s'", + id_name.c_str (), lexer.fcn_file_full_name.c_str ()); + } + + fcn->stash_function_name (id_name); + + if (! lexer.help_text.empty () && curr_fcn_depth == 1 + && ! parsing_subfunctions) + { + fcn->document (lexer.help_text); + + lexer.help_text = ""; + } + + if (lexer.reading_fcn_file && curr_fcn_depth == 1 + && ! parsing_subfunctions) + primary_fcn_ptr = fcn; + + return fcn; + } + + tree_function_def * + base_parser::finish_function (tree_parameter_list *ret_list, + octave_user_function *fcn, + octave_comment_list *lc, + int l, int c) + { + tree_function_def *retval = 0; + + if (ret_list) + ret_list->mark_as_formal_parameters (); + + if (fcn) + { + std::string nm = fcn->name (); + std::string file = fcn->fcn_file_name (); + + std::string tmp = nm; + if (! file.empty ()) + tmp += ": " + file; + + symbol_table::cache_name (fcn->scope (), tmp); + + if (lc) + fcn->stash_leading_comment (lc); + + fcn->define_ret_list (ret_list); + + if (curr_fcn_depth > 1 || parsing_subfunctions) + { + fcn->mark_as_subfunction (); + fcn->stash_fcn_location (l, c); + + subfunction_names.push_back (nm); + + if (endfunction_found && function_scopes.size () > 1) + { + symbol_table::scope_id pscope + = function_scopes[function_scopes.size ()-2]; + + symbol_table::install_nestfunction (nm, octave_value (fcn), + pscope); + } + else + symbol_table::install_subfunction (nm, octave_value (fcn), + primary_fcn_scope); + } + + if (curr_fcn_depth == 1 && fcn) + symbol_table::update_nest (fcn->scope ()); + + if (! lexer.reading_fcn_file && curr_fcn_depth == 1) + { + // We are either reading a script file or defining a function + // at the command line, so this definition creates a + // tree_function object that is placed in the parse tree. + // Otherwise, it is just inserted in the symbol table, + // either as a subfunction or nested function (see above), + // or as the primary function for the file, via + // primary_fcn_ptr (see also load_fcn_from_file,, + // parse_fcn_file, and + // symbol_table::fcn_info::fcn_info_rep::find_user_function). + + retval = new tree_function_def (fcn); + } + } + + return retval; + } + + void + base_parser::recover_from_parsing_function (void) + { + lexer.symtab_context.pop (); + + if (lexer.reading_fcn_file && curr_fcn_depth == 1 + && ! parsing_subfunctions) + parsing_subfunctions = true; + + curr_fcn_depth--; + function_scopes.pop_back (); + + lexer.defining_func--; + lexer.parsed_function_name.pop (); + lexer.looking_at_return_list = false; + lexer.looking_at_parameter_list = false; + } + + tree_funcall * + base_parser::make_superclass_ref (const std::string& method_nm, + const std::string& class_nm) + { + octave_value_list args; + + args(1) = class_nm; + args(0) = method_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__superclass_reference__"); + + return new tree_funcall (fcn, args); + } + + tree_funcall * + base_parser::make_meta_class_query (const std::string& class_nm) + { + octave_value_list args; + + args(0) = class_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__meta_class_query__"); + + return new tree_funcall (fcn, args); + } + + // A CLASSDEF block defines a class that has a constructor and other + // methods, but it is not an executable command. Parsing the block + // makes some changes in the symbol table (inserting the constructor + // and methods, and adding to the list of known objects) and creates + // a parse tree containing meta information about the class. + + tree_classdef * + base_parser::make_classdef (token *tok_val, + tree_classdef_attribute_list *a, + tree_identifier *id, + tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc) + { + tree_classdef *retval = 0; + + std::string cls_name = id->name (); std::string nm = lexer.fcn_file_name; @@ -3156,969 +3374,754 @@ if (pos != std::string::npos) nm = lexer.fcn_file_name.substr (pos+1); - if (nm != id_name) + if (nm != cls_name) + { + delete a; + delete id; + delete sc; + delete body; + + bison_error ("invalid classdef definition, the class name must match the filename"); + + } + else + { + if (end_token_ok (end_tok, token::classdef_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! body) + body = new tree_classdef_body (); + + retval = new tree_classdef (a, id, sc, body, lc, tc, + curr_package_name, l, c); + } + else + { + delete a; + delete id; + delete sc; + delete body; + + end_token_error (end_tok, token::switch_end); + } + } + + return retval; + } + + tree_classdef_properties_block * + base_parser::make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, + octave_comment_list *lc) + { + tree_classdef_properties_block *retval = 0; + + if (end_token_ok (end_tok, token::properties_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! plist) + plist = new tree_classdef_property_list (); + + retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c); + } + else + { + delete a; + delete plist; + + end_token_error (end_tok, token::properties_end); + } + + return retval; + } + + tree_classdef_methods_block * + base_parser::make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, + octave_comment_list *lc) + { + tree_classdef_methods_block *retval = 0; + + if (end_token_ok (end_tok, token::methods_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! mlist) + mlist = new tree_classdef_methods_list (); + + retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c); + } + else + { + delete a; + delete mlist; + + end_token_error (end_tok, token::methods_end); + } + + return retval; + } + + tree_classdef_events_block * + base_parser::make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, + octave_comment_list *lc) + { + tree_classdef_events_block *retval = 0; + + if (end_token_ok (end_tok, token::events_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! elist) + elist = new tree_classdef_events_list (); + + retval = new tree_classdef_events_block (a, elist, lc, tc, l, c); + } + else + { + delete a; + delete elist; + + end_token_error (end_tok, token::events_end); + } + + return retval; + } + + tree_classdef_enum_block * + base_parser::make_classdef_enum_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + token *end_tok, + octave_comment_list *lc) + { + tree_classdef_enum_block *retval = 0; + + if (end_token_ok (end_tok, token::enumeration_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! elist) + elist = new tree_classdef_enum_list (); + + retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c); + } + else + { + delete a; + delete elist; + + end_token_error (end_tok, token::enumeration_end); + } + + return retval; + } + + octave_user_function* + base_parser::start_classdef_external_method (tree_identifier *id, + tree_parameter_list *pl) + { + octave_user_function* retval = 0; + + // External methods are only allowed within @-folders. In this case, + // curr_class_name will be non-empty. + + if (! curr_class_name.empty ()) + { + + std::string mname = id->name (); + + // Methods that cannot be declared outside the classdef file: + // - methods with '.' character (e.g. property accessors) + // - class constructor + // - `delete' + + if (mname.find_first_of (".") == std::string::npos + && mname != "delete" + && mname != curr_class_name) + { + // Create a dummy function that is used until the real method + // is loaded. + + retval = new octave_user_function (-1, pl); + + retval->stash_function_name (mname); + + int l = id->line (); + int c = id->column (); + + retval->stash_fcn_location (l, c); + } + else + bison_error ("invalid external method declaration, an external " + "method cannot be the class constructor, `delete' " + "or have a dot (.) character in its name"); + } + else + bison_error ("external methods are only allowed in @-folders"); + + if (! retval) + delete id; + + return retval; + } + + tree_function_def * + base_parser::finish_classdef_external_method (octave_user_function *fcn, + tree_parameter_list *ret_list, + octave_comment_list *cl) + { + if (ret_list) + fcn->define_ret_list (ret_list); + + if (cl) + fcn->stash_leading_comment (cl); + + int l = fcn->beginning_line (); + int c = fcn->beginning_column (); + + return new tree_function_def (fcn, l, c); + } + + // Make an index expression. + + tree_index_expression * + base_parser::make_index_expression (tree_expression *expr, + tree_argument_list *args, + char type) + { + tree_index_expression *retval = 0; + + if (args && args->has_magic_tilde ()) + { + delete expr; + delete args; + + bison_error ("invalid use of empty argument (~) in index expression"); + } + else { - warning_with_id - ("Octave:function-name-clash", - "function name '%s' does not agree with function filename '%s'", - id_name.c_str (), lexer.fcn_file_full_name.c_str ()); - - id_name = nm; + int l = expr->line (); + int c = expr->column (); + + if (! expr->is_postfix_indexed ()) + expr->set_postfix_index (type); + + if (expr->is_index_expression ()) + { + tree_index_expression *tmp = + static_cast (expr); + + tmp->append (args, type); + + retval = tmp; + } + else + retval = new tree_index_expression (expr, args, l, c, type); + } + + return retval; + } + + // Make an indirect reference expression. + + tree_index_expression * + base_parser::make_indirect_ref (tree_expression *expr, + const std::string& elt) + { + tree_index_expression *retval = 0; + + int l = expr->line (); + int c = expr->column (); + + if (! expr->is_postfix_indexed ()) + expr->set_postfix_index ('.'); + + if (expr->is_index_expression ()) + { + tree_index_expression *tmp = static_cast (expr); + + tmp->append (elt); + + retval = tmp; + } + else + retval = new tree_index_expression (expr, elt, l, c); + + lexer.looking_at_indirect_ref = false; + + return retval; + } + + // Make an indirect reference expression with dynamic field name. + + tree_index_expression * + base_parser::make_indirect_ref (tree_expression *expr, + tree_expression *elt) + { + tree_index_expression *retval = 0; + + int l = expr->line (); + int c = expr->column (); + + if (! expr->is_postfix_indexed ()) + expr->set_postfix_index ('.'); + + if (expr->is_index_expression ()) + { + tree_index_expression *tmp = static_cast (expr); + + tmp->append (elt); + + retval = tmp; + } + else + retval = new tree_index_expression (expr, elt, l, c); + + lexer.looking_at_indirect_ref = false; + + return retval; + } + + // Make a declaration command. + + tree_decl_command * + base_parser::make_decl_command (int tok, token *tok_val, + tree_decl_init_list *lst) + { + tree_decl_command *retval = 0; + + int l = tok_val->line (); + int c = tok_val->column (); + + switch (tok) + { + case GLOBAL: + retval = new tree_global_command (lst, l, c); + break; + + case PERSISTENT: + if (curr_fcn_depth > 0) + retval = new tree_persistent_command (lst, l, c); + else + { + if (lexer.reading_script_file) + warning ("ignoring persistent declaration near line %d of file '%s'", + l, lexer.fcn_file_full_name.c_str ()); + else + warning ("ignoring persistent declaration near line %d", l); + } + break; + + default: + panic_impossible (); + break; + } + + return retval; + } + + bool + base_parser::validate_array_list (tree_expression *e) + { + bool retval = true; + + tree_array_list *al = dynamic_cast (e); + + for (tree_array_list::iterator i = al->begin (); i != al->end (); i++) + { + tree_argument_list *row = *i; + + if (row && row->has_magic_tilde ()) + { + retval = false; + + if (e->is_matrix ()) + bison_error ("invalid use of tilde (~) in matrix expression"); + else + bison_error ("invalid use of tilde (~) in cell expression"); + + break; + } + } + + return retval; + } + + tree_argument_list * + base_parser::validate_matrix_for_assignment (tree_expression *e) + { + tree_argument_list *retval = 0; + + if (e->is_constant ()) + { + octave_value ov = e->rvalue1 (); + + delete e; + + if (ov.is_empty ()) + bison_error ("invalid empty left hand side of assignment"); + else + bison_error ("invalid constant left hand side of assignment"); + } + else + { + bool is_simple_assign = true; + + tree_argument_list *tmp = 0; + + if (e->is_matrix ()) + { + tree_matrix *mat = dynamic_cast (e); + + if (mat && mat->size () == 1) + { + tmp = mat->front (); + mat->pop_front (); + delete e; + is_simple_assign = false; + } + } + else + tmp = new tree_argument_list (e); + + if (tmp && tmp->is_valid_lvalue_list ()) + { + lexer.mark_as_variables (tmp->variable_names ()); + retval = tmp; + } + else + { + delete tmp; + + bison_error ("invalid left hand side of assignment"); + } + + if (retval && is_simple_assign) + retval->mark_as_simple_assign_lhs (); + } + + return retval; + } + + // Finish building an array_list. + + tree_expression * + base_parser::finish_array_list (tree_array_list *array_list) + { + tree_expression *retval = array_list; + + octave::unwind_protect frame; + + frame.protect_var (discard_error_messages); + frame.protect_var (discard_warning_messages); + + discard_error_messages = true; + discard_warning_messages = true; + + if (array_list->all_elements_are_constant ()) + { + try + { + octave_value tmp = array_list->rvalue1 (); + + tree_constant *tc_retval + = new tree_constant (tmp, array_list->line (), + array_list->column ()); + + std::ostringstream buf; + + tree_print_code tpc (buf); + + array_list->accept (tpc); + + tc_retval->stash_original_text (buf.str ()); + + delete array_list; + + retval = tc_retval; + } + catch (const octave_execution_exception&) + { + recover_from_exception (); + } + } + + return retval; + } + + // Finish building a matrix list. + + tree_expression * + base_parser::finish_matrix (tree_matrix *m) + { + return (m + ? finish_array_list (m) + : new tree_constant (octave_null_matrix::instance)); + } + + // Finish building a cell list. + + tree_expression * + base_parser::finish_cell (tree_cell *c) + { + return (c + ? finish_array_list (c) + : new tree_constant (octave_value (Cell ()))); + } + + void + base_parser::maybe_warn_missing_semi (tree_statement_list *t) + { + if (curr_fcn_depth > 0) + { + tree_statement *tmp = t->back (); + + if (tmp->is_expression ()) + warning_with_id + ("Octave:missing-semicolon", + "missing semicolon near line %d, column %d in file '%s'", + tmp->line (), tmp->column (), lexer.fcn_file_full_name.c_str ()); } } - if (lexer.reading_fcn_file || lexer.reading_classdef_file || autoloading) - { - octave::sys::time now; - - fcn->stash_fcn_file_name (lexer.fcn_file_full_name); - fcn->stash_fcn_file_time (now); - fcn->mark_as_system_fcn_file (); - - if (fcn_file_from_relative_lookup) - fcn->mark_relative (); - - if (curr_fcn_depth > 1 || parsing_subfunctions) - { - fcn->stash_parent_fcn_name (lexer.fcn_file_name); - - if (curr_fcn_depth > 1) - fcn->stash_parent_fcn_scope (function_scopes[function_scopes.size ()-2]); - else - fcn->stash_parent_fcn_scope (primary_fcn_scope); - } - - if (lexer.parsing_class_method) - { - if (curr_class_name == id_name) - fcn->mark_as_class_constructor (); - else - fcn->mark_as_class_method (); - - fcn->stash_dispatch_class (curr_class_name); - } - - std::string nm = fcn->fcn_file_name (); - - octave::sys::file_stat fs (nm); - - if (fs && fs.is_newer (now)) - warning_with_id ("Octave:future-time-stamp", - "time stamp for '%s' is in the future", nm.c_str ()); - } - else if (! input_from_tmp_history_file - && ! lexer.force_script - && lexer.reading_script_file - && lexer.fcn_file_name == id_name) - { - warning ("function '%s' defined within script file '%s'", - id_name.c_str (), lexer.fcn_file_full_name.c_str ()); - } - - fcn->stash_function_name (id_name); - - if (! lexer.help_text.empty () && curr_fcn_depth == 1 - && ! parsing_subfunctions) - { - fcn->document (lexer.help_text); - - lexer.help_text = ""; - } - - if (lexer.reading_fcn_file && curr_fcn_depth == 1 - && ! parsing_subfunctions) - primary_fcn_ptr = fcn; - - return fcn; -} - -tree_function_def * -octave_base_parser::finish_function (tree_parameter_list *ret_list, - octave_user_function *fcn, - octave_comment_list *lc, - int l, int c) -{ - tree_function_def *retval = 0; - - if (ret_list) - ret_list->mark_as_formal_parameters (); - - if (fcn) - { - std::string nm = fcn->name (); - std::string file = fcn->fcn_file_name (); - - std::string tmp = nm; - if (! file.empty ()) - tmp += ": " + file; - - symbol_table::cache_name (fcn->scope (), tmp); - - if (lc) - fcn->stash_leading_comment (lc); - - fcn->define_ret_list (ret_list); - - if (curr_fcn_depth > 1 || parsing_subfunctions) - { - fcn->mark_as_subfunction (); - fcn->stash_fcn_location (l, c); - - subfunction_names.push_back (nm); - - if (endfunction_found && function_scopes.size () > 1) - { - symbol_table::scope_id pscope - = function_scopes[function_scopes.size ()-2]; - - symbol_table::install_nestfunction (nm, octave_value (fcn), - pscope); - } - else - symbol_table::install_subfunction (nm, octave_value (fcn), - primary_fcn_scope); - } - - if (curr_fcn_depth == 1 && fcn) - symbol_table::update_nest (fcn->scope ()); - - if (! lexer.reading_fcn_file && curr_fcn_depth == 1) - { - // We are either reading a script file or defining a function - // at the command line, so this definition creates a - // tree_function object that is placed in the parse tree. - // Otherwise, it is just inserted in the symbol table, - // either as a subfunction or nested function (see above), - // or as the primary function for the file, via - // primary_fcn_ptr (see also load_fcn_from_file,, - // parse_fcn_file, and - // symbol_table::fcn_info::fcn_info_rep::find_user_function). - - retval = new tree_function_def (fcn); - } - } - - return retval; -} - -void -octave_base_parser::recover_from_parsing_function (void) -{ - lexer.symtab_context.pop (); - - if (lexer.reading_fcn_file && curr_fcn_depth == 1 - && ! parsing_subfunctions) - parsing_subfunctions = true; - - curr_fcn_depth--; - function_scopes.pop_back (); - - lexer.defining_func--; - lexer.parsed_function_name.pop (); - lexer.looking_at_return_list = false; - lexer.looking_at_parameter_list = false; -} - -tree_funcall * -octave_base_parser::make_superclass_ref (const std::string& method_nm, - const std::string& class_nm) -{ - octave_value_list args; - - args(1) = class_nm; - args(0) = method_nm; - - octave_value fcn - = symbol_table::find_built_in_function ("__superclass_reference__"); - - return new tree_funcall (fcn, args); -} - -tree_funcall * -octave_base_parser::make_meta_class_query (const std::string& class_nm) -{ - octave_value_list args; - - args(0) = class_nm; - - octave_value fcn - = symbol_table::find_built_in_function ("__meta_class_query__"); - - return new tree_funcall (fcn, args); -} - -// A CLASSDEF block defines a class that has a constructor and other -// methods, but it is not an executable command. Parsing the block -// makes some changes in the symbol table (inserting the constructor -// and methods, and adding to the list of known objects) and creates -// a parse tree containing meta information about the class. - -tree_classdef * -octave_base_parser::make_classdef (token *tok_val, - tree_classdef_attribute_list *a, - tree_identifier *id, - tree_classdef_superclass_list *sc, - tree_classdef_body *body, token *end_tok, - octave_comment_list *lc) -{ - tree_classdef *retval = 0; - - std::string cls_name = id->name (); - - std::string nm = lexer.fcn_file_name; - - size_t pos = nm.find_last_of (octave::sys::file_ops::dir_sep_chars ()); - - if (pos != std::string::npos) - nm = lexer.fcn_file_name.substr (pos+1); - - if (nm != cls_name) - { - delete a; - delete id; - delete sc; - delete body; - - bison_error ("invalid classdef definition, the class name must match the filename"); - - } - else - { - if (end_token_ok (end_tok, token::classdef_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - if (! body) - body = new tree_classdef_body (); - - retval = new tree_classdef (a, id, sc, body, lc, tc, - curr_package_name, l, c); - } - else - { - delete a; - delete id; - delete sc; - delete body; - - end_token_error (end_tok, token::switch_end); - } - } - - return retval; -} - -tree_classdef_properties_block * -octave_base_parser::make_classdef_properties_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_property_list *plist, - token *end_tok, - octave_comment_list *lc) -{ - tree_classdef_properties_block *retval = 0; - - if (end_token_ok (end_tok, token::properties_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - if (! plist) - plist = new tree_classdef_property_list (); - - retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c); - } - else - { - delete a; - delete plist; - - end_token_error (end_tok, token::properties_end); - } - - return retval; -} - -tree_classdef_methods_block * -octave_base_parser::make_classdef_methods_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_methods_list *mlist, - token *end_tok, - octave_comment_list *lc) -{ - tree_classdef_methods_block *retval = 0; - - if (end_token_ok (end_tok, token::methods_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - if (! mlist) - mlist = new tree_classdef_methods_list (); - - retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c); - } - else - { - delete a; - delete mlist; - - end_token_error (end_tok, token::methods_end); - } - - return retval; -} - -tree_classdef_events_block * -octave_base_parser::make_classdef_events_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_events_list *elist, - token *end_tok, - octave_comment_list *lc) -{ - tree_classdef_events_block *retval = 0; - - if (end_token_ok (end_tok, token::events_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - if (! elist) - elist = new tree_classdef_events_list (); - - retval = new tree_classdef_events_block (a, elist, lc, tc, l, c); - } - else - { - delete a; - delete elist; - - end_token_error (end_tok, token::events_end); - } - - return retval; -} - -tree_classdef_enum_block * -octave_base_parser::make_classdef_enum_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_enum_list *elist, - token *end_tok, - octave_comment_list *lc) -{ - tree_classdef_enum_block *retval = 0; - - if (end_token_ok (end_tok, token::enumeration_end)) - { - octave_comment_list *tc = lexer.comment_buf.get_comment (); - - int l = tok_val->line (); - int c = tok_val->column (); - - if (! elist) - elist = new tree_classdef_enum_list (); - - retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c); - } - else - { - delete a; - delete elist; - - end_token_error (end_tok, token::enumeration_end); - } - - return retval; -} - -octave_user_function* -octave_base_parser::start_classdef_external_method (tree_identifier *id, - tree_parameter_list *pl) -{ - octave_user_function* retval = 0; - - // External methods are only allowed within @-folders. In this case, - // curr_class_name will be non-empty. - - if (! curr_class_name.empty ()) - { - - std::string mname = id->name (); - - // Methods that cannot be declared outside the classdef file: - // - methods with '.' character (e.g. property accessors) - // - class constructor - // - `delete' - - if (mname.find_first_of (".") == std::string::npos - && mname != "delete" - && mname != curr_class_name) - { - // Create a dummy function that is used until the real method - // is loaded. - - retval = new octave_user_function (-1, pl); - - retval->stash_function_name (mname); - - int l = id->line (); - int c = id->column (); - - retval->stash_fcn_location (l, c); - } - else - bison_error ("invalid external method declaration, an external " - "method cannot be the class constructor, `delete' " - "or have a dot (.) character in its name"); - } - else - bison_error ("external methods are only allowed in @-folders"); - - if (! retval) - delete id; - - return retval; -} - -tree_function_def * -octave_base_parser::finish_classdef_external_method (octave_user_function *fcn, - tree_parameter_list *ret_list, - octave_comment_list *cl) -{ - if (ret_list) - fcn->define_ret_list (ret_list); - - if (cl) - fcn->stash_leading_comment (cl); - - int l = fcn->beginning_line (); - int c = fcn->beginning_column (); - - return new tree_function_def (fcn, l, c); -} - -// Make an index expression. - -tree_index_expression * -octave_base_parser::make_index_expression (tree_expression *expr, - tree_argument_list *args, - char type) -{ - tree_index_expression *retval = 0; - - if (args && args->has_magic_tilde ()) - { - delete expr; - delete args; - - bison_error ("invalid use of empty argument (~) in index expression"); - } - else - { - int l = expr->line (); - int c = expr->column (); - - if (! expr->is_postfix_indexed ()) - expr->set_postfix_index (type); - - if (expr->is_index_expression ()) - { - tree_index_expression *tmp = - static_cast (expr); - - tmp->append (args, type); - - retval = tmp; - } - else - retval = new tree_index_expression (expr, args, l, c, type); - } - - return retval; -} - -// Make an indirect reference expression. - -tree_index_expression * -octave_base_parser::make_indirect_ref (tree_expression *expr, - const std::string& elt) -{ - tree_index_expression *retval = 0; - - int l = expr->line (); - int c = expr->column (); - - if (! expr->is_postfix_indexed ()) - expr->set_postfix_index ('.'); - - if (expr->is_index_expression ()) - { - tree_index_expression *tmp = static_cast (expr); - - tmp->append (elt); - - retval = tmp; - } - else - retval = new tree_index_expression (expr, elt, l, c); - - lexer.looking_at_indirect_ref = false; - - return retval; -} - -// Make an indirect reference expression with dynamic field name. - -tree_index_expression * -octave_base_parser::make_indirect_ref (tree_expression *expr, - tree_expression *elt) -{ - tree_index_expression *retval = 0; - - int l = expr->line (); - int c = expr->column (); - - if (! expr->is_postfix_indexed ()) - expr->set_postfix_index ('.'); - - if (expr->is_index_expression ()) - { - tree_index_expression *tmp = static_cast (expr); - - tmp->append (elt); - - retval = tmp; - } - else - retval = new tree_index_expression (expr, elt, l, c); - - lexer.looking_at_indirect_ref = false; - - return retval; -} - -// Make a declaration command. - -tree_decl_command * -octave_base_parser::make_decl_command (int tok, token *tok_val, - tree_decl_init_list *lst) -{ - tree_decl_command *retval = 0; - - int l = tok_val->line (); - int c = tok_val->column (); - - switch (tok) - { - case GLOBAL: - retval = new tree_global_command (lst, l, c); - break; - - case PERSISTENT: - if (curr_fcn_depth > 0) - retval = new tree_persistent_command (lst, l, c); - else - { - if (lexer.reading_script_file) - warning ("ignoring persistent declaration near line %d of file '%s'", - l, lexer.fcn_file_full_name.c_str ()); - else - warning ("ignoring persistent declaration near line %d", l); - } - break; - - default: - panic_impossible (); - break; - } - - return retval; -} - -bool -octave_base_parser::validate_array_list (tree_expression *e) -{ - bool retval = true; - - tree_array_list *al = dynamic_cast (e); - - for (tree_array_list::iterator i = al->begin (); i != al->end (); i++) - { - tree_argument_list *row = *i; - - if (row && row->has_magic_tilde ()) - { - retval = false; - - if (e->is_matrix ()) - bison_error ("invalid use of tilde (~) in matrix expression"); - else - bison_error ("invalid use of tilde (~) in cell expression"); - - break; - } - } - - return retval; -} - -tree_argument_list * -octave_base_parser::validate_matrix_for_assignment (tree_expression *e) -{ - tree_argument_list *retval = 0; - - if (e->is_constant ()) - { - octave_value ov = e->rvalue1 (); - - delete e; - - if (ov.is_empty ()) - bison_error ("invalid empty left hand side of assignment"); - else - bison_error ("invalid constant left hand side of assignment"); - } - else - { - bool is_simple_assign = true; - - tree_argument_list *tmp = 0; - - if (e->is_matrix ()) - { - tree_matrix *mat = dynamic_cast (e); - - if (mat && mat->size () == 1) - { - tmp = mat->front (); - mat->pop_front (); - delete e; - is_simple_assign = false; - } - } - else - tmp = new tree_argument_list (e); - - if (tmp && tmp->is_valid_lvalue_list ()) - { - lexer.mark_as_variables (tmp->variable_names ()); - retval = tmp; - } - else - { - delete tmp; - - bison_error ("invalid left hand side of assignment"); - } - - if (retval && is_simple_assign) - retval->mark_as_simple_assign_lhs (); - } - - return retval; -} - -// Finish building an array_list. - -tree_expression * -octave_base_parser::finish_array_list (tree_array_list *array_list) -{ - tree_expression *retval = array_list; - - octave::unwind_protect frame; - - frame.protect_var (discard_error_messages); - frame.protect_var (discard_warning_messages); - - discard_error_messages = true; - discard_warning_messages = true; - - if (array_list->all_elements_are_constant ()) - { - try - { - octave_value tmp = array_list->rvalue1 (); - - tree_constant *tc_retval - = new tree_constant (tmp, array_list->line (), - array_list->column ()); - - std::ostringstream buf; - - tree_print_code tpc (buf); - - array_list->accept (tpc); - - tc_retval->stash_original_text (buf.str ()); - - delete array_list; - - retval = tc_retval; - } - catch (const octave_execution_exception&) - { - recover_from_exception (); - } - } - - return retval; -} - -// Finish building a matrix list. - -tree_expression * -octave_base_parser::finish_matrix (tree_matrix *m) -{ - return (m - ? finish_array_list (m) - : new tree_constant (octave_null_matrix::instance)); -} - -// Finish building a cell list. - -tree_expression * -octave_base_parser::finish_cell (tree_cell *c) -{ - return (c - ? finish_array_list (c) - : new tree_constant (octave_value (Cell ()))); -} - -void -octave_base_parser::maybe_warn_missing_semi (tree_statement_list *t) -{ - if (curr_fcn_depth > 0) - { - tree_statement *tmp = t->back (); - - if (tmp->is_expression ()) - warning_with_id - ("Octave:missing-semicolon", - "missing semicolon near line %d, column %d in file '%s'", - tmp->line (), tmp->column (), lexer.fcn_file_full_name.c_str ()); - } -} - -tree_statement_list * -octave_base_parser::set_stmt_print_flag (tree_statement_list *list, - char sep, bool warn_missing_semi) -{ - tree_statement *tmp = list->back (); - - switch (sep) - { - case ';': - tmp->set_print_flag (false); - break; - - case 0: - case ',': - case '\n': - tmp->set_print_flag (true); - if (warn_missing_semi) - maybe_warn_missing_semi (list); - break; - - default: - warning ("unrecognized separator type!"); - break; - } - - // Even if a statement is null, we add it to the list then remove it - // here so that the print flag is applied to the correct statement. - - if (tmp->is_null_statement ()) - { - list->pop_back (); - delete tmp; - } - - return list; -} - -// Finish building a statement. -template -tree_statement * -octave_base_parser::make_statement (T *arg) -{ - octave_comment_list *comment = lexer.get_comment (); - - return new tree_statement (arg, comment); -} - -tree_statement_list * -octave_base_parser::make_statement_list (tree_statement *stmt) -{ - return new tree_statement_list (stmt); -} - -tree_statement_list * -octave_base_parser::append_statement_list (tree_statement_list *list, - char sep, tree_statement *stmt, - bool warn_missing_semi) -{ - set_stmt_print_flag (list, sep, warn_missing_semi); - - list->append (stmt); - - return list; -} - -void -octave_base_parser::bison_error (const std::string& str, int l, int c) -{ - int err_line = l < 0 ? lexer.input_line_number : l; - int err_col = c < 0 ? lexer.current_input_column - 1 : c; - - std::ostringstream output_buf; - - if (lexer.reading_fcn_file || lexer.reading_script_file - || lexer.reading_classdef_file) - output_buf << "parse error near line " << err_line - << " of file " << lexer.fcn_file_full_name; - else - output_buf << "parse error:"; - - if (str != "parse error") - output_buf << "\n\n " << str; - - output_buf << "\n\n"; - - std::string curr_line = lexer.current_input_line; - - if (! curr_line.empty ()) - { - size_t len = curr_line.length (); - - if (curr_line[len-1] == '\n') - curr_line.resize (len-1); - - // Print the line, maybe with a pointer near the error token. - - output_buf << ">>> " << curr_line << "\n"; - - if (err_col == 0) - err_col = len; - - for (int i = 0; i < err_col + 3; i++) - output_buf << " "; - - output_buf << "^"; - } - - output_buf << "\n"; - - parse_error_msg = output_buf.str (); -} - -int -octave_parser::run (void) -{ - int status = -1; - - yypstate *pstate = static_cast (parser_state); - - try - { - status = octave_pull_parse (pstate, *this); - } - catch (octave_execution_exception& e) - { - std::string file = lexer.fcn_file_full_name; - - if (file.empty ()) - error (e, "parse error"); - else - error (e, "parse error in %s", file.c_str ()); - } - catch (octave_interrupt_exception &) - { - throw; - } - catch (...) - { - std::string file = lexer.fcn_file_full_name; - - if (file.empty ()) - error ("unexpected exception while parsing input"); - else - error ("unexpected exception while parsing %s", file.c_str ()); - } - - if (status != 0) - parse_error ("%s", parse_error_msg.c_str ()); - - return status; -} - -// Parse input from INPUT. Pass TRUE for EOF if the end of INPUT should -// finish the parse. - -int -octave_push_parser::run (const std::string& input, bool eof) -{ - int status = -1; - - dynamic_cast (lexer).append_input (input, eof); - - do - { - YYSTYPE lval; - - int token = octave_lex (&lval, scanner); - - if (token < 0) - { - if (! eof && lexer.at_end_of_buffer ()) - { - status = -1; - break; - } - } - - yypstate *pstate = static_cast (parser_state); - - try - { - status = octave_push_parse (pstate, token, &lval, *this); - } - catch (octave_execution_exception& e) - { - std::string file = lexer.fcn_file_full_name; - - if (file.empty ()) - error (e, "parse error"); - else - error (e, "parse error in %s", file.c_str ()); - } - catch (octave_interrupt_exception &) - { - throw; - } - catch (...) - { - std::string file = lexer.fcn_file_full_name; - - if (file.empty ()) - error ("unexpected exception while parsing input"); - else - error ("unexpected exception while parsing %s", file.c_str ()); - } - } - while (status == YYPUSH_MORE); - - if (status != 0) - parse_error ("%s", parse_error_msg.c_str ()); - - return status; + tree_statement_list * + base_parser::set_stmt_print_flag (tree_statement_list *list, + char sep, bool warn_missing_semi) + { + tree_statement *tmp = list->back (); + + switch (sep) + { + case ';': + tmp->set_print_flag (false); + break; + + case 0: + case ',': + case '\n': + tmp->set_print_flag (true); + if (warn_missing_semi) + maybe_warn_missing_semi (list); + break; + + default: + warning ("unrecognized separator type!"); + break; + } + + // Even if a statement is null, we add it to the list then remove it + // here so that the print flag is applied to the correct statement. + + if (tmp->is_null_statement ()) + { + list->pop_back (); + delete tmp; + } + + return list; + } + + // Finish building a statement. + template + tree_statement * + base_parser::make_statement (T *arg) + { + octave_comment_list *comment = lexer.get_comment (); + + return new tree_statement (arg, comment); + } + + tree_statement_list * + base_parser::make_statement_list (tree_statement *stmt) + { + return new tree_statement_list (stmt); + } + + tree_statement_list * + base_parser::append_statement_list (tree_statement_list *list, + char sep, tree_statement *stmt, + bool warn_missing_semi) + { + set_stmt_print_flag (list, sep, warn_missing_semi); + + list->append (stmt); + + return list; + } + + void + base_parser::bison_error (const std::string& str, int l, int c) + { + int err_line = l < 0 ? lexer.input_line_number : l; + int err_col = c < 0 ? lexer.current_input_column - 1 : c; + + std::ostringstream output_buf; + + if (lexer.reading_fcn_file || lexer.reading_script_file + || lexer.reading_classdef_file) + output_buf << "parse error near line " << err_line + << " of file " << lexer.fcn_file_full_name; + else + output_buf << "parse error:"; + + if (str != "parse error") + output_buf << "\n\n " << str; + + output_buf << "\n\n"; + + std::string curr_line = lexer.current_input_line; + + if (! curr_line.empty ()) + { + size_t len = curr_line.length (); + + if (curr_line[len-1] == '\n') + curr_line.resize (len-1); + + // Print the line, maybe with a pointer near the error token. + + output_buf << ">>> " << curr_line << "\n"; + + if (err_col == 0) + err_col = len; + + for (int i = 0; i < err_col + 3; i++) + output_buf << " "; + + output_buf << "^"; + } + + output_buf << "\n"; + + parse_error_msg = output_buf.str (); + } + + int + parser::run (void) + { + int status = -1; + + yypstate *pstate = static_cast (parser_state); + + try + { + status = octave_pull_parse (pstate, *this); + } + catch (octave_execution_exception& e) + { + std::string file = lexer.fcn_file_full_name; + + if (file.empty ()) + error (e, "parse error"); + else + error (e, "parse error in %s", file.c_str ()); + } + catch (octave_interrupt_exception &) + { + throw; + } + catch (...) + { + std::string file = lexer.fcn_file_full_name; + + if (file.empty ()) + error ("unexpected exception while parsing input"); + else + error ("unexpected exception while parsing %s", file.c_str ()); + } + + if (status != 0) + parse_error ("%s", parse_error_msg.c_str ()); + + return status; + } + + // Parse input from INPUT. Pass TRUE for EOF if the end of INPUT should + // finish the parse. + + int + push_parser::run (const std::string& input, bool eof) + { + int status = -1; + + dynamic_cast (lexer).append_input (input, eof); + + do + { + YYSTYPE lval; + + int token = octave_lex (&lval, scanner); + + if (token < 0) + { + if (! eof && lexer.at_end_of_buffer ()) + { + status = -1; + break; + } + } + + yypstate *pstate = static_cast (parser_state); + + try + { + status = octave_push_parse (pstate, token, &lval, *this); + } + catch (octave_execution_exception& e) + { + std::string file = lexer.fcn_file_full_name; + + if (file.empty ()) + error (e, "parse error"); + else + error (e, "parse error in %s", file.c_str ()); + } + catch (octave_interrupt_exception &) + { + throw; + } + catch (...) + { + std::string file = lexer.fcn_file_full_name; + + if (file.empty ()) + error ("unexpected exception while parsing input"); + else + error ("unexpected exception while parsing %s", file.c_str ()); + } + } + while (status == YYPUSH_MORE); + + if (status != 0) + parse_error ("%s", parse_error_msg.c_str ()); + + return status; + } } static void @@ -4159,10 +4162,10 @@ { frame.add_fcn (safe_fclose, ffile); - // octave_base_parser constructor sets this for us. + // octave::base_parser constructor sets this for us. frame.protect_var (LEXER); - octave_parser parser (ffile); + octave::parser parser (ffile); parser.curr_class_name = dispatch_type; parser.curr_package_name = package_name; @@ -4942,7 +4945,7 @@ { octave_value_list retval; - octave_parser parser (eval_str); + octave::parser parser (eval_str); do { @@ -4986,7 +4989,7 @@ retval = octave_value_list (); } else if (nargout == 0) - parser.stmt_list->accept (*current_evaluator); + parser.stmt_list->accept (*octave::current_evaluator); else error ("eval: invalid use of statement list"); @@ -5208,7 +5211,7 @@ // generally. Any that go through Octave's parser should have // already been checked. - if (is_keyword (nm)) + if (octave::is_keyword (nm)) error ("assignin: invalid assignment to keyword '%s'", nm.c_str ()); symbol_table::assign (nm, args(2)); diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/parse-tree/parse.h --- a/libinterp/parse-tree/parse.h Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/parse.h Tue Jul 12 14:28:07 2016 -0400 @@ -138,390 +138,393 @@ extern OCTINTERP_API void cleanup_statement_list (tree_statement_list **lst); -// Global access to currently active lexer. -// FIXME: to be removed after more parser+lexer refactoring. -extern octave_base_lexer *LEXER; - -class -octave_base_parser +namespace octave { -public: + // Global access to currently active lexer. + // FIXME: to be removed after more parser+lexer refactoring. + extern base_lexer *LEXER; - octave_base_parser (octave_base_lexer& lxr); + class + base_parser + { + public: - ~octave_base_parser (void); + base_parser (base_lexer& lxr); - void reset (void); + ~base_parser (void); - // Error mesages for mismatched end tokens. - void end_token_error (token *tok, token::end_tok_type expected); + void reset (void); + + // Error mesages for mismatched end tokens. + void end_token_error (token *tok, token::end_tok_type expected); - // Check to see that end tokens are properly matched. - bool end_token_ok (token *tok, token::end_tok_type expected); + // Check to see that end tokens are properly matched. + bool end_token_ok (token *tok, token::end_tok_type expected); - // Maybe print a warning if an assignment expression is used as the - // test in a logical expression. - void maybe_warn_assign_as_truth_value (tree_expression *expr); + // Maybe print a warning if an assignment expression is used as the + // test in a logical expression. + void maybe_warn_assign_as_truth_value (tree_expression *expr); + + // Maybe print a warning about switch labels that aren't constants. + void maybe_warn_variable_switch_label (tree_expression *expr); - // Maybe print a warning about switch labels that aren't constants. - void maybe_warn_variable_switch_label (tree_expression *expr); + // Finish building a range. + tree_expression *finish_colon_expression (tree_colon_expression *e); - // Finish building a range. - tree_expression *finish_colon_expression (tree_colon_expression *e); + // Build a constant. + tree_constant *make_constant (int op, token *tok_val); - // Build a constant. - tree_constant *make_constant (int op, token *tok_val); + // Build a function handle. + tree_fcn_handle *make_fcn_handle (token *tok_val); - // Build a function handle. - tree_fcn_handle *make_fcn_handle (token *tok_val); + // Build an anonymous function handle. + tree_anon_fcn_handle * + make_anon_fcn_handle (tree_parameter_list *param_list, tree_statement *stmt); - // Build an anonymous function handle. - tree_anon_fcn_handle * - make_anon_fcn_handle (tree_parameter_list *param_list, tree_statement *stmt); - - // Build a binary expression. - tree_expression * - make_binary_op (int op, tree_expression *op1, token *tok_val, - tree_expression *op2); + // Build a binary expression. + tree_expression * + make_binary_op (int op, tree_expression *op1, token *tok_val, + tree_expression *op2); - // Build a boolean expression. - tree_expression * - make_boolean_op (int op, tree_expression *op1, token *tok_val, - tree_expression *op2); + // Build a boolean expression. + tree_expression * + make_boolean_op (int op, tree_expression *op1, token *tok_val, + tree_expression *op2); - // Build a prefix expression. - tree_expression * - make_prefix_op (int op, tree_expression *op1, token *tok_val); + // Build a prefix expression. + tree_expression * + make_prefix_op (int op, tree_expression *op1, token *tok_val); + + // Build a postfix expression. + tree_expression * + make_postfix_op (int op, tree_expression *op1, token *tok_val); - // Build a postfix expression. - tree_expression * - make_postfix_op (int op, tree_expression *op1, token *tok_val); + // Build an unwind-protect command. + tree_command * + make_unwind_command (token *unwind_tok, tree_statement_list *body, + tree_statement_list *cleanup, token *end_tok, + octave_comment_list *lc, octave_comment_list *mc); - // Build an unwind-protect command. - tree_command * - make_unwind_command (token *unwind_tok, tree_statement_list *body, - tree_statement_list *cleanup, token *end_tok, - octave_comment_list *lc, octave_comment_list *mc); + // Build a try-catch command. + tree_command * + make_try_command (token *try_tok, tree_statement_list *body, + char catch_sep, tree_statement_list *cleanup, + token *end_tok, octave_comment_list *lc, + octave_comment_list *mc); - // Build a try-catch command. - tree_command * - make_try_command (token *try_tok, tree_statement_list *body, - char catch_sep, tree_statement_list *cleanup, - token *end_tok, octave_comment_list *lc, - octave_comment_list *mc); + // Build a while command. + tree_command * + make_while_command (token *while_tok, tree_expression *expr, + tree_statement_list *body, token *end_tok, + octave_comment_list *lc); - // Build a while command. - tree_command * - make_while_command (token *while_tok, tree_expression *expr, + // Build a do-until command. + tree_command * + make_do_until_command (token *until_tok, tree_statement_list *body, + tree_expression *expr, octave_comment_list *lc); + + // Build a for command. + tree_command * + make_for_command (int tok_id, token *for_tok, tree_argument_list *lhs, + tree_expression *expr, tree_expression *maxproc, tree_statement_list *body, token *end_tok, octave_comment_list *lc); - // Build a do-until command. - tree_command * - make_do_until_command (token *until_tok, tree_statement_list *body, - tree_expression *expr, octave_comment_list *lc); + // Build a break command. + tree_command *make_break_command (token *break_tok); + + // Build a continue command. + tree_command *make_continue_command (token *continue_tok); - // Build a for command. - tree_command * - make_for_command (int tok_id, token *for_tok, tree_argument_list *lhs, - tree_expression *expr, tree_expression *maxproc, - tree_statement_list *body, token *end_tok, - octave_comment_list *lc); + // Build a return command. + tree_command *make_return_command (token *return_tok); - // Build a break command. - tree_command *make_break_command (token *break_tok); + // Start an if command. + tree_if_command_list * + start_if_command (tree_expression *expr, tree_statement_list *list); - // Build a continue command. - tree_command *make_continue_command (token *continue_tok); + // Finish an if command. + tree_if_command * + finish_if_command (token *if_tok, tree_if_command_list *list, + token *end_tok, octave_comment_list *lc); - // Build a return command. - tree_command *make_return_command (token *return_tok); + // Build an elseif clause. + tree_if_clause * + make_elseif_clause (token *elseif_tok, tree_expression *expr, + tree_statement_list *list, octave_comment_list *lc); - // Start an if command. - tree_if_command_list * - start_if_command (tree_expression *expr, tree_statement_list *list); + // Finish a switch command. + tree_switch_command * + finish_switch_command (token *switch_tok, tree_expression *expr, + tree_switch_case_list *list, token *end_tok, + octave_comment_list *lc); - // Finish an if command. - tree_if_command * - finish_if_command (token *if_tok, tree_if_command_list *list, - token *end_tok, octave_comment_list *lc); - - // Build an elseif clause. - tree_if_clause * - make_elseif_clause (token *elseif_tok, tree_expression *expr, + // Build a switch case. + tree_switch_case * + make_switch_case (token *case_tok, tree_expression *expr, tree_statement_list *list, octave_comment_list *lc); - // Finish a switch command. - tree_switch_command * - finish_switch_command (token *switch_tok, tree_expression *expr, - tree_switch_case_list *list, token *end_tok, - octave_comment_list *lc); + // Build an assignment to a variable. + tree_expression * + make_assign_op (int op, tree_argument_list *lhs, token *eq_tok, + tree_expression *rhs); - // Build a switch case. - tree_switch_case * - make_switch_case (token *case_tok, tree_expression *expr, - tree_statement_list *list, octave_comment_list *lc); + // Define a script. + void make_script (tree_statement_list *cmds, tree_statement *end_script); + + // Begin defining a function. + octave_user_function * + start_function (tree_parameter_list *param_list, tree_statement_list *body, + tree_statement *end_function); - // Build an assignment to a variable. - tree_expression * - make_assign_op (int op, tree_argument_list *lhs, token *eq_tok, - tree_expression *rhs); + // Create a no-op statement for end_function. + tree_statement *make_end (const std::string& type, bool eof, int l, int c); - // Define a script. - void make_script (tree_statement_list *cmds, tree_statement *end_script); + // Do most of the work for defining a function. + octave_user_function * + frob_function (const std::string& fname, octave_user_function *fcn); - // Begin defining a function. - octave_user_function * - start_function (tree_parameter_list *param_list, tree_statement_list *body, - tree_statement *end_function); + // Finish defining a function. + tree_function_def * + finish_function (tree_parameter_list *ret_list, + octave_user_function *fcn, octave_comment_list *lc, + int l, int c); - // Create a no-op statement for end_function. - tree_statement *make_end (const std::string& type, bool eof, int l, int c); - - // Do most of the work for defining a function. - octave_user_function * - frob_function (const std::string& fname, octave_user_function *fcn); + // Reset state after parsing function. + void + recover_from_parsing_function (void); - // Finish defining a function. - tree_function_def * - finish_function (tree_parameter_list *ret_list, - octave_user_function *fcn, octave_comment_list *lc, - int l, int c); + tree_funcall * + make_superclass_ref (const std::string& method_nm, + const std::string& class_nm); - // Reset state after parsing function. - void - recover_from_parsing_function (void); + tree_funcall * + make_meta_class_query (const std::string& class_nm); - tree_funcall * - make_superclass_ref (const std::string& method_nm, - const std::string& class_nm); - - tree_funcall * - make_meta_class_query (const std::string& class_nm); + tree_classdef * + make_classdef (token *tok_val, tree_classdef_attribute_list *a, + tree_identifier *id, tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc); - tree_classdef * - make_classdef (token *tok_val, tree_classdef_attribute_list *a, - tree_identifier *id, tree_classdef_superclass_list *sc, - tree_classdef_body *body, token *end_tok, - octave_comment_list *lc); + tree_classdef_properties_block * + make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, octave_comment_list *lc); - tree_classdef_properties_block * - make_classdef_properties_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_property_list *plist, - token *end_tok, octave_comment_list *lc); + tree_classdef_methods_block * + make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, octave_comment_list *lc); - tree_classdef_methods_block * - make_classdef_methods_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_methods_list *mlist, - token *end_tok, octave_comment_list *lc); + tree_classdef_events_block * + make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, octave_comment_list *lc); - tree_classdef_events_block * - make_classdef_events_block (token *tok_val, + tree_classdef_enum_block * + make_classdef_enum_block (token *tok_val, tree_classdef_attribute_list *a, - tree_classdef_events_list *elist, + tree_classdef_enum_list *elist, token *end_tok, octave_comment_list *lc); - tree_classdef_enum_block * - make_classdef_enum_block (token *tok_val, - tree_classdef_attribute_list *a, - tree_classdef_enum_list *elist, - token *end_tok, octave_comment_list *lc); + octave_user_function * + start_classdef_external_method (tree_identifier *id, + tree_parameter_list *pl); - octave_user_function * - start_classdef_external_method (tree_identifier *id, - tree_parameter_list *pl); + tree_function_def * + finish_classdef_external_method (octave_user_function *fcn, + tree_parameter_list *ret_list, + octave_comment_list *cl); - tree_function_def * - finish_classdef_external_method (octave_user_function *fcn, - tree_parameter_list *ret_list, - octave_comment_list *cl); + // Make an index expression. + tree_index_expression * + make_index_expression (tree_expression *expr, + tree_argument_list *args, char type); - // Make an index expression. - tree_index_expression * - make_index_expression (tree_expression *expr, - tree_argument_list *args, char type); + // Make an indirect reference expression. + tree_index_expression * + make_indirect_ref (tree_expression *expr, const std::string&); - // Make an indirect reference expression. - tree_index_expression * - make_indirect_ref (tree_expression *expr, const std::string&); + // Make an indirect reference expression with dynamic field name. + tree_index_expression * + make_indirect_ref (tree_expression *expr, tree_expression *field); - // Make an indirect reference expression with dynamic field name. - tree_index_expression * - make_indirect_ref (tree_expression *expr, tree_expression *field); + // Make a declaration command. + tree_decl_command * + make_decl_command (int tok, token *tok_val, tree_decl_init_list *lst); - // Make a declaration command. - tree_decl_command * - make_decl_command (int tok, token *tok_val, tree_decl_init_list *lst); + // Validate matrix or cell + bool validate_array_list (tree_expression *e); - // Validate matrix or cell - bool validate_array_list (tree_expression *e); + // Validate matrix object used in "[lhs] = ..." assignments. + tree_argument_list *validate_matrix_for_assignment (tree_expression *e); - // Validate matrix object used in "[lhs] = ..." assignments. - tree_argument_list *validate_matrix_for_assignment (tree_expression *e); + // Finish building an array_list (common action for finish_matrix + // and finish_cell). + tree_expression *finish_array_list (tree_array_list *a); - // Finish building an array_list (common action for finish_matrix - // and finish_cell). - tree_expression *finish_array_list (tree_array_list *a); + // Finish building a matrix list. + tree_expression *finish_matrix (tree_matrix *m); - // Finish building a matrix list. - tree_expression *finish_matrix (tree_matrix *m); + // Finish building a cell list. + tree_expression *finish_cell (tree_cell *c); - // Finish building a cell list. - tree_expression *finish_cell (tree_cell *c); + // Maybe print a warning. Duh. + void maybe_warn_missing_semi (tree_statement_list *); - // Maybe print a warning. Duh. - void maybe_warn_missing_semi (tree_statement_list *); + // Set the print flag for a statement based on the separator type. + tree_statement_list * + set_stmt_print_flag (tree_statement_list *, char, bool); - // Set the print flag for a statement based on the separator type. - tree_statement_list * - set_stmt_print_flag (tree_statement_list *, char, bool); + // Finish building a statement. + template + tree_statement *make_statement (T *arg); - // Finish building a statement. - template - tree_statement *make_statement (T *arg); + // Create a statement list. + tree_statement_list *make_statement_list (tree_statement *stmt); - // Create a statement list. - tree_statement_list *make_statement_list (tree_statement *stmt); + // Append a statement to an existing statement list. + tree_statement_list * + append_statement_list (tree_statement_list *list, char sep, + tree_statement *stmt, bool warn_missing_semi); - // Append a statement to an existing statement list. - tree_statement_list * - append_statement_list (tree_statement_list *list, char sep, - tree_statement *stmt, bool warn_missing_semi); + // Generic error messages. + void bison_error (const std::string& s, int l = -1, int c = -1); - // Generic error messages. - void bison_error (const std::string& s, int l = -1, int c = -1); + // Contains error message if Bison-generated parser returns non-zero + // status. + std::string parse_error_msg; + + // Have we found an explicit end to a function? + bool endfunction_found; - // Contains error message if Bison-generated parser returns non-zero - // status. - std::string parse_error_msg; - - // Have we found an explicit end to a function? - bool endfunction_found; + // TRUE means we are in the process of autoloading a function. + bool autoloading; - // TRUE means we are in the process of autoloading a function. - bool autoloading; + // TRUE means the current function file was found in a relative path + // element. + bool fcn_file_from_relative_lookup; - // TRUE means the current function file was found in a relative path - // element. - bool fcn_file_from_relative_lookup; + // FALSE if we are still at the primary function. Subfunctions can + // only be declared inside function files. + bool parsing_subfunctions; - // FALSE if we are still at the primary function. Subfunctions can - // only be declared inside function files. - bool parsing_subfunctions; + // Maximum function depth detected. Used to determine whether + // we have nested functions or just implicitly ended subfunctions. + int max_fcn_depth; - // Maximum function depth detected. Used to determine whether - // we have nested functions or just implicitly ended subfunctions. - int max_fcn_depth; + // = 0 currently outside any function. + // = 1 inside the primary function or a subfunction. + // > 1 means we are looking at a function definition that seems to be + // inside a function. Note that the function still might not be a + // nested function. + int curr_fcn_depth; - // = 0 currently outside any function. - // = 1 inside the primary function or a subfunction. - // > 1 means we are looking at a function definition that seems to be - // inside a function. Note that the function still might not be a - // nested function. - int curr_fcn_depth; + // Scope where we install all subfunctions and nested functions. Only + // used while reading function files. + symbol_table::scope_id primary_fcn_scope; - // Scope where we install all subfunctions and nested functions. Only - // used while reading function files. - symbol_table::scope_id primary_fcn_scope; + // Name of the current class when we are parsing class methods or + // constructors. + std::string curr_class_name; - // Name of the current class when we are parsing class methods or - // constructors. - std::string curr_class_name; - - // Name of the current package when we are parsing an element contained - // in a package directory (+-directory). - std::string curr_package_name; + // Name of the current package when we are parsing an element contained + // in a package directory (+-directory). + std::string curr_package_name; - // A stack holding the nested function scopes being parsed. - // We don't use std::stack, because we want the clear method. Also, we - // must access one from the top - std::vector function_scopes; + // A stack holding the nested function scopes being parsed. + // We don't use std::stack, because we want the clear method. Also, we + // must access one from the top + std::vector function_scopes; - // Pointer to the primary user function or user script function. - octave_function *primary_fcn_ptr; + // Pointer to the primary user function or user script function. + octave_function *primary_fcn_ptr; - // List of subfunction names, initially in the order they are - // installed in the symbol table, then ordered as they appear in the - // file. Eventually stashed in the primary function object. - std::list subfunction_names; + // List of subfunction names, initially in the order they are + // installed in the symbol table, then ordered as they appear in the + // file. Eventually stashed in the primary function object. + std::list subfunction_names; - // Pointer to the classdef object we just parsed, if any. - tree_classdef *classdef_object; + // Pointer to the classdef object we just parsed, if any. + tree_classdef *classdef_object; - // Result of parsing input. - tree_statement_list *stmt_list; + // Result of parsing input. + tree_statement_list *stmt_list; - // State of the lexer. - octave_base_lexer& lexer; + // State of the lexer. + base_lexer& lexer; - // Internal state of the Bison parser. - void *parser_state; + // Internal state of the Bison parser. + void *parser_state; -private: + private: - // No copying! + // No copying! - octave_base_parser (const octave_base_parser&); + base_parser (const base_parser&); - octave_base_parser& operator = (const octave_base_parser&); -}; + base_parser& operator = (const base_parser&); + }; -class -octave_parser : public octave_base_parser -{ -public: + class + parser : public base_parser + { + public: - octave_parser (void) - : octave_base_parser (*(new octave_lexer ())) - { } + parser (void) + : base_parser (*(new octave::lexer ())) + { } - octave_parser (FILE *file) - : octave_base_parser (*(new octave_lexer (file))) - { } + parser (FILE *file) + : base_parser (*(new octave::lexer (file))) + { } - octave_parser (const std::string& eval_string) - : octave_base_parser (*(new octave_lexer (eval_string))) - { } + parser (const std::string& eval_string) + : base_parser (*(new octave::lexer (eval_string))) + { } - octave_parser (octave_lexer& lxr) - : octave_base_parser (lxr) - { } + parser (octave::lexer& lxr) + : base_parser (lxr) + { } - ~octave_parser (void) { } + ~parser (void) { } - int run (void); + int run (void); + + private: -private: + // No copying! - // No copying! + parser (const parser&); - octave_parser (const octave_parser&); - - octave_parser& operator = (const octave_parser&); -}; + parser& operator = (const parser&); + }; -class -octave_push_parser : public octave_base_parser -{ -public: + class + push_parser : public base_parser + { + public: + + push_parser (void) + : base_parser (*(new octave::push_lexer ())) + { } - octave_push_parser (void) - : octave_base_parser (*(new octave_push_lexer ())) - { } + ~push_parser (void) { } - ~octave_push_parser (void) { } + int run (const std::string& input, bool eof); - int run (const std::string& input, bool eof); + private: -private: + // No copying! - // No copying! + push_parser (const push_parser&); - octave_push_parser (const octave_push_parser&); - - octave_push_parser& operator = (const octave_push_parser&); -}; + push_parser& operator = (const push_parser&); + }; +} #endif diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/parse-tree/pt-assign.cc --- a/libinterp/parse-tree/pt-assign.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/pt-assign.cc Tue Jul 12 14:28:07 2016 -0400 @@ -105,7 +105,7 @@ retval = ult.value (); if (print_result () - && tree_evaluator::statement_printing_enabled ()) + && octave::tree_evaluator::statement_printing_enabled ()) { // We clear any index here so that we can // get the new value of the referenced @@ -319,7 +319,7 @@ } if (print_result () - && tree_evaluator::statement_printing_enabled ()) + && octave::tree_evaluator::statement_printing_enabled ()) { // We clear any index here so that we can get // the new value of the referenced object below, diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/parse-tree/pt-eval.cc --- a/libinterp/parse-tree/pt-eval.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/pt-eval.cc Tue Jul 12 14:28:07 2016 -0400 @@ -49,23 +49,6 @@ //FIXME: This should be part of tree_evaluator #include "pt-jit.h" -static tree_evaluator std_evaluator; - -tree_evaluator *current_evaluator = &std_evaluator; - -int tree_evaluator::dbstep_flag = 0; - -size_t tree_evaluator::current_frame = 0; - -bool tree_evaluator::debug_mode = false; - -bool tree_evaluator::quiet_breakpoint_flag = false; - -tree_evaluator::stmt_list_type tree_evaluator::statement_context - = tree_evaluator::other; - -bool tree_evaluator::in_loop_command = false; - // Maximum nesting level for functions, scripts, or sourced files called // recursively. int Vmax_recursion_depth = 256; @@ -74,67 +57,83 @@ // semicolon has been appended to each statement). static bool Vsilent_functions = false; -// Normal evaluator. - -void -tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&) +namespace octave { - panic_impossible (); -} + int tree_evaluator::dbstep_flag = 0; + + size_t tree_evaluator::current_frame = 0; + + bool tree_evaluator::debug_mode = false; -void -tree_evaluator::visit_argument_list (tree_argument_list&) -{ - panic_impossible (); -} + bool tree_evaluator::quiet_breakpoint_flag = false; + + tree_evaluator::stmt_list_type tree_evaluator::statement_context + = tree_evaluator::other; + + bool tree_evaluator::in_loop_command = false; + + // Normal evaluator. -void -tree_evaluator::visit_binary_expression (tree_binary_expression&) -{ - panic_impossible (); -} + void + tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&) + { + panic_impossible (); + } -void -tree_evaluator::visit_break_command (tree_break_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); + void + tree_evaluator::visit_argument_list (tree_argument_list&) + { + panic_impossible (); + } - if (statement_context == function || statement_context == script - || in_loop_command) - tree_break_command::breaking = 1; -} + void + tree_evaluator::visit_binary_expression (tree_binary_expression&) + { + panic_impossible (); + } -void -tree_evaluator::visit_colon_expression (tree_colon_expression&) -{ - panic_impossible (); -} + void + tree_evaluator::visit_break_command (tree_break_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); -void -tree_evaluator::visit_continue_command (tree_continue_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); + if (statement_context == function || statement_context == script + || in_loop_command) + tree_break_command::breaking = 1; + } + + void + tree_evaluator::visit_colon_expression (tree_colon_expression&) + { + panic_impossible (); + } - if (statement_context == function || statement_context == script - || in_loop_command) - tree_continue_command::continuing = 1; -} + void + tree_evaluator::visit_continue_command (tree_continue_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); + + if (statement_context == function || statement_context == script + || in_loop_command) + tree_continue_command::continuing = 1; + } -void -tree_evaluator::reset_debug_state (void) -{ - debug_mode = bp_table::have_breakpoints () || Vdebugging; + void + tree_evaluator::reset_debug_state (void) + { + debug_mode = bp_table::have_breakpoints () || Vdebugging; - dbstep_flag = 0; -} + dbstep_flag = 0; + } -bool -tree_evaluator::statement_printing_enabled (void) -{ - return ! (Vsilent_functions && (statement_context == function - || statement_context == script)); + bool + tree_evaluator::statement_printing_enabled (void) + { + return ! (Vsilent_functions && (statement_context == function + || statement_context == script)); + } } static inline void @@ -191,71 +190,53 @@ } } -void -tree_evaluator::do_decl_init_list (decl_elt_init_fcn fcn, - tree_decl_init_list *init_list) +namespace octave { - if (init_list) - { - for (tree_decl_init_list::iterator p = init_list->begin (); - p != init_list->end (); p++) - { - tree_decl_elt *elt = *p; + void + tree_evaluator::do_decl_init_list (decl_elt_init_fcn fcn, + tree_decl_init_list *init_list) + { + if (init_list) + { + for (tree_decl_init_list::iterator p = init_list->begin (); + p != init_list->end (); p++) + { + tree_decl_elt *elt = *p; - fcn (*elt); - } - } -} + fcn (*elt); + } + } + } -void -tree_evaluator::visit_global_command (tree_global_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - do_decl_init_list (do_global_init, cmd.initializer_list ()); -} - -void -tree_evaluator::visit_persistent_command (tree_persistent_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); + void + tree_evaluator::visit_global_command (tree_global_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); - do_decl_init_list (do_static_init, cmd.initializer_list ()); -} + do_decl_init_list (do_global_init, cmd.initializer_list ()); + } -void -tree_evaluator::visit_decl_elt (tree_decl_elt&) -{ - panic_impossible (); -} + void + tree_evaluator::visit_persistent_command (tree_persistent_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); -#if 0 -bool -tree_decl_elt::eval (void) -{ - bool retval = false; + do_decl_init_list (do_static_init, cmd.initializer_list ()); + } - if (id && expr) - { - octave_lvalue ult = id->lvalue (); - - octave_value init_val = expr->rvalue1 (); - - ult.assign (octave_value::op_asn_eq, init_val); + void + tree_evaluator::visit_decl_elt (tree_decl_elt&) + { + panic_impossible (); + } - retval = true; - } - - return retval; -} -#endif - -void -tree_evaluator::visit_decl_init_list (tree_decl_init_list&) -{ - panic_impossible (); + void + tree_evaluator::visit_decl_init_list (tree_decl_init_list&) + { + panic_impossible (); + } } // Decide if it's time to quit a for or while loop. @@ -279,920 +260,922 @@ return quit; } -void -tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd) +namespace octave { - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - // FIXME: need to handle PARFOR loops here using cmd.in_parallel () - // and cmd.maxproc_expr (); + void + tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); - octave::unwind_protect frame; + // FIXME: need to handle PARFOR loops here using cmd.in_parallel () + // and cmd.maxproc_expr (); - frame.protect_var (in_loop_command); + octave::unwind_protect frame; - in_loop_command = true; + frame.protect_var (in_loop_command); + + in_loop_command = true; - tree_expression *expr = cmd.control_expr (); + tree_expression *expr = cmd.control_expr (); - octave_value rhs = expr->rvalue1 (); + octave_value rhs = expr->rvalue1 (); #if defined (HAVE_LLVM) - if (tree_jit::execute (cmd, rhs)) - return; + if (tree_jit::execute (cmd, rhs)) + return; #endif - if (rhs.is_undefined ()) - return; + if (rhs.is_undefined ()) + return; + + tree_expression *lhs = cmd.left_hand_side (); + + octave_lvalue ult = lhs->lvalue (); + + tree_statement_list *loop_body = cmd.body (); + + if (rhs.is_range ()) + { + Range rng = rhs.range_value (); + + octave_idx_type steps = rng.numel (); + + for (octave_idx_type i = 0; i < steps; i++) + { + octave_value val (rng.elem (i)); + + ult.assign (octave_value::op_asn_eq, val); + + if (loop_body) + loop_body->accept (*this); - tree_expression *lhs = cmd.left_hand_side (); + if (quit_loop_now ()) + break; + } + } + else if (rhs.is_scalar_type ()) + { + ult.assign (octave_value::op_asn_eq, rhs); + + if (loop_body) + loop_body->accept (*this); - octave_lvalue ult = lhs->lvalue (); + // Maybe decrement break and continue states. + quit_loop_now (); + } + else if (rhs.is_matrix_type () || rhs.is_cell () || rhs.is_string () + || rhs.is_map ()) + { + // A matrix or cell is reshaped to 2 dimensions and iterated by + // columns. + + dim_vector dv = rhs.dims ().redim (2); + + octave_idx_type nrows = dv(0); + octave_idx_type steps = dv(1); + + if (steps > 0) + { + octave_value arg = rhs; + if (rhs.ndims () > 2) + arg = arg.reshape (dv); - tree_statement_list *loop_body = cmd.body (); + // for row vectors, use single index to speed things up. + octave_value_list idx; + octave_idx_type iidx; + if (nrows == 1) + { + idx.resize (1); + iidx = 0; + } + else + { + idx.resize (2); + idx(0) = octave_value::magic_colon_t; + iidx = 1; + } + + for (octave_idx_type i = 1; i <= steps; i++) + { + // do_index_op expects one-based indices. + idx(iidx) = i; + octave_value val = arg.do_index_op (idx); + + ult.assign (octave_value::op_asn_eq, val); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + } + } + } + else + error ("invalid type in for loop expression near line %d, column %d", + cmd.line (), cmd.column ()); + } - if (rhs.is_range ()) - { - Range rng = rhs.range_value (); + void + tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); + + octave::unwind_protect frame; + + frame.protect_var (in_loop_command); + + in_loop_command = true; + + tree_expression *expr = cmd.control_expr (); + + octave_value rhs = expr->rvalue1 (); + + if (rhs.is_undefined ()) + return; + + if (! rhs.is_map ()) + error ("in statement 'for [X, Y] = VAL', VAL must be a structure"); - octave_idx_type steps = rng.numel (); + // Cycle through structure elements. First element of id_list + // is set to value and the second is set to the name of the + // structure element. + + tree_argument_list *lhs = cmd.left_hand_side (); + + tree_argument_list::iterator p = lhs->begin (); + + tree_expression *elt = *p++; + + octave_lvalue val_ref = elt->lvalue (); + + elt = *p; + + octave_lvalue key_ref = elt->lvalue (); + + const octave_map tmp_val = rhs.map_value (); + + tree_statement_list *loop_body = cmd.body (); + + string_vector keys = tmp_val.keys (); + + octave_idx_type nel = keys.numel (); - for (octave_idx_type i = 0; i < steps; i++) - { - octave_value val (rng.elem (i)); + for (octave_idx_type i = 0; i < nel; i++) + { + std::string key = keys[i]; + + const Cell val_lst = tmp_val.contents (key); + + octave_idx_type n = val_lst.numel (); + + octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst); + + val_ref.assign (octave_value::op_asn_eq, val); + key_ref.assign (octave_value::op_asn_eq, key); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + } + } + + void + tree_evaluator::visit_octave_user_script (octave_user_script&) + { + panic_impossible (); + } - ult.assign (octave_value::op_asn_eq, val); + void + tree_evaluator::visit_octave_user_function (octave_user_function&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_octave_user_function_header (octave_user_function&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_octave_user_function_trailer (octave_user_function&) + { + panic_impossible (); + } - if (loop_body) - loop_body->accept (*this); + void + tree_evaluator::visit_function_def (tree_function_def& cmd) + { + octave_value fcn = cmd.function (); + + octave_function *f = fcn.function_value (); + + if (f) + { + std::string nm = f->name (); + + symbol_table::install_cmdline_function (nm, fcn); + + // Make sure that any variable with the same name as the new + // function is cleared. + + symbol_table::assign (nm); + } + } - if (quit_loop_now ()) + void + tree_evaluator::visit_identifier (tree_identifier&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_if_clause (tree_if_clause&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_if_command (tree_if_command& cmd) + { + tree_if_command_list *lst = cmd.cmd_list (); + + if (lst) + lst->accept (*this); + } + + void + tree_evaluator::visit_if_command_list (tree_if_command_list& lst) + { + for (tree_if_command_list::iterator p = lst.begin (); p != lst.end (); p++) + { + tree_if_clause *tic = *p; + + tree_expression *expr = tic->condition (); + + if (statement_context == function || statement_context == script) + octave_call_stack::set_location (tic->line (), tic->column ()); + + if (debug_mode && ! tic->is_else_clause ()) + do_breakpoint (tic->is_breakpoint (true)); + + if (tic->is_else_clause () || expr->is_logically_true ("if")) + { + tree_statement_list *stmt_lst = tic->commands (); + + if (stmt_lst) + stmt_lst->accept (*this); + break; - } - } - else if (rhs.is_scalar_type ()) - { - ult.assign (octave_value::op_asn_eq, rhs); + } + } + } + + void + tree_evaluator::visit_index_expression (tree_index_expression&) + { + panic_impossible (); + } - if (loop_body) - loop_body->accept (*this); + void + tree_evaluator::visit_matrix (tree_matrix&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_cell (tree_cell&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_multi_assignment (tree_multi_assignment&) + { + panic_impossible (); + } - // Maybe decrement break and continue states. - quit_loop_now (); - } - else if (rhs.is_matrix_type () || rhs.is_cell () || rhs.is_string () - || rhs.is_map ()) - { - // A matrix or cell is reshaped to 2 dimensions and iterated by - // columns. + void + tree_evaluator::visit_no_op_command (tree_no_op_command& cmd) + { + if (debug_mode && cmd.is_end_of_fcn_or_script ()) + do_breakpoint (cmd.is_breakpoint (true), true); + } + + void + tree_evaluator::visit_constant (tree_constant&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_fcn_handle (tree_fcn_handle&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_funcall (tree_funcall&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_parameter_list (tree_parameter_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_postfix_expression (tree_postfix_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_prefix_expression (tree_prefix_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_return_command (tree_return_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); + + // Act like dbcont. + + if (Vdebugging + && octave_call_stack::current_frame () == current_frame) + { + Vdebugging = false; + + reset_debug_state (); + } + else if (statement_context == function || statement_context == script + || in_loop_command) + tree_return_command::returning = 1; + } - dim_vector dv = rhs.dims ().redim (2); + void + tree_evaluator::visit_return_list (tree_return_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_simple_assignment (tree_simple_assignment&) + { + panic_impossible (); + } - octave_idx_type nrows = dv(0); - octave_idx_type steps = dv(1); + void + tree_evaluator::visit_statement (tree_statement& stmt) + { + tree_command *cmd = stmt.command (); + tree_expression *expr = stmt.expression (); + + if (cmd || expr) + { + if (statement_context == function || statement_context == script) + { + // Skip commands issued at a debug> prompt to avoid disturbing + // the state of the program we are debugging. + + if (Vtrack_line_num) + octave_call_stack::set_location (stmt.line (), stmt.column ()); - if (steps > 0) - { - octave_value arg = rhs; - if (rhs.ndims () > 2) - arg = arg.reshape (dv); + if ((statement_context == script + && ((Vecho_executing_commands & ECHO_SCRIPTS + && octave_call_stack::all_scripts ()) + || Vecho_executing_commands & ECHO_FUNCTIONS)) + || (statement_context == function + && Vecho_executing_commands & ECHO_FUNCTIONS)) + stmt.echo_code (); + } + + try + { + if (cmd) + cmd->accept (*this); + else + { + if (debug_mode) + do_breakpoint (expr->is_breakpoint (true)); + + // FIXME: maybe all of this should be packaged in + // one virtual function that returns a flag saying whether + // or not the expression will take care of binding ans and + // printing the result. + + // FIXME: it seems that we should just have to + // call expr->rvalue1 () and that should take care of + // everything, binding ans as necessary? + + bool do_bind_ans = false; + + if (expr->is_identifier ()) + { + tree_identifier *id = dynamic_cast (expr); + + do_bind_ans = (! id->is_variable ()); + } + else + do_bind_ans = (! expr->is_assignment_expression ()); + + octave_value tmp_result = expr->rvalue1 (0); + + if (do_bind_ans && tmp_result.is_defined ()) + bind_ans (tmp_result, expr->print_result () + && statement_printing_enabled ()); - // for row vectors, use single index to speed things up. - octave_value_list idx; - octave_idx_type iidx; - if (nrows == 1) + // if (tmp_result.is_defined ()) + // result_values(0) = tmp_result; + } + } + catch (const std::bad_alloc&) + { + // FIXME: We want to use error_with_id here so that give users + // control over this error message but error_with_id will + // require some memory allocations. Is there anything we can + // do to make those more likely to succeed? + + error_with_id ("Octave:bad-alloc", + "out of memory or dimension too large for Octave's index type"); + } + } + } + + void + tree_evaluator::visit_statement_list (tree_statement_list& lst) + { + // FIXME: commented out along with else clause below. + // static octave_value_list empty_list; + + tree_statement_list::iterator p = lst.begin (); + + if (p != lst.end ()) + { + while (true) + { + tree_statement *elt = *p++; + + if (! elt) + error ("invalid statement found in statement list!"); + + octave_quit (); + + elt->accept (*this); + + if (tree_break_command::breaking + || tree_continue_command::continuing) + break; + + if (tree_return_command::returning) + break; + + if (p == lst.end ()) + break; + else + { + // Clear previous values before next statement is + // evaluated so that we aren't holding an extra + // reference to a value that may be used next. For + // example, in code like this: + // + // X = rand (N); # refcount for X should be 1 + // # after this statement + // + // X(idx) = val; # no extra copy of X should be + // # needed, but we will be faked + // # out if retval is not cleared + // # between statements here + + // result_values = empty_list; + } + } + } + } + + void + tree_evaluator::visit_switch_case (tree_switch_case&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_switch_case_list (tree_switch_case_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_switch_command (tree_switch_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); + + tree_expression *expr = cmd.switch_value (); + + if (! expr) + error ("missing value in switch command near line %d, column %d", + cmd.line (), cmd.column ()); + + octave_value val = expr->rvalue1 (); + + tree_switch_case_list *lst = cmd.case_list (); + + if (lst) + { + for (tree_switch_case_list::iterator p = lst->begin (); + p != lst->end (); p++) + { + tree_switch_case *t = *p; + + if (t->is_default_case () || t->label_matches (val)) + { + tree_statement_list *stmt_lst = t->commands (); + + if (stmt_lst) + stmt_lst->accept (*this); + + break; + } + } + } + } + + void + tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd) + { + bool execution_error = false; + + { // unwind frame before catch block + octave::unwind_protect frame; + + frame.protect_var (buffer_error_messages); + frame.protect_var (Vdebug_on_error); + frame.protect_var (Vdebug_on_warning); + + buffer_error_messages++; + Vdebug_on_error = false; + Vdebug_on_warning = false; + + // The catch code is *not* added to unwind_protect stack; + // it doesn't need to be run on interrupts. + + tree_statement_list *try_code = cmd.body (); + + if (try_code) + { + try { - idx.resize (1); - iidx = 0; - } - else - { - idx.resize (2); - idx(0) = octave_value::magic_colon_t; - iidx = 1; + in_try_catch++; + try_code->accept (*this); + in_try_catch--; } - - for (octave_idx_type i = 1; i <= steps; i++) + catch (const octave_execution_exception&) { - // do_index_op expects one-based indices. - idx(iidx) = i; - octave_value val = arg.do_index_op (idx); + recover_from_exception (); - ult.assign (octave_value::op_asn_eq, val); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; + in_try_catch--; // must be restored before "catch" block + execution_error = true; } } + // Unwind to let the user print any messages from + // errors that occurred in the body of the try_catch statement, + // or throw further errors. } - else - error ("invalid type in for loop expression near line %d, column %d", - cmd.line (), cmd.column ()); -} - -void -tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - octave::unwind_protect frame; - - frame.protect_var (in_loop_command); - - in_loop_command = true; - - tree_expression *expr = cmd.control_expr (); - - octave_value rhs = expr->rvalue1 (); - - if (rhs.is_undefined ()) - return; - - if (! rhs.is_map ()) - error ("in statement 'for [X, Y] = VAL', VAL must be a structure"); - - // Cycle through structure elements. First element of id_list - // is set to value and the second is set to the name of the - // structure element. - - tree_argument_list *lhs = cmd.left_hand_side (); - - tree_argument_list::iterator p = lhs->begin (); - - tree_expression *elt = *p++; - - octave_lvalue val_ref = elt->lvalue (); - - elt = *p; - - octave_lvalue key_ref = elt->lvalue (); - - const octave_map tmp_val = rhs.map_value (); - - tree_statement_list *loop_body = cmd.body (); - - string_vector keys = tmp_val.keys (); - - octave_idx_type nel = keys.numel (); - - for (octave_idx_type i = 0; i < nel; i++) - { - std::string key = keys[i]; - - const Cell val_lst = tmp_val.contents (key); - - octave_idx_type n = val_lst.numel (); - - octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst); - - val_ref.assign (octave_value::op_asn_eq, val); - key_ref.assign (octave_value::op_asn_eq, key); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; - } -} - -void -tree_evaluator::visit_octave_user_script (octave_user_script&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_octave_user_function (octave_user_function&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_octave_user_function_header (octave_user_function&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_octave_user_function_trailer (octave_user_function&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_function_def (tree_function_def& cmd) -{ - octave_value fcn = cmd.function (); - - octave_function *f = fcn.function_value (); - - if (f) - { - std::string nm = f->name (); - - symbol_table::install_cmdline_function (nm, fcn); - // Make sure that any variable with the same name as the new - // function is cleared. - - symbol_table::assign (nm); - } -} - -void -tree_evaluator::visit_identifier (tree_identifier&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_if_clause (tree_if_clause&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_if_command (tree_if_command& cmd) -{ - tree_if_command_list *lst = cmd.cmd_list (); - - if (lst) - lst->accept (*this); -} - -void -tree_evaluator::visit_if_command_list (tree_if_command_list& lst) -{ - for (tree_if_command_list::iterator p = lst.begin (); p != lst.end (); p++) - { - tree_if_clause *tic = *p; - - tree_expression *expr = tic->condition (); - - if (statement_context == function || statement_context == script) - octave_call_stack::set_location (tic->line (), tic->column ()); - - if (debug_mode && ! tic->is_else_clause ()) - do_breakpoint (tic->is_breakpoint (true)); - - if (tic->is_else_clause () || expr->is_logically_true ("if")) - { - tree_statement_list *stmt_lst = tic->commands (); - - if (stmt_lst) - stmt_lst->accept (*this); - - break; - } - } -} + if (execution_error) + { + tree_statement_list *catch_code = cmd.cleanup (); + if (catch_code) + { + tree_identifier *expr_id = cmd.identifier (); + octave_lvalue ult; -void -tree_evaluator::visit_index_expression (tree_index_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_matrix (tree_matrix&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_cell (tree_cell&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_multi_assignment (tree_multi_assignment&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_no_op_command (tree_no_op_command& cmd) -{ - if (debug_mode && cmd.is_end_of_fcn_or_script ()) - do_breakpoint (cmd.is_breakpoint (true), true); -} - -void -tree_evaluator::visit_constant (tree_constant&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_fcn_handle (tree_fcn_handle&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_funcall (tree_funcall&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_parameter_list (tree_parameter_list&) -{ - panic_impossible (); -} + if (expr_id) + { + ult = expr_id->lvalue (); -void -tree_evaluator::visit_postfix_expression (tree_postfix_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_prefix_expression (tree_prefix_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_return_command (tree_return_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - // Act like dbcont. - - if (Vdebugging - && octave_call_stack::current_frame () == current_frame) - { - Vdebugging = false; - - reset_debug_state (); - } - else if (statement_context == function || statement_context == script - || in_loop_command) - tree_return_command::returning = 1; -} - -void -tree_evaluator::visit_return_list (tree_return_list&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_simple_assignment (tree_simple_assignment&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_statement (tree_statement& stmt) -{ - tree_command *cmd = stmt.command (); - tree_expression *expr = stmt.expression (); + octave_scalar_map err; - if (cmd || expr) - { - if (statement_context == function || statement_context == script) - { - // Skip commands issued at a debug> prompt to avoid disturbing - // the state of the program we are debugging, but still track - // progress through user functions called from debug> prompt. - - if (Vtrack_line_num) - octave_call_stack::set_location (stmt.line (), stmt.column ()); - - if ((statement_context == script - && ((Vecho_executing_commands & ECHO_SCRIPTS - && octave_call_stack::all_scripts ()) - || Vecho_executing_commands & ECHO_FUNCTIONS)) - || (statement_context == function - && Vecho_executing_commands & ECHO_FUNCTIONS)) - stmt.echo_code (); - } + err.assign ("message", last_error_message ()); + err.assign ("identifier", last_error_id ()); + err.assign ("stack", last_error_stack ()); - try - { - if (cmd) - cmd->accept (*this); - else - { - if (debug_mode) - do_breakpoint (expr->is_breakpoint (true)); - - // FIXME: maybe all of this should be packaged in - // one virtual function that returns a flag saying whether - // or not the expression will take care of binding ans and - // printing the result. - - // FIXME: it seems that we should just have to - // call expr->rvalue1 () and that should take care of - // everything, binding ans as necessary? - - bool do_bind_ans = false; - - if (expr->is_identifier ()) - { - tree_identifier *id = dynamic_cast (expr); - - do_bind_ans = (! id->is_variable ()); - } - else - do_bind_ans = (! expr->is_assignment_expression ()); - - octave_value tmp_result = expr->rvalue1 (0); - - if (do_bind_ans && tmp_result.is_defined ()) - bind_ans (tmp_result, expr->print_result () - && statement_printing_enabled ()); + ult.assign (octave_value::op_asn_eq, err); + } - // if (tmp_result.is_defined ()) - // result_values(0) = tmp_result; - } - } - catch (const std::bad_alloc&) - { - // FIXME: We want to use error_with_id here so that give users - // control over this error message but error_with_id will - // require some memory allocations. Is there anything we can - // do to make those more likely to succeed? - - error_with_id ("Octave:bad-alloc", - "out of memory or dimension too large for Octave's index type"); - } - } -} - -void -tree_evaluator::visit_statement_list (tree_statement_list& lst) -{ - // FIXME: commented out along with else clause below. - // static octave_value_list empty_list; - - tree_statement_list::iterator p = lst.begin (); - - if (p != lst.end ()) - { - while (true) - { - tree_statement *elt = *p++; - - if (! elt) - error ("invalid statement found in statement list!"); - - octave_quit (); - - elt->accept (*this); - - if (tree_break_command::breaking - || tree_continue_command::continuing) - break; - - if (tree_return_command::returning) - break; + // perform actual "catch" block + if (catch_code) + catch_code->accept (*this); + } + } + } - if (p == lst.end ()) - break; - else - { - // Clear previous values before next statement is - // evaluated so that we aren't holding an extra - // reference to a value that may be used next. For - // example, in code like this: - // - // X = rand (N); # refcount for X should be 1 - // # after this statement - // - // X(idx) = val; # no extra copy of X should be - // # needed, but we will be faked - // # out if retval is not cleared - // # between statements here - - // result_values = empty_list; - } - } - } -} - -void -tree_evaluator::visit_switch_case (tree_switch_case&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_switch_case_list (tree_switch_case_list&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_switch_command (tree_switch_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - tree_expression *expr = cmd.switch_value (); - - if (! expr) - error ("missing value in switch command near line %d, column %d", - cmd.line (), cmd.column ()); - - octave_value val = expr->rvalue1 (); - - tree_switch_case_list *lst = cmd.case_list (); - - if (lst) - { - for (tree_switch_case_list::iterator p = lst->begin (); - p != lst->end (); p++) - { - tree_switch_case *t = *p; - - if (t->is_default_case () || t->label_matches (val)) - { - tree_statement_list *stmt_lst = t->commands (); - - if (stmt_lst) - stmt_lst->accept (*this); - - break; - } - } - } -} - -void -tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd) -{ - bool execution_error = false; - - { // unwind frame before catch block + void + tree_evaluator::do_unwind_protect_cleanup_code (tree_statement_list *list) + { octave::unwind_protect frame; - frame.protect_var (buffer_error_messages); - frame.protect_var (Vdebug_on_error); - frame.protect_var (Vdebug_on_warning); + frame.protect_var (octave_interrupt_state); + octave_interrupt_state = 0; + + // We want to preserve the last location info for possible + // backtracking. + frame.add_fcn (octave_call_stack::set_line, + octave_call_stack::current_line ()); + frame.add_fcn (octave_call_stack::set_column, + octave_call_stack::current_column ()); + + // Similarly, if we have seen a return or break statement, allow all + // the cleanup code to run before returning or handling the break. + // We don't have to worry about continue statements because they can + // only occur in loops. + + frame.protect_var (tree_return_command::returning); + tree_return_command::returning = 0; + + frame.protect_var (tree_break_command::breaking); + tree_break_command::breaking = 0; + + try + { + if (list) + list->accept (*this); + } + catch (const octave_execution_exception&) + { + recover_from_exception (); + + if (tree_break_command::breaking || tree_return_command::returning) + frame.discard (2); + else + frame.run (2); + + frame.discard (2); + + throw; + } - buffer_error_messages++; - Vdebug_on_error = false; - Vdebug_on_warning = false; + // The unwind_protects are popped off the stack in the reverse of + // the order they are pushed on. - // The catch code is *not* added to unwind_protect stack; - // it doesn't need to be run on interrupts. + // FIXME: these statements say that if we see a break or + // return statement in the cleanup block, that we want to use the + // new value of the breaking or returning flag instead of restoring + // the previous value. Is that the right thing to do? I think so. + // Consider the case of + // + // function foo () + // unwind_protect + // fprintf (stderr, "1: this should always be executed\n"); + // break; + // fprintf (stderr, "1: this should never be executed\n"); + // unwind_protect_cleanup + // fprintf (stderr, "2: this should always be executed\n"); + // return; + // fprintf (stderr, "2: this should never be executed\n"); + // end_unwind_protect + // endfunction + // + // If we reset the value of the breaking flag, both the returning + // flag and the breaking flag will be set, and we shouldn't have + // both. So, use the most recent one. If there is no return or + // break in the cleanup block, the values should be reset to + // whatever they were when the cleanup block was entered. - tree_statement_list *try_code = cmd.body (); + if (tree_break_command::breaking || tree_return_command::returning) + frame.discard (2); + else + frame.run (2); + } - if (try_code) + void + tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd) + { + tree_statement_list *cleanup_code = cmd.cleanup (); + + tree_statement_list *unwind_protect_code = cmd.body (); + + if (unwind_protect_code) { try { - in_try_catch++; - try_code->accept (*this); - in_try_catch--; + unwind_protect_code->accept (*this); } catch (const octave_execution_exception&) { + // FIXME: Maybe we should be able to temporarily set the + // interpreter's exception handling state to something "safe" + // while the cleanup block runs instead of just resetting it + // here? recover_from_exception (); - in_try_catch--; // must be restored before "catch" block - execution_error = true; + // Run the cleanup code on exceptions, so that it is run even + // in case of interrupt or out-of-memory. + do_unwind_protect_cleanup_code (cleanup_code); + + // If an error occurs inside the cleanup code, a new + // exception will be thrown instead of the original. + throw; } + + // Also execute the unwind_protect_cleanump code if the + // unwind_protect block runs without error. + do_unwind_protect_cleanup_code (cleanup_code); } - // Unwind to let the user print any messages from - // errors that occurred in the body of the try_catch statement, - // or throw further errors. } - if (execution_error) - { - tree_statement_list *catch_code = cmd.cleanup (); - if (catch_code) - { - tree_identifier *expr_id = cmd.identifier (); - octave_lvalue ult; - - if (expr_id) - { - ult = expr_id->lvalue (); - - octave_scalar_map err; - - err.assign ("message", last_error_message ()); - err.assign ("identifier", last_error_id ()); - err.assign ("stack", last_error_stack ()); - - ult.assign (octave_value::op_asn_eq, err); - } - - // perform actual "catch" block - if (catch_code) - catch_code->accept (*this); - } - } -} - -void -tree_evaluator::do_unwind_protect_cleanup_code (tree_statement_list *list) -{ - octave::unwind_protect frame; - - frame.protect_var (octave_interrupt_state); - octave_interrupt_state = 0; + void + tree_evaluator::visit_while_command (tree_while_command& cmd) + { +#if defined (HAVE_LLVM) + if (tree_jit::execute (cmd)) + return; +#endif - // We want to preserve the last location info for possible - // backtracking. - frame.add_fcn (octave_call_stack::set_line, - octave_call_stack::current_line ()); - frame.add_fcn (octave_call_stack::set_column, - octave_call_stack::current_column ()); + octave::unwind_protect frame; - // Similarly, if we have seen a return or break statement, allow all - // the cleanup code to run before returning or handling the break. - // We don't have to worry about continue statements because they can - // only occur in loops. - - frame.protect_var (tree_return_command::returning); - tree_return_command::returning = 0; - - frame.protect_var (tree_break_command::breaking); - tree_break_command::breaking = 0; + frame.protect_var (in_loop_command); - try - { - if (list) - list->accept (*this); - } - catch (const octave_execution_exception&) - { - recover_from_exception (); + in_loop_command = true; - if (tree_break_command::breaking || tree_return_command::returning) - frame.discard (2); - else - frame.run (2); + tree_expression *expr = cmd.condition (); - frame.discard (2); - - throw; - } + if (! expr) + panic_impossible (); - // The unwind_protects are popped off the stack in the reverse of - // the order they are pushed on. + for (;;) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); - // FIXME: these statements say that if we see a break or - // return statement in the cleanup block, that we want to use the - // new value of the breaking or returning flag instead of restoring - // the previous value. Is that the right thing to do? I think so. - // Consider the case of - // - // function foo () - // unwind_protect - // fprintf (stderr, "1: this should always be executed\n"); - // break; - // fprintf (stderr, "1: this should never be executed\n"); - // unwind_protect_cleanup - // fprintf (stderr, "2: this should always be executed\n"); - // return; - // fprintf (stderr, "2: this should never be executed\n"); - // end_unwind_protect - // endfunction - // - // If we reset the value of the breaking flag, both the returning - // flag and the breaking flag will be set, and we shouldn't have - // both. So, use the most recent one. If there is no return or - // break in the cleanup block, the values should be reset to - // whatever they were when the cleanup block was entered. + if (expr->is_logically_true ("while")) + { + tree_statement_list *loop_body = cmd.body (); - if (tree_break_command::breaking || tree_return_command::returning) - frame.discard (2); - else - frame.run (2); -} - -void -tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd) -{ - tree_statement_list *cleanup_code = cmd.cleanup (); + if (loop_body) + loop_body->accept (*this); - tree_statement_list *unwind_protect_code = cmd.body (); - - if (unwind_protect_code) - { - try - { - unwind_protect_code->accept (*this); - } - catch (const octave_execution_exception&) - { - // FIXME: Maybe we should be able to temporarily set the - // interpreter's exception handling state to something "safe" - // while the cleanup block runs instead of just resetting it - // here? - recover_from_exception (); + if (quit_loop_now ()) + break; + } + else + break; + } + } - // Run the cleanup code on exceptions, so that it is run even - // in case of interrupt or out-of-memory. - do_unwind_protect_cleanup_code (cleanup_code); - - // If an error occurs inside the cleanup code, a new - // exception will be thrown instead of the original. - throw; - } - - // Also execute the unwind_protect_cleanump code if the - // unwind_protect block runs without error. - do_unwind_protect_cleanup_code (cleanup_code); - } -} - -void -tree_evaluator::visit_while_command (tree_while_command& cmd) -{ + void + tree_evaluator::visit_do_until_command (tree_do_until_command& cmd) + { #if defined (HAVE_LLVM) - if (tree_jit::execute (cmd)) - return; + if (tree_jit::execute (cmd)) + return; #endif - octave::unwind_protect frame; - - frame.protect_var (in_loop_command); + octave::unwind_protect frame; - in_loop_command = true; + frame.protect_var (in_loop_command); - tree_expression *expr = cmd.condition (); + in_loop_command = true; - if (! expr) - panic_impossible (); + tree_expression *expr = cmd.condition (); + int until_line = cmd.line (); + int until_column = cmd.column (); - for (;;) - { - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - if (expr->is_logically_true ("while")) - { - tree_statement_list *loop_body = cmd.body (); + if (! expr) + panic_impossible (); - if (loop_body) - loop_body->accept (*this); + for (;;) + { + tree_statement_list *loop_body = cmd.body (); + + if (loop_body) + loop_body->accept (*this); - if (quit_loop_now ()) - break; - } - else - break; - } -} + if (quit_loop_now ()) + break; -void -tree_evaluator::visit_do_until_command (tree_do_until_command& cmd) -{ -#if defined (HAVE_LLVM) - if (tree_jit::execute (cmd)) - return; -#endif + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); - octave::unwind_protect frame; + octave_call_stack::set_location (until_line, until_column); - frame.protect_var (in_loop_command); - - in_loop_command = true; - - tree_expression *expr = cmd.condition (); - int until_line = cmd.line (); - int until_column = cmd.column (); + if (expr->is_logically_true ("do-until")) + break; + } + } - if (! expr) - panic_impossible (); - - for (;;) - { - tree_statement_list *loop_body = cmd.body (); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; + void + tree_evaluator::do_breakpoint (tree_statement& stmt) const + { + do_breakpoint (stmt.is_breakpoint (true), stmt.is_end_of_fcn_or_script ()); + } - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - octave_call_stack::set_location (until_line, until_column); + void + tree_evaluator::do_breakpoint (bool is_breakpoint, + bool is_end_of_fcn_or_script) const + { + bool break_on_this_statement = false; - if (expr->is_logically_true ("do-until")) - break; - } -} + if (octave_debug_on_interrupt_state) + { + break_on_this_statement = true; -void -tree_evaluator::do_breakpoint (tree_statement& stmt) const -{ - do_breakpoint (stmt.is_breakpoint (true), stmt.is_end_of_fcn_or_script ()); -} + octave_debug_on_interrupt_state = false; -void -tree_evaluator::do_breakpoint (bool is_breakpoint, - bool is_end_of_fcn_or_script) const -{ - bool break_on_this_statement = false; + current_frame = octave_call_stack::current_frame (); + } + else if (is_breakpoint) + { + break_on_this_statement = true; + + dbstep_flag = 0; - if (octave_debug_on_interrupt_state) - { - break_on_this_statement = true; - - octave_debug_on_interrupt_state = false; + current_frame = octave_call_stack::current_frame (); + } + else if (dbstep_flag > 0) + { + if (octave_call_stack::current_frame () == current_frame) + { + if (dbstep_flag == 1 || is_end_of_fcn_or_script) + { + // We get here if we are doing a "dbstep" or a "dbstep N" and the + // count has reached 1 so that we must stop and return to debug + // prompt. Alternatively, "dbstep N" has been used but the end + // of the frame has been reached so we stop at the last line and + // return to prompt. - current_frame = octave_call_stack::current_frame (); - } - else if (is_breakpoint) - { - break_on_this_statement = true; - - dbstep_flag = 0; + break_on_this_statement = true; - current_frame = octave_call_stack::current_frame (); - } - else if (dbstep_flag > 0) - { - if (octave_call_stack::current_frame () == current_frame) - { - if (dbstep_flag == 1 || is_end_of_fcn_or_script) - { - // We get here if we are doing a "dbstep" or a "dbstep N" and the - // count has reached 1 so that we must stop and return to debug - // prompt. Alternatively, "dbstep N" has been used but the end - // of the frame has been reached so we stop at the last line and - // return to prompt. + dbstep_flag = 0; + } + else + { + // Executing "dbstep N". Decrease N by one and continue. + + dbstep_flag--; + } - break_on_this_statement = true; + } + else if (dbstep_flag == 1 + && octave_call_stack::current_frame () < current_frame) + { + // We stepped out from the end of a function. - dbstep_flag = 0; - } - else - { - // Executing "dbstep N". Decrease N by one and continue. + current_frame = octave_call_stack::current_frame (); - dbstep_flag--; - } + break_on_this_statement = true; - } - else if (dbstep_flag == 1 - && octave_call_stack::current_frame () < current_frame) - { - // We stepped out from the end of a function. - - current_frame = octave_call_stack::current_frame (); - - break_on_this_statement = true; + dbstep_flag = 0; + } + } + else if (dbstep_flag == -1) + { + // We get here if we are doing a "dbstep in". - dbstep_flag = 0; - } - } - else if (dbstep_flag == -1) - { - // We get here if we are doing a "dbstep in". + break_on_this_statement = true; - break_on_this_statement = true; - - dbstep_flag = 0; + dbstep_flag = 0; - current_frame = octave_call_stack::current_frame (); - } - else if (dbstep_flag == -2) - { - // We get here if we are doing a "dbstep out". Check for end of - // function and whether the current frame is the same as the - // cached value because we want to step out from the frame where - // "dbstep out" was evaluated, not from any functions called from - // that frame. + current_frame = octave_call_stack::current_frame (); + } + else if (dbstep_flag == -2) + { + // We get here if we are doing a "dbstep out". Check for end of + // function and whether the current frame is the same as the + // cached value because we want to step out from the frame where + // "dbstep out" was evaluated, not from any functions called from + // that frame. + + if (is_end_of_fcn_or_script + && octave_call_stack::current_frame () == current_frame) + dbstep_flag = -1; + } - if (is_end_of_fcn_or_script - && octave_call_stack::current_frame () == current_frame) - dbstep_flag = -1; - } + if (break_on_this_statement) + do_keyboard (); - if (break_on_this_statement) - do_keyboard (); + } -} + // ARGS is currently unused, but since the do_keyboard function in + // input.cc accepts an argument list, we preserve it here so that the + // interface won't have to change if we decide to use it in the future. -// ARGS is currently unused, but since the do_keyboard function in -// input.cc accepts an argument list, we preserve it here so that the -// interface won't have to change if we decide to use it in the future. - -octave_value -tree_evaluator::do_keyboard (const octave_value_list& args) const -{ - return ::do_keyboard (args); + octave_value + tree_evaluator::do_keyboard (const octave_value_list& args) const + { + return ::do_keyboard (args); + } } DEFUN (max_recursion_depth, args, nargout, diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/parse-tree/pt-eval.h --- a/libinterp/parse-tree/pt-eval.h Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/pt-eval.h Tue Jul 12 14:28:07 2016 -0400 @@ -34,162 +34,169 @@ class tree_expression; -// How to evaluate the code that the parse trees represent. +namespace octave +{ + class interpreter; -class -OCTINTERP_API -tree_evaluator : public tree_walker -{ -public: + // How to evaluate the code that the parse trees represent. - typedef void (*decl_elt_init_fcn) (tree_decl_elt&); - - tree_evaluator (void) { } + class + OCTINTERP_API + tree_evaluator : public tree_walker + { + public: - ~tree_evaluator (void) { } + typedef void (*decl_elt_init_fcn) (tree_decl_elt&); - void visit_anon_fcn_handle (tree_anon_fcn_handle&); + tree_evaluator (interpreter *interp_context) + : m_interp_context (interp_context) + { } - void visit_argument_list (tree_argument_list&); + ~tree_evaluator (void) { } - void visit_binary_expression (tree_binary_expression&); + void visit_anon_fcn_handle (tree_anon_fcn_handle&); - void visit_break_command (tree_break_command&); + void visit_argument_list (tree_argument_list&); - void visit_colon_expression (tree_colon_expression&); + void visit_binary_expression (tree_binary_expression&); - void visit_continue_command (tree_continue_command&); + void visit_break_command (tree_break_command&); - void visit_global_command (tree_global_command&); + void visit_colon_expression (tree_colon_expression&); - void visit_persistent_command (tree_persistent_command&); + void visit_continue_command (tree_continue_command&); - void visit_decl_elt (tree_decl_elt&); + void visit_global_command (tree_global_command&); - void visit_decl_init_list (tree_decl_init_list&); + void visit_persistent_command (tree_persistent_command&); - void visit_simple_for_command (tree_simple_for_command&); + void visit_decl_elt (tree_decl_elt&); - void visit_complex_for_command (tree_complex_for_command&); + void visit_decl_init_list (tree_decl_init_list&); - void visit_octave_user_script (octave_user_script&); + void visit_simple_for_command (tree_simple_for_command&); - void visit_octave_user_function (octave_user_function&); + void visit_complex_for_command (tree_complex_for_command&); - void visit_octave_user_function_header (octave_user_function&); + void visit_octave_user_script (octave_user_script&); - void visit_octave_user_function_trailer (octave_user_function&); + void visit_octave_user_function (octave_user_function&); - void visit_function_def (tree_function_def&); + void visit_octave_user_function_header (octave_user_function&); - void visit_identifier (tree_identifier&); + void visit_octave_user_function_trailer (octave_user_function&); - void visit_if_clause (tree_if_clause&); + void visit_function_def (tree_function_def&); - void visit_if_command (tree_if_command&); + void visit_identifier (tree_identifier&); - void visit_if_command_list (tree_if_command_list&); + void visit_if_clause (tree_if_clause&); - void visit_index_expression (tree_index_expression&); + void visit_if_command (tree_if_command&); - void visit_matrix (tree_matrix&); + void visit_if_command_list (tree_if_command_list&); - void visit_cell (tree_cell&); + void visit_index_expression (tree_index_expression&); - void visit_multi_assignment (tree_multi_assignment&); + void visit_matrix (tree_matrix&); - void visit_no_op_command (tree_no_op_command&); + void visit_cell (tree_cell&); - void visit_constant (tree_constant&); + void visit_multi_assignment (tree_multi_assignment&); - void visit_fcn_handle (tree_fcn_handle&); + void visit_no_op_command (tree_no_op_command&); - void visit_funcall (tree_funcall&); + void visit_constant (tree_constant&); + + void visit_fcn_handle (tree_fcn_handle&); - void visit_parameter_list (tree_parameter_list&); + void visit_funcall (tree_funcall&); - void visit_postfix_expression (tree_postfix_expression&); + void visit_parameter_list (tree_parameter_list&); - void visit_prefix_expression (tree_prefix_expression&); + void visit_postfix_expression (tree_postfix_expression&); - void visit_return_command (tree_return_command&); + void visit_prefix_expression (tree_prefix_expression&); - void visit_return_list (tree_return_list&); + void visit_return_command (tree_return_command&); - void visit_simple_assignment (tree_simple_assignment&); + void visit_return_list (tree_return_list&); - void visit_statement (tree_statement&); + void visit_simple_assignment (tree_simple_assignment&); + + void visit_statement (tree_statement&); - void visit_statement_list (tree_statement_list&); + void visit_statement_list (tree_statement_list&); - void visit_switch_case (tree_switch_case&); + void visit_switch_case (tree_switch_case&); - void visit_switch_case_list (tree_switch_case_list&); + void visit_switch_case_list (tree_switch_case_list&); - void visit_switch_command (tree_switch_command&); + void visit_switch_command (tree_switch_command&); - void visit_try_catch_command (tree_try_catch_command&); + void visit_try_catch_command (tree_try_catch_command&); - void do_unwind_protect_cleanup_code (tree_statement_list *list); + void do_unwind_protect_cleanup_code (tree_statement_list *list); - void visit_unwind_protect_command (tree_unwind_protect_command&); + void visit_unwind_protect_command (tree_unwind_protect_command&); - void visit_while_command (tree_while_command&); + void visit_while_command (tree_while_command&); - void visit_do_until_command (tree_do_until_command&); + void visit_do_until_command (tree_do_until_command&); - static void reset_debug_state (void); + static void reset_debug_state (void); - static bool statement_printing_enabled (void); + static bool statement_printing_enabled (void); - // If > 0, stop executing at the (N-1)th stopping point, counting - // from the the current execution point in the current frame. - // - // If < 0, stop executing at the next possible stopping point. - static int dbstep_flag; + // If > 0, stop executing at the (N-1)th stopping point, counting + // from the the current execution point in the current frame. + // + // If < 0, stop executing at the next possible stopping point. + static int dbstep_flag; - // The number of the stack frame we are currently debugging. - static size_t current_frame; + // The number of the stack frame we are currently debugging. + static size_t current_frame; - static bool debug_mode; + static bool debug_mode; - static bool quiet_breakpoint_flag; + static bool quiet_breakpoint_flag; - // Possible types of evaluation contexts. - enum stmt_list_type - { - function, // function body - script, // script file - other // command-line input or eval string - }; + // Possible types of evaluation contexts. + enum stmt_list_type + { + function, // function body + script, // script file + other // command-line input or eval string + }; - // The context for the current evaluation. - static stmt_list_type statement_context; + // The context for the current evaluation. + static stmt_list_type statement_context; - // TRUE means we are evaluating some kind of looping construct. - static bool in_loop_command; + // TRUE means we are evaluating some kind of looping construct. + static bool in_loop_command; -private: + private: - void do_decl_init_list (decl_elt_init_fcn fcn, - tree_decl_init_list *init_list); + void do_decl_init_list (decl_elt_init_fcn fcn, + tree_decl_init_list *init_list); - void do_breakpoint (tree_statement& stmt) const; + void do_breakpoint (tree_statement& stmt) const; - void do_breakpoint (bool is_breakpoint, - bool is_end_of_fcn_or_script = false) const; + void do_breakpoint (bool is_breakpoint, + bool is_end_of_fcn_or_script = false) const; - virtual octave_value - do_keyboard (const octave_value_list& args = octave_value_list ()) const; + virtual octave_value + do_keyboard (const octave_value_list& args = octave_value_list ()) const; - // No copying! + interpreter *m_interp_context; - tree_evaluator (const tree_evaluator&); + // No copying! + + tree_evaluator (const tree_evaluator&); - tree_evaluator& operator = (const tree_evaluator&); -}; - -extern tree_evaluator *current_evaluator; + tree_evaluator& operator = (const tree_evaluator&); + }; +} // Maximum nesting level for functions, scripts, or sourced files called // recursively. diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/parse-tree/pt-exp.h --- a/libinterp/parse-tree/pt-exp.h Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/pt-exp.h Tue Jul 12 14:28:07 2016 -0400 @@ -95,7 +95,7 @@ // Check if the result of the expression should be printed. // Should normally be used in conjunction with - // tree_evaluator::statement_printing_enabled. + // octave::tree_evaluator::statement_printing_enabled. bool print_result (void) const { return print_flag; } virtual std::string oper (void) const { return ""; } diff -r 93ed9396f2c3 -r dd992fd74fce libinterp/parse-tree/pt-id.cc --- a/libinterp/parse-tree/pt-id.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/pt-id.cc Tue Jul 12 14:28:07 2016 -0400 @@ -94,7 +94,7 @@ else { if (print_result () && nargout == 0 - && tree_evaluator::statement_printing_enabled ()) + && octave::tree_evaluator::statement_printing_enabled ()) val.print_with_name (octave_stdout, name ()); retval = val;