随笔-341  评论-2670  文章-0  trackbacks-0
    说到底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) 阅读(1611) 评论(1)  编辑 收藏 引用 所属分类: 脚本技术

评论:
# re: 使用Kernel FP API实现一个运行Kernel FP代码的控制台程序 2008-12-18 06:29 | dell笔记本
收藏,谢谢  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理