欢迎访问 Lu程序设计

MLu64.dll V2.0 使用说明

目  录

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。这两个函数可准确定位运行错误。


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 初始化MLuint _stdcall InitMLu(void);

    MLu初始化后才能使用。该函数对MLu进行初始化,成功时返回非0值,返回0表示初始化失败。可使用该函数对MLu重新初始化,但必须关闭主程序中正在运行的Lu程序。

1.2 释放MLuvoid _stdcall FreeMLu(void);

    在使用完MLu之后必须用该函数释放加载的资源。

1.3 得到Lu核心库的句柄HINSTANCE _stdcall GetLuHandle(void);

    MLu会自动加载Lu核心库,该函数用于获得Lu核心库的句柄。

    警告:不要使用Lu核心库的InitLuFreeLu两个函数。

1.4 得到Lu核心库的输出函数void * _stdcall GetLuProc(char *name);

    name是Lu核心库的输出函数名。

    警告:不要使用Lu核心库的InitLuFreeLu两个函数。

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 如何加载使用MLu  [目录]

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-1luPoiKey_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锁定一个键的类型为字符串,然后将被锁定的键KeyTypeInsertKey("mluErrStr",9,luPriKey_User,KeyType,DelKey,NULL,0,v)传送给Lu,这样MLu就可以给出更详细的运行错误说明。实际上,当出现运行错误时,MLu查找与出错函数名相同的键,键的类型为KeyType,其键值为一个字符串,该字符串包含了出错原因。该字符串格式如下:

    #-2:...; #-1:...; #1:...; #2:错误2; #3:...; ... ...

    例如,当运行错误代码为2时,将输出“#2:错误2;”中的“错误2”。每一个错误描述以“#”开头,后面紧跟错误代码和一个冒号“:”,冒号“:”后为错误说明,错误说明以分号“;”结尾。

    请参考函数ExeModuleerr的说明。

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,&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)立即销毁该模块 ,否则将导致某些全局函数无法编译。
    err1err2:返回编译出错位置,该值是否有意义取决于函数的返回值(返回值为-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)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日