2

我最近创建了自己的脚本语言。我的代码结构很大程度上基于多态性。(我不太确定它是如何调用的。我有一个虚函数,然后我派生类并让操作系统决定在运行时调用什么):

class Statement 
{ 
    virtual void exec() = 0; 
};

class PrintStmt : public Statement
{ 
    void exec() 
    { 
        std::cout << expression->eval(); 
    };    

class AssignStmt : public Statement
{ 
    void exec() 
    { 
        vm->bind_var(name, expression->eval()) 
    };

有什么想法可以重做它,以便它可以由纯 C 编译器编译吗?我知道这是一个普遍的问题,没有单一的答案,但你会怎么做呢?

注意:我已经下载了 python 代码作为参考,但要弄清楚它是如何工作的还需要一些时间。

4

2 回答 2

3

Statement将是一个struct. 除了它的数据成员之外,您还需要一个函数指针,例如

struct Statement
{
    void(*exec)(Statement* this); // Function pointer
    // Other members
};

然后,您将拥有每个语句类型的函数的不同实现以及用于制造正确类型的对象的函数,例如

static void printExec(struct Statement* this)
{
    printf("%s", this->whatever);
}

struct Statement* createPrintStatement()
{
    struct Statement* statement = calloc(1, sizeof(struct Statement));
    statement->exec = printExec;
    return statement;
}

你会像这样调用它:

statement->exec(statement);

this指针使您可以访问特定结构的数据成员,即您调用其 exec 方法的实例。

如果您有很多功能,请考虑使用 vtable。

struct VTable
{
    void(*exec)(Statement* this); // Function pointer
    const char* (*stringValue)(Statement* this); // Function pointer
};

struct Statement
{
    struct VTable* vtable;
    // Other members
};

您只为每种对象构建一个 vtable 一次

struct VTable printVTable =
{
    printExec,
    printStringValue
};

您可以这样创建新对象:

struct Statement* createPrintStatement()
{
    struct Statement* statement = calloc(1, sizeof(struct Statement));
    statement->vtable = &printVTable;
    return statement;
}

并调用这些方法

statement->vtable->exec(statement);

vtable 方法或多或少是 C++ 在幕后所做的。

于 2013-04-19T15:58:21.290 回答
1

将其转换为 C 的最直接方法可能是使用函数指针。正如@DrewNorman 所说,您将需要了解 vtables 的工作方式、类布局等,并在 C 中重新实现它(至少部分地)。下面的示例代码非常有限,但会给您一些预期的提示。

struct Statement {
  void (*exec)(struct Statement* s);
};
struct PrintStmt {
  struct Statement statement;
  char* what;
};

void print_function(struct Statement* s) {
    struct PrintStmt* p = (struct PrintStmt*)s;
    printf(p->what);
}

// ...

struct PrintStmt p;
p.statement.exec = &print_function;
p.what = "Hello world";
p.statement.exec(p);

有许多 C 项目使用这种技术,我想到了 GObject,但它远非唯一。

(注意:我习惯了 C++ 而不是真正的 C,所以这甚至可能不是有效的 C,但你还是明白了)

于 2013-04-19T15:54:42.087 回答