说到底Kernel FP是一个脚本引擎,所以是需要API的。接下来的代码用来加载一些Kernel FP代码文件,并执行main函数。
首先,我们读入的文件是一个目录,目录记录了一个Kernel FP程序所需要的所有代码文件:Project.txt
1 Startup.txt
2 SysUtils.txt
3 List.txt
读入文件之后将文件按行分割:
1 VUnicodeString TestDataPath=VFileName(GetConsole()->GetAppPath()).MakeAbsolute(L"..\\TestData\\").GetStrW();
2 VUnicodeString TestOutput;
3 VL_UniStrings CodeFiles;
4 {
5 VL_FileStream Stream(TestDataPath+L"Project.txt",VL_FileStream::vfomRead);
6 VUnicodeString Project=ReadText(&Stream);
7 CodeFiles.SetText(Project);
8 }
现在CodeFiles已经有3个文件的文件名了,现在需要声明一些Kernel FP对象,然后加载这些文件。文件在语法分析的时候出错,程序需要打印出错误信息:
1 VL_KfpSymbol Symbol;
2 Symbol.AddUnit(CreateConsoleUnit());
3 VBool ErrorOccurred=false;
4 for(VInt i=0;i<CodeFiles.GetCount();i++)
5 {
6 VL_FileStream Stream(TestDataPath+CodeFiles[i],VL_FileStream::vfomRead);
7 VUnicodeString TestCode=ReadText(&Stream);
8
9 VL_KfpError::List Errors;
10 Symbol.AddUnit(TestCode,Errors);
11 if(Errors.GetCount())
12 {
13 TestOutput+=L"文件\""+VUnicodeString(CodeFiles[i])+L"\"含有语法错误:\r\n";
14 TestOutput+=ToString(Errors);
15 ErrorOccurred=true;
16 }
17 }
收集了所有代码文件之后,需要先进行一次编译,在内部生成运行时所需要的assembly。当然,API不允许外部访问内部信息:
1 if(!ErrorOccurred)
2 {
3 VL_KfpError::List Errors;
4 Symbol.PreCompile(Errors);
5 if(Errors.GetCount())
6 {
7 TestOutput+=L"生成符号表时发生错误\r\n";
8 TestOutput+=ToString(Errors);
9 ErrorOccurred=true;
10 }
11 }
如果到这一步仍然没有问题的话,我们可以创建VL_KfpMachine了。这个Machine提供了访问程序公布的一些函数和对象。
1 if(!ErrorOccurred)
2 {
3 VL_KfpMachine::Ptr Machine=Symbol.CreateMachine();
4 RunProgram(Machine);
5 }
6 else
7 {
8 GetConsole()->Write(TestOutput);
9 }
中间有一步出错的话,控制台窗口上会显示所有错误信息。在上面我们发现有一个ToString函数将一个错误列表转换成字符串:
1 VUnicodeString ToString(VL_KfpError::List& Errors)
2 {
3 VUnicodeString Result=L"";
4 for(VInt i=0;i<Errors.GetCount();i++)
5 {
6 Result+=L"错误["+VUnicodeString(i+1)+L"]\t模块:"+Errors[i]->Module+L"\t行号:"+VUnicodeString(Errors[i]->Token.LineInFile+1)+L"\r\n";
7 Result+=L"信息:"+Errors[i]->Message+L"\r\n";
8 }
9 return Result;
10 }
接下来是RunProgram函数了。这个函数获得startup.main,我们假设main函数是放在startup命名空间下面的。当然,如果不确定命名空间的话,我们可以通过其他丰富的查询手段来获得我们需要的函数:
1 void RunProgram(VL_KfpMachine::Ptr Machine)
2 {
3 ConsolePlugin Plugin;
4 Machine->AddPlugin(&Plugin,false);
5
6 VInt Index=0;
7 VInt ID=Machine->GetFunctionFirstIdByName(L"startup.main");
8 if(ID==-1)
9 {
10 break;
11 }
12 else
13 {
14 VL_KfpValue MainFunction=Machine->CreateFunction(ID);
15 if(MainFunction.IsInvokable())
16 {
17 MainFunction=Machine->CreateEvaluableIO(MainFunction);
18 }
19 GetConsole()->Write(L"返回值:"+MainFunction.GetDebugString()+L"\r\n");
20 }
21 }
这里面有两个问题。控制台程序是要有read和write的API的。所以我们这里提供了两个接口。首先,刚才在编译Kernel FP之前有一句代码添加read和write的符号:
1 VL_KfpSymbol Symbol;
2 Symbol.AddUnit(CreateConsoleUnit());
CreateConsoleUnit代码如下:
1 KfpUnit CreateConsoleUnit()
2 {
3 KfpUnit Unit(L"console");
4 Unit.AddImport(L"system");
5 //func read :: IO string alias "KfpType::read"
6 Unit.AddFuncAlias(KfpDecl(L"read"),
7 KfpType(L"IO")<<KfpType(L"string"),
8 L"console::read"
9 );
10 //func write :: string -> IO void alias "KfpType::write"
11 Unit.AddFuncAlias(KfpDecl(L"write"),
12 KfpType(L"string")>>(KfpType(L"IO")<<KfpType(L"void")),
13 L"console::write"
14 );
15 //func writeln :: string -> IO void alias "KfpType::writeln"
16 Unit.AddFuncAlias(KfpDecl(L"writeln"),
17 KfpType(L"string")>>(KfpType(L"IO")<<KfpType(L"void")),
18 L"console::writeln"
19 );
20 return Unit;
21 }
有了这些符号还是不够的。程序运行的过程中,调用了这些函数的话,仍然需要我们处理。所以我们还得实现一个插件来执行这三个函数:
1 class ConsolePlugin : public VL_KfpPlugin
2 {
3 protected:
4 VInt FuncRead;
5 VInt FuncWrite;
6 VInt FuncWriteLine;
7 public:
8 ConsolePlugin()
9 {
10 FuncRead=-1;
11 FuncWrite=-1;
12 FuncWriteLine=-1;
13 }
14
15 void DestroyUserValue(VL_Base* Object)
16 {
17 }
18
19 void ConnectMachine()
20 {
21 FuncRead =RegisterExternalFunction(L"console::read", 1);
22 FuncWrite =RegisterExternalFunction(L"console::write", 2);
23 FuncWriteLine =RegisterExternalFunction(L"console::writeln", 2);
24 }
25
26 VUnicodeString GetName()
27 {
28 return L"Vczh KernelFP Demo Console Plugin";
29 }
30
31 VLE_KfpPluginResult Invoke(VInt ExternalID , InParams& In , OutParams& Out)
32 {
33 if(ExternalID==FuncWrite || ExternalID==FuncWriteLine)
34 {
35 if(In.Parameters.GetCount()==2)
36 {
37 VUnicodeString String;
38 if(In.Parameters[0].GetString(String))
39 {
40 if(ExternalID==FuncWrite)
41 {
42 GetConsole()->Write(String);
43 }
44 else
45 {
46 GetConsole()->Write(String+L"\r\n");
47 }
48 Out.Result=GetMachine()->CreateIOSuccess(GetMachine()->CreateVoid());
49 return vkprSuccess;
50 }
51 else if(In.Parameters[0].GetErrorMessage(Out.ErrorMessage))
52 {
53 return vkprFail;
54 }
55 }
56 Out.ErrorMessage=
57 (ExternalID==FuncWrite?
58 L"write函数的参数必须是一个string和一个IOEnv。":
59 L"writeln函数的参数必须是一个string和一个IOEnv。"
60 );
61 return vkprFail;
62 }
63 if(ExternalID==FuncRead)
64 {
65 if(In.Parameters.GetCount()==1)
66 {
67 VUnicodeString String;
68 GetConsole()->Read(String);
69 Out.Result=GetMachine()->CreateIOSuccess(GetMachine()->CreateString(String));
70 return vkprSuccess;
71 }
72 else
73 {
74 Out.ErrorMessage=L"read函数的参数必须是一个IOEnv。";
75 return vkprFail;
76 }
77 }
78 return vkprPass;
79 }
80 };
插件在ConnectMachine的时候,注册函数名和参数个数,然后返回一个ID供Invoke使用。跟IO有关的函数都是IO类型的。譬如read是IO string,而write是string->IO void。IO类型的函数都多了一个参数用于其他用途,所以read、write和writeln的参数个数才会是1、2和2。
Kernel FP API还提供了一些辅助函数用于创建或访问IO对象。实际上只要插件的行为与插件所声明的函数类型一致的话,基本上是不会有问题的。程序到这里就结束了,让我们看一看system(自动加载)模块与console(CreateConsoleUnit)模块生成的代码:
首先是system模块:
1 module system
2
3 type void
4
5 type int
6
7 type float
8
9 type char
10
11 data bool = (false | true)
12
13 data list T = (empty | (list T (list T)))
14
15 data maybe Ts Tf = ((success Ts) | (fail Tf))
16
17 type string = (list char)
18
19 data pair T1 T2 = (pair T1 T2)
20
21 data IOError = (ioemessage string)
22
23 type IOEnv
24
25 type IO T = (IOEnv -> (maybe (pair T IOEnv) IOError))
26
27 func iadd :: (int -> (int -> int)) alias "kernelfp::iadd"
28
29 func isub :: (int -> (int -> int)) alias "kernelfp::isub"
30
31 func imul :: (int -> (int -> int)) alias "kernelfp::imul"
32
33 func idiv :: (int -> (int -> int)) alias "kernelfp::idiv"
34
35 func imod :: (int -> (int -> int)) alias "kernelfp::imod"
36
37 func igt :: (int -> (int -> bool)) alias "kernelfp::igt"
38
39 func ilt :: (int -> (int -> bool)) alias "kernelfp::ilt"
40
41 func iequ :: (int -> (int -> bool)) alias "kernelfp::iequ"
42
43 func iegt :: (int -> (int -> bool)) alias "kernelfp::iegt"
44
45 func ielt :: (int -> (int -> bool)) alias "kernelfp::ielt"
46
47 func ineq :: (int -> (int -> bool)) alias "kernelfp::ineq"
48
49 func fadd :: (float -> (float -> float)) alias "kernelfp::fadd"
50
51 func fsub :: (float -> (float -> float)) alias "kernelfp::fsub"
52
53 func fmul :: (float -> (float -> float)) alias "kernelfp::fmul"
54
55 func fdiv :: (float -> (float -> float)) alias "kernelfp::fdiv"
56
57 func fmod :: (float -> (float -> float)) alias "kernelfp::fmod"
58
59 func fgt :: (float -> (float -> bool)) alias "kernelfp::fgt"
60
61 func flt :: (float -> (float -> bool)) alias "kernelfp::flt"
62
63 func fequ :: (float -> (float -> bool)) alias "kernelfp::fequ"
64
65 func fegt :: (float -> (float -> bool)) alias "kernelfp::fegt"
66
67 func felt :: (float -> (float -> bool)) alias "kernelfp::felt"
68
69 func fneq :: (float -> (float -> bool)) alias "kernelfp::fneq"
70
71 func isnan :: (float -> bool) alias "kernelfp::isnan"
72
73 func isinf :: (float -> bool) alias "kernelfp::isinf"
74
75 func chr :: (int -> char) alias "kernelfp::chr"
76
77 func ord :: (char -> int) alias "kernelfp::ord"
78
79 func cgt :: (char -> (char -> bool)) alias "kernelfp::cgt"
80
81 func clt :: (char -> (char -> bool)) alias "kernelfp::clt"
82
83 func cequ :: (char -> (char -> bool)) alias "kernelfp::cequ"
84
85 func cegt :: (char -> (char -> bool)) alias "kernelfp::cegt"
86
87 func celt :: (char -> (char -> bool)) alias "kernelfp::celt"
88
89 func cneq :: (char -> (char -> bool)) alias "kernelfp::cneq"
90
91 func ceil :: (float -> float) alias "kernelfp::ceil"
92
93 func floor :: (float -> float) alias "kernelfp::floor"
94
95 func trunc :: (float -> float) alias "kernelfp::trunc"
96
97 func itof :: (int -> float) alias "kernelfp::itof"
98
99 func ftoi :: (float -> int) alias "kernelfp::ftoi"
100
101 func abs :: (float -> float) alias "kernelfp::abs"
102
103 func exp :: (float -> float) alias "kernelfp::exp"
104
105 func ln :: (float -> float) alias "kernelfp::ln"
106
107 func lg :: (float -> float) alias "kernelfp::lg"
108
109 func sqr :: (float -> float) alias "kernelfp::sqr"
110
111 func pow :: (float -> (float -> float)) alias "kernelfp::pow"
112
113 func sin :: (float -> float) alias "kernelfp::sin"
114
115 func cos :: (float -> float) alias "kernelfp::cos"
116
117 func tan :: (float -> float) alias "kernelfp::tan"
118
119 func asin :: (float -> float) alias "kernelfp::asin"
120
121 func acos :: (float -> float) alias "kernelfp::acos"
122
123 func atan :: (float -> float) alias "kernelfp::atan"
124
125 func atan2 :: (float -> (float -> float)) alias "kernelfp::atan2"
126
127 func itoa :: (int -> string) alias "kernelfp::itoa"
128
129 func ftoa :: (float -> string) alias "kernelfp::ftoa"
130
131 func atoi :: (string -> (maybe int string)) alias "kernelfp::atoi"
132
133 func atof :: (string -> (maybe float string)) alias "kernelfp::atof"
134
135 func iovoid :: (IO void) alias "kernelfp::iovoid"
136
137 func (>>>) T1 T2 :: ((IO T1) -> ((IO T2) -> (IO T2))) alias "kernelfp::(>>>)"
138
139 func (>>=) T1 T2 :: ((IO T1) -> ((T1 -> (IO T2)) -> (IO T2))) alias "kernelfp::(>>=)"
140
然后是console模块:
1 module console
2 import system
3
4 func read :: (IO string) alias "console::read"
5
6 func write :: (string -> (IO void)) alias "console::write"
7
8 func writeln :: (string -> (IO void)) alias "console::writeln"
9
一个将Kernel FP代码当成命令行程序执行的宿主程序已经完成了。现在让我们看看完整的代码:
1 #include "..\..\..\..\VL++\Library\Platform\VL_Console.h"
2 #include "..\..\..\..\VL++\Library\Script\KernelFP\VL_KFPScript.h"
3 #include "..\..\..\..\VL++\Library\Data\VL_Stream.h"
4 #include "..\..\..\..\VL++\Library\Data\VL_System.h"
5 #include "..\..\..\..\VL++\Library\Data\VL_Uniop.h"
6
7 using namespace vl;
8 using namespace vl::platform;
9 using namespace vl::kernalfp;
10 using namespace vl::stream;
11 using namespace vl::system;
12 using namespace vl::uniop;
13
14 VUnicodeString ToString(VL_KfpError::List& Errors)
15 {
16 VUnicodeString Result=L"";
17 for(VInt i=0;i<Errors.GetCount();i++)
18 {
19 Result+=L"错误["+VUnicodeString(i+1)+L"]\t模块:"+Errors[i]->Module+L"\t行号:"+VUnicodeString(Errors[i]->Token.LineInFile+1)+L"\r\n";
20 Result+=L"信息:"+Errors[i]->Message+L"\r\n";
21 }
22 return Result;
23 }
24
25 KfpUnit CreateConsoleUnit()
26 {
27 KfpUnit Unit(L"console");
28 Unit.AddImport(L"system");
29 //func read :: IO string alias "KfpType::read"
30 Unit.AddFuncAlias(KfpDecl(L"read"),
31 KfpType(L"IO")<<KfpType(L"string"),
32 L"console::read"
33 );
34 //func write :: string -> IO void alias "KfpType::write"
35 Unit.AddFuncAlias(KfpDecl(L"write"),
36 KfpType(L"string")>>(KfpType(L"IO")<<KfpType(L"void")),
37 L"console::write"
38 );
39 //func writeln :: string -> IO void alias "KfpType::writeln"
40 Unit.AddFuncAlias(KfpDecl(L"writeln"),
41 KfpType(L"string")>>(KfpType(L"IO")<<KfpType(L"void")),
42 L"console::writeln"
43 );
44 return Unit;
45 }
46
47 class ConsolePlugin : public VL_KfpPlugin
48 {
49 protected:
50 VInt FuncRead;
51 VInt FuncWrite;
52 VInt FuncWriteLine;
53 public:
54 ConsolePlugin()
55 {
56 FuncRead=-1;
57 FuncWrite=-1;
58 FuncWriteLine=-1;
59 }
60
61 void DestroyUserValue(VL_Base* Object)
62 {
63 }
64
65 void ConnectMachine()
66 {
67 FuncRead =RegisterExternalFunction(L"console::read", 1);
68 FuncWrite =RegisterExternalFunction(L"console::write", 2);
69 FuncWriteLine =RegisterExternalFunction(L"console::writeln", 2);
70 }
71
72 VUnicodeString GetName()
73 {
74 return L"Vczh KernelFP Demo Console Plugin";
75 }
76
77 VLE_KfpPluginResult Invoke(VInt ExternalID , InParams& In , OutParams& Out)
78 {
79 if(ExternalID==FuncWrite || ExternalID==FuncWriteLine)
80 {
81 if(In.Parameters.GetCount()==2)
82 {
83 VUnicodeString String;
84 if(In.Parameters[0].GetString(String))
85 {
86 if(ExternalID==FuncWrite)
87 {
88 GetConsole()->Write(String);
89 }
90 else
91 {
92 GetConsole()->Write(String+L"\r\n");
93 }
94 Out.Result=GetMachine()->CreateIOSuccess(GetMachine()->CreateVoid());
95 return vkprSuccess;
96 }
97 else if(In.Parameters[0].GetErrorMessage(Out.ErrorMessage))
98 {
99 return vkprFail;
100 }
101 }
102 Out.ErrorMessage=
103 (ExternalID==FuncWrite?
104 L"write函数的参数必须是一个string和一个IOEnv。":
105 L"writeln函数的参数必须是一个string和一个IOEnv。"
106 );
107 return vkprFail;
108 }
109 if(ExternalID==FuncRead)
110 {
111 if(In.Parameters.GetCount()==1)
112 {
113 VUnicodeString String;
114 GetConsole()->Read(String);
115 Out.Result=GetMachine()->CreateIOSuccess(GetMachine()->CreateString(String));
116 return vkprSuccess;
117 }
118 else
119 {
120 Out.ErrorMessage=L"read函数的参数必须是一个IOEnv。";
121 return vkprFail;
122 }
123 }
124 return vkprPass;
125 }
126 };
127
128 void RunProgram(VL_KfpMachine::Ptr Machine)
129 {
130 ConsolePlugin Plugin;
131 Machine->AddPlugin(&Plugin,false);
132
133 VInt Index=0;
134 VInt ID=Machine->GetFunctionFirstIdByName(L"startup.main");
135 if(ID==-1)
136 {
137 break;
138 }
139 else
140 {
141 VL_KfpValue MainFunction=Machine->CreateFunction(ID);
142 if(MainFunction.IsInvokable())
143 {
144 MainFunction=Machine->CreateEvaluableIO(MainFunction);
145 }
146 GetConsole()->Write(L"返回值:"+MainFunction.GetDebugString()+L"\r\n");
147 }
148 }
149
150 void vlmain()
151 {
152 GetConsole()->SetTitle(L"Vczh Kernal FP");
153 GetConsole()->SetPauseOnExit(true);
154 GetConsole()->SetTestMemoryLeaks(true);
155
156 VUnicodeString TestDataPath=VFileName(GetConsole()->GetAppPath()).MakeAbsolute(L"..\\TestData\\").GetStrW();
157 VUnicodeString TestOutput;
158 VL_UniStrings CodeFiles;
159 {
160 VL_FileStream Stream(TestDataPath+L"Project.txt",VL_FileStream::vfomRead);
161 VUnicodeString Project=ReadText(&Stream);
162 CodeFiles.SetText(Project);
163 }
164
165 VL_KfpSymbol Symbol;
166 Symbol.AddUnit(CreateConsoleUnit());
167 VBool ErrorOccurred=false;
168 for(VInt i=0;i<CodeFiles.GetCount();i++)
169 {
170 VL_FileStream Stream(TestDataPath+CodeFiles[i],VL_FileStream::vfomRead);
171 VUnicodeString TestCode=ReadText(&Stream);
172
173 VL_KfpError::List Errors;
174 Symbol.AddUnit(TestCode,Errors);
175 if(Errors.GetCount())
176 {
177 TestOutput+=L"文件\""+VUnicodeString(CodeFiles[i])+L"\"含有语法错误:\r\n";
178 TestOutput+=ToString(Errors);
179 ErrorOccurred=true;
180 }
181 }
182 if(!ErrorOccurred)
183 {
184 VL_KfpError::List Errors;
185 Symbol.PreCompile(Errors);
186 if(Errors.GetCount())
187 {
188 TestOutput+=L"生成符号表时发生错误\r\n";
189 TestOutput+=ToString(Errors);
190 ErrorOccurred=true;
191 }
192 }
193 if(!ErrorOccurred)
194 {
195 VL_KfpMachine::Ptr Machine=Symbol.CreateMachine();
196 RunProgram(Machine);
197 }
198 else
199 {
200 GetConsole()->Write(TestOutput);
201 }
202 }
posted on 2008-12-17 19:15
陈梓瀚(vczh) 阅读(1627)
评论(1) 编辑 收藏 引用 所属分类:
脚本技术