I recently came accross the yield
keyword in Python (as well as JavaScript) - I understand that this is primarliy used for the generator pattern, but the language construct seems to be used in asynchronous functions as well where my interests lie. In asynchronous functions it may merely act as syntatic-sugar and I know there are alternative patterns to achieve the same effect - But I like it - A LOT!
I want to know if I can do something similar in C (even with inline assembly). I came across a Java implementation using threads https://github.com/mherrmann/java-generator-functions which I can more or less implement in C. However this is won't be a freestanding implementation, and my interest is purely in a freestanding implementation.
Coming to C co-routines (http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html), one of the deficits is that stack objects can't be used. However I am still OK with this since current asynchronous callback implementations also can't use the stack. However the problem lies in a freestanding implementation - I can't think of a way to collect all the register variables and store them without a hosted environment.
There's probably a solution using the setjmp/longjmp
, however I am pretty sure these can't be implemented freestanding.
So the question is: Is it possible to implement Python yield functionality in freestanding C?
Personally I think I have exhausted the possibilites, so I'll ask this - If you could have a hosted implementation, how would you implement it (preferably with some macro magic)? I have a fairly ugly implementation which I'll post later on if nothing cool comes up.
Also I don't want C++ implementations - Unless you can wrap around the C++ with pure C functions.
EDIT: A basic requirement is that the generator function has to be re-enterant.
yield in Python can be used like the return statement in a function. When done so, the function instead of returning the output, it returns a generator that can be iterated upon. You can then iterate through the generator to extract items. Iterating is done using a for loop or simply using the next() function.
yield keyword is used to create a generator function. A type of function that is memory efficient and can be used like an iterator object. In layman terms, the yield keyword will turn any expression that is given with it into a generator object and return it to the caller.
Inside a program, when you call a function that has a yield statement, as soon as a yield is encountered, the execution of the function stops and returns an object of the generator to the function caller.
Yield is generally used to convert a regular Python function into a generator. Return is generally used for the end of the execution and “returns” the result to the caller statement. It replace the return of a function to suspend its execution without destroying local variables.
I'm going to answer using setjmp
and longjmp
since those interfaces are standard and you can easily find their implementations for any HW platform. They are freestanding, but HW dependent.
struct _yield_state {
jmp_buf buf;
_Bool yielded;
};
#define yieldable static struct _yield_state _state; \
if (_state.yielded) longjmp(_state.buf, 1); else {}
#define yield(x) if (setjmp(_state.buf)) { _state.yielded = false; }\
else { _state.yielded = true; return x }
int func(int a, int b)
{
yieldable;
if (a > b)
yield(0);
return a + b;
}
You can find an example setjmp
and longjmp
implementation here. It is pure assembly, specific only to the underlying hardware.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With