2
2
* Exercise 5-20. Expand dcl to handle declarations with function argument
3
3
* types, qualifiers like const, and so on.
4
4
*
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)
9
10
*
10
- * function parameter's declaration:
11
- * paramlist -> paramdecl | paramlist , paramdecl
12
- * paramdecl -> declaration-specifiers dcl
11
+ * declaration:
12
+ * dclspc dcl
13
13
*
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
16
17
*
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.
18
34
*/
19
35
36
+ #include <ctype.h>
20
37
#include <stdio.h>
38
+ #include <stdlib.h>
21
39
#include <string.h>
22
- #include <ctype.h>
23
40
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
29
44
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 };
31
49
32
50
/* functions */
33
- int gettoken (void );
34
51
void dcl (void );
35
52
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 );
39
58
void paramdcl (void );
40
59
41
60
/* 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 */
100
70
101
71
/* dcl: parse a declarator */
102
- void dcl (void )
72
+ void dcl (void )
103
73
{
104
- int ns ;
74
+ int ns ; /* number of asterisks */
105
75
106
- for (ns = 0 ; gettoken () == '*' ; ) /* count *'s */
107
- ns ++ ;
76
+ for (ns = 0 ; gettoken () == '*' ; ++ ns ) /* count *'s */
77
+ ;
108
78
dirdcl ();
109
79
while (ns -- > 0 )
110
80
strcat (out , " pointer to" );
@@ -115,83 +85,169 @@ void dirdcl(void)
115
85
{
116
86
int type ;
117
87
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" );
129
100
}
130
-
131
- if (tokentype == ERROR )
132
- return ;
133
-
134
101
while ((type = gettoken ()) == PARENS || type == BRACKETS || type == '(' )
135
102
if (type == PARENS )
136
103
strcat (out , " function returning" );
137
104
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" );
143
108
} 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
+ }
148
113
}
149
114
115
+ /* paramdcl: parse parameter-declaration */
150
116
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 )
151
138
{
152
- char prevName [ MAXTOKEN ] ;
139
+ int count ;
153
140
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 */
157
148
}
158
149
159
- void paramList (void )
150
+ /* typespc: return 1 if token is a type-specifier, otherwise return 0 */
151
+ int typespc (void )
160
152
{
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" };
167
155
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 ;
178
203
}
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 ;
180
221
}
181
222
182
- /* convert declaration to words */
183
- int main (void )
223
+ /* getch: get a (possibly pushed back) character */
224
+ int getch (void )
184
225
{
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 ();
195
227
}
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
+ }
196
252
return 0 ;
197
253
}
0 commit comments