Kernel FP已經可以運行小程序了。現在還處于測試階段,過于復雜的程序估計是跑不過的。先簡單介紹一下如何在C++調用Kernel FP的代碼。
首先貼出一段Kernel FP的代碼:
1 module startup
2 import system
3
4 data maybe T = return T | error T
5
6 def add a b =
7 let
8 def xadd = iadd a b
9 in xadd
10
11 def foo a =
12 select a of
13 case 0 : return 100
14 case 1 : return 200
15 case 2 : return 300
16 else : error a
17 end
18
19 def translate a =
20 select a of
21 case return t : iadd 10000 t
22 case error t : iadd 1000 t
23 end
24
25 def main = translate (foo (add 1 2))
程序非常直白。add 1 2返回3,經過foo選擇返回error 3,經過translate變成iadd 1000 3,最后輸出1003。現在Kernel FP的對外api還沒寫,只是在調試內核代碼。為什么只有iadd呢?因為我只實現了iadd……其他的等以后再說。先看看如何調用一個main函數。在沒有對外api的情況下,只能對內核的對象進行裸調……
1 void RunProgram(VL_KfpRuntimeProgram::Ptr Program)
2 {
3 VL_KfpRuntimeEnvironment Environment;
4 Environment.Program=Program;
5
6 MyPlugin Plugin(&Environment);
7 Environment.Plugins.Add(&Plugin);
8
9 VL_KfpRuntimeFunction* Function=&Program->Functions[Program->FunctionIDMap[L"startup.main"][0]];
10
11 VL_KfpRuntimeValueEnvironment ValueEnvironment;
12 ValueEnvironment.Environment=&Environment;
13 ValueEnvironment.SetTable(new VL_KfpRuntimeValueTable(new VL_KfpRuntimeValueTable(0,0),Function->Instance));
14
15 VL_KfpRuntimeExpression* Expression=Function->AssociatedExpression;
16 VL_KfpRuntimeValue* Value=Expression->CreateRuntimeValue(&ValueEnvironment);
17 Value->Increase();
18 VL_KfpRuntimeEvaluateResult Result;
19 Value->EvaluateUntilGetType(&Environment,Result);
20 if(Result.HasError)
21 {
22 GetConsole()->Write(L"發生錯誤:"+Result.ErrorMessage+L"\r\n");
23 }
24 else
25 {
26 if(Result.Value.GetValue()->Kind==VL_KfpRuntimeValue::vkekInteger)
27 {
28 GetConsole()->Write(L"返回值:"+VUnicodeString(((VL_KfpRuntimeIntegerValue*)Result.Value.GetValue())->Data)+L"\r\n");
29 }
30 else
31 {
32 GetConsole()->Write(L"返回值不是整數。\r\n");
33 }
34 }
35 Value->Decrease();
36 }
首先程序經過先前實現的類型推導,得到編譯后的程序VL_KfpRuntimeProgram,然后取出startup.main的函數指針。得到了函數指針之后,將函數的上下文和函數綁定的表達式都保存起來,然后將表達式轉換為VL_RuntimeValue。最后對VL_RuntimeValue與上下文結合進行求值。
當然了,程序會調用到iadd,這是一個外部函數,實現兩個整數的加法。所以還得實現一個插件來執行iadd:
1 class MyPlugin : public VL_KfpRuntimePlugin
2 {
3 public:
4 VL_KfpRuntimeEnvironment* Environment;
5 VInt External_IAdd;
6
7 MyPlugin(VL_KfpRuntimeEnvironment* aEnvironment)
8 {
9 Environment=aEnvironment;
10
11 External_IAdd=Environment->Program->ExternalIDMap[L"kernelfp::iadd"];
12 }
13
14 VLE_KfpPluginResult Invoke(VInt ExternalID , InParams& In , OutParams& Out)
15 {
16 if(ExternalID==External_IAdd)
17 {
18 if(In.Parameters.GetCount()==2)
19 {
20 VL_KfpRuntimeEvaluateResult r1,r2;
21
22 In.Parameters[0].GetValue()->EvaluateUntilGetType(Environment,r1);
23 if(r1.HasError)
24 {
25 Out.ErrorMessage=r1.ErrorMessage;
26 return vkprFail;
27 }
28 if(r1.Value.GetValue()->Kind!=VL_KfpRuntimeValue::vkekInteger)
29 {
30 Out.ErrorMessage=L"iadd函數的參數必須是兩個int。";
31 return vkprFail;
32 }
33
34 In.Parameters[1].GetValue()->EvaluateUntilGetType(Environment,r2);
35 if(r2.HasError)
36 {
37 Out.ErrorMessage=r2.ErrorMessage;
38 return vkprFail;
39 }
40 if(r2.Value.GetValue()->Kind!=VL_KfpRuntimeValue::vkekInteger)
41 {
42 Out.ErrorMessage=L"iadd函數的參數必須是兩個int。";
43 return vkprFail;
44 }
45
46 VInt Value1=((VL_KfpRuntimeIntegerValue*)r1.Value.GetValue())->Data;
47 VInt Value2=((VL_KfpRuntimeIntegerValue*)r2.Value.GetValue())->Data;
48 Out.Result.SetValue(new VL_KfpRuntimeIntegerValue(Value1+Value2));
49 return vkprSuccess;
50 }
51 else
52 {
53 Out.ErrorMessage=L"iadd函數的參數必須是兩個int。";
54 return vkprFail;
55 }
56 }
57 else
58 {
59 return vkprPass;
60 }
61 }
62
63 VLE_KfpPluginResult GetParameterCount(VInt ExternalID , VInt& Count)
64 {
65 if(ExternalID==External_IAdd)
66 {
67 Count=2;
68 return vkprSuccess;
69 }
70 else
71 {
72 return vkprPass;
73 }
74 }
75 };
這也就是MyPlugin類的內容了。
posted on 2008-12-10 23:03
陳梓瀚(vczh) 閱讀(1719)
評論(2) 編輯 收藏 引用 所屬分類:
腳本技術