前面的21点扑克小游戏是使用全局变量作为数组的索引名的,这种做法需要消耗一部分全局变量,本节v0.0.19版本增加了def关键字,用于替代这种做法,从而减少全局变量的开销。 ...
前面的21点扑克小游戏是使用全局变量作为数组的索引名的,这种做法需要消耗一部分全局变量,本节v0.0.19版本增加了def关键字,用于替代这种做法,从而减少全局变量的开销。
本节v0.0.19版本的源代码下载地址为:http://pan.baidu.com/share/link?shareid=213915&uk=940392313 (此为百度云盘的共享链接地址),访问该地址可以看到三个文件:zengl_lang_v0.0.19_forXP.rar (XP系统下的vs2008解决方案和源代码), zengl_language_v0.0.19_forLinux.tar.gz (Linux系统下的源代码和makefile) ,v0.0.19-v0.0.18-diffs.txt (v0.0.19和v0.0.18的代码变化情况)。
SourceForge.net上的仓库地址为:https://sourceforge.net/projects/zengl/files/ 从里面可以看到各个版本的代码压缩包,比如本节的zengl_lang_v0.0.19_forXP.rar ,zengl_language_v0.0.19_forLinux.tar.gz,v0.0.19-v0.0.18-diffs.txt 。
先来看下本版本的描述(在linux代码包里的usage.txt里有这段描述,在目前几个带有git版本的....-diffs.txt和git log中也有这段描述):
v0.0.19版本,该版本实现了def常量(宏)的定义。
在main.c中添加了def关键字,该关键字用于实现常量(宏)的定义,例如def Money 100;这条语句就定义了一个Money的常量,或者说是Money的宏,其值为100,所有使用到Money的地方都会被编译器替换为100。
有点类似c语言的#define宏预定义,也有点类似php的define函数。不过def只能定义常量宏,不能定义类似c中的函数宏,例如在c中可以用 到#define max(a,b) a>b 这样的宏定义形式,但是在本脚本语言中是不允许的,只能定义字母数字下划线构成的常量宏,如果以后有需要的话,可能会实现类似c中的函数宏形式。另外,宏 的值只能是整数,浮点数以及字符串,并且以分号结尾。
为了实现def关键字,在main.c中添加了stDef_table(存放常量宏及值的动态数组),hash表(用于从stDef_table中搜索常 量宏的,该hash表采用symbol.c中定义的全局hash表),以及stFactors_for_def(和parser.c中的 factors_strlist用法类似)。通过这几个数组加上相关的操作函数,就可以将def定义的常量宏储存起来,在后面的getToken时如果发 现某id标识符的名字在def中定义过的话,就将该标识符替换为def定义的值。
在main.c做完词法分析后,最后调用FreeDefTables清理hash表,这样后面的符号表才能正常使用hash表,并且清理掉stDef_table和stFactors_for_def分配的内存空间。
将def定义运用到game_21_point.zl(21点的游戏程序)中,减少了不必要的全局变量所带来的内存开销,同时由于def指令不会生成汇编代码,所以减少了代码量,优化了速度。
详情请用git log -p 或 gitk 查看。
作者:zenglong
时间:2012年5月5日
官网网站:www.zengl.com
先来看下本节21点扑克小游戏的beta改进版:game_21_point.zl文件中和def宏定义有关的代码:
use builtin;
def TRUE 1;
def FALSE 0;
def Name 0;//用户或android庄家的昵称。
def PokerCnt 1; //用户或android获取的扑克牌数目。
def Pokers 2;//存放获取的扑克牌数组。
def TotalPoker 3;//扑克牌的总点数。
def Money 4;//用户或android的当前资金。
android[Name]='Android'; //这里就使用了Name宏定义来代替数字0,即数组的第一个元素的索引。
user[Name]='User';
user[Money] = android[Money] = 2000;
......................... //省略N行代码
/*myIsNeedPoker函数用于机器人通过概率来判断
是否需要继续要牌*/
fun myIsNeedPoker(array)
num = 21 - array[TotalPoker]; //因为使用了宏来代替全局变量所以函数里就不需要global来引入全局变量了,这里直接用TotalPoker宏代替索引值3
if(bltRandom()%13 +1 <= num)
return 1;
else
return 0;
endif
endfun
......................... //省略N行代码
上面的绿色部分的注释在原文件中也有,棕色的注释是这里额外添加的。其他的代码在前面章节已经都讲解过,所以这里就省略了。
本版本的C源代码主要修改了三个文件:global.h main.c symbol.c ,可以在git bash中使用git log --stat命令来查看:
如 果想查看这三个文件到底和上一个版本相比修改了哪些地方,可以在git bash中使用git log -p命令来查看,需要注意的是如果是linux系统,因为终端缓存的问题,可能会出现显示不全的问题,这时可以使用linux系统中的gitk图形软件来 查看(如果没有,请结合自己的发行版进行安装,本人的slackware系统自带了gitk,所以无需安装)。
具体的C文件代码部分,请结合源代码中的注释,再加上git工具以及vs2008或者eclipse+CDT插件或者gcc,gdb等工具进行分析。
最后还是老生常谈的话题:
windowsXP压缩包中的代码包括game_21_point.zl测试脚本都是采用GBK的编码,Linux压缩包中的代码包括测试文件以及git里的信息都是UTF8的编码,所以如果哪些地方出现了乱码,请自行调整。
对于windows用户,请确保在项目属性的配置里,命令行参数配置的是game_21_point.zl(对于zengl_lang_v0.0.19的项目)或game_21_point.zlc(对于zenglrun的项目)。
另外对于vs2008的用户,我在项目属性里:[配置属性>>>>C/C++ >>>> 高级] 部分设置了禁用特定警告:4013,4715,4996 ,这几个警告会显示一些某某函数是非安全的函数,或者函数没有返回值等,这里禁用掉,防止出现过多的警告。另外还有个警告是显示某某变量没被使用过的, 这个警告我没禁用,可以不用管它。我最开始是在Linux系统中使用eclipse+CDT插件以及gcc等开发的zengl ,在我的GCC下面并没有显示过这些讨厌的警告,所以就没处理,不过还好这些警告都无关痛痒,无需理会。
还有一个地方:VS2008项目中,在[配置属性>>>> C/C++ >>>> 预处理器] 部分都设置了预处理器定义的宏:OS_IN_WINDOWS ,因为源代码既要在WINDOWS下编译,又要在LINUX下编译,所以需要通过这个宏来告诉程序当前的环境是windows还是linux,在 windows下面,在程序结束时会执行system ("pause");这条语句(vs2008下为了能看到结果,需要暂停,否则就一闪而过,什么都看不到咯。) 而linux系统主要在bash终端下执行,不需要这条语句。
linux系统下的用户请结合usage.txt的说明,先运行make clean 将原来生成的zengl zenglrun 和 main.o parser.o assemble.o ld.o func.o run.o symbol.o builtin.o文件删除。
再运行make all (单纯的make只能生成zengl,所以需要make all来生成所有的目标)
生成zengl zenglrun 和 main.o parser.o assemble.o ld.o func.o run.o symbol.o builtin.o。(在生成过程中如果出现一些警告,暂不管他)
最后运行 ./zengl test.zl (本节是game_21_point.zl) 查看printASTnodes函数打印抽象语法树节点的结果,以及符号表输出的变量信息以及函数信息等。(例如变量的内存地址,以及在源文件的行列号,函数的唯一标识ID等)。
接着运行./zenglrun test.zlc(本节是game_21_point.zlc)(注意是.zlc结尾的文件名,因为zenglrun虚拟机只能运行.zlc里的汇编代码)。
zengl语言涉及到的很多高级的编译原理都可以在《龙书》中找到。
最后的最后,如果转载请注明来源 http://www.zengl.com , OK , 先到这里,休息,休息一下 O(∩_∩)O~