# HG changeset patch # User John W. Eaton # Date 1303252308 14400 # Node ID c6e79120fc48d0bd55d4f76fc0010b8ad88e734d # Parent f212ff846296d8c47e6292c78c54c93484aa2d9f fix precedence level of transpose operators Bug #32533. * Makefile.am: Note 16 shift/reduce conflicts in oct-parse.yy. * oct-parse.yy: Set precedence level as documented and for compatibility with Matlab. Don't set precedence for comma, semicolon or newline characters. (UNARY, PLUS_PLUS, MINUS_MINUS, EXPR_NOT): Associativity is now right, not left. (oper_expr): New non-terminal. Merge all operator non-terminals except postfix increment and decrement into oper_expr. (prefix_expr, binary_expr): Delete unused non-terminals. * expr.txi: Document precedence to match reality. * test_parser.m: Fix tests for increment and decrement operators to match current behavior. diff --git a/doc/interpreter/expr.txi b/doc/interpreter/expr.txi --- a/doc/interpreter/expr.txi +++ b/doc/interpreter/expr.txi @@ -1239,51 +1239,55 @@ any such mistake. When operators of equal precedence are used together, the leftmost -operator groups first, except for the assignment and exponentiation -operators, which group in the opposite order. Thus, the expression -@code{a - b + c} groups as @code{(a - b) + c}, but the expression -@code{a = b = c} groups as @code{a = (b = c)}. +operator groups first, except for the assignment operators, which group +in the opposite order. Thus, the expression @code{a - b + c} groups as +@code{(a - b) + c}, but the expression @code{a = b = c} groups as +@code{a = (b = c)}. The precedence of prefix unary operators is important when another operator follows the operand. For example, @code{-x^2} means @code{-(x^2)}, because @samp{-} has lower precedence than @samp{^}. -Here is a table of the operators in Octave, in order of increasing -precedence. +Here is a table of the operators in Octave, in order of decreasing +precedence. Unless noted, all operators group left to right. @table @code -@item statement separators -@samp{;}, @samp{,}. +@item function call and array indexing, cell array indexing, structure element indexing, postfix increment, and postfix decrement +@samp{()}, @samp{@{@}}, @samp{.}, @samp{++}, @samp{--}. -@item assignment -@samp{=}, @samp{+=}, @samp{-=}, @samp{*=},@samp{/=}. This operator -groups right to left. +@item transpose and exponentiation +@samp{'}, @samp{.'}, @samp{^}, @samp{**}, @samp{.^}, @samp{.**}. -@item logical "or" and "and" -@samp{||}, @samp{&&}. +@item unary plus, unary minus, prefix increment, prefix decrement, and logical "not" +@samp{+}, @samp{-}, @samp{++}, @samp{--}, @samp{~}, @samp{!}. -@item element-wise "or" and "and" -@samp{|}, @samp{&}. +@item multiply and divide +@samp{*}, @samp{/}, @samp{\}, @samp{.\}, @samp{.*}, @samp{./}. + +@item add, subtract +@samp{+}, @samp{-}. + +@item colon +@samp{:}. @item relational @samp{<}, @samp{<=}, @samp{==}, @samp{>=}, @samp{>}, @samp{!=}, @samp{~=}. -@item colon -@samp{:}. +@item element-wise "and" +@samp{&}. -@item add, subtract -@samp{+}, @samp{-}. +@item element-wise "or" +@samp{|}. -@item multiply, divide -@samp{*}, @samp{/}, @samp{\}, @samp{.\}, @samp{.*}, @samp{./}. +@item logical "and" +@samp{&&}. -@item transpose -@samp{'}, @samp{.'} +@item logical "or" +@samp{||}. -@item unary plus, minus, increment, decrement, and ``not'' -@samp{+}, @samp{-}, @samp{++}, @samp{--}, @samp{!}, @samp{~}. - -@item exponentiation -@samp{^}, @samp{**}, @samp{.^}, @samp{.**}. +@item assignment +@samp{=}, @samp{+=}, @samp{-=}, @samp{*=}, @samp{/=}, @samp{\=}, +@samp{^=}, @samp{.*=}, @samp{./=}, @samp{.\=}, @samp{.^=}, @samp{|=}, +@samp{&=}. These operators group right to left. @end table diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -736,7 +736,7 @@ ## We require Bison. #parse.cc : parse.y -# @echo "expect 14 shift/reduce conflicts" +# @echo "expect 16 shift/reduce conflicts" # $(YACC) $(YFLAGS) --output=$@ --defines=y.tab.h $< #lex.cc : lex.l diff --git a/src/oct-parse.yy b/src/oct-parse.yy --- a/src/oct-parse.yy +++ b/src/oct-parse.yy @@ -471,7 +471,7 @@ %type matrix_rows matrix_rows1 %type cell_rows cell_rows1 %type matrix cell -%type primary_expr postfix_expr prefix_expr binary_expr +%type primary_expr oper_expr %type simple_expr colon_expr assign_expr expression %type identifier fcn_name magic_tilde %type superclass_identifier meta_identifier @@ -514,7 +514,6 @@ %type class_body // Precedence and associativity. -%left ';' ',' '\n' %right '=' ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ OR_EQ AND_EQ LSHIFT_EQ RSHIFT_EQ %left EXPR_OR_OR %left EXPR_AND_AND @@ -525,7 +524,7 @@ %left ':' %left '-' '+' EPLUS EMINUS %left '*' '/' LEFTDIV EMUL EDIV ELEFTDIV -%left UNARY PLUS_PLUS MINUS_MINUS EXPR_NOT +%right UNARY PLUS_PLUS MINUS_MINUS EXPR_NOT %left POW EPOW QUOTE TRANSPOSE %left '(' '.' '{' @@ -796,69 +795,61 @@ { lexer_flags.looking_at_indirect_ref = true; } ; -postfix_expr : primary_expr +oper_expr : primary_expr { $$ = $1; } - | postfix_expr '(' ')' + | oper_expr PLUS_PLUS + { $$ = make_postfix_op (PLUS_PLUS, $1, $2); } + | oper_expr MINUS_MINUS + { $$ = make_postfix_op (MINUS_MINUS, $1, $2); } + | oper_expr '(' ')' { $$ = make_index_expression ($1, 0, '('); } - | postfix_expr '(' arg_list ')' + | oper_expr '(' arg_list ')' { $$ = make_index_expression ($1, $3, '('); } - | postfix_expr '{' '}' + | oper_expr '{' '}' { $$ = make_index_expression ($1, 0, '{'); } - | postfix_expr '{' arg_list '}' + | oper_expr '{' arg_list '}' { $$ = make_index_expression ($1, $3, '{'); } - | postfix_expr PLUS_PLUS - { $$ = make_postfix_op (PLUS_PLUS, $1, $2); } - | postfix_expr MINUS_MINUS - { $$ = make_postfix_op (MINUS_MINUS, $1, $2); } - | postfix_expr QUOTE + | oper_expr QUOTE { $$ = make_postfix_op (QUOTE, $1, $2); } - | postfix_expr TRANSPOSE + | oper_expr TRANSPOSE { $$ = make_postfix_op (TRANSPOSE, $1, $2); } - | postfix_expr indirect_ref_op STRUCT_ELT + | oper_expr indirect_ref_op STRUCT_ELT { $$ = make_indirect_ref ($1, $3->text ()); } - | postfix_expr indirect_ref_op '(' expression ')' + | oper_expr indirect_ref_op '(' expression ')' { $$ = make_indirect_ref ($1, $4); } - ; - -prefix_expr : postfix_expr - { $$ = $1; } - | binary_expr - { $$ = $1; } - | PLUS_PLUS prefix_expr %prec UNARY + | PLUS_PLUS oper_expr %prec UNARY { $$ = make_prefix_op (PLUS_PLUS, $2, $1); } - | MINUS_MINUS prefix_expr %prec UNARY + | MINUS_MINUS oper_expr %prec UNARY { $$ = make_prefix_op (MINUS_MINUS, $2, $1); } - | EXPR_NOT prefix_expr %prec UNARY + | EXPR_NOT oper_expr %prec UNARY { $$ = make_prefix_op (EXPR_NOT, $2, $1); } - | '+' prefix_expr %prec UNARY + | '+' oper_expr %prec UNARY { $$ = make_prefix_op ('+', $2, $1); } - | '-' prefix_expr %prec UNARY + | '-' oper_expr %prec UNARY { $$ = make_prefix_op ('-', $2, $1); } - ; - -binary_expr : prefix_expr POW prefix_expr + | oper_expr POW oper_expr { $$ = make_binary_op (POW, $1, $2, $3); } - | prefix_expr EPOW prefix_expr + | oper_expr EPOW oper_expr { $$ = make_binary_op (EPOW, $1, $2, $3); } - | prefix_expr '+' prefix_expr + | oper_expr '+' oper_expr { $$ = make_binary_op ('+', $1, $2, $3); } - | prefix_expr '-' prefix_expr + | oper_expr '-' oper_expr { $$ = make_binary_op ('-', $1, $2, $3); } - | prefix_expr '*' prefix_expr + | oper_expr '*' oper_expr { $$ = make_binary_op ('*', $1, $2, $3); } - | prefix_expr '/' prefix_expr + | oper_expr '/' oper_expr { $$ = make_binary_op ('/', $1, $2, $3); } - | prefix_expr EPLUS prefix_expr + | oper_expr EPLUS oper_expr { $$ = make_binary_op ('+', $1, $2, $3); } - | prefix_expr EMINUS prefix_expr + | oper_expr EMINUS oper_expr { $$ = make_binary_op ('-', $1, $2, $3); } - | prefix_expr EMUL prefix_expr + | oper_expr EMUL oper_expr { $$ = make_binary_op (EMUL, $1, $2, $3); } - | prefix_expr EDIV prefix_expr + | oper_expr EDIV oper_expr { $$ = make_binary_op (EDIV, $1, $2, $3); } - | prefix_expr LEFTDIV prefix_expr + | oper_expr LEFTDIV oper_expr { $$ = make_binary_op (LEFTDIV, $1, $2, $3); } - | prefix_expr ELEFTDIV prefix_expr + | oper_expr ELEFTDIV oper_expr { $$ = make_binary_op (ELEFTDIV, $1, $2, $3); } ; @@ -866,9 +857,9 @@ { $$ = finish_colon_expression ($1); } ; -colon_expr1 : prefix_expr +colon_expr1 : oper_expr { $$ = new tree_colon_expression ($1); } - | colon_expr1 ':' prefix_expr + | colon_expr1 ':' oper_expr { if (! ($$ = $1->append ($3))) ABORT_PARSE; diff --git a/test/test_parser.m b/test/test_parser.m --- a/test/test_parser.m +++ b/test/test_parser.m @@ -127,16 +127,11 @@ %# be left to right except for exponents and assignments. %# Level 11 (exponentiation) %!test -%# FIXME : Exponentiation seems to work left to right, despite the -%# documentation and ordinary mathematical rules of precedence. -%! assert (2^3**2, 512) +%# Note: Exponentiation works left to right for compatibility with Matlab. +%! assert (2^3**2, 64) %# Level 10 (unary plus, increment, not) %!test %! assert (+-+1, -1) -%! a = 0; -%# FIXME : Should we test for this corner case at all? -%# (unary minus)(auto-decrement operator) -%! assert (---a, 1); %! a = -1; %! assert (!++a, true) %! assert (a, 0)