blob: 0d9d43224325ca6e2ec4b2c7115207e972a8c4ab [file] [log] [blame]
/*=============================================================================
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 <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())
{
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
assert(*i->value.begin() == '-');
return - eval_expression(i->children.begin());
}
else if (i->value.id() == term.id())
{
if (*i->value.begin() == '*')
{
assert(i->children.size() == 2);
return eval_expression(i->children.begin()) *
eval_expression(i->children.begin()+1);
}
else if (*i->value.begin() == '/')
{
assert(i->children.size() == 2);
return eval_expression(i->children.begin()) /
eval_expression(i->children.begin()+1);
}
else
assert(0);
}
else if (i->value.id() == expression.id())
{
if (*i->value.begin() == '+')
{
assert(i->children.size() == 2);
return eval_expression(i->children.begin()) +
eval_expression(i->children.begin()+1);
}
else if (*i->value.begin() == '-')
{
assert(i->children.size() == 2);
return eval_expression(i->children.begin()) -
eval_expression(i->children.begin()+1);
}
else
assert(0);
}
else
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;
}