重現木蘭編程語言(三)——一探特別的除

簡單回顧下。本項目是爲了重現「木蘭」編程語言編譯器,剛開始原型搭建,與原始版本一樣,用 Python3 和 RPly 實現,照例使用中文命名標識符。

之前實現了加法打印輸出。此文實現整數的減、乘、除,其中“除”的語義與 Python3 不同。

比如print(2+3*4/5)在「木蘭」中輸出 4,而不是像 Python3 中輸出的 4.4。

設計分析

可以想見,「木蘭」的除法中,如果倆數是整數,除法結果就仍是整數,而小數部分直接捨去。

而 Python3 無論是否相除的倆數是否整數,都會返回小數部分(如果有的話)。

在進入實現細節之前,想先嚐試猜度一下這種設計的思路。剛搜了下 Python2 的除法語義和「木蘭」是一致的。而 Python3 新加了一個//達到捨去小數的目的。

估計「木蘭」設計者也是參考了兩種設計,最後選擇了 Python2 的設計。從逆向工程看,「木蘭」實現用的是 Python3。從後面的實現細節可以看出,是額外添加了一點代碼才實現了 Python2 的除法。

相比之下,個人的理解是,Python3 添加一種運算符的一個好處是能讓語義更直觀,省得除法結果依賴於操作數是否是整數,因爲這不一定那麼好確定。而 Python2 的“整數除法得整數”這一層語義在實際應用中的用途感覺並不那麼廣泛。即使在需要實現這一功能時再自行實現也就是調用個floor函數的事。

那麼爲何仍選擇用 Python2 的除法設計,而不使用//運算符呢?使用手冊第一趴中可見,「木蘭」選擇了用///* */作爲註釋標誌。相信這是爲了與市面上佔大頭的 C 系列、Java、JS、PHP 等等編程語言的語法靠近。

語言設計時的各種取捨可見一斑。

具體實現

比較簡單,在之前的基礎上,加減乘部分與最上面的 RPly 入門示例大致相同這裏不重複。下面是除法運算的相關部分。

語法分析部分:

@分析器母機.production('二元表達式 : 表達式 除 表達式')
def 除法(片段):
    return 語法樹.調用(
        函數=語法樹.名稱(
            標識='__除__',
            上下文=(ast.Load()),
            行號=0,
            列號=0),
        參數=[片段[0], 片段[2]],
        行號=0,
        列號=0)

行號列號還是全 0,比較刺眼,會盡快研究。下面是除法內置函數:

def __內置_除(a, b):
    if isinstance(a, int):
        if isinstance(b, int):
            return math.floor(a / b)
    return a / b

的確就是用了floor進行了特殊處理。

完整代碼在此,語法分析部分已上升到 85 行,相比「木蘭」的 1400 行,還有相當距離。

下面打算對錯誤處理和行列號進行研究。

更多「木蘭」相關技術文章,歡迎關注木蘭編程語言知乎專欄。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章