代码之家  ›  专栏  ›  技术社区  ›  Ingwie Phoenix

将Gravity(脚本语言)调用转换为本机C函数调用

  •  4
  • Ingwie Phoenix  · 技术社区  · 5 年前

    我目前正在研究如何实现一种从 Gravity 脚本语言。

    到目前为止,最简单的例子是:

    int add(int lhs, int rhs) {
      return lhs + rhs;
    }
    
    static void gravity_wrap_add(
      gravity_vm* vm,
      gravity_value_t* args, uint32_t nargs, 
      uint32_t retIndex, void* data
    ) {
      int lhs, rhs, rt;
    
      // Unwrap
      lhs = VALUE_AS_INT(args[1]);
      rhs = VALUE_AS_INT(args[2]);
    
      // Perform call, capture return
      rt = add(lhs, rhs);
    
      // Forward the return
      gravity_vm_setslot(vm, VALUE_FROM_INT(rt), retIndex);
    }
    

    使用C++(98)模板或C预处理器魔术,会有一种方法来生成包装器函数吗?

    上面包装函数的一个非常非常复杂的例子是:

    static void gravity_wrap_add(
      gravity_vm* vm,
      gravity_value_t* args, uint32_t nargs, 
      uint32_t retIndex, void* data
    ) {
      gravity_vm_setslot(vm, 
       VALUE_FROM_INT(
         add(VALUE_AS_INT(args[1]), VALUE_AS_INT(args[2]))
       ), 
      retIndex);
    }
    

    这个版本在技术上是我想要达到的,但是通过像预处理器或C++模板这样的方法。出于跨平台兼容性的原因,我想坚持C++ 98(因为MSVC对现代特性不太好)。

    1 回复  |  直到 5 年前
        1
  •  0
  •   Davis Herring    5 年前

    namespace gravity {
      template<class T> struct value {};
      // for brevity and deduction:
      template<class T> T get(const gravity_value_t &v)
      {return value<T>::get(v);}
      template<class T> gravity_value_t put(const T &t)
      {return value<T>::put(t);}
      template<> struct value<int> {
        int get(const gravity_value_t &v)
        {return VALUE_AS_INT(v);}
        gravity_value_t put(int i)
        {return VALUE_FROM_INT(i);}
      };
      // more specializations…
    
      template<class R,R f()>
      void wrap(gravity_vm* vm,
                gravity_value_t* args, uint32_t nargs, 
                uint32_t retIndex, void* data) {
        assert(nargs==0);
        gravity_vm_setslot(vm,put(f()),retIndex);
      }
      template<class R,class A,R f(A)>
      void wrap(gravity_vm* vm,
                gravity_value_t* args, uint32_t nargs, 
                uint32_t retIndex, void* data) {
        assert(nargs==1);
        gravity_vm_setslot(vm,put(f(get<A>(args[0]))),retIndex);
      }
      // more overloads with more arguments…
    
      /*gravity_register*/(wrap<int,int,int,add>);
    }
    

    像往常一样, void 返回类型将是一个痛苦;你得重复一遍 的参数计数重载 R 属于 无效

    可以使用演绎法,以避免在使用时重复签名 wrap ,但随后会得到更少的函数和额外的闭包对象来区分它们(您可以通过 data 参数)。