该版本增加了zenglApi_CacheMemData和zenglApi_ReUseCacheMemData接口函数。 zenglApi_CacheMemData接口用于将编译器和解释器中主要的内存编译数据缓存起来,缓存的数据可以存储到文件或者别的地方。之后就可以利用缓存起来的内存编译数据来跳过编译过程,直接执行虚拟汇编指令...

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

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

zengl v1.8.0:

    该版本增加了zenglApi_CacheMemData和zenglApi_ReUseCacheMemData接口函数。

    zenglApi_CacheMemData接口用于将编译器和解释器中主要的内存编译数据缓存起来,缓存的数据可以存储到文件或者别的地方。之后就可以利用缓存起来的内存编译数据来跳过编译过程,直接执行虚拟汇编指令。不过,缓存起来的内存数据只可以用于当前机器。

    zenglApi_ReUseCacheMemData接口则用于重利用缓存数据,从而跳过编译过程。

    该版本的main.c文件中默认启用了缓存功能。当缓存文件不存在时,执行完脚本后,会自动生成缓存文件。因此在执行任何一个脚本时,第一次在底部都会看到write zengl cache to file...的信息。第二次执行相同脚本时,就会自动重利用缓存过的编译数据,来跳过编译过程,并在脚本执行的开头可以看到reuse cache file: ...的信息。可以使用test.zl或者别的已有的脚本进行测试:

[email protected]:~/zengl/zengl_language/linux$ ./zengl test.zl
run(编译执行中)...
stat cache file: "caches/1_8_0_8_511b9a8710a4fc9ffd4640f7041aa65a" failed, maybe no cache file [recompile]
encrypt[0]:214
encrypt[1]:105
encrypt[2]:71
encrypt[3]:66
encrypt[4]:135
[0] 190
[1] 0
[2] 45
[3] 41
[4] 235
encrypt[0]:214
encrypt[1]:105
encrypt[2]:71
encrypt[3]:66
encrypt[4]:135
[0] 104
[1] 105
[2] 106
[3] 107
[4] 108
0.3141570548847388
test: 0101 0000 0110 1100 1001 1000 1100 0100 1000 1001 1010 0010 0010 01 [54]
a = 0x36 & 0x55 then a &= 0x4 now a is 4
e = &a so now e is address of a
e |= 0x9 is 13
now e is 13 and a is 13 they are same
unset(&e) then e=10 now e is 10 a is 13 so e is not address of a use unset!
b is 119 b|0x8 is 127
c is 99 c ^ 0x3 is 96
d is 1
d << 2 is 4
d <<= 3 is 8
now d is 8
next d is 8
d >> 2 is 2
d >>= 2 is 2
now d is 2
next d init is 1
2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912 1073741824 2147483648 4294967296 
now d is 4294967296
f = ~0x1 & 0xf is 14
f = !0x1 is 0
zengl version is v1.8.0
write zengl cache to file "caches/1_8_0_8_511b9a8710a4fc9ffd4640f7041aa65a" success 
run finished(编译执行结束)
[email protected]:~/zengl/zengl_language/linux$ ./zengl test.zl
run(编译执行中)...
test.zl mtime:1521965370
reuse cache file: "caches/1_8_0_8_511b9a8710a4fc9ffd4640f7041aa65a" mtime:1521978039
encrypt[0]:214
encrypt[1]:105
encrypt[2]:71
encrypt[3]:66
encrypt[4]:135
[0] 190
[1] 0
[2] 45
[3] 41
[4] 235
encrypt[0]:214
encrypt[1]:105
encrypt[2]:71
encrypt[3]:66
encrypt[4]:135
[0] 104
[1] 105
[2] 106
[3] 107
[4] 108
0.3141570548847388
test: 0101 0000 0110 1100 1001 1000 1100 0100 1000 1001 1010 0010 0010 01 [54]
a = 0x36 & 0x55 then a &= 0x4 now a is 4
e = &a so now e is address of a
e |= 0x9 is 13
now e is 13 and a is 13 they are same
unset(&e) then e=10 now e is 10 a is 13 so e is not address of a use unset!
b is 119 b|0x8 is 127
c is 99 c ^ 0x3 is 96
d is 1
d << 2 is 4
d <<= 3 is 8
now d is 8
next d is 8
d >> 2 is 2
d >>= 2 is 2
now d is 2
next d init is 1
2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912 1073741824 2147483648 4294967296 
now d is 4294967296
f = ~0x1 & 0xf is 14
f = !0x1 is 0
zengl version is v1.8.0
run finished(编译执行结束)
[email protected]:~/zengl/zengl_language/linux$ ls caches/
1_8_0_8_511b9a8710a4fc9ffd4640f7041aa65a
[email protected]:~/zengl/zengl_language/linux$ 


    可以看到,存储编译信息的缓存文件会生成到caches目录中,缓存文件名是由zengl版本号,指针长度,以及脚本执行路径的md5值组成的。如果缓存文件不存在时,在正常编译执行完脚本后,会自动生成缓存文件。如果存在则直接reuse重利用该缓存文件,跳过编译过程。

    如果主执行脚本文件或者其加载的脚本的内容发生的改变,都会自动重新生成新的缓存文件:

[email protected]:~/zengl/zengl_language/linux$ vim test.zl
[email protected]:~/zengl/zengl_language/linux$ ./zengl test.zl
run(编译执行中)...
test.zl mtime:1521978768 [changed] [recompile]
encrypt[0]:214
encrypt[1]:105
encrypt[2]:71
encrypt[3]:66
encrypt[4]:135
[0] 190
[1] 0
[2] 45
[3] 41
[4] 235
encrypt[0]:214
encrypt[1]:105
encrypt[2]:71
encrypt[3]:66
encrypt[4]:135
[0] 104
[1] 105
[2] 106
[3] 107
[4] 108
0.3141570548847388
test: 0101 0000 0110 1100 1001 1000 1100 0100 1000 1001 1010 0010 0010 01 [54]
a = 0x36 & 0x55 then a &= 0x4 now a is 4
e = &a so now e is address of a
e |= 0x9 is 13
now e is 13 and a is 13 they are same
unset(&e) then e=10 now e is 10 a is 13 so e is not address of a use unset!
b is 119 b|0x8 is 127
c is 99 c ^ 0x3 is 96
d is 1
d << 2 is 4
d <<= 3 is 8
now d is 8
next d is 16
d >> 2 is 4
d >>= 2 is 4
now d is 4
next d init is 1
2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912 1073741824 2147483648 4294967296 
now d is 4294967296
f = ~0x1 & 0xf is 14
f = !0x1 is 0
zengl version is v1.8.0
write zengl cache to file "caches/1_8_0_8_511b9a8710a4fc9ffd4640f7041aa65a" success 
run finished(编译执行结束)
[email protected]:~/zengl/zengl_language/linux$ 


    上面用vim编辑器修改了test.zl脚本的内容后,再次执行脚本时,就会recompile重新编译该脚本,并将新的内存编译数据写入缓存。下次执行脚本时,就会直接使用新生成的缓存来跳过编译过程了。

    重利用缓存的编译数据时,依然可以使用调试功能。可以在脚本文件名后面加入-d参数进行调试测试:

[email protected]:~/zengl/zengl_language/linux$ ./zengl test.zl -d
run(编译执行中)...
test.zl mtime:1521979089
reuse cache file: "caches/1_8_0_8_511b9a8710a4fc9ffd4640f7041aa65a" mtime:1521979093
* test.zl:1 Break index:0 [current]
>>> debug input:b test.zl 46
设置断点成功
>>> debug input:B
[0] test.zl:1 N:1 D:enable [current]
[1] test.zl:46 N:0 D:enable
total:2
>>> debug input:c
* test.zl:46 Break index:1 [current]
>>> debug input:S
* test.zl:47 Single Break [current]
>>> debug input:S
encrypt[0]:214
encrypt[1]:105
encrypt[2]:71
encrypt[3]:66
encrypt[4]:135
* test.zl:48 Single Break [current]
>>> debug input:p str
str :array or class obj:
[0] 190
[1] 0
[2] 45
[3] 41
[4] 235

>>> debug input:c
[0] 190
[1] 0
[2] 45
[3] 41
[4] 235
................................................................
f = ~0x1 & 0xf is 14
f = !0x1 is 0
zengl version is v1.8.0
run finished(编译执行结束)
[email protected]:~/zengl/zengl_language/linux$ 


    和编译缓存相关的接口函数:zenglApi_CacheMemData和zenglApi_ReUseCacheMemData的C源码都定义在zenglApi.c文件里:

typedef struct _API_MEM_POOL_POINT_TYPE{
	ZL_VOID * point; // 内存池中的指针值
	ZL_INT size;     // 内存池指针所占用的内存大小
	ZL_INT offset;   // 指针对应的在缓存中的偏移值
}API_MEM_POOL_POINT_TYPE; // 该结构中存储了指针和缓存偏移值的对应关系,通过该对应关系,可以找到某个指针对应的偏移值

/**
 * 将内存池指针和相应的偏移值存储到对应关系结构体中
 */
static ZL_VOID zengl_api_make_mempool(API_MEM_POOL_POINT_TYPE * api_mempool,
		ZENGL_MEM_POOL_TYPE * mempool, ZL_BYTE * cachePtr)
{
	ZL_INT i, j, k, offset = 0;
	API_MEM_POOL_POINT_TYPE temp;
	for(i=0;i < mempool->count;i++) {
		ZENGL_SYS_MEM_COPY((cachePtr + offset), mempool->points[i].point, mempool->points[i].size);
		api_mempool[i].point = mempool->points[i].point;
		api_mempool[i].size = mempool->points[i].size;
		api_mempool[i].offset = offset;
		offset += mempool->points[i].size;
	}
	// 将api_mempool动态数组中的指针值按照从小到大的顺序进行排列
	for(i=0;i < (mempool->count - 1);i++)
	{
		k = i;
		for(j=i+1;j < (mempool->count - 1);j++)
			if(api_mempool[k].point > api_mempool[j].point)
				k = j;
		if(k!=i)
		{
			temp = api_mempool[i];
			api_mempool[i] = api_mempool[k];
			api_mempool[k] = temp;
		}
	}
}

/**
 * 从api_mempool动态数组中,采用折中算法,搜索point指针对应的缓存偏移值,并将偏移值返回
 * 返回的值是实际的偏移值加一,这样可以和NULL空指针区分开
 */
static ZL_INT zengl_api_search_api_mempool(API_MEM_POOL_POINT_TYPE * api_mempool, ZL_INT count, ZL_VOID * point)
{
	ZL_VOID * min, * max;
	min = api_mempool[0].point;
	max = api_mempool[count - 1].point;
	if(point == min) {
		return (api_mempool[0].offset + 1);
	}
	else if(point == max) {
		return (api_mempool[count - 1].offset + 1);
	}
	else {
		ZL_INT minIndex=0,maxIndex=count - 1,diff;
		ZL_VOID * diffpoint;
		do
		{
			diff = (maxIndex - minIndex)/2;
			if(diff == 0) {
				return -1;
			}
			else {
				diffpoint = api_mempool[minIndex + diff].point;
				if(point == diffpoint) {
					return (api_mempool[minIndex + diff].offset + 1);
				}
				else if(point > diffpoint) {
					minIndex += diff;
				}
				else
					maxIndex = minIndex + diff;
			}
		}while(ZL_TRUE);
	}
}

/**
 * 计算内存池的实际总大小
 */
static ZL_INT zengl_api_compute_mempool_realsize(ZENGL_MEM_POOL_TYPE * mempool)
{
	ZL_INT i, realsize = 0;
	for(i=0;i < mempool->count;i++) {
		realsize += mempool->points[i].size;
	}
	return realsize;
}

/**
 * API接口,将编译器和解释器中主要的内存数据缓存起来,缓存的内存数据可以存储到文件或者别的地方,
 * 之后可以利用缓存起来的内存数据跳过编译过程,直接执行虚拟汇编指令,缓存起来的内存数据只可以用于当前机器
 */
ZL_EXPORT ZL_EXP_INT zenglApi_CacheMemData(ZL_EXP_VOID * VM_ARG, ZL_EXP_VOID ** cachePoint, ZL_EXP_INT * cacheSize)
{
	ZENGL_VM_TYPE * VM = (ZENGL_VM_TYPE *)VM_ARG;
	ZENGL_COMPILE_TYPE * compile;
	ZENGL_RUN_TYPE * run;
	ZENGL_EXPORT_API_CACHE_TYPE * api_cache;
	ZL_BYTE * cachePtr, * api_mempool, * api_cache_mempool, * tmp_point, * tmp_point2, * tp;
	ZL_INT baseSize, totalSize, mempoolRealSize, instListSize, instDataStringPoolSize, tmpIndex, i;
	ZL_LONG offset, file_offset;
	ZL_CHAR * ApiName = "zenglApi_CacheMemData";
	if(VM->signer != ZL_VM_SIGNER) //通过虚拟机签名判断是否是有效的虚拟机
		return -1;
	switch(VM->ApiState)
	{
	case ZL_API_ST_AFTER_RUN:
	case ZL_API_ST_REUSE:
		break;
	default:
		VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_INVALID_CALL_POSITION, ApiName , ApiName);
		return -1;
		break;
	}
	compile = &VM->compile;
	run = &VM->run;
	/* compile->mempool + compile->def_StringPool + compile->def_table + compile->HashTable +
	 * compile->LineCols + compile->FileStackList + compile->SymGlobalTable + compile->SymLocalTable +
	 * compile->SymClassTable + compile->SymClassMemberTable + compile->SymFunTable + compile->LDAddrList +
	 * compile->AST_nodes + compile->Token_StringPool */
	baseSize = sizeof(ZENGL_EXPORT_API_CACHE_TYPE) + sizeof(ZENGL_STRING_POOL_TYPE) + sizeof(ZENGL_DEF_TABLE) +
				sizeof(ZL_INT) * ZL_SYM_HASH_TOTAL_SIZE + sizeof(ZENGL_LINECOL_TABLE) +
				sizeof(ZENGL_FILE_STACKLIST_TYPE) + sizeof(ZENGL_SYM_GLOBAL_TABLE) +
				sizeof(ZENGL_SYM_LOCAL_TABLE) + sizeof(ZENGL_SYM_CLASS_TABLE) +
				sizeof(ZENGL_SYM_CLASSMEMBER_TABLE) + sizeof(ZENGL_SYM_FUN_TABLE) + sizeof(ZENGL_LD_ADDRLIST_TYPE) +
				sizeof(ZENGL_AST_TYPE) + sizeof(ZENGL_TOKEN_STRING_POOL);
	mempoolRealSize = zengl_api_compute_mempool_realsize(&compile->mempool);
	instListSize = sizeof(ZENGL_RUN_INST_LIST) + run->inst_list.count * sizeof(ZENGL_RUN_INST_LIST_MEMBER);
	instDataStringPoolSize = sizeof(ZENGL_RUN_INST_DATA_STRING_POOL) + (run->InstData_StringPool.count * sizeof(ZL_CHAR));
	totalSize = baseSize + mempoolRealSize + instListSize + instDataStringPoolSize;
	cachePtr = (ZL_BYTE *)run->memAlloc(VM_ARG,totalSize, &tmpIndex);
	ZENGL_SYS_MEM_SET(cachePtr, 0, totalSize);
	api_cache = (ZENGL_EXPORT_API_CACHE_TYPE *)cachePtr;
	api_cache->signer = ZL_EXP_API_CACHE_SIGNER;  // 设置缓存签名,方便判断是否是有效的缓存数据
	api_cache->mempoolRealSize = mempoolRealSize; // 内存池的实际大小
	api_cache->mempoolOffset = baseSize; // 拷贝到缓存中的内存池的偏移值
	api_cache->totalSize = totalSize; // 缓存数据的总大小
	api_mempool = (ZL_BYTE *)run->memAlloc(VM_ARG, compile->mempool.count * sizeof(API_MEM_POOL_POINT_TYPE), &tmpIndex);
	api_cache_mempool = cachePtr + api_cache->mempoolOffset;
	zengl_api_make_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, &compile->mempool, api_cache_mempool);

	// 将def_StringPool宏定义常量的字符串池拷贝到缓存中
	tmp_point = cachePtr + sizeof(ZENGL_EXPORT_API_CACHE_TYPE); // compile->def_StringPool
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->def_StringPool, sizeof(ZENGL_STRING_POOL_TYPE));
	if(compile->def_StringPool.ptr != ZL_NULL) {
		// 将指针转为offset(缓存偏移值),并存储到缓存里,重利用缓存时,只需将offset加上缓存基址,即可得到指针值
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->def_StringPool.ptr);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_STRING_POOL_TYPE *)tmp_point)->ptr = (ZL_CHAR *)offset;
	}

	// 将def_table宏定义动态数组拷贝到缓存中
	tmp_point += sizeof(ZENGL_STRING_POOL_TYPE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->def_table, sizeof(ZENGL_DEF_TABLE));
	if(compile->def_table.defs != ZL_NULL) {
		// 将指针转为offset(缓存中的偏移值)
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->def_table.defs);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_DEF_TABLE *)tmp_point)->defs = (ZENGL_DEF_TABLE_MEMBER *)offset;
	}

	// 将哈希表拷贝到缓存中
	tmp_point += sizeof(ZENGL_DEF_TABLE);
	ZENGL_SYS_MEM_COPY(tmp_point, compile->HashTable, sizeof(ZL_INT) * ZL_SYM_HASH_TOTAL_SIZE);

	// 将存储行列号的动态数组拷贝到缓存中
	tmp_point += sizeof(ZL_INT) * ZL_SYM_HASH_TOTAL_SIZE;
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->LineCols, sizeof(ZENGL_LINECOL_TABLE));
	if(compile->LineCols.lines != ZL_NULL) {
		// 将LineCols.lines指针转为offset缓存偏移值
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->LineCols.lines);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_LINECOL_TABLE *)tmp_point)->lines = (ZENGL_LINECOL *)offset;
		tmp_point2 = api_cache_mempool + (offset - 1);
		tp = ZL_NULL;
		offset = 0;
		for(i=0; i < compile->LineCols.count ;i++) {
			if(compile->LineCols.lines[i].filename != ZL_NULL) {
				// 将行列号信息中的filename文件名指针转为缓存偏移值
				if(tp != (ZL_BYTE *)compile->LineCols.lines[i].filename) {
					offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->LineCols.lines[i].filename);
					if(offset < 0) {
						VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
						return -1;
					}
					tp = (ZL_BYTE *)compile->LineCols.lines[i].filename;
				}
				((ZENGL_LINECOL *)tmp_point2)[i].filename = (ZL_CHAR *)offset;
			}
		}
	}

	// 将inc加载的文件信息的堆栈拷贝到缓存中
	tmp_point += sizeof(ZENGL_LINECOL_TABLE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->FileStackList, sizeof(ZENGL_FILE_STACKLIST_TYPE));
	if(compile->FileStackList.stacks != ZL_NULL) {
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->FileStackList.stacks);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_FILE_STACKLIST_TYPE *)tmp_point)->stacks = (ZENGL_FILE_STACK_TYPE *)offset;
		tmp_point2 = api_cache_mempool + (offset - 1);
		tp = ZL_NULL;
		offset = 0;
		for(i=0; i < compile->FileStackList.count ;i++) {
			// 将source中的filename指针转为offset缓存偏移值
			if(compile->FileStackList.stacks[i].source.filename != ZL_NULL) {
				if(tp != (ZL_BYTE *)compile->FileStackList.stacks[i].source.filename) {
					offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count,
							compile->FileStackList.stacks[i].source.filename);
					if(offset < 0) {
						VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
						return -1;
					}
					tp = (ZL_BYTE *)compile->FileStackList.stacks[i].source.filename;
				}
				((ZENGL_FILE_STACK_TYPE *)tmp_point2)[i].source.filename = (ZL_CHAR *)offset;
				((ZENGL_FILE_STACK_TYPE *)tmp_point2)[i].source.file = ZL_NULL;
			}
		}

		// FileStackList.filenames中存储了所有加载过的文件的文件名信息,将这些文件名指针都转为offset缓存偏移值并存储到缓存里
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->FileStackList.filenames);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_FILE_STACKLIST_TYPE *)tmp_point)->filenames = (ZL_CHAR **)offset;
		api_cache->filenames = (ZL_CHAR **)offset;
		api_cache->filenames_count = compile->FileStackList.filenames_count;
		tmp_point2 = api_cache_mempool + (offset - 1);
		tp = ZL_NULL;
		offset = 0;
		for(i=0; i < compile->FileStackList.filenames_count; i++) {
			if(compile->FileStackList.filenames[i] != ZL_NULL) {
				// 将加载过的文件名指针都转为offset缓存偏移值
				if(tp != (ZL_BYTE *)compile->FileStackList.filenames[i]) {
					offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count,
												compile->FileStackList.filenames[i]);
					if(offset < 0) {
						VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
						return -1;
					}
					tp = (ZL_BYTE *)compile->FileStackList.filenames[i];
				}
				((ZL_CHAR **)tmp_point2)[i] = (ZL_CHAR *)offset;
			}
		}
	}

	// 将全局变量符号表拷贝到缓存中
	tmp_point += sizeof(ZENGL_FILE_STACKLIST_TYPE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->SymGlobalTable, sizeof(ZENGL_SYM_GLOBAL_TABLE));
	if(compile->SymGlobalTable.sym != ZL_NULL) {
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->SymGlobalTable.sym);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_SYM_GLOBAL_TABLE *)tmp_point)->sym = (ZENGL_SYM_GLOBAL_TABLE_MEMBER *)offset;
	}

	// 将脚本函数参数和局部变量符号表拷贝到缓存中
	tmp_point += sizeof(ZENGL_SYM_GLOBAL_TABLE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->SymLocalTable, sizeof(ZENGL_SYM_LOCAL_TABLE));
	if(compile->SymLocalTable.local != ZL_NULL) {
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->SymLocalTable.local);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_SYM_LOCAL_TABLE *)tmp_point)->local = (ZENGL_SYM_LOCAL_TABLE_MEMBER *)offset;
	}

	// 将类符号表拷贝到缓存中
	tmp_point += sizeof(ZENGL_SYM_LOCAL_TABLE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->SymClassTable, sizeof(ZENGL_SYM_CLASS_TABLE));
	if(compile->SymClassTable.classTable != ZL_NULL) {
		// 将类符号表中的classTable动态数组的指针转为offset缓存偏移值
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->SymClassTable.classTable);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_SYM_CLASS_TABLE *)tmp_point)->classTable = (ZENGL_SYM_CLASS_TABLE_MEMBER *)offset;
	}

	// 将类成员符号表拷贝到缓存中
	tmp_point += sizeof(ZENGL_SYM_CLASS_TABLE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->SymClassMemberTable, sizeof(ZENGL_SYM_CLASSMEMBER_TABLE));
	if(compile->SymClassMemberTable.members != ZL_NULL) {
		// 将类成员符号表的members动态数组的指针转为offset缓存偏移值
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->SymClassMemberTable.members);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_SYM_CLASSMEMBER_TABLE *)tmp_point)->members = (ZENGL_SYM_CLASSMEMBER_TABLE_MEMBER *)offset;
	}

	// 将函数符号表拷贝到缓存中
	tmp_point += sizeof(ZENGL_SYM_CLASSMEMBER_TABLE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->SymFunTable, sizeof(ZENGL_SYM_FUN_TABLE));
	if(compile->SymFunTable.funs != ZL_NULL) {
		// 将函数符号表的动态数组的指针值转为offset缓存偏移值,并存储到缓存里
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->SymFunTable.funs);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_SYM_FUN_TABLE *)tmp_point)->funs = (ZENGL_SYM_FUN_TABLE_MEMBER *)offset;
	}

	// 将链接地址动态数组拷贝到缓存中
	tmp_point += sizeof(ZENGL_SYM_FUN_TABLE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->LDAddrList, sizeof(ZENGL_LD_ADDRLIST_TYPE));
	if(compile->LDAddrList.addr != ZL_NULL) {
		// 将动态数组的指针转为缓存偏移值
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->LDAddrList.addr);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_LD_ADDRLIST_TYPE *)tmp_point)->addr = (ZENGL_LD_ADDR_TYPE *)offset;
	}

	// 将AST抽象语法树拷贝到缓存中
	tmp_point += sizeof(ZENGL_LD_ADDRLIST_TYPE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->AST_nodes, sizeof(ZENGL_AST_TYPE));
	if(compile->AST_nodes.nodes != ZL_NULL) {
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->AST_nodes.nodes);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_AST_TYPE *)tmp_point)->nodes = (ZENGL_AST_NODE_TYPE *)offset;
		tmp_point2 = api_cache_mempool + (offset - 1);
		tp = ZL_NULL;
		offset = 0;
		file_offset = 0;
		for(i=0; i < compile->AST_nodes.count ;i++) {
			// 将语法树的每个节点中包含的文件名指针转为偏移值
			if(compile->AST_nodes.nodes[i].filename != ZL_NULL) {
				if(tp != (ZL_BYTE *)compile->AST_nodes.nodes[i].filename) {
					file_offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->AST_nodes.nodes[i].filename);
					if(file_offset < 0) {
						VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
						return -1;
					}
					tp = (ZL_BYTE *)compile->AST_nodes.nodes[i].filename;
				}
				((ZENGL_AST_NODE_TYPE *)tmp_point2)[i].filename = (ZL_CHAR *)file_offset;
			}
			// 将节点的extchilds扩展子节点动态数组的指针值转为offset偏移值
			if(compile->AST_nodes.nodes[i].childs.extchilds != ZL_NULL) {
				offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->AST_nodes.nodes[i].childs.extchilds);
				if(offset < 0) {
					VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
					return -1;
				}
				((ZENGL_AST_NODE_TYPE *)tmp_point2)[i].childs.extchilds = (ZL_INT *)offset;
			}
		}
	}

	// 将token字符串池拷贝到缓存中
	tmp_point += sizeof(ZENGL_AST_TYPE);
	ZENGL_SYS_MEM_COPY(tmp_point, &compile->Token_StringPool, sizeof(ZENGL_TOKEN_STRING_POOL));
	if(compile->Token_StringPool.ptr != ZL_NULL) {
		// 将token字符串的指针转为offset偏移值
		offset = zengl_api_search_api_mempool((API_MEM_POOL_POINT_TYPE *)api_mempool, compile->mempool.count, compile->Token_StringPool.ptr);
		if(offset < 0) {
			VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_SEARCH_MEMPOOL_POINT_FAILED, ApiName , ApiName);
			return -1;
		}
		((ZENGL_TOKEN_STRING_POOL *)tmp_point)->ptr = (ZL_CHAR *)offset;
	}

	// 将解释器的指令列表相关的结构体拷贝到缓存中
	tmp_point = cachePtr + (baseSize + mempoolRealSize);
	ZENGL_SYS_MEM_COPY(tmp_point, &run->inst_list, sizeof(ZENGL_RUN_INST_LIST));
	((ZENGL_RUN_INST_LIST *)tmp_point)->size = ((ZENGL_RUN_INST_LIST *)tmp_point)->count;
	((ZENGL_RUN_INST_LIST *)tmp_point)->mempool_index = 0;
	((ZENGL_RUN_INST_LIST *)tmp_point)->insts = ZL_NULL;

	// 将指令列表中所有的指令都拷贝到缓存中
	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));

	tmp_point = cachePtr + (baseSize + mempoolRealSize + instListSize);
	// 将指令操作数字符串池相关的结构体拷贝到缓存中
	ZENGL_SYS_MEM_COPY(tmp_point, &run->InstData_StringPool, sizeof(ZENGL_RUN_INST_DATA_STRING_POOL));
	((ZENGL_RUN_INST_DATA_STRING_POOL *)tmp_point)->size = ((ZENGL_RUN_INST_DATA_STRING_POOL *)tmp_point)->count;
	((ZENGL_RUN_INST_DATA_STRING_POOL *)tmp_point)->mempool_index = 0;
	((ZENGL_RUN_INST_DATA_STRING_POOL *)tmp_point)->ptr = ZL_NULL;

	tmp_point += sizeof(ZENGL_RUN_INST_DATA_STRING_POOL);
	// 将指令操作数字符串池中的所有字符都拷贝到缓存中
	ZENGL_SYS_MEM_COPY(tmp_point, run->InstData_StringPool.ptr, run->InstData_StringPool.count * sizeof(ZL_CHAR));

	// 将缓存指针和缓存大小通过指针参数返回给调用者
	(*cachePoint) = cachePtr;
	(*cacheSize) = totalSize;
	return 0;
}

/* API接口,重利用缓存数据,就可以跳过编译过程 */
ZL_EXPORT ZL_EXP_INT zenglApi_ReUseCacheMemData(ZL_EXP_VOID * VM_ARG, ZL_EXP_VOID * cachePoint, ZL_EXP_INT cacheSize)
{
	ZENGL_VM_TYPE * VM = (ZENGL_VM_TYPE *)VM_ARG;
	ZENGL_COMPILE_TYPE * compile;
	ZENGL_RUN_TYPE * run;
	ZENGL_EXPORT_API_CACHE_TYPE * api_cache;
	ZL_BYTE * mempoolPtr, * tmp_point, * cachePtr;
	ZL_INT i, str_Index;
	ZL_LONG offset;
	ZL_CHAR * ApiName = "zenglApi_ReUseCacheMemData";
	ZL_CHAR * inst_data_string_ptr;
	//ZENGL_RUN_INST_DATA_STRING_POOL tmp_inst_data_str_pool;
	cachePtr = (ZL_BYTE *)cachePoint;
	if(VM->signer != ZL_VM_SIGNER) //通过虚拟机签名判断是否是有效的虚拟机
		return -1;
	switch(VM->ApiState)
	{
	case ZL_API_ST_OPEN:
	case ZL_API_ST_RESET:
		break;
	default:
		VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_INVALID_CALL_POSITION, ApiName , ApiName);
		return -1;
		break;
	}
	compile = &VM->compile;
	run = &VM->run;
	api_cache = (ZENGL_EXPORT_API_CACHE_TYPE *)cachePoint;
	// 通过缓存签名,判断是否是有效的缓存数据
	if(api_cache->signer != ZL_EXP_API_CACHE_SIGNER) {
		VM->run.SetApiErrorEx(VM_ARG,ZL_ERR_VM_API_CACHE_INVALID_CACHE_DATA, ApiName , ApiName);
		return -1;
	}
	mempoolPtr = (ZL_BYTE *)compile->memAlloc(VM_ARG, api_cache->mempoolRealSize);
	// 将缓存中保存的内存池数据,拷贝到编译器中
	ZENGL_SYS_MEM_COPY(mempoolPtr, (cachePtr + api_cache->mempoolOffset), api_cache->mempoolRealSize);

	tmp_point = cachePtr + sizeof(ZENGL_EXPORT_API_CACHE_TYPE);
	// 将缓存中的def宏定义常量的字符串池拷贝到编译器中
	ZENGL_SYS_MEM_COPY(&compile->def_StringPool, tmp_point, sizeof(ZENGL_STRING_POOL_TYPE));
	offset = (ZL_LONG)compile->def_StringPool.ptr;
	if(offset > 0) // 将缓存中的偏移值转为可以使用的指针值
		compile->def_StringPool.ptr = (ZL_CHAR *)(mempoolPtr + offset - 1);

	tmp_point += sizeof(ZENGL_STRING_POOL_TYPE);
	// 将def_table宏定义动态数组拷贝到编译器中
	ZENGL_SYS_MEM_COPY(&compile->def_table, tmp_point, sizeof(ZENGL_DEF_TABLE));
	offset = (ZL_LONG)compile->def_table.defs;
	if(offset > 0) // 将缓存偏移值转为指针值
		compile->def_table.defs = (ZENGL_DEF_TABLE_MEMBER *)(mempoolPtr + offset - 1);

	tmp_point += sizeof(ZENGL_DEF_TABLE);
	// 将缓存的哈希表拷贝到编译器
	ZENGL_SYS_MEM_COPY(compile->HashTable, tmp_point, sizeof(ZL_INT) * ZL_SYM_HASH_TOTAL_SIZE);

	tmp_point += sizeof(ZL_INT) * ZL_SYM_HASH_TOTAL_SIZE;
	// 将缓存的行列号动态数组拷贝到编译器
	ZENGL_SYS_MEM_COPY(&compile->LineCols, tmp_point, sizeof(ZENGL_LINECOL_TABLE));
	offset = (ZL_LONG)compile->LineCols.lines;
	if(offset > 0) {
		compile->LineCols.lines = (ZENGL_LINECOL *)(mempoolPtr + offset - 1);
		for(i=0; i < compile->LineCols.count ;i++) {
			// 将缓存偏移值转为指针值
			offset = (ZL_LONG)(compile->LineCols.lines[i].filename);
			if(offset > 0)
				compile->LineCols.lines[i].filename = (ZL_CHAR *)(mempoolPtr + offset - 1);
		}
	}

	tmp_point += sizeof(ZENGL_LINECOL_TABLE);
	// 将缓存的inc加载的文件信息堆栈拷贝到编译器,并将缓存偏移值转为可以使用的指针值
	ZENGL_SYS_MEM_COPY(&compile->FileStackList, tmp_point, sizeof(ZENGL_FILE_STACKLIST_TYPE));
	offset = (ZL_LONG)compile->FileStackList.stacks;
	if(offset > 0) {
		compile->FileStackList.stacks = (ZENGL_FILE_STACK_TYPE *)(mempoolPtr + offset - 1);
		for(i=0; i < compile->FileStackList.count ;i++) {
			offset = (ZL_LONG)(compile->FileStackList.stacks[i].source.filename);
			if(offset > 0)
				compile->FileStackList.stacks[i].source.filename = (ZL_CHAR *)(mempoolPtr + offset - 1);
		}
	}

	tmp_point += sizeof(ZENGL_FILE_STACKLIST_TYPE);
	// 将缓存的全局符号表拷贝到编译器
	ZENGL_SYS_MEM_COPY(&compile->SymGlobalTable, tmp_point, sizeof(ZENGL_SYM_GLOBAL_TABLE));
	offset = (ZL_LONG)compile->SymGlobalTable.sym;
	if(offset > 0) // 将缓存偏移转为指针
		compile->SymGlobalTable.sym = (ZENGL_SYM_GLOBAL_TABLE_MEMBER *)(mempoolPtr + offset - 1);

	tmp_point += sizeof(ZENGL_SYM_GLOBAL_TABLE);
	// 将缓存的局部变量(包括函数参数)符号表拷贝到编译器
	ZENGL_SYS_MEM_COPY(&compile->SymLocalTable, tmp_point, sizeof(ZENGL_SYM_LOCAL_TABLE));
	offset = (ZL_LONG)compile->SymLocalTable.local;
	if(offset > 0) // 将缓存偏移转为指针
		compile->SymLocalTable.local = (ZENGL_SYM_LOCAL_TABLE_MEMBER *)(mempoolPtr + offset - 1);

	tmp_point += sizeof(ZENGL_SYM_LOCAL_TABLE);
	// 将缓存的类符号表拷贝到编译器
	ZENGL_SYS_MEM_COPY(&compile->SymClassTable, tmp_point, sizeof(ZENGL_SYM_CLASS_TABLE));
	offset = (ZL_LONG)compile->SymClassTable.classTable;
	if(offset > 0) // 将缓存偏移转为指针
		compile->SymClassTable.classTable = (ZENGL_SYM_CLASS_TABLE_MEMBER *)(mempoolPtr + offset - 1);

	tmp_point += sizeof(ZENGL_SYM_CLASS_TABLE);
	// 将缓存的类成员符号表拷贝到编译器
	ZENGL_SYS_MEM_COPY(&compile->SymClassMemberTable, tmp_point, sizeof(ZENGL_SYM_CLASSMEMBER_TABLE));
	offset = (ZL_LONG)compile->SymClassMemberTable.members;
	if(offset > 0) // 将缓存偏移转为指针
		compile->SymClassMemberTable.members = (ZENGL_SYM_CLASSMEMBER_TABLE_MEMBER *)(mempoolPtr + offset - 1);

	tmp_point += sizeof(ZENGL_SYM_CLASSMEMBER_TABLE);
	// 将缓存的函数符号表拷贝到编译器
	ZENGL_SYS_MEM_COPY(&compile->SymFunTable, tmp_point, sizeof(ZENGL_SYM_FUN_TABLE));
	offset = (ZL_LONG)compile->SymFunTable.funs;
	if(offset > 0) // 将缓存偏移转为指针
		compile->SymFunTable.funs = (ZENGL_SYM_FUN_TABLE_MEMBER *)(mempoolPtr + offset - 1);

	tmp_point += sizeof(ZENGL_SYM_FUN_TABLE);
	// 将缓存的链接地址动态数组拷贝到编译器
	ZENGL_SYS_MEM_COPY(&compile->LDAddrList, tmp_point, sizeof(ZENGL_LD_ADDRLIST_TYPE));
	offset = (ZL_LONG)compile->LDAddrList.addr;
	if(offset > 0) // 将缓存偏移转为指针
		compile->LDAddrList.addr = (ZENGL_LD_ADDR_TYPE *)(mempoolPtr + offset - 1);

	tmp_point += sizeof(ZENGL_LD_ADDRLIST_TYPE);
	// 将缓存的AST抽象语法树拷贝到编译器
	ZENGL_SYS_MEM_COPY(&compile->AST_nodes, tmp_point, sizeof(ZENGL_AST_TYPE));
	offset = (ZL_LONG)compile->AST_nodes.nodes;
	if(offset > 0) { // 将节点中的各个缓存偏移值转为指针值
		compile->AST_nodes.nodes = (ZENGL_AST_NODE_TYPE *)(mempoolPtr + offset - 1);
		for(i=0; i < compile->AST_nodes.count ;i++) {
			offset = (ZL_LONG)(compile->AST_nodes.nodes[i].filename);
			if(offset > 0)
				compile->AST_nodes.nodes[i].filename = (ZL_CHAR *)(mempoolPtr + offset - 1);
			offset = (ZL_LONG)(compile->AST_nodes.nodes[i].childs.extchilds);
			if(offset > 0)
				compile->AST_nodes.nodes[i].childs.extchilds = (ZL_INT *)(mempoolPtr + offset - 1);
		}
	}

	tmp_point += sizeof(ZENGL_AST_TYPE);
	// 将缓存的token字符串池拷贝到编译器
	ZENGL_SYS_MEM_COPY(&compile->Token_StringPool, tmp_point, sizeof(ZENGL_TOKEN_STRING_POOL));
	offset = (ZL_LONG)compile->Token_StringPool.ptr;
	if(offset > 0) // 将缓存偏移转为指针
		compile->Token_StringPool.ptr = (ZL_CHAR *)(mempoolPtr + offset - 1);

	tmp_point = cachePtr + (api_cache->mempoolOffset + api_cache->mempoolRealSize);
	// 将缓存的指令列表相关的结构体拷贝到解释器
	ZENGL_SYS_MEM_COPY( &run->inst_list, tmp_point, sizeof(ZENGL_RUN_INST_LIST));
	run->inst_list.insts = (ZENGL_RUN_INST_LIST_MEMBER *)run->memAlloc(VM_ARG, run->inst_list.count * sizeof(ZENGL_RUN_INST_LIST_MEMBER),
			&run->inst_list.mempool_index);

	tmp_point += sizeof(ZENGL_RUN_INST_LIST);
	// 将缓存的指令列表中的所有指令都拷贝到解释器
	ZENGL_SYS_MEM_COPY(run->inst_list.insts, tmp_point, run->inst_list.count * sizeof(ZENGL_RUN_INST_LIST_MEMBER));

	tmp_point += run->inst_list.count * sizeof(ZENGL_RUN_INST_LIST_MEMBER);
	//ZENGL_SYS_MEM_COPY(&tmp_inst_data_str_pool, tmp_point, sizeof(ZENGL_RUN_INST_DATA_STRING_POOL));
	tmp_point += sizeof(ZENGL_RUN_INST_DATA_STRING_POOL);
	inst_data_string_ptr = (ZL_CHAR *)tmp_point;
	// 将缓存的指令操作数字符串通过InstDataStringPoolAdd函数添加到当前解释器中,并相应的调整指令中的str_Index的值(字符串在字符串池中的索引)
	for(i=0; i < run->inst_list.count ;i++) {
		if(run->inst_list.insts[i].src.type == ZL_R_DT_STR) {
			str_Index = run->inst_list.insts[i].src.val.str_Index;
			if(str_Index > 0)
				run->inst_list.insts[i].src.val.str_Index = run->InstDataStringPoolAdd(VM_ARG, (inst_data_string_ptr + str_Index));
		}
		if(run->inst_list.insts[i].dest.type == ZL_R_DT_STR) {
			str_Index = run->inst_list.insts[i].dest.val.str_Index;
			if(str_Index > 0)
				run->inst_list.insts[i].dest.val.str_Index = run->InstDataStringPoolAdd(VM_ARG, (inst_data_string_ptr + str_Index));
		}
	}
	// 在将缓存的编译数据都拷贝到虚拟机中后,就可以将编译器的isReUse设置为ZL_TRUE,这样在解释执行时,就可以跳过编译过程
	VM->compile.isReUse = ZL_TRUE;
	return 0;
}


    在main.c文件中,就使用了这两个接口函数,来完成编译数据的缓存和重利用:

/**
 * 将append_path路径追加到full_path中,如果追加路径后,full_path长度会超出full_path_size时,路径将会被截断
 */
static int main_full_path_append(char * full_path, int full_path_length, int full_path_size, char * append_path)
{
	int append_path_length = strlen(append_path);
	int max_length = full_path_size - full_path_length - 1;
	if(append_path_length > max_length)
		append_path_length = max_length;
	if(append_path_length > 0)
		strncpy((full_path + full_path_length), append_path, append_path_length);
	return append_path_length;
}

static void main_compute_md5(char * buf, char * str, ZL_EXP_BOOL isLowerCase, ZL_EXP_BOOL is32)
{
	MD5_CTX md5;
	unsigned char * encrypt = (unsigned char *)str;
	unsigned char decrypt[16];
	char * p;
	const char * format;
	int start_idx, end_idx, i;
	MD5Init(&md5);
	MD5Update(&md5,encrypt,strlen((char *)encrypt));
	MD5Final(&md5,decrypt);
	p = buf;
	start_idx = is32 ? 0 : 4;
	end_idx = is32 ? 16 : 12;
	format = isLowerCase ? "%02x" : "%02X";
	for(i = start_idx; i < end_idx; i++) {
		sprintf(p, format, decrypt[i]);
		p += 2;
	}
	(*p) = '\0';
}

/**
 * 根据full_path脚本路径,得到最终要生成的缓存文件的路径信息
 */
static void main_get_zengl_cache_path(char * cache_path, int cache_path_size, char * full_path)
{
	char fullpath_md5[33];
	char cache_prefix[20] = {0};
	const char * cache_path_prefix = "caches/"; // 缓存文件都放在caches目录中
	int append_length;
	main_compute_md5(fullpath_md5, full_path, ZL_EXP_TRUE, ZL_EXP_TRUE); // 将full_path进行md5编码
	// 在缓存路径前面加上zengl版本号和指针长度,不同的zengl版本生成的缓存有可能会不一样,另外,32位和64位环境下生成的内存缓存数据也是不一样的
	// 32位系统中生成的缓存数据放到64位中运行,或者反过来,都会报内存相关的错误
	sprintf(cache_prefix, "%d_%d_%d_%ld_", ZL_EXP_MAJOR_VERSION, ZL_EXP_MINOR_VERSION, ZL_EXP_REVISION, sizeof(char *));
	append_length = main_full_path_append(cache_path, 0, cache_path_size, (char *)cache_path_prefix);
	append_length += main_full_path_append(cache_path, append_length, cache_path_size, cache_prefix);
	append_length += main_full_path_append(cache_path, append_length, cache_path_size, fullpath_md5);
	cache_path[append_length] = '\0';
}

/**
 * 尝试重利用full_path脚本文件对应的缓存数据,cache_path表示缓存数据所在的文件路径
 * 如果缓存文件不存在,则会重新生成缓存文件,如果full_path脚本文件内容发生了改变或者其加载的脚本文件内容发生了改变,也会重新生成缓存
 * 外部调用者通过is_reuse_cache变量的值来判断是否需要生成缓存文件,如果is_reuse_cache为ZL_EXP_FALSE,就表示没有重利用缓存,则需要生成缓存文件
 * 如果is_reuse_cache为ZL_EXP_TRUE,则说明重利用了缓存,不需要再生成缓存文件了
 */
static void main_try_to_reuse_zengl_cache(ZL_EXP_VOID * VM, char * cache_path, char * full_path, ZL_EXP_BOOL * is_reuse_cache)
{
	FILE * ptr_fp;
	ZL_EXP_VOID * cachePoint;
	ZENGL_EXPORT_API_CACHE_TYPE * api_cache;
	ZL_EXP_LONG offset, cache_mtime, file_mtime;
	ZL_EXP_BYTE * mempoolPtr;
	ZL_EXP_CHAR ** filenames, * filename;
	ZL_EXP_INT cacheSize, i;
	struct stat stat_result;
	(* is_reuse_cache) = ZL_EXP_FALSE;
	if(stat(cache_path, &stat_result)==0) { // 获取缓存文件的修改时间
		cache_mtime = (ZL_EXP_LONG)stat_result.st_mtime;
	}
	else { // 获取文件的状态信息失败,可能缓存文件不存在,需要重新编译生成缓存,直接返回
		printf("stat cache file: \"%s\" failed, maybe no cache file [recompile]\n", cache_path);
		return ;
	}
	if(stat(full_path, &stat_result)==0) { // 获取主执行脚本的修改时间
		file_mtime = (ZL_EXP_LONG)stat_result.st_mtime;
		printf("%s mtime:%ld", full_path, file_mtime);
		if(file_mtime >= cache_mtime) { // 如果主执行脚本的修改时间大于等于缓存数据的修改时间,则说明主执行脚本的内容发生了改变,需要重新编译生成新的缓存
			printf(" [changed] [recompile]\n");
			return;
		}
		printf("\n");
	}
	else { // 主执行脚本不存在,直接返回
		printf("warning stat script file: \"%s\" failed, maybe no such file! [recompile]\n", full_path);
		return ;
	}
	// 打开缓存文件
	if((ptr_fp = fopen(cache_path, "rb")) == NULL) {
		printf("no cache file: \"%s\" [recompile]\n", cache_path);
		return ;
	}
	fseek(ptr_fp,0L,SEEK_END);
	cacheSize = ftell(ptr_fp); // 得到缓存数据的大小
	fseek(ptr_fp,0L,SEEK_SET);
	cachePoint = malloc(cacheSize); // 根据缓存大小分配堆空间,先将缓存数据读取到该堆内存中
	if(fread(cachePoint, cacheSize, 1, ptr_fp) != 1) { // 读取缓存数据
		printf("read cache file \"%s\" failed [recompile]\n", cache_path);
		goto end;
	}
	api_cache = (ZENGL_EXPORT_API_CACHE_TYPE *)cachePoint;
	if(api_cache->signer != ZL_EXP_API_CACHE_SIGNER) { // 根据缓存签名判断是否是有效的缓存数据
		printf("invalid cache file \"%s\" [recompile]\n", cache_path);
		goto end;
	}
	mempoolPtr = ((ZL_EXP_BYTE *)cachePoint + api_cache->mempoolOffset);
	offset = (ZL_EXP_LONG)api_cache->filenames;
	filenames = (ZL_EXP_CHAR **)(mempoolPtr + offset - 1);
	if(api_cache->filenames_count > 0) {
		// 循环判断加载的脚本文件的内容是否发生了改变,如果改变了,则需要重新编译生成新的缓存
		for(i=0; i < api_cache->filenames_count; i++) {
			offset = (ZL_EXP_LONG)(filenames[i]);
			filename = (ZL_EXP_CHAR *)(mempoolPtr + offset - 1);
			printf("%s", filename);
			if(stat(filename, &stat_result)==0) {
				file_mtime = (ZL_EXP_LONG)stat_result.st_mtime;
				printf(" mtime:%ld", file_mtime);
				if(file_mtime >= cache_mtime){
					printf(" [changed] [recompile]\n");
					goto end;
				}
			}
			else {
				printf(" stat failed [recompile]\n");
				goto end;
			}
			printf("\n");
		}
	}
	// 通过zenglApi_ReUseCacheMemData接口函数,将编译好的缓存数据加载到编译器和解释器中,这样就可以跳过编译过程,直接运行
	if(zenglApi_ReUseCacheMemData(VM, cachePoint, cacheSize) == -1) {
		printf("reuse cache file \"%s\" failed: %s [recompile]\n", cache_path, zenglApi_GetErrorString(VM));
		goto end;
	}
	(* is_reuse_cache) = ZL_EXP_TRUE;
	printf("reuse cache file: \"%s\" mtime:%ld\n", cache_path, cache_mtime);
end:
	fclose(ptr_fp);
	free(cachePoint);
}

/**
 * 在编译执行结束后,生成缓存数据并写入缓存文件
 */
static void main_write_zengl_cache_to_file(ZL_EXP_VOID * VM, char * cache_path)
{
	FILE * ptr_fp;
	ZL_EXP_VOID * cachePoint;
	ZL_EXP_INT cacheSize;
	// 通过zenglApi_CacheMemData接口函数,将编译器和解释器中的主要的内存数据缓存到cachePoint对应的内存中
	if(zenglApi_CacheMemData(VM, &cachePoint, &cacheSize) == -1) {
		printf("write zengl cache to file \"%s\" failed: %s\n", cache_path,zenglApi_GetErrorString(VM));
		return;
	}

	// 打开cache_path对应的缓存文件
	if((ptr_fp = fopen(cache_path, "wb")) == NULL) {
		printf("write zengl cache to file \"%s\" failed: open failed\n", cache_path);
		return;
	}

	// 将缓存数据写入缓存文件
	if( fwrite(cachePoint, cacheSize, 1, ptr_fp) != 1)
		printf("write zengl cache to file \"%s\" failed: write failed\n", cache_path);
	else
		printf("write zengl cache to file \"%s\" success \n", cache_path);
	fclose(ptr_fp);
}

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

/**
	用户程序执行入口。
*/
int main(int argc,char * argv[])
{
	............................................................
	ZL_EXP_BOOL is_reuse_cache;
	char cache_path[200];

	............................................................
	if(argc >= 3 && strcmp(argv[2],"-d") == 0)
		zenglApi_DebugSetBreakHandle(VM,main_debug_break,main_debug_conditionError,ZL_EXP_TRUE,ZL_EXP_FALSE); //设置调试API

	// 根据脚本文件名得到缓存文件的路径信息
	main_get_zengl_cache_path(cache_path, sizeof(cache_path), argv[1]);
	// 尝试重利用缓存数据
	main_try_to_reuse_zengl_cache(VM, cache_path, argv[1], &is_reuse_cache);
	if(zenglApi_Run(VM,argv[1]) == -1) //编译执行zengl脚本
		main_exit(VM,"错误:编译<%s>失败:%s\n",argv[1],zenglApi_GetErrorString(VM));
	else if(!is_reuse_cache) // 如果没有重利用缓存数据,则生成新的缓存数据,并将其写入缓存文件中
		main_write_zengl_cache_to_file(VM, cache_path);

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

	return 0;
}


    以上就是当前版本的相关内容,限于篇幅,本章就到这里,读者可以根据源码的相关注释来加深理解。当前版本也只在windows,linux,macosx中进行过基本的测试。

结束语:

    不要怀疑自己的价值 不要迷失自我

——  《纳尼亚传奇3》
 
上下篇

下一篇: zengl v1.8.1 修复bug

上一篇: zengl v1.7.4 修复Bug

相关文章

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

zengl v1.8.1 修复bug

zengl v1.7.2, zenglServer v0.2.0

zengl编程语言v0.0.11实现循环控制结构

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

zengl v1.2.1 修复函数调用BUG