Arithmetic bug in csh. An explanation and a question.
Michael Greim
greim at sbsvax.UUCP
Thu Apr 14 21:34:59 AEST 1988
Hello netland,
Just recently Paul Heckbert raised an interesting question concerning
the way the csh is evaluating expressions. (See also comp.bugs.4bsd)
The Berkely manuals doesn't mention anything concerning right associativity,
but by the simple examples
>The command @ x = 0 - 1 + 2 sets x to -3 (should be 1)
>
>The command @ x = 0 - 1 - 2 sets x to 1 (should be -3)
you can see, that expressions are evaluated from right to left.
The SUN manuals state, as Wayne Mesard, Michael Thompson and I posted:
>From csh(1):
>Expressions and Operators
>[...]
> * / %
> multiplication, division, remainder (These are right
> associative, which can lead to unexpected results.
> Group combinations explicitly with parentheses.)
> + -
> addition, subtraction (also right associative)
I just took the time to look into the source.
The syntax of expression is :
exp0 : exp1 { "||" exp0 }
exp1 : exp2 { "&&" exp1 }
exp2 : exp2a { "|" exp2 }
exp2a : exp2b { "^" exp2a }
exp2b : exp2c { "&" exp2b }
exp2c : exp3 { EQOP exp3 }
exp3 : exp3a { RELOP exp3 }
exp3a : exp4 { SHIFT exp3a }
exp4 : exp5 { ADDOP exp4 }
exp5 : exp6 { MULOP exp5 }
exp6 : "!" exp6
| "~" exp6
| "(" exp0 ")"
| "{" ... "}"
| -[erwxfdzo] name
EQOP : "==" | "!=" | "=~" | "!~"
RELOP : "<=" | ">=" | "<" | ">"
SHIFT : "<<" | ">>"
ADDOP : "+" | "-"
MULOP : "*" | "/" | "%"
Here '{ .. }' means that '...' is optional, '[...]' means: one of the
letters of '...', the rest of the notation should be too obvious to
need elaboration.
The expressions are parsed top-down, the routines have the same names
as the right hand sides of the above productions, except for EQOP,
RELOP, ... which are recognized separately.
The typical way of evaluation is :
call first_routine
if there is an operator {
remember that operator
call second_routine
perform operation on results of first and second routines
}
This causes right-to-left evaluation for all operators except
the EQOP's.
Another example :
if ( -1 > -2 > -3 ) then
echo "true"
else
echo "false"
endif
First, "-1" is evaluated, then "-2 > -3", which yields "1", then "-1 > 1" which
yields "0", hence "false" is printed.
This right associativity is of course going against what one would exspect.
(I hope my English is understandibilitish :-)
It is relativly easy to change the source to get left-associativity :
just take out the recursion and write it as while stat's, like :
call first_routine
while there is an operator {
remember that operator
call second_routine
perform operation on results of first and second routines
}
The syntax has to be rewritten, like:
exp0 : exp1 { "||" exp1 }*
exp1 : exp2 { "&&" exp2 }*
exp2 : exp2a { "|" exp2a }*
...
("*" means "repeat" like in regular expressions)
Now we come to the problem :
IS IT REALLY NECESSARY TO DO THIS?
And:
WHO CAN DECIDE?
And:
WHY BEAT A DEAD HORSE? (except for the fun of it ;-/
Any ideas and comments anybody ?
Michael
PS: I will change my local csh version to get left associativity, and
implement some other changes too, like an operator '.' for
concatenation of strings (to get complicated patterns) and
enabeling evaluation of `...` as a primitive.
--
+------------------------------------------------------------------------------+
| UUCP: ...!uunet!unido!sbsvax!greim | Michael T. Greim |
| or greim at sbsvax.UUCP | Universitaet des Saarlandes |
| CSNET: greim%sbsvax.uucp at Germany.CSnet| FB 10 - Informatik (Dept. of CS) |
| ARPA: greim%sbsvax.uucp at uunet.UU.NET | Bau 36, Im Stadtwald 15 |
| Phone: +49 681 302 2434 | D-6600 Saarbruecken 11, West Germany |
+------------------------------------------------------------------------------+
| These lines are intentionally filled with something to prevent users from |
| getting the idea that it were empty by mistake rather than intent. |
+------------------------------------------------------------------------------+
More information about the Comp.unix.questions
mailing list