I am trying to use Boost.Spirit (V. 2.5) library to create a mini-calculator. Features I want to implement : - basic calculus (+,-,/,*), that works - some functions (like min, max), that works too - declaring/assigning double variables, and there is the problem... when I add "[vars.add]" I get compilation error (template parameter ambiguious). I've tried "add(char_(_1)", "add(_1)",... and nothing seems to work. I am obviously missing something (not understanding something actually). If someone could help me on this I would me most gratefull!
Here is the source :
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/home/phoenix/statement/if.hpp>
#include <boost/spirit/home/phoenix/bind/bind_function.hpp>
#include <iostream>
#include <string>
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phx = boost::phoenix;
struct vars_ : qi::symbols<char, double> {
vars_() {
add("ans" , 0);
}
} vars;
template <typename Iterator>
struct parser : qi::grammar<Iterator, double()>
{
parser() : parser::base_type(function)
{
using qi::eps;
using qi::lit;
using qi::_val;
using qi::_1;
using ascii::char_;
using qi::double_;
using qi::string;
using qi::lexeme;
using boost::phoenix::if_;
using qi::alpha;
using qi::alnum;
MAX = lexeme[string("max") | string("MAX")]; //define max symbol
MIN = lexeme[string("min") | string("MIN")]; //define min symbol
D = lexeme[string("d") | string("D")]; //define distance symbol
ANS = lexeme[string("ans") | string("ANS")]; //not working yet
function =
expression [_val = _1]
| declaration
| assignment
| ( MAX >> "(" >> function [_val = _1] >>
+(',' >> function [if_(_1 > _val)[_val = _1]]) >> ')') // call : max(function,...)
| ( MIN >> "(" >> function [_val = _1] >>
+(',' >> function [if_(_1 < _val)[_val = _1]]) >> ')') // call : min(function,...)
| ( D >> "(" >> (function >> ',' >> function) >> ')'); // call : d(point1,point2) not implemented yet
expression =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1]));
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1]));
factor =
double_ [_val = _1]
| (vars [_val += _1] )
| '(' >> expression [_val = _1] >> ')'
| ('-' >> factor [_val = -_1])
| ('+' >> factor [_val = _1])
| declaration;
;
assignment =
vars >> '=' >> function;
var_decl =
lexeme [ qi::raw [ ( alpha >> *( alnum | '_' ) ) - vars ] ] //[ phx::bind(vars.add, _1) ]
;
declaration =
"var " >> var_decl >> *( ',' >> var_decl );
}
qi::rule<Iterator, double()> MAX, MIN, D, ANS, expression, term, factor,
function, assignment, var_decl, declaration;
};
}
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int main()
{
std::cout << "**********************************************************" << std::endl;
std::cout << "* *" << std::endl;
std::cout << "* Command interface for VideoTraction4 *" << std::endl;
std::cout << "* *" << std::endl;
std::cout << "**********************************************************" << std::endl << std::endl;
std::cout << "Type an expression...or [q or Q] to quit" << std::endl << std::endl;
typedef std::string::const_iterator iterator_type;
typedef client::parser<iterator_type> parser;
parser _parser; // Our grammar
std::string str;
double result;
while (std::getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
bool r = parse(iter, end, _parser, result);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "result = " << result << std::endl;
std::cout << "-------------------------\n";
client::vars.remove("ans");
client::vars.add("ans",result);
}
else
{
std::string rest(iter, end);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << rest << "\"\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}
I would like to do things such as :
var i,j
i = 1
j = max(2*(i+1),5)
Huh, I've never actually added symbols from directly inside Semantic Actions myself (I prefer to build ASTs, and then traverse those).
The fact that you wrote it like this and the absence of a SSCCE had me blindsided for a moment. Turns out, I should just have ignored the circumstantial 'evidence' and went straight for the docs + win:
or
and some similar incantations will apply
Edit Here is the complete source, compiled on MSVC 2010, with boost 1.47:
Output:
On a slightly unrelated note: it looks kind-a funny that the exposed attribute of the var_decl rule appears to be
char
?You might want to read up on auto-rules and the
%=
operator; Without %=, the presence of a Semantic Action will suppress all automatic attribute propagation. That is helpful in case the required customization points do not exist. As written, the exposed attribute will always be unassigned-to.