2

So I noticed that in C, I can put parentheses on left side of assignment statements around the variable and it compiles correctly:

int a;
(a) = 3;

But it doesn't work if I put parentheses on the definition itself:

(int a) = 3;

So my question is, in the first code snippet, does the C grammar actually works around the fact that (a) means a by ignoring the parentheses or does the compiler actually evaluate it to mean a. Because if the grammar is ignoring it, then why doesn't the second code snippet also work?

Reinderien
  • 11,755
  • 5
  • 49
  • 77
Kartik Anand
  • 4,513
  • 5
  • 41
  • 72
  • 1
    `(...)` are relevant to [C Operator Precedence](https://en.cppreference.com/w/c/language/operator_precedence) (but irrelevant as you use them here). The only place you are allowed to use `(int ...)` is within a `for` loop declaration in C99+, e.g. `for (int a = 3; a < 8; a++) { /* do something */ }` Your `(int a) = 3;` simply describes syntax the compiler does not know how to handle. – David C. Rankin Oct 27 '18 at 07:05
  • Yeah, I agree that `(...)` are used for operator precedence, but what does it mean to use them on the left side of an assignment? – Kartik Anand Oct 27 '18 at 07:18
  • In an assignment, you have an expression on left and right side of `=`. The left must provide an LValue, the right not. Of course, you may put expressions in parentheses and it's still an expression. `int a = 3;` does look similar **but** it's a definition (a declaration with initialization). Beyound the fact, that it's semantically something different, there are separate grammar rules to resolve this. Initialization and assignment are two completely different things - they just look similar because the same `=` token is used. – Scheff's Cat Oct 27 '18 at 07:44

1 Answers1

4

Concerning OP's first sample code:

int a;
(a) = 3;

This is a declaration (1st line), followed by an assignment expression (2nd line).

The second sample code:

(int a) = 3; /* COMPILER ERROR */

is illegal but for further explanations I change this into:

int a = 3;

which is a definition – a declaration with initialization.

Assignment and declaration with initialization are something different although they look very similar (probably intentionally). (I got the feeling the OP is not aware about this, so I elaborate a bit.)

A complete C grammar can be found ANSI C Yacc grammar. (This is really old but I believe for what I want to explain it's sufficient.)

Rules applied to (a) = 3;:

  • for 3: primary_expression : CONSTANT

  • for a: primary_expression : IDENTIFIER

  • for (a): primary_expression : '(' expression ')'

  • for =: assignment_operator : '='

  • for (a) = 3: assignment_expression : unary_expression assignment_operator assignment_expression
    (where the assignment_expression on right-hand side is resolved in multiple steps to a primary_expression).

Rules applied to int a = 3;

  • for int: type_specifier : INT

  • for a: direct_declarator : IDENTIFIER`

  • for int a = 3;: (this becomes complicated)
    declaration : declaration_specifiers init_declarator_list ';'
    declaration_specifiers : type_specifier
    init_declarator_list : init_declarator
    init_declarator : declarator '=' initializer
    initializer : assignment_expression

Putting this together, it comes out that the following would be valid:

int b, a = (b) = 5;
/*       ^     ^
 *       |     +--- assignment operator
 *       +--------- initializer
 */

but there is simply nothing in the grammar to resolve

(int a) = 3; /* COMPILER ERROR */

May be, it's worth to mention that there is a similar question

SO: Initialization vs Assignment in C.

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
  • Thanks for pointing out the grammar here. It seems here that C allows for expressions to be `lvalue`, that's what I wanted to confirm. We're creating a toy grammar for compilers class, and we were only allowing identifiers to be `lvalue` which would prohibit brackets on the left side. Aside from the above example, is there any other scenario where it would make sense to have an expression on the left side of assignment? – Kartik Anand Oct 27 '18 at 08:35
  • 1
    @KartikAnand: Examples of expressions on the left side include `Array[Index] = Value`, `Structure.Member = Value`, and `*Pointer = Value`. – Eric Postpischil Oct 27 '18 at 08:45
  • Ok yeah, I totally forgot about them for the moment. Since the toy grammar we're making doesn't support pointers and array, for a moment I assumed only identifiers can come on the left side of an assignment. – Kartik Anand Oct 27 '18 at 08:46
  • @KartikAnand According to grammar, there might be a `unary_expression` on left-hand side which can be something pre-fixed or post-fixed or even an `( expression )`. Whether it forms an LValue or not is not subject of grammar but of semantic evaluation. – Scheff's Cat Oct 27 '18 at 08:48
  • 1
    note that declarators can also be parenthesized, e.g. `int (a) = 5;` – M.M Mar 30 '20 at 01:55