美文网首页
创建自定义块 - 运算符优先级

创建自定义块 - 运算符优先级

作者: mimimomo | 来源:发表于2018-02-07 10:05 被阅读61次

    title: 创建自定义块 - 运算符优先级

    代码生成器用于将Blockly的程序转换为JavaScript,Python,PHP,Lua,Dart等。为新块创建代码生成器时最具挑战性的问题是处理操作的顺序,以便生成的代码按预期执行。

    坑爹的括号


    考虑以下块的装配。

    如果生成器不知道运算符优先级,则生成的JavaScript代码将是:

    alert(2 * 3 + 4);
    

    这显然是不正确的,因为乘法运算符分割加法,先乘以3。一个解决方案是将每个值块的结果包裹在括号中:

    alert(((2) * ((3) + (4)));
    

    这个解决方案完美地工作,但它导致非常凌乱的代码与大量的冗余括号。对于一些使用情况,这不是一个问题。如果人眼永远不会看到生成的代码,那么这是可以接受的。但是,Blockly经常被用作介绍编程的教育工具,一种依赖于生成人类可读代码的用例。

    Good Parentheses


    为了生成没有不合理数量的括号的正确代码,每个语言生成器都提供了有序的优先级列表。这里是JavaScript的列表:

    Blockly.JavaScript.ORDER_ATOMIC = 0;         // 0 "" ...
    Blockly.JavaScript.ORDER_MEMBER = 1;         // . []
    Blockly.JavaScript.ORDER_NEW = 1;            // new
    Blockly.JavaScript.ORDER_FUNCTION_CALL = 2;  // ()
    Blockly.JavaScript.ORDER_INCREMENT = 3;      // ++
    Blockly.JavaScript.ORDER_DECREMENT = 3;      // --
    Blockly.JavaScript.ORDER_LOGICAL_NOT = 4;    // !
    Blockly.JavaScript.ORDER_BITWISE_NOT = 4;    // ~
    Blockly.JavaScript.ORDER_UNARY_PLUS = 4;     // +
    Blockly.JavaScript.ORDER_UNARY_NEGATION = 4; // -
    Blockly.JavaScript.ORDER_TYPEOF = 4;         // typeof
    Blockly.JavaScript.ORDER_VOID = 4;           // void
    Blockly.JavaScript.ORDER_DELETE = 4;         // delete
    Blockly.JavaScript.ORDER_MULTIPLICATION = 5; // \*
    Blockly.JavaScript.ORDER_DIVISION = 5;       // /
    Blockly.JavaScript.ORDER_MODULUS = 5;        // %
    Blockly.JavaScript.ORDER_ADDITION = 6;       // +
    Blockly.JavaScript.ORDER_SUBTRACTION = 6;    // -
    Blockly.JavaScript.ORDER_BITWISE_SHIFT = 7;  // << >> >>>
    Blockly.JavaScript.ORDER_RELATIONAL = 8;     // < <= > >=
    Blockly.JavaScript.ORDER_IN = 8;             // in
    Blockly.JavaScript.ORDER_INSTANCEOF = 8;     // instanceof
    Blockly.JavaScript.ORDER_EQUALITY = 9;       // == != === !==
    Blockly.JavaScript.ORDER_BITWISE_AND = 10;   // &
    Blockly.JavaScript.ORDER_BITWISE_XOR = 11;   // ^
    Blockly.JavaScript.ORDER_BITWISE_OR = 12;    // |
    Blockly.JavaScript.ORDER_LOGICAL_AND = 13;   // &&
    Blockly.JavaScript.ORDER_LOGICAL_OR = 14;    // ||
    Blockly.JavaScript.ORDER_CONDITIONAL = 15;   // ?:
    Blockly.JavaScript.ORDER_ASSIGNMENT = 16;    // = += -= \*= /= %= <<= >>= ...
    Blockly.JavaScript.ORDER_COMMA = 17;         // ,
    Blockly.JavaScript.ORDER_NONE = 99;          // (...)
    

    此列表的大部分直接取自JavaScript的语言规范language spec,其中ORDER_ATOMIC添加到开始,ORDER_NONE添加到结尾。

    应用这些规则会在每个块的生成器中的两个地方使用到。第一个地方是从连接的值块获取生成的代码。在这种情况下,我们传递常数,该常数表示与子块生成的代码相邻的任何运算符的最大绑定强度。例如:

    var arg0 = Blockly.JavaScript.valueToCode(this, 'NUM1', Blockly.JavaScript.ORDER_DIVISION);
    

    第二个是从值块返回生成的代码。在这种情况下,我们传递常量,它代表块生成代码中任何运算符的最小绑定强度。例如:

    return [arg0 + ' / ' + arg1, Blockly.JavaScript.ORDER_DIVISION];
    

    如果子块返回的顺序值弱于或等于父块的顺序参数的顺序值,那么valueToCode函数将自动将子块代码的内容括在括号中,以防止它由父块的代码割裂开。

    下面是一些更多的例子。在每种情况下,块具有被表示为“X”的一个连接子块('X'的内容是未知的并且无关紧要)。第二列列出可能分裂“X”的最强运算符。第三列列出了块的最终代码中最弱的运算符。

    生成的代码 Max strength against X Min strength of block
    X + 1 ORDER_ADDITION ORDER_ADDITION
    Math.sqrt(X) ORDER_NONE ORDER_MEMBER
    !X && false ORDER_LOGICAL_NOT ORDER_LOGICAL_AND
    foo[X % 60] ORDER_MODULUS ORDER_MEMBER

    数学很难


    还是不明白?没问题。只需使用ORDER_ATOMIC作为每次调用valueToCode的顺序,并使用ORDER_NONE作为每个值块上最终返回语句的顺序。结果代码将被不必要的括号侵蚀,但是保证是正确的。

    相关文章

      网友评论

          本文标题:创建自定义块 - 运算符优先级

          本文链接:https://www.haomeiwen.com/subject/idkqmttx.html