From: li@nssdca.gsfc.nasa.gov (Constance Y. Li (301)513-1649)
Newsgroups: comp.lang.c
Subject: Re: Suspicious pointer conversion?
Summary: Clockwise Spiral Rule to help in parsing complicated declarations
Date: 9 Apr 92 19:58:00 GMT
Organization: NASA - Goddard Space Flight Center
News-Software: VAX/VMS VNEWS 1.41

In article <11404@anderson>, anderson@Software.Mitel.COM (David Anderson) writes...
>In article <57006@cup.portal.com> ts@cup.portal.com (Tim W Smith) writes:
>>>   To declare signal(), using prototypes, but without typedef, we must%
>>>   write:
>>>
>>>      void (*signal(int, void (*)(int)))(int);
>>>
>>>   This is not particularly readable. [...]
>>>
>>>
>>> So how does one parse such an expression?  If I understood the rules at this
>>> level, I would be able to write these things much easier rathyer than by trial
>>> and error.
>>
> 
>I have been using a very easy rule to reading complicated declarations that I
>use when teaching C for the College, called the "Clockwise Rule". I read
>about it in an article sometime ago... anyway, it is so easy to use that
>you don't even need to write anything down to parse it all in your head!
> 
>Here is how it works:
> 
>1) Starting with the unknown element, move in a spiral/clockwise direction and
>   when you ecounter the following elements replace them with the corresponding
>   english statements:
> 
>    [X] or []       = Array X size of... or Array undefined size of...
>    (type1, type2)  = function passing type1 and type2 returning...
>    *               = pointer(s) to...
> 
>2) Keep doing this in a spiral/clockwise direction until all tokens are covered
>3) Always resolve anything in parenthesis first!
> 
>Some examples are required to fully understand this concept.
> 
>Example #1: Simple declaration
> 
>                     +-------+
>                     | +-+   |
>                     | ^ |   |
>                char *str[10];
>                 ^   ^   |   |
>                 |   +---+   |
>                 +-----------+
> 
>Question we ask ourselves: What is str?
> 
>                "str is an...
> 
>o We move in a spiral clockwise direction starting with 'str' and the first
>  character we see is a '[' so, that means we have an array, so...
> 
>                "str is an array 10 of...
> 
>o Continue in a spiral clockwise direction, and the next thing we encounter is
>  the '*' so, that means we have pointers, so...
> 
>                "str is an array 10 of pointers to...
> 
>o Continue in a spiral direction and we see the end of the line (the ';' ) so
>  keep going and we get to the type 'char', so...
> 
>                "str is an array 10 of pointers to char"
> 
>o We have now "visited" every token; therefore we are done!
> 
>============================================================================
> 
>Example #2: Pointer to Function declaration
> 
>                     +--------------------+
>                     | +---+              |
>                     | |+-+|              |
>                     | |^ ||              |
>                char *(*fp)( int, float *);
>                 ^   ^ ^  ||              |
>                 |   | +--+|              |
>                 |   +-----+              |
>                 +------------------------+
> 
>Question we ask ourselves: What is fp?
> 
>  "fp is a...
> 
>o Moving in a spiral clockwise direction, the first thing we see is a ')';
>  therefore, fp is inside parenthesis, so we continue the spiral inside the
>  parenthesis and the next character seen is the '*', so...
> 
>  "fp is a pointer to...
> 
>o We are now out of the parenthesis and continuing in a spiral clockwise
>  direction, we see the '('; therefore, we have a function, so...
> 
>  "fp is a pointer to a function passing an int and a pointer to float
>   returning...
> 
>o Continuing in a spiral fashion, we then see the '*' character, so...
> 
>  "fp is a pointer to a function passing an int and a pointer to float
>   returning a pointer to...
> 
>o Continuing in a spiral fashion we see the ';', but we haven't visited all
>  token so we continue and we finally get to the type char, so...
> 
>  "fp is a pointer to a function passing an int and a pointer to float
>   returning a pointer to a char"
> 
>============================================================================
> 
>Example #3: The original posters dilemma
> 
>                      +-----------------------------+
>                      |                  +---+      |
>                      |  +---+           |+-+|      |
>                      |  ^   |           |^ ||      |
>                void (*signal(int, void (*fp)(int)))(int);
>                 ^    ^      |      ^    ^  ||      |
>                 |    +------+      |    +--+|      |
>                 |                  +--------+      |
>                 +----------------------------------+
> 
>Question we ask ourselves: What is 'signal'?
> 
>Notice that signal is *inside* parenthesis, so we must resolve this first!
> 
>o Moving in a *clockwise* direction we see '(' so we have...
> 
>  "signal is a function passing an int and a...
> 
>o Hmmm, we can use this same rule on 'fp', so... What is fp? fp is also inside
>  parenthesis so continuing we see an '*', so...
> 
>  "fp is a pointer to...
> 
>o Continue in a spiral clockwise direction and we get to '(', so...
> 
>  "fp is a pointer to a function passing int returning..."
> 
>o Now we continue out of the function parenthesis and we see void, so...
> 
>  "fp is a pointer to a function passing int returning nothing (void)"
> 
>o We have finished with fp so let's catch up with 'signal', we now have...
> 
>  "signal is a function passing an int and a pointer to a function passing an
>   int returning nothing (void) returning...
> 
>o We are still inside parenthesis so the next character seen is a '*', so...
> 
>  "signal is a function passing an int and a pointer to a function passing an
>   int returning nothing (void) returning a pointer to...
> 
>o We have now resolved the items within parenthesis, so continuing clockwise,
>  we then see another '(', so...
> 
>  "signal is a function passing an int and a pointer to a function passing an
>   int returning nothing (void) returning a pointer to a function passing an
>   int returning...
> 
>o *Finally* we continue and the only thing left is the word 'void', so the
>final complete definition for signal is:
> 
>  "signal is a function passing an int and a pointer to a function passing an
>   int returning nothing (void) returning a pointer to a function passing an
>   int returning nothing (void)"
> 
>=============================================================================
> 
>This explanation is long only because I broke it down into separate sections,
>once you get used to it, anyone can "whip" off any declaration within seconds!
> 
>It also helps to use this rule when trying to determine if your declaration
>makes sense.
> 
>One last point, for things like const and volatile and far etc..., always
>associate them from left to right; for example:
> 
>        const char *chptr;
> 
>o Associate const with the token to the right, so in your mind imagine as if
>  it was declared as follows:
> 
>        (const char) *chptr;
> 
>o Now, what is chptr??
> 
>  "chptr is a pointer to a constant char"
> 
>How about this one:
> 
>        char const *chptr;
> 
>o Associate the const with the token to the right and you then imagine:
> 
>       char (const *)chptr;
> 
>o Now, what is chptr??
> 
>  "chptr is a constant pointer to char"
> 
>This technique has really been useful in helping my students get through
>complicated declarations, with practice you should be able to parse any
>declaration thrown at you...
> 
>Practice this on the examples in K&R II on page 122.
> 
>Hope this helps,
> 
>Regards,
> 
>/David
>-- 
>-------------------------------------------------------
>David AR Anderson   Email: anderson@Software.Mitel.COM
>Software Tools and Integration
>Mitel Corporation   Disclaimer: My opinions are my own!
Newsgroups: comp.lang.c