yield equivalent in C/JavaScript?

Bengt Richter bokr at oz.net
Sun Jun 30 18:37:16 EDT 2002


On Sun, 30 Jun 2002 14:01:39 -0400, Oren Tirosh <oren-py-l at hishome.net> wrote:

>On Sat, Jun 29, 2002 at 07:12:46PM +0100, Robin Becker wrote:
>> Is there any way to do yielding easily in C? I have a bunch of programs
>> which are normally connected together using unix pipes. I would like to
>> merge them and the problem is then how to get them to communicate nicely
>> using a single process.
>
>It's possible to implement this in C using Duff's Device:
>
>#define BEGIN_GENERATOR static int _GenState=0; \
>  switch(_GenState) { \
>    case 0:
>
>#define END_GENERATOR } \
>  _GenState = 0;
>
>#define YIELD(x) _GenState=__line__; return (x); case __line__:
>
>
>int generator(arguments) {
>
>  static int foo, bar, etc;	/* Make all variables static */
>
>  BEGIN_GENERATOR 
>  for(...) {
>      if(...) {
>        ...
>        YIELD(x)
>        ...
>      } else {
>        ...
>      }
>      ...
>      YIELD(y)
>      ...
>   }
>   END_GENERATOR
>}
>
>If you want this to be reentrant use a struct passed as an argument
>to the function instead of static variables.
>
That's cool, but I'm wondering how generally BEGIN_GENERATOR's switch/case hopping
into the inside of the for loop like the above will work. Mind-bogglingly, it seems the
switch/case can slice just about orthogonally through loop code. Normally jumping into loops
is frowned upon, I thought, but it seems like case is practically like a label for a goto with
the minor restriction of being inside a switch(){...}, which your BEGIN_/END_GENERATOR guarantees.
I never explored this particular arena of possible abuses much ;-)

Anyway, you can't generate case numbers from line numbers without some risk of collision:

E.g., looking at the preprocessor output (which doesn't mind your ellipses ;-)
and putting a contrived switch around the second YIELD like
--
      switch(y){
      case 28:
          YIELD(y);
          printf("YIELD will make this case 29 here");
          break;
      case 29: printf("So this won't compile"); break;
      }
--

in place of the plain YIELD(y) line, we get:

--
int generator(arguments) {

  static int foo, bar, etc;     /* Make all variables static */

  static int _GenState=0; switch(_GenState) { case 0:
  for(...) {
      if(...) {
        ...
        _GenState=21; return (x); case 21:
        ...
      } else {
        ...
      }
      ...
      switch(y){
      case 28:
          _GenState=29; return (y); case 29:;
          printf("YIELD will make this case 29 here");
          break;
      case 29: printf("So this won't compile"); break;
      }
      ...
   }
   } _GenState = 0;
}
--

BTW, MSVCC6.0 wants
    #define __line__ __LINE__
at the top to do the above. And for compiling, it doesn't like case __LINE__:
because __LINE__ appears not to be a constant expression to it. At the moment
I can't find the directive to get around that. It's happy to compile the
pre-processor output though ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list