Mercurial > hg > octave-terminal
changeset 4238:a5a68c0afe56
[project @ 2002-12-25 21:04:33 by jwe]
author | jwe |
---|---|
date | Wed, 25 Dec 2002 21:04:34 +0000 |
parents | 9c8034434982 |
children | 90db7796adc2 |
files | src/ChangeLog src/lex.h src/lex.l src/ov-usr-fcn.cc src/ov-usr-fcn.h src/parse.h src/parse.y src/symtab.cc src/symtab.h src/toplev.cc src/toplev.h src/variables.cc |
diffstat | 12 files changed, 339 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,8 +1,74 @@ +2002-12-25 John W. Eaton <jwe@bevo.che.wisc.edu> + + * variables.cc (link_to_builtin_or_function): Maybe prepend parent + function name symbol name. + + * parse.y (parent_function_name): New variable. + (fcn_name): New non-terminal. + (function2): Use it. + (parsed_fcn_name): Fold into fcn_name. + (function_end): Don't call check_for_garbage_after_fcn_def. + Set lexer_flags.parsing_nested_function on EOF. + * parse.h: Provide decl for parent_function_name. + + * ov-usr-fcn.h (octave_user_function::mark_as_nested_function, + (octave_user_funciton::is_nested_function): New functions. + (octave_user_function::nested_function): New data member. + (octave_user_function::do_multi_index_op): Maybe protect and set + curr_parent_function pointer. + * parse.y (frob_function): Maybe mark as nested function. + + * toplev.cc (curr_parent_function): New global variable. + * toplev.h: Provide decl. + + * lex.l (check_for_garbage_after_fcn_def): Delete. + * lex.h: Delete decl. + + * lex.l (prep_for_nested_function): New function. + (<NESTED_FUNCTION_START>): Use it here. + (is_keyword): And here. + (lookup_identifier): Maybe prepend parent function name. + + * variables.cc (initialize_symbol_tables): Give names to the three + main symbol tables. + * symtab.cc (symbol_table::lookup, symbol_table::rename): Print + debugging info if Vdebug_symtab_lookups is nonzero. + (debug_symtab_lookups): New function. + (Vdebug_symtab_lookups): New static varaible. + (symbols_of_symtab): DEFVAR it. + * symtab.h (symbol_table::table_name): New member variable. + (symtab_count): New static member variable. + (symbol_table::symbol_table): Handle table name. + 2002-12-24 John W. Eaton <jwe@bevo.che.wisc.edu> + * parse.y (frob_function): Don't give nested functions the same + name as the function file. + + * lex.h (lexical_feedback::parsing_nested_function): New data member. + * lex.l (lexical_feedback::init): Initialize it to false. + (<NESTED_FUNCTION_START>): Set lexer_flags.parsing_nested_function + to true. + + * parse.y (symtab_context): Now a stack. Change all uses. + + * lex.l (NESTED_FUNCTION_START): New start state to handle + "function" keyword in a nested function context. + (prep_for_function): New function. + (is_keyword): Allow functions to be nested in function files. + + * lex.l (is_keyword): Maybe ignore END tokens. + Increment and decrement end_tokens_expected as appropriate. + (handle_identifier): If is_keyword returns -1, return immediately. + ({IDENT}{S}*): Do nothing if handle_identifier returns -1. + + * parse.y (end_tokens_expected): New variable. + (parse_fcn_file): Protect and set it. + * parse.y (begin_obj_idx): Increment lexer_flags.looking_at_object_index. (postfix_expr): Decrement it as appropriate here. + * lex.h (lexical_feedback::looking_at_object_index): Now int. * parse.y (postfix_expr): Reset lexer_flags.looking_at_object_index
--- a/src/lex.h +++ b/src/lex.h @@ -113,11 +113,6 @@ // Delete a buffer (for unwind-prot). extern void delete_input_buffer (void *buf); -// See if a function file has extra garbage after the end statement. -// This needs to be defined in lex.l so that it can use yyinput() but -// it must be called from parse.y. -extern void check_for_garbage_after_fcn_def (void); - // For communication between the lexer and parser. class @@ -191,6 +186,9 @@ // Should only matter if defining_func is also TRUE. bool parsed_function_name; + // TRUE means that we're parsing a nested function definition. + bool parsing_nested_function; + // TRUE means we've seen something that means we must be past the // range part of a plot command. bool past_plot_range;
--- a/src/lex.l +++ b/src/lex.l @@ -22,6 +22,7 @@ %s COMMAND_START %s MATRIX_START +%s NESTED_FUNCTION_START %{ #ifdef HAVE_CONFIG_H @@ -193,6 +194,8 @@ static void do_comma_insert_check (void); static int is_plot_keyword (const std::string& s); static int is_keyword (const std::string& s); +static void prep_for_function (void); +static void prep_for_nested_function (void); static std::string plot_style_token (const std::string& s); static symbol_record *lookup_identifier (const std::string& s); static void grab_help_text (void); @@ -238,6 +241,12 @@ NUMBER (({D}+\.?{D}*{EXPON}?)|(\.{D}+{EXPON}?)|(0[xX][0-9a-fA-F]+)) %% +<NESTED_FUNCTION_START>{} { + BEGIN 0; + prep_for_nested_function (); + return FCN; + } + %{ // Help and other command-style functions are a pain in the ass. This // stuff needs to be simplified. May require some changes in the @@ -529,7 +538,10 @@ %} {IDENT}{S}* { - return handle_identifier (); + int id_tok = handle_identifier (); + + if (id_tok >= 0) + return id_tok; } %{ @@ -814,7 +826,10 @@ error_state = 0; warning_state = 0; parser_end_of_input = false; - symtab_context = 0; + end_tokens_expected = 0; + + while (! symtab_context.empty ()) + symtab_context.pop (); // We do want a prompt by default. promptflag = 1; @@ -1046,7 +1061,35 @@ } } -// Handle keywords. +static void +prep_for_function (void) +{ + end_tokens_expected++; + + // Prepare for local symbols. + + tmp_local_sym_tab = new symbol_table (); + + promptflag--; + + lexer_flags.defining_func = true; + lexer_flags.parsed_function_name = false; + lexer_flags.beginning_of_function = true; + + if (! (reading_fcn_file || reading_script_file)) + input_line_number = 1; +} + +static void +prep_for_nested_function (void) +{ + lexer_flags.parsing_nested_function = true; + prep_for_function (); + yylval.tok_val = new token (input_line_number, current_input_column); + token_stack.push (yylval.tok_val); +} + +// Handle keywords. Return -1 if the keyword should be ignored. static int is_keyword (const std::string& s) @@ -1111,40 +1154,65 @@ if (lexer_flags.looking_at_object_index) return 0; else - yylval.tok_val = new token (token::simple_end, l, c); + { + if (reading_fcn_file && end_tokens_expected == 1) + return -1; + else + { + yylval.tok_val = new token (token::simple_end, l, c); + end_tokens_expected--; + } + } break; case end_try_catch_kw: + end_tokens_expected--; yylval.tok_val = new token (token::try_catch_end, l, c); break; case end_unwind_protect_kw: + end_tokens_expected--; yylval.tok_val = new token (token::unwind_protect_end, l, c); break; case endfor_kw: + end_tokens_expected--; yylval.tok_val = new token (token::for_end, l, c); break; case endfunction_kw: - yylval.tok_val = new token (token::function_end, l, c); + { + if (reading_fcn_file && end_tokens_expected == 1) + return -1; + else + { + yylval.tok_val = new token (token::function_end, l, c); + end_tokens_expected--; + } + } break; case endif_kw: + end_tokens_expected--; yylval.tok_val = new token (token::if_end, l, c); break; case endswitch_kw: + end_tokens_expected--; yylval.tok_val = new token (token::switch_end, l, c); break; case endwhile_kw: + end_tokens_expected--; yylval.tok_val = new token (token::while_end, l, c); break; - case do_kw: case for_kw: case while_kw: + end_tokens_expected++; + // Fall through... + + case do_kw: promptflag--; lexer_flags.looping++; break; @@ -1153,6 +1221,7 @@ case try_kw: case switch_kw: case unwind_protect_kw: + end_tokens_expected++; promptflag--; break; @@ -1172,35 +1241,40 @@ break; case function_kw: - if (lexer_flags.defining_func) - { - error ("function keyword invalid within a function body"); - - if ((reading_fcn_file || reading_script_file) - && ! curr_fcn_file_name.empty ()) - error ("defining new function near line %d of file `%s.m'", - input_line_number, curr_fcn_file_name.c_str ()); - else - error ("defining new function near line %d", - input_line_number); - - return LEXICAL_ERROR; - } - else - { - // Prepare for local symbols. - - tmp_local_sym_tab = new symbol_table (); - - promptflag--; - - lexer_flags.defining_func = true; - lexer_flags.parsed_function_name = false; - lexer_flags.beginning_of_function = true; - - if (! (reading_fcn_file || reading_script_file)) - input_line_number = 1; - } + { + if (lexer_flags.defining_func) + { + if (reading_fcn_file) + { + + if (lexer_flags.parsing_nested_function) + { + BEGIN NESTED_FUNCTION_START; + yylval.tok_val = new token (token::function_end, l, c); + } + 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 (); + } break; case magic_file_kw: @@ -1248,7 +1322,13 @@ static symbol_record * lookup_identifier (const std::string& name) { - return curr_sym_tab->lookup (name, true); + std::string sym_name = name; + + if (curr_sym_tab == fbi_sym_tab + && lexer_flags.parsing_nested_function) + sym_name = parent_function_name + ":" + sym_name; + + return curr_sym_tab->lookup (sym_name, true); } static bool @@ -2243,7 +2323,8 @@ } // Figure out exactly what kind of token to return when we have seen -// an identifier. Handles keywords. +// an identifier. Handles keywords. Return -1 if the identifier +// should be ignored. static int handle_identifier (void) @@ -2295,7 +2376,9 @@ if (kw_token) { - if (kw_token == STYLE) + if (kw_token < 0) + return kw_token; + else if (kw_token == STYLE) { current_input_column += yyleng; lexer_flags.quote_is_transpose = false; @@ -2536,6 +2619,7 @@ beginning_of_function = false; defining_func = false; parsed_function_name = false; + parsing_nested_function = false; // Not parsing a function return or parameter list. looking_at_return_list = false;
--- a/src/ov-usr-fcn.cc +++ b/src/ov-usr-fcn.cc @@ -82,7 +82,8 @@ t_parsed (static_cast<time_t> (0)), t_checked (static_cast<time_t> (0)), system_fcn_file (false), call_depth (0), - num_named_args (0), args_passed (), num_args_passed (0), + num_named_args (0), nested_function (false), + args_passed (), num_args_passed (0), curr_va_arg_number (0), vr_list (0), symtab_entry (0), argn_sr (0), nargin_sr (0), nargout_sr (0), varargin_sr (0) { @@ -405,6 +406,12 @@ unwind_protect_ptr (curr_function); curr_function = this; + if (! is_nested_function ()) + { + unwind_protect_ptr (curr_parent_function); + curr_parent_function = this; + } + // Save and restore args passed for recursive calls. save_args_passed (args);
--- a/src/ov-usr-fcn.h +++ b/src/ov-usr-fcn.h @@ -120,6 +120,10 @@ std::string function_name (void) { return fcn_name; } + void mark_as_nested_function (void) { nested_function = true; } + + bool is_nested_function (void) const { return nested_function; } + void save_args_passed (const octave_value_list& args) { if (call_depth > 1) @@ -211,6 +215,9 @@ // The number of arguments that have names. int num_named_args; + // TRUE means this is a nested function. + bool nested_function; + // The values that were passed as arguments. octave_value_list args_passed;
--- a/src/parse.h +++ b/src/parse.h @@ -73,11 +73,18 @@ extern bool evaluating_function_body; // Keep track of symbol table information when parsing functions. -extern symbol_table *symtab_context; +extern std::stack<symbol_table*> symtab_context; + +// Name of parent function when parsing function files that might +// contain nested functions. +extern std::string parent_function_name; // TRUE means warn about function files that have time stamps in the future. extern bool Vwarn_future_time_stamp; +// Keep a count of how many END tokens we expect. +extern int end_tokens_expected; + extern void parse_and_execute (FILE *f);
--- a/src/parse.y +++ b/src/parse.y @@ -133,8 +133,15 @@ // an eval() statement. bool evaluating_function_body = false; +// Keep a count of how many END tokens we expect. +int end_tokens_expected = 0; + // Keep track of symbol table information when parsing functions. -symbol_table *symtab_context = 0; +std::stack<symbol_table*> symtab_context; + +// Name of parent function when parsing function files that might +// contain nested functions. +std::string parent_function_name; // Forward declarations for some functions defined at the bottom of // the file. @@ -321,10 +328,10 @@ { \ global_command = 0; \ yyerrok; \ - if (symtab_context) \ + if (! symtab_context.empty ()) \ { \ - curr_sym_tab = symtab_context; \ - symtab_context = 0; \ + curr_sym_tab = symtab_context.top (); \ + symtab_context.pop (); \ } \ if (interactive || forced_interactive) \ YYACCEPT; \ @@ -420,7 +427,7 @@ %type <tree_expression_type> title matrix cell %type <tree_expression_type> primary_expr postfix_expr prefix_expr binary_expr %type <tree_expression_type> simple_expr colon_expr assign_expr expression -%type <tree_identifier_type> identifier +%type <tree_identifier_type> identifier fcn_name %type <octave_user_function_type> function1 function2 function3 %type <tree_index_expression_type> word_list_cmd %type <tree_colon_expression_type> colon_expr1 @@ -1097,12 +1104,7 @@ // =========================================== save_symtab : // empty - { - if (symtab_context) - panic_impossible (); - - symtab_context = curr_sym_tab; - } + { symtab_context.push (curr_sym_tab); } ; function_symtab : // empty @@ -1117,10 +1119,6 @@ { lexer_flags.looking_at_return_list = true; } ; -parsed_fcn_name : // empty - { lexer_flags.parsed_function_name = true; } - ; - // =========================== // List of function parameters // =========================== @@ -1229,8 +1227,8 @@ // Function definition // =================== -function_beg : save_symtab FCN stash_comment function_symtab - { $$ = $3; } +function_beg : save_symtab FCN function_symtab stash_comment + { $$ = $4; } ; function : function_beg function2 @@ -1257,9 +1255,24 @@ { $$ = $3; } ; -function2 : identifier local_symtab parsed_fcn_name function3 +fcn_name : identifier local_symtab { - if (! ($$ = frob_function ($1, $4))) + 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; + + $$ = $1; + } + ; + +function2 : fcn_name function3 + { + if (! ($$ = frob_function ($1, $2))) ABORT_PARSE; } ; @@ -1276,16 +1289,13 @@ function_end : END { - if (end_token_ok ($1, token::function_end)) - { - if (reading_fcn_file) - check_for_garbage_after_fcn_def (); - } - else + if (! end_token_ok ($1, token::function_end)) ABORT_PARSE; } | END_OF_INPUT { + lexer_flags.parsing_nested_function = false; + if (! (reading_fcn_file || reading_script_file || get_input_from_eval_string)) YYABORT; @@ -2525,7 +2535,8 @@ if (reading_fcn_file) { - if (curr_fcn_file_name != id_name) + if (! lexer_flags.parsing_nested_function + && curr_fcn_file_name != id_name) { if (Vwarn_function_name_clash) warning ("function name `%s' does not agree with function\ @@ -2569,7 +2580,12 @@ symbol_record *sr = fbi_sym_tab->lookup (id_name); if (sr) - fcn->stash_symtab_ptr (sr); + { + fcn->stash_symtab_ptr (sr); + + if (lexer_flags.parsing_nested_function) + fcn->mark_as_nested_function (); + } else panic_impossible (); @@ -2613,11 +2629,11 @@ static void recover_from_parsing_function (void) { - if (! symtab_context) + if (symtab_context.empty ()) panic_impossible (); - curr_sym_tab = symtab_context; - symtab_context = 0; + curr_sym_tab = symtab_context.top (); + symtab_context.pop (); lexer_flags.defining_func = false; lexer_flags.beginning_of_function = false; @@ -3238,13 +3254,17 @@ unwind_protect_int (input_line_number); unwind_protect_int (current_input_column); + unwind_protect_int (end_tokens_expected); unwind_protect_bool (reading_fcn_file); unwind_protect_bool (line_editing); + unwind_protect_str (parent_function_name); input_line_number = 0; current_input_column = 1; + end_tokens_expected = 0; reading_fcn_file = true; line_editing = false; + parent_function_name = ""; FILE *ffile = get_input_from_file (ff, 0);
--- a/src/symtab.cc +++ b/src/symtab.cc @@ -47,11 +47,16 @@ #include "utils.h" #include "variables.h" +unsigned long int symbol_table::symtab_count = 0; + // Should variables be allowed to hide functions of the same name? A // positive value means yes. A negative value means yes, but print a // warning message. Zero means it should be considered an error. static int Vvariables_can_hide_functions; +// Nonzero means we print debugging info about symbol table lookups. +static int Vdebug_symtab_lookups; + octave_allocator symbol_record::symbol_def::allocator (sizeof (symbol_record::symbol_def)); @@ -462,6 +467,15 @@ symbol_record * symbol_table::lookup (const std::string& nm, bool insert, bool warn) { + if (Vdebug_symtab_lookups) + { + std::cerr << (table_name.empty () ? "???" : table_name) + << " symtab::lookup [" + << (insert ? "I" : "-") + << (warn ? "W" : "-") + << "] \"" << nm << "\"\n"; + } + unsigned int index = hash (nm); symbol_record *ptr = table[index].next (); @@ -491,6 +505,15 @@ void symbol_table::rename (const std::string& old_name, const std::string& new_name) { + if (Vdebug_symtab_lookups) + { + std::cerr << (table_name.empty () ? "???" : table_name) + << " symtab::rename " + << "\"" << old_name << "\"" + << " to " + << "\"" << new_name << "\"\n"; + } + unsigned int index = hash (old_name); symbol_record *prev = &table[index]; @@ -1072,6 +1095,14 @@ return 0; } +static int +debug_symtab_lookups (void) +{ + Vdebug_symtab_lookups = check_preference ("debug_symtab_lookups"); + + return 0; +} + void symbols_of_symtab (void) { @@ -1083,6 +1114,11 @@ will cause Octave to print a warning, but allow the operation.\n\ @end defvr"); + DEFVAR (debug_symtab_lookups, false, debug_symtab_lookups, + "-*- texinfo -*-\n\ +@defvr debug_symtab_lookups\n\ +If the value of htis variable is nonzero, print debugging info when\n\ +searching for symbols in the symbol tables"); }
--- a/src/symtab.h +++ b/src/symtab.h @@ -32,6 +32,7 @@ #include <string> #include <stack> +#include "lo-sstream.h" #include "oct-alloc.h" #include "str-vec.h" @@ -406,10 +407,20 @@ { public: - symbol_table (unsigned int tab_size = 128) - : table_size (tab_size), table (new symbol_record [table_size]) + symbol_table (unsigned int tab_size = 128, + const std::string& nm = std::string ()) + : table_size (tab_size), table (new symbol_record [table_size]), + table_name (nm) { assert ((tab_size % 2) == 0); + + if (table_name.empty ()) + { + OSSTREAM buf; + buf << symtab_count++ << OSSTREAM_ENDS; + table_name = OSSTREAM_STR (buf); + OSSTREAM_FREEZE (buf); + } } ~symbol_table (void) @@ -495,6 +506,10 @@ symbol_record *table; + std::string table_name; + + static unsigned long int symtab_count; + unsigned int hash (const std::string& s); // No copying!
--- a/src/toplev.cc +++ b/src/toplev.cc @@ -92,6 +92,9 @@ // Pointer to function that is currently being evaluated. octave_user_function *curr_function = 0; +// Pointer to parent function that is currently being evaluated. +octave_user_function *curr_parent_function = 0; + // Original value of TEXMFDBS environment variable. std::string octave_original_texmfdbs;
--- a/src/toplev.h +++ b/src/toplev.h @@ -48,6 +48,9 @@ // Pointer to function that is currently being evaluated. extern octave_user_function *curr_function; +// Pointer to parent function that is currently being evaluated. +extern octave_user_function *curr_parent_function; + // Original value of TEXMFDBS environment variable. extern std::string octave_original_texmfdbs;
--- a/src/variables.cc +++ b/src/variables.cc @@ -86,13 +86,13 @@ initialize_symbol_tables (void) { if (! fbi_sym_tab) - fbi_sym_tab = new symbol_table (2048); + fbi_sym_tab = new symbol_table (2048, "FBI"); if (! global_sym_tab) - global_sym_tab = new symbol_table (2048); + global_sym_tab = new symbol_table (2048, "GLOBAL"); if (! top_level_sym_tab) - top_level_sym_tab = new symbol_table (4096); + top_level_sym_tab = new symbol_table (4096, "TOP"); curr_sym_tab = top_level_sym_tab; } @@ -923,7 +923,19 @@ void link_to_builtin_or_function (symbol_record *sr) { - symbol_record *tmp_sym = fbi_sym_tab->lookup (sr->name ()); + std::string nm = sr->name (); + + symbol_record *tmp_sym = 0; + + if (curr_parent_function) + { + std::string parent = curr_parent_function->function_name (); + + tmp_sym = fbi_sym_tab->lookup (parent + ":" + nm); + } + + if (! tmp_sym) + tmp_sym = fbi_sym_tab->lookup (nm); if (tmp_sym && (tmp_sym->is_builtin_variable ()