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)