Page 145
Implement a simple version of the #define
processor (i.e., no arguments) suitable
for use with C programs, based on the routines of this section. You may also find
getch
and ungetch
helpful.
#include <stdio.h>
#include <ctype.h>
#define IDENTIFIER "#define"
#define MAXBUF 1000
struct nlist {
struct nlist *next;
char *name;
char *defn;
};
struct nlist *install(char *name, char *defn);
struct nlist *lookup(char *name);
int main()
{
enum state { NONE, DECLARATION, NAME, VALUE };
int c, i = 0, j = 0, getch(void);
void ungetch(int);
char buf[MAXBUF], name[MAXBUF], val[MAXBUF];
enum state state = NONE;
struct nlist *res;
while ((c = buf[i++] = getch()) != EOF) {
switch (state) {
case NONE:
if (c == IDENTIFIER[0]) {
state = DECLARATION;
j = 1;
} else if (!isalnum(c)) {
buf[--i] = '\0';
res = lookup(buf);
printf("%s%c", res == NULL ? buf : res->defn,
c);
i = 0;
}
break;
case DECLARATION:
if (IDENTIFIER[j] == '\0') {
ungetch(c);
i--;
state = NAME;
j = 0;
} else if (c != IDENTIFIER[j]) {
state = NONE;
j = 0;
} else {
j++;
}
break;
case NAME:
if (!isspace(c)) {
name[j++] = c;
} else if (j > 0) {
ungetch(c);
i--;
name[j] = '\0';
j = 0;
state = VALUE;
}
break;
case VALUE:
if (!isspace(c)) {
val[j++] = c;
} else if (j > 0) {
val[j] = '\0';
install(name, val);
j = 0;
ungetch(c);
i--;
state = NONE;
}
break;
}
}
}
#define HASHSIZE 101
#include <string.h>
#include <stdlib.h>
unsigned hash(char *s)
{
unsigned hashval;
for (hashval = 0; *s != '\0'; s++) {
hashval = *s + 31 * hashval;
}
return hashval % HASHSIZE;
}
static struct nlist *hashtab[HASHSIZE];
struct nlist *lookup(char *s)
{
struct nlist *np;
for (np = hashtab[hash(s)]; np != NULL; np = np->next) {
if (strcmp(s, np->name) == 0) {
return np;
}
}
return NULL;
}
struct nlist *install(char *name, char *defn)
{
struct nlist *np;
unsigned hashval;
if ((np = lookup(name)) == NULL) {
np = (struct nlist *)malloc(sizeof(*np));
if (np == NULL || (np->name = strdup(name)) == NULL) {
return NULL;
}
hashval = hash(name);
np->next = hashtab[hashval];
hashtab[hashval] = np;
} else {
free((void *)np->defn);
}
if ((np->defn = strdup(defn)) == NULL) {
return NULL;
}
return np;
}
#define BUFSIZE 100
char buf[BUFSIZE];
int bufp = 0;
int getch(void)
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c)
{
if (bufp >= BUFSIZE) {
printf("ungetch: too many characters\n");
} else {
buf[bufp++] = c;
}
}