# HG changeset patch # User John W. Eaton # Date 1303179950 14400 # Node ID 2dc5d8ddd71f9b1e3929e6f5f6fe99217e5e13b5 # Parent f212ff846296d8c47e6292c78c54c93484aa2d9f fix precedence level of transpose operators * Makefile.am: Note 16 shift/reduce conflicts in oct-parse.yy. * oct-parse.yy (oper_expr): New non-terminal. Merge prefix_expr, postfix_expr, and binary_expr non-terminals into oper_expr. (prefix_expr, postfix_expr, binary_expr): Delete unused non-terminals. (INDEX): New precedence level for index expressions. (oper_expr): Tag index expressions with %prec INDEX. Set precedence level as documented and for compatibility with Matlab. * expr.txi: Document precedence to match reality. diff --git a/doc/interpreter/expr.txi b/doc/interpreter/expr.txi --- a/doc/interpreter/expr.txi +++ b/doc/interpreter/expr.txi @@ -1249,21 +1249,27 @@ @code{-(x^2)}, because @samp{-} has lower precedence than @samp{^}. Here is a table of the operators in Octave, in order of increasing -precedence. +precedence. Unless noted, all operators group left to right. @table @code @item statement separators @samp{;}, @samp{,}. @item assignment -@samp{=}, @samp{+=}, @samp{-=}, @samp{*=},@samp{/=}. This operator -groups right to left. +@samp{=}, @samp{+=}, @samp{-=}, @samp{*=},@samp{/=}. These operators +group right to left. -@item logical "or" and "and" -@samp{||}, @samp{&&}. +@item logical "or" +@samp{||}. -@item element-wise "or" and "and" -@samp{|}, @samp{&}. +@item logical "and" +@samp{&&}. + +@item element-wise "or" +@samp{|}. + +@item element-wise "and" +@samp{&}. @item relational @samp{<}, @samp{<=}, @samp{==}, @samp{>=}, @samp{>}, @samp{!=}, @@ -1278,12 +1284,12 @@ @item multiply, divide @samp{*}, @samp{/}, @samp{\}, @samp{.\}, @samp{.*}, @samp{./}. -@item transpose -@samp{'}, @samp{.'} +@item unary plus, minus, and logical "not" +@samp{+}, @samp{-}, @samp{!}, @samp{~}. -@item unary plus, minus, increment, decrement, and ``not'' -@samp{+}, @samp{-}, @samp{++}, @samp{--}, @samp{!}, @samp{~}. +@item transpose and exponentiation +@samp{'}, @samp{.'}, @samp{^}, @samp{**}, @samp{.^}, @samp{.**}. -@item exponentiation -@samp{^}, @samp{**}, @samp{.^}, @samp{.**}. +@item increment and decrement +@samp{+}, @samp{-}, @samp{++}. @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 @@ -525,9 +525,10 @@ %left ':' %left '-' '+' EPLUS EMINUS %left '*' '/' LEFTDIV EMUL EDIV ELEFTDIV -%left UNARY PLUS_PLUS MINUS_MINUS EXPR_NOT -%left POW EPOW QUOTE TRANSPOSE -%left '(' '.' '{' +%left UNARY EXPR_NOT +%left QUOTE TRANSPOSE POW EPOW +%left PLUS_PLUS MINUS_MINUS +%left INDEX '(' '.' '{' // Where to start. %start input @@ -796,69 +797,61 @@ { lexer_flags.looking_at_indirect_ref = true; } ; -postfix_expr : primary_expr +oper_expr : primary_expr { $$ = $1; } - | postfix_expr '(' ')' + | oper_expr '(' ')' %prec INDEX { $$ = make_index_expression ($1, 0, '('); } - | postfix_expr '(' arg_list ')' + | oper_expr '(' arg_list ')' %prec INDEX { $$ = make_index_expression ($1, $3, '('); } - | postfix_expr '{' '}' + | oper_expr '{' '}' %prec INDEX { $$ = make_index_expression ($1, 0, '{'); } - | postfix_expr '{' arg_list '}' + | oper_expr '{' arg_list '}' %prec INDEX { $$ = make_index_expression ($1, $3, '{'); } - | postfix_expr PLUS_PLUS + | oper_expr indirect_ref_op STRUCT_ELT %prec INDEX + { $$ = make_indirect_ref ($1, $3->text ()); } + | oper_expr indirect_ref_op '(' expression ')' %prec INDEX + { $$ = make_indirect_ref ($1, $4); } + | oper_expr PLUS_PLUS { $$ = make_postfix_op (PLUS_PLUS, $1, $2); } - | postfix_expr MINUS_MINUS + | oper_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 - { $$ = make_indirect_ref ($1, $3->text ()); } - | postfix_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 { $$ = make_prefix_op (PLUS_PLUS, $2, $1); } - | MINUS_MINUS prefix_expr %prec UNARY + | MINUS_MINUS oper_expr { $$ = 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 +859,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,9 +127,8 @@ %# 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)