该版本修复了zenglApi_CacheMemData接口生成的编译缓存问题,修复b = b;语句,当b为数组时会将自己给释放掉的BUG,修复POP指令在弹出内存块时,没有将refcount引用数还原的问题,修复调试命令r会多返回一层的问题...

    页面导航: 项目下载地址:

    zengl language v1.8.1 源代码的相关地址:https://github.com/zenglong/zengl_language/  对应的tag标签为:v1.8.1

zengl v1.8.1:

    该版本修复了zenglApi_CacheMemData接口生成的编译缓存问题。

    由于CALL指令的src源操作数在执行时,会被替换为模块函数的整数索引值,如果客户端调整了模块函数(例如新增了模块函数的话),那么缓存的模块函数索引值就会对应到错误的模块函数。因此,当前版本在生成缓存时,会将索引值还原为字符串,从而让缓存的CALL指令在执行时,能重新查询模块函数以得到正确的索引值。修复的代码位于zenglApi.c文件中:

/**
 * API接口,将编译器和解释器中主要的内存数据缓存起来,缓存的内存数据可以存储到文件或者别的地方,
 * 之后可以利用缓存起来的内存数据跳过编译过程,直接执行虚拟汇编指令,缓存起来的内存数据只可以用于当前机器
 */
ZL_EXPORT ZL_EXP_INT zenglApi_CacheMemData(ZL_EXP_VOID * VM_ARG, ZL_EXP_VOID ** cachePoint, ZL_EXP_INT * cacheSize)
{
	.........................................................
	// 将指令列表中所有的指令都拷贝到缓存中
	tmp_point += sizeof(ZENGL_RUN_INST_LIST);
	ZENGL_SYS_MEM_COPY(tmp_point, run->inst_list.insts, run->inst_list.count * sizeof(ZENGL_RUN_INST_LIST_MEMBER));
	for(i=0; i < run->inst_list.count ;i++) {
		if(run->inst_list.insts[i].type == ZL_R_IT_CALL) {
			// 如果CALL指令的src源操作数在执行时,被替换为了模块函数的整数索引值,则将其还原为字符串。
			// 如果不进行还原操作,那么当客户端调整了模块函数时,原索引值可能会对应到错误的模块函数
			if(run->inst_list.insts[i].src.type == ZL_R_DT_NUM) {
				ZENGL_RUN_INST_LIST_MEMBER * tmp_member = (((ZENGL_RUN_INST_LIST_MEMBER *)tmp_point) + i);
				tmpIndex = run->inst_list.insts[i].src.val.num;
				tmp_member->src.type = ZL_R_DT_STR;
				tmp_member->src.val.str_Index = run->ModFunTable.mod_funs[tmpIndex].strIndex;
			}
		}
	}
	.........................................................
}


    该版本还可以执行类似return a['test'];的语句,如果a是局部变量,同时a['test']是一个数组时,之前的版本会将其释放掉,而无法将a['test']对应的数组返回。当前版本在zenglrun_main.c中增加了zenglrun_memblock_free_local静态函数,专门用于释放局部变量中的内存块(也就是数组),当内存块被赋值给AX寄存器进行脚本函数返回时,就只将refcount引用数减一,而不进行实际的释放操作。这样外部脚本函数的调用者就可以使用返回的内存块了。修复的代码位于zenglrun_main.c文件中:

// 该函数专门用于释放局部变量中的内存块,当内存块被赋值给AX寄存器进行脚本函数返回时,就只将refcount数减一,而不进行实际的释放操作。这样外部脚本函数的调用者就可以使用返回的内存块了。
static ZL_VOID zenglrun_memblock_free_local(ZL_VOID * VM_ARG,ZENGL_RUN_VIRTUAL_MEM_LIST * memblock,ZL_INT * index)
{
	ZENGL_RUN_TYPE * run = &((ZENGL_VM_TYPE *)VM_ARG)->run;
	ZL_INT i;
	if(memblock == ZL_NULL)
		return;
	memblock->refcount--;
	// 如果当前局部变量的内存块等于AX返回寄存器的内存块,说明该内存块很有可能会被外部调用者使用,就只将refcount引用计数减一,而不执行具体的释放内存块的操作。
	if(ZENGL_RUN_REG(ZL_R_RT_AX).runType == ZL_R_RDT_MEM_BLOCK && ZENGL_RUN_REGVAL(ZL_R_RT_AX).memblock == memblock) 
	{
		if(memblock->refcount < 0)
			memblock->refcount = 0;
		return; // 直接返回,不进行后面的释放操作
	}
	if(memblock->refcount <= 0)
	{
		for(i=0;i<memblock->size;i++)
		{
			if(memblock->mem_array[i].runType == ZL_R_RDT_STR && 
				memblock->mem_array[i].str_Index > 0)
			{
				run->memFreeIndex(VM_ARG,memblock->mem_array[i].val.str,&memblock->mem_array[i].str_Index);
				memblock->mem_array[i].val.str = ZL_NULL;
			}
			else if(memblock->mem_array[i].runType == ZL_R_RDT_MEM_BLOCK &&
				memblock->mem_array[i].val.memblock != ZL_NULL)
			{
				zenglrun_memblock_free_local(VM_ARG,(ZENGL_RUN_VIRTUAL_MEM_LIST *)memblock->mem_array[i].val.memblock,&memblock->mem_array[i].memblk_Index);
				memblock->mem_array[i].val.memblock = ZL_NULL;
			}
		}
		run->memFreeIndex(VM_ARG,memblock->mem_array,&memblock->mempool_index); // 将内存块的mem_array动态数组释放掉
		if(memblock->hash_array.hash_code_table.members != ZL_NULL)
			run->memFreeIndex(VM_ARG,memblock->hash_array.hash_code_table.members,&(memblock->hash_array.hash_code_table.mempool_index)); // 释放哈希数组中的哈希表
		if(memblock->hash_array.str_pool.ptr != ZL_NULL)
			run->memFreeIndex(VM_ARG,memblock->hash_array.str_pool.ptr,&(memblock->hash_array.str_pool.mempool_index)); // 释放哈希数组中的字符串池
		run->memFreeIndex(VM_ARG,memblock,index); // 将内存块自己给释放掉
	}
}

.............................................................

/*释放栈中参数部分和局部变量部分的所有内存块*/
ZL_VOID zenglrun_memblock_freeall_local(ZL_VOID * VM_ARG)
{
	ZENGL_RUN_TYPE * run = &((ZENGL_VM_TYPE *)VM_ARG)->run;
	ZL_INT locIndex = ZENGL_RUN_REGVAL(ZL_R_RT_ARG).dword;
	for(;locIndex < run->vstack_list.count;locIndex++)
	{
		switch(run->vstack_list.mem_array[locIndex].runType)
		{
		case ZL_R_RDT_MEM_BLOCK:
			if(run->vstack_list.mem_array[locIndex].val.memblock != ZL_NULL)
			{
				zenglrun_memblock_free_local(VM_ARG,run->vstack_list.mem_array[locIndex].val.memblock, &run->vstack_list.mem_array[locIndex].memblk_Index);
				run->vstack_list.mem_array[locIndex].runType = ZL_R_RDT_NONE;
				run->vstack_list.mem_array[locIndex].val.dword = 0;
				run->vstack_list.mem_array[locIndex].val.memblock = ZL_NULL;
			}
			break;
		case ZL_R_RDT_ADDR: //将局部变量和参数里的引用也释放掉
		case ZL_R_RDT_ADDR_LOC:
		case ZL_R_RDT_ADDR_MEMBLK:
			run->vstack_list.mem_array[locIndex].runType = ZL_R_RDT_NONE;
			run->vstack_list.mem_array[locIndex].val.dword = 0;
			run->vstack_list.mem_array[locIndex].val.memblock = ZL_NULL;
			run->vstack_list.mem_array[locIndex].memblk_Index = 0;
			break;
		}
	}
}


    修复b = b;语句,当b为数组时会将自己给释放掉的BUG。在zenglrun_main.c中增加了zenglrun_memblock_free_for_ops静态函数,专用于VMemBlockOps,VMemListOps,VStackListOps的内存块释放操作。如果源操作数的内存块与目标操作数的内存块相同,则不进行实际的释放操作,例如假设变量b是一个数组,那么b = b;语句在执行时就不会将自己给释放掉:

// 专用于VMemBlockOps,VMemListOps,VStackListOps的内存块释放函数
static ZL_VOID zenglrun_memblock_free_for_ops(ZL_VOID * VM_ARG,ZENGL_RUN_VIRTUAL_MEM_LIST * memblock,ZL_INT * index, ZENGL_RUN_VMEM_OP_TYPE op, ZENGL_RUN_VIRTUAL_MEM_STRUCT * tmpmem);

..............................................................

/**
	虚拟机的虚拟内存操作函数
	第一个参数ZENGL_RUN_VMEM_OP_TYPE opType为内存操作类型
	如 ZL_R_VMOPT_GETMEM 为从某虚拟内存读取值。
*/
ZENGL_RUN_VIRTUAL_MEM_STRUCT zenglrun_VMemListOps(ZL_VOID * VM_ARG,ZENGL_RUN_VMEM_OP_TYPE opType,ZL_INT memloc,
												  ZENGL_RUN_VIRTUAL_MEM_STRUCT argval)
{
	.......................................................
	if(opType != ZL_R_VMOPT_GETMEM)
	{
		//如果所访问的内存原先是个数组之类的内存块的话,就将该内存块的内存空间释放掉
		if(run->vmem_list.mem_array[memloc].runType == ZL_R_RDT_MEM_BLOCK && run->vmem_list.mem_array[memloc].val.memblock != ZL_NULL)
		{
			zenglrun_memblock_free_for_ops(VM_ARG,run->vmem_list.mem_array[memloc].val.memblock, &run->vmem_list.mem_array[memloc].memblk_Index, opType, &argval);
			run->vmem_list.mem_array[memloc].val.memblock = ZL_NULL;
		}
		else if(run->vmem_list.mem_array[memloc].runType == ZL_R_RDT_ADDR_MEMBLK) //如果是内存块引用,则直接将memblock内存块指针设为ZL_NULL
			run->vmem_list.mem_array[memloc].val.memblock = ZL_NULL;
	}
	.......................................................
}

..............................................................

/**
	虚拟堆栈空间的操作函数,虚拟机中堆栈的概念类似汇编语言里的堆栈概念。用于保存和恢复数据的地方。经常用于存放局部变量,函数的返回地址,寄存器的值等。
	参数valid用于判断是否需要将某栈内存设为占用状态,占用表示该栈内存已经被初始化,主要用于判断函数参数是否被初始化
*/
ZENGL_RUN_VIRTUAL_MEM_STRUCT zenglrun_VStackListOps(ZL_VOID * VM_ARG,ZENGL_RUN_VMEM_OP_TYPE opType,ZL_INT index,
												  ZENGL_RUN_VIRTUAL_MEM_STRUCT argval,ZL_BOOL valid)
{
	.......................................................
	if(opType != ZL_R_VMOPT_GETMEM)
	{
		if(run->vstack_list.mem_array[index].runType == ZL_R_RDT_MEM_BLOCK && 
			run->vstack_list.mem_array[index].val.memblock != ZL_NULL) //如果栈中该元素之前是个数组之类的内存块,就将内存块进行释放
		{
			zenglrun_memblock_free_for_ops(VM_ARG,run->vstack_list.mem_array[index].val.memblock,
				&run->vstack_list.mem_array[index].memblk_Index, opType, &argval);
			run->vstack_list.mem_array[index].val.memblock = ZL_NULL;
		}
		else if(run->vstack_list.mem_array[index].runType == ZL_R_RDT_ADDR_MEMBLK) //如果是内存块引用,就直接将memblock内存块指针设为ZL_NULL
			run->vstack_list.mem_array[index].val.memblock = ZL_NULL;
	}
	.......................................................
}

..............................................................

/*对数组ptr里的index索引指向的内存进行操作*/
ZENGL_RUN_VIRTUAL_MEM_STRUCT zenglrun_VMemBlockOps(ZL_VOID * VM_ARG,ZENGL_RUN_VMEM_OP_TYPE op,ZENGL_RUN_VIRTUAL_MEM_LIST * ptr,ZL_INT index,
												   ZENGL_RUN_VIRTUAL_MEM_STRUCT * tmpmem)
{
	.......................................................
	if(op != ZL_R_VMOPT_GETMEM)
	{
		if(tmpmem->runType != ZL_R_RDT_STR && ptr->mem_array[index].runType == ZL_R_RDT_STR && 
			ptr->mem_array[index].str_Index > 0) //在设置某数组元素时,先将数组元素之前存储的字符串内存空间释放掉。
		{
			run->memFreeIndex(VM_ARG,ptr->mem_array[index].val.str,&ptr->mem_array[index].str_Index);
			ptr->mem_array[index].val.str = ZL_NULL;
		}
		else if(ptr->mem_array[index].runType == ZL_R_RDT_MEM_BLOCK) //在设置某数组元素时,如果该数组元素本身又是一个数组,则将该数组元素分配的内存块释放掉。
		{
			zenglrun_memblock_free_for_ops(VM_ARG,(ZENGL_RUN_VIRTUAL_MEM_LIST *)ptr->mem_array[index].val.memblock,&ptr->mem_array[index].memblk_Index, op, tmpmem);
			ptr->mem_array[index].val.memblock = ZL_NULL;
		}
	}
	.......................................................
}

..............................................................

// 专用于VMemBlockOps,VMemListOps,VStackListOps的内存块释放函数
static ZL_VOID zenglrun_memblock_free_for_ops(ZL_VOID * VM_ARG,ZENGL_RUN_VIRTUAL_MEM_LIST * memblock,ZL_INT * index, ZENGL_RUN_VMEM_OP_TYPE op, ZENGL_RUN_VIRTUAL_MEM_STRUCT * tmpmem)
{
	ZENGL_RUN_TYPE * run = &((ZENGL_VM_TYPE *)VM_ARG)->run;
	// 如果和要操作的数据相同,则不进行实际的释放操作,例如假设变量b是一个数组,那么b = b;语句在执行时就不会将自己给释放掉
	switch(op) {
		case ZL_R_VMOPT_SETMEM_MEMBLOCK:
		case ZL_R_VMOPT_ADDMEM_MEMBLOCK:
			if(memblock == tmpmem->val.memblock) {
				memblock->refcount--;
				if(memblock->refcount < 0)
					memblock->refcount = 0;
				return;
			}
		break;
	}
	// 否则执行实际的释放操作
	run->memblock_free(VM_ARG, memblock, index);
}


    修复POP指令在弹出内存块时,没有将refcount引用数还原的问题。修复的代码也位于zenglrun_main.c文件里:

/**
	虚拟堆栈空间的操作函数,虚拟机中堆栈的概念类似汇编语言里的堆栈概念。用于保存和恢复数据的地方。经常用于存放局部变量,函数的返回地址,寄存器的值等。
	参数valid用于判断是否需要将某栈内存设为占用状态,占用表示该栈内存已经被初始化,主要用于判断函数参数是否被初始化
*/
ZENGL_RUN_VIRTUAL_MEM_STRUCT zenglrun_VStackListOps(ZL_VOID * VM_ARG,ZENGL_RUN_VMEM_OP_TYPE opType,ZL_INT index,
												  ZENGL_RUN_VIRTUAL_MEM_STRUCT argval,ZL_BOOL valid)
{
	.......................................................
	if(index < 0) //小于0属于压栈操作
	{
		switch(opType)
		{
		........................................................
		case ZL_R_VMOPT_GETMEM: //获取堆栈的最后一个值,并弹出该值,有点像汇编的POP操作。
			if(run->vstack_list.count <= 0) //过分弹出数据或未知原因导致堆栈反向溢出。
				run->exit(VM_ARG,ZL_ERR_RUN_VSTACK_LIST_OVERFLOW,ZL_R_REG_PC,ZL_R_REG_PC);
			switch(run->vstack_list.mem_array[run->vstack_list.count - 1].runType)
			{
			case ZL_R_RDT_ADDR: //如果是全局变量内存的引用,就通过VMemListOps来访问
				retmem = run->VMemListOps(VM_ARG,opType,run->vstack_list.mem_array[run->vstack_list.count - 1].val.dword,argval);
				break;
			case ZL_R_RDT_ADDR_LOC: ////如果是局部变量栈内存的引用,就通过VStackListOps来访问
				retmem = run->VStackListOps(VM_ARG,opType,run->vstack_list.mem_array[run->vstack_list.count - 1].val.dword,argval,ZL_TRUE);
				break;
			case ZL_R_RDT_MEM_BLOCK: // 如果要弹出的数据是内存块,则将引用数减一,这样之前PUSH操作增加的引用数就可以被还原
				{
					ZENGL_RUN_VIRTUAL_MEM_LIST * tmp_memblock = run->vstack_list.mem_array[run->vstack_list.count - 1].val.memblock;
					tmp_memblock->refcount--;
					if(tmp_memblock->refcount < 0)
						tmp_memblock->refcount = 0;
				} // 继续执行default里的操作,将最后一个元素返回,所以这里不需要break
			default:
				retmem = run->vstack_list.mem_array[run->vstack_list.count - 1]; //如果不是引用,就将栈中最后一个元素返回
				break;
			}
			run->vstack_list.count--; //栈顶计数器减一。
			return retmem;
			break;
		}
	}
	.......................................................
}


    修复调试命令r会多返回一层的问题(main.c中在执行r调试命令时,多调用了一次zenglApi_DebugGetTrace接口),修复的代码位于main.c文件里(将多调用的zenglApi_DebugGetTrace接口给注释掉了):

ZL_EXP_INT main_debug_break(ZL_EXP_VOID * VM_ARG,ZL_EXP_CHAR * cur_filename,ZL_EXP_INT cur_line,ZL_EXP_INT breakIndex,ZL_EXP_CHAR * log)
{
	...................................................................
	while(!exit)
	{
		...........................................................
		switch(command[0])
		{
		...........................................................
		case 'r':
			{
				int arg = -1;
				int loc = -1;
				int pc = -1;
				int tmpPC;
				int ret;
				int size,i;
				int line = 0;
				char * fileName = ZL_EXP_NULL;
				ZL_EXP_BOOL hasBreaked = ZL_EXP_FALSE;
				ret = zenglApi_DebugGetTrace(VM_ARG,&arg,&loc,&pc,&fileName,&line,ZL_EXP_NULL,ZL_EXP_NULL);
				if(ret == 1)
				{
					// zenglApi_DebugGetTrace(VM_ARG,&arg,&loc,&pc,&fileName,&line,ZL_EXP_NULL,ZL_EXP_NULL); // 该行会让r返回到上一层的上一层,多返回一层,所以注释掉
					pc++;
					size = zenglApi_DebugGetBreak(VM_ARG,-1,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL);
					for(i=0;i<size;i++)
					{
						if(zenglApi_DebugGetBreak(VM_ARG,i,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,&tmpPC) == -1)
							continue;
						else if(pc == tmpPC)
						{
							hasBreaked = ZL_EXP_TRUE;
							break;
						}
					}
					if(!hasBreaked)
					{
						if(zenglApi_DebugSetBreakEx(VM_ARG,pc,ZL_EXP_NULL,ZL_EXP_NULL,1,ZL_EXP_FALSE) == -1)
							printf("%s",zenglApi_GetErrorString(VM_ARG));
						else
							exit = 1;
					}
					else
						exit = 1;
				}
				else if(ret == 0)
					exit = 1;
				else if(ret == -1)
					printf("%s",zenglApi_GetErrorString(VM_ARG));
			}
			break;
		...........................................................
		}
	} //while(!exit)
	if(str != ZL_EXP_NULL)
		zenglApi_FreeMem(VM_ARG,str);
	return 0;
}


    修复执行复杂的调试语句时,可能会定位到错误的参数或局部变量的问题。例如:p bltCount(posts) && posts['id'] > 0调试命令在执行时(假设该语句位于某个脚本函数内,同时posts是一个包含'id'这个key的有效的数组),之前的版本,p调试命令的结果会是0,正确的结果应该是整数1。这是因为之前的版本在设置调试器的脚本环境时,在设置ARG和LOC寄存器的dword值时,并没有设置runType为ZL_R_RDT_INT,导致类型是默认的ZL_R_RDT_NONE,ZL_R_RDT_NONE类型的寄存器在PUSH的时候会被强制当成整数0,这样设置的dword值就会失效。导致前面&&右侧的posts['id'] > 0语句在调试时,找不到正确的posts变量。修复的代码位于zenglDebug.c文件中:

/*设置调试器所在的脚本函数环境*/
ZL_INT zenglDebug_SetFunInfo(ZL_VOID * VM_ARG)
{
	..............................................................
	for(;arg > 0 && loc > 0;)
	{
		PJmp = PRun->vstack_list.mem_array[loc - 1].val.dword - 1;
		if(PDebug->api_call_pc > 0 && PDebug->api_call_arg == arg) //如果在zenglApi_Call调用的最外层时
		{
			......................................................
			run->reg_list[ZL_R_RT_ARG].val.dword = arg;
			// 如果不设置ZL_R_RDT_INT,则默认是ZL_R_RDT_NONE类型,ZL_R_RDT_NONE类型的寄存器在PUSH的时候会被强制当成0,这样设置的dword值就会失效了!
			run->reg_list[ZL_R_RT_ARG].runType = ZL_R_RDT_INT;
			run->reg_list[ZL_R_RT_LOC].val.dword = loc;
			// 和上面同理
			run->reg_list[ZL_R_RT_LOC].runType = ZL_R_RDT_INT;
			return 0;
		}
		else if(PRun->inst_list.insts[PJmp].type == ZL_R_IT_CALL)
		{
			tmp_arg = arg;
			arg = PRun->vstack_list.mem_array[tmp_arg - 3].val.dword;
			loc = PRun->vstack_list.mem_array[tmp_arg - 2].val.dword;
			continue;
		}
		else if(PRun->inst_list.insts[PJmp].type == ZL_R_IT_JMP)
		{
			......................................................
			run->reg_list[ZL_R_RT_ARG].val.dword = arg;
			// 如果不设置ZL_R_RDT_INT,则默认是ZL_R_RDT_NONE类型,ZL_R_RDT_NONE类型的寄存器在PUSH的时候会被强制当成0,这样设置的dword值就会失效了!
			run->reg_list[ZL_R_RT_ARG].runType = ZL_R_RDT_INT;
			run->reg_list[ZL_R_RT_LOC].val.dword = loc;
			// 和上面同理
			run->reg_list[ZL_R_RT_LOC].runType = ZL_R_RDT_INT;
			return 0;
		}
		else
			break;
	}
	..............................................................
}


    该版本添加了一个简单的测试脚本:test_scripts/v1.8.1/test.zl:

use builtin;
def TRUE 1;
def FALSE 0;

fun test()
	a['test'] = array();
	a['test', 'name'] = 'zengl';
	print 'test,name:'+a['test', 'name'];
	return a['test']; // 测试返回数组成员
endfun

fun show_bool(bool = TRUE)
	// 测试r调试命令是否会返回上一层
	print bool ? "true" : "false";
endfun

fun test2(posts = 0)
	// 测试p bltCount(posts) && posts['id'] > 0调试命令是否会得到整数1
	if(bltCount(posts) && posts['id'] > 0)
		show_bool(TRUE);
	else
		show_bool(FALSE);
	endif

	// 测试POP指令是否会将posts数组的refcount引用计数器还原
	if(posts && posts['id'] > 0)
		show_bool(TRUE);
	else
		show_bool(FALSE);
	endif
endfun

b = test();
b = b; // 测试是否会释放掉自己
print 'b,name:'+b['name'];
print 'test2:';
posts['id'] = 12;
test2(posts);


    执行结果如下:

[email protected]:~/zengl_v1.8.1/zengl_language/linux$ ./zengl test_scripts/v1.8.1/test.zl 
run(编译执行中)...
test_scripts/v1.8.1/test.zl mtime:1523615373
reuse cache file: "caches/1_8_1_8_abf6b392622260993e2d5e7acaa9f99b" mtime:1523615642
test,name:zengl
b,name:zengl
test2:
true
true
run finished(编译执行结束)
[email protected]:~/zengl_v1.8.1/zengl_language/linux$ 


    可以在后面加入-d参数进行简单的调试,来测试r命令和p命令等:

[email protected]:~/zengl_v1.8.1/zengl_language/linux$ ./zengl test_scripts/v1.8.1/test.zl -d
run(编译执行中)...
test_scripts/v1.8.1/test.zl mtime:1523615373
reuse cache file: "caches/1_8_1_8_abf6b392622260993e2d5e7acaa9f99b" mtime:1523615642
* test_scripts/v1.8.1/test.zl:1 Break index:0 [current]
..............................................................
>>> debug input:s
* test_scripts/v1.8.1/test.zl:19 Single Break [current]
>>> debug input:p bltCount(posts) && posts['id'] > 0
bltCount(posts) && posts['id'] > 0 :integer:1
..............................................................
>>> debug input:s
* test_scripts/v1.8.1/test.zl:14 Single Break [current]
>>> debug input:T
 test_scripts/v1.8.1/test.zl:14 show_bool
 test_scripts/v1.8.1/test.zl:20 test2
 test_scripts/v1.8.1/test.zl:38 
>>> debug input:r
true
* test_scripts/v1.8.1/test.zl:20 Break index:0 [current]
>>> debug input:c
true
run finished(编译执行结束)
[email protected]:~/zengl_v1.8.1/zengl_language/linux$ 


    以上就是当前版本的相关内容,当前版本的代码也只在windows,linux和mac OSX中进行过基本的测试。

结束语:

    “别的星球上有人吗”    “我不知道,不过我想如果只有我们的话,就太浪费空间了。”

——  《超时空接触》
 
上下篇

下一篇: zengl v1.8.2 修复内存泄漏

上一篇: zengl v1.8.0 缓存内存中的编译数据,跳过编译过程

相关文章

zengl编程语言v0.0.23,SDL游戏开发,类定义

zengl编程语言v0.0.16数组,21点扑克小游戏

zengl编程语言v0.0.14加载模块函数

zengl v1.4.1 及zengl_SDL新增的Android工程

zengl编程语言v0.0.6创建小型计算器

zengl编程语言v0.0.13函数中实现global和return