add missing files.

This commit is contained in:
suter_a 2020-04-30 17:20:38 +02:00
parent d81a10e450
commit 5755331273
11 changed files with 1592 additions and 0 deletions

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,113 @@
/***************************************************************************
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 <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);
if (err_pos != last) {
std::cout << message << what << ':' << std::endl;
std::cout << get_line(line_start) << std::endl;
for (; line_start != err_pos; ++line_start)
std::cout << ' ';
std::cout << "^~~" << std::endl;
} else {
std::cout << "**ERROR** Unexpected end of file. ";
std::cout << 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,155 @@
/***************************************************************************
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)
("exp", ast::fun_exp)
("log", ast::fun_log)
("ln", ast::fun_ln)
;
///////////////////////////////////////////////////////////////////////
// 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,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,661 @@
/***************************************************************************
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_exp:
case ast::fun_log:
case ast::fun_ln:
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_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;
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>;