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); }
うは、思った以上に変態チックですね・・・。
表示はかなり手抜きです。
テスト
% 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したい。
- 色々課題が見えてきました。
クラスのチェーンだと楽に出来そうな気がする。