diff --git a/Calculator_main/Calculator_main/CMakeLists.txt b/Calculator_main/Calculator_main/CMakeLists.txt new file mode 100644 index 0000000..534b484 --- /dev/null +++ b/Calculator_main/Calculator_main/CMakeLists.txt @@ -0,0 +1,12 @@ +# CMakeList.txt : CMake project for Calculator_main_v.f, include source and define +# project specific logic here. +# +cmake_minimum_required (VERSION 3.8) + +project( Calculator_main) +set(CMAKE_CXX_STANDARD 20) +# Add source to this project's executable. + +set(PROJECT_HEADERS Calculator_main.h, calcul.h) +add_executable(Calculator_main ${PROJECT_SOURCE_DIR}/ Calculator_main.cpp calcul.cpp "dll_read.cpp" "dll_read.h") + diff --git a/Calculator_main/Calculator_main/Calculator_main.cpp b/Calculator_main/Calculator_main/Calculator_main.cpp new file mode 100644 index 0000000..f3f5742 --- /dev/null +++ b/Calculator_main/Calculator_main/Calculator_main.cpp @@ -0,0 +1,33 @@ +// Calculator_main.cpp : Defines the entry point for the application. +// + +#include "Calculator_main.h" + +// Calculator_main_v.f.cpp : Defines the entry point for the application. +// +#include +#include "calcul.h" + +void main() +{ + std::cout << "This is a calculator" << std::endl; + std::cout << "Standart operations: +, -, *, /, ^, ()" << std::endl; + std::cout << "Non-standart mathematical operations: cos lg sin tg ctg ln sqrt cubsqrt abs round" << std::endl; + std::cout << "cubsqrt - counts the cubic root" << std::endl; + std::cout << "round - rounds to the largest integer, but not more than this number" << std::endl; + std::cout << "To complete the work enter #" << std::endl << std::endl; + + calcul cal; + cal.validation(); + std::cout << "Enter the expression: "; + char c; + while (c = std::cin.peek()) + { + if (c == '#') break;//interrupting the recording cycle + cal.readthread(); + cal.maths(); + std::cin.ignore();//extracting a scanned character for a common expression from a stream + std::cout << std::endl << "Enter the expression: "; + } + +} diff --git a/Calculator_main/Calculator_main/Calculator_main.h b/Calculator_main/Calculator_main/Calculator_main.h new file mode 100644 index 0000000..31a6fb2 --- /dev/null +++ b/Calculator_main/Calculator_main/Calculator_main.h @@ -0,0 +1,8 @@ +// Calculator_main.h : Include file for standard system include files, +// or project specific include files. + +#pragma once + +#include + +// TODO: Reference additional headers your program requires here. diff --git a/Calculator_main/Calculator_main/calcul.cpp b/Calculator_main/Calculator_main/calcul.cpp new file mode 100644 index 0000000..eacd678 --- /dev/null +++ b/Calculator_main/Calculator_main/calcul.cpp @@ -0,0 +1,281 @@ +#include "calcul.h" + +calcul::calcul() +{ + oper_priority = { + {"+",1}, + {"-",1}, + {"*",2}, + {"/",2}, + {"^",3} + }; + function.insert( + { "+", + [&](double a,double b) {double c = a + b; number.push(c); }//put the result into the stack of numbers + } + ); + function.insert( + { "-", + [&](double a,double b) + {double c = b - a;//change order because the stack order is different from the initial order in the console + number.push(c); + }//put the result into the stack of numbers + } + ); + function.insert( + { "*", + [&](double a,double b) {double c = a * b; number.push(c); }//put the result into the stack of numbers + } + ); + function.insert( + { "/", + [&](double a,double b) { + if (a == 0) + { + std::cout << "Error. You can't divide by zero" << std::endl; + //In order not to continue processing operations, we clear stacks of numbers and operations + deleteStacksEr(); + return; + } + double c = b / a;//change order because the stack order is different from the initial order in the console + number.push(c);//put the result into the stack of numbers + } + } + ); + function.insert( + { + "^", + [&](double a,double b) {double c = pow(b,a);//change order because the stack order is different from the initial order in the console + number.push(c); } + }); +} + +void calcul::validation() +{ + //exception handling + try + { + dll.read_files(); + } + catch (std::exception) + { + std::cout << "Error in dll" << std::endl; + } +} + +template //template, because we have two stacks of different types +void calcul::clearStack(std::stack & s) +{ + while (s.size() != 0) { + s.pop(); + } + return; +} + +void calcul::readthread() +{ + char c; + while (c = std::cin.peek()) + { + if (c == '\n') break; + if (c == ' ') + { + std::cin.ignore(); + continue; + }; + if (((c >= '0') && (c <= '9')) || check_neg(c))//number 0 to 9 + negative number check + { + is_number(c); + continue; + } + if ((c == '+') || (c == '-') || (c == '/') || (c == '*') || (c == '(') || (c == '^'))//checking if the function is standard + { + is_standart(c); + continue; + } + if (isalpha(c))//checking whether the function is non-standard (determines the first character of a non-standard operation and reads it before the opening parenthesis, + // if a non-standard function was read, it will be found out later when checking) + { + if (!is_nonstandart(c)) break; + continue; + } + if (c == ')') + { + if (!is_brecket(c)) break; + continue; + } + //caught an incorrect character + deleteStacksEr(); + break; + } +} + + +void calcul::is_number(char c) +{ + double value; + std::cin >> value;//extracting a number from the stream + number.push(value); +} +void calcul::is_standart(char c) +{ + std::string s; + std::stringstream ss; + ss << c; + ss >> s; + processing_oper(s); + if ((number.size() != 0) || (operation.size() != 0)) std::cin.ignore();//extracting the viewed symbol from the stream +} +bool calcul::is_nonstandart(char c) +{ + std::string nstand; + while (c != '(') { + if (std::isupper(c)) c=(char)std::tolower(c); + nstand.push_back(c); + std::cin.ignore(); + c = std::cin.peek(); + if ((c == ')') || (c == '\n')) break;//the expression was entered incorrectly + } + if ((c == ')') || (c == '\n')) + { + deleteStacksEr(); + return false; + } + operation.push(nstand); + return true; +} +bool calcul::is_brecket(char c) +{ + while (operation.top() != "(")//we perform operations in parentheses + { + if (function.find(operation.top()) != function.end()) + { + oper(); + if (operation.size() == 0) break;//if there was a division by 0, then the stacks became empty and it is necessary to stop the cycle + continue; + } + expr_incor(); + break; + } + if (number.size() != 0) std::cin.ignore();//extracting the scanned symbol from the stream, provided that there was no stack clearing due to an incorrect expression + if (operation.size() != 0) + { + operation.pop();//if there was no division by zero, then the opening bracket remains in the stack and it must be removed from the stack + if (nonstandart() == -1)//checking that a non-standard function is valid + { + deleteStacksEr(); + return false; + } + } + return true; +} + +void calcul::expr_incor() +{ + std::cout << "Expression entered incorrectly" << std::endl; + clearStack(operation); + clearStack(number); +} + +void calcul::deleteStacksEr() +{ + std::string s; + std::getline(std::cin, s, '\n'); + expr_incor(); + std::cout << "To continue, press Enter" << std::endl; +} + +void calcul::processing_oper(std::string c)//processing of the received options +{ + if ((operation.empty()) || (c == "("))//in any case, the opening bracket is either at the beginning of the stack, or we put it on the stack on top of other operations + { + operation.push(c); + return; + } + + if (oper_priority[c] <= oper_priority[operation.top()]) + //if the operation in question has a priority less than or equal to the operation already lying on the stack, then first we will count the operation that is on the stack, and then we will add a new one + { + oper(); + if (number.size() != 0) operation.push(c);//check if the stack is not cleared after dividing by 0 + return; + } + //the stack with operations is not empty and the priority of the operation in question is not less than the one already placed on the stack + operation.push(c); + return; +} + +bool calcul::check_neg(char c)//processing negative numbers if it is the first number in the expression or comes after the opening parenthesis +{ + if (c == '-') + { + if (number.size() == 0) + return true; + if (operation.size() != 0) + { + if ((operation.top() == "(") && (operation.size() > number.size()))//when '-' is immediately after the parentheses, the number of operations exceeds the number of numbers read + return true; + } + return false;//c='-' but none of the conditions are met + } + return false; +} + +void calcul::maths()//to process all raw operations with numbers +{ + while (operation.size() != 0) + { + if (function.find(operation.top()) != function.end()) + { + oper(); + continue; + } + //there is no processing of functions from plugins as we consider them as soon as we met, + //so that complex expressions using non-standard functions can be correctly calculated + expr_incor(); + break; + } + if (number.size() != 0) + { + std::cout << "Result=" << number.top() << std::endl; + number.pop();//deleting the last number in the stack (result) + } +} + +int calcul::nonstandart() +{ + if (!operation.empty()) + { + if (dll.is_plugin(operation.top())) + { + double a = number.top(); + number.pop(); + if (!dll.calculation(operation.top(), a)) return -1; + number.push(a); + operation.pop(); + return 1; + } + } + return 0; +} + +void calcul::oper()//handles only one standard operation with numbers +{ + double a, b; + a = number.top();//took the top number from the stack + number.pop();//removed the taken number from the stack + b = number.top();//took the top number from the stack + number.pop();//removed the taken number from the stack + + //taking an operation from the stack with operations + function[operation.top()](a, b); + if (operation.size() != 0) operation.pop();//we remove the operation from the stack, provided that it is not empty, after an attempt to divide by 0 +} + +calcul::~calcul() +{ + clearStack(operation);//clearing the stack with operations + clearStack(number);//clearing the stack with numbers + function.clear();//clearing the map with operations + oper_priority.clear();//clearing the map with priorities +} \ No newline at end of file diff --git a/Calculator_main/Calculator_main/calcul.h b/Calculator_main/Calculator_main/calcul.h new file mode 100644 index 0000000..f783e7b --- /dev/null +++ b/Calculator_main/Calculator_main/calcul.h @@ -0,0 +1,45 @@ +#pragma once +#ifndef calcul_h +#define calcul_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dll_read.h" + + +class calcul +{ +private: + std::stack number; + std::stack operation; + std::map oper_priority;//mathematical operations priorities + std::map > function;//correlation of a mathematical operation and what it does + dll_read dll; + bool check_neg(char c);//checking whether the number is negative + void is_number(char c);//checking whether a number is + void is_standart(char c);//checking whether it is a standard operation + bool is_nonstandart(char c);//checking whether it is a non-standard operation + bool is_brecket(char c);//checking whether the bracket is closing + void oper();//processing of a single mathematical operation + int nonstandart();//working with non-standard functions + void deleteStacksEr();//clearing stacks if an error occurred when evaluating an expression (exception handling) + void processing_oper(std::string c);//processing of mathematical operations, namely checking for the emptiness of the stack and the priority of the mathematical operation + void expr_incor();//clearing stacks when an expression is entered incorrectly + template + void clearStack(std::stack & s); + +public: + calcul(); + void validation();//checking exceptions from dynamic libraries + void readthread();//reading an expression from a stream + void maths();//perform mathematical operations and is responsible for the output of the result to the console + ~calcul(); +}; +#endif \ No newline at end of file diff --git a/Calculator_main/Calculator_main/dll_read.cpp b/Calculator_main/Calculator_main/dll_read.cpp new file mode 100644 index 0000000..dd6af54 --- /dev/null +++ b/Calculator_main/Calculator_main/dll_read.cpp @@ -0,0 +1,36 @@ +#include "dll_read.h" + + +void dll_read::read_files() { + WIN32_FIND_DATAA detect; + HANDLE det = FindFirstFileA((p + std::string("*.dll")).c_str(), &detect); + + if (det == INVALID_HANDLE_VALUE) { + throw std::exception();//the library does not exist + return; + } + do { + std::string func_name(detect.cFileName); + HMODULE hm = LoadLibraryA((p + func_name).c_str()); + if (!hm) throw std::exception();//the problem is loading the library + + std::string funct = func_name.substr(0, func_name.find(".dll")); + + auto func = (bool (*) (double&))GetProcAddress(hm, "func"); + + if (func) { + function.insert(std::pair(funct, func)); + continue; + } + throw std::exception();//error in extracting the function address + } while (FindNextFileA(det, &detect) != NULL); +} + + +bool dll_read::calculation(std::string s, double& num) { + return(function[s](num)); +} + +bool dll_read::is_plugin(std::string str) { + return(function.find(str) != function.end()); +} \ No newline at end of file diff --git a/Calculator_main/Calculator_main/dll_read.h b/Calculator_main/Calculator_main/dll_read.h new file mode 100644 index 0000000..e62b8a9 --- /dev/null +++ b/Calculator_main/Calculator_main/dll_read.h @@ -0,0 +1,26 @@ +#pragma once +#ifndef dll_read_h +#define dll_read_h + +#include +#include +#include +#include +#include + + +class dll_read +{ +private: + std::map > function; + std::string p = ".\\plugins\\"; + +public: + dll_read() {}; + void read_files(); + bool is_plugin(std::string s); + bool calculation(std::string s, double& number); + ~dll_read() { function.clear(); }; +}; + +#endif \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/abs.cpp b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/abs.cpp new file mode 100644 index 0000000..9d5325e --- /dev/null +++ b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/abs.cpp @@ -0,0 +1,7 @@ +#include +extern "C" __declspec(dllexport) + +bool func(double& number) { + number = std::abs(number); + return true; +} \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/abs.dll b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/abs.dll new file mode 100644 index 0000000..77e4946 Binary files /dev/null and b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/abs.dll differ diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cos.cpp b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cos.cpp new file mode 100644 index 0000000..4fb6b6b --- /dev/null +++ b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cos.cpp @@ -0,0 +1,15 @@ +#include +#define _USE_MATH_DEFINES +#define pi 3.14159265358979323846 +extern "C" __declspec(dllexport) + +bool func(double& number) { + double d=number; + number=std::cos(number*pi/180); + if (abs(sin(d * pi / 180)) == 1) + { + number=0;// angle= pi/2, 3*pi/2.. + } + + return true; +} \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cos.dll b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cos.dll new file mode 100644 index 0000000..0f8f90e Binary files /dev/null and b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cos.dll differ diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ctg.cpp b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ctg.cpp new file mode 100644 index 0000000..9774097 --- /dev/null +++ b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ctg.cpp @@ -0,0 +1,17 @@ +#include +#include +#define _USE_MATH_DEFINES +#define pi 3.14159265358979323846 +extern "C" __declspec(dllexport) + +bool func(double& number) { + if (abs(cos(number * pi / 180)) == 1)//in this case sin=0 + { + std::cout << "The cotangent from 0 does not exist" << std::endl; + return false; + } + double d=number; + number = std::cos(number * pi / 180) / std::sin(number * pi / 180); + if (abs(sin(d * pi / 180)) == 1) number=0; + return true; +} \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ctg.dll b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ctg.dll new file mode 100644 index 0000000..8ef7f2d Binary files /dev/null and b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ctg.dll differ diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cubsqrt.cpp b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cubsqrt.cpp new file mode 100644 index 0000000..69c198c --- /dev/null +++ b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cubsqrt.cpp @@ -0,0 +1,8 @@ +#include +#include +extern "C" __declspec(dllexport) + +bool func(double& number) { + number=std::cbrt(number); + return true; +} \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cubsqrt.dll b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cubsqrt.dll new file mode 100644 index 0000000..0ad28bf Binary files /dev/null and b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/cubsqrt.dll differ diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/lg.cpp b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/lg.cpp new file mode 100644 index 0000000..96f5916 --- /dev/null +++ b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/lg.cpp @@ -0,0 +1,13 @@ +#include +#include +extern "C" __declspec(dllexport) + +bool func(double& number) { + if (number <= 0) + { + std::cout << "The logarithm of a non-positive number does not exist" << std::endl; + return false; + } + number=std::log10(number); + return true; +} \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/lg.dll b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/lg.dll new file mode 100644 index 0000000..87c4b55 Binary files /dev/null and b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/lg.dll differ diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ln.cpp b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ln.cpp new file mode 100644 index 0000000..6311159 --- /dev/null +++ b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ln.cpp @@ -0,0 +1,13 @@ +#include +#include +extern "C" __declspec(dllexport) + +bool func(double& number) { + if (number <= 0) + { + std::cout << "The logarithm of a non-positive number does not exist" << std::endl; + return false; + } + number = std::log(number); + return true; +} \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ln.dll b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ln.dll new file mode 100644 index 0000000..600385e Binary files /dev/null and b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/ln.dll differ diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/round.cpp b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/round.cpp new file mode 100644 index 0000000..627f8c3 --- /dev/null +++ b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/round.cpp @@ -0,0 +1,7 @@ +#include +extern "C" __declspec(dllexport) + +bool func(double& number) { + number=std::floor(number); + return true; +} \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/round.dll b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/round.dll new file mode 100644 index 0000000..2518f2d Binary files /dev/null and b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/round.dll differ diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/sin.cpp b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/sin.cpp new file mode 100644 index 0000000..bf7a374 --- /dev/null +++ b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/sin.cpp @@ -0,0 +1,14 @@ +#include +#define _USE_MATH_DEFINES +#define pi 3.14159265358979323846 +extern "C" __declspec(dllexport) + +bool func(double& number) { + double d=number; + number=std::sin(number*pi/180); + if (abs(cos(d * pi / 180)) == 1) + { + number=0;// angle=0,pi; 2*pi.. + } + return true; +} \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/sin.dll b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/sin.dll new file mode 100644 index 0000000..83a7872 Binary files /dev/null and b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/sin.dll differ diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/sqrt.cpp b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/sqrt.cpp new file mode 100644 index 0000000..402728e --- /dev/null +++ b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/sqrt.cpp @@ -0,0 +1,13 @@ +#include +#include +extern "C" __declspec(dllexport) + +bool func(double& number) { + if (number<0) + { + std::cout<<"there is no square root of a negative number"< +#include +#define _USE_MATH_DEFINES +#define pi 3.14159265358979323846 +extern "C" __declspec(dllexport) + +bool func(double& number) { + + if (abs(sin(number * pi / 180)) == 1)//in this case cos=0 + { + std::cout << "The tangent from 90 does not exist" << std::endl; + return false; + } + double d=number; + number = std::sin(number * pi / 180) / std::cos(number * pi / 180); + if (abs(cos(d * pi / 180)) == 1) + { + number = 0; + } + return true; +} \ No newline at end of file diff --git a/Calculator_main/out/build/x64-debug/Calculator_main/plugins/tg.dll b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/tg.dll new file mode 100644 index 0000000..8b2e6ca Binary files /dev/null and b/Calculator_main/out/build/x64-debug/Calculator_main/plugins/tg.dll differ