2012-12-04 39 views
2

我試圖讓Boost.Spirit來解析MSVC強化符號。這些格式如下:在開始之前解析一個短語的末尾在Boost.Spirit

[email protected]@@2HC 這意味着「volatile int myclass :: myvolatileStaticMember」。

解析的「關鍵」是符號「@@」處的雙精度值。 @@之前是由C++標識符組成的符號名稱,後跟零個或多個「@」個附加標識符,以在其絕對名稱空間層次結構中完全表示該符號。將@@是什麼樣的標識符是(變量,函數等)

現在說明書之後,我可以得到Boost.Spirit解析後@@的部分之前的部分@@。我還沒有弄清楚如何讓Boost.Spirit找到@@並將之前發生的事情提供給一個自定義分析器,以及之後到達另一個自定義分析器的內容。

這裏是我的解析器的一部分@@前面:

// This grammar is for a MSVC mangled identifier 
template<typename iterator> struct msvc_name : grammar<iterator, SymbolType(), locals<SymbolType, string>> 
{ 
    SymbolTypeDict &typedict; 
    void name_writer(SymbolType &val, const string &i) const { val.name=i; } 
    void dependent_writer(SymbolType &val, const string &i) const 
    { 
     SymbolTypeDict::const_iterator dt=typedict.find(i); 
     if(dt==typedict.end()) 
     { 
      auto _dt=typedict.emplace(make_pair(i, SymbolType(SymbolTypeQualifier::None, SymbolTypeType::Namespace, i))); 
      dt=_dt.first; 
     } 
     val.dependents.push_back(&dt->second); 
    } 
    // These work by spreading the building of a templated type over multiple calls using local variables _a and _b 
    // We accumulate template parameters into _a and accumulate mangled symbolness into _b 
    void begin_template_dependent_writer(SymbolType &, SymbolType &a, string &b, const string &i) const 
    { 
     a=SymbolType(SymbolTypeQualifier::None, SymbolTypeType::Class, i); 
     b=i; 
    } 
    void add_template_constant_dependent_writer(SymbolType &a, string &b, long long constant) const 
    { 
     string i("_c"+to_string(constant)); 
     SymbolTypeDict::const_iterator dt=typedict.find(i); 
     if(dt==typedict.end()) 
     { 
      auto _dt=typedict.emplace(make_pair(i, SymbolType(SymbolTypeQualifier::None, SymbolTypeType::Constant, to_string(constant)))); 
      dt=_dt.first; 
     } 
     a.templ_params.push_back(&dt->second); 
     b.append(i); 
    } 
    void add_template_type_dependent_writer(SymbolType &a, string &b, SymbolTypeType type) const 
    { 
     string i("_t"+to_string(static_cast<int>(type))); 
     SymbolTypeDict::const_iterator dt=typedict.find(i); 
     if(dt==typedict.end()) 
     { 
      auto _dt=typedict.emplace(make_pair(i, SymbolType(SymbolTypeQualifier::None, type))); 
      dt=_dt.first; 
     } 
     a.templ_params.push_back(&dt->second); 
     b.append(i); 
    } 
    void finish_template_dependent_writer(SymbolType &val, SymbolType &a, string &b) const 
    { 
     SymbolTypeDict::const_iterator dt=typedict.find(b); 
     if(dt==typedict.end()) 
     { 
      auto _dt=typedict.emplace(make_pair(b, a)); 
      dt=_dt.first; 
     } 
     val.dependents.push_back(&dt->second); 
    } 
    msvc_name(SymbolTypeDict &_typedict) : msvc_name::base_type(start), typedict(_typedict) 
    { 
     identifier=+(char_ - '@'); 
     identifier.name("identifier"); 
     template_dependent_identifier=+(char_ - '@'); 
     template_dependent_identifier.name("template_dependent_identifier"); 
     dependent_identifier=+(char_ - '@'); 
     dependent_identifier.name("dependent_identifier"); 
     start = identifier [ boost::phoenix::bind(&msvc_name::name_writer, this, _val, _1) ] >> *(
      lit("@@") >> eps 
      | (("@?$" > template_dependent_identifier [ boost::phoenix::bind(&msvc_name::begin_template_dependent_writer, this, _val, _a, _b, _1) ]) 
       > "@" > +(("$0" > constant [ boost::phoenix::bind(&msvc_name::add_template_constant_dependent_writer, this, _a, _b, _1) ]) 
        | type [ boost::phoenix::bind(&msvc_name::add_template_type_dependent_writer, this, _a, _b, _1) ]) 
       >> eps [ boost::phoenix::bind(&msvc_name::finish_template_dependent_writer, this, _val, _a, _b) ]) 
      | ("@" > dependent_identifier [ boost::phoenix::bind(&msvc_name::dependent_writer, this, _val, _1) ])) 
      ; 
     BOOST_SPIRIT_DEBUG_NODE(start); 
     start.name("msvc_name"); 
     on_error<boost::spirit::qi::fail, iterator>(start, 
      cerr << boost::phoenix::val("Parsing error: Expected ") << _4 << boost::phoenix::val(" here: \"") 
       << boost::phoenix::construct<string>(_3, _2) << boost::phoenix::val("\"") << endl); 
    } 

    rule<iterator, SymbolType(), locals<SymbolType, string>> start; 
    rule<iterator, string()> identifier, template_dependent_identifier, dependent_identifier; 
    msvc_type type; 
    msvc_constant<iterator> constant; 
}; 

你會注意到「上火(」 @@「)>> EPS」裏我試圖得到它一旦發現@@就停止匹配。現在,這裏是應該匹配整個重整符號的一部分:

template<typename iterator> struct msvc_symbol : grammar<iterator, SymbolType()> 
{ 
    SymbolTypeDict &typedict; 
    /* The key to Microsoft symbol mangles is the operator '@@' which consists of a preamble 
    and a postamble. Immediately following the '@@' operator is: 
    Variable: 
    3<type><storage class> 
    Static member variable: 
    2<type><storage class> 
    Function: 
    <near|far><calling conv>[<stor ret>] <return type>[<parameter type>...]<term>Z 
    <Y |Z ><A|E|G  >[<?A|?B|?C|?D>]<MangledToSymbolTypeType...>  <@>Z 
    Member Function: 
    <protection>[<const>]<calling conv>[<stor ret>] <return type>[<parameter type>...]<term>Z 
    <A-V  >[<A-D> ]<A|E|G  >[<?A|?B|?C|?D>]<MangledToSymbolTypeType...>  <@>Z 
    */ 
    msvc_symbol(SymbolTypeDict &_typedict) : msvc_symbol::base_type(start), typedict(_typedict), name(_typedict), variable(_typedict) 
    { 
     start="?" >> name >> ("@@" >> variable); 
     BOOST_SPIRIT_DEBUG_NODE(start); 
     on_error<boost::spirit::qi::fail, iterator>(start, 
      cerr << boost::phoenix::val("Parsing error: Expected ") << _4 << boost::phoenix::val(" here: \"") 
       << boost::phoenix::construct<string>(_3, _2) << boost::phoenix::val("\"") << endl); 
    } 

    rule<iterator, SymbolType()> start; 
    msvc_name<iterator> name; 
    msvc_variable<iterator> variable; 
}; 

因此,它匹配「?」很容易;)。問題是,它發送「?」後的所有內容到msvc_name解析器,因此,而不是從@@開始的位轉到msvc_variable,其餘的轉到msvc_name,msvc_name將消耗一切直至包括@@。這不直觀,因爲人們會認爲括號意味着首先做這件事。

因此,如果我更換: start="?" >> name >> ("@@" >> variable); start="?" >> name >> variable; ......這一切工作正常。

但是我真的不想這樣做。理想情況下,我希望Boost.Spirit在msvc_symbol中以@@乾淨的方式進行分割,然後「做正確的事情」。我在想我可能沒有足夠的遞歸思考?無論哪種方式,我很難過。

注:是的,我知道我可以打破@@字符串並運行兩個單獨的解析器。這不是我要問的 - 相反,我問如何配置Boost.Spirit在開始之前解析短語的結尾。

另請注意:我知道一個隊長可以用來製作@@空白區域並以這種方式進行分割。問題在於,@@之前的內容非常具體,就像@@後面的內容一樣。因此它不是空白的。

非常感謝任何人誰可以提供幫助。從Google和Stackoverflow搜索與此相關的問題,克服Boost.Spirit的「從左到右的貪婪」是很多人的問題。

尼爾

+0

啊。我以爲我記得這個 – sehe

回答

2

這似乎是你可以做很多事情:

  1. 明確地禁止雙重「@@」你想到哪裏「@」。另請參見

  2. 記號化第一(使用精神萊克斯?)

在這裏,我向您展示了第一種方法的工作示例:

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/karma.hpp> 
namespace qi = boost::spirit::qi; 

template<typename T> T reversed(T c) { return T(c.rbegin(), c.rend()); } 

int main (int argc, char** argv) 
{ 
    const std::string input("[email protected]@@2HC"); 

    auto f = begin(input), l = end(input); 

    auto identifier = +~qi::char_("@"); 
    auto delimit = qi::lit("@") - "@@"; 

    std::vector<std::string> qualifiedName; 
    std::string typeId; 

    if (qi::parse(f,l, 
       '?' >> identifier % delimit >> "@@" >> +qi::char_, 
       qualifiedName, 
       typeId)) 
    { 
     using namespace boost::spirit::karma; 
     qualifiedName = reversed(qualifiedName); 
     std::cout << "Qualified name: " << format(auto_ % "::" << "\n", qualifiedName); 
     std::cout << "Type indication: '" << typeId << "'\n"; 
    } 
} 

輸出:

Qualified name: myclass::myvolatileStaticMember 
Type indication: '2HC' 
+0

傑出!明顯的出血點 - 正如我慢慢來到的那樣,Boost Spirit總是隻從左到右進行解析,所以''''identifier'*'將匹配@,如果標識符不匹配,則期望失敗。因此,需要根據「@」 - 「@@」作爲匹配字符串來思考。非常感謝你指出我的意見。尼爾 –

相關問題