【问题标题】:Constructing and returning Julia types in C在 C 中构造和返回 Julia 类型
【发布时间】:2019-02-19 09:06:15
【问题描述】:

您将如何从使用 Julia 的 ccall 调用的 C 函数构造和返回 Julia Expr,比如 :(x + 2),最好这样它可以被 Julia 垃圾收集?

编辑:

由于建议进行一些其他详细信息的编辑,所以在这里。首先,问题不是一次性生成Expr,而是要能够逐步构建任意Exprs 等,见下文。

我需要一个用于 Julia 项目的解析器。解析器输入的内容部分是代数表达式,我希望最终得到等效的 Julia Expr。由于似乎没有带有 Julia 目标的解析器生成器,我正在考虑用 C++ 制作解析器(这很方便,因为我需要在同一个项目中对 C++ 代码使用相同的解析器语法),或者使用 flex/bison 或ANTLR。所以问题实际上是如何在 Julia 中从 C++ 解析器构建 AST。我有一些解决这个问题的想法:

  1. 在 Julia 中有一堆 C++ 代码可以调用的回调(例如,代数表达式的推送文字/添加等)并且 Julia 管理 AST 节点的分配。或者可能只是调用Symbol()Expr() 等等,以及针对特定于问题的结构的更专门的回调。即使我对 Julia 很陌生,我想我也可以做到。
  2. 让 C++ 解析器生成一个普通结构的 AST,Julia 代码可以遍历该 AST 以构建等效的 Julia 结构。有点混乱的解决方案,但也许吧。
  3. 让 C++ 代码直接分配并返回 Julia AST,如果可能的话,我认为这相当于 jl_type_t 和朋友的 AST。最大的问题是如何构建这样的结构。除了 .h 文件之外,我没有找到任何文档,这些文件的注释不是很好。而且我也怀疑在 C++ 代码中分配的内存是否可以在 Julia 中释放(垃圾收集),我想知道您如何解决这个问题。

【问题讨论】:

  • 也许更多细节会有所帮助。如果 C 函数也可以调用 Julia 函数,那么您不能通过在 C 函数中调用 Expr() 函数来创建 Julia Expr 吗?这不是解决方案吗?
  • @Hckr 是的,也许,看看问题的编辑。

标签: c julia


【解决方案1】:

回答我自己的问题,我认为采用问题中所述的策略 ​​1 是解决此问题的最简单和最有效的方法。策略 2 是可能的,但这涉及在 C 和 Julia 中使用镜像 AST,这使得解决方案更难维护。策略 3,如果可能的话,需要深入了解 Julia 类型系统如何在底层工作,并且基本上相当于从 Julia C 源代码中复制功能。

我的解决方案的唯一(次要)麻烦是我无法使用@cfunction 获得指向可变参数Expr 的指针。因此,在代数表达式的上下文中,例如,您将需要单独的函数指针来构造一元和二元运算。如果有人在这方面取得了更大的成功,请告诉我。

代码

expr.c

// struct to gather neccessary callbacks
typedef struct {
  void* (*symbol_callback)(char const *); // Symbol(Cstring)
  void* (*int_callback)(int); // Int(Int) - boxing an int
  void* (*expr4_callback)(void *, void*, void*, void*); // Expr for binary op
} callbacks;

void *expr(callbacks *c) {
  return c->expr4_callback(
    c->symbol_callback("call"),
    c->symbol_callback("+"),
    c->symbol_callback("x"),
    c->int_callback(2)
  );
}

生成文件

CC=gcc

CFLAGS=-c -Wall -fPIC

SOURCES=expr.c
OBJECTS=$(SOURCES:.c=.o)

.c.o:
    $(CC) $(CFLAGS) $< -o $@

lib: $(OBJECTS)
    $(CC) -shared -fPIC -o libexpr.so $(OBJECTS)

clean:
    rm *.o *.so

Test.jl

# define a proxy function for Symbol(::String) that does the conversion from
# a C byte string
symbol_proxy(name::Ptr{UInt8})::Symbol = Symbol(unsafe_string(name))

struct Callbacks
    # pointer to Symbol(::String) proxy
    symbol::Ptr{Nothing}
    # pointer to Int(::Int) function
    int64::Ptr{Nothing}
    # pointer to Expr() function with four arguments (for binary op)
    expr4::Ptr{Nothing}
end

# get callbacks
c = Callbacks(
    @cfunction(symbol_proxy, Ref{Symbol}, (Ptr{UInt8},)),
    @cfunction(Int, Ref{Int64}, (Cint,)),
    @cfunction(Expr, Ref{Expr}, (Any,Any,Any,Any))
)

# call shared library to construct :(x+2)
e = ccall((:expr, "./libexpr"), Ref{Expr}, (Ref{Callbacks},), c)
dump(e)

输出

使用make lib 编译共享库并运行Test.jl 会产生输出

Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol +
    2: Symbol x
    3: Int64 2

【讨论】:

    猜你喜欢
    • 2015-07-08
    • 1970-01-01
    • 2019-09-03
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 1970-01-01
    相关资源
    最近更新 更多