Created
May 3, 2013 20:54
-
-
Save jefftrull/5514049 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// An attempt to generically parse expressions like this: | |
// <token> <int> ; | |
// - <some-expr> ; | |
// - <some-expr> ; | |
// - <some-expr> ; <- exactly as many times as given by <int> above | |
// END <token> | |
// where <token> is a string, and <some-expr> is a rule with attribute A | |
// the synthesized attribute of the result should be a fusion sequence of A | |
// Furthermore the resulting grammar should check the number of <some-expr> and ensure it | |
// matches the supplied <int>, with (ideally) a suitable error message | |
// first experiment: use a grammar with a rule parameter. Jeroen Habraken says: | |
// jaafar, it should be able to accept the rule as an inherited attribute which you then pass to lazy() | |
// however, it must be a complete type, thus rule<I, T(), S> (S optional), i.e., T must be there at that point | |
#include <string> | |
#include <vector> | |
#include <iterator> | |
#include <iostream> | |
#include <algorithm> | |
#include <boost/fusion/include/adapt_struct.hpp> | |
#include <boost/spirit/include/qi.hpp> | |
#include <boost/spirit/include/phoenix.hpp> | |
#include <boost/spirit/repository/include/qi_kwd.hpp> | |
#include <boost/spirit/repository/include/qi_keywords.hpp> | |
#include <boost/spirit/include/support_istream_iterator.hpp> | |
// typedef for stream iterator we will use | |
typedef boost::spirit::istream_iterator Iter; | |
using namespace boost::spirit::qi; | |
using boost::spirit::qi::rule; | |
using boost::spirit::qi::locals; | |
using boost::spirit::qi::grammar; | |
template<typename Attr> | |
struct rpt_parser : grammar<Iter, | |
locals<int>, | |
std::vector<Attr>(std::string, | |
rule<Iter, Attr(), space_type>), | |
space_type> | |
{ | |
rpt_parser(std::string const& kwd, | |
rule<Iter, Attr(), space_type> baserule) | |
: rpt_parser::base_type(rpt_stmt) | |
{ | |
using namespace boost::spirit::qi; | |
using boost::spirit::repository::dkwd; | |
using boost::phoenix::push_back; // to store results in containers | |
using boost::phoenix::val; // to defer evaluation of parsers | |
rpt_stmt = dkwd(kwd)[omit[int_[_a = _1]]] > ';' // preamble | |
> repeat(_a)['-' > lazy(val(baserule))[push_back(_val, _1) > ';']] // repeated statements | |
> dkwd("END") > dkwd(kwd) ; // termination | |
} | |
rule<Iter, | |
locals<int>, | |
std::vector<Attr>(std::string, rule<Iter, Attr(), space_type>), | |
space_type> rpt_stmt; | |
}; | |
struct test_result | |
{ | |
std::vector<std::string> strings; | |
std::vector<int> ints; | |
}; | |
BOOST_FUSION_ADAPT_STRUCT( | |
test_result, | |
(std::vector<std::string>, strings) | |
(std::vector<int>, ints) | |
) | |
struct test_parser : grammar<Iter, test_result(), space_type> | |
{ | |
test_parser() : test_parser::base_type(start) | |
{ | |
using namespace boost::spirit::qi; | |
start = rpt_parser<std::string>("WORDS", string) >> rpt_parser<int>("INTS", int_) ; | |
} | |
rule<Iter, test_result(), space_type> start; | |
}; | |
int main() | |
{ | |
std::stringstream testdata("WORDS 5;\n- ALPHA ;\n- BETA ;\n- GAMMA ;\n- DELTA ;\n- EPSILON ;\nEND WORDS\nINTS 3;\n- -1 ;\n- 17 ;\n- 3223 ;\nEND INTS\n"); | |
testdata.unsetf(std::ios::skipws); | |
Iter beg(testdata), end; | |
test_parser tp; | |
test_result result; | |
if (!phrase_parse(beg, end, tp, space, result)) | |
{ | |
std::cerr << "failed to parse input" << std::endl; | |
return 1; | |
} else if (beg != end) { | |
std::cerr << "parse succeeded but not all input consumed" << std::endl; | |
std::cerr << "remaining: "; | |
std::copy(beg, end, std::ostream_iterator<char>(std::cout, "")); | |
return 1; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment