TCPL——练习6.5 & 6.6
这两道习题综合起来是利用散列表写个适用C语言的简单#define处理器,只能处理#define/#undef不带参数的情形,并且#define后面必须带值。不带值其实也就是加多一个处理,分辨#define语句是否已经结束。这里输入代码我用的是TCPL的getch, ungetch,其实本应该直接读入一个C文件,可是这里我偷懒了。读入文件的话处理代码差别也不大。我把代码分为几个模块:
hash.c:散列表相关代码
io.c:输入输出相关代码
main.c:测试
以下是代码hash.h:保留三个借口给其他模块调用
#ifndef HASH_H
#define HASH_H
struct nlist;
struct nlist *install(char *name, char *defn);
int undef(char *name);
void print(void);
#endif
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct nlist {
char *name; /* defined name */
char *defn; /* replaced value */
struct nlist *next; /* next node */
};
#define HASHSIZE 101
static struct nlist *hashtab[HASHSIZE];
void print(void)
{
struct nlist *np;
for (int i = 0; i < HASHSIZE; ++i) {
if (hashtab[i] != NULL) {
for (np = hashtab[i]; np != NULL; np = np->next) {
printf("name: %-10s defn: %-5s\n", np->name, np->defn);
}
}
}
}
static char *strdup(char *s)
{
char *p;
p = (char *)malloc(strlen(s) + 1);
if (p != NULL) {
strcpy(p, s);
}
return p;
}
static unsigned int hash(char *s)
{
unsigned int hashval;
for (hashval = 0; *s != '\0'; ++s) {
hashval = *s + 31 * hashval;
}
return hashval % HASHSIZE;
}
static 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 int hashval;
if ( (np = lookup(name)) == NULL) {
np = (struct nlist *)malloc(sizeof(struct nlist));
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); /* free the prev defn */
}
if ( (np->defn = strdup(defn)) == NULL) {
return NULL;
}
return np;
}
int undef(char *name)
{
struct nlist *prev, *np;
unsigned int hashval;
if ( (np = lookup(name)) != NULL) {
hashval = hash(name);
prev = hashtab[hashval];
if (prev == np) {
printf("only one node\n");
free(np->defn);
free(np->name);
free(np);
} else {
printf("more than one node\n");
for ( ; prev->next != np; prev = prev->next)
;
prev->next = np->next;
free(np->defn);
free(np->name);
free(np);
}
return 0;
}
return -1;
}
#ifndef IO_H
#define IO_H
int getword(char *word, int lim);
#endif
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#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("buffer is full.\n");
}
buf[bufp++] = c;
}
int getword(char *word, int lim)
{
int c;
char *w;
memset(word, 0x00, lim);
w = word;
while (isspace(c = getch()) )
;
if (c != EOF) {
*w++ = c;
} else {
return c;
}
for ( ; --lim > 0; w++) {
if (!isalnum(*w = getch()) ) {
ungetch(*w);
break;
}
}
*w = '\0';
return word[0];
}
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "io.h"
#include "hash.h"
typedef enum _status {
NONE,
GET_NAME,
GET_VALUE,
UNGET_NAME
} Status;
#define MAXSIZE 100
int main(void)
{
struct nlist *np;
Status status = NONE;
char word[MAXSIZE] = {0};
char name[MAXSIZE] = {0};
char defn[MAXSIZE] = {0};
while (getword(word, MAXSIZE) != EOF) {
if (strcmp(word, "#define") == 0) {
status = GET_NAME;
continue;
} else if (strcmp(word, "#undef") == 0) {
status = UNGET_NAME;
continue;
}
if (status == GET_NAME) {
memset(name, 0x00, sizeof(name));
strcpy(name, word);
status = GET_VALUE;
} else if (status == GET_VALUE) {
memset(defn, 0x00, sizeof(defn));
strcpy(defn, word);
status = NONE;
if ( (np = install(name, defn)) == NULL) {
return -1;
}
} else if (status == UNGET_NAME) {
undef(word);
}
}
print();
return 0;
}
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
ken@Linux:~/TCPL/chap6/hash$ ./main
#include <stdio.h>
#define A 100
#define B 200
#define C 300
#undef A
in #undef.
only one node
name: defn:
name: B defn: 200
name: C defn: 300