UCScript——C++集成脚本

使用UCScript作脚本,主要是因为它几个特点很适合用于集成(脚本引擎体积小,占用资源少,运行快,跨平台跨语言,与宿主语言交互方便),而且它的语法类C语言,不用去多学一门语言。在C++中集成UCScript脚本是轻而易举的事。我们接下来用实例来说明,如何把UCScript脚本集成到你的程序中去。

1. 创建UCScript引擎

    ucScript ucs; 或者 ucScript* ucs= new ucScript;

创建一个ucScript对象,就是创建一个UCScript脚本引擎。可以创建任意多个脚本引擎,甚至可以分布在不同的线程当中。

注意:指定合适的预定义,Windows用_UC_WIN,Linux用_UC_LINUX(即编译参数-D_UC_LINUX)。如果以动态库的形式使用脚本,还得指定_UC_IMPORT。

2. 执行脚本程序 你可以从缓冲区中装载脚本,也可以直接解析文件:

    const char * szCode="ret 1+2*3;";
    ucScript ucs;
    ucCalcVar vRet= ucs.Parse(szCode);
    assert(vRet.value.iVal == 7);

如果你想对你的源代码进行保护而不是赤裸裸的袒露在大家的眼前,或者提高脚本性能,你可以把脚本编译成二进制中间码。

3. 如何让脚本调用C++的函数。比如让脚本以string: get_peername(int: id)的形式调用我的C++代码,代码可以写成:

UCSFUNC3(get_peername,CVT_STRING, "get peer name by peer id",
        CVT_INTEGER,"puid",
        CVT_STRING,"def=/"unknown/"",
        1)
{
    int puid;
    //  get an integer value from the first parameter
    ucAdaptCVT::cvt2out(params[0], puid);

    CPeer * p=CPeerMgr::Instance().GetPeer(puid);
    if(p) {
        return p->m_PeerInfo.name;  //  return the string of name
    }
    const char * def="unknown";
    if(count>1) {
        ucAdaptCVT::cvt2out(params[1], def);  //  get default name specified by parameter
    }
    return def;
}

上面代码用了UCSFUNC(xxx) 辅助宏,定义在ucScriptFunc.h头文件。其中xxx表示脚本变量类型个数(即返回值和参数的个数)。上例的宏参数分别表示:

get_peername函数名字
CVT_STRING函数返回值的类型为string
函数的提示信息在脚本集成开发环境ucDev可以看到
CVT_INTEGER第一个参数,类型为integer
参数的提示信息用在ucDev
CVT_STRING第二个参数,类型string
参数提示信息用在ucDev
1有 1 个参数有默认值,即最后一个参数

脚本调用如下:

string: strName;

strName = get_peername(12);  //  Kevin's ID is 12, so strName = "Kevin"
strName = get_peername(-1);  //  none, strName = "unknown"
strName = get_peername(-1, "no user");  //  none, strName = "no user"

最让我激动的是,该脚本把非标准类型的变量全部当作object类型,也就是说任何C++类型都可以接受。下面例子演示如何传递和返回非基本类型的变量。

UCSFUNC2(get_parentwnd, CVT_OBJECT, "get a parent window",
       CVT_OBJECT,"wnd",
        0)
{
    ucCalcVar vRet(CVT_OBJECT);
    CWnd * pWnd=NULL;
    //  get CWnd from parameter
    ucAdaptCVT::cvt2out(params[0], pWnd);

    if(pWnd && ::IsWindow(pWnd->GetSafeHwnd()) )
    {
        ucAdaptCVT::out2cvt(pWnd->GetParent(), vRet);
    }
    return vRet;
}

4. 结束语

UCScript是一种面向集成的脚本语言,上面例子是针对C++语言,还支持的其他语言有C#(.Net),Java,Delphi,Visual Basic等等。脚本开发工具可以从http://www.ucscript.com/view_download.asp?id=3下载。初学者可以从http://www.ucscript.com/download.asp下载脚本用户手册。

(上文转自http://blog.csdn.net/amken/article/details/1491877)


不同语言之间相互调用函数,这是很普遍的现象,尤其是多种语言并存开发的大项目。一般解决方案是,其中一种通过动态链接库或者COM组件暴露接口,而另一种语言去调用。


脚本语言调用其它语言,则是通过支持库或者脚本自身支持。就拿VBScript来说,可以通过实现IDispatch接口,脚本创建自动化对象来调用。各种脚本语言都有各自的方式来实现。UCScript是面向集成的脚本语言,这方面跟其它语言来比,更显简练和高效的优势。下面分别从普通函数、类成员函数这两方面介绍UCScript如何调用C++语言的函数。

1. 普通函数
在C++一提到函数调用,不得不提到的是调用约定(calling convention)。最常用的有__stdcall,__cdecl,__fastcall等几种方式。


__stdcall是Windows API函数使用的规范,由被调用函数负责参数从堆栈移走,生成的代码比__cdecl小。this指针压入堆栈。以“?”标识函数名的开始,后跟函数名; 函数名后面以“@@YG”标识参数表的开始,后跟参数表; 参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前。


__cdecl调用约定是C/C++默认的调用规范,由调用函数负责参数从堆栈移走,有利于参数个数可变。this指针压入堆栈。对于传送参数的栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。 __cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。


__fastcall规则同上面的__stdcall调用约定,它的主要特点就是快,因为它是通过寄存器来传送参数的,即用ECX和EDX传送前两个参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈),在函数名修饰约定方面,它和前两者均不同。UCScript不支持这种调用的函数。


__stdcall和__cdecl的最大区别就是用来传递参数的堆栈空间的清除。UCScript底层屏蔽这个差异,也就是说不管是哪一种方式,对UCScript都是一样的。用户不必关心这些细节,可以降低用户使用复杂度。


int __cdecl strtoint(std::string str) {
printf("strtoint: str=%s\n", str.c_str());
return atol(str.c_str());
}


要让脚本调用这个C语言的函数,只需如下的一行语句即可


BIND_UCSFUNC2(strtoint, strtoint, CVT_INTEGER, "convert string to int", (std::string*)CVT_OBJECT, "str");


下面分析上面各个参数的含义。


BIND_UCSFUNC2 该函数有2个脚本类别(Script Type),返回值和一个参数
strtoint 脚本可以调用到的函数名字,不必跟C++语言函数相同名字
strtoint C++语言的函数名字
CVT_INTEGER 函数返回值是Integer
"convert string to int" 函数说明,在ucDev编程可以看到该提示
(std::string*)CVT_OBJECT 参数是Object,并且转换为std::string类型
"str" 参数说明,在ucDev编程可以看到该提示

2. 类成员函数
类成员函数可以分成两类。一类是this指针通过ECX寄存器来传递;另一类是this指针通过参数传递。UCScript的辅助宏通过参数来区别这种区别。如下例:


class CMyClass {
public:
CMyClass() { m_id = 100; }
int GetId() {
printf("CMyClass::GetId, id=%d\n", m_id);
return m_id;
}
void SetId(int id) {
printf("CMyClass::SetId, id=%d\n", id); m_id = id;
}
int m_id;
};


要让脚本调用到上面的GetId函数,只需下面语句


BIND_UCSFUNC_CM1(get_id, CMyClass, CMyClass::GetId, 1, CVT_INTEGER,"get id from a object");


上面的第4个参数指定this指针的传递方式:1表示标准方式,也就是this通过ECX寄存器传递;0是非标准方式,this通过参数传递。


当然,要调用这个函数还得传入一个对象,这个对象可以是其它函数的返回值或者用BIND_UCS_GLOBALVAR绑定的全局对象。比如脚本的代码可能如下:


object: obj;
// get obj by any way
... ...
int: id=get_id(obj);

3. 结束语
UCScript作为一种面向集成的脚本语言,在调用C++语言有自己独特的方式。总结一下有如下特点:
可以传递任意C++类型,如上例的std::string类
封装调用约定(calling convention)的差异
支持类成员函数调用
简单方便,一行声明语句即可

转载于:https://www.cnblogs.com/zcwsmile/p/4027809.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432542.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python经纬度转换xy坐标公式 pyqt_EXCEL公式进行经纬度与XY坐标的相互转换

一、用EXCEL进行高斯投影换算从经纬度B、L换算到高斯平面直角坐标X、Y(高斯投影正算),或从X、Y换算成B、L(高斯投影反算),一般需要专用计算机软件完成。在目前流行的换算软件中不足之处,就是灵活性较差,大都需要一个点一个点地进行…

display:inline-block之用法

HTML的元素有多种display属性&#xff0c;比较常见的有display:none; display:block; display:inline和display:inline-block;等。详细可参阅 W3Schools文档。有些HTML元素自然地带有display:block;样式属性&#xff0c;比如<div><h1>...<h6><p><ul…

java桥_JAVA 桥模式

桥梁模式的用意是“将抽象化(Abstraction)与实现化(Implementation)脱耦&#xff0c;使得二者可以独立地变化”。这句话很短&#xff0c;但是第一次读到这句话的人很可能都会思考良久而不解其意。这句话有三个关键词&#xff0c;也就是抽象化、实现化和脱耦。理解这三个词所代表…

display:inline display:block

display:inline; 元素会被显示为内联元素&#xff0c;元素前后没有换行符. display:block 元素将显示为块级元素&#xff0c;此元素前后会带有换行符. 举例&#xff1a; 1.display:block <span style"display:block">11111111</span><span>2222…

java utf8 byte_byte以及UTF-8的转码规则

https://www.cnblogs.com/hell8088/p/9184336.html多年来闲麻烦&#xff0c;只记录笔记&#xff0c;不曾编写BLOG&#xff0c;本文为原创&#xff0c;如需转载请标明出处废话不说&#xff0c;直奔主题ascii计算机只接受 “高”、“低”电压&#xff0c;所以使用二进制 1 和 …

Unreal4(虚幻4抽茧剥丝)——02章格式化C++和蓝图

本章先写个占位符&#xff0c;原因是具体内容正在构思&#xff0c;希望不和网上已有文章内容出现雷同尽量让读者接受新的知识转载于:https://www.cnblogs.com/hiroshiryu/p/3764013.html

jni c call java_Java通过-jni调用c语言

(4)生成的TestJNI.h文件如下&#xff1a;/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class TestJNI */#ifndef _Included_TestJNI#define _Included_TestJNI#ifdef __cplusplusextern "C" {#endif/** Class: TestJNI* Method…

OpenSceneGraph 笔记–如何导出三角形数据

在OpenSceneGraph开发中&#xff0c;为了方便会经常使用到一些不是三角形片的数据&#xff0c;比如四边形等数据。例如画一个管子用四边形带比用三角形片好计算得多。比如现在我们要画一个由两个平面组成的面&#xff0c;我可以这样做&#xff1a; osg::Geode*geodenewosg::Geo…

自由与限制

#自由与限制##自由 前端&#xff0c;包括html-css-javascript三大基础技术&#xff0c;都是非常能体验出开放自由的。具体说来&#xff0c;因为这三大技术都是以标准先行&#xff0c;html-css的标准由w3c组织制定&#xff0c;js的标准由ECMA制定&#xff0c;都是只有标准&#…

理解GL_TRIANGLE_STRIP等绘制三角形序列的三种方式

GL_TRIANGLE_STRIP绘制三角形方式很多时候令人疑惑&#xff0c;在这里对其运作机理进行解释。 一般情况下有三种绘制一系列三角形的方式&#xff0c;分别是GL_TRIANGLES、GL_TRIANGLE_STRIP和GL_TRIANGLE_FAN。 如下图所示&#xff1a; GL_TRIANGLES是以每三个顶点绘制一个三…

Swift的笔记和参考

好久没来了&#xff0c;趁着新语言Swift发布&#xff0c;继续钻研中&#xff01; Create Class 创建类 &#xff08;重载效果&#xff09; // Create Class 创建类 class MyClass {// Properties 成员变量init() {// Constructor 构造函数}// Method 成员方法func doIt() {prin…

java正则过滤js_JS/Java正则表达式验证

校验密码&#xff1a;6-15位var pwdreg /^[0-9A-Za-z_,.!#$%^*]{6,15}$/;pwdreg.test(phonenum)校验手机号var mobilereg /^0?1[3|4|5|7|8][0-9]\d{8}$/;mobilereg.test(phonenum)只能输入数字(年龄大小)只能输入中文、英文、数字、空格(微信中&#xff0c;关键字&#xff0…

UE4中的字符串转换

虚幻4学习---UE4中的字符串转换(文章来自于UE4官方文档) String Conversions: FString To FName FString To Int32 Float To FString FArrayReaderPtr To FString TArray<uint8> To FString FString To char * --- ( TCHAR_TO_ANSI() ) FString To TCHAR * FString …

DeDeCMS后台批量修改替换sql语句大全

有时候后台文章内容、标题或者锚文本出错&#xff0c;需要修改批量修改&#xff0c;那么就需要用dedecms的sql语句进行批量修改了。 利用dedecms后台SQL命令行工具批量修改内容&#xff0c;路径和超链接等信息。语句 DEDECMS SQL命令批量替换1.更改文章中的内容update dede_add…

jpa mysql乐观锁_【快学springboot】8.JPA乐观锁OptimisticLocking

介绍当涉及到企业应用程序时&#xff0c;正确地管理对数据库的并发访问是至关重要的。为此&#xff0c;我们可以使用Java Persistence API提供的乐观锁定机制。它导致在同一时间对同一数据进行多次更新不会相互干扰。为了使用OptimisticLocking&#xff0c;我们需要一个实体(En…

UE4 连接自定义服务器

UE4 dedicated server是一个很好的游戏服务器,但是对于大厅和聊天服务器来说,我们要自行开发,通过UE4的socket组建很方便的和其他服务器建立连接 创建Socket FSocket* Socket ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("de…

学习笔记-java编程-交通灯管理器设计流程。

先抛出需求&#xff1a; 异步随机生成按照各个路线行驶的车辆。例如&#xff1a; 由南向而来去往北向的车辆 ---- 直行车辆 由西向而来去往南向的车辆 ---- 右转车辆 由东向而来去往南向的车辆 ---- 左转车辆 。。。 信号灯忽略黄灯&#xff0c;只考虑红灯和绿灯。应考虑左转车…

php mysql 库存变负数_php解决秒杀并发入库导致的库存负数

我们知道数据库处理sql是一条条处理的&#xff0c;假设购买商品的流程是这样的&#xff1a;sql1:查询商品库存1 if(库存数量 > 0)2 {3 //生成订单4 //库存-15 >当没有并发时&#xff0c;上面的流程看起来是如此完美&#xff0c;假设同时两个人下单&#xff0c;而库存只有…

Codeforces Testing Round #10 A. Forgotten Episode

水题&#xff0c;注意数据范围 #include <iostream> using namespace std;int main(){long long n,a;cin >> n;long long sum (n*(n1))>>1;for(int i 0 ; i < n-1 ; i){cin >>a;sum -a;}cout<<sum<<endl; } 转载于:https://www.cnblo…

UE4--多线程的实现方式

首先查阅了WIKI中能找到Rama大神的两篇文章&#xff0c;讲了两个开线程的方式&#xff1a; https://wiki.unrealengine.com/Multi-Threading:_Task_Graph_System https://wiki.unrealengine.com/Multi-Threading:_How_to_Create_Threads_in_UE4 TaskGraph与FRunnable的比较 一…