问题
I am interested in Boost Spirit nowadays and trying to build something. Can we implement something like a const in C++ using Spirit? For instance, user will define an item like;
constant var PROG_LANG="Java";
"constant var" seems weird, I accept but you got the idea. I searched the internet but can't found anything about it.
回答1:
What the BigBoss said :)
Only I'd do without the semantic actions - making it far less... verbose (See also Boost Spirit: "Semantic actions are evil"?):
vdef =
("constant" >> attr(true) | attr(false)) >>
"var" >> identifier >> '=' >> identifier_value >> ';' ;
That's all. This uses qi::attr
to account for the default (missing constant
keyword).
Here's a full demo with output:
http://liveworkspace.org/code/c9e4bef100d2249eb4d4b88205f85c4b
Output:
parse success: 'var myvariable = "has some value";'
data: false;myvariable;has some value;
parse success: 'constant var myvariable = "has some value";'
data: true;myvariable;has some value;
Code:
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;
struct var_definition {
bool is_constant;
std::string name;
std::string value;
var_definition() : is_constant( false ) {}
};
BOOST_FUSION_ADAPT_STRUCT(var_definition, (bool, is_constant)(std::string, name)(std::string, value))
void doParse(const std::string& input)
{
typedef std::string::const_iterator It;
qi::rule<It, std::string()> identifier, identifier_value;
qi::rule<It, var_definition(), qi::space_type> vdef;
{
using namespace qi;
identifier_value = '"' >> lexeme [ +~char_('"') ] > '"';
identifier = lexeme [ +graph ];
vdef =
("constant" >> attr(true) | attr(false)) >>
"var" >> identifier >> '=' >> identifier_value >> ';' ;
}
var_definition data;
It f(std::begin(input)), l(std::end(input));
bool ok = qi::phrase_parse(f,l,vdef,qi::space,data);
if (ok)
{
std::cout << "parse success: '" << input << "'\n";
std::cout << "data: " << karma::format_delimited(karma::auto_, ';', data) << "\n";
}
}
int main()
{
doParse("var myvariable = \"has some value\";");
doParse("constant var myvariable = \"has some value\";");
}
回答2:
I don't get your question correctly, spirit
is a parser and it has nothing to do with the meaning of constant
it can only parse it, but if you mean parse an optional variable like constant
then it can be something line:
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
typedef std::string::const_iterator it;
struct var_definition {
bool is_constant;
std::string name;
std::string value;
var_definition() : is_constant( false ) {}
};
qi::rule<it, std::string()> identifier;
qi::rule<it, std::string()> identifier_value;
qi::rule<it, var_definition(), boost::spirit::ascii::space_type> vdef;
void mark_var_as_constant(var_definition& vd) {vd.is_constant=true;}
void set_var_name(var_definition& vd, std::string const& val) {vd.name=val;}
void set_var_value(var_definition& vd, std::string const& val) {vd.value=val;}
vdef %=
-qi::lit("constant")[phx::bind(mark_var_as_constant, qi::_val)] >>
qi::lit("var") >>
identifier[phx::bind(set_var_name, qi::_val, qi::_1)] >>
qi::char_('=') >>
identifier_value[phx::bind(set_var_value, qi::_val, qi::_1)] >>
qi::char_(';');
Of course there are other ways, for example:
(qi::lit("constant")[phx::bind(mark_var_as_constant, qi::_val)] | qi::eps)
And the easiest is:
qi::hold[ qi::lit("constant")[phx::bind(mark_var_as_constant, qi::_val)] ]
来源:https://stackoverflow.com/questions/13114052/how-can-i-implement-const-in-boost-spirit