diff --git a/CAS.exe b/CAS.exe new file mode 100644 index 0000000..ac2aa94 Binary files /dev/null and b/CAS.exe differ diff --git a/Console.cpp b/Console.cpp new file mode 100644 index 0000000..5dbdb66 --- /dev/null +++ b/Console.cpp @@ -0,0 +1,35 @@ +#include "Console.hpp" +#include "Interpreter.hpp" + +#include +#include + +char* Console::input = new char[INPUT_BUFFER_SIZE]; + + +void Console::run() +{ + while (true) // Main loop, runs until process is terminated + { + awaitInput(); // Waits for input + handleInput(); // Handles input + } + + delete[] input; // After process is terminated, release the pointer +} + + + +void Console::awaitInput() +{ + std::cout << ">>>"; + std::cin >> std::setw(INPUT_BUFFER_SIZE) >> input; // Await input +} + + + +void Console::handleInput() +{ + double result = Interpreter::interpret(input); + std::cout << result << std::endl << std::endl; +} diff --git a/Console.hpp b/Console.hpp new file mode 100644 index 0000000..3ac54b5 --- /dev/null +++ b/Console.hpp @@ -0,0 +1,30 @@ +#pragma once + +const constexpr unsigned int INPUT_BUFFER_SIZE = 256; + +class Console +{ +public: + /////////////////////////////////////////////////////////// + /// \brief Calls every important process functions + /// + /////////////////////////////////////////////////////////// + static void run(); + +private: + static char* input; + + /////////////////////////////////////////////////////////// + /// \brief Waits for user input and writes it into a variable + /// + /////////////////////////////////////////////////////////// + static void awaitInput(); + + + /////////////////////////////////////////////////////////// + /// \brief Takes input and manages it + /// + /////////////////////////////////////////////////////////// + static void handleInput(); +}; + diff --git a/Error.hpp b/Error.hpp new file mode 100644 index 0000000..0c1c596 --- /dev/null +++ b/Error.hpp @@ -0,0 +1,18 @@ +#pragma once +#include + +#define INTERPRETER_ERROR std::cout << "+++ INTERPRETER: " +#define INTEGER_ERROR std::cout << "+++ INTEGER: " +#define MATHEMATICAL_ERROR std::cout << "+++ MATH: " + +#define UNKNOWN_CHAR_ERROR(x) INTERPRETER_ERROR << "Unknown character <" << (x) << "> found in string +++" << std::endl; return false +#define SYMBOL_LIST_ERROR INTERPRETER_ERROR << "Failed to create Symbol list +++" << std::endl; return false +#define TOKEN_LIST_ERROR INTERPRETER_ERROR << "Failed to create Token list +++" << std::endl; return false +#define TOO_MANY_OPERATORS INTERPRETER_ERROR << "Found multiple operators in sequence +++" << std::endl; return false +#define ILLEGAL_OPERATOR_POSITION INTERPRETER_ERROR << "An operator was found in an illegal position +++" << std::endl; return false + +#define INTEGER_TOO_BIG(x) INTEGER_ERROR << "Integer <" << (x) << "> cannot be converted to int +++" << std::endl; return false; +#define ENDS_ON_DECIMAL_POINT INTEGER_ERROR << "Integers cannot end with a decimal point +++" << std::endl; return false + +#define DIVIDE_BY_ZERO MATHEMATICAL_ERROR << "Division by zero +++" << std::endl; return false +#define IMAGINARY_NUMBERS MATHEMATICAL_ERROR << "Imaginary numbers are not supported +++" << std::endl; return false \ No newline at end of file diff --git a/Interpreter.cpp b/Interpreter.cpp new file mode 100644 index 0000000..a4f6318 --- /dev/null +++ b/Interpreter.cpp @@ -0,0 +1,242 @@ +#include "Interpreter.hpp" +#include "Error.hpp" + +#include + +double Interpreter::result = 0; +bool Interpreter::justNumber = false; +std::string Interpreter::numbers = "0123456789Aa.,"; +std::string Interpreter::operators = "+-*/^_"; +std::string Interpreter::string = ""; +std::map Interpreter::operation_order = { + {'+', 0}, + {'-', 0}, + {'*', 1}, + {'/', 1}, + {'^', 2}, + {'_', 2} +}; + +double Interpreter::interpret(char * _string) +{ + string = _string; + justNumber = false; + + if (!scanForErrors()) + return NULL; + + if (!getResult()) + return NULL; + + if (justNumber) + { + return result; + } + + return result; +} + + +bool Interpreter::scanForErrors() +{ + for (char c : string) + { + if (std::find(std::begin(numbers), std::end(numbers), c) == std::end(numbers) && + std::find(std::begin(operators), std::end(operators), c) == std::end(operators)) + { + UNKNOWN_CHAR_ERROR(c); + } + } + + return true; +} + +bool Interpreter::getResult() +{ + std::vector symbols; + if (!createSymbolList(symbols)) { + SYMBOL_LIST_ERROR; + } + + if (justNumber) + { + return true; + } + + std::vector tokens; + if (!createOrderedTokenList(symbols, tokens)) { + TOKEN_LIST_ERROR; + } + + result = tokens[tokens.size() - 1]->value(); + + return true; +} + +bool Interpreter::createSymbolList(std::vector& symbols) +{ + bool number = false; + bool hasOperator = false; + std::string num = ""; + + for (char c : string) + { + if (std::find(std::begin(numbers), std::end(numbers), c) != std::end(numbers)) + { + if (c == 'A' || c == 'a') + { + //printf("%f", result); + symbols.push_back(new Number(result)); + } + if (c == '.' || c == ',') + { + num += '.'; + } + else + { + num += c; + } + number = true; + } + + if (std::find(std::begin(operators), std::end(operators), c) != std::end(operators)) + { + hasOperator = true; + if (number == true) + { + //std::cout << "++++++++++++" << num << "++++++++++++++" << std::endl; + if (num != "") + { + try + { + if (number == true) symbols.push_back(new Number(std::stod(num))); + } + catch (...) + { + INTEGER_TOO_BIG(num); + } + } + symbols.push_back(new Operator(c)); + number = false; + num = ""; + } + else + { + if (c == '-') + { + number = true; + num += c; + } + else { + TOO_MANY_OPERATORS; + } + } + + } + } + + if (number != true) + { + ILLEGAL_OPERATOR_POSITION; + } + + if (num != "") + { + try + { + if (number == true) symbols.push_back(new Number(std::stod(num))); + } + catch (...) + { + INTEGER_TOO_BIG(num); + } + } + + if (!hasOperator) + { + justNumber = true; + result = symbols[0]->value(); + return true; + } + + return true; +} + +bool Interpreter::createOrderedTokenList(std::vector symbols, std::vector& tokens) +{ + //std::cout << operation_order.find(43)->second << std::endl; + + while (true) + { + int currentOperation = 0; + bool foundOperator = false; + + for (int i = 0; i < symbols.size(); i++) + { + if (!symbols[i]->isNumber()) + { + if (currentOperation == 0) + currentOperation = i; + + foundOperator = true; + if (operation_order.find((char)symbols[i]->value())->second > operation_order.find((char)symbols[currentOperation]->value())->second) + currentOperation = i; + } + } + + if (foundOperator) + { + switch ((int)symbols[currentOperation]->value()) + { + case '+': + tokens.push_back(new AddToken(symbols[currentOperation - 1]->value(), symbols[currentOperation + 1]->value())); + break; + + case '-': + tokens.push_back(new SubToken(symbols[currentOperation - 1]->value(), symbols[currentOperation + 1]->value())); + break; + + case '*': + tokens.push_back(new MulToken(symbols[currentOperation - 1]->value(), symbols[currentOperation + 1]->value())); + break; + + case '/': + if (symbols[currentOperation + 1]->value() == 0) { + DIVIDE_BY_ZERO; + } + tokens.push_back(new DivToken(symbols[currentOperation - 1]->value(), symbols[currentOperation + 1]->value())); + break; + + case '^': + tokens.push_back(new ExpToken(symbols[currentOperation - 1]->value(), symbols[currentOperation + 1]->value())); + break; + + case '_': + if (symbols[currentOperation - 1]->value() == 0) { + DIVIDE_BY_ZERO; + } + if (symbols[currentOperation + 1]->value() < 0) { + IMAGINARY_NUMBERS; + } + + tokens.push_back(new RootToken(symbols[currentOperation - 1]->value(), symbols[currentOperation + 1]->value())); + break; + + default: + + break; + } + + symbols.erase(symbols.begin() + currentOperation + 1); + symbols[currentOperation] = new Number(tokens[tokens.size() - 1]->value()); + symbols.erase(symbols.begin() + currentOperation - 1); + } + else { + break; + } + + foundOperator = false; + } + + return true; +} \ No newline at end of file diff --git a/Interpreter.hpp b/Interpreter.hpp new file mode 100644 index 0000000..d0e52c0 --- /dev/null +++ b/Interpreter.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include + +#include "Token.hpp" + +class Interpreter +{ +public: + static double interpret(char* _string); + +private: + static bool scanForErrors(); + static bool getResult(); + + static bool createSymbolList(std::vector& symbols); + static bool createOrderedTokenList(std::vector symbols, std::vector& tokens); + + static std::string string; + static std::string numbers; + static std::string operators; + static std::map operation_order; + + static double result; + static bool justNumber; +}; + diff --git a/Token.hpp b/Token.hpp new file mode 100644 index 0000000..cb53a13 --- /dev/null +++ b/Token.hpp @@ -0,0 +1,161 @@ +#pragma once +#include + +///////////////////////////////////////////////////// +/// \brief Abstract Token base class +/// +/// A token contains an operation - this means it will +/// hold two numbers, as well as their result after +/// the according operation. +/// +///////////////////////////////////////////////////// + +class Token +{ +public: + virtual bool nonCharToken() = 0; +}; + + + + + + + + +class NonChar : public Token +{ +public: + bool nonCharToken() override { return true; } + double value() { return result; } + +protected: + double a, b, result; +}; + + + +class Symbol : public Token +{ +public: + bool nonCharToken() override { return false; } + virtual bool isNumber() = 0; + virtual double value() = 0; +}; + + + + +class Operator : public Symbol +{ +public: + Operator(char _c) + { + c = _c; + } + + bool isNumber() override { return false; } + double value() { return c; } + +private: + char c; +}; + + +class Number : public Symbol +{ +public: + Number(double _i) + { + i = _i; + } + + bool isNumber() override { return true; } + double value() { return i; } + +private: + double i; +}; + + + + +class AddToken : public NonChar +{ +public: + AddToken(double _a, double _b) + { + a = _a; + b = _b; + + result = a + b; + } +}; + + + +class SubToken : public NonChar +{ +public: + SubToken(double _a, double _b) + { + a = _a; + b = _b; + + result = a - b; + } +}; + + + +class MulToken : public NonChar +{ +public: + MulToken(double _a, double _b) + { + a = _a; + b = _b; + + result = a * b; + } +}; + + +class DivToken : public NonChar +{ +public: + DivToken(double _a, double _b) + { + a = _a; + b = _b; + + result = a / b; + } +}; + + + +class ExpToken : public NonChar +{ +public: + ExpToken(double _a, double _b) + { + a = _a; + b = _b; + + result = pow(a, b); + } +}; + + +class RootToken : public NonChar +{ +public: + RootToken(double _a, double _b) + { + a = _a; + b = _b; + + result = pow(b, 1.0 / a); + } +}; \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..11bd710 --- /dev/null +++ b/main.cpp @@ -0,0 +1,12 @@ +#include "Console.hpp" +#include "Token.hpp" + +#include "Error.hpp" + + +int main() +{ + Console::run(); + + return 0; +} \ No newline at end of file