/* * Parsodus - A language agnostic parser generator * Copyright © 2016-2017 Thomas Avé, Robin Jadoul, Kobe Wullaert * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "AST.h" #include #include #include #include namespace calc { namespace { using d2dfn = double(*)(double); std::function wrap(std::function fn) { return [fn](const Variables& vars, const Functions& funs, FunctionArguments& args) -> double{ if (args.size() != 1) return 0; return fn(args[0]->eval(vars, funs)); }; } std::map> builtins = { {"if", [](const Variables& vars, const Functions& funs, FunctionArguments& args) -> double { if (args.size() != 3) return 0; double test = args[0]->eval(vars, funs); if (test == 0) return args[2]->eval(vars, funs); else return args[1]->eval(vars, funs); }}, {"sin", wrap((d2dfn)(std::sin))}, {"cos", wrap((d2dfn)(std::cos))}, {"tan", wrap((d2dfn)(std::tan))}, {"asin", wrap((d2dfn)(std::asin))}, {"acos", wrap((d2dfn)(std::acos))}, {"atan", wrap((d2dfn)(std::atan))}, {"abs", wrap((d2dfn)(std::fabs))} }; } Number::Number(double d) : m_val(d) {} double Number::eval(const Variables&, const Functions&) const { return m_val; } Var::Var(std::string name) : m_name(name) {} double Var::eval(const Variables& vars, const Functions&) const { auto v = vars.find(m_name); if (v != vars.end()) return v->second; return 0; } std::string Var::getName() const { return m_name; } Binop::Binop(std::unique_ptr&& left, std::string op, std::unique_ptr&& right) : m_left(std::move(left)), m_right(std::move(right)), m_op(op) {} double Binop::eval(const Variables& vars, const Functions& funs) const { double left = m_left->eval(vars, funs); double right = m_right->eval(vars, funs); if (m_op == "+") return left + right; else if (m_op == "-") return left - right; else if (m_op == "*") return left * right; else if (m_op == "/") return left / right; else if (m_op == "^") return std::pow(left, right); else if (m_op == "<") return left < right ? 1 : 0; return 0; } Unop::Unop(std::string op, std::unique_ptr&& operand) : m_op(op), m_operand(std::move(operand)) {} double Unop::eval(const Variables& vars, const Functions& funs) const { if (m_op == "-") return -m_operand->eval(vars, funs); return 0; } double FormalParameters::eval(const Variables&, const Functions&) const { return 0; } void FormalParameters::push_back(std::unique_ptr&& arg) { m_args.emplace_back(std::move(arg)); } std::deque>::const_iterator FormalParameters::begin() { return m_args.begin(); } std::deque>::const_iterator FormalParameters::end() { return m_args.end(); } double FunctionArguments::eval(const Variables&, const Functions&) const { return 0; } std::unique_ptr& FunctionArguments::operator[](std::size_t idx) { return m_args[idx]; } void FunctionArguments::push_back(std::unique_ptr&& arg) { m_args.push_back(std::move(arg)); } std::size_t FunctionArguments::size() const { return m_args.size(); } FunctionCall::FunctionCall(std::string name, std::unique_ptr&& arguments) : m_name(name), m_arguments(std::move(arguments)) {} double FunctionCall::eval(const Variables& vars, const Functions& funs) const { auto fp = funs.find(m_name); if (fp == funs.end()) { if (builtins.count(m_name)) { return builtins[m_name](vars, funs, *m_arguments); } else { return 0; } } Function& fun = *dynamic_cast((fp->second.get())); if (m_arguments->size() != fun.getParams().size()) return 0; Variables newVars = vars; std::size_t i = 0; for (const std::string& param : fun.getParams()) { newVars[param] = (*m_arguments)[i]->eval(vars, funs); i++; } return fun.eval(newVars, funs); } Function::Function(std::deque formalParams, std::unique_ptr&& body) : m_formalParams(std::move(formalParams)), m_body(std::move(body)) {} double Function::eval(const Variables& vars, const Functions& funs) const { return m_body->eval(vars, funs); } const std::deque& Function::getParams() const { return m_formalParams; } } /* calc */