# HG changeset patch # User John W. Eaton # Date 1364065349 14400 # Node ID 11115c237231d356aeb9bc0e14f71582ec616e83 # Parent 253e13e77d12125134129d16b93fa4473db61f2c recognize variables when parsing (bug #38576) * lex.h, lex.ll (lexical_feedback::mark_as_variable, lexical_feedback::maybe_mark_previous_token_as_variable, lexical_feedback::mark_as_variables, octave_lexer::is_variable): New fucntions. ("="): Call maybe_mark_previous_toke_as_variable. (handle_identifier): Don't tag variables as possible commands. (param_list): Mark names in list as variables. (octave_base_parser::validate_matrix_for_assignment): Likewise. * pt-arg-list.h, pt-arg-list.cc (tree_argument_list::variable_names): New function. * pt-misc.h, pt-misc.cc (tree_parameter_list::variable_names): New function. * token.h, token.cc (token::symbol_name, token::is_symbol): New functions. * test/bug-38576.tst: New file. * test/Makefile.am (FCN_FILES): Add bug-38576.tst to the list. diff --git a/libinterp/parse-tree/lex.h b/libinterp/parse-tree/lex.h --- a/libinterp/parse-tree/lex.h +++ b/libinterp/parse-tree/lex.h @@ -307,6 +307,11 @@ 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; @@ -518,6 +523,8 @@ bool inside_any_object_index (void); + bool is_variable (const std::string& name); + int is_keyword_token (const std::string& s); bool whitespace_is_significant (void); diff --git a/libinterp/parse-tree/lex.ll b/libinterp/parse-tree/lex.ll --- a/libinterp/parse-tree/lex.ll +++ b/libinterp/parse-tree/lex.ll @@ -1056,7 +1056,12 @@ // = and op= operators. %} -"=" { return curr_lexer->handle_op ("=", '='); } +"=" { + curr_lexer->maybe_mark_previous_token_as_variable (); + + return curr_lexer->handle_op ("=", '='); + } + "+=" { return curr_lexer->handle_incompatible_op ("+=", ADD_EQ); } "-=" { return curr_lexer->handle_incompatible_op ("-=", SUB_EQ); } "*=" { return curr_lexer->handle_incompatible_op ("*=", MUL_EQ); } @@ -1551,6 +1556,24 @@ return tok ? tok->may_be_command () : false; } +void +lexical_feedback::maybe_mark_previous_token_as_variable (void) +{ + token *tok = tokens.front (); + if (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 looks_like_copyright (const std::string& s) { @@ -1784,6 +1807,14 @@ return retval; } +bool +octave_base_lexer::is_variable (const std::string& name) +{ + return (symbol_table::is_variable (name) + || (pending_local_variables.find (name) + != pending_local_variables.end ())); +} + // Handle keywords. Return -1 if the keyword should be ignored. int @@ -2551,7 +2582,8 @@ input_line_number, current_input_column); if (at_beginning_of_statement - && (! (tok == "e" + && (! (is_variable (tok) + || tok == "e" || tok == "I" || tok == "i" || tok == "J" || tok == "j" || tok == "Inf" || tok == "inf" diff --git a/libinterp/parse-tree/oct-parse.in.yy b/libinterp/parse-tree/oct-parse.in.yy --- a/libinterp/parse-tree/oct-parse.in.yy +++ b/libinterp/parse-tree/oct-parse.in.yy @@ -1036,7 +1036,12 @@ ; param_list : param_list_beg param_list1 param_list_end - { $$ = $2; } + { + if ($2) + lexer.mark_as_variables ($2->variable_names ()); + + $$ = $2; + } | param_list_beg error { parser.bison_error ("invalid parameter list"); @@ -1051,7 +1056,10 @@ { $1->mark_as_formal_parameters (); if ($1->validate (tree_parameter_list::in)) - $$ = $1; + { + lexer.mark_as_variables ($1->variable_names ()); + $$ = $1; + } else ABORT_PARSE; } @@ -2969,7 +2977,10 @@ tmp = new tree_argument_list (e); if (tmp && tmp->is_valid_lvalue_list ()) - retval = tmp; + { + lexer.mark_as_variables (tmp->variable_names ()); + retval = tmp; + } else { bison_error ("invalid left hand side of assignment"); diff --git a/libinterp/parse-tree/pt-arg-list.cc b/libinterp/parse-tree/pt-arg-list.cc --- a/libinterp/parse-tree/pt-arg-list.cc +++ b/libinterp/parse-tree/pt-arg-list.cc @@ -283,6 +283,26 @@ return retval; } +std::list +tree_argument_list::variable_names (void) const +{ + std::list retval; + + for (const_iterator p = begin (); p != end (); p++) + { + tree_expression *elt = *p; + + if (elt->is_identifier ()) + { + tree_identifier *id = dynamic_cast (elt); + + retval.push_back (id->name ()); + } + } + + return retval; +} + tree_argument_list * tree_argument_list::dup (symbol_table::scope_id scope, symbol_table::context_id context) const diff --git a/libinterp/parse-tree/pt-arg-list.h b/libinterp/parse-tree/pt-arg-list.h --- a/libinterp/parse-tree/pt-arg-list.h +++ b/libinterp/parse-tree/pt-arg-list.h @@ -85,6 +85,8 @@ string_vector get_arg_names (void) const; + std::list variable_names (void) const; + tree_argument_list *dup (symbol_table::scope_id scope, symbol_table::context_id context) const; diff --git a/libinterp/parse-tree/pt-misc.cc b/libinterp/parse-tree/pt-misc.cc --- a/libinterp/parse-tree/pt-misc.cc +++ b/libinterp/parse-tree/pt-misc.cc @@ -228,6 +228,21 @@ } } +std::list +tree_parameter_list::variable_names (void) const +{ + std::list retval; + + for (const_iterator p = begin (); p != end (); p++) + { + tree_decl_elt *elt = *p; + + retval.push_back (elt->name ()); + } + + return retval; +} + octave_value_list tree_parameter_list::convert_to_const_vector (int nargout, const Cell& varargout) diff --git a/libinterp/parse-tree/pt-misc.h b/libinterp/parse-tree/pt-misc.h --- a/libinterp/parse-tree/pt-misc.h +++ b/libinterp/parse-tree/pt-misc.h @@ -78,6 +78,8 @@ bool is_defined (void); + std::list variable_names (void) const; + octave_value_list convert_to_const_vector (int nargout, const Cell& varargout); tree_parameter_list *dup (symbol_table::scope_id scope, diff --git a/libinterp/parse-tree/token.cc b/libinterp/parse-tree/token.cc --- a/libinterp/parse-tree/token.cc +++ b/libinterp/parse-tree/token.cc @@ -138,6 +138,13 @@ return *str; } +std::string +token::symbol_name (void) const +{ + assert (type_tag == sym_rec_token); + return sr->name (); +} + double token::number (void) const { diff --git a/libinterp/parse-tree/token.h b/libinterp/parse-tree/token.h --- a/libinterp/parse-tree/token.h +++ b/libinterp/parse-tree/token.h @@ -94,7 +94,13 @@ return type_tag == keyword_token || type_tag == ettype_token; } + bool is_symbol (void) const + { + return type_tag == sym_rec_token; + } + std::string text (void) const; + std::string symbol_name (void) const; double number (void) const; token_type ttype (void) const; end_tok_type ettype (void) const; diff --git a/test/Makefile.am b/test/Makefile.am --- a/test/Makefile.am +++ b/test/Makefile.am @@ -24,6 +24,7 @@ fntests.m \ args.tst \ bug-31371.tst \ + bug-38576.tst \ diag-perm.tst \ error.tst \ eval-catch.tst \ diff --git a/test/bug-38576.tst b/test/bug-38576.tst new file mode 100644 --- /dev/null +++ b/test/bug-38576.tst @@ -0,0 +1,16 @@ +%!function r = f1 () +%! ls = svd (1); +%! r = eval ("ls -1;"); +%!endfunction +%!function r = f2 () +%! [u,ls,v] = svd (1); +%! r = eval ("ls -1;"); +%!endfunction +%!function r = f3 (ls) +%! r = eval ("ls -1;"); +%!endfunction + +%!assert (f1 (), 0); +%!assert (f2 (), 0); +%!assert (ischar (f3 ()), true); +%!assert (f3 (1), 0);