[编译原理]用BDD方式开发lisp解释器(编译器)|开发语言java|Groovy|Spock
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.
本人精通java高并发,DDD,微服务等技术实践,专注java,rust技术栈。 本人姓名郭莹城,坐标深圳,前IBM架构师、咨询师、敏捷开发技术教练,前IBM区块链研究小组成员、十多年架构设计工作经验,《区块链核心技术与应用》作者之一, 现聚焦于:区块链创投与交易所资源对接和技术咨询。 工作微信&QQ:360369487,区块链创投与交易所资源对接,加我注明:博客园+对接,技术咨询和顾问,加我注明:博客园+顾问。想学习golang和rust的同学,也可以加我微信,备注:博客园+golang或博客园+rust,谢谢!