發表文章

目前顯示的是 2011的文章

Lua for UEFI

圖片
利用點空閒時間將 Lua 移植到 UEFI ,作成一支Shell Application,直接執行不帶參數的話可以直接在銀幕上輸入Script,二次Enter後直接執行,執行結果立即顯示在畫面上。 按照慣例,當然要弄個Game來玩玩,所以再把Good裡的 打磚塊 範例拿來稍微改一下。 這下子,在UEFI下也能打磚塊了!

以yardparser實作算式計算機

圖片
這篇文章是算式計算機系列的完結篇。 (E)BNF表示式 手工打造算式計算機 以lex/yacc實作算式計算機 以Boost.Spirit實作算式計算機 ; ( 下載範例 ) yardparser 在使用上雖然沒辨法像Boost Spirit 一樣那麼直覺便利,可以將EBNF 語法規則直接定義在程式裡建立解析器,但使用類似的手法一樣可以將EBNF語法規則轉換為程式定義,建立一個語法解析器。yardparser也沒辨法像Boos Spirit那樣,可以在執行時期(run-time)動態的改變或產生新的解析器。除了上述的不同處之外,最大的差異是 yardparser 的編譯時間非常短及以 yardparser建立的parser執行速度非常快,同時產生的目的碼大小(code size)也相對小很多。 Boost Spirit 因為大量使用了 C++ Template Meta-programming 的相關技術,很完美的將EBNF語法規則語句嵌入到C++程式碼內和我們所寫的程式碼結合在一起,相當直覺也相當神奇。只不過如果從得到的編譯時間和執行效率來看,只能說 Boost Spirit 為我們提供了相當出色的語法糖(syntactic sugar),對於大型複雜的語法來說反而較難以適用。而 yardparser 雖然在使用上不如Boost Spirit那樣直覺便利,但至少在編譯時間和執行效率是大大滿足我們日常工作的需求。 底下同樣以簡單範例開始,介紹yardparser的基本使用。 A B 上面是原EBNF表示式的寫法,用來表示一個序列,在 A之後會有個B。而使用yardparser 則寫成如下的形式。 struct AB : CharSeq<'A', 'B'> { }; CharSeq 是 yardparser裡面事先定義好的 一個struct,作用是對輸入來源串流讀入字元來進行匹配動作。 (AB)* 以上定義了零個以上個AB序列的EBNF表示式的寫法,底下一樣轉換成yardparser的寫法。 struct StarAB : Star<AB> { }; AB是上一個例子裡定義,用來匹配 AB序列的規則。而Star是yardparser事先定義的一個struct,把A

How to debugger? (1)

圖片
許多人都說:不懂debugger的人,不會寫程式。身為一個會寫程式的程序員,我也是十分同意這句話的。想當初我也是渾渾噩噩的寫了一陣子程式之後,才知道什麼是debugger,之後果然就好像打通任督二脈一樣,突飛猛進。所以說,要會寫程式,一定要會debugger。礙於有許多新手程序員還是不懂什麼叫作debugger,所以就寫了這篇文,對debugger作一個基本的介紹,希望能對大家有所幫忙,可以像我一樣勇猛精進。 首先,由寫一個小小的測試程式開始,慢慢的再進入主題。 #include <iostream> using namespace std; int mul2(int a) {   return 3 * a; } int main(void) {   if (20 == mul2(10))     cout << "debugger讚!\n";   else     cout << "奇怪ㄋㄟ\n";   return 0; } 下面是程式執行的結果。 真是奇怪ㄋㄟ,應該是要顯示"debugger讚!"才對吧!?這個時候只好來debugger一下下了,看看問題出在那裡。 第一招,小紅點 下小紅點,也就是所謂的下斷點,也有人說中斷,或說breakpoint。在程式裡面放個小紅點,當程式跑到有小紅點的地方的時候就會停下來,這時候我們就抓到機會,可以去檢查看看各個可疑的地方,也可以偷偷竄改一些資料,無所不用其極的就是要把程式裡面的虫抓出來搞定它。 下小紅點的方法有很多種,這裡我可以告訴你四種方法。 __debugbreak(); __asm int 3 __asm _emit 0xCC 以上的方法都是手動在程式裡面放入小紅點,也就是在程式裡面塞進一個0xCC。那到底0xCC是什麼東西。去查一下x86指令集,原來0xCC就是int3。你又要問:什麼是int3?答案是:int3是個中斷,由x86硬體支援,軟體觸發。 當CPU執行指令的時候,如果執行到的指令是0xCC,也就是int3的時候,它會發出一個中斷,也就是interrupt。中斷發生的時候,CPU會暫時停止目前手上的工作,然後跳到事先準備好的中斷處理常式去執行,就跟執行副程式

充分發揮多核威力的排序法 sleep sort

程式(sleepsort.bash): while [ -n "$1" ] do   (sleep "$1"; echo "$1") &   shift done wait 執行例: user@your-c24a217e1d ~ $ bash sleepsort.bash 4 1 3 1 3 4 user@your-c24a217e1d ~ $ bash sleepsort.bash 4 2 5 1 3 1 2 3 4 5

mutable關鍵字的用法

mutable關鍵字總是會和const關鍵字扯上關係,所以要使用mutable關鍵字前,你先要知道const關鍵字的用法。const關鍵字的使用方法這裡就不提了,這是閱讀本文的基礎知識。 關鍵字const的用途很廣,這裡我們只需專注在和mutable有關係的部份即可,那就是const member function。 ; 範例1 class Sprite { public: ... int getWidth() const; int getHeight() const; ... }; 如範例所示,Sprite的getWidth和getHeight函式都是const,表示說呼叫到這二個函式的時候不會變動到任何這個Sprite物件內的資料。這是一般的情況。可是有時候我們所設計的介面,雖然在語意上它是const,但在實作上我們又不得不去變動到物件內部的某些資料。 ; 範例2 class ResourceManager { public: ... bool loadResource(string const& resName, ResourceItemHandle& item) const; ... }; 在範例中ResourceManager提供的loadResource函式,依照原始的設計,這個函式它會載入指定名稱的ResourceItem,而這個動作不會對ResourceManager內部產生任何變更。可是為了增加效率,我們在實作時在ResourceManager內部作了一個Cache的動作,把載入的ResourceItem快取起來,這樣下次再載入時就可以直接用比較快的速度完成載作動作。 這個時候就會產生如上所提到的和const衝突的情形,所以我們就只好把const修飾拿掉。拿掉const修飾字是一種解決的方法,但長遠來看這實在不是個好主意。解決的辨法是使用mutable關鍵字。 ; 範例3 class ResourceManager { public: ... bool loadResource(string const& resName, ResourceItemHandle& item) const; ... private: mutable Resourc

不可思議: for (i = 0; i < 10; i++) 停不下來 !?

圖片
其實這是一個真實事件... 某一天上班時,我從一早就三不五時的聽到坐在我背後的同事低聲的哇哇叫。幾次下來,我也忍不住好奇的湊過去看看到底是怎麼一回事。結果他Demo了這麼一個不可思議的for迴圈給我看,難怪他一整個早上都在哇哇叫。這位同事因為整個陷入在這個不可思議的for迴圈裡而跳不出來,找不到問題的所在。但當局者迷,我當下眉頭一皺發覺事情並不單純,問題肯定不是出在這個for迴圈上面,再怎麼去看也是白癈力氣。這種奇奇怪怪的問題,很有可能是和記憶體的使用有關係,這個不可思議的for迴圈只不過是因為其它地方的Bug,所產生的現象。我把我的想法告訴了我這位同事後,過了不了多久,果然在其它地方找到了真正的問題所在,的確是因為記憶體的使用不當造成的現象。 ; 底下在VC2003寫支小程式,立刻就能摸擬出這樣的現象。 int main() { int i, a[1]; for (i = 0; i < 10; i++) { a[i] = 0; } } 如上所示,我宣告了一個只有一個元素的陣列a,然後用一個for迴圈去填a的內容。這裡所要示範的一個概念是:會產生這樣的問題,是因為i的值被其它人動到了。而在這個簡單的例子,就是利用這個概念,想辨法讓在填a的內容時,因為填寫錯誤(超出範圍),而去覆寫了i的值,而造成for迴圈停不下來的奇妙現象。 如圖在除錯模式中,在Watch裡加上檢視i和陣列a的位址和內容,然後一步步執行看看。可以發現i的位址和a[3]重疊了,但問題是a只宣告了一個元素,而這個迴圈卻打算存取10個元素。在這樣的情況下,i的值果然被覆寫了,所以這個for迴圈就這樣成為無窮迴圈而永遠跳不出來。 ; PS: 這個實驗是在VC2003和2005上作的,在其它Compiler也許會有不一樣的結果。

關於最佳化

過早作最佳化是萬惡的根源 (Premature optimization is the root of all evil.) 最佳化守則 別作! (Don't do it!) 高手專用:先別作! (For experts only: Don't do it yet!)

用Java寫一個簡單的Web Server

Java的生產力很高,拿它來寫個簡單的Web Server只需要不到200行的程式碼,底下就用Java一步一步實作一個簡單的HTTP網頁伺服器。 ; 在開始前,需要對 HTTP協定 有一個基本的認識,在我們這個例子裡面,只需要知道GET請求(Request)即可。 當我們在瀏覽器的網址列輸入一個位址時,瀏覽器會送出一個GET請求到位址欄裡指定的網頁伺服器,去跟這個網頁伺服器取得網頁或檔案的內容。 例如,我們在網址列輸入 http://www.google.com.tw/ ,就是向www.google.com.tw這台伺服器要求一個檔案,而要求的檔案就是首頁(/)。 這個動作,瀏覽器會送出如下的HTTP請求命令到伺服器去 (以Chrome為例): GET / HTTP/1.1 Host: www.google.com.tw Connection: keep-alive Cache-Control: max-age=0 Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,i mage/png,*/*;q=0.5 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 ( KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10 Accept-Encoding: gzip,deflate,sdch Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4 Accept-Charset: Big5,utf-8;q=0.7,*;q=0.3 這裡的重點是第一行和最後一行。 由第一行,伺服器可以知道Client作的是那一種類的請求,這裡可以明顯的看到Client(Chrome)作了一個GET請求。同時,在第一行裡面也可以知道Client請求的是什麼。在此例中,可以看到Client請求的是/這個檔案。在第一行最後的部份,則是註明HTTP協定的版本號。 而最後一行,是一個空行,表示請求包的結束。伺服器在收到一個請求時,從第一行的請求命令開始,一直讀取到一個空行為止,為一個完整的封包。除了