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[][] = {
{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},
{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}
};
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);
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) {
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 {
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);
}
}