From 575533127397948f6a079f67e6965f634e09beef Mon Sep 17 00:00:00 2001 From: Andreas Suter Date: Thu, 30 Apr 2020 17:20:38 +0200 Subject: [PATCH] add missing files. --- .../mupp/var/include/PAnnotation.hpp | 103 +++ .../mupp/var/include/PErrorHandler.hpp | 113 +++ .../mupp/var/include/PExpression.hpp | 83 +++ .../mupp/var/include/PExpressionDef.hpp | 155 ++++ .../mupp/var/include/PProgram.hpp | 159 +++++ .../mupp/var/include/PSkipper.hpp | 73 ++ .../mupp/var/include/PStatement.hpp | 58 ++ .../mupp/var/include/PStatementDef.hpp | 107 +++ src/musredit_qt5/mupp/var/src/PExpression.cpp | 40 ++ src/musredit_qt5/mupp/var/src/PProgram.cpp | 661 ++++++++++++++++++ src/musredit_qt5/mupp/var/src/PStatement.cpp | 40 ++ 11 files changed, 1592 insertions(+) create mode 100644 src/musredit_qt5/mupp/var/include/PAnnotation.hpp create mode 100644 src/musredit_qt5/mupp/var/include/PErrorHandler.hpp create mode 100644 src/musredit_qt5/mupp/var/include/PExpression.hpp create mode 100644 src/musredit_qt5/mupp/var/include/PExpressionDef.hpp create mode 100644 src/musredit_qt5/mupp/var/include/PProgram.hpp create mode 100644 src/musredit_qt5/mupp/var/include/PSkipper.hpp create mode 100644 src/musredit_qt5/mupp/var/include/PStatement.hpp create mode 100644 src/musredit_qt5/mupp/var/include/PStatementDef.hpp create mode 100644 src/musredit_qt5/mupp/var/src/PExpression.cpp create mode 100644 src/musredit_qt5/mupp/var/src/PProgram.cpp create mode 100644 src/musredit_qt5/mupp/var/src/PStatement.cpp diff --git a/src/musredit_qt5/mupp/var/include/PAnnotation.hpp b/src/musredit_qt5/mupp/var/include/PAnnotation.hpp new file mode 100644 index 00000000..4e4467c3 --- /dev/null +++ b/src/musredit_qt5/mupp/var/include/PAnnotation.hpp @@ -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 +#include +#include +#include +#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 + struct PAnnotation + { + template + struct result { typedef void type; }; + + std::vector& iters; + PAnnotation(std::vector& iters) : iters(iters) {} + + struct set_id + { + typedef void result_type; + + int id; + set_id(int id) : id(id) {} + + template + void operator()(T& x) const + { + this->dispatch(x, boost::is_base_of()); + } + + // This will catch all nodes except those inheriting from ast::tagged + template + void dispatch(T& x, boost::mpl::false_) const + { + // (no-op) no need for tags + } + + // This will catch all nodes inheriting from ast::tagged + template + 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_ + diff --git a/src/musredit_qt5/mupp/var/include/PErrorHandler.hpp b/src/musredit_qt5/mupp/var/include/PErrorHandler.hpp new file mode 100644 index 00000000..214a386d --- /dev/null +++ b/src/musredit_qt5/mupp/var/include/PErrorHandler.hpp @@ -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 +#include +#include + +namespace mupp +{ + /////////////////////////////////////////////////////////////////////////////// + // The error handler + /////////////////////////////////////////////////////////////////////////////// + template + struct PErrorHandler + { + template + struct result { typedef void type; }; + + PErrorHandler(Iterator first, Iterator last) + : first(first), last(last) {} + + template + 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 iters; + }; +} + +#endif //_PERROR_HANDLER_HPP_ + diff --git a/src/musredit_qt5/mupp/var/include/PExpression.hpp b/src/musredit_qt5/mupp/var/include/PExpression.hpp new file mode 100644 index 00000000..f8d3de0e --- /dev/null +++ b/src/musredit_qt5/mupp/var/include/PExpression.hpp @@ -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 +#include "PAst.hpp" +#include "PErrorHandler.hpp" +#include "PSkipper.hpp" +#include + +namespace mupp { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The expression grammar + /////////////////////////////////////////////////////////////////////////////// + template + struct PExpression : qi::grammar > + { + PExpression(PErrorHandler& error_handler); + + qi::symbols additive_op, multiplicative_op, unary_op; + qi::symbols fun_tok; + + qi::rule > expr; + qi::rule > additive_expr; + qi::rule > multiplicative_expr; + qi::rule > unary_expr; + qi::rule > primary_expr; + qi::rule > identifier; + }; +}} + +#endif // _PEXPRESSION_HPP_ + + diff --git a/src/musredit_qt5/mupp/var/include/PExpressionDef.hpp b/src/musredit_qt5/mupp/var/include/PExpressionDef.hpp new file mode 100644 index 00000000..13981692 --- /dev/null +++ b/src/musredit_qt5/mupp/var/include/PExpressionDef.hpp @@ -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 + +namespace mupp { namespace parser +{ + template + PExpression::PExpression(PErrorHandler& 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 > error_handler_function; + typedef function > 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(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)); + } +}} + + diff --git a/src/musredit_qt5/mupp/var/include/PProgram.hpp b/src/musredit_qt5/mupp/var/include/PProgram.hpp new file mode 100644 index 00000000..0eaa2aa1 --- /dev/null +++ b/src/musredit_qt5/mupp/var/include/PProgram.hpp @@ -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 +#include +#include + +#include "PAst.hpp" +#include "PErrorHandler.hpp" + +#include +#include +#include +#include +#include + +namespace mupp { namespace prog { + /////////////////////////////////////////////////////////////////////////// + // Variable Handler + /////////////////////////////////////////////////////////////////////////// + class PVarHandler + { + public: + PVarHandler() : fName("") {} + + void SetName(std::string name) { fName = name; } + void SetValue(std::vector &dval) { fValue = dval; } + void SetValue(double dval, unsigned idx); + void SetError(std::vector &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 GetValue() { return fValue; } + double GetValue(unsigned int idx) { return (idx < fValue.size()) ? fValue[idx] : 0; } + std::vector GetError() { return fError; } + double GetError(unsigned int idx) { return (idx < fError.size()) ? fError[idx] : 0; } + + private: + std::string fName; + std::vector fValue; + std::vector fError; + }; + + /////////////////////////////////////////////////////////////////////////// + // Program Semantic Analysis + /////////////////////////////////////////////////////////////////////////// + struct PProgram + { + typedef bool result_type; + + template + PProgram(PErrorHandler& error_handler_) + { + using namespace boost::phoenix::arg_names; + namespace phx = boost::phoenix; + using boost::phoenix::function; + error_handler = function(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 &val, + std::vector &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 getVars() { return fVariable; } + + private: + std::vector fVariable; + std::map fVarPos; + + boost::function< + void(int tag, std::string const& what)> + error_handler; + }; + + /////////////////////////////////////////////////////////////////////////// + // Program Evaluation + /////////////////////////////////////////////////////////////////////////// + struct PProgEval + { + typedef std::vector result_type; + + PProgEval(std::vector var) : fVariable(var) {} + + std::vector operator()(ast::nil); + std::vector operator()(double x); + std::vector operator()(ast::assignment const &x); + std::vector operator()(ast::expression const &x); + std::vector operator()(ast::function const &x); + std::vector operator()(ast::operation const &x, std::vector lhs); + std::vector operator()(ast::power const &x); + std::vector operator()(ast::statement const &x); + std::vector operator()(ast::statement_list const &x); + std::vector operator()(ast::unary const &x); + std::vector operator()(ast::variable const &x); + std::vector operator()(ast::variable_declaration const &x); + + PVarHandler getVar(const std::string name, bool &ok); + void print_result(); + + private: + std::vector fVariable; + + unsigned int find_var(std::string const &name); + }; +}} + +#endif // _PPROGRAM_HPP_ diff --git a/src/musredit_qt5/mupp/var/include/PSkipper.hpp b/src/musredit_qt5/mupp/var/include/PSkipper.hpp new file mode 100644 index 00000000..5a8d103b --- /dev/null +++ b/src/musredit_qt5/mupp/var/include/PSkipper.hpp @@ -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 + +namespace mupp { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The skipper grammar + /////////////////////////////////////////////////////////////////////////////// + template + struct PSkipper : qi::grammar + { + 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 single_line_comment; + qi::rule start; + }; +}} + +#endif // _PSKIPPER_HPP_ + + diff --git a/src/musredit_qt5/mupp/var/include/PStatement.hpp b/src/musredit_qt5/mupp/var/include/PStatement.hpp new file mode 100644 index 00000000..ccf5e7f9 --- /dev/null +++ b/src/musredit_qt5/mupp/var/include/PStatement.hpp @@ -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 + struct PStatement : qi::grammar > + { + PStatement(PErrorHandler& error_handler); + + PExpression expr; + qi::rule > statement_list; + qi::rule > variable_declaration; + qi::rule > assignment; + qi::rule > identifier; + }; +}} + +#endif // _PSTATEMENT_HPP_ + + diff --git a/src/musredit_qt5/mupp/var/include/PStatementDef.hpp b/src/musredit_qt5/mupp/var/include/PStatementDef.hpp new file mode 100644 index 00000000..0d114e3a --- /dev/null +++ b/src/musredit_qt5/mupp/var/include/PStatementDef.hpp @@ -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 + PStatement::PStatement(PErrorHandler& 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 > error_handler_function; + typedef function > 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(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)); + } +}} + + diff --git a/src/musredit_qt5/mupp/var/src/PExpression.cpp b/src/musredit_qt5/mupp/var/src/PExpression.cpp new file mode 100644 index 00000000..351b5145 --- /dev/null +++ b/src/musredit_qt5/mupp/var/src/PExpression.cpp @@ -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; diff --git a/src/musredit_qt5/mupp/var/src/PProgram.cpp b/src/musredit_qt5/mupp/var/src/PProgram.cpp new file mode 100644 index 00000000..fac4a014 --- /dev/null +++ b/src/musredit_qt5/mupp/var/src/PProgram.cpp @@ -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 +#include +#include +#include +#include +#include + +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 &val, + std::vector &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= fVarPos.size()) + ok = false; + else + result = fVarPos[num]; + } + + return result; + } + + + std::vector PProgEval::operator()(ast::nil) + { + std::vector result; + result.resize(fVariable[0].GetSize()); + + for (unsigned int i=0; i PProgEval::operator()(double x) + { + std::vector result; + result.resize(fVariable[0].GetSize()); + + for (unsigned int i=0; i PProgEval::operator()(ast::assignment const &x) + { + std::vector result; + result.resize(fVariable[0].GetSize()); + + result = (*this)(x.rhs); + + // keep all data under not Err. + // Err data go to error, whereas + // data go to 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 PProgEval::operator()(ast::expression const &x) + { + std::vector vec = boost::apply_visitor(*this, x.first); + + BOOST_FOREACH(ast::operation const& oper, x.rest) { + vec = (*this)(oper, vec); + } + return vec; + } + + std::vector PProgEval::operator()(ast::function const &x) + { + std::vector vec = (*this)(x.arg); + + double dval; + switch(x.func_id) { + case ast::fun_max: + dval = -1.0e10; + for (unsigned int i=0; i dval) + dval = vec[i]; + } + for (unsigned int i=0; i PProgEval::operator()(ast::operation const &x, std::vector lhs) + { + std::vector 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 PProgEval::operator()(ast::power const &x) + { + std::vector baseV = (*this)(x.base); + std::vector powV = (*this)(x.pow); + + if (baseV.size() != powV.size()) { + BOOST_ASSERT(0); + return baseV; + } + + std::vector result; + result.resize(baseV.size()); + for (unsigned int i=0; i PProgEval::operator()(ast::statement const &x) + { + // as35: not-yet-implemented + std::vector result; + result.resize(fVariable[0].GetSize()); + + for (unsigned int i=0; i PProgEval::operator()(ast::statement_list const &x) + { + // as35: not-yet-implemented + std::vector result; + result.resize(fVariable[0].GetSize()); + + for (unsigned int i=0; i PProgEval::operator()(ast::unary const &x) + { + std::vector vec = boost::apply_visitor(*this, x.operand_); + + if (x.operator_ == ast::op_negative) { + for (unsigned int i=0; i 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 PProgEval::operator()(ast::variable_declaration const &x) + { + std::vector result; + result.resize(fVariable[0].GetSize()); + + // keep all data under not Err. + // Err data go to error, whereas + // data go to 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 val, err; + for (unsigned int i=0; i;