Exercise 5.18 - recover from input errors¶
Question¶
Make dcl recover from input errors.
/* DCL: A Recursive Descent Parser */
/* dcl: parse a declarator */
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#define MAXTOKEN 100
enum {NAME,PARENS,BRACKETS};
enum { NO, YES};
void dcl(void);
void dirdcl(void);
void errmsg(char *);
int gettoken(void);
int tokentype; /* type of last token */
char token[MAXTOKEN]; /* last token string */
char name[MAXTOKEN]; /* identifier name */
char out[1000];
char datatype[MAXTOKEN];
extern int prevtoken;
extern int tokentype;
extern char token[];
int prevtoken = NO;
int main(void)
{
int i;
if(gettoken()!=EOF)
{
strcpy(datatype,token);
out[0]='\0';
dcl();
if(tokentype != '\n')
printf("syntax error \n");
printf(" %s %s %s \n",name,out,datatype);
for(i=0;i<MAXTOKEN;i++)
{
datatype[i] = '\0'; //overwrites name
out[i] = '\0';
name[i] = '\0';
}
}
else
{
return 0;
}
}
int gettoken(void)
{
int c, getch(void);
void ungetch(int);
char *p = token;
if(prevtoken == YES)
{
prevtoken = NO;
return tokentype;
}
while((c=getch()) == ' ' || c == '\t')
;
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';
ungetch(c);
return tokentype = NAME;
}
else
return tokentype =c;
}
/* dcl: parse a declarator */
void dcl(void)
{
int ns;
for(ns=0;gettoken()=='*';) /* count *'s */
ns++;
dirdcl();
while(ns-- > 0)
strcat(out," pointer to");
}
/* dirdcl: parse a direct declarator */
void dirdcl(void)
{
int type;
if(tokentype == '(') /* dcl */
{
dcl();
if(tokentype != ')')
errmsg("error: missing ) \n");
}
else if(tokentype == NAME) /* variable name */
strcpy(name,token);
else
errmsg("error: expected name or (dcl) \n");
while((type=gettoken()) == PARENS || type == BRACKETS )
if(type == PARENS)
strcat(out,"function returning");
else
{
strcat(out," arg");
strcat(out,token);
strcat(out," of");
}
}
void errmsg(char *msg)
{
printf("%s", msg);
prevtoken = YES;
}
#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) /* push a character back on input */
{
if(bufp >= BUFSIZE)
printf("ungetch: too many characters \n");
else
buf[bufp++] = c;
}
Explanation¶
This program is a recursive descent parser that converts C-style declarations into English descriptions. The program takes a C declaration as input and converts it into a more readable English description. For example:
./ex_5.18_dcl-errorec
char *str[]
str arg[] of pointer to char
The program has an errmsg function that is called whenever an error is detected during parsing. The dcl and dirdcl functions, which are responsible for parsing the declarator, continue parsing even if an error is encountered.