Assigning parsers to auto variables
Spirit Parsers are not designed to be used with auto
in Spirit V2.
This is because the underlying Proto expression templates hold references to the temporaries.
You can use
qi::copy()
(existing in the trunk after boost_1_55_0, not in any released version at this time)boost::proto::deep_copy
- or BOOST_SPIRIT_AUTO (first coined here)
I've written about these things more often on SO: https://stackoverflow.com/search?q=user%3A85371+deep_copy, specifically, this:
- boost spirit V2 qi bug associated with optimization level
Boost Spirit X3 will not have this limitation.
Boost Spirit optional parser and backtracking
Firstly, it's UB to use the auto
variables to keep the expression templates, because they hold references to the temporaries "a"
and "b"
[1].
Instead write
expr = +qi::char_("a") >> -(qi::char_("b") >> +qi::char_("a"));
or, if you insist:
auto a = boost::proto::deep_copy(qi::char_("a"));
auto b = boost::proto::deep_copy(qi::char_("b"));
expr = +a >> -(b >> +a);
Now noticing the >> lit("bc")
part hiding in the parse
call, suggests you may expect backtracking to on succesfully matched tokens when a parse failure happens down the road.
That doesn't happen: Spirit generates PEG grammars, and always greedily matches from left to right.
On to the sample given, ab
results, even though backtracking does occur, the effects on the attribute are not rolled back without qi::hold
: Live On Coliru
Container attributes are passed along by ref and the effects of previous (successful) expressions is not rolled back, unless you tell Spirit too. This way, you can "pay for what you use" (as copying temporaries all the time would be costly).
See e.g.
- boost::spirit::qi duplicate parsing on the output
- Understanding Boost.spirit's string parser
- Boost spirit revert parsing
<a>
<try>abc</try>
<success>bc</success>
<attributes>[a]</attributes>
</a>
<a>
<try>bc</try>
<fail/>
</a>
<b>
<try>bc</try>
<success>c</success>
<attributes>[b]</attributes>
</b>
<a>
<try>c</try>
<fail/>
</a>
<bc>
<try>bc</try>
<success></success>
<attributes>[]</attributes>
</bc>
Success: 'ab'
[1] see here:
- Assigning parsers to auto variables
- Generating Spirit parser expressions from a variadic list of alternative parser expressions
- boost spirit V2 qi bug associated with optimization level
Boost Qi Composing rules using Functions
Quite simply: using auto
with Spirit (or any EDSL based on Boost Proto and Boost Phoenix) is most likely Undefined Behaviour¹
Now, you can usually fix this using
- BOOST_SPIRIT_AUTO
boost::proto::deep_copy
- the new facility that's coming in the most recent version of Boost (TODO add link)
In this case,
template<typename AttrName, typename Value>
auto attribute(AttrName attrName, Value value) {
return boost::proto::deep_copy(attrName >> ':' >> value);
}
fixes it: Live On Coliru
Alternatively
you could use
qi::lazy[]
with inherited attributes.I do very similar things in the
prop_key
rule in Reading JSON file with C++ and BOOST.you could have a look at the Keyword List Operator from the Spirit Repository. It's designed to allow easier construction of grammars like:
no_constraint_person_rule %=
kwd("name")['=' > parse_string ]
/ kwd("age") ['=' > int_]
/ kwd("size") ['=' > double_ > 'm']
;This you could potentially combine with the Nabialek Trick. I'd search the answers on SO for examples. (One is Grammar balancing issue)
¹ Except for entirely stateless actors (Eric Niebler on this) and expression placeholders. See e.g.
- Assigning parsers to auto variables
- undefined behaviour somewhere in boost::spirit::qi::phrase_parse
- C++ Boost qi recursive rule construction
- boost spirit V2 qi bug associated with optimization level
Some examples
- Define parsers parameterized with sub-parsers in Boost Spirit
- Generating Spirit parser expressions from a variadic list of alternative parser expressions
Parsing using boost Spirit into STL vector
int_ >> int_
synthesizes a tuple of int, int.¹
If you want to force synthesizing a container, make it repeat(2) [ int_ ]
to express that.
Sidenote: As you'll see below, there's room for attribute compatibility even if the bound attribute is a cotainer, so you don't need to.
Sidenote:
auto
with parser expressions is asking undefined behaviour: Assigning parsers to auto variables
Sidenote: your input uses space delimiter, but the parser doesn't. That will never work.
Your code sample seems to have little to do with the goal, so here's my small example:
1. vector<int>
:
Live On Coliru
#include <boost/spirit/include/qi.hpp>
using Vec = std::vector<int>;
namespace qi = boost::spirit::qi;
template <typename It> Vec parse_ivec(It first, It last) {
Vec v;
if (qi::phrase_parse(first, last, qi::int_ >> qi::int_ >> qi::eoi, qi::space, v))
return v;
throw std::runtime_error("Parse failed");
}
Vec parse_ivec(std::string const& r) { return parse_ivec(begin(r), end(r)); }
int main() {
for (int i : parse_ivec("12 13")) {
std::cout << i << "\n";
}
}
Prints
12
13
2. Adapted structs
Alternatively, if you wanted a struct, not std::vector<>
:
Live On Coliru
#include <boost/fusion/adapted/struct.hpp>
struct Vec { int a, b; };
BOOST_FUSION_ADAPT_STRUCT(Vec, a, b)
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
template <typename It> Vec parse_ivec(It first, It last) {
Vec v;
if (qi::phrase_parse(first, last, qi::int_ >> qi::int_ >> qi::eoi, qi::space, v))
return v;
throw std::runtime_error("Parse failed");
}
Vec parse_ivec(std::string const& r) { return parse_ivec(begin(r), end(r)); }
int main() {
Vec vec = parse_ivec("12 13");
std::cout << vec.a << " " << vec.b << "\n";
}
Prints
12 13
3. std::tuple<int, int>
:
Live On Coliru
#include <boost/fusion/adapted/std_tuple.hpp>
using Vec = std::tuple<int, int>;
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
template <typename It> Vec parse_ivec(It first, It last) {
Vec v;
if (qi::phrase_parse(first, last, qi::int_ >> qi::int_ >> qi::eoi, qi::space, v))
return v;
throw std::runtime_error("Parse failed");
}
Vec parse_ivec(std::string const& r) { return parse_ivec(begin(r), end(r)); }
int main() {
Vec vec = parse_ivec("12 13");
std::cout << std::get<0>(vec) << " " << std::get<1>(vec) << "\n";
}
Prints
12 13
¹ Technically, a Fusion sequence, which can be made compatible with a host of types like std::pair, or your own types adapted.
Boost Spirit Qi crashes for memory violation
The problem is the use of auto
expressions to capture rules, which deduces the types from the parser expressions. That type is a proto-expression tree, which captures any relations by reference, but that means many of _the intermediates are gone after the end of the enclosing full-expresion (see C++: Life span of temporary arguments?).
This is pretty well-known, as you can see here:
- Assigning parsers to auto variables
- boost spirit V2 qi bug associated with optimization level
- undefined behaviour somewhere in boost::spirit::qi::phrase_parse
- And some more
Here's the simplest fix:
auto versionParser = bsq::copy(
bsq::uint_
>> -('.' >> bsq::uint_)
>> -('.' >> bsq::uint_)
>> -('.' >> bsq::uint_));
If you also fix the missing intialization of the local variables it works correctly:
Live On Coliru
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace bsq = boost::spirit::qi;
int main()
{
std::cout << "BOOST_VERSION: " << BOOST_VERSION << std::endl;
std::uint16_t major = 0, minor = 0, build = 0, revision = 0;
auto versionParser = bsq::copy(
bsq::uint_
>> -('.' >> bsq::uint_)
>> -('.' >> bsq::uint_)
>> -('.' >> bsq::uint_));
std::string version = "3.5.1";
auto start = version.begin();
if (!bsq::parse(start, version.end(), versionParser, major, minor, build, revision))
{
std::cout << "Error!\n";
}
std::cout << major << "-" << minor << "-" << build << "-" << revision << std::endl;
}
Prints
BOOST_VERSION: 106600
3-5-1-0
Additional Notes
To avoid the whole "unitialized attribute" situation, let's make it so the parser assigns to all elements, even if unspecified in the input text:
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))To diagnose errors where there is trailing "garbage" (like with
"3.4bogus"
), you could add a check that the full input is parsed:auto versionParser = bsq::copy(
bsq::uint_
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> bsq::eoi);Because a version is semantically a tuple, why not represent it as such?
using Version = std::tuple<uint16_t, uint16_t, uint16_t, uint16_t>;
Version parsed;
if (!bsq::parse(version.begin(), version.end(), versionParser, parsed))
std::cout << "Error!\n";That way you can even say:
using boost::fusion::operator<<;
auto obsolete = parsed < Version(3, 4, 0, 0);
std::cout << "Version " << parsed << " " << (obsolete? "too old" : "supported") << "\n";
Combining those:
Live On Coliru
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/spirit/include/qi.hpp>
namespace bsq = boost::spirit::qi;
int main() {
auto versionParser = bsq::copy(
bsq::uint_
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> bsq::eoi);
std::string version = "3.5.1";
using Version = std::tuple<uint16_t, uint16_t, uint16_t, uint16_t>;
Version parsed;
if (!bsq::parse(version.begin(), version.end(), versionParser, parsed))
std::cout << "Error!\n";
using boost::fusion::operator<<;
auto obsolete = parsed < Version(3, 4, 0, 0);
std::cout << "Version " << parsed << " " << (obsolete? "too old" : "supported") << "\n";
}
Prints
Version (3 5 1 0) supported
std::tuple
sucks?
I agree. So, equivalently write your own struct:
Live On Coliru
struct Version {
uint16_t major, minor, revision, build;
auto key() const { return std::tie(major, minor, revision, build); }
bool operator<(Version const& b) const { return key() < b.key(); }
};
BOOST_FUSION_ADAPT_STRUCT(Version, major, minor, revision, build)
Gettin' With The Times
Note that Spirit X3 (Getting into boost spirit; Qi or X3?) doesn't have the auto
-issues that you ran into:
Live On Coliru
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/io.hpp>
#include <iostream>
namespace bsx = boost::spirit::x3;
struct Version {
uint16_t major, minor, revision, build;
auto key() const { return std::tie(major, minor, revision, build); }
bool operator<(Version const& b) const { return key() < b.key(); }
};
BOOST_FUSION_ADAPT_STRUCT(Version, major, minor, revision, build)
int main() {
auto versionParser = bsx::uint_
>> ('.' >> bsx::uint_ | bsx::attr(0))
>> ('.' >> bsx::uint_ | bsx::attr(0))
>> ('.' >> bsx::uint_ | bsx::attr(0))
>> bsx::eoi;
std::string version = "3.5.1";
Version parsed;
if (!parse(version.begin(), version.end(), versionParser, parsed))
std::cout << "Error!\n";
using boost::fusion::operator<<;
auto obsolete = parsed < Version{3, 4, 0, 0};
std::cout << "Version " << parsed << " " << (obsolete? "too old" : "supported") << "\n";
}
Also printing the same.
boost spirit qi parser failed in release and pass in debug
You can't use auto with Spirit v2:
- Assigning parsers to auto variables
You have Undefined Behaviour
DEMO
I tried to make (more) sense of the rest of the code. There were various instances that would never work:
txt('=')
is an invalid Qi expression. I assumed you wantedtxt >> ('=')
insteadqi::char_("a-zA-Z0-9_.\\:$\\-{}[]+/()")
doesn't do what you think because$-{
is actually the character "range"\x24-\x7b
... Escape the-
(or put it at the very end/start of the set like in the other char_ call).qi::char_('-','.','_')
can't work. Did you meanqi::char_("-._")
?specialtxt
andanytxt
were unused...prefer
const_iterator
prefer namespace aliases above
using namespace
to prevent hard-to-detect errors
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
int main() {
std::string const s = "abc=[];";
auto specialtxt = qi::copy(*(qi::char_("-._")));
auto anytxt = qi::copy(*(qi::char_("a-zA-Z0-9_.\\:$\\-{}[]+/()")));
(void) specialtxt;
(void) anytxt;
auto txt = qi::copy(qi::no_skip[*(qi::char_("a-zA-Z0-9_.\\:$\'-"))]);
qi::rule<std::string::const_iterator, qi::space_type> rule2 = txt >> '=' >> '[' >> ']';
auto begin = s.begin();
auto end = s.end();
if (qi::phrase_parse(begin, end, rule2, qi::space)) {
std::cout << "MATCH" << std::endl;
} else {
std::cout << "NO MATCH" << std::endl;
}
if (begin != end) {
std::cout << "Trailing unparsed: '" << std::string(begin, end) << "'\n";
}
}
Printing
MATCH
Trailing unparsed: ';'
Boost.spirit segmentation fault when parsing with composite grammar
Giving you some free advice beyond the duplicate: Assigning parsers to auto variables
Let's parse the simple FNT sample:
info face="Arial" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0
common lineHeight=32 base=26 scaleW=256 scaleH=256 pages=0 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0
chars count=0
Notes:
- use a skipper to allow for the insignificant whitespace. In this case, use
qi::blank
because it keepseol
significant - allow for multivalue (
"property=0,0,0"
style) by doingdouble % ','
- use BOOST_SPIRIT_DEBUG with rules
- declare skipperless rules for implicit lexemes (Boost spirit skipper issues)
Live On Coliru
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <fstream>
namespace qi = boost::spirit::qi;
int main() {
using It = boost::spirit::istream_iterator;
qi::rule<It>
word = +qi::alnum,
literal = '"' >> *(qi::char_ - '"') >> '"';
qi::rule<It, std::string()>
value = qi::raw[literal | qi::double_ % ','];
BOOST_SPIRIT_DEBUG_NODES((word)(literal)(value))
const auto pair = qi::copy(word >> '=' >> value);
const auto line = qi::copy(word >> ( + pair ) >> qi::eol);
const auto document = qi::copy(+ line);
std::ifstream in("input.fnt");
in.unsetf(std::ios::skipws);
It begin(in), end;
bool ok = qi::phrase_parse(begin, end, document, qi::blank);
std::cout << std::boolalpha << ok << '\n';
}
Prints:
true
With debug info:
<word>
<try>info face="Arial" si</try>
<success> face="Arial" size=3</success>
<attributes>[]</attributes>
</word>
<word>
<try>face="Arial" size=32</try>
<success>="Arial" size=32 bol</success>
<attributes>[]</attributes>
</word>
<value>
<try>"Arial" size=32 bold</try>
<literal>
<try>"Arial" size=32 bold</try>
<success> size=32 bold=0 ital</success>
<attributes>[]</attributes>
</literal>
<success> size=32 bold=0 ital</success>
<attributes>[[", A, r, i, a, l, "]]</attributes>
</value>
<word>
<try>size=32 bold=0 itali</try>
<success>=32 bold=0 italic=0 </success>
<attributes>[]</attributes>
</word>
<value>
<try>32 bold=0 italic=0 c</try>
<literal>
<try>32 bold=0 italic=0 c</try>
<fail/>
</literal>
<success> bold=0 italic=0 cha</success>
<attributes>[[3, 2]]</attributes>
</value>
<word>
<try>bold=0 italic=0 char</try>
<success>=0 italic=0 charset=</success>
<attributes>[]</attributes>
</word>
<value>
<try>0 italic=0 charset="</try>
<literal>
<try>0 italic=0 charset="</try>
<fail/>
</literal>
<success> italic=0 charset=""</success>
<attributes>[[0]]</attributes>
</value>
<word>
<try>italic=0 charset="" </try>
<success>=0 charset="" unicod</success>
<attributes>[]</attributes>
</word>
<value>
<try>0 charset="" unicode</try>
<literal>
<try>0 charset="" unicode</try>
<fail/>
</literal>
<success> charset="" unicode=</success>
<attributes>[[0]]</attributes>
</value>
<word>
<try>charset="" unicode=1</try>
<success>="" unicode=1 stretc</success>
<attributes>[]</attributes>
</word>
<value>
<try>"" unicode=1 stretch</try>
<literal>
<try>"" unicode=1 stretch</try>
<success> unicode=1 stretchH=</success>
<attributes>[]</attributes>
</literal>
<success> unicode=1 stretchH=</success>
<attributes>[[", "]]</attributes>
</value>
<word>
<try>unicode=1 stretchH=1</try>
<success>=1 stretchH=100 smoo</success>
<attributes>[]</attributes>
</word>
<value>
<try>1 stretchH=100 smoot</try>
<literal>
<try>1 stretchH=100 smoot</try>
<fail/>
</literal>
<success> stretchH=100 smooth</success>
<attributes>[[1]]</attributes>
</value>
<word>
<try>stretchH=100 smooth=</try>
<success>=100 smooth=1 aa=1 p</success>
<attributes>[]</attributes>
</word>
<value>
<try>100 smooth=1 aa=1 pa</try>
<literal>
<try>100 smooth=1 aa=1 pa</try>
<fail/>
</literal>
<success> smooth=1 aa=1 paddi</success>
<attributes>[[1, 0, 0]]</attributes>
</value>
<word>
<try>smooth=1 aa=1 paddin</try>
<success>=1 aa=1 padding=0,0,</success>
<attributes>[]</attributes>
</word>
<value>
<try>1 aa=1 padding=0,0,0</try>
<literal>
<try>1 aa=1 padding=0,0,0</try>
<fail/>
</literal>
<success> aa=1 padding=0,0,0,</success>
<attributes>[[1]]</attributes>
</value>
<word>
<try>aa=1 padding=0,0,0,0</try>
<success>=1 padding=0,0,0,0 s</success>
<attributes>[]</attributes>
</word>
<value>
<try>1 padding=0,0,0,0 sp</try>
<literal>
<try>1 padding=0,0,0,0 sp</try>
<fail/>
</literal>
<success> padding=0,0,0,0 spa</success>
<attributes>[[1]]</attributes>
</value>
<word>
<try>padding=0,0,0,0 spac</try>
<success>=0,0,0,0 spacing=1,1</success>
<attributes>[]</attributes>
</word>
<value>
<try>0,0,0,0 spacing=1,1 </try>
<literal>
<try>0,0,0,0 spacing=1,1 </try>
<fail/>
</literal>
<success> spacing=1,1 outline</success>
<attributes>[[0, ,, 0, ,, 0, ,, 0]]</attributes>
</value>
<word>
<try>spacing=1,1 outline=</try>
<success>=1,1 outline=0\ncommo</success>
<attributes>[]</attributes>
</word>
<value>
<try>1,1 outline=0\ncommon</try>
<literal>
<try>1,1 outline=0\ncommon</try>
<fail/>
</literal>
<success> outline=0\ncommon li</success>
<attributes>[[1, ,, 1]]</attributes>
</value>
<word>
<try>outline=0\ncommon lin</try>
<success>=0\ncommon lineHeight</success>
<attributes>[]</attributes>
</word>
<value>
<try>0\ncommon lineHeight=</try>
<literal>
<try>0\ncommon lineHeight=</try>
<fail/>
</literal>
<success>\ncommon lineHeight=3</success>
<attributes>[[0]]</attributes>
</value>
<word>
<try>\ncommon lineHeight=3</try>
<fail/>
</word>
<word>
<try>common lineHeight=32</try>
<success> lineHeight=32 base=</success>
<attributes>[]</attributes>
</word>
<word>
<try>lineHeight=32 base=2</try>
<success>=32 base=26 scaleW=2</success>
<attributes>[]</attributes>
</word>
<value>
<try>32 base=26 scaleW=25</try>
<literal>
<try>32 base=26 scaleW=25</try>
<fail/>
</literal>
<success> base=26 scaleW=256 </success>
<attributes>[[3, 2]]</attributes>
</value>
<word>
<try>base=26 scaleW=256 s</try>
<success>=26 scaleW=256 scale</success>
<attributes>[]</attributes>
</word>
<value>
<try>26 scaleW=256 scaleH</try>
<literal>
<try>26 scaleW=256 scaleH</try>
<fail/>
</literal>
<success> scaleW=256 scaleH=2</success>
<attributes>[[2, 6]]</attributes>
</value>
<word>
<try>scaleW=256 scaleH=25</try>
<success>=256 scaleH=256 page</success>
<attributes>[]</attributes>
</word>
<value>
<try>256 scaleH=256 pages</try>
<literal>
<try>256 scaleH=256 pages</try>
<fail/>
</literal>
<success> scaleH=256 pages=0 </success>
<attributes>[[2, 5, 6]]</attributes>
</value>
<word>
<try>scaleH=256 pages=0 p</try>
<success>=256 pages=0 packed=</success>
<attributes>[]</attributes>
</word>
<value>
<try>256 pages=0 packed=0</try>
<literal>
<try>256 pages=0 packed=0</try>
<fail/>
</literal>
<success> pages=0 packed=0 al</success>
<attributes>[[2, 5, 6]]</attributes>
</value>
<word>
<try>pages=0 packed=0 alp</try>
<success>=0 packed=0 alphaChn</success>
<attributes>[]</attributes>
</word>
<value>
<try>0 packed=0 alphaChnl</try>
<literal>
<try>0 packed=0 alphaChnl</try>
<fail/>
</literal>
<success> packed=0 alphaChnl=</success>
<attributes>[[0]]</attributes>
</value>
<word>
<try>packed=0 alphaChnl=1</try>
<success>=0 alphaChnl=1 redCh</success>
<attributes>[]</attributes>
</word>
<value>
<try>0 alphaChnl=1 redChn</try>
<literal>
<try>0 alphaChnl=1 redChn</try>
<fail/>
</literal>
<success> alphaChnl=1 redChnl</success>
<attributes>[[0]]</attributes>
</value>
<word>
<try>alphaChnl=1 redChnl=</try>
<success>=1 redChnl=0 greenCh</success>
<attributes>[]</attributes>
</word>
<value>
<try>1 redChnl=0 greenChn</try>
<literal>
<try>1 redChnl=0 greenChn</try>
<fail/>
</literal>
<success> redChnl=0 greenChnl</success>
<attributes>[[1]]</attributes>
</value>
<word>
<try>redChnl=0 greenChnl=</try>
<success>=0 greenChnl=0 blueC</success>
<attributes>[]</attributes>
</word>
<value>
<try>0 greenChnl=0 blueCh</try>
<literal>
<try>0 greenChnl=0 blueCh</try>
<fail/>
</literal>
<success> greenChnl=0 blueChn</success>
<attributes>[[0]]</attributes>
</value>
<word>
<try>greenChnl=0 blueChnl</try>
<success>=0 blueChnl=0\nchars </success>
<attributes>[]</attributes>
</word>
<value>
<try>0 blueChnl=0\nchars c</try>
<literal>
<try>0 blueChnl=0\nchars c</try>
<fail/>
</literal>
<success> blueChnl=0\nchars co</success>
<attributes>[[0]]</attributes>
</value>
<word>
<try>blueChnl=0\nchars cou</try>
<success>=0\nchars count=0\n</success>
<attributes>[]</attributes>
</word>
<value>
<try>0\nchars count=0\n</try>
<literal>
<try>0\nchars count=0\n</try>
<fail/>
</literal>
<success>\nchars count=0\n</success>
<attributes>[[0]]</attributes>
</value>
<word>
<try>\nchars count=0\n</try>
<fail/>
</word>
<word>
<try>chars count=0\n</try>
<success> count=0\n</success>
<attributes>[]</attributes>
</word>
<word>
<try>count=0\n</try>
<success>=0\n</success>
<attributes>[]</attributes>
</word>
<value>
<try>0\n</try>
<literal>
<try>0\n</try>
<fail/>
</literal>
<success>\n</success>
<attributes>[[0]]</attributes>
</value>
<word>
<try>\n</try>
<fail/>
</word>
<word>
<try></try>
<fail/>
</word>
Related Topics
How to Convert Std::String to Lpcwstr in C++ (Unicode)
Compelling Examples of Custom C++ Allocators
How Does the Ampersand(&) Sign Work in C++
C++ Preprocessor #Define-Ing a Keyword. Is It Standards Conforming
Exporting Classes Containing 'Std::' Objects (Vector, Map etc.) from a Dll
C++: Constructor Initializer For Arrays
Should I Use an Exception Specifier in C++
When Is a Private Constructor Not a Private Constructor
What Belongs in an Educational Tool to Demonstrate the Unwarranted Assumptions People Make in C/C++
Createprocess from Memory Buffer
How to Assign an Alias to a Function Name in C++
Why Do We Not Have a Virtual Constructor in C++
How to Get Error Message When Ifstream Open Fails
Why Do I See Strange Values When I Print Uninitialized Variables
How to Declare a Templated Struct/Class as a Friend