앞에서 구현한 수식 파서 트리를 이용한 계산기의 실행 결과입니다.
▷ 실행 결과
2+3-5*5+6/2을 계산합니다. ... 2 3 + 5 5 * - 6 2 / + 2+3-5*5+6/2=-17 23*5/2+4*6을 계산합니다. ... 23 5 * 2 / 4 6 * + 23*5/2+4*6=81 2+4*5#6을 계산합니다. ... 사용할 수 없는 기호가 있습니다. 2+3*5+을 계산합니다. ... 수식에 사용한 표현이 문법에 맞지 않습니다. 3+36+-7을 계산합니다. ... 수식에 사용한 표현이 문법에 맞지 않습니다. 45+3*5-2+5/2*7을 계산합니다. ... 45 3 5 * + 2 - 5 2 / 7 * + 45+3*5-2+5/2*7=72
다음은 전체 코드입니다.
//Token.h #pragma once #include <iostream> using namespace std; #include <string.h> class Token { int priority; public: virtual void View()const=0; bool MoreThanPriority(Token *token); protected: void SetPriority(int priority); }; #include <vector> using namespace std; typedef vector<Token *> Tokens; typedef Tokens::iterator TIter; typedef Tokens::const_iterator CTIter;
//Token.cpp #include "Token.h" bool Token::MoreThanPriority(Token *token) { return priority>=token->priority; } void Token::SetPriority(int priority) { this->priority = priority; }
//Operator.h #pragma once #include "token.h" class Operator : public Token { char ch; public: Operator(char ch); void View()const; int Calculate(int lvalue, int rvalue)const; static bool IsOperator(char ch); static bool IsOperator(const Token *token); };
//Operator.cpp #include "Operator.h" Operator::Operator(char ch) { this->ch = ch; if((ch=='+')||(ch=='-')) { SetPriority(1); } else { SetPriority(2); } } void Operator::View()const { cout<<ch<<" "; } int Operator::Calculate(int lvalue, int rvalue)const { switch(ch) { case '+': return lvalue + rvalue; case '-': return lvalue - rvalue; case '*': return lvalue * rvalue; case '/': if(rvalue) { return lvalue / rvalue; } cout<<"divide zero error"<<endl; return 0; } throw "연산자 기호에 문제가 있습니다."; } bool Operator::IsOperator(char ch) { return (ch=='+')||(ch=='-')||(ch=='*')||(ch=='/'); } bool Operator::IsOperator(const Token *token) { return dynamic_cast<const Operator *>(token)!=0; }
//Operand.h #pragma once #include "Token.h" class Operand: public Token { int value; public: Operand(int value); void View()const; int GetValue()const; static bool IsDigit(char ch); static int ConvertStrToInt(const char *str,int &index); static bool IsOperand(const Token *token); };
//Operand.cpp #include "Operand.h" Operand::Operand(int value) { this->value = value; SetPriority(3); } void Operand::View()const { cout<<value<<" "; } int Operand::GetValue()const { return value; } bool Operand::IsDigit(char ch) { return (ch>='0')&&(ch<='9'); } int Operand::ConvertStrToInt(const char *str,int &index) { int value = 0; while(IsDigit(str[index])) { value = value * 10 + str[index] - '0'; index++; } return value; } bool Operand::IsOperand(const Token *token) { return dynamic_cast<const Operand *>(token)!=0; }
//Lexer.h #pragma once #include "Operand.h" #include "Operator.h" class Lexer { Tokens tokens; public: bool MakeToken(const char *expr); Tokens GetTokens()const; ~Lexer(); };
//Lexer.cpp #include "Lexer.h" bool Lexer::MakeToken(const char *expr) { tokens.clear(); int i = 0; while(expr[i]) { if(Operator::IsOperator(expr[i])) { tokens.push_back(new Operator(expr[i])); i++; } else { if(Operand::IsDigit(expr[i])) { int value = Operand::ConvertStrToInt(expr,i); tokens.push_back(new Operand(value)); } else { return false; } } } return true; } Tokens Lexer::GetTokens()const { return tokens; } Lexer::~Lexer() { TIter seek = tokens.begin(); TIter last = tokens.end(); for( ;seek != last; ++seek) { delete (*seek); } }
//SynAnalyzer.h #pragma once #include "Operator.h" #include "Operand.h" class SynAnalyzer { public: static bool Analyze(Tokens tokens); };
//SynAnalyzer.cpp #include "SynAnalyzer.h" bool SynAnalyzer::Analyze(Tokens tokens) { int tcnt = tokens.size(); if(tcnt%2==0) { return false; } if(Operand::IsOperand(tokens[0])==false) { return false; } for(int i = 1; i<tcnt; i+=2) { if(Operator::IsOperator(tokens[i])==false) { return false; } if(Operand::IsOperand(tokens[i+1])==false) { return false; } } return true; }
//Parser.h #pragma once #include "Operator.h" #include "Operand.h" class Parser { Tokens tokens; struct Node { Token *token; Node *lc; Node *rc; Node(Token *token) { this->token = token; lc = rc = 0; } }; Node *root; public: Parser(Tokens tokens); ~Parser(void); void Parsing(); void PostOrderView()const; int Calculate(); private: void Add(Token *token); void PostOrder(Node *sr)const; int PostOrderCalculate(Node *sr); void Clear(Node *sr); };
//Parser.cpp #include "Parser.h" Parser::Parser(Tokens tokens) { this->tokens = tokens; } Parser::~Parser(void) { Clear(root); } void Parser::Clear(Node *sr) { if(sr) { Clear(sr->lc); Clear(sr->rc); delete sr; } } void Parser::Parsing() { int tcnt = tokens.size(); root = new Node(tokens[0]); for(int i = 1; i<tcnt;i++) { Add(tokens[i]); } } void Parser::Add(Token *token) { Node *now = new Node(token); Token *st = root->token; if(st->MoreThanPriority(token)) { now->lc = root; root = now; } else { if(Operand::IsOperand(token)==false) { now->lc = root->rc; root->rc = now; } else { Node *pa = root; while(pa->rc) { pa = pa->rc; } pa->rc = now; } } } void Parser::PostOrderView()const { PostOrder(root); cout<<endl; } void Parser::PostOrder(Node *sr)const { if(sr) { PostOrder(sr->lc); PostOrder(sr->rc); sr->token->View(); } } int Parser::Calculate() { return PostOrderCalculate(root); } int Parser::PostOrderCalculate(Node *sr) { if(sr->lc) { int lvalue = PostOrderCalculate(sr->lc); int rvalue = PostOrderCalculate(sr->rc); Operator *op = dynamic_cast<Operator *>(sr->token); return op->Calculate(lvalue, rvalue); } else { Operand *op = dynamic_cast<Operand *>(sr->token); return op->GetValue(); } }
//Calculator.h #pragma once #include "Lexer.h" #include "SynAnalyzer.h" #include "Parser.h" class Calculator { char *expr; Tokens tokens; public: Calculator(const char *expr); ~Calculator(void); void Run(); };
//Calculator.cpp #include "Calculator.h" Calculator::Calculator(const char *expr) { int len_p1 = strlen(expr)+1; this->expr = new char[len_p1]; strcpy_s(this->expr,len_p1,expr); } Calculator::~Calculator(void) { delete[] expr; } void Calculator::Run() { cout<<expr<<"을 계산합니다. ..."<<endl; Lexer lexer; if(lexer.MakeToken(expr)) { tokens = lexer.GetTokens(); if(SynAnalyzer::Analyze(tokens)) { Parser parser(tokens); parser.Parsing(); parser.PostOrderView(); cout<<expr<<"="<<parser.Calculate()<<endl; } else { cout<<"수식에 사용한 표현이 문법에 맞지 않습니다."<<endl; } } else { cout<<"사용할 수 없는 기호가 있습니다."<<endl; } cout<<endl; }
//Program.cpp #include "Calculator.h" int main() { char *tc_exprs[6]= { "2+3-5*5+6/2", "23*5/2+4*6", "2+4*5#6", "2+3*5+", "3+36+-7", "45+3*5-2+5/2*7" }; for(int i = 0; i<6; i++) { Calculator *cal = new Calculator(tc_exprs[i]); cal->Run(); delete cal; } return 0; }