简单代码解释器

一、词法语法标准

if &param1== 2:
 if &param2== 0:1.0
 else:
  if &param3== 6 : 3.0
  elif &param3==5 :3.0
  elif &param3==8:
   if &param4 == 6 :
    if &param3== 1:3.3
    elif &param3== 2:2.7
    else:3.0
   else:
    if &param3== 2:2.6
    else:2.8
  elif &param5  == 3:
   if &param4 == 1 : 7.0
   elif &param4 == 2 : 3.5
   else : 3.0
  else : 2.6 
else:1.0

按上图语法标准

关键字:if else elif

变量引用:&字母数字组合,字母开头

运算符:==,<= ,>=,>,<

分隔符::

格式符:if else elif前面的空格

二、词法分析

输入:一个代码段字符串,变量对应的值字典 

代码段如上图,字典value_map:{param1: 2, param2: 4, ...}

输出:代码段分词后的列表ret_list

js代码

function _split_rule(value_map, rule) {
    /**
     * 对规则语句进行分词与识别,词法分析
     * @param {object} value_map 数据映射表
     * @param {String} rule 计算规则
     * @return {Array} 分词好的规则列表
     */
    rule = rule.replace(/\t/g, '');
    let rule_array = rule.str2array();

    // 命令寄存器
    let temp_command = [];
    // 操作符暂存器
    let temp_str = "";

    while (rule_array.length > 0) {
        let current_char = rule_array.shift();

        // 如果读取到“[”则进入列表读取模式,shift,直到读出“]”,并把读到的内容去除空格后加入操作符暂存器
        if (current_char === "[") {
            temp_command.push(_recognize_list(rule_array));
        }
        // 如果读取到“&”则进入变量读取模式
        else if (current_char === "&") {
            while (rule_array.length > 0 && rule_array[0].match(/[a-zA-Z\d]/) !== null) {
                temp_str += rule_array.shift();
            }
            temp_command.push(value_map[temp_str]);
            temp_str = "";
        }
        // 如果读取到'<', '>' ,'='则进入符号读取模式,判断下一位是否仍然是符号,如果是需要再读一位
        else if (['<', '>' ,'='].contain(current_char)) {
            temp_str += current_char;
            if (rule_array.length > 0 && rule_array[0] === '=') {
                temp_str += rule_array.shift();
            }
            temp_command.push(temp_str);
            temp_str = "";
        }
        // 如果读取到数字,则进入数字读取模式,一直读取下去,直到将要读取到非数字时停止
        else if (current_char.match(/\d/) !== null) {
            temp_str += current_char;
            while (rule_array.length > 0 && rule_array[0].match(/\d|\./) !== null) {
                temp_str += rule_array.shift();
            }
            temp_command.push(parseFloat(temp_str));
            // temp_command.push(temp_str);
            temp_str = "";
        }
        // 匹配多个分隔符
        else if ([' ', ':', '\n'].contain(current_char)) {
            if (temp_str !== '') {
                temp_command.push(temp_str);
                temp_str = "";
            }
            if (current_char === ':') {
                temp_command.push(current_char);
            }
            // 读到换行符后紧挨的空格需要记录
            else if (current_char === '\n') {
                while (rule_array.length > 0 && rule_array[0] === ' ') {
                    temp_str += rule_array.shift();
                }
                if (temp_str.length > 0) {
                    temp_command.push(temp_str);
                    temp_str = "";
                }
            }
        }
        else {
            temp_str += current_char;
        }
    }

    return temp_command;
}

function _recognize_list(rule_array) {
    /**
     * 识别列表与列表中的数,传入参数类似[1,2,[1,2 , 3],],会少前面一个[。识别完成后,返回的列表在原来的参数中将消失
     * @param {Array} rule_array 待识别列表
     * @return {Array} 识别完成的列表
     */
    let temp_list = [];
    let temp_str = '';
    let sign = 1;

    while (sign > 0 && rule_array.length > 0) {
        let current_char = rule_array.shift();
        // current_char = rule_array.shift();
        if (current_char === '[') {
            sign += 1;
            temp_list.push(_recognize_list(rule_array));
        }
        else if (current_char === ']') {
            sign -= 1;

            if (temp_str !== '') {
                // 匹配浮点数或整数
                if (temp_str.match(/^(-?\d+)(\.\d+)?$/) !== null) {
                    temp_list.push(parseFloat(temp_str));
                    temp_str = '';
                }
                else {
                    temp_list.push(temp_str);
                    temp_str = '';
                }
            }
        }
        else if (current_char === ' ') {
            continue;
        }
        else if (current_char === ',') {
            if (temp_str !== '') {
                // 匹配浮点数或整数
                if (temp_str.match(/^(-?\d+)(\.\d+)?$/) !== null) {
                    temp_list.push(parseFloat(temp_str));
                    temp_str = '';
                }
                else {
                    temp_list.push(temp_str);
                    temp_str = '';
                }
            }
        }
        else {
            temp_str += current_char;
        }
    }
    return temp_list;
}

三、语法分析

输入:词法分析后的列表

输出:逻辑结果

const IF = "if";
const ELIF = 'elif';
const ELSE = 'else';

function _calculate_sentence(split_rule){
    /**
     * 根据已经分词好的规则列表计算语句的值,语法分析
     * @param {Array} split_rule 分词好的规则列表
     * @return {Array} 识别完成的列表
     */
    let expression = [];
    let judgment;
    // if,elif,else前面的空格标志,起始为无空格,层级加一空格一
    let sign = '';
    while (split_rule.length > 0) {
        let current_element = split_rule.shift();

        if ([IF, ELIF, ELSE].contain(current_element)) {
            if (current_element === ELSE) {
                judgment = true;
            }
            else {
                // 向后连取直到':'
                while (split_rule.length > 0 && split_rule[0] !== ':') {
                    expression.push(split_rule.shift());
                }

                judgment = calculate_expression(expression);
                expression = [];
            }
            // 把’;‘shift出去
            split_rule.shift();

            if (judgment) {
                sign += ' ';
                // 判断':'后面是格式符号还是结果值,如果是格式符号则后面必跟’空格‘+if,shift格式符,然后进行下一次循环
                if (split_rule[0] === sign) {
                    split_rule.shift();
                    continue;
                }
                else {
                    return split_rule[0];
                }
            }
            // 跳转到下一个对应的elif或者else
            else {
                if (sign === '') {
                    while (split_rule.length > 0 && ![IF, ELIF, ELSE].contain(split_rule[0])) {
                        current_element = split_rule.shift();
                        // 把空格后的if,elif,else都去除掉,以免误判
                        if (typeof(current_element) === 'string' && current_element.match(/\s/) !== null) {
                            split_rule.shift();
                        }
                    }
                }
                else{
                    while (split_rule.length > 0 && split_rule.shift() !== sign) {}
                }
            }
        }
        else {
            return current_element;
        }
    }
    return null;
}

const IN = 'in';
const AND = 'and';
const OR = 'or';
const CALCULATION_SYMBOL = ['<', '>', '=', '==', '>=', '<=', '!=', IN, AND, OR]

function calculate_expression(infix_expression) {
    let postfix_expression = _transform_expression_2_postfix(infix_expression);
    return _calculate_postfix_expression(postfix_expression);
}

function _get_priority(opt) {
    /**
     * 获取优先级
     * @param {string} opt 计算符
     * @return {number} 优先级大小
     */
    if (['(', ')'].contain(opt)) {
        // 随便给一个值,运算时不会取括号的优先级
        return 1;
    }
    else if (['<', '>', '==', '>=', '<=', '!=', IN].contain(opt)) {
        return 9;
    }
    else if ([AND, OR].contain(opt)) {
        return 8;
    }
    else {
        console.error('function:[_get_inferior] 异常运算符: ' + opt);
        return 0;
    }
}

function _transform_expression_2_postfix(infix_expression) {
    /**
     * 单元计算器
     * @param {Array} infix_expression 中缀表达式
     * @return {Array} 后缀表达式
     */
    // 后缀表达式
    let postfix_expression = [];
    // 操作符栈
    let opt_stack = [];
    while (infix_expression.length > 0) {
        let current_element = infix_expression.shift();

        if (['number', 'object'].contain(typeof(current_element))) {
            postfix_expression.push(current_element);
        }
        else {
            if (opt_stack.length === 0 || current_element === '(' || opt_stack.slice(-1)[0] === '(') {
                opt_stack.push(current_element);
            }
            else if (_get_priority(opt_stack.slice(-1)[0]) < _get_priority(current_element)) {
                opt_stack.push(current_element);
            }
            else {
                if (current_element === ')') {
                    while (opt_stack.slice(-1)[0] !== '(') {
                        postfix_expression.push(opt_stack.pop());
                    }
                    // 左括号出栈
                    opt_stack.pop();
                }
                else {
                    while (opt_stack.length > 0 && opt_stack.slice(-1)[0] !== '(' &&
                        _get_priority(opt_stack.slice(-1)[0]) >= _get_priority(current_element)) {
                        postfix_expression.push(opt_stack.pop());
                    }
                    opt_stack.push(current_element);
                }
            }
        }
    }
    while (opt_stack.length > 0) {
        postfix_expression.push(opt_stack.pop());
    }
    return postfix_expression;
}

function _calculate_postfix_expression(postfix_expression) {
    let ret_stack = [];
    while (postfix_expression.length > 0) {
        let current_element = postfix_expression.shift();
        if (['number', 'object'].contain(typeof(current_element))) {
            ret_stack.push(current_element);
        }
        else {
            ret_stack.push(_unit_calculator(ret_stack.pop(), current_element, ret_stack.pop()));
        }
    }
    return ret_stack[0];
}

function _unit_calculator(num_b, opt, num_a) {
    /**
     * 单元计算器
     * @param {Any} num_a 计算数A
     * @param {string} opt 操作数
     * @param {Any} num_b 计算数B
     * @return {Any} 计算结果
     */
    if (!CALCULATION_SYMBOL.contain(opt)) {
        console.error("非法计算符" + opt);
        return null;
    }
    if (opt === IN) {
        return num_b.contain(num_a);
    }
    else if (opt === '==') {
        return num_a === num_b;
    }
    else if (opt === '!=') {
        return num_a !== num_b;
    }
    else if (opt === '>=') {
        return num_a >= num_b;
    }
    else if (opt === '<=') {
        return num_a <= num_b;
    }
    else if (opt === '>') {
        return num_a > num_b;
    }
    else if (opt === '<') {
        return num_a < num_b;
    }
    else if (opt === AND) {
        return num_a && num_b;
    }
    else if (opt === OR) {
        return num_a || num_b;
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值