本节v0.0.18的版本没什么大的改动,只是添加了个初始化数组的函数,和PHP语言里的array()函数差不多,只不过不能设置键名,另外还修复了一个语法上的BUG。     本节v0.0....

    本节v0.0.18的版本没什么大的改动,只是添加了个初始化数组的函数,和PHP语言里的array()函数差不多,只不过不能设置键名,另外还修复了一个语法上的BUG。

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

   
SourceForge.net上的仓库地址为:https://sourceforge.net/projects/zengl/files/   从里面可以看到各个版本的代码压缩包,比如本节的zengl_lang_v0.0.18_forXP.rar zengl_language_v0.0.18_forLinux.tar.gzv0.0.18-v0.0.17-diffs.txt

    先来看下本版本的描述(在linux代码包里的usage.txt里有这段描述,在目前几个带有git版本的....-diffs.txt和git log中也有这段描述):

    v0.0.18版本,该版本添加了数组的初始化函数,同时修复了一个语法生成的BUG。
   
    在builtin.c内建函数模块内,添加了array函数。该函数会将函数的所有参数组合在一起生成一个初始化过的数组。例如test = array('hello','helloworld')该函数执行完后就可以得到一个包含'hello'及'helloworld'两个元素的数组 test。在test.zl测试脚本中包含了数组相关的测试代码。
    parser.c中修复了一个当数组的中括号和普通的括号在一起时可能会出现的语法错误的BUG。
    详情请通过git log -p 或 gitk 来查看。
   
    作者:zenglong
    时间:2012年5月4日
    官网网站:www.zengl.com

    本节的测试脚本test.zl如下:

use builtin;

array = array('星期一','星期二','星期三',
       //array('hello begin',2,3,3.51,6.666,'hello end'),   //可以把此处的注释和下面的多行注释取消掉,此处证明可以嵌入一个数组构成一个二维数组。
       '星期四','星期五','星期六','星期天');

/* for(i=0;i<8;i++)
    if(i==3)
        for(j=0;j<6;j++)
            print ' ' + array[i,j];  //将二维数组打印显示出来。
        endfor
    else
        print array[i];
    endif
endfor */


for(;;)
    print '请输入数字(1到7),输入q结束!';
    input = read();
    if(input == 'q')
        break;
    elif((input = ((input-0)+5)%7)==0) //这里input-0的含义是将用户输入的字符串转为数字,这样才能以数字的形式参与后面的加法运算。
        input = 7;   
    endif
    print '你下次是' + array[input-1] + '值班';
endfor

    上面这段脚本是个小应用:一个星期分为7天,假设你的单位是
进行轮 班制值班的,而且假定有5个人轮班,那么,只要输入你这个星期是星期几值班,就可以推算出你下次是星期几值班,上面就是使用array函数来初始化数组的 例子。中间有两处注释掉的代码,是用来测试数组的嵌入用法的,可以取消掉那两处的注释进行测试,这两处注释掉的代码说明array函数里可以再嵌入一个 array函数构成一个二维数组,然后可以使用array[i,j]的形式访问二维数组里的元素,当然还可再嵌入一些数组构成更多维的数组。
   
    下面是builtin.c里关于array函数初始化数组的代码部分:


..............................................  //省略N行代码

    case ARRAY:     //array函数用于创建zengl脚本的动态数组。
        if(argcount == 0) //如果array函数没带参数,则创建一个默认大小的未初始化的数组。
        {
            REG(AX).idtype = IDMEM_BLOCK;
            REGVAL(AX).memblock = (void *)alloc_memblock(®(AX).memptrIndex);
        }
        else if(argcount >= 1)    //如果带了参数则使用参数作为数组的初始值。
        {
            MEM_LIST * memblock = NULL;
            MEM_STRUCT argval={0}; //需要初始化,否则vs2008运行时会报Run-Time Check Failure错误。
            int memptrIndex,i;
            memblock = alloc_memblock(&memptrIndex);  //分配一个默认大小的数组
            memblock = realloc_memblock(memblock,argcount - 1);    //根据参数的实际数目调整数组的大小
           
for(i=0;i<argcount;i++) //循环读取参数,利用参数初始化数组。
            {
                argval = StackOps(GETMEM,argval,REGVAL(ARG).dword + i);
                switch(argval.idtype)
                {
                case IDINT:
                    memop_array_addr(SETMEM_INT,memblock,i,&argval);
                    break;
                case IDFLOAT:
                    memop_array_addr(SETMEM_DOUBLE,memblock,i,&argval);
                    break;
                case IDSTR:
                    memop_array_addr(SETMEM_PTR,memblock,i,&argval);
                    break;
                case IDMEM_BLOCK:
                    memop_array_addr(SETMEM_MEMBLOCK,memblock,i,&argval);
                    break;
                case IDADDR:
                case IDADDR_LOC:
                case IDADDR_MEMBLK:
                    memop_array_addr(SETMEM_ADDR,memblock,i,&argval);
                    break;
                }
            }
            REG(AX).idtype = IDMEM_BLOCK; //设置AX返回值类型为IDMEM_BLOCK内存块类型
            REGVAL(AX).memblock = (void *)memblock;    //设置AX内存块指针
            REG(AX).memptrIndex = memptrIndex;    //设置内存块在内存池中的索引。
        }
        else
            myexit(" arg's count can't less then 0 (内建模块异常:array函数参数个数小于0)\n");
        break;

..............................................  //省略N行代码

    下面是程序在windows下的运行截图:

    具体的C文件代码部分,请结合源代码中的注释,再加上git工具以及vs2008或者eclipse+CDT插件或者gcc,gdb等工具进行分析。

   
最后还是老生常谈的话题:
    windowsXP压缩包中的代码包括test.zl
测试脚本都是采用GBK的编码,Linux压缩包中的代码包括测试文件以及git里的信息都是UTF8的编码,所以如果哪些地方出现了乱码,请自行调整。

    对于windows用户,请确保在项目属性的配置里,命令行参数配置的是test.zl(对于zengl_lang_v0.0.18的项目)或test.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
查看printASTnodes函数打印抽象语法树节点的结果,以及符号表输出的变量信息以及函数信息等。(例如变量的内存地址,以及在源文件的行列号,函数的唯一标识ID等)。
    接着运行./zenglrun test.zlc
注意是.zlc结尾的文件名,因为zenglrun虚拟机只能运行.zlc里的汇编代码)。

    zengl语言涉及到的很多高级的编译原理都可以在《龙书》中找到。

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

上下篇

下一篇: zengl编程语言v0.0.19 def宏定义

上一篇: zengl编程语言v0.0.17单行多行注释

相关文章

zengl v1.3.2 编译静态库 Bug和向下兼容处理

v1.3.1 Android编译执行zengl脚本

zengl编程语言v1.0.6 问号冒号选择运算符,endswitch,endclass

zengl编程语言v0.0.12函数的实现

zengl编程语言v0.0.5构建符号表汇编代码和虚拟机

zengl v1.4.0 调试接口 zengl_SDL项目