boost-spirit numeric parsers and getting the desired synthesised attributes
--edit -- Solved the question : a comment on the last sidenote would be helpfull. Also comments on phoenix::bind overload handling would be helpfull (in my answer).
I'm workin开发者_运维知识库g on a system with strict typing requirements, I want to ensure that I am parsing integers that meet the constraints of int32_t and int64_t, I wan't the parsers to synthesise and constrain the parsed strings to the mentioned types.
How do I go about this ? The document mentions that long_long
is only available on platforms with 64-bit support, but I need to parse int64_t's on 32-bit platforms as well.
An excerpt from my parser is as follows:
...
eps(_b == VALUE_INT4) >> qi::long_
[phoenix::bind(&AddEntry, _r1,_a, _1, _pass)] ) //
| ( eps(_b == VALUE_INT8) >> qi::long_long)
...
AddEntry has a int32_t
overload and a int64_t
overload, is a phoenix::static_cast_ on _1
in order ? And if this is the case how do I parse 64-bit integers on a modern 32-bit platform ? I assume BOOST_HAS_LONG_LONG
is only not-defined on archaic hardware like the 8008 ;) .
<Rant>
I wish they had stuck with the standards set out in c99 and <boost/cstdint.hpp>
, most of us want to program against clean abstractions. There are probably good reasons for the numeric parsers being defined the way they are. however, grand-scheme use could be better defined in the documentation.
</Rant>
On a side note: Does the conditional epsilon style above rival a case statement in performance ?
1) Qi parsers already check for overflow conditions. The parser component will fail if the input is not representable by the type the component is supposed to match. For instance, int_parser<int32_t, 10>
will fail for numbers not fitting into a signed 32 bit integer.
You can use the long_long
parser (i.e. the predefined 64 bit integer parser) only if BOOST_HAS_LONG_LONG
is defined. If you have a platform where this is not the case, you can still emulate a 64bit integer by writing your own wrapper type exposing the functionality as expected by Qi numeric parsers (see here), for instance:
struct my_64bit_int {
//...
};
typedef int_parser<my_64bit_int, 10> my_64bit_int_parser_type;
my_64bit_int_parser_type const my_64bit_int_parser;
and use it as:
my_64bit_int bigint;
parse(b, e, my_64bit_int_parser, bigint);
2) You can't bind overloaded functions without helping the compiler, i.e. given:
void AddEntry(int32_t);
void AddEntry(int64_t);
you need to cast the function pointer explicitly if you want to bind for an int32_t
:
phoenix::bind((void(*)(int32_t))&AddEntry, _1);
Answer to sidenote: No. The alternative parser is always sequentially executing the different alternatives in the same sequence as specified, stopping when the first of those matches. Its overall complexity is O(N)
, where N
is the number of separate alternatives (see here).
These templatas will get you the semantics you want.
qi::int_parser< int32_t, 10, 1,10> p_int32_t;
qi::int_parser< int64_t, 10, 1, 19> p_int64_t;
These parsers were unit tested and created expectation errors on overflow --i.e., when >= 2^31
and >= 2^63
respectively.
Overloads aren't picked up by phoenix::bind afaik (correct me if I'm wrong please),
therefore a macro along the lines of
#define ADD_ENTRY(TP,prefix) \
void AddEntry_##prefix( value_variant_vector & v, uint32_t ordinal, \
TP entry, bool & ok_) \
For those interested the compiler error message is as follows (when AddEntry is a template function):
/opt/dev_64_swat/dsl/src/parser/RowAndTable.cc:43: error: no matching function
for call to ‘bind(<unresolved overloaded function type>, const
boost::phoenix::actor<boost::spirit::attribute<1> >&, const
boost::phoenix::actor<boost::spirit::local_variable<0> >&, const
boost::phoenix::actor<boost::spirit::argument<0> >&, const
boost::phoenix::actor<boost::phoenix::argument<2> >&)’
I get errors on hand written overloads as well.
精彩评论