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