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;
}