diff --git a/CMakeLists.txt b/CMakeLists.txt index 95c0dc1..e893a07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.21) # Only set the cxx_standard if it is not set by someone else if (NOT DEFINED CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 98) + set(CMAKE_CXX_STANDARD 11) endif() # strongly encouraged to enable this globally to avoid conflicts between diff --git a/src/infiz/infiz.cpp b/src/infiz/infiz.cpp index 5f14689..dd724fb 100644 --- a/src/infiz/infiz.cpp +++ b/src/infiz/infiz.cpp @@ -1,25 +1,21 @@ // infiz.cpp #include "../libinfiz/Evaluator.hpp" -#include "../libinfiz/RationalNumber.h" -#include "../libinfiz/Stack.h" -#include "../libinfiz/StringTokenizer.h" -#include +#include #include -const int max_line = 255; +constexpr int max_line = 255; int main(int /*argc*/, char * /*args*/[]) { + std::array input{}; - char input[max_line];// NOLINT - - std::cin.getline(static_cast(input), max_line - 1, '\n'); + std::cin.getline(input.data(), max_line - 1, '\n'); while (std::cin.good()) { - StringTokenizer tokenizer(static_cast(input)); - const RationalNumber answer = evaluateExpression(tokenizer); + StringTokenizer tokenizer(input.data()); + const auto answer = evaluateExpression(tokenizer); std::cout << "answer: "; if (answer.getDenominator() == 1) { @@ -28,6 +24,6 @@ int main(int /*argc*/, char * /*args*/[]) std::cout << answer.getNumerator() << '/' << answer.getDenominator() << " (" << answer.getFloat() << ")" << '\n'; } - std::cin.getline(static_cast(input), max_line - 1, '\n'); + std::cin.getline(input.data(), max_line - 1, '\n'); } } diff --git a/src/libinfiz/CMakeLists.txt b/src/libinfiz/CMakeLists.txt index 72f089e..c469312 100644 --- a/src/libinfiz/CMakeLists.txt +++ b/src/libinfiz/CMakeLists.txt @@ -3,7 +3,6 @@ include(GenerateExportHeader) add_library(libinfiz Evaluator.cpp - RationalNumber.cpp StringTokenizer.cpp) @@ -15,7 +14,6 @@ target_link_libraries(libinfiz PRIVATE infiz_options infiz_warnings) target_include_directories(libinfiz ${WARNING_GUARD} PUBLIC $ $) -target_compile_features(libinfiz PUBLIC cxx_std_20) set_target_properties( libinfiz diff --git a/src/libinfiz/Evaluator.cpp b/src/libinfiz/Evaluator.cpp index 1c9f627..c16b5b7 100644 --- a/src/libinfiz/Evaluator.cpp +++ b/src/libinfiz/Evaluator.cpp @@ -3,18 +3,18 @@ #include -int precedence(Operators input) +int precedence(Operators input) noexcept { switch (input) { - case CLOSE_PAREN: + case Operators::CLOSE_PAREN: return 3; - case PLUS_SIGN: - case MINUS_SIGN: + case Operators::PLUS_SIGN: + case Operators::MINUS_SIGN: return 1; - case MULTIPLY_SIGN: - case DIVIDE_SIGN: + case Operators::MULTIPLY_SIGN: + case Operators::DIVIDE_SIGN: return 2; - case OPEN_PAREN: + case Operators::OPEN_PAREN: return 0; } @@ -22,20 +22,20 @@ int precedence(Operators input) } -void evaluateStacks(Stack &numbers, Stack &operators) +void evaluateStacks(Stack &numbers, Stack &operators) { bool eatOpenParen = false; bool cont = true; - if (*operators.peek() == CLOSE_PAREN) { + if (!operators.empty() && *operators.peek() == Operators::CLOSE_PAREN) { eatOpenParen = true; operators.pop(); } - while ((operators.peek() != NULL) && cont) {// NOLINT + while (!operators.empty() && cont && (operators.peek() != nullptr)) { switch (*operators.peek()) { - case OPEN_PAREN: + case Operators::OPEN_PAREN: if (eatOpenParen) { operators.pop(); cont = false; @@ -45,35 +45,38 @@ void evaluateStacks(Stack &numbers, Stack &operators) break; - case PLUS_SIGN: { + case Operators::PLUS_SIGN: { operators.pop(); - const RationalNumber operand2 = numbers.pop(); - const RationalNumber operand1 = numbers.pop(); + const auto operand2 = numbers.pop(); + const auto operand1 = numbers.pop(); numbers.push(operand1 + operand2); break; } - case MINUS_SIGN: { + case Operators::MINUS_SIGN: { operators.pop(); numbers.push(-numbers.pop()); break; } - case MULTIPLY_SIGN: { + case Operators::MULTIPLY_SIGN: { operators.pop(); - const RationalNumber operand2 = numbers.pop(); - const RationalNumber operand1 = numbers.pop(); + const auto operand2 = numbers.pop(); + const auto operand1 = numbers.pop(); numbers.push(operand1 * operand2); break; } - case DIVIDE_SIGN: { + case Operators::DIVIDE_SIGN: { operators.pop(); - const RationalNumber operand2 = numbers.pop(); - const RationalNumber operand1 = numbers.pop(); + const auto operand2 = numbers.pop(); + const auto operand1 = numbers.pop(); numbers.push(operand1 / operand2); break; } + + case Operators::CLOSE_PAREN: + break;// we want to continue } } } @@ -81,61 +84,60 @@ void evaluateStacks(Stack &numbers, Stack &operators) RationalNumber evaluateExpression(StringTokenizer &tokenizer) { - Stack operators; + Stack operators; Stack numbers; while (tokenizer.hasMoreTokens()) { - std::string next = tokenizer.nextToken(); + auto next = tokenizer.nextToken(); - Operators value = PLUS_SIGN; + auto value = Operators::PLUS_SIGN; if (!next.empty()) { - bool operation = false; + auto operation = false; switch (next[0]) { case '+': - value = PLUS_SIGN; + value = Operators::PLUS_SIGN; operation = true; break; case '/': - value = DIVIDE_SIGN; + value = Operators::DIVIDE_SIGN; operation = true; break; case '-': - value = MINUS_SIGN; + value = Operators::MINUS_SIGN; operation = true; break; case '*': - value = MULTIPLY_SIGN; + value = Operators::MULTIPLY_SIGN; operation = true; break; case ')': - value = CLOSE_PAREN; + value = Operators::CLOSE_PAREN; operation = true; break; case '(': - value = OPEN_PAREN; + value = Operators::OPEN_PAREN; operation = true; break; default: operation = false; - numbers.push(RationalNumber(atoi(next.c_str()), 1));// NOLINT + numbers.emplace(atoi(next.c_str()), 1);// NOLINT break; } if (operation) { switch (value) { - case OPEN_PAREN: + case Operators::OPEN_PAREN: operators.push(value); break; - case CLOSE_PAREN: + case Operators::CLOSE_PAREN: operators.push(value); evaluateStacks(numbers, operators); break; default: - if (operators.peek() != NULL// NOLINT - && precedence(value) <= precedence(static_cast(*operators.peek()))) { + if (operators.peek() != nullptr && precedence(value) <= precedence(*operators.peek())) { evaluateStacks(numbers, operators); } operators.push(value); @@ -145,12 +147,11 @@ RationalNumber evaluateExpression(StringTokenizer &tokenizer) } } - if (operators.peek() != NULL)// NOLINT - evaluateStacks(numbers, operators); + if (operators.peek() != nullptr) { evaluateStacks(numbers, operators); } - if (numbers.peek() != NULL) {// NOLINT + if (numbers.peek() != nullptr) { return *numbers.peek(); } else { - return RationalNumber(0, 0);// NOLINT + return { 0, 0 }; } } diff --git a/src/libinfiz/Evaluator.hpp b/src/libinfiz/Evaluator.hpp index 269497c..6bf299a 100644 --- a/src/libinfiz/Evaluator.hpp +++ b/src/libinfiz/Evaluator.hpp @@ -1,15 +1,14 @@ #ifndef INFIZ_EVALUATOR_HPP #define INFIZ_EVALUATOR_HPP -#include "RationalNumber.h" -#include "Stack.h" -#include "StringTokenizer.h" +#include "RationalNumber.hpp" +#include "Stack.hpp" +#include "StringTokenizer.hpp" -enum Operators { PLUS_SIGN, CLOSE_PAREN, OPEN_PAREN, MINUS_SIGN, DIVIDE_SIGN, MULTIPLY_SIGN }; +enum struct Operators { PLUS_SIGN, CLOSE_PAREN, OPEN_PAREN, MINUS_SIGN, DIVIDE_SIGN, MULTIPLY_SIGN }; -int precedence(Operators input); RationalNumber evaluateExpression(StringTokenizer &tokenizer); -void evaluateStacks(Stack &numbers, Stack &operators); +void evaluateStacks(Stack &numbers, Stack &operators); #endif \ No newline at end of file diff --git a/src/libinfiz/RationalNumber.cpp b/src/libinfiz/RationalNumber.cpp deleted file mode 100644 index 00ef4e1..0000000 --- a/src/libinfiz/RationalNumber.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// RationalNumber.h - -#include "RationalNumber.h" - -RationalNumber::RationalNumber(int num, int den)// NOLINT - : numerator(num), denominator(den) -{} - -RationalNumber RationalNumber::operator/(const RationalNumber &rhs) const -{ - return RationalNumber(// NOLINT - numerator * rhs.getDenominator(), - denominator * rhs.getNumerator()); -} - -RationalNumber RationalNumber::operator*(const RationalNumber &rhs) const -{ - return RationalNumber(// NOLINT - numerator * rhs.getNumerator(), - denominator * rhs.getDenominator()); -} - -RationalNumber RationalNumber::operator+(const RationalNumber &rhs) const -{ - const int denom = denominator * rhs.getDenominator(); - const int new_numerator = this->numerator * rhs.getDenominator(); - const int numer = new_numerator + (rhs.getNumerator() * denominator); - - return RationalNumber(numer, denom);// NOLINT -} - -RationalNumber RationalNumber::operator-(const RationalNumber &rhs) const -{ - const int denom = denominator * rhs.getDenominator(); - - const int new_numerator = this->numerator * rhs.getDenominator(); - const int numer = new_numerator - (rhs.getNumerator() * denominator); - - return RationalNumber(numer, denom);// NOLINT -} - -int RationalNumber::getDenominator() const { return denominator; } - -RationalNumber RationalNumber::operator-() const -{ - return RationalNumber(numerator * -1, denominator);// NOLINT -} - -int RationalNumber::getNumerator() const { return numerator; } - -float RationalNumber::getFloat() const { return ((static_cast(numerator)) / (static_cast(denominator))); } diff --git a/src/libinfiz/RationalNumber.h b/src/libinfiz/RationalNumber.h deleted file mode 100644 index 93dbf61..0000000 --- a/src/libinfiz/RationalNumber.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef INFIZ_RATIONAL_NUMBER_H -#define INFIZ_RATIONAL_NUMBER_H - -// RationalNumber.h - -/** - * A Class that stores the numerator and denominator - * of a rational number. - */ - -class RationalNumber -{ -public: - RationalNumber(int num, int den); - RationalNumber operator/(const RationalNumber &rhs) const; - RationalNumber operator*(const RationalNumber &rhs) const; - RationalNumber operator+(const RationalNumber &rhs) const; - RationalNumber operator-(const RationalNumber &rhs) const; - RationalNumber operator-() const; - - int getNumerator() const; - int getDenominator() const; - - float getFloat() const; - -private: - int numerator; - int denominator; -}; - -#endif \ No newline at end of file diff --git a/src/libinfiz/RationalNumber.hpp b/src/libinfiz/RationalNumber.hpp new file mode 100644 index 0000000..b24fed6 --- /dev/null +++ b/src/libinfiz/RationalNumber.hpp @@ -0,0 +1,56 @@ +#ifndef INFIZ_RATIONAL_NUMBER_H +#define INFIZ_RATIONAL_NUMBER_H + +// RationalNumber.h + +/** + * A Class that stores the numerator and denominator + * of a rational number. + */ + +class RationalNumber +{ +public: + constexpr RationalNumber(int num, int den) noexcept// NOLINT + : numerator(num), denominator(den) + {} + + constexpr RationalNumber operator/(const RationalNumber &rhs) const noexcept + { + return { numerator * rhs.getDenominator(), denominator * rhs.getNumerator() }; + } + + constexpr RationalNumber operator*(const RationalNumber &rhs) const noexcept + { + return { numerator * rhs.getNumerator(), denominator * rhs.getDenominator() }; + } + + constexpr RationalNumber operator+(const RationalNumber &rhs) const noexcept + { + return { numerator * rhs.getDenominator() + (rhs.getNumerator() * denominator), + denominator * rhs.getDenominator() }; + } + + constexpr RationalNumber operator-(const RationalNumber &rhs) const noexcept + { + return { numerator * rhs.getDenominator() - (rhs.getNumerator() * denominator), + denominator * rhs.getDenominator() }; + } + + constexpr int getDenominator() const noexcept { return denominator; } + + constexpr RationalNumber operator-() const { return { numerator * -1, denominator }; } + + constexpr int getNumerator() const noexcept { return numerator; } + + constexpr float getFloat() const noexcept + { + return ((static_cast(numerator)) / (static_cast(denominator))); + } + +private: + int numerator; + int denominator; +}; + +#endif \ No newline at end of file diff --git a/src/libinfiz/Stack.h b/src/libinfiz/Stack.hpp similarity index 65% rename from src/libinfiz/Stack.h rename to src/libinfiz/Stack.hpp index a14ce76..8bccb85 100644 --- a/src/libinfiz/Stack.h +++ b/src/libinfiz/Stack.hpp @@ -1,5 +1,5 @@ -#ifndef INFIZ_STACK_H -#define INFIZ_STACK_H +#ifndef INFIZ_STACK_HPP +#define INFIZ_STACK_HPP // Stack.h @@ -15,8 +15,11 @@ template class Stack { public: - Stack() {} + Stack() = default; + bool empty() const noexcept { + return data.empty(); + } Contained pop() { @@ -26,12 +29,18 @@ template class Stack return toReturn; } + template + Contained &emplace( Param && ... param) { + data.emplace_back(std::forward(param)...); + return data.back(); + } + void push(const Contained &newElem) { data.push_back(newElem); } const Contained *peek() const { if (data.empty()) { - return NULL; + return nullptr; } else { return &data.back(); } diff --git a/src/libinfiz/StringTokenizer.cpp b/src/libinfiz/StringTokenizer.cpp index 1536b39..dd7b60c 100644 --- a/src/libinfiz/StringTokenizer.cpp +++ b/src/libinfiz/StringTokenizer.cpp @@ -1,10 +1,11 @@ // StringTokenizer.cpp -#include "StringTokenizer.h" +#include "StringTokenizer.hpp" #include +#include -StringTokenizer::StringTokenizer(const std::string &n_string)// NOLINT - : string(n_string), currentOffset(0), moreTokens(true) +StringTokenizer::StringTokenizer(std::string n_string) noexcept + : string(std::move(n_string)), currentOffset(0), moreTokens(true) {} @@ -12,7 +13,7 @@ std::string StringTokenizer::nextToken() { while (currentOffset < string.size() && isWhiteSpace(string[currentOffset])) { ++currentOffset; } - const size_type endOfToken = findTokenEnd(currentOffset, string); + const auto endOfToken = findTokenEnd(currentOffset, string); std::string toReturn = string.substr(currentOffset, endOfToken - currentOffset); currentOffset = endOfToken; @@ -22,9 +23,8 @@ std::string StringTokenizer::nextToken() return toReturn; } -bool StringTokenizer::hasMoreTokens() const { return moreTokens; } -StringTokenizer::size_type StringTokenizer::findTokenEnd(size_type start, const std::string &string) +std::size_t StringTokenizer::findTokenEnd(std::size_t start, const std::string &string) { if (string.empty()) { return start; } @@ -39,7 +39,7 @@ StringTokenizer::size_type StringTokenizer::findTokenEnd(size_type start, const } -bool StringTokenizer::isOperator(char input) +bool StringTokenizer::isOperator(char input) noexcept { switch (input) { case '+': @@ -55,7 +55,7 @@ bool StringTokenizer::isOperator(char input) } -bool StringTokenizer::isNumber(char input) +bool StringTokenizer::isNumber(char input) noexcept { switch (input) { case '1': @@ -75,4 +75,4 @@ bool StringTokenizer::isNumber(char input) } -bool StringTokenizer::isWhiteSpace(char input) { return !isNumber(input) && !isOperator(input); } +bool StringTokenizer::isWhiteSpace(char input) noexcept { return !isNumber(input) && !isOperator(input); } diff --git a/src/libinfiz/StringTokenizer.h b/src/libinfiz/StringTokenizer.h deleted file mode 100644 index 5f57b3e..0000000 --- a/src/libinfiz/StringTokenizer.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef INFIZ_STRING_TOKENIZER_H -#define INFIZ_STRING_TOKENIZER_H - -#include - -// StringTokenizer.h - -/** - * A Class that tokenizes strings consisting of - * arithmetic operators and numbers. - */ - -class StringTokenizer -{ -public: - typedef std::string::size_type size_type; - - explicit StringTokenizer(const std::string &n_string); - - bool hasMoreTokens() const; - - std::string nextToken(); - -private: - std::string string; - size_type currentOffset; - bool moreTokens; - - static bool isNumber(char input); - static bool isOperator(char input); - static bool isWhiteSpace(char input); - static size_type findTokenEnd(size_type start, const std::string &); -}; - -#endif \ No newline at end of file diff --git a/src/libinfiz/StringTokenizer.hpp b/src/libinfiz/StringTokenizer.hpp new file mode 100644 index 0000000..1a8aa44 --- /dev/null +++ b/src/libinfiz/StringTokenizer.hpp @@ -0,0 +1,33 @@ +#ifndef INFIZ_STRING_TOKENIZER_H +#define INFIZ_STRING_TOKENIZER_H + +#include + +// StringTokenizer.h + +/** + * A Class that tokenizes strings consisting of + * arithmetic operators and numbers. + */ + +class StringTokenizer +{ +public: + explicit StringTokenizer(std::string n_string) noexcept; + + bool hasMoreTokens() const noexcept { return moreTokens; } + + std::string nextToken(); + +private: + std::string string; + std::size_t currentOffset; + bool moreTokens; + + static bool isNumber(char input) noexcept; + static bool isOperator(char input) noexcept; + static bool isWhiteSpace(char input) noexcept; + static std::size_t findTokenEnd(std::size_t start, const std::string &); +}; + +#endif \ No newline at end of file