部分答案参考了官方题解和网上的答案,仅供参考,可能也有部分bug未发现或解决。

exercise6-1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#define NKEYS (sizeof keytab / sizeof(keytab[0]))

int binsearch(char *word, struct key tab[], int n)
{
    int cond;
    int low, high, mid;
    low = 0;
    high = n - 1;
    while (low <= high)
    {
        mid = (low + high) / 2;
        if ((cond = strcmp(word, tab[mid].word)) < 0)
            high = mid - 1;
        else if (cond > 0)
            low = mid + 1;
        else
            return mid;
    }
    return -1;
}

int getword(char *word, int lim)
{
    int c;
    char *w = word;
    while (isspace(c = getch()))
        ;
    if (c != EOF)
        *w++ = c;
    if (!isalpha(c))
    {
        *w = '\0';
        return c;
    }
    for (; --lim > 0; w++)
        if (!isalnum(*w = getch()))
        {
            ungetch(*w);
            break;
        }
    *w = '\0';
    return word[0];
}

int main()
{
    int n;
    char word[MAXWORD];
    while (getword(word, MAXWORD) != EOF)
        if (isalpha(word[0]))
            if ((n = binsearch(word, keytab, NKEYS)) >= 0)
                keytab[n].count++;
    for (n = 0; n < NKEYS; n++)
        if (keytab[n].count > 0)
            printf("%4d %s\n",
                   keytab[n].count, keytab[n].word);
    return 0;
}

上述 getword 函数不能正确处理下划线、字符串常量、注释及预处理器控制指令。请编写一个更完善的 getword 函数。

代码:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
enum
{
    NORMAL,
    COMMENT,
    PREPROCESSOR,
    STRING,
    UNDERSCORE
};

int getword02(char *word, int lim)
{
    int c, d, inComment = 0, inString = 0, isPreprocessor = 0, isUnderscore = 0; // 分别表示是否在注释、字符串、预处理指令、下划线中
    char *w = word;

    while (isspace(c = getch()))
        ;

    if (c != EOF)  
        *w++ = c;

    type = NORMAL;  // 默认为普通字符

    if (c == '"')
        inString = 1;
    else if (c == '/' && (d = getch()) == '*')  // 注释
    {
        *w++ = d;
        inComment = 1;
    }
    else if (c == '#')  // 预处理指令
    {
        isPreprocessor = 1;
    }
    else if (c == '_')  // 下划线
    {
        isUnderscore = 1;
    }
    else if (!isalpha(c) && c != '_')   // 不合法字符
    {
        *w = '\0';
        return c;
    }

    for (; --lim > 0; w++)
    {
        if (inString)   // 如果在字符串中,直到遇到双引号才结束
        {
            if ((*w = getch()) == '"')
            {
                w++;
                type = STRING;
                break;
            }
        }
        else if (inComment)
        {
            if ((*w = getch()) == '*' && (d = getch()) == '/')  // 注释结束
            {
                w++;
                *w++ = d;
                type = COMMENT;
                break;
            }
        }
        else if (isPreprocessor)    // 如果在预处理指令中,直到遇到空格才结束
        {
            if (isspace(*w = getch()))
            {
                type = PREPROCESSOR;
                break;
            }
        }
        else if (isUnderscore)  // 如果在下划线中,直到遇到空格才结束
        {
            if (isspace(*w = getch()))
            {
                type = UNDERSCORE;
                break;
            }
        }
        else
        {
            if (!isalnum(*w = getch()) && *w != '_')    // 如果不是字母或下划线,结束
            {
                ungetch(*w);
                break;
            }
        }
    }

    *w = '\0';
    return word[0];
}

int main()
{
    int n;
    char word[MAXWORD];
    while (getword02(word, MAXWORD) != EOF) // 读取单词
    {
        if (type == COMMENT)
            printf("Comment: %s\n", word);
        else if (type == PREPROCESSOR)
            printf("Preprocessor: %s\n", word);
        else if (type == STRING)
            printf("String: %s\n", word);
        else if (type == UNDERSCORE)
            printf("Underscore: %s\n", word);
        else if (isalpha(word[0]) && ((n = binsearch(word, keytab, NKEYS)) >= 0))
        {
            keytab[n].count++;
            printf("Keyword: %s\n", word);
        }
    }
    printf("\nkeywords:\n");
    for (n = 0; n < NKEYS; n++)
        if (keytab[n].count > 0)
            printf("%4d %s\n",
                   keytab[n].count, keytab[n].word);
    return 0;
}

运行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
/*comment*/ #define "string" while for while int _variable
Comment: /*comment*/
Preprocessor: #define
String: "string"
Keyword: while
Keyword: for
Keyword: while
Keyword: int
Underscore: _variable

keywords:
   1 for
   1 int
   2 while

exercise6-2

编写一个程序,用以读入一个 C 语言程序,并按字母表顺序分组打印变量名,要求每一组内各变量名的前 6 个字符相同,其余字符不同。字符串和注释中的单词不予考虑。请将 6 作为一个可在命令行中设定的参数。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#define GRPLEN 6

#define NKEYS (sizeof keytab / sizeof(keytab[0]))

enum
{
    NORMAL,
    COMMENT,
    PREPROCESSOR,
    STRING,
    UNDERSCORE
};

struct tnode
{                        /* the tree node: */
    char *word;          /* points to the text */
    int count;           /* number of occurrences */
    struct tnode *left;  /* left child */
    struct tnode *right; /* right child */
};
int group_length = GRPLEN;

int type;

struct tnode *talloc(void)
{
    return (struct tnode *)malloc(sizeof(struct tnode));
}

char *Strdup(char *s) /* make a duplicate of s */
{
    char *p;
    p = (char *)malloc(strlen(s) + 1); /* +1 for '\0' */
    if (p != NULL)
        strcpy(p, s);
    return p;
}

/* addtree: add a node with w, at or below p */
struct tnode *addtree(struct tnode *p, char *w)
{
    int cond;
    if (p == NULL)
    {                 /* a new word has arrived */
        p = talloc(); /* make a new node */
        p->word = Strdup(w);
        p->count = 1;
        p->left = p->right = NULL;
    }
    else if ((cond = strcmp(w, p->word)) == 0)
        p->count++;    /* repeated word */
    else if (cond < 0) /* less than into left subtree */
        p->left = addtree(p->left, w);
    else /* greater than into right subtree */
        p->right = addtree(p->right, w);
    return p;
}

/* treeprint: in-order print of tree p */
void treeprint(struct tnode *p)
{
    if (p != NULL)
    {
        treeprint(p->left);
        printf("%4d %s\n", p->count, p->word);
        treeprint(p->right);
    }
}

int binsearch(char *word, struct key tab[], int n)
{
    int cond;
    int low, high, mid;
    low = 0;
    high = n - 1;
    while (low <= high)
    {
        mid = (low + high) / 2;
        if ((cond = strcmp(word, tab[mid].word)) < 0)
            high = mid - 1;
        else if (cond > 0)
            low = mid + 1;
        else
            return mid;
    }
    return -1;
}

int getword(char *word, int lim)
{
    int c, d, inComment = 0, inString = 0, isPreprocessor = 0, isUnderscore = 0; // 分别表示是否在注释、字符串、预处理指令、下划线中
    char *w = word;

    while (isspace(c = getch()))
        ;

    if (c != EOF)
        *w++ = c;

    type = NORMAL; // 默认为普通字符

    if (c == '"')
        inString = 1;
    else if (c == '/' && (d = getch()) == '*') // 注释
    {
        *w++ = d;
        inComment = 1;
    }
    else if (c == '#') // 预处理指令
    {
        isPreprocessor = 1;
    }
    else if (c == '_') // 下划线
    {
        isUnderscore = 1;
    }
    else if (!isalpha(c) && c != '_') // 不合法字符
    {
        *w = '\0';
        return c;
    }

    for (; --lim > 0; w++)
    {
        if (inString) // 如果在字符串中,直到遇到双引号才结束
        {
            if ((*w = getch()) == '"')
            {
                w++;
                type = STRING;
                break;
            }
        }
        else if (inComment)
        {
            if ((*w = getch()) == '*' && (d = getch()) == '/') // 注释结束
            {
                w++;
                *w++ = d;
                type = COMMENT;
                break;
            }
        }
        else if (isPreprocessor) // 如果在预处理指令中,直到遇到空格才结束
        {
            if (isspace(*w = getch()))
            {
                type = PREPROCESSOR;
                break;
            }
        }
        else if (isUnderscore) // 如果在下划线中,直到遇到空格才结束
        {
            if (isspace(*w = getch()))
            {
                type = UNDERSCORE;
                break;
            }
        }
        else
        {
            if (!isalnum(*w = getch()) && *w != '_') // 如果不是字母或下划线,结束
            {
                ungetch(*w);
                break;
            }
        }
    }

    *w = '\0';
    return word[0];
}

bool is_variable(char *word)
{
    return binsearch(word, keytab, NKEYS) < 0;
}

void groupprint(struct tnode *p, char *prefix)
{
    if (p != NULL)
    {
        groupprint(p->left, prefix);
        if (strncmp(p->word, prefix, group_length) == 0)
        {
            printf("%4d %s\n", p->count, p->word);
        }
        groupprint(p->right, prefix);
    }
}

void print_groups(struct tnode *root)
{
    if (root == NULL)
        return;

    char current_prefix[MAXWORD] = "";
    struct tnode *current = root;

    while (current != NULL)
    {
        strncpy(current_prefix, current->word, group_length);
        current_prefix[group_length] = '\0';
        printf("Group: %s\n", current_prefix);
        groupprint(root, current_prefix);
        current = current->right;
    }
}

int main(int argc, char *argv[])
{
    if (argc > 1)
    {
        group_length = atoi(argv[1]);
    }

    int n;
    struct tnode *root = NULL;
    char word[MAXWORD];

    while (getword(word, MAXWORD) != EOF)
        if (type == NORMAL && isalpha(word[0]) && is_variable(word))        
            root = addtree(root, word);
    print_groups(root);
    return 0;
}

运行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
➜  ch06 git:(main) ./Exercise6-2 5
#include <stdio.h>

int main() {
    int varOne = 1;
    int varTwo = 2;
    int varThree = 3;
    float varOneMore = 4.0;
    char varTwoMore = 'a'; // This is a comment
    /* This is a block comment
       int varFour = 4; */
    return 0;
}
Group: stdio
   1 stdio
Group: varOn
   1 varOne
   1 varOneMore
Group: varTw
   1 varTwo
   1 varTwoMore
Group: varTw
   1 varTwo
   1 varTwoMore

exercise6-3

编写一个交叉引用程序,打印文档中所有单词的列表,并且每个单词还有一个列表,记录出现过该单词的行号。对 the、and 等非实义单词不予考虑。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
struct tnode
{
    char *word;
    int lines[MAXLINES];
    int line_count;
    struct tnode *left;
    struct tnode *right;
};

int line_number = 1;

struct tnode *talloc(void)
{
    return (struct tnode *)malloc(sizeof(struct tnode));
}

char *strdup(const char *s)
{
    char *p = (char *)malloc(strlen(s) + 1);
    if (p != NULL)
        strcpy(p, s);
    return p;
}

struct tnode *addtree(struct tnode *p, char *w, int lineno)
{
    int cond;

    if (p == NULL)
    {
        p = talloc();
        p->word = strdup(w);
        p->lines[0] = lineno;
        p->line_count = 1;
        p->left = p->right = NULL;
    }
    else if ((cond = strcmp(w, p->word)) == 0)
    {
        if (p->lines[p->line_count - 1] != lineno)
            p->lines[p->line_count++] = lineno;
    }
    else if (cond < 0)
        p->left = addtree(p->left, w, lineno);
    else
        p->right = addtree(p->right, w, lineno);
    return p;
}

void treeprint(struct tnode *p)
{
    if (p != NULL)
    {
        treeprint(p->left);
        printf("%s: ", p->word);
        for (int i = 0; i < p->line_count; i++)
            printf("%d ", p->lines[i]);
        printf("\n");
        treeprint(p->right);
    }
}

int getword(char *word, int lim)
{
    int c;
    char *w = word;

    while (isspace(c = getch()))
        if (c == '\n')
            line_number++;
    if (c != EOF)
        *w++ = c;
    if (!isalpha(c))
    {
        *w = '\0';
        return c;
    }
    for (; --lim > 0; w++)
        if (!isalnum(*w = getch()))
        {
            ungetch(*w);
            break;
        }

    *w = '\0';
    return word[0];
}

int is_noise_word(char *word)
{
    static char *noise_words[] = {
        "the", "and", "a", "an", "in", "on", "of", "to", "is", "are", "was", "were", "it", "that", "this", "with", "as", "for", "by", "at", "from", "but", "or", "not", "be", "have", "has", "had", "do", "does", "did", "will", "would", "can", "could", "should", "shall", "may", "might", "must", "if", "then", "else", "when", "where", "which", "who", "whom", "whose", "why", "how", NULL};
    for (char **p = noise_words; *p != NULL; p++)
        if (strcmp(word, *p) == 0)
            return 1;
    return 0;
}

int main(void)
{
    struct tnode *root = NULL;
    char word[MAXWORD];

    while (getword(word, MAXWORD) != EOF)
        if (isalpha(word[0]) && !is_noise_word(word))
            root = addtree(root, word, line_number);
    treeprint(root);
    return 0;
}

运行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
➜  ch06 git:(main) ./Exercise6-3 < test.txt 
AFAIK: 3 
Cassandra: 1 4 
Hopefully: 5 
It: 1 
So: 3 
This: 4 
To: 2 
UK: 2 
Well: 3 
What: 5 
about: 4 
according: 5 
account: 1 
accounts: 2 
all: 3 
always: 3 
approximately: 4 
been: 3 
best: 4 5 
better: 1 
calls: 3 
cardinality: 5 
case: 4 5 
cases: 5 
client: 1 
conclusion: 4 
country: 2 
e: 4 
each: 2 
enough: 3 
equal: 4 
even: 1 5 
every: 2 3 
expected: 1 
fine: 5 
finer: 5 
found: 2 3 
good: 1 
i: 4 
importance: 1 
index: 2 5 
indexed: 5 
indexes: 4 
into: 1 
leads: 4 
looks: 2 
lookup: 2 
low: 5 
n: 4 
narrow: 5 
node: 2 3 
nodes: 3 4 
number: 1 4 5 
other: 5 
p: 4 
partition: 2 
partitions: 4 
perform: 2 
queried: 2 3 
quite: 1 
requested: 1 5 
resulting: 5 
rows: 1 3 5 
s: 1 4 
secondary: 4 
seconday: 5 
sets: 5 
stop: 3 
summary: 1 
taking: 1 
there: 5 
up: 2 
use: 4 5 
user: 2 
values: 5 
vs: 5 

exercise6-4

编写一个程序,根据单词的出现频率按降序打印输入的各个不同单词,并在每个单词的前面标上它的出现次数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 将树转换为列表
void treeToList(struct tnode *p, struct wordinfo list[])
{
    if (p != NULL)
    {
        treeToList(p->left, list);
        list[counter].word = strdup(p->word);
        list[counter].count = p->count;
        counter++;
        treeToList(p->right, list);
    }
}

// 打印列表
void listprint(struct wordinfo list[])
{
    for (int i = 0; i < wordCount; i++)
    {
        printf("%4d %s\n", list[i].count, list[i].word);
    }
}

// 交换两个元素
void swap(struct wordinfo list[], int i, int j)
{
    struct wordinfo temp;
    temp = list[i];
    list[i] = list[j];
    list[j] = temp;
}

// 根据单词出现的频率来进行快速排序
void mqsort(struct wordinfo list[], int left, int right)
{
    int i, last;

    if (left >= right)
        return;
    swap(list, left, (left + right) / 2);
    last = left;
    for (i = left + 1; i <= right; i++)
        if (list[i].count > list[left].count)
            swap(list, ++last, i);
    swap(list, left, last);
    mqsort(list, left, last - 1);
    mqsort(list, last + 1, right);
}

int main(void)
{
    struct tnode *root;
    char word[MAXWORD];

    root = NULL;
    while (getword(word, MAXWORD) != EOF)
        if (isalpha(word[0]))
            root = addtree(root, word);
    printf("Count of words is %d\n", wordCount);
    struct wordinfo list[wordCount];
    treeToList(root, list);
    mqsort(list, 0, wordCount - 1);
    listprint(list);
    return 0;
}

运行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
➜  ch06 git:(main) ./Exercise6-4 < test.txt
Count of words is 95
  12 the
   6 of
   6 is
   4 number
   3 queried
   3 rows
   3 are
   3 node
   3 to
   3 when
   3 use
   2 index
   2 found
   2 have
   2 Cassandra
   2 looks
   2 cardinality
   2 nodes
   2 even
   2 not
   2 for
   2 partition
   2 best
   2 requested
   2 every
   2 s
   2 case
   2 that
   2 a
   2 up
   1 leads
   1 So
   1 This
   1 e
   1 or
   1 enough
   1 other
   1 and
   1 p
   1 expected
   1 calls
   1 finer
   1 partitions
   1 been
   1 perform
   1 accounts
   1 To
   1 importance
   1 quite
   1 indexed
   1 all
   1 into
   1 resulting
   1 it
   1 UK
   1 better
   1 always
   1 low
   1 secondary
   1 narrow
   1 seconday
   1 but
   1 sets
   1 country
   1 stop
   1 equal
   1 summary
   1 fine
   1 taking
   1 good
   1 cases
   1 AFAIK
   1 Well
   1 Hopefully
   1 then
   1 lookup
   1 there
   1 It
   1 What
   1 each
   1 client
   1 account
   1 conclusion
   1 indexes
   1 user
   1 n
   1 values
   1 approximately
   1 vs
   1 according
   1 about
   1 i
   1 where
   1 by
   1 would

exercise6-5

编写函数 undef,它将从由 lookup 和 install 维护的表中删除一个变量及其定义。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/* undef: remove a name and its definition from the hashtab */
void undef(char *name)
{
    struct nlist *np, *prev = NULL;
    unsigned hashval = hash(name);

    for (np = hashtab[hashval]; np != NULL; prev = np, np = np->next)   // 遍历链表
    {
        if (strcmp(name, np->name) == 0)    
        {
            if (prev == NULL)
                hashtab[hashval] = np->next;
            else
                prev->next = np->next;
            free(np->name);
            free(np->defn);
            free(np);
            return;
        }
    }
}

int main(void)
{
    struct nlist *np;
    printf("test install \"MAXLINE\"  \"BUFSIZE\":\n");
    install("MAXLINE", "1000");
    install("BUFSIZE", "100");

    np = lookup("MAXLINE");

    if (np == NULL) 
        printf("install failed\n");
    else 
        printf("defination of \"MAXLINE\" is: %s\n", np->defn);
    printf("install success\n");
    printf("\ntest undef \"BUFSIZE\":\n");
    undef("BUFSIZE");
    np = lookup("BUFSIZE");
    if (np == NULL)
        printf("can not find defination of \"BUFSIZE\"\nundef success\n");
    return 0;
}

运行:

1
2
3
4
5
6
7
8
➜  ch06 git:(main) ✗ ./Exercise6-5   
test install "MAXLINE"  "BUFSIZE":
defination of "MAXLINE" is: 1000
install success

test undef "BUFSIZE":
can not find defination of "BUFSIZE"
undef success

exercise6-6

以本节介绍的函数为基础,编写一个适合 C 语言程序使用的#define 处理器的简单版本(即无参数的情况)。你会发现 getch 和 ungetch 函数非常有用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
void skipblanks(void)
{
    int c;
    while ((c = getch()) == ' ' || c == '\t')
        ;
    ungetch(c);
}

void getdef(void)
{
    int c, i;
    char def[BUFSIZE], name[BUFSIZE];

    skipblanks();
    if (!isalpha(c = getch()))
    {
        printf("getdef: invalid macro name\n");
        return;
    }

    for (i = 0; isalnum(c) || c == '_'; c = getch())
        name[i++] = c;
    name[i] = '\0';

    skipblanks();
    if (c != ' ')
    {
        printf("getdef: missing space after macro name\n");
        return;
    }

    for (i = 0; (c = getch()) != EOF && c != '\n';)
        def[i++] = c;
    def[i] = '\0';

    if (i > 0)
        install(name, def);
}

void procdef(void)
{
    int c;
    while ((c = getch()) != EOF)
    {
        if (c == '#')
        {
            char keyword[7];
            int i;
            for (i = 0; i < 6 && (c = getch()) != EOF; i++)
            {
                keyword[i] = c;
            }
            keyword[i] = '\0';

            if (strcmp(keyword, "define") == 0)
            {
                getdef();
            }
        }
    }
}

int main(void)
{
    procdef();
    printf("name            defination\n");
    for (int i = 0; i < HASHSIZE; i++)
    {
        struct nlist *np = hashtab[i];
        while (np != NULL)
        {
            printf("%-16s%s\n", np->name, np->defn);
            np = np->next;
        }
    }
    return 0;
}

对于test.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define  LISTENQ    1024
#define  MAXLINE    4096
#define  BUFFSIZE  8192
#define  SERV_PORT     9877
#define  AI_PASSIVE     1
#define  AI_CANONNAME   2
#define  NI_MAXHOST    1025
#define  NI_MAXSERV      32
#define  NI_NOFQDN       1
#define  NI_NUMERICHOST   2
#define  NI_NAMEREQD       4
#define  NI_NUMERICSERV   8
#define  NI_DGRAM      16
#define  EAI_ADDRFAMILY   1
#define  EAI_AGAIN     2
#define  EAI_BADFLAGS   3
#define  EAI_FAIL     4
#define  EAI_FAMILY     5
#define  EAI_MEMORY     6
#define  EAI_NODATA     7
#define  EAI_NONAME     8
#define  EAI_SERVICE     9
#define  EAI_SOCKTYPE  10
#define  EAI_SYSTEM    11

运行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
➜  ch06 git:(main) ✗ ./Exercise6-6 < test.c
name            defination
AI_CANONNAME    2
NI_NUMERICHOST  2
EAI_NONAME      8
EAI_ADDRFAMILY  1
NI_NUMERICSERV  8
AI_PASSIVE      1
EAI_SERVICE     9
SERV_PORT       9877
EAI_SOCKTYPE    10
EAI_MEMORY      6
EAI_AGAIN       2
EAI_BADFLAGS    3
NI_MAXHOST      1025
EAI_FAIL        4
NI_NAMEREQD     4
EAI_NODATA      7
MAXLINE         4096
NI_MAXSERV      32
EAI_SYSTEM      11
BUFFSIZE        8192
NI_DGRAM        16
NI_NOFQDN       1
EAI_FAMILY      5
LISTENQ         1024