11/*
22 * 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
44 * section. You may also find getch and ungetch helpful.
5+ *
56 * By Faisal Saadatmand
67 */
78
9+ #include <ctype.h>
810#include <stdio.h>
911#include <stdlib.h>
1012#include <string.h>
11- #include <ctype.h>
1213
1314#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
2318
2419struct nlist { /* table entry: */
2520 struct nlist * next ; /* next entry in chain */
@@ -28,139 +23,82 @@ struct nlist { /* table entry: */
2823};
2924
3025/* 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 */
3328static struct nlist * hashtab [HASHSIZE ]; /* pointer table */
3429
35- struct key symbol [] = { /* array is sorted for binary search */
36- { "\"" , 0 },
37- { "#" , 0 },
38- { "*" , 0 },
39- { "/" , 0 },
40- { "\\" , 0 },
41- { "_" , 0 },
42- };
43-
4430/* functions */
45- struct key * binsearch (char * , struct key * , int );
4631int getword (char * , int );
47- int getLine (char * , int );
32+ int getdef (char * , int );
4833char * strDup (char * );
4934unsigned hash (char * );
5035struct nlist * lookup (char * );
5136struct nlist * install (char * , char * );
5237void printtab (struct nlist * [], int );
5338void freetable (struct nlist * [], int );
5439
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 )
5742{
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 ;
6246
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 ;
7370}
7471
75- int getch (void ) /* get a (possibly pushed back) character */
72+ /* get a (possibly pushed back) character */
73+ int getch (void )
7674{
7775 return (bufp > 0 ) ? buf [-- bufp ] : getchar ();
7876}
7977
80- void ungetch (int c ) /* push character back on input */
78+ /* push character back on input */
79+ void ungetch (int c )
8180{
8281 if (bufp >= BUFSIZE )
8382 printf ("ungetch: too many characters\n" );
8483 else
8584 buf [bufp ++ ] = c ;
8685}
8786
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 )
15191{
15292 int c , len ;
15393
15494 while (isspace (c = getch ()))
15595 ;
15696 * s ++ = c ;
157-
15897 len = 0 ;
15998 while (-- lim > 0 && (c = getchar ()) != EOF && c != '\n' ) {
16099 * s ++ = c ;
161100 ++ len ;
162101 }
163-
164102 * s = '\0' ;
165103 return len ;
166104}
@@ -170,8 +108,8 @@ char *strDup(char *s)
170108{
171109 char * p ;
172110
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 )
175113 strcpy (p , s );
176114 return p ;
177115}
@@ -181,7 +119,7 @@ unsigned hash(char *s)
181119{
182120 unsigned hashval ;
183121
184- for (hashval = 0 ; * s != '\0' ; s ++ )
122+ for (hashval = 0 ; * s ; ++ s )
185123 hashval = * s + (31 * hashval );
186124 return hashval % HASHSIZE ;
187125}
@@ -191,8 +129,8 @@ struct nlist *lookup(char *s)
191129{
192130 struct nlist * np ;
193131
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 ))
196134 return np ; /* found */
197135 return NULL ;
198136}
@@ -203,19 +141,16 @@ struct nlist *install(char *name, char *defn)
203141 struct nlist * np ;
204142 unsigned hashval ;
205143
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 )))
209147 return NULL ; /* no (heap) memory */
210148 hashval = hash (name );
211149 np -> next = hashtab [hashval ];
212150 hashtab [hashval ] = np ;
213151 } else /* already there */
214152 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 */
219154 return NULL ;
220155 return np ;
221156}
@@ -224,45 +159,35 @@ void printtab(struct nlist *node[], int size)
224159{
225160 int i ;
226161
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 );
231165}
232166
233167/* freetable: free table's (and its content's) allocated memory from heap */
234168void freetable (struct nlist * node [], int size )
235169{
236170 int i ;
237171
238- for (i = 0 ; i < size ; i ++ )
239- if (node [i ] != NULL ) {
172+ for (i = 0 ; i < size ; ++ i )
173+ if (node [i ]) {
240174 free (node [i ]-> name );
241175 free (node [i ]-> defn );
242176 free (node [i ]);
243177 }
244178}
245179
246- /* simple define processor (no arguments) */
247180int main (void )
248181{
249- // struct nlist *p;
250182 char word [MAXWORD ];
251183 char defn [MAXLEN ];
252- char * name , * keyword = "#define" ;
253- int ctrline ;
254-
255- name = word ; /* unnecessary. Added for clarity */
184+ const char * keyword = "#define" ;
256185
257- ctrline = 0 ;
258186 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 );
266191 }
267192 printf ("Hash Table Values:\n" );
268193 printtab (hashtab , HASHSIZE );
0 commit comments