简体   繁体   English

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

[英]Guile Scheme - How to pass C struct value back to Guile for scripting

I'm writing a program/game where I use Guile for scripting on top of a C program.我正在编写一个程序/游戏,我使用 Guile 在 C 程序之上编写脚本。 For example I have a command struct type(which is also used for move_to) in C and corresponding move_to wrapper function to to create move_to commands in Guile.例如,我在 C 中有一个命令结构类型(也用于 move_to)和相应的move_to包装器 function 以在 Guile 中创建 move_to 命令。 In the UI an input line can be entered and is then executed in Guile.在 UI 中,可以输入一行输入,然后在 Guile 中执行。

For move_to it look like this in C: Some entity id is passed here as a SCM value, same for the new the position and SCM value is passed for x and the same for y.对于move_to ,它在 C 中看起来像这样:一些实体 ID 作为 SCM 值传递到这里,对于新的 position 和 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;
    }

In this code the entity is searched in some entity list and if it exist, we create a new move_to_command and add it to the command list of the entity.在此代码中,在某个实体列表中搜索实体,如果存在,我们创建一个新的move_to_command并将其添加到实体的命令列表中。

In the UI then eg (move_to 0 100 100) can be entered and is then executed.然后在 UI 中输入(move_to 0 100 100)然后执行。

It's straightforward when creating a C function and wrapper when the function just returns an integer or nothing at all.当创建 C function 和包装器时,当 function 仅返回 integer 或根本不返回任何内容时,这很简单。 But I'm not sure how to implement a function which returns a (C-/Guile-) struct value to Guile.但是我不确定如何实现一个 function,它将 (C-/Guile-) 结构值返回给 Guile。

Let's say we have this struct type in C:假设我们在 C 中有这个结构类型:

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

How would I go to create a Guile struct value from this C struct which is returned when when for example some Guile function - like 'get-next-event' (which I have to write) is called.我 go 如何从这个 C 结构创建一个 Guile 结构值,例如当调用一些 Guile function 时返回的结构值 - 比如'get-next-event' (我必须写)。 It would now also be OK if I had to copy the value from the C struct to a new Guile struct over.如果我必须将值从 C 结构复制到新的 Guile 结构,现在也可以。

Saw that there is the function scm_make_struct(SCM vtable, SCM tail_size, SCM init_list) , but I am not sure how to create a vtable value which to pass here as a first argument.看到有 function scm_make_struct(SCM vtable, SCM tail_size, SCM init_list) ,但我不确定如何创建一个 vtable 值作为第一个参数传递到这里。

I think older guile versions there was scm_make_vtable_vtable .我认为旧的 guile 版本有scm_make_vtable_vtable Also I tried the C-function scm_struct_vtable from the current version.我还尝试了当前版本的 C 函数scm_struct_vtable

ADDENDUM:附录:

  • found a function to create a vtable in the file struct.h, which is not documented: SCM_API SCM scm_make_vtable (SCM fields, SCM printer);找到一个function在文件struct.h中创建一个vtable,没有记录: SCM_API SCM scm_make_vtable (SCM fields, SCM printer);

Source Code Example:源代码示例:

#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 */
}

Which can be compiled with this line for example: gcc -o main -I/usr/include/guile/3.0 -lguile-3.0 main.c可以用这一行编译,例如:gcc -o main -I/usr/include/guile/3.0 -lguile-3.0 main.c

Example output:示例 output:

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

Thank you for any help and suggestions, Rael感谢您的任何帮助和建议,雷尔

To use and export C structs to Guile, one could do it like this - the example code is from here: https://github.com/agentlans/guile-foreign-example/blob/master/bessel.c要使用 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM