演習6-6 K&R プログラミング言語C
2010年03月05日
演習6-6
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MAXWORD 100 #define BUFSIZE 100 #define HASHSIZE 101 char buf[BUFSIZE]; /* ungetch 用のバッファ */ int bufp = 0; /* buf 中の次の空き位置 */ struct nlist { /* テーブルの項目 */ struct nlist *next; /* チェインの中の次の項目 */ char *name; /* 定義された名前 */ char *defn; /* 置換テキスト */ }; static struct nlist *hashtab[HASHSIZE]; /* ポインタのテーブル */ unsigned hash(char *); struct nlist *lookup(char *); struct nlist *install(char *, char *); char *my_strdup(char *); char *search_defn(char *); void undef(char *); int getword(char *, int); int is_legal_char(char); enum { LABEL, NAME, DEFINITION }; int main(void) { char word[MAXWORD]; int cond = LABEL; char *name; char *defn; while (getword(word, MAXWORD) != EOF) { if (is_legal_char(word[0])) { if (cond == LABEL && strcmp(word, "#define") == 0) { cond = NAME; } else if (cond == NAME) { name = strdup(word); cond = DEFINITION; } else if (cond == DEFINITION) { defn = strdup(word); cond = LABEL; install(name, defn); } if (cond == LABEL) { printf("%s is %s\n", name, search_defn(name)); } } } return 0; } /* undef : ハッシュテーブルから名前と定義を削除する */ void undef(char *s) { struct nlist *np1, *np2; /* np1 は削除対象のポインタ */ unsigned hashval = hash(s); for (np1 = np2 = hashtab[hashval]; np1 != NULL; np2 = np1, np1 = np1->next) { if (strcmp(s, np1->name) == 0) { /* s がハッシュテーブルに見つかった */ if (np1 == np2) { /* リストの先頭の場合 */ hashtab[hashval] = np1->next; } else { /* np2 が np1 の前の場合 */ np2->next = np1->next; } free(np1->name); free(np1->defn); free(np1); break; } } } /* search_defn : 名前文字列 s からハッシュに登録されている定義文字列を探す */ char *search_defn(char *s) { struct nlist *np; if ((np = lookup(s)) != NULL) { /* 見つかった */ return np->defn; } else { return "not defined."; } } /* hash : 文字列 s に対しハッシュの値を求める */ unsigned hash(char *s) { unsigned hashval; for (hashval = 0; *s != '\0'; s++) { hashval = *s + 31 *hashval; } return hashval % HASHSIZE; } /* lookup : hashtab の中で s を探す */ 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; /* 見つからない */ } /* install : hashtab の中に (name, defn) を置く */ 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 = my_strdup(name)) == NULL) { return NULL; } hashval = hash(name); np->next = hashtab[hashval]; hashtab[hashval] = np; } else { /* すでにある */ free((void *) np->defn); /* 以前の defn を解放する */ } if ((np->defn = my_strdup(defn)) == NULL) { return NULL; } return np; } /* my_strdup : s の複製を作る */ char *my_strdup(char *s) { char *p; p = (char *) malloc(strlen(s)+1); /* + 1 for '\0' */ if (p != NULL) { strcpy(p, s); } return p; } /* #define に利用できる文字かチェックする */ int is_legal_char(char c) { if (isalnum(c)) { return 1; } else if (c == '_') { return 1; } else if (c == '#') { return 1; } else if (c == '"') { return 1; } else if (c == '\'') { return 1; } else { return 0; } } /* getword : 入力から次の語または文字を求める */ int getword(char *word, int lim) { int c, getch(void); void ungetch(int); char *w = word; while (isspace(c = getch())) ; if (c != EOF) { *w++ = c; } if (!is_legal_char(c)) { *w = '\0'; return c; } for ( ; --lim > 0; w++) { if (!is_legal_char(*w = getch())) { ungetch(*w); break; } } *w = '\0'; return word[0]; } int getch(void) /* (押し戻された可能性もある) 1文字をとってくる */ { return (bufp > 0) ? buf[--bufp] : getchar(); } void ungetch(int c) /* 文字を入力に押し戻す */ { if (bufp > BUFSIZE) fprintf(stderr, "ungetch : too many characters\n"); else buf[bufp++] = c; }
実行結果
$ cat sample.txt #define MAX 1000 #define MIN 100 #define MSG "hello" #define IS_WORD 1 $ ./ex6-6 <sample.txt MAX is 1000 MIN is 100 MSG is "hello" IS_WORD is 1
プログラミング言語C 第2版 ANSI規格準拠
posted with amazlet at 09.11.27
B.W. カーニハン D.M. リッチー
共立出版
売り上げランキング: 9726
共立出版
売り上げランキング: 9726