はじめに
ド深夜に目が覚めて、ストゼロ飲みながら書きました。
GNU 拡張の statement expression を使っているので、gcc でコンパイルしてください。
たぶん30分くらいでバーって書いたので、バグがあったら教えてください (気が向いたら直します)
このヘッダを include すれば call/cc できます。
書きました。
(最初は __ret を volatile にするのを忘れていて、コメントでバグの指摘を頂いて修正しました)
callCC.h
#ifndef CALLCC_H
#define CALLCC_H
#include <setjmp.h>
typedef struct {
jmp_buf *buf;
volatile void *p_ret;
} continuation;
/* Evaluate given expression with current continuation */
/* __cont : name of current continuation */
/* __typ : type of callCC expression */
/* __expr : expression to evaluate with current continuation */
#define callCC(__cont, __typ, __expr) ({ \
volatile __typ __ret; \
jmp_buf __buf; \
\
continuation __cont; \
__cont.p_ret = &__ret; \
__cont.buf = &__buf; \
if(setjmp(__buf) == 0){ \
__ret = __expr; \
} \
__ret; \
})
/* Ignore current continuation and use given continuation */
/* __cont : continuation */
/* __typ : type of associated call/cc */
/* __dummy : just a dummy to deceive type checker */
/* that never get evaluated */
/* __val : value passed to given continuation */
#define useCont(__cont, __typ, __dummy, __val) ({ \
*((volatile __typ *) __cont.p_ret) = (__val); \
longjmp(*(__cont.buf), 1); \
__dummy; \
})
#endif /* CALLCC_H */
テスト
main.c
#include <stdio.h>
#include "callCC.h"
#define dummy 0
int func(continuation cont, int x){
int a;
a = 5 + useCont(cont, int, dummy,
x + 25
);
return 100000;
}
int main(int argc,char **argv){
int a;
/* test1 */
a = 5 + callCC(cont, int,
10*10
);
printf("%d\n", a);
/* test2 */
a = 5 + callCC(cont, int,
10 * 10 * useCont(cont, int, dummy, 20)
);
printf("%d\n", a);
/* test3 */
a = 5 + callCC(cont0, int,
3 + callCC(cont1, int,
10 + useCont(cont0, int, dummy, 7 + 9)
)
);
printf("%d\n", a);
/* test4 */
printf("%d\n", 7 + callCC(cont, int, 100 + func(cont, 10)));
}
実行、
$ gcc main.c
$ ./a.out
105
25
21
42
おわりに
いいんじゃないっすかね
追記
scheme とかの call/cc で取り出した継続って、大域変数にバインドして、call/ccの外側からも呼び出せるんですね。
知らんかった、そこまで出来とらんかった。
ぴえん。