單元 22 · 運算子優先序與括號自動化

Order 列舉、valueToCode 傳遞規則、最小括號原則

22.1 為什麼需要自動括號

積木本身「隱含括號」:下面的積木代表 -(5 + 2) 而不是 -5 + 2

負號積木包含加法積木(5, 2)

如果每個內嵌積木都包括號,會得到 ((5) * (2)) + (3)——正確但難以閱讀。Blockly 用運算子優先序(precedence)只在「必要」時加括號。

黃金規則:外層運算子比內層強時才需要括號。Blockly 靠兩個值判斷:`valueToCode` 傳入的「外層最強優先序」、生成器回傳的「內層最弱優先序」。

22.2 Order 列舉

每個語言生成器都定義自己的 Order 列舉(對應該語言的真實優先序),例如 JavaScript 的 OrderADDITIONMULTIPLICATIONRELATIONALLOGICAL_NOT

Order 值意義使用時機
Order.ATOMIC最強(原子值)想「永遠加括號」時傳給 valueToCode;積木無運算子時回傳
Order.NONE最弱想「永遠加括號」時回傳;無運算子作用於內嵌積木時傳入
其他各語言真實優先序依你的積木使用了哪種運算子選擇
重點:「強」的數值小(如 ATOMIC),「弱」的數值大(如 NONE)。你可以想成「強壯的選手等級低、卻贏過弱的」。

22.3 valueToCode 的傳入規則

呼叫 generator.valueToCode(block, 'NAME', order) 時,傳入的 order你的積木中作用於該內嵌值的最強運算子——也就是內嵌碼需要「被保護不被拆散」的那個運算子。

範例
// 積木:-(內嵌值) + 2
// 作用於內嵌值的運算子:負號(UNARY_NEGATION)與加法(ADDITION)
// 負號最強 → 傳給 valueToCode
const innerCode = generator.valueToCode(block, 'INNER', Order.UNARY_NEGATION);
const code = `-${innerCode} + 2`;
// 本積木內最弱的運算是加法 → 回傳 ADDITION
return [code, Order.ADDITION];

22.4 回傳優先序規則

回傳的 order 是積木內部最弱的運算子——也就是最需要被保護的那個。這樣外層積木在包這塊積木時,才知道要不要加括號。

負號+加法積木
// 積木內容:-x + 2(有負號與加法兩個運算子)
// 加法比負號弱 → 回傳 ADDITION
return [code, Order.ADDITION];

// 若被「乘法積木」當內嵌:2 * (-x + 2)
// MULTIPLICATION 比 ADDITION 強 → 自動加括號 → 正確!
// 若被「負號積木」當內嵌:-(-x + 2)
// 也是 UNARY_NEGATION 較強 → 括號保護 → 正確
直覺:回傳「最弱」= 告訴外界「我是這個等級的貨色,想把我拆開請先加括號」。

22.5 強制括號的兩種方法

對比
最小括號:5 * 2 + 3
永遠括號:((5) * (2)) + (3)
// 兩者都 = 13,但前者可讀性高得多

22.6 Worked Example:修正漏括號的生成器

範例
問題:下面的生成器回傳 [code] 而非 [code, order]:
javascriptGenerator.forBlock['negate_plus_two'] = function(block, generator) {
  const inner = generator.valueToCode(block, 'INNER', Order.ATOMIC);
  const code = '-' + inner + ' + 2';
  return code;                    // ✗ 沒回傳 order
};
// 當它被乘法積木內嵌 → 生成 "2 * -x + 2"(錯!應是 2 * (-x + 2))

修正:
  return [code, Order.ADDITION];  // ✓ 告知外界「我內部最弱是加法」

驗證:
  乘積木內嵌時 → valueToCode 收到 ADDITION 弱於 MULTIPLICATION
  → 自動包括號 → "2 * (-x + 2)" ✓

22.7 練習

  1. 為什麼「外層比內層強」才需要括號?
  2. 寫一個「加法積木」的生成器,並正確回傳 order。
  3. 用 `Order.ATOMIC` 重寫,比較產出與最小括號版的差異。
看完這單元你應該能說出:
  • 解釋 Order 列舉與 ATOMIC/NONE 的用途。
  • 說明 valueToCode 傳入與回傳優先序的規則。
  • 預測並修正括號遺漏的程式碼。

延伸閱讀