• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            流逝的時光
            總有一天我們都會離去 email: zzxhang@gmail.com
            posts - 21,comments - 111,trackbacks - 0

              續(xù)上篇文章http://www.shnenglu.com/zzxhang/archive/2009/03/13/76490.html,繼續(xù)說明LuckyScript作為一門腳本是如何與主程序交互的,到目前為止,我已基本實現(xiàn)了大部分我最初對這門腳本的設(shè)想,我想,很快我就可以將它發(fā)布出去了,也許本來是可以更快一點的,這段時間煩人的事太多,而且,工作也開始忙起來了,我所謂的業(yè)余時間已經(jīng)越來越少,我想,是時候結(jié)束這個吉祥物的開發(fā)了。

            1、調(diào)用主程序函數(shù)
            所有提供給腳本調(diào)用的函數(shù)都必須滿足luckyScript主程序函數(shù)的原型定義,這個原型是typedef void (*Lucky_Host_Func)(RuntimeState*),比如如果我們想提供一個求和的函數(shù)給腳本定義,那么首先必須在主程序中這樣定義這個求和函數(shù):

            void add(RuntimeState* state)
            RuntimeState保存了腳本運行時的所有狀態(tài)信息,腳本在調(diào)用這個主函數(shù)時會把所有參數(shù)值推棧保存,需要注意的是參數(shù)是從左到右先后入棧的,所以取出參數(shù)的順序是從右到左
             1void add(RuntimeState* state)
             2{
             3    //取出參數(shù),右邊的參數(shù)先出棧
             4    int val2 = lucky_popValueAsInt(state);
             5    int val1 = lucky_popValueAsInt(state); 
             6//取出參數(shù),右邊的參數(shù)先出棧
             7
             8    int sum = val1 + val2; 
             9
            10     //把結(jié)果傳進腳本
            11    lucky_setReturnValue(state,sum);
            12}
            最后調(diào)用lucky_setReturnValue把結(jié)果傳進腳本,在完成這么個函數(shù)的定義后,我們必須把它注冊給腳本
            lucky_registerHostFunc(state,add,"add")
            這樣在腳本中就可以使用這個函數(shù)了,另外如果這個主程序函數(shù)返回的是腳本中所沒有的類型(比如對象,當(dāng)然必須先注冊給腳本),那么還必須指定第四個參數(shù)returnType說明返回的類型。

            2、調(diào)用DLL函數(shù)
            在腳本中,我們可以導(dǎo)入DLL,并使用其中函數(shù),luckyScript提供了兩個命令__importdll,__importdllfunction用于在腳本中導(dǎo)入DLL函數(shù),例如,我們可以建一個DLL工程,在里面添加下面代碼:
            extern "C" __declspec(dllexport)
            int add(int a,int b)
            {
                
            return a + b;
            }
            假設(shè)導(dǎo)出的DLL名為test.dl,那么在腳本中,我們可以這樣導(dǎo)入這個函數(shù)
            1__importdll "test.dll"
            2//給出函數(shù)的原型定義
            3__importdllfunction int __cdecl add(int a,int b)
            4
            5func Main()
            6{
            7    var sum = add(2,4);
            8}

            函數(shù)的調(diào)用約定可以指定為__cdecl或者__stdcall,至于值的類型則包含這些:int ,float,double,int64, char,wchar,ptr(指針), str(字符串) ,void,如果是已經(jīng)在腳本注冊過的對象類型,那么指定為ptr.

            3.用戶數(shù)據(jù)
            類似lua,luckyScript允許用戶往腳本添加自己的數(shù)據(jù),在適當(dāng)?shù)臅r候,我們可以再取出這些數(shù)據(jù),這個所謂"適當(dāng)?shù)臅r候"通常也就是腳本調(diào)用主程序函數(shù)的時候,我們得到事先添加進腳本的數(shù)據(jù),然后再用它做一些我們自己的事情,對于用戶數(shù)據(jù)的操作,luckyScript提供了以下幾個API:

            1LUCKY_API void* lucky_addUserData(size_t size);
            2
            3    LUCKY_API int lucky_getLastUserDataIndex();
            4
            5    LUCKY_API void* lucky_getUserData(int index);
            6
            7    LUCKY_API void lucky_clearAddedUserData();
            這幾個函數(shù),恩,老實說,用法有點別扭,需要具體點說明,先看下面的代碼:
             1struct TestData
             2{
             3    int val;
             4}
            ;
             5
             6void doSomething(RuntimeState* state)
             7{
             8    TestData* d = (TestData*)lucky_popValueAsUserData(state);
             9    const char* str = lucky_popValueAsString(state);
            10    print("%s: %d",str,d->val)
            11}

            12
            13void TestFunc()
            14{
            15    TestData t;
            16    t.val = 4;
            17
            18    lucky_initScript();
            19
            20    void* data = lucky_addUserData(sizeof(TestData));
            21    memcpy(data,&t,sizeof(TestData));
            22    
            23    //得到索引
            24    int index = lucky_getLastUserDataIndex();
            25    
            26    lucky_registerGlobalHostFunc(state,doSomething,"doSomething");
            27    
            28    //清空
            29    lucky_clearAddedUserData();
            30
            31    //取出userData
            32    TestData* t2 = (TestData*)lucky_getUserData(index);  
            33
            34    print("value(in TestFunc): %d",t2->val);
            35
            36    lucky_doString("doSomething(\"value(in doSomething): \")");
            37
            38    lucky_exitScript();
            39}
             
            40
            41

            在某個地方調(diào)用這個TestFunc,一切順利的話,應(yīng)該會輸出"value(in TestFunc): 4 value(in doSomething): 4",但我并不確定,以上及以下的代碼都是我隨手打的,只用我的眼睛編譯過....如果你認真看完了上面的代碼,那么我想對這幾個函數(shù)的用法你應(yīng)該都已經(jīng)了解了,唯一需要解釋的是23-30行之間的代碼:為了更緊密地與主程序結(jié)合,當(dāng)lucky_registerGlobalHostFunc或lucky_registerHostFunc被調(diào)用的時候,在內(nèi)部,腳本引擎會把從上一次調(diào)用或還沒調(diào)用lucky_clearAddedUserData到現(xiàn)在為止所添加進去的用戶數(shù)據(jù)跟lucky_registerGlobalFunc所注冊的主程序函數(shù)綁定,當(dāng)我們在腳本中調(diào)用這個主程序函數(shù)時,這些用戶數(shù)據(jù)就會被當(dāng)作參數(shù)一樣壓棧,這樣,在主程序函數(shù)中,我們就可以調(diào)用lucky_popValueAsUserData取出這些數(shù)據(jù),取出數(shù)據(jù)的順序跟添加的順序相反,也就是說,最后添加的用戶數(shù)據(jù)會被放在棧頂。利用這個特性,我們可以對luckyScript進行高層的封裝,使之可以更方便地注冊C++的類跟函數(shù),在下一篇文章中,我會向你展示這個特性是如何被利用的。

            4.主程序?qū)ο?br>  前面已經(jīng)多次提到關(guān)于主程序?qū)ο蟮淖裕琹uckyScript允許用戶往腳本添加自己的對象類型,但不得不說,這個過程是有點小麻煩的,luckyScrip采用一套預(yù)定義的規(guī)定來進行主程序?qū)ο髷?shù)據(jù)與腳本間的通信,在腳本中,所有主程序?qū)ο蟮牟僮?,包括?gòu)造,析構(gòu),成員調(diào)用等都是由一些預(yù)定義命名規(guī)范的主程序函數(shù)來完成的,當(dāng)一個主程序?qū)ο笤谀_本中構(gòu)造時,與此對象類型同名的主程序函數(shù)將會被調(diào)用,當(dāng)調(diào)用主程序?qū)ο蟮姆椒〞r,腳本將會采用className + memberFuncName的命名方式來call主程序函數(shù),具體的命名規(guī)范如下所示:
            構(gòu)造函數(shù):與類型名同名
            析構(gòu)函數(shù):下劃線 + 類型名
            調(diào)用成員函數(shù):類型名 + 下劃線  +  成員函數(shù)名
            操作符重載:類型名 +  下劃線 + Overide + 下劃線  +  操作符英文符號(如 '+' 為 Add)
            成員變量存:類型名 + 下劃線 + set + 下劃線 + 成員變量名
            成員變量取:類型名 + 下劃線 + get + 下劃線 +  成員變量名 

            接下來用一個完整的例子代碼進一步說明主程序?qū)ο蟮淖苑椒?br>

             1class TestObj
             2{
             3public:
             4    TestObj()
             5    {
             6    
             7    }

             8
             9    ~TestObj()
            10    {
            11
            12    }

            13
            14    void operator = (const TestObj& otherObj)
            15    {
            16        val = otherObj.val;
            17    }

            18
            19    void doSomething()
            20    {
            21
            22    }

            23
            24    int val;
            25}
            ;
            26
            27void TestObjConstructor(RuntimeState* state)
            28{
            29    void* data = lucky_popValueAsUserData(state);
            30
            31    new(data) TestObj();
            32}

            33
            34void TestObjDesConstructor(RuntimeState* state)
            35{
            36    TestObj* obj = (TestObj*)lucky_popValueAsUserData(state);
            37
            38    obj->~TestObj();
            39}

            40
            41void TestObjSetVal(RuntimeState* state)
            42{
            43    TestObj* obj = (TestObj*)lucky_popValueAsUserData(state);
            44
            45    int setVal = lucky_popValueAsInt(state);
            46    
            47    obj->val = setVal;
            48}

            49
            50void TestObjGetVal(RuntimeState* state)
            51{
            52    TestObj* obj = (TestObj*)lucky_popValueAsUserData(state);
            53    
            54    lucky_setReturnValue(state,obj->val);
            55}

            56
            57void TestObjDoSomethingFunc(RuntimeState* state)
            58{
            59    TestObj* obj = (TestObj*)lucky_popValueAsUserData(state);
            60    
            61    obj->doSomething();
            62}

            63
            64void TestObjOverideAssign(RuntimeState* state)
            65{
            66    TestObj* otherObj = (TestObj*)lucky_popValueAsUserData(state);
            67    TestObj* obj = (TestObj*)lucky_popValueAsUserData(state);
            68    
            69    (*obj) = (*otherObj);
            70}

            71
            72int main()
            73{
            74    lucky_initScript();
            75
            76    lucky_registerHostClass("TestObj",sizeof(TestObj));
                       //構(gòu)造函數(shù)處理回調(diào)函數(shù)命名規(guī)范:類型名
                       lucky_registerGlobalHostFunc(TestObjConstructor,"Test");
                      //析構(gòu)函數(shù)處理回調(diào)函數(shù)命名規(guī)范:下劃線 + 類型名
                       lucky_registerGlobalHostFunc(TestObjDesConstructor,"_Test");
            77    lucky_addHostMemberFunc("TestObj","doSomething");
            78    //成員函數(shù)處理回調(diào)函數(shù)命名規(guī)范:類型名 + 下劃線 + 成員函數(shù)名
            79    lucky_registerGlobalHostFunc(TestObjDoSomethingFunc,"TestObj_doSomething");
            80
            81    lucky_addHostMemberVal("TestObj","val");
            82    //成員變量處理回調(diào)函數(shù)命名規(guī)范:類型名 + 下劃線 + set/get + 下劃線 + 成員函數(shù)名
            83    lucky_registerGlobalHostFunc(TestObjSetVal,"TestObj_set_val");
            84    lucky_registerGlobalHostFunc(TestObjGetVal,"TestObj_get_val");
            85
            86    //操作符重載處理回調(diào)函數(shù)命名規(guī)范:類型名 + 下劃線 + Overide + 下劃線 + 操作符英文符號
            87    lucky_registerGlobalHostFunc(TestObjOverideAssign,"TestObj_Overide_Assign");
            88
            89   lucky_doString("var t = new TestObj();\
            90                   var t2 = new TestObj();\
            91                   t.doSomething();\
            92                   t.val = 3;\
            93                   t2.val = t.val + 1;\
            94                   t = t2;");
            95
            96   lucky_exitScript();
            97}
              同樣,我不能保證上面代碼的正確性,我甚至沒有檢查過,但用它來說明問題已經(jīng)足夠

            5.調(diào)用腳本函數(shù)
            腳本中能引用主程序的方法對象,主程序當(dāng)然也可以用腳本的一些東西,luckyScript直接提供了API用于調(diào)用腳本函數(shù):
            LUCKY_API void lucky_callFunc(RuntimeState* state,const char* funcName,int paramNum);
            LUCKY_API 
            void lucky_callFunc(RuntimeState* state,const char* funcName,char** paramsTypeName,int paramNum);
            需要說明下的是第二個API,假如你想調(diào)用的API包含主程序?qū)ο箢愋偷脑挘敲催€必須把所有參數(shù)的類型名傳進來,順序是從左到右,還有,兩個API都必須提供參數(shù)個數(shù).....你要問為什么會這么麻煩,我會告訴你,一切都源于那個該死的所謂泛化特性,調(diào)用同一函數(shù),提供不同的參數(shù)列表會編譯為不同的函數(shù),當(dāng)然函數(shù)名也會是不一樣的,so,我得根據(jù)參數(shù)類型的情況具體處理。

            6.腳本對象
            在這一塊我只提供了主程序?qū)δ_本全局變量的訪問
             1LUCKY_API int lucky_getGlobalIdentValAsInt(RuntimeState* state,const char* identName);
             2
             3LUCKY_API float lucky_getGlobalIdentValAsFloat(RuntimeState* state,const char* identName);
             4
             5LUCKY_API const char* lucky_getGlobalIdentValAsString(RuntimeState* state,const char* identName);
             6
             7LUCKY_API void* lucky_getGlobalIdentValAsUserData(RuntimeState* state,const char* identName);
             8
             9LUCKY_API void lucky_setGlobalIdentVal(RuntimeState* state,const char* identName,int val);
            10
            11LUCKY_API void lucky_setGlobalIdentVal(RuntimeState* state,const char* identName,float val);
            12
            13LUCKY_API void lucky_setGlobalIdentVal(RuntimeState* state,const char* identName,const char* val);
            14
            15LUCKY_API void lucky_setGlobalIdentVal(RuntimeState* state,const char* identName,void* val,const char* freeFuncName = "Null",size_t size = 0);
            在最后一個API中,假設(shè)你提供的是主程序?qū)ο蠖植淮蛩阍谥鞒绦蛑惺謩俞尫潘脑挘敲催€必須提供此對象的釋放主函數(shù)


            可以看到,使用上面的介紹的方法來進行主程序跟luckyScript腳本的交互的話還是有諸多不方便的,因為這個原因,我已經(jīng)為luckyScript實現(xiàn)了一個c++封裝庫,使用這個封裝庫可以方便的實現(xiàn)C++跟腳本間數(shù)據(jù)的通信,隱去一切瑣碎的細節(jié),在下篇文章中,我會詳細介紹這個封裝庫。
            posted on 2009-04-16 15:57 清風(fēng) 閱讀(1325) 評論(1)  編輯 收藏 引用 所屬分類: LuckyScript

            FeedBack:
            # re: LuckyScript與主程序的交互
            2009-04-18 10:30 | 陳梓瀚(vczh)
            我現(xiàn)在調(diào)用dll的方法是吧整個腳本都弄成機器碼,然后在里面調(diào)……  回復(fù)  更多評論
              
            久久久久久精品久久久久| 99久久www免费人成精品| 囯产极品美女高潮无套久久久| 人妻无码αv中文字幕久久| 日本三级久久网| 久久精品日日躁夜夜躁欧美| 热久久国产精品| 日韩精品无码久久久久久| 久久亚洲精品无码观看不卡| 精品免费久久久久久久| 亚洲精品无码久久久久AV麻豆| 久久综合久久综合久久综合| 久久久久久久久久久| 久久综合九色综合久99| 99久久精品日本一区二区免费| 国产精品99久久久精品无码| 狠狠人妻久久久久久综合| www.久久热| 久久精品aⅴ无码中文字字幕重口| 久久有码中文字幕| 色噜噜狠狠先锋影音久久| 久久精品国产亚洲AV高清热| 国内精品久久久久影院薰衣草| 伊人久久无码精品中文字幕| www亚洲欲色成人久久精品| 国产精品久久久久久吹潮| 久久综合九色综合网站| 亚洲中文字幕无码久久精品1| 综合久久给合久久狠狠狠97色 | 99久久99这里只有免费的精品| 综合久久一区二区三区 | 亚洲色大成网站www久久九| 亚洲欧美一级久久精品| 久久久久亚洲精品天堂久久久久久| 99久久精品无码一区二区毛片| 国产精品美女久久久久网| 91精品国产综合久久婷婷| 国产精品久久久久9999高清| 久久99精品久久久久婷婷| 久久国产乱子精品免费女| 精品国产一区二区三区久久蜜臀|