我試圖讓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的「從左到右的貪婪」是很多人的問題。
尼爾
啊。我以爲我記得這個 – sehe