zoukankan      html  css  js  c++  java
  • C/C++对Lu系统内置动态对象进行运算符重载

    欢迎访问Lu程序设计

    C/C++对Lu系统内置动态对象进行运算符重载

    1 说明

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

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

    2 关于运算符重载

        在本教程系列的开始,介绍了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决定了实际的数据结构,而扩展数据类型VType决定了重载函数。若要对某数据类型VType进行运算符重载,需要用函数LockKeyVType加锁,该函数定义如下:

    int _stdcall LockKey(luKEY VType,void (_stdcall *DeleteKey)(void *),luOperator OpLock);

        VType:被锁定的键的类型。VType>luPubKey_User(公有键、普通键)或者VType<luPriKey_User(私有键)
       
    DeleteKey:删除键值的函数指针,用于标识要加锁的键。该函数由用户定义,但由Lu调用。若DeleteKey=NULL,表示解锁指定的键。
       
    OpLockluOperator类型的函数指针,用于对象(用指针标识)的运算符重载,该参数不可为NULL。解锁和加锁所用的OpLock函数必须相同。参考[注1]

        如果加锁或解锁成功,该函数返回0,否则返回非0值。

        [注1]:运算符重载函数luOperator函数格式如下(与Lu二级函数相比,仅多了一个参数theOperator):

    //m指出数组Para的参数个数(也即操作数的个数,0表示1个,1表示2个,以此类推)。
    //hFor为调用该函数的表达式句柄(与二级函数中的表达式句柄相同)。
    //theOperator指出运算符的类型或操作类型:+、-、*、/、^、... ...。
    LuData (_stdcall *luOperator)(luINT m,LuData *Para,void *hFor,int theOperator);
    
    LuData _stdcall OpLock(luINT m,LuData *Para,void *hFor,int theOperator)
    {
        //... ...
        switch(theOperator)
        {
        case 0:    //重载运算符+
            //... ...
        case 1:    //重载运算符-
            //... ...
        case 2:    //重载运算符*
            //... ...
        case 3:    //重载运算符%
            //... ...
        case 4:    //重载运算符/
            //... ...
        ... ...
        }
    }


        如果不打算给加锁的键提供运算符或函数重载功能,须使用函数SetRunErr向Lu报告运行错误。

        本文讨论C/C++对Lu系统内置动态对象进行运算符重载。本文的例子来自Lu系统扩展库LuSystem中的Lu表(有改动,有所简化),参考源代码lu1code.rar,实现对Lu系统内置动态对象lu的数据类型扩展luu(基本类型为 luDynData_lu,扩展类型为 key_luu)

        动态对象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数据

    3 代码

    #include <stdio.h>
    #include <locale.h>
    #include "lu32.h"
    
    #pragma comment( lib, "lu32.lib" )
    
    luKEY key_luu = luPoiKey_User-20;	//标识luu的私有键,将对其加锁
    
    void _stdcall Del_luu(void *me)	//销毁luu的函数,但什么也不做,只为了配合运算符重载,加锁键使用
    {
    }
    
    void _stdcall LuMessage(wchar_t *pch) //输出动态库信息,该函数注册到Lu,由Lu二级函数调用
    {
    	wprintf(L"%s",pch);
    }
    
    //Lu脚本可调用的二级函数定义
    //生成一个luu对象,注册到Lu脚本系统
    LuData _stdcall lu_luu(luINT mm,LuData *xx,void *vFor)
    {
    	static wchar_t ErrName[]=L"luu";
    	luINT i;
    	luLu *pLu;
    	LuData a;
    
    	pLu=(luLu *)NewSysObj(luDynData_lu,mm+1,0);
    	if(!pLu)
    	{
    		a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
    		return a;
    	}
    	for(i=0;i<=mm;i++) pLu->Lu[i]=xx[i];
    	a.BType=luDynData_lu; a.VType=key_luu; a.x=0; *(luVOID *)&(a.x)=(luVOID)pLu;
    	FunReObj(vFor);
    	return a;
    }
    
    //返回两个luu相加(或者一个luu加其他任意数据)的结果,通过运算符重载间接调用
    LuData _stdcall lu_addLuu(luINT mm,LuData *xx,void *vFor)
    {
    	static wchar_t ErrName[]=L"luu +";
    	luLu *pLu,*pLu0,*pLu1;
    	luVOID i,j;
    	LuData a;
    
    	a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
    	pLu0=(luLu *)SearchKey((char *)&(xx->x),sizeof(luVOID),luDynData_lu);
    	pLu1=(luLu *)SearchKey((char *)&((xx+1)->x),sizeof(luVOID),luDynData_lu);
    	if(pLu0 && pLu1 && xx->BType==luDynData_lu && (xx+1)->BType==luDynData_lu)
    	{
    		pLu=(luLu *)NewSysObj(luDynData_lu,pLu0->Len+pLu1->Len,0);
    		if(!pLu) return a;
    		for(i=0,j=0;i<pLu0->Len;i++,j++) pLu->Lu[j]=pLu0->Lu[i];
    		for(i=0;i<pLu1->Len;i++,j++) pLu->Lu[j]=pLu1->Lu[i];
    	}
    	else if(pLu0  && xx->BType==luDynData_lu)
    	{
    		pLu=(luLu *)NewSysObj(luDynData_lu,pLu0->Len+1,0);
    		if(!pLu) return a;
    		for(i=0,j=0;i<pLu0->Len;i++,j++) pLu->Lu[j]=pLu0->Lu[i];
    		pLu->Lu[j]=xx[1];
    	}
    	else if(pLu1 && (xx+1)->BType==luDynData_lu)
    	{
    		pLu=(luLu *)NewSysObj(luDynData_lu,pLu1->Len+1,0);
    		if(!pLu) return a;
    		for(i=0,j=1;i<pLu1->Len;i++,j++) pLu->Lu[j]=pLu1->Lu[i];
    		pLu->Lu[0]=xx[0];
    	}
    	else
    	{
    		return a;
    	}
    	a.BType=luDynData_lu; a.VType=key_luu; a.x=0; *(luVOID *)&(a.x)=(luVOID)pLu;
    	FunReObj(vFor);
    	return a;
    }
    
    //输出luu的信息,通过重载函数o间接调用
    LuData _stdcall lu_oLuu(luINT mm,LuData *xx,void *vFor)
    {
    	static wchar_t ErrName[]=L"luu o";
    	luLu *pLu;
    	luMessage pMessage;
    	luVOID k=0;
    	LuData a;
    
    	a.BType=luStaData_int64; a.VType=luStaData_int64; a.x=0;
    	pMessage=(luMessage)SearchKey((char *)&k,sizeof(luVOID),luPubKey_User);
    	if(!pMessage) return a;
    	pLu=(luLu *)SearchKey((char *)&(xx->x),sizeof(luVOID),luDynData_lu);
    	if(!pLu)		//不可识别的lu对象
    	{
    		SetRunErr(1,ErrName,1,0,vFor); return a;
    	}
    	pMessage(L"luu{... ...} ");
    	a.x=13;
    	return a;
    }
    
    LuData _stdcall OpLock_luu(luINT m,LuData *Para,void *vFor,int theOperator)	//luu的运算符重载函数
    {
    	LuData a;
    
        switch(theOperator)
        {
        case 0:	//重载运算符+
    		return lu_addLuu(m,Para,vFor);
        case 44:	//重载函数len
    		Para->VType=luDynData_lu;
    		a=ExeOperator(m,Para,vFor,theOperator,luDynData_lu);	//直接调用基本类型luDynData_lu的len函数
    		Para->VType=key_luu;
    		return a;
        case 46:	//重载函数new
    		a=ExeOperator(m,Para,vFor,theOperator,luDynData_lu);	//直接调用基本类型luDynData_lu的new函数
    		if(a.VType==luDynData_lu) a.VType=key_luu;		//设置扩展类型为自定义的key_luu类型
    		return a;
        case 47:	//重载函数oset
        case 48:	//重载函数oget
    		Para->VType=luDynData_lu;
    		a=ExeOperator(m,Para,vFor,theOperator,luDynData_lu);	//直接调用基本类型luDynData_lu的oset或oget函数
    		Para->VType=key_luu;
    		return a;
        case 49:	//重载函数o
    		return lu_oLuu(m,Para,vFor);
    	default:
    		SetRunErr(1,L"luu 无法识别的运算符!",theOperator,0,vFor);
            break;
        }
    	a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0;
    	return a;
    }
    
    void main(void)
    {
    	void *hFor;		//存放表达式句柄,即脚本函数句柄
    	luINT nPara;		//存放表达式的自变量个数
    	LuData *pPara;		//存放输入自变量的数组指针
    	luINT ErrBegin,ErrEnd;	//表达式编译出错的初始位置和结束位置
    	int ErrCode;		//错误代码
    	LuData Val;		//Lu基本数据类型
    	void *v=NULL;		//为了避免编译器报错,初始化为NULL
    	luVOID k=0;		//32位平台上luVOID被定义为__int32;64位平台上luVOID被定义为__int64;k必须赋值为0
    	wchar_t ForStr[]=L"main(:a,i)= a=luu[22, "abc",3.5], o[a], i=-1,while{++i<len(a), o[a(i),"  "]}";	//字符串表达式
    
    	setlocale(LC_ALL, "chs");	//设置可以输出中文
    
    	if(!InitLu()) return;	//初始化Lu
    
    	InsertKey((char *)&k,sizeof(luVOID),luPubKey_User,LuMessage,NULL,NULL,1,v);//使Lu运行时可输出函数信息
    
    	Val.BType=luStaData_int64; Val.VType=luStaData_int64; Val.x=key_luu;	//定义整数常量luu,标识luu对象
    	SetConst(L"luu",&Val);	//设置常量
    
    	SetFunction(L"luu",lu_luu,-2);	//设置二级函数,参数-2表示有不确定的任意多个自变量
    
    	LockKey(key_luu,Del_luu,OpLock_luu);	//在Lu键树中加锁键,只能存储luu类型,但实际上什么也不存储,只为了配合运算符重载
    
    	ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd);	//编译表达式
    	if(ErrCode)
    	{
    		printf("表达式有错误!错误代码: %d 
    ",ErrCode);
    	}
    	else
    	{
    		LuCal(hFor,pPara);	//计算表达式的值,hFor即编译得到的表达式句柄
    	}
    
    	LockKey(key_luu,NULL,OpLock_luu);	//在Lu键树中解锁键
    
    	FreeLu();			//释放Lu
    }


    运行结果:

    luu{... ...} 22 abc 3.5

    4函数说明

        本例用到了Lu的10个输出函数:初始化Lu的函数InitLu,释放Lu的函数FreeLu,编译表达式的函数LuCom、计算表达式的函数LuCal、加锁键函数LockKey、注册C/C++函数的函数SetFunction、申请系统内置动态对象函数NewSysObj、插入键值的函数InsertKey、查找键值的函数SearchKey、按指定类型执行运算符重载函数ExeOperator。从这里查看这些函数的说明:Lu编程指南

    5 难点分析

        在对Lu系统内置动态对象进行运算符重载时,需要:(1)用LockKey加锁一个键(本例为key_luu),但不需要向Lu系统注册任何键值;(2)删除键值的函数(本例为Del_luu)定义为空函数;(3)定义运算符重载函数(本例为OpLock_luu)。

        值得一提的是,使用申请系统内置动态对象函数NewSysObj很方便,不仅高效,而且返回的对象已注册到了Lu键树中,不需要自己再进行注册。使用按指定类型执行运算符重载函数ExeOperator也很方便,免去了自己的编码之苦。

        (1)如果修改代码中的字符串表达式为(注意C/C++字符串中转义字符 " 的使用,下同):

    main(:a,i)= a=new[luu,3 : 22, "abc",3.5], o[a], i=-1,while{++i<len(a), o[a(i)," "]}

        可得到如下结果:

    luu{... ...} 22 abc 3.5

        (2)如果修改代码中的字符串表达式为:

    main(:a,i)= a=luu[22, "abc",3.5], a=55+a+"asd", o[a], i=-1,while{++i<len(a), o[a(i)," "]}

        可得到如下结果:

    luu{... ...} 55 22 abc 3.5 asd

    6 其他

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


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

  • 相关阅读:
    hdu 1009 贪心算法
    hdu10007
    HDU1005 数列找规律
    HDU1004 (数组元素出现最多)
    HDU1003 dp 动态规划解析
    活字格Web应用平台学习笔记4
    活字格学习
    活字格Web应用平台学习笔记3-显示数据列表
    活字格Web应用平台学习笔记2-基础教程-开始
    活字格Web应用平台学习笔记1
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3507257.html
Copyright © 2011-2022 走看看