2bda35f0fd
libs\spirit\classic\test\ast_calc_tests.cpp(209) : warning C4702: unreachable code
280 lines
10 KiB
C++
280 lines
10 KiB
C++
/*=============================================================================
|
|
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();
|
|
}
|
|
|
|
|