1
1
/*
2
2
* Exercise 6-6. Implement a simple version of the #define processor (i.e., no
3
- * arguments) suitable for use with C programs, base on the routines of this
3
+ * arguments) suitable for use with C programs, based on the routines of this
4
4
* section. You may also find getch and ungetch helpful.
5
+ *
5
6
* By Faisal Saadatmand
6
7
*/
7
8
9
+ #include <ctype.h>
8
10
#include <stdio.h>
9
11
#include <stdlib.h>
10
12
#include <string.h>
11
- #include <ctype.h>
12
13
13
14
#define HASHSIZE 101
14
- #define MAXWORD 100
15
- #define MAXLEN 5000
16
- #define BUFSIZE 100
17
- #define NSYMBOLS (sizeof symbol / sizeof symbol[0])
18
-
19
- struct key {
20
- char * word ;
21
- int count ;
22
- };
15
+ #define MAXWORD 100
16
+ #define MAXLEN 5000
17
+ #define BUFSIZE 100
23
18
24
19
struct nlist { /* table entry: */
25
20
struct nlist * next ; /* next entry in chain */
@@ -28,139 +23,82 @@ struct nlist { /* table entry: */
28
23
};
29
24
30
25
/* globals */
31
- int buf [BUFSIZE ]; /* buffer from ungetch */
32
- int bufp = 0 ; /* next free position in buf */
26
+ int buf [BUFSIZE ]; /* buffer from ungetch */
27
+ int bufp = 0 ; /* next free position in buf */
33
28
static struct nlist * hashtab [HASHSIZE ]; /* pointer table */
34
29
35
- struct key symbol [] = { /* array is sorted for binary search */
36
- { "\"" , 0 },
37
- { "#" , 0 },
38
- { "*" , 0 },
39
- { "/" , 0 },
40
- { "\\" , 0 },
41
- { "_" , 0 },
42
- };
43
-
44
30
/* functions */
45
- struct key * binsearch (char * , struct key * , int );
46
31
int getword (char * , int );
47
- int getLine (char * , int );
32
+ int getdef (char * , int );
48
33
char * strDup (char * );
49
34
unsigned hash (char * );
50
35
struct nlist * lookup (char * );
51
36
struct nlist * install (char * , char * );
52
37
void printtab (struct nlist * [], int );
53
38
void freetable (struct nlist * [], int );
54
39
55
- /* binsearch: find word in tab[0]...tab[n - 1] */
56
- struct key * binsearch (char * word , struct key * tab , int n )
40
+ /* getword: get next word or character from input */
41
+ int getword (char * word , int lim )
57
42
{
58
- int cond ;
59
- struct key * low = & tab [0 ];
60
- struct key * high = & tab [n ];
61
- struct key * mid ;
43
+ int c , getch (void );
44
+ void ungetch (int );
45
+ char * w = word ;
62
46
63
- while (low < high ) {
64
- mid = low + (high - low ) / 2 ;
65
- if ((cond = strcmp (word , mid -> word )) < 0 )
66
- high = mid ;
67
- else if (cond > 0 )
68
- low = mid + 1 ;
69
- else
70
- return mid ;
71
- }
72
- return NULL ;
47
+ while (isspace (c = getch ()))
48
+ ;
49
+ if (c != EOF )
50
+ * w ++ = c ;
51
+ if (isalpha (c ) || c == '_' || c == '#' ) {
52
+ for ( ; -- lim > 0 ; ++ w )
53
+ if (!isalnum (* w = getch ()) && * w != '_' ) {
54
+ ungetch (* w );
55
+ break ;
56
+ }
57
+ } else if (c == '\'' ) /* skip character constants */
58
+ while ((c = getch ()) != '\'' )
59
+ ;
60
+ else if (c == '\"' ) { /* skip string constants */
61
+ while ((c = getch ()) != '\"' )
62
+ if (c == '\\' )
63
+ getch ();
64
+ } else if (c == '/' && (c = getch ()) == '*' ) /* skip comments */
65
+ while ((c = getch ()) != EOF )
66
+ if (c == '*' && (c = getch ()) == '/' )
67
+ break ;
68
+ * w = '\0' ;
69
+ return c ;
73
70
}
74
71
75
- int getch (void ) /* get a (possibly pushed back) character */
72
+ /* get a (possibly pushed back) character */
73
+ int getch (void )
76
74
{
77
75
return (bufp > 0 ) ? buf [-- bufp ] : getchar ();
78
76
}
79
77
80
- void ungetch (int c ) /* push character back on input */
78
+ /* push character back on input */
79
+ void ungetch (int c )
81
80
{
82
81
if (bufp >= BUFSIZE )
83
82
printf ("ungetch: too many characters\n" );
84
83
else
85
84
buf [bufp ++ ] = c ;
86
85
}
87
86
88
- /* getword: get next word or character from input: C program specific (modified
89
- * for define preprocessor control line) */
90
- int getword (char * word , int lim )
91
- {
92
- int c , getch (void );
93
- void ungetch (int );
94
- char * w = word ;
95
- struct key * p ;
96
-
97
- while (isspace (c = getch ()))
98
- ;
99
-
100
- if (c != EOF ) {
101
- * w ++ = c ;
102
- * w = '\0' ;
103
- } else
104
- return c ;
105
-
106
- if (!isalpha (c ) && (p = binsearch (word , symbol , NSYMBOLS )) == NULL )
107
- return c ;
108
-
109
- switch (c ) {
110
- case '\\' : /* handle escape sequences */
111
- c = getch ();
112
- break ;
113
- case '\"' : /* skip words inside string constant */
114
- while ((c = getch ()) != '\"' )
115
- if (c == EOF )
116
- return c ;
117
- break ;
118
- case '/' : /* skip words inside C comments */
119
- if ((c = getch ()) == '*' ) {
120
- while ((c = getch ()))
121
- if (c == '*' && (c = getch ()) == '/' )
122
- break ;
123
- else if (c == EOF )
124
- return c ;
125
- } else /* don't skip pointer variables */
126
- ungetch (c );
127
- break ;
128
- default :
129
- if (c == '#' ) {
130
- while (isspace (c = getch ()))
131
- ;
132
- * w ++ = c ;
133
- }
134
-
135
- for ( ; -- lim > 0 ; w ++ )
136
- if (!isalnum (* w = getch ()) && * w != '_' ) {
137
- ungetch (* w );
138
- break ;
139
- }
140
- break ;
141
- }
142
-
143
- * w = '\0' ;
144
- return word [0 ];
145
- }
146
-
147
- /* getLine: get line into s, return length of s -- modified to skip blanks at
148
- * the beginning of the line and not to insert a newline character at the end.
149
- * */
150
- int getLine (char * s , int lim )
87
+ /* getdef: copy the rest of the line int s, return length of s. This is a
88
+ * modified version of getLine, which skips leading blanks andd does not insert
89
+ * a newline character at the end. */
90
+ int getdef (char * s , int lim )
151
91
{
152
92
int c , len ;
153
93
154
94
while (isspace (c = getch ()))
155
95
;
156
96
* s ++ = c ;
157
-
158
97
len = 0 ;
159
98
while (-- lim > 0 && (c = getchar ()) != EOF && c != '\n' ) {
160
99
* s ++ = c ;
161
100
++ len ;
162
101
}
163
-
164
102
* s = '\0' ;
165
103
return len ;
166
104
}
@@ -170,8 +108,8 @@ char *strDup(char *s)
170
108
{
171
109
char * p ;
172
110
173
- p = ( char * ) malloc (strlen (s ) + 1 ); /* +1 for '\0' */
174
- if (p != NULL )
111
+ p = malloc (strlen (s ) + 1 ); /* +1 for '\0' */
112
+ if (p )
175
113
strcpy (p , s );
176
114
return p ;
177
115
}
@@ -181,7 +119,7 @@ unsigned hash(char *s)
181
119
{
182
120
unsigned hashval ;
183
121
184
- for (hashval = 0 ; * s != '\0' ; s ++ )
122
+ for (hashval = 0 ; * s ; ++ s )
185
123
hashval = * s + (31 * hashval );
186
124
return hashval % HASHSIZE ;
187
125
}
@@ -191,8 +129,8 @@ struct nlist *lookup(char *s)
191
129
{
192
130
struct nlist * np ;
193
131
194
- for (np = hashtab [hash (s )]; np != NULL ; np = np -> next )
195
- if (strcmp (s , np -> name ) == 0 )
132
+ for (np = hashtab [hash (s )]; np ; np = np -> next )
133
+ if (! strcmp (s , np -> name ))
196
134
return np ; /* found */
197
135
return NULL ;
198
136
}
@@ -203,19 +141,16 @@ struct nlist *install(char *name, char *defn)
203
141
struct nlist * np ;
204
142
unsigned hashval ;
205
143
206
- if ((np = lookup (name )) == NULL ) { /* not found */
207
- np = ( struct nlist * ) malloc (sizeof (* np ));
208
- if (np == NULL || (np -> name = strDup (name )) == NULL )
144
+ if (! (np = lookup (name ))) { /* not found */
145
+ np = malloc (sizeof (* np ));
146
+ if (! np || ! (np -> name = strDup (name )))
209
147
return NULL ; /* no (heap) memory */
210
148
hashval = hash (name );
211
149
np -> next = hashtab [hashval ];
212
150
hashtab [hashval ] = np ;
213
151
} else /* already there */
214
152
free ((void * ) np -> defn ); /* free previous definition */
215
-
216
- np -> defn = strDup (defn ); /* copy definition */
217
-
218
- if (np -> defn == NULL )
153
+ if (!(np -> defn = strDup (defn ))) /* copy definition */
219
154
return NULL ;
220
155
return np ;
221
156
}
@@ -224,45 +159,35 @@ void printtab(struct nlist *node[], int size)
224
159
{
225
160
int i ;
226
161
227
- for (i = 0 ; i < size ; i ++ )
228
- if (node [i ] != NULL )
229
- printf ("%i name: %s defn: %s\n" ,
230
- i , node [i ]-> name , node [i ]-> defn );
162
+ for (i = 0 ; i < size ; ++ i )
163
+ if (node [i ])
164
+ printf ("%i name: %s defn: %s\n" , i , node [i ]-> name , node [i ]-> defn );
231
165
}
232
166
233
167
/* freetable: free table's (and its content's) allocated memory from heap */
234
168
void freetable (struct nlist * node [], int size )
235
169
{
236
170
int i ;
237
171
238
- for (i = 0 ; i < size ; i ++ )
239
- if (node [i ] != NULL ) {
172
+ for (i = 0 ; i < size ; ++ i )
173
+ if (node [i ]) {
240
174
free (node [i ]-> name );
241
175
free (node [i ]-> defn );
242
176
free (node [i ]);
243
177
}
244
178
}
245
179
246
- /* simple define processor (no arguments) */
247
180
int main (void )
248
181
{
249
- // struct nlist *p;
250
182
char word [MAXWORD ];
251
183
char defn [MAXLEN ];
252
- char * name , * keyword = "#define" ;
253
- int ctrline ;
254
-
255
- name = word ; /* unnecessary. Added for clarity */
184
+ const char * keyword = "#define" ;
256
185
257
- ctrline = 0 ;
258
186
while (getword (word , MAXWORD ) != EOF )
259
- if (word [0 ] == '#' && !ctrline ) {
260
- if (strcmp (word , keyword ) == 0 )
261
- ctrline = 1 ; /* found processor control line */
262
- } else if (ctrline ) { /* parse name and definition */
263
- getLine (defn , MAXLEN );
264
- install (name , defn );
265
- ctrline = 0 ;
187
+ if (word [0 ] == '#' && !strcmp (word , keyword )) { /* found #define */
188
+ getword (word , MAXLEN ); /* get the name */
189
+ getdef (defn , MAXLEN ); /* parse definition */
190
+ install (word , defn );
266
191
}
267
192
printf ("Hash Table Values:\n" );
268
193
printtab (hashtab , HASHSIZE );
0 commit comments