Skip to content

SamGaaWaa/c_yield

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

English | 中文

c_yield - C 协程转换器

c_yield.py 是一个源到源的转换器,可将包含 yield() 调用的 C 函数转换为可恢复的状态机(协程)。

功能特点

  • 将包含 yield() 的函数转换为状态机
  • 在 yield 之间保留局部变量
  • 处理循环、条件语句和嵌套作用域
  • 生成初始化函数和恢复函数
  • 仅支持 C(由于 RAII 问题不支持 C++)

要求

Python 依赖

  • Python 3.8+
  • Python libclang 包(提供带有捆绑 libclang 二进制文件的 clang.cindex 模块)

安装

安装 Python 包:

pip install libclang

使用方法

基本用法:

python c_yield.py input.c output.c

带选项:

python c_yield.py --help

示例:

python c_yield.py test.c transformed.c

函数要求

需要转换的函数必须满足:

  1. 返回类型: void
  2. 第一个参数: 指向结构体的指针(状态结构)
  3. 包含 yield() 调用
  4. 不支持 C++(不支持析构函数和 RAII)

转换规则

原始代码

struct my_state {};

void my_func(struct my_state *s, int param) {
    int local = param * 2;
    printf("Start: %d\n", local);
    yield();
    local += 10;
    printf("After: %d\n", local);
    yield();
    printf("Done\n");
}

转换后的代码

转换器生成:

  1. 扩展的状态结构,包含局部变量和 yield 索引
  2. 初始化函数 (my_func),用于设置状态
  3. 恢复函数 (my_func_resume),用于继续执行
struct my_state {
    int param;
    union {
        struct {
            int local;
        } __scope_1;
    };
    int __Idx;
};

void my_func_resume(void *state_ptr) {
    struct my_state *s = (struct my_state*)state_ptr;
    switch (s->__Idx) {
        case 0: break;
        case -1: return;
        case 1: s->__Idx = -1; goto __Label_0;
        case 2: s->__Idx = -1; goto __Label_1;
    }
    (s->__scope_1.local) = (s->param) * 2;
    printf("Start: %d\n", (s->__scope_1.local));
    { s->__Idx = 1; return; __Label_0:; }
    (s->__scope_1.local) += 10;
    printf("After: %d\n", (s->__scope_1.local));
    { s->__Idx = 2; return; __Label_1:; }
    printf("Done\n");
}

void my_func(struct my_state *s, int param) {
    s->param = param;
    s->__Idx = 0;
}

工作原理

  1. 解析: 使用 libclang 解析 C 源代码,查找包含 yield() 调用的函数
  2. 作用域分析: 识别局部变量及其相对于 yield 点的生命周期
  3. 变量提升: 将局部变量移动到状态结构中
  4. 状态机生成: 创建基于 switch 的分派和 goto 标签
  5. 代码重写: 用初始化函数和恢复函数替换原始函数

状态索引 (__Idx)

  • 0: 初始状态(开始执行)
  • 1..N: yield 点索引(从特定 yield 恢复)
  • -1: 最终状态(执行完成)

限制

  1. 不支持 C++: 不支持 C++ 特性(构造函数、析构函数、异常、RAII)
  2. 变量地址: 获取局部变量的地址在转换后可能无法正常工作
  3. setjmp/longjmp: 与状态机方法不兼容
  4. 递归 Yield: 在嵌套函数调用中 yield 的函数需要谨慎设计
  5. 线程安全: 状态机本身不是线程安全的

API 使用模式

struct my_state s = {};
my_func(&s, 42);  // 初始化

while (s.__Idx != -1) {
    my_func_resume(&s);  // 恢复直到完成
    // 处理中间结果
}

示例用例

  • 生成器: 产生值序列
  • 异步 I/O: 协作式调度的操作
  • 游戏 AI: 有状态的行为树
  • 解析器: 增量输入处理
  • 协议处理器: 有状态的网络协议

使用 CMake 构建

项目包含 CMake 构建系统,便于编译和测试。

c_yield - C Coroutine Transformer

c_yield.py is a source-to-source transformer that converts C functions containing yield() calls into resumable state machines (coroutines).

Features

  • Converts functions with yield() into state machines
  • Preserves local variables across yields
  • Handles loops, conditionals, and nested scopes
  • Generates initialization and resume functions
  • Supports C only (no C++ due to RAII issues)

Requirements

Python Dependencies

  • Python 3.8+
  • Python libclang package (provides clang.cindex module with bundled libclang binaries)

Installation

Install the Python package:

pip install libclang

Usage

Basic usage:

python c_yield.py input.c output.c

With options:

python c_yield.py --help

Example:

python c_yield.py test.c transformed.c

Function Requirements

Functions to be transformed must satisfy:

  1. Return type: void
  2. First parameter: Pointer to a struct (state structure)
  3. Contains yield() calls
  4. No C++ (destructors and RAII not supported)

Transformation Rules

Original Code

struct my_state {};

void my_func(struct my_state *s, int param) {
    int local = param * 2;
    printf("Start: %d\n", local);
    yield();
    local += 10;
    printf("After: %d\n", local);
    yield();
    printf("Done\n");
}

Transformed Code

The transformer generates:

  1. Expanded state structure with local variables and yield index
  2. Initialization function (my_func) that sets up the state
  3. Resume function (my_func_resume) that continues execution
struct my_state {
    int param;
    union {
        struct {
            int local;
        } __scope_1;
    };
    int __Idx;
};

void my_func_resume(void *state_ptr) {
    struct my_state *s = (struct my_state*)state_ptr;
    switch (s->__Idx) {
        case 0: break;
        case -1: return;
        case 1: s->__Idx = -1; goto __Label_0;
        case 2: s->__Idx = -1; goto __Label_1;
    }
    (s->__scope_1.local) = (s->param) * 2;
    printf("Start: %d\n", (s->__scope_1.local));
    { s->__Idx = 1; return; __Label_0:; }
    (s->__scope_1.local) += 10;
    printf("After: %d\n", (s->__scope_1.local));
    { s->__Idx = 2; return; __Label_1:; }
    printf("Done\n");
}

void my_func(struct my_state *s, int param) {
    s->param = param;
    s->__Idx = 0;
}

How It Works

  1. Parsing: Uses libclang to parse C source and find functions with yield() calls
  2. Scope Analysis: Identifies local variables and their lifetimes relative to yield points
  3. Variable Lifting: Moves local variables into the state structure
  4. State Machine Generation: Creates switch-based dispatch with goto labels
  5. Code Rewriting: Replaces original function with initialization + resume functions

State Index (__Idx)

  • 0: Initial state (start execution)
  • 1..N: Yield point indices (resume from specific yield)
  • -1: Final state (execution completed)

Limitations

  1. No C++: C++ features (constructors, destructors, exceptions, RAII) are not supported
  2. Variable Address: Taking address of local variables may not work correctly after transformation
  3. setjmp/longjmp: Not compatible with the state machine approach
  4. Recursive Yields: Functions that yield within nested function calls require careful design
  5. Thread Safety: State machines are not inherently thread-safe

API Usage Pattern

struct my_state s = {};
my_func(&s, 42);  // Initialize

while (s.__Idx != -1) {
    my_func_resume(&s);  // Resume until done
    // Process intermediate results
}

Example Use Cases

  • Generators: Produce sequences of values
  • Async I/O: Cooperatively scheduled operations
  • Game AI: Stateful behavior trees
  • Parsers: Incremental input processing
  • Protocol Handlers: Stateful network protocols

Building with CMake

The project includes a CMake build system for easy compilation and testing.

About

C协程转状态机 C-coroutine to state machine

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors