[comp.lang.c] precedence of ?:

wittig@gmdzi.UUCP (Georg Wittig) (09/11/89)

How should
	0 ? 0 : i = 0
be interpreted?

1)	as	(0) ? (0) : (i=0)
	resulting in a (strange but) legal expression

or 2)	as	(0 ? 0 : i) = 0
	resulting in a syntax error
?

Existing compilers don't agree on which alternative is the correct one.

Thanks in advance,
-- 
Georg Wittig		     email:wittig@gmdzi.uucp   phone:(+49 2241) 14-2294
German National Research Laboratory for Computer Science (GMD)
P.O. Box 1240				|"Freedom's just another word for noth-
D-5205 St. Augustin 1 (West Germany)	| ing left to lose" (K. Kristofferson)

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/12/89)

In article <1265@gmdzi.UUCP> wittig@gmdzi.UUCP (Georg Wittig) writes:
-How should
-	0 ? 0 : i = 0
-be interpreted?
-1)	as	(0) ? (0) : (i=0)
-	resulting in a (strange but) legal expression
-or 2)	as	(0 ? 0 : i) = 0
-	resulting in a syntax error

The latter is the correct parse.  See the table on p. 49 of K&R I.
As you note, it is an unwell-formed formula.

-Existing compilers don't agree on which alternative is the correct one.

Well, they ought to.  See the table on p. 49 of K&R I.

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/12/89)

In article <11030@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> In article <1265@gmdzi.UUCP> wittig@gmdzi.UUCP (Georg Wittig) writes:
> -How should
> -	0 ? 0 : i = 0
> -be interpreted?
> -1)	as	(0) ? (0) : (i=0)
> -	resulting in a (strange but) legal expression
> -or 2)	as	(0 ? 0 : i) = 0
> -	resulting in a syntax error
> The latter is the correct parse.  See the table on p. 49 of K&R I.

OOPS!  As Steve Emmerson was the first to point out to me, the correct
way to parse expressions in C is to follow the formal grammar reduction
rules, not rely on the precedence/associativity tables.  Because the
left operand in an assignment expression cannot be a conditional
expression (it is constrained to be a unary expression with lvalueness),
there is no legal way to parse the example into the second form.  Thus
I was mistaken, as were the compiler implementors who parsed it that
way.  Perhaps they made the same mistake I just did.

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/15/89)

In article <3260@solo5.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>[...	0 ? 0 : i = 0
>is accepted, whereas
>	0 && i = 0
>is not.]
>But why allow the `?:' expression, why make it a special case?

I was mistaken in my original response; 0 ? 0 : i = 0 is not legal.
However, to save another iteration in this series of postings, note
that 0 ? i = 0 : 0 is legal.
	conditional-expression:
		logical-OR-expression
		logical-OR-expression ? expression : conditional-expression
So the interesting question becomes, why is that "expression" for the
second operand of ?: and not "logical-OR-expression".  (I think that
"conditional-expression" might result in ambiguity.)  The Rationale
says merely that "several extant implementations have adopted this
practice".  That must be the answer..

michi@anvil.oz (Michael Henning) (09/15/89)

In article <1265@gmdzi.UUCP>, wittig@gmdzi.UUCP (Georg Wittig) writes:
> 
> How should
> 	0 ? 0 : i = 0
> be interpreted?
> 
> 1)	as	(0) ? (0) : (i=0)
> 	resulting in a (strange but) legal expression
> 
> or 2)	as	(0 ? 0 : i) = 0
> 	resulting in a syntax error
> ?
> 

The correct interpretation is

	(0 ? 0 : i) = 0

because the precedence of ':' is higher than that of '='. Compilers which
accept '0 ? 0 : i = 0' as correct are simply wrong. I strongly recommend
the book

	"C A Reference Manual" by Harbison and Steele (Prentice Hall)

for the answers to problems such as the one above. It is the best reference
text for C I have seen so far.

					Michi.
-- 
| Michael Henning            |  Internet   : michi@anvil.oz{.au}              |
| Anvil Designs              |  JANET      : michi%anvil.oz@uk.ac.ukc         |
| P.O. Box 954               |  ARPA,Bitnet: michi%anvil.oz.au@uunet.uu.net   |
| Toowong 4066, Australia    |  UUCP       : ...!uunet!munnari!anvil.oz!michi |

decot@hpisod2.HP.COM (Dave Decot) (09/15/89)

> I don't find the grammar especially "convoluted"; in fact it's
> relatively straightforward.  The reason for the several types of
> expression is precisely to reflect the correct precedence without
> requiring precedence to be provided by means outside the grammar.

Note that it also renders invalid several classes of expression that
were completely correct in K&R I.  The changes to the grammar require
conforming compilers to reject (or at least warn about) such expressions,
because they are now syntax errors.  For instance, consider:

    double five, three;

	five = 2.0 +  three = 3.0;

Although I grant that it seems ambiguous, it has two valid parses according
to K&R I's grammar (ignoring its precedence rules, for the moment):

    (five = 2.0) + (three = 3.0);	/* somewhat silly */
 or
    (five = (2.0 + (three = 3.0)));	/* more likely what was intended */

The second of these above is the correct interpretation when using the
precedence rules to resolve ambiguity (the only moral use of precedence
rules as far as I'm concerned).

Another interesting effect of the Standard's grammar is that:

    k = (!y ? 0 : t = 1);

is valid, but

    k = (y ? t = 1 : 0);

is a syntax error, although it had a single unambiguous parse in K&R I.

The kinds of valid expression are different for the two right-hand
operands of the ?: operator.

Dave

maart@cs.vu.nl (Maarten Litmaath) (09/15/89)

gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
\In article <3260@solo5.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
\>[...	0 ? 0 : i = 0
\>is accepted, whereas
\>	0 && i = 0
\>is not.]
\>But why allow the `?:' expression, why make it a special case?
\
\I was mistaken in my original response; 0 ? 0 : i = 0 is not legal.

Indeed!  Yet both (SunOS 4.0.1) cc AND gcc 1.35 let it pass due to constant
folding! :-(
Let's see how this will do:

$ cat c.c
main()
{
	int     a, b, c, d;

	a = f();
	b = g();
	d = h();

	test(a ? b : c = d);
}
$ cc -c c.c
"c.c", line 9: illegal lhs of assignment operator
$ gcc c.c
ld: Undefined symbol 
   _test 
   _f 
   _g 
   _h 
$

\However, to save another iteration in this series of postings, note
\that 0 ? i = 0 : 0 is legal.
\	conditional-expression:
\		logical-OR-expression
\		logical-OR-expression ? expression : conditional-expression
\So the interesting question becomes, why is that "expression" for the
\second operand of ?: and not "logical-OR-expression".  (I think that
\"conditional-expression" might result in ambiguity.)  [...]

I don't think so: a ? b ? c : d : e has only one parse.
(If "expression" is OK, "conditional-expression" surely is too!)

Conclusion: cc has a small bug, gcc 1.35 has a more serious one.
-- 
   creat(2) shouldn't have been create(2): |Maarten Litmaath @ VU Amsterdam:
      it shouldn't have existed at all.    |maart@cs.vu.nl, mcvax!botter!maart

scjones@sdrc.UUCP (Larry Jones) (09/17/89)

In article <11069@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> So the interesting question becomes, why is that "expression" for the
> second operand of ?: and not "logical-OR-expression".  (I think that
> "conditional-expression" might result in ambiguity.)  The Rationale
> says merely that "several extant implementations have adopted this
> practice".  That must be the answer..

The answer is that the "?" and ":" are paired delimiters, just
like parentheses.  That means that you can put any arbitrary
expression between them without creating any ambiguity just like
you can put any arbitrary expression between "(" and ")".
----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                      scjones@SDRC.UU.NET
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150-2789             AT&T: (513) 576-2070
"I have plenty of good sense.  I just choose to ignore it."
-Calvin

bill@twwells.com (T. William Wells) (09/17/89)

In article <2550103@hpisod2.HP.COM> decot@hpisod2.HP.COM (Dave Decot) writes:
: > I don't find the grammar especially "convoluted"; in fact it's
: > relatively straightforward.  The reason for the several types of
: > expression is precisely to reflect the correct precedence without
: > requiring precedence to be provided by means outside the grammar.
:
: Note that it also renders invalid several classes of expression that
: were completely correct in K&R I.  The changes to the grammar require
: conforming compilers to reject (or at least warn about) such expressions,
: because they are now syntax errors.  For instance, consider:
:
:     double five, three;
:
:       five = 2.0 +  three = 3.0;
:
: Although I grant that it seems ambiguous, it has two valid parses according
: to K&R I's grammar (ignoring its precedence rules, for the moment):

But you *can't* ignore the precedence rules.

:     (five = 2.0) + (three = 3.0);     /* somewhat silly */
:  or
:     (five = (2.0 + (three = 3.0)));   /* more likely what was intended */
:
: The second of these above is the correct interpretation when using the
: precedence rules to resolve ambiguity (the only moral use of precedence
: rules as far as I'm concerned).

No it is not the correct interpretation. The precedence rules state
that addition is done before assignment. They do *not* state that
addition is done before assignment when there are two ways of
interpreting the expression. PARSING IS (with one exception) DONE
INDEPENDENTLY OF SEMANTIC ANALYSIS. (The exception? Type names must
be distinguished from other identifiers or the language is ambiguous.)
Thus the precedence rules say that the correct parse is:

	five = (2.0 +  three) = 3.0;

This will, of course, fail due to the semantic error. And we'll note
that existing compilers will flag the original as an error.

: Another interesting effect of the Standard's grammar is that:
:
:     k = (!y ? 0 : t = 1);
:
: is valid, but

No it is not. t = 1 is not a conditional-expression.

:     k = (y ? t = 1 : 0);
:
: is a syntax error, although it had a single unambiguous parse in K&R I.

Wrong again. It is frequently done incorrectly by K&R compilers,
precisely because precedence is not a good way to specify ?:. And,
since t = 1 *is* an expression, Standard C will permit it.

: The kinds of valid expression are different for the two right-hand
: operands of the ?: operator.

That is correct. The middle expression is any arbitrary expression;
the rightmost is a conditional-expression, which means that it can't
contain an unparenthesised assignment or comma operator.

BTW, the left operand is slightly more restricted: not only can it
not contain the assignment or comma, it can't contain ?:.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/17/89)

In article <3269@solo5.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>\	conditional-expression:
>\		logical-OR-expression
>\		logical-OR-expression ? expression : conditional-expression
>\So the interesting question becomes, why is that "expression" for the
>\second operand of ?: and not "logical-OR-expression".  (I think that
>\"conditional-expression" might result in ambiguity.)  [...]
>I don't think so: a ? b ? c : d : e has only one parse.

I had thought perhaps if you got enough interlaced ?: pairs that they
might be parsed ambiguously.  However (see below), if that were the
case then the Standard would have the same problem.  After doing some
"yacc" experiments with ?: grammars for a while, I found that it's not
possible to parse them in the wrong order even under
logical-OR-expression ? conditional-expression : conditional-expression
However,
conditional-expression ? logical-OR-expression : conditional-expression
or
conditional-expression ? conditional-expression : conditional-expression
would lead to an ambiguous grammar.

>(If "expression" is OK, "conditional-expression" surely is too!)

Yes, "expression" can be expanded to produce "conditional-expression".
The more general form in the Standard appears to not introduce ambiguity.

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/17/89)

In article <2550103@hpisod2.HP.COM> decot@hpisod2.HP.COM (Dave Decot) writes:
>Note that it also renders invalid several classes of expression that
>were completely correct in K&R I.

It wasn't at all clear what was intended by K&R I.

>Another interesting effect of the Standard's grammar is that:
>    k = (!y ? 0 : t = 1);
>is valid, but
>    k = (y ? t = 1 : 0);
>is a syntax error, although it had a single unambiguous parse in K&R I.

Other way around.

I think all existing usage where different compilers always parsed
the expressions the same way still work as before.  In cases where
there were varying interpretations, the Standard now provides a
single unambiguous prescription for how to parse the expressions.

karzes@mfci.UUCP (Tom Karzes) (09/19/89)

In article <2550103@hpisod2.HP.COM> decot@hpisod2.HP.COM (Dave Decot) writes:
>Another interesting effect of the Standard's grammar is that:
>
>    k = (!y ? 0 : t = 1);
>
>is valid, but
>
>    k = (y ? t = 1 : 0);
>
>is a syntax error, although it had a single unambiguous parse in K&R I.

Wrong, you've got it backwards.

As someone else mentioned, it's easy to permit any expression between the
? and the : because they are paired and must be properly nested.  Presumably
most C compilers have always allowed arbitrary expressions between the ? and
the :, so the standard allows it as well (although the lack of symmetry
between the true and false cases is somewhat annoying).

As for the first and last operands, at most one of them can be an
unparenthesized ?: expression, since permitting both to be would
introduce an ambiguity.  For example:

    a ? b : c ? d : e

could be:

    (a ? b : c) ? d : e

or it could be:

    a ? b : (c ? d : e)

The latter is more intuitive and useful since it permits else-if chains
without having to stack up parentheses, and this is the correct
interpretation according to the ANSI C standard.  It is also the
interpretation used by correct K&R C compilers, which require ?:
operators to group right-to-left.

Note that there was a mistake in the version of the C reference manual
appearing in some early editions of K&R, in which ?: expressions were
said to group left-to-right.  From section 18.1:

    Binary operators and the conditional operator all group left-to-right,
    and have priority decreasing as indicated:

However, the ?: operator is correctly described in section 7.13 of the
same C reference manual:

    Conditional expressions group right-to-left.

It is also described correctly in the table in section 2.12 of K&R (the
book, not the reference manual).  And of course, ?: groups right-to-left
in the pcc.

Later versions of the C reference manual corrected the error:

    The conditional operator groups right to left.

bill@twwells.com (T. William Wells) (09/30/89)

In article <658@anvil.oz> michi@anvil.oz (Michael Henning) writes:
: In article <1265@gmdzi.UUCP>, wittig@gmdzi.UUCP (Georg Wittig) writes:
: > How should
: >     0 ? 0 : i = 0
: > be interpreted?
: >
: > 1)  as      (0) ? (0) : (i=0)
: >     resulting in a (strange but) legal expression
: >
: > or 2)       as      (0 ? 0 : i) = 0
: >     resulting in a syntax error
: > ?
:
: The correct interpretation is
:
:       (0 ? 0 : i) = 0
:
: because the precedence of ':' is higher than that of '='.

No it isn't. Because the LHS of an assignment operator is a unary
expression, not a conditional expression. Precedence rules are not
adequate for analyzing C expressions.

It is not the case (as I'm assuming that Mr. Henning is asserting)
that the expression is parsed "(0 ? 0 : i) = 0" and then rejected
because "0 ? 0 : i" is not an lvalue. Instead, there is no valid
parse of the expression and the lvalueness of "0 ? 0 : i" is not
relevant.

Didn't we just finish beating this into the ground?

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com