再帰で一行取得とHQ9+

Cでファイルから一行取得するのは結構面倒な作業だと思います。でも、再帰使ったららくちんに一行取得出来るんじゃないかと。

再帰だと、

  • 改行があるまでgetchr
  • 改行があったらmalloc
  • ダダァッと文字を書き込む

という感じに書ける。


一行取得だけじゃ面白くないので、インタプリタHQ9+を書いてみた。

HQ9+ - Wikipediaによると、HQ9+の仕様は

  • H Hello, World!!を出力
  • Q プログラムの内容を出力
  • 9 99 Bottles of Beerの歌詞を出力する
  • + カウンタを一個増やす。

99の数え歌は出力が長すぎるので、カウンタ分歌詞を表示する仕様にしました。

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

char *get_line_iter(int n)
{
    char *s;
    int c = getchar();

    if (c == EOF) {
        if (n == 0)
            return NULL;
        else {
            s = (char *) malloc(n + 1);
            c = '\0';
        }
    } else if (c == '\n') {
        s = (char *) malloc(n + 2);
        *(s + n + 1) = '\0';
    } else
        s = get_line_iter(n + 1);

    *(s + n) = c;

    return s;
}

char *get_line(void)
{
    return get_line_iter(0);
}

void nn(int n)
{
    if (n != 0) {
        printf("%d bottles of beer on the wall, %d bottles of beer.\n" ,n, n);
        printf("Take one down and pass it around, %d bottle of beer on the wall.\n", n - 1);
        nn(n - 1);
    }
}

int main(void)
{
    char *s;
    int i, a = 0;

    while (NULL != (s = get_line())) {
        for (i = 0; *(s + i) != '\0'; i++) {
            switch (*(s + i)) {
            case 'H' : printf("Hello, World!!\n"); break;
            case 'Q' : printf("%s", s); break;
            case '9' : nn(a); break;
            case '+' : a++; break;
            case '\n' : printf("\n"); break;
            default : printf("Syntax Error"); break;
            }
        }
        free(s);
    }

    return EXIT_SUCCESS;
}

再帰で書いた方がすっきり書ける。EOFで行が終了してる場合どうするのが一般的なんだろうか。

仕様をしっかり詰めた後で高速化していけばいいので、再帰でプログラムをデザインしていくというやり方は関数型言語でなくても適用出来そうな気がする。

実行してみると。

% ./HQ9+
HQ++++9

こんな感じの出力に。

Hello, World!!
HQ++++9
4 bottles of beer on the wall, 4 bottles of beer.
Take one down and pass it around, 3 bottle of beer on the wall.
3 bottles of beer on the wall, 3 bottles of beer.
Take one down and pass it around, 2 bottle of beer on the wall.
2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.
1 bottles of beer on the wall, 1 bottles of beer.
Take one down and pass it around, 0 bottle of beer on the wall.

うは、なんだコレ。HQ9+はすげー変な言語だ。