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

には、ruby ファイルを読み込んで mruby で実行できるmruby/compile.hメソッドがあります。mrb_load_file

#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 に答える
1

コードが file に保存されていると仮定するとfoo、ファイルを開いて読み取るだけで済みます。fopen()ファイルを開くには、stdio.h で定義されている が必要です。その後、 を使用して行ごとに読み取ることができますfgets()。私は mruby に詳しくないので、mrb_load_string がすべての mruby コードが 1 行にあることを期待しているかどうかは正確にはわかりません。そう仮定します。方法は次のとおりです。

#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ありchar *ません. それがあなたのやり方です。

複数行のコードを含むファイルを読みたい場合は、十分な大きさのバッファを割り当てて、以下を使用して読み取るしかありません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()の戻り値をいじって、バッファ サイズがすべてを読み取るのに十分でなかったかどうかを知ることができます。

完了したら、ファイルを閉じるのを忘れないようにしてください。

編集:バージョンについてはfgets()、行が 128 文字未満の場合、改行が に保持されることに注意してくださいcode_bufcode_buf[strlen(code_buf)-1]その場合は に設定するとよいでしょう'\0'

アップデート:

以下のコメントに関する議論から、コンパイル時に Ruby ファイルを読み取れるように、初歩的なパーサーで回答を更新しています。基本的に、パーサーは Ruby ファイルを読み取り、ファイルの内容を char 配列に挿入する有効な C コードを含む出力ファイルを生成します。したがって、特殊文字はエスケープされます。ここにあります:

#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 ディレクティブを追加します。

#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 ファイルはコンパイル時に1 回読み込まれました。

于 2013-10-13T17:35:45.617 に答える