I am trying to use qi::on_success
callback (here) to set a field when a rule is matched. The code below is slightly adapted from this code though my slight changes to the rules/ast class has made it no to recognize _rule_name
. My intention is commented in the code below. I want to set the field term_type
to TermType::literal
if the _literal
rule is matched or to Term::rule_name
if _rule_name
rule is matched.
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace Ast {
enum class TermType {
literal,
rule_name
};
struct Term {
std::string data;
TermType term_type;
};
using List = std::list<Term>;
using Expression = std::list<List>;
struct Rule {
Term name; // lhs
Expression rhs;
};
using Syntax = std::list<Rule>;
}
BOOST_FUSION_ADAPT_STRUCT(Ast::Term, data)
BOOST_FUSION_ADAPT_STRUCT(Ast::Rule, name, rhs)
namespace Parser {
template<typename Iterator>
struct BNF : qi::grammar<Iterator, Ast::Syntax()> {
BNF() : BNF::base_type(start) {
using namespace qi;
_blank = blank;
_skipper = blank | (eol >> !skip(_blank.alias())[_rule]);
start = skip(_skipper.alias())[_rule % +eol];
_rule = _rule_name >> "::=" >> _expression;
_expression = _list % '|';
_list = +(_literal | _rule_name);
_literal = '"' >> *(_character - '"') >> '"'
| "'" >> *(_character - "'") >> "'";
_character = alnum | char_("\"'| !#$%&()*+,./:;>=<?@]\\^_`{}~[-");
_rule_name = '<' >> (alpha >> *(alnum | char_('-'))) >> '>';
BOOST_SPIRIT_DEBUG_NODES(
(_rule)(_expression)(_list)(_literal)
(_character)
(_rule_name))
}
/*qi::on_success(_term, setTermTypeHandler());
setTermTypeHandler(){
if term is literal
term.symbol_type = TermType::literal
else
term.term_type = TermType::rule_name
}
*/
private:
using Skipper = qi::rule<Iterator>;
Skipper _skipper, _blank;
qi::rule<Iterator, Ast::Syntax()> start;
qi::rule<Iterator, Ast::Rule(), Skipper> _rule;
qi::rule<Iterator, Ast::Expression(), Skipper> _expression;
qi::rule<Iterator, Ast::List(), Skipper> _list;
// lexemes
qi::rule<Iterator, Ast::Term()> _literal;
qi::rule<Iterator, Ast::Term()> _rule_name;
// qi::rule<Iterator, std::string()> _literal;
qi::rule<Iterator, char()> _character;
};
}
int main() {
Parser::BNF<std::string::const_iterator> const parser;
std::string const input = R"(<code> ::= <letter><digit> | <letter><digit><code>
<letter> ::= "a" | "b" | "c" | "d" | "e"
| "f" | "g" | "h" | "i"
<digit> ::= "0" | "1" | "2" | "3" |
"4"
)";
auto it = input.begin(), itEnd = input.end();
Ast::Syntax syntax;
if (parse(it, itEnd, parser, syntax)) {
for (auto &rule : syntax) {
std::cout << rule.name.data << " ::= ";
std::string sep;
for (auto &list : rule.rhs) {
std::cout << sep;
for (auto &term: list) { std::cout << term.data; }
sep = " | ";
};
std::cout << "\n";
}
} else {
std::cout << "Failed\n";
}
if (it != itEnd)
std::cout << "Remaining: " << std::quoted(std::string(it, itEnd)) << "\n";
}