diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..3add209 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,20 @@ +version: 2 +jobs: + build: + docker: + - image: debian:stretch + + steps: + - checkout + - run: + name: Install deps + command: | + apt update -y + apt install -y build-essential + - run: + name: Test + command: | + cd test + make + ./test + diff --git a/.gitignore b/.gitignore index 6e20617..481f66e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +.vscode mathcalc core /*.dSYM +/test/*.dSYM +/test/test diff --git a/Makefile b/Makefile index 58f54e8..6ed4686 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,23 @@ DBG_OPTS = -O0 -g3 -Wall -SOURCE = mathcalc.cpp TARGET = mathcalc +SOURCE = mathcalc.cpp \ + calculator.cpp \ + stringExpression.cpp \ + expressionList.cpp \ + rpn.cpp mathcalc: $(SOURCE) - g++ $(DBG_OPTS) -Wall -o $(TARGET) $(SOURCE) + g++ $(DBG_OPTS) -std=c++11 -o $(TARGET) $(SOURCE) -.PHONY: clean run debug release +.PHONY: clean run release clean: - rm $(TARGET) - rm -r mathcalc.dSYM + $(shell [ -e $(TARGET) ] && rm $(TARGET)) + $(shell [ -d $(TARGET).dSYM ] && rm -r $(TARGET).dSYM) + $(shell [ -e core ] && rm core) + @echo Done run: $(TARGET) ./mathcalc release: mathcalc.cpp - g++ -Wall -o $(TARGET) $(SOURCE) + g++ -o $(TARGET) $(SOURCE) diff --git a/README.md b/README.md index c058a35..7359e33 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # mathcalc -Simple arithmetic calculater for command-line. +> Simple arithmetic calculater for command-line. + +[![CircleCI](https://circleci.com/gh/IzumiSy/mathcalc.svg?style=svg)](https://circleci.com/gh/IzumiSy/mathcalc) + ```bash $ ./mathcalc "1+2+(10*2+(5*2))+10" > 1+2+(10*2+(5*2))+10 diff --git a/bracket.h b/bracket.h deleted file mode 100644 index d59b252..0000000 --- a/bracket.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef BRACKET_H -#define BRACKET_H - -#include "types.h" -#include "calcurate.h" - -#define BEGIN_BRACKET 1 -#define END_BRACKET 2 - -#define NO_MORE_BRACKETS -1 -#define BRACKET_MISMATCH -2 - -int bracket_count(list expressions, int type) -{ - list::iterator it = expressions.begin(); - int result = 0; - - while (it != expressions.end()) { - switch (type) { - case BEGIN_BRACKET: - if (*it == "(") { - result++; - } - break; - case END_BRACKET: - if (*it == ")") { - result++; - } - break; - default: - ; - } - it++; - } - - return result; -} - -int process_brackets(struct PROGRESSION_FLAGS *pflags) -{ - list partial_expressions; - list::iterator it, pair_match_seek_it; - list::iterator last_begin_bracket_it, - pair_end_bracket_it; - list::iterator statement_begin, - statement_end; - list::iterator delete_back_it; - list::iterator insert_position; - bool begin_bracket_found, - end_bracket_found; - int begin_bracket_counter = 0, - end_bracket_counter = 0; - int bracket_value = 0; - - begin_bracket_counter = bracket_count(pflags->expressions, BEGIN_BRACKET); - end_bracket_counter = bracket_count(pflags->expressions, END_BRACKET); - if (begin_bracket_counter != end_bracket_counter) { - return BRACKET_MISMATCH; - } - if (!begin_bracket_counter || !end_bracket_counter) { - return NO_MORE_BRACKETS; - } - - it = pflags->expressions.begin(); - while (it != pflags->expressions.end()) { - begin_bracket_found = false; - end_bracket_found = false; - - if (*it == "(") { - begin_bracket_found = true; - last_begin_bracket_it = it; - - pair_match_seek_it = it; - while (pair_match_seek_it != pflags->expressions.end()) { - pair_match_seek_it++; - if (*pair_match_seek_it == "(") { - break; - } - if (*pair_match_seek_it == ")") { - end_bracket_found = true; - pair_match_seek_it++; - pair_end_bracket_it = pair_match_seek_it; - break; - } - } - } - if (begin_bracket_found && end_bracket_found) { - break; - } - - it++; - } - - statement_begin = last_begin_bracket_it; - statement_begin++; - statement_end = pair_end_bracket_it; - statement_end--; - bracket_value = calcurate(statement_begin, statement_end); - - delete_back_it = pair_end_bracket_it; - delete_back_it++; - - insert_position = pflags->expressions.erase(last_begin_bracket_it, delete_back_it); - insert_position = pflags->expressions.insert(insert_position, _itos(bracket_value)); - - // Clean up waste element that is added after inserting bracket_value - insert_position--; - pflags->expressions.erase(insert_position); - - cout << stringify_list(pflags->expressions) << endl; - - return 0; -} - -void exec_bracket_processing(struct PROGRESSION_FLAGS *pflags) -{ - bool exit_bracket_processing = false; - - while (1) { - cout << "------" << endl; - switch (process_brackets(pflags)) { - case NO_MORE_BRACKETS: - exit_bracket_processing = true; - break; - case BRACKET_MISMATCH: - cout << "Bracket mis-match" << endl; - return; - default: - break; - } - if (exit_bracket_processing) { - break; - } - } - - return; -} - -#endif diff --git a/calculator.cpp b/calculator.cpp new file mode 100644 index 0000000..e1e6330 --- /dev/null +++ b/calculator.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include "calculator.h" +#include "stringExpression.h" + +// Parses string expressions of std::string into ExpressionList +void Calculator::parse(std::string expressions) { + StringExpression stringExpression(expressions); + + while (1) { + stringExpression.begin(); + stringExpression.parseNumberValue(); + if (stringExpression.hasNextExpression()) { + stringExpression.parseExpression(); + stringExpression.next(); + } else { + break; + } + } + + this->expressionList = stringExpression.getExpressionsList(); + this->expressionList.cleanupJunks(); + return; +} + +// Prints stringified ExpressionList into STDOUT +void Calculator::print() { + std::cout << this->expressionList.stringify() << std::endl; + return; +} + +// Checks out if this->expressionList has any invalid expression, and throws exceptions. +// his method expects to be called after Calculator::parse because this->expressionList is populated by it. +void Calculator::validate() { + this->expressionList.validateBracketsParing(); + this->expressionList.validateDuplicatedSymbol(); + this->expressionList.validateLonelySymbol(); + return; +} + +void Calculator::run() { + // TODO: あとでつくる + return; +} diff --git a/calculator.h b/calculator.h new file mode 100644 index 0000000..cac97e2 --- /dev/null +++ b/calculator.h @@ -0,0 +1,20 @@ +#ifndef __CALCULATOR_H__ +#define __CALCULATOR_H__ + +#include +#include +#include "expressionList.h" + +class Calculator { + private: + ExpressionList expressionList; + + public: + void parse(std::string expressions); + void print(); + void validate(); + void run(); +}; + +#endif // __CALCULATOR_H__ + diff --git a/calcurate.h b/calcurate.h deleted file mode 100644 index 5cbe7c0..0000000 --- a/calcurate.h +++ /dev/null @@ -1,198 +0,0 @@ -#ifndef _CALCURATE_H_ -#define _CALCURATE_H_ - -#define DIV 1 -#define MUL 2 -#define PLS 3 -#define MNS 4 - -#define NO_EXP 0 - -// Process expressions -int expression_processor( - string it, - bool *exists_mul_and_div, - bool *exists_pls_and_mns, - bool go_through ) -{ - int exptype = NO_EXP; - - if (it == "*") { - exptype = MUL; - *exists_mul_and_div = true; - } else if (it == "/") { - exptype = DIV; - *exists_mul_and_div = true; - } - if (!*exists_mul_and_div && go_through) { - if (it == "+") { - exptype = PLS; - *exists_pls_and_mns = true; - } else if (it == "-") { - exptype = MNS; - *exists_pls_and_mns = true; - } - } - - return exptype; -} - -void exp_divider( - list *exp_array, - list::iterator *it, - struct EXP_DIVIDER_RESULT *exp_result ) -{ - string buf; - - *it = exp_array->erase(*it); - buf = *(*it); - exp_result->right_value = _stoi(buf); - - *it = exp_array->erase(*it); - *(*it)--; - buf = *(*it); - exp_result->left_value = _stoi(buf); -} - -int exec_calcurate(int exptype, struct EXP_DIVIDER_RESULT divider_result) -{ - int let = 0; - int right = divider_result.right_value; - int left = divider_result.left_value; - - switch (exptype) { - case MUL: let = right * left; break; - case DIV: let = left / right; break; - case PLS: let = left + right; break; - case MNS: let = left - right; break; - default: let = (int)NULL; break; - } - - return let; -} - -int sub_calcurate(struct PROGRESSION_FLAGS *pflags) -{ - struct EXP_DIVIDER_RESULT edr; - int right, left, let; - int exptype; - - exptype = expression_processor( - *pflags->it, &pflags->exists_mul_and_div, - &pflags->exists_pls_and_mns, pflags->go_through - ); - - if (exptype != NO_EXP) { - exp_divider(&pflags->expressions, &pflags->it, &edr); - right = edr.right_value; - left = edr.left_value; - - if (right == -1 || left == -1) { - return -1; - } - - let = exec_calcurate(exptype, edr); - - if (let == (int)NULL) { - return -2; - } - - pflags->expressions.insert(pflags->it, _itos(let)); - pflags->it = pflags->expressions.erase(pflags->it); - - return 1; - } - - return 0; -} - -int calcurate(list::iterator begin, list::iterator end) -{ - struct PROGRESSION_FLAGS pflags; - int result; - - pflags.it = begin; - for (;pflags.it != end;pflags.it++) { - pflags.expressions.push_back(*pflags.it); - } - - pflags.go_through = false; - - cout << "(" << stringify_list(pflags.expressions) << ")" << endl; - - while (1) { - pflags.exists_mul_and_div = false; - pflags.exists_pls_and_mns = false; - - pflags.it = pflags.expressions.begin(); - while (pflags.it != pflags.expressions.end()) { - result = sub_calcurate(&pflags); - - if (result == 1) { - cout << "= (" << stringify_list(pflags.expressions) << ")" << endl; - } else if (result < 0) { - cout << "Error(" << result << ")" << endl; - } - - pflags.it++; - } - - if (pflags.go_through && - !pflags.exists_mul_and_div && - !pflags.exists_pls_and_mns) { - break; - } - - // processing for subtraction and addition is not going - // to be triggerd off before going-through expression - // processing has not completed once. - pflags.go_through = true; - } - - return _stoi(*pflags.expressions.begin()); -} - -void build_expressions(string expressions, struct PROGRESSION_FLAGS *pflags) -{ - string::size_type current, prev, pos_plus, pos_minus, pos_multi, pos_div; - string::size_type pos_bracket_begin, pos_bracket_end; - string substr_buffer; - bool noexp; - - current = 0; - noexp = false; - - while (1) { - pos_plus = expressions.find("+", current); - pos_minus = expressions.find("-", current); - pos_multi = expressions.find("*", current); - pos_div = expressions.find("/", current); - pos_bracket_begin = expressions.find("(", current); - pos_bracket_end = expressions.find(")", current); - if (pos_plus == string::npos && - pos_minus == string::npos && - pos_multi == string::npos && - pos_div == string::npos && - pos_bracket_begin == string::npos && - pos_bracket_end == string::npos) { - noexp = true; - } - - // number - prev = current; - current = min(pos_plus, min(pos_minus, min(pos_multi, - min(pos_div, min(pos_bracket_begin, pos_bracket_end))))); - pflags->expressions.push_back(expressions.substr(prev, current - prev)); - - // expression - if (noexp) break; - pflags->expressions.push_back(expressions.substr(current, 1)); - current++; - } - - cout << "> " << stringify_list(pflags->expressions) << endl; - - return; -} - -#endif diff --git a/exception.h b/exception.h new file mode 100644 index 0000000..15a4d99 --- /dev/null +++ b/exception.h @@ -0,0 +1,20 @@ +#ifndef EXCEPTION_H +#define EXCEPTION_H + +#include + +struct Exception { + std::string message; + + static struct Exception make(std::string message) { + struct Exception e; + e.message = message; + return e; + }; + + const char *msg() { + return this->message.c_str(); + }; +}; + +#endif \ No newline at end of file diff --git a/expression.h b/expression.h new file mode 100644 index 0000000..11c6cf9 --- /dev/null +++ b/expression.h @@ -0,0 +1,42 @@ +#ifndef EXPRESSION_H +#define EXPRESSION_H + +#include + +// TODO: EXPRESSIONは単なるインターフェースにしてこれを満たす +// 数値クラス, 記号クラスを実装するほうがよい. 例えばtoLongメソッド +// などは記号に対してはどのように作用するか予測できないためよくない。 +struct EXPRESSION { + enum TYPES { + VALUE = 0, + SYMBOL + }; + + EXPRESSION::TYPES type; + std::string value; + + static struct EXPRESSION make(EXPRESSION::TYPES type, std::string value) { + struct EXPRESSION expression; + expression.type = type; + expression.value = value; + return expression; + }; + + bool operator==(std::string value) const { + return (this->value == value); + } + + inline bool isSymbol() const { + return this->type == SYMBOL; + } + + inline long toLong() const { + if (this->isSymbol()) { + return 0; + } else { + return std::stol(this->value); + } + } +}; + +#endif // EXPRESSION_H diff --git a/expressionList.cpp b/expressionList.cpp new file mode 100644 index 0000000..5feee82 --- /dev/null +++ b/expressionList.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#include "expression.h" +#include "exception.h" +#include "expressionList.h" + +void ExpressionList::add(struct EXPRESSION expression) { + this->expressions.push_back(expression); +} + +void ExpressionList::cleanupJunks() { + this->expressions.remove_if(ExpressionList::emptyExpression); +} + +void ExpressionList::validateBracketsParing() { + size_t beginBracketCount = std::count(this->expressions.begin(), this->expressions.end(), std::string("(")); + size_t endBracketCount = std::count(this->expressions.begin(), this->expressions.end(), std::string(")")); + + if (beginBracketCount != endBracketCount) { + throw Exception::make("Brackets unmatched."); + } + + return; +} + +void ExpressionList::validateDuplicatedSymbol() { + std::list::iterator it = this->expressions.begin(); + std::list::iterator end = this->expressions.end(); + std::list::iterator temp; + + for (; it != end; it++) { + if (it->type == EXPRESSION::SYMBOL) { + temp = it; + temp++; + if ((it->value != std::string(")")) && + (temp->type == EXPRESSION::SYMBOL) && + (temp->value != std::string("("))) { + throw Exception::make("Duplicated symbol."); + } + } + } + + return; +} + +void ExpressionList::validateLonelySymbol() { + std::list::const_iterator head = this->expressions.begin(); + std::list::const_iterator tail = this->expressions.end(); + + tail--; + if ((head->type == EXPRESSION::SYMBOL && head->value != std::string("(")) || + (tail->type == EXPRESSION::SYMBOL && tail->value != std::string(")"))) { + throw Exception::make("Lonely symbol."); + } + + return; +} + +std::string ExpressionList::stringify() const { + std::string buffer; + std::list::const_iterator it = this->expressions.begin(); + std::list::const_iterator end = this->expressions.end(); + + for (; it != end; it++) { + buffer += it->value; + } + + return buffer; +} + +std::list ExpressionList::toList() const { + return this->expressions; +} diff --git a/expressionList.h b/expressionList.h new file mode 100644 index 0000000..43a8ccb --- /dev/null +++ b/expressionList.h @@ -0,0 +1,27 @@ +#ifndef __EXPRESSION_LIST_H__ +#define __EXPRESSION_LIST_H__ + +#include +#include +#include "expression.h" + +class ExpressionList { + private: + std::list expressions; + + static bool emptyExpression(const struct EXPRESSION &expression) { + return (expression.type == EXPRESSION::VALUE && expression.value == ""); + }; + + public: + void add(struct EXPRESSION expression); + void cleanupJunks(); + void validateBracketsParing(); + void validateDuplicatedSymbol(); + void validateLonelySymbol(); + + std::string stringify() const; + std::list toList() const; +}; + +#endif // __EXPRESSION_LIST_H__ diff --git a/mathcalc.cpp b/mathcalc.cpp index bd8804c..8c56c59 100644 --- a/mathcalc.cpp +++ b/mathcalc.cpp @@ -5,32 +5,31 @@ #include #include #include +#include "exception.h" using namespace std; -#include "types.h" -#include "utils.h" -#include "bracket.h" -#include "calcurate.h" +#include "calculator.h" int main(int argc, char *argv[]) { - struct PROGRESSION_FLAGS pflags; - string expressions; - if (argc == 1) { cout << "usage: mathcalc [expression]" << endl; - return 0; + exit(1); } - // Build expression array from string given from command-line - expressions = argv[1]; - build_expressions(expressions, &pflags); - - // Clean up bracket-wrapped expressions - exec_bracket_processing(&pflags); - - // Last calcuration after cleaning up of brackets - cout << calcurate(pflags.expressions.begin(), pflags.expressions.end()) << endl; + // struct PROGRESSION_FLAGS pflags; + string expressions = argv[1]; + + Calculator calc; + try { + calc.parse(expressions); + calc.validate(); + calc.print(); + calc.run(); + } catch (struct Exception e) { + std::cerr << "Error: " << e.msg() << std::endl; + exit(1); + } return 0; } diff --git a/rpn.cpp b/rpn.cpp new file mode 100644 index 0000000..5c17f02 --- /dev/null +++ b/rpn.cpp @@ -0,0 +1,42 @@ +#include "rpn.h" +#include "expression.h" +#include +#include +#include + +RPN::RPN(std::list expressions) { + this->expressions = expressions; +} + +long RPN::result() const { + std::stack calcStack; + std::list::const_iterator it = this->expressions.begin(); + std::list::const_iterator end = this->expressions.end(); + + for (; it != end; it++) { + if ((*it).isSymbol()) { + const long left = calcStack.top(); + calcStack.pop(); + const long right = calcStack.top(); + calcStack.pop(); + calcStack.push(this->operate(left, right, (*it).value)); + } else { + calcStack.push((*it).toLong()); + } + } + + return calcStack.top(); +} + +// TODO: 予期しない記号が来た場合の処理が微妙なのでどうにかしたい +long RPN::operate(const long left, const long right, const std::string symbol) const { + if (symbol == "+") { + return left + right; + } else if (symbol == "-") { + return left - right; + } else if (symbol == "*") { + return left * right; + } else { // (symbol == "/") + return left / right; + } +} diff --git a/rpn.h b/rpn.h new file mode 100644 index 0000000..76a001b --- /dev/null +++ b/rpn.h @@ -0,0 +1,17 @@ +#ifndef RPN_H +#define RPN_H + +#include +#include + +class RPN { + private: + std::list expressions; + long operate(const long left, const long right, const std::string symbol) const; + + public: + RPN(std::list expressions); + long result() const; +}; + +#endif // RPN_H diff --git a/stringExpression.cpp b/stringExpression.cpp new file mode 100644 index 0000000..e44e723 --- /dev/null +++ b/stringExpression.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include "expression.h" +#include "stringExpression.h" +#include "expressionList.h" + +void StringExpression::addSymbol(struct SYMBOL symbol) { + this->symbols.push_back(symbol); +} + +void StringExpression::defineSymbols() { + this->addSymbol(SYMBOL::make("+", SYMBOL::PLUS)); + this->addSymbol(SYMBOL::make("-", SYMBOL::MINUS)); + this->addSymbol(SYMBOL::make("*", SYMBOL::MULTIPLY)); + this->addSymbol(SYMBOL::make("/", SYMBOL::DIVIDE)); + this->addSymbol(SYMBOL::make("(", SYMBOL::BRACKET_BEGIN)); + this->addSymbol(SYMBOL::make(")", SYMBOL::BRACKET_END)); +} + +std::string::size_type StringExpression::getNextExpressionPos() { + std::vector expressionPositionsIndex; + std::vector::iterator it = this->symbols.begin(); + std::vector::iterator end = this->symbols.end(); + + for (; it != end; it++) { + expressionPositionsIndex.push_back(this->expressions.find(it->character, this->currentPos)); + } + + return *std::min_element(expressionPositionsIndex.begin(), expressionPositionsIndex.end()); +} + +StringExpression::StringExpression(std::string expressions) { + this->defineSymbols(); + this->expressions = expressions; + this->currentPos = 0; +} + +ExpressionList StringExpression::getExpressionsList() { + return this->expressionList; +} + +void StringExpression::begin() { + this->nextExpressionPos = this->getNextExpressionPos(); +} + +void StringExpression::next() { + this->currentPos = (nextExpressionPos + 1); +} + +bool StringExpression::hasNextExpression() { + this->nextExpressionPos = this->getNextExpressionPos(); + if (this->nextExpressionPos == std::string::npos) { + return false; + } else { + return true; + } +} + +void StringExpression::parseNumberValue() { + std::string valuePart = + this->expressions.substr(this->currentPos, this->nextExpressionPos - this->currentPos); + this->expressionList.add(EXPRESSION::make(EXPRESSION::VALUE, valuePart)); +} + +void StringExpression::parseExpression() { + std::string symbolPart = this->expressions.substr(nextExpressionPos, 1); + this->expressionList.add(EXPRESSION::make(EXPRESSION::SYMBOL, symbolPart)); +} + diff --git a/stringExpression.h b/stringExpression.h new file mode 100644 index 0000000..18d6641 --- /dev/null +++ b/stringExpression.h @@ -0,0 +1,33 @@ +#ifndef __STRING_EXPRESSION_H__ +#define __STRING_EXPRESSION_H__ + +#include +#include +#include "symbol.h" +#include "expressionList.h" + +class StringExpression { + private: + ExpressionList expressionList; + std::vector symbols; + std::string::size_type currentPos; + std::string::size_type nextExpressionPos; + std::string expressions; + + void addSymbol(struct SYMBOL sign); + void defineSymbols(); + SYMBOL::TYPES getExpressionType(std::string sign); + std::string::size_type getNextExpressionPos(); + + public: + StringExpression(std::string expressions); + ExpressionList getExpressionsList(); + + bool hasNextExpression(); + void parseNumberValue(); + void parseExpression(); + void begin(); + void next(); +}; + +#endif diff --git a/symbol.h b/symbol.h new file mode 100644 index 0000000..b85a78b --- /dev/null +++ b/symbol.h @@ -0,0 +1,32 @@ +#ifndef SYMBOL_H +#define SYMBOL_H + +#include + +struct SYMBOL { + enum TYPES { + PLUS = 0, + MINUS, + DIVIDE, + MULTIPLY, + BRACKET_BEGIN, + BRACKET_END, + OTHER + }; + + SYMBOL::TYPES type; + std::string character; + + static struct SYMBOL make(std::string character, SYMBOL::TYPES type) { + struct SYMBOL symbol; + symbol.character = character; + symbol.type = type; + return symbol; + }; + + bool operator==(std::string character) { + return (this->character == character); + } +}; + +#endif // SYMBOL_H \ No newline at end of file diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..aafaa37 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,15 @@ +DBG_OPTS = -O0 -g3 -Wall +TARGET = test +TEST_SOURCE = test.cpp ../rpn.cpp + +test: $(TEST_SOURCE) + g++ $(DBG_OPTS) -std=c++11 -o $(TARGET) $(TEST_SOURCE) -I vendors + +.PHONY: clean +clean: $(TARGET) + $(shell [ -e $(TARGET) ] && rm $(TARGET)) + $(shell [ -d $(TARGET).dSYM ] && rm -r $(TARGET).dSYM) + @echo Done + +run: $(TARGET) + ./$(TARGET) diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 0000000..4005995 --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,65 @@ +#include "vendors/minunit.h" +#include "../expression.h" +#include "../rpn.h" +#include + +MU_TEST(rpnPlus) { + const struct EXPRESSION plus = + EXPRESSION::make(EXPRESSION::TYPES::SYMBOL, "+"); + + std::list expressions; + expressions.push_back(EXPRESSION::make(EXPRESSION::TYPES::VALUE, "10")); + expressions.push_back(EXPRESSION::make(EXPRESSION::TYPES::VALUE, "5")); + expressions.push_back(plus); + + const RPN rpnPlus(expressions); + mu_check(rpnPlus.result() == 15); +} + +MU_TEST(rpnMinus) { + const struct EXPRESSION minus = + EXPRESSION::make(EXPRESSION::TYPES::SYMBOL, "-"); + + std::list expressions; + expressions.push_back(EXPRESSION::make(EXPRESSION::TYPES::VALUE, "10")); + expressions.push_back(EXPRESSION::make(EXPRESSION::TYPES::VALUE, "20")); + expressions.push_back(minus); + + const RPN rpnMinus(expressions); + mu_check(rpnMinus.result() == 10); +} + +MU_TEST(rpnMulti) { + const struct EXPRESSION minus = + EXPRESSION::make(EXPRESSION::TYPES::SYMBOL, "*"); + + std::list expressions; + expressions.push_back(EXPRESSION::make(EXPRESSION::TYPES::VALUE, "20")); + expressions.push_back(EXPRESSION::make(EXPRESSION::TYPES::VALUE, "3")); + expressions.push_back(minus); + + const RPN rpnMinus(expressions); + mu_check(rpnMinus.result() == 60); +} + +MU_TEST(rpnDivision) { + const struct EXPRESSION minus = + EXPRESSION::make(EXPRESSION::TYPES::SYMBOL, "/"); + + std::list expressions; + expressions.push_back(EXPRESSION::make(EXPRESSION::TYPES::VALUE, "3")); + expressions.push_back(EXPRESSION::make(EXPRESSION::TYPES::VALUE, "30")); + expressions.push_back(minus); + + const RPN rpnMinus(expressions); + mu_check(rpnMinus.result() == 10); +} + +int main(int argc, char *argv[]) { + MU_RUN_TEST(rpnPlus); + MU_RUN_TEST(rpnMinus); + MU_RUN_TEST(rpnMulti); + MU_RUN_TEST(rpnDivision); + MU_REPORT(); + return minunit_status; +} diff --git a/test/vendors/minunit.h b/test/vendors/minunit.h new file mode 100644 index 0000000..263a200 --- /dev/null +++ b/test/vendors/minunit.h @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2012 David Siñuela Pastor, siu.4coders@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef MINUNIT_MINUNIT_H +#define MINUNIT_MINUNIT_H + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined(_WIN32) +#include +#if defined(_MSC_VER) && _MSC_VER < 1900 + #define snprintf _snprintf + #define __func__ __FUNCTION__ +#endif + +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) + +/* Change POSIX C SOURCE version for pure c99 compilers */ +#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif + +#include /* POSIX flags */ +#include /* clock_gettime(), time() */ +#include /* gethrtime(), gettimeofday() */ +#include +#include +#include + +#if defined(__MACH__) && defined(__APPLE__) +#include +#include +#endif + +#else +#error "Unable to define timers for an unknown OS." +#endif + +#include +#include + +/* Maximum length of last message */ +#define MINUNIT_MESSAGE_LEN 1024 +/* Accuracy with which floats are compared */ +#define MINUNIT_EPSILON 1E-12 + +/* Misc. counters */ +static int minunit_run = 0; +static int minunit_assert = 0; +static int minunit_fail = 0; +static int minunit_status = 0; + +/* Timers */ +static double minunit_real_timer = 0; +static double minunit_proc_timer = 0; + +/* Last message */ +static char minunit_last_message[MINUNIT_MESSAGE_LEN]; + +/* Test setup and teardown function pointers */ +static void (*minunit_setup)(void) = NULL; +static void (*minunit_teardown)(void) = NULL; + +/* Definitions */ +#define MU_TEST(method_name) static void method_name(void) +#define MU_TEST_SUITE(suite_name) static void suite_name(void) + +#define MU__SAFE_BLOCK(block) do {\ + block\ +} while(0) + +/* Run test suite and unset setup and teardown functions */ +#define MU_RUN_SUITE(suite_name) MU__SAFE_BLOCK(\ + suite_name();\ + minunit_setup = NULL;\ + minunit_teardown = NULL;\ +) + +/* Configure setup and teardown functions */ +#define MU_SUITE_CONFIGURE(setup_fun, teardown_fun) MU__SAFE_BLOCK(\ + minunit_setup = setup_fun;\ + minunit_teardown = teardown_fun;\ +) + +/* Test runner */ +#define MU_RUN_TEST(test) MU__SAFE_BLOCK(\ + if (minunit_real_timer==0 && minunit_proc_timer==0) {\ + minunit_real_timer = mu_timer_real();\ + minunit_proc_timer = mu_timer_cpu();\ + }\ + if (minunit_setup) (*minunit_setup)();\ + /* minunit_status = 0; // here resets an error code (maybe a bug?) */ \ + test();\ + minunit_run++;\ + if (minunit_status) {\ + minunit_fail++;\ + printf("F");\ + printf("\n%s\n", minunit_last_message);\ + }\ + fflush(stdout);\ + if (minunit_teardown) (*minunit_teardown)();\ +) + +/* Report */ +#define MU_REPORT() MU__SAFE_BLOCK(\ + double minunit_end_real_timer;\ + double minunit_end_proc_timer;\ + printf("\n\n%d tests, %d assertions, %d failures\n", minunit_run, minunit_assert, minunit_fail);\ + minunit_end_real_timer = mu_timer_real();\ + minunit_end_proc_timer = mu_timer_cpu();\ + printf("\nFinished in %.8f seconds (real) %.8f seconds (proc)\n\n",\ + minunit_end_real_timer - minunit_real_timer,\ + minunit_end_proc_timer - minunit_proc_timer);\ +) + +/* Assertions */ +#define mu_check(test) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (!(test)) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, #test);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_fail(message) MU__SAFE_BLOCK(\ + minunit_assert++;\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, message);\ + minunit_status = 1;\ + return;\ +) + +#define mu_assert(test, message) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (!(test)) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, message);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_int_eq(expected, result) MU__SAFE_BLOCK(\ + int minunit_tmp_e;\ + int minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (expected);\ + minunit_tmp_r = (result);\ + if (minunit_tmp_e != minunit_tmp_r) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %d expected but was %d", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_double_eq(expected, result) MU__SAFE_BLOCK(\ + double minunit_tmp_e;\ + double minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (expected);\ + minunit_tmp_r = (result);\ + if (fabs(minunit_tmp_e-minunit_tmp_r) > MINUNIT_EPSILON) {\ + int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON);\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %.*g expected but was %.*g", __func__, __FILE__, __LINE__, minunit_significant_figures, minunit_tmp_e, minunit_significant_figures, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_string_eq(expected, result) MU__SAFE_BLOCK(\ + const char* minunit_tmp_e = expected;\ + const char* minunit_tmp_r = result;\ + minunit_assert++;\ + if (!minunit_tmp_e) {\ + minunit_tmp_e = "";\ + }\ + if (!minunit_tmp_r) {\ + minunit_tmp_r = "";\ + }\ + if(strcmp(minunit_tmp_e, minunit_tmp_r)) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: '%s' expected but was '%s'", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +/* + * The following two functions were written by David Robert Nadeau + * from http://NadeauSoftware.com/ and distributed under the + * Creative Commons Attribution 3.0 Unported License + */ + +/** + * Returns the real time, in seconds, or -1.0 if an error occurred. + * + * Time is measured since an arbitrary and OS-dependent start time. + * The returned real time is only useful for computing an elapsed time + * between two calls to this function. + */ +static double mu_timer_real(void) +{ +#if defined(_WIN32) + /* Windows 2000 and later. ---------------------------------- */ + LARGE_INTEGER Time; + LARGE_INTEGER Frequency; + + QueryPerformanceFrequency(&Frequency); + QueryPerformanceCounter(&Time); + + Time.QuadPart *= 1000000; + Time.QuadPart /= Frequency.QuadPart; + + return (double)Time.QuadPart / 1000000.0; + +#elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) + /* HP-UX, Solaris. ------------------------------------------ */ + return (double)gethrtime( ) / 1000000000.0; + +#elif defined(__MACH__) && defined(__APPLE__) + /* OSX. ----------------------------------------------------- */ + static double timeConvert = 0.0; + if ( timeConvert == 0.0 ) + { + mach_timebase_info_data_t timeBase; + (void)mach_timebase_info( &timeBase ); + timeConvert = (double)timeBase.numer / + (double)timeBase.denom / + 1000000000.0; + } + return (double)mach_absolute_time( ) * timeConvert; + +#elif defined(_POSIX_VERSION) + /* POSIX. --------------------------------------------------- */ + struct timeval tm; +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + { + struct timespec ts; +#if defined(CLOCK_MONOTONIC_PRECISE) + /* BSD. --------------------------------------------- */ + const clockid_t id = CLOCK_MONOTONIC_PRECISE; +#elif defined(CLOCK_MONOTONIC_RAW) + /* Linux. ------------------------------------------- */ + const clockid_t id = CLOCK_MONOTONIC_RAW; +#elif defined(CLOCK_HIGHRES) + /* Solaris. ----------------------------------------- */ + const clockid_t id = CLOCK_HIGHRES; +#elif defined(CLOCK_MONOTONIC) + /* AIX, BSD, Linux, POSIX, Solaris. ----------------- */ + const clockid_t id = CLOCK_MONOTONIC; +#elif defined(CLOCK_REALTIME) + /* AIX, BSD, HP-UX, Linux, POSIX. ------------------- */ + const clockid_t id = CLOCK_REALTIME; +#else + const clockid_t id = (clockid_t)-1; /* Unknown. */ +#endif /* CLOCK_* */ + if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) + return (double)ts.tv_sec + + (double)ts.tv_nsec / 1000000000.0; + /* Fall thru. */ + } +#endif /* _POSIX_TIMERS */ + + /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, POSIX, Solaris. ----- */ + gettimeofday( &tm, NULL ); + return (double)tm.tv_sec + (double)tm.tv_usec / 1000000.0; +#else + return -1.0; /* Failed. */ +#endif +} + +/** + * Returns the amount of CPU time used by the current process, + * in seconds, or -1.0 if an error occurred. + */ +static double mu_timer_cpu(void) +{ +#if defined(_WIN32) + /* Windows -------------------------------------------------- */ + FILETIME createTime; + FILETIME exitTime; + FILETIME kernelTime; + FILETIME userTime; + + /* This approach has a resolution of 1/64 second. Unfortunately, Windows' API does not offer better */ + if ( GetProcessTimes( GetCurrentProcess( ), + &createTime, &exitTime, &kernelTime, &userTime ) != 0 ) + { + ULARGE_INTEGER userSystemTime; + memcpy(&userSystemTime, &userTime, sizeof(ULARGE_INTEGER)); + return (double)userSystemTime.QuadPart / 10000000.0; + } + +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) + /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris --------- */ + +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + /* Prefer high-res POSIX timers, when available. */ + { + clockid_t id; + struct timespec ts; +#if _POSIX_CPUTIME > 0 + /* Clock ids vary by OS. Query the id, if possible. */ + if ( clock_getcpuclockid( 0, &id ) == -1 ) +#endif +#if defined(CLOCK_PROCESS_CPUTIME_ID) + /* Use known clock id for AIX, Linux, or Solaris. */ + id = CLOCK_PROCESS_CPUTIME_ID; +#elif defined(CLOCK_VIRTUAL) + /* Use known clock id for BSD or HP-UX. */ + id = CLOCK_VIRTUAL; +#else + id = (clockid_t)-1; +#endif + if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) + return (double)ts.tv_sec + + (double)ts.tv_nsec / 1000000000.0; + } +#endif + +#if defined(RUSAGE_SELF) + { + struct rusage rusage; + if ( getrusage( RUSAGE_SELF, &rusage ) != -1 ) + return (double)rusage.ru_utime.tv_sec + + (double)rusage.ru_utime.tv_usec / 1000000.0; + } +#endif + +#if defined(_SC_CLK_TCK) + { + const double ticks = (double)sysconf( _SC_CLK_TCK ); + struct tms tms; + if ( times( &tms ) != (clock_t)-1 ) + return (double)tms.tms_utime / ticks; + } +#endif + +#if defined(CLOCKS_PER_SEC) + { + clock_t cl = clock( ); + if ( cl != (clock_t)-1 ) + return (double)cl / (double)CLOCKS_PER_SEC; + } +#endif + +#endif + + return -1; /* Failed. */ +} + +#ifdef __cplusplus +} +#endif + +#endif /* MINUNIT_MINUNIT_H */ diff --git a/types.h b/types.h index f2d65b9..3f787ec 100644 --- a/types.h +++ b/types.h @@ -1,17 +1,19 @@ #ifndef TYPES_H #define TYPES_H +/* struct EXP_DIVIDER_RESULT { - int left_value; - int right_value; + int left_value; + int right_value; }; struct PROGRESSION_FLAGS { - list expressions; - list::iterator it; - bool exists_mul_and_div; - bool exists_pls_and_mns; - bool go_through; + std::list expressions; + std::list::iterator it; + bool exists_mul_and_div; + bool exists_pls_and_mns; + bool go_through; }; +*/ -#endif +#endif // TYPES_H \ No newline at end of file diff --git a/utils.h b/utils.h deleted file mode 100644 index 7a44d2b..0000000 --- a/utils.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -string _itos(int n) -{ - stringstream s; - s << n; - return s.str(); -} - -int _stoi(string s) { - if (s.empty()) { - return -1; - } - return atoi(s.c_str()); -} - -string stringify_list(list n) -{ - string buf; - list::iterator begin = n.begin(); - list::iterator end = n.end(); - - for (;begin != end;begin++) { - buf += *begin; - } - - return buf; -} - -#endif