Guile Scheme -如何将C结构值传递回Guile进行脚本编写

yc0p9oo0  于 2023-01-25  发布在  其他
关注(0)|答案(1)|浏览(125)

我正在写一个程序/游戏,我使用Guile在C程序上编写脚本。例如,我在C中有一个命令结构类型(也用于move_to)和相应的move_to Package 函数,以在Guile中创建move_to命令。在UI中,可以输入一行输入,然后在Guile中执行。
对于move_to,它在C语言中如下所示:一些实体id在这里作为SCM值传递,对于新的位置也是如此,SCM值传递给x,传递给y。

static SCM move_to(SCM scm_id, SCM x, SCM y) {

        unsigned int id = scm_to_int(scm_id);
        float new_x = scm_to_double(x);
        float new_y = scm_to_double(y);

        // Search for entity 
       int index = -1;
       for (int i = 0; i < gs.entities.size(); i++) {

           if (get_id(&(gs.entities[i])) == id) { index = i; break; }
       }

      command c = {new_x,new_y,MOVETO,0};

      // Add move command to entity if one was found
      if (index != -1) { printf("found index\n");add_command(&(gs.entities[index]), c); }

      return SCM_UNSPECIFIED;
    }

在这段代码中,实体在实体列表中搜索,如果存在,我们创建一个新的move_to_command并将其添加到实体的命令列表中。
在UI中,可以输入(move_to 0 100 100),然后执行。
当函数只返回一个整数或者什么都不返回时,创建一个C函数和 Package 器是很简单的,但是我不确定如何实现一个向Guile返回(C -/Guile-)结构值的函数。
假设我们在C语言中有这样的结构类型:

typedef struct {
  unsigned int id;
  event_type type;
  unsigned int entity_id;
  unsigned int by_entity;
} event;

我如何从这个C结构体创建一个Guile结构体值,这个C结构体值是在调用一些Guile函数时返回的,比如'get-next-event'(我必须写),现在如果我必须把这个值从C结构体复制到一个新的Guile结构体中,也是可以的。
看到有函数scm_make_struct(SCM vtable, SCM tail_size, SCM init_list),但我不知道如何创建一个vtable值,将其作为第一个参数传递到这里。
我认为旧的guile版本是scm_make_vtable_vtable。我也尝试了当前版本的C函数scm_struct_vtable
附录:

  • 在文件struct. h中找到一个创建vtable的函数,但未记录:SCM_API SCM scm_make_vtable (SCM fields, SCM printer);

源代码示例:

#include "libguile.h"

static SCM give_me_100(void) {

  return scm_from_int(100);
}

static SCM give_me_a_struct(void) {

  SCM fields = scm_from_locale_string("pwpw");
  SCM vtable = scm_make_vtable(fields,0);

  SCM mystruct = scm_c_make_struct(vtable,0, 10, 20,  SCM_UNDEFINED);                                                                                             //

  return mystruct;

}

static void inner_main(void *closure, int argc, char **argv) {

    /* preparation - make C functions callable from Guile */
    scm_c_define_gsubr("give-me-100", 0, 0, 0, &give_me_100);
    scm_c_define_gsubr("give-me-a-struct", 0, 0, 0, &give_me_a_struct);

    scm_shell(argc, argv);
    /* after exit */
}

int main(int argc, char **argv) {

    scm_boot_guile(argc, argv, inner_main, 0);
    return 0; /* never reached, see inner_main */
}

例如,可以使用以下代码行进行编译:gcc-o主文件-I/用户名/包含/文件夹/3.0-文件夹-3.0主文件. c
输出示例:

GNU Guile 3.0.8
Copyright (C) 1995-2021 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (give-me-100)
$1 = 100
scheme@(guile-user)> (give-me-a-struct)
$2 = zsh: segmentation fault (core dumped)  ./main

谢谢你的任何帮助和建议,雷尔

5tmbdcev

5tmbdcev1#

要使用C结构体并将其导出到Guile,可以这样做-示例代码来自以下内容:https://github.com/agentlans/guile-foreign-example/blob/master/bessel.c

#include <math.h>
#include <libguile.h>

// Returns value of j0 Bessel function. This will be called from Guile Scheme.
SCM
j0_wrapper (SCM x)
{
    return scm_from_double (j0 (scm_to_double (x)));
}

// A C struct that can hold any Guile Scheme object
struct foo
{
    SCM x;
};

// Represents the foo type in Scheme
static SCM foo_type;

// Declarations needed for foo structs to be usable in Scheme
void init_foo_type()
{
    SCM name = scm_from_utf8_symbol("foo");
    SCM slots = scm_list_1(scm_from_utf8_symbol("x"));
    foo_type = scm_make_foreign_object_type(name, slots, NULL); // NULL finalizer
}

// Creates a new foo struct containing the given Scheme object
SCM make_foo(SCM obj)
{
    struct foo *foo_obj = scm_gc_malloc(sizeof(struct foo), "foo");
    foo_obj->x = obj;
    return scm_make_foreign_object_1(foo_type, foo_obj);
}

// Returns the Scheme object inside the foo struct
SCM get_foo(SCM foo_obj)
{
    scm_assert_foreign_object_type(foo_type, foo_obj);
    return ((struct foo *) scm_foreign_object_ref(foo_obj, 0))->x;
}

// Initializes the functions exposed in this Guile extension
void
init_bessel ()
{
    scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper);

    init_foo_type();
    scm_c_define_gsubr("make-foo", 1, 0, 0, make_foo);
    scm_c_define_gsubr("get-foo", 1, 0, 0, get_foo);
}

相关问题