[编译原理]用BDD方式开发lisp解释器(编译器)|开发语言java|Groovy|Spock

· · 1194 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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

(+ 1 2 )

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

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

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

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

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

image

因为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的功能。

先写测试用例:

<pre>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
}
} </pre>

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

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

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

<pre>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对象的代码很简单: </pre>

<pre>package com.github.eric.camel;
/**

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

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

本人精通java高并发,DDD,微服务等技术实践,以及python,golang技术栈。 本人姓名郭莹城,坐标深圳,前IBM架构师、咨询师、敏捷开发技术教练,前IBM区块链研究小组成员、十多年架构设计工作经验,《区块链核心技术与应用》作者之一, 现有成熟团队提供区块链开发相关业务(公链,交易所,钱包,Dapp,智能合约)。 工作微信&QQ:360369487,交易所开发与区块链钱包开发业务,加我注明:博客园+开发,想学习golang和rust的同学,也可以加我微信,备注:博客园+golang或博客园+rust,谢谢!


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1194 次点击  ∙  1 赞  
加入收藏 微博
被以下专栏收入,发现更多相似内容
上一篇:源码搭建gitea
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传