lisp是一门简单又强大的语言,其语法极其简单:

(+ 1 2 )

上面的意思 是:+是方法或函数,1 ,2 是参数,fn=1+2,即对1,2进行相加求值,结果是:3

双括号用来提醒解释器开始和结束。

之前在iteye写过一篇文章来简单介绍怎么写lisp的解释器:

http://gyc567.iteye.com/blog/2242960

同时也画了一张草图来说明:

因为lexer(词法分析器)主要工作就是把程序的字符串表达式转化为tokens.(Pair),以下是百科对词法分析的说明:

词法分析是编译过程的第一个阶段,是编译的基础。这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。

因为lisp的语法极其简单,词法分析可以认为就是把字符串“(+ 1 2 )”转化为Pair对象,这个Pair 有两个属性:first,rest,first用来记录“+”,rest用来记录另一个Pair,如下图:

Pair1 :

first-->"+"

rest-->Pair2

Pair2:

first-->"1"

rest-->"2"

所以这里主要关注parser,parser主要工作是把Pair对象转化为抽象语法树(AST),并对其他求值返回。

好,现在尝试用BDD的方式来开发实现parser的功能。

先写测试用例:

package com.github.eric.camel

import spock.lang.Specification

/**
* Created by eric567 on 4/4/2016.
*/
class LispSpockTest extends Specification {
def "Caculate"() {
given:"a instance of Lisp,args: 1 2 "
Lisp lisp=new Lisp()
int arg1=1
int arg2=2
when:"invoke lisp method caculate "
int rt=lisp.caculate(arg1,arg2)
then:"return the result :3"
rt==3 } def "Eval"() {
given:"new Lisp instance,Pair1:fisrt-->+,rest-->Pair2;Pair2:first-->1,rest-->2"
Lisp lisp=new Lisp() ValuePair valuePair2=new ValuePair()
valuePair2.first="1"
valuePair2.rest="2"
ValuePair valuePair1=new ValuePair()
valuePair1.first="+"
valuePair1.rest=valuePair2 when:"eval the Pair1"
Object rt=lisp.eval(valuePair1)
then:"the result should be :3 "
Integer.valueOf(rt)==3 }
}

第一个测试用例用来 测试caculate方法,也这里就是简单的相加功能。代码已经说明一切。

第二个测试用来测试eval求值函数。

好,现在写代码通过这两个测试:

package com.github.eric.camel;

/**
* Created by eric567 on 3/8/2016.
*/
public class Lisp {
public int caculate(int i, int i1) {
return i+i1;
} public Object eval(ValuePair valuePair)
{
String fn= (String) valuePair.first;
if(fn!=null&&fn.equals("+"))
{
ValuePair args= (ValuePair) valuePair.rest;
int arg1= Integer.valueOf((String) args.first);
int arg2= Integer.valueOf((String) args.rest);
Integer rt=caculate(arg1,arg2);
return rt;
}
return null;
}
} 而Pair对象的代码很简单:
package com.github.eric.camel;

/**
* Created by eric567 on 3/8/2016.
*/ public class ValuePair {
Object first;
Object rest; }

好,再次运行测试用例,应该可以出现绿色线条,祝贺你,你已经实现了一个简单的lisp解释器,you got it .cheeers.

[编译原理]用BDD方式开发lisp解释器(编译器)|开发语言java|Groovy|Spock的更多相关文章

  1. 前端与编译原理——用JS写一个JS解释器

    说起编译原理,印象往往只停留在本科时那些枯燥的课程和晦涩的概念.作为前端开发者,编译原理似乎离我们很远,对它的理解很可能仅仅局限于"抽象语法树(AST)".但这仅仅是个开头而已.编 ...

  2. 学了编译原理能否用 Java 写一个编译器或解释器?

    16 个回答 默认排序​ RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...

  3. 用C/C++手撕CPlus语言的集成开发环境(1)—— 语言规范 + 词法分析器

    序言 之所以叫做CPlus语言,是因为原本是想起名为CMinus的,结果发现GitHub和Gitee上一堆的CMinus的编译器(想必都是开过编译原理课程并且写了个玩具级的语言编译器的大佬们吧).但是 ...

  4. Knowledge Point 20180303 对比编译器、解释器与Javac编译原理

    编译器与Javac编译原理 在前文我们知道了Java是一种编译语言和解释语言,它的源代码经过编译器Javac编译为能够被JVM识别的二进制语言,然后JVM将其解释为能够被平台识别的机器语言.那么什么是 ...

  5. <编译原理 - 函数绘图语言解释器(1)词法分析器 - python>

    <编译原理 - 函数绘图语言解释器(1)词法分析器 - python> 背景 编译原理上机实现一个对函数绘图语言的解释器 - 用除C外的不同种语言实现 解释器分为三个实现块: 词法分析器: ...

  6. <编译原理 - 函数绘图语言解释器(2)语法分析器 - python>

    <编译原理 - 函数绘图语言解释器(2)语法分析器 - python> 背景 编译原理上机实现一个对函数绘图语言的解释器 - 用除C外的不同种语言实现 设计思路: 设计函数绘图语言的文法, ...

  7. <编译原理 - 函数绘图语言解释器(3)解释器 - python>

    <编译原理 - 函数绘图语言解释器(3)解释器 - python> <编译原理 - 函数绘图语言解释器(2)词法分析器 - python> <编译原理 - 函数绘图语言解 ...

  8. Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用

    catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...

  9. MOOC 编译原理笔记(一):编译原理概述以及程序设计语言的定义

    编译原理概述 什么是编译程序 编译程序指:把某一种高级语言程序等价地转换成另一张低级语言程序(如汇编语言或机器代码)的程序. 高级语言程序-翻译->机器语言程序-运行->结果. 其中编译程 ...

随机推荐

  1. 当出现no changes added to commit时如何正确使用git提交命令

    对于这个问题,最好的解决方法就是按如下步骤:1.到根目录下:git add .  :("."是必须要的)2.git commit -m "some word"3 ...

  2. springboot+mybatis+SpringSecurity 实现用户角色数据库管理(一)

    本文使用springboot+mybatis+SpringSecurity 实现用户权限数据库管理 实现用户和角色用数据库存储,而资源(url)和权限的对应采用硬编码配置. 也就是角色可以访问的权限通 ...

  3. linux命令--truncate 学习

    truncate命令可以将一个文件缩小或者扩展到某个给定的大小 可以利用该命令和-s选项来特别指定文件的大小 1.清空一个文件内容,尤其是log 2. truncate -s 0 test

  4. ubuntu 18.04 gcc g++降级4.8版

    $ sudo apt-get install -y gcc-4.8 $ sudo apt-get install -y g++-4.8 $ cd /usr/bin $ sudo rm gcc $ su ...

  5. Windows操作路由表

    route print route add 172.17.0.0 mask 255.255.0.0 192.168.99.100 route delete 172.17.0.0 mask 255.25 ...

  6. JavaScript函数、BOM

    [函数的声明和调用] 1.>>>函数声明的格式:形参可以不用var声明 使用function关键字声明: function 函数名 (参数1,参数2,......){ //函数体 r ...

  7. Jmeter之仅一次控制器

    在进行压测时,往往登录只需要一次,其他的接口需要循环测试.这里就会用到控制器中的仅一次控制器.只要放置在控制器的请求,不管在哪种情况下,都只执行一次. 1.名称:可以标识在该控制器下主要完成的 工作内 ...

  8. linux打包

    1.打成tar包 sudo tar -zcf boot.tar /boot/ 2.打成zip包 sudo zip -r boot.zip ./*

  9. HTML——超级链接 表格 框架

  10. 【EW系列】SAP EWM模块-EWM的常用T-CODE整理

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[EWM系列]SAP EWM模块-EWM的常用T ...