Przeglądaj źródła

feat: 调用C函数允许传递int类型的参数

link #9
SongZihuan 4 lat temu
rodzic
commit
f7f0c45277

+ 21 - 0
VirtulMathCore/include/parameter.h

@@ -51,9 +51,23 @@ struct ArgumentParser{
     int c_count;
 };
 
+// 该结构体为数组形式, 因此不需要make函数(即不存在于堆中)
+// 但其成员arg等为不确定长度的数组,因此需要memCalloc申请内存, 并且释放
+struct ArgumentFFI {
+    ffi_type **arg;  // arg的类型
+    void **arg_v;  // arg的真实数值
+    enum ArgumentFFIType{
+        af_int,
+        af_double,
+        af_str,
+    } *type;  // 数据类型 (决定如何释放arg_v)
+    unsigned int size;  // 数组长度
+};
+
 typedef struct Parameter Parameter;
 typedef struct Argument Argument;
 typedef struct ArgumentParser ArgumentParser;
+typedef struct ArgumentFFI ArgumentFFI;
 
 Argument *makeArgument(void);
 Argument *makeValueArgument(LinkValue *value);
@@ -101,4 +115,11 @@ Argument *parserArgumentValueCore(Argument *arg, ArgumentParser *ap);
 ArgumentParser *parserArgumentNameDefault(ArgumentParser *ap);
 ArgumentParser *parserArgumentValueDefault(ArgumentParser *ap);
 int parserArgumentVar(ArgumentParser *ap, Inter *inter, VarList *var_list);
+
+void setArgumentFFICore(ArgumentFFI *af);
+void setArgumentFFI(ArgumentFFI *af, unsigned int size);
+void freeArgumentFFI(ArgumentFFI *af);
+
+unsigned int checkArgument(Argument *arg, enum ArgumentType type);
+bool setArgumentToFFI(ArgumentFFI *af, Argument *arg);
 #endif //VIRTUALMATH_PARAMETER_H

+ 63 - 0
VirtulMathCore/src/parameter.c

@@ -858,3 +858,66 @@ ArgumentParser *parserArgumentNameDefault(ArgumentParser *ap){
     }
     return ap;
 }
+
+void setArgumentFFICore(ArgumentFFI *af) {
+    af->type = NULL;
+    af->arg = NULL;
+    af->arg_v = NULL;
+    af->size = 0;
+}
+
+void setArgumentFFI(ArgumentFFI *af, unsigned int size) {
+    af->type = memCalloc((size_t)size, sizeof(enum ArgumentFFIType));
+    af->arg = memCalloc((size_t)size, sizeof(ffi_type *));
+    af->arg_v = memCalloc((size_t)size, sizeof(void *));
+    af->size = size;
+    memset(af->type, 0, (size_t)size);
+    memset(af->arg, 0, (size_t)size);
+    memset(af->arg_v, 0, (size_t)size);
+}
+
+void freeArgumentFFI(ArgumentFFI *af) {
+    for (unsigned int i=0; i < af->size; i++) {
+        switch (af->type[i]) {
+            case af_double:
+            case af_int:
+                memFree(af->arg_v[i]);
+                break;
+            default:
+                break;
+        }
+    }
+
+    memFree(af->type);
+    memFree(af->arg);
+    memFree(af->arg_v);
+}
+
+unsigned int checkArgument(Argument *arg, enum ArgumentType type) {
+    unsigned int count;
+    for (count = 0; arg != NULL; arg = arg->next, count ++) {
+        if (arg->type != type)
+            return -1;
+    }
+    return count;
+}
+
+bool setArgumentToFFI(ArgumentFFI *af, Argument *arg) {
+    for (unsigned int i=0; arg != NULL && i < af->size; arg = arg->next, i++) {
+        if (af->arg[i] == NULL) {
+            switch (arg->data.value->value->type) {
+                case V_int:
+                    af->arg[i] = &ffi_type_sint;  // af->arg是ffi_type **arg, 即*arg[]
+                    af->type[i] = af_int;
+
+                    af->arg_v[i] = (int *)memCalloc(1, sizeof(int));  // af->arg_v是ffi_type **arg_v, 即 *arg_v[]
+                    *(int *)(af->arg_v[i]) = (int)arg->data.value->value->data.int_.num;
+                    break;
+                default:
+                    return false;
+            }
+        } else
+            return false;
+    }
+    return arg == NULL ? true : false;
+}

+ 20 - 4
VirtulMathCore/src/runcall.c

@@ -260,14 +260,30 @@ static ResultType callCFunction(LinkValue *function_value, Argument *arg, long i
 
 static ResultType callFFunction(LinkValue *function_value, Argument *arg, long int line, char *file, int pt_sep, FUNC_NT){
     ffi_cif cif;
+    unsigned int size;
+    ArgumentFFI af;
     setResultCore(result);
-    gc_addTmpLink(&function_value->gc_status);
+    setArgumentFFICore(&af);
+    if (pt_sep != 0 || (size = checkArgument(arg, value_arg)) == -1) {
+        setResultError(E_ArgumentException, L"does not support key-value arguments", line, file, true, CNEXT_NT);
+        return R_error;
+    }
 
-    ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, &ffi_type_void, NULL);
-    ffi_call(&cif, function_value->value->data.function.ffunc,  NULL, NULL);
+    setArgumentFFI(&af, size);
+    if (!setArgumentToFFI(&af, arg)) {
+        setResultError(E_ArgumentException, L"parameter exception when calling C function", line, file, true, CNEXT_NT);
+        goto return_;
+    }
 
-    setResult(result, inter);
+    gc_addTmpLink(&function_value->gc_status);
+    ffi_prep_cif(&cif, FFI_DEFAULT_ABI, af.size, &ffi_type_void, af.arg);
+    ffi_call(&cif, function_value->value->data.function.ffunc,  NULL, af.arg_v);
     gc_freeTmpLink(&function_value->gc_status);
+
+    setResult(result, inter);
+
+    return_:
+    freeArgumentFFI(&af);
     return result->type;
 }