2011-01-06 34 views
6

就像其他很多問題一樣,我試圖用Boost.Spirit.Qi將簡單的語法解析爲結構樹。Boost.Spirit.Qi:獲取規則的屬性並將其設置爲封閉規則的結構屬性的字段?

我會嘗試提煉出我想要做的最簡單的情況。我有:

struct Integer { 
    int value; 
}; 
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value)) 

後來,裏面的語法結構的,我有以下成員變量:

qi::rule<Iterator, Integer> integer; 

,我正與

integer = qi::int_; 

定義當我嘗試實際解析一個整數,然而,使用

qi::phrase_parse(iter, end, g, space, myInteger); 

myInteger.value總是在成功解析後未初始化。 同樣,我曾嘗試以下定義(顯然不編譯那些是錯的):

integer = qi::int_[qi::_val = qi::_1]; //compiles, uninitialized value 
integer = qi::int_[qi::_r1 = qi::_1]; //doesn't compile 
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; //doesn't 
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; //doesn't 

顯然我誤解一些有關精神,鳳凰,還是其他什麼東西。我的理解是,qi::_1qi::int_的第一個屬性,在此處應該表示解析的整數,方括號中的部分作爲函數對象執行。然後,我假設函數對象將包含integer屬性qi::_val並嘗試並將分析的整數賦值給它。我的猜測是,由於我的BOOST_FUSION_ADAPT_STRUCT調用,兩者將是兼容的,從靜態分析的角度來看,似乎確實如此,但數據並未得到保留。

是否有參考(&)指定我在某處或某處丟失?

+0

我剛剛發現,編譯,雖然它不初始化的數據導致另一種組合:我添加了一個構造函數`Integer`,需要一個值的`value` ,然後將我的整數解析器定義爲整數= qi :: long_long [qi :: _val = phx :: construct (qi :: _ 1)];` – jtolds 2011-01-06 21:31:31

+0

oops,我的意思是`qi :: int_` – jtolds 2011-01-06 21:54:42

回答

13

如果整數應該是規則所暴露的屬性,你需要將其聲明爲:

qi::rule<Iterator, Integer()> integer; 

(注意括號)。 Spirit需要使用函數聲明語法來描述規則的「接口」。它不僅用於Spirit,還用於其他一些庫(參見boost :: function)。

這樣做的主要原因是它是指定函數接口的一種簡潔方式。如果你考慮一個規則是什麼,你很快意識到它就像一個函數:它可能會返回一個值(解析結果,即綜合屬性)。此外,它可能需要一個或多個參數(繼承的屬性)。

其次,但次要的原因是Spirit需要能夠區分規則的不同模板參數。模板參數可以以任何順序指定(迭代器除外),因此它需要一些方法來確定是什麼。函數聲明語法與skipper或編碼(另外兩個可能的模板參數)有很大不同,以便在編譯時識別它。

讓我們看看你的不同的嘗試:

這可以使你改變,因爲上面列出的規則定義工作。

integer = qi::int_[qi::_val = qi::_1]; 

_val指的是你Integer,而_1int。因此,你需要從int定義賦值運算,使這項工作:

struct Integer { 
    int value; 
    Integer& operator=(int) {...} 
};      

你並不需要去適應你的類型,在這種情況下,融合序列。

但是你可以寫它更容易:

integer = qi::int_ >> qi::eps; 

這是100%的當量(EPS的是用於右手邊轉換爲解析器序列,這使得利用一招內置屬性傳播將自適應Fusion序列的元素映射到序列元素的屬性)。

此:

integer = qi::int_[qi::_r1 = qi::_1]; 

不會因爲_r1工作是指規則的第一繼承屬性。但是,你的規則沒有隱藏的屬性。

這將工作:

integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; 

,但並不需要去適應你的類型中的融合序列。

,因此將這樣的:

integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1];