K&Rを読もう(5) 1.5(2) 関数チェーンを使ってwcを作ろう。

地震の影響で会社が休みになってしまった。さて、リストが出来たので早速料理再開。今回のテーマはwc。wcも定番っすね。

線形リストを使って関数チェーンを作っていこうと思います。イメージはこんな感じです。

count_word > count_line > count_char > print_char > NULL

関数チェーンを操作することによって、自由度が格段に広がるかなぁなんて思ったり。

#include <stdio.h>
#include <stdlib.h>

#include "list.h"

#define IN  1
#define OUT 0

// 関数のチェーンを逐次実行する。
void chain(List *list, int c)
{
    // 実行用
    void execute(VALUE data)
    {
        void (*f)(int c) = (void (*)(int c)) data;
        f(c);
    }
    each_list(list, execute);
}

int main(void)
{
    // 変数の定義
    List *list;
    int char_c = 0;
    int line_c = 0;
    int word_c = 0;
    int status = OUT;

    // wc本体
    void print_char(int c) { putchar(c); }
    void count_char(int c) { char_c++; }
    void count_line(int c) { if (c == '\n') line_c++; }
    void count_word(int c)
    {
        if (c == ' ' || c == '\t' || c == '\n') status = OUT;
        else if(status == OUT) { status = IN; ++word_c;}
    }
    
    // /* 関数チェーンのpush
    list = new_list();
    list = push_list(list, (VALUE) print_char);
    list = push_list(list, (VALUE) count_char);
    list = push_list(list, (VALUE) count_line);
    list = push_list(list, (VALUE) count_word);
    // */

    /* scheme 風push
    list = push_list(
            push_list(
                push_list(
                    push_list( 
                        new_list(),
                        (VALUE) print_char),
                    (VALUE) count_char),
                (VALUE) count_line),
            (VALUE) count_word);
    */


    // 文字の読み取り(再帰)
    void read_char()
    {
        int c = getchar();
        if (c == EOF)
            return;
        chain(list, c);
        read_char();
    }

    read_char();

    delete_list(list);

    // 表示は手抜き
    printf("%d %d %d\n", line_c, word_c, char_c);

    exit(EXIT_SUCCESS);
}

うは、思った以上に変態チックですね・・・。

表示はかなり手抜きです。

テスト

再帰を使っているので、-O2付きでコンパイルします。

% gcc -Wextra -O2 -o wc list.c 1.5.2.c
% ./wc < 1.5.2.c
#include <stdio.h>
...(略
    exit(EXIT_SUCCESS);
}
80 195 1731
% wc < 1.5.2.c
  80  195 1731

wc風に出来ました。

課題

  • 激しく重くなりそうですね(汗
  • 関数のネストは標準Cではないので、スコープの問題を考えなくてはいけません。
  • 配列でガガーっとpushしたい。
  • 前、中、後の関数を同時にpushしたい。
  • 色々課題が見えてきました。

クラスのチェーンだと楽に出来そうな気がする。