> For the complete documentation index, see [llms.txt](https://koshizuow.gitbook.io/compilerbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://koshizuow.gitbook.io/compilerbook/calculator_level_language/step6.md).

# 第6步：單項加與單項減

減法運算的`-`運算子，不只可以像在`5-3`一樣寫在2項中間，也可以像`-3`一樣寫在單項前面。同理，`+`運算子也可以像`+3`這樣用在沒有左項的時候。像這樣只取單項的運算子稱為「單項運算子」（unary operator）。相對的，取2項的運算子就稱為「2項運算子」（binary operator）。

C語言中，除了`+`和`-`以外，也有取得指標位址的`&`和提取指標（dereference）的`*`這些單項運算子。不過這一步我們只會實作`+`和`-`這兩個而已。

單項`+`和單項`-`雖然和2項的`+`和`-`是一樣的符號，但是定義不同。2項的`-`的定義是從左邊減去右邊，但是單項根本沒有左邊，照搬2項`-`的定義的話會無法適用。C語言的單項`-`是定義為把右邊的正負號反轉的運算。而單項`+`則是把右邊直接傳回的運算子，這個運算子不是必要的，是和單項`-`成對存在的贈品。

我們可以合理想像，像+和-這樣，有單項和2項相似但不同定義的同名運算子有很多個。是單項還是2項則需要看前後文脈絡來區分。底下是包含單項`+`/`-`的新文法：

```
expr  = mul ("+" mul | "-" mul)*
mul   = unary ("*" unary | "/" unary)*
unary = ("+" | "-")? term
term  = num | "(" expr ")"
```

上述文法追加了`unary`這個非終端符號，`mul`不是用上`term`而是改為`unary`。`X?`是代表選擇性的，也就是說，`X`會出現0次或1次的 EBNF 語法。`unary = ("+" | "-")? term`這條規則的意思，是表示`unary`這個非終端符號，不論有或沒有1個`+`/`-`符號其後都會接上`term`。

我們來驗證`-3`或`-(3+5)`、`-3*+5`這類式子可以和新的文法對應。底下是`-3*+5`的語法樹：

![-3\*+5的語法樹](/files/-LotQPNixZeJ5NV7RcOm)

我們來依照這個文法修改分析器。照慣例，只要把文法照搬成函式的呼叫我們的分析器應該就改好了。分析`unary`的函式如下所示：

```c
Node *unary() {
  if (consume('+'))
    return term();
  if (consume('-'))
    return new_node(ND_SUB, new_node_num(0), term());
  return term();
}
```

在這個階段，分析器把`+x`用`x`替換、`-x`用`0-x`替換。所以在這一步我們不用修改指令產生器。

加上幾條測試、和加上單項`+`/`-`的程式碼一起 commit 後，這一步就做完了。寫測試的時候，要注意測試的結果要落在0\~255之間。在這一步，請利用像`-10+20`這樣，用上了單項`-`但是整體的結果是正數的算式。

> 參考實作： [bb5fe99dbad62c95](https://github.com/rui314/chibicc/commit/bb5fe99dbad62c9516ec6a4bc64e444d09115e6d)

{% hint style="info" %}

#### 小知識：單項加減和文法的好壞

單項`+`運算子在原始的C編譯器裡並不存在，是在1989年 ANSI（美國國家標準協會）在制定C語言標準時，官方才加上去的。因為有單項`-`，確實有單項`+`會提升對稱性，但實際上單項`+`並沒有什麼用處。

同時，在文法裡加上單項`+`有其副作用。不習慣C語言的人可能會誤把`+=`運算子錯寫成`i =+ 3`。如果沒有單項+的話會回報語法錯誤，但是因為有單項`+`所以這會被解釋為`i = +3`，編譯器會以為這是正確的代入式默默地接受。像這樣，在擴充文法時發生沒想到的副作用是在設計語言時很常發生的事。

ANSI 制定C語言標準的小組，應該是了解上述問題的前提之下決定加上單項`+`的，不過讀者們會怎麼想呢？如果你是C語言標準小組的一員，你會贊成還是反對呢？
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://koshizuow.gitbook.io/compilerbook/calculator_level_language/step6.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
