网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > C/C++
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
本月文章推荐
.More Effective C++之引用计数.
.给datagrid的按钮列添加css.
.慎用url重写.
.Code Red 蠕虫攻击方式分析.
.简易的四则运算.
.C/C++指针应用.
.高质量C++/C编程指南 --&nb.
.C++程序设计从零开始之语句.
.用Delphi实现图像放大镜.
.指针与指针变量.
.C++学习:在C++中创建持久对象.
.C++ Builder中应用GDI实现虚拟台.
.沧海一粟之垃圾游戏一.
.Windows Sockets:套接字通知.
.对于c/c++中的数组排序及计算平均.
.在BCB中使用VCL控件数组1.
.Windows中控制台程序的全屏模式开.
.Windows API-GDI入门基础知识详.
.More Effective C++:不使用多态.
.C++ Builder 使用动作.

递归下降纯解释器编写的困惑

发表日期:2008-3-8



  python,lua还有javascript这些脚本语言其实是通过编译成中间码,然后再解释这个中间码来执行的,所以并不是纯解释的脚本。假如要写一个纯解释的脚本语言解释器,这种解释器的速度肯定不会很快,但是程序可以更简单一些。这对于需要小型的脚本解释器的情况比较适用,因为一个人只要几天就可以完成。比如unix的shell,windows中的cmd等。当然,对于一般的程序员来说,主要是为了嵌入自己的程序。假设我们的脚本包含变量,基本表达式,顺序,分支,循环语句,goto等。手工编写,当然是采用递归下降方法。

  变量用一个链表或数组就可以解决。解释赋值语句时,将变量存在符号表中。  

  表达式已经有很成熟的解决方法,就是一个算符堆栈,一个操作数堆栈,然后按算符优先级来做就可以了  

  然后我们讨论基本语句的执行  

  statements==>if_statements,for_statements,goto_statements等

  我们用c函数exec_if,exec_for,exec_goto来分别解释它们,用exec_statements()函数来递归调用前面这些函数。  

   假如是如下顺序执行的脚本,实现是比较轻易的,就是顺序执行。  

  COMMAND:statements;  

  就是前面是命令后面是语句,在c语言中可以用一个switch轻松搞定。但是假如出现了分支与循环,函数的时候,情况就变得复杂了。先看循环语句,比如如下脚本  

  for i= 1 to 100 do  

  statements;  

  end  

  假设现在我们已经将脚本都加载到内存中了,有一个char *指针current指向当前的脚本的位置。这个解释执行并不难。先解释for i=1 to 100 do这句,将自变量i保存到符号表中,这时候current已经指向statements了。循环解释执行的c程序伪码如下:  

  char *old=current;  

  for(i=自变量开始值;i++;i<自变量目标值)  

  {  

   current =old;  

   执行 statements;(这个过程中current会变化)  

  }  

  其中自变量开始值和自变量目标值都可以解释获得,每次执行完statements后在开始循环时恢复current指针即可。 

   但是分支语句可没这么简单,比如脚本  

  if eXP1 then  

   statements1;  

  elseif exp2 then  

  statements2;  

  end  

  假设exp1为真则执行statements1,exp2为真则执行statement2。那么解释执行的时候问题就来了,当exp1为真时,执行完statements1后,我们要跳过statements2到end,然后再执行,同样exp1为假,exp2为真的时候,问题也同样存在,需要跳过statements1.问题是怎么跳过?statements1,statements2均可能包含嵌套的分支或循环。在编译型的脚本中,其实不管是statements1,statements2在编译的时候都是需要编译的,在编译完这些语句后再进行代码回填。这样在执行中间码的过程中exp1,exp2执行完后,就知道跳到哪里执行了,实际上在执行中间码的时候脚本编译器已经进行了一次源码的扫描了,执行的函数不关心这些。但是我们现在是纯解释执行,就是一次扫描了。除了编译成中间码这个方法外,我没有想到更优雅的办法,这个方法因为涉及到编译,不是纯解释因此排除掉。对每种语句都有一个解释执行该语句的函数,例如  

  for 语句我们用exec_for()函数来执行,if我们用exec_if来执行。一种方法是可以对应编写一个pass函数,例如pass_for(),pass_if(),这样对于statements我们只需要一个pass_statements()函数就可以了,pass_statements()递归调用pass_for,pass_if,这样就可以过滤掉不需要执行的语句了。pass函数只改变current的值而并不执行被pass掉的那些语句。  

  显然pass_statemts除了不修改符号表,不做其它动作外,其它逻辑流程与exec_statements函数相同。这显然不够优雅。
  
  goto则需要先扫描行号,执行goto时跳到对应的行。  

   不知有没有更好的coding技巧,探索中。
上一篇:一个c++写的发牌程序 人气:500
下一篇:用GDI+实现半透明渐变的特效窗口 人气:755
浏览全部C/C++的内容 Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐