Crockfords自上而下的运营商优先权

Mor*_*ler 26 javascript parsing

出于兴趣,我想学习如何为一种简单的语言编写一个解析器,最终为我自己的小代码打高尔夫语言编写一个解释器,一旦我理解了这些东西的工作原理.

所以我开始阅读Douglas Crockfords的文章Top Down Operator Precedence.

注意:如果您想更深入地了解下面代码片段的上下文,您应该阅读本文

我无法理解var语句和赋值运算符=应如何协同工作.

DC定义了一个赋值运算符

var assignment = function (id) {
    return infixr(id, 10, function (left) {
        if (left.id !== "." && left.id !== "[" &&
                left.arity !== "name") {
            left.error("Bad lvalue.");
        }
        this.first = left;
        this.second = expression(9);
        this.assignment = true;
        this.arity = "binary";
        return this;
    });
};
assignment("=");  
Run Code Online (Sandbox Code Playgroud)

注意:[[value]]是指一个简化为其值的标记

现在,如果表达式函数达到例如[[t]],[[=]],[[2]],结果[[=]].led是这样的.

{
    "arity": "binary",
    "value": "=",
    "assignment": true, //<-
    "first": {
        "arity": "name",
        "value": "t"
    },
    "second": {
        "arity": "literal",
        "value": "2"
    }
}
Run Code Online (Sandbox Code Playgroud)

DC使assignment功能因为

我们希望它做两个额外的业务:检查左操作数以确保它是一个合适的左值,并设置一个赋值成员,以便我们以后可以快速识别赋值语句.

这对我来说是有意义的,直到他介绍 var语句,其定义如下.

var语句定义当前块中的一个或多个变量.每个名称可以选择后跟=和初始化表达式.

stmt("var", function () {
    var a = [], n, t;
    while (true) {
        n = token;
        if (n.arity !== "name") {
            n.error("Expected a new variable name.");
        }
        scope.define(n);
        advance();
        if (token.id === "=") {
            t = token;
            advance("=");
            t.first = n;
            t.second = expression(0);
            t.arity = "binary";
            a.push(t);
        }
        if (token.id !== ",") {
            break;
        }
        advance(",");
    }
    advance(";");
    return a.length === 0 ? null : a.length === 1 ? a[0] : a;
});
Run Code Online (Sandbox Code Playgroud)

现在,如果解析器到达一组令牌,就像[[var]],[[t]],[[=]],[[1]]生成的树看起来像.

{
    "arity": "binary",
    "value": "=",
    "first": {
        "arity": "name",
        "value": "t"
    },
    "second": {
        "arity": "literal",
        "value": "1"
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题的关键if (token.id === "=") {...}部分是部分.

我不明白为什么打电话

    t = token;
    advance("=");
    t.first = n;
    t.second = expression(0);
    t.arity = "binary";
    a.push(t);
Run Code Online (Sandbox Code Playgroud)

而不是

    t = token;
    advance("=");
    t.led (n);
    a.push(t);  
Run Code Online (Sandbox Code Playgroud)

在这...部分.

这将调用我们的[[=]]运营led功能(该分配功能),它不

确保它是一个合适的左值,并设置一个赋值成员,以便我们以后可以快速识别赋值语句. 例如

{
    "arity": "binary",
    "value": "=",
    "assignment": true,
    "first": {
        "arity": "name",
        "value": "t"
    },
    "second": {
        "arity": "literal",
        "value": "1"
    }
}
Run Code Online (Sandbox Code Playgroud)

因为没有lbp0到10之间的运算符,所以调用expression(0) vs. expression (9)没有区别.(!(0<0) && !(9<0) && 0<10 && 9<10))

token.id === "="条件防止分配到一个对象部件为token.id要么是'[''.'并且t.led将不被调用.

我的问题很简单:

为什么我们不能在变量声明后面调用赋值运算符的可用led函数.而是手动设置firstsecond声明的成员,但不是assignment会员?

这里有两个解析简单字符串的小提琴.使用原始代码和使用赋值运算符的代码led.

Ben*_*aum 8

在解析语言时,有两件事很重要 - 语义和语法.

语义,var x=5;并且var x;x=5看起来非常接近,如果不相同(因为在这两种情况下,首先声明一个变量,然后一个值分配给该声明的变量,这是你所观察到的,是在大多数情况下是正确的.

然而,在语法上,两者不同(清楚可见).

在自然语言中,类似物将是:

  • 这个男孩有一个苹果.
  • 有一个苹果,男孩有它.

现在要简明扼要!让我们看看这两个例子.

虽然这两个(几乎)意思相同,但它们显然不是同一个句子.回到JavaScript!

第一招:var x=5阅读以下方式:

var                      x              =                  5
-----------------------VariableStatement--------------------
var -------------------        VariableDeclarationList 
var -------------------        VariableDeclaration
var            Identifier -------   Initialiser(opt)
var ------------------- x              = AssignmentExpression
var ------------------- x ------------ = LogicalORExpression
var ------------------- x ------------ = LogicalANDExpression
var ------------------- x ------------ = BitwiseORExpression
var ------------------- x ------------ = BitwiseXORExpression
var ------------------- x ------------ = BitwiseANDExpression 
var ------------------- x ------------ = EqualityExpression
var ------------------- x ------------ = ShiftExpression
var ------------------- x ------------ = AdditiveExpression
var ------------------- x ------------ = MultiplicativeExpression
var ------------------- x ------------ = UnaryExpression
var ------------------- x ------------ = PostfixExpression 
var ------------------- x ------------ = NewExpression
var ------------------- x ------------ = MemberExpression
var ------------------- x ------------ = PrimaryExpression
var ------------------- x ------------ = Literal
var ------------------- x ------------ = NumericLiteral
var ------------------- x ------------ = DecimalLiteral
var ------------------- x ------------ = DecimalDigit 
var ------------------- x ------------ = 5
Run Code Online (Sandbox Code Playgroud)

唷!所有这一切都必须在语法上进行解析var x = 5,当然,很多都是处理表达式 - 但它就是它,让我们检查另一个版本.

这分为两个陈述.var x; x = 5第一个是:

var                      x 
--------VariableStatement---
var ---- VariableDeclarationList 
var ---- VariableDeclaration
var                 Idenfifier (optional initializer not present)
var                      x
Run Code Online (Sandbox Code Playgroud)

第二部分是x=5赋值语句.我可以继续用同样的表达疯狂 - 但它几乎是一样的.

总而言之,虽然两者在语义上产生相同的结果,但在语法上与官方语言语法指定的一样 - 它们是不同的.在这种情况下,结果确实是相同的.