C/C++使用Lu脚本协程(一)

2014-11-24 07:44:29 · 作者: · 浏览: 0

欢迎访问 Lu程序设计

C/C++使用Lu脚本协程

1 说明

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

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

2 关于Lu协程

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

如果Lu表达式(函数)中使用了函数yield,该表达式称为一个协程(coroutine)(详细参考Lu用户指南)。协程不能递归运行,只有这一个限制。Lu协程有4种状态:正常、运行、挂起、 终止。正常态是可以运行但还没有运行的状态;终止态协程是不能运行的,如果运行将返回nil。与协程相关函数有5个:

yield :挂起协程并立即返回表达式(函数)的值。
status :查询表达式(包含协程)的状态。
abort :中止挂起的协程,此时协程处于正常态。
terminate :终止协程,协程处于终止态,不能运行。
resume :重启一个终止的协程,协程转为正常态。

详细说明:

(1)查询表达式(包含协程)状态 status(p):

p是一个表达式句柄。正常返回一个整数表示表达式状态:0:普通表达式;1:普通表达式正在运行;2:普通表达式递归运行;5:协程;6:协程正在运行;7:协程挂起;8:协程终止。p非法时返回nil。

(2)中止挂起的协程 abort(p):

p是一个协程句柄,正处于挂起状态。协程中止后,可以再次从头开始执行。操作成功返回true,否则返回false。

(3)终止协程 terminate(p):

p是一个协程句柄,处于正常等待运行状态或者挂起状态。协程终止后将不能执行,执行时总返回nil。操作成功返回true,否则返回false。

(4)重启一个终止的协程 resume(p):

p是一个协程句柄,正处于终止状态,重启后可以运行。操作成功返回true,否则返回false。

如果用C/C++编程,可以使用Lu核心库的输出函数ExMsgWithLu的4、8、9、10号功能操作协程。见下面的说明:

void * _stdcall ExMsgWithLu(int Type,void *hMsg,void **Msg1,void **Msg2); //C定义

Type:输入参数,信息交换的类型。
hMsg:输入参数,信息句柄,其意义取决于Type。
Msg1:该参数必须为变量,不能为常量。输入值及返回值取决于Type。
Msg2:该参数必须为变量,不能为常量。输入值及返回值取决于Type。
返回值:返回值的意义取决于Type。

说明:与Lu进行信息交换,向Lu传送信息或者从Lu获得信息。信息的类型及意义如下表所示:

Type hMsg Msg1 Msg2 返回值 说明
1 从二级函数获得的表达式句柄

返回指向表达式模块号的指针

返回表达式句柄 指向表达式名称的字符串指针 得到表达式名称、模块号、句柄
2 编译表达式得到的表达式句柄

返回指向表达式模块号的指针

无意义 指向表达式名称的字符串指针 得到表达式名称、模块号
3 luVOID类型指针,模块号 luVOID类型指针,返回模块中的表达式数目 无意义 无意义 得到模块中的表达式数目
4 编译表达式得到的表达式句柄

无意义

无意义 将返回值取整数,表示表达式的状态。 返回值表示表达式状态:0:普通表达式;1:普通表达式正在运行;2:普通表达式递归运行;5:协程;6:协程正在运行;7:协程挂起;8:协程终止。
5 无意义 无意义 无意义 无意义 清空缓冲池
6 luIFOR类型指针,设置对象总数 luIFOR类型指针,返回以前设置的对象总数 无意义 无意义 设置对象(指针键)总数为多少时自动启动垃圾收集器GC。当*hMsg小于等于0时不会自动启动垃圾收集器。
7 函数指针:void (_stdcall *GcEndCallMe)(void); 非0表示设置函数指针,0表示取消设置 无意义 非0表示操作成功。 设置一个函数GcEndCallMe,该函数将在垃圾收集器的最后调用。
8 编译表达式得到的表达式句柄 无意义 无意义 非0表示操作成功。 中止正处于挂起状态的协程。协程中止后,可以再次从头开始执行。
9 编译表达式得到的表达式句柄 无意义 无意义 非0表示操作成功。 终止处于正常等待运行状态或者挂起状态的协程。协程终止后将不能执行,执行时总返回nil。
10 编译表达式得到的表达式句柄 无意义 无意义 非0表示操作成功。 重启一个终止的协程,重启后可以运行。

3 代码

代码1:最简单的协程

#include 
  
   
#include "lu32.h"
#pragma comment( lib, "lu32.lib" )
void main(void)
{
	void *hFor;		//存放表达式句柄,即脚本函数句柄
	luINT nPara;		//存放表达式的自变量个数
	LuData *pPara;		//存放输入自变量的数组指针
	LuData Val;		//存放表达式的值
	luINT ErrBegin,ErrEnd;	//表达式编译出错的初始位置和结束位置
	int ErrCode;		//错误代码
	wchar_t ForStr[]=L"f(x:i)= i=0, while{(i++, i<=5), yield(i)}, 888";	//字符串表达式
	int i;
	if(!InitLu()) return;	//初始化Lu
	ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd);	//编译表达式
	if(ErrCode)
	{
		printf("表达式有错误!错误代码: %d \n",ErrCode);
	}
	else
	{
		for(i=0;i<8;i++)	//循环调用8次,观察每次调用的结果
		{
			Val=LuCal(hFor,pPara);	//计算表达式的值
			if(Val.BType==luStaData_int64) printf("%I64d\n",Val.x);
		}
	}
	FreeLu();		//释放Lu
}
  


运行结果:

1
2
3
4
5
888
1
2

代码2:协程状态转换

#include 
  
   
#include "lu32.h"
#pragma comment( lib, "lu32.lib" )
void main(void)
{
	void *hFor;		//存放表达式句柄,即脚本函数句柄
	luINT nPara;		//存放表达式的自变量个数
	LuData *pPara;		//存放输入自变量的数组指针
	LuData Val;		//存放表达式的值
	luINT ErrBegin,ErrEnd;	//表达式编译出错的初始位置和结束位置
	int ErrCode;		//错误代码
	void *Msg1, *Msg2;		//与Lu交换信息用
	wchar_t ForStr[]=L"f(x:i)= i=0, while{(i++, i<=5), yield(i)}, 888";	//字符串表达式
	if(!InitLu()) return;	//初始化Lu
	ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd);	//编译表达式
	if(ErrCode)
	{
		printf("表达式有错误!错误代码: %d \n",ErrCode);
	}
	else
	{
		Val=LuCal(hFor,pPara);
		if(Val.BType==luStaData_int64) printf("%I64d\n",Val.x);
		Val=LuCal(hFor,pPara);
		if(Val.BType==luStaData_int64) printf("%I64d\n",Val.x);
		printf("协程状态 %d\n",(int)ExMsgWithLu(4,hFor, &Msg1, &Msg2));
		Val=LuCal(hFor,pPara);
		if(Val.BType==luStaData_int64) printf("%I64d\n",Val.x);
		if(ExMsgWithLu(8,hFor, &Msg1, &Msg2)) printf("协程已中止!\n");
		Val=LuCal(hFor,pPara);
		if(Val.BType==luStaData_int64) printf("%I64d\n",Val.x);
		if(ExMsgWithLu(9,hFor, &Msg1, &Msg2)) printf("协程已终止!\n");
		printf("协程状态 %d\n",(int)ExMsgWithLu(4,hFor, &Msg1, &Msg2));
		Val=LuCal(hFor,pPara);
		if(Val.BType==luStaData_nil) printf("协程返回nil!\n");
		if(ExMsgWithLu(10,hFor, &Msg1, &Msg2)) printf("协程已重启!\n");
		Val=LuCal(hFor,pPara);
		if(Val.BType==luStaData_int64) printf("%I64d\n",Val.x);
		Val=LuCal(hFor,pPara);
		if(Val.BType==luStaData_int64) printf("%I64d\n",Val.x);
		Val=LuCal(hFor,pPara);
		if(Val.BType==luStaData_int64) printf("%I64d\n",Val.x);
	}
	FreeLu();		//释放Lu
}
  


运行结果:

1
2
协程状态 7
3
协程已中止!
1
协程已终止!
协程状态 8
协程返回nil!
协程已重启!
1
2
3

代码3:处理随机数的协程

#include 
  
   
#include 
   
     #include 
    
      #include "lu32.h" #pragma comment( lib, "lu32.lib" ) void _stdcall LuMessage(wchar_t *pch) //输出动态库信息,该函数注册到Lu,由Lu二级函数调用 { wprintf(L"%s",pch); } //Lu脚本可调用的二级函数定义 LuData _stdcall lu_rand(luINT mm,LuData *xx,void *vFor) //生成0~9的随机数,通过参数返回 { xx[0].BType=luStaData_int64; xx[0].VType=luStaData_int64; xx[0].x = rand()%10; xx[1].BType=luStaData_int64; xx[1].VType=luStaData_int64; xx[1].x = rand()%10; return *xx; } void main(void) { void *hSend,*hReceive1,*hReceive2; //存放表达式句柄,即脚本函数句柄 luINT nPara; //存放表达式的自变量个数 LuData *pPara; //存放输入自变量的数组指针 LuData Para[2]; //存放表达式的参数 luINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置 luVOID k=0; //32位平台上luVOID被定义为__int32;64位平台上luVOID被定义为__int64;k必须赋值为0 void *Msg1, *Msg2; //与Lu交换信息用 wchar_t send[]=L"send(x,y)= while{true, rand(&x,&y), o{\"\\r\\n*** send : \", x, \" \", y}, yield(0)}"; //生成数据的脚本函数 wchar_t receive1[]=L"receive1(x,y:a)= a=0, while{(a=a+(x+y), a< 30 ), o{\"\\r\\n+++ receive1 : \", a}, yield(0)}"; //处理数据的脚本函数 wchar_t receive2[]=L"receive2(x,y:a)= a=0, while{(a=a+(x-y), a>(-10)), o{\"\\r\\n--- receive2 : \", a}, yield(0)}"; //处理数据的脚本函数 srand(1); //设置随机数的种子,改变该值可演示不同结果 setlocale(LC_ALL, "chs"); //设置可以输出中文 if(!InitLu()) return; //初始化Lu InsertKey((char *)&k,sizeof(luVOID),luPubKey_User,LuMessage,NULL,NULL,1,&Msg1); //使Lu运行时可输出函数信息 SetFunction(L"rand",lu_rand,1); //设置二级函数,有2个自变量参数 if( LuCom(send, 0,0,0,&hSend, &nPara,&pPara,&ErrBegin,&ErrEnd) || //编译表达式 LuCom(receive1,0,0,0,&hReceive1,&nPara,&pPara,&ErrBegin,&ErrEnd) || LuCom(receive2,0,0,0,&hReceive2,&nPara,&pPara,&ErrBegin,&ErrEnd)) { printf("表达式有错误!\n"); } else { while(1) { LuCal(hSend,Para); //运行协程hSend,产生数据,数据由Para返回 LuCal(hReceive1,Para); //运行协程hReceive1,处理数据 if((int)ExMsgWithLu(4,hReceive1, &Msg1, &Msg2)==5) //如果协程hReceive1结束 { ExMsgWithLu(9,hReceive1, &Msg1, &Msg2); //终止协程hReceive1 } LuCal(hReceive2,Para); //运行协程h