/** * Author: Shiuh-Sheng Yu * Last Update: 4/21/1998 * Modified Date: 03/31/2003 */ import java.awt.*; import java.awt.event.*; public class Calc implements ActionListener { private Frame f; private TextField display; public Calc() { Font font = new Font("Serif",Font.PLAIN,16); f = new Frame("小算盤"); MenuBar mb = new MenuBar(); mb.setFont(font); f.setMenuBar(mb); Menu m = new Menu("說明"); mb.add(m); MenuItem mi = new MenuItem("about"); m.add(mi); f.addWindowListener(new CloseWindow(f,true)); mi.addActionListener(this); f.setLayout(new GridBagLayout()); f.setFont(font); display = new TextField(40); AddConstraint.addConstraint(f,display,0,0,1,1, GridBagConstraints.HORIZONTAL, GridBagConstraints.NORTHWEST, 1,0,0,0,0,0); Panel funButtons = new Panel(); AddConstraint.addConstraint(f,funButtons,0,1,1,1, GridBagConstraints.BOTH, GridBagConstraints.NORTHWEST, 1,1,0,0,0,0); funButtons.setLayout(new GridLayout(1,1)); ((Button)funButtons.add(new Button("clear"))).addActionListener(this); Panel keyButtons = new Panel(); keyButtons.setLayout(new GridLayout(6,5)); AddConstraint.addConstraint(f,keyButtons,0,2,1,1, GridBagConstraints.BOTH, GridBagConstraints.NORTHWEST, 1,1,0,0,0,0); String[] buttons = {"7","8","9","/","^","4","5","6","*","%","1","2","3","-",".","0","+","=","sqrt","abs","acos","asin","atan","cos","sin","tan","exp","log","round"}; for (int i=0; i<buttons.length; i++) { ((Button)keyButtons.add(new Button(buttons[i]))).addActionListener(this); } f.pack(); f.show(); } public static void main(String argv[]) { new Calc(); } public void actionPerformed(ActionEvent e) { String see = display.getText(); String rel; int i = display.getCaretPosition(); String command = e.getActionCommand(); if (command.equals("=")) { rel = eval(display.getText()); display.setText(rel); display.setCaretPosition(rel.length()); } else if (command.length()==1) { // 數字按鍵 display.setText(see.substring(0,i)+command+see.substring(i)); display.setCaretPosition((see.substring(0,i)+command).length()); } else if (command.equals("clear")) { display.setText(""); } else if (command.equals("about")) { new About(f,"俞旭昇寫好玩的"); } else { // 其他函數 display.setText(see.substring(0,i)+command+"()"+see.substring(i)); display.setCaretPosition((see.substring(0,i)+command).length()+1); } display.requestFocus(); } public static final int SQRT = 0; public static final int ABS = 1; public static final int ACOS = 2; public static final int ASIN = 3; public static final int ATAN = 4; public static final int COS = 5; public static final int SIN = 6; public static final int TAN = 7; public static final int EXP = 8; public static final int LOG = 9; public static final int ROUND = 10; public static final int PLUS = 0; public static final int MINUS = 1; public static final int MULTIPLY = 2; public static final int DIVIDE = 3; public static final int MODE = 4; public static final int POWER = 5; public static final int FUN = 6; public static final int LEFT_ROUND_BRACKET = 7; public static final int RIGHT_ROUND_BRACKET = 8; public static final int END = 9; public static final int LITERAL = 10; public static final int ERROR = 11; public static final int PUSH = 0; public static final int POP = 1; public static final int ELIMINATE = 2; public static final int DEAD = 3; public static final int TERMINATE = 4; public static final int table[][] = { // add more elements // + - * / % ^ FUN ( ) end {POP, POP, POP, POP, POP, POP, POP, PUSH, DEAD,PUSH}, // + {POP, POP, POP, POP, POP, POP, POP, PUSH, DEAD,PUSH}, // - {PUSH,PUSH,POP, POP, POP, POP, POP, PUSH, DEAD,PUSH}, // * {PUSH,PUSH,POP, POP, POP, POP, POP, PUSH, DEAD,PUSH}, // / {PUSH,PUSH,POP, POP, POP, POP, POP, PUSH, DEAD,PUSH}, // % {PUSH,PUSH,PUSH,PUSH,PUSH,PUSH,POP, PUSH, DEAD,PUSH}, // ^ {PUSH,PUSH,PUSH,PUSH,PUSH,PUSH,DEAD,PUSH, DEAD,PUSH}, // FUN {PUSH,PUSH,PUSH,PUSH,PUSH,PUSH,PUSH,PUSH, DEAD,PUSH}, // ( {POP, POP, POP, POP, POP, POP, POP, ELIMINATE,DEAD,DEAD}, // ) {POP, POP, POP, POP, POP, POP, POP, DEAD, DEAD,TERMINATE}// end }; String eval(String expression) { Expression exp = new Expression(expression); IntStack operator_stack = new IntStack(); DoubleStack operand_stack = new DoubleStack(); Token token; int act, op; double op1,op2,tmp; operator_stack.push(END); // put sentinel for (;;) { token = exp.next_token(); if (token.type == ERROR) { return "算式不合法"; } if (token.type == LITERAL) { operand_stack.push(Double.valueOf(token.data).doubleValue()); } else { act = table[token.type][operator_stack.peek()]; while (act == POP) { // pop out all higher priority operator op2 = operand_stack.pop(); op1 = operand_stack.pop(); tmp = 0; op = operator_stack.pop(); if (op == PLUS) { tmp = op1 + op2; } else if (op == MINUS) { tmp = op1 - op2; } else if (op == MULTIPLY) { tmp = op1 * op2; } else if (op == MODE) { if ((int)op2 != 0) { tmp = (int)op1 % (int)op2; } else { return "zero divisor"; } } else if (op == DIVIDE) { if (op2 != 0) { tmp = op1 / op2; } else { return "zero divisor"; } } else if (op == POWER) { tmp = Math.pow(op1,op2); } else if (op == FUN) { if (op1 == SQRT) { tmp = Math.sqrt(op2); } else if (op1 == ABS) { tmp = Math.abs(op2); } else if (op1 == ACOS) { tmp = Math.acos(op2); } else if (op1 == ASIN) { tmp = Math.asin(op2); } else if (op1 == ATAN) { tmp = Math.atan(op2); } else if (op1 == COS) { tmp = Math.cos(op2); } else if (op1 == SIN) { tmp = Math.sin(op2); } else if (op1 == TAN) { tmp = Math.tan(op2); } else if (op1 == EXP) { tmp = Math.exp(op2); } else if (op1 == LOG) { tmp = Math.log(op2); } else if (op1 == ROUND) { tmp = Math.round(op2); } else { return("內部錯誤"); } } operand_stack.push(tmp); act = table[token.type][operator_stack.peek()]; } if (act == PUSH) { operator_stack.push(token.type); if (token.type == FUN) { if (token.data.equals("sqrt")) { operand_stack.push((double)SQRT); } else if (token.data.equals("abs")) { operand_stack.push((double)ABS); } else if (token.data.equals("acos")) { operand_stack.push((double)ACOS); } else if (token.data.equals("asin")) { operand_stack.push((double)ASIN); } else if (token.data.equals("atan")) { operand_stack.push((double)ATAN); } else if (token.data.equals("cos")) { operand_stack.push((double)COS); } else if (token.data.equals("sin")) { operand_stack.push((double)SIN); } else if (token.data.equals("tan")) { operand_stack.push((double)TAN); } else if (token.data.equals("exp")) { operand_stack.push((double)EXP); } else if (token.data.equals("log")) { operand_stack.push((double)LOG); } else if (token.data.equals("round")) { operand_stack.push((double)ROUND); } else { return("算式不合法"); } } } else if (act == ELIMINATE) { if (operator_stack.peek() == LEFT_ROUND_BRACKET) { operator_stack.pop(); } else { return"括弧不對稱"; } } else if (act == TERMINATE) { return Double.toString(operand_stack.pop()); } else { // DEAD return("算式不合法"); } } } } } class DoubleStack { private int top; private double data[]; public DoubleStack() { top = 0; data = new double[100]; } public void push(double val) { data[top++] = val; } public double pop() { return data[--top]; } public double peek() { return data[top-1]; } } class IntStack { private int top; private int data[]; public IntStack() { top = 0; data = new int[100]; } public void push(int val) { data[top++] = val; } public int pop() { return data[--top]; } public int peek() { return data[top-1]; } } class Token { int type; String data; Token(int t, String d) { type = t; data = d; } } class Expression { private int ptr; private String data; private boolean wantOperand = true; public Expression(String s) { ptr = 0; data = s; } public Token next_token() { int i; for (i = ptr; i < data.length() && data.charAt(i)==' '; i++) { } ptr = i; if (i == data.length()) { return new Token(Calc.END,""); } switch (data.charAt(i)) { case '+': ptr++; wantOperand = true; return new Token(Calc.PLUS,"+"); case '*': ptr++; wantOperand = true; return new Token(Calc.MULTIPLY,"*"); case '/': ptr++; wantOperand = true; return new Token(Calc.DIVIDE,"/"); case '%': ptr++; wantOperand = true; return new Token(Calc.MODE,"%"); case '^': ptr++; wantOperand = true; return new Token(Calc.POWER,"^"); case '(': ptr++; wantOperand = true; return new Token(Calc.LEFT_ROUND_BRACKET,"("); case ')': ptr++; wantOperand = false; return new Token(Calc.RIGHT_ROUND_BRACKET,")"); default: if (data.charAt(i) == '-' && !wantOperand) { ptr++; wantOperand = true; return new Token(Calc.MINUS,"-"); } StringBuffer buf = new StringBuffer(); if (data.charAt(i)=='-' ||(data.charAt(i)>='0' && data.charAt(i)<='9') || data.charAt(i)=='.') { wantOperand = false; if (data.charAt(i) == '-') { buf.append(data.charAt(i++)); } while (i<data.length() && data.charAt(i)>='0' && data.charAt(i)<='9') { buf.append(data.charAt(i++)); } if (i<data.length() && data.charAt(i) == '.') { buf.append(data.charAt(i++)); while (i<data.length() && data.charAt(i)>='0' && data.charAt(i)<='9') { buf.append(data.charAt(i++)); } } if (i<data.length() && data.charAt(i) == 'E') { buf.append(data.charAt(i++)); if (i<data.length() && data.charAt(i) == '-') { buf.append(data.charAt(i++)); } while (i<data.length() && data.charAt(i)>='0' && data.charAt(i)<='9') { buf.append(data.charAt(i++)); } } ptr = i; if (buf.length()==0) { return new Token(Calc.ERROR,""); } else { return new Token(Calc.LITERAL,buf.toString()); } } else { while(i<data.length() && data.charAt(i)>='a' && data.charAt(i)<='z') { buf.append(data.charAt(i++)); } ptr = i; if (buf.length()==0) { return new Token(Calc.ERROR,""); } else if (i>=data.length() || data.charAt(i)!='(') { return new Token(Calc.ERROR,""); } else { return new Token(Calc.FUN,buf.toString()); } } } } } class About { public About(Frame f, String message) { Dialog d = new Dialog(f,true); d.addWindowListener(new CloseWindow(d,false)); Label l = new Label(message); d.setLayout(new GridBagLayout()); AddConstraint.addConstraint(d,l,0,0,1,1, GridBagConstraints.BOTH, GridBagConstraints.NORTHWEST, 1,1,0,0,0,0); Button b = new Button("OK"); AddConstraint.addConstraint(d,b,0,1,1,1, GridBagConstraints.BOTH, GridBagConstraints.NORTHWEST, 1,1,0,0,0,0); b.addActionListener(new CloseWindow(d,false)); d.pack(); d.show(); } } class CloseWindow extends WindowAdapter implements ActionListener { private Window target; private boolean exit; public CloseWindow(Window target, boolean exit) { super(); this.target = target; this.exit = exit; } public void windowClosing(WindowEvent e) { target.dispose(); if (exit) System.exit(0); } public void actionPerformed(ActionEvent e) { target.dispose(); if (exit) System.exit(0); } } class AddConstraint { public static void addConstraint(Container container, Component component, int grid_x, int grid_y, int grid_width, int grid_height, int fill, int anchor, double weight_x, double weight_y, int top, int left, int bottom, int right) { GridBagConstraints c = new GridBagConstraints(); c.gridx = grid_x; c.gridy = grid_y; c.gridwidth = grid_width; c.gridheight = grid_height; c.fill = fill; c.anchor = anchor; c.weightx = weight_x; c.weighty = weight_y; c.insets = new Insets(top,left,bottom,right); ((GridBagLayout)container.getLayout()).setConstraints(component,c); container.add(component); } }