UCScript——C++集成脚本
使用UCScript作腳本,主要是因?yàn)樗鼛讉€(gè)特點(diǎn)很適合用于集成(腳本引擎體積小,占用資源少,運(yùn)行快,跨平臺(tái)跨語(yǔ)言,與宿主語(yǔ)言交互方便),而且它的語(yǔ)法類C語(yǔ)言,不用去多學(xué)一門語(yǔ)言。在C++中集成UCScript腳本是輕而易舉的事。我們接下來(lái)用實(shí)例來(lái)說(shuō)明,如何把UCScript腳本集成到你的程序中去。
1. 創(chuàng)建UCScript引擎
??? ucScript ucs; 或者 ucScript* ucs= new ucScript;
創(chuàng)建一個(gè)ucScript對(duì)象,就是創(chuàng)建一個(gè)UCScript腳本引擎。可以創(chuàng)建任意多個(gè)腳本引擎,甚至可以分布在不同的線程當(dāng)中。
注意:指定合適的預(yù)定義,Windows用_UC_WIN,Linux用_UC_LINUX(即編譯參數(shù)-D_UC_LINUX)。如果以動(dòng)態(tài)庫(kù)的形式使用腳本,還得指定_UC_IMPORT。
2. 執(zhí)行腳本程序 你可以從緩沖區(qū)中裝載腳本,也可以直接解析文件:
??? const char * szCode="ret 1+2*3;";
??? ucScript ucs;
??? ucCalcVar vRet= ucs.Parse(szCode);
??? assert(vRet.value.iVal == 7);
如果你想對(duì)你的源代碼進(jìn)行保護(hù)而不是赤裸裸的袒露在大家的眼前,或者提高腳本性能,你可以把腳本編譯成二進(jìn)制中間碼。
3. 如何讓腳本調(diào)用C++的函數(shù)。比如讓腳本以string: get_peername(int: id)的形式調(diào)用我的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表示腳本變量類型個(gè)數(shù)(即返回值和參數(shù)的個(gè)數(shù))。上例的宏參數(shù)分別表示:
| get_peername | 函數(shù)名字 |
| CVT_STRING | 函數(shù)返回值的類型為string |
| 函數(shù)的提示信息 | 在腳本集成開發(fā)環(huán)境ucDev可以看到 |
| CVT_INTEGER | 第一個(gè)參數(shù),類型為integer |
| 參數(shù)的提示信息 | 用在ucDev |
| CVT_STRING | 第二個(gè)參數(shù),類型string |
| 參數(shù)提示信息 | 用在ucDev |
| 1 | 有 1 個(gè)參數(shù)有默認(rèn)值,即最后一個(gè)參數(shù) |
腳本調(diào)用如下:
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"
最讓我激動(dòng)的是,該腳本把非標(biāo)準(zhǔn)類型的變量全部當(dāng)作object類型,也就是說(shuō)任何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. 結(jié)束語(yǔ)
UCScript是一種面向集成的腳本語(yǔ)言,上面例子是針對(duì)C++語(yǔ)言,還支持的其他語(yǔ)言有C#(.Net),Java,Delphi,Visual Basic等等。腳本開發(fā)工具可以從http://www.ucscript.com/view_download.asp?id=3下載。初學(xué)者可以從http://www.ucscript.com/download.asp下載腳本用戶手冊(cè)。
(上文轉(zhuǎn)自http://blog.csdn.net/amken/article/details/1491877)
不同語(yǔ)言之間相互調(diào)用函數(shù),這是很普遍的現(xiàn)象,尤其是多種語(yǔ)言并存開發(fā)的大項(xiàng)目。一般解決方案是,其中一種通過(guò)動(dòng)態(tài)鏈接庫(kù)或者COM組件暴露接口,而另一種語(yǔ)言去調(diào)用。
腳本語(yǔ)言調(diào)用其它語(yǔ)言,則是通過(guò)支持庫(kù)或者腳本自身支持。就拿VBScript來(lái)說(shuō),可以通過(guò)實(shí)現(xiàn)IDispatch接口,腳本創(chuàng)建自動(dòng)化對(duì)象來(lái)調(diào)用。各種腳本語(yǔ)言都有各自的方式來(lái)實(shí)現(xiàn)。UCScript是面向集成的腳本語(yǔ)言,這方面跟其它語(yǔ)言來(lái)比,更顯簡(jiǎn)練和高效的優(yōu)勢(shì)。下面分別從普通函數(shù)、類成員函數(shù)這兩方面介紹UCScript如何調(diào)用C++語(yǔ)言的函數(shù)。
1. 普通函數(shù)
在C++一提到函數(shù)調(diào)用,不得不提到的是調(diào)用約定(calling convention)。最常用的有__stdcall,__cdecl,__fastcall等幾種方式。
__stdcall是Windows API函數(shù)使用的規(guī)范,由被調(diào)用函數(shù)負(fù)責(zé)參數(shù)從堆棧移走,生成的代碼比__cdecl小。this指針壓入堆棧。以“?”標(biāo)識(shí)函數(shù)名的開始,后跟函數(shù)名; 函數(shù)名后面以“@@YG”標(biāo)識(shí)參數(shù)表的開始,后跟參數(shù)表; 參數(shù)表的第一項(xiàng)為該函數(shù)的返回值類型,其后依次為參數(shù)的數(shù)據(jù)類型,指針標(biāo)識(shí)在其所指數(shù)據(jù)類型前。
__cdecl調(diào)用約定是C/C++默認(rèn)的調(diào)用規(guī)范,由調(diào)用函數(shù)負(fù)責(zé)參數(shù)從堆棧移走,有利于參數(shù)個(gè)數(shù)可變。this指針壓入堆棧。對(duì)于傳送參數(shù)的棧是由調(diào)用者來(lái)維護(hù)的(正因?yàn)槿绱?#xff0c;實(shí)現(xiàn)可變參數(shù)的函數(shù)只能使用該調(diào)用約定)。另外,在函數(shù)名修飾約定方面也有所不同。 __cdecl是C和C++程序的缺省調(diào)用方式。每一個(gè)調(diào)用它的函數(shù)都包含清空堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會(huì)比調(diào)用_stdcall函數(shù)的大。函數(shù)采用從右到左的壓棧方式。
__fastcall規(guī)則同上面的__stdcall調(diào)用約定,它的主要特點(diǎn)就是快,因?yàn)樗峭ㄟ^(guò)寄存器來(lái)傳送參數(shù)的,即用ECX和EDX傳送前兩個(gè)參數(shù),剩下的參數(shù)仍舊自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的內(nèi)存棧),在函數(shù)名修飾約定方面,它和前兩者均不同。UCScript不支持這種調(diào)用的函數(shù)。
__stdcall和__cdecl的最大區(qū)別就是用來(lái)傳遞參數(shù)的堆棧空間的清除。UCScript底層屏蔽這個(gè)差異,也就是說(shuō)不管是哪一種方式,對(duì)UCScript都是一樣的。用戶不必關(guān)心這些細(xì)節(jié),可以降低用戶使用復(fù)雜度。
int __cdecl strtoint(std::string str) {
printf("strtoint: str=%s\n", str.c_str());
return atol(str.c_str());
}
要讓腳本調(diào)用這個(gè)C語(yǔ)言的函數(shù),只需如下的一行語(yǔ)句即可
BIND_UCSFUNC2(strtoint, strtoint, CVT_INTEGER, "convert string to int", (std::string*)CVT_OBJECT, "str");
下面分析上面各個(gè)參數(shù)的含義。
BIND_UCSFUNC2 該函數(shù)有2個(gè)腳本類別(Script Type),返回值和一個(gè)參數(shù)
strtoint 腳本可以調(diào)用到的函數(shù)名字,不必跟C++語(yǔ)言函數(shù)相同名字
strtoint C++語(yǔ)言的函數(shù)名字
CVT_INTEGER 函數(shù)返回值是Integer
"convert string to int" 函數(shù)說(shuō)明,在ucDev編程可以看到該提示
(std::string*)CVT_OBJECT 參數(shù)是Object,并且轉(zhuǎn)換為std::string類型
"str" 參數(shù)說(shuō)明,在ucDev編程可以看到該提示
2. 類成員函數(shù)
類成員函數(shù)可以分成兩類。一類是this指針通過(guò)ECX寄存器來(lái)傳遞;另一類是this指針通過(guò)參數(shù)傳遞。UCScript的輔助宏通過(guò)參數(shù)來(lái)區(qū)別這種區(qū)別。如下例:
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;
};
要讓腳本調(diào)用到上面的GetId函數(shù),只需下面語(yǔ)句
BIND_UCSFUNC_CM1(get_id, CMyClass, CMyClass::GetId, 1, CVT_INTEGER,"get id from a object");
上面的第4個(gè)參數(shù)指定this指針的傳遞方式:1表示標(biāo)準(zhǔn)方式,也就是this通過(guò)ECX寄存器傳遞;0是非標(biāo)準(zhǔn)方式,this通過(guò)參數(shù)傳遞。
當(dāng)然,要調(diào)用這個(gè)函數(shù)還得傳入一個(gè)對(duì)象,這個(gè)對(duì)象可以是其它函數(shù)的返回值或者用BIND_UCS_GLOBALVAR綁定的全局對(duì)象。比如腳本的代碼可能如下:
object: obj;
// get obj by any way
... ...
int: id=get_id(obj);
3. 結(jié)束語(yǔ)
UCScript作為一種面向集成的腳本語(yǔ)言,在調(diào)用C++語(yǔ)言有自己獨(dú)特的方式。總結(jié)一下有如下特點(diǎn):
可以傳遞任意C++類型,如上例的std::string類
封裝調(diào)用約定(calling convention)的差異
支持類成員函數(shù)調(diào)用
簡(jiǎn)單方便,一行聲明語(yǔ)句即可
轉(zhuǎn)載于:https://www.cnblogs.com/zcwsmile/p/4027809.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的UCScript——C++集成脚本的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: JAVA在线购物B2C商城源码
- 下一篇: 精通QTP-自动化测试技术领航