Page MenuHomec4science

algebraic_parser.cc
No OneTemporary

File Metadata

Created
Sun, Jul 7, 01:58

algebraic_parser.cc

/**
* @file algebraic_parser.cc
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @date Wed Mar 13 16:53:59 2013
*
* @brief The algebraic expression parser for LM config files
*
* @section LICENSE
*
* Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* LibMultiScale is free software: you can redistribute it and/or modify it
* under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* LibMultiScale is distributed in the hope that it will be useful, but
* WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* -------------------------------------------------------------------------- */
#include "algebraic_parser.hh"
#include "lm_common.hh"
#include "lm_parser.hh"
#include <limits>
/* -------------------------------------------------------------------------- */
#include <iostream>
#include <map>
#include <string>
/* -------------------------------------------------------------------------- */
#include <boost/config/warning_disable.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/version.hpp>
#if (BOOST_VERSION / 100) % 1000 <= 55
#include <boost/spirit/home/phoenix/bind/bind_function.hpp>
#include <boost/spirit/home/phoenix/bind/bind_member_function.hpp>
#else
#include <boost/phoenix/bind/bind_function.hpp>
#include <boost/phoenix/bind/bind_member_function.hpp>
#endif
/* -------------------------------------------------------------------------- */
#include <boost/mpl/bool.hpp>
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
template <typename Iterator>
struct AlgebraicParser : boost::spirit::qi::grammar<Iterator, double()> {
/* ------------------------------------------------------------------------ */
/* Constructors/Destructors */
/* ------------------------------------------------------------------------ */
public:
AlgebraicParser();
/* ------------------------------------------------------------------------ */
/* Methods */
/* ------------------------------------------------------------------------ */
public:
private:
inline double set_var_value(double const &val,
std::string const &var_name) const;
inline double get_env_var(std::string const &var_name) const;
inline double get_var_value(std::string const &var_name) const;
inline double get_func_result(double const &entry,
std::string const &func_name) const;
inline double debug_double(double const &test) const;
inline std::string debug_string(std::string const &test) const;
inline std::string get_string(std::vector<char> const &vec) const;
inline std::string concat_string(std::vector<char> const &vec,
std::string const &str2) const;
/* ------------------------------------------------------------------------ */
/* Class Members */
/* ------------------------------------------------------------------------ */
private:
//! grammar rules
boost::spirit::qi::rule<Iterator, double(),
boost::spirit::qi::locals<std::string>>
set_var;
boost::spirit::qi::rule<Iterator, double()> item;
boost::spirit::qi::rule<Iterator, std::string(),
boost::spirit::qi::locals<std::string>>
obj_name;
boost::spirit::qi::rule<Iterator, double(),
boost::spirit::qi::locals<std::string>>
func;
boost::spirit::qi::rule<Iterator, double()> num;
boost::spirit::qi::rule<Iterator, double()> env_var;
boost::spirit::qi::rule<Iterator, double()> term;
boost::spirit::qi::rule<Iterator, double()> factor;
boost::spirit::qi::rule<Iterator, double()> start;
boost::spirit::qi::rule<Iterator, double()> white_space;
public:
//! map of functions
std::map<std::string, double (*)(double)> function_maps;
//! map of variables and values
mutable std::map<std::string, double> variables;
};
/* -------------------------------------------------------------------------- */
template <typename Iterator>
inline double
AlgebraicParser<Iterator>::debug_double(double const &test) const {
std::cerr << "parsing " << test << std::endl;
return test;
}
/* -------------------------------------------------------------------------- */
template <typename Iterator>
inline std::string
AlgebraicParser<Iterator>::debug_string(std::string const &test) const {
std::cerr << "parsing " << test << std::endl;
return test;
}
/* -------------------------------------------------------------------------- */
template <typename Iterator>
inline std::string
AlgebraicParser<Iterator>::get_string(std::vector<char> const &vec) const {
std::string str = std::string(vec.begin(), vec.end());
return str;
}
/* -------------------------------------------------------------------------- */
template <typename Iterator>
inline std::string
AlgebraicParser<Iterator>::concat_string(std::vector<char> const &vec,
std::string const &str2) const {
std::string str = std::string(vec.begin(), vec.end());
return str2 + str;
}
/* -------------------------------------------------------------------------- */
template <typename Iterator>
inline double
AlgebraicParser<Iterator>::get_var_value(std::string const &vname) const {
if (vname[0] == '$') {
std::string env_varname = vname.substr(1);
char *var = getenv(env_varname.c_str());
if (var == NULL)
LM_THROW("unknown environment variable " << env_varname);
return (atof(var));
} else {
std::map<std::string, double>::const_iterator it = variables.find(vname);
if (it == variables.end())
LM_THROW("unknown variable " << vname);
return (*it).second;
}
}
/* -------------------------------------------------------------------------- */
template <typename Iterator>
inline double
AlgebraicParser<Iterator>::set_var_value(double const &val,
std::string const &vname) const {
DUMPFILE(Parser::fout, "LET " << vname << " = " << val);
variables[vname] = val;
return val;
}
/* -------------------------------------------------------------------------- */
template <typename Iterator>
inline double
AlgebraicParser<Iterator>::get_env_var(std::string const &vname) const {
char *var = getenv(vname.c_str());
if (var == NULL)
LM_THROW("unknown env variable " << vname);
std::string vvname(var);
if (variables.count(var))
return variables[vvname];
return atof(var);
}
/* -------------------------------------------------------------------------- */
template <typename Iterator>
inline double
AlgebraicParser<Iterator>::get_func_result(double const &entry,
std::string const &func_name) const {
std::map<std::string, double (*)(double)>::const_iterator it =
function_maps.find(func_name);
if (it == function_maps.end())
LM_THROW("unknown function " << func_name);
return (*(*it).second)(entry);
}
/* -------------------------------------------------------------------------- */
#define _call(x) boost::phoenix::bind(&AlgebraicParser::x, this, _1)
#define _call2(x) boost::phoenix::bind(&AlgebraicParser::x, this, _1, _a)
/* -------------------------------------------------------------------------- */
template <typename Iterator>
AlgebraicParser<Iterator>::AlgebraicParser()
: AlgebraicParser::base_type(start) {
using boost::spirit::_val;
using boost::spirit::lit;
using boost::spirit::standard::space;
using boost::spirit::standard::alnum;
using boost::spirit::standard::alpha;
using boost::spirit::double_;
using boost::spirit::int_;
using boost::spirit::eoi;
using boost::spirit::_1;
using boost::spirit::_a;
using boost::phoenix::ref;
using boost::phoenix::val;
set_var = *space >> obj_name[_a = _1] >> *space >> "=" >>
term[_val = _call2(set_var_value)];
obj_name = (+alpha)[_a = _call(get_string)] >>
(*alnum)[_val = _call2(concat_string)];
func =
obj_name[_a = _1] >> "(" >> term[_val = _call2(get_func_result)] >> ")";
env_var = "$" >> obj_name[_val = _call(get_env_var)];
num = *space >>
(double_[_val = _1] | "(" >> term[_val = _1] >> ")" | func[_val = _1] |
obj_name[_val = _call(get_var_value)] | env_var[_val = _1]) >>
*space;
item = *space >> "-" >> num[_val = val(-1.) * _1] | num[_val = _1];
factor = item[_val = _1] >>
*(("*" >> item[_val *= _1]) | ("/" >> item[_val /= _1]));
term = factor[_val = _1] >>
*(("+" >> factor[_val += _1]) | ("-" >> factor[_val -= _1]));
start = (set_var[_val = _1] | term[_val = _1]) >> *space >> eoi;
// setting the default variables and functions
variables["pi"] = M_PI;
variables["INF"] = std::numeric_limits<Real>::max();
variables["avogadro"] = avogadro;
variables["boltzmann"] = boltzmann;
function_maps["cos"] = std::cos;
function_maps["acos"] = std::acos;
function_maps["sin"] = std::sin;
function_maps["sqrt"] = std::sqrt;
function_maps["abs"] = std::abs;
function_maps["atan"] = std::atan;
}
/* -------------------------------------------------------------------------- */
AlgebraicExpressionParser::AlgebraicExpressionParser() {
my_parser = new AlgebraicParser<std::string::const_iterator>();
}
/* -------------------------------------------------------------------------- */
AlgebraicExpressionParser::~AlgebraicExpressionParser() { delete my_parser; }
/* -------------------------------------------------------------------------- */
bool AlgebraicExpressionParser::parse(const std::string &str, double &result) {
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
bool parsed = boost::spirit::qi::parse(iter, end, *my_parser, result);
if (!parsed) {
std::string rest(iter, end);
LM_THROW("could not parse -- stopped at " << rest);
}
return parsed;
}
/* -------------------------------------------------------------------------- */
Real &AlgebraicExpressionParser::operator[](const std::string &var_name) {
LM_ASSERT(doesExist(var_name), "Unknown variable");
return my_parser->variables[var_name];
}
/* -------------------------------------------------------------------------- */
void AlgebraicExpressionParser::eraseVariable(const std::string &var_name) {
my_parser->variables.erase(var_name);
}
/* -------------------------------------------------------------------------- */
bool AlgebraicExpressionParser::doesExist(const std::string &var_name) {
if (my_parser->variables.count(var_name))
return true;
return false;
}
/* -------------------------------------------------------------------------- */
std::map<std::string, double> &AlgebraicExpressionParser::getVariables() {
return my_parser->variables;
}
__END_LIBMULTISCALE__

Event Timeline