Arithmetic evaluation: Difference between revisions
Content added Content deleted
(Undo revision 17565 by 87.117.229.252 (Talk): The task explicitly demands construction of an AST!) |
|||
Line 330: | Line 330: | ||
{{libheader|Boost.Spirit}}1.8.4 |
{{libheader|Boost.Spirit}}1.8.4 |
||
<cpp>#include <boost/spirit |
<cpp> #include <boost/spirit.hpp> |
||
#include <boost/spirit/ |
#include <boost/spirit/tree/ast.hpp> |
||
#include < |
#include <string> |
||
#include < |
#include <cassert> |
||
#include <iostream> |
|||
#include <istream> |
|||
//////////////////////////////////////////////////////////////////////////// |
|||
#include <ostream> |
|||
using namespace std; |
|||
using namespace boost::spirit; |
|||
using |
using boost::spirit::rule; |
||
using boost::spirit::parser_tag; |
|||
using boost::spirit::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 |
|||
double> >& node, |
|||
std::string::iterator begin, |
|||
std::string::iterator end) const |
|||
{ |
|||
) |
|||
node.value.value(self.tmp); |
|||
} |
|||
parser const& self; |
|||
}; |
|||
= 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 = 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 - op2; |
|||
case '*': |
|||
return op1 * op2; |
|||
case '/': |
|||
return op1 / op2; |
|||
cout << "-------------------------\n"; |
|||
default: |
|||
cout << "Parsing succeeded\n"; |
|||
assert(!"Should not happen"); |
|||
} |
|||
cout << "-------------------------\n"; |
|||
default: |
|||
assert(!"Should not happen"); |
|||
} |
|||
return 0; |
|||
cout << "-------------------------\n"; |
|||
} |
|||
cout << "Parsing failed\n"; |
|||
cout << "stopped at: \": " << info.stop << "\"\n"; |
|||
// the read/eval/write loop |
|||
cout << "-------------------------\n"; |
|||
int main() |
|||
} |
|||
{ |
|||
} |
|||
parser eval; |
|||
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> |
</cpp> |
||