Line data Source code
1 : #pragma once 2 : 3 : #include <map> 4 : #include <memory> 5 : #include <string> 6 : 7 : namespace matheval { 8 : 9 : /// @brief Parse a mathematical expression 10 : /// 11 : /// This can parse and evaluate a mathematical expression for a given 12 : /// symbol table using Boost.Spirit X3. The templates of Boost.Spirit 13 : /// are very expensive to parse and instantiate, which is why we hide 14 : /// it behind an opaque pointer. 15 : /// 16 : /// The drawback of this approach is that calls can no longer be 17 : /// inlined and because the pointer crosses translation unit 18 : /// boundaries, dereferencing it can also not be optimized out at 19 : /// compile time. We have to rely entirely on link-time optimization 20 : /// which might be not as good. 21 : /// 22 : /// The pointer to the implementation is a std::unique_ptr which makes 23 : /// the class not copyable but only moveable. Copying shouldn't be 24 : /// required but is easy to implement. 25 : class Parser { 26 : class impl; 27 : std::auto_ptr<impl> pimpl; 28 : 29 : public: 30 : /// @brief Constructor 31 : Parser(); 32 : 33 : /// @brief Destructor 34 : ~Parser(); 35 : 36 : /// @brief Parse the mathematical expression into an abstract syntax tree 37 : /// 38 : /// @param[in] expr The expression given as a std::string 39 : void parse(std::string const &expr); 40 : 41 : /// @brief Perform constant folding onto the abstract syntax tree 42 : void optimize(); 43 : 44 : /// @brief Evaluate the abstract syntax tree for a given symbol table 45 : /// 46 : /// @param[in] st The symbol table 47 : double evaluate(std::map<std::string, double> const &st = 48 : std::map<std::string, double>()); 49 : }; 50 : 51 : /// @brief Convenience function 52 : /// 53 : /// This function builds the grammar, parses the iterator to an AST, 54 : /// evaluates it, and returns the result. 55 : /// 56 : /// @param[in] expr mathematical expression 57 : /// @param[in] st the symbol table for variables 58 86 : inline double parse( 59 : std::string const &expr, 60 : std::map<std::string, double> const &st = std::map<std::string, double>()) { 61 172 : Parser parser; 62 86 : parser.parse(expr); 63 167 : return parser.evaluate(st); 64 : } 65 : 66 : } // namespace matheval