Skip to content

Commit 2edf348

Browse files
committed
rewrite
Rewrote the code accoring to a revised parsing grammar and used the error recovery approach from 5-18.
1 parent e704ec7 commit 2edf348

File tree

1 file changed

+197
-141
lines changed

1 file changed

+197
-141
lines changed

chapter05/5-20.c

+197-141
Original file line numberDiff line numberDiff line change
@@ -2,109 +2,79 @@
22
* Exercise 5-20. Expand dcl to handle declarations with function argument
33
* types, qualifiers like const, and so on.
44
*
5-
* Grammer (simplified):
6-
* declaration:
7-
* dcl -> *'s opt dirdcl
8-
* dirdcl -> name | (dcl) | dirtdcl() | dirdcl(paramlist) | dirdcl[size opt]
5+
* By Faisal Saadatmand
6+
*/
7+
8+
/*
9+
* Expanded grammar to: (refer to Appendix A, sections 8, 8.2, 8.5 and 8.6.3)
910
*
10-
* function parameter's declaration:
11-
* paramlist -> paramdecl | paramlist , paramdecl
12-
* paramdecl -> declaration-specifiers dcl
11+
* declaration:
12+
* dclspc dcl
1313
*
14-
* TODO: error checking is still finicky, e.g.: "int f(char f()" will not recover; add
15-
* type-qualifiers support.
14+
* dclspc:
15+
* typespc dclspc
16+
* typespc dclspc_opt
1617
*
17-
* By Faisal Saadatmand
18+
* dcl:
19+
* optional *'s dirdcl
20+
*
21+
* dirdcl:
22+
* name
23+
* ( dcl )
24+
* dirdcl( paramdcl_opt )
25+
* dirdcl[ size_opt ]
26+
*
27+
* paramdcl:
28+
* paramdcl , dclspc dcl
29+
*
30+
*
31+
* NOTE: for simplicity's sake, typespc supports only char, double, float, int
32+
* and void; qualspc supports const and volatile. There is no support for
33+
* pointer qualifiers.
1834
*/
1935

36+
#include <ctype.h>
2037
#include <stdio.h>
38+
#include <stdlib.h>
2139
#include <string.h>
22-
#include <ctype.h>
2340

24-
#define MAXTOKEN 100
25-
#define BUFSIZE 100
26-
#define EMPTY_LINE (tokentype == '\n')
27-
#define RECOVER while (tokentype != EOF && gettoken() != '\n')
28-
#define SKIP_BLANKS(c) while (((c) = getch()) == ' ' || (c) == '\t')
41+
#define BUFSIZE 100
42+
#define MAXLEN 1000
43+
#define MAXTOKEN 100
2944

30-
enum { NAME, PARENS, BRACKETS, ERROR };
45+
#define SIZE(a) sizeof((a)) / sizeof((a)[0])
46+
47+
enum { NAME, PARENS, BRACKETS };
48+
enum { GOOD, FAIL };
3149

3250
/* functions */
33-
int gettoken(void);
3451
void dcl(void);
3552
void dirdcl(void);
36-
int getch(void);
37-
void ungetch(int);
38-
void paramList(void);
53+
int gettoken();
54+
void errmsg(const char *);
55+
void dclspc(char *);
56+
int typespc(void);
57+
int typeqaul(void);
3958
void paramdcl(void);
4059

4160
/* globals */
42-
char token[MAXTOKEN]; /* last token string */
43-
int tokentype; /* type of last token */
44-
char name[MAXTOKEN]; /* identifier name */
45-
char datatype[MAXTOKEN]; /* data type = char, int, etc. */
46-
char paramDataType[1000]; /* parameter data type */
47-
char out[1000];
48-
int buf[BUFSIZE]; /* buffer from ungetch */
49-
int bufp; /* next free position in buf */
50-
int pushedEOF; /* signals EOF has been pushed-back */
51-
52-
/* gettoekn: return next token */
53-
int gettoken(void)
54-
{
55-
int c, getch(void);
56-
void ungetch(int);
57-
char *p = token;
58-
59-
SKIP_BLANKS(c);
60-
61-
if (c == '(') {
62-
SKIP_BLANKS(c); /* allow spaces in parens */
63-
if (c == ')') {
64-
strcpy(token, "()");
65-
return tokentype = PARENS;
66-
} else {
67-
ungetch(c);
68-
return tokentype = '(';
69-
}
70-
} else if (c == '[') {
71-
for (*p++ = c; (*p = getch()) != ']'; p++)
72-
if (*p == '\n') /* error check for missing ']' */
73-
return *p;
74-
*++p = '\0';
75-
return tokentype = BRACKETS;
76-
} else if (isalpha(c)) {
77-
for (*p++ = c; isalnum(c = getch()); p++)
78-
*p = c;
79-
*p = '\0';
80-
ungetch(c);
81-
return tokentype = NAME;
82-
} else
83-
return tokentype = c;
84-
}
85-
86-
/* getch: get a (possibly pushed back) character */
87-
int getch(void)
88-
{
89-
return (bufp > 0) ? buf[--bufp] : getchar();
90-
}
91-
92-
/* ungerch: push character back on input */
93-
void ungetch(int c)
94-
{
95-
if (bufp >= BUFSIZE)
96-
printf("ungetch: too many characters\n");
97-
else
98-
buf[bufp++] = c;
99-
}
61+
int buf[BUFSIZE]; /* buffer from ungetch */
62+
int bufp = 0; /* next free position in buf */
63+
int tokentype; /* type of last token */
64+
char token[MAXTOKEN]; /* last token string */
65+
char name[MAXTOKEN]; /* identifier name */
66+
char datatype[MAXTOKEN]; /* data type = char, int, etc. */
67+
char out[MAXLEN]; /* composed output string */
68+
char state; /* flag to propagate the current state of parsing */
69+
int paramtype; /* signal that type is a parameter type */
10070

10171
/* dcl: parse a declarator */
102-
void dcl (void)
72+
void dcl(void)
10373
{
104-
int ns;
74+
int ns; /* number of asterisks */
10575

106-
for (ns = 0; gettoken() == '*'; ) /*count *'s */
107-
ns++;
76+
for (ns = 0; gettoken() == '*'; ++ns) /* count *'s */
77+
;
10878
dirdcl();
10979
while (ns-- > 0)
11080
strcat(out, " pointer to");
@@ -115,83 +85,169 @@ void dirdcl(void)
11585
{
11686
int type;
11787

118-
if (tokentype == '(') { /* ( dcl ) */
119-
dcl ();
120-
if (tokentype != ')') {
121-
tokentype = ERROR;
122-
printf("error: missing )\n");
123-
}
124-
} else if (tokentype == NAME) { /* variable name */
125-
strcpy(name, token);
126-
} else {
127-
tokentype = ERROR;
128-
printf("error: expected name or (dcl)\n");
88+
if (tokentype == '(') { /* ( dcl ) */
89+
dcl();
90+
if (tokentype != ')')
91+
errmsg("error: missing )\n");
92+
} else if (tokentype == NAME) { /* variable name */
93+
if (!name[0]) /* skip if name exists */
94+
strcpy(name, token);
95+
} else {
96+
if (paramtype)
97+
state = FAIL; /* push back tokentype without printing error msg */
98+
else
99+
errmsg("error: expected name or (dcl)\n");
129100
}
130-
131-
if (tokentype == ERROR)
132-
return;
133-
134101
while ((type = gettoken()) == PARENS || type == BRACKETS || type == '(')
135102
if (type == PARENS)
136103
strcat(out, " function returning");
137104
else if (type == '(') {
138-
strcat(out, " function accepts");
139-
paramList();
140-
strcat(out, " returning");
141-
if (tokentype == ERROR)
142-
return;
105+
strcat(out, " function expecting");;
106+
paramdcl();
107+
strcat(out, " and returning");
143108
} else {
144-
strcat(out, " array");
145-
strcat(out, token);
146-
strcat(out, " of");
147-
}
109+
strcat(out, " array");
110+
strcat(out, token);
111+
strcat(out, " of");
112+
}
148113
}
149114

115+
/* paramdcl: parse parameter-declaration */
150116
void paramdcl(void)
117+
{
118+
char temp[MAXTOKEN];
119+
120+
do {
121+
temp[0] = '\0'; /* clear previous parameter type */
122+
gettoken();
123+
dclspc(temp);
124+
paramtype = 1; /* allow type-specifier without names */
125+
dcl();
126+
paramtype = 0;
127+
if (tokentype == ',')
128+
strcat(temp, ",");
129+
strcat(out, " ");
130+
strcat(out, temp);
131+
} while (tokentype == ',');
132+
if (tokentype != ')')
133+
errmsg("missing ) in parameter declaration\n");
134+
}
135+
136+
/* decl-spc: parse a declarations-specifier */
137+
void dclspc(char *type)
151138
{
152-
char prevName[MAXTOKEN];
139+
int count;
153140

154-
strcpy(prevName, name); /* save main function's name */
155-
dcl(); /* note: dcl will skip current token */
156-
strcpy(name, prevName); /* restore mian function's name */
141+
for (count = 0; tokentype == NAME && (typespc() || typeqaul()); ++count) {
142+
if (count) /* qualifier added? */
143+
strcat(type, " ");
144+
strcat(type, token); /* is the datatype */
145+
gettoken();
146+
}
147+
state = FAIL; /* push back previous token */
157148
}
158149

159-
void paramList(void)
150+
/* typespc: return 1 if token is a type-specifier, otherwise return 0 */
151+
int typespc(void)
160152
{
161-
do {
162-
if (gettoken() == '\n') {
163-
printf("error: parameters syntax\n");
164-
tokentype = ERROR;
165-
return;
166-
}
153+
int isequal(const void *, const void *), combination_chk();
154+
static const char *typetab[] = { "char", "double", "float", "int", "void" };
167155

168-
if (tokentype == NAME) {
169-
sprintf(paramDataType, " %s", token);
170-
paramdcl();
171-
}
172-
if (tokentype == ERROR)
173-
return;
174-
else if (tokentype == ',' || tokentype == ')') {
175-
strcat(out, paramDataType);
176-
if (tokentype == ',')
177-
strcat(out, " and" );
156+
if (!bsearch(&token, typetab, SIZE(typetab), sizeof(char *), isequal))
157+
return 0; /* not a specifier */
158+
return 1;
159+
}
160+
161+
/* typequal: return 1 if token is type-qualifier, otherwise return 0 */
162+
int typeqaul(void)
163+
{
164+
int isequal(const void *, const void *), combination_chk();
165+
static const char *qualtab[] = { "const", "volatile" };
166+
167+
if (!bsearch(&token, qualtab, SIZE(qualtab), sizeof(char *), isequal))
168+
return 0;
169+
return 1;
170+
}
171+
172+
/* isequal: comparator function: return 0 if the content of s is equal to t,
173+
* otherwise return a non-zero value */
174+
int isequal(const void *s, const void *t)
175+
{
176+
return strcmp((char *) s, *(char **) t);
177+
}
178+
179+
/* errmsg: print error message, set state flag to FAIL */
180+
void errmsg(const char *msg)
181+
{
182+
printf("%s", msg);
183+
state = FAIL;
184+
}
185+
186+
/* gettoken: return next token */
187+
int gettoken(void)
188+
{
189+
int c, getch(void);
190+
void ungetch(int);
191+
char *p = token;
192+
193+
if (state == FAIL) {
194+
state = GOOD;
195+
return tokentype; /* push back the previous token */
196+
}
197+
while ((c = getch()) == ' ' || c == '\t')
198+
;
199+
if (c == '(') {
200+
if ((c = getch()) == ')') {
201+
strcpy(token, "()");
202+
return tokentype = PARENS;
178203
}
179-
} while (tokentype != ')');
204+
ungetch(c);
205+
return tokentype = '(';
206+
}
207+
if (c == '[') {
208+
for (*p++ = c; (*p++ = getch()) != ']'; )
209+
;
210+
*p = '\0';
211+
return tokentype = BRACKETS;
212+
}
213+
if (isalpha(c)) {
214+
for (*p++ = c; isalnum(c = getch()); )
215+
*p++ = c;
216+
*p = '\0';
217+
ungetch(c);
218+
return tokentype = NAME;
219+
}
220+
return tokentype = c;
180221
}
181222

182-
/* convert declaration to words */
183-
int main(void)
223+
/* getch: get a (possibly pushed back) character */
224+
int getch(void)
184225
{
185-
while (gettoken() != EOF) { /* last token on line */
186-
strcpy(datatype, token); /* is the datatype */
187-
out[0] = '\0';
188-
if (EMPTY_LINE)
189-
continue; /* skip empty input lines */
190-
dcl();
191-
if (tokentype != '\n' || tokentype == ERROR)
192-
printf("syntax error\n");
193-
else
194-
printf("%s: %s %s\n", name, out, datatype);
226+
return (bufp > 0) ? buf[--bufp] : getchar();
195227
}
228+
229+
/* ungerch: push character back on input */
230+
void ungetch(int c)
231+
{
232+
if (bufp >= BUFSIZE)
233+
printf("ungetch: too many characters\n");
234+
else
235+
buf[bufp++] = c;
236+
}
237+
238+
int main(void)
239+
{
240+
while (gettoken() != EOF) { /* first token on line */
241+
if (tokentype == '\n') /* skip empty lines */
242+
continue;
243+
datatype[0] = '\0';
244+
dclspc(datatype); /* parse data type */
245+
name[0] = out[0] = '\0';
246+
dcl(); /* parse rest of line */
247+
if (tokentype != '\n')
248+
printf("%s", "syntax error\n");
249+
else if (state == GOOD)
250+
printf("%s: %s %s\n", name, out, datatype);
251+
}
196252
return 0;
197253
}

0 commit comments

Comments
 (0)