add first Qt6 version of musredit, mupp, etc.

This commit is contained in:
2021-01-22 22:04:11 +01:00
parent 386217b1fe
commit 5dcc962351
358 changed files with 59153 additions and 47 deletions

View File

@@ -0,0 +1 @@
add_subdirectory(src)

View File

@@ -0,0 +1,103 @@
/***************************************************************************
PAnnotation.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef _PANNOTATION_HPP_
#define _PANNOTATION_HPP_
#include <map>
#include <boost/variant/apply_visitor.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/mpl/bool.hpp>
#include "PAst.hpp"
namespace mupp
{
///////////////////////////////////////////////////////////////////////////////
// The annotation handler links the AST to a map of iterator positions
// for the purpose of subsequent semantic error handling when the
// program is being compiled.
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct PAnnotation
{
template <typename, typename>
struct result { typedef void type; };
std::vector<Iterator>& iters;
PAnnotation(std::vector<Iterator>& iters) : iters(iters) {}
struct set_id
{
typedef void result_type;
int id;
set_id(int id) : id(id) {}
template <typename T>
void operator()(T& x) const
{
this->dispatch(x, boost::is_base_of<ast::tagged, T>());
}
// This will catch all nodes except those inheriting from ast::tagged
template <typename T>
void dispatch(T& x, boost::mpl::false_) const
{
// (no-op) no need for tags
}
// This will catch all nodes inheriting from ast::tagged
template <typename T>
void dispatch(T& x, boost::mpl::true_) const
{
x.id = id;
}
};
void operator()(ast::operand& ast, Iterator pos) const
{
int id = iters.size();
iters.push_back(pos);
boost::apply_visitor(set_id(id), ast);
}
void operator()(ast::assignment& ast, Iterator pos) const
{
int id = iters.size();
iters.push_back(pos);
ast.lhs.id = id;
}
};
}
#endif // _PANNOTATION_HPP_

View File

@@ -0,0 +1,204 @@
/***************************************************************************
PAst.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef _PAST_HPP_
#define _PAST_HPP_
#include <boost/config/warning_disable.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/optional.hpp>
#include <list>
namespace mupp { namespace ast
{
///////////////////////////////////////////////////////////////////////////
// The AST
///////////////////////////////////////////////////////////////////////////
struct tagged
{
int id; // Used to annotate the AST with the iterator position.
// This id is used as a key to a map<int, Iterator>
// (not really part of the AST.)
};
enum optoken
{
op_plus,
op_minus,
op_times,
op_divide,
op_positive,
op_negative,
};
enum funid
{
fun_max,
fun_min,
fun_abs,
fun_sin,
fun_cos,
fun_tan,
fun_sinh,
fun_cosh,
fun_tanh,
fun_asin,
fun_acos,
fun_atan,
fun_exp,
fun_log,
fun_ln,
fun_sqrt
};
struct nil {};
struct unary;
struct expression;
struct function;
struct power;
struct variable : tagged
{
variable(std::string const& name = "") : name(name) {}
std::string name;
};
typedef boost::variant<
nil
, double
, variable
, boost::recursive_wrapper<function>
, boost::recursive_wrapper<power>
, boost::recursive_wrapper<unary>
, boost::recursive_wrapper<expression>
>
operand;
struct unary
{
optoken operator_;
operand operand_;
};
struct operation
{
optoken operator_;
operand operand_;
};
struct expression
{
operand first;
std::list<operation> rest;
};
struct function
{
funid func_id;
expression arg;
};
struct power
{
expression base;
expression pow;
};
struct assignment
{
variable lhs;
expression rhs;
};
struct variable_declaration
{
variable lhs;
boost::optional<expression> rhs;
};
typedef boost::variant<
variable_declaration
, assignment>
statement;
typedef std::list<statement> statement_list;
// print functions for debugging
inline std::ostream& operator<<(std::ostream& out, nil) { out << "nil"; return out; }
inline std::ostream& operator<<(std::ostream& out, variable const& var) { out << var.name; return out; }
}}
BOOST_FUSION_ADAPT_STRUCT(
mupp::ast::unary,
(mupp::ast::optoken, operator_)
(mupp::ast::operand, operand_)
)
BOOST_FUSION_ADAPT_STRUCT(
mupp::ast::operation,
(mupp::ast::optoken, operator_)
(mupp::ast::operand, operand_)
)
BOOST_FUSION_ADAPT_STRUCT(
mupp::ast::expression,
(mupp::ast::operand, first)
(std::list<mupp::ast::operation>, rest)
)
BOOST_FUSION_ADAPT_STRUCT(
mupp::ast::function,
(mupp::ast::funid, func_id)
(mupp::ast::expression, arg)
)
BOOST_FUSION_ADAPT_STRUCT(
mupp::ast::power,
(mupp::ast::expression, base)
(mupp::ast::expression, pow)
)
BOOST_FUSION_ADAPT_STRUCT(
mupp::ast::variable_declaration,
(mupp::ast::variable, lhs)
(boost::optional<mupp::ast::expression>, rhs)
)
BOOST_FUSION_ADAPT_STRUCT(
mupp::ast::assignment,
(mupp::ast::variable, lhs)
(mupp::ast::expression, rhs)
)
#endif // _PAST_HPP_

View File

@@ -0,0 +1,118 @@
/***************************************************************************
PErrorHandler.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef _PERROR_HANDLER_HPP_
#define _PERROR_HANDLER_HPP_
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
namespace mupp
{
///////////////////////////////////////////////////////////////////////////////
// The error handler
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct PErrorHandler
{
template <typename, typename, typename>
struct result { typedef void type; };
PErrorHandler(Iterator first, Iterator last)
: first(first), last(last) {}
template <typename Message, typename What>
void operator()(
Message const& message,
What const& what,
Iterator err_pos) const
{
int line;
Iterator line_start = get_pos(err_pos, line);
const char *homeStr = getenv("HOME");
char fln[1024];
sprintf(fln, "%s/.musrfit/mupp/mupp_err.log", homeStr);
std::ofstream fout(fln, std::ofstream::app);
if (err_pos != last) {
fout << message << what << ':' << std::endl;
fout << get_line(line_start) << std::endl;
for (; line_start != err_pos; ++line_start)
fout << ' ';
fout << "^~~" << std::endl;
} else {
fout << "**ERROR** Unexpected end of file. ";
fout << message << what << " line " << line << std::endl;
}
}
Iterator get_pos(Iterator err_pos, int& line) const
{
line = 1;
Iterator i = first;
Iterator line_start = first;
while (i != err_pos) {
bool eol = false;
if (i != err_pos && *i == '\r') { // CR
eol = true;
line_start = ++i;
}
if (i != err_pos && *i == '\n') { // LF
eol = true;
line_start = ++i;
}
if (eol)
++line;
else
++i;
}
return line_start;
}
std::string get_line(Iterator err_pos) const
{
Iterator i = err_pos;
// position i to the next EOL
while (i != last && (*i != '\r' && *i != '\n'))
++i;
return std::string(err_pos, i);
}
Iterator first;
Iterator last;
std::vector<Iterator> iters;
};
}
#endif //_PERROR_HANDLER_HPP_

View File

@@ -0,0 +1,83 @@
/***************************************************************************
PExpression.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef _PEXPRESSION_HPP_
#define _PEXPRESSION_HPP_
///////////////////////////////////////////////////////////////////////////////
// Spirit v2.5 allows you to suppress automatic generation
// of predefined terminals to speed up complation. With
// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are
// responsible in creating instances of the terminals that
// you need (e.g. see qi::uint_type uint_ below).
#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment this if you want to enable debugging
// #define BOOST_SPIRIT_QI_DEBUG
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/qi.hpp>
#include "PAst.hpp"
#include "PErrorHandler.hpp"
#include "PSkipper.hpp"
#include <vector>
namespace mupp { namespace parser
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
///////////////////////////////////////////////////////////////////////////////
// The expression grammar
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct PExpression : qi::grammar<Iterator, ast::expression(), PSkipper<Iterator> >
{
PExpression(PErrorHandler<Iterator>& error_handler);
qi::symbols<char, ast::optoken> additive_op, multiplicative_op, unary_op;
qi::symbols<char, ast::funid> fun_tok;
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > expr;
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > additive_expr;
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > multiplicative_expr;
qi::rule<Iterator, ast::operand(), PSkipper<Iterator> > unary_expr;
qi::rule<Iterator, ast::operand(), PSkipper<Iterator> > primary_expr;
qi::rule<Iterator, std::string(), PSkipper<Iterator> > identifier;
};
}}
#endif // _PEXPRESSION_HPP_

View File

@@ -0,0 +1,162 @@
/***************************************************************************
PExpressionDef.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "PExpression.hpp"
#include "PErrorHandler.hpp"
#include "PAnnotation.hpp"
#include <boost/spirit/include/phoenix_function.hpp>
namespace mupp { namespace parser
{
template <typename Iterator>
PExpression<Iterator>::PExpression(PErrorHandler<Iterator>& error_handler)
: PExpression::base_type(expr)
{
qi::_1_type _1;
qi::_2_type _2;
qi::_3_type _3;
qi::_4_type _4;
qi::char_type char_;
qi::double_type double_;
qi::_val_type _val;
qi::raw_type raw;
qi::lexeme_type lexeme;
qi::alpha_type alpha;
qi::alnum_type alnum;
using qi::on_error;
using qi::on_success;
using qi::fail;
using boost::phoenix::function;
typedef function<mupp::PErrorHandler<Iterator> > error_handler_function;
typedef function<mupp::PAnnotation<Iterator> > annotation_function;
///////////////////////////////////////////////////////////////////////
// Tokens
additive_op.add
("+", ast::op_plus)
("-", ast::op_minus)
;
multiplicative_op.add
("*", ast::op_times)
("/", ast::op_divide)
;
unary_op.add
("+", ast::op_positive)
("-", ast::op_negative)
;
fun_tok.add
("max", ast::fun_max)
("min", ast::fun_min)
("abs", ast::fun_abs)
("sin", ast::fun_sin)
("cos", ast::fun_cos)
("tan", ast::fun_tan)
("sinh", ast::fun_sinh)
("cosh", ast::fun_cosh)
("tanh", ast::fun_tanh)
("asin", ast::fun_asin)
("acos", ast::fun_acos)
("atan", ast::fun_atan)
("exp", ast::fun_exp)
("log", ast::fun_log)
("ln", ast::fun_ln)
("sqrt", ast::fun_sqrt)
;
///////////////////////////////////////////////////////////////////////
// Grammar
expr =
additive_expr.alias()
;
additive_expr =
multiplicative_expr
>> *(additive_op > multiplicative_expr)
;
multiplicative_expr =
unary_expr
>> *(multiplicative_op > unary_expr)
;
unary_expr =
primary_expr
| (unary_op > primary_expr)
;
primary_expr =
double_
| identifier
| fun_tok > '(' > expr > ')'
| "pow(" > expr > ',' > expr > ')'
| '(' > expr > ')'
;
identifier =
raw[lexeme['$' >> *(alnum | '_')]]
;
// name all the rules
additive_expr.name("additive_expr");
multiplicative_expr.name("multiplicative_expr");
unary_expr.name("unary_expr");
primary_expr.name("primary_expr");
identifier.name("identifier");
// Debugging and error handling and reporting support.
BOOST_SPIRIT_DEBUG_NODES(
(expr)
(additive_expr)
(multiplicative_expr)
(unary_expr)
(primary_expr)
(identifier)
);
// Error handling: on error in expr, call error_handler.
on_error<fail>(expr,
error_handler_function(error_handler)(
"**ERROR** Expecting ", _4, _3));
// Annotation: on success in primary_expr, call annotation.
on_success(primary_expr,
annotation_function(error_handler.iters)(_val, _1));
}
}}

View File

@@ -0,0 +1,159 @@
/***************************************************************************
PProgram.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef _PPROGRAM_HPP_
#define _PPROGRAM_HPP_
#include <string>
#include <vector>
#include <map>
#include "PAst.hpp"
#include "PErrorHandler.hpp"
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
namespace mupp { namespace prog {
///////////////////////////////////////////////////////////////////////////
// Variable Handler
///////////////////////////////////////////////////////////////////////////
class PVarHandler
{
public:
PVarHandler() : fName("") {}
void SetName(std::string name) { fName = name; }
void SetValue(std::vector<double> &dval) { fValue = dval; }
void SetValue(double dval, unsigned idx);
void SetError(std::vector<double> &dval) { fError = dval; }
void SetError(double dval, unsigned idx);
std::string GetName() { return fName; }
unsigned int GetSize() { return (fValue.size() == fError.size()) ? fValue.size() : 0; }
std::vector<double> GetValue() { return fValue; }
double GetValue(unsigned int idx) { return (idx < fValue.size()) ? fValue[idx] : 0; }
std::vector<double> GetError() { return fError; }
double GetError(unsigned int idx) { return (idx < fError.size()) ? fError[idx] : 0; }
private:
std::string fName;
std::vector<double> fValue;
std::vector<double> fError;
};
///////////////////////////////////////////////////////////////////////////
// Program Semantic Analysis
///////////////////////////////////////////////////////////////////////////
struct PProgram
{
typedef bool result_type;
template <typename PErrorHandler>
PProgram(PErrorHandler& error_handler_)
{
using namespace boost::phoenix::arg_names;
namespace phx = boost::phoenix;
using boost::phoenix::function;
error_handler = function<PErrorHandler>(error_handler_)(
"**ERROR** ", _2, phx::cref(error_handler_.iters)[_1]);
}
bool operator()(ast::nil) { BOOST_ASSERT(0); return false; }
bool operator()(double x);
bool operator()(ast::assignment const &x);
bool operator()(ast::expression const &x);
bool operator()(ast::function const &x);
bool operator()(ast::operation const &x);
bool operator()(ast::power const &x);
bool operator()(ast::statement const &x);
bool operator()(ast::statement_list const &x);
bool operator()(ast::unary const &x);
bool operator()(ast::variable const &x);
bool operator()(ast::variable_declaration const &x);
void add_predef_var_values(const std::string &name,
std::vector<double> &val,
std::vector<double> &err);
void add_var(std::string const& name);
bool find_var(std::string const &name);
bool find_var(std::string const &name, unsigned int &idx);
std::string pos_to_var(std::string const &name, bool &ok);
std::vector<PVarHandler> getVars() { return fVariable; }
private:
std::vector<PVarHandler> fVariable;
std::map<int, std::string> fVarPos;
boost::function<
void(int tag, std::string const& what)>
error_handler;
};
///////////////////////////////////////////////////////////////////////////
// Program Evaluation
///////////////////////////////////////////////////////////////////////////
struct PProgEval
{
typedef std::vector<double> result_type;
PProgEval(std::vector<PVarHandler> var) : fVariable(var) {}
std::vector<double> operator()(ast::nil);
std::vector<double> operator()(double x);
std::vector<double> operator()(ast::assignment const &x);
std::vector<double> operator()(ast::expression const &x);
std::vector<double> operator()(ast::function const &x);
std::vector<double> operator()(ast::operation const &x, std::vector<double> lhs);
std::vector<double> operator()(ast::power const &x);
std::vector<double> operator()(ast::statement const &x);
std::vector<double> operator()(ast::statement_list const &x);
std::vector<double> operator()(ast::unary const &x);
std::vector<double> operator()(ast::variable const &x);
std::vector<double> operator()(ast::variable_declaration const &x);
PVarHandler getVar(const std::string name, bool &ok);
void print_result();
private:
std::vector<PVarHandler> fVariable;
unsigned int find_var(std::string const &name);
};
}}
#endif // _PPROGRAM_HPP_

View File

@@ -0,0 +1,73 @@
/***************************************************************************
PSkipper.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on a mini_c,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef _PSKIPPER_HPP_
#define _PSKIPPER_HPP_
#include <boost/spirit/include/qi.hpp>
namespace mupp { namespace parser
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
///////////////////////////////////////////////////////////////////////////////
// The skipper grammar
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct PSkipper : qi::grammar<Iterator>
{
PSkipper() : PSkipper::base_type(start)
{
qi::char_type char_;
qi::lit_type lit;
qi::eol_type eol;
ascii::space_type space;
ascii::print_type print;
single_line_comment = (lit('%') | lit('#') | lit("//")) >> *print >> eol;
start =
space // tab/space/cr/lf
| "/*" >> *(char_ - "*/") >> "*/" // C-style comments
| single_line_comment
;
}
qi::rule<Iterator> single_line_comment;
qi::rule<Iterator> start;
};
}}
#endif // _PSKIPPER_HPP_

View File

@@ -0,0 +1,58 @@
/***************************************************************************
PStatement.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef _PSTATEMENT_HPP_
#define _PSTATEMENT_HPP_
#include "PExpression.hpp"
namespace mupp { namespace parser
{
///////////////////////////////////////////////////////////////////////////////
// The statement grammar
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct PStatement : qi::grammar<Iterator, ast::statement_list(), PSkipper<Iterator> >
{
PStatement(PErrorHandler<Iterator>& error_handler);
PExpression<Iterator> expr;
qi::rule<Iterator, ast::statement_list(), PSkipper<Iterator> > statement_list;
qi::rule<Iterator, ast::variable_declaration(), PSkipper<Iterator> > variable_declaration;
qi::rule<Iterator, ast::assignment(), PSkipper<Iterator> > assignment;
qi::rule<Iterator, std::string(), PSkipper<Iterator> > identifier;
};
}}
#endif // _PSTATEMENT_HPP_

View File

@@ -0,0 +1,107 @@
/***************************************************************************
PStatementDef.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "PStatement.hpp"
#include "PErrorHandler.hpp"
#include "PAnnotation.hpp"
namespace mupp { namespace parser
{
template <typename Iterator>
PStatement<Iterator>::PStatement(PErrorHandler<Iterator>& error_handler)
: PStatement::base_type(statement_list), expr(error_handler)
{
qi::_1_type _1;
qi::_2_type _2;
qi::_3_type _3;
qi::_4_type _4;
qi::_val_type _val;
qi::raw_type raw;
qi::lexeme_type lexeme;
qi::alpha_type alpha;
qi::alnum_type alnum;
using qi::on_error;
using qi::on_success;
using qi::fail;
using boost::phoenix::function;
typedef function<mupp::PErrorHandler<Iterator> > error_handler_function;
typedef function<mupp::PAnnotation<Iterator> > annotation_function;
statement_list =
+(variable_declaration | assignment)
;
identifier =
raw[lexeme[(alpha | '_') >> *(alnum | '_')]]
;
variable_declaration =
lexeme["var" >> !(alnum | '_')] // make sure we have whole words
> identifier
> -('=' > expr)
;
assignment =
identifier
> '='
> expr
;
// name all the rules
statement_list.name("statement_list");
identifier.name("identifier");
variable_declaration.name("variable_declaration");
assignment.name("assignment");
// Debugging and error handling and reporting support.
BOOST_SPIRIT_DEBUG_NODES(
(statement_list)
(identifier)
(variable_declaration)
(assignment)
);
// Error handling: on error in statement_list, call error_handler.
on_error<fail>(statement_list,
error_handler_function(error_handler)(
"**ERROR** Expecting ", _4, _3));
// Annotation: on success in assignment, call annotation.
on_success(assignment,
annotation_function(error_handler.iters)(_val, _1));
}
}}

View File

@@ -0,0 +1,69 @@
/***************************************************************************
PVarHandler.h
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
***************************************************************************/
/***************************************************************************
* Copyright (C) 2007-2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef _PVARHANDLER_H_
#define _PVARHANDLER_H_
#include <string>
#include <vector>
#include <QString>
#include "Pmupp.h"
#include "PAst.hpp"
#include "PProgram.hpp"
class PVarHandler {
public:
PVarHandler();
PVarHandler(PmuppCollection *coll, std::string parse_str, std::string var_name="");
bool isValid() { return fIsValid; }
QString getCollName() { return fColl->GetName(); }
QString getVarName() { return QString(fVarName.c_str()); }
std::vector<double> getValues();
std::vector<double> getErrors();
private:
PmuppCollection *fColl; ///< collection needed for parsing and evaluation
std::string fParseStr; ///< the variable input to be parsed
std::string fVarName; ///< variable name
mupp::prog::PVarHandler fVar; ///< values of the evaluation
bool fIsValid;
mupp::ast::statement_list fAst; ///< the AST
void injectPredefVariables();
std::string getVarName(int idx);
std::vector<double> getData(int idx);
std::vector<double> getDataErr(int idx);
};
#endif //_PVARHANDLER_H_

View File

@@ -0,0 +1,7 @@
target_sources(mupp
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/PVarHandler.cpp
${CMAKE_CURRENT_LIST_DIR}/PExpression.cpp
${CMAKE_CURRENT_LIST_DIR}/PProgram.cpp
${CMAKE_CURRENT_LIST_DIR}/PStatement.cpp
)

View File

@@ -0,0 +1,40 @@
/***************************************************************************
PExpression.hpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#if defined(_MSC_VER)
# pragma warning(disable: 4345)
#endif
#include "PExpressionDef.hpp"
typedef std::string::const_iterator iterator_type;
template struct mupp::parser::PExpression<iterator_type>;

View File

@@ -0,0 +1,702 @@
/***************************************************************************
PProgram.cpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "PProgram.hpp"
#include <boost/foreach.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/assert.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <set>
namespace mupp { namespace prog {
void PVarHandler::SetValue(double dval, unsigned idx)
{
if (idx >= fValue.size()) {
std::cerr << "**ERROR** SetValue: idx=" << idx << " is out-of-range." << std::endl;
return;
}
fValue[idx] = dval;
}
void PVarHandler::SetError(double dval, unsigned idx)
{
if (idx >= fError.size()) {
std::cerr << "**ERROR** SetError: idx=" << idx << " is out-of-range." << std::endl;
return;
}
fError[idx] = dval;
}
bool PProgram::operator()(double x)
{
return true;
}
bool PProgram::operator()(ast::assignment const &x)
{
// check that the variable exists
if (!find_var(x.lhs.name)) {
error_handler(0, "Undeclared variable: " + x.lhs.name);
return false;
}
if (!(*this)(x.rhs)) {
std::cout << "**SEM ERROR** in var assignment of var: " << x.lhs.name << std::endl;
std::cout << " rhs is missing or has an error." << std::endl;
return false;
}
return true;
}
bool PProgram::operator()(ast::expression const &x)
{
if (!boost::apply_visitor(*this, x.first))
return false;
BOOST_FOREACH(ast::operation const& oper, x.rest) {
if (!(*this)(oper))
return false;
}
return true;
}
bool PProgram::operator()(ast::function const &x)
{
switch (x.func_id) {
case ast::fun_max:
case ast::fun_min:
case ast::fun_abs:
case ast::fun_sin:
case ast::fun_cos:
case ast::fun_tan:
case ast::fun_sinh:
case ast::fun_cosh:
case ast::fun_tanh:
case ast::fun_asin:
case ast::fun_acos:
case ast::fun_atan:
case ast::fun_exp:
case ast::fun_log:
case ast::fun_ln:
case ast::fun_sqrt:
break;
default:
BOOST_ASSERT(0);
return false;
}
if (!(*this)(x.arg)) {
std::cout << "**SEM ERROR** in function: arg is missing or has an error." << std::endl;
return false;
}
return true;
}
bool PProgram::operator()(ast::operation const &x)
{
if (!boost::apply_visitor(*this, x.operand_))
return false;
switch (x.operator_) {
case ast::op_plus:
break;
case ast::op_minus:
break;
case ast::op_times:
break;
case ast::op_divide:
break;
case ast::op_positive:
break;
case ast::op_negative:
break;
default:
BOOST_ASSERT(0);
return false;
}
return true;
}
bool PProgram::operator()(ast::power const &x)
{
if (!(*this)(x.base)) {
std::cout << "**SEM ERROR** in power: base argument is missing or has an error." << std::endl;
return false;
}
if (!(*this)(x.pow)) {
std::cout << "**SEM ERROR** in power: power argument is missing or has an error." << std::endl;
return false;
}
return true;
}
bool PProgram::operator()(ast::statement const &x)
{
return boost::apply_visitor(*this, x);
}
bool PProgram::operator()(ast::statement_list const &x)
{
BOOST_FOREACH(ast::statement const& s, x) {
if (!(*this)(s))
return false;
}
return true;
}
bool PProgram::operator()(ast::unary const &x)
{
if (!boost::apply_visitor(*this, x.operand_))
return false;
switch (x.operator_) {
case ast::op_negative:
break;
case ast::op_positive:
break;
default:
BOOST_ASSERT(0);
return false;
}
return true;
}
bool PProgram::operator()(ast::variable const &x)
{
bool ok(false);
std::string var_name;
var_name = pos_to_var(x.name, ok);
if (!ok) {
error_handler(0, "Position variable out-of-range: " + x.name);
return false;
}
if (!find_var(var_name)) {
error_handler(0, "Undeclared variable: " + var_name);
return false;
}
return true;
}
bool PProgram::operator()(ast::variable_declaration const &x)
{
if (find_var(x.lhs.name)) {
error_handler(0, "Duplicate variable: " + x.lhs.name);
return false;
}
if (x.rhs) { // if there's a RHS initializer
bool r = (*this)(*x.rhs);
if (r) { // don't add the variable if the RHS fails
add_var(x.lhs.name);
} else {
std::cout << "**SEM ERROR** rhs of var decl, name: " << x.lhs.name << ", failed" << std::endl;
return r;
}
} else {
add_var(x.lhs.name);
}
return true;
}
void PProgram::add_predef_var_values(const std::string &name,
std::vector<double> &val,
std::vector<double> &err)
{
unsigned int idx;
if (!find_var(name, idx)) {
std::cerr << "**ERROR** couldn't find pre-def variable : " << name << std::endl;
return;
}
fVariable[idx].SetValue(val);
fVariable[idx].SetError(err);
}
void PProgram::add_var(std::string const& name)
{
PVarHandler var;
var.SetName(name);
fVariable.push_back(var);
// add map var <-> pos
std::size_t n = fVarPos.size();
fVarPos[n] = name;
}
bool PProgram::find_var(std::string const &name)
{
unsigned int idx;
return find_var(name, idx);
}
bool PProgram::find_var(std::string const &name, unsigned int &idx)
{
bool result=false;
// remove leading '$' of identifier
std::string id("");
if (name[0] == '$')
id = name.substr(1);
else
id = name;
for (unsigned int i=0; i<fVariable.size(); i++) {
if (id == fVariable[i].GetName()) {
idx = i;
result = true;
break;
}
}
return result;
}
std::string PProgram::pos_to_var(std::string const &name, bool &ok)
{
std::string result("??");
ok = true;
// remove leading '$' if present
if (name[0] == '$')
result = name.substr(1);
else
result = name;
// check if number
char *p;
int num = strtol(result.c_str(), &p, 10);
if (*p == 0) {
if (num >= fVarPos.size())
ok = false;
else
result = fVarPos[num];
}
return result;
}
std::vector<double> PProgEval::operator()(ast::nil)
{
std::vector<double> result;
result.resize(fVariable[0].GetSize());
for (unsigned int i=0; i<result.size(); i++)
result[i] = 0.0;
BOOST_ASSERT(0);
return result;
}
std::vector<double> PProgEval::operator()(double x)
{
std::vector<double> result;
result.resize(fVariable[0].GetSize());
for (unsigned int i=0; i<result.size(); i++)
result[i] = x;
return result;
}
std::vector<double> PProgEval::operator()(ast::assignment const &x)
{
std::vector<double> result;
result.resize(fVariable[0].GetSize());
result = (*this)(x.rhs);
// keep all data under <varName> not <varName>Err.
// <varName>Err data go to <varName> error, whereas
// <varName> data go to <varName> value
std::string name = x.lhs.name;
bool errorVal(false);
// check for error variable
std::size_t pos = name.find("Err");
if (pos != std::string::npos) { // it is an error variable
name = name.substr(0, pos);
errorVal = true;
}
unsigned int idx = find_var(name);
if (errorVal)
fVariable[idx].SetError(result);
else
fVariable[idx].SetValue(result);
return result;
}
std::vector<double> PProgEval::operator()(ast::expression const &x)
{
std::vector<double> vec = boost::apply_visitor(*this, x.first);
BOOST_FOREACH(ast::operation const& oper, x.rest) {
vec = (*this)(oper, vec);
}
return vec;
}
std::vector<double> PProgEval::operator()(ast::function const &x)
{
std::vector<double> vec = (*this)(x.arg);
double dval;
switch(x.func_id) {
case ast::fun_max:
dval = -1.0e10;
for (unsigned int i=0; i<vec.size(); i++) {
if (vec[i] > dval)
dval = vec[i];
}
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = dval;
break;
case ast::fun_min:
dval = 1.0e10;
for (unsigned int i=0; i<vec.size(); i++) {
if (vec[i] < dval)
dval = vec[i];
}
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = dval;
break;
case ast::fun_abs:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = fabs(vec[i]);
break;
case ast::fun_sin:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = sin(vec[i]);
break;
case ast::fun_cos:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = cos(vec[i]);
break;
case ast::fun_tan:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = tan(vec[i]);
break;
case ast::fun_sinh:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = sinh(vec[i]);
break;
case ast::fun_cosh:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = cosh(vec[i]);
break;
case ast::fun_tanh:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = tanh(vec[i]);
break;
case ast::fun_asin:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = asin(vec[i]);
break;
case ast::fun_acos:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = acos(vec[i]);
break;
case ast::fun_atan:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = atan(vec[i]);
break;
case ast::fun_exp:
for (unsigned int i=0; i<vec.size(); i++)
vec[i] = exp(vec[i]);
break;
case ast::fun_log:
for (unsigned int i=0; i<vec.size(); i++) {
if (vec[i] <= 0.0) {
BOOST_ASSERT(0);
break;
} else {
vec[i] = log10(vec[i]);
}
}
break;
case ast::fun_ln:
for (unsigned int i=0; i<vec.size(); i++) {
if (vec[i] <= 0.0) {
BOOST_ASSERT(0);
break;
} else {
vec[i] = log(vec[i]);
}
}
break;
case ast::fun_sqrt:
for (unsigned int i=0; i<vec.size(); i++) {
if (vec[i] <= 0.0) {
BOOST_ASSERT(0);
break;
} else {
vec[i] = sqrt(vec[i]);
}
}
break;
default:
BOOST_ASSERT(0);
break;
}
return vec;
}
std::vector<double> PProgEval::operator()(ast::operation const &x, std::vector<double> lhs)
{
std::vector<double> rhs = boost::apply_visitor(*this, x.operand_);
// make sure both vectors have the same size
if (lhs.size() != rhs.size()) {
BOOST_ASSERT(0);
return lhs;
}
switch (x.operator_) {
case ast::op_plus:
for (unsigned int i=0; i<lhs.size(); i++)
lhs[i] = lhs[i] + rhs[i];
break;
case ast::op_minus:
for (unsigned int i=0; i<lhs.size(); i++)
lhs[i] = lhs[i] - rhs[i];
break;
case ast::op_times:
for (unsigned int i=0; i<lhs.size(); i++)
lhs[i] = lhs[i] * rhs[i];
break;
case ast::op_divide:
for (unsigned int i=0; i<lhs.size(); i++) {
if (rhs[i] == 0.0) {
BOOST_ASSERT(0);
return lhs;
} else {
lhs[i] = lhs[i] / rhs[i];
}
}
break;
default:
BOOST_ASSERT(0);
return lhs;
}
return lhs;
}
std::vector<double> PProgEval::operator()(ast::power const &x)
{
std::vector<double> baseV = (*this)(x.base);
std::vector<double> powV = (*this)(x.pow);
if (baseV.size() != powV.size()) {
BOOST_ASSERT(0);
return baseV;
}
std::vector<double> result;
result.resize(baseV.size());
for (unsigned int i=0; i<baseV.size(); i++)
result[i] = pow(baseV[i], powV[i]);
return result;
}
std::vector<double> PProgEval::operator()(ast::statement const &x)
{
// as35: not-yet-implemented
std::vector<double> result;
result.resize(fVariable[0].GetSize());
for (unsigned int i=0; i<result.size(); i++)
result[i] = 0.0;
boost::apply_visitor(*this, x);
return result;
}
std::vector<double> PProgEval::operator()(ast::statement_list const &x)
{
// as35: not-yet-implemented
std::vector<double> result;
result.resize(fVariable[0].GetSize());
for (unsigned int i=0; i<result.size(); i++)
result[i] = 0.0;
BOOST_FOREACH(ast::statement const& s, x) {
(*this)(s);
}
return result;
}
std::vector<double> PProgEval::operator()(ast::unary const &x)
{
std::vector<double> vec = boost::apply_visitor(*this, x.operand_);
if (x.operator_ == ast::op_negative) {
for (unsigned int i=0; i<vec.size(); i++) {
vec[i] *= -1.0;
}
}
return vec;
}
std::vector<double> PProgEval::operator()(ast::variable const &x)
{
std::string name = x.name;
bool errorVal(false);
// check for injected error variable
std::size_t pos = name.find("Err");
if (pos != std::string::npos) { // it is an error variable
name = name.substr(0, pos);
errorVal = true;
}
unsigned idx = find_var(name);
if (errorVal)
return fVariable[idx].GetError();
else
return fVariable[idx].GetValue();
}
std::vector<double> PProgEval::operator()(ast::variable_declaration const &x)
{
std::vector<double> result;
result.resize(fVariable[0].GetSize());
// keep all data under <varName> not <varName>Err.
// <varName>Err data go to <varName> error, whereas
// <varName> data go to <varName> value
std::string name = x.lhs.name;
bool errorVal(false);
// check for error variable
std::size_t pos = name.find("Err");
if (pos != std::string::npos) { // it is an error variable
name = name.substr(0, pos);
errorVal = true;
}
unsigned int idx = find_var(name);
if (x.rhs) { // if there's a RHS initializer
result = (*this)(*x.rhs);
} else {
// injected variable content
if (errorVal)
result = fVariable[idx].GetError();
else
result = fVariable[idx].GetValue();
}
if (errorVal)
fVariable[idx].SetError(result);
else
fVariable[idx].SetValue(result);
return result;
}
unsigned int PProgEval::find_var(std::string const &name)
{
// remove leading '$' of identifier
std::string id("");
if (name[0] == '$')
id = name.substr(1);
else
id = name;
unsigned idx = 0;
for (unsigned int i=0; i<fVariable.size(); i++) {
if (id == fVariable[i].GetName()) {
idx = i;
break;
}
}
return idx;
}
PVarHandler PProgEval::getVar(const std::string name, bool &ok)
{
PVarHandler var = fVariable[0];
ok = false;
for (unsigned int i=0; i<fVariable.size(); i++) {
if (fVariable[i].GetName() == name) {
var = fVariable[i];
ok = true;
break;
}
}
return var;
}
void PProgEval::print_result()
{
std::vector<double> val, err;
for (unsigned int i=0; i<fVariable.size(); i++) {
if (!strstr(fVariable[i].GetName().c_str(), "Err")) {
std::cout << "+++++" << std::endl;
std::cout << "var Name: " << fVariable[i].GetName() << std::endl;
val = fVariable[i].GetValue();
err = fVariable[i].GetError();
for (unsigned int j=0; j<val.size(); j++) {
if (j<err.size())
std::cout << " " << j << ": " << val[j] << " +- " << err[j] << std::endl;
else
std::cout << " " << j << ": " << val[j] << std::endl;
}
}
}
std::cout << "+++++" << std::endl;
}
}}

View File

@@ -0,0 +1,40 @@
/***************************************************************************
PStatement.cpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
Based on Joel de Guzman example on calc7,
see https://github.com/boostorg/spirit
***************************************************************************/
/***************************************************************************
* Copyright (C) 2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#if defined(_MSC_VER)
# pragma warning(disable: 4345)
#endif
#include "PStatementDef.hpp"
typedef std::string::const_iterator iterator_type;
template struct mupp::parser::PStatement<iterator_type>;

View File

@@ -0,0 +1,212 @@
/***************************************************************************
PVarHandler.cpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
***************************************************************************/
/***************************************************************************
* Copyright (C) 2007-2020 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <iostream>
#include "PVarHandler.h"
#include "PSkipper.hpp"
#include "PErrorHandler.hpp"
#include "PStatement.hpp"
#include "PProgram.hpp"
//--------------------------------------------------------------------------
/**
* @brief PVarHandler::PVarHandler
*/
PVarHandler::PVarHandler() :
fColl(nullptr), fParseStr(""), fVarName(""), fIsValid(false)
{
// nothing to be done here
}
//--------------------------------------------------------------------------
/**
* @brief PVarHandler::PVarHandler
*/
PVarHandler::PVarHandler(PmuppCollection *coll, std::string parse_str, std::string var_name) :
fColl(coll), fParseStr(parse_str), fVarName(var_name), fIsValid(false)
{
injectPredefVariables();
typedef std::string::const_iterator iterator_type;
iterator_type iter = fParseStr.begin();
iterator_type end = fParseStr.end();
mupp::PErrorHandler<iterator_type> error_handler(iter, end); // the error handler
mupp::parser::PStatement<iterator_type> parser(error_handler); // the parser
mupp::prog::PProgram prog(error_handler); // our compiler, and exec
mupp::parser::PSkipper<iterator_type> skipper; // the skipper parser
// perform the parsing
bool success = phrase_parse(iter, end, parser, skipper, fAst);
if (success && iter == end) {
if (prog(fAst)) { // semantic analysis
std::vector<double> data, dataErr;
for (unsigned int i=0; i<fColl->GetRun(0).GetNoOfParam(); i++) {
data = getData(i);
dataErr = getDataErr(i);
prog.add_predef_var_values(getVarName(i), data, dataErr);
}
if (!fVarName.empty()) {
mupp::prog::PProgEval eval(prog.getVars()); // setup evaluation stage
eval(fAst); // evaluate stuff
// keep data
bool ok;
fVar = eval.getVar(fVarName, ok);
if (!ok) {
std::cerr << "**ERROR** evalution failed..." << std::endl;
fIsValid = false;
}
}
}
fIsValid = true;
} else {
std::cerr << "**ERROR** parsing failed..." << std::endl;
}
}
//--------------------------------------------------------------------------
/**
* @brief PVarHandler::getValues
* @return
*/
std::vector<double> PVarHandler::getValues()
{
std::vector<double> data;
if (fIsValid)
data = fVar.GetValue();
return data;
}
//--------------------------------------------------------------------------
/**
* @brief PVarHandler::getErrors
* @return
*/
std::vector<double> PVarHandler::getErrors()
{
std::vector<double> data;
if (fIsValid)
data = fVar.GetError();
return data;
}
//--------------------------------------------------------------------------
/**
* @brief PVarHandler::injectPredefVariables
*/
void PVarHandler::injectPredefVariables()
{
mupp::ast::statement var_stat;
mupp::ast::variable_declaration var;
std::string varName, errVarName;
PmuppRun run = fColl->GetRun(0);
for (int i=0; i<run.GetNoOfParam(); i++) {
varName = run.GetParam(i).GetName().toLatin1().data();
errVarName = varName + "Err";
// inject err_name
var.lhs.name = errVarName;
var_stat = var;
fAst.push_front(var_stat);
// inject var_name
var.lhs.name = varName;
var_stat = var;
fAst.push_front(var_stat);
}
}
//--------------------------------------------------------------------------
/**
* @brief PVarHandler::getVarName
* @param idx
* @return
*/
std::string PVarHandler::getVarName(int idx)
{
std::string name("??");
// make sure idx is in range
if (idx >= fColl->GetRun(0).GetNoOfParam())
return name;
return fColl->GetRun(0).GetParam(idx).GetName().toLatin1().data();
}
//--------------------------------------------------------------------------
/**
* @brief PVarHandler::getData
* @param idx
* @return
*/
std::vector<double> PVarHandler::getData(int idx)
{
std::vector<double> data;
// make sure idx is in range
if (idx >= fColl->GetRun(0).GetNoOfParam())
return data;
double dval;
for (int i=0; i<fColl->GetNoOfRuns(); i++) {
dval = fColl->GetRun(i).GetParam(idx).GetValue();
data.push_back(dval);
}
return data;
}
//--------------------------------------------------------------------------
/**
* @brief PVarHandler::getDataErr
* @param idx
* @return
*/
std::vector<double> PVarHandler::getDataErr(int idx)
{
std::vector<double> err;
// make sure idx is in range
if (idx >= fColl->GetRun(0).GetNoOfParam())
return err;
double dvalPos, dvalNeg;
for (int i=0; i<fColl->GetNoOfRuns(); i++) {
dvalPos = fColl->GetRun(i).GetParam(idx).GetPosErr();
dvalNeg = fColl->GetRun(i).GetParam(idx).GetNegErr();
dvalPos = sqrt(fabs(dvalPos*dvalNeg)); // geometric mean of pos/neg error
err.push_back(dvalPos);
}
return err;
}