之前的一篇文章曾經(jīng)說過我在準(zhǔn)備一個(gè)面向組合子編程的ppt和demo。在公司內(nèi)部進(jìn)行試運(yùn)行之后,今天終于開講了。
當(dāng)然在這之間的幾個(gè)星期里面,我修改了ppt的內(nèi)容,還有為demo添加了單元測試。所以我把
ppt的內(nèi)容和demo的代碼也一起打包上來了。
ppt包含2003和2007兩種格式,demo使用的是Visual Studio2010的C#,當(dāng)然是為了使用那個(gè)激動(dòng)人心的“缺省參數(shù)”語法了。如果沒裝2010的話,那就趕緊裝一個(gè)哈,如果不想裝,那看看代碼就行了。
posted @
2010-09-01 20:42 陳梓瀚(vczh) 閱讀(5178) |
評(píng)論 (3) |
編輯 收藏
因?yàn)樵陂_發(fā)
CMinus的過程中為了異常處理(最終沒有實(shí)現(xiàn)進(jìn)CMinus),曾經(jīng)學(xué)習(xí)了一下
怎么用匯編語言寫try-catch,因此這個(gè)CPU相關(guān)的處理方法就被我偷了哈,實(shí)現(xiàn)在了
NativeX的虛擬機(jī)里。
在NativeX里面,try-catch和throw非常簡單。throw你可以加一個(gè)值當(dāng)異常數(shù)據(jù),也可以不加(不會(huì)修改上次的異常數(shù)據(jù),可以當(dāng)rethrow用)。catch的話沒辦法跟C++一樣根據(jù)類型來判斷,因此我會(huì)給你一個(gè)異常數(shù)據(jù)的指針,你自己看著辦哈,因?yàn)镹ativeX跟C一樣沒有RTTI。因此throw就很簡單了,就是恢復(fù)棧頂和棧底指針之后跳轉(zhuǎn)到最近的異常處理程序里面去。try和catch就是用來創(chuàng)建和銷毀異常處理程序的。所有的異常處理程序構(gòu)成了一個(gè)鏈表,這個(gè)鏈表被我記在了堆棧里面,而最近的異常處理節(jié)點(diǎn)的指針則被我放在了整個(gè)堆棧控件的最頂部,接在后面的是異常對(duì)象的數(shù)據(jù)。你每次throw的東西的尺寸可以不同,因此占用的“堆棧最頂部空間”也不同。當(dāng)然如果你函數(shù)遞歸太深而導(dǎo)致棧頂覆蓋了異常對(duì)象的數(shù)據(jù)區(qū)域時(shí),就會(huì)觸發(fā)“堆棧溢出”事件。在NativeX里面堆棧溢出代表你這程序已經(jīng)廢了,因此這個(gè)是不能catch的,虛擬機(jī)返回給宿主程序一個(gè)信號(hào)然后就停止執(zhí)行了。
我們來看一個(gè)簡單的例子,如何throw之后把異常對(duì)象的返回給函數(shù),首先是代碼:
1 /*NativeX Code*/
2 unit nativex_program_generated;
3 function int32 main()
4 {
5 (result = 10s32);
6 try
7 Throw();
8 catch
9 (result = ( * cast<int32*>(exception)));
10 }
11
12 function void Throw()
13 throw 20s32;
main函數(shù)首先將函數(shù)返回值設(shè)置成10,然后調(diào)用throw函數(shù)。throw函數(shù)會(huì)把20給throw出來,然后main函數(shù)catch了,把結(jié)果返回。NativeX使用了關(guān)鍵字exception來表達(dá)異常對(duì)象的地址。當(dāng)然你如果要throw各種不同的東西的話,你得自己做標(biāo)記(親自實(shí)現(xiàn)RTTI)了。好了,我們看看產(chǎn)生的指令:
1 // unit nativex_program_generated;
2 0: stack_reserve 0
3 1: stack_reserve 0
4 2: ret 0
5 // function int32 main()
6 3: stack_reserve 0
7 // (result = 10s32);
8 4: push s32 10
9 5: resptr
10 6: write s32
11 // try
12 7: exception_handler_push 14
13 // Throw();
14 8: stack_reserve 1
15 9: stack_top 0
16 10: call 20 1
17 11: stack_reserve -1
18 // try
19 12: exception_handler_pop
20 13: jump 18 1
21 14: exception_handler_pop
22 // (result = ( * cast<int32*>(exception)));
23 15: exception_object_address
24 16: resptr
25 17: copymem 4
26 // function int32 main()
27 18: stack_reserve 0
28 19: ret 0
29 // function void Throw()
30 20: stack_reserve 0
31 // throw 20s32;
32 21: exception_object_reserve 4
33 22: push s32 20
34 23: exception_object_address
35 24: write s32
36 25: exception_raise
37 // function void Throw()
38 26: stack_reserve 0
39 27: ret 0
try首先會(huì)將catch之后的第一個(gè)指令給exception_handler_push了,在try的結(jié)尾當(dāng)然要取消掉這個(gè)異常處理函數(shù)了,因此pop一下,然后jump到catch后面。當(dāng)然catch的第一件事也是exception_handler_pop。exception_object_reserve在棧頂預(yù)留指定的空間來存放異常對(duì)象,exception_object_address則是獲得異常對(duì)象的地址,exception_raise就是跳轉(zhuǎn)到最近的異常處理函數(shù)了。raise不會(huì)把異常處理函數(shù)的記錄給pop掉,所以要靠catch自己去pop。
NativeX已經(jīng)完成了,接下來就可以開始打造周邊工具了哇哈哈。將來的目標(biāo)是將類似C#和Javascript的語言都編譯到NativeX上,然后為這三類語言寫很多語法分析器,然后他們就變成很多語言了。當(dāng)然這些語言只是demo。
Vczh Library++的目的是提供實(shí)現(xiàn)編譯器的中間每一層的類庫,因此想干嘛就可以干嘛了哈。
posted @
2010-08-28 01:14 陳梓瀚(vczh) 閱讀(3492) |
評(píng)論 (9) |
編輯 收藏
摘要: 如上一篇文章所說,Vczh Library++3.0的NativeX語言實(shí)現(xiàn)了計(jì)劃的所有泛型語法。讓我們來看一個(gè)簡單的例子:我們?yōu)轭愋蛯懸粋€(gè)Equals函數(shù)。我們可以為普通類型,譬如int32寫一個(gè)Equals函數(shù)。我們有Vector<T>類型,只要T類型擁有一個(gè)Equals函數(shù),那么Vector<T>顯然也可以有Equals函數(shù)。問題...
閱讀全文
posted @
2010-08-26 03:09 陳梓瀚(vczh) 閱讀(3104) |
評(píng)論 (3) |
編輯 收藏
這幾天寫了一個(gè)關(guān)于面向組合子編程的ppt。幾個(gè)月前跟某個(gè)dev lead借了他翻譯的中文版
Pattern Hatching,條件是要在公司里面開一場關(guān)于設(shè)計(jì)模式的講座。其實(shí)本來一個(gè)月前就要講了,不過中間出了點(diǎn)事情,所以等到這個(gè)月才開始。因此我挑選了面向組合子編程的這個(gè)主題,做了個(gè)demo和ppt。
面向組合子編程原本是函數(shù)式編程的內(nèi)容,主要說的是既然我們可以用Composite模式(參見
這里和
這里)來做出像樹一樣的數(shù)據(jù)結(jié)構(gòu),那么我們做出組合起來跟樹一樣的行為(譬如Command模式,用類代表行為)不也可以嗎?這個(gè)做法當(dāng)然是行得通的,只不過一般我們很難看到一個(gè)需求的時(shí)候,可以意識(shí)到可以用面向組合子編程來搞定這個(gè)東西。因此我在這個(gè)ppt里面就舉了這樣的一個(gè)例子,也就是老掉牙的Log系統(tǒng)了:
我們編譯器在編譯代碼的時(shí)候,會(huì)產(chǎn)生下面的文件:
buildchk.err -- 記錄著錯(cuò)誤
buildchk.wrn -- 記錄著警告
buildchk.log -- 記錄所有詳細(xì)信息和時(shí)間戳
命令行窗口 -- 記錄摘要,當(dāng)然錯(cuò)誤和警告還是要輸出來的,只是內(nèi)容可以簡要一點(diǎn)
然后我就用面像組合子來開發(fā)了一個(gè)小巧玲瓏的系統(tǒng),最終通過一個(gè)聲明式編程的接口暴露出來,然后你還可以往里面添加新的功能。
當(dāng)然系統(tǒng)還是要經(jīng)得起修改的,因此我還舉了個(gè)例子,如果有了需求變更——
err和wrn要加錯(cuò)誤/警告的序號(hào)
支持GUI了——跟VS的錯(cuò)誤列表差不多
最后展示了面向組合子編程最強(qiáng)大的威力——只需要添加零件,所有已經(jīng)存在的工具都可以立刻在這個(gè)零件上面使用了,因此只需要非常少的代碼就可以完成這個(gè)需求變更。
這里就
放上我的ppt了。明天還要先開一個(gè)內(nèi)部講座看看別人有什么意見然后進(jìn)一步修改,完了demo在放出來。這個(gè)demo當(dāng)然是C#寫的了,有GUI,C++寫GUI多麻煩啊……
posted @
2010-08-16 09:10 陳梓瀚(vczh) 閱讀(4913) |
評(píng)論 (15) |
編輯 收藏
最近在忙一些其他的事情。因?yàn)楣ぷ鞯年P(guān)系我稍微花了點(diǎn)時(shí)間研究了一下C#,因此就沒往博客上寫文章了。
Vczh Library++ 3.0的工作也暫停了半個(gè)月,下個(gè)星期就要開始恢復(fù)了。最近Codeplex服務(wù)器的URL修改了導(dǎo)致項(xiàng)目連接不上,后來還是修掉了,主要是得手動(dòng)更改sln文件的內(nèi)容,花了好久才知道怎么做。
目前的進(jìn)度是實(shí)現(xiàn)了generic constraint的數(shù)據(jù)結(jié)構(gòu)但是沒有加入語法分析和語義分析的內(nèi)容。generic constraint比較簡單,就如同C#的那個(gè)where,我可以寫:
1 concept T : IEq
2 {
3 
4 }
5
6 concept T : ISort
7 where T : IEq
8 {
9 
10 }
11
12 generic<T>
13 where T : ISort
14 function void Sort(T* values, int count)
15 {
16 
17 }
這是很重要的,因?yàn)闆]有了where,在Sort下面就沒辦法使用ISort和IEq里面定義的函數(shù)了。在NativeX可以成為一門真正可以使用的中間語言之前,還必須實(shí)現(xiàn)下面的功能:
1、 generic constraint
2、concept instance函數(shù)調(diào)用
3、異常處理
4、外部函數(shù)接口
5、調(diào)試器接口
6、裝載的時(shí)候檢查元數(shù)據(jù)引入表是否匹配了所有已經(jīng)加載的assembly
剩下的事情也不多了,就慢慢做吧。做完之后就可以開始寫一些parser來驗(yàn)證這個(gè)NativeX究竟行不行了,我可以將Python和Basic都修改成一個(gè)類似C的語言(可以處理指針,沒有垃圾收集,等),然后把它編譯成NativeX的語法樹,這樣就可以開發(fā)一個(gè)支持多語言的編程接口并測試它了。
posted @
2010-08-06 18:31 陳梓瀚(vczh) 閱讀(3167) |
評(píng)論 (12) |
編輯 收藏
摘要: 根據(jù)之前的文章的討論,Vczh Library++3.0泛型全局存儲(chǔ)是一個(gè)大型的映射。假設(shè)你有下面的代碼:
1 generic<T>2 structure StorageType3 {4 wchar* name;5 T ...
閱讀全文
posted @
2010-07-17 21:28 陳梓瀚(vczh) 閱讀(2962) |
評(píng)論 (2) |
編輯 收藏
第三篇草稿講了泛型concept的概念,這篇最終稿可以確定
Vczh Library++ 3.0的NativeX所要支持的泛型concept的比較精確的特性了。
泛型的concept的概念還是比較清晰的,這次我們便通過一個(gè)例子來講解他。假如在NativeX里面實(shí)現(xiàn)一個(gè)列表,顯然因?yàn)镹ativeX只有指針,所以寫起來大概就是:
1 generic<T>
2 structure List
3 {
4 T* items;
5 int count;
6 }
于是我們想寫一個(gè)函數(shù)判斷兩個(gè)List是否相等。因?yàn)?a style="TEXT-DECORATION: underline" href="http://www.shnenglu.com/vczh/archive/2010/07/12/120141.html" target=_blank>NativeX現(xiàn)在已經(jīng)有模板函數(shù)了,所以我們很簡單的一個(gè)想法是,傳入兩個(gè)List<T>*,然后再傳入一個(gè)函數(shù)指針function bool(T,T),就可以寫出下面的函數(shù)了:
1 generic<T>
2 function bool ListEquals(List<T>* xs, List<T>* ys, function bool(T,T) comparer)
3 {
4 result=true;
5 if(xs->count!=yx->count)
6 {
7 result=false;
8 }
9 else
10 {
11 variable int current=xs->count-1;
12 while(current>=0)
13 {
14 if(!comparer(xs->items[current], yx->items[current]))
15 {
16 result=false;
17 exit;
18 }
19 current--;
20 }
21 }
22 }
這個(gè)做法咋一看好像沒什么問題,但是如果我們要比較List<List<int>>怎么辦呢?我們可以先寫一個(gè)function bool IntEquals(int a, int b);,然后再寫一個(gè)function bool IntListEquals(List<T> a, List<T> b);,這個(gè)函數(shù)里面用IntEquals加上ListEquals<int>來實(shí)現(xiàn),最后將他傳進(jìn)ListEquals<List<int>>。到了這里還好,如果我們還想比較List<List<double>>、List<List<char>>等等,我們就要被迫搞出很多函數(shù)了。而且最大的問題是,當(dāng)我們寫好這么多東西以后,我們想實(shí)現(xiàn)一個(gè)Find函數(shù)來查找List里面的對(duì)象的話,面對(duì)List<List<int>>、List<List<double>>等等的東西,我們又得重新寫一次了……
這個(gè)問題在面向?qū)ο蟮恼Z言里面都很容易做到,只需要在一個(gè)類里面實(shí)現(xiàn)operator==就可以了。那這兩種方法有什么區(qū)別呢?假設(shè)我們把C++里面的類去掉,那么我們會(huì)發(fā)現(xiàn),ListEquals<T>的comparer參數(shù)是通過T自動(dòng)找到的,而不是我們自己傳進(jìn)去的。因此如何設(shè)計(jì)一套可以從類型找到某一組函數(shù)的機(jī)制,就因?yàn)槲覀儼涯0搴瘮?shù)加入NativeX語言(基本上就是C語言)而變成了一個(gè)必須實(shí)現(xiàn)的功能了。在這里我準(zhǔn)備引入concept這個(gè)概念。concept跟
C++0x的concept以及
haskell的type class的概念基本一致。現(xiàn)在就讓我們逐步在NativeX里面實(shí)現(xiàn)這套機(jī)制。
我們在這里面對(duì)的問題是給一些給定的類型(或泛型類型,譬如說List<T>)實(shí)現(xiàn)Equals函數(shù),然后每一個(gè)Equals函數(shù)里面如果需要其他類型U的Equals函數(shù),可以直接找到,而不需要我們自己傳進(jìn)去。因此這個(gè)問題可以抽象為,某些類型具有可以被兩兩比較是否相等的能力。因此定義如下:
1 generic<T>
2 concept Eq
3 {
4 bool Equals(T a, T b);
5 }
當(dāng)然這些函數(shù)不能直接生出來,因此我們對(duì)于想比較的每一個(gè)類型都需要給出相應(yīng)的Equals函數(shù)。下面的代碼為int類型定義了Equals:
1 instance int : Eq
2 {
3 Equals = IntEquals;
4 }
5
6 generic<T>
7 function bool IntEquals(int a, int b)
8 {
9 result=a==b;
10 }
每比較一次數(shù)字就得調(diào)用一次函數(shù),這個(gè)開銷還是比較大的。在NativeX的所有設(shè)施都做好之后,我會(huì)開始做指令級(jí)別的優(yōu)化,然后看看要不要實(shí)現(xiàn)自動(dòng)判斷并inline的功能。有了int : Eq之后,我們就可以為List<T>也寫一個(gè)Eq了。如果我們給出了List<T>的Equals的話,為了使用這個(gè)Equals,T也必須有相應(yīng)的Equals函數(shù),于是我們可以寫:
1 generic<T>
2 instance List : Eq
3 where T : Eq
4 {
5 Equals = ListEquals<T>;
6 }
最后就是實(shí)現(xiàn)ListEquals了,注意ListEquals函數(shù)內(nèi)部是如何拿到類型T的Equals函數(shù)的:
1 generic<T>
2 where T : Eq
3 function bool ListEquals(List<T> xs, List<T> ys)
4 {
5 result=true;
6 if(xs->count!=ys->count)
7 {
8 result=false;
9 }
10 else
11 {
12 variable int current=xs->count-1;
13 while(current>=0)
14 {
15 if(!Eq<T>::Equals(xs->items[current], yx->items[current]))
16 {
17 result=false;
18 exit;
19 }
20 current--;
21 }
22 }
23 }
這里引入了一個(gè)新的語法:Eq<T>::Equals,用于自動(dòng)搜索自己dll或者其他dll實(shí)現(xiàn)的這個(gè)函數(shù)。搜索會(huì)在虛擬機(jī)里面完成,編譯器只負(fù)責(zé)提供符號(hào),并檢查類型。因此就大功告成了。
這個(gè)instance的設(shè)計(jì)基本上來源于Haskell的type class,其實(shí)跟C++0x的那個(gè)concept關(guān)系還是比較小,畢竟NativeX沒有類,C++有類,Haskell沒有類。當(dāng)然其缺點(diǎn)是你不能在定義了Eq<List<T>>::Equals的同時(shí),專門為Eq<List<bool>>::Equals定義一個(gè)特殊的版本,就如同C++的偏特化一樣,這個(gè)就過于復(fù)雜了。雖然偏特化在C++的用處非常大,而且也十分常用,但是在NativeX里面就因?yàn)镹ativeX的模板可以編譯成二進(jìn)制而會(huì)因?yàn)檎也坏礁咝阅艿膶?shí)現(xiàn)方法被砍掉。
posted @
2010-07-13 04:26 陳梓瀚(vczh) 閱讀(3007) |
評(píng)論 (8) |
編輯 收藏
摘要: 經(jīng)過一個(gè)星期的奮斗,二進(jìn)制模板函數(shù)終于實(shí)現(xiàn)了,當(dāng)然這還是沒有g(shù)eneric concept的版本。現(xiàn)在NativeX已經(jīng)支持跟C#一樣的模板函數(shù)了:可以被編譯進(jìn)獨(dú)立的二進(jìn)制文件,然后另外一個(gè)代碼引用該二進(jìn)制文件,還能實(shí)例化新的模板函數(shù)。現(xiàn)在先來看debug log輸出的二進(jìn)制結(jié)構(gòu)。首先是被編譯的代碼。下面的代碼因?yàn)槭侵苯訌恼Z法樹生成的,所以括號(hào)什么的會(huì)比較多,...
閱讀全文
posted @
2010-07-12 03:12 陳梓瀚(vczh) 閱讀(3111) |
評(píng)論 (8) |
編輯 收藏
似乎C++“過于復(fù)雜”已經(jīng)成為了詬病,不過對(duì)于我個(gè)人來講我實(shí)在很難理解這個(gè)觀點(diǎn)。之前有個(gè)朋友說stream::operator<<很復(fù)雜,其實(shí)也就是幾個(gè)overloading。還有些人說傳參數(shù)的時(shí)候很復(fù)雜,這無非就是復(fù)制構(gòu)造函數(shù)、析構(gòu)函數(shù)和引用吧。雖然我個(gè)人覺得模板元編程其實(shí)才是C++里面最復(fù)雜的地方,但是鑒于模板元編程實(shí)際的用處不大,我想應(yīng)該只有少數(shù)幾個(gè)人會(huì)使用它。但是這樣很多人還是C++復(fù)雜,那我就不知道究竟在指什么了。
所以大家對(duì)C++有什么想噴的就趕緊留言哈,我也好看看別人是怎么理解的,然后討論討論。
(不過從我自己的角度出發(fā),我認(rèn)為凡是編譯器不能檢查的東西(譬如可變參數(shù),指針類型強(qiáng)制轉(zhuǎn)換),都遠(yuǎn)比能檢查的東西(模板元編程)要復(fù)雜,因?yàn)槿撕苋菀追稿e(cuò),機(jī)器不會(huì)。)
posted @
2010-07-06 19:52 陳梓瀚(vczh) 閱讀(11489) |
評(píng)論 (68) |
編輯 收藏
這
幾年來屢屢被網(wǎng)友教育說不要造車輪,我覺得我有必要專門寫幾句話來闡述我的觀點(diǎn)。
1:公司的代碼,自然有規(guī)定,你造不了車輪。
2:自己外包賺錢的代碼,造了也只會(huì)浪費(fèi)時(shí)間,這個(gè)隨便你。
3:自己寫的代碼。無論你開源也好,不開源也好,自己寫那些不能換錢的代碼無非就是因?yàn)槟銓懙乃铮窃燔囕嗊€能提高自己功力,為啥總是有人來說這樣不行呢?這又不是公司的代碼,也不是拿去完成別人外包給我項(xiàng)目的代碼,這個(gè)時(shí)候你還用別人的東西,完全是沒有意義的。
除非你所謂的學(xué)習(xí)就是學(xué)習(xí)如何使用別人的車輪。當(dāng)然我自己的定義是,學(xué)習(xí)造車輪,不僅能知道很多你不造車輪不知道的東西,同時(shí)造完了,你看別人的車輪,瞬間就知道怎么用了。而且如果你想的話,你還能研究一下怎么比別人造得更好。什么?你相信自己無論如何這一輩子寫到死也比別人爛么?那就是另一回事了。
posted @
2010-07-01 01:14 陳梓瀚(vczh) 閱讀(5838) |
評(píng)論 (21) |
編輯 收藏