diff --git a/lab1/CMakeLists.txt b/lab1/CMakeLists.txt new file mode 100644 index 0000000..d735ce7 --- /dev/null +++ b/lab1/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.27) + +project(calculator + VERSION 0.1.0 + DESCRIPTION "Simple calculator <3" + LANGUAGES CXX +) + +SET(CMAKE_CXX_STANDARD 20) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_subdirectory(default_operators) +add_subdirectory(dll_plugins) +add_subdirectory(calculator) \ No newline at end of file diff --git a/lab1/README.md b/lab1/README.md new file mode 100644 index 0000000..e351dd9 --- /dev/null +++ b/lab1/README.md @@ -0,0 +1,21 @@ +# Calculator + +Приложение состоит из исполняемого файла - .exe, который имеет консольный интерфейс и +способен вычислять выражения с операциями + - / * (). +- Ввод: 16 + 4 * (3 – 1) +- Вывод: 24 + +При запуске приложение обращается в папку ./plugins, и из каждой dll загружает и распознает +соответствующую функцию. + - ./calc.exe + - ./plugins/funcsin.dll + - ./plugins/funcdeg.dll + +Что приводит к возможности использовать эти функции сразу же после запуска приложения, делая валидными вычисления: +- 2^4 + sin(90) + +Примечания: +- Каждый плагин содержит ровно одну функцию. +- Имя файла dll не должно участвовать на +определение самой функции и ее имени. +- Необходимо определить и обработать исключительные случаи (некорректная dll, нет никаких dll, какая-то из функций бросает исключение, например, ln(-100) ) diff --git a/lab1/calc_custom_exception/CalcException.hpp b/lab1/calc_custom_exception/CalcException.hpp new file mode 100644 index 0000000..0a7278f --- /dev/null +++ b/lab1/calc_custom_exception/CalcException.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + + +class CalcException : public std::exception { + std::string const message; +public: + explicit CalcException(std::string const &tag, std::string const &description) : message( + std::format("{}: {}", tag, description)) {} + + char const *what() const noexcept override { + return message.c_str(); + } +}; diff --git a/lab1/calculator/CMakeLists.txt b/lab1/calculator/CMakeLists.txt new file mode 100644 index 0000000..d0c15c1 --- /dev/null +++ b/lab1/calculator/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.27) + +project(calc) + +SET(CMAKE_CXX_STANDARD 20) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../out) + +SET(SOURCE_FILES + source/main.cpp + source/Calculator/TokenScanner.cpp + source/Calculator/TokenConverter.cpp + source/Calculator/PolishCalculator.cpp + source/Calculator/Calculator.cpp + source/Calculator/PluginsLoader/PluginsLoader.cpp +) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + + +set(TOKEN_I_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../token_default_classes) +set(DEFAULT_OP_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../default_operators) +set(PLUGINS_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../dll_plugins) +set(CALC_EXCEPTION_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../calc_custom_exception) + +target_include_directories(${PROJECT_NAME} PRIVATE + ${TOKEN_I_SOURCE} + ${DEFAULT_OP_SOURCE}/include + ${PLUGINS_SOURCE}/include + ${CALC_EXCEPTION_SOURCE} +) + +target_link_libraries(${PROJECT_NAME} PRIVATE ${DEFAULT_OP_SOURCE}/lib/default_operators.lib) \ No newline at end of file diff --git a/lab1/calculator/source/CLI.hpp b/lab1/calculator/source/CLI.hpp new file mode 100644 index 0000000..64e19e0 --- /dev/null +++ b/lab1/calculator/source/CLI.hpp @@ -0,0 +1,31 @@ +#pragma once +#include + +#include "CalcException.hpp" + + +class CLI { +public: + static void startInteraction() { + std::cout << R"(print "exit" or ":q" to leave)" << std::endl; + + std::string exprStr; + Calculator calculator; + while (true) { + std::cout << "> "; + std::getline(std::cin, exprStr); + + if (exprStr == "exit" || exprStr == ":q") + return; + + try { + std::cout << std::format("{} = {}\n", exprStr, calculator.calculate(exprStr)); + } catch (CalcException& exception) { + std::cout << exception.what() << std::endl; + } catch (std::exception& exception) { + std::cout << std::format("Caught exception during program runtime\nwhat: {}", exception.what()); + exit(1); + } + } + } +}; diff --git a/lab1/calculator/source/Calculator/Calculator.cpp b/lab1/calculator/source/Calculator/Calculator.cpp new file mode 100644 index 0000000..0efe4d5 --- /dev/null +++ b/lab1/calculator/source/Calculator/Calculator.cpp @@ -0,0 +1,6 @@ +#include "Calculator.hpp" + + +double Calculator::calculate(std::string const& exprStr) { + return polishCalculator.calculate(*converter.convert(*scanner.buildTokens(exprStr))); +} diff --git a/lab1/calculator/source/Calculator/Calculator.hpp b/lab1/calculator/source/Calculator/Calculator.hpp new file mode 100644 index 0000000..6a9095b --- /dev/null +++ b/lab1/calculator/source/Calculator/Calculator.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +#include "TokenScanner.hpp" +#include "TokenConverter.hpp" +#include "PolishCalculator.hpp" + + +class Calculator { + TokenConverter converter; + TokenScanner scanner; + PolishCalculator polishCalculator; +public: + [[nodiscard]] double calculate(std::string const& exprStr); +}; diff --git a/lab1/calculator/source/Calculator/PluginsLoader/PluginsLoader.cpp b/lab1/calculator/source/Calculator/PluginsLoader/PluginsLoader.cpp new file mode 100644 index 0000000..b227f4b --- /dev/null +++ b/lab1/calculator/source/Calculator/PluginsLoader/PluginsLoader.cpp @@ -0,0 +1,61 @@ +#include "PluginsLoader.hpp" + +#include +#include +#include +#include + +#include "export.hpp" + + +void PluginsLoader::loadPlugins() { + loadedPlugins.clear(); + for (auto const &entry: std::filesystem::directory_iterator(dllDir)) { + HMODULE dllHandler = LoadLibrary(_T(entry.path().string().c_str())); + if (!dllHandler) { + continue; + } + FARPROC getNameFuncAddr = GetProcAddress(dllHandler, "getName"); + FARPROC calcFuncAddr = GetProcAddress(dllHandler, "calc"); + FARPROC getTypeFuncAddr = GetProcAddress(dllHandler, "getType"); + FARPROC getPriorLevelFuncAddr = GetProcAddress(dllHandler, "getPriorityLevel"); + + if (!calcFuncAddr || !getNameFuncAddr || !getTypeFuncAddr || !getPriorLevelFuncAddr) + continue; + + std::function getNameFunc((decltype(&::getName)(getNameFuncAddr))); + std::function calcFunc((decltype(&::calc)(calcFuncAddr))); + std::function getTypeFunc((decltype(&::getType)(getTypeFuncAddr))); + std::function getPriorityLevelFunc((decltype(&::getPriorityLevel)(getPriorLevelFuncAddr))); + + nameToFunc.emplace( + getNameFunc(), + CalcFuncWithInfo{ + getTypeFunc(), + calcFunc, + getPriorityLevelFunc() + }); + loadedPlugins.emplace_back(dllHandler); + } +} + +bool PluginsLoader::contains(std::string const &opName, Tok::TokenType opType) { + return nameToFunc.contains(opName) && nameToFunc.at(opName).type == opType; +} + +std::function const &)> &PluginsLoader::getOpFunction(std::string const &opName) { + return nameToFunc.at(opName).calcFunc; +} + +uint8_t PluginsLoader::getPriorityLevel(std::string const &opName) { + return nameToFunc.at(opName).priorityLevel; +} + +void PluginsLoader::freePlugins() { + loadedPlugins.clear(); +} + + +PluginsLoader::DllWatcher::~DllWatcher() { + FreeLibrary(dllHandler); +} diff --git a/lab1/calculator/source/Calculator/PluginsLoader/PluginsLoader.hpp b/lab1/calculator/source/Calculator/PluginsLoader/PluginsLoader.hpp new file mode 100644 index 0000000..d09f4c4 --- /dev/null +++ b/lab1/calculator/source/Calculator/PluginsLoader/PluginsLoader.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "Token.hpp" + + +class PluginsLoader { + class DllWatcher { + HMODULE dllHandler; + public: + explicit DllWatcher(HMODULE dllHandler) : dllHandler(dllHandler) {} + + ~DllWatcher(); + }; + + class CalcFuncWithInfo { + public: + Tok::TokenType type; + std::function const &)> calcFunc; + uint8_t priorityLevel; + }; + + std::wstring const dllDir; + std::list loadedPlugins; + std::unordered_map nameToFunc; +public: + PluginsLoader(std::wstring dllDir = L"plugins") : dllDir(std::move(dllDir)) {} + + ~PluginsLoader() { freePlugins(); } + + void loadPlugins(); + + bool contains(std::string const &opName, Tok::TokenType opType); + + std::function const &)> &getOpFunction(std::string const &opName); + + uint8_t getPriorityLevel(std::string const &opName); + + void freePlugins(); +}; diff --git a/lab1/calculator/source/Calculator/PolishCalculator.cpp b/lab1/calculator/source/Calculator/PolishCalculator.cpp new file mode 100644 index 0000000..efa9be6 --- /dev/null +++ b/lab1/calculator/source/Calculator/PolishCalculator.cpp @@ -0,0 +1,35 @@ +#include "PolishCalculator.hpp" + +#include "ComputableOperator.hpp" + + +double PolishCalculator::calculate(std::queue& tokens) { + operandStack = std::make_shared>(); + + while (!tokens.empty()) { + auto token = tokens.front(); + tokens.pop(); + parseToken(token); + } + + auto result = operandStack->top()->getValue(); + operandStack.reset(); + + return result; +} + +void PolishCalculator::parseToken(Tok::TokenPtr &token) { + switch (token->getType()) { + case Tok::PREFIX_OPERATOR: + case Tok::SUFFIX_OPERATOR: + case Tok::POSTFIX_OPERATOR: + std::dynamic_pointer_cast(token)->doCalc(*operandStack); + break; + case Tok::OPERAND: + operandStack->push(std::dynamic_pointer_cast(token)); + break; + case Tok::OPENING_PARENTHESIS: + case Tok::CLOSING_PARENTHESIS: + break; + } +} diff --git a/lab1/calculator/source/Calculator/PolishCalculator.hpp b/lab1/calculator/source/Calculator/PolishCalculator.hpp new file mode 100644 index 0000000..f37ff4b --- /dev/null +++ b/lab1/calculator/source/Calculator/PolishCalculator.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +#include "Token.hpp" +#include "Operand.hpp" + + +class PolishCalculator { + std::shared_ptr> operandStack; + + void parseToken(Tok::TokenPtr &token); +public: + double calculate(std::queue &tokens); +}; diff --git a/lab1/calculator/source/Calculator/TokenConverter.cpp b/lab1/calculator/source/Calculator/TokenConverter.cpp new file mode 100644 index 0000000..13759f3 --- /dev/null +++ b/lab1/calculator/source/Calculator/TokenConverter.cpp @@ -0,0 +1,87 @@ +#include "TokenConverter.hpp" + +#include +#include + +#include "Parenthesis.hpp" +#include "CalcException.hpp" + + +void TokenConverter::dropOperators(Tok::OperatorPtr const &op) { + while (!operatorsStack->empty() && *op <= *operatorsStack->top()) { + resultTokens->push(operatorsStack->top()); + operatorsStack->pop(); + } +} + +void TokenConverter::parseForPrefix(std::shared_ptr &token) { + if (token->getType() == Tok::TokenType::OPERAND) { + resultTokens->push(token); + state = ConvertState::WAITING_FOR_SUFFIX; + return; + } + + auto opToken = std::dynamic_pointer_cast(token); + if (opToken->getType() == Tok::TokenType::OPENING_PARENTHESIS || + opToken->getType() == Tok::TokenType::PREFIX_OPERATOR) { + operatorsStack->push(opToken); + } else { + throw CalcException("ConvertError", std::format("Expected number or \"(\", found {}", opToken->getName())); + } +} + +void TokenConverter::parseForSuffix(std::shared_ptr &token) { + if (token->getType() == Tok::TokenType::OPERAND) + throw CalcException("ConvertError", "Expected binary operator or \")\", found number"); + + auto opToken = std::dynamic_pointer_cast(token); + dropOperators(opToken); + + if (opToken->getType() == Tok::TokenType::OPENING_PARENTHESIS && + (operatorsStack->empty() || operatorsStack->top()->getType() != Tok::TokenType::CLOSING_PARENTHESIS)) + throw CalcException("ConvertError", "Expected \"(\""); + + if (opToken->getType() == Tok::TokenType::CLOSING_PARENTHESIS) + operatorsStack->pop(); + else if (opToken->getType() != Tok::TokenType::CLOSING_PARENTHESIS) { + operatorsStack->push(opToken); + if (opToken->getType() != Tok::TokenType::POSTFIX_OPERATOR) + state = ConvertState::WAITING_FOR_PREFIX; + } +} + +std::shared_ptr> TokenConverter::convert(std::queue &tokens) { + resultTokens = std::make_shared>(); + operatorsStack = std::make_unique>(); + + std::shared_ptr token; + state = ConvertState::WAITING_FOR_PREFIX; + + while (true) { + if (tokens.empty() && state == ConvertState::WAITING_FOR_PREFIX) + throw CalcException("ConvertError", "Unexpected end of the expression"); + if (tokens.empty() && state == ConvertState::WAITING_FOR_SUFFIX) { + break; + } else { + token = tokens.front(); + tokens.pop(); + } + + switch (state) { + case WAITING_FOR_PREFIX: + parseForPrefix(token); + break; + case WAITING_FOR_SUFFIX: + parseForSuffix(token); + break; + } + } + + dropOperators(std::make_shared()); + if (!operatorsStack->empty()) + throw CalcException("ConvertError", "Expected \")\""); + operatorsStack.reset(); + + return resultTokens; +} + diff --git a/lab1/calculator/source/Calculator/TokenConverter.hpp b/lab1/calculator/source/Calculator/TokenConverter.hpp new file mode 100644 index 0000000..3858030 --- /dev/null +++ b/lab1/calculator/source/Calculator/TokenConverter.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include + +#include "Operator.hpp" +#include "SuffixOperator.hpp" + + +class TokenConverter { + enum ConvertState { + WAITING_FOR_PREFIX = 0, + WAITING_FOR_SUFFIX + } state; + + std::shared_ptr> resultTokens; + std::unique_ptr> operatorsStack; + + static std::unordered_map const opPriority; + + void dropOperators(Tok::OperatorPtr const &op); + + void parseForPrefix(Tok::TokenPtr &token); + + void parseForSuffix(Tok::TokenPtr &token); +public: + std::shared_ptr> convert(std::queue &tokens); +}; diff --git a/lab1/calculator/source/Calculator/TokenScanner.cpp b/lab1/calculator/source/Calculator/TokenScanner.cpp new file mode 100644 index 0000000..ad34fcf --- /dev/null +++ b/lab1/calculator/source/Calculator/TokenScanner.cpp @@ -0,0 +1,113 @@ +#include "TokenScanner.hpp" + +#include +#include + +#include "SuffixOperator.hpp" +#include "PrefixOperator.hpp" +#include "PostfixOperator.hpp" +#include "Function.hpp" +#include "CalcException.hpp" + + +double TokenScanner::readNumber(std::string::const_iterator &iter, std::string const &expr) { + double number = 0.0; + + while (iter != expr.end() && std::isdigit(*iter)) { + number = number * 10.0 + *iter - '0'; + ++iter; + } + if (iter == expr.end() || *iter != '.') + return number; + + ++iter; + double denominator = 0.1; + while (iter != expr.end() && std::isdigit(*iter)) { + number += (*iter - '0') * denominator; + denominator /= 10.0; + ++iter; + } + + return number; +} + + +std::string TokenScanner::readName(std::string::const_iterator &iter, std::string const &expr) { + std::string name; + while (iter != expr.end() && std::isalpha(*iter)) { + name += *iter; + ++iter; + } + + return name; +} + +std::shared_ptr>> TokenScanner::buildTokens(std::string const &expr) { + tokens = std::make_shared>(); + expectingOp = false; + + for (auto iter = expr.begin(); iter != expr.end();) { + char const ch = *iter; + + if (ch == ' ' || ch == '\n') { + ++iter; + continue; + } + if (std::isdigit(ch)) { + tokens->push(std::make_shared(readNumber(iter, expr))); + expectingOp = true; + } else if (addOperator(std::string(1, ch))) { + ++iter; + } else if (std::isalpha(ch)) { + std::string name = readName(iter, expr); + + if (pluginsLoader.contains(name, Tok::PREFIX_OPERATOR)) { + tokens->emplace(std::make_shared(name, pluginsLoader.getOpFunction(name))); + } else { + throw CalcException("ScanError", std::format("Unknown name \"{}\"", name)); + } + } else { + throw CalcException("ScanError", std::format("Unknown literal \"{}\"", ch)); + } + } + + return tokens; +} + + +bool TokenScanner::loadFunction(DefaultOperators &defaultOperators, + std::function const &)> &func, std::uint8_t &priorityLevel, + Tok::TokenType const opType, std::string const &opName) { + if (defaultOperators.contains(opName)) { + func = defaultOperators.getCalcFunction(opName); + priorityLevel = defaultOperators.getPriorityLevel(opName); + } else if (pluginsLoader.contains(opName, opType)) { + func = pluginsLoader.getOpFunction(opName); + priorityLevel = pluginsLoader.getPriorityLevel(opName); + } else + return false; + return true; +} + + +bool TokenScanner::addOperator(std::string const &opName) noexcept { + std::function const &)> func; + std::uint8_t priorityLevel; + if (opName == "(") + tokens->emplace(std::make_shared()); + else if (opName == ")") + tokens->emplace(std::make_shared()); + else if (expectingOp && + loadFunction(defaultPostfixOperators, func, priorityLevel, Tok::POSTFIX_OPERATOR, opName)) { + tokens->emplace(std::make_shared(opName, priorityLevel, func)); + } else if (expectingOp && + loadFunction(defaultSuffixOperators, func, priorityLevel, Tok::SUFFIX_OPERATOR, opName)) { + tokens->emplace(std::make_shared(opName, priorityLevel, func)); + expectingOp = false; + } else if (!expectingOp && + loadFunction(defaultPrefixOperators, func, priorityLevel, Tok::PREFIX_OPERATOR, opName)) { + tokens->emplace(std::make_shared(opName, priorityLevel, func)); + } else + return false; + return true; +} diff --git a/lab1/calculator/source/Calculator/TokenScanner.hpp b/lab1/calculator/source/Calculator/TokenScanner.hpp new file mode 100644 index 0000000..193553c --- /dev/null +++ b/lab1/calculator/source/Calculator/TokenScanner.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include +#include + +#include "ComputableOperator.hpp" +#include "Operands.hpp" +#include "Parenthesis.hpp" + +#include "DefaultSuffixOperators.hpp" +#include "DefaultPrefixOperators.hpp" +#include "DefaultPostfixOperators.hpp" + +#include "PluginsLoader/PluginsLoader.hpp" + + +class TokenScanner { + DefaultPrefixOperators defaultPrefixOperators; + DefaultSuffixOperators defaultSuffixOperators; + DefaultPostfixOperators defaultPostfixOperators; + PluginsLoader pluginsLoader; + + bool expectingOp = false; + std::shared_ptr> tokens; + + static double readNumber(std::string::const_iterator &iter, std::string const &expr); + + bool loadFunction(DefaultOperators &defaultOperators, + std::function const &)> &func, std::uint8_t &priorityLevel, + Tok::TokenType const opType, std::string const &opName); + + static std::string readName(std::string::const_iterator &iter, std::string const &expr); + + bool addOperator(std::string const &opName) noexcept; + +public: + TokenScanner() { pluginsLoader.loadPlugins(); } + + std::shared_ptr> buildTokens(std::string const &expr); +}; diff --git a/lab1/calculator/source/main.cpp b/lab1/calculator/source/main.cpp new file mode 100644 index 0000000..2b0b1d1 --- /dev/null +++ b/lab1/calculator/source/main.cpp @@ -0,0 +1,11 @@ +#include +#include + +#include "Calculator/Calculator.hpp" +#include "CLI.hpp" + + +int main() { + CLI::startInteraction(); + return 0; +} \ No newline at end of file diff --git a/lab1/default_operators/CMakeLists.txt b/lab1/default_operators/CMakeLists.txt new file mode 100644 index 0000000..4d340b3 --- /dev/null +++ b/lab1/default_operators/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.27) + +project(default_operators) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib) +set(CMAKE_STATIC_LIBRARY_PREFIX "") + +set(SOURCE_FILES + source/default_suffix_operators/DefaultSuffixOperators.cpp + source/default_prefix_operators/DefaultPrefixOperators.cpp + source/default_postfix_operators/DefaultPostfixOperators.cpp + source/DefaultOperators.cpp +) + +set(TOKEN_I_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../token_default_classes) +set(CALC_EXCEPTION_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../calc_custom_exception) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +target_include_directories(${PROJECT_NAME} PRIVATE + include + ${TOKEN_I_SOURCE} + ${CALC_EXCEPTION_SOURCE} +) + +set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".lib") + +file(GLOB_RECURSE header_files "source/*.hpp") +foreach (header_file_path ${header_files}) + get_filename_component(filename ${header_file_path} NAME) + message(${CMAKE_CURRENT_SOURCE_DIR}/include/${filename}) + add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${header_file_path} + ${CMAKE_CURRENT_SOURCE_DIR}/include/${filename} + ) +endforeach () \ No newline at end of file diff --git a/lab1/default_operators/include/DefaultOperators.hpp b/lab1/default_operators/include/DefaultOperators.hpp new file mode 100644 index 0000000..0b80da4 --- /dev/null +++ b/lab1/default_operators/include/DefaultOperators.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include +#include +#include + + +class DefaultOperators { +protected: + class opInfo { + public: + std::uint8_t priorityLevel; + std::function const &)> calcFunction; + }; + + std::unordered_map opSymbolToInfo; +public: + bool contains(std::string const &opName); + + std::function const &)> getCalcFunction(std::string const &opName); + + std::uint8_t getPriorityLevel(std::string const &opName); +}; diff --git a/lab1/default_operators/include/DefaultPostfixOperators.hpp b/lab1/default_operators/include/DefaultPostfixOperators.hpp new file mode 100644 index 0000000..510ba8e --- /dev/null +++ b/lab1/default_operators/include/DefaultPostfixOperators.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "DefaultOperators.hpp" + + +class DefaultPostfixOperators : public DefaultOperators { +protected: + static double factorial(std::vector const &numbers); +public: + DefaultPostfixOperators(); +}; \ No newline at end of file diff --git a/lab1/default_operators/include/DefaultPrefixOperators.hpp b/lab1/default_operators/include/DefaultPrefixOperators.hpp new file mode 100644 index 0000000..ffa25b9 --- /dev/null +++ b/lab1/default_operators/include/DefaultPrefixOperators.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "DefaultOperators.hpp" + + +class DefaultPrefixOperators : public DefaultOperators { + static double unaryMinus(std::vector const &numbers); +public: + DefaultPrefixOperators(); +}; \ No newline at end of file diff --git a/lab1/default_operators/include/DefaultSuffixOperators.hpp b/lab1/default_operators/include/DefaultSuffixOperators.hpp new file mode 100644 index 0000000..89bdb89 --- /dev/null +++ b/lab1/default_operators/include/DefaultSuffixOperators.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "DefaultOperators.hpp" + + +class DefaultSuffixOperators : public DefaultOperators { + static double addition(std::vector const &numbers); + + static double subtraction(std::vector const &numbers); + + static double multiplication(std::vector const &numbers); + + static double division(std::vector const &numbers); + + static double modulo(std::vector const &numbers); +public: + DefaultSuffixOperators(); +}; \ No newline at end of file diff --git a/lab1/default_operators/lib/default_operators.lib b/lab1/default_operators/lib/default_operators.lib new file mode 100644 index 0000000..14c2b2a Binary files /dev/null and b/lab1/default_operators/lib/default_operators.lib differ diff --git a/lab1/default_operators/source/DefaultOperators.cpp b/lab1/default_operators/source/DefaultOperators.cpp new file mode 100644 index 0000000..755df63 --- /dev/null +++ b/lab1/default_operators/source/DefaultOperators.cpp @@ -0,0 +1,13 @@ +#include "DefaultOperators.hpp" + +bool DefaultOperators::contains(std::string const &opName) { + return opSymbolToInfo.contains(opName); +} + +std::function const &)> DefaultOperators::getCalcFunction(std::string const &opName) { + return opSymbolToInfo.at(opName).calcFunction; +} + +std::uint8_t DefaultOperators::getPriorityLevel(std::string const &opName) { + return opSymbolToInfo.at(opName).priorityLevel; +} diff --git a/lab1/default_operators/source/DefaultOperators.hpp b/lab1/default_operators/source/DefaultOperators.hpp new file mode 100644 index 0000000..0b80da4 --- /dev/null +++ b/lab1/default_operators/source/DefaultOperators.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include +#include +#include + + +class DefaultOperators { +protected: + class opInfo { + public: + std::uint8_t priorityLevel; + std::function const &)> calcFunction; + }; + + std::unordered_map opSymbolToInfo; +public: + bool contains(std::string const &opName); + + std::function const &)> getCalcFunction(std::string const &opName); + + std::uint8_t getPriorityLevel(std::string const &opName); +}; diff --git a/lab1/default_operators/source/default_postfix_operators/DefaultPostfixOperators.cpp b/lab1/default_operators/source/default_postfix_operators/DefaultPostfixOperators.cpp new file mode 100644 index 0000000..9bc25d0 --- /dev/null +++ b/lab1/default_operators/source/default_postfix_operators/DefaultPostfixOperators.cpp @@ -0,0 +1,25 @@ +#include "DefaultPostfixOperators.hpp" + +#include +#include + +#include "DefaultPriorityRanges.hpp" +#include "CalcException.hpp" + + +DefaultPostfixOperators::DefaultPostfixOperators() { + opSymbolToInfo = { + {"!", {DEFAULT_POSTFIX_OPERATOR_PRIORITY, factorial}} + }; +} + +double DefaultPostfixOperators::factorial(const std::vector &numbers) { + if (numbers[0] < 0.0 || std::abs(static_cast(numbers[0]) - numbers[0]) > 0.0) + throw CalcException("CalcError", "Invalid factorial argument"); + + double result = 1.0; + for (uint32_t i = 2; i <= numbers[0]; i++) + result *= i; + + return result; +} diff --git a/lab1/default_operators/source/default_postfix_operators/DefaultPostfixOperators.hpp b/lab1/default_operators/source/default_postfix_operators/DefaultPostfixOperators.hpp new file mode 100644 index 0000000..510ba8e --- /dev/null +++ b/lab1/default_operators/source/default_postfix_operators/DefaultPostfixOperators.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "DefaultOperators.hpp" + + +class DefaultPostfixOperators : public DefaultOperators { +protected: + static double factorial(std::vector const &numbers); +public: + DefaultPostfixOperators(); +}; \ No newline at end of file diff --git a/lab1/default_operators/source/default_prefix_operators/DefaultPrefixOperators.cpp b/lab1/default_operators/source/default_prefix_operators/DefaultPrefixOperators.cpp new file mode 100644 index 0000000..7f36672 --- /dev/null +++ b/lab1/default_operators/source/default_prefix_operators/DefaultPrefixOperators.cpp @@ -0,0 +1,17 @@ +#include "DefaultPrefixOperators.hpp" + +#include + +#include "DefaultPriorityRanges.hpp" + + +DefaultPrefixOperators::DefaultPrefixOperators() { + opSymbolToInfo = { + {"-", {DEFAULT_PREFIX_OPERATOR_PRIORITY, unaryMinus}} + }; +} + + +double DefaultPrefixOperators::unaryMinus(std::vector const &numbers) { + return -numbers[0]; +} diff --git a/lab1/default_operators/source/default_prefix_operators/DefaultPrefixOperators.hpp b/lab1/default_operators/source/default_prefix_operators/DefaultPrefixOperators.hpp new file mode 100644 index 0000000..ffa25b9 --- /dev/null +++ b/lab1/default_operators/source/default_prefix_operators/DefaultPrefixOperators.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "DefaultOperators.hpp" + + +class DefaultPrefixOperators : public DefaultOperators { + static double unaryMinus(std::vector const &numbers); +public: + DefaultPrefixOperators(); +}; \ No newline at end of file diff --git a/lab1/default_operators/source/default_suffix_operators/DefaultSuffixOperators.cpp b/lab1/default_operators/source/default_suffix_operators/DefaultSuffixOperators.cpp new file mode 100644 index 0000000..ecf5e5a --- /dev/null +++ b/lab1/default_operators/source/default_suffix_operators/DefaultSuffixOperators.cpp @@ -0,0 +1,39 @@ +#include "DefaultSuffixOperators.hpp" + +#include + +#include "DefaultPriorityRanges.hpp" +#include "CalcException.hpp" + + +DefaultSuffixOperators::DefaultSuffixOperators() { + opSymbolToInfo = { + {"+", {MIN_SUFFIX_OPERATORS_PRIORITY + 1, DefaultSuffixOperators::addition}}, + {"-", {MIN_SUFFIX_OPERATORS_PRIORITY + 1, DefaultSuffixOperators::subtraction}}, + {"*", {MIN_SUFFIX_OPERATORS_PRIORITY + 2, DefaultSuffixOperators::multiplication}}, + {"/", {MIN_SUFFIX_OPERATORS_PRIORITY + 2, DefaultSuffixOperators::division}}, + {"%", {MIN_SUFFIX_OPERATORS_PRIORITY + 2, DefaultSuffixOperators::modulo}}, + }; +} + +double DefaultSuffixOperators::addition(std::vector const& numbers) { + return numbers[0] + numbers[1]; +} + +double DefaultSuffixOperators::subtraction(std::vector const& numbers) { + return numbers[0] - numbers[1]; +} + +double DefaultSuffixOperators::multiplication(std::vector const& numbers) { + return numbers[0] * numbers[1]; +} + +double DefaultSuffixOperators::division(std::vector const& numbers) { + if (numbers[1] == 0.0) + throw CalcException("CalcError", "Division by zero"); + return numbers[0] / numbers[1]; +} + +double DefaultSuffixOperators::modulo(std::vector const& numbers) { + return static_cast(static_cast(numbers[0]) % static_cast(numbers[1])); +} diff --git a/lab1/default_operators/source/default_suffix_operators/DefaultSuffixOperators.hpp b/lab1/default_operators/source/default_suffix_operators/DefaultSuffixOperators.hpp new file mode 100644 index 0000000..89bdb89 --- /dev/null +++ b/lab1/default_operators/source/default_suffix_operators/DefaultSuffixOperators.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "DefaultOperators.hpp" + + +class DefaultSuffixOperators : public DefaultOperators { + static double addition(std::vector const &numbers); + + static double subtraction(std::vector const &numbers); + + static double multiplication(std::vector const &numbers); + + static double division(std::vector const &numbers); + + static double modulo(std::vector const &numbers); +public: + DefaultSuffixOperators(); +}; \ No newline at end of file diff --git a/lab1/dll_plugins/CMakeLists.txt b/lab1/dll_plugins/CMakeLists.txt new file mode 100644 index 0000000..2faaa16 --- /dev/null +++ b/lab1/dll_plugins/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.27) + +project(functions + DESCRIPTION "Functions for calculator, stored in dynamic library" + VERSION 0.1.0 + LANGUAGES CXX +) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../out/plugins) + +list(APPEND plugins + sqrt log sin cos pow +) + +set(TOKEN_I_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../token_default_classes) +set(CALC_EXCEPTION_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../calc_custom_exception) + +foreach (plugin ${plugins}) + add_library(${plugin} SHARED source/${plugin}.cpp) + set_target_properties(${plugin} PROPERTIES PREFIX "") + target_compile_definitions(${plugin} PRIVATE COMPILE_EXPORT) + target_include_directories(${plugin} PRIVATE + ${TOKEN_I_SOURCE} + ${CALC_EXCEPTION_SOURCE} + ) + + add_custom_command( + TARGET ${plugin} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/source/export.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/export.hpp + ) +endforeach () diff --git a/lab1/dll_plugins/include/export.hpp b/lab1/dll_plugins/include/export.hpp new file mode 100644 index 0000000..658e7c0 --- /dev/null +++ b/lab1/dll_plugins/include/export.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include "Token.hpp" +#include "CalcException.hpp" + + +#if defined(linux) || defined(__linux__) + #define FUNC_API __attribute__((visibility("default"))) +#elif defined(_WIN64) || defined(__WIN32__) + #if defined(COMPILE_EXPORT) + #define FUNC_API extern "C" __declspec(dllexport) + #else + #define FUNC_API extern "C" __declspec(dllimport) + #endif +#endif + + +FUNC_API std::string const& getName(); + +FUNC_API double calc(std::vector const &x); + +FUNC_API Tok::TokenType getType(); + +FUNC_API uint8_t getPriorityLevel(); diff --git a/lab1/dll_plugins/source/cos.cpp b/lab1/dll_plugins/source/cos.cpp new file mode 100644 index 0000000..2870345 --- /dev/null +++ b/lab1/dll_plugins/source/cos.cpp @@ -0,0 +1,24 @@ +#include "export.hpp" + +#include +#include + +#include "DefaultPriorityRanges.hpp" + +std::string const name = "cos"; + +std::string const& getName() { + return name; +} + +double calc(std::vector const &x) { + return static_cast(std::cos(static_cast(x[0]))); +} + +Tok::TokenType getType() { + return Tok::TokenType::PREFIX_OPERATOR; +} + +uint8_t getPriorityLevel() { + return DEFAULT_FUNCTION_PRIORITY; +} \ No newline at end of file diff --git a/lab1/dll_plugins/source/export.hpp b/lab1/dll_plugins/source/export.hpp new file mode 100644 index 0000000..658e7c0 --- /dev/null +++ b/lab1/dll_plugins/source/export.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include "Token.hpp" +#include "CalcException.hpp" + + +#if defined(linux) || defined(__linux__) + #define FUNC_API __attribute__((visibility("default"))) +#elif defined(_WIN64) || defined(__WIN32__) + #if defined(COMPILE_EXPORT) + #define FUNC_API extern "C" __declspec(dllexport) + #else + #define FUNC_API extern "C" __declspec(dllimport) + #endif +#endif + + +FUNC_API std::string const& getName(); + +FUNC_API double calc(std::vector const &x); + +FUNC_API Tok::TokenType getType(); + +FUNC_API uint8_t getPriorityLevel(); diff --git a/lab1/dll_plugins/source/log.cpp b/lab1/dll_plugins/source/log.cpp new file mode 100644 index 0000000..5a30c71 --- /dev/null +++ b/lab1/dll_plugins/source/log.cpp @@ -0,0 +1,25 @@ +#include "export.hpp" + +#include +#include + +std::string const name = "log"; + +std::string const& getName() { + return name; +} + +double calc(std::vector const &x) { + if (x[0] < 0.0) { + throw CalcException("CalcError", "\"log\" argument must be more than 0"); + } + return static_cast(std::log(static_cast(x[0]))); +} + +Tok::TokenType getType() { + return Tok::TokenType::PREFIX_OPERATOR; +} + +uint8_t getPriorityLevel() { + return DEFAULT_FUNCTION_PRIORITY; +} \ No newline at end of file diff --git a/lab1/dll_plugins/source/pow.cpp b/lab1/dll_plugins/source/pow.cpp new file mode 100644 index 0000000..166a098 --- /dev/null +++ b/lab1/dll_plugins/source/pow.cpp @@ -0,0 +1,24 @@ +#include "export.hpp" + +#include +#include + +std::string const name = "^"; + +std::string const& getName() { + return name; +} + +double calc(std::vector const &x) { + if (x[0] < 0.0 && std::abs(static_cast(x[1]) - x[1]) > 0.0) + throw CalcException("CalcError", "Exponentiation of a negative number"); + return std::pow(x[0], x[1]); +} + +Tok::TokenType getType() { + return Tok::TokenType::SUFFIX_OPERATOR; +} + +uint8_t getPriorityLevel() { + return MIN_SUFFIX_OPERATORS_PRIORITY + 3; +} \ No newline at end of file diff --git a/lab1/dll_plugins/source/sin.cpp b/lab1/dll_plugins/source/sin.cpp new file mode 100644 index 0000000..7037170 --- /dev/null +++ b/lab1/dll_plugins/source/sin.cpp @@ -0,0 +1,22 @@ +#include "export.hpp" + +#include +#include + +std::string const name = "sin"; + +std::string const& getName() { + return name; +} + +double calc(std::vector const &x) { + return static_cast(std::sin(static_cast(x[0]))); +} + +Tok::TokenType getType() { + return Tok::TokenType::PREFIX_OPERATOR; +} + +uint8_t getPriorityLevel() { + return DEFAULT_FUNCTION_PRIORITY; +} \ No newline at end of file diff --git a/lab1/dll_plugins/source/sqrt.cpp b/lab1/dll_plugins/source/sqrt.cpp new file mode 100644 index 0000000..12b95f1 --- /dev/null +++ b/lab1/dll_plugins/source/sqrt.cpp @@ -0,0 +1,26 @@ +#include "export.hpp" + +#include +#include + + +std::string const name = "sqrt"; + +std::string const& getName() { + return name; +} + +double calc(std::vector const &x) { + if (x[0] < 0.0) { + throw CalcException("CalcError", "\"sqrt\" argument must be more than 0"); + } + return static_cast(std::sqrt(static_cast(x[0]))); +} + +Tok::TokenType getType() { + return Tok::TokenType::PREFIX_OPERATOR; +} + +uint8_t getPriorityLevel() { + return DEFAULT_FUNCTION_PRIORITY; +} \ No newline at end of file diff --git a/lab1/out/plugins/cos.dll b/lab1/out/plugins/cos.dll new file mode 100644 index 0000000..1c35a27 Binary files /dev/null and b/lab1/out/plugins/cos.dll differ diff --git a/lab1/out/plugins/log.dll b/lab1/out/plugins/log.dll new file mode 100644 index 0000000..0203f34 Binary files /dev/null and b/lab1/out/plugins/log.dll differ diff --git a/lab1/out/plugins/pow.dll b/lab1/out/plugins/pow.dll new file mode 100644 index 0000000..98d9af8 Binary files /dev/null and b/lab1/out/plugins/pow.dll differ diff --git a/lab1/out/plugins/sin.dll b/lab1/out/plugins/sin.dll new file mode 100644 index 0000000..4bc666e Binary files /dev/null and b/lab1/out/plugins/sin.dll differ diff --git a/lab1/out/plugins/sqrt.dll b/lab1/out/plugins/sqrt.dll new file mode 100644 index 0000000..d0bd046 Binary files /dev/null and b/lab1/out/plugins/sqrt.dll differ diff --git a/lab1/token_default_classes/ComputableOperator.hpp b/lab1/token_default_classes/ComputableOperator.hpp new file mode 100644 index 0000000..72a077c --- /dev/null +++ b/lab1/token_default_classes/ComputableOperator.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +#include "Operator.hpp" +#include "Operands.hpp" + + +namespace Tok { + + class ComputableOperator : public Operator { + private: + std::function const &)> calcFunc; + protected: + virtual std::vector getNumbers(std::stack &numStack) = 0; + + public: + explicit ComputableOperator(std::string const &name, std::uint8_t const priorityLevel, + std::function const &)> &calcFunc) + : Operator(name, priorityLevel), calcFunc(calcFunc) {} + + void doCalc(std::stack &numStack) { + numStack.push(std::make_shared(calcFunc(getNumbers(numStack)))); + } + }; + + + using ComputableOperatorPtr = std::shared_ptr; + +} \ No newline at end of file diff --git a/lab1/token_default_classes/DefaultPriorityRanges.hpp b/lab1/token_default_classes/DefaultPriorityRanges.hpp new file mode 100644 index 0000000..a6a0328 --- /dev/null +++ b/lab1/token_default_classes/DefaultPriorityRanges.hpp @@ -0,0 +1,10 @@ +#pragma once + +#define OPENING_PARENTHESIS_PRIORITY 0 +#define CLOSING_PARENTHESIS_PRIORITY 1 + +#define MIN_SUFFIX_OPERATORS_PRIORITY 4 + +#define DEFAULT_FUNCTION_PRIORITY 11 +#define DEFAULT_PREFIX_OPERATOR_PRIORITY 11 +#define DEFAULT_POSTFIX_OPERATOR_PRIORITY 15 \ No newline at end of file diff --git a/lab1/token_default_classes/Function.hpp b/lab1/token_default_classes/Function.hpp new file mode 100644 index 0000000..ce16894 --- /dev/null +++ b/lab1/token_default_classes/Function.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "PrefixOperator.hpp" + + +namespace Tok { + + class Function : public PrefixOperator { + public: + explicit Function(std::string const &name, std::function const &)>& calcFunc) + : PrefixOperator(name, DEFAULT_FUNCTION_PRIORITY, calcFunc) {} + }; + +} \ No newline at end of file diff --git a/lab1/token_default_classes/Operand.hpp b/lab1/token_default_classes/Operand.hpp new file mode 100644 index 0000000..1180935 --- /dev/null +++ b/lab1/token_default_classes/Operand.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "Token.hpp" + + +namespace Tok { + + class Operand : public Token { + public: + [[nodiscard]] TokenType getType() const override { return TokenType::OPERAND; } + + [[nodiscard]] virtual double getValue() const = 0; + }; + + using OperandPtr = std::shared_ptr; + +} \ No newline at end of file diff --git a/lab1/token_default_classes/Operands.hpp b/lab1/token_default_classes/Operands.hpp new file mode 100644 index 0000000..41b0a42 --- /dev/null +++ b/lab1/token_default_classes/Operands.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "Operand.hpp" + + +namespace Tok { + + class Number : public Operand { + double const value; + public: + explicit Number(double const value) : value(value) {} + + [[nodiscard]] double getValue() const override { return value; } + }; + + + class Variable : public Operand { + std::string const name; + std::shared_ptr cachedValue; + public: + explicit Variable(std::string const &name) : name(name) {} + + explicit Variable(std::string &&name) : name(name) {} + + [[nodiscard]] double getValue() const override { return *cachedValue; } + }; + +} \ No newline at end of file diff --git a/lab1/token_default_classes/Operator.hpp b/lab1/token_default_classes/Operator.hpp new file mode 100644 index 0000000..ab4d807 --- /dev/null +++ b/lab1/token_default_classes/Operator.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include "Token.hpp" + + +namespace Tok { + + class Operator : public Token { + protected: + std::string const name; + std::uint8_t priorityLevel; + + explicit Operator(std::string const &name, std::uint8_t const priorityLevel) + : name(name), priorityLevel(priorityLevel) {} + + public: + auto operator<=>(Operator const &op) const { + return priorityLevel <=> op.priorityLevel; + } + + [[nodiscard]] std::string const &getName() const { return name; } + }; + + + using OperatorPtr = std::shared_ptr; + +} \ No newline at end of file diff --git a/lab1/token_default_classes/Parenthesis.hpp b/lab1/token_default_classes/Parenthesis.hpp new file mode 100644 index 0000000..162d086 --- /dev/null +++ b/lab1/token_default_classes/Parenthesis.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "Operator.hpp" + + +namespace Tok { + + class OpeningParenthesis : public Operator { + public: + OpeningParenthesis() : Operator("(", OPENING_PARENTHESIS_PRIORITY) {} + + [[nodiscard]] TokenType getType() const final { return TokenType::OPENING_PARENTHESIS; } + }; + + + class ClosingParenthesis : public Operator { + public: + ClosingParenthesis() : Operator(")", CLOSING_PARENTHESIS_PRIORITY) {} + + [[nodiscard]] TokenType getType() const final { return TokenType::CLOSING_PARENTHESIS; } + }; + +} \ No newline at end of file diff --git a/lab1/token_default_classes/PostfixOperator.hpp b/lab1/token_default_classes/PostfixOperator.hpp new file mode 100644 index 0000000..7e8512e --- /dev/null +++ b/lab1/token_default_classes/PostfixOperator.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "PrefixOperator.hpp" + + +namespace Tok { + + class PostfixOperator : public PrefixOperator { + public: + explicit PostfixOperator(std::string const &name, std::uint8_t const priorityLevel, + std::function const &)> calcFunc) + : PrefixOperator(name, priorityLevel, calcFunc) {} + + [[nodiscard]] TokenType getType() const override { return TokenType::POSTFIX_OPERATOR; } + }; + +} \ No newline at end of file diff --git a/lab1/token_default_classes/PrefixOperator.hpp b/lab1/token_default_classes/PrefixOperator.hpp new file mode 100644 index 0000000..2fc8e23 --- /dev/null +++ b/lab1/token_default_classes/PrefixOperator.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "ComputableOperator.hpp" +#include "CalcException.hpp" + + +namespace Tok { + + class PrefixOperator : public ComputableOperator { + protected: + std::vector getNumbers(std::stack &numStack) override { + if (numStack.size() < 1ull) + throw CalcException("CalcMultiplyError", "Unexpected end of expression"); + + auto value = numStack.top(); + numStack.pop(); + + return {value->getValue()}; + } + + public: + explicit PrefixOperator(std::string const &name, std::uint8_t const priorityLevel, + std::function const &)> calcFunc) + : ComputableOperator(name, priorityLevel, calcFunc) {} + + [[nodiscard]] TokenType getType() const override { return TokenType::PREFIX_OPERATOR; } + }; + +} diff --git a/lab1/token_default_classes/SuffixOperator.hpp b/lab1/token_default_classes/SuffixOperator.hpp new file mode 100644 index 0000000..7439d78 --- /dev/null +++ b/lab1/token_default_classes/SuffixOperator.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include "ComputableOperator.hpp" +#include "CalcException.hpp" + + +namespace Tok { + + class SuffixOperator : public ComputableOperator { + protected: + std::vector getNumbers(std::stack &numStack) override { + if (numStack.size() < 2ull) + throw CalcException("CalcMultiplyError", "Unexpected end of expression"); + + auto rightValue = numStack.top(); + numStack.pop(); + auto leftValue = numStack.top(); + numStack.pop(); + + return {leftValue->getValue(), rightValue->getValue()}; + } + + public: + explicit SuffixOperator(std::string const &name, std::uint8_t const priorityLevel, + std::function const &)> calcFunc) + : ComputableOperator(name, priorityLevel, calcFunc) {} + + [[nodiscard]] TokenType getType() const override { return TokenType::SUFFIX_OPERATOR; } + }; + +} diff --git a/lab1/token_default_classes/Token.hpp b/lab1/token_default_classes/Token.hpp new file mode 100644 index 0000000..f6cbd4d --- /dev/null +++ b/lab1/token_default_classes/Token.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "DefaultPriorityRanges.hpp" + +namespace Tok { + + enum TokenType { + SUFFIX_OPERATOR = 0, + PREFIX_OPERATOR, + POSTFIX_OPERATOR, + OPERAND, + OPENING_PARENTHESIS, + CLOSING_PARENTHESIS + }; + + class Token { + public: + [[nodiscard]] virtual TokenType getType() const = 0; + + virtual ~Token() = default; + }; + + using TokenPtr = std::shared_ptr; + +} \ No newline at end of file