Reading K&R suggests that since ++ is right associative, and has a
higher precedence than +, the 'correct' answer is
a + (++b)
However, actual code execution gives:
(a++) + b
on both machines I've tried.
Actual behavior makes sense with the ++ being tokenized 'left to right',
which is certainly easy to do.
I'm curious about what the 'right' official behavior is supposed to
be, or if it is undefined. [I suppose 'right' is ANSI nowadays, though
if K&R addresses the topic I'd be interested as well.]
I'd avoid writing this in code I wanted to work reliably, natch :-)
Sorry, no. Associativity and precedence control how an expression is
evaluated *after* it has been tokenized. So you start with
a+++b
and then tokenize it (using the "longest possible token" rule) into
a ++ + b
Then you disambiguate it (if necessary) using associativity and/or
precedence, resulting in
( a ++ ) + b
--
Barry Margolin
System Manager, Thinking Machines Corp.
bar...@think.com {uunet,harvard}!think!barmar
In article <kumra5...@early-bird.think.com> bar...@think.com
(Barry Margolin) writes:
>... Associativity and precedence control how an expression is
>evaluated *after* it has been tokenized.
Barry is correct, of course; `a+++b' means `a++ + b', which means:
Inspect the object `a'. Toss its current value in the air,
aiming it towards a `sum' operation. Toss (a + 1) in the air,
aiming it towards the object `a'. Inspect b. Toss b's current
value in the air, aiming it towards the same `sum' operation.
If the next thing is a semicolon, we get a sequence point, which means:
Wait for the dust to settle.
after which a and b have been summed, with the result discarded, and a+1
has landed in a. The compiler is like a juggler tossing eggs. At
sequence points, it gets to stop and rest a bit.
Note that, if you write `a++ + a++', you toss (a+1) in the air *twice*,
aiming the results at the same spot. The eggs (a+1's) collide in midair
and bits fly everywhere. All you get is a mess---unless you have a slow
and stupid kind of compiler, one incapable of juggling more than one
thing at a time.
--
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 510 486 5427)
Berkeley, CA Domain: to...@ee.lbl.gov
What I forgot to mention---I had intended this when I started the
follow-up, but I got interrupted and lost the thread---is that
associativity and precedence are concepts that apply to `operator
precedence' grammars. The C grammar can be defined without referring
to precedence, and in fact, the ANSI C standard does so. Our notions
of `precedence'---what gets done first---are merely a convenient
shorthand for remembering how the parse goes.
Anyway, `a+++b' is first broken into tokens: <a> <++> <+> <b>. These
then wend their way through the ANSI grammar to become, ultimately:
expression
|
assignment-expression
|
conditional-expression
|
logical-OR-expression
|
logical-AND-expression
|
inclusive-OR-expression
|
exclusive-OR-expression
|
AND-expression
|
equality-expression
|
relational-expression
|
shift-expression
|
additive-expression
|
additive-expression <+> multiplicative-expression
| |
multiplicative-expression cast-expression
| |
cast-expression unary-expression
| |
unary-expression postfix-expression
| |
postfix-expression primary-expression
| |
postfix-expression <++> identifier <b>
|
primary-expression
|
identifier <a>
This is a relatively simple expression, yet it requires, in the grammar
given in the ANSI standard, quite a long parse tree. In an operator-
precedence grammar (e.g., in the Unix PCC compiler) we get a much simpler
tree:
expression
|
expression <+> expression
| |
term term
| |
term <++> identifier <b>
|
identifier <a>
This is, of course, why humans use precedence to remember how C works.
It is not *necessary*, but it *is* a whole lot easier.