目 录
MLu说明 | 基于MLu的Lu扩展动态库 |
1 MLu的输出函数 2 如何使用MLu 3 二级函数 4 模块源文件 5 例子 |
1 OpenLuGl:基于OpenGL的图形库 |
MLu是程序和Lu核心库之间的一个接口库,MLu会自动加载Lu核心库和动态加载多个Lu扩展库,简化了Lu系统的使用;MLu可对Lu源程序进行模块化编译,能够编译运行具有固定格式的源程序(字符串表达式),源程序中可以使用C++风格的注释。此外,MLu还提供了多个线程互斥地访问Lu资源的功能;提供了Lu运行监视器,以退出耗时较长的程序;提供在脚本中动态编译函数的功能;提供错误处理函数,实现错误(异常)处理的恢复模型等等。
与MLu V1.0相比,Mlu V2.0更新了输出函数ExeModule和二级函数geterr。这两个函数可准确定位运行错误。
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 _stdcall InitMLu(void);
MLu初始化后才能使用。该函数对MLu进行初始化,成功时返回非0值,返回0表示初始化失败。可使用该函数对MLu重新初始化,但必须关闭主程序中正在运行的Lu程序。
1.2 释放MLu:void _stdcall FreeMLu(void);
在使用完MLu之后必须用该函数释放加载的资源。
1.3 得到Lu核心库的句柄:HINSTANCE _stdcall GetLuHandle(void);
MLu会自动加载Lu核心库,该函数用于获得Lu核心库的句柄。
警告:不要使用Lu核心库的InitLu和FreeLu两个函数。
1.4 得到Lu核心库的输出函数:void * _stdcall GetLuProc(char *name);
name是Lu核心库的输出函数名。
警告:不要使用Lu核心库的InitLu和FreeLu两个函数。
1.5 加载Lu扩展动态库:void _stdcall LoadDll(wchar_t *DllStr);
DllStr:含有Lu扩展动态库名称的字符串。
允许加载多个Lu扩展动态库。Lu扩展动态库名字要放在双引号"..."之间。忽略在尖括号<"..." ...>内的Lu扩展动态库。
需要注意Lu扩展动态库的加载顺序。
例如:"LuMath64","d:\\lu\\LuSystem64.dll"
加载Lu扩展动态库的名字后允许使用冒号:"dll\LuOpt64.dll:601508320",冒号后的字符串将传递给扩展库的唯一输出函数LuDll64的参数me,可用于验证用户能否使用该库。
//Lu扩展动态库唯一的输出函数;
//hLu:Lu64.dll的句柄;iInit!=0:初始化动态库,iInit=0:释放动态库;
//me:指向任意数据的指针,可用于验证用户能否使用该库,为了方便验证,约定该指针指向一个wchar_t类型的字符串。
//iInit!=0时,返回值LuDll=0:初始化失败;LuDll=1:初始化成功;返回值LuDll=2:初始化成功,仅注册一些常量,初始化完成后可卸载该库。
//iInit=0时,返回值LuDll=0:释放失败;LuDll=1:释放成功;
extern
"C" int _stdcall LuDll64(HINSTANCE hLu,int iInit,void *me)
{
.
.
.
if(iInit) //初始化动态库
{
.
.
.
return 1;
}
else //释放动态库
{
.
.
.
return 1;
}
}
1.6 释放Lu扩展动态库:void _stdcall FreeDll(void);
1.7 申请进入或退出Lu工作区:int _stdcall UseLu(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 编译源程序:ComModule
//C++定义
int
_stdcall ComModule(wchar_t *LuStr,luVOID &nModule,void
*&hModule,luINT &err1,luINT &err2);
//C定义
int
_stdcall ComModule(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 执行模块:int _stdcall ExeModule(void *hModule,void (_stdcall *outlu)(LuData *LD),void *&hErrModule,luINT &err1,luINT &err2);
hModule:编译源程序时得到的模块的句柄
。如果hModule=0,不执行模块中的表达式,仅获取当前运行错误。
outlu:输出表达式的值。这个回调函数在执行表达式时被调用,输出信息。该参数可设为NULL。
注意1:该函数只执行模块中的无参表达式。
注意2:当Lu键树中有一个被锁定为字符串的键给出运行错误说明时,MLu将试图找出出现运行错误的原因。请参考
键mluErrStr的说明。
hErrModule:返回出现运行错误的模块句柄,该句柄为使用输出函数ComModule或二级函数ComModule编译源程序时得到,与源程序相关联。
若hErrModule=0,则运行出错的表达式非Mlu所编译。
err1:返回出现运行错误时源程序中的代码当前位置,即运行至此位置时出现运行错误
,故错误是当前位置的前一个运算(在该位置附近,有可能在前面,也有可能在后面)引起的。当前位置通常有一个或多个字符,其末位置由参数err2返回。
err2:返回出现运行错误时源程序中的代码末位置。
返回值:正常运行时返回0,否则出现运行错误。
1.10 删除模块:void _stdcall DelModule(void *hModule);
hModule:编译源程序时得到的模块的句柄。
2.1 MLu的加载和卸载
(1)隐式调用
使用MLu核心库的导入库文件mlu64.lib。这种方法比较方便。
(2)显示调用
应用程序可调用LoadLibrary直接加载MLu64.dll。
HANDLE hMLu;
//动态库模块句柄
hMLu=LoadLibrary(L"MLu64.dll");
//加载动态库MLu64.dll
加载MLu64.dll成功后,需调用函数GetProcAddress获取MLu输出函数的地址。例如:
mluInitMLu pInitMLu;
//mluInitLu 在头文件Lu64.h中定义,为初始化MLu的函数指针;
pInitMLu=(mluInitLu) GetProcAddress(hMLu,"InitMLu");
该函数获得了初始化MLu的函数地址,保存在指针pInitMLu中。
当程序不再需要访问MLu64.dll时,应调用函数FreeLibrary将其卸载。
FreeLibrary(hMLu); //释放动态库MLu64.dll;
2.2 MLu使用说明
MLu加载成功后,必须先用函数InitMLu进行初始化;在卸载MLu之前,要用函数FreeMLu释放使用的资源。
因MLu对多线程中使用Lu提供了支持,故在使用Lu及MLu的许多输出函数时,须先使用函数UseLu获得使用Lu的许可,并在用完Lu后,及时归还Lu资源的使用权。 参见下表:
函 数 | 说 明 | 来 源 | 是否需要UseLu |
InitMLu | 初始化MLu。 | MLu | 否 |
FreeMLu | 释放MLu。 | MLu | 否 |
GetLuHandle | 得到Lu64.dll的句柄。 | MLu | 否 |
GetLuProc | 得到Lu64.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核心库 | 是 |
在MLu中使用了 luPriKey_User-1 和 luPoiKey_User-1 两个私有键,故主程序及所加载的Lu扩展库不能再使用这两个键。
在主调程序或任一个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 _stdcall LuMessage(wchar_t *)。然后将该函数的地址用InsertKey("\0\0\0\0\0\0\0\0",8,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,&hModule,&err1,&err2);
FunName:Lu字符串。返回出错函数名;若字符串长度太小,仅返回部分函数名;若不是一个字符串,什么也不做。当返回值等于2或3时,返回空字符串。
FunCode:当返回值等于1时,返回函数错误代码。当返回值等于2或3时,返回0。
ForHandle:返回出错表达式的句柄,该句柄即编译表达式时获得的句柄。若ForHandle=0,则运行出错的表达式已被销毁。
hModule:返回出现运行错误的模块句柄,该句柄为使用输出函数ComModule或二级函数ComModule编译源程序时得到,与源程序相关联。
err1:返回出现运行错误时源程序中的代码当前位置,即运行至此位置时出现运行错误,故错误是当前位置的前一个运算引起的。当前位置通常有一个或多个字符,其末位置由参数err2返回。
err2:返回出现运行错误时源程序中的代码末位置。
返回值:运行错误的类型。返回值=0:没有运行错误; 返回值<0:运行警告;返回值=1:表达式运行错误;返回值=2:父表达式被删除,父表达式即该表达式中所调用的表达式,也称基表达式;返回值=3:该表达式中所调用的二级函数被删除;返回值=其它值:其它类型运行错误。
例子:f(: a, b, c, d, e, f, g) = seterr[66, "aaa", 23], a = geterr[b="\[10]", &c, &d, &e, &f, &g], 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:成功返回。
注意:由于Lu只保存出现的第一个运行错误或警告,故Lu有可能忽略本次设置。若先设置了警告,后设置错误,则警告信息将被丢弃。
例子:f(: a, b, c, d, e, f, g) = seterr[66, "aaa", 23], a = geterr[b="\[10]", &c, &d, &e, &f, &g], 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)C++版本的头文件lu64.h。
(2)导入库lu64.lib及mlu64.lib。
(3)核心库lu64.dll和模块化编译运行库mlu64.dll。
#include <windows.h> #include <iostream> #include "lu64.h" //Lu头文件
#pragma comment( lib, "lu64.lib" ) #pragma comment( lib, "mlu64.lib" )
using namespace std;
void main(void) { void *hModule; //模块句柄 luINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置 int i; //错误代码 void *hFor; //表达式句柄 luVOID nModule=0; //表达式所在模块 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,pPara,nPara)) //查找全局函数 { 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
请按任意键继续. . .
如果使用C版本的头文件lu64.h,代码如下:
#include <stdio.h> #include "lu64.h" //Lu头文件 #pragma comment( lib, "lu64.lib" ) #pragma comment( lib, "mlu64.lib" ) void main(void) { void *hModule; //模块句柄 luINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置 int i; //错误代码 void *hFor; //表达式句柄 luVOID nModule=0; //表达式所在模块 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) { printf("Lu源程序有错误!错误代码:%d\r\n",i); } else { if(GetFor(L"ff",1,NULL,&nModule,&hFor,&pPara,&nPara)) //查找全局函数 { 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); //计算表达式的值 printf("%u\r\n",Val.x); } else { printf("找不到指定的函数!"); } } UseLu(0); //归还Lu的使用权 } FreeMLu(); //释放MLu }
5.2 显式加载例子
该例子需要以下支持文件:
(1)头文件lu64.h。
(2)核心库lu64.dll和模块化编译运行库mlu64.dll。
#include <windows.h> #include <iostream> #include "Lu64.h"
using namespace std;
HINSTANCE hMLu=NULL; //动态库MLu64.dll的句柄 //MLu输出函数 mluInitMLu pInitMLu; mluFreeMLu pFreeMLu; mluGetLuProc pGetLuProc; mluUseLu pUseLu; mluComModule pComModule; //Lu输出函数 luGetFor pGetFor; luLuCal pLuCal;
bool theInitMLu(void) //初始化MLu { hMLu=LoadLibrary(L"MLu64.dll"); //加载动态库MLu64.dll if(!hMLu) { cout<<"找不到MLu64.dll!请将该库放到WINDOWS的搜索路径内!"; return false; } //以下几个语句获取MLu64.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()) //初始化MLu64.dll { FreeLibrary(hMLu); //释放动态库 cout<<"MLu初始化失败!"; return false; } //以下几个语句获取Lu64.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; //表达式所在模块 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,pPara,nPara)) { 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-2021,保留所有权利
E-mail:
forcal@sina.com
QQ:630715621
最近更新:
2021年06月14日