欢迎访问 Lu程序设计

MLu32.dll V1.0 使用说明

目 录

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运行监视器，以退出耗时较长的程序；提供在脚本中动态编译函数的功能；提供错误处理函数，实现错误（异常）处理的恢复模型等等。

1 MLu的输出函数 [目录]

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扩展动态库。
例如："LuMath32","d:\\lu\\LuSystem32.dll"

需要注意Lu扩展动态库的加载顺序。

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 执行模块：void _stdcall ExeModule(void *hModule,void (_stdcall *outlu)(LuData *LD));

hModule：编译源程序时得到的模块的句柄。
outlu：输出表达式的值。这个回调函数在执行表达式时被调用，输出信息。该参数可设为NULL。
注意1：该函数只执行模块中的无参表达式。
注意2：当Lu键树中有一个被锁定为字符串的键给出运行错误说明时，MLu将试图找出出现运行错误的原因。请参考 键mluErrStr的说明。

1.10 删除模块：void _stdcall DelModule(void *hModule);

hModule：编译源程序时得到的模块的句柄。

2 如何加载使用MLu [目录]

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 | 得到Lu32.dll的句柄。 | MLu | 否
GetLuProc | 得到Lu32.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# my Module语句，就将 my Module 传送给该函数进行处理）；若不传送该函数，MLu就不能编译模块。该函数接受一个模块名，然后返回该模块的编译代码，代码的意义与函数 ComModule(...)返回的编译代码意义相同（实际上，只有-6和-7两个代码须由该函数处理）。该函数必须能判断是否进行了模块的递归调用。任一线程均可设置该函数。

在主调程序或任一个Lu扩展动态库中均可以设置一个函数void _stdcall LuMessage(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”。每一个错误描述以“#”开头，后面紧跟错误代码和一个冒号“:”，冒号“:”后为错误说明，错误说明以分号“;”结尾。

请参考函数 ExeModule 和 err 的说明。

2.3 使用MLu的一般步骤

（1）使用函数InitMLu进行初始化（必须）。

（2）使用函数LoadDll加载需要的Lu扩展库。

（3）使用函数ComModule将字符串源代码编译为模块（必须）。

（4）使用函数ExeModule执行模块，或者使用函数GetFor获取需要的表达式进行计算（必须）。

（5）使用函数SearchKey验证操作数据的类型，然后进行数据传送操作。

（6）使用函数FreeDll卸载Lu扩展库。

（7）使用函数FreeMLu释放资源（必须）。

3 二级函数 [目录]

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 模块源文件 [目录]

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可以在其他可执行的表达式中被调用。

4.3 源程序中的模块 [目录]

编译时，将源程序中的表达式编译为一个或多个模块，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 例子 [目录]

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;		//表达式所在模块
    	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
> 请按任意键继续. . .

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;		//表达式所在模块
    	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-2013，保留所有权利
E-mail: forcal@sina.com QQ：630715621
最近更新: 2013年09月10日