[comp.lang.c] rules for transforming casts to declarations?

stevev@tekchips.LABS.TEK.COM (Steve Vegdahl) (03/15/89)

I am working on a preprocessor that needs to---among other things---transform
between "cast-style" types and "declaration-style" types.  For example,
the user's input might contain the string:
  (int (*)())
The preprocessor would need to tranform this into the declaration:
  int (*foo)();

I am treating this problem as a transformation from a list of tokens to
a list of tokens.  (We can assume that the original list is a well-formed
cast expression.)

Not being an expert on C type-declarations, I would appreciate opinions as
to whether this method handles all cases and, if not, some examples
cast-expressions on which it will fail.

Thanks.
		Steve Vegdahl
		Computer Research Lab
		Tektronix Labs
		Beaverton, Oregon

----------------------------------------------------------------

Alleged algorithm for transforming cast-style type into a declaration.

  1. strip away the outer parentheses of the cast expression
  2. find the position to insert the to-be-declared identifier
      a. skip over all identifiers, left parentheses, and asterisks (i.e.,
         go until you hit a right parenthesis, left bracket or end of string)
      b. if the token that "stopped us" was a right parentheses, and the
         previous tokens a left parentheses, back up on
  3. insert the identifer in the current position
  4. add a semicolon to the end

Example #1: declare "foo" as a "(float *)":
  after step 1: "float *"
  after step 2: "float * "
			^current position
  after step 3: "float * foo"
  after step 4: "float * foo;"

Example #2: declare "foo" as an "(unsigned float **[]())"
  after step 1: "unsigned float **[]()"
  after step 2: "unsigned float ** []()"
				  ^current position
  after step 3: "unsigned float ** foo []()"
  after step 4: "unsigned float ** foo []();"

Example #3: declare "foo" as an "(int (*)())"
  after step 1: "int (*)()"
  after step 2: "int (* )()"
		       ^current position
  after step 3: "int (*foo)()"
  after step 4: "int (*foo)();"

(Is the algorithm for going the other direction simply that of removing the
declared name and the semicolon and surrounding the entire thing with
parentheses?)

mouse@mcgill-vision.UUCP (der Mouse) (03/29/89)

In article <3698@tekcrl.LABS.TEK.COM>, stevev@tekchips.LABS.TEK.COM (Steve Vegdahl) writes:
> [is building something to transform casts to declarations]

> Not being an expert on C type-declarations, I would appreciate
> opinions as to whether this method handles all cases and, if not,
> some examples cast-expressions on which it will fail.

> Alleged algorithm for transforming cast into a declaration.
[compressed slightly -dM]
>   1. strip away the outer parentheses of the cast expression
>   2. find the position to insert the to-be-declared identifier:
>       a. skip over all identifiers, left parentheses, and asterisks
[You have to treat type keywords as "identifiers" to make that work]
>       b. if we stopped just after ( and just before ), back up
>   3. insert the identifer in the current position
>   4. add a semicolon to the end

I think this is correct, though I am not at all certain.

In a declaration, the only things that can appear before the identifier
being declared are certain keywords, typedef names, left parentheses,
and *s.  (This is based on an examination of the grammar in the back of
K&RV2; I'm sure I'll be, er, "corrected" if I'm wrong.)

However, the identifier does not necessarily fit into the spot found by
the above algorithm, though I *think* it will, provided the cast is
legal.  (Definitely not for some illegal casts; consider, for example,
(int ()), a cast to function returning int (which isn't legal).  Your
algorithm will place the identifier so as to make this a declaration of
an int variable.)  All the cases I have been able to construct where
the algorithm fails involve casts to function types; I have tried to
convince myself this must be so, but so far have failed.

> (Is the algorithm for going the other direction simply that of
> removing the declared name and the semicolon and surrounding the
> entire thing with parentheses?)

You have to remove at least some redundant parentheses first.  For
example,

int (foo);

declares foo as an int, but

(int ())

is the (pseudo-)cast I mentioned above to function-returning-int.

I find this disturbing, in view of the statement near the top of page
221 of K&RV2, when discussing abstract types (as used in, eg, casts):

	It is possible to identify uniquely the location in the
	abstract-declarator where the identifier would appear if the
	construction were a declarator in a declaration.

As far as I can see, the only thing that allows us to deduce that
(int ()) is a cast to function-returning-int rather than to int is the
fact that "int foo();" is semantically illegal, while "int (foo);" is
legal.  Huh?  Isn't that backwards?  And wait a minute!  "int foo();"
*is* legal - when foo is a formal parameter: see the paragraph
beginning on the fifth line of page 226.  Yet I'm sure that (int ()) is
understood as a cast to function rather than to int; our (pcc-based)
compiler certainly does this ("illegal lhs of assignment operator", not
the best possible error), and while pcc does some strange things, a
basic misunderstanding of casts strikes me as unlikely to be among
them.

Is this apparent weirdness due to (a) a real ambiguity, (b) me being
confused about something, or (c) K&R being less pedantic than the
(p)ANS in their wording?  (Or something else?)

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu