84
7
if (node.hasOwnProperty('Identifier')) {
if (context.Constants.hasOwnProperty(node.Identifier)) {
return context.Constants[node.Identifier];
}
if (context.Variables.hasOwnProperty(node.Identifier)) {
return context.Variables[node.Identifier];
}
throw new SyntaxError('Unknown identifier');
}
Assignment (like x = 3) works the other way around, though we have to ensure that
we process only variable assignment and not constant override:
if (node.hasOwnProperty('Assignment')) {
right = exec(node.Assignment.value);
context.Variables[node.Assignment.name.Identifier] = right;
return right;
}
Finally, the remaining function node is handled as follows. Basically, the function
arguments (if any) are prepared in an array and then passed to the actual function.
Note that in our default context, we simply wire a bunch of functions to the methods
of the built-in
Math object:
if (node.hasOwnProperty('FunctionCall')) {
expr = node.FunctionCall;
if (context.Functions.hasOwnProperty(expr.name)) {
args = [];
for (i = 0; i < expr.args.length; i += 1) {
args.push(exec(expr.args[i]));
}
return context.Functions[expr.name].apply(null, args);
}
throw new SyntaxError('Unknown function ' + expr.name);
}
What if we want to have a custom function, maybe because it is not supported by the
Math object? It can’t be easier: all we have to do is define the function for the context.
As an example, let’s implement
sum, which adds all the numbers passed in the argu-
ment. Since we’re dealing with a function that may have a variable number of argu-
ments, we use a special
arguments object instead of named parameters:
context.Functions.sum = function () {
var i, total = 0;
for (i = 0; i < arguments.length; i += 1) {
total += arguments[i];
}
return total;
}
TREE WALKER AND EXPRESSION EVALUATOR
75
如果
Math
对象不支持某一运算,我们想自己定义一个函数该怎么办?再简单不过了
我们只需在上下文对象上定义该函数。例如,我们想实现 sum函数,对以参数形式
传入的数字进行求和操作。因为函数的参数个数不定,我们使用特殊的 arguments
对象而不使用每个参数的名称:
if (node.hasOwnProperty('Identifier')) {
if (context.Constants.hasOwnProperty(node.Identifier)) {
return context.Constants[node.Identifier];
}
if (context.Variables.hasOwnProperty(node.Identifier)) {
return context.Variables[node.Identifier];
}
throw new SyntaxError('Unknown identifier');
}
Assignment (like x = 3) works the other way around, though we have to ensure that
we process only variable assignment and not constant override:
if (node.hasOwnProperty('Assignment')) {
right = exec(node.Assignment.value);
context.Variables[node.Assignment.name.Identifier] = right;
return right;
}
Finally, the remaining function node is handled as follows. Basically, the function
arguments (if any) are prepared in an array and then passed to the actual function.
Note that in our default context, we simply wire a bunch of functions to the methods
of the built-in
Math object:
if (node.hasOwnProperty('FunctionCall')) {
expr = node.FunctionCall;
if (context.Functions.hasOwnProperty(expr.name)) {
args = [];
for (i = 0; i < expr.args.length; i += 1) {
args.push(exec(expr.args[i]));
}
return context.Functions[expr.name].apply(null, args);
}
throw new SyntaxError('Unknown function ' + expr.name);
}
What if we want to have a custom function, maybe because it is not supported by the
Math object? It can’t be easier: all we have to do is define the function for the context.
As an example, let’s implement
sum, which adds all the numbers passed in the argu-
ment. Since we’re dealing with a function that may have a variable number of argu-
ments, we use a special
arguments object instead of named parameters:
context.Functions.sum = function () {
var i, total = 0;
for (i = 0; i < arguments.length; i += 1) {
total += arguments[i];
}
return total;
}
TREE WALKER AND EXPRESSION EVALUATOR
75
小结
本章的简单示例可轻松扩展或修改,以适用于多种领域特定语言。对于更简单的语
言,词法分析器可以用一组正则表达式来实现。此外,简单的状态机往往适合多种
应用场景。另一方面,语法复杂的语言,也许需要层级更深的递归下降分析方法
有时,使用基于栈的移进和规约方法处理某些递归问题则更方便。
一些语言因其某些奇怪的用法,增加了词法和句法分析器的处理难度。例如,众所
周知,对
JavaScript
代码进行词法分析,由于
/
符号存在歧义,所以困难重重:它
既可以表示除法运算符,也可以表示正则表达式的开始,此外,著名的自动分号插
入功能,要求分析器的不同部件考虑分号是否是语言规范要求强制添加的。了解不
同的分析器是如何处理这些不同类型的特殊情况,非常有启发意义。
解析快乐!

Get JavaScript 之美 now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.