对于SNL语言解释器的内容可以参考我的前一篇文章《使用antlr4及java实现snl语言的解释器》。此文只讲一下“尾递归优化”是如何实现的——“尾递归优化”并不是一个语言实现必须要做的,但这是一个比较有趣的东西,所以我还是想拿来讲一讲。

在前一篇文章中有一个例子:

program recursion

procedure f(integer d);

begin

write(d);

f(d + 1)

end

begin

f(1)

end

这个例子是我用来测试我写的解释器是否正常实现了最基本的尾递归优化的。

这段代码用JAVA翻译过来是这样的:

public class Test {

static void f(long l) {

System.out.println(l);

f(l + 1);

}

public static void main(String[] args) {

f(0);

}

}

就是对一个方法f进行递归调用并且没有任何正常的退出逻辑(要退出就只能抛出异常或我们主动杀死那个进程)。

这段JAVA代码如果运行起来,很快就会发生堆栈溢出的错误(java.lang.StackOverflowError),但我写的SNL代码运行在我实现的SNL解释器中却会一直运行下去,直到那个进程被杀死(不会有类似堆栈溢出的问题抛出来)。之所以会这样就是因为我的解释器实现了“尾递归优化”。

什么是“尾递归优化”呢?

我对尾递归优化的定义是:一个过程返回之前,调用的最后一条语句如果是对当前过程的递归调用时,则可以用一个小技巧把递归调用变成循环。这里使用到的“小技巧”就是尾递归优化了。

科班出身的程序员都受过这样的训练:把各种递归的程序修改成等价的没有递归调用的程序。这其中的各种方法一般都很难实现一个通用的转换程序——输入一个递归的代码,输出一段等价的,无递归的代码——但对于最后一条执行语句是对当前过程的递归时,这个转换过程就比较容易实现了。

从尾递归优化的定义中可以看出两个关键点: 先找到最后一条可执行语句(并判断是否是对当前过程的递归)。

使用那个“小技巧”。

首先,我们如何知道最后一条语句是哪条呢?

我们知道,SNL语言的语句有七种:条件语句;循环语句;输入语句;输出语句;赋值语句;过程调用语句;return语句

同时,我们知道,SNL文法中,我们解析stmList时,是要先解析第一条stm,然后再看后面的是否还有其它stmList。

这样我们有以下逻辑可以判断当前识别到的stm是否可能是最后一条: 如果当前stm之后不再有stmList,则可以认为这个stm就是最后一条了。

如果之后再有stmList,且这个stmList下的第一个stm是return语句,则可以认为这个stm就是最后一条了。

有了这两个逻辑还不算完,因为“条件语句”内部可以复合stmList的,这样我就需要在“当前stmList的最后一条语句是条件语句”的情况下还需要判断这个条件语句的两个可能的分支中的stmList的最后一条语句的最后一条语句是哪条了(即然是分支,那么两个分支都自己的最后一条,也就是说可能有多条语句都是最后一条)。

注:对于“循环语句”也是可以在内部复合stmList的,但因为一般我们只有在运行时才知道最后一次循环是什么时候结束的,所以我们暂时不考虑循环语句。

找到最后一条语句(或多条都可能在自己的分支内是最后一条)之后,判断是否为当前过程的递归就简单了:首先它必须是“过程调用语句”,然后其过程签名必须与当前过程完全相同(我在实现SNL语言的解释器时,为了实现简单,直接用过程名做为过程的签名了,但这样实现存在一个问题:在这个SNL语言的实现中就不支持重载了)。

现在我们已经找到了一些可能是最后一条的语句了,那么只要运用那个“小技巧”就可以了。

这个小技巧非常简单:跳转到当前过程的最开头(跳转之前,需要清理一下当前过程创建的上下文——也就是当前过程自己定义的变量等内容)即可。

其实我们自己想像一下也可以想到:递归调用其实就是跳转到最开头,这就是循环了。

到这里还没完——我们如何跳到最开头去呢?

如果我们写的是编译器就比较简单:直接用一个类似JMP或GOTO这样的指令就可以了。

但我们现在写的是解释器,解释器在解释一个proc时几乎不会把整个解释的逻辑放到同一个方法中来实现的(也是几乎不可能做到的),所以当我们当前所在的是用来解析callStm的方法时,如何可以跳转到很多步调用之前的解析procDeclare方法中去呢?

JAVA中只有一种语言机制可以帮助我们做到这点,即:抛异常。

原文:http://www.cnblogs.com/naturemickey/p/3801714.html

snl递归语法java,对SNL语言的解释器实现尾递归优化相关推荐

  1. python递归详解_打破递归栈的深度限制: 解析一种Python尾递归优化的方法

    Python的递归调用栈的深度有限制, 可以通过sys.getrecursionlimit()查看. 尾递归在很多语言中都可以被编译器优化, 基本都是直接复用旧的执行栈, 不用再创建新的栈帧, 原理上 ...

  2. java实现尾递归优化,你们都知道递归,尾递归呢?什么又是尾递归优化?

    你们都知道递归,尾递归呢?什么又是尾递归优化? 码农唐磊 程序猿石头 今天,咱们来聊聊递归函数.为啥忽然想到递归?其实就从电影名字<恐怖游轮><盗梦空间>想到了.图片java ...

  3. 大家都知道递归,尾递归呢?什么又是尾递归优化?

    点击上方蓝色字体,关注我 -- 一个在阿里云打工的清华学渣! 今天,我们来聊聊递归函数.为啥突然想到递归?其实就从电影名字<恐怖游轮><盗梦空间>想到了. 递归是啥? 递归函数 ...

  4. 使用antlr4及java实现snl语言的解释器

    对于antlr4的基础使用,请参考我的前一篇文章<用antlr4来实现<按编译原理的思路设计的一个计算器>中的计算器>. 其实我对于antlr4的理解也仅限于那篇文章的范围,但 ...

  5. java实现snl语法分析_使用antlr4及java实现snl语言的解释器

    其实我对于antlr4的理解也仅限于那篇文章的范围,但那些内容对于我们实现一个SNL语言已是足够了. 简单说来,这是一个非常简单的结构化编程语言,它包含了一个编程语言应该有的最基本的东西,同时基本上不 ...

  6. 知识库递归编程java和prolog代码;逻辑语言Prolog简介(附24555字PDF发“递归prolog简介”下载)

    知识库递归编程java和prolog代码:逻辑语言Prolog简介(附24555字PDF发"递归prolog简介"下载) 数据简化DataSimp 今天 数据简化DataSimp导 ...

  7. Python同Java同Js语言语法区别之四判断字符串列表字典是否相等

    字符串列表字典是否相等 前言 Python 字符串or数字 列表 字典 总结 Java 字符串 数组 Map 总结 JS 字符串 数组 对象 总结 前言 作为一枚测开工程师,需要的技能是全栈的,项目中 ...

  8. 【超硬核】Java SE 基础语法知识点 (C语言快速转Java)

    目录 1.Java程序基础 1.1 JDK和JRD 1.2 命令行操作 1.3 pubilic+class 1.4 字节码文件 2.标识符 2.1 标识符的组成 2.2 遵守驼峰命名方式 2.3 类名 ...

  9. 【Groovy】Groovy 语言特点简介 ( 支持 Java 语法 | 支持 Java 虚拟机 | Groovy 语言是动态语言 | Groovy 扩展 JDK | 编译时元编程 )

    文章目录 一.Groovy 支持 Java 语法 二.Groovy 支持 Java 虚拟机 三.Groovy 语言是 动态语言 四.Groovy 扩展 JDK 五.Groovy 编译时元编程 一.Gr ...

最新文章

  1. css样式之background详解(格子效果)
  2. MySQL5.6多实例部署
  3. python语言编写一个生成九宫格图片的代码_python简单实现9宫格图片实例
  4. 60-008-020-使用-命令-flink命令
  5. IDEA破解(破解补丁)
  6. 非索引列上的统计 第二篇
  7. 求合作开发伙伴 .NET 中高级工程师 1-2名
  8. 使用MEAT在iOS设备上采集取证信息
  9. 如果计算机正执行屏幕保护程序 当用户,计算机1级考试参考试题(含答案)章节1.doc...
  10. Word转换成pdf之pdf虚拟打印机如何使用操作教程
  11. 如何快速推广你的博客
  12. laravel 图片流_laravel 做图片的缩略图 踩坑
  13. 命令行安装卸载驱动服务
  14. uchome二次开发
  15. 汉字转GB2312编码程序c语言
  16. 关于redis (error) CLUSTERDOWN Hash slot not served
  17. html 图片循环轮播,如何在Web端实现动画切换效果一致的无限循环图片轮播?
  18. 决策树--CART算法
  19. 数电实验 可逆计数器设计
  20. 图表示学习之时序的事件和节点动态

热门文章

  1. 快速解决电脑无线网络无法连接问题
  2. while后面的分号可以省略吗_do-while循环中while语句后面的分号可以省略()
  3. Python--安装pyecharts包,anaconda环境下如何正确安装神奇可视化pyecharts包[安装的那些事儿]
  4. 软件设计(四)--MTBF、MTTF、MTTR
  5. Oracle executeBatch异常 ArrayIndexOutOfBoundsException
  6. python计算信息熵_Python计算信息熵实例
  7. mrtg监控linux主机的甚至,依赖SNMP的MRTG监控--linux
  8. 我的并行计算之路(三)MPI集合通信之Scatter和Gather
  9. 计算机的收获初一作文,《初一的收获》作文五篇
  10. 网站SEO小助手 V1.4版 简单轻松使用的SEO工具