摘要: 做編譯器難免會(huì)遇到如何輸出錯(cuò)誤信息的問(wèn)題。這個(gè)問(wèn)題不是那么好解決的,因?yàn)橛锌赡苣阈枰峁┲形摹⒂⑽倪€是其他什么亂七八糟語(yǔ)言的編譯器。于是就要想一種辦法讓錯(cuò)誤信息的語(yǔ)言可以很方便的切換。 由于同時(shí)提供中文和英文的編譯器其實(shí)沒(méi)什么用,中文的編譯器和英文的編譯器其實(shí)可以是兩個(gè)不同的exe,因此我想寫兩個(gè)宏,譬如說(shuō)中文.bat點(diǎn)擊了...
閱讀全文
posted @
2010-03-05 23:08 陳梓瀚(vczh) 閱讀(2505) |
評(píng)論 (2) |
編輯 收藏
今天終于讓
腳本引擎可以成功執(zhí)行int main(){return 1+1;}了,總算是讓冒煙測(cè)試過(guò)了。一開始沒(méi)那么順利,主要是因?yàn)樽蛱鞂懥艘徽齑a,犯了點(diǎn)錯(cuò)誤。
舉個(gè)例子,腳本里面有return語(yǔ)句,這個(gè)語(yǔ)句實(shí)際上是對(duì)應(yīng)到一個(gè)jump指令去,跳到函數(shù)最后面執(zhí)行一些代碼然后返回。當(dāng)代碼生成執(zhí)行到return的時(shí)候,實(shí)際上函數(shù)還沒(méi)生成完,所以不知道jump到什么地方。因此我想到一個(gè)辦法,我先把這些需要延遲填充的指令都記下來(lái),當(dāng)函數(shù)結(jié)束的時(shí)候一次性填充它們。于是我使用了下面的代碼:
1 needToReturns.Add(&ins[ins.Count()-1]);
這樣做我就把剛剛加入的那條jump指令,也就是當(dāng)前的最后一條指令的指針添加到一個(gè)列表里面去了。于是我接著處理很多代碼生成的工作,也免不了往needToReturns添加很多的其他jump指令。于是到了最后填充它們的時(shí)候了,沒(méi)有問(wèn)題發(fā)生。代碼生成結(jié)束之后,我就要把再也不需要的符號(hào)表給析構(gòu)掉,這個(gè)時(shí)候VC就報(bào)告說(shuō)釋放一個(gè)TypeInfo的時(shí)候完蛋了。
其實(shí)很明顯,錯(cuò)誤肯定不會(huì)出現(xiàn)在TypeInfo里面的,想都不用想肯定是哪里溢出了。但是自己的容器的operator[]都有溢出檢查的,不可能通過(guò)a[b]=c;的方法導(dǎo)致內(nèi)存出現(xiàn)錯(cuò)誤。最后想來(lái)想去,發(fā)現(xiàn)問(wèn)題出在上面那一行代碼里。
我們都知道,一個(gè)列表在Add的時(shí)候,他所擁有的緩沖區(qū)肯定最終都會(huì)用光,然后分配一個(gè)更大的。于是之前的&ins[x]跟之后的&ins[x]的地址肯定不一樣,于是我添加到needToReturns里面的引用就變成一個(gè)野引用了。搞定一個(gè)函數(shù)之后,我一下子填充它們,也就等于往各種各樣不同的野引用里面寫東西。剛好之后創(chuàng)建的一個(gè)符號(hào)表項(xiàng)就是某一個(gè)野引用指向的地方,于是內(nèi)容就被我破壞了,釋放它的時(shí)候當(dāng)然就出現(xiàn)問(wèn)題了。
這個(gè)故事告訴我們
1:永遠(yuǎn)不要試圖獲取容器中某一個(gè)項(xiàng)的引用。
2:就算是自己的類,有時(shí)候也會(huì)誤用的。
關(guān)于我如何執(zhí)行int main(){return 1+1;},可以在
Vczh Library++3.0的單元測(cè)試代碼(UnitTest\UnitTest\TestScripting_BasicLanguage_CodeGeneration.cpp)里面找到。
posted @
2010-02-26 19:41 陳梓瀚(vczh) 閱讀(2410) |
評(píng)論 (6) |
編輯 收藏
已經(jīng)差不多有三個(gè)多星期沒(méi)有寫博客了。這段時(shí)間主要是在休假。休假的時(shí)候?qū)懘a,跟朋友玩,去了趟廣州辦點(diǎn)事情,然后就要結(jié)束了。
Vczh Library++3.0還是一直在開發(fā)。第一層語(yǔ)言的語(yǔ)義分析基本上已經(jīng)做完了,不過(guò)還需要加一點(diǎn)功能進(jìn)去,這在代碼生成部分做了之后再做。
這次的思路比之前清晰了很多。我一直在思考如何將Javascript編譯成C#再編譯成C語(yǔ)言的問(wèn)題。當(dāng)然這說(shuō)的三種語(yǔ)言只是“類似”,無(wú)論換成python也好lua也好都是一樣的。作為一個(gè)通用的腳本語(yǔ)言開發(fā)平臺(tái),我的目標(biāo)是讓一門新語(yǔ)言可以被很快的組裝起來(lái),并在我開發(fā)的平臺(tái)上運(yùn)行,與平臺(tái)上的其他語(yǔ)言互通并共享函數(shù)庫(kù)。前者是重點(diǎn),后者是支撐。也就是說(shuō)無(wú)論怎么定位,最終都是要做成一個(gè)可以讓各種語(yǔ)言同時(shí)運(yùn)行,并讓新語(yǔ)言可以被快速開發(fā)的一個(gè)平臺(tái)。于是每一層語(yǔ)言需要支持的特性都得經(jīng)過(guò)深思熟慮才能確定下來(lái)。
因此,我的策略是為各種不同類型的語(yǔ)言開發(fā)一個(gè)元語(yǔ)言,然后通過(guò)描述一門新語(yǔ)言與相應(yīng)的元語(yǔ)言的不同之處來(lái)完成該新語(yǔ)言的開發(fā)工作。因此最近的工作主要都是針對(duì)最基礎(chǔ)的那一層——也就是面向過(guò)程非托管語(yǔ)言。在這里大概可以稱之為Native X語(yǔ)言吧。之所以叫Native X,是因?yàn)檫@玩意兒跟C語(yǔ)言還是有一些比較大的區(qū)別的。跟之前的CMinus不一樣,CMinus致力于將C(做了一點(diǎn)修改)編譯成x86的代碼,而Native X則致力于提供大多數(shù)面向過(guò)程的非托管語(yǔ)言所需要的組件,并且為面向?qū)ο蟮耐泄苷Z(yǔ)言提供必要的基礎(chǔ)設(shè)施。
在不斷地思考中,我的目標(biāo)已經(jīng)漸漸清楚了。Native X語(yǔ)言與C語(yǔ)言的差別主要有以下部分:
1、沒(méi)有宏
2、提供struct的構(gòu)造函數(shù)和析構(gòu)函數(shù)
3、提供泛型
4、提供dll級(jí)別的反射和泛型支持。
5、源代碼組織方法不體現(xiàn)在代碼里(沒(méi)有#include,或者#import之類的預(yù)編譯指令)
6、提供new和delete的變形
也就是說(shuō),今后用Native X語(yǔ)言寫的模板函數(shù)和模板類型,就算編譯進(jìn)dll也無(wú)所謂,照樣可以被其他程序拿去使用。這樣的話可以做很多事情,譬如說(shuō)實(shí)現(xiàn)pascal和basic的數(shù)組和字符串,實(shí)現(xiàn)C#的類引用等等。但是Native X語(yǔ)言同時(shí)具有操作指針和內(nèi)存的能力,雖然比較危險(xiǎn),但是可以通過(guò)上層語(yǔ)言的編譯器來(lái)確保產(chǎn)生的代碼是受保護(hù)的。這樣做的好處是在Vczh Library++3.0開發(fā)完以后,一個(gè)游戲的腳本可以大部分用Lua來(lái)寫,而且其中需要后門的一小部分代碼可以用C來(lái)寫,然后編譯在一起成為一個(gè)獨(dú)立的腳本程序,最后讓游戲去執(zhí)行它。
上面描述的功能是在抽象了很多語(yǔ)言的語(yǔ)法之后確定下來(lái)的。這個(gè)目標(biāo)在當(dāng)前進(jìn)度下實(shí)現(xiàn)了一般,也就是說(shuō)這些多出來(lái)的部分還沒(méi)做,但是C語(yǔ)言有的那一部分的語(yǔ)義分析已經(jīng)做完了,順帶搞定了一個(gè)通用的符號(hào)表雛形,還有大大簡(jiǎn)化語(yǔ)法樹以及相關(guān)算法開發(fā)的各種基礎(chǔ)設(shè)施。目前的計(jì)劃是先實(shí)現(xiàn)C語(yǔ)言有的那一部分的代碼生成,讓腳本可以運(yùn)行起來(lái),然后將上面列出來(lái)的“區(qū)別”一個(gè)一個(gè)添加進(jìn)去,同時(shí)做好unit test的工作。
最新的代碼可以在
http://vlpp.codeplex.com下載。
posted @
2010-02-23 08:59 陳梓瀚(vczh) 閱讀(2719) |
評(píng)論 (9) |
編輯 收藏
也是cppblog一位同學(xué)寫的文章,原文在
這里。
其實(shí)總的來(lái)說(shuō)這篇文章還是沒(méi)什么大的問(wèn)題,你看那五點(diǎn)粗字標(biāo)題,就是在告訴你不僅要寫好的程序,還要寫有用的程序。不過(guò)進(jìn)了公司老板很難給你寫沒(méi)用的程序的,這點(diǎn)就忽略了。緊扣著客戶的需求寫是好事,不過(guò)這跟廣大的大學(xué)同學(xué)們還是沒(méi)什么關(guān)系,所以最后一點(diǎn)就忽略了。咱慢慢看前面的四點(diǎn)。
第一點(diǎn)說(shuō)在校期間的實(shí)習(xí)是很重要的。這一點(diǎn)當(dāng)然是對(duì)的,不過(guò)下面的論據(jù)有點(diǎn)問(wèn)題。先看后面的。公司要能干活的人是真的,學(xué)計(jì)算機(jī)搞創(chuàng)新搞研究能拿獎(jiǎng)那也是真的,只是拿的是圖靈獎(jiǎng)不是諾貝爾獎(jiǎng)。這個(gè)諾貝爾獎(jiǎng)有點(diǎn)問(wèn)題啊,沒(méi)有數(shù)學(xué)沒(méi)有計(jì)算機(jī)(他老人家死得太早了,原諒他),所以數(shù)學(xué)和計(jì)算機(jī)就自立門戶了。
在校實(shí)習(xí)可以賺工作經(jīng)驗(yàn)。為什么這么講呢?(華南理工大學(xué)的師弟師妹在2009年的時(shí)候告訴我們,金山公司給實(shí)習(xí),做的東西不會(huì)拿去賣的,你們做完就完了。道聽途說(shuō),謝絕跨省。)一般大公司都會(huì)給你真刀真槍的東西。寫的代碼會(huì)被最終用戶運(yùn)行,修bug的結(jié)果也是被最終用戶運(yùn)行的。到時(shí)候會(huì)有一大堆人指導(dǎo)你該怎么做的,因?yàn)槿绻銓懙拇a太爛他們也不好意思把你的代碼拿去用是不是。
但是說(shuō)學(xué)校教的東西與社會(huì)脫節(jié)就不好了。要我是校長(zhǎng)肯定會(huì)拍案而起:“你們把學(xué)校當(dāng)成什么東西了,Java速成班?”學(xué)校教的很多東西都是基礎(chǔ)知識(shí),根據(jù)《Teach yourself programming in 10 years(想看的自己去google)》,4年是遠(yuǎn)遠(yuǎn)不夠成為一名優(yōu)秀的程序員的。我們的確需要花大量的時(shí)間在基礎(chǔ)課上面,譬如說(shuō)掌握一兩門語(yǔ)言和一點(diǎn)API讓你們可以做出真正有用的東西啦,數(shù)據(jù)結(jié)構(gòu),網(wǎng)絡(luò),數(shù)據(jù)庫(kù),編譯原理,操作系統(tǒng)原理,等等等等。但現(xiàn)在的事實(shí)是很多高三的學(xué)生們?cè)谔钪驹傅臅r(shí)候還不知道自己學(xué)了計(jì)算機(jī)就會(huì)上了賊船,所以大量的人是大一的人才開始寫代碼的。4年當(dāng)然不夠了,所以在學(xué)習(xí)基礎(chǔ)課的時(shí)候,我們還需要自己給自己出點(diǎn)難題,寫點(diǎn)代碼。在我看來(lái),
學(xué)校只需要保證一個(gè)幾乎把自己所有的時(shí)間投入到代碼中去的人能夠找到合理的工作就好了。誰(shuí)讓他花那么多時(shí)間玩游戲的(其實(shí)我也喜歡玩,但我不會(huì)沒(méi)日沒(méi)夜的,寫完代碼才會(huì)玩的),那將來(lái)結(jié)果不盡人意只能怪自己了。
需要注意一點(diǎn)的是,上面那句話最后幾個(gè)字是“合理的工作”而不是“理想的工作”。為什么呢?這跟你學(xué)了什么東西是很有關(guān)系的。找到理想的工作還要有一個(gè)前提,跟學(xué)校無(wú)關(guān)的,就是你要挖掘出自己的興趣所在。你往那方面不短拼命練習(xí),就可以保證你可以只找你喜歡的工作,找到了當(dāng)然是理想的了。如果你并不是特別喜歡寫代碼,但是也成為了一名不錯(cuò)的程序員的話,那只能說(shuō)是合理了。好工作,但你不喜歡罷了。
先總結(jié)一下,學(xué)校教基礎(chǔ),實(shí)用的自己去學(xué)。至于那些理論課有什么用,
當(dāng)你一個(gè)工程的代碼寫到了好幾萬(wàn)行而且里面絕大多數(shù)都不是用來(lái)處理UI和SQL的時(shí)候,你就能開始理解了。
第二點(diǎn),思想周密謹(jǐn)慎。文章下面只有一句話,其實(shí)說(shuō)是說(shuō)對(duì)了,只是泛泛而談也不能當(dāng)指南來(lái)看。當(dāng)然我并不是在批評(píng)作者,說(shuō)不定人家本來(lái)就不想寫指南,只是“讀者有心”罷了。
思想為什么要周密謹(jǐn)慎,因?yàn)橛?jì)算機(jī)語(yǔ)言太低級(jí),我們不得不去處理大量的其實(shí)跟我們要解決的問(wèn)題沒(méi)什么關(guān)系的細(xì)節(jié)。為了很好的掌控這些東西,就要學(xué)習(xí)學(xué)校教給你們的那些所謂與社會(huì)脫節(jié)的基礎(chǔ)課啦。就跟學(xué)數(shù)學(xué)一樣,就算你將來(lái)真的不用考計(jì)算微積分來(lái)吃飯,但好歹學(xué)那個(gè)東西還是提高了你的智商的。如果你有幸真的需要考那些基礎(chǔ)課來(lái)混飯吃的話,那你就更會(huì)體會(huì)到它們的重要性了……說(shuō)白了還是那句話,實(shí)踐出真知啊。趁著還在讀書的時(shí)候趕緊寫代碼,等到將來(lái)被HR鄙視就晚了。
第三點(diǎn),不要因?yàn)榇a簡(jiǎn)單就不想寫。文中的一個(gè)觀點(diǎn)就是,同一個(gè)東西,你寫的次數(shù)越多,你解決它的方法就越美妙。這就是為什么我們要不斷地重寫重構(gòu)的原因了,代碼速度越快,
并且越容易維護(hù)的話,將來(lái)遇到需求變更你就不用覺得自己快死了一樣。 第四點(diǎn)就不評(píng)論了。記得在Channel9看一個(gè)叫eric的老頭講解haskell的時(shí)候,他不停的說(shuō)要“Put your love in your code.”要有愛。為了能讓自己的愛發(fā)揮作用,當(dāng)然首先要讓自己寫出漂亮的代碼了。
總結(jié):不要抱怨學(xué)校,高考志愿是你自己填的。總的來(lái)說(shuō)文章的大道理還是對(duì)的,就是論據(jù)稍微有點(diǎn)什么,總之自己看著辦吧。
posted @
2010-01-31 03:44 陳梓瀚(vczh) 閱讀(5235) |
評(píng)論 (10) |
編輯 收藏
可擴(kuò)展編譯器架構(gòu)的構(gòu)想是最近幾天在洗澡的時(shí)候才最終完成的。我在思考如何開發(fā)一個(gè)可以同時(shí)給C、Pascal、Basic、Fortran和未知的
類似語(yǔ)言使用的前端+后端。這只是VL++3.0的其中一個(gè)小部分,我把語(yǔ)言歸為幾類,C一類,C#一類,Javascript一類,還有其他的等等。這些類型會(huì)分別提供不同的前端支持。在設(shè)計(jì)第一類的編譯器期間遇到了點(diǎn)困難。
第一個(gè)困難是語(yǔ)法樹很難統(tǒng)一。其實(shí)這并不是說(shuō)那些語(yǔ)言完全不同,而是在于我想讓這N種語(yǔ)言的區(qū)別只有從字符串到語(yǔ)法樹的部分,從語(yǔ)法樹開始都執(zhí)行相同的代碼來(lái)編譯。這就遇到了點(diǎn)麻煩。在語(yǔ)法分析的過(guò)程中,對(duì)于Pascal我不知道Name(Param)究竟是函數(shù)調(diào)用還是強(qiáng)制類型轉(zhuǎn)換,對(duì)于Basic來(lái)說(shuō)我不知道Name(Param)是函數(shù)調(diào)用還是數(shù)組下標(biāo)。還有Pascal和Basic的and等操作符可以同時(shí)作用于整數(shù)和布爾型(C使用了&&和&,而且它們?cè)趯?shí)現(xiàn)上有巨大差別)。Pascal自己還擴(kuò)展了一些類型譬如說(shuō)set,Pascal和Basic還有字符串。所以在語(yǔ)法分析的時(shí)候很難構(gòu)直接造出FunctionInvokeExpression、SubscribeExpression和TypeCastExpression。
第二個(gè)困難是擴(kuò)展的類型。上面提到了Pascal有自己的set,我如何讓我的編譯器從前端開始就可以應(yīng)付一門類似的未知語(yǔ)言他自己的新東西。譬如說(shuō)未知的set類型,他也有自己的操作符(連已經(jīng)存在的操作符operator+也可以用的),代碼生成的時(shí)候還有自己的方法。這不僅要求語(yǔ)法樹是可擴(kuò)展的,接下來(lái)的一切包括符號(hào)表、語(yǔ)義分析、代碼生成等所有部分都需要可擴(kuò)展的。
第三個(gè)困難是C自己造成的,他有一個(gè)十分討厭的地方。當(dāng)我得到ABC*DEF;的時(shí)候,語(yǔ)義分析沒(méi)開始,我不可能知道這是乘法還是定義一個(gè)變量。
思考了許久,得出一個(gè)大概的方案:我先定義一門比較嚴(yán)格的語(yǔ)言,然后讓C、Pascal、Basic和Fortran來(lái)定義自己
與該語(yǔ)言的不同之處,從而盡可能復(fù)用編譯器其余相同的部分。想到這里我得到一個(gè)比較奇怪的做法:
第一個(gè)做法是在語(yǔ)義分析的時(shí)候修改語(yǔ)法樹。對(duì)于C語(yǔ)言的ABC*DEF;,這是一個(gè)statement。我給出一個(gè)接口,這個(gè)接口在語(yǔ)義分析的過(guò)程中被調(diào)用。語(yǔ)義分析產(chǎn)生了大量的信息全部傳遞過(guò)去,然后再第一次接觸到一個(gè)statement的時(shí)候,調(diào)用其中的ReplaceStatement函數(shù)。這個(gè)時(shí)候接口的ReplaceStatement可以通過(guò)語(yǔ)義分析的結(jié)果看看需不需要修改這個(gè)節(jié)點(diǎn)。如果上下文是int a,b;,那么a*b;就會(huì)被替換為乘法表達(dá)式。如果上下文是typedef int a;,那么a*b;保持不變(因?yàn)槲夷J(rèn)是優(yōu)先看成變量聲明)。ReplaceStatement對(duì)于同一個(gè)statement只會(huì)調(diào)用一次。至于Pascal的集合操作也可以通過(guò)這個(gè)來(lái)完成。對(duì)于a+b,可以在ReplaceExpression里面查看a和b是不是集合類型,如果是的話替換成自己的PascalSetBinaryExpression。這個(gè)小技巧解決了語(yǔ)法分析的時(shí)候遇到的歧義問(wèn)題。這也是沒(méi)有辦法的辦法,因?yàn)檫@一次設(shè)計(jì)出來(lái)的結(jié)構(gòu)的目的是為了讓新的語(yǔ)言可以用很小的代價(jià)來(lái)實(shí)現(xiàn)。
第二個(gè)做法是語(yǔ)法樹的所有部分譬如Type、Expression、Statement和Declaration都存在一個(gè)ExtendedType、ExtendedExpression、ExtendedStatement和ExtendedDeclaration,語(yǔ)言可以通過(guò)繼承這四個(gè)“擴(kuò)展類”來(lái)提供未知的東西,當(dāng)然這個(gè)時(shí)候就要連帶提供所有操作了,譬如說(shuō)根據(jù)語(yǔ)義分析的上下文來(lái)判斷他自己的ExtendedExpression的返回類型啦。
至于符號(hào)表的可擴(kuò)展性,我設(shè)計(jì)了一個(gè)可以應(yīng)付絕大多數(shù)情況的通用符號(hào)表,因此隨時(shí)加入新的東西還是比較容易的。
最新的代碼可以在
http://vlpp.codeplex.com/這里獲得。
posted @
2010-01-31 00:13 陳梓瀚(vczh) 閱讀(2459) |
評(píng)論 (5) |
編輯 收藏
開源了之后反而就不是很想寫開發(fā)紀(jì)事了,因?yàn)槊恳淮蝐heck-in到服務(wù)器上都會(huì)寫幾句描述,就有了一種已經(jīng)公布了進(jìn)度的錯(cuò)覺。Codeplex加上Visual Studio Team Foundation System真是方便,不像其他的源碼管理系統(tǒng)一樣要配置到半死,還要到命令行里面搞來(lái)搞去,好不容易找到一個(gè)UI插不進(jìn)Visual Studio,好不容易找到一個(gè)能插的老是要掛。
但是開源了之后就不好意思不寫文檔了。把自己的代碼放上網(wǎng)的另一個(gè)好處就是總是覺得會(huì)有很多人來(lái)看,所以還是要寫點(diǎn)文檔介紹介紹。Codeplex是英文的,文檔還不能只有中文。而且自己認(rèn)識(shí)的很多程序員是說(shuō)中文的,文檔也不能只有英文。結(jié)果干脆就維護(hù)起了雙語(yǔ)文檔。不過(guò)雙語(yǔ)文檔真是麻煩啊。現(xiàn)在沒(méi)看到什么文檔生成工具可以產(chǎn)生多種語(yǔ)言(指自然語(yǔ)言)的文檔的,而且格式還不好看(想象一下Doxygen的東西,全都是參差不齊的表格,不知道從哪里下手看啊),因?yàn)槲臋n除了介紹每一個(gè)函數(shù)的作用以外,還要有編程指南。其實(shí)有些函數(shù)用指南來(lái)寫反而比單獨(dú)的介紹函數(shù)的返回值參數(shù)什么的要好得多。特別是C++。
現(xiàn)在Vczh Library++3.0的Core Library應(yīng)該算成型了,于是在做腳本引擎的部分。我打算把腳本引擎分為若干個(gè)模塊。首先是基礎(chǔ)語(yǔ)言的中間指令集,其實(shí)就像是專門為C語(yǔ)言設(shè)計(jì)出來(lái)的指令集。其次是基礎(chǔ)語(yǔ)言的語(yǔ)法樹,這次的語(yǔ)法樹的類型規(guī)則要足夠簡(jiǎn)單,因?yàn)橹饕怯脕?lái)給高級(jí)語(yǔ)言的編譯器產(chǎn)生輸出的。第三是一門類似C#(當(dāng)然這只是個(gè)比喻)的語(yǔ)言,然后把這個(gè)語(yǔ)言的語(yǔ)法樹轉(zhuǎn)換為C語(yǔ)言的語(yǔ)法樹。想來(lái)想去之前 CMinus的失敗其實(shí)并不是說(shuō)高級(jí)語(yǔ)言語(yǔ)法樹不能轉(zhuǎn)換為C語(yǔ)言的語(yǔ)法樹,而是設(shè)計(jì)出來(lái)的語(yǔ)法樹太強(qiáng)大了反而不好拿來(lái)生成。最后就是動(dòng)態(tài)語(yǔ)言了。
這次做出來(lái)的應(yīng)該是一個(gè)框架,我提供一大堆工具輔助開發(fā)語(yǔ)法分析器,然后底下有一層把虛擬機(jī)的事情全都給做了。于是就可以在上面用非常小的代價(jià)來(lái)實(shí)現(xiàn)各種各樣的語(yǔ)言了。
現(xiàn)在基礎(chǔ)語(yǔ)言的中間指令集算是搞定了,當(dāng)然只剩下一點(diǎn)點(diǎn),不過(guò)這個(gè)在后面的東西完成之前沒(méi)法繼續(xù)寫。C語(yǔ)言的編譯器正在搞,我提供了一大堆的工具讓人們可以在C++里面漂亮的拼出語(yǔ)法樹,然后可以執(zhí)行。當(dāng)然以后還可能會(huì)有專門的語(yǔ)法分析器和代碼生成器來(lái)在一些語(yǔ)言和這個(gè)語(yǔ)法樹之間進(jìn)行轉(zhuǎn)換,不過(guò)這也僅僅是為了調(diào)試用的,因?yàn)橐獙?shí)現(xiàn)的語(yǔ)言其實(shí)是一門類似C#的高動(dòng)態(tài)和靜態(tài)結(jié)合的語(yǔ)言的語(yǔ)法樹。
但是開發(fā)一個(gè)語(yǔ)法樹是相當(dāng)麻煩的,因?yàn)檎Z(yǔ)法樹基本上就是幾套大規(guī)模繼承類的組合,然后要給他們寫各種各樣的虛函數(shù),每一次要修改虛函數(shù)的參數(shù)表的時(shí)候都是大動(dòng)干戈。于是今天早上開發(fā)出了一堆宏,用來(lái)方便地寫語(yǔ)法樹的visitor(這幾乎是處理語(yǔ)法樹的唯一辦法),萬(wàn)一遇到需求變更,改起來(lái)更加方便。代碼在Library\Scripting\Common\AlgorithmDeclaration.h,還附帶有一個(gè)TestCase,在UnitTest\UnitTest\TestScripting_BasicLanguage.cpp里面。
接下來(lái)就可以開發(fā)C語(yǔ)言語(yǔ)法樹到中間指令集的轉(zhuǎn)換了,然后一層一層做下去。最后要是有空,把最低下的中間指令集拿來(lái)一x86,整個(gè)瞬間就變成JIT了。
posted @
2010-01-09 23:37 陳梓瀚(vczh) 閱讀(2410) |
評(píng)論 (1) |
編輯 收藏
最近在公司寫了一大堆復(fù)雜的界面,終于體會(huì)到了前輩們那種上刀山下火海的感覺了。做完了之后回頭想想,MVC還是有道理的。
什么是MVC?其實(shí)可以簡(jiǎn)單的理解為一個(gè)有UI的程序可以劃分為三個(gè)部分:數(shù)據(jù)層、邏輯層和應(yīng)用層。當(dāng)然這些名字是我亂起的。數(shù)據(jù)層顧名思義就是用來(lái)讀寫數(shù)據(jù)的地方,譬如說(shuō)一個(gè)電話本的文件。邏輯層就是用戶在界面上的操作的抽象,譬如說(shuō)要通過(guò)名字來(lái)查找消息啦,給一個(gè)關(guān)鍵字求得篩選后的電話信息列表啦。應(yīng)用層指的就是那一堆控件了。MVC三個(gè)字母分別指的是Model、View和Controller,也就是模型、視圖和控制器了,分別對(duì)應(yīng)于數(shù)據(jù)層、應(yīng)用層和邏輯層。
以前在看MVC的時(shí)候總是被一些教條主義的東西迷惑,說(shuō)什么在MVC里面,MV解耦,所以M可被替換,V也可被替換。這個(gè)時(shí)候往往會(huì)感到迷惑。為什么模型,或者說(shuō)數(shù)據(jù)層要被替換?為什么視圖,或者說(shuō)界面要被替換?其實(shí)這在一個(gè)不是復(fù)雜到神級(jí)級(jí)別的程序里面是不會(huì)發(fā)生的。但是MVC并不是為了讓你能夠?qū)崿F(xiàn)模型被替換或者試圖被替換而產(chǎn)生出來(lái)的,我覺得這個(gè)模式(其實(shí)這不是設(shè)計(jì)模式的其中一項(xiàng),真的)更加重要的特點(diǎn)是可以讓你的程序?qū)懫饐卧獪y(cè)試來(lái)更加容易。
還是電話本,現(xiàn)在有一個(gè)要求,說(shuō)在輸入人的名字之后,只要系統(tǒng)檢查出你超過(guò)0.5秒沒(méi)有持續(xù)輸入,那么底下的列表就會(huì)自動(dòng)根據(jù)你上面的輸入進(jìn)行篩選。其實(shí)這有點(diǎn)像Outlook。這要怎么寫單元測(cè)試?我們知道雖然正規(guī)的測(cè)試會(huì)有一大堆用來(lái)自動(dòng)完成界面操作的工具啊,或者類庫(kù),但是作為單元測(cè)試來(lái)講我們并不需要去做這種事情。因?yàn)閱卧獪y(cè)試是程序員寫的,凡是程序員寫的東西當(dāng)然是需要盡快得到結(jié)果的。一般的開發(fā)方法是寫一點(diǎn)代碼,寫一點(diǎn)測(cè)試,跑,有bug改沒(méi)有bug繼續(xù)。我們?cè)陂_發(fā)程序的時(shí)候會(huì)不斷地、頻繁地跑單元測(cè)試,來(lái)看看我們的東西是不是有問(wèn)題,或者在重構(gòu)的時(shí)候我們對(duì)于我們的代碼正確的信心會(huì)大一點(diǎn)。
那界面怎么辦呢?難道我們真的要去引入一個(gè)庫(kù)來(lái)搞界面的自動(dòng)測(cè)試嗎?當(dāng)然想要也可以,不過(guò)這畢竟太復(fù)雜,而且這一類的工具的穩(wěn)定性其實(shí)都不是特別好,被誤導(dǎo)的幾率倒是大增。這僅僅是對(duì)于程序員來(lái)講的,當(dāng)然搞測(cè)試的那些人自有他們的辦法。那既然我們不做界面的自動(dòng)測(cè)試那怎么知道文本框被輸入之后究竟篩選出來(lái)的數(shù)據(jù)對(duì)還是不對(duì)呢?
答案:MVC。
為什么View,也就是試圖,也就是界面,可以被替換是一件很重要的事情?想一想,如果控件可以被換成單元測(cè)試的一段代碼,那豈不是很爽么?舉個(gè)例子,我們要告知用戶說(shuō),我們的事情已經(jīng)做了一半了,這個(gè)時(shí)候我們可能會(huì)去設(shè)置進(jìn)度條的位置。但是“告訴用戶說(shuō)我們的事情已經(jīng)做了一半”跟“設(shè)置進(jìn)度條的位置”其實(shí)是完全無(wú)關(guān)的兩件事情。因此我們的Controller要負(fù)責(zé)通知View說(shuō)事情做了一半了,然后View就可以去設(shè)置進(jìn)度條的位置了。現(xiàn)在我們把View換成單元測(cè)試的一段代碼,這個(gè)時(shí)候就變成Controller通知測(cè)試程序說(shuō)事情已經(jīng)做到一半了,然后測(cè)試程序就會(huì)去檢查說(shuō)現(xiàn)在是不是應(yīng)該做到了一半,如果應(yīng)該,顯然這個(gè)用例就通過(guò)了。
那Model呢?Model可以簡(jiǎn)單的理解為數(shù)據(jù)源,其實(shí)當(dāng)然不只是那么簡(jiǎn)單,不過(guò)這樣理解會(huì)讓我們更容易接受一點(diǎn)。數(shù)據(jù)源是什么,當(dāng)你寫單元測(cè)試的時(shí)候,去連接一個(gè)數(shù)據(jù)庫(kù)來(lái)獲得數(shù)據(jù)源,然后就操作Controller,這個(gè)時(shí)候你如果不親自去讀一下數(shù)據(jù)庫(kù),你怎么知道Controller給你的東西究竟是對(duì)的還是錯(cuò)的?顯然Model我們也可以換掉,測(cè)試程序偽造數(shù)據(jù)成為一個(gè)Model,然后插入Controller,事情就解決了。數(shù)據(jù)是我們自己給的,那Controller應(yīng)該提供什么我們也能知道了。
于是,使用了MVC之后,單元測(cè)試想換Model就換Model,想換View就換View,測(cè)試什么就非常容易了。至于說(shuō)用戶停止輸入0.5秒之后是不是會(huì)真的去進(jìn)行數(shù)據(jù)的篩選,這個(gè)我們手工測(cè)試就好了,而且那些搞測(cè)試的人也會(huì)幫我們檢查的。
好吧,說(shuō)到這里有人可能會(huì)問(wèn)為什么我沒(méi)有給出一個(gè)Demo?這東西太虛,實(shí)踐實(shí)踐自己體會(huì)一下就行了,而且MVC變形那么多,有Model-View-Presenter,還有最近興起的Model-View-ViewModel等等,其實(shí)現(xiàn)都跟傳說(shuō)中的那個(gè)類似橋接模式的東西差別甚遠(yuǎn)。這個(gè)自己去看一看就好了。
posted @
2010-01-08 03:58 陳梓瀚(vczh) 閱讀(5068) |
評(píng)論 (9) |
編輯 收藏
zero = \s.\z.z
succ = \a.\s.\z.a s (s z)
add = \a.\b.a succ b
mul = \a.\b.a (add b) zero
pow = \a.\b.a (mul b) (succ zero)
true = \a.\b.a
false = \a.\b.b
if = \c.\t.\f.c t f
not = \a.a false true
and = \a.\b.a b false
or = \a.\b.a true b
xor = \a.\b.a (not b) b
pair = \a.\b.\c.c a b
fst = \p.p true
snd = \p.p false
const = true
iszero = \n.n (const false) true
pred = (\pack.\packpred.\n.snd (n packpred (pack n))) (\n.pair zero n) (\n.iszero (fst n) (pair (succ zero) (snd n)) (pair (succ zero) (pred (snd n)))
sub = \a.\b.b pred a
eq = \a.\b.and (iszero (sub a b)) (iszero (sub b a))
ne=\a.\b.not (eq a b)
lt = \a.\b.and (iszero (sub a b)) (not (iszero (sub b a)))
le = \a.\b.or (eq a b) (lt a b)
gt = \a.\b.not (le a b)
ge = \a.\b.not (lt a b)
div = (\init.\step.\a.\b.add (fst (a step (init a b))) (fst (b step (init b a)))) (\a.\b.pair zero (pair a b)) (\i.(ge fst(snd i)) (snd (snd i))) (pair (succ (fst i)) (sub (fst (snd i)) (snd (snd i))) (snd (snd i))) i)
empty = pair zero zero
cons = \a.\b.pair (succ zero) (pair a b)
isempty = \l.iszero (fst l)
head = \l.fst (snd l)
tail = \l.snd (snd l)
Y=\f.(\t.f (t t))(\t.f (t t))
foldr = Y (\self.\f.\e.\l.(isempty l) e (f (head l) (self f e (tail l))))
length = \l.foldr (true succ) zero l
sum = \l.foldr add zero l
product - \l.foldr mul (succ zero) l
append = \h.\l.foldr cons l h
reverse = \l.foldr (\a.\b.append b (const a empty)) empty l
map = \f.\l.foldr (\a.\b.cons (f a) b) l
zip = Y (\self.\a.\b.(or (isempty a) (isempty b)) empty (cons (pair (head a) (head b)) (self (tail a) (tail b))))
flatten = \l.map append l
posted @
2009-12-24 08:55 陳梓瀚(vczh) 閱讀(2489) |
評(píng)論 (4) |
編輯 收藏
今年事情比較多,第一個(gè)是自己終于從本科畢業(yè)了,第二個(gè)是自己找到了工作,拿了一份offer。雖然當(dāng)初為了去Microsoft實(shí)習(xí)錯(cuò)過(guò)了一大堆其他公司的面試機(jī)會(huì),只投了Microsoft,Google和百度。不過(guò)最后還是進(jìn)了Microsoft,在這危機(jī)四伏的日子里,雖然說(shuō)自己寫了10年代碼總歸有點(diǎn)功力,但是也有運(yùn)氣的成分在。只是面試百度的時(shí)候我明明在簡(jiǎn)歷上寫了我人在上海,他非要我飛回廣州面試,很不爽,拒了他。
去年下半年幾乎都投身Microsoft的實(shí)習(xí),到了12月上旬回學(xué)校,于是從今年的元旦開始其實(shí)就是在學(xué)校里面混日子了。其實(shí)還好,完成了一個(gè)
閹割版的Haskell編譯器當(dāng)畢業(yè)設(shè)計(jì),還做了一個(gè)
C語(yǔ)言編譯到機(jī)器碼寫入內(nèi)存的編譯器,最后
重寫了Vczh Library++3.0,還把它
開源了,雖然還沒(méi)最終完成。不過(guò)開源了之后就得補(bǔ)文檔了,因此近期的開發(fā)進(jìn)度可能會(huì)慢一點(diǎn)。
回想大學(xué)四年,還是寫了不少代碼的,也足夠拼成一張至少可以留住HR眼球的簡(jiǎn)歷了。當(dāng)初比較大的轉(zhuǎn)變是我剛上大一,可憐的Borland就不行了,于是很喜歡的Delphi看來(lái)也有危機(jī)了,所以轉(zhuǎn)去C++。幸好所學(xué)的知識(shí)并不是綁定在Delphi的平臺(tái)上,因此剛開始也只覺得是換了個(gè)語(yǔ)法。不夠C++實(shí)在是博大精深,里面可以用各種各樣的范式寫代碼,比較突出的是元編程,雖然這種東西在現(xiàn)實(shí)生活中重要性不言而喻不過(guò)所占比例還是很小的。
于是開始拿C++練手了。高中的Delphi時(shí)代寫了不少游戲,積累了一個(gè)2D的游戲引擎,其實(shí)也不復(fù)雜,不過(guò)好歹也到了3.0了,里面有圖形圖像、音效、數(shù)據(jù)管理、腳本引擎,還有一個(gè)UI。因此C++上手了之后,自然是移植它了。移植的過(guò)程中發(fā)現(xiàn)C++的寫法跟Delphi還是截然不同,因此Vczh Library++ 1.0基本上是失敗告終,雖然那個(gè)Delphi的游戲引擎大部分都實(shí)現(xiàn)了。在開發(fā)的途中我曾經(jīng)寫了一個(gè)模仿顯卡固頂管線的3D軟件渲染器,不過(guò)最后一個(gè)Demo應(yīng)該是在大二,用OpenGL實(shí)現(xiàn)了3D模型的骨骼動(dòng)畫,用的好像還是Halflife 1的幾個(gè)模型,什么鳥啊,僵尸啊,警察啊。后來(lái)覺得實(shí)在是找不到美工,而且自己還有一項(xiàng)喜歡的,也就是寫編譯器了,所以干脆就集中力量搞編譯器吧。
第一個(gè)見得人的編譯器應(yīng)該是
Vczh Jove Script了。這個(gè)東西閹割了Java,然后實(shí)現(xiàn)了一次,主要是針對(duì)OOP,有繼承,有虛函數(shù),還有泛型。當(dāng)然泛型我實(shí)現(xiàn)了跟C#一樣的參數(shù)約束,也就是可以指定說(shuō)某個(gè)類型參數(shù)必須繼承與另一個(gè)類。數(shù)組使用引用計(jì)數(shù),其他的都垃圾收集。當(dāng)然最后發(fā)現(xiàn)數(shù)組用引用計(jì)數(shù)是不對(duì)的,會(huì)導(dǎo)致垃圾收集。
之后我就對(duì)計(jì)算機(jī)的理論燃起了熱情了,首當(dāng)其沖當(dāng)然是編譯原理。當(dāng)時(shí)受到了CSDN上那個(gè)袁泳的一點(diǎn)指導(dǎo),其實(shí)主要不是技術(shù)上的,是方向上的,后來(lái)給我看了一本很厲害的書叫《Parsing Techniques》。很多知識(shí)都從這里面吸收了,然后就要開刀,當(dāng)然是從最簡(jiǎn)單的正則表達(dá)式引擎下手。第一次寫還是有點(diǎn)別扭,到現(xiàn)在一共寫了三次,其中第二次是在第一次寫完了之后覺得很不爽立刻重寫的。寫完了就輪到Syngram,是一個(gè)將文法寫進(jìn)C++然后自動(dòng)變成語(yǔ)法分析器的小庫(kù)。當(dāng)然后來(lái)也重寫了。
上面的事情完成了之后就著手
Vczh Free Script的開發(fā)了。這是一個(gè)“純”動(dòng)態(tài)語(yǔ)言。為什么說(shuō)純呢,因?yàn)槲覉?jiān)持所有東西匿名(包括類定義,其實(shí)結(jié)果就是返回一個(gè)類型,像C#的System.Type,然后可以到處傳),所以為了給一個(gè)東西命名就寫一個(gè)賦值語(yǔ)句。當(dāng)然不僅如此,我還實(shí)現(xiàn)了函數(shù)閉包,然后將之后的所有特性譬如說(shuō)動(dòng)態(tài)的Multiple Dispatch(虛函數(shù)是Single Dispatch)啊,namespace啊,類和繼承什么的統(tǒng)統(tǒng)編譯到函數(shù)閉包上,整個(gè)語(yǔ)言是匿名的。當(dāng)然我還是把它是實(shí)現(xiàn)成一個(gè)C++的類庫(kù),如果你愿意在我的接口下面寫插件的話,就可以跟Python一樣直接應(yīng)用到你自己的工程里面去了。
在這個(gè)過(guò)程中我學(xué)習(xí)了很多關(guān)于編程語(yǔ)言方面的基礎(chǔ)理論,還學(xué)了一點(diǎn)數(shù)學(xué)雖然我還是覺得數(shù)學(xué)有點(diǎn)難度。完了之后就開發(fā)一個(gè)小型的IDE,其亮點(diǎn)是就算代碼是動(dòng)態(tài)生成的,我也能捕捉到然后給你單步調(diào)試。不過(guò)這個(gè)由于穩(wěn)定性并不是非常好,第一次將C++跟C#混起來(lái)用還是有點(diǎn)力不從心,因此就沒(méi)拿出來(lái)貢獻(xiàn)給大家了。
之后就開始Microsoft的實(shí)習(xí)之旅了,在實(shí)習(xí)的過(guò)程中我首先封裝了一次win32api的GUI部分,盡量達(dá)到跟Delphi一樣好用,于是有了這個(gè)
Demo,然后做了閹割版Haskell——也就是Kernel FP了。當(dāng)初叫這個(gè)名稱我只是想看看實(shí)現(xiàn)一個(gè)最小的純函數(shù)式語(yǔ)言的內(nèi)核要怎么辦,要包含多少功能(當(dāng)然是越少越好,其他的都是語(yǔ)法糖或者庫(kù),不過(guò)不能讓能力下降)。后來(lái)又看了一本書好像叫做《The Implementation of Functional Programmang Languages》,也很好看,學(xué)到了很多東西。
于是2008年就結(jié)束了,進(jìn)入2009年,做了一個(gè)CMinus,可以把C語(yǔ)言編譯到內(nèi)存里面,搞成x86的機(jī)器碼,然后就能將一個(gè)寫了代碼的txt文件變成一個(gè)函數(shù)指針了。然后就畢業(yè)了。
7月13日開始入職Microsoft,雖然說(shuō)是在開發(fā)界面,不過(guò)我還是覺得需要自己仍然保持熱情,于是工作結(jié)束之后自己要繼續(xù)寫自己的代碼,也就是Vczh Library++ 3.0了。上面做了很多4個(gè)編譯器,剛好針對(duì)語(yǔ)言的4中特性,這次看看能不能把它們綜合起來(lái),變成一個(gè)真正有用的腳本引擎。當(dāng)然這不是重復(fù)勞動(dòng)了,畢竟自己實(shí)現(xiàn)給自己帶來(lái)的質(zhì)的提高會(huì)比你純粹用別人的要高很多。但至于最后怎么辦,其實(shí)我還是覺得.NET的潛力比較大,總之挑戰(zhàn)它是不明智的,但我還是想自己試一試。
從第一個(gè)QBasic的Hello World到現(xiàn)在也差不多要10年了,初中因?yàn)椴恍⌒哪玫搅吮綫Basic的書然后戲劇性地開始了我程序員的人生,所幸中間沒(méi)有間斷過(guò),而且也將對(duì)一貫來(lái)編程的激情很好的保存了下來(lái),有增無(wú)減。至于說(shuō)30歲(其實(shí)日本說(shuō)的是35歲)就要轉(zhuǎn)管理什么的,我還是不太相信,或者說(shuō)我愿意就做一線的開發(fā)人員,或者架構(gòu)師(當(dāng)然這個(gè)跟通常意義上的架構(gòu)師還是不一樣的,有朝一日真的給我做了,我還是想跟一線的程序員一起寫代碼)。管理還是不適合我,畢竟我對(duì)錢(或者是權(quán)力?)沒(méi)那么渴望,夠花就好了,雖然我自己沒(méi)多少錢。
總之,要有激情,無(wú)論是對(duì)什么事情。剩下的就是要追求快樂(lè),不同的人對(duì)快樂(lè)的定義還是不一樣的,不過(guò)我目前只要能寫有挑戰(zhàn)性的代碼,我就會(huì)覺得很快樂(lè)了。工作了之后因?yàn)樵谏虾#查g感到了房?jī)r(jià)的壓力。只是如果要我犧牲寫代碼的時(shí)間和樂(lè)趣去換取那些所謂的財(cái)產(chǎn),我還是不太愿意的。
posted @
2009-12-23 05:22 陳梓瀚(vczh) 閱讀(14821) |
評(píng)論 (40) |
編輯 收藏
項(xiàng)目主頁(yè):
http://vlpp.codeplex.com/ Vczh Library++從2006年就開始開發(fā),到現(xiàn)在經(jīng)歷了一些版本變遷,到現(xiàn)在已經(jīng)正式步入3.0了。現(xiàn)在Vczh Library++ 3.0的基礎(chǔ)部分已經(jīng)成型,我的目標(biāo)是將Vczh Library++ 3.0做成一個(gè)在性能不是極端苛刻情況下使用的數(shù)據(jù)處理庫(kù),附帶一個(gè)高速的腳本引擎。未來(lái)可能會(huì)提供更多的東西,但主要圍繞著這兩個(gè)目標(biāo)走。
我選擇CodePlex主要是因?yàn)镃odePlex支持Team Foundation System,這個(gè)系統(tǒng)跟Visual Studio 2008結(jié)合的相當(dāng)好,提交更改都非常方便。而且CodePlex也提供SVN服務(wù),一些不喜歡IDE的大大們也可以用SVN來(lái)下載代碼。
至于為什么上面的描述是英文的,因?yàn)樵诿赖酃玖?xí)慣了……
posted @
2009-12-13 03:21 陳梓瀚(vczh) 閱讀(4811) |
評(píng)論 (18) |
編輯 收藏