編譯
Librian使用「Liber語言」書寫劇本。
(這名字當然是我現編的……)
Liber的寫法接近真實的劇本和自然語言,特點是易讀易寫。
設計Liber語言的文法時,發現現實的劇本幾乎是三型文法——
因此沒有採用一般語言的編譯手段,而使用了基於正則表達式的簡單編譯方法。
按行解析
以一行 對話
爲例:
馬克吐溫 「寫作很簡單,你所要做的只有把不正確的詞都劃掉。」
這句 對話
包含一個 人名
,一個 對話
, 分隔符
只有 空格
和 直角引號「」
。
因此,使用了這樣的正則表達式來匹配並解析——
(?P<人名>.+?) +「(?P<對話>.*?)」
《優秀的語言是不需要詞法分析的》
前幾天我面試一個編程語言,連續幾個專業問題它都沒答上來。
尷尬之餘,我問它「你沒有理想嗎?你現在最渴望的事情是什麼?」
編程語言轉悠着大眼睛,不假思索道「找一個詞法分析器!」
這樣一來 馬克吐溫
的名言就會被解析爲字典對象 {'人名': '马克吐温', '對話': '寫作很簡單,你所要做的只有把不正確的詞都劃掉。'}
。
因爲對話中還可能含有 表情
,所以得在中間加上——
(?P<人名>.+?) +(\((?P<表情>.+?)\))? *「(?P<對話>.*?)」
這樣一來就足夠解析樣例中 潘大爺
的話語了。
潘大爺 (笑)「來吧,和我一起,去到地上!」
可以解析爲字典對象 {'人名': '潘大爺', '表情': '笑', '对话': '來吧,和我一起,去到地上!'}
之後無論加入再多特性,只要屬於三型文法,就可以統統塞進去。
類型識別
使用每一個正則表達式對應每一種語句類型。
編譯器在讀入一行時,對每個正則表達式進行匹配。
如果可以匹配多個則拋出編譯錯誤,如果無法匹配則使用默認類型 旁白
。
遞歸結構
如果把大量語法都塞進一個正則表達式裏,表達式就會變得冗長,維護就會變得困難。
因此將複雜的正則表達式組織爲字典,像是——
'....(?P<元素1>).....(?P<元素2>)....': {
'子樹': {
'元素2': {
'?P<小元素1>...?P<小元素2>....': None
}
}
},
使用遞歸的正則匹配——樣例中先提取出兩個元素,再從第二個元素中提取出小元素們。
預處理
有時,對話
中可能包含 換行
。
莎士比亞 「戰爭將銅像推翻,
內訌將城市化爲一片廢墟。」
預處理需要將需要續行的情況連成一行。
因此設置了用於預處理的 續行組
。如果當前行能匹配到 續行組
中的任意正則表達式,就把下一行加入當前行。
在本例中,需要續行的情況是對話的 直角引號
還沒有閉合,因此 續行組
有正則表達式 缺少右引號的對話
,像是這樣——
(?P<人名>.+?) +(\((?P<表情>.+?)\))? *「([^」]*)
因爲現代漢語中不允許出現 「「」」
的引號嵌套,因此可以在遇到第一個 」
時直接判定閉合。