C/C++使用Lu脚本中的动态对象lu

来源:互联网 发布:excel数据汇总 编辑:程序博客网 时间:2024/05/17 22:58


欢迎访问Lu程序设计

C/C++使用Lu脚本中的动态对象lu

1 说明

    要演示本文的例子,你必须下载Lu32脚本系统。本文的例子需要lu32.dll、lu32.lib、C格式的头文件lu32.h,相信你会找到并正确使用这几个文件。

    用C/C++编译器创建一个控制台应用程序,复制本文的例子代码直接编译运行即可。

2 关于动态对象及lu动态对象

    在本教程系列的开始,介绍了Lu脚本的基本数据结构(详细参考Lu编程指南),即:

struct LuData{    //Lu基本数据结构。
    luIFOR x;    
//luIFOR被定义为64位整数__int64,用于存放数据。对于动态数据类型,对象指针约定保存在x的前4个字节中
    luIFOR y;    
//存放数据。
    luIFOR z;    
//存放数据。
    luKEY  VType;
//luKEY被定义为32位整数__int32。扩展数据类型,决定重载函数,从而决定了对数据的操作方式。
    luKEY  BType;
//基本数据类型,决定了Lu数据的结构。
};

    基本数据类型BType决定了实际的数据结构 。静态类型数据最多存放24个字节的数据,类似于字符串、数组等占用字节数可多可少,或者占用字节数超过24的数据,Lu脚本中称之为动态数据类型(或者称为动态对象)。对于动态对象,在Lu基本数据结构LuData中只保存动态对象的指针,对象的32位指针保存在LuData::x的前32位中。 本节以动态对象lu为例,介绍如何使用动态对象。

    动态对象lu是一个线性表(简称Lu表,可以保存任何数据,包括任意多个lu表),是Lu脚本的基本数据类型,参考C格式的头文件lu32.h,动态对象lu的结构定义如下:

//动态Lu表
typedef struct luLu
{
    LuData *Lu;
//允许为NULL
    luVOID Len;
//Lu数据缓冲区长度
} luLu;

    Lu表在Lu系统键树中的键值(即基本数据类型BType)为luDynData_lu,参考头文件lu32.h中的定义:

#define luDynData_lu -255 //动态Lu数据

    Lu动态对象保存在Lu字符串键树中(不仅可以保存动态数据,任意数据都可以),Lu键树保存数据的格式如下:

KeyStr:键的名称(char *KeyStr)。区分大小写,可包含任意字符,包括NULL('\0')。
ByteNum:键的长度(luINT ByteNum)。ByteNum>0
KeyType:键的类型(luKEY KeyType)。

    也就是说,数据与键的名称、长度、类型是一一对应的关系。设指针plu指向一个luLu类型的指针对象,则该对象在Lu键树中是按如下格式保存的(其他动态对象都有类似的格式):

KeyStr(char *)&plu   //将指针转换为一个字符串
ByteNumsizeof(luVOID)//取指针的大小,32位平台上为4个字节,动态对象的键长总是4个字节
KeyTypeluDynData_lu  //键的类型

    那么,该如何使用一个动态对象呢?由于Lu基本数据结构中只保存了动态对象的指针,该指针是否真正有效(有很多原因会导致指针失效,例如对象已销毁,或者对该指针不负责任地修改等;与其他脚本不同,Lu脚本中允许用户用delete立即销毁一个对象),在使用之前必须进行验证。对动态对象验证(即在Lu系统中查找一个键)的函数为SearchKey, 用法非常简单:

void * _stdcall SearchKey(char *KeyStr,luINT ByteNum,luKEY KeyType); //参数意义如前所述,返回指向键值(动态对象)的指针,或者返回NULL。

    顺便说一下,Lu与C/C++交互、或者Lu与脚本用户交互时,对动态对象的管理,灵活而方便。C/C++可以向Lu系统注册对象,也可以方便地销毁对象;脚本用户随时可以生成动态对象,也可以立即销毁动态对象。脚本用户使用动态对象没有任何限制,但C/C++程序要注意两点:(1)多线程程序设计中,多数情况下,各线程要互斥访问Lu系统;(2)使用一个动态对象前,要用SearchKey函数,或者其他专用的函数,对动态对象进行验证。以后我们会提供这方面的例子。

    在成千上万个动态对象的Lu系统中,如果你对SearchKey函数的效率有怀疑,可以自己测试一下。

3 代码

#include <stdio.h>#include "lu32.h"#pragma comment( lib, "lu32.lib" )void PrintLu(LuData *pVal)//输出lu对象的值,仅支持整数、实数、lu对象{luLu *plu;//lu对象指针static luLu *pmainlu=NULL;//记住最初的lu对象,避免该函数无穷递归调用static int k;int j;luVOID i;if(pVal->BType!=luDynData_lu) return;//验证lu对象是否有效plu=(luLu *)SearchKey((char *)&(pVal->x), sizeof(luVOID), luDynData_lu);if(NULL==plu){printf("无效的lu对象指针!\n");return;}if(plu==pmainlu){printf("这是个递归嵌套的lu对象!\n");return;}if(pmainlu==NULL) pmainlu=plu;  //记住最初的lu对象k++;for(i=0;i<plu->Len;i++){for(j=0;j<k;j++) printf("lu:");if(plu->Lu[i].BType==luStaData_int64){printf(" %I64d \n",plu->Lu[i].x);}else if(plu->Lu[i].BType==luStaData_double){printf(" %f \n",*(double *)&(plu->Lu[i].x));}else if(plu->Lu[i].BType==luDynData_lu){printf(" >>\n");PrintLu(plu->Lu+i);  //递归调用for(j=0;j<k;j++) printf("lu:");printf(" <<\n");}else{printf(" 对象不可识别 %I64d \n",plu->Lu[i].x);}}k--;}void main(void){void *hFor;//表达式句柄luINT nPara;//存放表达式的自变量个数LuData *pPara;//存放输入自变量的数组指针luINT ErrBegin,ErrEnd;//表达式编译出错的初始位置和结束位置int ErrCode;//错误代码LuData Val;//Lu基本数据类型wchar_t ForStr[]=L"global(true), lu{1,lu[-2.2,lu(3,lu(-4,4.4),33),-22],11.0,lu[-2,22.2],111}";//字符串表达式if(!InitLu()) return;//初始化LuErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd);  //编译表达式if(ErrCode){printf("表达式有错误!错误代码: %d \n",ErrCode);}else{Val=LuCal(hFor,pPara);//计算表达式的值if(Val.BType==luDynData_lu) PrintLu(&Val);//输出lu对象的值}FreeLu();//释放Lu}

运行结果:

lu: 1
lu: >>
lu:lu: -2.200000
lu:lu: >>
lu:lu:lu: 3
lu:lu:lu: >>
lu:lu:lu:lu: -4
lu:lu:lu:lu: 4.400000
lu:lu:lu: <<
lu:lu:lu: 33
lu:lu: <<
lu:lu: -22
lu: <<
lu: 11.000000
lu: >>
lu:lu: -2
lu:lu: 22.200000
lu: <<
lu: 111

4函数说明

    本例用到了Lu的5个输出函数:初始化Lu的函数InitLu,释放Lu的函数FreeLu,编译表达式的函数LuCom、 计算表达式的函数LuCal、查找键值函数SearchKey。从这里查看这些函数的说明:Lu编程指南

5 难点分析

    本例专门设计了一个函数PrintLu用 来输出Lu对象的值,采用深度优先递归调用方式工作。

    根据规定,Lu脚本函数中生成的动态对象都是局部对象,在函数执行完毕后会自动销毁(会暂时存放到垃圾对象缓冲区中),为了使函数执行完毕动态对象仍然有效,在Lu字符串表达式中使用了函数global(true),该函数用法如下:

    global(p)将局部动态对象p转换为全局动态对象。另外,在global(true),... ...,global(false)之间生成的动态对象都为全局动态对象。

    另外,local(p)将全局动态对象p转换为局部动态对象。

    实现类似功能的更好的字符串表达式定义是:lu{1,lu[-2.2,lu(3,lu(-4,4.4),33),-22],11.0,lu[-2,22.2],111}.yield()

    函数yield表示该表达式是一个协程,该协程第一次运行时会挂起,局部对象不会被释放,故达到了相同效果。使用协程的好处是:当协程运行结束或者销毁表达式时,会自动销毁里面的局部动态对象。

    为了简单,本例中的lu对象中只包含了整数、实数、lu对象三种对象,实际上lu表中可以包含任何数据。

6 其他

    你可能注意到了,我的联系方式就在下面,如有不明之处或有什么建议,可随时与我进行联系。


版权所有© Lu程序设计 2002-2013,保留所有权利
E-mail: forcal@sina.com
  QQ:630715621
最近更新: 2013年12月29日

0 0
原创粉丝点击