發表文章

目前顯示的是 6月, 2010的文章

以Boost.Spirit實作算式計算機

Spirit 是開源碼C++程式庫 Boost 裡的一個項目,大量使用了C++ Template Meta-Programming實作技術。它提供了一個用來實作語言剖析器的框架,就好像lex/yacc一樣是專門用來製作語言剖析器的工具。但是Spirit因為應用了C++ Template Meta-Programming的技術,使得我們可以在C++程式碼中寫出相當於 EBNF 的描述且可直接編譯並執行,也因為如此Spirit是一套既神奇又威力強大的工具程式庫。 按照慣例,前面我們已經以 手工的方法 ,以及 lex/yacc的方式 實作了算式計算機,這次我們要使用Spirit來作個簡單的算式計算機。 EBNF表示式 雖然前面我們已經提到過Spirit的神奇的能力,也就是可以直接把EBNF式直接以程式碼的形式寫在C++程式碼內,但是因為受限於C++程式語言的語言,有些表式法需要作些調動,這裡面主要有幾個地方的語法需要注意。 A B 上面是原EBNF表示式的寫法,用來表示一個序列,A之後會有個B。而在Spirit裡需改寫成如下的形式。 A >> B 看起來沒有什麼太大的不同,也可以很容易的理解這是表示在A之後跟著B的序列。再來是*號的用法。 A* 在EBNF內,在符號A之後加個*號,表示A的數量是可重複的,可以是0個以上的A所構成的序列。而在Spirit中需改寫成如下形式。 *A 正好相反,需要把*號擺到符號的前面,因為在C++裡面並沒有任何後序式的*號運算元。不過就算改成前置式也不會影響到原來所代表的意義,並不會造成什麼衝突,容易理解。 A? 這是表示符號A是可有可無,也就是A的數量可以是0個或一個。以下改成以Spirit的寫法。 !A 如你所見到的,問號變成驚嘆號,同時也提到前面變成前置式。那麼一個以上的表示式呢?一樣使用加號,也一樣改成前置式即可,如下所示。 +A 現在來看一個簡單的範例,如下所示是EBNF式,用來表示以逗號分隔的數字的EBNF表示式。 S := INTEGER (',' INTEGER)* 改成Spirit的形式。 S = INTEGER >> *(',' INTEGER); 很直接,也不需要再多作說明。不過上面的式子還不是最終可用的版本,底下還會再陸續交待清楚。 Parser 在上面我們所看

malloc(0)的回傳值?

用VC寫個小程式作個實驗。 int *a = (int*)malloc(0); if (a)   cout << "not null\n"; else   cout << "null\n"; 程式執行的結果是, 'not null' 為什麼配置一塊大小為0的記憶體的回傳值不是NULL? 有時候要配置的記憶體大小是計算得到的,這個大小有可能為0,為了和配置失敗回傳的NULL作區分,同時也能保持程式對任何大小記憶體的處理一致,所以就讓0大小的配置也回傳個有效的指標。 不管是不是NULL,free都能接受。 ... 最後,根據 C99標準 : If the size of the space requested is zero, the behavior is implementation-defined : either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object. 所以,簡單的講,malloc(0)是沒有定義的行為。對於沒有定義的行為,去討論它是沒意義的...