2

我开始使用mruby。我对 C 编程也很陌生,所以我可能不熟悉许多基础知识。我能够编译从字符串加载 ruby​​ 代码的示例 mruby 程序。现在我想从外部文件加载它。这是我正在使用的示例代码:

#include <stdlib.h>
#include <stdio.h>
#include <mruby.h>

static mrb_value my_c_method(mrb_state *mrb, mrb_value value)
{
  puts("Called my C method");
  return value;
}

int main(void)
{
  mrb_state *mrb = mrb_open();

  struct RClass *mymodule = mrb_define_module(mrb, "MyModule");
  mrb_define_class_method(mrb, mymodule, "my_c_method", my_c_method, MRB_ARGS_NONE());

  mrb_load_string(mrb, "MyModule.my_c_method"); // move this to an external file
  return 0;
}

正如您在上面的示例中看到的,我想将 ruby​​ 代码移动到外部文件中。对于是否可以简单地“包含”ruby 文件,或者是否需要将其预编译到文件中,我有点困惑.mrb。即使那样,我也不确定.mrb在编译时如何包含该文件。

我需要更改什么才能从外部文件加载 ruby​​ 代码?

4

2 回答 2

1

假设您的代码存储在 file 中foo,您只需打开文件并读取它。要打开文件,您需要fopen()在 stdio.h 中定义。然后,您可以使用fgets(). 我不熟悉 mruby,所以我不确定 mrb_load_string 是否期望每个 mruby 代码都在一行中。我会这样假设。以下是您的操作方法:

#define MAX_CODE_SIZE 128
FILE *code;
char code_buf[128]
code = fopen("foo", "r");
if (code == NULL) {
    /* File couldn't be opened, handle error case... */
}
fgets(code_buf, MAX_CODE_SIZE, code);
/* Do some work ... */

fclose(code); /* Don't forget to close the file */

这段代码读取 file 的第一行foo,最多 127 个字符(包括换行符),并将其存储在code_buf. 然后您可以致电mrb_load_string

mrb_load_string(mrb, code);

我不确定这是否是您想要的,我从未接触过 mruby,但从我所看到的情况来看,mrb_load_string期望 achar *带有代码,而您希望它来自文件。你就是这样做的。

如果要读取包含多行代码的文件,则别无选择,只能分配足够大的缓冲区并使用以下命令读取fread()

#include <stdio.h>
#define MAX_LINE_LENGTH 128
#define MAX_LINES 256
#define MAX_FILE_SIZE MAX_LINE_LENGTH*MAX_LINES

char code[MAX_FILE_SIZE];

int read_code(char *filepath) {
    FILE *fp = fopen(filepath, "r");
    if (fp == NULL)
        return 0;
    fread(code, 1, MAX_FILE_SIZE, fp);
    fclose(fp);
    return 1;
}

这个函数读取整个文件(假设它没有超出我们的缓冲区限制)。code是全局的,因为如果分配较大的局部变量,您可以轻松达到堆栈容量(另一种选择是使用动态分配)。调用read_code()时,应确保检查其返回值,以检查打开文件时可能出现的错误。此外,您可以使用fread()'s 返回值来了解缓冲区大小是否不足以读取所有内容。

只要确保完成后不要忘记关闭文件。

编辑:对于fgets()版本,请注意,如果该行少于 128 个字符,换行符将保留在code_buf. 如果是这种情况,您可能需要设置code_buf[strlen(code_buf)-1]'\0'

更新:

根据我们对以下评论的讨论,我正在使用基本解析器更新我的答案,以使您能够在编译时读取 ruby​​ 文件。基本上,解析器将读取您的 ruby​​ 文件并生成一个带有有效 C 代码的输出文件,该文件将文件的内容插入 char 数组中。特殊字符相应地被转义。这里是:

#include <stdio.h>

void inline insert(int, FILE *);

int main(int argc, char *argv[]) {
    FILE *out, *in;
    int c;
    if (argc != 3) {
        printf("Usage: %s <input_file> <output_file>\n", argv[0]);
        return 1;
    }

    in = fopen(argv[1], "r");
    out = fopen(argv[2], "w");

    if (out == NULL) {
        printf("Unable to create or write to %s\n", argv[1]);
        return 1;
    }

    if (in == NULL) {
        printf("Unable to read %s\n", argv[1]);
        return 1;
    }

    fputs("#ifndef MRUBY_CODE_FILE_GUARD\n", out);
    fputs("#define MRUBY_CODE_FILE_GUARD\n", out);
    fputs("char mruby_code[] = \"", out);
    while ((c = getc(in)) != EOF)
        insert(c, out);
    fputs("\";\n", out);
    fputs("#endif\n", out);
    fclose(in);
    fclose(out);
    return 0;
}

void inline insert(int c, FILE *fp) {
    switch (c) {
        case '\a':
            fputs("\\a", fp);
            break;
        case '\b':
            fputs("\\b", fp);
            break;
        case '\f':
            fputs("\\f", fp);
            break;
        case '\n':
            fputs("\\n", fp);
            break;
        case '\r':
            fputs("\\r", fp);
            break;
        case '\t':
            fputs("\\t", fp);
            break;
        case '\v':
            fputs("\\v", fp);
            break;
        case '\\':
            fputs("\\\\", fp);
            break;
        case '\'':
            fputs("\\'", fp);
            break;
        case '"':
            fputs("\\\"", fp);
            break;
        default:
            fputc(c, fp);
    }
}

现在,回到你原来的程序并在开头添加以下包含指令:

#include mruby_code.h

你必须执行以下步骤来编译一个可运行的程序,假设这个解析器被编译成一个名为的文件fileparser.c

  • 运行./fileparser /path/to/mruby_code_file /path/to/program/mruby_code.h
  • 编译你的原始程序(它将包括mruby_code.h

mruby 代码在一个名为mruby_code. 这是一个 char 数组,因此您可以将其传递给mrb_load_string. 瞧,您在编译时读取了一次mruby 文件。

于 2013-10-13T17:35:45.617 回答
1

在其中mruby/compile.h有一个名为的方法mrb_load_file,它允许您加载 ruby​​ 文件并使用 mruby 执行它:

#include <stdlib.h>
#include <stdio.h>

#include <mruby.h>
#include <mruby/compile.h>

static mrb_value my_c_method(mrb_state *mrb, mrb_value value)
{
  puts("Called my C method");
  return value;
}

int main(void)
{
  mrb_state *mrb = mrb_open();

  struct RClass *mymodule = mrb_define_module(mrb, "MyModule");
  mrb_define_class_method(mrb, mymodule, "my_c_method", my_c_method, MRB_ARGS_NONE());

  FILE *f = fopen("example.rb", "r");
  mrb_load_file(mrb, f);

  return 0;
}
于 2013-10-14T05:42:39.657 回答