Add files via upload
This commit is contained in:
parent
06c9c3c857
commit
70fcce6d11
35
Console.cpp
Normal file
35
Console.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "Console.hpp"
|
||||
#include "Interpreter.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
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;
|
||||
}
|
30
Console.hpp
Normal file
30
Console.hpp
Normal file
|
@ -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();
|
||||
};
|
||||
|
18
Error.hpp
Normal file
18
Error.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include <iostream>
|
||||
|
||||
#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
|
242
Interpreter.cpp
Normal file
242
Interpreter.cpp
Normal file
|
@ -0,0 +1,242 @@
|
|||
#include "Interpreter.hpp"
|
||||
#include "Error.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
double Interpreter::result = 0;
|
||||
bool Interpreter::justNumber = false;
|
||||
std::string Interpreter::numbers = "0123456789Aa.,";
|
||||
std::string Interpreter::operators = "+-*/^_";
|
||||
std::string Interpreter::string = "";
|
||||
std::map<char, unsigned int> 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<Symbol*> symbols;
|
||||
if (!createSymbolList(symbols)) {
|
||||
SYMBOL_LIST_ERROR;
|
||||
}
|
||||
|
||||
if (justNumber)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<NonChar*> tokens;
|
||||
if (!createOrderedTokenList(symbols, tokens)) {
|
||||
TOKEN_LIST_ERROR;
|
||||
}
|
||||
|
||||
result = tokens[tokens.size() - 1]->value();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Interpreter::createSymbolList(std::vector<Symbol*>& 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<Symbol*> symbols, std::vector<NonChar*>& 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;
|
||||
}
|
28
Interpreter.hpp
Normal file
28
Interpreter.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "Token.hpp"
|
||||
|
||||
class Interpreter
|
||||
{
|
||||
public:
|
||||
static double interpret(char* _string);
|
||||
|
||||
private:
|
||||
static bool scanForErrors();
|
||||
static bool getResult();
|
||||
|
||||
static bool createSymbolList(std::vector<Symbol*>& symbols);
|
||||
static bool createOrderedTokenList(std::vector<Symbol*> symbols, std::vector<NonChar*>& tokens);
|
||||
|
||||
static std::string string;
|
||||
static std::string numbers;
|
||||
static std::string operators;
|
||||
static std::map<char, unsigned int> operation_order;
|
||||
|
||||
static double result;
|
||||
static bool justNumber;
|
||||
};
|
||||
|
161
Token.hpp
Normal file
161
Token.hpp
Normal file
|
@ -0,0 +1,161 @@
|
|||
#pragma once
|
||||
#include <math.h>
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/// \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);
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue