Skip to content

Commit 3c6c063

Browse files
committed
rewrite
Improved error recovery. The current approach pushes back the previous token if parsing failed. In addition to allowing recovery from errors it also would allows the continuation of parsing, see exercise 5-20.
1 parent f1eff24 commit 3c6c063

File tree

1 file changed

+90
-98
lines changed

1 file changed

+90
-98
lines changed

chapter05/5-18.c

Lines changed: 90 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,150 +1,142 @@
11
/*
22
* Exercise 5-18. Make dcl recover from input error.
3+
*
34
* By Faisal Saadatmand
45
*/
56

7+
#include <ctype.h>
68
#include <stdio.h>
79
#include <string.h>
8-
#include <ctype.h>
910

10-
#define MAXTOKEN 100
11-
#define BUFSIZE 100
12-
#define EMPTY_LINE (tokentype == '\n')
13-
#define RECOVER(c) while (((c) = getch()) != '\n')
14-
#define SKIP_BLANKS(c) while (((c) = getch()) == ' ' || (c) == '\t')
11+
#define BUFSIZE 100
12+
#define MAXLEN 1000
13+
#define MAXTOKEN 100
1514

16-
enum { NAME, PARENS, BRACKETS, ERROR };
15+
enum { NAME, PARENS, BRACKETS };
16+
enum { GOOD, FAIL };
1717

1818
/* functions */
19-
int gettoken(void);
2019
void dcl(void);
2120
void dirdcl(void);
22-
int getch(void);
23-
void ungetch(int);
21+
int gettoken();
22+
void errmsg(const char *);
2423

2524
/* globals */
26-
char token[MAXTOKEN]; /* last token string */
27-
int tokentype; /* type of last token */
28-
char name[MAXTOKEN]; /* identifier name */
29-
char datatype[MAXTOKEN]; /* data type = char, int, etc. */
30-
char out[1000];
31-
int buf[BUFSIZE]; /* buffer from ungetch */
32-
int bufp; /* next free position in buf */
33-
int pushedEOF; /* signals EOF has been pushed-back */
25+
int buf[BUFSIZE]; /* buffer from ungetch */
26+
int bufp = 0; /* next free position in buf */
27+
int tokentype; /* type of last token */
28+
char token[MAXTOKEN]; /* last token string */
29+
char name[MAXTOKEN]; /* identifier name */
30+
char datatype[MAXTOKEN]; /* data type = char, int, etc. */
31+
char out[MAXLEN]; /* composed output string */
32+
char state; /* flag to propagate the current state of parsing */
33+
34+
/* dcl: parse a declarator */
35+
void dcl(void)
36+
{
37+
int ns; /* number of asterisks */
38+
39+
for (ns = 0; gettoken() == '*'; ++ns) /* count *'s */
40+
;
41+
dirdcl();
42+
while (ns-- > 0)
43+
strcat(out, " pointer to");
44+
}
3445

35-
/* gettoekn: return next token */
46+
/* dirdcl: parse a direct declarator */
47+
void dirdcl(void)
48+
{
49+
int type;
50+
51+
if (tokentype == '(') { /* ( dcl ) */
52+
dcl();
53+
if (tokentype != ')')
54+
errmsg("error: missing )\n");
55+
} else if (tokentype == NAME) /* variable name */
56+
strcpy(name, token);
57+
else
58+
errmsg("error: expected name of (dcl)\n");
59+
while ((type = gettoken()) == PARENS || type == BRACKETS)
60+
if (type == PARENS)
61+
strcat(out, " function returning");
62+
else {
63+
strcat(out, " array");
64+
strcat(out, token);
65+
strcat(out, " of");
66+
}
67+
}
68+
69+
/* errmsg: print error message, set state flag to FAIL */
70+
void errmsg(const char *msg)
71+
{
72+
printf("%s", msg);
73+
state = FAIL; /* propagate state of parsing to allow for error recovery */
74+
}
75+
76+
/* gettoken: return next token */
3677
int gettoken(void)
3778
{
3879
int c, getch(void);
3980
void ungetch(int);
4081
char *p = token;
4182

42-
SKIP_BLANKS(c);
43-
83+
if (state == FAIL) {
84+
state = GOOD;
85+
return tokentype; /* push back the previous token */
86+
}
87+
while ((c = getch()) == ' ' || c == '\t')
88+
;
4489
if (c == '(') {
45-
SKIP_BLANKS(c); /* allow spaces in parens */
46-
if (c == ')') {
90+
if ((c = getch()) == ')') {
4791
strcpy(token, "()");
4892
return tokentype = PARENS;
49-
} else {
50-
ungetch(c);
51-
return tokentype = '(';
5293
}
53-
} else if (c == '[') {
54-
for (*p++ = c; (*p = getch()) != ']'; p++)
55-
if (*p == '\n') /* error check: missing ']' */
56-
return *p;
57-
*++p = '\0';
94+
ungetch(c);
95+
return tokentype = '(';
96+
}
97+
if (c == '[') {
98+
for (*p++ = c; (*p++ = getch()) != ']'; )
99+
;
100+
*p = '\0';
58101
return tokentype = BRACKETS;
59-
} else if (isalpha(c)) {
60-
for (*p++ = c; isalnum(c = getch()); p++)
61-
*p = c;
102+
}
103+
if (isalpha(c)) {
104+
for (*p++ = c; isalnum(c = getch()); )
105+
*p++ = c;
62106
*p = '\0';
63107
ungetch(c);
64108
return tokentype = NAME;
65-
} else
66-
return tokentype = c;
109+
}
110+
return tokentype = c;
67111
}
68112

69113
/* getch: get a (possibly pushed back) character */
70114
int getch(void)
71115
{
72-
return (bufp > 0) ? buf[--bufp] : (pushedEOF) ? EOF : getchar();
116+
return (bufp > 0) ? buf[--bufp] : getchar();
73117
}
74118

75119
/* ungerch: push character back on input */
76120
void ungetch(int c)
77121
{
78-
if (c == EOF) {
79-
pushedEOF = 1;
80-
return;
81-
}
82-
83122
if (bufp >= BUFSIZE)
84123
printf("ungetch: too many characters\n");
85124
else
86125
buf[bufp++] = c;
87126
}
88127

89-
/* dcl: parse a declarator */
90-
void dcl (void)
91-
{
92-
int ns;
93-
94-
for (ns = 0; gettoken() == '*'; ) /*count *'s */
95-
ns++;
96-
dirdcl();
97-
while (ns-- > 0)
98-
strcat(out, " pointer to");
99-
}
100-
101-
/* dirdcl: parse a direct declarator */
102-
void dirdcl(void)
103-
{
104-
int type;
105-
106-
if (tokentype == '(') { /* ( dcl ) */
107-
dcl ();
108-
if (tokentype != ')') {
109-
printf("error: missing )\n");
110-
tokentype = ERROR;
111-
}
112-
} else if (tokentype == NAME) { /* variable name */
113-
strcpy(name, token);
114-
} else {
115-
printf("error: expected name or (dcl)\n");
116-
tokentype = ERROR;
117-
}
118-
119-
if (tokentype == ERROR)
120-
return;
121-
122-
while ((type = gettoken()) == PARENS || type == BRACKETS)
123-
if (type == PARENS)
124-
strcat(out, " function returning");
125-
else {
126-
strcat(out, " array");
127-
strcat(out, token);
128-
strcat(out, " of");
129-
}
130-
}
131-
132128
/* convert declaration to words */
133-
int main(void)
129+
int main(void)
134130
{
135-
int c;
136-
137-
while (gettoken() != EOF) { /* last token on line */
138-
strcpy(datatype, token); /* is the datatype */
131+
while (gettoken() != EOF) { /* first token on line */
132+
if (tokentype == '\n') /* skip empty lines */
133+
continue;
134+
strcpy(datatype, token); /* is the datatype */
139135
out[0] = '\0';
140-
if (EMPTY_LINE)
141-
continue; /* skip empty input lines */
142-
dcl();
143-
if (tokentype != '\n') {
144-
printf("syntax error\n");
145-
// RECOVER(c);
146-
// ungetch(c);
147-
} else
136+
dcl(); /* parse rest of line */
137+
if (tokentype != '\n')
138+
printf("%s", "syntax error\n");
139+
else if (state == GOOD)
148140
printf("%s: %s %s\n", name, out, datatype);
149141
}
150142
return 0;

0 commit comments

Comments
 (0)