您应该如何从Julia的Expr
调用的C函数中构造并返回Julia :(x + 2)
,例如ccall
,以便使其能够被Julia进行垃圾回收? / p>
编辑:
建议进行编辑,并附上一些其他详细信息。首先,问题不是一口气生成Expr
,而是评估者能够逐步构造任意Expr
等,请参见下文。
我需要一个Julia的项目解析器。解析器输入的内容部分是代数表达式,最后我想使用等效的Julia Expr
。由于似乎没有带有Julia目标的解析器生成器,我在考虑使用C ++生成解析器(这很方便,因为无论如何我都需要在同一项目中为C ++代码使用相同的解析器语法),或者使用flex / bison或ANTLR。因此,问题实际上是如何从C ++解析器在Julia中构建AST。我有一些解决方案:
Symbol()
,Expr()
等,再加上针对该问题的特定结构的更专业的回调。即使我对朱莉娅(Julia)非常陌生,我也认为可以实现目标。jl_type_t
和朋友。最大的问题是如何构造这样的结构。除了.h文件,我没有找到任何文档,它们的注释不那么好。而且我也怀疑在Julia中是否可以释放C ++代码中分配的内存(收集垃圾),我想知道如何解决这个问题。答案 0 :(得分:0)
回答我自己的问题,我认为按照问题中所述的策略1进行解决是最简单,最有效的方法。策略2是可行的,但是涉及在C和Julia中镜像AST,这使解决方案更难维护。策略3,即使有可能,也需要深入了解Julia类型系统在幕后的工作方式,本质上等同于从Julia C源代码复制功能。
我的解决方案唯一(次要)的麻烦是,我无法使用Expr
来获取指向vararg @cfunction
的指针。因此,在代数表达式的上下文中,例如,您将需要单独的函数指针来构造一元和二进制运算。如果有人在此方面获得更多成功,请告诉我。
// 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
# 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