# HG changeset patch # User John W. Eaton # Date 1626875349 14400 # Node ID da6e5914ddaf6d3dd4d317802354e7aa0e018959 # Parent 853e4b7ae0d51e9a1fcc8c8cb81804fa39498288 handle all binary operators the same when detecting command syntax (bug #60882) This change breaks Matlab compatibility when parsing things like x += 2 Matlab will handle this as a command-style function call with two arguments '+=' and '2'. Octave will now treat this as a computed assignment (the variable X incremented by 2). Octave will still handle x +=2 as a command-style function call when parsing this statement inside a function. At the command line, Octave will recognize this statement as a computed assignment expression if X is already defined to be a variable. Note that command lines are parsed completely before executing anything, so in octave> clear x octave> x = 1; x +=2 the "x +=2" statement will be parsed as a command-style function call because the parser does not find a definition for X as a variable when that portion of the command line is parsed. * lex.ll (CMD_OR_COMPUTED_ASSIGN_OP): Delete macro. Change all uses to CMD_OR_OP instead. (base_lexer::handle_identifier): Don't call mark_may_be_command for token if we are at the top level and the identifier has already been recognized as a variable. * parser.tst: Update test. diff -r 853e4b7ae0d5 -r da6e5914ddaf libinterp/parse-tree/lex.ll --- a/libinterp/parse-tree/lex.ll Wed Jul 21 14:45:32 2021 +0200 +++ b/libinterp/parse-tree/lex.ll Wed Jul 21 09:49:09 2021 -0400 @@ -183,38 +183,6 @@ } \ while (0) -#if 0 -// Use the following to handle computed assignment operators -// (+=, -=, etc.) in word list commands in a way that is compatible -// with Matlab. However, that will also make it impossible to use -// these operators with a space before them: -// -// x = 1; -// x+=2; ## ok -// x+= 2; ## ok -// x +=2; ## error: invalid use of symbol as both variable and command -// x += 2; ## error: invalid use of symbol as both variable and command -// -# define CMD_OR_COMPUTED_ASSIGN_OP(PATTERN, TOK) \ - do \ - { \ - curr_lexer->lexer_debug (PATTERN); \ - \ - if (curr_lexer->previous_token_may_be_command () \ - && curr_lexer->space_follows_previous_token ()) \ - { \ - yyless (0); \ - curr_lexer->push_start_state (COMMAND_START); \ - } \ - else \ - return curr_lexer->handle_op (TOK, false, false); \ - } \ - while (0) -#else -# define CMD_OR_COMPUTED_ASSIGN_OP(PATTERN, TOK) \ - return curr_lexer->handle_op (TOK, false, false) -#endif - #define CMD_OR_UNARY_OP(PATTERN, TOK, COMPAT) \ do \ { \ @@ -1836,22 +1804,22 @@ return curr_lexer->handle_op ('='); } -"+=" { CMD_OR_COMPUTED_ASSIGN_OP ("+=", ADD_EQ); } -"-=" { CMD_OR_COMPUTED_ASSIGN_OP ("-=", SUB_EQ); } -"*=" { CMD_OR_COMPUTED_ASSIGN_OP ("*=", MUL_EQ); } -"/=" { CMD_OR_COMPUTED_ASSIGN_OP ("/=", DIV_EQ); } -"\\=" { CMD_OR_COMPUTED_ASSIGN_OP ("\\=", LEFTDIV_EQ); } -".+=" { CMD_OR_COMPUTED_ASSIGN_OP (".+=", ADD_EQ); } -".-=" { CMD_OR_COMPUTED_ASSIGN_OP (".-=", SUB_EQ); } -".*=" { CMD_OR_COMPUTED_ASSIGN_OP (".*=", EMUL_EQ); } -"./=" { CMD_OR_COMPUTED_ASSIGN_OP ("./=", EDIV_EQ); } -".\\=" { CMD_OR_COMPUTED_ASSIGN_OP (".\\=", ELEFTDIV_EQ); } -"^=" { CMD_OR_COMPUTED_ASSIGN_OP ("^=", POW_EQ); } -"**=" { CMD_OR_COMPUTED_ASSIGN_OP ("^=", POW_EQ); } -".^=" { CMD_OR_COMPUTED_ASSIGN_OP (".^=", EPOW_EQ); } -".**=" { CMD_OR_COMPUTED_ASSIGN_OP (".^=", EPOW_EQ); } -"&=" { CMD_OR_COMPUTED_ASSIGN_OP ("&=", AND_EQ); } -"|=" { CMD_OR_COMPUTED_ASSIGN_OP ("|=", OR_EQ); } +"+=" { CMD_OR_OP ("+=", ADD_EQ, false); } +"-=" { CMD_OR_OP ("-=", SUB_EQ, false); } +"*=" { CMD_OR_OP ("*=", MUL_EQ, false); } +"/=" { CMD_OR_OP ("/=", DIV_EQ, false); } +"\\=" { CMD_OR_OP ("\\=", LEFTDIV_EQ, false); } +".+=" { CMD_OR_OP (".+=", ADD_EQ, false); } +".-=" { CMD_OR_OP (".-=", SUB_EQ, false); } +".*=" { CMD_OR_OP (".*=", EMUL_EQ, false); } +"./=" { CMD_OR_OP ("./=", EDIV_EQ, false); } +".\\=" { CMD_OR_OP (".\\=", ELEFTDIV_EQ, false); } +"^=" { CMD_OR_OP ("^=", POW_EQ, false); } +"**=" { CMD_OR_OP ("^=", POW_EQ, false); } +".^=" { CMD_OR_OP (".^=", EPOW_EQ, false); } +".**=" { CMD_OR_OP (".^=", EPOW_EQ, false); } +"&=" { CMD_OR_OP ("&=", AND_EQ, false); } +"|=" { CMD_OR_OP ("|=", OR_EQ, false); } %{ // In Matlab, '{' may also trigger command syntax. @@ -3584,12 +3552,15 @@ token *tok = new token (NAME, ident, m_tok_beg, m_tok_end); - // The following symbols are handled specially so that things like + // For compatibility with Matlab, 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". + // function call with the argument "+1". Also for compatibility with + // Matlab, if we are at the top level workspace, do not consider IDENT + // as a possible command if it is already known to be a variable. if (m_at_beginning_of_statement && ! (m_parsing_anon_fcn_body @@ -3597,7 +3568,9 @@ || ident == "I" || ident == "i" || ident == "J" || ident == "j" || ident == "Inf" || ident == "inf" - || ident == "NaN" || ident == "nan")) + || ident == "NaN" || ident == "nan" + || (m_interpreter.at_top_level () + && m_interpreter.is_variable (ident)))) tok->mark_may_be_command (); push_token (tok); diff -r 853e4b7ae0d5 -r da6e5914ddaf test/parser.tst --- a/test/parser.tst Wed Jul 21 14:45:32 2021 +0200 +++ b/test/parser.tst Wed Jul 21 09:49:09 2021 -0400 @@ -91,7 +91,7 @@ %! assert (1 && a ++, false); %! assert (0 || a --, true); %! a = 5; b = 2; -%! b +=a ++; +%! b += a ++; %! assert (b, 7); ## Level 11 (transpose and exponentiation)