Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2edf348

Browse files
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

Lines changed: 197 additions & 141 deletions
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-
charprevName[MAXTOKEN];
139+
intcount;
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)

AltStyle によって変換されたページ (->オリジナル) /