# HG changeset patch # User John W. Eaton # Date 1588786462 14400 # Node ID 4ee43852f5b6829807155f6d7384192ce7f4e2d5 # Parent 6b6cb174d6bbee96a36a267ef530bbf9c894df66# Parent ce7a5b60e1028838283e1af01beb1594994b87ea maint: merge stable to default. diff -r 6b6cb174d6bb -r 4ee43852f5b6 libinterp/corefcn/interpreter.cc --- a/libinterp/corefcn/interpreter.cc Tue May 05 01:10:39 2020 -0400 +++ b/libinterp/corefcn/interpreter.cc Wed May 06 13:34:22 2020 -0400 @@ -1057,25 +1057,48 @@ int interpreter::main_loop (void) { + // The big loop. Read, Eval, Print, Loop. Normally user + // interaction at the command line in a terminal session, but we may + // also end up here when reading from a pipe or when stdin is + // connected to a file by the magic of input redirection. + int exit_status = 0; - // The big loop. + // FIXME: should this choice be a command-line option? Note that we + // intend that the push parser interface only be used for + // interactive sessions. #if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) - - input_reader reader (*this); + static bool use_command_line_push_parser = true; +#else + static bool use_command_line_push_parser = false; +#endif - push_parser repl_parser (*this); + // The following logic is written as it is to allow easy transition + // to setting USE_COMMAND_LINE_PUSH_PARSER at run time and to + // simplify the logic of the main loop below by using the same + // base_parser::run interface for both push and pull parsers. -#else + std::shared_ptr repl_parser; - // The pull parser takes ownership of the lexer and will delete it - // when the parser goes out of scope. - - parser repl_parser (m_interactive - ? new lexer (*this) : new lexer (stdin, *this)); - -#endif + if (m_interactive) + { + if (use_command_line_push_parser) + { + push_parser *pp = new push_parser (*this, new input_reader (*this)); + repl_parser = std::shared_ptr (pp); + } + else + { + parser *pp = new parser (new lexer (*this)); + repl_parser = std::shared_ptr (pp); + } + } + else + { + parser *pp = new parser (new lexer (stdin, *this)); + repl_parser = std::shared_ptr (pp); + } do { @@ -1083,7 +1106,7 @@ { unwind_protect_var upv (m_in_top_level_repl, true); - repl_parser.reset (); + repl_parser->reset (); if (m_evaluator.at_top_level ()) { @@ -1091,44 +1114,12 @@ m_evaluator.reset_debug_state (); } -#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) - - std::string prompt - = command_editor::decode_prompt_string (m_input_system.PS1 ()); - - do - { - // Reset status each time through the read loop so that - // it won't be set to -1 and cause us to exit the outer - // loop early if there is an exception while reading - // input or parsing. - - exit_status = 0; - - bool eof = false; - std::string input_line = reader.get_input (prompt, eof); + exit_status = repl_parser->run (); - if (eof) - { - exit_status = EOF; - break; - } - - exit_status = repl_parser.run (input_line, false); - - prompt = command_editor::decode_prompt_string (m_input_system.PS2 ()); - } - while (exit_status < 0); - -#else - - exit_status = repl_parser.run (); - -#endif if (exit_status == 0) { std::shared_ptr - stmt_list = repl_parser.statement_list (); + stmt_list = repl_parser->statement_list (); if (stmt_list) { @@ -1136,7 +1127,7 @@ m_evaluator.eval (stmt_list, m_interactive); } - else if (repl_parser.at_end_of_input ()) + else if (repl_parser->at_end_of_input ()) { exit_status = EOF; break; diff -r 6b6cb174d6bb -r 4ee43852f5b6 libinterp/parse-tree/oct-parse.yy --- a/libinterp/parse-tree/oct-parse.yy Tue May 05 01:10:39 2020 -0400 +++ b/libinterp/parse-tree/oct-parse.yy Wed May 06 13:34:22 2020 -0400 @@ -4717,6 +4717,46 @@ return status; } + int + push_parser::run (void) + { + if (! m_reader) + error ("push_parser::run requires valid input_reader"); + + int exit_status = 0; + + input_system& input_sys = m_interpreter.get_input_system (); + + std::string prompt + = command_editor::decode_prompt_string (input_sys.PS1 ()); + + do + { + // Reset status each time through the read loop so that + // it won't be set to -1 and cause us to exit the outer + // loop early if there is an exception while reading + // input or parsing. + + exit_status = 0; + + bool eof = false; + std::string input_line = m_reader->get_input (prompt, eof); + + if (eof) + { + exit_status = EOF; + break; + } + + exit_status = run (input_line, false); + + prompt = command_editor::decode_prompt_string (input_sys.PS2 ()); + } + while (exit_status < 0); + + return exit_status; + } + octave_value parse_fcn_file (interpreter& interp, const std::string& full_file, const std::string& file, const std::string& dir_name, diff -r 6b6cb174d6bb -r 4ee43852f5b6 libinterp/parse-tree/parse.h --- a/libinterp/parse-tree/parse.h Tue May 05 01:10:39 2020 -0400 +++ b/libinterp/parse-tree/parse.h Wed May 06 13:34:22 2020 -0400 @@ -36,6 +36,7 @@ #include #include +#include "input.h" #include "lex.h" #include "pt-misc.h" #include "symscope.h" @@ -466,6 +467,14 @@ const std::string& package_name, bool require_file, bool force_script, bool autoload, bool relative_lookup); + // Thih interface allows push or pull parsers to be used + // equivalently, provided that the push parser also owns its input + // method (see below). Alternatively, the push parser interface may + // use a separate run method and completely separate input from + // lexical analysis and parsing. + + virtual int run (void) = 0; + protected: // Contains error message if Bison-generated parser returns non-zero @@ -599,7 +608,16 @@ public: push_parser (interpreter& interp) - : base_parser (*(new push_lexer (interp))) + : base_parser (*(new push_lexer (interp))), + m_interpreter (interp), m_reader () + { } + + // The parser assumes ownership of READER, which must be created + // with new. + + push_parser (interpreter& interp, input_reader *reader) + : base_parser (*(new push_lexer (interp))), + m_interpreter (interp), m_reader (reader) { } // No copying! @@ -610,7 +628,22 @@ ~push_parser (void) = default; + // Use the push parser in the same way as the pull parser. The + // parser arranges for input through the M_READER object. See, for + // example, interpreter::main_loop. + + int run (void); + + // Parse INPUT. M_READER is not used. The user is responsible for + // collecting input. + int run (const std::string& input, bool eof); + + private: + + interpreter& m_interpreter; + + std::shared_ptr m_reader; }; extern OCTINTERP_API std::string