第6步:單項加與單項減
Last updated
Last updated
減法運算的-
運算子,不只可以像在5-3
一樣寫在2項中間,也可以像-3
一樣寫在單項前面。同理,+
運算子也可以像+3
這樣用在沒有左項的時候。像這樣只取單項的運算子稱為「單項運算子」(unary operator)。相對的,取2項的運算子就稱為「2項運算子」(binary operator)。
C語言中,除了+
和-
以外,也有取得指標位址的&
和提取指標(dereference)的*
這些單項運算子。不過這一步我們只會實作+
和-
這兩個而已。
單項+
和單項-
雖然和2項的+
和-
是一樣的符號,但是定義不同。2項的-
的定義是從左邊減去右邊,但是單項根本沒有左邊,照搬2項-
的定義的話會無法適用。C語言的單項-
是定義為把右邊的正負號反轉的運算。而單項+
則是把右邊直接傳回的運算子,這個運算子不是必要的,是和單項-
成對存在的贈品。
我們可以合理想像,像+和-這樣,有單項和2項相似但不同定義的同名運算子有很多個。是單項還是2項則需要看前後文脈絡來區分。底下是包含單項+
/-
的新文法:
上述文法追加了unary
這個非終端符號,mul
不是用上term
而是改為unary
。X?
是代表選擇性的,也就是說,X
會出現0次或1次的 EBNF 語法。unary = ("+" | "-")? term
這條規則的意思,是表示unary
這個非終端符號,不論有或沒有1個+
/-
符號其後都會接上term
。
我們來驗證-3
或-(3+5)
、-3*+5
這類式子可以和新的文法對應。底下是-3*+5
的語法樹:
我們來依照這個文法修改分析器。照慣例,只要把文法照搬成函式的呼叫我們的分析器應該就改好了。分析unary
的函式如下所示:
在這個階段,分析器把+x
用x
替換、-x
用0-x
替換。所以在這一步我們不用修改指令產生器。
加上幾條測試、和加上單項+
/-
的程式碼一起 commit 後,這一步就做完了。寫測試的時候,要注意測試的結果要落在0~255之間。在這一步,請利用像-10+20
這樣,用上了單項-
但是整體的結果是正數的算式。
參考實作: bb5fe99dbad62c95
單項+
運算子在原始的C編譯器裡並不存在,是在1989年 ANSI(美國國家標準協會)在制定C語言標準時,官方才加上去的。因為有單項-
,確實有單項+
會提升對稱性,但實際上單項+
並沒有什麼用處。
同時,在文法裡加上單項+
有其副作用。不習慣C語言的人可能會誤把+=
運算子錯寫成i =+ 3
。如果沒有單項+的話會回報語法錯誤,但是因為有單項+
所以這會被解釋為i = +3
,編譯器會以為這是正確的代入式默默地接受。像這樣,在擴充文法時發生沒想到的副作用是在設計語言時很常發生的事。
ANSI 制定C語言標準的小組,應該是了解上述問題的前提之下決定加上單項+
的,不過讀者們會怎麼想呢?如果你是C語言標準小組的一員,你會贊成還是反對呢?