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

2018-02-07  本文已影响61人  mimimomo

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作为每个值块上最终返回语句的顺序。结果代码将被不必要的括号侵蚀,但是保证是正确的。

上一篇 下一篇

猜你喜欢

热点阅读