您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    编程是门手艺,手写解析器:提升编程才能(2)
    时间:2021-08-30 21:22 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

        case '1'case '2'case '3'case '4'

        case '5'case '6'case '7'case '8'

        case '9'case '0'

            parse_number(parser); 

            break

     

     

        default

            parser.token.val = c; 

            parser.pos++; 

            break

        } 

     

     

    function parse_number(parser) { 

        var s = parser.text; 

        var num = 0

     

     

        while (parser.pos < s.length) { 

            var c = s[parser.pos]; 

     

     

            if (c >= '0' && c <= '9') { 

                num = num * 10 + (c - '0'); 

                parser.pos++; 

                continue

            } 

     

     

            break

        } 

     

     

        parser.token.val = TOK_NUM; 

        parser.token.num = num; 

    每次调用next_token(),就能拿到以后的token,并且解析移动到下一个token的末尾位置。

    简化2:可以将运算符*和+当作同一级,但是这里篇幅有限,不贴中间完成进程

    简化3: 剖析逻辑,直到能明晰的表达,这也阐明你足够了解它的本质了。

    以"1 + 2 * 3 - 4"为例:

    我们将整个字符串称为expression,外面的各块也是expression。表达式的表示是 expression: expression [op expression]。

    因此 "1 + 2 * 3 - 4"是表达式,"2 * 3"也是表达式, "1"和"4"也是表达式。

    留意*的优先级比+高,由于可以这样剖析:

    2 * 3是一个全体,操作数(2) 操作符(*) 操作数(3)

    1 + 2 * 3也是一个全体,操作数(1) 操作符(+) 操作数(2 * 3)

    依此类推。代码如下:

    var OP_END = 0

        OP_NUM = 1

        OP_ADD = 2

        OP_SUB = 3

        OP_MUL = 4

        OP_DIV = 5

         

    function calc_parse_expr(parser, level) { 

        if (level == 0) { 

            return calc_parse_unary(parser); 

        } 

     

     

        if (calc_parse_expr(parser, level - 1)) { 

            return -1

        } 

     

     

        for (;;) { 

            var op = parser.token.val; 

     

     

            switch (level) { 

            case 1

                switch (op) { 

                case '*'

                    var opcode = OP_MUL; 

                    break

     

     

                case '/'

                    var opcode = OP_DIV; 

                    break

     

     

                default

                    return 0

                } 

     

     

                break

     

     

            case 2

                switch (op) { 

                case '+'

                    var opcode = OP_ADD; 

                    break

     

     

                case '-'

                    var opcode = OP_SUB; 

                    break

     

     

                default

                    return 0

                } 

     

     

                break

            } 

     

     

            next_token(parser); 

     

     

            if (calc_parse_expr(parser, level - 1)) { 

                return -1

            } 

     

     

            parser.code.push(opcode); 

        } 

     

     

        return 0

     

     

    function calc_parse_unary(parser) { 

        switch (parser.token.val) { 

        case TOK_NUM: 

            parser.code.push(OP_NUM); 

            parser.code.push(parser.token.num); 

            break

     

     

        default

            return -1

        } 

     

     

        next_token(parser); 

     

     

        return 0

    留意:我们是边解析边产生中间码的。

    完成之执行

    执行就相对复杂很多了,只需思绪明晰。

    function calc_exec(code) { 

        var i = 0

        var stack = []; 

     

     

        for (;;) { 

            opcode = code[i++]; 

     

     

            switch (opcode) { 

            case OP_END: 

                return stack[0]; 

     

     

            case OP_NUM: 

                var num = code[i++]; 

                stack.push(num); 

                break

     

     

            case OP_ADD: 

                var op2 = stack.pop(); 

                var op1 = stack.pop(); 

                var r = op1 + op2; 

                stack.push(r); 

                break

     

     

            case OP_SUB: 

                var op2 = stack.pop(); 

                var op1 = stack.pop(); 

                var r = op1 - op2; 

                stack.push(r); 

                break

     

     

            case OP_MUL: 

                var op2 = stack.pop(); 

                var op1 = stack.pop(); 

                var r = op1 * op2; 

                stack.push(r); 

                break

     

     

            case OP_DIV: 

                var op2 = stack.pop(); 

                var op1 = stack.pop(); 

                var r = op1 / op2; 

                stack.push(r); 

                break

            } 

        } 

    测试用例很重要

    function calc_run(text) { 

        var code = calc_parse(text); 

        if (code == null) { 

            return null

        } 

     

     

        return calc_exec(code); 

     

     

    function unit_test(tests) { 

        for (var i = 0; i < tests.length; i++) { 

            var test = tests[i]; 

            var ret = calc_run(test.text); 

     

     

     

     

            if (ret != test.expect) { 

    (责任编辑:admin)