[comp.lang.c] The right-left rule

will@kfw.COM (Will Crowder) (07/16/90)

I've received several mail messages since offering to explain the 
right-left rule via e-mail, so I've decided to post.  For those of
you who already know this or don't care, quit now (this is a little
long).

Here's a control-L:



Thanks for sticking around... :) :) :)

The "right-left" rule is a completely regular rule for deciphering C
declarations.  It can also be useful in creating them.

First, symbols.  Read

     *		as "pointer to"
     [] 	as "array of"
     ()		as "function returning"

as you encounter them in the declaration.

STEP 1
------
Find the identifier.  This is your starting point.  Then say to yourself,
"identifier is".  You've started your declaration.

STEP 2
------
Look at the symbols on the right of the identifier.  If, say, you find "()"
there, then you know that this is the declaration for a function.  So you
would then have "identifier is function returning".  Or if you found a 
"[]" there, you would say "identifier is array of".  Continue right until
you run out of symbols *OR* hit a *left* parenthesis.  (If you hit a 
right parenthesis, that's the beginning of a () symbol, even if there
is stuff in between the parentheses.  More on that below.)

STEP 3
------
Look at the symbols to the left of the identifier.  If it is not one of our
symbols above (say, something like "int"), just say it.  Otherwise, translate
it into English using that table above.  Keep going left until you run out of
symbols *OR* hit a *right* parenthesis.  

Now repeat steps 2 and 3 until you've formed your declaration.  Here are some
examples:

     int *p[];

1) Find identifier.          int *p[];
                                  ^
   "p is"

2) Move right until out of symbols or left parenthesis hit.
                             int *p[];
                                   ^^
   "p is array of"

3) Can't move right anymore (out of symbols), so move left and find:
                             int *p[];
                                 ^
   "p is array of pointer to"

4) Keep going left and find:
                             int *p[];
                             ^^^
   "p is array of pointer to int".

Another example:

   int *(*func())();

1) Find the identifier.      int *(*func())();
                                    ^^^^
   "func is"

2) Move right.               int *(*func())();
                                        ^^
   "func is function returning"

3) Can't move right anymore because of the left parenthesis, so move left.
                             int *(*func())();
                                   ^
   "func is function returning pointer to"

4) Can't move left anymore because of the right parenthesis, so keep going
   right.                    int *(*func())();
                                           ^^
   "func is function returning pointer to function returning"

5) Can't move right anymore because we're out of symbols, so go left.
                             int *(*func())();
                                 ^
   "func is function returning pointer to function returning pointer to"

6) And finally, keep going left, because there's nothing left on the right.
                             int *(*func())();
                             ^^^
   "func is function returning pointer to function returning pointer to int".

Whew!  (Brief pause whilst the author wipes the sweat off his brow.)

As you can see, this rule can be quite useful.  You can also use it to
sanity check yourself while you are creating declarations, and to give
you a hint about where the put the next symbol and whether parentheses
are required.

Some declarations look much more complicated than they are due to array
sizes and argument lists in prototype form.  If you see "[3]", that's
read as "array (size 3) of...".  If you see "(char *,int)" that's read
as "function expecting (char *,int) and returning...".  Here's a fun
one:

                 int (*(*fun_one)(char *,double))[9][20];

I won't go through each of the steps to decipher this one.  Here's a 
control-L.  Press <return> (or whatever) to see what this one is.



Ok.  It's:

     "fun_one is pointer to function expecting (char *,double) and 
      returning pointer to array (size 9) of array (size 20) of int."

As you can see, it's not as complicated if you get rid of the array sizes
and argument lists:

     int (*(*fun_one)())[][];

You can decipher it that way, and then put in the array sizes and argument
lists later.

Some final words:

It is quite possible to make illegal declarations using this rule,
so some knowledge of what's legal in C is necessary.  For instance,
if the above had been:

     int *((*fun_one)())[][];

it would have been "fun_one is pointer to function returning array of array of
                                          ^^^^^^^^^^^^^^^^^^^^^^^^
pointer to int".  Since a function cannot return an array, but only a 
pointer to an array, that declaration is illegal.

Anyway, there it is folks.  Clarifications via e-mail (and boy I hope I
didn't slip this one up!).

Will
will@kfw.com
uunet!charyb!will

will@kfw.COM (Will Crowder) (07/17/90)

In the above-referenced article, I screwed up, and demonstrated that at
age 26, I still can't tell the difference between left and right.

Thanks to uunet!andrew.cmu.edu!ghoti+ (Adam Stoller) for pointing 
out the error.

:) :)

Here is the corrected article:


I've received several mail messages since offering to explain the 
right-left rule via e-mail, so I've decided to post.  For those of
you who already know this or don't care, quit now (this is a little
long).

Here's a control-L:



Thanks for sticking around... :) :) :)

The "right-left" rule is a completely regular rule for deciphering C
declarations.  It can also be useful in creating them.

First, symbols.  Read

     *		as "pointer to"
     [] 	as "array of"
     ()		as "function returning"

as you encounter them in the declaration.

STEP 1
------
Find the identifier.  This is your starting point.  Then say to yourself,
"identifier is".  You've started your declaration.

STEP 2
------
Look at the symbols on the right of the identifier.  If, say, you find "()"
there, then you know that this is the declaration for a function.  So you
would then have "identifier is function returning".  Or if you found a 
"[]" there, you would say "identifier is array of".  Continue right until
you run out of symbols *OR* hit a *right* parenthesis ")".  (If you hit a 
left parenthesis, that's the beginning of a () symbol, even if there
is stuff in between the parentheses.  More on that below.)

STEP 3
------
Look at the symbols to the left of the identifier.  If it is not one of our
symbols above (say, something like "int"), just say it.  Otherwise, translate
it into English using that table above.  Keep going left until you run out of
symbols *OR* hit a *left* parenthesis "(".  

Now repeat steps 2 and 3 until you've formed your declaration.  Here are some
examples:

     int *p[];

1) Find identifier.          int *p[];
                                  ^
   "p is"

2) Move right until out of symbols or left parenthesis hit.
                             int *p[];
                                   ^^
   "p is array of"

3) Can't move right anymore (out of symbols), so move left and find:
                             int *p[];
                                 ^
   "p is array of pointer to"

4) Keep going left and find:
                             int *p[];
                             ^^^
   "p is array of pointer to int".

Another example:

   int *(*func())();

1) Find the identifier.      int *(*func())();
                                    ^^^^
   "func is"

2) Move right.               int *(*func())();
                                        ^^
   "func is function returning"

3) Can't move right anymore because of the right parenthesis, so move left.
                             int *(*func())();
                                   ^
   "func is function returning pointer to"

4) Can't move left anymore because of the left parenthesis, so keep going
   right.                    int *(*func())();
                                           ^^
   "func is function returning pointer to function returning"

5) Can't move right anymore because we're out of symbols, so go left.
                             int *(*func())();
                                 ^
   "func is function returning pointer to function returning pointer to"

6) And finally, keep going left, because there's nothing left on the right.
                             int *(*func())();
                             ^^^
   "func is function returning pointer to function returning pointer to int".

Whew!  (Brief pause whilst the author wipes the sweat off his brow.)

As you can see, this rule can be quite useful.  You can also use it to
sanity check yourself while you are creating declarations, and to give
you a hint about where the put the next symbol and whether parentheses
are required.

Some declarations look much more complicated than they are due to array
sizes and argument lists in prototype form.  If you see "[3]", that's
read as "array (size 3) of...".  If you see "(char *,int)" that's read
as "function expecting (char *,int) and returning...".  Here's a fun
one:

                 int (*(*fun_one)(char *,double))[9][20];

I won't go through each of the steps to decipher this one.  Here's a 
control-L.  Press <return> (or whatever) to see what this one is.



Ok.  It's:

     "fun_one is pointer to function expecting (char *,double) and 
      returning pointer to array (size 9) of array (size 20) of int."

As you can see, it's not as complicated if you get rid of the array sizes
and argument lists:

     int (*(*fun_one)())[][];

You can decipher it that way, and then put in the array sizes and argument
lists later.

Some final words:

It is quite possible to make illegal declarations using this rule,
so some knowledge of what's legal in C is necessary.  For instance,
if the above had been:

     int *((*fun_one)())[][];

it would have been "fun_one is pointer to function returning array of array of
                                          ^^^^^^^^^^^^^^^^^^^^^^^^
pointer to int".  Since a function cannot return an array, but only a 
pointer to an array, that declaration is illegal.

Anyway, there it is folks.  Clarifications via e-mail (and boy I hope I
didn't slip this one up!).

Will
will@kfw.com
uunet!charyb!will

karl@haddock.ima.isc.com (Karl Heuer) (07/17/90)

In article <1990Jul16.195111.5976@kfw.COM> will@kfw.com (Will Crowder) writes:
>[150 lines about the right-left rule]

Summary: in declarations as well as in expressions, postfix unary has higher
precedence than prefix unary; parens may be used to override this.

See also: cdecl(1).

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

dankg@tornado.Berkeley.EDU (Dan KoGai) (07/17/90)

	Thanks for your great article.  And that reminded me of the one
of the IOCCC winner's code:  That takes C expression and parses it to
English (i.e.  "int (*foo())[]" -> foo is array of ptr to function that
returns int).  I had that code but it was lost due to damn cracker who
messed my accout (sigh).  But it was greate, useful, and well, obfuscunated.
I don't know the server that retrieves IOCCC winner of the past but it's
worth taking a look.

----------------
____  __  __    + Dan The "Precedence sucks sometimes" Man
    ||__||__|   + E-mail:       dankg@ocf.berkeley.edu
____| ______    + Voice:        +1 415-549-6111
|     |__|__|   + USnail:       1730 Laloma Berkeley, CA 94709 U.S.A
|___  |__|__|   + Oxymora:    Usable MS-DOS, Multitasking Mac, Secure Unix,
    |____|____  + 		rec.humor posters without sense of humor,
  \_|    |      +		Christian Science, and English grammer

korsberg@abaa.uucp (Ed Korsberg) (07/17/90)

In article <1990Jul16.195111.5976@kfw.COM> will@kfw.com (Will Crowder) writes:
>[150 lines about the right-left rule]

I have a table driven FSM with a state variable (state_variable) which points to 
one of several state tables (see trivial example below).  Given the current 
state (state_variable) and an event, I want to call the appropriate action 
(func_x in tables).

void            (*state1_table[]) () =
{
    func_1                /* EVENT 1 */
    ,func_2               /* EVENT 2 */
    ,func_3               /* EVENT 3 */
    ,func_4               /* EVENT 4 */
};

void            (*state2_table[]) () =
{
    func_1                /* EVENT 1 */
    ,func_2               /* EVENT 2 */
    ,func_7               /* EVENT 3 */
    ,func_6               /* EVENT 4 */
};

void            (*state3_table[]) () =
{
    func_1                /* EVENT 1 */
    ,func_8               /* EVENT 2 */
    ,func_0               /* EVENT 3 */
    ,func_4               /* EVENT 4 */
};


fsm(event)
unsigned int event;			/* occurance of EVENT n */
{
	void	(*action)();
	
	action = state_variable[event]; /* From STATE and EVENT, get action */
	(*action)();			/* perform action */
}

****************************************************************************
Problem is how do you declare a pointer to an array of pointers of functions 
returning void?

I need something like 
	void (*state_variable)[]
but cannot seem to get the syntax correct.  
Any help on this would be appreciated.
---------------------------------------------------------------------------

Ed Korsberg	korsberg@aa.ab.com

will@kfw.COM (Will Crowder) (07/18/90)

In article <1990Jul17.125413.7968@agate.berkeley.edu>
  dankg@tornado.Berkeley.EDU (Dan KoGai) writes:

>	Thanks for your great article.

You're welcome.

>                                       And that reminded me of the one
>of the IOCCC winner's code:  That takes C expression and parses it to
>English (i.e.  "int (*foo())[]" -> foo is array of ptr to function that
>returns int).

Actually, foo is a function that returns a pointer to an array of ints.
I have a Turbo C hack I call c2eng which will take the above and emit
English for it.  I'd be happy to e-mail it (uuencoded, compressed) to
whomever wants it.  Just send me mail, folks!  It's not obfuscated...

>----------------
>____  __  __    + Dan The "Precedence sucks sometimes" Man

Will
will@kfw.com
uunet!charyb!will

will@kfw.COM (Will Crowder) (07/18/90)

In article <5593@abaa.UUCP> korsberg@abaa.UUCP (Ed Korsberg) writes:

[description of a table-driven FSM which requires....]

>[...] a pointer to an array of pointers of functions 
>returning void.

           void (*(*foo)[])();

Ugly, ain't it?

>Ed Korsberg	korsberg@aa.ab.com

Will
will@kfw.com
uunet!charyb!will

jk@hpfelg.HP.COM (John Kessenich) (07/19/90)

>Summary: in declarations as well as in expressions, postfix unary has higher
>precedence than prefix unary; parens may be used to override this.

K&R treats punctuation, i.e. 

    ()[].-> 

as operators having the highest precedence.  Thus, this all reduces to 

    "Declarations may be read correctly by starting with the name and
     then reading in precedence order."

This makes more sense (and seems simpler) to me than rules like 
"inside out", "alternating left and right", etc. which seem like artificial 
structures added on top of the language.

--------------
John Kessenich

johnb@srchtec.UUCP (John Baldwin) (07/19/90)

Does anyone have a PD or shareware version (preferably source code) for
an English <--> C Complex Declarator  translator?  I know there's a
version in K&R 2nd ed.;  what I'm looking for is a robust version that
can handle type qualifiers (like const), function argument types, and
the like, and can recover from bad input (at least being able to recognize
an error and say: "I can't translate that!").

-- 
John T. Baldwin			| The opinions expressed herein are available
research analyst		| for the small price of $5.
search technology, inc.		| Operators are online 24 hours a day; call
johnb@srchtec.uucp		| 1-800-366-2277 (1-800-FOO-BARR).

jk@hpfelg.HP.COM (John Kessenich) (07/20/90)

>Problem is how do you declare a pointer to an array of pointers of functions 
>returning void?

Lets see,

	void (*state_variable)();

read in precedence order would be a pointer to function returning void.  
To get a pointer to an array of these you need a pointer to one of these,

	void (**state_variable)();

Reading in precedence order gives a pointer to a pointer to a function 
that returns void, which is equivalent to saying a pointer to an array 
of functions returning void.

To get an array of pointers to functions returning void, just use

	void (*state_variable[SIZE])();

--------------
John Kessenich

chris@mimsy.umd.edu (Chris Torek) (07/20/90)

In article <5593@abaa.UUCP> korsberg@abaa.uucp (Ed Korsberg) writes:
>I have a table driven FSM with a state variable (state_variable) which
>points to  one of several state tables ....

>void            (*state1_table[]) () =
>{
>    func_1                /* EVENT 1 */
>    ,func_2               /* EVENT 2 */
>    ,func_3               /* EVENT 3 */
>    ,func_4               /* EVENT 4 */
>};

Two comments: these are actually events 0..3, not 1..4; C syntax allows
trailing commas so that you can write

	void (*tab[])() = {
		f0,
		f1,
		f2,
		f3,
	};

[more tables omitted]
>fsm(event)
>unsigned int event;			/* occurance of EVENT n */
>{
>	void	(*action)();
>	
>	action = state_variable[event]; /* From STATE and EVENT, get action */
>	(*action)();			/* perform action */
>}
>
>****************************************************************************
>Problem is how do you declare a pointer to an array of pointers of functions 
>returning void?

Here is a danger sign: if you ever want a `pointer to an array', think
hard about it.  In particular, think hardest about the N in the array.
Every array is an `array N of T', where N is some constant.  If you do
not know the constant, you probably do not want a pointer to the (entire)
array.  Logically, a pointer to the whole array will do you no good,
because you do not know how many array elements that pointer points to.
You might as well instead point to one array element at a time---if you
can.

This follows from The Rule:

    In any value context, an object of type `array N of T' becomes a
    value of type `pointer to T' whose value is the address of the
    first (0th) element of that array.

Thus, instead of a `pointer to array N of T', you most often want a
`pointer to T'.  (Note, however, that the Rule stops applying once you
have a pointer.  Thus, if you have an `array N of T' where T is, say,
`array 3 of int', you wind up with a `pointer to T', or a `pointer to
array 3 of int'.  This is not an object of type `array N of ...', it is
a value of type `pointer to ...'; it does not get converted again, and
you will need to know the (new) N in the sub-array that is part of `T'.)

In other words, rather than `pointer to array N of T=pointer-to-function-
of-void-returning-void', you probably really want `pointer to T', because
each of your table objects is an `array N of T'.  You could---given N,
or deciding that `N=?'---get a pointer to each one, but you do not *have*
to; it is more convenient to point to the first element of each table.

Thus, you want:

    $ T='pointer to function returning void'
    $ echo "declare state_variable as pointer to $T" | cdecl
    void (**state_table)()
    $

If you really prefer it, you can fix an N (either 4 or ? will suffice
for the example given) and write either

	void (*(*state_table)[4])()	/* N=4 */

or

	void (*(*state_table)[])()	/* N=? */

or either of those using typedef to make them `simpler'.  You will
then have to write, e.g.,

	state_table = &state1_table;

instead of the simpler

	state_table = state1_table;

for the first declaration.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris