之前的版本对应的脚本代码都是按顺序执行的,没有if-elif-else之类的流程控制结构,本节的v0.0.9版本就实现了if-elif- else-endif的条件控制结构。类似C语言的if(...)....else if(....)....else.......

   之前的版本对应的脚本代码都是按顺序执行的,没有if-elif-else之类的流程控制结构,本节的v0.0.9版本就实现了if-elif- else-endif的条件控制结构。类似C语言的if(...)....else if(....)....else....的结构。

    本节v0.0.9版本的源代码下载地址为: http://pan.baidu.com/share/link?shareid=107063&uk=940392313 (此为百度云盘的共享链接地址),访问该地址可以看到三个文件: zengl_lang_v0.0.9_forXP.rar (XP系统下的vs2008解决方案和源代码), zengl_language_v0.0.9_forLinux.tar.gz  (Linux系统下的源代码和makefile) ,v0.0.9-v0.0.8-diffs.txt  (v0.0.9和v0.0.8的代码变化情况)。

    SourceForge.net上的仓库地址为:https://sourceforge.net/projects/zengl/files/   从里面可以看到各个版本的代码压缩包,比如本节的zengl_lang_v0.0.9_forXP.rar ,zengl_language_v0.0.9_forLinux.tar.gz,v0.0.9-v0.0.8-diffs.txt 。(当然由于sourceforge是国外的代码仓库,国内访问困难时(原因你明白的),就用百度盘下载好了,百度盘的速度还不错的)

   
先来看下本版本的描述 (在linux代码包里的usage.txt里有这段描述)

    v0.0.9版本,该版本实现了if-elif-else-endif的条件选择结构。
   
    parser.c中当遇到IF的RESERVE关键字时调用if_stmt函数来生成if的语法树结构,IF的token作为if结构的父节点,它的第一 个子节点为if需要进行判断的表达式,第2个子节点为当if判断通过时需要执行的语句序列,通过stmt_sequence函数来生成语句序列的语法树结 构,通过节点信息中的nextnode成员将语句序列中的所有语句连接在一起。IF的第2个子节点后面为ELIF或ELSE节点,以及ELIF或ELSE 对应要执行的语句序列,例如:可能第3个子节点为ELIF,则第4个子节点为ELIF要执行的语句序列,第5个可能为ELSE的节点,则第6个就是 ELSE对应要执行的语句序列,其中,ELIF节点的子节点为ELIF要进行判断的表达式。

    main.c中在前一个commit中就加入了if,elif,else,endif的关键字的token的判断。

    assemble.c中将if-elif-else的语法结构转为要执行的汇编代码,添加了JMP,JE两个指令,JE为当表达式的结果AX为NULL时 就发生跳转,JMP为无条件强制跳转指令,主要用于当if相关的指令执行完后,直接跳到endif后面继续执行。因为跳转用到了伪地址名,如 __if_address_0等,这些名字要替换为具体的指令PC地址值,所以就需要ld.c程序来扫描并替换__if_address等为具体的PC 值。如JMP __if_address_0 可能会被替换为 JMP 36 表示将PC值设为36,解释器就会从36的指令位置处开始执行。

    main.c中通过调用ld.c中的ld_replace_address()函数来实现地址的扫描替换操作,ld.c类似C编程时会用到的链接器。

    run.c中通过op_je函数来实现JE跳转指令,JMP实现方法和JE类似,本质就是修改虚拟寄存器PC的值,从而实现跳转。

    global.h和run.h中增加了和if-elif-else新的结构相关的一些定义。

    makefile文件加入了新增文件ld.c的编译选项。
   
    作者:zenglong
    时间:2012年2月21日

    本节就不作源码分析了,因为代码里已经有很详细的注释了,而且还有v0.0.9-v0.0.8-diffs.txt可以查看和上一个版本的变换情况。
    就来看看if-elif-else-endif结构的语法树生成。

本节的测试代码如下:
a = 18;
b = 30;

if(a > b)
  print 'a is '+a+' b is '+b+' a > b';
elif(a == b)
  print 'a is '+a+' b is '+b+' a = b';
else
  print 'a is '+a+' b is '+b+' a < b';
endif

这段代码很好理解,就是先将a变量设为18,b变量设为30,然后对a和b进行比较,根据比较的结果打印不同的信息。

 

对应生成的汇编代码为(注释只是这里起说明作用的,在实际生成的代码文件里没有):
0 MOV AX 18;
1 MOV (0) AX;  //将18赋值给变量a
2 MOV AX 30;
3 MOV (1) AX; //将30赋值给变量b
4 MOV AX (0);
5 MOV BX (1);
6 GREAT;  //将a和b的值进行GREAT大于比较操作
7 JE 19;  //如果结果为0,即ab的信息
8 MOV AX "a is ";
9 MOV BX (0);
10 PLUS;
11 MOV BX " b is ";
12 PLUS;
13 MOV BX (1);
14 PLUS;
15 MOV BX " a > b";
16 PLUS;
17 print AX;  //打印出a>b的信息
18 JMP 44;  //执行完if的代码块后,直接跳到44代码处,即endif后面结束该次if结构。
19 MOV AX (0);
20 MOV BX (1);
21 EQUAL;
...... //省略N行代码
44 END;
    OK,本节解说到此,预听下回分解,请看下集。O(∩_∩)O~

    最后老生常谈,说下编译代码的注意事项:
   
    对于其他代码的分析,因为已经在C源代码里加了很多注释,请结合注释,加上VS2008之类的调试开发环境进行调试分析。    
    对于windows用户,请确保在项目属性的配置里,命令参数配置的是test.zl(对于zengl_lang_v0.0.8的项目)或test.zlc(对于zenglrun的项目),上一节提到过。
    linux系统下的用户请结合usage.txt的说明,先运行make clean 将原来生成的zengl zenglrun 和 main.o parser.o assemble.o ld.o func.o run.o  symbol.o文件删除。

    再运行make all (单纯的make只能生成zengl,所以需要make all来生成所有的目标)

    生成zengl zenglrun 和 main.o parser.o assemble.o ld.o func.o run.o  symbol.o。(在生成过程中如果出现一些警告,暂不管他)

    最后运行 ./zengl test.zl 查看printASTnodes函数打印抽象语法树节点的结果,以及符号表输出的变量信息(例如变量的内存地址,以及在源文件的行列号等)。
    接着运行./zenglrun test.zlc (注意是.zlc结尾的文件名,因为zenglrun虚拟机只能运行.zlc里的汇编代码)。

    本例的抽象语法树等很多高级的原理都可以在《龙书》中找到。

    最后的最后,如果转载请注明来源 http://www.zengl.com   , OK , 先到这里,休息,休息一下 O(∩_∩)O~

上下篇

下一篇: zengl编程语言v0.0.10实现流程嵌入结构

上一篇: zengl编程语言v0.0.8第二代语法解析函数

相关文章

zengl v1.4.0 调试接口 zengl_SDL项目

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

zengl v1.9.1 函数参数可以使用负数作为默认值

zengl编程语言 中序

zengl v1.2.0 嵌入式编程语言

zengl编程语言v0.0.21汇编级调试