Skip to content

編譯

Librian使用「Liber語言」書寫劇本。
(這名字當然是我現編的……)

Liber的寫法接近真實的劇本和自然語言,特點是易讀易寫。

設計Liber語言的文法時,發現現實的劇本幾乎是三型文法——
因此沒有採用一般語言的編譯手段,而使用了基於正則表達式的簡單編譯方法。

按行解析

以一行 對話 爲例:

馬克吐溫 「寫作很簡單,你所要做的只有把不正確的詞都劃掉。」

這句 對話 包含一個 人名,一個 對話分隔符 只有 空格直角引號「」
因此,使用了這樣的正則表達式來匹配並解析——

(?P<人名>.+?) +「(?P<對話>.*?)」

《優秀的語言是不需要詞法分析的》
前幾天我面試一個編程語言,連續幾個專業問題它都沒答上來。
尷尬之餘,我問它「你沒有理想嗎?你現在最渴望的事情是什麼?」
編程語言轉悠着大眼睛,不假思索道「找一個詞法分析器!」

這樣一來 馬克吐溫 的名言就會被解析爲字典對象 {'人名': '马克吐温', '對話': '寫作很簡單,你所要做的只有把不正確的詞都劃掉。'}

因爲對話中還可能含有 表情,所以得在中間加上——

(?P<人名>.+?) +(\((?P<表情>.+?)\))? *「(?P<對話>.*?)」

這樣一來就足夠解析樣例中 潘大爺 的話語了。

潘大爺 (笑)「來吧,和我一起,去到地上!」

可以解析爲字典對象 {'人名': '潘大爺', '表情': '笑', '对话': '來吧,和我一起,去到地上!'}

之後無論加入再多特性,只要屬於三型文法,就可以統統塞進去。

類型識別

使用每一個正則表達式對應每一種語句類型。

編譯器在讀入一行時,對每個正則表達式進行匹配。
如果可以匹配多個則拋出編譯錯誤,如果無法匹配則使用默認類型 旁白

遞歸結構

如果把大量語法都塞進一個正則表達式裏,表達式就會變得冗長,維護就會變得困難。

因此將複雜的正則表達式組織爲字典,像是——

'....(?P<元素1>).....(?P<元素2>)....': {
    '子樹': {
        '元素2': {
            '?P<小元素1>...?P<小元素2>....': None
        }
    }
},

使用遞歸的正則匹配——樣例中先提取出兩個元素,再從第二個元素中提取出小元素們。

預處理

有時,對話 中可能包含 換行

莎士比亞 「戰爭將銅像推翻,
        內訌將城市化爲一片廢墟。」

預處理需要將需要續行的情況連成一行。
因此設置了用於預處理的 續行組 。如果當前行能匹配到 續行組 中的任意正則表達式,就把下一行加入當前行。

在本例中,需要續行的情況是對話的 直角引號 還沒有閉合,因此 續行組 有正則表達式 缺少右引號的對話 ,像是這樣——

(?P<人名>.+?) +(\((?P<表情>.+?)\))? *「([^」]*)

因爲現代漢語中不允許出現 「「」」 的引號嵌套,因此可以在遇到第一個 時直接判定閉合。