123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /*=============================================================================
- 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)
- =============================================================================*/
- // JDG 4-16-03 Modified from ast_calc.cpp as a test
- #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/detail/workaround.hpp>
- #include <iostream>
- #include <stack>
- #include <functional>
- #include <string>
- #include <boost/detail/lightweight_test.hpp>
- using namespace BOOST_SPIRIT_CLASSIC_NS;
- ////////////////////////////////////////////////////////////////////////////
- //
- // 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[real_p]; // we're not really using a real
- // but just for compile checking
- // the AST tree match code...
- 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
- }
- 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; }
- };
- };
- ////////////////////////////////////////////////////////////////////////////
- //
- // Our calculator grammar, but with dynamically assigned rule ID's
- //
- ////////////////////////////////////////////////////////////////////////////
- struct dyn_calculator : public grammar<dyn_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(dyn_calculator const& /*self*/)
- {
- expression.set_id(expressionID);
- term.set_id(termID);
- factor.set_id(factorID);
- integer.set_id(integerID);
-
- // Start grammar definition
- integer = leaf_node_d[real_p]; // we're not really using a real
- // but just for compile checking
- // the AST tree match code...
- 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
- }
- rule<ScannerT, parser_context<>, dynamic_parser_tag> expression;
- rule<ScannerT, parser_context<>, dynamic_parser_tag> term;
- rule<ScannerT, parser_context<>, dynamic_parser_tag> factor;
- rule<ScannerT, parser_context<>, dynamic_parser_tag> integer;
- rule<ScannerT, parser_context<>, dynamic_parser_tag> const&
- start() const { return expression; }
- };
- };
- ////////////////////////////////////////////////////////////////////////////
- using namespace std;
- using namespace BOOST_SPIRIT_CLASSIC_NS;
- typedef char const* parser_iterator_t;
- typedef tree_match<parser_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)
- {
- switch (i->value.id().to_long())
- {
- case calculator::integerID:
- {
- BOOST_TEST(i->children.size() == 0);
- // extract integer (not always delimited by '\0')
- #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003))
- // std::string(iter,iter) constructor has a bug in MWCW 8.3:
- // in some situations, the null terminator won't be added
- // and c_str() will return bogus data. Conservatively, I
- // activate this workaround up to version 8.3.
- std::vector<char> value(i->value.begin(), i->value.end());
- value.push_back('\0');
- return strtol(&value[0], 0, 10);
- #else
- string integer(i->value.begin(), i->value.end());
- return strtol(integer.c_str(), 0, 10);
- #endif
- }
- case calculator::factorID:
- {
- // factor can only be unary minus
- BOOST_TEST(*i->value.begin() == '-');
- return - eval_expression(i->children.begin());
- }
- case calculator::termID:
- {
- if (*i->value.begin() == '*')
- {
- BOOST_TEST(i->children.size() == 2);
- return eval_expression(i->children.begin()) *
- eval_expression(i->children.begin()+1);
- }
- else if (*i->value.begin() == '/')
- {
- BOOST_TEST(i->children.size() == 2);
- return eval_expression(i->children.begin()) /
- eval_expression(i->children.begin()+1);
- }
- else
- std::abort();
- }
- case calculator::expressionID:
- {
- if (*i->value.begin() == '+')
- {
- BOOST_TEST(i->children.size() == 2);
- return eval_expression(i->children.begin()) +
- eval_expression(i->children.begin()+1);
- }
- else if (*i->value.begin() == '-')
- {
- BOOST_TEST(i->children.size() == 2);
- return eval_expression(i->children.begin()) -
- eval_expression(i->children.begin()+1);
- }
- else
- std::abort();
- }
- default:
- std::abort(); // error
- }
- #if defined(_MSC_VER) && (_MSC_VER < 1700)
- return 0;
- #endif
- }
- ////////////////////////////////////////////////////////////////////////////
- int
- parse(char const* str)
- {
- calculator calc;
- tree_parse_info<> info = ast_parse(str, calc, space_p);
- if (info.full)
- return evaluate(info);
- else
- return -1;
- }
- int
- parse_dyn(char const* str)
- {
- dyn_calculator calc;
- tree_parse_info<> info = ast_parse(str, calc, space_p);
- if (info.full)
- return evaluate(info);
- else
- return -1;
- }
- int
- main()
- {
- // test the calculator with statically assigned rule ID's
- BOOST_TEST(parse("12345") == 12345);
- BOOST_TEST(parse("-12345") == -12345);
- BOOST_TEST(parse("1 + 2") == 1 + 2);
- BOOST_TEST(parse("1 * 2") == 1 * 2);
- BOOST_TEST(parse("1/2 + 3/4") == 1/2 + 3/4);
- BOOST_TEST(parse("1 + 2 + 3 + 4") == 1 + 2 + 3 + 4);
- BOOST_TEST(parse("1 * 2 * 3 * 4") == 1 * 2 * 3 * 4);
- BOOST_TEST(parse("(1 + 2) * (3 + 4)") == (1 + 2) * (3 + 4));
- BOOST_TEST(parse("(-1 + 2) * (3 + -4)") == (-1 + 2) * (3 + -4));
- BOOST_TEST(parse("1 + ((6 * 200) - 20) / 6") == 1 + ((6 * 200) - 20) / 6);
- BOOST_TEST(parse("(1 + (2 + (3 + (4 + 5))))") == (1 + (2 + (3 + (4 + 5)))));
- BOOST_TEST(parse("1 + 2 + 3 + 4 + 5") == 1 + 2 + 3 + 4 + 5);
- BOOST_TEST(parse("(12 * 22) + (36 + -4 + 5)") == (12 * 22) + (36 + -4 + 5));
- BOOST_TEST(parse("(12 * 22) / (5 - 10 + 15)") == (12 * 22) / (5 - 10 + 15));
- BOOST_TEST(parse("12 * 6 * 15 + 5 - 25") == 12 * 6 * 15 + 5 - 25);
- // test the calculator with dynamically assigned rule ID's
- BOOST_TEST(parse_dyn("12345") == 12345);
- BOOST_TEST(parse_dyn("-12345") == -12345);
- BOOST_TEST(parse_dyn("1 + 2") == 1 + 2);
- BOOST_TEST(parse_dyn("1 * 2") == 1 * 2);
- BOOST_TEST(parse_dyn("1/2 + 3/4") == 1/2 + 3/4);
- BOOST_TEST(parse_dyn("1 + 2 + 3 + 4") == 1 + 2 + 3 + 4);
- BOOST_TEST(parse_dyn("1 * 2 * 3 * 4") == 1 * 2 * 3 * 4);
- BOOST_TEST(parse_dyn("(1 + 2) * (3 + 4)") == (1 + 2) * (3 + 4));
- BOOST_TEST(parse_dyn("(-1 + 2) * (3 + -4)") == (-1 + 2) * (3 + -4));
- BOOST_TEST(parse_dyn("1 + ((6 * 200) - 20) / 6") == 1 + ((6 * 200) - 20) / 6);
- BOOST_TEST(parse_dyn("(1 + (2 + (3 + (4 + 5))))") == (1 + (2 + (3 + (4 + 5)))));
- BOOST_TEST(parse_dyn("1 + 2 + 3 + 4 + 5") == 1 + 2 + 3 + 4 + 5);
- BOOST_TEST(parse_dyn("(12 * 22) + (36 + -4 + 5)") == (12 * 22) + (36 + -4 + 5));
- BOOST_TEST(parse_dyn("(12 * 22) / (5 - 10 + 15)") == (12 * 22) / (5 - 10 + 15));
- BOOST_TEST(parse_dyn("12 * 6 * 15 + 5 - 25") == 12 * 6 * 15 + 5 - 25);
- return boost::report_errors();
- }
|