近期忽然有興趣寫個文法解釋器,因而SPAS就出爐了。其實最初是看到boost.spirit的強大才想研究下如何去實現一個文法解釋器的。在看了一些關於boost.spirit庫的相關資料後,個人頭腦中逐漸構建起了一個文法解釋的框架,因而我便試着去實現它。 shell
語言能夠從產生和接收兩個角度進行定義,從產生的角度就是形式語言,而從接收的角度就是自動機。本人以前按照自動機寫了一個浮點數的識別程序,可是以爲實現頗爲繁瑣。用自動機來描述語言不夠簡潔,語法稍微複雜一點,狀態就會不少,實現起來也很不容易。因此本人就想仿照boost.spirit庫,經過定義語法來實現語言的解釋。 框架
一個語言是有字母表、語法構成的,對咱們來講字母表其實並非很重要,字母表只是一個符號表而已,重要的是語法。在SPAS中,字母表就是char/wchar_t的數值空間,語法就是定義的一條條規則。下面來看一個使用SPAS定義的四則運算解釋計算示例。 ui
opr2 = _int[arg[1] = ref<int>(arg)] | ('(' >> expr[arg[3] = ref<int>(arg)] >> ')'); mulr = '*' >> opr2[arg[1] = ref<int>(arg)]; divr = '/' >> opr2[arg[1] = ref<int>(arg)]; opr1 = opr2[arg[1] = ref<int>(arg)] >> * (mulr[arg[3] = arg[3] * ref<int>(arg)] | divr[arg[3] = arg[3] / ref<int>(arg)]); sumr = '+' >> opr1[arg[1] = ref<int>(arg)]; subr = '-' >> opr1[arg[1] = ref<int>(arg)]; expr = opr1[arg[1] = ref<int>(arg)] >> * (sumr[arg[3] = arg[3] + ref<int>(arg)] | subr[arg[3] = arg[3] - ref<int>(arg)]); endr = expr[ref(result) = arg];將四則表達式使用形式語言寫出來,以下:
opr2 -> int | ( expr ) mulr -> *opr2; divr -> /opr2; opr1 -> opr2 | opr2 mulr | opr2 divr; sumr -> +opr1; subr -> -opr1; expr -> opr1 | opr1 sumr | opr1 subr; endr = expr;上面這個文法可以產生全部的整數四則運算。SPAS的規則就是根據這個文法來寫的,在SPAS中A|B表示A、B兩者擇一,A >> B表示A後面緊跟着B,*A表示有0個或多個A,+A表示有1個或多個A,repeat<N,M>(A)表示A的個數在N到M之間,repeat<N>(A)表示有N個A。
SPAS不只可以檢查文本是否符合語法,還可以經過在rule中嵌入操做(即上述示例中方括號內內容)來對文法的解釋過程進行控制。SPAS中,arg表示rule的值,arg[n]表示rule的第n個父rule的值,ref是引用外部變量,ref<type>(x)是將x轉變爲type類型。此外還能經過在比較語句對語法進行進一步的限制,例如,_int匹配全部的整型數,而_int[arg < 100]就表示全部小於100的整型數。這種控制很實用,例如,_uint[arg < 256u] >> repeat<3>('.' >> _uint[arg < 256u])這個規則是產生IPv4地址的語法。 google
SPAS地址:https://code.google.com/p/spas/ spa