├── Scripts ├── travis_build.sh ├── azure_pipelines_build_linux.yml ├── azure_pipelines_build_macos.yml ├── travis_build_docker.sh ├── Dockerfile.bionic └── azure_pipelines_build_windows.yml ├── Sources ├── Expressions │ ├── ExpressionTree.cpp │ ├── Expression.cpp │ ├── ExpressionMaker.cpp │ └── ExpressionUtil.cpp ├── main.cpp ├── Operators │ ├── Sine.cpp │ ├── Plus.cpp │ ├── Cosine.cpp │ ├── Tangent.cpp │ ├── Multiply.cpp │ ├── Power.cpp │ ├── Divide.cpp │ ├── Minus.cpp │ ├── UnaryOperator.cpp │ ├── Assign.cpp │ └── BinaryOperator.cpp ├── Operands │ ├── Operand.cpp │ ├── Real.cpp │ ├── Integer.cpp │ └── Variable.cpp ├── CMakeLists.txt ├── Variables │ └── VariableTable.cpp └── Programs │ └── Calculator.cpp ├── Includes ├── Operators │ ├── Sine.hpp │ ├── Cosine.hpp │ ├── Plus.hpp │ ├── Tangent.hpp │ ├── Power.hpp │ ├── Divide.hpp │ ├── Multiply.hpp │ ├── Assign.hpp │ ├── UnaryOperator.hpp │ ├── Minus.hpp │ └── BinaryOperator.hpp ├── Expressions │ ├── ExpressionUtil.hpp │ ├── ExpressionTree.hpp │ ├── ExpressionMaker.hpp │ └── Expression.hpp ├── Operands │ ├── Real.hpp │ ├── Integer.hpp │ ├── Variable.hpp │ └── Operand.hpp ├── Variables │ └── VariableTable.hpp ├── Programs │ └── Calculator.hpp └── Commons │ └── Constants.hpp ├── azure-pipelines.yml ├── appveyor.yml ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── CMakeSettings.json ├── .gitignore ├── CMake └── CompileOptions.cmake └── README.md /Scripts/travis_build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | export NUM_JOBS=1 6 | 7 | mkdir build 8 | cd build 9 | cmake .. 10 | make 11 | -------------------------------------------------------------------------------- /Scripts/azure_pipelines_build_linux.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - checkout: self 3 | fetchDepth: 2 4 | submodules: true 5 | - script: | 6 | docker build -f Scripts/Dockerfile.bionic -t utilforever/cubbycalc:bionic . -------------------------------------------------------------------------------- /Scripts/azure_pipelines_build_macos.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - checkout: self 3 | fetchDepth: 2 4 | submodules: true 5 | - script: | 6 | brew update 7 | mkdir build 8 | cd build 9 | cmake .. 10 | make -j 8 -------------------------------------------------------------------------------- /Scripts/travis_build_docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | if [ $# -eq 0 ] 6 | then 7 | docker build -t utilforever/cubbycalc . 8 | else 9 | docker build -f $1 -t utilforever/cubbycalc:$2 . 10 | fi -------------------------------------------------------------------------------- /Sources/Expressions/ExpressionTree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | ExpressionTree::ExpressionTree() 4 | { } 5 | 6 | ExpressionTree::ExpressionTree(const ExpressionTree&) 7 | { } 8 | 9 | ExpressionTree::~ExpressionTree() 10 | { } -------------------------------------------------------------------------------- /Scripts/Dockerfile.bionic: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | MAINTAINER Chris Ohk 3 | 4 | RUN apt-get update -yq && \ 5 | apt-get install -yq build-essential cmake 6 | 7 | ADD . /app 8 | 9 | WORKDIR /app/build 10 | RUN cmake .. && \ 11 | make -j`nproc` && \ 12 | make install 13 | -------------------------------------------------------------------------------- /Scripts/azure_pipelines_build_windows.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - checkout: self 3 | fetchDepth: 2 4 | submodules: true 5 | - script: | 6 | md build 7 | cd build 8 | cmake .. -G "Visual Studio 15 2017 Win64" 9 | - task: VSBuild@1 10 | inputs: 11 | solution: 'D:\a\1\s\build\CubbyCalc.sln' 12 | configuration: Release 13 | platform: x64 14 | -------------------------------------------------------------------------------- /Sources/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | Calculator calc; 8 | 9 | try 10 | { 11 | calc.Run(); 12 | } 13 | catch (const std::exception& e) 14 | { 15 | std::cout << e.what() << std::endl; 16 | } 17 | catch (...) 18 | { 19 | std::cout << "Unknown exception error" << std::endl; 20 | } 21 | 22 | return 0; 23 | } -------------------------------------------------------------------------------- /Includes/Operators/Sine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_SINE_HPP 2 | #define CUBBYCALC_SINE_HPP 3 | 4 | #include 5 | 6 | class Sine : public UnaryOperator 7 | { 8 | protected: 9 | Sine(const Sine&); 10 | 11 | public: 12 | Sine(ExpressionTree* = 0); 13 | 14 | ExpressionTree* Clone() const; 15 | std::string ToString() const; 16 | double Evaluate() const; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /Includes/Operators/Cosine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_COSINE_HPP 2 | #define CUBBYCALC_COSINE_HPP 3 | 4 | #include 5 | 6 | class Cosine : public UnaryOperator 7 | { 8 | protected: 9 | Cosine(const Cosine&); 10 | 11 | public: 12 | Cosine(ExpressionTree* = 0); 13 | 14 | ExpressionTree* Clone() const; 15 | std::string ToString() const; 16 | double Evaluate() const; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /Includes/Operators/Plus.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_PLUS_HPP 2 | #define CUBBYCALC_PLUS_HPP 3 | 4 | #include 5 | 6 | class Plus : public BinaryOperator 7 | { 8 | protected: 9 | Plus(const Plus&); 10 | 11 | public: 12 | Plus(ExpressionTree*, ExpressionTree*); 13 | 14 | ExpressionTree* Clone() const; 15 | std::string ToString() const; 16 | double Evaluate() const; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /Includes/Expressions/ExpressionUtil.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_EXPRESSION_UTIL_HPP 2 | #define CUBBYCALC_EXPRESSION_UTIL_HPP 3 | 4 | #include 5 | #include 6 | 7 | class InfixError : public std::logic_error 8 | { 9 | public: 10 | explicit InfixError(const std::string& whatArg) throw() 11 | : logic_error(whatArg) { } 12 | }; 13 | 14 | std::string InfixToPostfix(const std::string& infix); 15 | 16 | #endif -------------------------------------------------------------------------------- /Includes/Operands/Real.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_REAL_HPP 2 | #define CUBBYCALC_REAL_HPP 3 | 4 | #include 5 | 6 | class Real : public Operand 7 | { 8 | private: 9 | double m_value; 10 | 11 | protected: 12 | Real(const Real&); 13 | 14 | public: 15 | Real(double = 0.0); 16 | 17 | ExpressionTree* Clone() const; 18 | std::string ToString() const; 19 | double Evaluate() const; 20 | }; 21 | 22 | #endif -------------------------------------------------------------------------------- /Includes/Operators/Tangent.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_TANGENT_HPP 2 | #define CUBBYCALC_TANGENT_HPP 3 | 4 | #include 5 | 6 | class Tangent : public UnaryOperator 7 | { 8 | protected: 9 | Tangent(const Tangent&); 10 | 11 | public: 12 | Tangent(ExpressionTree* = 0); 13 | 14 | ExpressionTree* Clone() const; 15 | std::string ToString() const; 16 | double Evaluate() const; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: Windows 3 | pool: 4 | vmImage: 'vs2017-win2016' 5 | steps: 6 | - template: Scripts/azure_pipelines_build_windows.yml 7 | - job: Linux 8 | pool: 9 | vmImage: 'Ubuntu-16.04' 10 | steps: 11 | - template: Scripts/azure_pipelines_build_linux.yml 12 | - job: macOS 13 | pool: 14 | vmImage: 'macOS 10.13' 15 | steps: 16 | - template: Scripts/azure_pipelines_build_macos.yml -------------------------------------------------------------------------------- /Includes/Operators/Power.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_POWER_HPP 2 | #define CUBBYCALC_POWER_HPP 3 | 4 | #include 5 | 6 | class Power : public BinaryOperator 7 | { 8 | protected: 9 | Power(const Power&); 10 | 11 | public: 12 | Power(ExpressionTree* = 0, ExpressionTree* = 0); 13 | 14 | ExpressionTree* Clone() const; 15 | std::string ToString() const; 16 | double Evaluate() const; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /Includes/Operands/Integer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_INTEGER_HPP 2 | #define CUBBYCALC_INTEGER_HPP 3 | 4 | #include 5 | 6 | class Integer : public Operand 7 | { 8 | private: 9 | int m_value; 10 | 11 | protected: 12 | Integer(const Integer&); 13 | 14 | public: 15 | Integer(int = 0); 16 | 17 | ExpressionTree* Clone() const; 18 | std::string ToString() const; 19 | double Evaluate() const; 20 | }; 21 | 22 | #endif -------------------------------------------------------------------------------- /Includes/Operators/Divide.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_DIVIDE_HPP 2 | #define CUBBYCALC_DIVIDE_HPP 3 | 4 | #include 5 | 6 | class Divide : public BinaryOperator 7 | { 8 | protected: 9 | Divide(const Divide&); 10 | 11 | public: 12 | Divide(ExpressionTree* = 0, ExpressionTree* = 0); 13 | 14 | ExpressionTree* Clone() const; 15 | std::string ToString() const; 16 | double Evaluate() const; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /Includes/Operators/Multiply.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_MULTIPLY_HPP 2 | #define CUBBYCALC_MULTIPLY_HPP 3 | 4 | #include 5 | 6 | class Multiply : public BinaryOperator 7 | { 8 | protected: 9 | Multiply(const Multiply&); 10 | 11 | public: 12 | Multiply(ExpressionTree* = 0, ExpressionTree* = 0); 13 | 14 | ExpressionTree* Clone() const; 15 | std::string ToString() const; 16 | double Evaluate() const; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /Sources/Operators/Sine.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | Sine::Sine(ExpressionTree* child) 6 | : UnaryOperator(child) 7 | { } 8 | 9 | Sine::Sine(const Sine& sineNode) 10 | : UnaryOperator(sineNode) 11 | { } 12 | 13 | ExpressionTree* Sine::Clone() const 14 | { 15 | return new Sine(*this); 16 | } 17 | 18 | std::string Sine::ToString() const 19 | { 20 | return "sin"; 21 | } 22 | 23 | double Sine::Evaluate() const 24 | { 25 | return std::sin(m_tree->Evaluate()); 26 | } -------------------------------------------------------------------------------- /Sources/Operators/Plus.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Plus::Plus(ExpressionTree* left, ExpressionTree* right) 4 | : BinaryOperator(left, right) 5 | { } 6 | 7 | Plus::Plus(const Plus& plusNode) 8 | : BinaryOperator(plusNode) 9 | { } 10 | 11 | ExpressionTree* Plus::Clone() const 12 | { 13 | return new Plus(*this); 14 | } 15 | 16 | std::string Plus::ToString() const 17 | { 18 | return "+"; 19 | } 20 | 21 | double Plus::Evaluate() const 22 | { 23 | return m_leftTree->Evaluate() + m_rightTree->Evaluate(); 24 | } -------------------------------------------------------------------------------- /Sources/Operators/Cosine.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | Cosine::Cosine(ExpressionTree* child) 6 | : UnaryOperator(child) 7 | { } 8 | 9 | Cosine::Cosine(const Cosine& cosineNode) 10 | : UnaryOperator(cosineNode) 11 | { } 12 | 13 | ExpressionTree* Cosine::Clone() const 14 | { 15 | return new Cosine(*this); 16 | } 17 | 18 | std::string Cosine::ToString() const 19 | { 20 | return "cos"; 21 | } 22 | 23 | double Cosine::Evaluate() const 24 | { 25 | return std::cos(m_tree->Evaluate()); 26 | } -------------------------------------------------------------------------------- /Sources/Operators/Tangent.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | Tangent::Tangent(ExpressionTree* child) 6 | : UnaryOperator(child) 7 | { } 8 | 9 | Tangent::Tangent(const Tangent& tangentNode) 10 | : UnaryOperator(tangentNode) 11 | { } 12 | 13 | ExpressionTree* Tangent::Clone() const 14 | { 15 | return new Tangent(*this); 16 | } 17 | 18 | std::string Tangent::ToString() const 19 | { 20 | return "tan"; 21 | } 22 | 23 | double Tangent::Evaluate() const 24 | { 25 | return std::tan(m_tree->Evaluate()); 26 | } -------------------------------------------------------------------------------- /Includes/Operators/Assign.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_ASSIGN_HPP 2 | #define CUBBYCALC_ASSIGN_HPP 3 | 4 | #include 5 | 6 | class Assign : public BinaryOperator 7 | { 8 | private: 9 | VariableTable& m_varTable; 10 | 11 | protected: 12 | Assign(const Assign&); 13 | 14 | public: 15 | Assign(ExpressionTree*, ExpressionTree*, VariableTable&); 16 | 17 | ExpressionTree* Clone() const; 18 | std::string ToString() const; 19 | double Evaluate() const; 20 | virtual std::string GetInfix(bool = false) const; 21 | }; 22 | 23 | 24 | #endif -------------------------------------------------------------------------------- /Sources/Operands/Operand.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | Operand::Operand() 7 | { } 8 | 9 | Operand::Operand(const Operand& operandNode) 10 | : ExpressionTree(operandNode) 11 | { } 12 | 13 | std::string Operand::GetPostfix() const 14 | { 15 | return (ToString() + " "); 16 | } 17 | 18 | std::string Operand::GetInfix(bool) const 19 | { 20 | return ToString(); 21 | } 22 | 23 | void Operand::Print(std::ostream& os, int depth) const 24 | { 25 | os << std::setw(depth) << ToString() << std::endl; 26 | } -------------------------------------------------------------------------------- /Sources/Operands/Real.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | Real::Real(double value) 7 | : m_value(value) 8 | { } 9 | 10 | Real::Real(const Real& realNode) 11 | : Operand(realNode), m_value(realNode.m_value) 12 | { } 13 | 14 | std::string Real::ToString() const 15 | { 16 | std::ostringstream oss; 17 | oss << m_value; 18 | return oss.str(); 19 | } 20 | 21 | double Real::Evaluate() const 22 | { 23 | return m_value; 24 | } 25 | 26 | ExpressionTree* Real::Clone() const 27 | { 28 | return new Real(*this); 29 | } -------------------------------------------------------------------------------- /Sources/Operators/Multiply.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Multiply::Multiply(ExpressionTree* left, ExpressionTree* right) 4 | : BinaryOperator(left, right) 5 | { } 6 | 7 | Multiply::Multiply(const Multiply& multiplyNode) 8 | : BinaryOperator(multiplyNode) 9 | { } 10 | 11 | ExpressionTree* Multiply::Clone() const 12 | { 13 | return new Multiply(*this); 14 | } 15 | 16 | std::string Multiply::ToString() const 17 | { 18 | return "*"; 19 | } 20 | 21 | double Multiply::Evaluate() const 22 | { 23 | return m_leftTree->Evaluate() * m_rightTree->Evaluate(); 24 | } -------------------------------------------------------------------------------- /Sources/Operators/Power.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | Power::Power(ExpressionTree* left, ExpressionTree* right) 6 | : BinaryOperator(left, right) 7 | { } 8 | 9 | Power::Power(const Power& powerNode) 10 | : BinaryOperator(powerNode) 11 | { } 12 | 13 | ExpressionTree* Power::Clone() const 14 | { 15 | return new Power(*this); 16 | } 17 | 18 | std::string Power::ToString() const 19 | { 20 | return "^"; 21 | } 22 | 23 | double Power::Evaluate() const 24 | { 25 | return std::pow(m_leftTree->Evaluate(), m_rightTree->Evaluate()); 26 | } -------------------------------------------------------------------------------- /Includes/Operands/Variable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_VARIABLE_HPP 2 | #define CUBBYCALC_VARIABLE_HPP 3 | 4 | #include 5 | 6 | class Variable : public Operand 7 | { 8 | private: 9 | std::string m_token; 10 | VariableTable& m_varTable; 11 | 12 | protected: 13 | Variable(const Variable&); 14 | 15 | public: 16 | Variable(const std::string&, VariableTable&); 17 | 18 | double GetValue() const; 19 | void SetValue(const double&); 20 | 21 | ExpressionTree* Clone() const; 22 | std::string ToString() const; 23 | double Evaluate() const; 24 | }; 25 | 26 | #endif -------------------------------------------------------------------------------- /Sources/Operands/Integer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | Integer::Integer(int value) 7 | : m_value(value) 8 | { } 9 | 10 | Integer::Integer(const Integer& integerNode) 11 | : Operand(integerNode), m_value(integerNode.m_value) 12 | { } 13 | 14 | std::string Integer::ToString() const 15 | { 16 | std::ostringstream oss; 17 | oss << m_value; 18 | return oss.str(); 19 | } 20 | 21 | ExpressionTree* Integer::Clone() const 22 | { 23 | return new Integer(*this); 24 | } 25 | 26 | double Integer::Evaluate() const 27 | { 28 | return m_value; 29 | } -------------------------------------------------------------------------------- /Includes/Operands/Operand.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_OPERAND_HPP 2 | #define CUBBYCALC_OPERAND_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | class Operand : public ExpressionTree 10 | { 11 | protected: 12 | Operand(const Operand&); 13 | 14 | public: 15 | Operand(); 16 | 17 | virtual double Evaluate() const = 0; 18 | virtual ExpressionTree* Clone() const = 0; 19 | virtual std::string ToString() const = 0; 20 | virtual std::string GetPostfix() const; 21 | virtual void Print(std::ostream&, int = 0) const; 22 | virtual std::string GetInfix(bool = false) const; 23 | }; 24 | 25 | #endif -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.1 ({build}) 2 | 3 | skip_branch_with_pr: true 4 | 5 | os: 6 | - Visual Studio 2017 7 | 8 | platform: 9 | - x64 10 | 11 | matrix: 12 | fast_finish: true # Stop remaining jobs after a job failure 13 | 14 | configuration: 15 | - Release 16 | 17 | clone_folder: C:\CubbyCalc 18 | 19 | install: 20 | - git submodule update --init 21 | - ps: | 22 | $env:CMAKE_GENERATOR = "Visual Studio 15 2017 Win64" 23 | 24 | before_build: 25 | - md C:\CubbyCalc\build 26 | - cd C:\CubbyCalc\build 27 | - cmake .. -G "%CMAKE_GENERATOR%" 28 | 29 | build: 30 | project: C:\CubbyCalc\build\CubbyCalc.sln 31 | parallel: true 32 | verbosity: normal -------------------------------------------------------------------------------- /Sources/Operators/Divide.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Divide::Divide(ExpressionTree* left, ExpressionTree* right) 4 | : BinaryOperator(left, right) 5 | { } 6 | 7 | Divide::Divide(const Divide& divideNode) 8 | : BinaryOperator(divideNode) 9 | { } 10 | 11 | ExpressionTree* Divide::Clone() const 12 | { 13 | return new Divide(*this); 14 | } 15 | 16 | std::string Divide::ToString() const 17 | { 18 | return "/"; 19 | } 20 | 21 | double Divide::Evaluate() const 22 | { 23 | double tempEval = m_rightTree->Evaluate(); 24 | 25 | if (tempEval == 0) 26 | { 27 | throw ExpressionTreeError("Divided by 0"); 28 | } 29 | 30 | return m_leftTree->Evaluate() / tempEval; 31 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | matrix: 4 | include: 5 | # Test Docker based on Ubuntu 18.04 LTS + gcc 6 | - os: linux 7 | dist: trusty 8 | sudo: required 9 | services: docker 10 | script: 11 | - sh Scripts/travis_build_docker.sh Scripts/Dockerfile.bionic bionic 12 | # Test OS X 10.12 + Xcode 9 + clang 13 | - os: osx 14 | osx_image: xcode9 15 | compiler: clang 16 | script: 17 | - sh Scripts/travis_build.sh 18 | 19 | before_install: 20 | - eval "${MATRIX_EVAL}" 21 | - if [ $TRAVIS_OS_NAME == linux ]; then 22 | sudo apt-get update -qq; 23 | fi 24 | - if [ $TRAVIS_OS_NAME == osx ]; then 25 | brew update; 26 | fi 27 | -------------------------------------------------------------------------------- /Includes/Operators/UnaryOperator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_UNARY_OPERATOR_HPP 2 | #define CUBBYCALC_UNARY_OPERATOR_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | class UnaryOperator : public ExpressionTree 9 | { 10 | private: 11 | UnaryOperator& operator=(const UnaryOperator&); 12 | 13 | protected: 14 | UnaryOperator(ExpressionTree*); 15 | UnaryOperator(const UnaryOperator&); 16 | 17 | ExpressionTree* m_tree; 18 | 19 | public: 20 | ~UnaryOperator(); 21 | 22 | virtual double Evaluate() const = 0; 23 | virtual ExpressionTree* Clone() const = 0; 24 | virtual std::string GetPostfix() const; 25 | virtual void Print(std::ostream&, int = 0) const; 26 | virtual std::string GetInfix(bool = false) const; 27 | }; 28 | 29 | #endif -------------------------------------------------------------------------------- /Includes/Operators/Minus.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_MINUS_HPP 2 | #define CUBBYCALC_MINUS_HPP 3 | 4 | #include 5 | #include 6 | 7 | class UnaryMinus : public UnaryOperator 8 | { 9 | protected: 10 | UnaryMinus(const UnaryMinus&); 11 | 12 | public: 13 | UnaryMinus(ExpressionTree* = 0); 14 | 15 | ExpressionTree* Clone() const; 16 | std::string ToString() const; 17 | double Evaluate() const; 18 | }; 19 | 20 | class BinaryMinus : public BinaryOperator 21 | { 22 | protected: 23 | BinaryMinus(const BinaryMinus&); 24 | 25 | public: 26 | BinaryMinus(ExpressionTree* = 0, ExpressionTree* = 0); 27 | 28 | ExpressionTree* Clone() const; 29 | std::string ToString() const; 30 | double Evaluate() const; 31 | }; 32 | 33 | 34 | #endif -------------------------------------------------------------------------------- /Includes/Operators/BinaryOperator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_BINARY_OPERATOR_HPP 2 | #define CUBBYCALC_BINARY_OPERATOR_HPP 3 | 4 | #include 5 | #include 6 | 7 | class BinaryOperator : public ExpressionTree 8 | { 9 | private: 10 | BinaryOperator& operator=(const BinaryOperator&); 11 | 12 | protected: 13 | BinaryOperator(ExpressionTree*, ExpressionTree*); 14 | BinaryOperator(const BinaryOperator&); 15 | 16 | ExpressionTree* m_leftTree; 17 | ExpressionTree* m_rightTree; 18 | 19 | public: 20 | ~BinaryOperator(); 21 | 22 | virtual double Evaluate() const = 0; 23 | virtual ExpressionTree* Clone() const = 0; 24 | virtual std::string GetPostfix() const; 25 | virtual void Print(std::ostream&, int = 0) const; 26 | virtual std::string GetInfix(bool = false) const; 27 | }; 28 | 29 | #endif -------------------------------------------------------------------------------- /Includes/Variables/VariableTable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_VARIABLE_TABLE_HPP 2 | #define CUBBYCALC_VARIABLE_TABLE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class VariableTableError : public std::logic_error 9 | { 10 | public: 11 | explicit VariableTableError(const std::string& whatArg) throw() 12 | : logic_error(whatArg) { } 13 | }; 14 | 15 | class VariableTable 16 | { 17 | private: 18 | std::map m_varTable; 19 | 20 | public: 21 | VariableTable(); 22 | ~VariableTable(); 23 | 24 | void Insert(const std::string&, const double&); 25 | void Remove(const std::string&); 26 | bool Find(const std::string&) const; 27 | double GetValue(const std::string&) const; 28 | void SetValue(const std::string&, const double&); 29 | void List(std::ostream&) const; 30 | void Clear(); 31 | bool Empty() const; 32 | }; 33 | 34 | #endif -------------------------------------------------------------------------------- /Includes/Expressions/ExpressionTree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_EXPRESSION_TREE_HPP 2 | #define CUBBYCALC_EXPRESSION_TREE_HPP 3 | 4 | #include 5 | 6 | class ExpressionTreeError : public std::logic_error 7 | { 8 | public: 9 | explicit ExpressionTreeError(const std::string& whatArg) throw() 10 | : logic_error(whatArg) { } 11 | }; 12 | 13 | class ExpressionTree 14 | { 15 | private: 16 | ExpressionTree& operator=(const ExpressionTree&); 17 | 18 | protected: 19 | ExpressionTree(const ExpressionTree&); 20 | public: 21 | ExpressionTree(); 22 | virtual ~ExpressionTree(); 23 | 24 | virtual double Evaluate() const = 0; 25 | virtual std::string GetPostfix() const = 0; 26 | virtual std::string ToString() const = 0; 27 | virtual void Print(std::ostream&, int = 0) const = 0; 28 | virtual ExpressionTree* Clone() const = 0; 29 | virtual std::string GetInfix(bool = false) const = 0; 30 | }; 31 | 32 | #endif -------------------------------------------------------------------------------- /Includes/Expressions/ExpressionMaker.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_EXPRESSION_MAKER_HPP 2 | #define CUBBYCALC_EXPRESSION_MAKER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | class ExpressionMakerError : public std::logic_error 12 | { 13 | public: 14 | explicit ExpressionMakerError(const std::string& whatArg) throw() 15 | : logic_error(whatArg) { } 16 | }; 17 | 18 | class ExpressionMaker 19 | { 20 | private: 21 | bool m_isTreeGenerated; 22 | std::string m_postfix; 23 | Expression m_internalExpression; 24 | VariableTable& m_varTable; 25 | 26 | ExpressionTree* MakeExpressionTree(const std::string&); 27 | 28 | public: 29 | ExpressionMaker(VariableTable&); 30 | ~ExpressionMaker(); 31 | 32 | Expression GetExpression(); 33 | void SetPostfix(const std::string&); 34 | }; 35 | 36 | #endif -------------------------------------------------------------------------------- /Includes/Expressions/Expression.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_EXPRESSION_HPP 2 | #define CUBBYCALC_EXPRESSION_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | class ExpressionError : public std::logic_error 9 | { 10 | public: 11 | explicit ExpressionError(const std::string& whatArg) throw() 12 | : logic_error(whatArg) { } 13 | }; 14 | 15 | class Expression 16 | { 17 | private: 18 | ExpressionTree* m_topNode; 19 | public: 20 | friend class Calculator; 21 | 22 | Expression(ExpressionTree* = 0); 23 | ~Expression(); 24 | 25 | Expression(const Expression&); 26 | 27 | Expression& operator=(Expression&); 28 | Expression& operator=(ExpressionTree*); 29 | 30 | double Evaluate() const; 31 | void PrintTree(std::ostream&) const; 32 | std::string GetPostfix() const; 33 | std::string GetInfix() const; 34 | void Swap(Expression&); 35 | bool Empty() const; 36 | bool TopNodeIsAssign() const; 37 | }; 38 | 39 | #endif -------------------------------------------------------------------------------- /Sources/Operands/Variable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | Variable::Variable(const std::string& token, VariableTable& varTable) 9 | : m_token(token), m_varTable(varTable) 10 | { } 11 | 12 | Variable::Variable(const Variable& variableNode) 13 | : Operand(variableNode), m_token(variableNode.m_token), m_varTable(variableNode.m_varTable) 14 | { } 15 | 16 | double Variable::Evaluate() const 17 | { 18 | return GetValue(); 19 | } 20 | 21 | ExpressionTree* Variable::Clone() const 22 | { 23 | return new Variable(*this); 24 | } 25 | 26 | double Variable::GetValue() const 27 | { 28 | return m_varTable.GetValue(m_token); 29 | } 30 | 31 | void Variable::SetValue(const double& value) 32 | { 33 | m_varTable.SetValue(m_token, value); 34 | } 35 | 36 | std::string Variable::ToString() const 37 | { 38 | return m_token; 39 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake version 2 | cmake_minimum_required(VERSION 3.8.2 FATAL_ERROR) 3 | 4 | # Include cmake modules 5 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") 6 | 7 | # Declare project 8 | project(CubbyCalc) 9 | 10 | # Set output directories 11 | set(DEFAULT_CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) 13 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) 14 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) 15 | 16 | # Set enable output of compile commands during generation 17 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 18 | 19 | # Includes 20 | include_directories(Includes) 21 | include_directories(Libraries) 22 | 23 | # Compile options 24 | include(CMake/CompileOptions.cmake) 25 | 26 | # Build type - Release by default 27 | if (NOT CMAKE_BUILD_TYPE) 28 | set(CMAKE_BUILD_TYPE Release) 29 | endif() 30 | 31 | # Overrides 32 | set(CMAKE_MACOSX_RPATH ON) 33 | 34 | # Project modules 35 | add_subdirectory(Sources) -------------------------------------------------------------------------------- /Sources/Operators/Minus.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | UnaryMinus::UnaryMinus(ExpressionTree* child) 4 | : UnaryOperator(child) 5 | { } 6 | 7 | UnaryMinus::UnaryMinus(const UnaryMinus& minusNode) 8 | : UnaryOperator(minusNode) 9 | { } 10 | 11 | ExpressionTree* UnaryMinus::Clone() const 12 | { 13 | return new UnaryMinus(*this); 14 | } 15 | 16 | std::string UnaryMinus::ToString() const 17 | { 18 | return "-"; 19 | } 20 | 21 | double UnaryMinus::Evaluate() const 22 | { 23 | return -1 * m_tree->Evaluate(); 24 | } 25 | 26 | BinaryMinus::BinaryMinus(ExpressionTree* left, ExpressionTree* right) 27 | : BinaryOperator(left, right) 28 | { } 29 | 30 | BinaryMinus::BinaryMinus(const BinaryMinus& minusNode) 31 | : BinaryOperator(minusNode) 32 | { } 33 | 34 | ExpressionTree* BinaryMinus::Clone() const 35 | { 36 | return new BinaryMinus(*this); 37 | } 38 | 39 | std::string BinaryMinus::ToString() const 40 | { 41 | return "-"; 42 | } 43 | 44 | double BinaryMinus::Evaluate() const 45 | { 46 | return m_leftTree->Evaluate() - m_rightTree->Evaluate(); 47 | } -------------------------------------------------------------------------------- /Sources/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Target name 2 | set(target CubbyCalc) 3 | 4 | # Define 5 | set(root_dir ${CMAKE_CURRENT_SOURCE_DIR}/..) 6 | 7 | # Includes 8 | include_directories( 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../Includes 10 | ${CMAKE_CURRENT_SOURCE_DIR}/../Libraries 11 | ) 12 | 13 | # Sources 14 | file(GLOB header_dir 15 | ${root_dir}/Includes) 16 | 17 | file(GLOB_RECURSE headers 18 | ${header_dir}/*.hpp) 19 | 20 | file(GLOB_RECURSE sources 21 | ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 22 | 23 | # Build library 24 | add_library(${target} 25 | ${sources}) 26 | 27 | # Project options 28 | set_target_properties(${target} 29 | PROPERTIES 30 | ${DEFAULT_PROJECT_OPTIONS} 31 | ) 32 | 33 | # Compile options 34 | target_compile_options(${target} 35 | PRIVATE 36 | 37 | PUBLIC 38 | ${DEFAULT_COMPILE_OPTIONS} 39 | 40 | INTERFACE 41 | ) 42 | 43 | target_link_libraries(${target} 44 | PRIVATE 45 | 46 | PUBLIC 47 | ${DEFAULT_LINKER_OPTIONS} 48 | 49 | INTERFACE 50 | ) 51 | 52 | # Install 53 | install(TARGETS ${target} DESTINATION lib) 54 | install(DIRECTORY ${header_dir} DESTINATION include) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Chris Ohk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Sources/Operators/UnaryOperator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | UnaryOperator::UnaryOperator(ExpressionTree* child) 7 | : m_tree(child) 8 | { 9 | if (!child) 10 | { 11 | delete m_tree; 12 | 13 | throw ExpressionTreeError("Operator can't operate"); 14 | } 15 | } 16 | 17 | UnaryOperator::UnaryOperator(const UnaryOperator& operatorNode) 18 | : ExpressionTree(operatorNode), m_tree(operatorNode.m_tree->Clone()) 19 | { } 20 | 21 | UnaryOperator::~UnaryOperator() 22 | { 23 | delete m_tree; 24 | } 25 | 26 | std::string UnaryOperator::GetPostfix() const 27 | { 28 | return (m_tree->GetPostfix() + ToString() + " "); 29 | } 30 | 31 | std::string UnaryOperator::GetInfix(bool isFirst) const 32 | { 33 | return ((isFirst) ? "" : "(") + 34 | ToString() + m_tree->GetInfix() + " " + 35 | ((isFirst) ? "" : ")"); 36 | } 37 | 38 | void UnaryOperator::Print(std::ostream& os, int depth) const 39 | { 40 | m_tree->Print(os, depth + 3); 41 | 42 | os << std::setw(depth + 2) << "/" << std::endl 43 | << std::setw(depth) << ToString() << std::endl 44 | << std::setw(depth + 2) << "\\" << std::endl; 45 | } -------------------------------------------------------------------------------- /Sources/Operators/Assign.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | Assign::Assign(ExpressionTree* left, ExpressionTree* right, VariableTable& varTable) 5 | : BinaryOperator(left, right), m_varTable(varTable) 6 | { } 7 | 8 | Assign::Assign(const Assign& assignNode) 9 | : BinaryOperator(assignNode), m_varTable(assignNode.m_varTable) 10 | { } 11 | 12 | ExpressionTree* Assign::Clone() const 13 | { 14 | return new Assign(*this); 15 | } 16 | 17 | std::string Assign::ToString() const 18 | { 19 | return "="; 20 | } 21 | 22 | std::string Assign::GetInfix(bool) const 23 | { 24 | return m_leftTree->GetInfix(true) + " " + ToString() + " " + m_rightTree->GetInfix(true); 25 | } 26 | 27 | double Assign::Evaluate() const 28 | { 29 | double rightTreeValue = m_rightTree->Evaluate(); 30 | Variable* varPointer = dynamic_cast(m_leftTree); 31 | 32 | if (varPointer) 33 | { 34 | if (m_varTable.Find(varPointer->ToString())) 35 | { 36 | varPointer->SetValue(rightTreeValue); 37 | } 38 | else 39 | { 40 | m_varTable.Insert(varPointer->ToString(), rightTreeValue); 41 | } 42 | } 43 | else 44 | { 45 | throw ExpressionTreeError("Invalid Assign"); 46 | } 47 | 48 | return rightTreeValue; 49 | } -------------------------------------------------------------------------------- /Includes/Programs/Calculator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_CALCULATOR_HPP 2 | #define CUBBYCALC_CALCULATOR_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | class Calculator 11 | { 12 | private: 13 | Calculator(const Calculator&); 14 | Calculator& operator=(const Calculator&); 15 | 16 | ExpressionMaker m_expMaker; 17 | VariableTable m_varTable; 18 | 19 | static const std::string m_validCommand; 20 | static const std::string m_numberedCommand; 21 | Expression m_currentExpression; 22 | char m_command; 23 | size_t m_expressionNumber; 24 | int m_expressionNR; 25 | std::vector m_oldExpressions; 26 | 27 | void PrintHelp(); 28 | void GetCommand(); 29 | bool ValidCommand(); 30 | void ExecuteCommand(); 31 | void PrintExpression(std::ostream&) const; 32 | void EvaluateAndPrintExpression(std::ostream&) const; 33 | void PrintPostfix(std::ostream&) const; 34 | void PrintInfix(std::ostream&) const; 35 | void PrintTree(std::ostream&) const; 36 | void SetCurrentExpression(); 37 | void ReadExpression(std::istream&); 38 | 39 | std::vector SplitExpression(const std::string&, const std::string&); 40 | public: 41 | Calculator(); 42 | ~Calculator(); 43 | 44 | void Run(); 45 | }; 46 | 47 | #endif -------------------------------------------------------------------------------- /Includes/Commons/Constants.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUBBYCALC_CONSTANTS_HPP 2 | #define CUBBYCALC_CONSTANTS_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace 9 | { 10 | const char* ops[] = { "+", "-", "*", "/", "=", "^", "u-", "sin", "cos", "tan", "(" }; 11 | const int init_input_priority[] = { 4, 4, 5, 5, 1, 6, 7, 7, 7, 7, 8 }; 12 | const int init_stack_priority[] = { 4, 4, 5, 5, 1, 6, 7, 7, 7, 7, 0 }; 13 | const int n_ops = sizeof(ops) / sizeof(char*); 14 | 15 | const std::vector operators(ops, ops + n_ops); 16 | 17 | const std::string digits("0123456789"); 18 | const std::string integer_chars(digits); 19 | const std::string real_chars(digits + '.'); 20 | const std::string identifier_chars("abcdefghijklmnopqrstuvwxyz"); 21 | const std::string operand_chars(identifier_chars + digits + '.'); 22 | 23 | typedef std::map priority_table; 24 | 25 | priority_table init_priority_table(const char* op_list[], const int* priority, const int n_op_list) 26 | { 27 | priority_table temp; 28 | 29 | for (int i = 0; i < n_op_list; ++i) 30 | { 31 | temp.insert(std::make_pair(std::string(op_list[i]), priority[i])); 32 | } 33 | 34 | return temp; 35 | } 36 | 37 | const priority_table input_priority = init_priority_table(ops, init_input_priority, n_ops); 38 | const priority_table stack_priority = init_priority_table(ops, init_stack_priority, n_ops); 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /Sources/Operators/BinaryOperator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | BinaryOperator::BinaryOperator(ExpressionTree* left, ExpressionTree* right) 9 | : m_leftTree(left), m_rightTree(right) 10 | { 11 | if (!(left && right)) 12 | { 13 | delete m_leftTree; 14 | delete m_rightTree; 15 | throw ExpressionTreeError("Operator can't operate"); 16 | } 17 | } 18 | 19 | BinaryOperator::BinaryOperator(const BinaryOperator& operatorNode) 20 | : ExpressionTree(operatorNode), m_leftTree(operatorNode.m_leftTree->Clone()), m_rightTree(operatorNode.m_rightTree->Clone()) 21 | { } 22 | 23 | BinaryOperator::~BinaryOperator() 24 | { 25 | delete m_leftTree; 26 | delete m_rightTree; 27 | } 28 | 29 | std::string BinaryOperator::GetPostfix() const 30 | { 31 | return (m_leftTree->GetPostfix() + m_rightTree->GetPostfix() + ToString() + " "); 32 | } 33 | 34 | std::string BinaryOperator::GetInfix(bool isFirst) const 35 | { 36 | return ((isFirst) ? "" : "(") + 37 | m_leftTree->GetInfix() + " " + ToString() + " " + m_rightTree->GetInfix() + 38 | ((isFirst) ? "" : ")"); 39 | } 40 | 41 | void BinaryOperator::Print(std::ostream& os, int depth) const 42 | { 43 | m_rightTree->Print(os, depth + 3); 44 | 45 | os << std::setw(depth + 2) << "/" << std::endl 46 | << std::setw(depth) << ToString() << std::endl 47 | << std::setw(depth + 2) << "\\" << std::endl; 48 | 49 | m_leftTree->Print(os, depth + 3); 50 | } -------------------------------------------------------------------------------- /CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file. 3 | "configurations": [ 4 | { 5 | "name": "x86-Debug", 6 | "generator": "Ninja", 7 | "configurationType": "Debug", 8 | "inheritEnvironments": [ "msvc_x86" ], 9 | "buildRoot": "${workspaceRoot}\\build\\${name}", 10 | "installRoot": "${env.USERPROFILE}", 11 | "cmakeCommandArgs": "", 12 | "buildCommandArgs": "-v", 13 | "ctestCommandArgs": "" 14 | }, 15 | { 16 | "name": "x86-Release", 17 | "generator": "Ninja", 18 | "configurationType": "Release", 19 | "inheritEnvironments": [ "msvc_x86" ], 20 | "buildRoot": "${workspaceRoot}\\build\\${name}", 21 | "installRoot": "${env.USERPROFILE}", 22 | "cmakeCommandArgs": "", 23 | "buildCommandArgs": "-v", 24 | "ctestCommandArgs": "" 25 | }, 26 | { 27 | "name": "x64-Debug", 28 | "generator": "Ninja", 29 | "configurationType": "Debug", 30 | "inheritEnvironments": [ "msvc_x64_x64" ], 31 | "buildRoot": "${workspaceRoot}\\build\\${name}", 32 | "installRoot": "${env.USERPROFILE}", 33 | "cmakeCommandArgs": "", 34 | "buildCommandArgs": "-v", 35 | "ctestCommandArgs": "" 36 | }, 37 | { 38 | "name": "x64-Release", 39 | "generator": "Ninja", 40 | "configurationType": "Release", 41 | "inheritEnvironments": [ "msvc_x64_x64" ], 42 | "buildRoot": "${workspaceRoot}\\build\\${name}", 43 | "installRoot": "${env.USERPROFILE}", 44 | "cmakeCommandArgs": "", 45 | "buildCommandArgs": "-v", 46 | "ctestCommandArgs": "" 47 | } 48 | ] 49 | } -------------------------------------------------------------------------------- /Sources/Variables/VariableTable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | typedef std::map variable_table; 8 | 9 | VariableTable::VariableTable() 10 | { } 11 | 12 | VariableTable::~VariableTable() 13 | { } 14 | 15 | void VariableTable::Insert(const std::string& token, const double& value) 16 | { 17 | if (Find(token)) 18 | { 19 | throw VariableTableError("Error: Token already exists"); 20 | } 21 | 22 | m_varTable.insert(std::make_pair(token, value)); 23 | } 24 | 25 | void VariableTable::Remove(const std::string& token) 26 | { 27 | if (!Find(token)) 28 | { 29 | throw VariableTableError("Error: Token not exists"); 30 | } 31 | 32 | m_varTable.erase(token); 33 | } 34 | 35 | bool VariableTable::Find(const std::string& token) const 36 | { 37 | return (m_varTable.find(token) != m_varTable.end()); 38 | } 39 | 40 | double VariableTable::GetValue(const std::string& token) const 41 | { 42 | variable_table::const_iterator iter = m_varTable.find(token); 43 | 44 | if (iter == m_varTable.end()) 45 | { 46 | throw VariableTableError("Error: Can't find token"); 47 | } 48 | 49 | return iter->second; 50 | } 51 | 52 | void VariableTable::SetValue(const std::string& token, const double& value) 53 | { 54 | variable_table::iterator iter = m_varTable.find(token); 55 | 56 | if (iter == m_varTable.end()) 57 | { 58 | throw VariableTableError("Error: Can't find token"); 59 | } 60 | 61 | iter->second = value; 62 | } 63 | 64 | void VariableTable::List(std::ostream& os) const 65 | { 66 | for (auto token : m_varTable) 67 | { 68 | os << token.first << ": " << token.second << std::endl; 69 | } 70 | } 71 | 72 | void VariableTable::Clear() 73 | { 74 | m_varTable.clear(); 75 | } 76 | 77 | bool VariableTable::Empty() const 78 | { 79 | return m_varTable.empty(); 80 | } -------------------------------------------------------------------------------- /Sources/Expressions/Expression.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | Expression::Expression(ExpressionTree* expTree) 8 | : m_topNode(expTree) 9 | { } 10 | 11 | Expression::~Expression() 12 | { 13 | if (m_topNode != nullptr) 14 | { 15 | delete m_topNode; 16 | m_topNode = nullptr; 17 | } 18 | } 19 | 20 | Expression::Expression(const Expression& exp) 21 | : m_topNode(nullptr) 22 | { 23 | if (!exp.Empty()) 24 | { 25 | m_topNode = exp.m_topNode->Clone(); 26 | } 27 | } 28 | 29 | Expression& Expression::operator=(Expression& exp) 30 | { 31 | if (this != &exp) 32 | { 33 | Expression temp(exp); 34 | Swap(temp); 35 | } 36 | 37 | return *this; 38 | } 39 | 40 | Expression& Expression::operator=(ExpressionTree* expTree) 41 | { 42 | Expression temp(expTree); 43 | Swap(temp); 44 | 45 | return *this; 46 | } 47 | 48 | double Expression::Evaluate() const 49 | { 50 | if (Empty()) 51 | { 52 | throw ExpressionError("Error: Expression is empty!"); 53 | } 54 | 55 | return m_topNode->Evaluate(); 56 | } 57 | 58 | void Expression::PrintTree(std::ostream& os) const 59 | { 60 | if (Empty()) 61 | { 62 | throw ExpressionError("Error: Expression is empty!"); 63 | } 64 | 65 | m_topNode->Print(os); 66 | } 67 | 68 | std::string Expression::GetPostfix() const 69 | { 70 | return Empty() ? "" : m_topNode->GetPostfix(); 71 | } 72 | 73 | std::string Expression::GetInfix() const 74 | { 75 | return Empty() ? "" : m_topNode->GetInfix(true); 76 | } 77 | 78 | void Expression::Swap(Expression& exp) 79 | { 80 | if (this != &exp) 81 | { 82 | std::swap(m_topNode, exp.m_topNode); 83 | } 84 | } 85 | 86 | bool Expression::Empty() const 87 | { 88 | return !m_topNode; 89 | } 90 | 91 | bool Expression::TopNodeIsAssign() const 92 | { 93 | return dynamic_cast(m_topNode); 94 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | *.opendb 198 | -------------------------------------------------------------------------------- /CMake/CompileOptions.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Platform and architecture setup 3 | # 4 | 5 | # Set warnings as errors flag 6 | option(CUBBYFLOW_WARNINGS_AS_ERRORS "Treat all warnings as errors" ON) 7 | if(CUBBYFLOW_WARNINGS_AS_ERRORS) 8 | if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 9 | set(WARN_AS_ERROR_FLAGS "/WX") 10 | else() 11 | set(WARN_AS_ERROR_FLAGS "-Werror") 12 | endif() 13 | endif() 14 | 15 | # Get upper case system name 16 | string(TOUPPER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME_UPPER) 17 | 18 | # Determine architecture (32/64 bit) 19 | set(X64 OFF) 20 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 21 | set(X64 ON) 22 | endif() 23 | 24 | # 25 | # Project options 26 | # 27 | 28 | set(DEFAULT_PROJECT_OPTIONS 29 | CXX_STANDARD 17 # Not available before CMake 3.8.2; see below for manual command line argument addition 30 | LINKER_LANGUAGE "CXX" 31 | POSITION_INDEPENDENT_CODE ON 32 | ) 33 | 34 | # 35 | # Include directories 36 | # 37 | 38 | set(DEFAULT_INCLUDE_DIRECTORIES) 39 | 40 | # 41 | # Libraries 42 | # 43 | 44 | set(DEFAULT_LIBRARIES) 45 | 46 | # 47 | # Compile definitions 48 | # 49 | 50 | set(DEFAULT_COMPILE_DEFINITIONS 51 | SYSTEM_${SYSTEM_NAME_UPPER} 52 | ) 53 | 54 | # MSVC compiler options 55 | if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 56 | set(DEFAULT_COMPILE_DEFINITIONS ${DEFAULT_COMPILE_DEFINITIONS} 57 | _SCL_SECURE_NO_WARNINGS # Calling any one of the potentially unsafe methods in the Standard C++ Library 58 | _CRT_SECURE_NO_WARNINGS # Calling any one of the potentially unsafe methods in the CRT Library 59 | ) 60 | endif () 61 | 62 | # 63 | # Compile options 64 | # 65 | 66 | set(DEFAULT_COMPILE_OPTIONS) 67 | 68 | # MSVC compiler options 69 | if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 70 | # remove default warning level from CMAKE_CXX_FLAGS 71 | string (REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 72 | endif() 73 | 74 | # MSVC compiler options 75 | if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 76 | set(DEFAULT_COMPILE_OPTIONS ${DEFAULT_COMPILE_OPTIONS} 77 | /MP # -> build with multiple processes 78 | /W4 # -> warning level 4 79 | ${WARN_AS_ERROR_FLAGS} 80 | 81 | # /wd4251 # -> disable warning: 'identifier': class 'type' needs to have dll-interface to be used by clients of class 'type2' 82 | # /wd4592 # -> disable warning: 'identifier': symbol will be dynamically initialized (implementation limitation) 83 | # /wd4201 # -> disable warning: nonstandard extension used: nameless struct/union (caused by GLM) 84 | # /wd4127 # -> disable warning: conditional expression is constant (caused by Qt) 85 | 86 | #$<$: 87 | #/RTCc # -> value is assigned to a smaller data type and results in a data loss 88 | #> 89 | 90 | $<$: 91 | /Gw # -> whole program global optimization 92 | /GS- # -> buffer security check: no 93 | /GL # -> whole program optimization: enable link-time code generation (disables Zi) 94 | /GF # -> enable string pooling 95 | > 96 | 97 | # No manual c++11 enable for MSVC as all supported MSVC versions for cmake-init have C++11 implicitly enabled (MSVC >=2013) 98 | ) 99 | endif () 100 | 101 | # GCC and Clang compiler options 102 | if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 103 | set(DEFAULT_COMPILE_OPTIONS ${DEFAULT_COMPILE_OPTIONS} 104 | -Wall 105 | -Wno-missing-braces 106 | 107 | ${WARN_AS_ERROR_FLAGS} 108 | -std=c++1z 109 | ) 110 | endif () 111 | if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") 112 | set(DEFAULT_COMPILE_OPTIONS ${DEFAULT_COMPILE_OPTIONS} 113 | -Wno-int-in-bool-context 114 | ) 115 | endif () 116 | 117 | # 118 | # Linker options 119 | # 120 | 121 | set(DEFAULT_LINKER_OPTIONS) 122 | 123 | # Use pthreads on mingw and linux 124 | if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_SYSTEM_NAME MATCHES "Linux") 125 | set(DEFAULT_LINKER_OPTIONS 126 | -pthread 127 | -lstdc++fs 128 | ) 129 | endif() 130 | -------------------------------------------------------------------------------- /Sources/Expressions/ExpressionMaker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | ExpressionMaker::ExpressionMaker(VariableTable& varTable) 24 | : m_isTreeGenerated(false), m_postfix(""), m_internalExpression(), m_varTable(varTable) 25 | { } 26 | 27 | ExpressionMaker::~ExpressionMaker() 28 | { } 29 | 30 | void ExpressionMaker::SetPostfix(const std::string& postfix) 31 | { 32 | m_postfix = postfix; 33 | m_isTreeGenerated = false; 34 | } 35 | 36 | Expression ExpressionMaker::GetExpression() 37 | { 38 | if (m_postfix == "") 39 | { 40 | throw ExpressionMakerError("Postfix is empty"); 41 | } 42 | else if (!m_isTreeGenerated) 43 | { 44 | Expression e(MakeExpressionTree(m_postfix)); 45 | m_internalExpression = e; 46 | m_isTreeGenerated = true; 47 | } 48 | 49 | return m_internalExpression; 50 | } 51 | 52 | ExpressionTree* ExpressionMaker::MakeExpressionTree(const std::string& postfix) 53 | { 54 | std::stack treeStack; 55 | std::string token; 56 | std::istringstream iss(postfix); 57 | 58 | while (iss >> token) 59 | { 60 | if (token == "u-") 61 | { 62 | ExpressionTree* rhs = treeStack.top(); 63 | treeStack.pop(); 64 | 65 | treeStack.push(new UnaryMinus(rhs)); 66 | } 67 | else if (token == "sin") 68 | { 69 | ExpressionTree* rhs = treeStack.top(); 70 | treeStack.pop(); 71 | 72 | treeStack.push(new Sine(rhs)); 73 | } 74 | else if (token == "cos") 75 | { 76 | ExpressionTree* rhs = treeStack.top(); 77 | treeStack.pop(); 78 | 79 | treeStack.push(new Cosine(rhs)); 80 | } 81 | else if (token == "tan") 82 | { 83 | ExpressionTree* rhs = treeStack.top(); 84 | treeStack.pop(); 85 | 86 | treeStack.push(new Tangent(rhs)); 87 | } 88 | else if (std::find(operators.begin(), operators.end(), token) != operators.end()) 89 | { 90 | ExpressionTree* rhs = treeStack.top(); 91 | treeStack.pop(); 92 | ExpressionTree* lhs = treeStack.top(); 93 | treeStack.pop(); 94 | 95 | if (token == "^") 96 | { 97 | treeStack.push(new Power(lhs, rhs)); 98 | } 99 | else if (token == "*") 100 | { 101 | treeStack.push(new Multiply(lhs, rhs)); 102 | } 103 | else if (token == "/") 104 | { 105 | treeStack.push(new Divide(lhs, rhs)); 106 | } 107 | else if (token == "+") 108 | { 109 | treeStack.push(new Plus(lhs, rhs)); 110 | } 111 | else if (token == "-") 112 | { 113 | treeStack.push(new BinaryMinus(lhs, rhs)); 114 | } 115 | else if (token == "=") 116 | { 117 | treeStack.push(new Assign(lhs, rhs, m_varTable)); 118 | } 119 | } 120 | else if (token.find_first_not_of(integer_chars) == std::string::npos) 121 | { 122 | treeStack.push(new Integer(atoi(token.c_str()))); 123 | } 124 | else if (token.find_first_not_of(real_chars) == std::string::npos) 125 | { 126 | treeStack.push(new Real(atof(token.c_str()))); 127 | } 128 | else if (token.find_first_not_of(identifier_chars) == std::string::npos) 129 | { 130 | treeStack.push(new Variable(token, m_varTable)); 131 | } 132 | else 133 | { 134 | while (!treeStack.empty()) 135 | { 136 | delete treeStack.top(); 137 | treeStack.pop(); 138 | } 139 | 140 | throw ExpressionMakerError("Invalid Postfix"); 141 | } 142 | } 143 | 144 | if (treeStack.empty()) 145 | { 146 | throw ExpressionMakerError("Invalid Postfix"); 147 | } 148 | 149 | if (treeStack.size() > 1) 150 | { 151 | while (!treeStack.empty()) 152 | { 153 | delete treeStack.top(); 154 | treeStack.pop(); 155 | } 156 | 157 | throw ExpressionMakerError("Invalid Postfix"); 158 | } 159 | 160 | return treeStack.top(); 161 | } 162 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Calculator Ver 1.03 2 | 3 | Simple Console Calculator using C++ 4 | 5 | [![License](https://img.shields.io/badge/Licence-MIT-blue.svg)](https://github.com/utilForever/CubbyCalc/blob/master/LICENSE) [![Build Status](https://travis-ci.org/utilForever/CubbyCalc.svg?branch=master)](https://travis-ci.org/utilForever/CubbyCalc/branches) [![Build status](https://ci.appveyor.com/api/projects/status/github/utilForever/CubbyCalc?branch=master&svg=true)](https://ci.appveyor.com/project/utilForever/CubbyCalc/branch/master) [![Build Status](https://dev.azure.com/utilforever/CubbyCalc/_apis/build/status/utilForever.CubbyCalc)](https://dev.azure.com/utilforever/CubbyCalc/_build/latest?definitionId=2) 6 | 7 | ## CodeMap 8 | 9 | ![CodeMap](https://github.com/utilForever/Calculator/blob/master/CodeMap.png) 10 | 11 | ## How to use 12 | 13 | - ?: Help 14 | - R: Read expression 15 | - E: Evaluate and print latest expression 16 | - E n: Evaluate and print nth expression 17 | - P: Print latest expression postfix 18 | - P n: Print nth expression postfix 19 | - I: Print latest expression infix 20 | - I n: Print nth expression infix 21 | - T: Print latest expression tree 22 | - T n: Print nth expression tree 23 | - V: Print variable table list 24 | - Q: Quit 25 | 26 | ``` 27 | Calculator Version 1.02 28 | ? : Help 29 | R : Read expression 30 | E : Evaluate and print latest expression 31 | E n: Evaluate and print nth expression 32 | P : Print latest expression postfix 33 | P n: Print nth expression postfix 34 | I : Print latest expression infix 35 | I n: Print nth expression infix 36 | T : Print latest expression tree 37 | T n: Print nth expression tree 38 | V : Print variable table list 39 | Q : Quit 40 | >> R 41 | a + b*s + c*sin(2*3.14*(d + t/e)) 42 | >> R 43 | a=1 44 | >> R 45 | b=2 46 | >> R 47 | c=3 48 | >> R 49 | d=4 50 | >> R 51 | e=5 52 | >> R 53 | s=5 54 | >> R 55 | t=1.25 56 | >> E 1 57 | 13.9997 58 | ``` 59 | 60 | ## Version History 61 | 62 | - Version 1.00 63 | 64 | - Implement binary operator (+, -, *, /, ^) 65 | - Implement unary operator (-) 66 | - Implement trigonometrical function (sin, cos, tan) 67 | - Implement expression tree (inheritance, polymorphism) 68 | - Implement infix to postfix converter 69 | - Implement variable table 70 | 71 | - Version 1.01 72 | 73 | - Fix the bug (Recognize "sinx" as not "sin" + "x", but "sinx") 74 | 75 | - Version 1.02 76 | 77 | - Constants refactoring (ExpressionMaker.cpp, ExpressionUtil.cpp → Constants.h) 78 | - Create help command 79 | 80 | - Version 1.03 81 | 82 | - Enable to input multiple expressions (Separator: ",") 83 | - Example 84 | ``` 85 | >> R 86 | a=1, b=2, c=3 87 | >> R 88 | a+b+c 89 | >> E 90 | 6 91 | ``` 92 | - Remove friend class declaration (Calculator.h) 93 | - 1st ExpressionTree refactoring (UnaryOperator.h/cpp, BinaryOperator.h/cpp, Operand.h/cpp) 94 | 95 | ## License 96 | 97 | 98 | 99 | The class is licensed under the [MIT License](http://opensource.org/licenses/MIT): 100 | 101 | Copyright © 2015 [Chris Ohk](http://www.github.com/utiLForever) 102 | 103 | 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: 104 | 105 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 106 | 107 | 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. -------------------------------------------------------------------------------- /Sources/Expressions/ExpressionUtil.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::string FormatInfix(const std::string& infix) 10 | { 11 | std::string::const_iterator bos = infix.begin(); 12 | std::string::const_iterator eos = infix.end(); 13 | std::string formatted; 14 | 15 | for (std::string::const_iterator it = bos; it != eos; ++it) 16 | { 17 | if (std::find(operators.begin(), operators.end(), std::string(1, *it)) != operators.end() || *it == '(' || *it == ')') 18 | { 19 | if (it != bos && *(it - 1) != ' ' && *(formatted.end() - 1) != ' ' ) 20 | { 21 | formatted.append(1, ' '); 22 | } 23 | 24 | formatted.append(1, *it); 25 | 26 | if ((it + 1) != eos && *(it + 1) != ' ') 27 | { 28 | formatted.append(1, ' '); 29 | } 30 | } 31 | // sin, cos, tan 32 | else if (infix.size() > 3 && it < eos - 3 && std::find(operators.begin(), operators.end(), std::string(it, it + 3)) != operators.end()) 33 | { 34 | if (it != bos && *(it - 1) != ' ' && *(formatted.end() - 1) != ' ') 35 | { 36 | formatted.append(1, ' '); 37 | } 38 | 39 | formatted.append(it, it + 3); 40 | it += 2; 41 | 42 | if ((it + 1) != eos && *(it + 1) != ' ') 43 | { 44 | formatted.append(1, ' '); 45 | } 46 | } 47 | else 48 | { 49 | if (*it != ' ') 50 | { 51 | formatted.append(1, *it); 52 | } 53 | else if (it != bos && *(it - 1) != ' ') 54 | { 55 | formatted.append(1, *it); 56 | } 57 | } 58 | } 59 | 60 | return formatted; 61 | } 62 | 63 | std::string InfixToPostfix(const std::string& infix) 64 | { 65 | std::stack operatorStack; 66 | std::string token; 67 | std::string previousToken = ""; 68 | int parenCount = 0; 69 | bool isUnary = true; 70 | 71 | std::istringstream is(FormatInfix(infix)); 72 | std::string postfix; 73 | 74 | while (is >> token) 75 | { 76 | if (token != "(" && std::find(operators.begin(), operators.end(), token) != operators.end()) 77 | { 78 | if (previousToken == "(") 79 | { 80 | throw InfixError("Operator can't evaluate with invalid operands"); 81 | } 82 | 83 | if (isUnary && token == "-") 84 | { 85 | token = "u" + token; 86 | } 87 | else 88 | { 89 | while (!operatorStack.empty() && input_priority.find(token)->second <= stack_priority.find(operatorStack.top())->second) 90 | { 91 | postfix += operatorStack.top() + ' '; 92 | operatorStack.pop(); 93 | } 94 | } 95 | 96 | operatorStack.push(token); 97 | isUnary = true; 98 | } 99 | else if (token == "(") 100 | { 101 | operatorStack.push(token); 102 | ++parenCount; 103 | } 104 | else if (token == ")") 105 | { 106 | if (parenCount == 0) 107 | { 108 | throw InfixError("Invalid Paren"); 109 | } 110 | if (previousToken == "(" && !postfix.empty()) 111 | { 112 | throw InfixError("Invalid Paren"); 113 | } 114 | 115 | while (!operatorStack.empty() && operatorStack.top() != "(") 116 | { 117 | postfix += operatorStack.top() + ' '; 118 | operatorStack.pop(); 119 | } 120 | 121 | operatorStack.pop(); 122 | --parenCount; 123 | } 124 | else if (token.find_first_not_of(operand_chars) == std::string::npos) 125 | { 126 | if (previousToken == ")") 127 | { 128 | throw InfixError("Operator can't evaluate with invalid operands"); 129 | } 130 | 131 | postfix += token + ' '; 132 | isUnary = false; 133 | } 134 | else 135 | { 136 | throw InfixError("Undefined Symbol"); 137 | } 138 | 139 | previousToken = token; 140 | } 141 | 142 | if (parenCount > 0) 143 | { 144 | throw InfixError("Invalid Paren"); 145 | } 146 | 147 | while (!operatorStack.empty()) 148 | { 149 | postfix += operatorStack.top() + ' '; 150 | operatorStack.pop(); 151 | } 152 | 153 | if (!postfix.empty()) 154 | { 155 | postfix.erase(postfix.size() - 1); 156 | } 157 | 158 | size_t equalPos = infix.find("="); 159 | 160 | if (equalPos != std::string::npos) 161 | { 162 | if (infix.substr(0, equalPos).find_first_not_of(identifier_chars + " " + "\t") != std::string::npos) 163 | { 164 | throw InfixError("Invalid Variable"); 165 | } 166 | if (equalPos != infix.rfind("=")) 167 | { 168 | throw InfixError("Invalid Variable"); 169 | } 170 | } 171 | 172 | return postfix; 173 | } 174 | -------------------------------------------------------------------------------- /Sources/Programs/Calculator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | const std::string Calculator::m_validCommand("?REPITVQ"); 11 | const std::string Calculator::m_numberedCommand("EPIT"); 12 | 13 | Calculator::Calculator() 14 | : m_expMaker(ExpressionMaker(m_varTable)) 15 | { } 16 | 17 | Calculator::~Calculator() 18 | { } 19 | 20 | void Calculator::Run() 21 | { 22 | std::cout << "Calculator Version 1.03" << std::endl; 23 | PrintHelp(); 24 | 25 | for (;;) 26 | { 27 | try 28 | { 29 | do 30 | { 31 | GetCommand(); 32 | if (ValidCommand()) 33 | { 34 | ExecuteCommand(); 35 | } 36 | } 37 | while (m_command != 'Q'); 38 | 39 | break; 40 | } 41 | catch (const std::exception& e) 42 | { 43 | std::cout << e.what() << std::endl; 44 | } 45 | } 46 | } 47 | 48 | void Calculator::PrintHelp() 49 | { 50 | std::cout 51 | << "? : Help" << std::endl 52 | << "R : Read expression" << std::endl 53 | << "E : Evaluate and print latest expression" << std::endl 54 | << "E n: Evaluate and print nth expression" << std::endl 55 | << "P : Print latest expression postfix" << std::endl 56 | << "P n: Print nth expression postfix" << std::endl 57 | << "I : Print latest expression infix" << std::endl 58 | << "I n: Print nth expression infix" << std::endl 59 | << "T : Print latest expression tree" << std::endl 60 | << "T n: Print nth expression tree" << std::endl 61 | << "V : Print variable table list" << std::endl 62 | << "Q : Quit" << std::endl; 63 | } 64 | 65 | void Calculator::GetCommand() 66 | { 67 | std::cout << ">> "; 68 | std::string readString = ""; 69 | getline(std::cin, readString); 70 | std::istringstream iss(readString); 71 | 72 | iss >> std::ws; 73 | iss >> m_command; 74 | m_command = static_cast(toupper(static_cast(m_command))); 75 | 76 | if (m_numberedCommand.find(m_command) != std::string::npos) 77 | { 78 | size_t readNumber = m_oldExpressions.size(); 79 | iss >> std::ws; 80 | if (isdigit(iss.peek())) 81 | { 82 | iss >> readNumber; 83 | if (readNumber < 1 || readNumber > m_oldExpressions.size()) 84 | { 85 | m_expressionNumber = m_oldExpressions.size() - 1; 86 | throw std::logic_error("The number is out of range"); 87 | } 88 | 89 | m_expressionNumber = readNumber - 1; 90 | } 91 | else 92 | { 93 | m_expressionNumber = std::numeric_limits::max(); 94 | } 95 | } 96 | } 97 | 98 | bool Calculator::ValidCommand() 99 | { 100 | if (m_validCommand.find(m_command) == std::string::npos) 101 | { 102 | std::cout << "Invalid Command: " << m_command << std::endl; 103 | return false; 104 | } 105 | 106 | return true; 107 | } 108 | 109 | void Calculator::ExecuteCommand() 110 | { 111 | if (m_command == '?') 112 | { 113 | PrintHelp(); 114 | } 115 | else if (m_command == 'R') 116 | { 117 | ReadExpression(std::cin); 118 | } 119 | else if (m_command == 'E') 120 | { 121 | EvaluateAndPrintExpression(std::cout); 122 | } 123 | else if (m_command == 'P') 124 | { 125 | PrintPostfix(std::cout); 126 | } 127 | else if (m_command == 'I') 128 | { 129 | PrintInfix(std::cout); 130 | } 131 | else if (m_command == 'T') 132 | { 133 | PrintTree(std::cout); 134 | } 135 | else if (m_command == 'V') 136 | { 137 | m_varTable.List(std::cout); 138 | } 139 | else if (m_command == 'Q') 140 | { 141 | std::cout << "Quit!" << std::endl; 142 | } 143 | else 144 | { 145 | std::cout << "Invalid Command" << std::endl; 146 | } 147 | } 148 | 149 | void Calculator::ReadExpression(std::istream& is) 150 | { 151 | std::string infix; 152 | 153 | is >> std::ws; 154 | 155 | if (getline(is, infix)) 156 | { 157 | std::vector expressions = SplitExpression(infix, ","); 158 | 159 | for (auto& expression : expressions) 160 | { 161 | m_expMaker.SetPostfix(InfixToPostfix(expression)); 162 | Expression exp = m_expMaker.GetExpression(); 163 | m_oldExpressions.push_back(Expression(exp)); 164 | m_currentExpression = exp; 165 | 166 | if (m_currentExpression.TopNodeIsAssign()) 167 | { 168 | m_currentExpression.Evaluate(); 169 | } 170 | } 171 | } 172 | else 173 | { 174 | std::cout << "Invalid Expression" << std::endl; 175 | } 176 | } 177 | 178 | void Calculator::PrintExpression(std::ostream& os) const 179 | { 180 | std::vector::const_iterator iter = m_oldExpressions.begin(); 181 | 182 | for (int i = 1; iter != m_oldExpressions.end(); ++iter, ++i) 183 | { 184 | os << i << ": " << (*iter).GetInfix() << std::endl; 185 | } 186 | } 187 | 188 | void Calculator::EvaluateAndPrintExpression(std::ostream& os) const 189 | { 190 | if (m_expressionNumber == std::numeric_limits::max()) 191 | { 192 | os << m_currentExpression.Evaluate() << std::endl; 193 | } 194 | else 195 | { 196 | os << m_oldExpressions.at(m_expressionNumber).Evaluate() << std::endl; 197 | } 198 | } 199 | 200 | void Calculator::PrintPostfix(std::ostream& os) const 201 | { 202 | if (m_expressionNumber == std::numeric_limits::max()) 203 | { 204 | os << m_currentExpression.GetPostfix() << std::endl; 205 | } 206 | else 207 | { 208 | os << m_oldExpressions.at(m_expressionNumber).GetPostfix() << std::endl; 209 | } 210 | } 211 | 212 | void Calculator::PrintInfix(std::ostream& os) const 213 | { 214 | if (m_expressionNumber == std::numeric_limits::max()) 215 | { 216 | os << m_currentExpression.GetInfix() << std::endl; 217 | } 218 | else 219 | { 220 | os << m_oldExpressions.at(m_expressionNumber).GetInfix() << std::endl; 221 | } 222 | } 223 | 224 | void Calculator::PrintTree(std::ostream& os) const 225 | { 226 | if (m_expressionNumber == std::numeric_limits::max()) 227 | { 228 | m_currentExpression.PrintTree(os); 229 | } 230 | else 231 | { 232 | m_oldExpressions.at(m_expressionNumber).PrintTree(os); 233 | } 234 | } 235 | 236 | void Calculator::SetCurrentExpression() 237 | { 238 | if (m_expressionNumber == std::numeric_limits::max()) 239 | { 240 | throw std::logic_error("Too many expressions"); 241 | } 242 | else 243 | { 244 | Expression exp = m_oldExpressions[m_expressionNumber]; 245 | m_currentExpression = exp; 246 | } 247 | } 248 | 249 | std::vector Calculator::SplitExpression(const std::string& input, const std::string& regex) 250 | { 251 | // passing -1 as the submatch index parameter performs splitting 252 | std::regex re(regex); 253 | std::sregex_token_iterator first{ input.begin(), input.end(), re, -1 }, last; 254 | 255 | return { first, last }; 256 | } --------------------------------------------------------------------------------