#ifndef _utl_UnitGrammar_h #define _utl_UnitGrammar_h /*! \file UnitGrammar.h \brief Unit evaluating grammar definition \author Roland Sipos */ #include #if BOOST_VERSION >= 103800 # define BOOST_SPIRIT_USE_OLD_NAMESPACE # include # include # include #else # include # include # include # include #endif #include #include #include namespace utl { // Raise X to power of Y template struct PowerToImpl { template struct result { typedef double type; }; template T1 operator()(T1& t1, T2& t2) const { return std::pow(t1, t2); } }; // Create it as a constant Phoenix Function const phoenix::function power = PowerToImpl(); // Unit Grammar Structure struct UnitGrammar : public boost::spirit::grammar { typedef std::map SymbolTable; enum EErrors { eOk, // Everything is ok eLookup, // Could not find symbol in table eBracket, // Bracket error eBadSymbol, // Wrong token, e.g. plus or minus eParsing, // Unknown parsing problem }; UnitGrammar(const SymbolTable& symbols, double& retval, EErrors& error) : fSymbols(symbols), fResult(retval), fError(error) { } //! Value closure set struct SValueClosure : public boost::spirit::closure { member1 value; }; //! Assignment closure set struct SAssignmentClosure : public boost::spirit::closure { member1 name; member2 value; }; //! String closure set struct SStringClosure : public boost::spirit::closure { member1 name; }; //! Boost spirit definition template (Read Boost Spirit documentation) template struct definition { definition(UnitGrammar const& self) { group = '(' >> expression[group.value = phoenix::arg1] >> ')' ; identifier = boost::spirit::lexeme_d[(boost::spirit::alpha_p | '_') >> *(boost::spirit::alnum_p | '_')][ identifier.name = phoenix::construct_(phoenix::arg1, phoenix::arg2) ] ; statement = expression[phoenix::bind(&UnitGrammar::SaveResult)(self, phoenix::arg1)] >> (boost::spirit::end_p | ';') ; literal = boost::spirit::longest_d[boost::spirit::int_p[literal.value = phoenix::arg1] | boost::spirit::real_p[literal.value = phoenix::arg1]] ; factor = literal[factor.value = phoenix::arg1] | group[factor.value = phoenix::arg1] | identifier[factor.value = phoenix::bind(&UnitGrammar::Lookup)(self, phoenix::arg1)] ; term = factor[term.value = phoenix::arg1] >> *( ('^' >> factor[term.value = power(term.value, phoenix::arg1)]) ) ; expression = term[expression.value = phoenix::arg1] >> *( ('*' >> term[expression.value *= phoenix::arg1]) | ('/' >> term[expression.value /= phoenix::arg1]) ) ; } boost::spirit::rule const& start() const { return statement; } boost::spirit::rule statement; boost::spirit::rule identifier; boost::spirit::rule expression, factor, group, literal, term; }; void SaveResult(double val) const { fResult = val; } //! Function which searches in the symbol table double Lookup(const std::string& variable) const { const SymbolTable::const_iterator it = fSymbols.find(variable); if (it == fSymbols.end()) { fError = eLookup; return 1; } else { return it->second; } } private: const SymbolTable& fSymbols; double& fResult; EErrors& fError; }; } #endif