• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-341  評論-2670  文章-0  trackbacks-0
             
            花了兩天時間,集成了以前開發的山寨Office2007的Ribbon框架,和之前開發的Intellisense算法和控件,打算做一個可以點擊Run之后出一只小烏龜畫圖的小demo哇哈哈。然后以此作為Vczh Library++ 3.0的第一個Release的Demo。

            vle.exe大概已經做完了,現在checkin了一個vlscript.dll的框架,但是還沒有實現里面的具體的函數。到時候這個用C#寫的demo就會調用C++寫的vlscript.dll,來實現烏龜畫圖功能。

            這個破IDE的代碼在“Tools\Release\VleSource\VlTurtle\VlTurtle.csproj”,大家有興趣的話可以去下載。打開那個solution,然后用release編譯,然后再release目錄下執行Deploy.bat之后,就可以F5看到效果了。

            此時的心情簡直無以倫比。

            posted @ 2011-02-24 08:54 陳梓瀚(vczh) 閱讀(25338) | 評論 (26)編輯 收藏
                Vczh Library++ 3.0這破東西也做了一年半了,因此打算給它制作第一個Release。這個Release將計劃包含下面的東西:

                1、vle.exe。這是一個編譯器和虛擬機的命令行程序。通過這個程序可以把NativeX程序編譯成assembly、可以執行基于控制臺的assembly程序、以及運行我為這個平臺開發的一個單元測試工具。這些是已經開發完成的了。接下來還要給vle.exe添加鏈接功能。所謂的鏈接功能是指將多個assembly合并成一個,并且預先展開所有模板函數、模板變量和concept mapping等等。雖然NativeX程序跟C語言很像(多了泛型和concept mapping),也需要頭文件,不過其機制并不像#include那樣把文件復制進去,而是類似pascal。為了調用另一個assembly而必須的頭文件可以讓編譯器在編譯的過程中產生,不需要人去維護。

                2、vlscript.dll。這是一個編譯器和虛擬機的函數庫。這個函數庫將會制作成C而不是C++的格式。我在盡可能讓vlscript.dll包含vle.exe所具有的全部功能以外,還要添加一些其他的譬如可以遍歷一個assembly里面各種聲明什么的的一些功能,以便二次開發的時候可以利用vlscript.dll完成很多有趣的事情。

                3、TurtleDotNet.exe。這暫時還是一個設想。還記得舊社會的LOGO語言吧?最近新出的Microsoft Small Basic也跟LOGO一樣可以使用烏龜畫圖。這是一個很好的教程式的函數庫,因此我也打算做一個。因為時間的關系,我并不會在第一個Release里面包含一個NativeX的IDE,而只是包含一個C#寫的窗口程序,可以讀取assembly并提供烏龜畫圖的功能。這也同時展示了C#如何跟C的dll進行互操作。

                4、各種NativeX的demo。現在已經開發好的demo包含一個四則運算分析器的程序。這個程序從字符串生成語法樹(NativeX也可以利用虛函數表來模擬多態,雖然這需要人肉完成而不是語法完成),然后做各種事情。我還附帶一個四則運算分析庫的單元測試程序。另一個開發好的demo是一個猜數字游戲。程序隨機產生4個0-9范圍內的數字,然后讓你也輸入4個,告訴你命中了多少,半命中(數字對位置不對)了多少,然后一直到你放棄或者猜中為止,程序結束。

                上面已經開發好的東西已經check in在codeplex里面了,感興趣的話可以自行下載。不過那個vle.exe是以源代碼的形式存放的(不像Release,都是編譯好的東西),因此如果想要看到效果的話,需要裝有Visual Studio 2010。編譯完之后,在Tools\Release\Vlpp\和Tools\Release\Vlpp\ScriptSample\CrossAssemblyInvoking\Binary\下面有Readme.txt,會告訴你在編譯完vle.exe之后如何部署他們,使得上述的兩個NativeX demo可以編譯和運行。

                拭目以待吧,哇哈哈。
            posted @ 2011-02-19 23:29 陳梓瀚(vczh) 閱讀(3482) | 評論 (1)編輯 收藏

            流水賬。

            今年春節回家的時候帶了三本書。去年中秋節的時候外服發了200塊錢的卓越卡(啊,不是公司的,啊,說出來沒人信),我覺得自己還是個看書的人,因此買了8本書。不過我覺得自己大概不是個做文學的人,所以買的都是些什么數學啊物理的民科書。里面有本講時間的,原本以為是物理,結果是本哲學書,堅持到看完了才知道。之后8本只看了1/4本,于是到了春節。家里的電腦是02年買的,到現在就跟屎一樣,因此給家里添置了一臺。不過在這之前的三天,只能把上網的時間用來看書了,然后把這本書給解決掉了。接下來解決了那本哲學的,現在在看一本我也不知道他在說什么的。

            我是懷著一種什么心情來看書的呢?覺得不看書就如同有負罪感一般,因此總是千方百計想把它們看完??赐甑臅r候是什么感覺呢?除了接收到了知識感到欣喜以外,還有一種神奇的感覺類似“如釋重負”的感覺。我覺得很不舒服。

            對比起自己更加喜愛的編程,我突然想起在大學的時候,不寫程序也是有負罪感的,不過現在沒有了。當時其實我也很坦白,說不寫程序會有負罪感,并且引以為豪,以此證明自己是一個愛寫程序的人?,F在想起來是有點滑稽。人每天都說話,說話就是生活,但有一兩天你沒說話,你有沒有負罪感呢?想必是沒有的。沒有人會覺得一兩天不說話會對不起自己或者對不起別人。當然吃飯是不一樣的,不吃飯是會死的。寫程序對于現在的我來說就如同說話。寫程序就是生活,但是有一兩天你沒寫程序,其實也覺得沒什么,這種事常有。但是自己是不會因此就再也不寫程序的,就如同你自己不會因為一兩天不說話就永遠不說話一樣。當然如果你一兩天不吃飯,估計就永遠不吃飯了……

            那寫程序對于我是什么呢?初中的時候,覺得寫程序很有意思,自己搞著搞著總能擺弄出一點事情來,沒有理過微軟的fellow們。高中的時候,覺得寫程序是一種追求,很有遠大理想,看到了微軟主頁上的那三十多個fellow,覺得自己將來就是想成為他們一樣的人。大學的時候,覺得寫程序是一種義務,雖然自己再也不拿fellow當終極目標了,覺得修煉自己就是一種快樂,覺得反正自己的目標大概是要成為一個厲害的人的,不管將來是不是fellow都無所謂。到了現在,寫程序儼然變成了生活的一部分。自己仍然對自己有嚴厲的要求,寫出來的代碼要高性能要好改還要富有藝術感,但已經不覺得厲害不厲害是一件多么大不了的事情了。我就是寫程序,寫程序就是我,反正遲早是要厲害的,那只是時間問題,也就不執著于那個了。

            因此我現在沒有宣稱自己是喜歡寫程序的人了,而宣稱我自己就是寫程序的人。想必當年覺得“喜歡寫程序”就是自己身份的一個標簽,認為只要不寫程序,我也就不成為我,而且對不起貼在身上的標簽了。如今,程序還是在寫,但標簽已經沒了。激情在,理想在,功夫也在,程序也一直在寫。只是寫程序已經變成了自己想寫就寫,不想寫就不寫,隨心所欲的狀態了。

            因此對比起看書,說不定自己仍然很在意“喜歡看民科書”的標簽。實際上我也是這么做的,對外宣稱自己是喜歡看民科書的人,而不是看民科書的人,跟寫程序相反。所以大概會有這種感覺罷。

            想想以前也有過不少愛好,譬如4歲的時候開始的鋼琴,8歲的時候開始的看民科書。10歲的時候開始的糊變形金剛,14歲的時候開始的寫程序。堅持下來的也就是看民科書跟寫程序了。然后經歷都是差不多的,一個事情自己做得好,然后就慢慢有了追求,然后就變成了標簽,如果順利的話那個事情也就成為了生活了。

            什么時候看民科書能成為生活呢?我想能看的民科書的數量也是有限的,大概也只能當個標簽吧,說不定哪天自己寫程序寫爽了,也寫寫跟編程相關的民科書,然后就貼上了個“喜歡寫民科書”的標簽了。

            posted @ 2011-02-08 09:09 陳梓瀚(vczh) 閱讀(4236) | 評論 (13)編輯 收藏
                今天做了一整天終于優化了kd-tree和Ambient Occlusion。先上代碼,后上圖。

                首先是做了一個kd-tree,渲染一幅有一千三百多萬個三角形的圖僅需要0.4秒。


                其次是Ambient Occlusion


                第三幅是對比圖。上圖有Ambient Occlusion,下圖沒有。
             

                再加兩張(博客發布后才添加的)。算法沒變,只不過多了模型,就暫時不更新代碼了:


            posted @ 2011-01-21 22:45 陳梓瀚(vczh) 閱讀(11471) | 評論 (11)編輯 收藏
                最近休了幾天假玩一玩所以進展比較慢。直到今天我做了高亮、4*4全屏幕消鋸齒、圓柱體和三角形模型。不過目前三角形我沒有用kd-tree,所以巨慢。在i7上做一個36096個面的Menger Sponge再加上全屏幕消鋸齒花掉了20分鐘……

                點擊這里下載當前進度的代碼。

                下面開始貼圖:

                Blinn Specular:


                全屏幕消鋸齒:


                傳說中三萬多個三角形的Menger Sponge


                無聊做的圓柱體求交函數:
            posted @ 2011-01-20 09:10 陳梓瀚(vczh) 閱讀(5188) | 評論 (9)編輯 收藏

                每年總有那么幾個星期不想寫編譯器,這個時候做做ray tracing就變成一件很美妙的事情了。因此這個星期重寫了當年那個超爛的光線追蹤,然后加上了貼圖的功能。當然圖是可以直接貼在物體上的,還支持了法線貼圖,譬如說下面做的地球在不同方向的光線的照射下顯得有立體效果:


                之所以FPS有16是因為我已經不再當年那個破thinkpad上渲染,而在一個i7四核超線程三通道的CPU上做了。渲染的時候為了簡單,把屏幕等分成了八行,然后創建八個線程分別綁定到八個CPU上面去(SetThreadAffinityMask),最后渲染完出來。當然比起那些專業的還是顯得相當慢,現在很多光線追蹤軟件都用了GPU來做,不過我GPU也沒用,SSE指令也沒用,就純粹C++寫。如今也懶得用C++做GUI了,所以把核心用C++做成了之后,export幾個函數出來,用C#的P/Invoke直接調用。C++渲染完以后給一個HBITMAP,C#拿過來就往窗口上畫,還是十分方便的哈。多語言開發萬歲。

                重寫了光線追蹤之后仍然把折射和反射給做了,因此可以做出個類似凸透鏡一樣的東西:


                需要提一下的是,做貼圖的時候實現了nearest、linear和bicubic三種插值方法。nearest基本上就是不插值,所以放大了之后會有馬賽克效果。linear是線性插值,如果放得太大還是能看出一點模糊的馬賽克。bicubic效果就好很多了,如果大家有興趣的話可以到這里去看。為了達到更好的效果,后面還有計劃做ray differential和各向異性過濾。ray differential之后就可以做photon mapping(一種比較高效的全局光照模型)了。做完photon mapping之后,無聊的心情大概就結束了,可以繼續寫編譯器了吧。

                嗯嗯,雖然ray differential和photon mapping還沒做,我就先把代碼丟上啦,不僅可以做備份,大家也能搞下來看一看。當然需要有Visual Studio 2010才能編譯的。選擇release編譯之后到release文件夾下去啟動,debug的話慢的不能忍。而且我的多線程模型是一個核(超線程的話算兩個)一個線程,那些古老的雙核CPU大概性能會很慘不忍賭吧……

             

            posted @ 2011-01-08 23:54 陳梓瀚(vczh) 閱讀(6968) | 評論 (15)編輯 收藏
                根據之前的計劃,讓Vczh Library++3.0的編譯器變成語言的公共后端的同時,開放幾乎所有層的API讓人們可以從各種基礎上開發自己的DSL,所以在做完NativeX之后,接下來的事情就是寫必要程度的庫之后,做一些基礎設施讓托管語言可以被編譯到NativeX上面去。因此現在需要完成的東西有:
                1、內存池,用來實現NativeX的new和delete。這個已經做完了。下一篇文章將詳細描述這個內存池的結構。
                2、線程和同步對象。這個很快就做完了。NativeX的線程不僅需要有基本的功能,還需要做一個內置的消息循環。當一部分線程選擇使用消息循環作為它的結構的時候,其他線程就可以把一些代碼片段發送給這個線程執行了。并且要做到跟C#一樣,當線程被外部強行中止的時候,線程內部會拋出一個異常,然后讓線程自己去處理。
                3、基本的字符串和數學函數庫
                4、垃圾收集器。這個垃圾收集器是不屬于NativeX的語法的。這個垃圾收集器將被開發成一個NativeX的函數庫,用于支持更高層次語言的編譯。

                當然為了完成這個目標,我給NativeX加上了一些無關痛癢但是卻會帶來方便的語法:
                1、#public編譯選項。只要在structure、function或者variable上面標記了#public的話,這個特殊的標志就會被記錄在編譯后的二進制文件的元數據里面。NativeX現在的元數據分為兩種。第一種是運行時元數據。之前的文章提到NativeX的模板函數和其他模板的東西都是可以直接編譯進二進制文件的,因此模板函數的實例化實際上是在運行是的時候做的。不過現在我也實現了一個編譯選項(不屬于NativeX,需要用C++去控制),可以在編譯完所有二進制文件之后,將他們合并成一個大的二進制文件并且預先展開所有需要的模板函數。這一步可以用于加快運行速度,還可以為將來運行時編譯成x86或者x64做準備。當#public被記錄到元數據里面之后,編譯器就可以從編譯好的二進制文件里面重新還原出該二進制文件的頭文件。
                2、sizeof(type)、offsetof(type::member)、typeof(expression)和typeof(type::member)。這個純粹是為了配合內存池和未來的垃圾收集器而做出來的。當你需要alloc一個東西的時候,你顯然需要知道一個類型的尺寸,而這個是會跟隨著不同的情況而變化的,所以就給出了這些東西,讓編譯器幫助你計算各種跟類型相關的數字。
                3、常量定義。這個還沒實現,到時候的語法可能會是constant type name = value;。而且當他被標記上#public之后,就可以在生成頭文件的時候包含該常量了。

                為了讓C++可以給NativeX添加外部函數,我做了一個輔助類用來簡化這個過程。舉個例子,我們需要實現一個叫做MemCreate的創建內存池的函數。首先我們需要在NativeX里面聲明它:
            1 structure __ForeignHandle
            2 {
            3 }
            4 
            5 foreign function __ForeignHandle* __MemCreate()
            6     alias SystemCoreForeignFunctions.MemCreate;

                這里的alias后面的一大串是外部函數的名稱,而__MemCreate則是他對于NativeX的名稱。接下來我們就得在C++實現這個函數了:
              1 #include "ScriptingUtilityForeignFunctions.h"
              2 #include "..\Languages\LanguageRuntime.h"
              3 #include "..\..\Entity\GeneralObjectPoolEntity.h"
              4 #include "..\..\Threading.h"
              5 
              6 namespace vl
              7 {
              8     namespace scripting
              9     {
             10         namespace utility
             11         {
             12             using namespace basicil;
             13             using namespace entities;
             14             using namespace collections;
             15 
             16             class SystemCoreMemoryManagerPlugin : public LanguagePlugin
             17             {
             18             public:
             19                 struct PoolPackage
             20                 {
             21                     GeneralObjectPool                    pool;
             22                     CriticalSection                        cs;
             23 
             24                     PoolPackage(vint poolUnitSize, vint poolUnitCount)
             25                         :pool(poolUnitSize, poolUnitCount)
             26                     {
             27                     }
             28                 };
             29 
             30                 List<Ptr<PoolPackage>>                    pools;
             31                 CriticalSection                            pluginCs;
             32 
             33                 class MemCreate : public Object, public IBasicILForeignFunction
             34                 {
             35                 protected:
             36                     SystemCoreMemoryManagerPlugin*        plugin;
             37                 public:
             38                     MemCreate(SystemCoreMemoryManagerPlugin* _plugin)
             39                         :plugin(_plugin)
             40                     {
             41                     }
             42 
             43                     void Invoke(BasicILInterpretor* interpretor, BasicILStack* stack, void* result, void* arguments)
             44                     {
             45                         LanguageArgumentReader reader(result, arguments, stack);
             46                         Ptr<PoolPackage> pool=new PoolPackage(1048576256);
             47 
             48                         CriticalSection::Scope scope(plugin->pluginCs);
             49                         plugin->pools.Add(pool);
             50                         reader.Result<PoolPackage*>()=pool.Obj();
             51                     }
             52                 };
             53 
             54                 static vint MemAlloc(void* result, void* arguments)
             55                 {
             56                     LanguageArgumentReader reader(result, arguments);
             57                     PoolPackage* pool=reader.NextArgument<PoolPackage*>();
             58                     vint size=reader.NextArgument<vint>();
             59 
             60                     CriticalSection::Scope scope(pool->cs);
             61                     reader.Result<char*>()=pool->pool.Alloc(size);
             62                     return reader.BytesToPop();
             63                 }
             64 
             65                 static vint MemFree(void* result, void* arguments)
             66                 {
             67                     LanguageArgumentReader reader(result, arguments);
             68                     PoolPackage* pool=reader.NextArgument<PoolPackage*>();
             69                     char* pointer=reader.NextArgument<char*>();
             70                     
             71                     CriticalSection::Scope scope(pool->cs);
             72                     reader.Result<bool>()=pool->pool.Free(pointer);
             73                     return reader.BytesToPop();
             74                 }
             75 
             76                 static vint MemIsValidHandle(void* result, void* arguments)
             77                 {
             78                     LanguageArgumentReader reader(result, arguments);
             79                     PoolPackage* pool=reader.NextArgument<PoolPackage*>();
             80                     char* pointer=reader.NextArgument<char*>();
             81                     
             82                     CriticalSection::Scope scope(pool->cs);
             83                     reader.Result<bool>()=pool->pool.IsValid(pointer);
             84                     return reader.BytesToPop();
             85                 }
             86 
             87                 static vint MemGetHandleSize(void* result, void* arguments)
             88                 {
             89                     LanguageArgumentReader reader(result, arguments);
             90                     PoolPackage* pool=reader.NextArgument<PoolPackage*>();
             91                     char* pointer=reader.NextArgument<char*>();
             92                     
             93                     CriticalSection::Scope scope(pool->cs);
             94                     reader.Result<vint>()=pool->pool.GetSize(pointer);
             95                     return reader.BytesToPop();
             96                 }
             97 
             98                 static vint MemGetOwnerHandle(void* result, void* arguments)
             99                 {
            100                     LanguageArgumentReader reader(result, arguments);
            101                     PoolPackage* pool=reader.NextArgument<PoolPackage*>();
            102                     char* pointer=reader.NextArgument<char*>();
            103                     
            104                     CriticalSection::Scope scope(pool->cs);
            105                     reader.Result<char*>()=pool->pool.GetHandle(pointer);
            106                     return reader.BytesToPop();
            107                 }
            108             protected:
            109                 bool RegisterForeignFunctions(BasicILRuntimeSymbol* symbol)
            110                 {
            111                     return
            112                         symbol->RegisterForeignFunction(L"SystemCoreForeignFunctions", L"MemCreate"new MemCreate(this)) &&
            113                         symbol->RegisterLightFunction(L"SystemCoreForeignFunctions", L"MemAlloc", MemAlloc) &&
            114                         symbol->RegisterLightFunction(L"SystemCoreForeignFunctions", L"MemFree", MemFree) &&
            115                         symbol->RegisterLightFunction(L"SystemCoreForeignFunctions", L"MemIsValidHandle", MemIsValidHandle) &&
            116                         symbol->RegisterLightFunction(L"SystemCoreForeignFunctions", L"MemGetHandleSize", MemGetHandleSize) &&
            117                         symbol->RegisterLightFunction(L"SystemCoreForeignFunctions", L"MemGetOwnerHandle", MemGetOwnerHandle);
            118                 }
            119             };
            120 
            121             Ptr<LanguagePlugin> CreateMemoryManagerPlugin()
            122             {
            123                 return new SystemCoreMemoryManagerPlugin();
            124             }
            125         }
            126     }
            127 }

                外部函數分兩種,一種是需要全局狀態的,而另一種不需要。在不需要的時候,我提供了一個不會跟虛函數打交道的接口來加快(雖然其實可以忽略,只是為了滿足那些有畸形性能欲望的人的心理而已)運行時的性能。

                就先說到這里了。NativeX函數庫的測試用例已經開始在做了,可以去Vczh Library++3.0下載最新代碼之后,在下面的目錄找到:
                Library\Scripting\Utility\:這里是外部函數的實現。
                UnitTest\Binary\ScriptCoreLibrary\:這里是NativeX將外部函數簡單的封裝起來之后的函數庫,以及他們的測試用例。我為NativeX實現了一個簡單的單元測試框架。
                UnitTest\UnitTest\TestScripting_Utility_System_CoreNative.cpp:這個是NativeX單元測試框架的host。
            posted @ 2011-01-01 05:14 陳梓瀚(vczh) 閱讀(3887) | 評論 (7)編輯 收藏

            距離元旦也就十幾天了,2010就要過去了。從第一行Hello World到現在,已經有10年了,所幸從未中斷,因此從某種意義上來講,我已經寫了10年的程序了。每個人回顧以往走過的路的時候,往往會發現今天的結果來源于之前的一些“關鍵步驟”。顯然我也是一樣的,所以這次的總結跟以往不同,就不列出之前做過的種種程序,而是聊一聊這些關鍵步驟和影響我的人給我帶來的影響。當然算得上關鍵步驟的,只能是那些能夠左右人生軌跡的事情。

            老爸、外婆和爺爺
            這倒不是說老爸老媽把我生下來了怎么樣怎么樣。老爸在我幼小的時候教我一些簡單的數學,給了我很多書,還有外婆教我識字,結果就是我從大概二年級開始就能夠閱讀老爸留給我的一些科普讀物了。這些科普讀物是他小的時候看的,上面還有語錄,每一篇的幾位都是偉大的思想指引我們前進云云。當然這并不妨礙書本的內容的質量。老爸的書也都一直保存得很好,后來我爺爺也給我弄了一套科普的啟蒙讀物,現在還保留著,只不過很多翻爛了。這套書是翻譯的,小日本寫的,不過內容卻十分豐富。里面包含了數學、物理、生物、手工和一些其他的很多東西,甚至連汽車和飛機的結構都有。加上外婆也十分贊成并且指引我看這些書,其結果就是從小就對一些科學的事情感興趣——當然也包括數學。從三年級開始到中學,老爸就給我買一些數學奧林匹克的書。當然這并不是讓我去參加競賽用的,只是他覺得既然他小時候也喜歡搞數學那我也應該繼承這個優點,從而就讓我去弄那些東西了。在五年級的時候,那次全市的數學競賽老爸也幫了我很多,我也拿了很好的成績。維持了那么多年從不間斷的強大的自信心和信念就是從這個時候開始的。人喜歡搞一些事情很大程度上都是因為那些事情曾經被搞得很好,因此我也就喜歡上數學了,后來有機會體驗到了數學的定理和公式的美妙之處,讓我一發不可收拾。

            汕頭市華僑中學的領導們
            這是個好學校。我整個讀書的生涯,唯一一次體驗到什么是素質教育就是在這里??墒呛髞碛捎诟鞣N微妙的問題導致這所學校的競爭力下降,這從某種程度上來說算是悲哀吧。我第一次接觸到編程就是在這里。初中二年級的時候,學校開Basic的課,但是并沒有試圖讓我們參加競賽——其實連提都沒提,只是就這么當成正常的課來上。把編程學得好,滿足下面兩個條件的話基本上可以說就是在走捷徑,第一個是會從心底里對公式和定理產生美的感覺,第二個就是要持續不斷地在編程上體會到成就感。這也是我為什么在一篇寫給師弟師妹的文章里面提到剛開始的時候學習制作軟件界面也是十分重要的,因為這會讓你產生源源不斷的動力,好讓你給以后學習算法打下精神基礎。QBasic教完自然就教Visual Basic了,當然都是很淺的內容。不過我由于受到吸引,從那以后就一直往書店里面跑,去掃蕩各種跟Visual Basic有關的書,后來學到了不少。我初二在新華書店很偶然的發現了那本《Visual Basic高級圖形程序設計教程》,不過坦白說我其實是被插圖吸引的。那個時候發現Visual Basic竟然可以僅憑代碼繪制出那么漂亮的圖形,從而興趣提高了不少。不過學習這個也是很辛苦的,這導致我不得不在初三的時候就去尋找并學習立體解析幾何,高中的時候提前學習數學分析,都是為了看懂這本書啊。這本書我從初二一直看到上了大學,還帶去宿舍看,看了好多年才把它每一頁都琢磨透。這從某種程度上來說也算是緣分吧。

            英語補習老師李培濤
            初中的英語被我一不小心搞的一塌糊涂,甚至到了快不及格的地步了,所幸當時我媽(特別感謝)非得讓我找一個英語的補習老師,所以就遇到了李老師了。雖然說補習課是要交錢的,不過李老師人倒是很好,不是為了收錢而收錢,還是花了很大精力實踐了因材施教的。我的英語就被他給搞好了。我們知道英語對于編程來說是不可或缺的一個重要條件,因為中文的資料從數量或者質量上來說,都遠遠比不上英文的資料。如果英語不好,這除了阻止知識到達你的大腦里面以外,沒有好處。

            汕頭市第一中學的張朝陽老師
            高一的時候是張老師給我們上的計算機課,這個時候他告訴我們有NOI這種東西,不過我著實對算法沒什么興趣,因為那個時候我對圖形更感興趣,而且絕大多數圖形的算法都不是搜索算法,而是跟數學知識有著更直接的聯系。因此我就沒有花多少時間在算法上面了。不過其實什么時候學習算法并不重要,只要你在工作之前學了就好了。原本那個時候也想靠NOI看看能不能混個保送什么的,由于我其實也不太認真做這個,因此只好親自高考了。但是在這里我并不是說張老師教給了我什么知識,其實那段時間我都是靠自學。只不過因為我在非NOI的編程競賽里面的成績很好,所以他給我大開方便之門,讓我可以利用學校的各種資源。我們都知道萬惡的學校經常會不知不覺做出一些扼制青少年素質全面發展的事情,因此張老師給我的方便是十分重要的,包括我可以擁有機房的鑰匙以便我在任何時候可以進去使用計算機寫程序。課還是要上的,但是由于我每一年都參加NOI,所以自習課我就可以跑去機房了,寫代碼的時間也就大大增加了,這著實是十分有好處。

            CSTC的同僚們
            CSTC我現在也搞不清楚究竟他們的使命是干啥,不過印象里面就是北京工業大學的幾個寫代碼比較厲害的人搞起來的。我有幸在上高中的時候接觸到了他們,其中曾毅和唐良兩個人對我的幫助很大。曾毅告訴我為了將來的前途也好,為了自己編程能力的發展也好,搞一個好學校總是必須的。唐良是在我上了大學之后告訴我這個世界上還有《算法導論》這本書,讓我的數據結構和算法知識有了十分穩固的基礎。當然其實不會數據結構和算法并不是說你就寫不了什么復雜的程序,而只是導致你寫出來的復雜的程序質量很差性能比較低而已。在高中的時候我已經做出了一個pascal的無指針版本的解釋程序了,不過在這個時候我說實話除了鏈表以外,什么都不知道,編譯原理也不知道,所有的東西都是硬湊出來的。當然程序還是能運行的,就是寫好之后就無法再修改了,實在改不下去。

            華南理工大學的陳健老師
            高三的時候寫出來的pascal解釋器實在是讓我十分興奮,所以在剛入學不久聽說我們的班主任陳建老師教編譯原理的,我就跟她說我對這方面有興趣了,而且當時還為我的下一個解釋器寫了一個很長的設計文檔。這份文檔一開始只是寫給我自己的,后來順便就給她看了。陳老師倒是沒說什么,過了許久,給了我一本《編譯原理》。當然這不是龍書,說實話那本課本也非常糟糕,只是這讓我知道這個世界上還有這種東西,也就足夠了。大一的時候迅速看完了這本書,覺得很不爽,就把龍書搞到手,然后看了一部分。大一結束的時候就做出一個面向對象帶模板和垃圾收集的靜態類型腳本語言了,陳老師實在是功不可沒。作為老師,能教你什么是不重要的,告訴你你還有什么不會才是最重要而且最有用的。

            華南理工大學的陳天老師
            這位老師給我們上了大一的C++課,不僅功底扎實,而且可以課也講得很好,無奈在我大三的時候說是實在不行了,跑去做程序員了。我就不對這件事情作評論了。陳天老師不僅告訴了我《設計模式》是十分重要的,而且也經常鼓勵我進行更加深入的學習,對我幫助很大。

            g9yuayon
            這是個人才啊,而且編程水平也十分地令人嘆為觀止。不過他對我幫助最大的莫過于告訴我這個世界上還存在著《Parsing Techniques》了。這是世界上最好的描述語法分析的書,連龍書的前幾個章節都不如這本書講得好。當然龍書還是包含了后端的,而《Parsing Techniques》是只有前端的。不僅如此,他還給了我不少論文看。其實如果看得下去的話,論文帶來的幫助遠比算法要大得多。因為數據結構和算法真正普遍實用的也就那么幾種,其實知識量是十分少的,還比不上數學分析。既然數學分析一年就可以上完,那實用數據結構和算法其實是不需要花那么久的。不過那些更加深刻的數據結構和算法當然不在此列了——還是很多的。但是論文,是方向性十分強,而且解決的問題其實范圍更狹窄的東西。只不過如果認真研讀論文的話,可以學到很多知識以外的東西,譬如說作者是如何整理他們的結果的。遇到好心的作者的話你連他們怎么發現這個事情都可以知道。由于從小就喜歡數學,所以看論文的時候看得十分入迷,也就看得更加認真仔細了。g9yuayon介紹給我的論文的確都是十分漂亮的,在我掌握了知識的同時,又讓我的基礎變得更扎實,并且對編程也更加喜愛了。

            龔敏敏一伙
            這倒是一個共同作用的結果,也是我第一個聯系比較緊密的圈子。群里面的人都分布在各大公司,而且水平都不錯,并且都是在研究圖形學的。至于說為什么會跟他們接觸,當然是因為高中的時候對圖形學特別熱衷的關系了。雖然后來轉去做編譯器了,不過學習圖形學并不是一個浪費,因為這個漫長的過程讓我的數學知識變的扎實,而且也產生了很多題目讓我練習編寫一些至少有點小規模的程序。實踐是檢驗真理的唯一標準,這話是不錯的。

            我還要提一下LYT同學。LYT并沒有在編程上幫助我,其實是我在教LYT寫代碼,只是LYT肯讓我教那么久著實也不容易。為了教LYT學會寫簡單的編譯器,讓我不得不將我學過的知識從頭到尾整理了一遍,而且還讓我思考如何使得一個人在學會編程的同時可以保持樂趣、自信心和良好的習慣。這個過程十分有意義,不僅讓我有一個機會可以從頭整理我學會的知識,思考一些更加深刻的東西,讓自己對知識的掌握更加深刻和牢固,而且其實對被教也是有幫助的。利己利人,何樂不為。LYT經過了我三年的精心指導,從對編程什么都不知道開始,最終順利拿到了網易的offer,而且工資也沒比我低多少,實在是讓我感到十分高興。

            在我2009年7月份畢業之后就去了Microsoft而且尚未跳槽。從畢業后開始到現在這段時間現任女朋友2A同學給了我很大的支持,并沒有覺得整天宅在電腦前寫代碼看動畫片很沒前途,而且還幫忙尋找各種書帶我去書店鼓勵我等等,對此十分感謝。

            當然這并不是說其他人就對我沒有幫助,而只是沒有滿足文章一開始提出來的“左右人生軌跡”的條件而已。因為對我有幫助的人其實非常多,志同道合的朋友也不少,在這里我就不一一列舉了。

            祝各位讀者們也能夠對編程感興趣而且在這個道路上不斷堅持越走越遠。

            <><><><><><><><><><>
            后記。突然想起來我忘記寫上,其實小日本的動畫片都是一些非常具有教育意義的東西,這讓我學會了很多黑暗的社會沒有任何機會讓我知道的人生的道理。大家一定要看啊。

            <><><><><><><><><><>
            后記2。今天空明流產說他是搞圖形那一群人里面為數不多的還做做shader前端的,所以我再提一下,啊哈哈哈。

            posted @ 2010-12-18 09:17 陳梓瀚(vczh) 閱讀(10613) | 評論 (33)編輯 收藏
                時隔一個月,終于在Vczh Library++ 3.0的IDE工程里實現了用戶自定義類型變綠(抄C#的娃哈哈)鼠標移動到對象上會出tooltip、顯示函數參數提示和Code snippet的功能了。由于我的語法樹的每一個節點都包含了它在源代碼中的位置,所以鼠標指向一個字符的時候,可以計算出他在語法樹的位置,從而可以查到他的聲明的語法樹節點,再用聲明節點的位置就可以把聲明的代碼復制出來顯示在tooltip上面了:

                同樣的方法可以用來實現顯示函數參數。這個比tooltip要復雜一點,因為要吧語法樹的聲明重新組織成代碼才能顯示出來,而且還有模板函數的類型問題。不過現在有兩個小功能還沒實現,第一個是在沒輸入的時候移動光標不會更新參數,這只是個小問題。另一個是對一個函數指針調用的時候做提示,這個還要進一步考慮。下圖顯示的是對一個模板函數做參數提示的時候,參數的類型會自動特化:

                接下來就是code snippet了。Code snippet是一個強大的功能,可以讓你免除一些無謂的手指的勞動。Visual Studio里面提供了大量的code snippet,不過在這里我暫時只提供for和forr兩種,用來輸入for循環。下面是使用code snippet輸入一個for循環的全過程:











                Code snippet是一個比較復雜的功能,在這里我只實現了上下文無關的一些特性。Visual Studio里面的就更為高級了,他在插入一個類名的時候,可以根據上下文來判斷是否需要出現完整的namespace。當然由于現在我用來做intellisense的語言還沒有這么復雜的元素,所以也就無從做起了。

                所有的代碼可以在Vczh Library++ 3.0里面找到。這篇文章的代碼跟(十)的時候的代碼已經大為不同了。經過一系列的重構,intellisense功能最終被做成一個靈活的插件形式,所有的細節都可以更改,甚至連code snippet那個黃色的輸入位置都可以再往上畫東西。因為在開發intellisense的時候發現了NativeX語言語法上一個二義性,因此NativeX的語法也做了一處小修改。而且我趁著這個時候重構了所有NativeX的測試用例,把在C++里面構造語法樹改成了用一系列make file和反射函數并運行的方式直接使用NativeXProvider編譯、運行main函數并與記錄在index文件中的結果進行比較的方法。

                接下來可以做的事情就比較多了。首先我要開始完成NativeX的調試功能,其次我要拿Microsoft SQL Server那個超級復雜的T-SQL來研究一個從文法產生intellisense代碼(是的,你沒看錯,是intellisense代碼)的方法,最后要在intellisense上實現NativeX的重構。對于那個自動生成intellisense代碼的算法,目前還僅僅出于YY階段,當然生成出來的也只能是上下文無關的intellisense。譬如說幫你列出數據庫里面的所有表啦,或者幫你列出前面聲明過的變量啦,不屬于自動生成的范圍。不過自動生成的intellisense還是會告訴你“現在需要彈出變量列表,需要提供內容”的這樣一種信息來讓你可以往里面添加一些不能自動生成的東西。當然做不做得出來那是另外一回事了,先研究研究。
            posted @ 2010-12-04 18:59 陳梓瀚(vczh) 閱讀(13365) | 評論 (16)編輯 收藏

                有兩個星期沒有更新博客了,主要是最近在研究一種更靈活的代碼編輯框的框架設計,修了很多bug,還有公司的事情多了起來?,F在全部都解決了,因此開始寫這一篇博客。上一篇文章提到了我搞定了一個智能提示的原型,當然現在已經在Vczh Library++ 3.0上面添加了鼠標指向一個對象顯示聲明代碼和打括號的時候提示函數參數(部分完成)的功能了。今天來說一下我是如何實現這些功能的。當然我不會講所有細節,只會講重點,如何實現那個界面也不包括在這里。我要說的是,如何立刻知道任意一個位置所在的代碼究竟是什么東西。

                如果你沒有讀過之前的幾篇文章的話,建議去翻一翻,因為我之前提到了一些背景,還有我實現的C#版yacc(當然只是指功能,并不兼容),IDE和編譯器的語法分析器的異同和實現一個IDE用的語法分析器要注意的地方。

                語法分析總是產生語法樹或者分析樹的,無論開發什么能夠感應代碼內容的工具,都逃不過語法分析。因此可以肯定的是,在你敲代碼的時候,IDE真的在背后生成了一棵樹,只不過為了要達到普通文本框的輸入性能,很多東西都要移動到后臺去做,但是為了瞬間響應并作智能提示,有一些東西要移動到前臺做。他們之間的分界線想要界定清楚其實也不是很難。

                假設我們要編輯一份超大文件(幾萬行吧,再超過要開除的哈),每當你打字修改它的時候,一定會進行語法分析并產生語法樹。對于這么大規模的代碼要產生語法樹肯定不是瞬間就能完成的(我那個東西大概要一秒鐘多一點),因此這一步是在后臺完成的。但是當你打一個"."的時候,你肯定希望立刻就要彈出列表的內容。為了知道列表的內容,你肯定得先知道那個"."出現在了什么表達式里面,以及"."前面的那個表達式究竟是什么類型,這是離不開全文分析的。但是全文分析又太慢,所以我引入了一個技術。

                為了完成這個技術,你必須在前臺分析得到那個表達式。我們很容易就知道,我們是不可能等待后臺分析給我們提供數據的。所以在這里我們要做的是,緩存當前我們感興趣的代碼。在這里簡單化一下,如果我們只需要提供按"."彈出列表的話,我們只需要緩存語句(statement)就可以了。怎么做呢?假設我們已經可以通過所在的位置得到代碼的內容(下面會講),那么我們顯然可以知道光標的位置所在的語句的語法樹對象究竟是什么。有了這個語法樹對象,我們就可以從代碼里面直接把這個語句的代碼文字復制出來,然后緩存語句的代碼、語句所在的全文位置和語句所在的作用域。作用域是語法樹的一部分,在做完語法分析之后,只需要做簡單的語義分析建立作用域就可以計算很多東西了。這個緩存會在光標位置移動的時候更新,也會在當前的全文分析結束的時候更新。

                一旦緩存下來之后,你往里面打了一個字符,那我不僅可以更新文本框里面的內容,我還可以更新緩存里面的代碼的內容,同時還可以知道新的緩存開始結束位置。一個語句通常都是很短的,最多也就一百來個字符,因此我們立刻在前臺對它做語法分析。而且往一個語句里面打字的話,99%以上的情況是不會影響到上下文的,所以這個語句的舊作用域對象仍然可用。這個時候我們用舊的作用域對象來對新的語句做語義分析,那么就可以知道這個語句每一個表達式的類型了,從而知道了"."前面的表達式究竟是什么類型。然后利用舊作用域對象,我們就可以知道這個類型包含了多少成員。到了這一步,列表里面的對象就構造完畢了。

                然而后臺的全文分析總是會結束的,所有的信息在這個時候就準備好了,然后發個消息給前臺讓它更新緩存。兩種更新緩存都是用GUI的消息驅動的,所以不可能同時發生,只會先后發生。之前談到的臨時更新跟后臺的全文分析是并行的,不過這個不會影響我們。只要我們正確處理后臺跟前臺的信息交換,那么整個智能感應的計算過程就可以做得十分安全,不會發生死鎖。我相信這一點應該不是很難。

                那么,現在回到了兩個最原始的問題。第一個是如何通過位置查找語法樹。這個很容易解決,只要在語法分析的時候把所有跟位置有關的信息都記錄在樹里面就可以了。第二個問題是我們如何處理用戶寫錯的代碼。平時編譯原理里面所教授的自動錯誤恢復其實是不好用的,你看看VC++的編譯器在你寫錯了什么東西之后,大部分的錯誤信息基本上都沒法看,因此如何進行錯誤恢復肯定要我們自己進行精心設計。但是問題來了,我們如何實現它呢?顯然手寫語法分析器會讓我們心煩意亂根本做不下去(還要處處記得記錄位置信息……),因此我們需要一個語法分析器生成器。

                在這里我建議大家去閱讀我博客上的兩篇文章,你可以從這兩篇文章所給的鏈接看到一些其他的東西,講的是如何用組合子開發語法分析器。我這里給語法樹添加了一個新屬性,也就是一種組合起來強大但是又容易指定的錯誤恢復技術了。這里的錯誤恢復技術分為兩種,一種是針對循環的,這個大家看代碼就可以了,因為跟第二種——也就是序列關系的文法的錯誤恢復——非常相似,只是一個理論上的變換而已。

                內容是這樣的。假設我們需要分析下面的表達式:EXPRESSION + "." + MEMBER,那么我們總是希望在殘缺不全的代碼里面恢復出盡可能正確的信息。我們知道一旦出現了".",用戶想要寫的必然是一個訪問對象成員的表達式,因此我們在"."那里表上記號,變成EXPRESSION + "." + MEMBER。標記有一個副作用,也就是一旦標記所包含的語法分析成功了,那么整條語法會保證產生出指定的語法樹結構。如果用戶出現了錯誤,那么所有的錯誤都會被當成用戶少輸入了什么東西而引起的。雖然這一個假設對于編譯器來說不太合適,但是對于IDE來說顯然是合適的。但是這種做法很容易在分析列表結構的代碼里引起死循環,所以需要做很多測試來保證你的標記不會造成問題。

                下面的例子也可以輔助說明這種方法的有效性。舉個例子,你需要做一個函數。你在寫函數的過程中顯然會臨時或者不小心少些一些東西——有時候我們并不是把所有的事情都想清楚了才開始寫代碼的。這個時候為了正確分析出函數的結構,我們做下面的語法并標記:
                FUNCTION_DECLARATION ::= TYPE + NAME + "(" + list<TYPE + NAME, ","> + ")" + COMPOSITE_STATEMENT
                VARIABLE_DECLARATION ::= TYPE + NAME + optional("=" + EXPRESSION) + ";"
                然后總是保證FUNCTION_DECLARATION的優先級比VARIABLE_DECLARATION更高,我們就總是可以恢復出最正確的語法結構了。這一種做法對于你在連續輸入代碼的過程中進行正確的提示是相當好用而且方便的。

                至于代碼生成器本身怎么實現,還是去Vczh Library++ 3.0下載代碼吧。

            posted @ 2010-11-22 03:29 陳梓瀚(vczh) 閱讀(13607) | 評論 (14)編輯 收藏
            僅列出標題
            共35頁: First 7 8 9 10 11 12 13 14 15 Last 
            久久99精品国产麻豆蜜芽| 国产一区二区精品久久| 久久久久av无码免费网| 国产人久久人人人人爽| 香蕉久久永久视频| 一本一道久久a久久精品综合| 久久精品国产亚洲7777| 精品久久人妻av中文字幕| 欧美亚洲另类久久综合婷婷| 久久精品无码一区二区三区免费| 精品久久久久久久无码| 久久久久人妻一区二区三区vr| 久久久久青草线蕉综合超碰| 午夜精品久久久久久| 久久久人妻精品无码一区 | 久久久无码精品亚洲日韩按摩| 日韩精品国产自在久久现线拍 | 一级做a爰片久久毛片人呢| 久久免费视频1| 久久久久亚洲精品天堂| 精品综合久久久久久888蜜芽| 久久久久久久波多野结衣高潮 | 国产精品热久久无码av| 久久亚洲精品国产精品婷婷| 久久99精品国产99久久6男男| 97久久精品无码一区二区天美| 久久久久人妻精品一区| 色婷婷久久综合中文久久蜜桃av| 久久国语露脸国产精品电影| 欧美熟妇另类久久久久久不卡| 99久久无码一区人妻a黑| 亚洲国产成人久久精品影视| 国产毛片久久久久久国产毛片| 久久99精品久久久久久不卡| 久久93精品国产91久久综合| 国产免费久久精品99re丫y| 亚洲综合熟女久久久30p| 国产精品久久自在自线观看| 免费精品久久久久久中文字幕 | 久久婷婷五月综合国产尤物app| 99国产欧美久久久精品蜜芽|