演習6-1 K&R プログラミング言語C

演習6-1

コメント、文字列リテラル内を無視するために skip_char 関数を定義して処理する。
現在の状態をセットして、コメント、文字列リテラル内では文字の取得をスキップする。

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#define MAXWORD 100
#define BUFSIZE 100
#define NKEYS (sizeof keytab / sizeof keytab[0])

char buf[BUFSIZE];  /* ungetch 用のバッファ */
int bufp = 0;       /* buf 中の次の空き位置 */

int getword(char *, int);
int skip_char(void);

enum boolean { FALSE, TRUE };
enum skipping_state { COMMENT_START, IN_COMMENT, COMMENT_END, IN_STR_C, OTHER };

struct key {
    char *word;
    int count;
} keytab[] = {
    { "#define", 0},
    { "#include", 0},
    { "auto", 0 },
    { "break", 0 },
    { "case", 0 },
    { "char", 0 },
    { "const", 0 },
    { "continue", 0 },
    { "default", 0 },
    { "double", 0},
    { "int", 0 },
    /* ... */
    { "return", 0 },
    { "size_t", 0 },
    { "unsigned", 0 },
    { "void", 0 },
    { "volatile", 0 },
    { "while", 0 }
};


/* C のキーワードを数える */
int main(void)
{
    int n;
    char word[MAXWORD];
    int binsearch(char *, struct key *, int);

    while (getword(word, MAXWORD) != EOF) {
        if (isalpha(word[0]) || 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;
}

/* binsearch : tab[0] ... tab[n-1] の中の語を探す */
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 skip_char(void)
{
    int c, getch(void);
    int escaped = FALSE;
    void ungetch(int);
    int type = OTHER;

    while ((c = getch()) != EOF) {
        switch (c) {
        case '/':
            if (type == OTHER) {
                type = COMMENT_START;
            } else if (type == COMMENT_END) {
                type = OTHER;
            }
            escaped = FALSE;
            break;
        case '*':
            if (type == COMMENT_START) {
                type = IN_COMMENT;
            } else if (type == IN_COMMENT) {
                type = COMMENT_END;
            }
            escaped = FALSE;
            break;
        case '"':
            if (!escaped) {
                if (type == OTHER) {
                    type = IN_STR_C;
                } else if (type == IN_STR_C) {
                    type = OTHER;
                }
            }
            escaped = FALSE;
            break;
        case '\\':
            if (type == IN_STR_C) {
                escaped = TRUE;
            }
            break;
        default:
            escaped = FALSE;
            break;
        }

        if (!isspace(c) && type == OTHER) {
            return c;
        }
    }
    return c;
}

/* getword : 入力から次の語または文字を求める */
int getword(char *word, int lim)
{
    int c, getch(void);
    void ungetch(int);
    char *w = word;

    c = skip_char();

    if (c != EOF) {
        *w++ = c;
    }
    if (c != '#' && !isalpha(c)) {
        *w = '\0';
        return c;
    }
    for ( ; --lim > 0; w++) {
        if (!isalnum(*w = getch()) && *w != '_') {
            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.c
#include <stdio.h>
#include <stdlib.h>

#define MAX 100

int main(void)
{
    int i = 0;
    size_t n = MAX;
    /* int j = 0; */

    printf("\"int\" i is %d\n", i);
    /* printf("int j is %d\n", j); */

    printf("\"size_t\" n is %d\n", n);
    /*printf("\"size_t\" n is %d\n", n); */

    return 0;
}
$ ./word_count <sample.c
1 #define
2 #include
2 int
1 return
1 size_t
1 void
プログラミング言語C 第2版 ANSI規格準拠
B.W. カーニハン D.M. リッチー
共立出版
売り上げランキング: 9726
«
»