Thread: Complex declarations & ?error in Kernighan/Ritchie?

  1. #1
    Registered User
    Join Date
    Oct 2004
    Posts
    26

    Complex declarations & ?error in Kernighan/Ritchie?

    Hi, all. I am reading through the Kernighan/Ritchie 2nd edition of "The C Programming Language", and ran into trouble in chapter 5.12 (pp 123-125), where they write a program to translate complex declarations like "char (*(*x[3])())[5]" into English. I don't think the program does what it is supposed to do.

    When fed the input
    Code:
    char	(*daytab)[13]
    it produces the output
    Code:
    error:  missing )
    syntax error
    daytab:   array[13] of pointer to char
    which is obviously wrong, since (1) there are no parentheses missing, (2) the declaration compiles perfectly well, and (3) daytab is supposed to be a pointer to array[13] of character, not the other way around.

    I tried looking up reported errata here (http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html), but it's not listed. But is this still a known error? And *why* doesn't it work? It's based on a recursive descent algorithm, which thinks of a declarator like this:
    Code:
    dcl:		optional *'s direct-dcl
    direct-dcl:	name OR
    		(dcl) OR
    		direct-dcl() OR
    		direct-dcl[optional size]
    As far as I can tell, the code pretty much matches the logic in the text. So why does it screw things up? Or maybe I screwed up? I've reproduced the code below (which I typed straight out of the book, with one or two additional comments to tell what pages things are from, etc.).

    Code:
    /*******************************************************************************
    Program to translate a complicated declaration into English
    Taken from K & R, The C Programming Language, 2nd ed., ch 5.12, p.123-125
    *******************************************************************************/
    
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    
    #define	 MAXTOKEN    100
    
    enum  { NAME, PARENS, BRACKETS };
    
    void  dcl(void);
    void  dirdcl(void);
    
    int   gettoken(void);
    int   tokentype;		/* type of last token */
    char  token[MAXTOKEN];		/* last token string */
    char  name[MAXTOKEN];		/* identifier name */
    char  datatype[MAXTOKEN];	/* data type = char, int, etc. */
    char  out[1000];		/* output string */
    
    
    int main()	/* convert declaration to words */
    {
    	while (gettoken() != EOF) {	/* 1st token on line */
    	     strcpy(datatype, token);	/* is the datatype */
    	     out[0] = '\0';
    	     dcl();			/* parse rest of line */
    	     if (tokentype != '\n')
    		printf("syntax error\n");
    	     printf("%s:  %s %s\n", name, out, datatype);
    	}
    	return 0;
    }
    
    
    /*************************************************************
    	IMPLEMENTATIONS
    *************************************************************/
    
    int gettoken(void)	/* returns next token */
    {
    	int	c, getch(void);	/* getch:  get a (possibly pushed back) character */
    	void	ungetch(int);	/* ungetch:  push character back on input */
    				/* functions from K&R, 2nd ed., ch 4.3, p. 79 */
    				/* reproduced at bottom of page */
    	char	*p = token;
    
    	while ( (c=getch())==' ' || c=='\t' )	/* skip white space */
    		;
    	if ( c=='(' ) {
    		if ( (c=getch())==')' ) {
    			strcpy(token, "()");
    			return tokentype = PARENS;
    		}
    		else {
    			ungetch(c);
    			return tokentype = '(';
    		}
    	}
    	else if ( c=='[' ) {
    		for(*p++ = c; (*p++ = getch()) != ']'; );  
    		*p = '\0';				   
    		return tokentype = BRACKETS;
    	}
    	else if ( isalpha(c) ) {
    		for (*p++ = c; isalnum(c=getch()); ) *p++ = c;  
    		*p = '\0';					
    		return tokentype = NAME;
    	}
    	else
    		return tokentype = c;
    }
    
    
    
    void dcl(void)		/* parse a declarator */
    {
    	int	ns;	/* number of stars */
    
    	for (ns=0; gettoken()=='*'; ) ns++;	/* count *'s */
    	dirdcl();
    	while (ns-- > 0) strcat(out, " pointer to");
    }
    
    
    void dirdcl(void)	/* parse a direct declarator */
    {
    	int	type;
    
    	if ( tokentype=='(' ) {		/* ( dcl ) */
    		dcl();
    		if ( tokentype != ')' ) printf("error:  missing )\n");
    	}
    	else if (tokentype == NAME)	/* variable name */
    		strcpy(name, token);
    	else
    		printf("error:  expected name or (dcl)\n");
    
    	while( (type=gettoken())==PARENS || type==BRACKETS) 
    		if (type==PARENS)
    			strcat(out, " function returning");
    		else {
    			strcat(out, " array");
    			strcat(out, token);
    			strcat(out, " of");
    		}
    }
    
    
    
    
    
    /************************************************************************
    	definitions of getch and ungetch, K&R 2nd ed., ch 4.3, p79.
    ************************************************************************/
    
    #define BUFSIZE 100
    
    char  buf[BUFSIZE];	/* buffer for ungetch */
    int   bufp = 0;		/* next free position in buf */
    
    int getch(void)		/* get a (possibly pushed back) character */
    {
    	return (bufp > 0)  ?  buf[--bufp]  :  getchar();
    }
    
    void ungetch(int c)	/* pretend to push character back on input */
    {
    	if (bufp >= BUFSIZE) printf("ungetch:  too many characters\n");
    	else buf[bufp++] = c;
    }

  2. #2
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    In gettoken():

    Code:
      else if ( isalpha(c) ) {
        for (*p++ = c; isalnum(c=getch()); ) 
          *p++ = c;  
        *p = '\0';          
        ungetch(c); /* This line was missing(!)*/
        return tokentype = NAME;
      }
    Does it work now? It does for me.


    Regards,

    Dave
    Last edited by Dave Evans; 10-04-2004 at 02:08 PM.

  3. #3
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    I didn't read through your code since your question seems to concern char (*daytab)[13].

    I would surmise that you forgot a semicolon at the end of that line. And compilers sometimes have trouble parsing stuff when something is written wrong. It would be a good idea to pay attention to what sort of error it gives for what sort of error actually exists.

  4. #4
    Registered User
    Join Date
    Oct 2004
    Posts
    26
    D'oh! Should have known it was failing to ungetch something from the supposedly missing parentheses and carriage return. It works perfectly now. You guys are the best. Thanks!
    Last edited by zzzaaahhh; 10-05-2004 at 05:53 AM.

  5. #5
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    Quote Originally Posted by zzzaaahhh

    ...

    You guys are the best. Thanks!
    Actually, K&R are the best. The rest of us just try to follow the bouncing ball.

    Regards,

    Dave

  6. #6
    ... kermit's Avatar
    Join Date
    Jan 2003
    Posts
    1,534
    Something you might want to keep in mind while working through K&R2 is the errata for the book.

    The official version, and another smaller version. The two may overlap somewhat, but I could not say as I have not compared them.

    ~/

  7. #7
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    Quote Originally Posted by kermit
    Something you might want to keep in mind while working through K&R2 is the errata for the book.

    The official version, and another smaller version. The two may overlap somewhat, but I could not say as I have not compared them.

    ~/
    A very good point. No book is perfect. If you see an example in a book that looks interesting, you should try things for yourself.

    I am not aware of any errata concerning pages 122-126 of the second edition of K&R.

    The program outlined there works for me on all compilers that I have tried (all two or three, that is). The original poster wanted to know if the program in the book works as K&R indicates that it should. It does (at least it does for me). His transcription omitted a line in one of the functions. With that line added, I think it's OK. (But if any other people are interested, they should try it themselves.)

    Regards,

    Dave

    [edit]
    As for the examples he gave, If I enter

    char (*daytab)[13]

    The program gives

    daytab: pointer to array[13] of char
    That seems Ok.

    If I enter

    char (*(*x[3])())[5]

    the program gives

    x: array[3] of pointer to function returning pointer to array[5] of char
    How does this look to you? My head is still swimming.

    [/edit]
    Last edited by Dave Evans; 10-04-2004 at 06:20 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Complex Number Class
    By Sephiroth1109 in forum C++ Programming
    Replies: 15
    Last Post: 12-12-2007, 04:46 PM
  2. Why am I getting 'undelcared identifier' ???
    By Bill83 in forum C++ Programming
    Replies: 2
    Last Post: 02-15-2006, 01:00 PM
  3. arithmetic operator friend functions
    By linucksrox in forum C++ Programming
    Replies: 7
    Last Post: 02-06-2006, 11:39 PM
  4. 2 am complex double conversion woes
    By Roule in forum C++ Programming
    Replies: 1
    Last Post: 10-14-2004, 02:53 PM
  5. Problem from texbook
    By Unregistered in forum C++ Programming
    Replies: 5
    Last Post: 07-26-2002, 04:55 AM