diff options
Diffstat (limited to 'src/boost/libs/spirit/classic/example')
66 files changed, 8015 insertions, 0 deletions
diff --git a/src/boost/libs/spirit/classic/example/Jamfile b/src/boost/libs/spirit/classic/example/Jamfile new file mode 100644 index 00000000..7079152f --- /dev/null +++ b/src/boost/libs/spirit/classic/example/Jamfile @@ -0,0 +1,300 @@ +#============================================================================== +# Copyright (c) 2002 Joel de Guzman +# http://spirit.sourceforge.net/ +# +# Use, modification and distribution is subject to 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) +#============================================================================== +# +# Spirit examples boost-jam file +# Joel de Guzman [Sep 27, 2002] : created +# Joel de Guzman [Oct 30, 2003] : separated the applications +# Martin Wille [Jan 15, 2004] : changes for new directory structure +# Martin Wille [Jan 20, 2004] : more changes for new directory structure +# Joel de Guzman [Jul 29, 2004] : added calc_debug.cpp +# + +exe ast_calc + : fundamental/ast_calc.cpp + : + ; + +exe "bind" + : fundamental/bind.cpp + : + ; + +exe boiler_plate + : fundamental/boiler_plate.cpp + : + ; + +exe calc_plain + : fundamental/calc_plain.cpp + : + ; + +exe calc_debug + : fundamental/calc_debug.cpp + : + ; + +exe comments + : fundamental/comments.cpp + : + ; + +exe complex_number + : fundamental/complex_number.cpp + : + ; + +exe error_handling + : fundamental/error_handling.cpp + : + ; + +exe error_reporting + : fundamental/error_reporting.cpp + : + ; + +exe file_parser + : fundamental/file_parser.cpp + : + ; + +exe full_calc + : fundamental/full_calc.cpp + : + ; + +exe functor_parser + : fundamental/functor_parser.cpp + : + ; + +exe list_parser + : fundamental/list_parser.cpp + : + ; + +exe matching_tags + : fundamental/matching_tags.cpp + : + ; + +exe no_actions + : fundamental/no_actions.cpp + : + ; + +exe number_list + : fundamental/number_list.cpp + : + ; + +exe parse_tree_calc1 + : fundamental/parse_tree_calc1.cpp + : + ; + +exe parser_context + : fundamental/parser_context.cpp + : + ; + +exe phoenix_calc + : fundamental/phoenix_calc.cpp + : + ; + +exe position_iterator + : fundamental/position_iterator/position_iterator.cpp + : + ; + +exe refactoring + : fundamental/refactoring.cpp + : + ; + +exe regular_expression + : fundamental/regular_expression.cpp + /boost//regex + : + ; + +exe roman_numerals + : fundamental/roman_numerals.cpp + : + ; + +exe stuff_vector + : fundamental/stuff_vector.cpp + : + ; + +exe stuff_vector2 + : fundamental/stuff_vector2.cpp + : + ; + +exe subrule_calc + : fundamental/subrule_calc.cpp + : + ; + +exe sum + : fundamental/sum.cpp + : + ; + +exe thousand_separated + : fundamental/thousand_separated.cpp + : + ; + +exe ast_calc2 + : fundamental/more_calculators/ast_calc2.cpp + : + ; + +exe calc_with_variables + : fundamental/more_calculators/calc_with_variables.cpp + : + ; + +exe phoenix_subrule_calc + : fundamental/more_calculators/phoenix_subrule_calc.cpp + : + ; + +exe primitive_calc + : fundamental/more_calculators/primitive_calc.cpp + : + ; + +exe rpn_calc + : fundamental/more_calculators/rpn_calc.cpp + : + ; + +exe vmachine_calc + : fundamental/more_calculators/vmachine_calc.cpp + : + ; + +exe distinct_parser + : fundamental/distinct/distinct_parser.cpp + : + ; + +exe distinct_parser_dynamic + : fundamental/distinct/distinct_parser_dynamic.cpp + : + ; + +################################################################################ + +exe ipv4 + : intermediate/ipv4.cpp + : + ; + +exe ipv4_opt + : intermediate/ipv4_opt.cpp + : + ; + +exe lazy_parser + : intermediate/lazy_parser.cpp + : + ; + +exe parameters + : intermediate/parameters.cpp + : + ; + +exe regex_convert + : intermediate/regex_convert.cpp + /boost//regex + : + ; + +exe simple_xml + : intermediate/simple_xml/driver.cpp + intermediate/simple_xml/tag.cpp + intermediate/simple_xml/tag.cpp + : + ; + +################################################################################ + +exe dynamic_rule + : techniques/dynamic_rule.cpp + : + ; + +exe epsilon + : techniques/epsilon.cpp + : + ; + +exe multiple_scanners + : techniques/multiple_scanners.cpp + : + ; + +exe nabialek + : techniques/nabialek.cpp + : + ; + +exe no_rule1 + : techniques/no_rules/no_rule1.cpp + : + ; + +exe no_rule2 + : techniques/no_rules/no_rule2.cpp + : + ; + +exe no_rule3 + : techniques/no_rules/no_rule3.cpp + : + ; + +exe typeof + : techniques/typeof.cpp + : + ; + +exe rule_parser_1_1 + : techniques/no_rules_with_typeof/rule_parser_1_1.cpp + : + ; + +exe rule_parser_1_2 + : techniques/no_rules_with_typeof/rule_parser_1_2.cpp + : + ; + +exe rule_parser_2_1 + : techniques/no_rules_with_typeof/rule_parser_2_1.cpp + : + ; + +exe rule_parser_2_2 + : techniques/no_rules_with_typeof/rule_parser_2_2.cpp + : + ; + +exe opaque_rule_parser + : techniques/no_rules_with_typeof/opaque_rule_parser.cpp + : + ; + diff --git a/src/boost/libs/spirit/classic/example/fundamental/ast_calc.cpp b/src/boost/libs/spirit/classic/example/fundamental/ast_calc.cpp new file mode 100644 index 00000000..33c5e0f1 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/ast_calc.cpp @@ -0,0 +1,159 @@ +/*============================================================================= + Copyright (c) 2001-2003 Daniel Nuffer + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Demonstrates the ASTs. This is discussed in the +// "Trees" chapter in the Spirit User's Guide. +// +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_SPIRIT_DUMP_PARSETREE_AS_XML + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_ast.hpp> +#include <boost/spirit/include/classic_tree_to_xml.hpp> +#include <boost/assert.hpp> +#include "tree_calc_grammar.hpp" + +#include <iostream> +#include <stack> +#include <functional> +#include <string> + +#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML) +#include <map> +#endif + +// This example shows how to use an AST. +//////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +typedef char const* iterator_t; +typedef tree_match<iterator_t> parse_tree_match_t; +typedef parse_tree_match_t::tree_iterator iter_t; + +//////////////////////////////////////////////////////////////////////////// +long evaluate(parse_tree_match_t hit); +long eval_expression(iter_t const& i); + +long evaluate(tree_parse_info<> info) +{ + return eval_expression(info.trees.begin()); +} + +long eval_expression(iter_t const& i) +{ + cout << "In eval_expression. i->value = " << + string(i->value.begin(), i->value.end()) << + " i->children.size() = " << i->children.size() << endl; + + if (i->value.id() == calculator::integerID) + { + BOOST_ASSERT(i->children.size() == 0); + + // extract integer (not always delimited by '\0') + string integer(i->value.begin(), i->value.end()); + + return strtol(integer.c_str(), 0, 10); + } + else if (i->value.id() == calculator::factorID) + { + // factor can only be unary minus + BOOST_ASSERT(*i->value.begin() == '-'); + return - eval_expression(i->children.begin()); + } + else if (i->value.id() == calculator::termID) + { + if (*i->value.begin() == '*') + { + BOOST_ASSERT(i->children.size() == 2); + return eval_expression(i->children.begin()) * + eval_expression(i->children.begin()+1); + } + else if (*i->value.begin() == '/') + { + BOOST_ASSERT(i->children.size() == 2); + return eval_expression(i->children.begin()) / + eval_expression(i->children.begin()+1); + } + else + BOOST_ASSERT(0); + } + else if (i->value.id() == calculator::expressionID) + { + if (*i->value.begin() == '+') + { + BOOST_ASSERT(i->children.size() == 2); + return eval_expression(i->children.begin()) + + eval_expression(i->children.begin()+1); + } + else if (*i->value.begin() == '-') + { + BOOST_ASSERT(i->children.size() == 2); + return eval_expression(i->children.begin()) - + eval_expression(i->children.begin()+1); + } + else + BOOST_ASSERT(0); + } + else + { + BOOST_ASSERT(0); // error + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + // look in tree_calc_grammar for the definition of calculator + calculator calc; + + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tThe simplest working calculator...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + tree_parse_info<> info = ast_parse(str.c_str(), calc); + + if (info.full) + { +#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML) + // dump parse tree as XML + std::map<parser_id, std::string> rule_names; + rule_names[calculator::integerID] = "integer"; + rule_names[calculator::factorID] = "factor"; + rule_names[calculator::termID] = "term"; + rule_names[calculator::expressionID] = "expression"; + tree_to_xml(cout, info.trees, str.c_str(), rule_names); +#endif + + // print the result + cout << "parsing succeeded\n"; + cout << "result = " << evaluate(info) << "\n\n"; + } + else + { + cout << "parsing failed\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/bind.cpp b/src/boost/libs/spirit/classic/example/fundamental/bind.cpp new file mode 100644 index 00000000..f38e9c23 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/bind.cpp @@ -0,0 +1,126 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Demonstrates use of boost::bind and spirit +// This is discussed in the "Functional" chapter in the Spirit User's Guide. +// +// [ JDG 9/29/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/bind.hpp> +#include <iostream> +#include <vector> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace boost; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our comma separated list parser +// +/////////////////////////////////////////////////////////////////////////////// +class list_parser +{ +public: + + typedef list_parser self_t; + + bool + parse(char const* str) + { + return BOOST_SPIRIT_CLASSIC_NS::parse(str, + + // Begin grammar + ( + real_p + [ + bind(&self_t::add, this, _1) + ] + + >> *( ',' + >> real_p + [ + bind(&self_t::add, this, _1) + ] + ) + ) + , + // End grammar + + space_p).full; + } + + void + add(double n) + { + v.push_back(n); + } + + void + print() const + { + for (vector<double>::size_type i = 0; i < v.size(); ++i) + cout << i << ": " << v[i] << endl; + } + + vector<double> v; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\tA comma separated list parser for Spirit...\n"; + cout << "\tDemonstrates use of boost::bind and spirit\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + cout << "Give me a comma separated list of numbers.\n"; + cout << "The numbers will be inserted in a vector of numbers\n"; + cout << "Type [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + list_parser lp; + if (lp.parse(str.c_str())) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << endl; + + lp.print(); + + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/boiler_plate.cpp b/src/boost/libs/spirit/classic/example/fundamental/boiler_plate.cpp new file mode 100644 index 00000000..91c9fc73 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/boiler_plate.cpp @@ -0,0 +1,97 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Boiler plate [ A template for writing your parser ] +// +// [ JDG 9/17/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// Semantic actions +// +/////////////////////////////////////////////////////////////////////////////// +struct my_action +{ + template <typename IteratorT> + void operator()(IteratorT first, IteratorT last) const + { + string s(first, last); + cout << "\tMy Action got: " << s << endl; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// My grammar +// +/////////////////////////////////////////////////////////////////////////////// +struct my_grammar : public grammar<my_grammar> +{ + template <typename ScannerT> + struct definition + { + definition(my_grammar const& self) + { + my_rule = + *lexeme_d[(+graph_p)[my_action()]] + ; + } + + rule<ScannerT> my_rule; + rule<ScannerT> const& + start() const { return my_rule; } + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Main program +// +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\t A boiler-plate parser...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type anything or [q or Q] to quit\n\n"; + + my_grammar g; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + if (parse(str.c_str(), g, space_p).full) + { + cout << "parsing succeeded\n"; + } + else + { + cout << "parsing failed\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/calc_debug.cpp b/src/boost/libs/spirit/classic/example/fundamental/calc_debug.cpp new file mode 100644 index 00000000..f0ddf425 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/calc_debug.cpp @@ -0,0 +1,199 @@ +/*============================================================================= + Copyright (c) 2001-2003 Dan Nuffer + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +//////////////////////////////////////////////////////////////////////////// +// +// Full calculator example using STL functors with debugging enabled. +// This is discussed in the "Functional" chapter in the Spirit User's Guide +// and the Debugging chapter. +// +// Ported to Spirit v1.5 from v1.2/1.3 example by Dan Nuffer +// [ JDG 9/18/2002 ] +// [ JDG 7/29/2004 ] +// +//////////////////////////////////////////////////////////////////////////// + +#define BOOST_SPIRIT_DEBUG +#include <boost/spirit/include/classic_core.hpp> +#include <iostream> +#include <stack> +#include <functional> +#include <string> + +//////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +//////////////////////////////////////////////////////////////////////////// +// +// Semantic actions +// +//////////////////////////////////////////////////////////////////////////// +struct push_int +{ + push_int(stack<long>& eval_) + : eval(eval_) {} + + void operator()(char const* str, char const* /*end*/) const + { + long n = strtol(str, 0, 10); + eval.push(n); + cout << "push\t" << long(n) << endl; + } + + stack<long>& eval; +}; + +template <typename op> +struct do_op +{ + do_op(op const& the_op, stack<long>& eval_) + : m_op(the_op), eval(eval_) {} + + void operator()(char const*, char const*) const + { + long rhs = eval.top(); + eval.pop(); + long lhs = eval.top(); + eval.pop(); + + cout << "popped " << lhs << " and " << rhs << " from the stack. "; + cout << "pushing " << m_op(lhs, rhs) << " onto the stack.\n"; + eval.push(m_op(lhs, rhs)); + } + + op m_op; + stack<long>& eval; +}; + +template <class op> +do_op<op> +make_op(op const& the_op, stack<long>& eval) +{ + return do_op<op>(the_op, eval); +} + +struct do_negate +{ + do_negate(stack<long>& eval_) + : eval(eval_) {} + + void operator()(char const*, char const*) const + { + long lhs = eval.top(); + eval.pop(); + + cout << "popped " << lhs << " from the stack. "; + cout << "pushing " << -lhs << " onto the stack.\n"; + eval.push(-lhs); + } + + stack<long>& eval; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Our calculator grammar +// +//////////////////////////////////////////////////////////////////////////// +struct calculator : public grammar<calculator> +{ + calculator(stack<long>& eval_) + : eval(eval_) {} + + template <typename ScannerT> + struct definition + { + definition(calculator const& self) + { + integer = + lexeme_d[ (+digit_p)[push_int(self.eval)] ] + ; + + factor = + integer + | '(' >> expression >> ')' + | ('-' >> factor)[do_negate(self.eval)] + | ('+' >> factor) + ; + + term = + factor + >> *( ('*' >> factor)[make_op(multiplies<long>(), self.eval)] + | ('/' >> factor)[make_op(divides<long>(), self.eval)] + ) + ; + + expression = + term + >> *( ('+' >> term)[make_op(plus<long>(), self.eval)] + | ('-' >> term)[make_op(minus<long>(), self.eval)] + ) + ; + + BOOST_SPIRIT_DEBUG_NODE(integer); + BOOST_SPIRIT_DEBUG_NODE(factor); + BOOST_SPIRIT_DEBUG_NODE(term); + BOOST_SPIRIT_DEBUG_NODE(expression); + } + + rule<ScannerT> expression, term, factor, integer; + rule<ScannerT> const& + start() const { return expression; } + }; + + stack<long>& eval; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tThe simplest working calculator...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + stack<long> eval; + calculator calc(eval); // Our parser + BOOST_SPIRIT_DEBUG_NODE(calc); + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + parse_info<> info = parse(str.c_str(), calc, space_p); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << "result = " << calc.eval.top() << endl; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "stopped at: \": " << info.stop << "\"\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/calc_plain.cpp b/src/boost/libs/spirit/classic/example/fundamental/calc_plain.cpp new file mode 100644 index 00000000..520134f3 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/calc_plain.cpp @@ -0,0 +1,129 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +//////////////////////////////////////////////////////////////////////////// +// +// Plain calculator example demostrating the grammar and semantic actions. +// This is discussed in the "Grammar" and "Semantic Actions" chapters in +// the Spirit User's Guide. +// +// [ JDG 5/10/2002 ] +// +//////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <iostream> +#include <string> + +//////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +//////////////////////////////////////////////////////////////////////////// +// +// Semantic actions +// +//////////////////////////////////////////////////////////////////////////// +namespace +{ + void do_int(char const* str, char const* end) + { + string s(str, end); + cout << "PUSH(" << s << ')' << endl; + } + + void do_add(char const*, char const*) { cout << "ADD\n"; } + void do_subt(char const*, char const*) { cout << "SUBTRACT\n"; } + void do_mult(char const*, char const*) { cout << "MULTIPLY\n"; } + void do_div(char const*, char const*) { cout << "DIVIDE\n"; } + void do_neg(char const*, char const*) { cout << "NEGATE\n"; } +} + +//////////////////////////////////////////////////////////////////////////// +// +// Our calculator grammar +// +//////////////////////////////////////////////////////////////////////////// +struct calculator : public grammar<calculator> +{ + template <typename ScannerT> + struct definition + { + definition(calculator const& /*self*/) + { + expression + = term + >> *( ('+' >> term)[&do_add] + | ('-' >> term)[&do_subt] + ) + ; + + term + = factor + >> *( ('*' >> factor)[&do_mult] + | ('/' >> factor)[&do_div] + ) + ; + + factor + = lexeme_d[(+digit_p)[&do_int]] + | '(' >> expression >> ')' + | ('-' >> factor)[&do_neg] + | ('+' >> factor) + ; + } + + rule<ScannerT> expression, term, factor; + + rule<ScannerT> const& + start() const { return expression; } + }; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tExpression parser...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + calculator calc; // Our parser + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + parse_info<> info = parse(str.c_str(), calc, space_p); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "stopped at: \": " << info.stop << "\"\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/comments.cpp b/src/boost/libs/spirit/classic/example/fundamental/comments.cpp new file mode 100644 index 00000000..9ffb4168 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/comments.cpp @@ -0,0 +1,232 @@ +/*============================================================================= + Copyright (c) 2001-2003 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This example shows: +// 1. Parsing of different comment styles +// parsing C/C++-style comment +// parsing C++-style comment +// parsing PASCAL-style comment +// 2. Parsing tagged data with the help of the confix_parser +// 3. Parsing tagged data with the help of the confix_parser but the semantic +// action is directly attached to the body sequence parser +// +/////////////////////////////////////////////////////////////////////////////// + +#include <string> +#include <iostream> +#include <cassert> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_confix.hpp> +#include <boost/spirit/include/classic_chset.hpp> + + +/////////////////////////////////////////////////////////////////////////////// +// used namespaces +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// actor called after successfully matching a single character +class actor_string +{ +public: + actor_string(std::string &rstr) : + matched(rstr) + { + } + + void operator() (const char *pbegin, const char *pend) const + { + matched += std::string(pbegin, pend-pbegin); + } + +private: + std::string &matched; +}; + +/////////////////////////////////////////////////////////////////////////////// +// actor called after successfully matching a C++-comment +void actor_cpp (const char *pfirst, const char *plast) +{ + cout << "Parsing C++-comment" <<endl; + cout << "Matched (" << plast-pfirst << ") characters: "; + cout << "\"" << std::string(pfirst, plast) << "\"" << endl; +} + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int main () +{ + +/////////////////////////////////////////////////////////////////////////////// +// +// 1. Parsing different comment styles +// parsing C/C++-style comments (non-nested!) +// +/////////////////////////////////////////////////////////////////////////////// + + char const* pCComment = "/* This is a /* nested */ C-comment */"; + + rule<> cpp_comment; + + cpp_comment = + comment_p("/*", "*/") // rule for C-comments + | comment_p("//") // rule for C++ comments + ; + + std::string comment_c; + parse_info<> result; + + result = parse (pCComment, cpp_comment[actor_string(comment_c)]); + if (result.hit) + { + cout << "Parsed C-comment successfully!" << endl; + cout << "Matched (" << (int)comment_c.size() << ") characters: "; + cout << "\"" << comment_c << "\"" << endl; + } + else + { + cout << "Failed to parse C/C++-comment!" << endl; + } + cout << endl; + + // parsing C++-style comment + char const* pCPPComment = "// This is a C++-comment\n"; + std::string comment_cpp; + + result = parse (pCPPComment, cpp_comment[&actor_cpp]); + if (result.hit) + cout << "Parsed C++-comment successfully!" << endl; + else + cout << "Failed to parse C++-comment!" << endl; + + cout << endl; + + + // parsing PASCAL-style comment (nested!) + char const* pPComment = "{ This is a (* nested *) PASCAL-comment }"; + + rule<> pascal_comment; + + pascal_comment = // in PASCAL we have two comment styles + comment_nest_p('{', '}') // both may be nested + | comment_nest_p("(*", "*)") + ; + + std::string comment_pascal; + + result = parse (pPComment, pascal_comment[actor_string(comment_pascal)]); + if (result.hit) + { + cout << "Parsed PASCAL-comment successfully!" << endl; + cout << "Matched (" << (int)comment_pascal.size() << ") characters: "; + cout << "\"" << comment_pascal << "\"" << endl; + } + else + { + cout << "Failed to parse PASCAL-comment!" << endl; + } + cout << endl; + +/////////////////////////////////////////////////////////////////////////////// +// +// 2. Parsing tagged data with the help of the confix parser +// +/////////////////////////////////////////////////////////////////////////////// + + std::string body; + rule<> open_tag, html_tag, close_tag, body_text; + + open_tag = + str_p("<b>") + ; + + body_text = + anychar_p + ; + + close_tag = + str_p("</b>") + ; + + html_tag = + confix_p (open_tag, (*body_text)[actor_string(body)], close_tag) + ; + + char const* pTag = "<b>Body text</b>"; + + result = parse (pTag, html_tag); + if (result.hit) + { + cout << "Parsed HTML snippet \"<b>Body text</b>\" successfully " + "(with re-attached actor)!" << endl; + cout << "Found body (" << (int)body.size() << " characters): "; + cout << "\"" << body << "\"" << endl; + } + else + { + cout << "Failed to parse HTML snippet (with re-attached actor)!" + << endl; + } + cout << endl; + +/////////////////////////////////////////////////////////////////////////////// +// +// 3. Parsing tagged data with the help of the confix_parser but the +// semantic action is directly attached to the body sequence parser +// (see comment in confix.hpp) and out of the usage of the 'direct()' +// construction function no automatic refactoring takes place. +// +// As you can see, for successful parsing it is required to refactor the +// confix parser by hand. To see, how it fails, you can try the following: +// +// html_tag_direct = +// confix_p.direct( +// str_p("<b>"), +// (*body_text)[actor_string(bodydirect)], +// str_p("</b>") +// ) +// ; +// +// Here the *body_text parser eats up all the input up to the end of the +// input sequence. +// +/////////////////////////////////////////////////////////////////////////////// + + rule<> html_tag_direct; + std::string bodydirect; + + html_tag_direct = + confix_p.direct( + str_p("<b>"), + (*(body_text - str_p("</b>")))[actor_string(bodydirect)], + str_p("</b>") + ) + ; + + char const* pTagDirect = "<b>Body text</b>"; + + result = parse (pTagDirect, html_tag_direct); + if (result.hit) + { + cout << "Parsed HTML snippet \"<b>Body text</b>\" successfully " + "(with direct actor)!" << endl; + cout << "Found body (" << (int)bodydirect.size() << " characters): "; + cout << "\"" << bodydirect << "\"" << endl; + } + else + { + cout << "Failed to parse HTML snippet (with direct actor)!" << endl; + } + cout << endl; + + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/fundamental/complex_number.cpp b/src/boost/libs/spirit/classic/example/fundamental/complex_number.cpp new file mode 100644 index 00000000..3cb8d807 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/complex_number.cpp @@ -0,0 +1,103 @@ +/*============================================================================= + Copyright (c) 2001-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A complex number micro parser (using subrules) +// +// [ JDG 5/10/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <iostream> +#include <complex> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our complex number micro parser +// +/////////////////////////////////////////////////////////////////////////////// +bool +parse_complex(char const* str, complex<double>& c) +{ + double rN = 0.0; + double iN = 0.0; + + subrule<0> first; + subrule<1> r; + subrule<2> i; + + if (parse(str, + + // Begin grammar + ( + first = '(' >> r >> !(',' >> i) >> ')' | r, + r = real_p[assign(rN)], + i = real_p[assign(iN)] + ) + , + // End grammar + + space_p).full) + { + c = complex<double>(rN, iN); + return true; + } + else + { + return false; + } +} + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA complex number micro parser for Spirit...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + cout << "Give me a complex number of the form r or (r) or (r,i) \n"; + cout << "Type [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + complex<double> c; + if (parse_complex(str.c_str(), c)) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << c << endl; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/distinct/distinct_parser.cpp b/src/boost/libs/spirit/classic/example/fundamental/distinct/distinct_parser.cpp new file mode 100644 index 00000000..6b4506d6 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/distinct/distinct_parser.cpp @@ -0,0 +1,68 @@ +/*============================================================================= + Copyright (c) 2003 Vaclav Vesely + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 <boost/assert.hpp> +#include <iostream> +#include <boost/cstdlib.hpp> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_distinct.hpp> + +using namespace std; +using namespace boost; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +// keyword_p for C++ +// (for basic usage instead of std_p) +const distinct_parser<> keyword_p("0-9a-zA-Z_"); + +// keyword_d for C++ +// (for mor intricate usage, for example together with symbol tables) +const distinct_directive<> keyword_d("0-9a-zA-Z_"); + +struct my_grammar: public grammar<my_grammar> +{ + template <typename ScannerT> + struct definition + { + typedef rule<ScannerT> rule_t; + + definition(my_grammar const& self) + { + top + = + keyword_p("declare") // use keyword_p instead of std_p + >> !ch_p(':') + >> keyword_d[str_p("ident")] // use keyword_d + ; + } + + rule_t top; + + rule_t const& start() const + { + return top; + } + }; +}; + +int main() +{ + my_grammar gram; + parse_info<> info; + + info = parse("declare ident", gram, space_p); + BOOST_ASSERT(info.full); // valid input + + info = parse("declare: ident", gram, space_p); + BOOST_ASSERT(info.full); // valid input + + info = parse("declareident", gram, space_p); + BOOST_ASSERT(!info.hit); // invalid input + + return exit_success; +} diff --git a/src/boost/libs/spirit/classic/example/fundamental/distinct/distinct_parser_dynamic.cpp b/src/boost/libs/spirit/classic/example/fundamental/distinct/distinct_parser_dynamic.cpp new file mode 100644 index 00000000..8e64fd64 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/distinct/distinct_parser_dynamic.cpp @@ -0,0 +1,64 @@ +/*============================================================================= + Copyright (c) 2003 Vaclav Vesely + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 <boost/assert.hpp> +#include <iostream> +#include <boost/cstdlib.hpp> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_distinct.hpp> + +using namespace std; +using namespace boost; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +struct my_grammar: public grammar<my_grammar> +{ + template <typename ScannerT> + struct definition + { + typedef rule<ScannerT> rule_t; + + // keyword_p for ASN.1 + dynamic_distinct_parser<ScannerT> keyword_p; + + definition(my_grammar const& self) + : keyword_p(alnum_p | ('-' >> ~ch_p('-'))) // ASN.1 has quite complex naming rules + { + top + = + keyword_p("asn-declare") // use keyword_p instead of std_p + >> !str_p("--") + >> keyword_p("ident") + ; + } + + rule_t top; + + rule_t const& start() const + { + return top; + } + }; +}; + +int main() +{ + my_grammar gram; + parse_info<> info; + + info = parse("asn-declare ident", gram, space_p); + BOOST_ASSERT(info.full); // valid input + + info = parse("asn-declare--ident", gram, space_p); + BOOST_ASSERT(info.full); // valid input + + info = parse("asn-declare-ident", gram, space_p); + BOOST_ASSERT(!info.hit); // invalid input + + return exit_success; +} diff --git a/src/boost/libs/spirit/classic/example/fundamental/error_handling.cpp b/src/boost/libs/spirit/classic/example/fundamental/error_handling.cpp new file mode 100644 index 00000000..f2efcc24 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/error_handling.cpp @@ -0,0 +1,55 @@ +/*============================================================================= + Copyright (c) 1998-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demonstrates error handling as seen in the +// Error Handling" chapter in the User's Guide. +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_exceptions.hpp> +#include <iostream> +#include <boost/assert.hpp> + +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +struct handler +{ + template <typename ScannerT, typename ErrorT> + error_status<> + operator()(ScannerT const& /*scan*/, ErrorT const& /*error*/) const + { + cout << "exception caught...Test concluded successfully" << endl; + return error_status<>(error_status<>::fail); + } +}; + +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tExceptions Test...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + assertion<int> expect(0); + guard<int> my_guard; + + rule<> start = + my_guard(ch_p('a') >> 'b' >> 'c' >> expect( ch_p('d') )) + [ + handler() + ]; + + bool r = parse("abcx", start).full; + + BOOST_ASSERT(!r); + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/fundamental/error_reporting.cpp b/src/boost/libs/spirit/classic/example/fundamental/error_reporting.cpp new file mode 100644 index 00000000..4b18781f --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/error_reporting.cpp @@ -0,0 +1,114 @@ +/*============================================================================= + Copyright (c) 2003 Pavel Baranov + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// An alternate error-handling scheme where the parser will +// complain (but not stop) if input doesn't match. +// +// [ Pavel Baranov 8/27/2003 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_functor_parser.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +static short errcount = 0; + +/////////////////////////////////////////////////////////////////////////////// +// +// Error reporting parser +// +/////////////////////////////////////////////////////////////////////////////// +struct error_report_parser { + + error_report_parser(const char *msg) : _msg(msg) {} + + typedef nil_t result_t; + + template <typename ScannerT> + int operator()(ScannerT const& scan, result_t& /*result*/) const + { + errcount++; + cerr << _msg << endl; + return 0; + } + +private: + string _msg; +}; + +typedef functor_parser<error_report_parser> error_report_p; + +/////////////////////////////////////////////////////////////////////////////// +// +// My grammar +// +/////////////////////////////////////////////////////////////////////////////// +struct my_grammar : public grammar<my_grammar> +{ + static error_report_p error_missing_semicolon; + static error_report_p error_missing_letter; + + template <typename ScannerT> + struct definition + { + definition(my_grammar const& self) : + SEMICOLON(';') + { + my_rule + = *(eps_p(alpha_p|SEMICOLON) >> + (alpha_p|error_missing_letter) >> + (SEMICOLON|error_missing_semicolon)) + ; + } + + chlit<> + SEMICOLON; + + rule<ScannerT> my_rule; + + rule<ScannerT> const& + start() const { return my_rule; } + }; +}; + +error_report_p my_grammar::error_missing_semicolon("missing semicolon"); +error_report_p my_grammar::error_missing_letter("missing letter"); + +/////////////////////////////////////////////////////////////////////////////// +// +// Main program +// +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << " Error handling demo\n\n"; + cout << " The parser expects a sequence of letter/semicolon pairs\n"; + cout << " and will complain (but not stop) if input doesn't match.\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + my_grammar g; + + string str( "a;;b;cd;e;fg;" ); + cout << "input: " << str << "\n\n"; + + if( parse(str.c_str(), g, space_p).full && !errcount ) + cout << "\nparsing succeeded\n"; + else + cout << "\nparsing failed\n"; + + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/fundamental/file_parser.cpp b/src/boost/libs/spirit/classic/example/fundamental/file_parser.cpp new file mode 100644 index 00000000..cd4036b1 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/file_parser.cpp @@ -0,0 +1,89 @@ +/*============================================================================= + Copyright (c) 2002 Jeff Westfahl + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A parser that echoes a file +// See the "File Iterator" chapter in the User's Guide. +// +// [ JMW 8/05/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_file_iterator.hpp> +#include <iostream> + +/////////////////////////////////////////////////////////////////////////////// +using namespace BOOST_SPIRIT_CLASSIC_NS; + +//////////////////////////////////////////////////////////////////////////// +// +// Types +// +//////////////////////////////////////////////////////////////////////////// +typedef char char_t; +typedef file_iterator<char_t> iterator_t; +typedef scanner<iterator_t> scanner_t; +typedef rule<scanner_t> rule_t; + +//////////////////////////////////////////////////////////////////////////// +// +// Actions +// +//////////////////////////////////////////////////////////////////////////// +void echo(iterator_t first, iterator_t const& last) +{ + while (first != last) + std::cout << *first++; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main(int argc, char* argv[]) +{ + if (2 > argc) + { + std::cout << "Must specify a filename!\n"; + return -1; + } + + // Create a file iterator for this file + iterator_t first(argv[1]); + + if (!first) + { + std::cout << "Unable to open file!\n"; + return -1; + } + + // Create an EOF iterator + iterator_t last = first.make_end(); + + // A simple rule + rule_t r = *(anychar_p); + + // Parse + parse_info <iterator_t> info = parse( + first, + last, + r[&echo] + ); + + // This really shouldn't fail... + if (info.full) + std::cout << "Parse succeeded!\n"; + else + std::cout << "Parse failed!\n"; + + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/fundamental/full_calc.cpp b/src/boost/libs/spirit/classic/example/fundamental/full_calc.cpp new file mode 100644 index 00000000..e1184d05 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/full_calc.cpp @@ -0,0 +1,188 @@ +/*============================================================================= + Copyright (c) 2001-2003 Dan Nuffer + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +//////////////////////////////////////////////////////////////////////////// +// +// Full calculator example using STL functors +// This is discussed in the "Functional" chapter in the Spirit User's Guide. +// +// Ported to Spirit v1.5 from v1.2/1.3 example by Dan Nuffer +// [ JDG 9/18/2002 ] +// +//////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <iostream> +#include <stack> +#include <functional> +#include <string> + +//////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +//////////////////////////////////////////////////////////////////////////// +// +// Semantic actions +// +//////////////////////////////////////////////////////////////////////////// +struct push_int +{ + push_int(stack<long>& eval_) + : eval(eval_) {} + + void operator()(char const* str, char const* /*end*/) const + { + long n = strtol(str, 0, 10); + eval.push(n); + cout << "push\t" << long(n) << endl; + } + + stack<long>& eval; +}; + +template <typename op> +struct do_op +{ + do_op(op const& the_op, stack<long>& eval_) + : m_op(the_op), eval(eval_) {} + + void operator()(char const*, char const*) const + { + long rhs = eval.top(); + eval.pop(); + long lhs = eval.top(); + eval.pop(); + + cout << "popped " << lhs << " and " << rhs << " from the stack. "; + cout << "pushing " << m_op(lhs, rhs) << " onto the stack.\n"; + eval.push(m_op(lhs, rhs)); + } + + op m_op; + stack<long>& eval; +}; + +template <class op> +do_op<op> +make_op(op const& the_op, stack<long>& eval) +{ + return do_op<op>(the_op, eval); +} + +struct do_negate +{ + do_negate(stack<long>& eval_) + : eval(eval_) {} + + void operator()(char const*, char const*) const + { + long lhs = eval.top(); + eval.pop(); + + cout << "popped " << lhs << " from the stack. "; + cout << "pushing " << -lhs << " onto the stack.\n"; + eval.push(-lhs); + } + + stack<long>& eval; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Our calculator grammar +// +//////////////////////////////////////////////////////////////////////////// +struct calculator : public grammar<calculator> +{ + calculator(stack<long>& eval_) + : eval(eval_) {} + + template <typename ScannerT> + struct definition + { + definition(calculator const& self) + { + integer = + lexeme_d[ (+digit_p)[push_int(self.eval)] ] + ; + + factor = + integer + | '(' >> expression >> ')' + | ('-' >> factor)[do_negate(self.eval)] + | ('+' >> factor) + ; + + term = + factor + >> *( ('*' >> factor)[make_op(multiplies<long>(), self.eval)] + | ('/' >> factor)[make_op(divides<long>(), self.eval)] + ) + ; + + expression = + term + >> *( ('+' >> term)[make_op(plus<long>(), self.eval)] + | ('-' >> term)[make_op(minus<long>(), self.eval)] + ) + ; + } + + rule<ScannerT> expression, term, factor, integer; + rule<ScannerT> const& + start() const { return expression; } + }; + + stack<long>& eval; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tThe simplest working calculator...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + stack<long> eval; + calculator calc(eval); // Our parser + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + parse_info<> info = parse(str.c_str(), calc, space_p); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "stopped at: \": " << info.stop << "\"\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/functor_parser.cpp b/src/boost/libs/spirit/classic/example/fundamental/functor_parser.cpp new file mode 100644 index 00000000..e9a52f31 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/functor_parser.cpp @@ -0,0 +1,160 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + Copyright (c) 2002 Juan Carlos Arevalo-Baeza + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_functor_parser.hpp> +#include <boost/spirit/include/classic_assign_actor.hpp> +#include <iostream> +#include <vector> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +// +// Demonstrates the functor_parser. This is discussed in the +// "Functor Parser" chapter in the Spirit User's Guide. +// +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our parser functor +// +/////////////////////////////////////////////////////////////////////////////// +struct number_parser +{ + typedef int result_t; + template <typename ScannerT> + int + operator()(ScannerT const& scan, result_t& result) const + { + if (scan.at_end()) + return -1; + + char ch = *scan; + if (ch < '0' || ch > '9') + return -1; + + result = 0; + int len = 0; + + do + { + result = result*10 + int(ch - '0'); + ++len; + ++scan; + } while (!scan.at_end() && (ch = *scan, ch >= '0' && ch <= '9')); + + return len; + } +}; + +functor_parser<number_parser> number_parser_p; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our number parser functions +// +/////////////////////////////////////////////////////////////////////////////// +bool +parse_number(char const* str, int& n) +{ + return parse(str, lexeme_d[number_parser_p[assign_a(n)]], space_p).full; +} + +bool +parse_numbers(char const* str, std::vector<int>& n) +{ + return + parse( + str, + lexeme_d[number_parser_p[push_back_a(n)]] + >> *(',' >> lexeme_d[number_parser_p[push_back_a(n)]]), + space_p + ).full; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA number parser implemented as a functor for Spirit...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + cout << "Give me an integer number command\n"; + cout << "Commands:\n"; + cout << " A <num> --> parses a single number\n"; + cout << " B <num>, <num>, ... --> parses a series of numbers "; + cout << "separated by commas\n"; + cout << " Q --> quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + else if (str[0] == 'a' || str[0] == 'A') + { + int n; + if (parse_number(str.c_str()+1, n)) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << n << endl; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + else if (str[0] == 'b' || str[0] == 'B') + { + std::vector<int> n; + if (parse_numbers(str.c_str()+1, n)) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + int size = n.size(); + cout << str << " Parses OK: " << size << " number(s): " << n[0]; + for (int i = 1; i < size; ++i) { + cout << ", " << n[i]; + } + cout << endl; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + else + { + cout << "-------------------------\n"; + cout << "Unrecognized command!!"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/fundamental/list_parser.cpp b/src/boost/libs/spirit/classic/example/fundamental/list_parser.cpp new file mode 100644 index 00000000..922fb5d0 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/list_parser.cpp @@ -0,0 +1,233 @@ +/*============================================================================= + Copyright (c) 2001-2003 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// This sample shows the usage of the list_p utility parser +// 1. parsing a simple ',' delimited list w/o item formatting +// 2. parsing a CSV list (comma separated values - strings, integers or reals) +// 3. parsing a token list (token separated values - strings, integers or +// reals) +// with an action parser directly attached to the item part of the list_p +// generated parser + +#include <string> +#include <iostream> +#include <cassert> +#include <vector> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_confix.hpp> +#include <boost/spirit/include/classic_lists.hpp> +#include <boost/spirit/include/classic_escape_char.hpp> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// actor, attached to the list_p parser +class list_actor +{ +public: + list_actor (std::vector<std::string> &vec_) : vec(vec_) {} + + // The following operator() is called by the action parser generated by + // attaching this actor to a list_p generated list parser. + + template <typename ActionIterT> + void operator() (ActionIterT const &first, ActionIterT const &last) const + { + vec.push_back(std::string(first, last-first)); + } + +private: + std::vector<std::string> &vec; +}; + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int main () +{ + // 1. parsing a simple ',' delimited list w/o item formatting + char const* plist_wo_item = "element1,element2,element3"; + rule<> list_wo_item; + std::vector<std::string> vec_list; + + list_wo_item = + list_p[push_back_a(vec_list)] + ; + + parse_info<> result = parse (plist_wo_item, list_wo_item); + + cout << "-----------------------------------------------------------------" + << endl; + + if (result.hit) + { + cout + << "Parsing simple list" << endl + << "\t" << plist_wo_item << endl + << "Parsed successfully!" << endl << endl; + + cout + << "Actor was called " << (int)vec_list.size() + << " times: " << endl; + + cout + << "Results got from the list parser:" << endl; + for (std::vector<std::string>::iterator it = vec_list.begin(); + it != vec_list.end(); ++it) + { + cout << *it << endl; + } + } + else + { + cout << "Failed to parse simple list!" << endl; + } + + cout << endl; + + // 2. parsing a CSV list (comma separated values - strings, integers or + // reals) + char const *plist_csv = "\"string\",\"string with an embedded \\\"\"," + "12345,0.12345e4,,2"; + rule<> list_csv, list_csv_item; + std::vector<std::string> vec_item; + + vec_list.clear(); + + list_csv_item = + !( + confix_p('\"', *c_escape_ch_p, '\"') + | longest_d[real_p | int_p] + ); + + list_csv = + list_p( + list_csv_item[push_back_a(vec_item)], + ',' + )[push_back_a(vec_list)] + ; + + result = parse (plist_csv, list_csv); + + cout << "-----------------------------------------------------------------" + << endl; + if (result.hit) + { + cout + << "Parsing CSV list (comma separated values) " << endl + << "\t" << plist_csv << endl + << "Parsed successfully!" << endl << endl; + + if (result.full) + { + cout << "Matched " << (int)vec_list.size() << + " list elements (full list): " << endl; + } + else + { + cout << "Matched " << (int)vec_list.size() << + " list elements: " << endl; + } + + cout << "The list parser matched:" << endl; + for (std::vector<std::string>::iterator itl = vec_list.begin(); + itl != vec_list.end(); ++itl) + { + cout << *itl << endl; + } + + cout << endl << "Item(s) got directly from the item parser:" << endl; + for (std::vector<std::string>::iterator it = vec_item.begin(); + it != vec_item.end(); ++it) + { + cout << *it << endl; + } + + } + else + { + cout << "Failed to parse CSV list!" << endl; + } + + cout << endl; + + // 3. parsing a token list (token separated values - strings, integers or + // reals) with an action parser directly attached to the item part of the + // list_p generated parser + char const *plist_csv_direct = "\"string\"<par>\"string with an embedded " + "\\\"\"<par>12345<par>0.12345e4"; + rule<> list_csv_direct, list_csv_direct_item; + + vec_list.clear(); + vec_item.clear(); + + // Note: the list parser is here generated through the list_p.direct() + // generator function. This inhibits re-attachment of the item_actor_direct + // during parser construction (see: comment in utility/lists.hpp) + list_csv_direct_item = + confix_p('\"', *c_escape_ch_p, '\"') + | longest_d[real_p | int_p] + ; + + list_csv_direct = + list_p.direct( + (*list_csv_direct_item)[list_actor(vec_item)], + "<par>" + )[list_actor(vec_list)] + ; + + result = parse (plist_csv_direct, list_csv_direct); + + cout << "-----------------------------------------------------------------" + << endl; + if (result.hit) + { + cout + << "Parsing CSV list (comma separated values)" << endl + << "The list parser was generated with 'list_p.direct()'" << endl + << "\t" << plist_csv_direct << endl + << "Parsed successfully!" << endl << endl; + + if (result.full) + { + cout << "Matched " << vec_list.size() << + " list elements (full list): " << endl; + } + else + { + cout << "Matched " << vec_list.size() << + " list elements: " << endl; + } + + cout << "The list parser matched:" << endl; + for (std::vector<std::string>::iterator itl = vec_list.begin(); + itl != vec_list.end(); ++itl) + { + cout << *itl << endl; + } + + cout << endl << "Items got directly from the item parser:" << endl; + for (std::vector<std::string>::iterator it = vec_item.begin(); + it != vec_item.end(); ++it) + { + cout << *it << endl; + } + + } + else + { + cout << "Failed to parse CSV list!" << endl; + } + + cout << endl; + + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/fundamental/matching_tags.cpp b/src/boost/libs/spirit/classic/example/fundamental/matching_tags.cpp new file mode 100644 index 00000000..14581ff5 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/matching_tags.cpp @@ -0,0 +1,115 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +//////////////////////////////////////////////////////////////////////////// +// +// HTML/XML like tag matching grammar +// Demonstrates phoenix and closures and parametric parsers +// This is discussed in the "Closures" chapter in the Spirit User's Guide. +// +// [ JDG 6/30/2002 ] +// +//////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_attribute.hpp> +#include <iostream> +#include <string> + +//////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +//////////////////////////////////////////////////////////////////////////// +// +// HTML/XML like tag matching grammar +// +//////////////////////////////////////////////////////////////////////////// +struct tags_closure : BOOST_SPIRIT_CLASSIC_NS::closure<tags_closure, string> +{ + member1 tag; +}; + +struct tags : public grammar<tags> +{ + template <typename ScannerT> + struct definition { + + definition(tags const& /*self*/) + { + element = start_tag >> *element >> end_tag; + + start_tag = + '<' + >> lexeme_d + [ + (+alpha_p) + [ + // construct string from arg1 and arg2 lazily + // and assign to element.tag + + element.tag = construct_<string>(arg1, arg2) + ] + ] + >> '>'; + + end_tag = "</" >> f_str_p(element.tag) >> '>'; + } + + rule<ScannerT, tags_closure::context_t> element; + rule<ScannerT> start_tag, end_tag; + + rule<ScannerT, tags_closure::context_t> const& + start() const { return element; } + }; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tHTML/XML like tag matching parser demo \n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an HTML/XML like nested tag input...or [q or Q] to quit\n\n"; + cout << "Example: <html><head></head><body></body></html>\n\n"; + + tags p; // Our parser + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + parse_info<> info = parse(str.c_str(), p, space_p); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "stopped at: \": " << info.stop << "\"\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/more_calculators/ast_calc2.cpp b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/ast_calc2.cpp new file mode 100644 index 00000000..a017b65f --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/ast_calc2.cpp @@ -0,0 +1,180 @@ +/*============================================================================= + Copyright (c) 2001-2003 Daniel Nuffer + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_ast.hpp> +#include <boost/assert.hpp> + +#include <iostream> +#include <stack> +#include <functional> +#include <string> + +// This example shows how to use an AST and tree_iter_node instead of +// tree_val_node +//////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +typedef char const* iterator_t; +typedef tree_match<iterator_t, node_iter_data_factory<> > + parse_tree_match_t; + +typedef parse_tree_match_t::tree_iterator iter_t; + +typedef ast_match_policy<iterator_t, node_iter_data_factory<> > match_policy_t; +typedef scanner<iterator_t, scanner_policies<iter_policy_t, match_policy_t> > scanner_t; +typedef rule<scanner_t> rule_t; + + +// grammar rules +rule_t expression, term, factor, integer; + +//////////////////////////////////////////////////////////////////////////// +long evaluate(parse_tree_match_t hit); +long eval_expression(iter_t const& i); +long eval_term(iter_t const& i); +long eval_factor(iter_t const& i); +long eval_integer(iter_t const& i); + +long evaluate(parse_tree_match_t hit) +{ + return eval_expression(hit.trees.begin()); +} + +long eval_expression(iter_t const& i) +{ + cout << "In eval_expression. i->value = " << + string(i->value.begin(), i->value.end()) << + " i->children.size() = " << i->children.size() << endl; + + cout << "ID: " << i->value.id().to_long() << endl; + + if (i->value.id() == integer.id()) + { + BOOST_ASSERT(i->children.size() == 0); + return strtol(i->value.begin(), 0, 10); + } + else if (i->value.id() == factor.id()) + { + // factor can only be unary minus + BOOST_ASSERT(*i->value.begin() == '-'); + return - eval_expression(i->children.begin()); + } + else if (i->value.id() == term.id()) + { + if (*i->value.begin() == '*') + { + BOOST_ASSERT(i->children.size() == 2); + return eval_expression(i->children.begin()) * + eval_expression(i->children.begin()+1); + } + else if (*i->value.begin() == '/') + { + BOOST_ASSERT(i->children.size() == 2); + return eval_expression(i->children.begin()) / + eval_expression(i->children.begin()+1); + } + else + BOOST_ASSERT(0); + } + else if (i->value.id() == expression.id()) + { + if (*i->value.begin() == '+') + { + BOOST_ASSERT(i->children.size() == 2); + return eval_expression(i->children.begin()) + + eval_expression(i->children.begin()+1); + } + else if (*i->value.begin() == '-') + { + BOOST_ASSERT(i->children.size() == 2); + return eval_expression(i->children.begin()) - + eval_expression(i->children.begin()+1); + } + else + BOOST_ASSERT(0); + } + else + BOOST_ASSERT(0); // error + + return 0; +} + +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + BOOST_SPIRIT_DEBUG_RULE(integer); + BOOST_SPIRIT_DEBUG_RULE(factor); + BOOST_SPIRIT_DEBUG_RULE(term); + BOOST_SPIRIT_DEBUG_RULE(expression); + // Start grammar definition + integer = leaf_node_d[ lexeme_d[ (!ch_p('-') >> +digit_p) ] ]; + factor = integer + | inner_node_d[ch_p('(') >> expression >> ch_p(')')] + | (root_node_d[ch_p('-')] >> factor); + term = factor >> + *( (root_node_d[ch_p('*')] >> factor) + | (root_node_d[ch_p('/')] >> factor) + ); + expression = term >> + *( (root_node_d[ch_p('+')] >> term) + | (root_node_d[ch_p('-')] >> term) + ); + // End grammar definition + + + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tThe simplest working calculator...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + const char* str_begin = str.c_str(); + const char* str_end = str.c_str(); + while (*str_end) + ++str_end; + + scanner_t scan(str_begin, str_end); + + parse_tree_match_t hit = expression.parse(scan); + + + if (hit && str_begin == str_end) + { +#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML) + // dump parse tree as XML + std::map<rule_id, std::string> rule_names; + rule_names[&integer] = "integer"; + rule_names[&factor] = "factor"; + rule_names[&term] = "term"; + rule_names[&expression] = "expression"; + tree_to_xml(cout, hit.trees, str.c_str(), rule_names); +#endif + + // print the result + cout << "parsing succeeded\n"; + cout << "result = " << evaluate(hit) << "\n\n"; + } + else + { + cout << "parsing failed\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/more_calculators/calc_with_variables.cpp b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/calc_with_variables.cpp new file mode 100644 index 00000000..5e43a7fc --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/calc_with_variables.cpp @@ -0,0 +1,261 @@ +/*============================================================================= + Copyright (c) 2001-2003 Dan Nuffer + Copyright (c) 2001-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Full calculator example with variables +// [ JDG 9/18/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_symbols.hpp> +#include <iostream> +#include <stack> +#include <functional> +#include <string> + +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// Semantic actions +// +/////////////////////////////////////////////////////////////////////////////// +struct push_num +{ + push_num(stack<double>& eval_) + : eval(eval_) {} + + void operator()(double n) const + { + eval.push(n); + cout << "push\t" << n << endl; + } + + stack<double>& eval; +}; + +template <typename op> +struct do_op +{ + do_op(op const& the_op, stack<double>& eval_) + : m_op(the_op), eval(eval_) {} + + void operator()(char const*, char const*) const + { + double rhs = eval.top(); + eval.pop(); + double lhs = eval.top(); + eval.pop(); + + cout << "popped " << lhs << " and " << rhs << " from the stack. "; + cout << "pushing " << m_op(lhs, rhs) << " onto the stack.\n"; + eval.push(m_op(lhs, rhs)); + } + + op m_op; + stack<double>& eval; +}; + +template <class op> +do_op<op> +make_op(op const& the_op, stack<double>& eval) +{ + return do_op<op>(the_op, eval); +} + +struct do_negate +{ + do_negate(stack<double>& eval_) + : eval(eval_) {} + + void operator()(char const*, char const*) const + { + double lhs = eval.top(); + eval.pop(); + + cout << "popped " << lhs << " from the stack. "; + cout << "pushing " << -lhs << " onto the stack.\n"; + eval.push(-lhs); + } + + stack<double>& eval; +}; + +struct get_var +{ + get_var(stack<double>& eval_) + : eval(eval_) {} + + void operator()(double n) const + { + eval.push(n); + cout << "push\t" << n << endl; + } + + stack<double>& eval; +}; + +struct set_var +{ + set_var(double*& var_) + : var(var_) {} + + void operator()(double& n) const + { + var = &n; + } + + double*& var; +}; + +struct redecl_var +{ + void operator()(double& /*n*/) const + { + cout << "Warning. You are attempting to re-declare a var.\n"; + } +}; + +struct do_assign +{ + do_assign(double*& var_, stack<double>& eval_) + : var(var_), eval(eval_) {} + + void operator()(char const*, char const*) const + { + if (var != 0) + { + *var = eval.top(); + cout << "assigning\n"; + } + } + + double*& var; + stack<double>& eval; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our calculator grammar +// +/////////////////////////////////////////////////////////////////////////////// +struct calculator : public grammar<calculator> +{ + calculator(stack<double>& eval_) + : eval(eval_) {} + + template <typename ScannerT> + struct definition + { + definition(calculator const& self) + { + factor = + real_p[push_num(self.eval)] + | vars[get_var(self.eval)] + | '(' >> expression >> ')' + | ('-' >> factor)[do_negate(self.eval)] + ; + + term = + factor + >> *( ('*' >> factor)[make_op(multiplies<double>(), self.eval)] + | ('/' >> factor)[make_op(divides<double>(), self.eval)] + ) + ; + + expression = + term + >> *( ('+' >> term)[make_op(plus<double>(), self.eval)] + | ('-' >> term)[make_op(minus<double>(), self.eval)] + ) + ; + + assignment = + vars[set_var(self.var)] + >> '=' >> expression[do_assign(self.var, self.eval)] + ; + + var_decl = + lexeme_d + [ + ((alpha_p >> *(alnum_p | '_')) + - vars[redecl_var()])[vars.add] + ] + ; + + declaration = + lexeme_d["var" >> space_p] >> var_decl >> *(',' >> var_decl) + ; + + statement = + declaration | assignment | '?' >> expression + ; + } + + symbols<double> vars; + rule<ScannerT> statement, declaration, var_decl, + assignment, expression, term, factor; + + rule<ScannerT> const& + start() const { return statement; } + }; + + mutable double* var; + stack<double>& eval; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Main program +// +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tThe calculator with variables...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type a statement...or [q or Q] to quit\n\n"; + cout << "Variables may be declared:\t\tExample: var i, j, k\n"; + cout << "Assigning to a variable:\t\tExample: i = 10 * j\n"; + cout << "To evaluate an expression:\t\tExample: ? i * 3.33E-3\n\n"; + + stack<double> eval; + calculator calc(eval); // Our parser + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + parse_info<> info = parse(str.c_str(), calc, space_p); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "stopped at: \": " << info.stop << "\"\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/more_calculators/phoenix_subrule_calc.cpp b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/phoenix_subrule_calc.cpp new file mode 100644 index 00000000..9cdfdd04 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/phoenix_subrule_calc.cpp @@ -0,0 +1,142 @@ +/*============================================================================= + Copyright (c) 2002-2003 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Full calculator example +// [ demonstrating phoenix and subrules ] +// +// [ Hartmut Kaiser 10/8/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// + +//#define BOOST_SPIRIT_DEBUG // define this for debug output + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_attribute.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our calculator grammar using phoenix to do the semantics and subrule's +// as it's working horses +// +// Note: The top rule propagates the expression result (value) upwards +// to the calculator grammar self.val closure member which is +// then visible outside the grammar (i.e. since self.val is the +// member1 of the closure, it becomes the attribute passed by +// the calculator to an attached semantic action. See the +// driver code that uses the calculator below). +// +/////////////////////////////////////////////////////////////////////////////// +struct calc_closure : BOOST_SPIRIT_CLASSIC_NS::closure<calc_closure, double> +{ + member1 val; +}; + +struct calculator : public grammar<calculator, calc_closure::context_t> +{ + template <typename ScannerT> + struct definition + { + definition(calculator const& self) + { + top = ( + expression = + term[self.val = arg1] + >> *( ('+' >> term[self.val += arg1]) + | ('-' >> term[self.val -= arg1]) + ) + , + + term = + factor[term.val = arg1] + >> *( ('*' >> factor[term.val *= arg1]) + | ('/' >> factor[term.val /= arg1]) + ) + , + + factor + = ureal_p[factor.val = arg1] + | '(' >> expression[factor.val = arg1] >> ')' + | ('-' >> factor[factor.val = -arg1]) + | ('+' >> factor[factor.val = arg1]) + ); + + BOOST_SPIRIT_DEBUG_NODE(top); + BOOST_SPIRIT_DEBUG_NODE(expression); + BOOST_SPIRIT_DEBUG_NODE(term); + BOOST_SPIRIT_DEBUG_NODE(factor); + } + + subrule<0, calc_closure::context_t> expression; + subrule<1, calc_closure::context_t> term; + subrule<2, calc_closure::context_t> factor; + + rule<ScannerT> top; + + rule<ScannerT> const& + start() const { return top; } + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Main program +// +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tExpression parser using Phoenix...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + calculator calc; // Our parser + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + double n = 0; + parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p); + + // calc[var(n) = arg1] invokes the calculator and extracts + // the result of the computation. See calculator grammar + // note above. + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << "result = " << n << endl; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "stopped at: \": " << info.stop << "\"\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/more_calculators/primitive_calc.cpp b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/primitive_calc.cpp new file mode 100644 index 00000000..22babb52 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/primitive_calc.cpp @@ -0,0 +1,96 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A primitive calculator that knows how to add and subtract. +// [ demonstrating phoenix ] +// +// [ JDG 6/28/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/phoenix1_primitives.hpp> +#include <boost/spirit/include/phoenix1_operators.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our primitive calculator +// +/////////////////////////////////////////////////////////////////////////////// +template <typename IteratorT> +bool primitive_calc(IteratorT first, IteratorT last, double& n) +{ + return parse(first, last, + + // Begin grammar + ( + real_p[var(n) = arg1] + >> *( ('+' >> real_p[var(n) += arg1]) + | ('-' >> real_p[var(n) -= arg1]) + ) + ) + , + // End grammar + + space_p).full; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA primitive calculator...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + cout << "Give me a list of numbers to be added or subtracted.\n"; + cout << "Example: 1 + 10 + 3 - 4 + 9\n"; + cout << "The result is computed using Phoenix.\n"; + cout << "Type [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + double n; + if (primitive_calc(str.begin(), str.end(), n)) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << endl; + + cout << "result = " << n; + cout << "\n-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/more_calculators/rpn_calc.cpp b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/rpn_calc.cpp new file mode 100644 index 00000000..844a7915 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/rpn_calc.cpp @@ -0,0 +1,163 @@ +/*============================================================================= + Copyright (c) 2001-2003 Hartmut Kaiser + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample shows, how to use Phoenix for implementing a +// simple (RPN style) calculator [ demonstrating phoenix ] +// +// [ HKaiser 2001 ] +// [ JDG 6/29/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_attribute.hpp> +#include <boost/spirit/include/phoenix1_functions.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our RPN calculator grammar using phoenix to do the semantics +// The class 'RPNCalculator' implements a polish reverse notation +// calculator which is equivalent to the following YACC description. +// +// exp: +// NUM { $$ = $1; } +// | exp exp '+' { $$ = $1 + $2; } +// | exp exp '-' { $$ = $1 - $2; } +// | exp exp '*' { $$ = $1 * $2; } +// | exp exp '/' { $$ = $1 / $2; } +// | exp exp '^' { $$ = pow ($1, $2); } /* Exponentiation */ +// | exp 'n' { $$ = -$1; } /* Unary minus */ +// ; +// +// The different notation results from the requirement of LL parsers not to +// allow left recursion in their grammar (would lead to endless recursion). +// Therefore the left recursion in the YACC script before is transformated +// into iteration. To some, this is less intuitive, but once you get used +// to it, it's very easy to follow. +// +// Note: The top rule propagates the expression result (value) upwards +// to the calculator grammar self.val closure member which is +// then visible outside the grammar (i.e. since self.val is the +// member1 of the closure, it becomes the attribute passed by +// the calculator to an attached semantic action. See the +// driver code that uses the calculator below). +// +/////////////////////////////////////////////////////////////////////////////// +struct pow_ +{ + template <typename X, typename Y> + struct result { typedef X type; }; + + template <typename X, typename Y> + X operator()(X x, Y y) const + { + using namespace std; + return pow(x, y); + } +}; + +// Notice how power(x, y) is lazily implemented using Phoenix function. +function<pow_> power; + +struct calc_closure : BOOST_SPIRIT_CLASSIC_NS::closure<calc_closure, double, double> +{ + member1 x; + member2 y; +}; + +struct calculator : public grammar<calculator, calc_closure::context_t> +{ + template <typename ScannerT> + struct definition { + + definition(calculator const& self) + { + top = expr [self.x = arg1]; + expr = + real_p [expr.x = arg1] + >> *( + expr [expr.y = arg1] + >> ( + ch_p('+') [expr.x += expr.y] + | ch_p('-') [expr.x -= expr.y] + | ch_p('*') [expr.x *= expr.y] + | ch_p('/') [expr.x /= expr.y] + | ch_p('^') [expr.x = power(expr.x, expr.y)] + ) + | ch_p('n') [expr.x = -expr.x] + ) + ; + } + + typedef rule<ScannerT, calc_closure::context_t> rule_t; + rule_t expr; + rule<ScannerT> top; + + rule<ScannerT> const& + start() const { return top; } + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Main program +// +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tExpression parser using Phoenix...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + calculator calc; // Our parser + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + double n = 0; + parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p); + + // calc[var(n) = arg1] invokes the calculator and extracts + // the result of the computation. See calculator grammar + // note above. + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << "result = " << n << endl; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "stopped at: \": " << info.stop << "\"\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/more_calculators/vmachine_calc.cpp b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/vmachine_calc.cpp new file mode 100644 index 00000000..bbcb52df --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/more_calculators/vmachine_calc.cpp @@ -0,0 +1,275 @@ +/*============================================================================= + Copyright (c) 1998-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +//////////////////////////////////////////////////////////////////////////// +// +// The calculator using a simple virtual machine and compiler. +// +// Ported to v1.5 from the original v1.0 code by JDG +// [ JDG 9/18/2002 ] +// +//////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <iostream> +#include <vector> +#include <string> + +//////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// The VMachine +// +/////////////////////////////////////////////////////////////////////////////// +enum ByteCodes +{ + OP_NEG, // negate the top stack entry + OP_ADD, // add top two stack entries + OP_SUB, // subtract top two stack entries + OP_MUL, // multiply top two stack entries + OP_DIV, // divide top two stack entries + OP_INT, // push constant integer into the stack + OP_RET // return from the interpreter +}; + +class vmachine +{ +public: + vmachine(unsigned stackSize = 1024) + : stack(new int[stackSize]), + stackPtr(stack) {} + ~vmachine() { delete [] stack; } + int top() const { return stackPtr[-1]; }; + void execute(int code[]); + +private: + + int* stack; + int* stackPtr; +}; + +void +vmachine::execute(int code[]) +{ + int const* pc = code; + bool running = true; + stackPtr = stack; + + while (running) + { + switch (*pc++) + { + case OP_NEG: + stackPtr[-1] = -stackPtr[-1]; + break; + + case OP_ADD: + stackPtr--; + stackPtr[-1] += stackPtr[0]; + break; + + case OP_SUB: + stackPtr--; + stackPtr[-1] -= stackPtr[0]; + break; + + case OP_MUL: + stackPtr--; + stackPtr[-1] *= stackPtr[0]; + break; + + case OP_DIV: + stackPtr--; + stackPtr[-1] /= stackPtr[0]; + break; + + case OP_INT: + // Check stack overflow here! + *stackPtr++ = *pc++; + break; + + case OP_RET: + running = false; + break; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// The Compiler +// +/////////////////////////////////////////////////////////////////////////////// +struct push_int +{ + push_int(vector<int>& code_) + : code(code_) {} + + void operator()(char const* str, char const* /*end*/) const + { + using namespace std; + int n = strtol(str, 0, 10); + code.push_back(OP_INT); + code.push_back(n); + cout << "push\t" << int(n) << endl; + } + + vector<int>& code; +}; + +struct push_op +{ + push_op(int op_, vector<int>& code_) + : op(op_), code(code_) {} + + void operator()(char const*, char const*) const + { + code.push_back(op); + + switch (op) { + + case OP_NEG: + cout << "neg\n"; + break; + + case OP_ADD: + cout << "add\n"; + break; + + case OP_SUB: + cout << "sub\n"; + break; + + case OP_MUL: + cout << "mul\n"; + break; + + case OP_DIV: + cout << "div\n"; + break; + } + } + + int op; + vector<int>& code; +}; + +template <typename GrammarT> +static bool +compile(GrammarT const& calc, char const* expr) +{ + cout << "\n/////////////////////////////////////////////////////////\n\n"; + + parse_info<char const*> + result = parse(expr, calc, space_p); + + if (result.full) + { + cout << "\t\t" << expr << " Parses OK\n\n\n"; + calc.code.push_back(OP_RET); + return true; + } + else + { + cout << "\t\t" << expr << " Fails parsing\n"; + cout << "\t\t"; + for (int i = 0; i < (result.stop - expr); i++) + cout << " "; + cout << "^--Here\n\n\n"; + return false; + } +} + +//////////////////////////////////////////////////////////////////////////// +// +// Our calculator grammar +// +//////////////////////////////////////////////////////////////////////////// +struct calculator : public grammar<calculator> +{ + calculator(vector<int>& code_) + : code(code_) {} + + template <typename ScannerT> + struct definition + { + definition(calculator const& self) + { + integer = + lexeme_d[ (+digit_p)[push_int(self.code)] ] + ; + + factor = + integer + | '(' >> expression >> ')' + | ('-' >> factor)[push_op(OP_NEG, self.code)] + | ('+' >> factor) + ; + + term = + factor + >> *( ('*' >> factor)[push_op(OP_MUL, self.code)] + | ('/' >> factor)[push_op(OP_DIV, self.code)] + ) + ; + + expression = + term + >> *( ('+' >> term)[push_op(OP_ADD, self.code)] + | ('-' >> term)[push_op(OP_SUB, self.code)] + ) + ; + } + + rule<ScannerT> expression, term, factor, integer; + + rule<ScannerT> const& + start() const { return expression; } + }; + + vector<int>& code; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA simple virtual machine...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + vmachine mach; // Our virtual machine + vector<int> code; // Our VM code + calculator calc(code); // Our parser + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + code.clear(); + if (compile(calc, str.c_str())) + { + mach.execute(&*code.begin()); + cout << "\n\nresult = " << mach.top() << "\n\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/no_actions.cpp b/src/boost/libs/spirit/classic/example/fundamental/no_actions.cpp new file mode 100644 index 00000000..a57b6e17 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/no_actions.cpp @@ -0,0 +1,56 @@ +/*============================================================================= + Copyright (c) 2003 Vaclav Vesely + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +// +// This example demonstrates no_actions_d directive. +// +// The no_actions_d directive ensures, that semantic actions of the inner +// parser would NOT be invoked. See the no_actions_scanner in the Scanner +// and Parsing chapter in the User's Guide. +// +//----------------------------------------------------------------------------- + +#include <boost/assert.hpp> +#include <iostream> +#include <boost/cstdlib.hpp> +#include <boost/spirit/include/classic_core.hpp> + +using namespace std; +using namespace boost; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +//----------------------------------------------------------------------------- + +int main() +{ + // To use the rule in the no_action_d directive we must declare it with + // the no_actions_scanner scanner + rule<no_actions_scanner<>::type> r; + + int i(0); + + // r is the rule with the semantic action + r = int_p[assign_a(i)]; + + parse_info<> info = parse( + "1", + + no_actions_d + [ + r + ] + ); + + BOOST_ASSERT(info.full); + // Check, that the action hasn't been invoked + BOOST_ASSERT(i == 0); + + return exit_success; +} + +//----------------------------------------------------------------------------- diff --git a/src/boost/libs/spirit/classic/example/fundamental/number_list.cpp b/src/boost/libs/spirit/classic/example/fundamental/number_list.cpp new file mode 100644 index 00000000..1756f118 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/number_list.cpp @@ -0,0 +1,93 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demontrates a parser for a comma separated list of numbers +// This is discussed in the "Quick Start" chapter in the Spirit User's Guide. +// +// [ JDG 5/10/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_push_back_actor.hpp> +#include <iostream> +#include <vector> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our comma separated list parser +// +/////////////////////////////////////////////////////////////////////////////// +bool +parse_numbers(char const* str, vector<double>& v) +{ + return parse(str, + + // Begin grammar + ( + real_p[push_back_a(v)] >> *(',' >> real_p[push_back_a(v)]) + ) + , + // End grammar + + space_p).full; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA comma separated list parser for Spirit...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + cout << "Give me a comma separated list of numbers.\n"; + cout << "The numbers will be inserted in a vector of numbers\n"; + cout << "Type [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + vector<double> v; + if (parse_numbers(str.c_str(), v)) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << endl; + + for (vector<double>::size_type i = 0; i < v.size(); ++i) + cout << i << ": " << v[i] << endl; + + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/parse_tree_calc1.cpp b/src/boost/libs/spirit/classic/example/fundamental/parse_tree_calc1.cpp new file mode 100644 index 00000000..755810e5 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/parse_tree_calc1.cpp @@ -0,0 +1,207 @@ +/*============================================================================= + Copyright (c) 2001-2003 Daniel Nuffer + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Demonstrates parse trees. This is discussed in the +// "Trees" chapter in the Spirit User's Guide. +// +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_SPIRIT_DUMP_PARSETREE_AS_XML + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_parse_tree.hpp> +#include <boost/assert.hpp> + +#include <iostream> +#include <stack> +#include <functional> +#include <string> + +#ifdef BOOST_SPIRIT_DUMP_PARSETREE_AS_XML +#include <boost/spirit/include/classic_tree_to_xml.hpp> +#include <map> +#endif + +//////////////////////////////////////////////////////////////////////////// +// This example shows how to use a parse tree +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +// Here's some typedefs to simplify things +typedef char const* iterator_t; +typedef tree_match<iterator_t> parse_tree_match_t; +typedef parse_tree_match_t::const_tree_iterator iter_t; + +typedef pt_match_policy<iterator_t> match_policy_t; +typedef scanner_policies<iteration_policy, match_policy_t, action_policy> scanner_policy_t; +typedef scanner<iterator_t, scanner_policy_t> scanner_t; +typedef rule<scanner_t> rule_t; + +// grammar rules +rule_t expression, term, factor, integer; + +//////////////////////////////////////////////////////////////////////////// +// Here's the function prototypes that we'll use. One function for each +// grammar rule. +long evaluate(const tree_parse_info<>& info); +long eval_expression(iter_t const& i); +long eval_term(iter_t const& i); +long eval_factor(iter_t const& i); +long eval_integer(iter_t const& i); + +long evaluate(const tree_parse_info<>& info) +{ + return eval_expression(info.trees.begin()); +} + +// i should be pointing to a node created by the expression rule +long eval_expression(iter_t const& i) +{ + parser_id id = i->value.id(); + BOOST_ASSERT(id == expression.id()); // check the id + + // first child points to a term, so call eval_term on it + iter_t chi = i->children.begin(); + long lhs = eval_term(chi); + for (++chi; chi != i->children.end(); ++chi) + { + // next node points to the operator. The text of the operator is + // stored in value (a vector<char>) + char op = *(chi->value.begin()); + ++chi; + long rhs = eval_term(chi); + if (op == '+') + lhs += rhs; + else if (op == '-') + lhs -= rhs; + else + BOOST_ASSERT(0); + } + return lhs; +} + +long eval_term(iter_t const& i) +{ + parser_id id = i->value.id(); + BOOST_ASSERT(id == term.id()); + + iter_t chi = i->children.begin(); + long lhs = eval_factor(chi); + for (++chi; chi != i->children.end(); ++chi) + { + char op = *(chi->value.begin()); + ++chi; + long rhs = eval_factor(chi); + if (op == '*') + lhs *= rhs; + else if (op == '/') + lhs /= rhs; + else + BOOST_ASSERT(0); + } + return lhs; +} + +long eval_factor(iter_t const& i) +{ + parser_id id = i->value.id(); + BOOST_ASSERT(id == factor.id()); + + iter_t chi = i->children.begin(); + id = chi->value.id(); + if (id == integer.id()) + return eval_integer(chi->children.begin()); + else if (*(chi->value.begin()) == '(') + { + ++chi; + return eval_expression(chi); + } + else if (*(chi->value.begin()) == '-') + { + ++chi; + return -eval_factor(chi); + } + else + { + BOOST_ASSERT(0); + return 0; + } +} + +long eval_integer(iter_t const& i) +{ + // extract integer (not always delimited by '\0') + string integer(i->value.begin(), i->value.end()); + + return strtol(integer.c_str(), 0, 10); +} + +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + + // Start grammar definition + integer = lexeme_d[ token_node_d[ (!ch_p('-') >> +digit_p) ] ]; + factor = integer + | '(' >> expression >> ')' + | ('-' >> factor); + term = factor >> + *( ('*' >> factor) + | ('/' >> factor) + ); + expression = term >> + *( ('+' >> term) + | ('-' >> term) + ); + // End grammar definition + + + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tThe simplest working calculator...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + const char* first = str.c_str(); + + tree_parse_info<> info = pt_parse(first, expression); + + if (info.full) + { +#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML) + // dump parse tree as XML + std::map<parser_id, std::string> rule_names; + rule_names[integer.id()] = "integer"; + rule_names[factor.id()] = "factor"; + rule_names[term.id()] = "term"; + rule_names[expression.id()] = "expression"; + tree_to_xml(cout, info.trees, first, rule_names); +#endif + + // print the result + cout << "parsing succeeded\n"; + cout << "result = " << evaluate(info) << "\n\n"; + } + else + { + cout << "parsing failed\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/parser_context.cpp b/src/boost/libs/spirit/classic/example/fundamental/parser_context.cpp new file mode 100644 index 00000000..d8ed32ba --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/parser_context.cpp @@ -0,0 +1,51 @@ +/*============================================================================= + Copyright (c) 2003 Vaclav Vesely + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +// +// This example demonstrates usage of the parser_context template with +// an explicit argument to declare rules with match results different from +// nil_t. For better understanding, you should read the chapter "In-depth: +// The Parser Context" in the documentation. +// +// The default context of non-terminals is the parser_context. +// The parser_context is a template with one argument AttrT, which is the type +// of match attribute. +// +// In this example int_rule is declared as rule with int match attribute's +// type, so in int_rule variable we can hold any parser, which returns int +// value. For example int_p or bin_p. And the most important is that we can +// use returned value in the semantic action binded to the int_rule. +// +//----------------------------------------------------------------------------- +#include <iostream> +#include <boost/cstdlib.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include <boost/spirit/include/classic_core.hpp> + +using namespace std; +using namespace boost; +using namespace phoenix; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +//----------------------------------------------------------------------------- + +int main() +{ + rule<parser_context<int> > int_rule = int_p; + + parse( + "123", + // Using a returned value in the semantic action + int_rule[cout << arg1 << endl] + ); + + return exit_success; +} + +//----------------------------------------------------------------------------- + diff --git a/src/boost/libs/spirit/classic/example/fundamental/phoenix_calc.cpp b/src/boost/libs/spirit/classic/example/fundamental/phoenix_calc.cpp new file mode 100644 index 00000000..d4f816e6 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/phoenix_calc.cpp @@ -0,0 +1,132 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +//////////////////////////////////////////////////////////////////////////// +// +// Full calculator example demonstrating Phoenix +// This is discussed in the "Closures" chapter in the Spirit User's Guide. +// +// [ JDG 6/29/2002 ] +// +//////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_attribute.hpp> +#include <iostream> +#include <string> + +//////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +//////////////////////////////////////////////////////////////////////////// +// +// Our calculator grammar using phoenix to do the semantics +// +// Note: The top rule propagates the expression result (value) upwards +// to the calculator grammar self.val closure member which is +// then visible outside the grammar (i.e. since self.val is the +// member1 of the closure, it becomes the attribute passed by +// the calculator to an attached semantic action. See the +// driver code that uses the calculator below). +// +//////////////////////////////////////////////////////////////////////////// +struct calc_closure : BOOST_SPIRIT_CLASSIC_NS::closure<calc_closure, double> +{ + member1 val; +}; + +struct calculator : public grammar<calculator, calc_closure::context_t> +{ + template <typename ScannerT> + struct definition + { + definition(calculator const& self) + { + top = expression[self.val = arg1]; + + expression + = term[expression.val = arg1] + >> *( ('+' >> term[expression.val += arg1]) + | ('-' >> term[expression.val -= arg1]) + ) + ; + + term + = factor[term.val = arg1] + >> *( ('*' >> factor[term.val *= arg1]) + | ('/' >> factor[term.val /= arg1]) + ) + ; + + factor + = ureal_p[factor.val = arg1] + | '(' >> expression[factor.val = arg1] >> ')' + | ('-' >> factor[factor.val = -arg1]) + | ('+' >> factor[factor.val = arg1]) + ; + } + + typedef rule<ScannerT, calc_closure::context_t> rule_t; + rule_t expression, term, factor; + rule<ScannerT> top; + + rule<ScannerT> const& + start() const { return top; } + }; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tExpression parser using Phoenix...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + calculator calc; // Our parser + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + double n = 0; + parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p); + + // calc[var(n) = arg1] invokes the calculator and extracts + // the result of the computation. See calculator grammar + // note above. + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << "result = " << n << endl; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "stopped at: \": " << info.stop << "\"\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.cpp b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.cpp new file mode 100644 index 00000000..94975919 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.cpp @@ -0,0 +1,173 @@ +/*============================================================================= + Copyright (c) 2002 Juan Carlos Arevalo-Baeza + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A parser for a comma separated list of numbers, +// with positional error reporting +// See the "Position Iterator" chapter in the User's Guide. +// +// [ JCAB 9/28/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_position_iterator.hpp> +#include <boost/spirit/include/classic_functor_parser.hpp> +#include <iostream> +#include <fstream> +#include <vector> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our error reporting parsers +// +/////////////////////////////////////////////////////////////////////////////// +std::ostream& operator<<(std::ostream& out, file_position const& lc) +{ + return out << + "\nFile:\t" << lc.file << + "\nLine:\t" << lc.line << + "\nCol:\t" << lc.column << endl; +} + +struct error_report_parser { + char const* eol_msg; + char const* msg; + + error_report_parser(char const* eol_msg_, char const* msg_): + eol_msg(eol_msg_), + msg (msg_) + {} + + typedef nil_t result_t; + + template <typename ScannerT> + int + operator()(ScannerT const& scan, result_t& /*result*/) const + { + if (scan.at_end()) { + if (eol_msg) { + file_position fpos = scan.first.get_position(); + cerr << fpos << eol_msg << endl; + } + } else { + if (msg) { + file_position fpos = scan.first.get_position(); + cerr << fpos << msg << endl; + } + } + + return -1; // Fail. + } + +}; +typedef functor_parser<error_report_parser> error_report_p; + +error_report_p +error_badnumber_or_eol = + error_report_parser( + "Expecting a number, but found the end of the file\n", + "Expecting a number, but found something else\n" + ); + +error_report_p +error_badnumber = + error_report_parser( + 0, + "Expecting a number, but found something else\n" + ); + +error_report_p +error_comma = + error_report_parser( + 0, + "Expecting a comma, but found something else\n" + ); + +/////////////////////////////////////////////////////////////////////////////// +// +// Our comma separated list parser +// +/////////////////////////////////////////////////////////////////////////////// +bool +parse_numbers(char const* filename, char const* str, vector<double>& v) +{ + typedef position_iterator<char const*> iterator_t; + iterator_t begin(str, str + strlen(str), filename); + iterator_t end; + begin.set_tabchars(8); + return parse(begin, end, + + // Begin grammar + ( + (real_p[push_back_a(v)] | error_badnumber) + >> *( + (',' | error_comma) + >> (real_p[push_back_a(v)] | error_badnumber_or_eol) + ) + ) + , + // End grammar + + space_p).full; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main(int argc, char **argv) +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\tAn error-reporting parser for Spirit...\n\n"; + cout << "Parses a comma separated list of numbers from a file.\n"; + cout << "The numbers will be inserted in a vector of numbers\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + char str[65536]; + char const* filename; + + if (argc > 1) { + filename = argv[1]; + ifstream file(filename); + file.get(str, sizeof(str), '\0'); + } else { + filename = "<cin>"; + cin.get(str, sizeof(str), '\0'); + } + + vector<double> v; + if (parse_numbers(filename, str, v)) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << endl; + + for (vector<double>::size_type i = 0; i < v.size(); ++i) + cout << i << ": " << v[i] << endl; + + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.err1 b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.err1 new file mode 100644 index 00000000..d6646b72 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.err1 @@ -0,0 +1,8 @@ +0, 1,2 , 3 a,4 +,5, +6 +, +7 + + +,08 diff --git a/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.err2 b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.err2 new file mode 100644 index 00000000..012e2738 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.err2 @@ -0,0 +1,8 @@ +0, 1,2 , 3 ,4 +,5, +6 +, +7 + + +, diff --git a/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.err3 b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.err3 new file mode 100644 index 00000000..8e011921 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.err3 @@ -0,0 +1,8 @@ +0, 1,2 , a3 ,4 +,5, +6 +, +7 + + +,08 diff --git a/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.ok b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.ok new file mode 100644 index 00000000..9bf6f0d1 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/position_iterator/position_iterator.ok @@ -0,0 +1,8 @@ +0, 1,2 , 3 ,4 +,5, +6 +, +7 + + +,08 diff --git a/src/boost/libs/spirit/classic/example/fundamental/refactoring.cpp b/src/boost/libs/spirit/classic/example/fundamental/refactoring.cpp new file mode 100644 index 00000000..701fdbef --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/refactoring.cpp @@ -0,0 +1,214 @@ +/*============================================================================= + Copyright (c) 2002-2003 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// This example shows the usage of the refactoring parser family parsers +// See the "Refactoring Parsers" chapter in the User's Guide. + +#include <iostream> +#include <string> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_refactoring.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// used namespaces +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// actor, used by the refactor_action_p test +struct refactor_action_actor +{ + refactor_action_actor (std::string &str_) : str(str_) {} + + template <typename IteratorT> + void operator() (IteratorT const &first, IteratorT const &last) const + { + str = std::string(first, last-first); + } + + std::string &str; +}; + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int main() +{ + parse_info<> result; + char const *test_string = "Some string followed by a newline\n"; + +/////////////////////////////////////////////////////////////////////////////// +// +// 1. Testing the refactor_unary_d parser +// +// The following test should successfully parse the test string, because the +// +// refactor_unary_d[ +// *anychar_p - '\n' +// ] +// +// is refactored into +// +// *(anychar_p - '\n'). +// +/////////////////////////////////////////////////////////////////////////////// + + result = parse(test_string, refactor_unary_d[*anychar_p - '\n'] >> '\n'); + + if (result.full) + { + cout << "Successfully refactored an unary!" << endl; + } + else + { + cout << "Failed to refactor an unary!" << endl; + } + +// Parsing the same test string without refactoring fails, because the +// *anychar_p eats up all the input up to the end of the input string. + + result = parse(test_string, (*anychar_p - '\n') >> '\n'); + + if (result.full) + { + cout + << "Successfully parsed test string (should not happen)!" + << endl; + } + else + { + cout + << "Correctly failed parsing the test string (without refactoring)!" + << endl; + } + cout << endl; + +/////////////////////////////////////////////////////////////////////////////// +// +// 2. Testing the refactor_action_d parser +// +// The following test should successfully parse the test string, because the +// +// refactor_action_d[ +// (*(anychar_p - '$'))[refactor_action_actor(str)] >> '$' +// ] +// +// is refactored into +// +// (*(anychar_p - '$') >> '$')[refactor_action_actor(str)]. +// +/////////////////////////////////////////////////////////////////////////////// + + std::string str; + char const *test_string2 = "Some test string ending with a $"; + + result = + parse(test_string2, + refactor_action_d[ + (*(anychar_p - '$'))[refactor_action_actor(str)] >> '$' + ] + ); + + if (result.full && str == std::string(test_string2)) + { + cout << "Successfully refactored an action!" << endl; + cout << "Parsed: \"" << str << "\"" << endl; + } + else + { + cout << "Failed to refactor an action!" << endl; + } + +// Parsing the same test string without refactoring fails, because the +// the attached actor gets called only for the first part of the string +// (without the '$') + + result = + parse(test_string2, + (*(anychar_p - '$'))[refactor_action_actor(str)] >> '$' + ); + + if (result.full && str == std::string(test_string2)) + { + cout << "Successfully parsed test string!" << endl; + cout << "Parsed: \"" << str << "\"" << endl; + } + else + { + cout + << "Correctly failed parsing the test string (without refactoring)!" + << endl; + cout << "Parsed instead: \"" << str << "\"" << endl; + } + cout << endl; + +/////////////////////////////////////////////////////////////////////////////// +// +// 3. Testing the refactor_action_d parser with an embedded (nested) +// refactor_unary_p parser +// +// The following test should successfully parse the test string, because the +// +// refactor_action_unary_d[ +// ((*anychar_p)[refactor_action_actor(str)] - '$') +// ] >> '$' +// +// is refactored into +// +// (*(anychar_p - '$'))[refactor_action_actor(str)] >> '$'. +// +/////////////////////////////////////////////////////////////////////////////// + + const refactor_action_gen<refactor_unary_gen<> > refactor_action_unary_d = + refactor_action_gen<refactor_unary_gen<> >(refactor_unary_d); + + result = + parse(test_string2, + refactor_action_unary_d[ + ((*anychar_p)[refactor_action_actor(str)] - '$') + ] >> '$' + ); + + if (result.full) + { + cout + << "Successfully refactored an action attached to an unary!" + << endl; + cout << "Parsed: \"" << str << "\"" << endl; + } + else + { + cout << "Failed to refactor an action!" << endl; + } + +// Parsing the same test string without refactoring fails, because the +// anychar_p eats up all the input up to the end of the string + + result = + parse(test_string2, + ((*anychar_p)[refactor_action_actor(str)] - '$') >> '$' + ); + + if (result.full) + { + cout << "Successfully parsed test string!" << endl; + cout << "Parsed: \"" << str << "\"" << endl; + } + else + { + cout + << "Correctly failed parsing the test string (without refactoring)!" + << endl; + cout << "Parsed instead: \"" << str << "\"" << endl; + } + cout << endl; + + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/fundamental/regular_expression.cpp b/src/boost/libs/spirit/classic/example/fundamental/regular_expression.cpp new file mode 100644 index 00000000..48b33cea --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/regular_expression.cpp @@ -0,0 +1,110 @@ +/*============================================================================= + Copyright (c) 2002-2003 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Demonstrate regular expression parser objects +// See the "Regular Expression Parser" chapter in the User's Guide. +// +// This sample requires an installed version of the boost regex library +// (http://www.boost.org) The sample was tested with boost V1.28.0 +// +/////////////////////////////////////////////////////////////////////////////// +#include <string> +#include <iostream> + +#include <boost/version.hpp> +#include <boost/spirit/include/classic_core.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// +// The following header must be included, if regular expression support is +// required for Spirit. +// +// The BOOST_SPIRIT_NO_REGEX_LIB PP constant should be defined, if you're +// using the Boost.Regex library from one translation unit only. Otherwise +// you have to link with the Boost.Regex library as defined in the related +// documentation (see. http://www.boost.org). +// +// For Boost > V1.32.0 you'll always have to link against the Boost.Regex +// libraries. +// +/////////////////////////////////////////////////////////////////////////////// +#if BOOST_VERSION <= 103200 +#define BOOST_SPIRIT_NO_REGEX_LIB +#endif +#include <boost/spirit/include/classic_regex.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// used namespaces +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int main() +{ + const char *ptest = "123 E 456"; + const char *prx = "[1-9]+[[:space:]]*E[[:space:]]*"; + + cout << "Parse " << ptest << " against regular expression: " << prx + << endl; + + // 1. direct use of rxlit<> + rxstrlit<> regexpr(prx); + parse_info<> result; + string str; + + result = parse (ptest, regexpr[assign(str)]); + if (result.hit) + { + cout << "Parsed regular expression successfully!" << endl; + cout << "Matched (" << (int)result.length << ") characters: "; + cout << "\"" << str << "\"" << endl; + } + else + { + cout << "Failed to parse regular expression!" << endl; + } + cout << endl; + + // 2. use of regex_p predefined parser object + str.empty(); + result = parse (ptest, regex_p(prx)[assign(str)]); + if (result.hit) + { + cout << "Parsed regular expression successfully!" << endl; + cout << "Matched (" << (int)result.length << ") characters: "; + cout << "\"" << str << "\"" << endl; + } + else + { + cout << "Failed to parse regular expression!" << endl; + } + cout << endl; + + // 3. test the regression reported by Grzegorz Marcin Koczyk (gkoczyk@echostar.pl) + string str1; + string str2; + char const *ptest1 = "Token whatever \nToken"; + + result = parse(ptest1, rxstrlit<>("Token")[assign(str1)] + >> rxstrlit<>("Token")[assign(str2)]); + + if (!result.hit) + cout << "Parsed regular expression successfully!" << endl; + else + cout << "Failed to parse regular expression!" << endl; + + cout << endl; + + return 0; +} + + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/roman_numerals.cpp b/src/boost/libs/spirit/classic/example/fundamental/roman_numerals.cpp new file mode 100644 index 00000000..32f26d9e --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/roman_numerals.cpp @@ -0,0 +1,189 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A Roman Numerals Parser (demonstrating the symbol table). This is +// discussed in the "Symbols" chapter in the Spirit User's Guide. +// +// [ JDG 8/22/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_symbols.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// Parse roman hundreds (100..900) numerals using the symbol table. +// Notice that the data associated with each slot is passed +// to attached semantic actions. +// +/////////////////////////////////////////////////////////////////////////////// +struct hundreds : symbols<unsigned> +{ + hundreds() + { + add + ("C" , 100) + ("CC" , 200) + ("CCC" , 300) + ("CD" , 400) + ("D" , 500) + ("DC" , 600) + ("DCC" , 700) + ("DCCC" , 800) + ("CM" , 900) + ; + } + +} hundreds_p; + +/////////////////////////////////////////////////////////////////////////////// +// +// Parse roman tens (10..90) numerals using the symbol table. +// +/////////////////////////////////////////////////////////////////////////////// +struct tens : symbols<unsigned> +{ + tens() + { + add + ("X" , 10) + ("XX" , 20) + ("XXX" , 30) + ("XL" , 40) + ("L" , 50) + ("LX" , 60) + ("LXX" , 70) + ("LXXX" , 80) + ("XC" , 90) + ; + } + +} tens_p; + +/////////////////////////////////////////////////////////////////////////////// +// +// Parse roman ones (1..9) numerals using the symbol table. +// +/////////////////////////////////////////////////////////////////////////////// +struct ones : symbols<unsigned> +{ + ones() + { + add + ("I" , 1) + ("II" , 2) + ("III" , 3) + ("IV" , 4) + ("V" , 5) + ("VI" , 6) + ("VII" , 7) + ("VIII" , 8) + ("IX" , 9) + ; + } + +} ones_p; + +/////////////////////////////////////////////////////////////////////////////// +// +// Semantic actions +// +/////////////////////////////////////////////////////////////////////////////// +struct add_1000 +{ + add_1000(unsigned& r_) : r(r_) {} + void operator()(char) const { r += 1000; } + unsigned& r; +}; + +struct add_roman +{ + add_roman(unsigned& r_) : r(r_) {} + void operator()(unsigned n) const { r += n; } + unsigned& r; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// roman (numerals) grammar +// +/////////////////////////////////////////////////////////////////////////////// +struct roman : public grammar<roman> +{ + template <typename ScannerT> + struct definition + { + definition(roman const& self) + { + first + = +ch_p('M') [add_1000(self.r)] + || hundreds_p [add_roman(self.r)] + || tens_p [add_roman(self.r)] + || ones_p [add_roman(self.r)]; + + // Note the use of the || operator. The expression + // a || b reads match a or b and in sequence. Try + // defining the roman numerals grammar in YACC or + // PCCTS. Spirit rules! :-) + } + + rule<ScannerT> first; + rule<ScannerT> const& + start() const { return first; } + }; + + roman(unsigned& r_) : r(r_) {} + unsigned& r; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Main driver code +// +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tRoman Numerals Parser\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type a Roman Numeral ...or [q or Q] to quit\n\n"; + + // Start grammar definition + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + unsigned n = 0; + roman roman_p(n); + if (parse(str.c_str(), roman_p).full) + { + cout << "parsing succeeded\n"; + cout << "result = " << n << "\n\n"; + } + else + { + cout << "parsing failed\n\n"; + } + } + + cout << "Bye... :-) \n\n"; + + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/fundamental/stuff_vector.cpp b/src/boost/libs/spirit/classic/example/fundamental/stuff_vector.cpp new file mode 100644 index 00000000..77f51b27 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/stuff_vector.cpp @@ -0,0 +1,114 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demontrates a parser for a comma separated list of numbers +// This is the phoenix version of number_list.cpp. +// This is discussed in the "Phoenix" chapter in the Spirit User's Guide. +// +// [ JDG 1/12/2004 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_operators.hpp> +#include <boost/spirit/include/phoenix1_functions.hpp> +#include <boost/spirit/include/phoenix1_primitives.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our comma separated list parser +// +/////////////////////////////////////////////////////////////////////////////// +struct push_back_impl +{ + template <typename Container, typename Item> + struct result + { + typedef void type; + }; + + template <typename Container, typename Item> + void operator()(Container& c, Item const& item) const + { + c.push_back(item); + } +}; + +function<push_back_impl> const push_back = push_back_impl(); + +bool +parse_numbers(char const* str, vector<double>& v) +{ + return parse(str, + + // Begin grammar + ( + real_p[push_back(var(v), arg1)] + >> *(',' >> real_p[push_back(var(v), arg1)]) + ) + , + // End grammar + + space_p).full; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA comma separated list parser for Spirit...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + cout << "Give me a comma separated list of numbers.\n"; + cout << "The numbers will be inserted in a vector of numbers\n"; + cout << "Type [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + vector<double> v; + if (parse_numbers(str.c_str(), v)) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << endl; + + for (vector<double>::size_type i = 0; i < v.size(); ++i) + cout << i << ": " << v[i] << endl; + + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/stuff_vector2.cpp b/src/boost/libs/spirit/classic/example/fundamental/stuff_vector2.cpp new file mode 100644 index 00000000..a5a3232c --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/stuff_vector2.cpp @@ -0,0 +1,125 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demontrates a parser for a comma separated list of identifiers +// This is a variation of stuff_vector.cpp. +// This is discussed in the "Phoenix" chapter in the Spirit User's Guide. +// +// [ JDG 1/12/2004 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_operators.hpp> +#include <boost/spirit/include/phoenix1_functions.hpp> +#include <boost/spirit/include/phoenix1_primitives.hpp> +#include <boost/spirit/include/phoenix1_casts.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our comma separated list parser +// +/////////////////////////////////////////////////////////////////////////////// +struct push_back_impl +{ + template <typename Container, typename Item> + struct result + { + typedef void type; + }; + + template <typename Container, typename Item> + void operator()(Container& c, Item const& item) const + { + c.push_back(item); + } +}; + +function<push_back_impl> const push_back = push_back_impl(); + +bool +parse_identifiers(char const* str, vector<std::string>& v) +{ + return parse(str, + + // Begin grammar + ( + (+alpha_p) + [ + push_back(var(v), construct_<std::string>(arg1, arg2)) + ] + >> + *(',' >> + (+alpha_p) + [ + push_back(var(v), construct_<std::string>(arg1, arg2)) + ] + ) + ) + , + // End grammar + + space_p).full; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA comma separated list parser for Spirit...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + cout << "Give me a comma separated list of identifiers.\n"; + cout << "An identifier is comprised of one or more alphabetic characters.\n"; + cout << "The identifiers will be inserted in a vector of numbers\n"; + cout << "Type [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + vector<std::string> v; + if (parse_identifiers(str.c_str(), v)) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << endl; + + for (vector<std::string>::size_type i = 0; i < v.size(); ++i) + cout << i << ": " << v[i] << endl; + + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/subrule_calc.cpp b/src/boost/libs/spirit/classic/example/fundamental/subrule_calc.cpp new file mode 100644 index 00000000..238a1299 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/subrule_calc.cpp @@ -0,0 +1,140 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This calculator example demontrates the use of subrules. +// This is discussed in the "Subrule" chapter in the Spirit User's Guide. +// +// [ JDG 4/11/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// + +//#define BOOST_SPIRIT_DEBUG // define this for debug output + +#include <boost/spirit/include/classic_core.hpp> +#include <iostream> +#include <string> + +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// Semantic actions +// +/////////////////////////////////////////////////////////////////////////////// +namespace +{ + void do_int(char const* str, char const* end) + { + string s(str, end); + cout << "PUSH(" << s << ')' << endl; + } + + void do_add(char const*, char const*) { cout << "ADD\n"; } + void do_subt(char const*, char const*) { cout << "SUBTRACT\n"; } + void do_mult(char const*, char const*) { cout << "MULTIPLY\n"; } + void do_div(char const*, char const*) { cout << "DIVIDE\n"; } + void do_neg(char const*, char const*) { cout << "NEGATE\n"; } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Our calculator grammar (using subrules) +// +/////////////////////////////////////////////////////////////////////////////// +struct calculator : public grammar<calculator> +{ + template <typename ScannerT> + struct definition { + + definition(calculator const& /*self*/) + { + first = ( + + expression = + term + >> *( ('+' >> term)[&do_add] + | ('-' >> term)[&do_subt] + ) + , + + term = + factor + >> *( ('*' >> factor)[&do_mult] + | ('/' >> factor)[&do_div] + ) + , + + factor + = lexeme_d[(+digit_p)[&do_int]] + | '(' >> expression >> ')' + | ('-' >> factor)[&do_neg] + | ('+' >> factor) + ); + + BOOST_SPIRIT_DEBUG_NODE(first); + BOOST_SPIRIT_DEBUG_NODE(expression); + BOOST_SPIRIT_DEBUG_NODE(term); + BOOST_SPIRIT_DEBUG_NODE(factor); + } + + subrule<0> expression; + subrule<1> term; + subrule<2> factor; + + rule<ScannerT> first; + rule<ScannerT> const& + start() const { return first; } + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Main program +// +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA calculator using subrules...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "Type an expression...or [q or Q] to quit\n\n"; + + calculator calc; // Our parser + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + parse_info<> info = parse(str.c_str(), calc, space_p); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "stopped at: \": " << info.stop << "\"\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/sum.cpp b/src/boost/libs/spirit/classic/example/fundamental/sum.cpp new file mode 100644 index 00000000..d6dd9c9d --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/sum.cpp @@ -0,0 +1,92 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A parser for summing a list of numbers. Demonstrating phoenix +// This is discussed in the "Phoenix" chapter in the Spirit User's Guide. +// +// [ JDG 6/28/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/phoenix1_primitives.hpp> +#include <boost/spirit/include/phoenix1_operators.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +/////////////////////////////////////////////////////////////////////////////// +// +// Our adder +// +/////////////////////////////////////////////////////////////////////////////// +template <typename IteratorT> +bool adder(IteratorT first, IteratorT last, double& n) +{ + return parse(first, last, + + // Begin grammar + ( + real_p[var(n) = arg1] >> *(',' >> real_p[var(n) += arg1]) + ) + , + // End grammar + + space_p).full; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA parser for summing a list of numbers...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + cout << "Give me a comma separated list of numbers.\n"; + cout << "The numbers are added using Phoenix.\n"; + cout << "Type [q or Q] to quit\n\n"; + + string str; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + double n; + if (adder(str.begin(), str.end(), n)) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << endl; + + cout << "sum = " << n; + cout << "\n-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/thousand_separated.cpp b/src/boost/libs/spirit/classic/example/fundamental/thousand_separated.cpp new file mode 100644 index 00000000..1b84e05b --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/thousand_separated.cpp @@ -0,0 +1,133 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A parser for a real number parser that parses thousands separated numbers +// with at most two decimal places and no exponent. This is discussed in the +// "Numerics" chapter in the Spirit User's Guide. +// +// [ JDG 12/16/2003 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_assign_actor.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; + +template <typename T> +struct ts_real_parser_policies : public ureal_parser_policies<T> +{ + // These policies can be used to parse thousand separated + // numbers with at most 2 decimal digits after the decimal + // point. e.g. 123,456,789.01 + + typedef uint_parser<int, 10, 1, 2> uint2_t; + typedef uint_parser<T, 10, 1, -1> uint_parser_t; + typedef int_parser<int, 10, 1, -1> int_parser_t; + + ////////////////////////////////// 2 decimal places Max + template <typename ScannerT> + static typename parser_result<uint2_t, ScannerT>::type + parse_frac_n(ScannerT& scan) + { return uint2_t().parse(scan); } + + ////////////////////////////////// No exponent + template <typename ScannerT> + static typename parser_result<chlit<>, ScannerT>::type + parse_exp(ScannerT& scan) + { return scan.no_match(); } + + ////////////////////////////////// No exponent + template <typename ScannerT> + static typename parser_result<int_parser_t, ScannerT>::type + parse_exp_n(ScannerT& scan) + { return scan.no_match(); } + + ////////////////////////////////// Thousands separated numbers + template <typename ScannerT> + static typename parser_result<uint_parser_t, ScannerT>::type + parse_n(ScannerT& scan) + { + typedef typename parser_result<uint_parser_t, ScannerT>::type RT; + static uint_parser<unsigned, 10, 1, 3> uint3_p; + static uint_parser<unsigned, 10, 3, 3> uint3_3_p; + if (RT hit = uint3_p.parse(scan)) + { + T n; + typedef typename ScannerT::iterator_t iterator_t; + iterator_t save = scan.first; + while (match<> next = (',' >> uint3_3_p[assign_a(n)]).parse(scan)) + { + hit.value((hit.value() * 1000) + n); + scan.concat_match(hit, next); + save = scan.first; + } + scan.first = save; + return hit; + + // Note: On erroneous input such as "123,45", the result should + // be a partial match "123". 'save' is used to makes sure that + // the scanner position is placed at the last *valid* parse + // position. + } + return scan.no_match(); + } +}; + +real_parser<double, ts_real_parser_policies<double> > const + ts_real_p = real_parser<double, ts_real_parser_policies<double> >(); + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + cout << "/////////////////////////////////////////////////////////\n\n"; + cout << "\t\tA real number parser that parses thousands separated\n"; + cout << "\t\tnumbers with at most two decimal places and no exponent...\n\n"; + cout << "/////////////////////////////////////////////////////////\n\n"; + + cout << "Give me a number.\n"; + cout << "Type [q or Q] to quit\n\n"; + + string str; + double n; + while (getline(cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + if (parse(str.c_str(), ts_real_p[assign_a(n)]).full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + cout << str << " Parses OK: " << endl; + cout << "n=" << n << endl; + cout << "-------------------------\n"; + } + else + { + cout << "-------------------------\n"; + cout << "Parsing failed\n"; + cout << "-------------------------\n"; + } + } + + cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/fundamental/tree_calc_grammar.hpp b/src/boost/libs/spirit/classic/example/fundamental/tree_calc_grammar.hpp new file mode 100644 index 00000000..26e42261 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/fundamental/tree_calc_grammar.hpp @@ -0,0 +1,76 @@ +/*============================================================================= + Copyright (c) 2001-2003 Daniel Nuffer + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +#ifndef BOOST_SPIRIT_TREE_CALC_GRAMMAR_HPP_ +#define BOOST_SPIRIT_TREE_CALC_GRAMMAR_HPP_ + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +/////////////////////////////////////////////////////////////////////////////// +// +// Demonstrates the AST and parse trees. This is discussed in the +// "Trees" chapter in the Spirit User's Guide. +// +/////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////// +// +// Our calculator grammar +// +//////////////////////////////////////////////////////////////////////////// +struct calculator : public grammar<calculator> +{ + static const int integerID = 1; + static const int factorID = 2; + static const int termID = 3; + static const int expressionID = 4; + + template <typename ScannerT> + struct definition + { + definition(calculator const& /*self*/) + { + // Start grammar definition + integer = leaf_node_d[ lexeme_d[ + (!ch_p('-') >> +digit_p) + ] ]; + + factor = integer + | inner_node_d[ch_p('(') >> expression >> ch_p(')')] + | (root_node_d[ch_p('-')] >> factor); + + term = factor >> + *( (root_node_d[ch_p('*')] >> factor) + | (root_node_d[ch_p('/')] >> factor) + ); + + expression = term >> + *( (root_node_d[ch_p('+')] >> term) + | (root_node_d[ch_p('-')] >> term) + ); + // End grammar definition + + // turn on the debugging info. + BOOST_SPIRIT_DEBUG_RULE(integer); + BOOST_SPIRIT_DEBUG_RULE(factor); + BOOST_SPIRIT_DEBUG_RULE(term); + BOOST_SPIRIT_DEBUG_RULE(expression); + } + + rule<ScannerT, parser_context<>, parser_tag<expressionID> > expression; + rule<ScannerT, parser_context<>, parser_tag<termID> > term; + rule<ScannerT, parser_context<>, parser_tag<factorID> > factor; + rule<ScannerT, parser_context<>, parser_tag<integerID> > integer; + + rule<ScannerT, parser_context<>, parser_tag<expressionID> > const& + start() const { return expression; } + }; +}; + +#endif + diff --git a/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp b/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp new file mode 100644 index 00000000..93453bac --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp @@ -0,0 +1,304 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_push_back_actor.hpp> +#include <boost/spirit/include/classic_if.hpp> +#include <boost/spirit/include/classic_for.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include <iostream> +#include <string> +#include <vector> +#include <algorithm> + +/////////////////////////////////////////////////////////////////////////////// +// +// Sample parser for binary data. This sample highlights the use of dynamic +// parsing where the result of actions direct the actual parsing behavior. +// We shall demonstrate 1) the use of phoenix to implement lambda (unnamed) +// functions, 2) dynamic looping using for_p, 3) the push_back_a actor for +// stuffing data into a vector, and 4) the if_p parser for choosing parser +// branches based on semantic conditions. +// +// << Sample idea by Florian Weimer >> +// +// For simplicity, we shall use bytes as atoms (and not 16-bit quantities +// in big-endian format or something similar, which would be more realistic) +// and PASCAL strings. +// +// A packet is the literal octet with value 255, followed by a variable +// octet N (denoting the total length of the packet), followed by N-2 octets +// (the payload). The payload contains a variable-length header, followed +// by zero or more elements. +// +// The header contains a single PASCAL string. +// +// An element is a PASCAL string (alternative: an element is an octet M, +// followed by [M/8] bytes, i.e. the necessary number of bytes to store M +// bits). +// +// (This data structure is inspired by the format of a BGP UPDATE message.) +// +// Packet layout: +// +// .-------------------. +// | 0xff | ^ +// +-------------------+ | +// | packet length | | +// +-------------------+ | number of bytes indicated by packet length +// : : | +// : payload : | +// | | v +// `-------------------' +// +// Payload layout: +// +// .-------------------. +// | header length | +// +-------------------+ +// | header octets | ^ +// : : | number of octets given by header length +// : : | +// : : v +// +-------------------+ +// | IPv4 prefix | ^ +// : : | IPv4 prefixes have variable length (see +// +-------------------+ | below). The number of prefixes is +// | IPv4 prefix | | determined by the packet length. +// : : | +// +-------------------+ | +// : : | +// : : v +// +// +// IPv4 prefix layout comes in five variants, depending on the first +// octet: +// +// .-------------------. +// | 0x00 | single octet, corresponds to 0.0.0.0/0 +// `-------------------' +// +// .-------------------. +// | 0x01 to 0x08 | two octets, prefix lengths up to /8. +// +-------------------+ +// | MSB of network | +// `-------------------' +// +// .-------------------. +// | 0x09 to 0x10 | three octets, prefix lengths up to /16. +// +-------------------+ +// | MSB of network | +// +-------------------+ +// | next octet | +// `-------------------' +// +// .-------------------. +// | 0x11 to 0x18 | four octets, prefix lengths up to /24. +// +-------------------+ +// | MSB of network | +// +-------------------+ +// | next octet | +// +-------------------+ +// | next octet | +// `-------------------' +// +// .-------------------. +// | 0x19 to 0x20 | five octets, prefix lengths up to /32. +// +-------------------+ +// | MSB of network | +// +-------------------+ +// | next octet | +// +-------------------+ +// | next octet | +// +-------------------+ +// | LSB of network | +// `-------------------' +// +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +struct ipv4_prefix_data +{ + char prefix_len, n0, n1, n2, n3; + + ipv4_prefix_data() + : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {} +}; + +struct ipv4_data +{ + char packet_len, header_len; + std::string header; + std::vector<ipv4_prefix_data> prefixes; + + ipv4_data() + : packet_len(0),header_len(0){} + +}; + +struct ipv4 : public grammar<ipv4> +{ + template <typename ScannerT> + struct definition + { + definition(ipv4 const& self) + { + packet = + '\xff' + >> anychar_p[var(self.data.packet_len) = arg1] + >> payload + ; + + payload = + anychar_p[var(self.data.header_len) = arg1] + >> for_p(var(i) = 0, var(i) < var(self.data.header_len), ++var(i)) + [ + anychar_p[var(self.data.header) += arg1] + ] + >> *ipv4_prefix + ; + + ipv4_prefix = + anychar_p + [ + var(temp.prefix_len) = arg1, + var(temp.n0) = 0, + var(temp.n1) = 0, + var(temp.n2) = 0, + var(temp.n3) = 0 + ] + + >> if_p(var(temp.prefix_len) > 0x00) + [ + anychar_p[var(temp.n0) = arg1] + >> if_p(var(temp.prefix_len) > 0x08) + [ + anychar_p[var(temp.n1) = arg1] + >> if_p(var(temp.prefix_len) > 0x10) + [ + anychar_p[var(temp.n2) = arg1] + >> if_p(var(temp.prefix_len) > 0x18) + [ + anychar_p[var(temp.n3) = arg1] + ] + ] + ] + ] + [ + push_back_a(self.data.prefixes, temp) + ] + ; + } + + int i; + ipv4_prefix_data temp; + rule<ScannerT> packet, payload, ipv4_prefix; + rule<ScannerT> const& + start() const { return packet; } + }; + + ipv4(ipv4_data& data) + : data(data) {} + + ipv4_data& data; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +as_byte(char n) +{ + if (n < 0) + return n + 256; + return n; +} + +void +print_prefix(ipv4_prefix_data const& prefix) +{ + cout << "prefix length = " << as_byte(prefix.prefix_len) << endl; + cout << "n0 = " << as_byte(prefix.n0) << endl; + cout << "n1 = " << as_byte(prefix.n1) << endl; + cout << "n2 = " << as_byte(prefix.n2) << endl; + cout << "n3 = " << as_byte(prefix.n3) << endl; +} + +void +parse_ipv4(char const* str, unsigned len) +{ + ipv4_data data; + ipv4 g(data); + parse_info<> info = parse(str, str+len, g); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + + cout << "packet length = " << as_byte(data.packet_len) << endl; + cout << "header length = " << as_byte(data.header_len) << endl; + cout << "header = " << data.header << endl; + + for_each(data.prefixes.begin(), data.prefixes.end(), print_prefix); + cout << "-------------------------\n"; + } + else + { + cout << "Parsing failed\n"; + cout << "stopped at:"; + for (char const* s = info.stop; s != str+len; ++s) + cout << static_cast<int>(*s) << endl; + } +} + +// Test inputs: + +// The string in the header is "empty", the prefix list is empty. +char const i1[8] = +{ + 0xff,0x08,0x05, + 'e','m','p','t','y' +}; + +// The string in the header is "default route", the prefix list +// has just one element, 0.0.0.0/0. +char const i2[17] = +{ + 0xff,0x11,0x0d, + 'd','e','f','a','u','l','t',' ', + 'r','o','u','t','e', + 0x00 +}; + +// The string in the header is "private address space", the prefix list +// has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16. +char const i3[32] = +{ + 0xff,0x20,0x15, + 'p','r','i','v','a','t','e',' ', + 'a','d','d','r','e','s','s',' ', + 's','p','a','c','e', + 0x08,0x0a, + 0x0c,0xac,0x10, + 0x10,0xc0,0xa8 +}; + +int +main() +{ + parse_ipv4(i1, sizeof(i1)); + parse_ipv4(i2, sizeof(i2)); + parse_ipv4(i3, sizeof(i3)); + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/intermediate/ipv4_opt.cpp b/src/boost/libs/spirit/classic/example/intermediate/ipv4_opt.cpp new file mode 100644 index 00000000..ed5429fd --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/ipv4_opt.cpp @@ -0,0 +1,213 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_push_back_actor.hpp> +#include <boost/spirit/include/classic_if.hpp> +#include <boost/spirit/include/classic_for.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include <iostream> +#include <string> +#include <vector> +#include <algorithm> + +/////////////////////////////////////////////////////////////////////////////// +// +// Please check it out ipv4.cpp sample first! +// << See ipv4.cpp sample for details >> +// +// This is a variation of the ipv4.cpp sample. The original ipv4.cpp code +// compiles to 36k on MSVC7.1. Not bad! Yet, we want to shave a little bit +// more. Is it possible? Yes! This time, we'll use subrules and just store +// the rules in a plain old struct. We are parsing at the char level anyway, +// so we know what type of rule we'll need: a plain rule<>. The result: we +// shaved off another 20k. Now the code compiles to 16k on MSVC7.1. +// +// Could we have done better? Yes, but only if only we had typeof! << See +// the techniques section of the User's guide >> ... Someday... :-) +// +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +struct ipv4_prefix_data +{ + char prefix_len, n0, n1, n2, n3; + + ipv4_prefix_data() + : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {} +}; + +struct ipv4_data +{ + char packet_len, header_len; + std::string header; + std::vector<ipv4_prefix_data> prefixes; + + ipv4_data() + : packet_len(0),header_len(0){} + +}; + +struct ipv4 +{ + ipv4(ipv4_data& data) + : data(data) + { + start = + ( + packet = + '\xff' + >> anychar_p[var(data.packet_len) = arg1] + >> payload + , + + payload = + anychar_p[var(data.header_len) = arg1] + >> for_p(var(i) = 0, var(i) < var(data.header_len), ++var(i)) + [ + anychar_p[var(data.header) += arg1] + ] + >> *ipv4_prefix + , + + ipv4_prefix = + anychar_p + [ + var(temp.prefix_len) = arg1, + var(temp.n0) = 0, + var(temp.n1) = 0, + var(temp.n2) = 0, + var(temp.n3) = 0 + ] + + >> if_p(var(temp.prefix_len) > 0x00) + [ + anychar_p[var(temp.n0) = arg1] + >> if_p(var(temp.prefix_len) > 0x08) + [ + anychar_p[var(temp.n1) = arg1] + >> if_p(var(temp.prefix_len) > 0x10) + [ + anychar_p[var(temp.n2) = arg1] + >> if_p(var(temp.prefix_len) > 0x18) + [ + anychar_p[var(temp.n3) = arg1] + ] + ] + ] + ] + [ + push_back_a(data.prefixes, temp) + ] + ); + } + + int i; + ipv4_prefix_data temp; + + rule<> start; + subrule<0> packet; + subrule<1> payload; + subrule<2> ipv4_prefix; + ipv4_data& data; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +as_byte(char n) +{ + if (n < 0) + return n + 256; + return n; +} + +void +print_prefix(ipv4_prefix_data const& prefix) +{ + cout << "prefix length = " << as_byte(prefix.prefix_len) << endl; + cout << "n0 = " << as_byte(prefix.n0) << endl; + cout << "n1 = " << as_byte(prefix.n1) << endl; + cout << "n2 = " << as_byte(prefix.n2) << endl; + cout << "n3 = " << as_byte(prefix.n3) << endl; +} + +void +parse_ipv4(char const* str, unsigned len) +{ + ipv4_data data; + ipv4 g(data); + parse_info<> info = parse(str, str+len, g.start); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + + cout << "packet length = " << as_byte(data.packet_len) << endl; + cout << "header length = " << as_byte(data.header_len) << endl; + cout << "header = " << data.header << endl; + + for_each(data.prefixes.begin(), data.prefixes.end(), print_prefix); + cout << "-------------------------\n"; + } + else + { + cout << "Parsing failed\n"; + cout << "stopped at:"; + for (char const* s = info.stop; s != str+len; ++s) + cout << static_cast<int>(*s) << endl; + } +} + +// Test inputs: + +// The string in the header is "empty", the prefix list is empty. +char const i1[8] = +{ + 0xff,0x08,0x05, + 'e','m','p','t','y' +}; + +// The string in the header is "default route", the prefix list +// has just one element, 0.0.0.0/0. +char const i2[17] = +{ + 0xff,0x11,0x0d, + 'd','e','f','a','u','l','t',' ', + 'r','o','u','t','e', + 0x00 +}; + +// The string in the header is "private address space", the prefix list +// has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16. +char const i3[32] = +{ + 0xff,0x20,0x15, + 'p','r','i','v','a','t','e',' ', + 'a','d','d','r','e','s','s',' ', + 's','p','a','c','e', + 0x08,0x0a, + 0x0c,0xac,0x10, + 0x10,0xc0,0xa8 +}; + +int +main() +{ + parse_ipv4(i1, sizeof(i1)); + parse_ipv4(i2, sizeof(i2)); + parse_ipv4(i3, sizeof(i3)); + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/intermediate/lazy_parser.cpp b/src/boost/libs/spirit/classic/example/intermediate/lazy_parser.cpp new file mode 100644 index 00000000..6035fd80 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/lazy_parser.cpp @@ -0,0 +1,126 @@ +/*============================================================================= + Copyright (c) 2003 Vaclav Vesely + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +// +// This example demonstrates the lazy_p parser. You should read +// "The Lazy Parser" in the documentation. +// +// We want to parse nested blocks of numbers like this: +// +// dec { +// 1 2 3 +// bin { +// 1 10 11 +// } +// 4 5 6 +// } +// +// where the numbers in the "dec" block are wrote in the decimal system and +// the numbers in the "bin" block are wrote in the binary system. We want +// parser to return the overall sum. +// +// To achive this when base ("bin" or "dec") is parsed, in semantic action +// we store a pointer to the appropriate numeric parser in the closure +// variable block.int_rule. Than, when we need to parse a number we use lazy_p +// parser to invoke the parser stored in the block.int_rule pointer. +// +//----------------------------------------------------------------------------- +#include <boost/assert.hpp> +#include <boost/cstdlib.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_symbols.hpp> +#include <boost/spirit/include/classic_attribute.hpp> +#include <boost/spirit/include/classic_dynamic.hpp> + +using namespace boost; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +//----------------------------------------------------------------------------- +// my grammar + +struct my_grammar + : public grammar<my_grammar, parser_context<int> > +{ + // grammar definition + template<typename ScannerT> + struct definition + { + typedef rule<ScannerT> rule_t; + typedef stored_rule<ScannerT, parser_context<int> > number_rule_t; + + struct block_closure; + typedef boost::spirit::classic::closure< + block_closure, + int, + typename number_rule_t::alias_t> + closure_base_t; + + struct block_closure : closure_base_t + { + typename closure_base_t::member1 sum; + typename closure_base_t::member2 int_rule; + }; + + // block rule type + typedef rule<ScannerT, typename block_closure::context_t> block_rule_t; + + block_rule_t block; + rule_t block_item; + symbols<number_rule_t> base; + + definition(my_grammar const& self) + { + block = + base[ + block.sum = 0, + // store a number rule in a closure member + block.int_rule = arg1 + ] + >> "{" + >> *block_item + >> "}" + ; + + block_item = + // use the stored rule + lazy_p(block.int_rule)[block.sum += arg1] + | block[block.sum += arg1] + ; + + // bind base keywords and number parsers + base.add + ("bin", bin_p) + ("dec", uint_p) + ; + } + + block_rule_t const& start() const + { + return block; + } + }; +}; + +//----------------------------------------------------------------------------- + +int main() +{ + my_grammar gram; + parse_info<> info; + + int result; + info = parse("bin{1 dec{1 2 3} 10}", gram[var(result) = arg1], space_p); + BOOST_ASSERT(info.full); + BOOST_ASSERT(result == 9); + + return exit_success; +} + +//----------------------------------------------------------------------------- diff --git a/src/boost/libs/spirit/classic/example/intermediate/parameters.cpp b/src/boost/libs/spirit/classic/example/intermediate/parameters.cpp new file mode 100644 index 00000000..b93fb0ec --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/parameters.cpp @@ -0,0 +1,216 @@ +/*============================================================================= + Copyright (c) 2001-2003 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// This sample show the usage of parser parameters. +// +// Parser parameters are used to pass some values from the outer parsing scope +// to the next inner scope. They can be imagined as the opposite to the return +// value paradigm, which returns some value from the inner to the next outer +// scope. See the "Closures" chapter in the User's Guide. + +#include <string> +#include <iostream> +#include <cassert> + +#if defined(_MSC_VER) /*&& !defined(__COMO__)*/ +#pragma warning(disable: 4244) +#pragma warning(disable: 4355) +#endif // defined(_MSC_VER) && !defined(__COMO__) + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_symbols.hpp> +#include <boost/spirit/include/classic_closure.hpp> + +#include <boost/spirit/include/phoenix1_tuples.hpp> +#include <boost/spirit/include/phoenix1_tuple_helpers.hpp> +#include <boost/spirit/include/phoenix1_primitives.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// used namespaces +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; +using namespace std; + +/////////////////////////////////////////////////////////////////////////////// +// Helper class for encapsulation of the type for the parsed variable names +class declaration_type +{ +public: + enum vartype { + vartype_unknown = 0, // unknown variable type + vartype_int = 1, // 'int' + vartype_real = 2 // 'real' + }; + + declaration_type() : type(vartype_unknown) + { + } + template <typename ItT> + declaration_type(ItT const &first, ItT const &last) + { + init(string(first, last-first-1)); + } + declaration_type(declaration_type const &type_) : type(type_.type) + { + } + declaration_type(string const &type_) : type(vartype_unknown) + { + init(type_); + } + +// access to the variable type + operator vartype const &() const { return type; } + operator string () + { + switch(type) { + default: + case vartype_unknown: break; + case vartype_int: return string("int"); + case vartype_real: return string("real"); + } + return string ("unknown"); + } + + void swap(declaration_type &s) { std::swap(type, s.type); } + +protected: + void init (string const &type_) + { + if (type_ == "int") + type = vartype_int; + else if (type_ == "real") + type = vartype_real; + else + type = vartype_unknown; + } + +private: + vartype type; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// used closure type +// +/////////////////////////////////////////////////////////////////////////////// +struct var_decl_closure : BOOST_SPIRIT_CLASSIC_NS::closure<var_decl_closure, declaration_type> +{ + member1 val; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// symbols_with_data +// +// Helper class for inserting an item with data into a symbol table +// +/////////////////////////////////////////////////////////////////////////////// +template <typename T, typename InitT> +class symbols_with_data +{ +public: + typedef + symbol_inserter<T, BOOST_SPIRIT_CLASSIC_NS::impl::tst<T, char> > + symbol_inserter_t; + + symbols_with_data(symbol_inserter_t const &add_, InitT const &data_) : + add(add_), data(as_actor<InitT>::convert(data_)) + { + } + + template <typename IteratorT> + symbol_inserter_t const & + operator()(IteratorT const &first_, IteratorT const &last) const + { + IteratorT first = first_; + return add(first, last, data()); + } + +private: + symbol_inserter_t const &add; + typename as_actor<InitT>::type data; +}; + +template <typename T, typename CharT, typename InitT> +inline +symbols_with_data<T, InitT> +symbols_gen(symbol_inserter<T, BOOST_SPIRIT_CLASSIC_NS::impl::tst<T, CharT> > const &add_, + InitT const &data_) +{ + return symbols_with_data<T, InitT>(add_, data_); +} + +/////////////////////////////////////////////////////////////////////////////// +// The var_decl_list grammar parses variable declaration list + +struct var_decl_list : + public grammar<var_decl_list, var_decl_closure::context_t> +{ + template <typename ScannerT> + struct definition + { + definition(var_decl_list const &self) + { + // pass variable type returned from 'type' to list closure member 0 + decl = type[self.val = arg1] >> +space_p >> list(self.val); + + // m0 to access arg 0 of list --> passing variable type down to ident + list = ident(list.val) >> *(',' >> ident(list.val)); + + // store identifier and type into the symbol table + ident = (*alnum_p)[symbols_gen(symtab.add, ident.val)]; + + // the type of the decl is returned in type's closure member 0 + type = + str_p("int")[type.val = construct_<string>(arg1, arg2)] + | str_p("real")[type.val = construct_<string>(arg1, arg2)] + ; + + BOOST_SPIRIT_DEBUG_RULE(decl); + BOOST_SPIRIT_DEBUG_RULE(list); + BOOST_SPIRIT_DEBUG_RULE(ident); + BOOST_SPIRIT_DEBUG_RULE(type); + } + + rule<ScannerT> const& + start() const { return decl; } + + private: + typedef rule<ScannerT, var_decl_closure::context_t> rule_t; + rule_t type; + rule_t list; + rule_t ident; + symbols<declaration_type> symtab; + + rule<ScannerT> decl; // start rule + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int main() +{ +var_decl_list decl; +declaration_type type; +char const *pbegin = "int var1"; + + if (parse (pbegin, decl[assign(type)]).full) { + cout << endl + << "Parsed variable declarations successfully!" << endl + << "Detected type: " << declaration_type::vartype(type) + << " (" << string(type) << ")" + << endl; + } else { + cout << endl + << "Parsing the input stream failed!" + << endl; + } + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/intermediate/regex_convert.cpp b/src/boost/libs/spirit/classic/example/intermediate/regex_convert.cpp new file mode 100644 index 00000000..e167c2e3 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/regex_convert.cpp @@ -0,0 +1,177 @@ +/*============================================================================= + Copyright (c) 2002-2003 Martin Wille + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// vim:ts=4:sw=4:et +// +// Demonstrate regular expression parsers for match based text conversion +// +// This sample requires an installed version of the boost regex library +// (http://www.boost.org) The sample was tested with boost V1.29.0 +// +// Note: - there is no error handling in this example +// - this program isn't particularly useful +// +// This example shows one way build a kind of filter program. +// It reads input from std::cin and uses a grammar and actions +// to print out a modified version of the input. +// +// [ Martin Wille, 10/18/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// + +#include <string> +#include <iostream> +#include <streambuf> +#include <sstream> +#include <deque> +#include <iterator> + +#include <boost/function.hpp> +#include <boost/spirit/include/classic_core.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// +// The following header must be included, if regular expression support is +// required for Spirit. +// +// The BOOST_SPIRIT_NO_REGEX_LIB PP constant should be defined, if you're using the +// Boost.Regex library from one translation unit only. Otherwise you have to +// link with the Boost.Regex library as defined in the related documentation +// (see. http://www.boost.org). +// +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_SPIRIT_NO_REGEX_LIB +#include <boost/spirit/include/classic_regex.hpp> + +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace std; + +namespace { + long triple(long val) + { + return 3*val; + } + /////////////////////////////////////////////////////////////////////////// + // + // actions + // + struct emit_constant + { + emit_constant(string const &text) + : msg(text) + {} + + template<typename Iterator> + void operator()(Iterator b, Iterator e) const + { + cout.rdbuf()->sputn(msg.data(), msg.size()); + } + + private: + + string msg; + }; + + void + copy_unmodified(char letter) + { + cout.rdbuf()->sputc(letter); + } + + struct emit_modified_subscript + { + emit_modified_subscript(boost::function<long (long)> const &f) + : modifier(f) + {} + + template<typename Iterator> + void operator()(Iterator b, Iterator e) const + { + string tmp(b+1,e-1); + long val = strtol(tmp.c_str(),0, 0); + ostringstream os; + os << modifier(val); + tmp = os.str(); + cout.rdbuf()->sputc('['); + cout.rdbuf()->sputn(tmp.c_str(), tmp.size()); + cout.rdbuf()->sputc(']'); + } + + private: + + boost::function<long (long)> modifier; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// The grammar 'conversion_grammar' serves as a working horse for match based +// text conversion. It does the following: +// +// - converts the word "class" into the word "struct" +// - multiplies any integer number enclosed in square brackets with 3 +// - any other input is simply copied to the output + +struct conversion_grammar + : grammar<conversion_grammar> +{ + template<class ScannerT> + struct definition + { + typedef ScannerT scanner_t; + + definition(conversion_grammar const &) + { + static const char expr[] = "\\[\\d+\\]"; + first = ( + ///////////////////////////////////////////////////////////// + // note that "fallback" is the last alternative here ! + top = *(class2struct || subscript || fallback), + ///////////////////////////////////////////////////////////// + // replace any occurrence of "class" by "struct" + class2struct = str_p("class") [emit_constant("struct")], + ///////////////////////////////////////////////////////////// + // if the input maches "[some_number]" + // "some_number" is multiplied by 3 before printing + subscript = regex_p(expr) [emit_modified_subscript(&triple)], + ///////////////////////////////////////////////////////////// + // if nothing else can be done with the input + // then it will be printed without modifications + fallback = anychar_p [©_unmodified] + ); + } + + rule<scanner_t> const & start() { return first; } + + private: + + subrule<0> top; + subrule<1> class2struct; + subrule<2> subscript; + subrule<3> fallback; + rule<scanner_t> first; + }; +}; + +int +main() +{ + // this would print "struct foo {}; foo bar[9];": + // parse("class foo {}; foo bar[3];", conversion_grammar()); + + // Note: the regular expression parser contained in the + // grammar requires a bidirectional iterator. Therefore, + // we cannot use sdt::istreambuf_iterator as one would + // do with other Spirit parsers. + istreambuf_iterator<char> input_iterator(cin); + std::deque<char> input(input_iterator, istreambuf_iterator<char>()); + + parse(input.begin(), input.end(), conversion_grammar()); + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/actions.hpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/actions.hpp new file mode 100644 index 00000000..285edf21 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/actions.hpp @@ -0,0 +1,68 @@ +// Copyright (c) 2005 Carl Barron. 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) + +#ifndef ACTIONS_H +#define ACTIONS_H +#include <boost/spirit/include/phoenix1.hpp> +#include <boost/variant.hpp> +#include "tag.hpp" + +struct push_child_impl +{ + template <class T,class A> + struct result {typedef void type;}; + + template <class T,class A> + void operator () (T &list, const A &value) const + { + typename tag::variant_type p(value); + list.push_back(p); + } +}; + +struct store_in_map_impl +{ + template <class T,class A> + struct result{typedef void type;}; + + template <class T,class A> + void operator () (T &map,const A &value)const + { + typedef typename T::value_type value_type; + map.insert(value_type(value)); + } +}; + +struct push_back_impl +{ + template <class T,class A> + struct result {typedef void type;}; + + template <class T,class A> + void operator () (T &list,const A &value)const + { + list.push_back(value); + } +}; + +struct store_tag_impl +{ + template <class T,class A,class B,class C> + struct result {typedef void type;}; + + template <class T,class A,class B,class C> + void operator ()(T &t,const A &a,const B &b,const C &c)const + { + t.id = a; + t.attributes = b; + t.children = c; + } +}; + + +typedef phoenix::function<push_back_impl> push_back_f; +typedef phoenix::function<store_in_map_impl>store_in_map_f; +typedef phoenix::function<push_child_impl> push_child_f; +typedef phoenix::function<store_tag_impl> store_tag_f; +#endif diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/driver.cpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/driver.cpp new file mode 100644 index 00000000..57ad6f20 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/driver.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2005 Carl Barron. 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 "xml_g.hpp" +#include <boost/spirit/include/classic_utility.hpp> +#include <iostream> + +namespace std +{ + std::ostream & operator << (std::ostream &os,std::pair<std::string,std::string> const &p) + { + return os << p.first << '=' << p.second; + } + + std::ostream & operator << (std::ostream &os,const tag &t) + { + return os << t.id; + } + +} + +int main() +{ + const char *test = + // "<A x=\"1\" y=\"2\"> test 1 </A>" + // "<B x=\"3\" y= \"4\" z = \"10\"> test 3 </B>" + // "<C><A></A><V><W></W></V></C>" + // "<D x=\"4\"/>" + "<E>xxx<F>yyy</F>zzz</E>" + ; + std::list<tag> tags; + xml_g g(tags); + + if(SP::parse(test,g,SP::comment_p("<---","--->")).full) + { + std::for_each(tags.begin(),tags.end(),walk_data()); + } + else + { + std::cout << "parse failed\n"; + } +} diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.cpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.cpp new file mode 100644 index 00000000..088f3a00 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2005 Carl Barron. 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 "tag.hpp" +#include <iostream> +#include <algorithm> + +namespace +{ + struct print_pair + { + template <class P> + void operator () (const P &x) + { + std::cout << '\t' << x.first << ':' << x.second <<'\n'; + } + }; + +} + +void walk_data::operator () (const std::string &x) +{ + std::cout << "String:" << x <<'\n'; +} + +void walk_data::operator () (const tag &t) +{ + std::cout << "Tag:" << t.id << '\n'; + std::cout << "Attributes\n"; + + std::for_each + ( + t.attributes.begin(), + t.attributes.end(), + print_pair() + ); + std::cout << "Children:\n"; + std::for_each + ( + t.children.begin(), + t.children.end(), + boost::apply_visitor(*this) + ); + std::cout << "End of tag:" << t.id << '\n'; +} diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.hpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.hpp new file mode 100644 index 00000000..15f97593 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.hpp @@ -0,0 +1,33 @@ +// Copyright (c) 2005 Carl Barron. 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) + +#ifndef SIMPLE_XML_TAG_H +#define SIMPLE_XML_TAG_H + +#include <boost/variant.hpp> +#include <list> +#include <map> +#include <string> + +struct tag +{ + std::string id; + std::map<std::string,std::string> attributes; + typedef boost::variant< + std::string, + boost::recursive_wrapper<tag> + > + variant_type; + std::list<variant_type> children; +}; + + +struct walk_data +{ + typedef void result_type; + void operator () (const std::string &x); + void operator () (const tag &t); +}; + +#endif diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/xml_g.hpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/xml_g.hpp new file mode 100644 index 00000000..fb0a4c61 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/xml_g.hpp @@ -0,0 +1,186 @@ +// Copyright (c) 2005 Carl Barron. 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) + +#ifndef XML_G_H +#define XML_G_H +#define BOOST_SPIRIT_DEBUG +#ifndef BOOST_SPIRIT_CLOSURE_LIMIT +#define BOOST_SPIRIT_CLOSURE_LIMIT 10 +#endif + +#ifndef PHOENIX_LIMIT +#define PHOENIX_LIMIT 10 +#endif + +#if BOOST_SPIRIT_CLOSURE_LIMIT < 6 +#undef BOOST_SPIRIT_CLOSURE_LIMIT +#define BOOST_SPIRIT_CLOSURE_LIMIT 6 +#endif + +#if PHOENIX_LIMIT < BOOST_SPIRIT_CLOSURE_LIMIT +#undef PHOENIX_LIMIT +#define PHOENIX_LIMIT BOOST_SPIRIT_CLOSURE_LIMIT +#endif + +#if 0 +#ifdef BOOST_SPIRIT_DEBUG_FLAGS +#undef BOOST_SPIRIT_DEBUG_FLAGS +#endif +#define BOOST_SPIRIT_DEBUG_FLAGS (BOOST_SPIRIT_DEBUG_FLAGS_MAX - BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES) +#endif + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_attribute.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include "tag.hpp" +#include "actions.hpp" +#include <boost/variant.hpp> + +#include <string> +#include <utility> + +namespace SP = BOOST_SPIRIT_CLASSIC_NS; +using phoenix::arg1; +using phoenix::arg2; +using phoenix::construct_; +using phoenix::var; + +struct str_cls:SP::closure<str_cls,std::string> +{ member1 value;}; + +struct attrib_cls:SP::closure +< + attrib_cls, + std::pair<std::string,std::string>, + std::string, + std::string +> +{ + member1 value; + member2 first; + member3 second; +}; + +struct tagged_cls:SP::closure +< + tagged_cls, + tag, + std::string, + std::map<std::string,std::string>, + std::list<typename tag::variant_type> +> +{ + member1 value; + member2 ID; + member3 attribs; + member4 children; +}; + +struct xml_g:SP::grammar<xml_g> +{ + std::list<tag> &tags; + xml_g(std::list<tag> &a):tags(a){} + template <class Scan> + struct definition + { + definition(const xml_g &s) + { + white = +SP::space_p + ; + + tagged = (start_tag + >> *inner + >> end_tag + | simple_start_tag + ) + [store_tag(tagged.value,tagged.ID,tagged.attribs, + tagged.children)] + ; + + end_tag = SP::str_p("</") + >> SP::f_str_p(tagged.ID) + >> '>' + ; + + inner = (tagged + | str) [push_child(tagged.children,arg1)] + ; + + str = SP::lexeme_d[+(SP::anychar_p - '<')] + [str.value=construct_<std::string>(arg1,arg2)] + ; + + top = +tagged + [push_back(var(s.tags),arg1)] + ; + + starter = SP::ch_p('<') + >> SP::lexeme_d[+SP::alpha_p] + [tagged.ID = construct_<std::string>(arg1,arg2)] + >> *attrib + [store_in_map(tagged.attribs,arg1)] + >> !white + ; + start_tag = starter + >> '>' + ; + + simple_start_tag = starter + >> "/>" + ; + + attrib = white + >>SP::lexeme_d[+SP::alpha_p] + [attrib.first = construct_<std::string>(arg1,arg2)] + >> !white + >> '=' + >> !white + >> '"' + >> SP::lexeme_d[+(SP::anychar_p - '"')] + [attrib.second = construct_<std::string>(arg1,arg2)] + >> SP::ch_p('"') + [attrib.value = construct_ + < + std::pair + < + std::string, + std::string + > + >(attrib.first,attrib.second)] + ; + BOOST_SPIRIT_DEBUG_RULE(tagged); + BOOST_SPIRIT_DEBUG_RULE(end_tag); + BOOST_SPIRIT_DEBUG_RULE(inner); + BOOST_SPIRIT_DEBUG_RULE(str); + BOOST_SPIRIT_DEBUG_RULE(top); + BOOST_SPIRIT_DEBUG_RULE(start_tag); + BOOST_SPIRIT_DEBUG_RULE(attrib); + BOOST_SPIRIT_DEBUG_RULE(white); + BOOST_SPIRIT_DEBUG_RULE(starter); + BOOST_SPIRIT_DEBUG_RULE(simple_start_tag); + } + + // actions + push_back_f push_back; + push_child_f push_child; + store_in_map_f store_in_map; + store_tag_f store_tag; + // rules + SP::rule<Scan,tagged_cls::context_t> tagged; + SP::rule<Scan> end_tag; + SP::rule<Scan> inner; + SP::rule<Scan,str_cls::context_t> str; + SP::rule<Scan> top; + SP::rule<Scan> starter; + SP::rule<Scan> simple_start_tag; + SP::rule<Scan> start_tag; + SP::rule<Scan> white; + SP::rule<Scan,attrib_cls::context_t> attrib; + SP::rule<Scan> const &start() const + { return top;} + }; +}; + +#endif + diff --git a/src/boost/libs/spirit/classic/example/techniques/dynamic_rule.cpp b/src/boost/libs/spirit/classic/example/techniques/dynamic_rule.cpp new file mode 100644 index 00000000..d3e1a086 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/dynamic_rule.cpp @@ -0,0 +1,58 @@ +/*============================================================================= + Copyright (c) 2003 Jonathan de Halleux (dehalleux@pelikhan.com) + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// This example shows how the assign operator can be used to modify +// rules with semantic actions +// +// First we show the basic spirit without (without any dynamic feature), +// then we show how to use assign_a to make it dynamic, +// +// the grammar has to parse abcabc... sequences +/////////////////////////////////////////////////////////////////////////////// +#include <iostream> + +#define BOOST_SPIRIT_DEBUG +#include <boost/spirit.hpp> + +#include <boost/spirit/include/classic_assign_actor.hpp> + +int main() +{ + using namespace BOOST_SPIRIT_CLASSIC_NS; + using namespace std; + + rule<> a,b,c,next; + const char* str="abcabc"; + parse_info<> hit; + BOOST_SPIRIT_DEBUG_NODE(next); + BOOST_SPIRIT_DEBUG_NODE(a); + BOOST_SPIRIT_DEBUG_NODE(b); + BOOST_SPIRIT_DEBUG_NODE(c); + + // basic spirit gram + a = ch_p('a') >> !b; + b = ch_p('b') >> !c; + c = ch_p('c') >> !a; + + hit = parse(str, a); + cout<<"hit :"<<( hit.hit ? "yes" : "no")<<", " + <<(hit.full ? "full": "not full") + <<endl; + + // using assign_a + a = ch_p('a')[ assign_a( next, b)] >> !next; + b = ch_p('b')[ assign_a( next, c)] >> !next; + c = ch_p('c')[ assign_a( next, a)] >> !next; + hit = parse(str, a); + cout<<"hit :"<<( hit.hit ? "yes" : "no")<<", " + <<(hit.full ? "full": "not full") + <<endl; + + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/techniques/epsilon.cpp b/src/boost/libs/spirit/classic/example/techniques/epsilon.cpp new file mode 100644 index 00000000..b331774d --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/epsilon.cpp @@ -0,0 +1,68 @@ +/*============================================================================= + Copyright (c) 2003 Vaclav Vesely + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +// +// This example demonstrates the behaviour of epsilon_p when used as parser +// generator. +// +// The "r" is the rule, which is passed as a subject to the epsilon_p parser +// generator. The "r" is the rule with binded semantic actions. But epsilon_p +// parser generator is intended for looking forward and we don't want to +// invoke semantic actions of subject parser. Hence the epsilon_p uses +// the no_actions policy. +// +// Because we want to use the "r" rule both in the epsilon_p and outside of it +// we need the "r" to support two differant scanners, one with no_actions +// action policy and one with the default action policy. To achieve this +// we declare the "r" with the no_actions_scanner_list scanner type. +// +//----------------------------------------------------------------------------- +#define BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT 2 + +#include <boost/assert.hpp> +#include <iostream> +#include <boost/cstdlib.hpp> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/phoenix1.hpp> + +using namespace std; +using namespace boost; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +//----------------------------------------------------------------------------- + +int main() +{ + rule< + // Support both the default phrase_scanner_t and the modified version + // with no_actions action_policy + no_actions_scanner_list<phrase_scanner_t>::type + > r; + + int i(0); + + r = int_p[var(i) += arg1]; + + parse_info<> info = parse( + "1", + + // r rule is used twice but the semantic action is invoked only once + epsilon_p(r) >> r, + + space_p + ); + + BOOST_ASSERT(info.full); + // Check, that the semantic action was invoked only once + BOOST_ASSERT(i == 1); + + return exit_success; +} + +//----------------------------------------------------------------------------- diff --git a/src/boost/libs/spirit/classic/example/techniques/multiple_scanners.cpp b/src/boost/libs/spirit/classic/example/techniques/multiple_scanners.cpp new file mode 100644 index 00000000..c7d48215 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/multiple_scanners.cpp @@ -0,0 +1,53 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ + +// *** See the section "Rule With Multiple Scanners" in +// *** chapter "Techniques" of the Spirit documentation +// *** for information regarding this snippet + +#define BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT 3 + +#include <iostream> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/assert.hpp> + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +struct my_grammar : grammar<my_grammar> +{ + template <typename ScannerT> + struct definition + { + definition(my_grammar const& self) + { + r = lower_p; + rr = +(lexeme_d[r] >> as_lower_d[r] >> r); + } + + typedef scanner_list< + ScannerT + , typename lexeme_scanner<ScannerT>::type + , typename as_lower_scanner<ScannerT>::type + > scanners; + + rule<scanners> r; + rule<ScannerT> rr; + rule<ScannerT> const& start() const { return rr; } + }; +}; + +int +main() +{ + my_grammar g; + bool success = parse("abcdef aBc d e f aBc d E f", g, space_p).full; + BOOST_ASSERT(success); + std::cout << "SUCCESS!!!\n"; + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/techniques/nabialek.cpp b/src/boost/libs/spirit/classic/example/techniques/nabialek.cpp new file mode 100644 index 00000000..c2fbd1a0 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/nabialek.cpp @@ -0,0 +1,94 @@ +/*============================================================================= + Copyright (c) 2003 Sam Nabialek + Copyright (c) 2003-2004 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 <iostream> + +#define BOOST_SPIRIT_DEBUG + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_error_handling.hpp> +#include <boost/spirit/include/classic_iterator.hpp> +#include <boost/spirit/include/classic_symbols.hpp> +#include <boost/spirit/include/classic_utility.hpp> + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +template <typename Rule> +struct SetRest +{ + SetRest(Rule& the_rule) + : m_the_rule(the_rule) + { + } + + void operator()(Rule* new_rule) const + { + m_the_rule = *new_rule; + } + +private: + + Rule& m_the_rule; +}; + + +struct nabialek_trick : public grammar<nabialek_trick> +{ + template <typename ScannerT> + struct definition + { + typedef rule<ScannerT> rule_t; + + rule_t name; + rule_t line; + rule_t rest; + rule_t main; + rule_t one; + rule_t two; + + symbols<rule_t*> continuations; + + definition(nabialek_trick const& self) + { + name = lexeme_d[repeat_p(1,20)[alnum_p | '_']]; + + one = name; + two = name >> ',' >> name; + + continuations.add + ("one", &one) + ("two", &two) + ; + + line = continuations[SetRest<rule_t>(rest)] >> rest; + main = *line; + + BOOST_SPIRIT_DEBUG_RULE(name); + BOOST_SPIRIT_DEBUG_RULE(line); + BOOST_SPIRIT_DEBUG_RULE(rest); + BOOST_SPIRIT_DEBUG_RULE(main); + BOOST_SPIRIT_DEBUG_RULE(one); + BOOST_SPIRIT_DEBUG_RULE(two); + } + + rule_t const& + start() const + { + return main; + } + }; +}; + +int +main() +{ + nabialek_trick g; + parse("one only\none again\ntwo first,second", g, space_p); + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/techniques/no_rules/no_rule1.cpp b/src/boost/libs/spirit/classic/example/techniques/no_rules/no_rule1.cpp new file mode 100644 index 00000000..547ee978 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/no_rules/no_rule1.cpp @@ -0,0 +1,51 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ + +// *** See the section "Look Ma' No Rules" in +// *** chapter "Techniques" of the Spirit documentation +// *** for information regarding this snippet + +#include <iostream> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/assert.hpp> + +using namespace BOOST_SPIRIT_CLASSIC_NS; + + struct skip_grammar : grammar<skip_grammar> + { + template <typename ScannerT> + struct definition + { + definition(skip_grammar const& /*self*/) + { + skip + = space_p + | "//" >> *(anychar_p - '\n') >> '\n' + | "/*" >> *(anychar_p - "*/") >> "*/" + ; + } + + rule<ScannerT> skip; + + rule<ScannerT> const& + start() const { return skip; } + }; + }; + +int +main() +{ + skip_grammar g; + bool success = parse( + "/*this is a comment*/\n//this is a c++ comment\n\n", + *g).full; + BOOST_ASSERT(success); + std::cout << "SUCCESS!!!\n"; + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/techniques/no_rules/no_rule2.cpp b/src/boost/libs/spirit/classic/example/techniques/no_rules/no_rule2.cpp new file mode 100644 index 00000000..ddd37d50 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/no_rules/no_rule2.cpp @@ -0,0 +1,58 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ + +// *** See the section "Look Ma' No Rules" in +// *** chapter "Techniques" of the Spirit documentation +// *** for information regarding this snippet + +#include <iostream> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/assert.hpp> + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +struct skip_grammar : grammar<skip_grammar> +{ + template <typename ScannerT> + struct definition + { + definition(skip_grammar const& /*self*/) + : skip + ( space_p + | "//" >> *(anychar_p - '\n') >> '\n' + | "/*" >> *(anychar_p - "*/") >> "*/" + ) + { + } + + typedef + alternative<alternative<space_parser, sequence<sequence< + strlit<const char*>, kleene_star<difference<anychar_parser, + chlit<char> > > >, chlit<char> > >, sequence<sequence< + strlit<const char*>, kleene_star<difference<anychar_parser, + strlit<const char*> > > >, strlit<const char*> > > + skip_t; + skip_t skip; + + skip_t const& + start() const { return skip; } + }; +}; + +int +main() +{ + skip_grammar g; + bool success = parse( + "/*this is a comment*/\n//this is a c++ comment\n\n", + *g).full; + BOOST_ASSERT(success); + std::cout << "SUCCESS!!!\n"; + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/techniques/no_rules/no_rule3.cpp b/src/boost/libs/spirit/classic/example/techniques/no_rules/no_rule3.cpp new file mode 100644 index 00000000..bbdde085 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/no_rules/no_rule3.cpp @@ -0,0 +1,86 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ + +// *** See the section "Look Ma' No Rules" in +// *** chapter "Techniques" of the Spirit documentation +// *** for information regarding this snippet + +#include <iostream> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/assert.hpp> + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +namespace boost { namespace spirit +{ + template <typename DerivedT> + struct sub_grammar : parser<DerivedT> + { + typedef sub_grammar self_t; + typedef DerivedT const& embed_t; + + template <typename ScannerT> + struct result + { + typedef typename parser_result< + typename DerivedT::start_t, ScannerT>::type + type; + }; + + DerivedT const& derived() const + { return *static_cast<DerivedT const*>(this); } + + template <typename ScannerT> + typename parser_result<self_t, ScannerT>::type + parse(ScannerT const& scan) const + { + return derived().start.parse(scan); + } + }; +}} + +/////////////////////////////////////////////////////////////////////////////// +// +// Client code +// +/////////////////////////////////////////////////////////////////////////////// +struct skip_grammar : boost::spirit::sub_grammar<skip_grammar> +{ + typedef + alternative<alternative<space_parser, sequence<sequence< + strlit<const char*>, kleene_star<difference<anychar_parser, + chlit<char> > > >, chlit<char> > >, sequence<sequence< + strlit<const char*>, kleene_star<difference<anychar_parser, + strlit<const char*> > > >, strlit<const char*> > > + start_t; + + skip_grammar() + : start + ( + space_p + | "//" >> *(anychar_p - '\n') >> '\n' + | "/*" >> *(anychar_p - "*/") >> "*/" + ) + {} + + start_t start; +}; + +int +main() +{ + skip_grammar g; + + bool success = parse( + "/*this is a comment*/\n//this is a c++ comment\n\n", + *g).full; + BOOST_ASSERT(success); + std::cout << "SUCCESS!!!\n"; + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/opaque_rule_parser.cpp b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/opaque_rule_parser.cpp new file mode 100644 index 00000000..7525bd95 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/opaque_rule_parser.cpp @@ -0,0 +1,67 @@ +/*============================================================================== + Copyright (c) 2006 Tobias Schwinger + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +==============================================================================*/ +//------------------------------------------------------------------------------ +// This example demonstrates the opaque rule parser. +// See boost/spirit/include/rule_parser.hpp for details. +//------------------------------------------------------------------------------ +#include <iostream> + +#include <boost/typeof/typeof.hpp> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_typeof.hpp> + +#include <boost/spirit/include/classic_rule_parser.hpp> + +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +namespace my_project { namespace my_grammar { + + using namespace BOOST_SPIRIT_CLASSIC_NS; + + #define BOOST_SPIRIT__NAMESPACE (2,(my_project,my_grammar)) + + BOOST_SPIRIT_OPAQUE_RULE_PARSER(word, + (1,( ((char const *),str) )), + -, + + lexeme_d[ str >> +space_p ] + ) + + BOOST_SPIRIT_OPAQUE_RULE_PARSER(main, + -,-, + + *( word("dup") | word("swap") | word("drop") | word("rot") | word("tuck") ) + ) + + #undef BOOST_SPIRIT__NAMESPACE + +} } // namespace my_project::my_grammar + + + +int main() +{ + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty()) + break; + + str += '\n'; + + if (BOOST_SPIRIT_CLASSIC_NS::parse(str.c_str(), my_project::my_grammar::main).full) + std::cout << "\nOK." << std::endl; + else + std::cout << "\nERROR." << std::endl; + } + return 0; +} + + diff --git a/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_1_1.cpp b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_1_1.cpp new file mode 100644 index 00000000..54d1a5d6 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_1_1.cpp @@ -0,0 +1,103 @@ +/*============================================================================== + Copyright (c) 2006 Tobias Schwinger + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +==============================================================================*/ +//------------------------------------------------------------------------------ +// This example uses typeof to build a nonrecursive grammar. +// See boost/spirit/include/rule_parser.hpp for details. +//------------------------------------------------------------------------------ +#include <string> +#include <iostream> + +#include <boost/typeof/typeof.hpp> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_typeof.hpp> + +#include <boost/spirit/include/classic_confix.hpp> +#include <boost/spirit/include/classic_typeof.hpp> + +#include <boost/spirit/include/classic_rule_parser.hpp> + +// It's important to create an own registration group, even if there are no +// manual Typeof registrations like in this case. +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + + +namespace my_project { namespace my_module { + + using namespace BOOST_SPIRIT_CLASSIC_NS; + + + // A semantic action. + void echo_uint(unsigned i) { std::cout << "- " << i << std::endl; } + + + #define BOOST_SPIRIT__NAMESPACE (2,(my_project,my_module)) + + // C/C++ comment and whitespace skip parser.. + BOOST_SPIRIT_RULE_PARSER(skipper, + -,-,-, + + ( confix_p("//",*anychar_p,eol_p) + | confix_p("/*",*anychar_p,"*/") + | space_p + ) + ) + + // Parser for unsigned decimal, hexadecimal and binary literals. + BOOST_SPIRIT_RULE_PARSER(uint_literal, + -,-,-, + + "0x" >> hex_p[ & echo_uint ] + | "0b" >> bin_p[ & echo_uint ] + | uint_p[ & echo_uint ] + ) + + // A generic list parser (in some ways similar to Spirit's list_p utility or + // the % operator) with two parameters. + BOOST_SPIRIT_RULE_PARSER(enumeration_parser, + (2,( element_parser, delimiter_parser )),-,-, + + element_parser >> *(delimiter_parser >> element_parser) + ) + + // Parse an optional, comma separated list of uints with explicit post-skip. + BOOST_SPIRIT_RULE_PARSER(line, + -,-,-, + ! enumeration_parser(uint_literal,',') + >> lexeme_d[ !skipper ] + ) + + bool parse_line(char const * str) + { + return BOOST_SPIRIT_CLASSIC_NS::parse(str,line,skipper).full; + } + + #undef BOOST_SPIRIT__NAMESPACE + +} } // namespace ::my_project::my_module + + +int main() +{ + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty()) + break; + + str += '\n'; + + if (my_project::my_module::parse_line(str.c_str())) + std::cout << "\nOK." << std::endl; + else + std::cout << "\nERROR." << std::endl; + } + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_1_2.cpp b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_1_2.cpp new file mode 100644 index 00000000..c80e49fc --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_1_2.cpp @@ -0,0 +1,100 @@ +/*============================================================================== + Copyright (c) 2006 Tobias Schwinger + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +==============================================================================*/ +//------------------------------------------------------------------------------ +// This example uses typeof to build a nonrecursive grammar. +// See boost/spirit/include/rule_parser.hpp for details. +//------------------------------------------------------------------------------ +#include <string> +#include <iostream> + +#include <boost/typeof/typeof.hpp> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_typeof.hpp> + +#include <boost/spirit/include/classic_confix.hpp> +#include <boost/spirit/include/classic_typeof.hpp> + +#include <boost/spirit/include/classic_rule_parser.hpp> + +// It's important to create an own registration group, even if there are no +// manual Typeof registrations like in this case. +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +namespace my_project { namespace my_module { + + // Semantic actions. + void echo_uint(unsigned i) { std::cout << i; } + void comma(unsigned) { std::cout << ','; } + + #define BOOST_SPIRIT__NAMESPACE (2,(my_project,my_module)) + + // Define the action placeholders we use. + BOOST_SPIRIT_ACTION_PLACEHOLDER(uint_action) + BOOST_SPIRIT_ACTION_PLACEHOLDER(next_action) + + // Parser for unsigned decimal, hexadecimal and binary literals. + // Takes a function pointer as its parameter. + BOOST_SPIRIT_RULE_PARSER(uint_literal + ,-,(1,( uint_action )),-, + + str_p("0x") >> hex_p[ uint_action ] + | str_p("0b") >> bin_p[ uint_action ] + | uint_p[ uint_action ] + ) + + // Parser for a list of (dec/hex/bin) uints. + BOOST_SPIRIT_RULE_PARSER(uint_list, + -,(2,( uint_action, next_action )),-, + + uint_literal[uint_action] >> *(',' >> uint_literal[next_action][uint_action]) + ) + + // Parse an optional, comma separated list of uints with explicit post-skip. + // Note that we have to put the rule into parentheses here, because it + // contains an unparenthesized comma. + BOOST_SPIRIT_RULE_PARSER(line, + -,-,-, + + ( + ! uint_list[ (uint_action = & echo_uint), (next_action = & comma) ] + >> lexeme_d[ !space_p ] + ) + ) + + bool parse_line(char const * str) + { + return BOOST_SPIRIT_CLASSIC_NS::parse(str,line,space_p).full; + } + + #undef BOOST_SPIRIT__NAMESPACE + +} } // namespace ::my_project::my_module + + +int main() +{ + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty()) + break; + + str += '\n'; + + if (my_project::my_module::parse_line(str.c_str())) + std::cout << "\nOK." << std::endl; + else + std::cout << "\nERROR." << std::endl; + } + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_2_1.cpp b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_2_1.cpp new file mode 100644 index 00000000..356bc505 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_2_1.cpp @@ -0,0 +1,107 @@ +/*============================================================================== + Copyright (c) 2002-2003 Joel de Guzman + Copyright (c) 2006 Tobias Schwinger + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +==============================================================================*/ +//------------------------------------------------------------------------------ +// This example shows a recursive grammar built using subrules and typeof. +// See boost/spirit/include/rule_parser.hpp for details. +// This example is based on subrule_calc.cpp. +//------------------------------------------------------------------------------ +#include <string> +#include <iostream> + +#include <boost/typeof/typeof.hpp> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_typeof.hpp> + +#include <boost/spirit/include/classic_rule_parser.hpp> + +// Don't forget to +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +// Semantic actions +namespace +{ + void do_int(int v) { std::cout << "PUSH(" << v << ')' << std::endl; } + void do_add(char const*, char const*) { std::cout << "ADD" << std::endl; } + void do_sub(char const*, char const*) { std::cout << "SUB" << std::endl; } + void do_mul(char const*, char const*) { std::cout << "MUL" << std::endl; } + void do_div(char const*, char const*) { std::cout << "DIV" << std::endl; } + void do_neg(char const*, char const*) { std::cout << "NEG" << std::endl; } +} + +// Operating at root namespace... +#define BOOST_SPIRIT__NAMESPACE - + + +// Our calculator grammar using subrules in a rule parser. +BOOST_SPIRIT_RULE_PARSER( calc, + -, + -, + (3,( ((subrule<0>),expression,()), + ((subrule<1>),term,()), + ((subrule<2>),factor,() )) ), + ( + expression = + term + >> *( ('+' >> term)[&do_add] + | ('-' >> term)[&do_sub] + ) + , + + term = + factor + >> *( ('*' >> factor)[&do_mul] + | ('/' >> factor)[&do_div] + ) + , + + factor = + int_p[&do_int] + | ('(' >> expression >> ')') + | ('-' >> factor)[&do_neg] + | ('+' >> factor) + ) +) + +#undef BOOST_SPIRIT__NAMESPACE + + +// Main program +int main() +{ + std::cout + << "/////////////////////////////////////////////////////////\n" + << "\t\tA ruleless calculator using subrules...\n" + << "/////////////////////////////////////////////////////////\n" + << "Type an expression...or an empty line to quit\n" + << std::endl; + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty()) break; + + parse_info<> info = parse(str.c_str(), calc, space_p); + + if (info.full) + std::cout + << "OK." + << std::endl; + else + std::cout + << "ERROR.\n" + << "Stopped at: \": " << info.stop << "\".\n" + << std::endl; + } + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_2_2.cpp b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_2_2.cpp new file mode 100644 index 00000000..3ae9738a --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/no_rules_with_typeof/rule_parser_2_2.cpp @@ -0,0 +1,142 @@ +/*============================================================================== + Copyright (c) 2002-2003 Joel de Guzman + Copyright (c) 2006 Tobias Schwinger + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +==============================================================================*/ +//------------------------------------------------------------------------------ +// This example demonstrates how to make recursive grammars scale with typeof. +// It uses a rule parser with member variables and the parser_reference utility. +// See boost/spirit/include/rule_parser.hpp for details. +// This example is based on subrule_calc.cpp. +//------------------------------------------------------------------------------ +#include <string> +#include <iostream> + +#include <boost/config.hpp> + +#if defined(BOOST_MSVC) +// Disable MSVC's "'this' used in base/member initializer" warning. +// It's perfectly safe to use 'this' in a base/member initializer [ 12.6.2-7 ]. +// The warning tries to prevent undefined behaviour when the 'this'-pointer is +// used to do illegal things during construction [ 12.6.2-8 ] -- we don't. +# pragma warning(disable:4355) +#endif + +#include <boost/typeof/typeof.hpp> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_typeof.hpp> + +#include <boost/spirit/include/classic_rule_parser.hpp> + + +// Don't forget to +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +// Semantic actions +namespace +{ + void do_int(int v) { std::cout << "PUSH(" << v << ')' << std::endl; } + void do_add(char const*, char const*) { std::cout << "ADD" << std::endl; } + void do_sub(char const*, char const*) { std::cout << "SUB" << std::endl; } + void do_mul(char const*, char const*) { std::cout << "MUL" << std::endl; } + void do_div(char const*, char const*) { std::cout << "DIV" << std::endl; } + void do_neg(char const*, char const*) { std::cout << "NEG" << std::endl; } +} + +// Operating at root namespace... +#define BOOST_SPIRIT__NAMESPACE - + +// Our calculator grammar using paramterized rule parsers. +// Subrules are passed to the rule parsers as arguments to allow recursion. + +BOOST_SPIRIT_RULE_PARSER(expression, + (1,(term)), + -, + -, + + term + >> *( ('+' >> term)[ &do_add ] + | ('-' >> term)[ &do_sub ] + ) +) + +BOOST_SPIRIT_RULE_PARSER(term, + (1,(factor)), + -, + -, + + factor + >> *( ('*' >> factor)[ &do_mul ] + | ('/' >> factor)[ &do_div ] + ) +) + +// This rule parser uses the 'parser_reference' utility to refer to itself. +// Note that here is another recursive loop, however, the self-reference, unlike +// a subrule, cannot be passed to contained parsers because we would end up with +// an endless loop at compile time finding the type. +BOOST_SPIRIT_RULE_PARSER(factor, + (1,(expression)), + -, + (1,( ((parser_reference<factor_t>),factor,(*this)) )), + + ( int_p[& do_int] + | ('(' >> expression >> ')') + | ('-' >> factor)[&do_neg] + | ('+' >> factor) + ) +) + + +// This rule parser implements recursion between the other ones. +BOOST_SPIRIT_RULE_PARSER( calc, + -, + -, + (3,( ((subrule<0>),sr_expression,()), + ((subrule<1>),sr_term,()), + ((subrule<2>),sr_factor,() )) ), + + ( + sr_expression = expression(sr_term), + sr_term = term(sr_factor), + sr_factor = factor(sr_expression) + ) +) + +// Main program +int main() +{ + std::cout + << "/////////////////////////////////////////////////////////////\n" + << "\t\tA ruleless calculator using rule parsers and subrules...\n" + << "/////////////////////////////////////////////////////////////\n" + << "Type an expression...or an empty line to quit\n" + << std::endl; + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty()) break; + + parse_info<> info = parse(str.c_str(), calc, space_p); + + if (info.full) + std::cout + << "OK." + << std::endl; + else + std::cout + << "ERROR.\n" + << "Stopped at: \": " << info.stop << "\".\n" + << std::endl; + } + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/techniques/right_recursion.cpp b/src/boost/libs/spirit/classic/example/techniques/right_recursion.cpp new file mode 100644 index 00000000..132b0dc5 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/right_recursion.cpp @@ -0,0 +1,90 @@ +/*============================================================================= + Copyright (c) 2005 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 <iostream> + +#define BOOST_SPIRIT_DEBUG +#include <boost/spirit/include/classic_core.hpp> +#include <boost/assert.hpp> + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +struct non_greedy_kleene : public grammar<non_greedy_kleene> +{ + template <typename ScannerT> + struct definition + { + typedef rule<ScannerT> rule_t; + rule_t r; + + definition(non_greedy_kleene const& self) + { + r = (alnum_p >> r) | digit_p; + BOOST_SPIRIT_DEBUG_RULE(r); + } + + rule_t const& + start() const + { + return r; + } + }; +}; + +struct non_greedy_plus : public grammar<non_greedy_plus> +{ + template <typename ScannerT> + struct definition + { + typedef rule<ScannerT> rule_t; + rule_t r; + + definition(non_greedy_plus const& self) + { + r = alnum_p >> (r | digit_p); + BOOST_SPIRIT_DEBUG_RULE(r); + } + + rule_t const& + start() const + { + return r; + } + }; +}; +int +main() +{ + bool success; + { + non_greedy_kleene k; + success = parse("3", k).full; + BOOST_ASSERT(success); + success = parse("abcdef3", k).full; + BOOST_ASSERT(success); + success = parse("abc2def3", k).full; + BOOST_ASSERT(success); + success = parse("abc", k).full; + BOOST_ASSERT(!success); + } + + { + non_greedy_plus p; + success = parse("3", p).full; + BOOST_ASSERT(!success); + success = parse("abcdef3", p).full; + BOOST_ASSERT(success); + success = parse("abc2def3", p).full; + BOOST_ASSERT(success); + success = parse("abc", p).full; + BOOST_ASSERT(!success); + } + + std::cout << "SUCCESS!!!\n"; + return 0; +} diff --git a/src/boost/libs/spirit/classic/example/techniques/typeof.cpp b/src/boost/libs/spirit/classic/example/techniques/typeof.cpp new file mode 100644 index 00000000..5aacd758 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/techniques/typeof.cpp @@ -0,0 +1,41 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ + +// *** See the section "typeof" in chapter "Techniques" of +// *** the Spirit documentation for information regarding +// *** this snippet. + +#include <iostream> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/typeof/typeof.hpp> +#include <boost/assert.hpp> + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +#define RULE(name, definition) BOOST_TYPEOF(definition) name = definition + +int +main() +{ + RULE( + skipper, + ( space_p + | "//" >> *(anychar_p - '\n') >> '\n' + | "/*" >> *(anychar_p - "*/") >> "*/" + ) + ); + + bool success = parse( + "/*this is a comment*/\n//this is a c++ comment\n\n", + *skipper).full; + BOOST_ASSERT(success); + std::cout << "SUCCESS!!!\n"; + return 0; +} + |