页面导航:
项目下载地址:
zengl language v1.7.4 源代码的相关地址:
https://github.com/zenglong/zengl_language/ 对应的tag标签为:v1.7.4
zengl v1.7.4:
该版本修复了zenglrun_makeInfoString函数(定义在zenglrun_func.c文件中)和zengl_makeInfoString函数(定义在zengl_main.c文件中)在生成格式化字符串时,如果格式化的字符串较长时,在64位gcc和clang中会出现乱码或者段错误的Bug:
/*生成格式化信息字符串*/
ZL_CHAR * zenglrun_makeInfoString(ZL_VOID * VM_ARG,ZENGL_RUN_INFO_STRING_TYPE * infoStringPtr , ZL_CONST ZL_CHAR * format , ZENGL_SYS_ARG_LIST arglist)
{
ZENGL_RUN_TYPE * run = &((ZENGL_VM_TYPE *)VM_ARG)->run;
ZENGL_SYS_ARG_LIST tmp_arglist;
ZL_INT retcount = -1;
ZENGL_SYS_ARG_END(tmp_arglist);
if(infoStringPtr->str == ZL_NULL)
{
infoStringPtr->size = ZL_INFO_STRING_SIZE;
infoStringPtr->str = run->memAlloc(VM_ARG,infoStringPtr->size * sizeof(ZL_CHAR),&infoStringPtr->mempool_index);
}
do
{
// 在64位系统中, GCC和clang会将va_list指向某种特殊的结构,该结构中存储了可变参数位置信息,
// 直接将va_list传递给vsnprintf的话,相当于将特殊结构的指针传递过去,vsnprintf根据指针,会修改该结构指向的参数位置,那么下一次再次执行
// vsnprintf时,虽然va_list指针没变化,但是va_list对应的结构,实际指向的可能是一个无效的参数。因此,需要先使用va_copy生成一个拷贝,
// 再将va_list的拷贝(包含了特殊结构的拷贝)传递给vsnprintf,
// 32位系统,不需要va_copy也可以正常工作,因为32位系统中的va_list是一个简单的栈指针,直接指向了可变参数位置,
// 32位中,va_list传递给vsnprintf时,本身就是以栈指针拷贝的方式传递的,所以32位系统中没有va_copy也可以正常工作,
// 不过,为了让代码能够在32位和64位中都正常运作,就统一使用va_copy的方式来处理,在VS2008之类的没有
// va_copy的环境中,会将va_copy定义为memcpy
ZENGL_SYS_ARG_COPY(tmp_arglist, arglist);
retcount = ZENGL_SYS_SPRINTF_ARG_NUM((infoStringPtr->str + infoStringPtr->cur),
(infoStringPtr->size - infoStringPtr->count),format,tmp_arglist);
ZENGL_SYS_ARG_END(tmp_arglist);
if(retcount >= 0 && retcount < (infoStringPtr->size - infoStringPtr->count))
{
infoStringPtr->count += retcount;
infoStringPtr->cur = infoStringPtr->count;
infoStringPtr->str[infoStringPtr->cur] = ZL_STRNULL;
return infoStringPtr->str;
}
infoStringPtr->size += ZL_INFO_STRING_SIZE;
infoStringPtr->str = run->memReAlloc(VM_ARG,infoStringPtr->str,infoStringPtr->size * sizeof(ZL_CHAR),&infoStringPtr->mempool_index);
} while(ZL_TRUE);
return ZL_NULL;
}
|
以及修复zenglrun_InstDataStringPoolAdd函数(定义在zenglrun_func.c文件中),在添加的指令操作数是字符串,且字符串的长度较长时,会出现的字符串截断和发生ZL_ERR_RUN_INST_DATA_STR_POOL_ADD_I_OUT_OF_BOUNDS错误的Bug:
/*
指令操作数字符串池添加字符串
*/
ZL_INT zenglrun_InstDataStringPoolAdd(ZL_VOID * VM_ARG , ZL_CHAR * src)
{
ZENGL_RUN_TYPE * run = &((ZENGL_VM_TYPE *)VM_ARG)->run;
ZL_INT len;
ZL_INT i,j;
if(!run->InstData_StringPool.isInit)
run->initInstDataStringPool(VM_ARG);
if(src == ZL_NULL)
return -1;
len = ZENGL_SYS_STRLEN(src);
// 这里使用while循环语句,循环增加size,直到size能够满足字符串的大小时才跳出循环
// 之前用的if语句,size只会增加一次,从而导致指令操作数中,较长的字符串会被截断,
// 并发生 ZL_ERR_RUN_INST_DATA_STR_POOL_ADD_I_OUT_OF_BOUNDS 错误
while(run->InstData_StringPool.count >= run->InstData_StringPool.size ||
run->InstData_StringPool.count + len + 1 > run->InstData_StringPool.size)
{
run->InstData_StringPool.size += ZL_R_INST_DATA_STRING_POOL_SIZE;
run->InstData_StringPool.ptr = run->memReAlloc(VM_ARG,run->InstData_StringPool.ptr,
run->InstData_StringPool.size * sizeof(ZL_CHAR),
&run->InstData_StringPool.mempool_index);
ZENGL_SYS_MEM_SET(run->InstData_StringPool.ptr + (run->InstData_StringPool.size - ZL_R_INST_DATA_STRING_POOL_SIZE),0,
ZL_R_INST_DATA_STRING_POOL_SIZE * sizeof(ZL_CHAR));
}
for(i=run->InstData_StringPool.count,j=0;
i<run->InstData_StringPool.size && j<len;i++,j++)
{
run->InstData_StringPool.ptr[i] = src[j];
}
if(i >= run->InstData_StringPool.size)
run->exit(VM_ARG,ZL_ERR_RUN_INST_DATA_STR_POOL_ADD_I_OUT_OF_BOUNDS);
else
run->InstData_StringPool.ptr[i] = ZL_STRNULL;
i = run->InstData_StringPool.count;
run->InstData_StringPool.count += len + 1;
return i;
}
|
在zengl_main函数里(定义在zengl_main.c中),添加检测errorFullString错误信息的代码:
/*编译器入口函数*/
ZL_INT zengl_main(ZL_VOID * VM_ARG,ZL_CHAR * script_file,ZENGL_EXPORT_VM_MAIN_ARGS * vm_main_args)
{
..........................................
compile->KeywordCompleteDetect(VM_ARG);
compile->buildAST(VM_ARG); //组建AST抽象语法树
compile->buildSymTable(VM_ARG); //组建符号表
compile->buildAsmCode(VM_ARG); //组建汇编代码
compile->LDAddrListReplaceAll(VM_ARG); //将所有的伪地址替换为真实的汇编代码位置,从而完成链接工作
/**
* 在编译过程中,如果调用了解释器的函数时,例如buildAsmCode组建汇编代码,向解释器写入虚拟汇编指令时
* 如果发生错误,是不会立即退出的,只会将错误信息写入到errorFullString中,因此,这里,如果检测到
* 错误,就退出编译器,并将错误信息传递给用户自定义函数(如果定义了的话)
*/
if(compile->errorFullString.str != ZL_NULL && compile->errorFullString.count > 0)
{
compile->exit(VM_ARG, ZL_ERR_RUN_ERROR_EXIT_WHEN_IN_COMPILE);
}
end:
..........................................
}
|
当编译器调用解释器的方法发生错误时,虚拟机如果是以zenglApi_Run的方式运行时,并不会立即退出,而只是将错误信息写入到errorFullString中,因此,需要在上面的zengl_main函数中添加相关的检测代码,这样当发生ZL_ERR_RUN_INST_DATA_STR_POOL_ADD_I_OUT_OF_BOUNDS之类的错误时,就能够及时退出编译器,并将错误信息显示出来。
测试脚本:test_scripts/v1.7.4/test.zl:
use builtin;
contents = '
年代:魏晋 作者:陶渊明
《归园田居 其一》
少无适俗韵,性本爱丘山。
误落尘网中,一去三十年。(误落 一作:误入)
羁鸟恋旧林,池鱼思故渊。
开荒南野际,守拙归园田。
方宅十余亩,草屋八九间。
榆柳荫后檐,桃李罗堂前。
暧暧远人村,依依墟里烟。
狗吠深巷中,鸡鸣桑树颠。(颠 通 巅)
户庭无尘杂,虚室有余闲。
久在樊笼里,复得返自然。
《归园田居 其二》
野外罕人事,穷巷寡轮鞅。
白日掩荆扉,虚室绝尘想。
时复墟曲中,披草共来往。(墟曲中 一作:墟曲人)
相见无杂言,但道桑麻长。
桑麻日已长,我土日已广。
常恐霜霰至,零落同草莽。
《归园田居 其三》
种豆南山下,草盛豆苗稀。
晨兴理荒秽,带月荷锄归。
道狭草木长,夕露沾我衣。
衣沾不足惜,但使愿无违。
《归园田居 其四》
久去山泽游,浪莽林野娱。
试携子侄辈,披榛步荒墟。
徘徊丘垄间,依依昔人居。
井灶有遗处,桑竹残朽株。
借问采薪者,此人皆焉如?
薪者向我言,死没无复余。
一世异朝市,此语真不虚。
人生似幻化,终当归空无。
《归园田居 其五》
怅恨独策还,崎岖历榛曲。
山涧清且浅,遇以濯吾足。
漉我新熟酒,双鸡招近局。
日入室中暗,荆薪代明烛。
欢来苦夕短,已复至天旭。
《饮酒 其一》
衰荣无定在,彼此更共之。
邵生瓜田中,宁似东陵时!
寒暑有代谢,人道每如兹。
达人解其会,逝将不复疑;
忽与一樽酒,日夕欢相持。
《饮酒 其二》
积善云有报,夷叔在西山。
善恶苟不应,何事空立言!
九十行带索,饥寒况当年。
不赖固穷节,百世当谁传。
《饮酒 其三》
道丧向千载,人人惜其情。
有酒不肯饮,但顾世间名。
所以贵我身,岂不在一生?
一生复能几,倏如流电惊。
鼎鼎百年内,持此欲何成!
《饮酒 其四》
栖栖失群鸟,日暮犹独飞。
徘徊无定止,夜夜声转悲。
厉响思清远,去来何依依。
因值孤生松,敛翮遥来归。
劲风无荣木,此荫独不衰。
托身已得所,千载不相违。
《饮酒 其五》
结庐在人境,而无车马喧。
问君何能尔?心远地自偏。
采菊东篱下,悠然见南山。
山气日夕佳,飞鸟相与还。
此中有真意,欲辨已忘言。(辨 通:辩)
《桃花源诗》
嬴氏乱天纪,贤者避其世。
黄绮之商山,伊人亦云逝。
往迹浸复湮,来径遂芜废。
相命肆农耕,日入从所憩。
桑竹垂馀荫,菽稷随时艺;
春蚕收长丝,秋熟靡王税。
荒路暧交通,鸡犬互鸣吠。
俎豆独古法,衣裳无新制。
童孺纵行歌,班白欢游诣。
草荣识节和,木衰知风厉。
虽无纪历志,四时自成岁。
怡然有馀乐,于何荣智慧!
奇踪隐五百,一朝敞神界。
淳薄既异源,旋复还幽蔽。
借问游方士,焉测尘嚣外。
愿言蹑清风,高举寻吾契。
《桃花源诗》这篇作品为陶渊明晚年所作。作品以虚构的方式,描绘了一幅没有战乱,没有压迫,没有剥削,人人劳动、平等自由,道德淳朴、宁静和睦的社会生活图景——桃花源,寄托了作者美好的社会理想。这个理想中的美好社会,与当时黑暗的现实社会形成鲜明的对比,从而表现出作者对现实社会的不满和否定,同时在一定程度上也反映了广大人民追求美好生活的愿望。
';
print '\ncontents length:' + bltGetStrLen(contents) + '\n';
print contents;
|
当前版本的执行结果如下:
zengl@zengl-ubuntu:~/zengl/zengl_language/linux$ ./zengl test_scripts/v1.7.4/test.zl
run(编译执行中)...
contents length:3634
年代:魏晋 作者:陶渊明
《归园田居 其一》
少无适俗韵,性本爱丘山。
误落尘网中,一去三十年。(误落 一作:误入)
羁鸟恋旧林,池鱼思故渊。
开荒南野际,守拙归园田。
方宅十余亩,草屋八九间。
榆柳荫后檐,桃李罗堂前。
暧暧远人村,依依墟里烟。
狗吠深巷中,鸡鸣桑树颠。(颠 通 巅)
户庭无尘杂,虚室有余闲。
久在樊笼里,复得返自然。
《归园田居 其二》
野外罕人事,穷巷寡轮鞅。
白日掩荆扉,虚室绝尘想。
时复墟曲中,披草共来往。(墟曲中 一作:墟曲人)
相见无杂言,但道桑麻长。
桑麻日已长,我土日已广。
常恐霜霰至,零落同草莽。
《归园田居 其三》
种豆南山下,草盛豆苗稀。
晨兴理荒秽,带月荷锄归。
道狭草木长,夕露沾我衣。
衣沾不足惜,但使愿无违。
《归园田居 其四》
久去山泽游,浪莽林野娱。
试携子侄辈,披榛步荒墟。
徘徊丘垄间,依依昔人居。
井灶有遗处,桑竹残朽株。
借问采薪者,此人皆焉如?
薪者向我言,死没无复余。
一世异朝市,此语真不虚。
人生似幻化,终当归空无。
《归园田居 其五》
怅恨独策还,崎岖历榛曲。
山涧清且浅,遇以濯吾足。
漉我新熟酒,双鸡招近局。
日入室中暗,荆薪代明烛。
欢来苦夕短,已复至天旭。
《饮酒 其一》
衰荣无定在,彼此更共之。
邵生瓜田中,宁似东陵时!
寒暑有代谢,人道每如兹。
达人解其会,逝将不复疑;
忽与一樽酒,日夕欢相持。
《饮酒 其二》
积善云有报,夷叔在西山。
善恶苟不应,何事空立言!
九十行带索,饥寒况当年。
不赖固穷节,百世当谁传。
《饮酒 其三》
道丧向千载,人人惜其情。
有酒不肯饮,但顾世间名。
所以贵我身,岂不在一生?
一生复能几,倏如流电惊。
鼎鼎百年内,持此欲何成!
《饮酒 其四》
栖栖失群鸟,日暮犹独飞。
徘徊无定止,夜夜声转悲。
厉响思清远,去来何依依。
因值孤生松,敛翮遥来归。
劲风无荣木,此荫独不衰。
托身已得所,千载不相违。
《饮酒 其五》
结庐在人境,而无车马喧。
问君何能尔?心远地自偏。
采菊东篱下,悠然见南山。
山气日夕佳,飞鸟相与还。
此中有真意,欲辨已忘言。(辨 通:辩)
《桃花源诗》
嬴氏乱天纪,贤者避其世。
黄绮之商山,伊人亦云逝。
往迹浸复湮,来径遂芜废。
相命肆农耕,日入从所憩。
桑竹垂馀荫,菽稷随时艺;
春蚕收长丝,秋熟靡王税。
荒路暧交通,鸡犬互鸣吠。
俎豆独古法,衣裳无新制。
童孺纵行歌,班白欢游诣。
草荣识节和,木衰知风厉。
虽无纪历志,四时自成岁。
怡然有馀乐,于何荣智慧!
奇踪隐五百,一朝敞神界。
淳薄既异源,旋复还幽蔽。
借问游方士,焉测尘嚣外。
愿言蹑清风,高举寻吾契。
《桃花源诗》这篇作品为陶渊明晚年所作。作品以虚构的方式,描绘了一幅没有战乱,没有压迫,没有剥削,人人劳动、平等自由,道德淳朴、宁静和睦的社会生活图景——桃花源,寄托了作者美好的社会理想。这个理想中的美好社会,与当时黑暗的现实社会形成鲜明的对比,从而表现出作者对现实社会的不满和否定,同时在一定程度上也反映了广大人民追求美好生活的愿望。
run finished(编译执行结束)
zengl@zengl-ubuntu:~/zengl/zengl_language/linux$
|
如果在zenglrun_makeInfoString函数中,不使用va_copy拷贝tmp_arglist,而像之前的版本那样,直接使用arglist进行vsnprintf操作的话:
/*生成格式化信息字符串*/
ZL_CHAR * zenglrun_makeInfoString(ZL_VOID * VM_ARG,ZENGL_RUN_INFO_STRING_TYPE * infoStringPtr , ZL_CONST ZL_CHAR * format , ZENGL_SYS_ARG_LIST arglist)
{
ZENGL_RUN_TYPE * run = &((ZENGL_VM_TYPE *)VM_ARG)->run;
ZENGL_SYS_ARG_LIST tmp_arglist;
ZL_INT retcount = -1;
ZENGL_SYS_ARG_END(tmp_arglist);
if(infoStringPtr->str == ZL_NULL)
{
infoStringPtr->size = ZL_INFO_STRING_SIZE;
infoStringPtr->str = run->memAlloc(VM_ARG,infoStringPtr->size * sizeof(ZL_CHAR),&infoStringPtr->mempool_index);
}
do
{
.............................................
// ZENGL_SYS_ARG_COPY(tmp_arglist, arglist);
retcount = ZENGL_SYS_SPRINTF_ARG_NUM((infoStringPtr->str + infoStringPtr->cur),
(infoStringPtr->size - infoStringPtr->count),format,arglist);
// ZENGL_SYS_ARG_END(tmp_arglist);
if(retcount >= 0 && retcount < (infoStringPtr->size - infoStringPtr->count))
{
infoStringPtr->count += retcount;
infoStringPtr->cur = infoStringPtr->count;
infoStringPtr->str[infoStringPtr->cur] = ZL_STRNULL;
return infoStringPtr->str;
}
infoStringPtr->size += ZL_INFO_STRING_SIZE;
infoStringPtr->str = run->memReAlloc(VM_ARG,infoStringPtr->str,infoStringPtr->size * sizeof(ZL_CHAR),&infoStringPtr->mempool_index);
} while(ZL_TRUE);
return ZL_NULL;
}
|
在64位gcc和clang的编译环境下,得到的就会是乱码(由于没有对va_list类型的arglist变量执行va_copy操作,64位环境中,当第二次执行vsnprintf时,就会指向错误的参数位置):
zengl@zengl-ubuntu:~/zengl/zengl_language/linux$ ./zengl test_scripts/v1.7.4/test.zl
run(编译执行中)...
contents length:3634
UH��H���
run finished(编译执行结束)
zengl@zengl-ubuntu:~/zengl/zengl_language/linux$
|
以上就是当前版本相关的内容,当前版本也只在windows,linux和mac OSX中进行过基本的测试。
结束语:
每样东西的背后,都有它的故事
—— 《夸世代》