经过采集器的嵌入式测试后,将zengl v1.2.2转为可以用于实际开发的发布版,采集器的源代码已经发布在网盘中,下载地址:http://pan.baidu.com/share/link?shareid=30200810&uk=940392313 (此...

    经过采集器的嵌入式测试后,将zengl v1.2.2转为可以用于实际开发的发布版,采集器的源代码已经发布在网盘中,下载地址:http://pan.baidu.com/share/link?shareid=30200810&uk=940392313 (此为采集器v1.2.0公测版的VS2008的项目源代码以及所依赖的wxWidgets库,wxSqlite库,libcurl库等,注意wxSqlite库是经过作者修改过的,官方的这个版本有BUG,所以请下载网盘里的压缩包,不要用官方的版本)

    zengl v1.2.2对应的github项目地址为:https://github.com/zenglong/zengl_language/  选择右侧的Download Zip或Clone in Desktop(这个作者没测试),v1.2.2的发布版对.gitattributes文件(git的配置文件)做了修改,添加了*.sln text eol=crlf (意思就是对应.sln后缀的文件,始终使用crlf的windows换行符) ,这样就解决了之前的版本中.sln文件无法打开的问题,如果你有vs项目放在github中,又无法打开.sln文件,那么可以借鉴这个方法,不过改了.gitattributes文件后,还需要手动修改.sln文件(可以在无关紧要的地方加个空格之类的),让这个文件处于修改状态,这样就可以将.sln重新commit提交上去,使其生效。

    百度盘共享链接地址:http://pan.baidu.com/share/link?shareid=24570629&uk=940392313 这是一个zip压缩包,是上面github项目下载重命名得来的。

    sourceforge.net上的项目地址为:https://sourceforge.net/projects/zengl/files/ (里面有所有历史版本的压缩包,包括v1.2.2的zip包)。

    对应windows用户直接解压后,进入windows_vs2008目录,双击zengl_lang_v1.2.2.sln,然后将测试项目zenglrun的调试 -->> 命令参数设置为:test.zl,然后运行即可(既可以使用Debug模式,也可以使用Release模式,Release模式生成的dll动态链接库可以随用户项目一起发布出去)。

    linux下的用户进入linux_gcc,按照usage.txt文件底部的说明make clean,再make,最后运行./zengl test.zl 即可测试。

    测试的项目可能让你觉得过于简单,那么你可以试试采集器v1.2.0公测版的源代码。进入上面提到的采集器源码的百度盘,再进入采集器v1.2.0源代码及所依赖的第三方库文件的文件夹,可以看到如下界面:


图1

    第一个是采集器的vs2008项目源代码,其他的都是依赖的库,解压采集器vs2008源代码.rar的压缩包,双击打开gui-caiji.sln ,里面的Debug模式和Release模式都已经配置好了,但是该采集器依赖其他的第三方库,所以必须先将上面的第三方库准备好,下载wxWidgets-2.9.2.tar.bz2压缩包,解压,进入build下面的msw目录,比如作者的路径为:E:\360Downloads\wxWidgets\wxWidgets-2.9.2\wxWidgets-2.9.2\build\msw ,从中选择合适的.sln版本,例如作者选择的是wx_vc9.sln,在菜单 生成 -->> 配置管理器里有很多解决方案可供选择:

图2

    由于采集器的项目使用的是Debug和Release两种模式,所以wxwidgets也需要对应生成Debug和Release两种模式的解决方案,需要注意的是Release模式,这个模式必须将其中22个项目都修改成:配置属性 -->> C/C++ -->> 代码生成 -->> 运行时库 -->> 多线程 (/MT) 模式(因为采集器的Release配置使用的也是/MT,所以必须统一一致,Debug模式默认都是相同的,就无需修改,/MT表示生成的代码可以直接在没安装vc++组件的电脑上直接运行,一般非程序员的普通用户的电脑里都没有这种组件),生成Debug模式和Release模式的wxwidgets需要比较长的时间,因为有22个项目要生成,要编译的文件也非常多,另外,Debug和Release生成的都是静态库,而非动态库,因为采集器需要的就是这些静态库,所以采集器的压缩包中没有多余的dll文件,因为wxwidgets以静态库的形式编译进程序里了,如果编译遇到问题,可以参考上面百度盘中wxWidgets.pdf电子档教程,或者百度,或者Google 。

    然后下载解压 wxsqlite3-1.9.9.rar ,这个包解压后得到的项目是经过作者修改和编译过的,非官方版本,所以,应该不需要再编译了,直接就有需要的静态库和开发头文件。

    最后就是下载解压libcurl-7.18.0-win32-msvc.rar,里面是官方编译好的dll动态库和所需的开发头文件,libcurl的动态库,作者直接放在了采集器的包中。

    另外采集器还依赖zengl嵌入式编程语言的dll动态库,这个库和相关的开发头文件都直接放在了采集器的包里。

    第三方库的准备工作做完后,就可以对vs2008进行选项配置,让vs的编译器和链接器可以找到上面的开发头文件和链接库文件,下面是作者的本机配置:

图3
 

图4
 
    上面是头文件相关配置,请根据自己的解压路径来定。(选项对话框在vs2008中是在工具菜单的最底下)
 
 

图5

    上面是库文件的配置,这些都配好后,就可以编译运行采集器的vs2008项目了。

    在采集器中所有的脚本模块函数接口都定义在global.cpp文件中,例如:
 

图6

    上面是采集器中通过zengl提供的API接口编写的bltPrintArray模块函数,有了此函数就可以在采集器对应的zengl脚本中使用该函数来打印出数组中的元素信息。在global.cpp中类似的模块函数一共有五六十个,所以在采集脚本中,使用了use builtin;语句后,就可以使用这些模块函数了。

    caiji.cpp是采集器的主体程序,在里面有wxwidgets的界面布局,事件响应等函数,另外还有加载运行zengl脚本的代码例如:

MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
       : wxFrame(NULL, -1, title, pos, size)
{
................................  //省略N行代码
    logfp = NULL;
    zengl_debuglogfile = fopen("zengl_debuglogs.txt","w+");
    m_dlgFind = NULL;
    ZL_EXP_VOID * VM = zenglApi_Open();
    zenglApi_SetFlags(VM,(ZENGL_EXPORT_VM_MAIN_ARG_FLAGS)(ZL_EXP_CP_AF_IN_DEBUG_MODE));
    zenglApi_SetModFunHandle(VM,0,"bltSetInitManageUrl",global_bltSetInitManageUrl);
    zenglApi_SetModFunHandle(VM,0,"bltSetModulePath",global_bltSetModulePath);
    if(zenglApi_Run(VM,"初始化脚本.zl") == -1)
        wxMessageBox(wxString::Format("'初始化脚本.zl'执行失败:%s",zenglApi_GetErrorString(VM)),"警告");
    zenglApi_Close(VM);
}

    这是窗口初始化过程中,在函数快结束时,加载执行初始化脚本.zl的方法,这是一种最简化的写法,通过zenglApi_Open创建一个新的VM虚拟机,然后通过zenglApi_SetFlags设置虚拟机为ZL_EXP_CP_AF_IN_DEBUG_MODE调试模式,这样当脚本出错时,可以定位到行列号和文件名信息。通过zenglApi_SetModFunHandle接口来设置在该脚本中可以使用的模块函数,"bltSetInitManageUrl"是模块函数名称,global_bltSetInitManageUrl是对应的模块函数处理句柄即用户自定义的函数。这样在初始化脚本中就可以直接使用bltSetInitManageUrlbltSetModulePath这两个模块函数,而不需要use builtin;之类的语句,在脚本中除了这两个函数,其他的模块函数都不可以用。接着zenglApi_Run运行脚本即可,返回-1表示失败,可以通过zenglApi_GetErrorString接口来获取出错信息。最后通过zenglApi_Close释放掉虚拟机,zenglApi_Open必须和zenglApi_Close接口一一对应。

    在采集器的采集线程中也是通过zengl的API接口来加载执行各模块的采集脚本的(该处代码也在caiji.cpp中):

void *MyThread2::Entry()
{
............................ //省略N行代码

    CUR_CAIJI_VM = zenglApi_Open();
    //zenglApi_SetFlags(CUR_CAIJI_VM,(ZENGL_EXPORT_VM_MAIN_ARG_FLAGS)(ZL_EXP_CP_AF_IN_DEBUG_MODE | ZL_EXP_CP_AF_OUTPUT_DEBUG_INFO));
    zenglApi_SetFlags(CUR_CAIJI_VM,(ZENGL_EXPORT_VM_MAIN_ARG_FLAGS)(ZL_EXP_CP_AF_IN_DEBUG_MODE));
    zenglApi_SetHandle(CUR_CAIJI_VM,ZL_EXP_VFLAG_HANDLE_COMPILE_INFO,global_userdef_compile_info_forZenglRunV2);
    zenglApi_SetHandle(CUR_CAIJI_VM,ZL_EXP_VFLAG_HANDLE_RUN_INFO,global_userdef_run_info_forZenglRunV2);
    zenglApi_SetHandle(CUR_CAIJI_VM,ZL_EXP_VFLAG_HANDLE_RUN_PRINT,global_userdef_run_print_forZenglRunV2);

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

    zenglApi_SetModInitHandle(CUR_CAIJI_VM,"builtin",global_builtin_module_init);
    if(zenglApi_Run(CUR_CAIJI_VM,(char *)ModFilePath.c_str().AsChar()) == -1) //编译执行zengl脚本
    {
        wxMyLogEvent eventforlog( wxEVT_MY_LOG_EVENT,wxID_ANY,wxString::Format("\n编译运行"+ModFilePath+"时发生异常:%s\n",zenglApi_GetErrorString(CUR_CAIJI_VM)), MY_RICHTEXT_RED_STYLE);
        wxQueueEvent(glmainFrame->GetEventHandler(),eventforlog.Clone());
        zenglApi_Close(CUR_CAIJI_VM);
        CUR_CAIJI_VM = ZL_EXP_NULL;
        return NULL;
    }
    zenglApi_Reset(CUR_CAIJI_VM);

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

   if(CUR_CAIJI_VM != ZL_EXP_NULL)
   {
        zenglApi_Close(CUR_CAIJI_VM);
        CUR_CAIJI_VM =ZL_EXP_NULL;
   }

    这种调用方法在zengl v1.2.2语言代码包的测试程序main.c中都涉及到了,这里就不再多说。

    在zengl v1.2.2中新增了zenglApi_SetExtraData,zenglApi_GetExtraData的接口,例如在采集器的caiji.cpp中:

void MyKeyDialog::OnJumpToCaijiUrl(wxCommandEvent& event)
{
............................ //省略N行代码
    ZL_EXP_VOID * VM = zenglApi_Open();
    //zenglApi_SetFlags(VM,(ZENGL_EXPORT_VM_MAIN_ARG_FLAGS)(ZL_EXP_CP_AF_IN_DEBUG_MODE | ZL_EXP_CP_AF_OUTPUT_DEBUG_INFO));
    zenglApi_SetFlags(VM,(ZENGL_EXPORT_VM_MAIN_ARG_FLAGS)(ZL_EXP_CP_AF_IN_DEBUG_MODE));
    zenglApi_SetHandle(VM,ZL_EXP_VFLAG_HANDLE_COMPILE_INFO,global_userdef_compile_info_forZenglRunV2);
    zenglApi_SetHandle(VM,ZL_EXP_VFLAG_HANDLE_RUN_INFO,global_userdef_run_info_forZenglRunV2);
    zenglApi_SetHandle(VM,ZL_EXP_VFLAG_HANDLE_RUN_PRINT,global_userdef_run_print_forZenglRunV2);    
    global_JumpToCaiji_InitFuncall(VM);
    zenglApi_SetExtraData(VM,"catid",(void *)m_catid.c_str().AsChar());
    zenglApi_SetExtraData(VM,"modid",(void *)m_modid.c_str().AsChar());

    wxString selectedKey = m_listbox->GetString(selectItem);
    zenglApi_SetExtraData(VM,"selectedKey",(void *)selectedKey.c_str().AsChar());
    zenglApi_SetExtraData(VM,"moduleName",(void *)global_MyModules[m_modid].c_str().AsChar());

    MyUserExtraData extraData;
    zenglApi_SetExtraData(VM,"extraData",(void *)(&extraData));

    if(zenglApi_Run(VM,"Module/采集跳转规则.zl") == -1) //编译执行zengl脚本
    {
        wxMessageBox(wxString::Format("\n编译运行'Module/采集跳转规则.zl'时发生异常:%s\n",zenglApi_GetErrorString(VM)),"警告");
        zenglApi_Close(VM);
        return ;
    }
    zenglApi_Close(VM);
}

    通过zenglApi_SetExtraData接口可以向虚拟机传递字符串指针,结构体的指针等,这样在模块函数定义中就可以通过zenglApi_GetExtraData接口和额外数据名称来获取这些指针。在这些指针中就可以放置一些用户自定义的额外数据。

    在采集器中都是使用的zenglApi_Open,zenglApi_Run,zenglApi_Close的方式,当然也可以使用zenglApi_Load的方式,不过这种Load的方式可控性不强,例如在采集器的bltLoadScript模块函数定义中:

    /*bltLoadScript模块函数,新建一个虚拟机,加载并执行某个脚本*/
    ZL_EXP_VOID global_bltLoadScript(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
    {
        ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
        ZL_EXP_CHAR * scriptName = ZL_EXP_NULL;
        zenglApi_GetFunArg(VM_ARG,1,&arg); //获取第一个参数为脚本名
        if(arg.type != ZL_EXP_FAT_STR)
            zenglApi_Exit(VM_ARG,"bltLoadScript函数第一个参数必须字符串,代表要加载的脚本文件名");
        scriptName = arg.val.str;
        ZENGL_EXPORT_VM_MAIN_ARGS vm_main_args = {global_userdef_compile_info_forZenglRunV2 ,
                                  global_userdef_compile_error_forZenglRunV2,
                                  global_userdef_run_info_forZenglRunV2,
                                  global_userdef_run_print_forZenglRunV2,
                                  global_userdef_run_error_forZenglRunV2,
                                  global_module_init,
                                  ZL_EXP_CP_AF_IN_DEBUG_MODE |
                                  ZL_EXP_CP_AF_OUTPUT_DEBUG_INFO};
        zenglApi_Load(scriptName,&vm_main_args);
        zenglApi_SetRetVal(VM_ARG,ZL_EXP_FAT_INT,ZL_EXP_NULL,1,0);
    }

    在采集器的采集脚本中有类函数的使用方法,可以参考采集器的Module/资讯模块规则.zl脚本,其他的脚本因时间关系就没改成类函数,其实类函数就像C++的namespace,仅仅是增加函数名的使用率,调用类函数就直接类名点函数名即可,例如:

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

  if(clsArt.ChkContLinkExist())
       continue;
  endif

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

class clsArt
    /*检查内容链接地址是否存在*/
    fun ChkContLinkExist()
....................  //省略N行代码
    endfun

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

    fun AddToDb_WhenErr(errorStr = '',extraInfo = '')

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

    endfun
....................  //省略N行代码
endclass //class clsArt

    上面显示了类函数的定义和使用方法,另外函数可以使用默认参数,例如上面的AddToDb_WhenErr(errorStr = '',extraInfo = '') 当errorStr或extraInfo在调用时没提供参数,那么就使用默认的空字符串作为参数。

    作者已经开放bbs.zengl.com作为论坛,有问题可以在论坛发布,不过因时间关系,作者可能会隔个几天才能看到,多半是晚上。

    OK,到这里,休息,休息一下 o(∩_∩)o~~
上下篇

下一篇: zengl v1.2.4 脚本加密,单目负号,VC6编译,新增API,BUG修复

上一篇: zengl v1.2.1 修复函数调用BUG

相关文章

zengl编程语言v0.0.18初始化数组函数

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

zengl编程语言v0.0.22实现switch...case

zengl编程语言 v1.0.2 修复BUG

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

v1.3.1 Android编译执行zengl脚本