12

例えば:

int getNext(int n) {
    while (TRUE) {
        n = n+1;
        yield n;
    }
}

int main() {
    while (TRUE) {
        int n = getNext(1);
        if (n > 42)
           break;
        printf("%d\n",n);
    }
}

上記のコードが 1 から 42 までのすべての数字を出力するように。 yieldgetNext のアドレスを の後の命令に変更することを考えましたyield。しかし、スタックが呼び出し元関数によって実行されるため、コンテキスト (レジスタ/変数) を保存する方法がわかりません。

ノート:

上記のコードは静的変数で簡単に実装できることはわかっていますが、それは重要ではありません。

4

2 に答える 2

18

移植可能な C であっても、そうすることができますgcc -Wall gen.c

#include <stdbool.h>
#include <stdio.h>
#include <setjmp.h>

#define YIELD(func, n) if (! setjmp(func##_gen_jmp)) {  \
      func##_ret = n;                                   \
         longjmp(func##_caller_jmp, 1);                 \
  }


#define GENERATOR(ret, func, argt, argv)        \
  static jmp_buf func##_caller_jmp;             \
  static jmp_buf func##_gen_jmp;                \
  static bool func##_continue=false;            \
  static ret func##_ret;                        \
                                                \
  void func##__real(argt argv);                 \
                                                \
  ret func(argt argv) {                         \
    if (!func##_continue) {                     \
    func##_continue=true ;                      \
      if (! setjmp(func##_caller_jmp)) {        \
        func##__real(argv);                     \
      } else {                                  \
        return func##_ret;                      \
      }                                         \
    }                                           \
     else {                                     \
      longjmp(func##_gen_jmp,1);                \
    }                                           \
    return 0;                                   \
  }                                             \
  void func##__real(argt argv)



GENERATOR(int, getNext, int, n) {
  static int counter;

  counter = n;
    while (true) {
        counter = counter+1;
        YIELD(getNext, counter);
    }
}

int main() {
    while (true) {
      int n = getNext(1);
        if (n > 42)
           break;
        printf("%d\n",n);
    }
    return 0;
}
于 2013-07-05T07:52:23.483 に答える