两周自制脚本语言-第6天 通过解释器执行程序

第6天 通过解释器执行程序

解释器从抽象语法树的根节点开始遍历该树直至叶节点,并计算各节点的内容

6.1 eval方法与环境对象

eval方法:eval是evaluate(求值)的缩写。eval方法将计算与该节点为根的子树对应的语句、表达式及子表达式,并返回执行结果。
eval方法递归调用子节点的eval方法
不同类型的节点的类,对eval方法有着不同的定义

eval方法的简化版本

public Object eval(Environment env){
    Object left = left().eval(env);
    Object right = right().eval(env);
    return (Integer)letf + (Integer)right;
}
public Object eval(Environment env){ return value(); }  // value()将返回该对象表示的整型字面量

类似深度优先树节点搜索算法

代码清单 6.1 环境对象的接口Environment.java

package chap6;

public interface Environment {
    void put(String name, Object value);
    Object get(String name);
}

代码清单 6.2 环境对象的类BasicEnv.java

package chap6;
import java.util.HashMap;

public class BasicEnv implements Environment {
    protected HashMap<String,Object> values;
    public BasicEnv() { values = new HashMap<String,Object>(); }
    public void put(String name, Object value) { values.put(name, value); }
    public Object get(String name) { return values.get(name); }
}

6.2 各种类型的eval方法

代码清单 6.3 新增的eval方法 (BasicEvaluator.java)

package chap6;

import stone.StoneException;
import stone.Token;
import stone.ast.*;
import javassist.gluonj.*;

import java.util.List;

@Reviser public class BasicEvaluator {
    public static final int TRUE = 1;
    public static final int FALSE = 0;
    @Reviser public static abstract class ASTreeEx extends ASTree {
        public abstract Object eval(Environment env);
    }
    @Reviser public static class ASTListEx extends ASTList {
        public ASTListEx(List<ASTree> c) { super(c); }
        public Object eval(Environment env) {
            throw new StoneException("cannot eval: " + toString(), this);
        }
    }
    @Reviser public static class ASTLeafEx extends ASTLeaf {
        public ASTLeafEx(Token t) { super(t); }
        public Object eval(Environment env) {
            throw new StoneException("cannot eval: " + toString(), this);
        }
    }
    @Reviser public static class NumberEx extends NumberLiteral {
        public NumberEx(Token t) { super(t); }
        public Object eval(Environment e) { return value(); }
    }
    @Reviser public static class StringEx extends StringLiteral {
        public StringEx(Token t) { super(t); }
        public Object eval(Environment e) { return value(); }
    }
    @Reviser public static class NameEx extends Name {
        public NameEx(Token t) { super(t); }
        public Object eval(Environment env) {
            Object value = env.get(name());
            if (value == null)
                throw new StoneException("undefined name: " + name(), this);
            else
                return value;
        }
    }
    @Reviser public static class NegativeEx extends NegativeExpr {
        public NegativeEx(List<ASTree> c) { super(c); }
        public Object eval(Environment env) {
            Object v = ((ASTreeEx)operand()).eval(env);
            if (v instanceof Integer)
                return new Integer(-((Integer)v).intValue());
            else
                throw new StoneException("bad type for -", this);
        }
    }
    @Reviser public static class BinaryEx extends BinaryExpr {
        public BinaryEx(List<ASTree> c) { super(c); }
        public Object eval(Environment env) {
            String op = operator();
            if ("=".equals(op)) {
                Object right = ((ASTreeEx)right()).eval(env);
                return computeAssign(env, right);
            }
            else {
                Object left = ((ASTreeEx)left()).eval(env);
                Object right = ((ASTreeEx)right()).eval(env);
                return computeOp(left, op, right);
            }
        }
        protected Object computeAssign(Environment env, Object rvalue) {
            ASTree l = left();
            if (l instanceof Name) {
                env.put(((Name)l).name(), rvalue);
                return rvalue;
            }
            else
                throw new StoneException("bad assignment", this);
        }
        protected Object computeOp(Object left, String op, Object right) {
            if (left instanceof Integer && right instanceof Integer) {
                return computeNumber((Integer)left, op, (Integer)right);
            }
            else
                if (op.equals("+"))
                    return String.valueOf(left) + String.valueOf(right);
                else if (op.equals("==")) {
                    if (left == null)
                        return right == null ? TRUE : FALSE;
                    else
                        return left.equals(right) ? TRUE : FALSE;
                }
                else
                    throw new StoneException("bad type", this);
        }
        protected Object computeNumber(Integer left, String op, Integer right) {
            int a = left.intValue();
            int b = right.intValue();
            if (op.equals("+"))
                return a + b;
            else if (op.equals("-"))
                return a - b;
            else if (op.equals("*"))
                return a * b;
            else if (op.equals("/"))
                return a / b;
            else if (op.equals("%"))
                return a % b;
            else if (op.equals("=="))
                return a == b ? TRUE : FALSE;
            else if (op.equals(">"))
                return a > b ? TRUE : FALSE;
            else if (op.equals("<"))
                return a < b ? TRUE : FALSE;
            else
                throw new StoneException("bad operator", this);
        }
    }
    @Reviser public static class BlockEx extends BlockStmnt {
        public BlockEx(List<ASTree> c) { super(c); }
        public Object eval(Environment env) {
            Object result = 0;
            for (ASTree t: this) {
                if (!(t instanceof NullStmnt))
                    result = ((ASTreeEx)t).eval(env);
            }
            return result;
        }
    }
    @Reviser public static class IfEx extends IfStmnt {
        public IfEx(List<ASTree> c) { super(c); }
        public Object eval(Environment env) {
            Object c = ((ASTreeEx)condition()).eval(env);
            if (c instanceof Integer && ((Integer)c).intValue() != FALSE)
                return ((ASTreeEx)thenBlock()).eval(env);
            else {
                ASTree b = elseBlock();
                if (b == null)
                    return 0;
                else
                    return ((ASTreeEx)b).eval(env);
            }
        }
    }
    @Reviser public static class WhileEx extends WhileStmnt {
        public WhileEx(List<ASTree> c) { super(c); }
        public Object eval(Environment env) {
            Object result = 0;
            for (;;) {
                Object c = ((ASTreeEx)condition()).eval(env);
                if (c instanceof Integer && ((Integer)c).intValue() == FALSE)
                    return result;
                else
                    result = ((ASTreeEx)body()).eval(env);
            }
        }
    }
}

6.3 关于GluonJ

在GluonJ中,标有@Reviser的类称为修改器(reviser)。修改器看起来和子类很相似,实则不然,它将直接修改(reviser)所继承的类的定义。

6.4 执行程序

eval方法是Stone语言解释器的核心完成了eval方法的实现之后解释器只要读取程序并调用eval方法,就能执行Stone语言程序。

代码清单 6.4 Stone语言的解释器 BasicInterpreter.java

package chap6;
import stone.*;
import stone.ast.ASTree;
import stone.ast.NullStmnt;

public class BasicInterpreter {
    public static void main(String[] args) throws ParseException {
        run(new BasicParser(), new BasicEnv());
    }
    public static void run(BasicParser bp, Environment env)
        throws ParseException
    {
        Lexer lexer = new Lexer(new CodeDialog());
        while (lexer.peek(0) != Token.EOF) {
            ASTree t = bp.parse(lexer);
            if (!(t instanceof NullStmnt)) {
                Object r = ((BasicEvaluator.ASTreeEx)t).eval(env);
                System.out.println("=> " + r);
            }
        }
    }
}

原文地址:https://www.cnblogs.com/ZCWang/p/12209891.html

时间: 2024-07-30 00:51:20

两周自制脚本语言-第6天 通过解释器执行程序的相关文章

两周自制脚本语言-第7天 添加函数功能

第7天 添加函数功能 基本的函数定义与调用执行.引入闭包使Stone语言可以将变量赋值为函数,或将函数作为参数传递给其他函数 有些函数将有返回值的归为函数,没有返回值的归为子程序 7.1 扩充语法规则 函数定义语句的语法规则 此书将函数定义语句称为def语句.def语句仅能用于最外层代码,用户无法在代码块中定义函数 Stone语言将最后执行语句(表达式)的计算结果将作为函数的返回值返回 代码清单 7.1 与函数相关的语法规则 param : IDENTIFIER params : param {

两周自制脚本语言-第9天 设计面向对象语言

第9天 设计面向对象语言 目标:为Stone语言添加类和对象的支持.仅支持单一继承 9.1 设计用于操作类与对象的语法 添加的类与对象的处理功能后,下面的Stone语言就能被正确执行了 class Position { x = y = 0 def move(nx,ny) { x = nx; y = ny } } p = Position.new p.move(3, 4) p.x = 10 print p.x + p.y 首先定义一个Position类,方法由def语句定义.类中字段通过变量表示,

两周自制脚本语言-第5天 设计语法分析器

第5天 设计语法分析器 5.1 Stone语言的语法 代码清单 5.1 Stone 语言的语法定义 primary : "(" expr ")" | NUMBER | IDENTIFIER | STRING factor : "-" primary | primary expr : factor { OP factor } block : "{" [ statement ] { (";" | EOL) [

两周自制脚本语言-第10天 无法割舍的数组

第10天 无法割舍的数组 目标:为Stone语言添加简单的数组功能,下标(index)只能使用整数值. 10.1扩展语法分析器 代码清单10.1 与数组相关的语法规则 elements : expr { "," expr } primary : ( "[" [ elements ] "]" | "(" expr ")" | NUMBER | IDENTIFIER | STRING ) { postfix }

两周自制脚本语言-第11天 优化变量读写性能

第11天 优化变量读写性能 以变量值的读写为例,向读者介绍基于这种理念的语言处理器性能优化方式. 11.1 通过简单数组来实现环境 假如函数包含局部变量x与y,程序可以事先将x设为数组的第0个元素,将y设为第1个元素,以此类推.这样一来,语言处理器引用变量时就无需计算哈希值.也就是说,这是一个通过编号,而非名称来查找变量值的环境 为了实现这种设计,语言处理器需要在函数定义完成后遍历对应的抽象语法树节点,获取该节点使用的所有函数参数与局部变量.遍历之后程序将得到函数中用到的参数与局部变量的数量,于

如何在Java平台上使用脚本语言做Java开发

如何在Java平台上使用脚本语言做Java开发     最近开始流行区分Java平台和Java语言,但很多Java开发者还是不能确定如何在 Java应用程序开发中结合脚本.本篇文章,Gregor Roth给出了在Java平台上使用脚本的方法.通过这篇文章,你可以了解怎样在你的Java应用程序中使用脚本,是否你要通过使用Groovy和 Jython把不同的Java应用程序模块粘合在一起,或者写一个你自己的基于JRuby的应用程序,适用于Java平台. 作为一个Java开发者,你可能已经注意到了,J

java脚本语言学习心得

第一篇技术博客,一定要认真! 第一篇技术博客,一定要认真! 第一篇技术博客,一定要认真! 好了,进入正题: 一 什么是脚本语言? 程序的运行方式有两种:编译运行和解释运行 1.1 前者的典型代表是java, 从文件角度看分为三步: write[编写]: a.java文件(拿个记事本就能写,扩展名是.java), compile[编译]: 编译(cmd命令是java a.java,ide集成了编译器运行之前自动编译)之后产生了a.class文件(是一堆二进制码,人看不懂,是给虚拟机看的) 运行[r

关于JS脚本语言的基础语法

JS脚本语言的基础语法:输出语法  alert("警告!");  confirm("确定吗?");   prompt("请输入密码");为弱类型语言: 开始时要嵌入JS代码:<script type="text/javascript"></script>: 关于写程序是需注意的基本语法:1.所有的字符全都是英文半角的:2.大部分情况下每条语句结束后要加分号:3.每一块代码结束后加换行:4.程序前呼后应:

shell、cmd、dos和脚本语言区别和联系

问题一:DOS与windows中cmd区别   在windows系统中,"开始-运行-cmd"可以打开"cmd.exe",进行命令行操作. 操作系统可以分成核心(kernel)和Shell(外壳)两部分,其中,Shell是操作系统与外部的主要接口,位于操作系统的外层,为用户提供与操作系统核心沟通的途径.在windows系统中见到的桌面即explorer.exe(资源管理器)是图形shell,而cmd就是命令行shell.这算是cmd与dos的最大区别,一个只是接口.