Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

But that's just not true. There is a single principled way for C declarations, and it's as easy as "a binding is a type name followed by an expression and a semicolon".

And while small inconcistencies have been introduced over time, it was entirely consistent when C was conceived. The problem is just that the simple rule how to read declarations is not well-known (I don't understand why). See my other comments.



> "a binding is a type name followed by an expression and a semicolon".

I find this hard to grock. Do you have a link to the actual grammar and production rules that apply to all cases ?

When I see:

  int a = 3;
I don't see a "type name followed by an expression and a semicolon", but rather the grammar "TYPE_NAME NAME = EXPR;". However, that's not correct, since TYPE_NAME cannot be any type (e.g. a function pointer won't work). When looking at

  void (*foo)(int) = expr;
  int (*foo)[N] = expr;
or at how the keywords "struct" and "union" are part of the type name in some contexts, but not others, I see quite different grammar rules.

I've tried to find literature about this, since I hack on a toy C parser every now and then, and those could simplify it, without much luck.

I've never thought of these as "CDECL = EXPR;" or similar, since that does not work either (e.g. a function declaration would be "void foo(int);" but that's not exactly the same as "void (*foo)(int) = expr;").


> Do you have a link to the actual grammar and production rules that apply to all cases ?

A google search returns that Annex A in the ISO standard has something like a grammar. Here is a link to an unoffical version of the standard: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf . However, this is not the right place to look for if you just want to understand the simple principle behind declarations, because the purity of declaration syntax has been considerably diluted in the last decades. So, only look in the standard if you are in good psychological health, and need to implement a production-grade C compiler. Also, note that grammars are overrated and tend to make things more complex than they really are. They are often too theoretical of a construct to be applicable, and that is certainly true for a language like C.

Instead, I recommend you to read the idea from the horse's mouth, here is Dennis Ritchie talking about it: https://www.bell-labs.com/usr/dmr/www/chist.html

> I don't see a "type name followed by an expression and a semicolon", but rather the grammar "TYPE_NAME NAME = EXPR;".

Let's ignore the optional equal sign + initializer expression, and just focus on declarations without initializers. The syntax is (as I said) "TYPE_NAME EXPR;" where EXPR is an expression that makes use of the newly-declared variable.

> (e.g. a function pointer won't work)

Not sure what you mean by "function pointer", but I'm pretty sure it's not a type name in the way I mean it. Here is how to look at your examples:

    void (*foo)(int) = expr;
                     ^^^^^^ (optional) initializer
         ^^^^^^^^^^^ expression (originally it was (*foo)(x),
                                 but as I said nowadays there are
                                 type specifiers in the list which
                                 is a little inconsistent.)
    ^^^^ type name 

    int (*foo)[N] = expr;
                  ^^^^^^ (optional) initializer
         ^^^^^^^^ expression
    ^^^ type name
Basically, the first example says "(* foo)(int) is a void", so you can conclude that foo is a pointer to a function that takes an int and returns a void.

The second example says "(* foo)[N] is an int" so you can conclude that foo is a pointer to an array of N ints.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: