目 录
MLu说明 | 基于MLu的Lu扩展动态 |
1 MLu的输出函数 2 如何使用MLu 3 二级函数 4 模块源文件 5 例子 | 1 OpenLuGl:基于OpenGL的图形库 2 LuWin:基于Windows的窗口库 |
MLu是程序和Lu核心库之间的一个接口库,MLu会自动加载Lu核心库和动态加载多个Lu扩展库,简化了Lu系统的使用;MLu可对Lu源程序进行模块化编译,能够编译运行具有固定格式的源程序(字符串表达式),源程序中可以使用C++风格的注释。此外,MLu还提供了多个线程互斥地访问Lu资源的功能;提供了Lu运行监视器,以退出耗时较长的程序;提供在脚本中动态编译函数的功能;提供错误处理函数,实现错误(异常)处理的恢复模型等等。
MLu共有10个输出函数,其中4个函数可在Lu键树中用SearchKey查询到,即:SearchKey("UseLu",5,luPriKey_User)、SearchKey("ComModule",9,luPriKey_User)、SearchKey("ExeModule",9,luPriKey_User)和SearchKey("DelModule",9,luPriKey_User)。这4个函数可用于Lu扩展库的设计。
1.1 初始化MLu:int _stdcallInitMLu(void);
MLu初始化后才能使用。该函数对MLu进行初始化,成功时返回非0值,返回0表示初始化失败。可使用该函数对MLu重新初始化,但必须关闭主程序中正在运行的Lu程序。
1.2 释放MLu:void _stdcallFreeMLu(void);
在使用完MLu之后必须用该函数释放加载的资源。
1.3 得到Lu核心库的句柄:HINSTANCE _stdcallGetLuHandle(void);
MLu会自动加载Lu核心库,该函数用于获得Lu核心库的句柄。
警告:不要使用Lu核心库的InitLu和FreeLu两个函数。
1.4 得到Lu核心库的输出函数:void * _stdcallGetLuProc(char *name);
name是Lu核心库的输出函数名。
警告:不要使用Lu核心库的InitLu和FreeLu两个函数。
1.5 加载Lu扩展动态库:void _stdcallLoadDll(wchar_t *DllStr);
DllStr:含有Lu扩展动态库名称的字符串。
允许加载多个Lu扩展动态库。Lu扩展动态库名字要放在双引号"..."之间。忽略在尖括号<"..." ...>内的Lu扩展动态库。
例如:"LuMath32","d:\\lu\\LuSystem32.dll"
需要注意Lu扩展动态库的加载顺序。
1.6 释放Lu扩展动态库:void _stdcallFreeDll(void);
1.7 申请进入或退出Lu工作区:int _stdcallUseLu(int iUse);
iUse=1时,表示要申请使用Lu,若函数返回值 UseLu=0:申请成功;UseLu=1:申请不成功,某线程正在使用Lu,稍后再进行申请;UseLu=-1:申请不成功,表示应用程序要释放Lu,因此要做好退出前的准备工作。
iUse=2时,表示要申请使用Lu,如果其他线程正在使用Lu,函数不返回,进行等待,直至申请成功。若函数返回值 UseLu=0:申请成功;UseLu=1:申请不成功,线程本身正在使用Lu,不能重复进行申请;UseLu=-1:申请不成功,表示应用程序要释放Lu,因此要做好退出前的准备工作。
iUse=0时,表示要归还Lu的使用权,函数返回值无意义。
iUse=3时,设置安全标志,表示Lu运行正常,函数返回值无意义。 一般在二级函数中设置该标志,当该函数在较长时间内运行时,可用此标志通知Lu,此时的运行是正常的,没有陷入无限循环等情况。
iUse=4时,取消安全标志,表示Lu运行处于不可控制阶段(有陷入无限循环的可能),函数返回值无意义。
iUse=5时,查询安全标志,UseLu=0:运行正常;UseLu=1:运行情况无法预测(有陷入无限循环的可能),这是Lu运行的一般情况。
注意:Lu是极为重要而有限的资源,用完后要及时归还。UseLu(1)(或者UseLu(2))和UseLu(0)必须成对使用,注意不能在二级函数中使用该功能,因为二级函数本身就是在Lu工作区中运行的。UseLu(3)和UseLu(4)也要成对使用,且一般在二级函数中使用。
可以在主调程序或Lu扩展动态库中使用该函数。在多线程程序中,必须通过申请Lu工作区的方法来使用Lu,因为在任何时刻,只允许一个线程使用Lu(GetRunErr()、TestRunErr()和SetRunErr()三个函数除外)。
1.8 编译源程序:int _stdcallComModule(wchar_t *LuStr,luVOID &nModule,void *&hModule,luINT &err1,luINT &err2);
LuStr:指向源程序字符串的指针;
nModule:返回多个模块的最小模块号。一般返回主模块号,如果主模块中没有表达式,就返回有表达式的最小子模块号。
hModule:返回模块的句柄,用于执行该模块。
err1和err2:返回编译出错位置,该值是否有意义取决于函数的返回值(返回值为-1、0、1、3、-2时无意义)。
该函数返回值的意义如下:
-7:递归调用指定的模块。(参考函数mluLoadModule的说明)
-6:找不到指定的模块。(参考函数mluLoadModule的说明)
-5:缺少模块名。(由程序员处理,不返回给用户)
-4:注释符号/* ... */不成对。
-3:未使用模块编译功能,不能编译指定的模块。
-2:无法加锁模块。(由程序员处理,修改nModule为较小的值可能修正此错误)
-1:未用!
0:没有错误,编译成功!
1:内存分配失败!
2:括号不成对!
3:(等号后)没有表达式!
4:非法的函数句柄!
5:字符串中转义字符错误!
6:字符串无效,即"..."不匹配!
7:不可识别字符!
8:表达式名称定义错误!
9:不可识别的自变量,自变量只能以字母、中文字符或下画线开头!
10:不可识别的自变量定义方法,“(,:,:,:,:,...)”冒号过多!
11:自变量定义错误!
12:continue()函数只能有0个参数!
13:只能在while,until中使用continue函数!
14:break()函数只能有0个参数!
15:只能在while,until中使用break函数!
16:if,while,until,which中的参数个数至少为2个!
17:表达式中的数字错误!
18:&单目取地址运算符只能用于单独的变量!
19:单目运算符++、--错误!
20:括号内没有数字!
21:单目运算符+、-、!、!!错误!
22:赋值“=”错误!
23:不正确的运算方式或其他语法错误!
24:不可识别变量名或常量名!
25:不可识别函数名!
26:一级函数参数不匹配!
27:二级函数参数不匹配!
28:关键字Static或Common的位置非法!
29:(模块中)表达式有重名!
30:对形如“-2^3”的式子,须用括号给前置单目运算符“-”和乘方运算符“^”(或点乘方运算符“.^”)指出运算顺序!
31:类成员运算符(函数参数运算符)后只能是变量名、字符串、括号运算符或者类成员函数!
32:后单目运算符'、.'错误!
33:调用表达式时参数不匹配!
34:未用!
35:自变量重名!
36:因检测到运行错误而退出!
37:未用!
38:未用!
39:源代码太长或字符串太多!
编译时,将源程序中的表达式编译为一个或多个模块,MLu会对每一个模块进行加锁。编译时首先设置起始模块,也称主模块(并非Lu的0#模块,恰恰相反,MLu不会将任何一个表达式编译为0#模块,定义主模块是为了与源程序中的其他模块相区别),以后每当遇到#MODULE#,开始编译为一个新的模块,称为子模块,而每当遇到#END#,回到主模块的编译。即#MODULE#和#END#之间的表达式定义为一个子模块,子模块之间不能嵌套定义。注意#MODULE#和#END#必须位于表达式的开头。
当nModule为0时,所有模块的模块号自动指定(MLu初始化时,设置最初的起始模块号为1,以后不断递增,但不一定连续,因为每次执行该函数,不管是否执行成功,模块号均加1),不会重复,也不会被编译为0#模块。任何时候,可用nModule传送给MLu一个起始模块号(必须大于0),以后的模块号将在该模块号的基础上递增,从而改变模块号序列。若要自己指定模块号,则每次编译源程序前,均指定一个起始模块号。MLu编译的多个模块序号是递增的,但不一定连续,因为如果MLu加锁一个模块不成功,就会继续加锁下一个模块号。
在模块中,以:::开头的表达式被编译为正模块号表达式(公有表达式或公有函数,也称为全局函数),能被其他模块访问到,其余的表达式均被编译为负模块号表达式(私有表达式或私有函数),其他模块无法访问。
在源程序的任何地方,可用指令#USE#调用另一个模块。
模块源文件的格式如下(没有定义子模块,子模块的例子请参考这里):
//单行注释:模块名:myModule
/*
多行注释:在同一模块源文件中的所有表达式属于同一个模块;
多行注释:以:::开头的表达式的模块号为正,可被其他模块的表达式所访问;
多行注释:不以:::开头的表达式的模块号为负,只能被该模块的表达式所访问。
*/
a(x)=10+x; //模块号为负,私有函数,只能被该模块的表达式所访问;
b()=100+100i; //模块号为负,私有函数,只能被该模块的表达式所访问;
:::c(x)=x-5; //模块号为正,全局函数,任意模块包括本模块均可访问;
:::f(x)=a(x)+b(); //模块号为正,全局函数,任意模块包括本模块均可访问;
:::g(x)=a(x)+c(x); //模块号为正,全局函数,任意模块包括本模块均可访问;
#USE# Module1; //使用模块Module1;
ff(5)+gg(6); //函数ff()和gg()在模块Module1中定义;
在其他模块中使用该模块的格式如下:
#USE# myModule; //关键字USE必须为大写,myModule是模块名称;
f(2)+g(3); //调用myModule模块中定义的函数;
1.9 执行模块:void _stdcall ExeModule(void *hModule,void (_stdcall *outlu)(LuData *LD));
hModule:编译源程序时得到的模块的句柄。
outlu:输出表达式的值。这个回调函数在执行表达式时被调用,输出信息。该参数可设为NULL。
注意1:该函数只执行模块中的无参表达式。
注意2:当Lu键树中有一个被锁定为字符串的键给出运行错误说明时,MLu将试图找出出现运行错误的原因。请参考键mluErrStr的说明。
1.10 删除模块:void _stdcallDelModule(void *hModule);
hModule:编译源程序时得到的模块的句柄。
2.1 MLu的加载和卸载
(1)隐式调用
使用MLu核心库的导入库文件mlu32.lib。这种方法比较方便。
(2)显示调用
应用程序可调用LoadLibrary直接加载MLu32.dll。
HANDLE hMLu; //动态库模块句柄
hMLu=LoadLibrary(L"MLu32.dll"); //加载动态库MLu32.dll
加载MLu32.dll成功后,需调用函数GetProcAddress获取MLu输出函数的地址。例如:
mluInitMLu pInitMLu; //mluInitLu 在头文件Lu32.h中定义,为初始化MLu的函数指针;
pInitMLu=(mluInitLu) GetProcAddress(hMLu,"InitMLu");
该函数获得了初始化MLu的函数地址,保存在指针pInitMLu中。
当程序不再需要访问MLu32.dll时,应调用函数FreeLibrary将其卸载。
FreeLibrary(hMLu); //释放动态库MLu32.dll;
2.2 MLu使用说明
MLu加载成功后,必须先用函数InitMLu进行初始化;在卸载MLu之前,要用函数FreeMLu释放使用的资源。
因MLu对多线程中使用Lu提供了支持,故在使用Lu及MLu的许多输出函数时,须先使用函数UseLu获得使用Lu的许可,并在用完Lu后,及时归还Lu资源的使用权。参见下表:
函 数 | 说 明 | 来 源 | 是否需要UseLu |
InitMLu | 初始化MLu。 | MLu | 否 |
FreeMLu | 释放MLu。 | MLu | 否 |
GetLuHandle | 得到Lu32W.dll的句柄。 | MLu | 否 |
GetLuProc | 得到Lu32W.dll的输出函数。 | MLu | 否 |
LoadDll | 加载Lu扩展动态库。 | MLu | 否 |
FreeDll | 释放Lu扩展动态库。 | MLu | 否 |
UseLu | 申请进入或退出Lu工作区。 | MLu | - |
ComModule | 编译源程序为一个模块。 | MLu | 是 |
ExeModule | 执行程序(模块)。 | MLu | 是 |
DelModule | 删除模块。 | MLu | 是 |
InitLu | 初始化Lu。 | Lu核心库 | 禁止使用该函数 |
FreeLu | 释放Lu。 | Lu核心库 | 禁止使用该函数 |
GetRunErr | 获得Lu运行错误。 | Lu核心库 | 否 |
TestRunErr | 测试Lu运行错误。 | Lu核心库 | 否 |
SetRunErr | 设置Lu运行错误。 | Lu核心库 | 否 |
GC | 垃圾收集。 | Lu核心库 | 部分需要UseLu |
Lu核心库的其他输出函数 | 除了GetRunErr()、TestRunErr()、SetRunErr()及GC()的之外的Lu核心库函数。 | Lu核心库 | 是 |
在主调程序中可以设置(并非强制设置)一个全局变量int QuitMLu=0。然后将该变量的地址用InsertKey("mluQuit",7,luPriKey_User,&QuitMLu,DelKey,NULL,0,v)传送给Lu。当QuitMLu!=0时将退出MLu。规定仅在主线程中设置和修改该变量,但该变量可被任一线程所访问。
在主调程序或任一个Lu扩展动态库中均可以设置一个函数int_stdcall mluLoadModule(wchar_t *ModuleName)。然后将该函数的地址用InsertKey("mluLoadModule",13,luPubKey_User,mluLoadModule,NULL,NULL,0,v)传送给Lu,这样MLu就可以编译模块(每当遇到#USE#myModule语句,就将myModule传送给该函数进行处理);若不传送该函数,MLu就不能编译模块。该函数接受一个模块名,然后返回该模块的编译代码,代码的意义与函数ComModule(...)返回的编译代码意义相同(实际上,只有-6和-7两个代码须由该函数处理)。该函数必须能判断是否进行了模块的递归调用。任一线程均可设置该函数。
在主调程序或任一个Lu扩展动态库中均可以设置一个函数void _stdcallLuMessage(wchar_t *)。然后将该函数的地址用InsertKey("\0\0\0\0",4,luPubKey_User,LuMessage,NULL,NULL,0,v)传送给Lu。按约定,Lu核心库及所有Lu扩展库都使用该函数发送信息。任一线程均可根据需要设置该函数。
在主调程序中可用Lu的加锁函数LockKey锁定一个键的类型为字符串,然后将被锁定的键KeyType用InsertKey("mluErrStr",9,luPriKey_User,KeyType,DelKey,NULL,0,v)传送给Lu,这样MLu就可以给出更详细的运行错误说明。实际上,当出现运行错误时,MLu查找与出错函数名相同的键,键的类型为KeyType,其键值为一个字符串,该字符串包含了出错原因。该字符串格式如下:
#-2:...; #-1:...; #1:...; #2:错误2; #3:...; ... ...
例如,当运行错误代码为2时,将输出“#2:错误2;”中的“错误2”。每一个错误描述以“#”开头,后面紧跟错误代码和一个冒号“:”,冒号“:”后为错误说明,错误说明以分号“;”结尾。
2.3 使用MLu的一般步骤
(1)使用函数InitMLu进行初始化(必须)。
(2)使用函数LoadDll加载需要的Lu扩展库。
(3)使用函数ComModule将字符串源代码编译为模块(必须)。
(4)使用函数ExeModule执行模块,或者使用函数GetFor获取需要的表达式进行计算(必须)。
(5)使用函数SearchKey验证操作数据的类型,然后进行数据传送操作。
(6)使用函数FreeDll卸载Lu扩展库。
(7)使用函数FreeMLu释放资源(必须)。
3.1 MLu版本信息:mluver();
3.2 检测输出并清除Lu运行错误:err();
检测到错误时,该函数返回错误类型代码。错误类型代码如下:
0:没有运行错误!
1:表达式运行错误!
2:父表达式(基表达式)被删除!
3:二级函数被删除!
其他非0值:其他运行错误!
注意:当Lu键树中有一个被锁定为字符串的键给出运行错误说明时,MLu将试图找出出现运行错误的原因。请参考键mluErrStr的说明。
3.3 获得Lu运行错误:geterr(FunName,&FunCode,&ForHandle);
FunName:Lu字符串。返回出错函数名;若字符串长度太小,仅返回部分函数名;若不是一个字符串,什么也不做。当返回值等于2或3时,返回空字符串。
FunCode:当返回值等于1时,返回函数错误代码。当返回值等于2或3时,返回0。
ForHandle:返回出错表达式的句柄,该句柄即编译表达式时获得的句柄。若ForHandle=0,则运行出错的表达式已被销毁。
返回值:运行错误的类型。返回值=0:没有运行错误;返回值=1:表达式运行错误;返回值=2:父表达式被删除,父表达式即该表达式中所调用的表达式,也称基表达式;返回值=3:该表达式中所调用的二级函数被删除;返回值=其它值:其它类型运行错误。
例子:f(:a,b,c,d)= seterr[66,"aaa",23], a=geterr[b="\[10]",&c,&d], o[b];
3.4 设置Lu运行错误:seterr(ErrType,FunName,FunCode);
ErrType:设置运行错误的类型。ErrType=0:没有错误;ErrType=1:表达式运行错误;不要设置ErrType=2或ErrType=3,这两个值由系统自动设置;ErrType=其它值:其它类型运行错误。
FunName:设置出错的函数名,要求传递一个Lu字符串(长度小于255)。
FunCode:设置函数错误代码。
返回值:false:非法的Lu字符串地址、ErrType=2或ErrType=3;true:成功返回。
例子:f(:a,b,c,d)= seterr[66,"aaa",23], a=geterr[b="\[10]",&c,&d], o[b];
3.5 清除Lu运行错误:clearerr();
3.6 停止函数:stop[];
该函数并不立即停止执行程序,只是在执行完本表达式后停止程序的执行。
若要立即停止程序的执行,需要在stop[]函数后紧跟一个从表达式立即返回的函数return[]。
例如:
{stop[],o["停止程序!"]};//输出了字符串之后,停止程序执行;
{stop[].return[],o["本字符串不会输出!"]}; //立即停止程序执行;
3.7 输出控制函数:SetTalk[bool];
缺省情况下,MLu的ExeModule()函数每计算完一个表达式,就输出该表达式的值。SetTalk[]函数用于设置是否输出表达式的值。当bool为true时,输出表达式的值;当bool为false时,不输出表达式的值,直到再一次遇到SetTalk[true]。注意当bool为false时,并不关闭其他函数的输出。
3.8 编译源程序为一个模块:ComModule(Str,&nModule,&hModule,&err1,&err2);
Str:源程序字符串;
nModule:当nModule为0时,所有模块的模块号自动指定(MLu初始化时,设置最初的起始模块号为1,以后不断递增,但不一定连续,因为每次执行该函数,不管是否执行成功,模块号均加1),不会重复,也不会被编译为0#模块。任何时候,可用nModule传送给MLu一个起始模块号(必须大于0),以后的模块号将在该模块号的基础上递增,从而改变模块号序列。若要自己指定模块号,则每次编译源程序前,均指定一个起始模块号。MLu编译的多个模块序号是递增的,但不一定连续,因为如果MLu加锁一个模块不成功,就会继续加锁下一个模块号。函数返回时,nModule返回多个模块的最小模块号。一般返回主模块号,如果主模块中没有表达式,就返回有表达式的最小子模块号。
hModule:返回模块的句柄。当该模块不用时,就用delete(hModule)立即销毁该模块,否则将导致某些全局函数无法编译。
err1和err2:返回编译出错位置,该值是否有意义取决于函数的返回值(返回值为-1、0、1、3、-2时无意义)。
该函数返回值的意义参考MLu的输出函数ComModule的说明。
例子:
mvar:
main(:a)=
t0=clock(), s=0, i=0,
while{++i<=10000,
//动态编译模块,该模块有2个函数,f为私有函数,ff为全局函数
ComModule["f(x)=x+1; :::ff(x,y)=f(x)+y;",0,&me,0,0],
a=HFor("ff"), //获得函数ff的句柄
s=s+a[1,1], //动态调用函数ff
delete[me] //立即销毁模块
},
s;
[clock()-t0]/1000.;
4.1 源程序的一般格式 [目录]
在MLu源文件中,可以有多个Lu表达式,表达式之间用分号“;”隔开。两个连续的分号“;;”表示前面的表达式在执行时不会输出结果。
若表达式以mvar:开头,表示自该表达式开始,后面的表达式允许使用未定义的模块变量;若表达式以unmvar:开头,表示取消这种设置。mvar:和unmvar:仅在当前模块起作用。
在源文件中可以进行注释,注释方法与C++语言相似,即:每行两个//后的内容为注释内容;在一行内或者多行之间/*...*/之间的内容为注释内容。注释不是源程序的有效部分,但可以使程序更易读。
举例如下:
//这是一个例子!灰色部分为注释,不会被执行;
2+3; //整数表达式
2.2+3.3; //实数表达式
sin(2.2+3.3i); //复数表达式
2+3;/* 从这里开始,连续几行注释:
333+222;
. . . . . . ;
555-222;
*/ sin(2.5);
exp(2.);
4.2 程序的执行 [目录]
由于表达式有些带有参数,有些不带参数,MLu在进行处理时,对于有参数的表达式只进行编译,不进行计算。
MLu只顺序执行不带参数的表达式。如果该表达式以两个连续的分号“;;”结尾,则该表达式只执行,不输出计算结果。
但是,如果表达式以~~~开头,则无论是有参表达式还是无参表达式,都是只编译,不执行,格式如下:
~~~ 2+3; //整数无参表达式,只编译,不执行
~~~ f1()=2+3; //整数无参表达式,只编译,不执行
~~~ 2.0+3; //实数无参表达式,只编译,不执行
~~~ f2()=2+3.0; //实数无参表达式,只编译,不执行
~~~ 2+3i; //复数无参表达式,只编译,不执行
~~~ f3()=2+3i; //复数无参表达式,只编译,不执行
无参表达式f1、f2和f3可以在其他可执行的表达式中被调用。
另外,如果无参表达式以感叹号!!!开头,则编译后立即执行,且以后执行模块时不再自动执行。格式如下:
!!! 2+3; //整数无参表达式,编译成功,立即执行,以后不再自动执行
!!! f1()=2+3; //整数无参表达式,编译成功,立即执行,以后不再自动执行
!!! 2.0+3; //实数无参表达式,编译成功,立即执行,以后不再自动执行
!!! f2()=2+3.0; //实数无参表达式,编译成功,立即执行,以后不再自动执行
!!! 2+3i; //复数无参表达式,编译成功,立即执行,以后不再自动执行
!!! f3()=2+3i; //复数无参表达式,编译成功,立即执行,以后不再自动执行
无参表达式f1、f2和f3可以在其他可执行的表达式中被调用。
编译时,将源程序中的表达式编译为一个或多个模块,MLu会对每一个模块进行加锁。编译时首先设置起始模块,也称主模块(并非Lu的0#模块,恰恰相反,MLu不会将任何一个表达式编译为0#模块,定义主模块是为了与源程序中的其他模块相区别),以后每当遇到#MODULE#,开始编译为一个新的模块,称为子模块,而每当遇到#END#,回到主模块的编译。即#MODULE#和#END#之间的表达式定义为一个子模块,子模块之间不能嵌套定义。注意#MODULE#和#END#必须位于表达式的开头。
在模块中,以:::开头的表达式被编译为公有表达式(全局表达式或全局函数),能被其他模块访问到,其余的表达式均被编译为私有表达式(私有函数),其他模块无法访问。所有模块的模块号由MLu或程序员指定,不会重复,也不会被编译为0#模块。在源程序的任何地方,可用指令#USE#调用另一个模块。
模块源文件的格式如下:
//单行注释:模块名:myModule
/*
多行注释:在同一模块源文件中的所有表达式属于同一个模块;
多行注释:以~开头的表达式可被其他模块的表达式所访问;
多行注释:不以~开头的表达式只能被该模块的表达式所访问。
*/
#MODULE# //定义一个子模块;
a(x)=10+x; //私有函数,只能被该模块的表达式所访问;
!!!b()=100+100i; //私有函数,只能被该模块的表达式所访问,该表达式是在编译时执行的;
:::c(x)=x-5; //全局函数,任意模块包括本模块均可访问;
:::f(x)=a(x)+b(); //全局函数,任意模块包括本模块均可访问;
:::g(x)=a(x)+c(x); //全局函数,任意模块包括本模块均可访问;
#USE# Module1; //使用模块Module1;
ff(5)+gg(6); //函数ff()和gg()在模块Module1中定义;
#END# //子模块定义结束,可缺省;
#MODULE# //定义一个子模块;
a(x)=10-x; //私有函数,只能被该模块的表达式所访问;
:::ff(x)=a(x); //全局函数,任意模块包括本模块均可访问;
#END# //子模块定义结束,不可缺省;
f(1); //主模块中的表达式。
ff(1); //主模块中的表达式。
在其他模块中使用该模块的格式如下:
#USE# myModule; //关键字USE必须为大写,myModule是模块名称;
f(2)+g(3); //调用myModule模块中定义的函数;
4.4 编译指令的位置和次序 [目录]
在MLu中使用的 #MODULE#、#END#、#USE#、mvar:、unmvar:、:::、!!!、~~~ 等称为编译指令,用以确定一个表达式所在模块、是否私有函数等属性。这些编译指令必须位于表达式的开头,有些指令能同时使用,有些指令不能同时使用,并且在使用时有一定的次序,按先后顺序依次为:
1)编译指令#MODULE#、#END#、#USE#、mvar:和unmvar:之间没有先后顺序,可混合使用,但这些指令必须在表达式的最前面,一般单独成行。注意mvar:和unmvar:只在本模块内有效。
2)编译指令!!!、~~~不能混合使用,只能使用其中的一个。~~~表示该表达式只编译,不执行;!!!表示该表达式编译后立即执行,但以后执行模块时不再自动执行。
3):::表示该表达式是一个全局表达式,否则是私有表达式。
如果表达式前没有使用任何一个编译指令,则按缺省表达式的类型编译为私有表达式,若该表达式是无参表达式,则执行模块时将自动执行。
5.1 隐式加载例子
该例子需要以下支持文件:
(1)头文件lu32.h。
(2)导入库lu32.lib及mlu32.lib。
(3)核心库lu32.dll和模块化编译运行库mlu32.dll。
#include <windows.h>
#include <iostream>
#include "lu32.h" //Lu头文件
#pragma comment( lib, "lu32.lib" )
#pragma comment( lib, "mlu32.lib" )
using namespace std;
void main(void)
{
void *hModule; //模块句柄
luINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置
int i; //错误代码
void *hFor; //表达式句柄
luVOID nModule=0; //表达式所在模块
void *vPara; //存放输入自变量的数组指针
LuData *pPara; //存放输入自变量的数组指针
luINT nPara; //存放表达式的自变量个数
LuData Val; //存放表达式的值
wchar_t ForStr[]=L"f(x)=x+1; :::ff(x,y)=f(x)+y;"; //Lu模块化源程序
if(!InitMLu()) return; //初始化MLu
if(!UseLu(2)) //申请使用Lu资源
{
i=ComModule(ForStr,nModule,hModule,ErrBegin,ErrEnd); //编译Lu源程序
if(i)
{
cout<<"Lu源程序有错误!错误代码:"<<i<<endl;
}
else
{
if(GetFor(L"ff",1,NULL,nModule,hFor,vPara,nPara)) //查找全局函数
{
pPara=(LuData *)vPara;
for(i=0;i<=nPara;i++) //表达式自变量赋值,均赋值为1
{
pPara[i].BType=luStaData_int64; pPara[i].VType=luStaData_int64; pPara[i].x=1;
}
Val=LuCal(hFor,pPara); //计算表达式的值
cout<<Val.x<<endl;
}
else
{
cout<<"找不到指定的函数!"<<endl;
}
}
UseLu(0); //归还Lu的使用权
}
FreeMLu(); //释放MLu
}
结果:
3
请按任意键继续. . .
5.2 显式加载例子
该例子需要以下支持文件:
(1)头文件lu32.h。
(2)核心库lu32.dll和模块化编译运行库mlu32.dll。
#include <windows.h>
#include <iostream>
#include "Lu32.h"
using namespace std;
HINSTANCE hMLu=NULL; //动态库MLu32.dll的句柄
//MLu输出函数
mluInitMLu pInitMLu;
mluFreeMLu pFreeMLu;
mluGetLuProc pGetLuProc;
mluUseLu pUseLu;
mluComModule pComModule;
//Lu输出函数
luGetFor pGetFor;
luLuCal pLuCal;
bool theInitMLu(void) //初始化MLu
{
hMLu=LoadLibrary(L"MLu32.dll"); //加载动态库MLu32.dll
if(!hMLu)
{
cout<<"找不到MLu32.dll!请将该库放到WINDOWS的搜索路径内!";
return false;
}
//以下几个语句获取MLu32.dll的输出函数
pInitMLu=(mluInitMLu) GetProcAddress(hMLu,"InitMLu");
pFreeMLu=(mluFreeMLu) GetProcAddress(hMLu,"FreeMLu");
pGetLuProc=(mluGetLuProc) GetProcAddress(hMLu,"GetLuProc");
pUseLu=(mluUseLu) GetProcAddress(hMLu,"UseLu");
pComModule=(mluComModule) GetProcAddress(hMLu,"ComModule");
if(!pInitMLu()) //初始化MLu32.dll
{
FreeLibrary(hMLu); //释放动态库
cout<<"MLu初始化失败!";
return false;
}
//以下几个语句获取Lu32.dll的输出函数
pGetFor=(luGetFor) pGetLuProc("GetFor");
pLuCal=(luLuCal) pGetLuProc("LuCal");
return true;
}
void theFreeMLu(void) //释放MLu
{
pFreeMLu(); //释放MLu申请的空间
FreeLibrary(hMLu); //释放动态库
}
void main(void)
{
void *hModule; //模块句柄
luINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置
int i; //错误代码
void *hFor; //表达式句柄
luVOID nModule=0; //表达式所在模块
void *vPara; //存放输入自变量的数组指针
LuData *pPara; //存放输入自变量的数组指针
luINT nPara; //存放表达式的自变量个数
LuData Val; //存放表达式的值
wchar_t ForStr[]=L"f(x)=x+1; :::ff(x,y)=f(x)+y;"; //Lu模块化源程序
if(!theInitMLu()) return; //初始化MLu
if(!pUseLu(2)) //申请使用Lu资源
{
i=pComModule(ForStr,nModule,hModule,ErrBegin,ErrEnd); //编译Lu源程序
if(i)
{
cout<<"Lu源程序有错误!错误代码:"<<i<<endl;
}
else
{
if(pGetFor(L"ff",1,NULL,nModule,hFor,vPara,nPara))
{
pPara=(LuData *)vPara;
for(i=0;i<=nPara;i++) //表达式自变量赋值,均赋值为1
{
pPara[i].BType=luStaData_int64; pPara[i].VType=luStaData_int64; pPara[i].x=1;
}
Val=pLuCal(hFor,pPara); //计算表达式的值
cout<<Val.x<<endl;
}
else
{
cout<<"找不到指定的函数!"<<endl;
}
}
pUseLu(0); //归还Lu的使用权
}
theFreeMLu(); //释放MLu
}
结果:
3
请按任意键继续. . .
版权所有© Lu程序设计 2011-2011,保留所有权利
E-mail: forcal@sina.com QQ:630715621
最近更新: 2011年10月30日