js实现一个粗略的四则运算解释器

这样的一个解释器几乎没用,不过只是为了学习一下解释器的知识,有空继续学习。

支持纯变量的解释,解释器第一个参数为纯变量的字符串,第二个参数为解释上下文,也就是变量的值。
支持四则运算,括号

function Context(map) {
    this.map = map;
}

Context.prototype.getContext = function() {

    return this.map;
}

var context;

function AbstractExpression() {

}
AbstractExpression.prototype.interpret = function() {

}

function TerminalExpression(val) {
    this.val = val;
}

TerminalExpression.prototype = new AbstractExpression();
TerminalExpression.prototype.interpret = function(isRaw) {
    if (!isNaN(+this.val)) {
        return this.val;
    }

    var result = context.getContext()[this.val];
    if (!result) {
        throw new Error('');
        return;
    }
    return result;
}

function NonTerminalExpression(left,  right) {
    this.left = left;
    this.right = right;
}

NonTerminalExpression.prototype = new AbstractExpression();
NonTerminalExpression.prototype.interpret = function() {
}

function AddExpression(left, right) {
    NonTerminalExpression.call(this, left, right);
}

AddExpression.prototype = new NonTerminalExpression();
AddExpression.prototype.interpret = function() {
    return this.left.interpret() + this.right.interpret();
}

function SubExpression(left, right) {
    NonTerminalExpression.call(this, left, right);
}

SubExpression.prototype = new NonTerminalExpression();
SubExpression.prototype.interpret = function() {
    return this.left.interpret() - this.right.interpret();
}

function MulExpression(left, right) {
    NonTerminalExpression.call(this, left, right);
}

MulExpression.prototype = new NonTerminalExpression();
MulExpression.prototype.interpret = function() {
    return this.left.interpret() * this.right.interpret();
}

function DivExpression(left, right) {
    NonTerminalExpression.call(this, left, right);
}

DivExpression.prototype = new NonTerminalExpression();
DivExpression.prototype.interpret = function() {
    return this.left.interpret() / this.right.interpret();
}

function BracketExpression(val) {
    this.val = val;
}

BracketExpression.prototype = new NonTerminalExpression();
BracketExpression.prototype.interpret = function() {
    var val = this.val.replace(/^\((.+)\)$/, '$1');

    var parser = new Parser();
    var root = parser.parse(val);
    if (!root) {
        return;
    }
    return root.interpret();
}

function Interpreter(expression, contextEnv) {
    this.parser = new Parser();
    this.expression = expression;

    context = new Context(contextEnv);
    this.root = null;
}

Interpreter.prototype.run = function() {
    this.root = this.parser.parse(this.expression);
    if (!this.root) {
        return;
    }
    var result = this.interpret();
    console.log(result);
}

Interpreter.prototype.interpret = function() {
    return this.root.interpret();
}

function Parser() {

}
Parser.prototype.parse = function(expression) {
    var iterator = new Iterator(expression);
    var root = null;
    var i = 0;
    var len = expression.length;
    var next, left, right;
    var current;
    var tmp = '';
    var stack = [];
    var map = {
        '+': AddExpression,
        '-': SubExpression,
        '*': MulExpression,
        '/': DivExpression
    };
    while(iterator.hasNext()) {
        current = iterator.nextToken(/[^\s]/);
        if (current === false) {
            return root;
        }
        switch(current) {
            case '(': 
                tmp = '(';
                stack.push('(');
                while(iterator.hasNext()) {
                    current = iterator.nextToken(/[^\s]/);
                    if (current === false) {
                        throw new Error('');
                        return;
                    }
                    if (current === '(') {
                        stack.push('(');
                    }
                    if (current === ')') {
                        stack.pop();
                        tmp += current;
                        if (stack.length === 0) {
                            break;
                        } else {
                            continue;
                        }
                    }
                    tmp += current;
                }
                if (root === null) {
                    root = new BracketExpression(tmp);
                } else {
                    root.right = new BracketExpression(tmp);
                }
                break;
            case '+':
            case '-':
            case '*':
            case '/':
                left = root;
                if (left === null) {
                    left = new TerminalExpression(0);
                }
                next = iterator.nextToken(/[^\s]/);
                if (next === false) {
                    throw new Error('');
                    return;
                }
                if (next === '(') {
                    iterator.rollback();
                    right = new TerminalExpression(null);
                } else if (/[0-9]/.test(next)){
                    throw new Error('');
                } else {
                    right = next;
                    while(next = iterator.nextToken(/[^\s]/)) {
                        if (/[a-zA-Z0-9]/.test(next)) {
                            right += next;
                        } else {
                            iterator.rollback();
                            break;
                        }
                    }
                    right = new TerminalExpression(right);
                }
                if (   (current === '*' || current === '/') 
                    && (left instanceof AddExpression || left instanceof SubExpression)
                ) {
                    left.right = new map[current](left.right, right);
                    root = left;
                    break;
                }
                root = new map[current](left, right);
                break;
            default: 
                root = new TerminalExpression(current);
        }
        i++;
    }
    return root;
}

function Iterator(val) {
    this.val = val;
    this.postion = 0;
    this.length = val.length;
}
Iterator.prototype.next = function() {
    return this.val[this.postion++];
}

Iterator.prototype.hasNext = function() {
    return this.postion < this.length;
}

Iterator.prototype.rollback = function() {
    return this.postion--;
}

Iterator.prototype.nextToken = function(regexp) {
    while(this.hasNext()) {
        var current = this.next();
        if (regexp.test(current)) {
            return current;
        }
    }
    return false;
}
new Interpreter('( ((a +b) + (c * a + (a* cc- bx )))) ',{a:1,b:2,c:3,bx:1,cc:2}).run();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值