Mercurial > octave
comparison libinterp/parse-tree/lex.ll @ 29900:da6e5914ddaf
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.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Wed, 21 Jul 2021 09:49:09 -0400 |
parents | e2e493712818 |
children | ef865fcd4611 |
comparison
equal
deleted
inserted
replaced
29899:853e4b7ae0d5 | 29900:da6e5914ddaf |
---|---|
180 } \ | 180 } \ |
181 else \ | 181 else \ |
182 return curr_lexer->handle_op (TOK, false, COMPAT); \ | 182 return curr_lexer->handle_op (TOK, false, COMPAT); \ |
183 } \ | 183 } \ |
184 while (0) | 184 while (0) |
185 | |
186 #if 0 | |
187 // Use the following to handle computed assignment operators | |
188 // (+=, -=, etc.) in word list commands in a way that is compatible | |
189 // with Matlab. However, that will also make it impossible to use | |
190 // these operators with a space before them: | |
191 // | |
192 // x = 1; | |
193 // x+=2; ## ok | |
194 // x+= 2; ## ok | |
195 // x +=2; ## error: invalid use of symbol as both variable and command | |
196 // x += 2; ## error: invalid use of symbol as both variable and command | |
197 // | |
198 # define CMD_OR_COMPUTED_ASSIGN_OP(PATTERN, TOK) \ | |
199 do \ | |
200 { \ | |
201 curr_lexer->lexer_debug (PATTERN); \ | |
202 \ | |
203 if (curr_lexer->previous_token_may_be_command () \ | |
204 && curr_lexer->space_follows_previous_token ()) \ | |
205 { \ | |
206 yyless (0); \ | |
207 curr_lexer->push_start_state (COMMAND_START); \ | |
208 } \ | |
209 else \ | |
210 return curr_lexer->handle_op (TOK, false, false); \ | |
211 } \ | |
212 while (0) | |
213 #else | |
214 # define CMD_OR_COMPUTED_ASSIGN_OP(PATTERN, TOK) \ | |
215 return curr_lexer->handle_op (TOK, false, false) | |
216 #endif | |
217 | 185 |
218 #define CMD_OR_UNARY_OP(PATTERN, TOK, COMPAT) \ | 186 #define CMD_OR_UNARY_OP(PATTERN, TOK, COMPAT) \ |
219 do \ | 187 do \ |
220 { \ | 188 { \ |
221 curr_lexer->lexer_debug (PATTERN); \ | 189 curr_lexer->lexer_debug (PATTERN); \ |
1834 curr_lexer->lexer_debug ("="); | 1802 curr_lexer->lexer_debug ("="); |
1835 | 1803 |
1836 return curr_lexer->handle_op ('='); | 1804 return curr_lexer->handle_op ('='); |
1837 } | 1805 } |
1838 | 1806 |
1839 "+=" { CMD_OR_COMPUTED_ASSIGN_OP ("+=", ADD_EQ); } | 1807 "+=" { CMD_OR_OP ("+=", ADD_EQ, false); } |
1840 "-=" { CMD_OR_COMPUTED_ASSIGN_OP ("-=", SUB_EQ); } | 1808 "-=" { CMD_OR_OP ("-=", SUB_EQ, false); } |
1841 "*=" { CMD_OR_COMPUTED_ASSIGN_OP ("*=", MUL_EQ); } | 1809 "*=" { CMD_OR_OP ("*=", MUL_EQ, false); } |
1842 "/=" { CMD_OR_COMPUTED_ASSIGN_OP ("/=", DIV_EQ); } | 1810 "/=" { CMD_OR_OP ("/=", DIV_EQ, false); } |
1843 "\\=" { CMD_OR_COMPUTED_ASSIGN_OP ("\\=", LEFTDIV_EQ); } | 1811 "\\=" { CMD_OR_OP ("\\=", LEFTDIV_EQ, false); } |
1844 ".+=" { CMD_OR_COMPUTED_ASSIGN_OP (".+=", ADD_EQ); } | 1812 ".+=" { CMD_OR_OP (".+=", ADD_EQ, false); } |
1845 ".-=" { CMD_OR_COMPUTED_ASSIGN_OP (".-=", SUB_EQ); } | 1813 ".-=" { CMD_OR_OP (".-=", SUB_EQ, false); } |
1846 ".*=" { CMD_OR_COMPUTED_ASSIGN_OP (".*=", EMUL_EQ); } | 1814 ".*=" { CMD_OR_OP (".*=", EMUL_EQ, false); } |
1847 "./=" { CMD_OR_COMPUTED_ASSIGN_OP ("./=", EDIV_EQ); } | 1815 "./=" { CMD_OR_OP ("./=", EDIV_EQ, false); } |
1848 ".\\=" { CMD_OR_COMPUTED_ASSIGN_OP (".\\=", ELEFTDIV_EQ); } | 1816 ".\\=" { CMD_OR_OP (".\\=", ELEFTDIV_EQ, false); } |
1849 "^=" { CMD_OR_COMPUTED_ASSIGN_OP ("^=", POW_EQ); } | 1817 "^=" { CMD_OR_OP ("^=", POW_EQ, false); } |
1850 "**=" { CMD_OR_COMPUTED_ASSIGN_OP ("^=", POW_EQ); } | 1818 "**=" { CMD_OR_OP ("^=", POW_EQ, false); } |
1851 ".^=" { CMD_OR_COMPUTED_ASSIGN_OP (".^=", EPOW_EQ); } | 1819 ".^=" { CMD_OR_OP (".^=", EPOW_EQ, false); } |
1852 ".**=" { CMD_OR_COMPUTED_ASSIGN_OP (".^=", EPOW_EQ); } | 1820 ".**=" { CMD_OR_OP (".^=", EPOW_EQ, false); } |
1853 "&=" { CMD_OR_COMPUTED_ASSIGN_OP ("&=", AND_EQ); } | 1821 "&=" { CMD_OR_OP ("&=", AND_EQ, false); } |
1854 "|=" { CMD_OR_COMPUTED_ASSIGN_OP ("|=", OR_EQ); } | 1822 "|=" { CMD_OR_OP ("|=", OR_EQ, false); } |
1855 | 1823 |
1856 %{ | 1824 %{ |
1857 // In Matlab, '{' may also trigger command syntax. | 1825 // In Matlab, '{' may also trigger command syntax. |
1858 %} | 1826 %} |
1859 | 1827 |
3582 return count_token_internal (kw_token); | 3550 return count_token_internal (kw_token); |
3583 } | 3551 } |
3584 | 3552 |
3585 token *tok = new token (NAME, ident, m_tok_beg, m_tok_end); | 3553 token *tok = new token (NAME, ident, m_tok_beg, m_tok_end); |
3586 | 3554 |
3587 // The following symbols are handled specially so that things like | 3555 // For compatibility with Matlab, the following symbols are |
3556 // handled specially so that things like | |
3588 // | 3557 // |
3589 // pi +1 | 3558 // pi +1 |
3590 // | 3559 // |
3591 // are parsed as an addition expression instead of as a command-style | 3560 // are parsed as an addition expression instead of as a command-style |
3592 // function call with the argument "+1". | 3561 // function call with the argument "+1". Also for compatibility with |
3562 // Matlab, if we are at the top level workspace, do not consider IDENT | |
3563 // as a possible command if it is already known to be a variable. | |
3593 | 3564 |
3594 if (m_at_beginning_of_statement | 3565 if (m_at_beginning_of_statement |
3595 && ! (m_parsing_anon_fcn_body | 3566 && ! (m_parsing_anon_fcn_body |
3596 || ident == "e" || ident == "pi" | 3567 || ident == "e" || ident == "pi" |
3597 || ident == "I" || ident == "i" | 3568 || ident == "I" || ident == "i" |
3598 || ident == "J" || ident == "j" | 3569 || ident == "J" || ident == "j" |
3599 || ident == "Inf" || ident == "inf" | 3570 || ident == "Inf" || ident == "inf" |
3600 || ident == "NaN" || ident == "nan")) | 3571 || ident == "NaN" || ident == "nan" |
3572 || (m_interpreter.at_top_level () | |
3573 && m_interpreter.is_variable (ident)))) | |
3601 tok->mark_may_be_command (); | 3574 tok->mark_may_be_command (); |
3602 | 3575 |
3603 push_token (tok); | 3576 push_token (tok); |
3604 | 3577 |
3605 // The magic end index can't be indexed. | 3578 // The magic end index can't be indexed. |