Arithmetic evaluation: Difference between revisions

Undo revision 17565 by 87.117.229.252 (Talk): The task explicitly demands construction of an AST!
(Undo revision 17565 by 87.117.229.252 (Talk): The task explicitly demands construction of an AST!)
Line 330:
{{libheader|Boost.Spirit}}1.8.4
 
<cpp> #include <boost/spirit/core.hpp>
#include <boost/spirit/attributetree/ast.hpp>
#include <iostreamstring>
#include <stringcassert>
#include <iostream>
 
#include <istream>
////////////////////////////////////////////////////////////////////////////
#include <ostream>
using namespace std;
using namespace boost::spirit;
using namespace phoenixboost::spirit::rule;
using boost::spirit::parser_tag;
 
struct calc_closure : using boost::spirit::closure<calc_closure, double>ch_p;
using boost::spirit::real_p;
{
member1 val;
using boost::spirit::tree_node;
};
using boost::spirit::node_val_data;
 
struct calculator : public grammar<calculator, calc_closure::context_t>
// The grammar
{
struct parser: public boost::spirit::grammar<parser>
template <typename ScannerT>
{
struct definition
enum rule_ids { addsub_id, multdiv_id, value_id, real_id };
{
definition(calculator const& self)
struct {set_value
{
top = expression[self.val = arg1];
set_value(parser const& p): self(p) {}
 
void operator()(tree_node<node_val_data<std::string::iterator,
expression
= term[expression.val = arg1] double> >& node,
>> *(std::string::iterator ('+' >> term[expression.val += arg1])begin,
std::string::iterator end) | ('-' >> term[expression.val -= arg1])const
{
)
node.value.value(self.tmp);
}
 
parser const& termself;
};
= factor[term.val = arg1]
>> *( ('*' >> factor[term.val *= arg1])
mutable double tmp;
| ('/' >> factor[term.val /= arg1])
)
template<typename Scanner> struct definition
;
{
 
rule<Scanner, parser_tag<addsub_id> > addsub;
factor
rule<Scanner, parser_tag<multdiv_id> > multdiv;
= ureal_p[factor.val = arg1]
rule<Scanner, parser_tag<value_id> > value;
| '(' >> expression[factor.val = arg1] >> ')'
rule<Scanner, parser_tag<real_id> > real;
| ('-' >> factor[factor.val = -arg1])
| ('+' >> factor[factor.val = arg1])
definition(parser const& self)
;
}{
using namespace boost::spirit;
 
addsub = multdiv
typedef rule<ScannerT, calc_closure::context_t> rule_t;
>> *((root_node_d[ch_p('+')] | root_node_d[ch_p('-')]) >> multdiv);
rule_t expression, term, factor;
multdiv rule<ScannerT>= top;value
>> *((root_node_d[ch_p('*')] | root_node_d[ch_p('/')]) >> value);
 
value = real | inner_node_d[('(' >> addsub >> ')')];
rule<ScannerT> const&
real = leaf_node_d[access_node_d[real_p[assign_a(self.tmp)]][set_value(self)]];
start() const { return top; }
};
};
rule<Scanner, parser_tag<addsub_id> > const& start() const
 
{
////////////////////////////////////////////////////////////////////////////
return addsub;
// Main program
}
////////////////////////////////////////////////////////////////////////////
};
int
};
main()
{
template<typename TreeIter>
cout << "/////////////////////////////////////////////////////////\n\n";
double evaluate(TreeIter const& i)
cout << "\t\tExpression parser using Phoenix...\n\n";
{
cout << "/////////////////////////////////////////////////////////\n\n";
double op1, op2;
cout << "Type an expression...or [q or Q] to quit\n\n";
switch (i->value.id().to_long())
 
{
calculator calc; // Our parser
case parser::real_id:
 
return i->value.value();
string str;
case parser::value_id:
while (getline(cin, str))
case parser::addsub_id:
{
case parser::multdiv_id:
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
op1 = evaluate(i->children.begin());
break;
op2 = evaluate(i->children.begin()+1);
 
switch(*i->value.begin())
double n = 0;
{
parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p);
case '+':
 
return op1 + op2;
// calc[var(n) = arg1] invokes the calculator and extracts
case '-':
// the result of the computation. See calculator grammar
return //op1 - note above.op2;
case '*':
 
return ifop1 (info.full)* op2;
case {'/':
return op1 / op2;
cout << "-------------------------\n";
default:
cout << "Parsing succeeded\n";
cout << assert(!"resultShould =not happen" << n << endl);
}
cout << "-------------------------\n";
}default:
assert(!"Should not elsehappen");
{}
return 0;
cout << "-------------------------\n";
}
cout << "Parsing failed\n";
cout << "stopped at: \": " << info.stop << "\"\n";
// the read/eval/write loop
cout << "-------------------------\n";
int main()
}
{
}
parser return 0eval;
std::string line;
}
while (std::cout << "Expression: "
&& std::getline(std::cin, line)
&& !line.empty())
{
typedef boost::spirit::node_val_data_factory<double> factory_t;
boost::spirit::tree_parse_info<std::string::iterator, factory_t> info =
boost::spirit::ast_parse<factory_t>(line.begin(), line.end(),
eval, boost::spirit::space_p);
if (info.full)
{
std::cout << "Result: " << evaluate(info.trees.begin()) << std::endl;
}
else
{
std::cout << "Error in expression." << std::endl;
}
}
};
</cpp>
 
973

edits