zoukankan      html  css  js  c++  java
  • [编译原理]用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,谢谢!
  • 相关阅读:
    There is no getter for property named 'XXX' in 'class java.lang.String'解决方法
    BigDecimal类型转换
    根据一个字段多值查询(正则)
    Innodb与Myisam引擎的区别与应用场景
    页面输入框查找乱码问题
    Oracle做insert或者update时未提交事务导致表锁定解决办法
    sql语句表连接删除
    Update修改方法判断该ID的数据是否超过24小时,超过不许修改
    如何确定dbgrid选择的是记录而不是分组
    sql server2005的死锁
  • 原文地址:https://www.cnblogs.com/gyc567/p/5351363.html
Copyright © 2011-2022 走看看