c++ - 脚本引擎 - 调用 "unknown"函数

标签 c++ c

我想创建脚本引擎,但发现了奇怪的问题。 首先我解释一下它(可能)如何工作: 脚本引擎 (DLL) 将独立于将使用的应用程序。 SE 将导出两个函数(像这样,可能有点不同):

// This will be called on beginning of host program, register set of functions, that
// script will provide to usere
SetFunc(void *func,byte code,char *descript);
  func     : pointer to existing function from host application (e.g. printf)
  code     : code for script compiler
  descript : func description, if eventually needed

// function calling functions inc Script Engine (in compiled DLL, which can't be 
// modified for host application, only input for SE is SetFunc
CallFunc(void *instr);
  instr : pointer to memory block, in which is stored 
          (instr_code - byte)(void* - pointer to func)(params_len - unsigned int)(params - data block)
                                   /\--- this will be filled after loading script to SE, according to table of registred functions (via Setfunc).

Callfunc(void *func,void *params,unsigned int param_length);
  func         : pointer to function
  params       : parameters for function in memory block (extracted from instr)
  param_length : what to say :o)

主程序示例:

#include "ScriptEngine.h"  // this will create connection to SE DLL

float add(double num1,double num2)
{
  return (num1+num2);
}

int main()
{
  SetFunc(add,1,"f:d,d/2");            // register one function to SE
  LoadScript("simple.sc","simple");    // load script to memory
  ExecuteScript("simple");             // execute script (only add two nums)
}

和脚本:

main()
{     
  add(3.45,8.87);
}

// after some compilation to binary format :
...
(1)(NULL)(16)(3.45)(8.87)  (instruction for "system call" (registred via SetFunc)
...

// after LoadScript
(1)(0x00402cc)(16)(3.45)(8.87)

并在 ExecuteScript 上调用内部 DLL 函数 CallFunc 并在其输入上设置来自 instr 的参数。

如何在这个环境中从指针调用函数并设置参数?我可以通过这种方式创建这个,或者有人有其他想法,如何做到这一点?

感谢您的所有回答:o)

最佳答案

一种不同的、更简单的方法:将脚本编译为基于堆栈的虚拟机的指令。所有 native 函数都应该遵循统一的签名,以便我们可以使用单个函数指针 typedef 来调用它们。例如,以下是我们如何实现并向脚本引擎公开 add 函数:

// Common type for all native functions.
typedef void(*NativeFuncPtr)(VM*);

// The Virtual Machine is wrapped in a `VM` object.
// popDouble() and pushDouble() make use of the more primitive
// stack operations push() and pop().

void add(Vm* vm)
{        
    double a = vm->popDouble();
    double b = vm->popDouble();
    vm->pushDouble(a + b); // leave the result on the VM stack.
} 

// The call to setFunc will map the string "add" to the address of the
// `add()` function in a hashtable.
vm->setFunc("add", &add);

现在让我们看看将 add(3.45,8.87); 编译为 VM 字节码的一种可能方法:

pushDouble 8.87
pushDouble 3.45    
call add

这是虚拟机执行这些指令的方式:

  1. 将 8.87 推送到数据堆栈上。
  2. 将 3.45 推送到数据堆栈上。
  3. 在本地函数字典中搜索名为“add”的函数。如果在那里找不到,则在原始函数表中查找。

虚拟机在 native 函数表中找到“add”并调用它:

NativeFuncPtr fptr = nativeFunctions["add"];
(*fptr)(this);

函数完成执行后,VM 将在数据堆栈上显示结果 - 12.32

这是一个非常简单的解释。在实际实现中,数据堆栈可能只能保存机器字大小的整数。所以它实际上包含double值的地址。像 popDouble 这样的函数应该对 native 函数实现者隐藏这些细节。

关于c++ - 脚本引擎 - 调用 "unknown"函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4722936/

相关文章:

将 TAB 连接到 gtkEntry

c++ - 模板和显式特化

c++ - Linux 的 COleDateTime 替代品

c++ - 在不转移所有权的情况下返回 unique_ptr 私有(private)成员数据

c++ - 可选参数 const 引用重新分配

c++ - 更改 C++ 程序入口点。 STL 崩溃

c - 使用 malloc() 和 free() 的程序崩溃

c - 在内存中有数据库 - C

c++ - C 中的逻辑运算符和位操作

c - 如何初始化作为结构成员的字符串数组?