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::unique_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 : }; 49 : 50 : /// @brief Convenience function 51 : /// 52 : /// This function builds the grammar, parses the iterator to an AST, 53 : /// evaluates it, and returns the result. 54 : /// 55 : /// @param[in] expr mathematical expression 56 : /// @param[in] st the symbol table for variables 57 98 : inline double parse(std::string const &expr, 58 : std::map<std::string, double> const &st = {}) { 59 196 : Parser parser; 60 98 : parser.parse(expr); 61 191 : return parser.evaluate(st); 62 : } 63 : 64 : } // namespace matheval