/*============================================================================= Copyright (c) 2001-2010 Joel de Guzman Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include "../../../../test/qi/test.hpp" #define SCHEME_QI_COMPILER_LIMIT 20 namespace scheme { namespace qi { /////////////////////////////////////////////////////////////////////////// // parser compiler /////////////////////////////////////////////////////////////////////////// namespace qi = boost::spirit::qi; namespace spirit = boost::spirit; typedef qi::rule skipper_type; typedef qi::rule rule_type; /////////////////////////////////////////////////////////////////////////// // All rule are stored here. Rules are held in the utree by its id; // i.e. its index in the vector. /////////////////////////////////////////////////////////////////////////// template class rule_fragments { public: rule_fragments() : index(0) { }; int new_rule() { rules[index]; return index++; } template void define_rule(int id, Expr const& expr) { rules[id] = expr; std::stringstream str; str << qi::what(expr); rules[id].name(str.str()); } Rule const& operator[](int id) const { typename std::map::const_iterator iter = rules.find(id); BOOST_ASSERT(iter != rules.end()); return iter->second; } Rule const& operator[](utree const& id) const { return (*this)[id.get()]; } private: int index; std::map rules; }; /////////////////////////////////////////////////////////////////////////// // Composes primitive parsers held by index. Handles the compilation of // primitive (nullary) parsers such as int_, double_, alpha, space and all // those that require no arguments. /////////////////////////////////////////////////////////////////////////// struct primitive_parser_composite : composite { int id; primitive_parser_composite(int id) : id(id) { } function compose(actor_list const& elements) const { return val(id); } }; template inline primitive_parser_composite make_primitive_parser_composite(Fragments& fragments, Expr const& expr) { int id = fragments.new_rule(); fragments.define_rule(id, expr); return primitive_parser_composite(id); } /////////////////////////////////////////////////////////////////////////// // Handles the compilation of char_ /////////////////////////////////////////////////////////////////////////// template struct char_function : actor > { mutable int id; function a; function b; Fragments& fragments; char_function( Fragments& fragments, function const& a, function const& b) : id(-1), a(a), b(b), fragments(fragments) { } void define() const { // char_ fragments.define_rule(id, qi::char_); } void define(utree const& a) const { // $$$ use exceptions here $$$. BOOST_ASSERT(a.which() == utree_type::string_type); utf8_string_range a_ = a.get(); if (a_.size() == 1) { // char_('x') fragments.define_rule(id, qi::char_(a_[0])); } else { // char_("some-regex") fragments.define_rule(id, qi::char_(std::string(a_.begin(), a_.end()))); } } void define(utree const& a, utree const& b) const { // $$$ use exceptions here $$$. BOOST_ASSERT(a.which() == utree_type::string_type); BOOST_ASSERT(b.which() == utree_type::string_type); utf8_string_range a_ = a.get(); utf8_string_range b_ = b.get(); // $$$ use exceptions here $$$. BOOST_ASSERT(a_.size() == 1); BOOST_ASSERT(b_.size() == 1); // char_('x', 'y') fragments.define_rule(id, qi::char_(a_[0], b_[0])); } utree eval(scope const& env) const { if (id != -1) return id; id = fragments.new_rule(); if (a.empty()) define(); else if (b.empty()) define(a(env)); else define(a(env), b(env)); return id; } }; template struct char_composite : composite > { Fragments& fragments; char_composite(Fragments& fragments) : fragments(fragments) {} function compose(actor_list const& elements) const { typedef char_function function_type; actor_list::const_iterator i = elements.begin(); function empty; function const& a = (i == elements.end())? empty : *i++; function const& b = (i == elements.end())? empty : *i; return function(function_type(fragments, a, b)); } }; /////////////////////////////////////////////////////////////////////////// // Handles the compilation of kleene *a /////////////////////////////////////////////////////////////////////////// template struct kleene_function : actor > { mutable int id; function a; Fragments& fragments; kleene_function( Fragments& fragments, function const& a) : id(-1), a(a), fragments(fragments) { } void define(utree const& a) const { fragments.define_rule(id, *fragments[a]); // *a } utree eval(scope const& env) const { if (id != -1) return id; id = fragments.new_rule(); define(a(env)); return id; } }; template struct kleene_composite : composite > { Fragments& fragments; kleene_composite(Fragments& fragments) : fragments(fragments) {} function compose(actor_list const& elements) const { typedef kleene_function function_type; return function(function_type(fragments, elements.front())); } }; /////////////////////////////////////////////////////////////////////////// // Handles the compilation of difference a - b /////////////////////////////////////////////////////////////////////////// template struct difference_function : actor > { mutable int id; function a; function b; Fragments& fragments; difference_function( Fragments& fragments, function const& a, function const& b) : id(-1), a(a), b(b), fragments(fragments) { } void define(utree const& a, utree const& b) const { fragments.define_rule(id, fragments[a] - fragments[b]); // a - b } utree eval(scope const& env) const { if (id != -1) return id; id = fragments.new_rule(); define(a(env), b(env)); return id; } }; template struct difference_composite : composite > { Fragments& fragments; difference_composite(Fragments& fragments) : fragments(fragments) {} function compose(actor_list const& elements) const { typedef difference_function function_type; actor_list::const_iterator i = elements.begin(); function const& a = *i++; function const& b = *i; return function(function_type(fragments, a, b)); } }; /////////////////////////////////////////////////////////////////////////// // Handles the compilation of sequence a >> b /////////////////////////////////////////////////////////////////////////// template struct sequence_function : actor > { mutable int id; actor_list elements; Fragments& fragments; sequence_function( Fragments& fragments, actor_list const& elements) : id(-1), elements(elements), fragments(fragments) { } void define(utree const& a, utree const& b) const { // a >> b fragments.define_rule(id, fragments[a] >> fragments[b]); } void define(utree const& a, utree const& b, utree const& c) const { // a >> b >> c fragments.define_rule(id, fragments[a] >> fragments[b] >> fragments[c]); } void define(utree const& a, utree const& b, utree const& c, utree const& d) const { // a >> b >> c >> d fragments.define_rule(id, fragments[a] >> fragments[b] >> fragments[c] >> fragments[d]); } void define(utree const& a, utree const& b, utree const& c, utree const& d, utree const& e) const { // a >> b >> c >> d >> e fragments.define_rule(id, fragments[a] >> fragments[b] >> fragments[c] >> fragments[d] >> fragments[e]); } utree eval(scope const& env) const { if (id != -1) return id; id = fragments.new_rule(); actor_list::const_iterator i = elements.begin(); switch (elements.size()) { case 2: { function const& a = *i++; function const& b = *i; define(a(env), b(env)); break; } case 3: { function const& a = *i++; function const& b = *i++; function const& c = *i; define(a(env), b(env), c(env)); break; } case 4: { function const& a = *i++; function const& b = *i++; function const& c = *i++; function const& d = *i; define(a(env), b(env), c(env), d(env)); break; } case 5: { function const& a = *i++; function const& b = *i++; function const& c = *i++; function const& d = *i++; function const& e = *i; define(a(env), b(env), c(env), d(env), e(env)); break; } // $$$ Use Boost PP using SCHEME_QI_COMPILER_LIMIT $$$ } return id; } }; template struct sequence_composite : composite > { Fragments& fragments; sequence_composite(Fragments& fragments) : fragments(fragments) {} function compose(actor_list const& elements) const { typedef sequence_function function_type; return function(function_type(fragments, elements)); } }; /////////////////////////////////////////////////////////////////////////// // Handles the compilation of alternatives a | b /////////////////////////////////////////////////////////////////////////// template struct alternative_function : actor > { mutable int id; actor_list elements; Fragments& fragments; alternative_function( Fragments& fragments, actor_list const& elements) : id(-1), elements(elements), fragments(fragments) { } void define(utree const& a, utree const& b) const { // a | b fragments.define_rule(id, fragments[a] | fragments[b]); } void define(utree const& a, utree const& b, utree const& c) const { // a | b | c fragments.define_rule(id, fragments[a] | fragments[b] | fragments[c]); } void define(utree const& a, utree const& b, utree const& c, utree const& d) const { // a | b | c | d fragments.define_rule(id, fragments[a] | fragments[b] | fragments[c] | fragments[d]); } void define(utree const& a, utree const& b, utree const& c, utree const& d, utree const& e) const { // a | b | c | d | e fragments.define_rule(id, fragments[a] | fragments[b] | fragments[c] | fragments[d] | fragments[e]); } utree eval(scope const& env) const { if (id != -1) return id; id = fragments.new_rule(); actor_list::const_iterator i = elements.begin(); switch (elements.size()) { case 2: { function const& a = *i++; function const& b = *i; define(a(env), b(env)); break; } case 3: { function const& a = *i++; function const& b = *i++; function const& c = *i; define(a(env), b(env), c(env)); break; } case 4: { function const& a = *i++; function const& b = *i++; function const& c = *i++; function const& d = *i; define(a(env), b(env), c(env), d(env)); break; } case 5: { function const& a = *i++; function const& b = *i++; function const& c = *i++; function const& d = *i++; function const& e = *i; define(a(env), b(env), c(env), d(env), e(env)); break; } // $$$ Use Boost PP using SCHEME_QI_COMPILER_LIMIT $$$ } return id; } }; template struct alternative_composite : composite > { Fragments& fragments; alternative_composite(Fragments& fragments) : fragments(fragments) {} function compose(actor_list const& elements) const { typedef alternative_function function_type; return function(function_type(fragments, elements)); } }; /////////////////////////////////////////////////////////////////////////// // Build our scheme compiler environment. /////////////////////////////////////////////////////////////////////////// template void build_environment(Fragments& fragments, environment& env) { build_basic_environment(env); env.define("qi:space", make_primitive_parser_composite(fragments, qi::space), 0, true); env.define("qi:alpha", make_primitive_parser_composite(fragments, qi::alpha), 0, true); env.define("qi:int_", make_primitive_parser_composite(fragments, qi::int_), 0, true); env.define("qi:char_", char_composite(fragments), 0, false); env.define("qi:*", kleene_composite(fragments), 1, true); env.define("qi:-", difference_composite(fragments), 2, true); env.define("qi:>>", sequence_composite(fragments), 2, false); env.define("qi:|", alternative_composite(fragments), 2, false); } }} /////////////////////////////////////////////////////////////////////////////// // Main program /////////////////////////////////////////////////////////////////////////////// int main() { using scheme::utree; using scheme::interpreter; using scheme::environment; using scheme::qi::build_environment; using scheme::qi::rule_fragments; using scheme::qi::rule_type; using spirit_test::test; environment env; rule_fragments fragments; build_environment(fragments, env); scheme::qi::skipper_type space = boost::spirit::qi::space; { utree src = "(define charx (qi:char_ \"x\"))" "(define integer (qi:int_))" "(define nonzero (qi:- (qi:int_) (qi:char_ \"0\")))" "(define integers (qi:* (qi:int_)))" "(define intpair (qi:>> " "(qi:char_ \"(\") " "(qi:int_) " "(qi:char_ \",\") " "(qi:int_) " "(qi:char_ \")\")))" ; interpreter parser(src, "parse.scm", &env); BOOST_TEST(test("z", fragments[parser["qi:char_"]()], space)); BOOST_TEST(test("x", fragments[parser["charx"]()], space)); BOOST_TEST(!test("y", fragments[parser["charx"]()], space)); BOOST_TEST(test("1234", fragments[parser["integer"]()], space)); BOOST_TEST(!test("x1234", fragments[parser["integer"]()], space)); BOOST_TEST(test("1 2 3 4", fragments[parser["integers"]()], space)); BOOST_TEST(test("1", fragments[parser["nonzero"]()], space)); BOOST_TEST(!test("0", fragments[parser["nonzero"]()], space)); BOOST_TEST(test("(1, 2)", fragments[parser["intpair"]()], space)); BOOST_TEST(!test("(1, x)", fragments[parser["intpair"]()], space)); } { char const* filename = filename = "calc.scm"; std::ifstream in(filename, std::ios_base::in); BOOST_TEST(in); // Ignore the BOM marking the beginning of a UTF-8 file in Windows char c = in.peek(); if (c == '\xef') { char s[3]; in >> s[0] >> s[1] >> s[2]; s[3] = '\0'; BOOST_TEST(s != std::string("\xef\xbb\xbf")); } interpreter parser(in, filename, &env); rule_type calc = fragments[parser["expression"]()].alias(); std::string str; while (std::getline(std::cin, str)) { if (str.empty() || str[0] == 'q' || str[0] == 'Q') break; char const* iter = str.c_str(); char const* end = iter + strlen(iter); bool r = phrase_parse(iter, end, calc, space); if (r && iter == end) { std::cout << "-------------------------\n"; std::cout << "Parsing succeeded\n"; std::cout << "-------------------------\n"; } else { std::string rest(iter, end); std::cout << "-------------------------\n"; std::cout << "Parsing failed\n"; std::cout << "stopped at: \": " << rest << "\"\n"; std::cout << "-------------------------\n"; } } } return boost::report_errors(); }