3

I can't quite understand what the syntax mean in C99. Here by saying C99 I mean ISO/IEC 9899:1999. Well, I think the grammar syntax part doesn't change much since ANSI C, C89.

Take for an example from this question:

6.5.5 Multiplicative operators
  Syntax
    multiplicative-expression:
      cast-expression
      multiplicative-expression * cast-expression
      multiplicative-expression / cast-expression
      multiplicative-expression % cast-expression

  Constraints

Each of the operands shall have arithmetic type. The operands of the % operator
shall have integer type.

  Semantics

The usual arithmetic conversions are performed on the operands.
The result of the binary * operator is the product of the operands.
The result of the / operator is the quotient 

I wonder why in the syntax of multiplicative operators we have a "cast-expression" ? And what grammar can this syntax imply? In that question @Avi said that in

a*b*c

"c must be parsed as a cast-expression", I can't quite understand this.

Take another example from c99 6.6.1,the syntax of constant expressions

Syntax
   constant-expression:
       conditional-expression

why this conditional-expression come up here? Can someone show me how to explain those syntax? Thank you all in advance.

Community
  • 1
  • 1
Allan Ruin
  • 5,229
  • 7
  • 37
  • 42

2 Answers2

3

I wonder why in the syntax of multiplicative operators we have a "cast-expression" ?

This is a typical device used in context free grammars to specify the grouping of operators of the same precedence and to specify the precedence in the first place (OK, this isn't precise; the grammar can express more than just assigning precedence to operators, but if we only wanted to express simple precedence based expression evaluation in CFG, we would do it just this way). The cast-expression is not related anyhow to the multiplicative-expression; it's just "any expression not containing multiplicative operations or operations of lower precedence".

So, how would this work:

  1. The grouping of same-precedence operators:

    1*2*3*4
    

    in this case, there are following possibilities for grouping (top level only):

    • 1*(2*3*4)
    • (1*2)*(3*4)
    • (1*2*3)*4

    by looking at the grammar, we know that whatever stands left of * must be a cast-expression, that is, must not contain (unparenthesized) *. Therefore, only the third alternative is viable

  2. The precedence. Imagine the expression

    a*b+c
    

    It could be parsed as either

    • (a*b)+c
    • a*(b+c)

    However, we know that the cast-expression on the right hand side can't contain (unparenthesized) + (or we can work that out from the grammar if we inspect it). That leaves the first option as the only possible alternative.

    Another expression

    a+b*c
    

    could be, in turn, parsed as

    • (a+b)*c
    • a+(b*c)

    However, the multiplicative-expression on the left of * can't contain (unparenthesized) + either (left as an exercise for the reader). Therefore, only the second alternative is viable.

To your question about conditional-expression: The grammar rule just disallows anything equivalent or below assignment operators to be parsed as constant-expressions. Therefore, a=b, a,b, a+=b can't possibly be constant expressions, while a+b, a[b] and a(b) possibly can. Note that it doesn't disallow eg. (a=b); you have to look to the actual clause specifying what are constant expressions, which restricts the realm of constant expressions more than the grammar.

jpalecek
  • 47,058
  • 7
  • 102
  • 144
  • I can see that if we just take `cast-expression` as some expression that is not `multiplicative-expression`, then we can know the associativity of multiplicative-expression. But, cast-expression itself does have an syntax in c99 `6.5.4.1`, we don't need to ensure the 'c' in the example expression is `cast-expression`? Can you explain a bit about the `conditional-expression` part? – Allan Ruin Apr 25 '12 at 13:24
  • That means we can simply change `cast-expression` to `conditional-expression` as well? – Allan Ruin Apr 25 '12 at 13:25
  • The cast operators merely happens to be the series of operators with one priority higher than the multiplicative operators. The whole operator precedence chapter of the standard is built in the same manner. Yes, it is quite unclear and confusing, as is the whole chapter regarding expressions in the standard. – Lundin Apr 25 '12 at 13:32
  • 1
    @AllanRuin: "But, cast-expression itself does have an syntax in c99 6.5.4.1, we don't need to ensure the 'c' in the example expression is cast-expression?" Of course we need. We then look at the standard, and see that `cast-expression -> unary-expression`, `unary-expression -> postfix-expression`, `postfix-expression -> primary-expression` and `primary-expression -> identifier` (`->` means "can be rewritten to"). `c` is an identifier, therefore, it can be parsed as a `cast-expression`. – jpalecek Apr 25 '12 at 13:41
1

I wonder why in the syntax of multiplicative operators we have a "cast-expression" ?

Let's start with a much simpler problem, and a correspondingly simpler grammar. We'll define a grammar to represent a simple arithmetic expression (1 + 2, 3 * (4 - 2), 42, etc.). Since we want a plain numeric constant to be a legal expression, we must define our grammar such that there is a path from the root non-terminal expression to a simple number:

expression:
    term  |
    term add-op expression

term:
    factor |
    factor mul-op term

factor:
    number |
    ( expression ) 

Non-terminals like number, add-op, and mul-op should be obvious.

42 is a number, which is a production of factor, which is a production of term, which is a production of expression. Thus 42 is a legal arithmetic expression according to our grammar; term and factor are intermediate productions in this path.

A similar thing is happening in the C grammar. A cast-expression is an intermediate production between an expression and some terminal such as an identifier or numeric constant. Our simple grammar defines 2 levels of precedence; the C grammar defines 16 distinct levels of precedence with a boatload more operators, so there are a lot more intermediate productions along that path. And we want a cast-expression to have a higher level of precedence than a multiplicative-expression so we can handle cases like

x = a * (int) b;

properly.

John Bode
  • 119,563
  • 19
  • 122
  • 198