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) 阅读(1711)
评论(2) 编辑 收藏 引用 所属分类:
脚本技术