関数ポインタで状態遷移
状態遷移の憂鬱
C で switch 文を使って状態遷移を書いていると「もうだめだぁ」と力尽きることが多い。
関数ポインタ
ググってみると関数ポインタを使うといいらしいのでメモ。
// Parser.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Parser Parser;
struct Parser {
void (*_worker)(Parser*, int); // 状態遷移の状態を持つ関数ポインタ
FILE* _stream; // 入力ストリーム
int _number; // 処理中の番号
int _buffer_pos; // バッファ位置
char _buffer[128]; // バッファ
};
// 状態遷移で使う関数のプロトタイプ
void Parser_first(Parser*, int);
void Parser_comma(Parser*, int);
void die(char const* msg) {
perror(msg);
exit(EXIT_FAILURE);
}
/**
* パーサーの構築
*/
Parser* Parser_new(void) {
Parser* self = (Parser*) calloc(1, sizeof(Parser));
if (!self) {
die("failed to allocate memory");
}
// 最初の状態
self->_worker = Parser_first;
return self;
}
/**
* パーサーの破棄
*/
void Parser_delete(Parser* self) {
if (self) {
free(self);
}
}
/**
* バッファにプッシュする
*/
void Parser_buffer_push(Parser* self, int ch) {
if (self->_buffer_pos >= sizeof(self->_buffer)-1) {
die("buffer overflow");
}
self->_buffer[self->_buffer_pos++] = ch;
self->_buffer[self->_buffer_pos] = 0;
}
/**
* バッファをクリアする
*/
void Parser_buffer_clear(Parser* self) {
self->_buffer[0] = 0;
self->_buffer_pos = 0;
}
void Parser_first(Parser* self, int ch) {
if (ch == ',' || ch == '\n') {
// 状態を更新
self->_worker = Parser_comma;
// debug
printf("[%s]\n", self->_buffer);
// バッファをクリア
Parser_buffer_clear(self);
} else {
Parser_buffer_push(self, ch);
}
}
void Parser_comma(Parser* self, int ch) {
if (ch == ',' || ch == '\n') {
// nothing todo
} else {
// 状態を更新
self->_worker = Parser_first;
Parser_buffer_push(self, ch);
}
}
/**
* パースを実行する
*/
void Parser_execute(Parser* self, FILE* stream) {
// 実行前に状態を初期化
self->_worker = Parser_first;
// 実行前にバッファをクリア
Parser_buffer_clear(self);
// 処理するストリームをセット
self->_stream = stream;
// ストリームをチェック
if (feof(self->_stream)) {
return;
}
// 実行
for (size_t i = 0; ; ++i) {
int ch = fgetc(self->_stream);
if (ch == EOF || ferror(self->_stream)) {
return;
}
self->_number = i;
// 状態が勝手に変わってくれるのでラク
self->_worker(self, ch);
}
}
int main(void) {
Parser* parser = Parser_new();
Parser_execute(parser, stdin);
Parser_delete(parser);
return 0;
}
$ clang test.c && ./a.out
123,223,323
[123]
[223]
[323]
abc,def,ghi
[abc]
[def]
[ghi]
Author And Source
この問題について(関数ポインタで状態遷移), 我々は、より多くの情報をここで見つけました https://qiita.com/narupo/items/1202e84626aaa07c2fe8著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .