Increment Operators vs. Precedence

Chris Torek torek at elf.ee.lbl.gov
Wed Mar 6 11:18:07 AEST 1991


In article <THOMSON.91Mar5173421 at zazen.macc.wisc.edu>
thomson at zazen.macc.wisc.edu (Don Thomson) writes:
>The example on the board is y = x++ ...  So the dilemma is how to explain
>that precedence is not the issue here, that the order of operations is
>tied to the definition of prefix versus postfix increment operators.

Precedence is purely syntactic; order of operations is semantic.

All `precedence' does is assign some particular grouping to a set of
symbols that otherwise have none.  For instance, given

	x = a + b * c++;

there is no grouping, and precedence (and associativity) is a simple way
of describing how the expression is parsed.

Exclusive of precedence and associativity, all of the following are possible
parses for the sentence above:

	((x = a) + (b * c))++

	(x = (a + b)) * (c++)

	(((x = a) + b) * c)++

	x = (a + (b * (c++)))

The last one is the one we actually want, and we can obtain it by using
precedence and associativity rules:

	post-increment > multiply > add > assign

In

	a = b = 0;

a right-associative rule for assignment is necessary to force

	a = (b = 0)

rather than

	(a = b) = 0

, and in

	x = a / b * c / d;

a left-associative rule is necessary to force

	x = (((a / b) * c) / d)

rather than

	x = ((a / (b * c)) / d)

or some such.

All of these simply give us some particular parse tree for some sentence.
It is up to us to assign semantics to each parse.  The semantics for `c++'
are `get the current value of c, and eventually---by the time you reach
the next sequence point---store that value, plus 1, in c'.

So in

	y = x++;

the parse tree looks like this:


		=

	     /     \
	    /       \
	   /         \

	  y	 postfix-++

		     |

		     x

or in list notation, (= y (postfix-++ x)), but the order of operations is:

	A. fetch current value of x

	B. [store in y] and [add 1 to x]

In particular, in an expression like:

	x = ++x;

we have a very specific parse tree, namely (= x (pre++ x)), but we may have
a nonspecific result, depending on implementation details:

	A. fetch current value of x
	B. [add 1 and store in x] and [add 1 to x]

If preincrement is implemented internally as:

	- put an `add 1 to x' on the list of things to do
	- fetch value of x and add 1
	- store in x
	- do the list of things to do

this expression might add 2 to x.  If, on the other hand, it is
implemented as:

	- fetch current value of x, add 1, store result in x, use result
	- store result in x

the expression will add 1 to x.  Since a compiler could even
(conceivably) `interleave' operations, it is possible that this might
act like `x += 0x101'.%  This is rather unlikely, but explains why no
more than one side effect should be applied to any individual object
between sequence points.
----
% Consider a machine in which `add 1 to x' is implemented as `fetch low byte
 of x, add 1, store; if result is 0, fetch high byte of x, add 1, store'
 and where there are two `processing units' and some peculiar delays:

		unit 1:				unit 2:
		------				------
	fetch low byte of x: (255)	(busy with something else)
	add 1: (0)			fetch low byte of x: (255)
	store: (low byte of x now 0)	add 1: (0)
	(delay)				store: (low byte of x still 0)
	(delay)				fetch high byte of x: (17)
	(delay)				add 1: (18)
	(delay)				store: (x is now 1 larger)
	fetch high byte of x: (18)	(do something else)
	add 1: (19)
	store: (x is now 0x101 larger)
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427)
Berkeley, CA		Domain:	torek at ee.lbl.gov



More information about the Comp.lang.c mailing list