Mercurial > hg > octave-kai
changeset 9474:25ed2d6aacf6
Parse nested functions more accurately.
author | David Grundberg <individ@acc.umu.se> |
---|---|
date | Thu, 30 Jul 2009 11:52:58 -0400 |
parents | 833109a9f37f |
children | 983de84e4bf3 |
files | doc/interpreter/contributors.in src/ChangeLog src/lex.h src/lex.l src/parse.h src/parse.y src/symtab.cc src/symtab.h |
diffstat | 8 files changed, 252 insertions(+), 272 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/interpreter/contributors.in +++ b/doc/interpreter/contributors.in @@ -62,6 +62,7 @@ Brian Gough Steffen Groot Etienne Grossmann +David Grundberg Peter Gustafson Kai Habel William P. Y. Hadisoeseno
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,48 @@ +2009-07-30 David Grundberg <individ@acc.umu.se> + + * symtab.h (symbol_table::parent_scope): Remove. + (symbol_table::set_parent_scope): Remove. + (symbol_table::reset_parent_scope): Remove. + (symbol_table::install_subfunction): Require scope parameter + instead of xparent_scope default. + * symtab.cc: Remove symbol_table::xparent_scope + * lex.h (lexical_feedback::parsing_nested_function): Remove. + * lex.l (is_keyword_token): Don't ignore endfunctions. + (prep_lexer_for_script_file): Renamed from prep_lexer_for_script. + (prep_lexer_for_function_file): New function. + (display_token): Display SCRIPT_FILE and FUNCTION_FILE. + (display_state): Display FUNCTION_FILE_BEGIN + (FUNCTION_FILE_BEGIN): New state. + (NESTED_FUNCTION_END, NESTED_FUNCTION_BEGIN): Remove states. + (prep_for_function, prep_for_nested_function): Remove functions. + * parse.h: Remove extern declaration parent_function_name, + end_tokens_expected. + * parse.y: Add variables current_function_depth, + max_function_depth, parsing_subfunctions, seen_endfunction. Remove + parent_function_name. Rename curr_fcn_ptr to primary_fcn_ptr. Add + token FUNCTION_FILE. Rename token SCRIPT to SCRIPT_FILE. + (function_file): New rule. + (input): Accept function_file. + (script_file): Rule renamed from script. + (function_file): New rule. + (function_list): New rule. + (push_fcn_symtab): Parse nested functions. + (fcn_name): Remove parent_function_name. + (function_end): Use seen_endfunction. New error messages. + (make_script): Use primary_fcn_ptr. + (frob_function): Simplify control structures. Don't use + symbol_table::parent_scope. + (push_fcn_symtab, function_end, frob_function, finish_function): + Use current_function_depth instead of + lexical_feedback::parsing_nested_function. + (make_return_command): Use current_function_depth instead of + lexical_feedback::defining_func. + (make_break_command, make_decl_command, maybe_warn_missing_semi): + Ditto + (parse_fcn_file): Warn when nested functions have been + declared. Remove superfluous local variables. Parse function files + using function_file rule. + 2009-07-30 Jaroslav Hajek <highegg@gmail.com> * data.cc (Fmerge): New DEFUN.
--- a/src/lex.h +++ b/src/lex.h @@ -46,7 +46,8 @@ // Is the given string a keyword? extern bool is_keyword (const std::string& s); -extern void prep_lexer_for_script (void); +extern void prep_lexer_for_script_file (void); +extern void prep_lexer_for_function_file (void); // For communication between the lexer and parser. @@ -117,15 +118,9 @@ bool looking_at_indirect_ref; // TRUE means that we've already seen the name of this function. - // Should only matter if defining_func is also TRUE. + // Should only matter if current_function_level > 0 bool parsed_function_name; - // Are we parsing a nested function? - // 1 ==> Yes. - // 0 ==> No. - // -1 ==> Yes, but it is the last one because we have seen EOF. - int parsing_nested_function; - // TRUE means we are parsing a class method. bool parsing_class_method;
--- a/src/lex.l +++ b/src/lex.l @@ -28,9 +28,7 @@ %s MATRIX_START %x SCRIPT_FILE_BEGIN - -%x NESTED_FUNCTION_END -%x NESTED_FUNCTION_BEGIN +%x FUNCTION_FILE_BEGIN %{ #ifdef HAVE_CONFIG_H @@ -282,8 +280,6 @@ static void fixup_column_count (char *s); static void do_comma_insert_check (void); static int is_keyword_token (const std::string& s); -static void prep_for_function (void); -static void prep_for_nested_function (void); static int process_comment (bool start_in_block, bool& eof); static bool match_any (char c, const char *s); static bool next_token_is_sep_op (void); @@ -329,34 +325,25 @@ NUMBER (({D}+\.?{D}*{EXPON}?)|(\.{D}+{EXPON}?)|(0[xX][0-9a-fA-F]+)) %% +%{ +// Make script and function files start with a bogus token. This makes +// the parser go down a special path. +%} + <SCRIPT_FILE_BEGIN>. { LEXER_DEBUG ("<SCRIPT_FILE_BEGIN>."); BEGIN (INITIAL); xunput (yytext[0], yytext); - COUNT_TOK_AND_RETURN (SCRIPT); + COUNT_TOK_AND_RETURN (SCRIPT_FILE); } -<NESTED_FUNCTION_END>. { - LEXER_DEBUG ("<NESTED_FUNCTION_END>."); - - BEGIN (NESTED_FUNCTION_BEGIN); - xunput (yytext[0], yytext); - - lexer_flags.at_beginning_of_statement = true; - - COUNT_TOK_AND_RETURN (';'); - } - -<NESTED_FUNCTION_BEGIN>. { - LEXER_DEBUG ("<NESTED_FUNCTION_BEGIN>."); +<FUNCTION_FILE_BEGIN>. { + LEXER_DEBUG ("<FUNCTION_FILE_BEGIN>."); BEGIN (INITIAL); xunput (yytext[0], yytext); - - prep_for_nested_function (); - - COUNT_TOK_AND_RETURN (FCN); + COUNT_TOK_AND_RETURN (FUNCTION_FILE); } %{ @@ -1004,8 +991,6 @@ . { LEXER_DEBUG ("."); - // EOF happens here if we are parsing nested functions. - xunput (yytext[0], yytext); int c = text_yyinput (); @@ -1058,13 +1043,10 @@ BEGIN (INITIAL); parser_end_of_input = false; - end_tokens_expected = 0; while (! symtab_context.empty ()) symtab_context.pop (); - symbol_table::reset_parent_scope (); - // We do want a prompt by default. promptflag = 1; @@ -1381,32 +1363,6 @@ delete_buffer (static_cast<YY_BUFFER_STATE> (buf)); } -static void -prep_for_function (void) -{ - end_tokens_expected++; - - promptflag--; - - lexer_flags.defining_func = true; - lexer_flags.parsed_function_name = false; - - if (! (reading_fcn_file || reading_script_file)) - input_line_number = 1; -} - -static void -prep_for_nested_function (void) -{ - lexer_flags.parsing_nested_function = 1; - help_buf.push (std::string ()); - prep_for_function (); - // We're still only expecting one end token for this set of functions. - end_tokens_expected--; - yylval.tok_val = new token (input_line_number, current_input_column); - token_stack.push (yylval.tok_val); -} - static bool inside_any_object_index (void) { @@ -1466,71 +1422,48 @@ && ! (lexer_flags.looking_at_return_list || lexer_flags.parsed_function_name))) return 0; - else - { - if (reading_fcn_file && end_tokens_expected == 1) - return -1; - else - { - yylval.tok_val = new token (token::simple_end, l, c); - lexer_flags.at_beginning_of_statement = true; - end_tokens_expected--; - } - } + + yylval.tok_val = new token (token::simple_end, l, c); + lexer_flags.at_beginning_of_statement = true; break; case end_try_catch_kw: yylval.tok_val = new token (token::try_catch_end, l, c); lexer_flags.at_beginning_of_statement = true; - end_tokens_expected--; break; case end_unwind_protect_kw: yylval.tok_val = new token (token::unwind_protect_end, l, c); lexer_flags.at_beginning_of_statement = true; - end_tokens_expected--; break; case endfor_kw: yylval.tok_val = new token (token::for_end, l, c); lexer_flags.at_beginning_of_statement = true; - end_tokens_expected--; break; case endfunction_kw: - { - if (reading_fcn_file && end_tokens_expected == 1) - return -1; - else - { - yylval.tok_val = new token (token::function_end, l, c); - lexer_flags.at_beginning_of_statement = true; - end_tokens_expected--; - } - } + yylval.tok_val = new token (token::function_end, l, c); + lexer_flags.at_beginning_of_statement = true; break; case endif_kw: yylval.tok_val = new token (token::if_end, l, c); lexer_flags.at_beginning_of_statement = true; - end_tokens_expected--; break; case endswitch_kw: yylval.tok_val = new token (token::switch_end, l, c); lexer_flags.at_beginning_of_statement = true; - end_tokens_expected--; break; case endwhile_kw: yylval.tok_val = new token (token::while_end, l, c); lexer_flags.at_beginning_of_statement = true; - end_tokens_expected--; break; case for_kw: case while_kw: - end_tokens_expected++; promptflag--; lexer_flags.looping++; break; @@ -1544,57 +1477,22 @@ case try_kw: case unwind_protect_kw: lexer_flags.at_beginning_of_statement = true; - end_tokens_expected++; promptflag--; break; case if_kw: case switch_kw: - end_tokens_expected++; promptflag--; break; case function_kw: - { - if (lexer_flags.defining_func) - { - if (reading_fcn_file) - { - if (lexer_flags.parsing_nested_function) - { - BEGIN (NESTED_FUNCTION_END); - - yylval.tok_val = new token (token::function_end, l, c); - token_stack.push (yylval.tok_val); - - lexer_flags.at_beginning_of_statement = true; - - return END; - } - else - { - prep_for_nested_function (); - - return FCN; - } - } - else - { - error ("nested functions not implemented in this context"); - - if ((reading_fcn_file || reading_script_file) - && ! curr_fcn_file_name.empty ()) - error ("near line %d of file `%s.m'", - input_line_number, curr_fcn_file_name.c_str ()); - else - error ("near line %d", input_line_number); - - return LEXICAL_ERROR; - } - } - else - prep_for_function (); - } + promptflag--; + + lexer_flags.defining_func = true; + lexer_flags.parsed_function_name = false; + + if (! (reading_fcn_file || reading_script_file)) + input_line_number = 1; break; case magic_file_kw: @@ -3254,7 +3152,6 @@ // Not initially defining a function. defining_func = false; parsed_function_name = false; - parsing_nested_function = 0; parsing_class_method = false; // Not initiallly looking at a function handle. @@ -3341,11 +3238,17 @@ } void -prep_lexer_for_script (void) +prep_lexer_for_script_file (void) { BEGIN (SCRIPT_FILE_BEGIN); } +void +prep_lexer_for_function_file (void) +{ + BEGIN (FUNCTION_FILE_BEGIN); +} + static void maybe_warn_separator_insert (char sep) { @@ -3495,6 +3398,8 @@ case LEXICAL_ERROR: std::cerr << "LEXICAL_ERROR\n\n"; break; case FCN: std::cerr << "FCN\n"; break; case CLOSE_BRACE: std::cerr << "CLOSE_BRACE\n"; break; + case SCRIPT_FILE: std::cerr << "SCRIPT_FILE\n"; break; + case FUNCTION_FILE: std::cerr << "FUNCTION_FILE\n"; break; case '\n': std::cerr << "\\n\n"; break; case '\r': std::cerr << "\\r\n"; break; case '\t': std::cerr << "TAB\n"; break; @@ -3532,12 +3437,8 @@ std::cerr << "SCRIPT_FILE_BEGIN" << std::endl; break; - case NESTED_FUNCTION_END: - std::cerr << "NESTED_FUNCTION_END" << std::endl; - break; - - case NESTED_FUNCTION_BEGIN: - std::cerr << "NESTED_FUNCTION_BEGIN" << std::endl; + case FUNCTION_FILE_BEGIN: + std::cerr << "FUNCTION_FILE_BEGIN" << std::endl; break; default:
--- a/src/parse.h +++ b/src/parse.h @@ -65,17 +65,10 @@ // Keep track of symbol table information when parsing functions. extern std::stack<symbol_table::scope_id> symtab_context; -// Name of parent function when parsing function files that might -// contain nested functions. -extern std::string parent_function_name; - // Name of the current class when we are parsing class methods or // constructors. extern std::string current_class_name; -// Keep a count of how many END tokens we expect. -extern int end_tokens_expected; - extern OCTINTERP_API std::string get_help_from_file (const std::string& nm, bool& symbol_found, std::string& file);
--- a/src/parse.y +++ b/src/parse.y @@ -2,6 +2,7 @@ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 John W. Eaton +Copyright (C) 2009 David Grundberg This file is part of Octave. @@ -100,16 +101,27 @@ // TRUE means input is coming from startup file. bool input_from_startup_file = false; -// Keep a count of how many END tokens we expect. -int end_tokens_expected = 0; +// = 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. +static int current_function_depth = 0; + +// Maximum function depth detected. Just here to determine whether +// we have nested functions or just implicitly ended subfunctions. +static int max_function_depth = 0; + +// FALSE if we are still at the primary function. Subfunctions can +// only be declared inside function files. +static int parsing_subfunctions = false; + +// Have we found an explicit end to a function? +static bool endfunction_found = false; // Keep track of symbol table information when parsing functions. std::stack<symbol_table::scope_id> symtab_context; -// Name of parent function when parsing function files that might -// contain nested functions. -std::string parent_function_name; - // Name of the current class when we are parsing class methods or // constructors. std::string current_class_name; @@ -121,9 +133,12 @@ // element. static bool fcn_file_from_relative_lookup = false; -// If nonzero, this is a pointer to the function we just finished -// parsing. -static octave_function *curr_fcn_ptr = 0; +// Pointer to the primary user function or user script function. +static octave_function *primary_fcn_ptr = 0; + +// Scope where we install all subfunctions and nested functions. Only +// used while reading function files. +static symbol_table::scope_id primary_fcn_scope; // List of autoloads (function -> file mapping). static std::map<std::string, std::string> autoload_map; @@ -424,7 +439,7 @@ // Other tokens. %token END_OF_INPUT LEXICAL_ERROR -%token FCN SCRIPT +%token FCN SCRIPT_FILE FUNCTION_FILE // %token VARARGIN VARARGOUT %token CLOSE_BRACE @@ -449,7 +464,8 @@ %type <tree_parameter_list_type> param_list param_list1 param_list2 %type <tree_parameter_list_type> return_list return_list1 %type <tree_command_type> command select_command loop_command -%type <tree_command_type> jump_command except_command function script +%type <tree_command_type> jump_command except_command function script_file +%type <tree_command_type> function_file function_list %type <tree_if_command_type> if_command %type <tree_if_clause_type> elseif_clause else_clause %type <tree_if_command_list_type> if_cmd_list1 if_cmd_list @@ -494,6 +510,10 @@ promptflag = 1; YYACCEPT; } + | function_file + { + YYACCEPT; + } | simple_list parse_error { ABORT_PARSE; } | parse_error @@ -903,7 +923,7 @@ { $$ = $1; } | function { $$ = $1; } - | script + | script_file { $$ = $1; } ; @@ -1112,11 +1132,20 @@ push_fcn_symtab : // empty { + current_function_depth++; + + if (max_function_depth < current_function_depth) + max_function_depth = current_function_depth; + symtab_context.push (symbol_table::current_scope ()); symbol_table::set_scope (symbol_table::alloc_scope ()); - if (! lexer_flags.parsing_nested_function) - symbol_table::set_parent_scope (symbol_table::current_scope ()); + if (! reading_script_file && current_function_depth == 1 + && ! parsing_subfunctions) + primary_fcn_scope = symbol_table::current_scope (); + + if (reading_script_file && current_function_depth > 1) + yyerror ("nested functions not implemented in this context"); } ; @@ -1218,7 +1247,7 @@ // Script file // =========== -script : SCRIPT opt_list END_OF_INPUT +script_file : SCRIPT_FILE opt_list END_OF_INPUT { tree_statement *end_of_script = make_end ("endscript", input_line_number, @@ -1230,6 +1259,17 @@ } ; +// ============= +// Function file +// ============= + +function_file : FUNCTION_FILE function_list opt_sep END_OF_INPUT + ; + +function_list : function + | function_list sep function + ; + // =================== // Function definition // =================== @@ -1254,12 +1294,8 @@ { std::string id_name = $1->name (); - if (reading_fcn_file - && ! lexer_flags.parsing_nested_function) - parent_function_name = (curr_fcn_file_name == id_name) - ? id_name : curr_fcn_file_name; - lexer_flags.parsed_function_name = true; + lexer_flags.defining_func = false; $$ = $1; } @@ -1284,6 +1320,7 @@ function_end : END { + endfunction_found = true; if (end_token_ok ($1, token::function_end)) $$ = make_end ("endfunction", $1->line (), $1->column ()); else @@ -1291,15 +1328,29 @@ } | END_OF_INPUT { - if (lexer_flags.parsing_nested_function) - lexer_flags.parsing_nested_function = -1; - - if (reading_fcn_file || reading_script_file - || get_input_from_eval_string) - $$ = make_end ("endfunction", input_line_number, - current_input_column); - else - YYABORT; +// A lot of tests are based on the assumption that this is OK +// if (reading_script_file) +// { +// yyerror ("function body open at end of script"); +// YYABORT; +// } + + if (endfunction_found) + { + yyerror ("inconsistent function endings -- " + "if one function is explicitly ended, " + "so must all the others"); + YYABORT; + } + + if (! reading_fcn_file && ! reading_script_file) + { + yyerror ("function body open at end of input"); + YYABORT; + } + + $$ = make_end ("endfunction", input_line_number, + current_input_column); } ; @@ -2241,7 +2292,7 @@ // so that we don't turn eval ("break;") inside a function, script, // or loop into a no-op command. - if (lexer_flags.looping || lexer_flags.defining_func + if (lexer_flags.looping || current_function_depth > 0 || reading_script_file || tree_evaluator::in_fcn_or_script_body || tree_evaluator::in_loop_command) retval = new tree_break_command (l, c); @@ -2294,7 +2345,7 @@ // that we don't turn eval ("return;") inside a function, script, // or loop into a no-op command. - if (lexer_flags.defining_func || reading_script_file + if (current_function_depth > 0 || reading_script_file || tree_evaluator::in_fcn_or_script_body) retval = new tree_return_command (l, c); else @@ -2503,7 +2554,7 @@ return retval; } -// Define a function. +// Define a script. static void make_script (tree_statement_list *cmds, tree_statement *end_script) @@ -2529,7 +2580,7 @@ script->stash_fcn_file_time (now); - curr_fcn_ptr = script; + primary_fcn_ptr = script; // Unmark any symbols that may have been tagged as local variables // while parsing (for example, by force_local_variable in lex.l). @@ -2581,35 +2632,34 @@ // 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 && reading_fcn_file + && (current_function_depth == 1 + && ! (parsing_subfunctions || lexer_flags.parsing_class_method))) + { + // FIXME -- should curr_fcn_file_name already be + // preprocessed when we get here? It seems to only be a + // problem with relative file names. + + std::string nm = curr_fcn_file_name; + + size_t pos = nm.find_last_of (file_ops::dir_sep_chars ()); + + if (pos != std::string::npos) + nm = curr_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 file name `%s'", + id_name.c_str (), curr_fcn_file_full_name.c_str ()); + + id_name = nm; + } + } if (reading_fcn_file || autoloading) { - if (! (autoloading - || lexer_flags.parsing_nested_function - || lexer_flags.parsing_class_method)) - { - // FIXME -- should curr_fcn_file_name already be - // preprocessed when we get here? It seems to only be a - // problem with relative file names. - - std::string nm = curr_fcn_file_name; - - size_t pos = nm.find_last_of (file_ops::dir_sep_chars ()); - - if (pos != std::string::npos) - nm = curr_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 file name `%s'", - id_name.c_str (), curr_fcn_file_full_name.c_str ()); - - id_name = nm; - } - } - octave_time now; fcn->stash_fcn_file_name (curr_fcn_file_full_name); @@ -2619,11 +2669,11 @@ if (fcn_file_from_relative_lookup) fcn->mark_relative (); - if (lexer_flags.parsing_nested_function) + if (current_function_depth > 1 || parsing_subfunctions) { - fcn->stash_parent_fcn_name (parent_function_name); - fcn->stash_parent_fcn_scope (symbol_table::parent_scope ()); - } + fcn->stash_parent_fcn_name (curr_fcn_file_name); + fcn->stash_parent_fcn_scope (primary_fcn_scope); + } if (lexer_flags.parsing_class_method) { @@ -2653,18 +2703,18 @@ fcn->stash_function_name (id_name); - if (! help_buf.empty ()) + if (! help_buf.empty () && current_function_depth == 1 + && ! parsing_subfunctions) { fcn->document (help_buf.top ()); help_buf.pop (); } - if (reading_fcn_file && ! lexer_flags.parsing_nested_function) - curr_fcn_ptr = fcn; - else - curr_fcn_ptr = 0; - + if (reading_fcn_file && current_function_depth == 1 + && ! parsing_subfunctions) + primary_fcn_ptr = fcn; + return fcn; } @@ -2693,23 +2743,21 @@ fcn->define_ret_list (ret_list); - if (lexer_flags.parsing_nested_function) - { + if (current_function_depth > 1 || parsing_subfunctions) + { + // FIXME -- is this flag used to determine if the function is a + // _subfunction_ somewhere? fcn->mark_as_nested_function (); - symbol_table::install_subfunction (nm, octave_value (fcn)); - - if (lexer_flags.parsing_nested_function < 0) - { - lexer_flags.parsing_nested_function = 0; - symbol_table::reset_parent_scope (); - } + symbol_table::install_subfunction (nm, octave_value (fcn), + primary_fcn_scope); } - else if (! curr_fcn_ptr) + + if (! primary_fcn_ptr) { // FIXME -- there should be a better way to indicate that we // should create a tree_function_def object other than - // looking at curr_fcn_ptr... + // looking at primary_fcn_ptr... retval = new tree_function_def (fcn); } @@ -2733,7 +2781,12 @@ symbol_table::set_scope (symtab_context.top ()); symtab_context.pop (); - lexer_flags.defining_func = false; + if (reading_fcn_file && current_function_depth == 1 + && ! parsing_subfunctions) + parsing_subfunctions = true; + + current_function_depth--; + lexer_flags.parsed_function_name = false; lexer_flags.looking_at_return_list = false; lexer_flags.looking_at_parameter_list = false; @@ -2835,7 +2888,7 @@ break; case STATIC: - if (lexer_flags.defining_func) + if (current_function_depth > 0) retval = new tree_static_command (lst, l, c); else { @@ -2912,7 +2965,7 @@ static void maybe_warn_missing_semi (tree_statement_list *t) { - if (lexer_flags.defining_func) + if (current_function_depth > 0) { tree_statement *tmp = t->back(); @@ -3153,8 +3206,6 @@ // Open function file and parse. - bool old_reading_fcn_file_state = reading_fcn_file; - FILE *in_stream = command_editor::get_input_stream (); unwind_protect::add_fcn (command_editor::set_input_stream, @@ -3164,19 +3215,23 @@ unwind_protect::protect_var (input_line_number); unwind_protect::protect_var (current_input_column); - unwind_protect::protect_var (end_tokens_expected); unwind_protect::protect_var (reading_fcn_file); unwind_protect::protect_var (line_editing); - unwind_protect::protect_var (parent_function_name); unwind_protect::protect_var (current_class_name); + unwind_protect::protect_var (current_function_depth); + unwind_protect::protect_var (max_function_depth); + unwind_protect::protect_var (parsing_subfunctions); + unwind_protect::protect_var (endfunction_found); input_line_number = 1; current_input_column = 1; - end_tokens_expected = 0; reading_fcn_file = true; line_editing = false; - parent_function_name = ""; current_class_name = dispatch_type; + current_function_depth = 0; + max_function_depth = 0; + parsing_subfunctions = false; + endfunction_found = false; // The next four lines must be in this order. unwind_protect::add_fcn (command_history::ignore_entries, ! Vsaving_history); @@ -3204,10 +3259,10 @@ { std::string file_type; - bool parsing_script = false; - unwind_protect::protect_var (get_input_from_eval_string); unwind_protect::protect_var (parser_end_of_input); + unwind_protect::protect_var (reading_fcn_file); + unwind_protect::protect_var (reading_script_file); get_input_from_eval_string = false; parser_end_of_input = false; @@ -3217,7 +3272,6 @@ file_type = "function"; unwind_protect::protect_var (Vecho_executing_commands); - unwind_protect::protect_var (reading_fcn_file); Vecho_executing_commands = ECHO_OFF; reading_fcn_file = true; @@ -3226,17 +3280,11 @@ { file_type = "script"; - // The value of `reading_fcn_file' will be restored to the - // proper value when we unwind from this frame. - reading_fcn_file = old_reading_fcn_file_state; - - unwind_protect::protect_var (reading_script_file); - - reading_script_file = true; - - parsing_script = true; + reading_fcn_file = false; } + reading_script_file = ! reading_fcn_file; + YY_BUFFER_STATE old_buf = current_buffer (); YY_BUFFER_STATE new_buf = create_buffer (ffile); @@ -3245,8 +3293,8 @@ switch_to_buffer (new_buf); - unwind_protect::protect_var (curr_fcn_ptr); - curr_fcn_ptr = 0; + unwind_protect::protect_var (primary_fcn_ptr); + primary_fcn_ptr = 0; reset_parser (); @@ -3259,14 +3307,21 @@ if (! help_txt.empty ()) help_buf.push (help_txt); - if (parsing_script) - prep_lexer_for_script (); + if (reading_script_file) + prep_lexer_for_script_file (); + else + prep_lexer_for_function_file (); lexer_flags.parsing_class_method = ! dispatch_type.empty (); int status = yyparse (); - fcn_ptr = curr_fcn_ptr; + fcn_ptr = primary_fcn_ptr; + + if (reading_fcn_file && endfunction_found && max_function_depth > 1) + warning_with_id ("Octave:nested-functions-coerced", + "nested functions are coerced into subfunctions " + "in file %s", ff.c_str ()); if (status != 0) error ("parse error while reading %s file %s", @@ -3879,6 +3934,10 @@ unwind_protect::protect_var (parser_end_of_input); unwind_protect::protect_var (line_editing); unwind_protect::protect_var (current_eval_string); + unwind_protect::protect_var (current_function_depth); + unwind_protect::protect_var (max_function_depth); + unwind_protect::protect_var (parsing_subfunctions); + unwind_protect::protect_var (endfunction_found); input_line_number = 1; current_input_column = 1; @@ -3886,6 +3945,10 @@ input_from_eval_string_pending = true; parser_end_of_input = false; line_editing = false; + current_function_depth = 0; + max_function_depth = 0; + parsing_subfunctions = false; + endfunction_found = false; current_eval_string = s;
--- a/src/symtab.cc +++ b/src/symtab.cc @@ -62,8 +62,6 @@ symbol_table::scope_id symbol_table::xcurrent_scope = 1; -symbol_table::scope_id symbol_table::xparent_scope = -1; - symbol_table::context_id symbol_table::xcurrent_context = 0; // Should Octave always check to see if function files have changed
--- a/src/symtab.h +++ b/src/symtab.h @@ -888,9 +888,6 @@ static context_id current_context (void) { return xcurrent_context; } - // We use parent_scope to handle parsing subfunctions. - static scope_id parent_scope (void) { return xparent_scope; } - static scope_id alloc_scope (void) { return scope_id_cache::alloc (); } static void set_scope (scope_id scope) @@ -942,16 +939,6 @@ } } - static void set_parent_scope (scope_id scope) - { - xparent_scope = scope; - } - - static void reset_parent_scope (void) - { - set_parent_scope (-1); - } - static void erase_scope (scope_id scope) { assert (scope != xglobal_scope); @@ -1207,7 +1194,7 @@ static void install_subfunction (const std::string& name, const octave_value& fcn, - scope_id scope = xparent_scope) + scope_id scope) { fcn_table_iterator p = fcn_table.find (name); @@ -1852,9 +1839,6 @@ static scope_id xcurrent_scope; - // We use parent_scope to handle parsing subfunctions. - static scope_id xparent_scope; - static context_id xcurrent_context; symbol_table (void)