각설하고, 완성된 사칙연산 계산기 프로그램입니다.
import java.util.Scanner; /** * 사칙 연산 계산기. * * - 사칙 연산 수식을 입력 받고, * - 해석한 후, * - 계산 결과를 출력한다. * * @author sunnyk */ public class FourArithExprProcessor { public static void main(String args[]) { // 스캐너 열기 Scanner scanner = new Scanner(System.in); // 사칙연산 수식 입력 System.out.print("Input expression : "); String mathExpression = scanner.nextLine(); // 빈 문장을 입력한 경우, 오류 메시지 출력 if (mathExpression.trim().isEmpty()) { System.out .println("You entered empty expression, so do nothing and quit!"); } // "test"를 입력하면, 사칙연산 테스트 실시... else if ("test".equals(mathExpression)) { runParser("A + B becomes A B +", "10 + 2"); runParser("A / B becomes A B /", "15 / 2"); runParser("A * B + C becomes A B * C +", "76 * 32 + 2"); runParser("A + B * C becomes A B C * +", "64 + 39 * 4"); runParser("A * (B + C) becomes A B C + *", "31 * (61 + 2)"); runParser("A * (B + C * D) + E becomes A B C D * + * E +", "1 * (2 + 3 * 4) + 2"); } // 수식이 입력된 경우 해석... else { System.out.format( "Entered four arithmetic operation (expression) is '%s'\n", mathExpression); runParser("", mathExpression); } // 스캐너 닫기 scanner.close(); } /* * 사칙연산 수식을 계산하고, 결과를 출력한다. * * @param msg 안내 메시지 * @param expr 입력 수식 */ private static void runParser(String msg, String expr) { if(msg == null || !msg.isEmpty()) { System.out.println("Run : " + msg); } FourArithExprParser parser = new FourArithExprParser(expr); // parse four arithmetic expression as infix. System.out.print("Infix expression : "); parser.parseSymbols(); parser.print(); // convert infix expression to postfix. System.out.print("Postfix expression : "); parser.toPostfix(); parser.print(); // calculate expression int result = parser.calcalate(); System.out.println("Caculcation result = " + result); System.out.println(); } }
import java.util.ArrayList; import java.util.List; import java.util.Stack; /** * 사칙 연산 수식 해석 (parse four arithmetic expression) * * @author sunnyk * */ public class FourArithExprParser { // 사칙연산자 목록 private static char[] OPERATORS = { '+', '-', '*', '/' }; // 좌/우 괄호 private static char[] PARENTHESISES = { '(', ')' }; private String numberBuffer; private String inputExpr; private List<String> symbols = new ArrayList<String>(); private Stack<String> aStack = new Stack<String>(); /** * 생성자에 중위식 사칙연산 수식을 입력. */ public FourArithExprParser(String expression) { this.inputExpr = expression; } /** * 중위식 사칙연산 수식에서 항목(symbol)들을 추출한다. */ public void parseSymbols() { // 문자(character) 단위로 분석.. for (int idx = 0; idx < inputExpr.length(); idx++) { char charInExpr = inputExpr.charAt(idx); // 공백(whitespace) 문자 - linefeed, space, tab 등-이면, 이전 버퍼의 내용을 비움. if (Character.isWhitespace(charInExpr)) { handleTempBuff(); } // 사칙연산 연산자 혹은 괄호인 경우, 항목 추가. else if (isMathOperatorOrParenthesis(charInExpr)) { handleTempBuff(); symbols.add(String.valueOf(charInExpr)); } // 숫자 문자인 경우, 숫자 버퍼에 추가.. else if (Character.isDigit(charInExpr)) { if (numberBuffer == null) { numberBuffer = String.valueOf(charInExpr); } else { numberBuffer += charInExpr; } } } handleTempBuff(); } /** * 중위식을 후위식으로 변환. */ public void toPostfix() { ListpostfixExpr = new ArrayList (); // 중위식 표현식의 각 항목에 대해서... for(String symbol : symbols) { char firstCharOfColumn = symbol.charAt(0); // 피연산자이면, 피연산자를 후위식에 추가 if(!isMathOperatorOrParenthesis(firstCharOfColumn)) { postfixExpr.add(symbol); } // 좌괄호이면 스택에 추가 else if('(' == firstCharOfColumn) { aStack.push(symbol); } // 우괄호이면, 좌괄호 '('가 나올 때까지 스택에서 꺼냄. else if(')' == firstCharOfColumn) { // 스택의 최상위 값이 좌괄호 '('가 아니면.. while (!"(".equals(aStack.peek())) { postfixExpr.add(aStack.pop()); } // while의 끝 // 좌괄호'(' 제거 aStack.pop(); } // 연산자이면, 스택에 있는 더 높은 우선순위 연산자 처리 else { // 만약, 스택이 비어 있거나, 스택의 최상위에 좌괄호가 들어 있으면, 연산자를 스택에 추가 if(aStack.isEmpty() || "(".equals(aStack.peek())) { aStack.push(symbol); } // 연산자의 우선순위가 스택의 최상위에 있는 연산자보다 높으면 스택에 추가 else if(priority(symbol) > priority(aStack.peek())) { aStack.push(symbol); } // 연산자의 우선순위가 스택의 최상위에 있는 연산자와 같으면, 연관에 따라 처리.. // (좌측에서 우측으로 연산하는 경우, 스택의 최상위 연산자를 꺼내고, 연산자를 스택에 추가) else if(priority(symbol) == priority(aStack.peek())) { postfixExpr.add(aStack.pop()); aStack.push(symbol); } // 새로운 연산자의 우선순위가 스택의 최상위에 있는 연산자보다 낮으면, // 스택의 최상위 연산자를 꺼내고, 새로운 연산자를 스택에 추가 else { while(!aStack.isEmpty() && priority(symbol) <= priority(aStack.peek())) { postfixExpr.add(aStack.pop()); } aStack.push(symbol); } } } // 후위식에 스택에 남은 연산자들을 추가 while(!aStack.isEmpty()) { postfixExpr.add(aStack.pop()); } // while의 끝 // 중위식을 후위식으로 덮어쓰기... symbols = postfixExpr; } /** * 후위식 계산을 수행하고 결과 값을 반환한다. */ public int calcalate() { // 후위식 기호(symbol)들을 순차적으로 처리한다. for(String symbol : symbols) { char firstChOfSymbol = symbol.charAt(0); // 사칙연산 연산자인 경우... if(isOperator(firstChOfSymbol)) { // 피연산자(operand)를 스택에서 꺼낸다. // (순서가 반대로 저장되어 있음을 주의할 것) int secondOperand = Integer.valueOf(aStack.pop()); int firstOperand = Integer.valueOf(aStack.pop()); // 연산자의 유형에 따라 계산을 수행한다. int result = 0; switch(firstChOfSymbol) { case '+': result = firstOperand + secondOperand; break; case '-': result = firstOperand - secondOperand; break; case '*': result = firstOperand * secondOperand; break; case '/': result = firstOperand / secondOperand; break; } // 연산 결과를 다시 스택에 담는다. aStack.push(String.valueOf(result)); } // 피연산자인 경우에는 스택에 무조건 담는다. else { aStack.push(symbol); } } // 모든 처리가 끝나면, 결과 값이 스택에 남아 있다. return Integer.valueOf(aStack.pop()); } /** * 수식 분석 결과를 화면에 출력. */ public void print() { for (String symbol : symbols) { System.out.print(symbol + " "); } System.out.println(); } /* * 새로운 항목(symbol)을 찾은 경우, 임시 버퍼의 내용을 항목 목록에 추가 */ private void handleTempBuff() { if (numberBuffer != null) { symbols.add(numberBuffer); numberBuffer = null; } } /* * 연산자 혹은 괄호인지 검사. */ private boolean isMathOperatorOrParenthesis(char inputChar) { for (char op : OPERATORS) { if (inputChar == op) { return true; } } for(char brace : PARENTHESISES) { if (inputChar == brace) { return true; } } return false; } /* * 연산자 인지 검사. */ private boolean isOperator(char inputChar) { for (char op : OPERATORS) { if (inputChar == op) { return true; } } return false; } /* * 연산자의 우선순위(priority)를 반환한다. */ private int priority(String symbol) { int priority = 0; switch(symbol){ case "*": case "/": priority = 2; break; case "+": case "-": priority = 1; } return priority; } }