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