/** * class StackCalc * Stack Calculator of Real Numbers * * * * * The applet nees JDK 1.1. * Tested in RedHat Linux 4.2 (JDK 1.1.3 and 1.1.5) and * under Win95, JDK 1.1.5. * */ import java.awt.*; import java.awt.event.*; import java.applet.Applet; public class SCalc extends Applet { DoubleStack stack; double number; boolean numberSet = false; Button plusButton; Button minusButton; Button multButton; Button divButton; Button sqrtButton; Button sinButton; Button cosButton; Button expButton; Button piButton; Button eButton; Button pushButton; Button popButton; Button initButton; TextField inputNumber; TextField resultNumber; // Layout constants static final int leftMargin = 5; static final int topMargin = 5; static final int headSkip = 30; static final int vertSkip = 5; static final int horSkip = 5; static final int buttonWidth = 60; static final int buttonHeight = 30; static final int stackDy = 24; static final int numberWidth = 300; public static void main(String[] args) { Frame f = new Frame("Stack Calculator of Real Numbers"); WindowAdapter wa = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; f.addWindowListener(wa); f.setFont(new Font("Helvetica", Font.PLAIN, 14)); // Add menu bar final MenuBar mb = new MenuBar(); f.setMenuBar(mb); final Menu fileMenu = new Menu("File"); final MenuItem quitItem = new MenuItem("Quit"); fileMenu.add(quitItem); mb.add(fileMenu); ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { // System.out.println("Action " + e); if (e.getActionCommand().equals("Quit")) { System.exit(0); } } }; fileMenu.addActionListener(al); SCalc sc = new SCalc(); f.add("Center", sc); // f.pack(); f.setSize( 2*leftMargin + buttonWidth + horSkip + numberWidth + 10, 2*topMargin + 9 * (buttonHeight + vertSkip) + headSkip + vertSkip + 60 // For menu bar ); sc.init(); sc.start(); f.setVisible(true); } public SCalc() { stack = new DoubleStack(); } public void init() { setLayout(null); setFont(new Font("Helvetica", Font.PLAIN, 14)); setBackground(Color.lightGray); Label headline = new Label("Stack Calculator of Real Numbers"); headline.setFont(new Font("TimesRoman", Font.BOLD, 18)); add(headline); headline.setBounds(leftMargin, topMargin, 300, 30); plusButton = new Button("+"); minusButton = new Button("-"); multButton = new Button("*"); divButton = new Button("/"); sqrtButton = new Button("sqrt"); expButton = new Button("exp"); sinButton = new Button("sin"); cosButton = new Button("cos"); piButton = new Button("pi"); eButton = new Button("e"); pushButton = new Button("Push"); popButton = new Button("Delete stack top"); initButton = new Button("Initialize"); // Button colors plusButton.setForeground(Color.blue); minusButton.setForeground(Color.blue); multButton.setForeground(Color.blue); divButton.setForeground(Color.blue); sqrtButton.setForeground(Color.blue); expButton.setForeground(Color.blue); sinButton.setForeground(Color.blue); cosButton.setForeground(Color.blue); piButton.setForeground(Color.blue); eButton.setForeground(Color.blue); resultNumber = new TextField(); resultNumber.setEditable(false); resultNumber.setForeground(Color.blue); add(resultNumber); inputNumber = new TextField(); add(inputNumber); // Add buttons to applet add(plusButton); add(minusButton); add(multButton); add(divButton); add(sqrtButton); add(expButton); add(sinButton); add(cosButton); add(piButton); add(eButton); add(pushButton); add(popButton); add(initButton); // Set component shapes int x0 = leftMargin; int x1 = leftMargin + buttonWidth + horSkip; int y = topMargin + headSkip + vertSkip; // Skip headline int dy = buttonHeight + vertSkip; Label resultLabel = new Label("Result:"); add(resultLabel); resultLabel.setBounds(x0, y, buttonWidth, buttonHeight); resultNumber.setBounds(x1, y, numberWidth, buttonHeight); y += dy; Label inputLabel = new Label("Input:"); add(inputLabel); inputLabel.setBounds(x0, y, buttonWidth, buttonHeight); inputNumber.setBounds(x1, y, numberWidth - buttonWidth - horSkip, buttonHeight); pushButton.setBounds(x1 + numberWidth - buttonWidth, y, buttonWidth, buttonHeight); y += dy; plusButton.setBounds(x0, y, buttonWidth, buttonHeight); minusButton.setBounds(x1, y, buttonWidth, buttonHeight); y += dy; multButton.setBounds(x0, y, buttonWidth, buttonHeight); divButton.setBounds(x1, y, buttonWidth, buttonHeight); y += dy; sqrtButton.setBounds(x0, y, buttonWidth, buttonHeight); expButton.setBounds(x1, y, buttonWidth, buttonHeight); y += dy; sinButton.setBounds(x0, y, buttonWidth, buttonHeight); cosButton.setBounds(x1, y, buttonWidth, buttonHeight); y += dy; piButton.setBounds(x0, y, buttonWidth, buttonHeight); eButton.setBounds(x1, y, buttonWidth, buttonHeight); y += dy; popButton.setBounds(x0, y, 2*buttonWidth+horSkip, buttonHeight); y += dy; initButton.setBounds(x0, y, 2*buttonWidth+horSkip, buttonHeight); y += dy; // Add action listener for "Input" text field // (for processing the "Enter" button) inputNumber.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { // System.out.println("Text action " + e); onPush(); } } ); // Add action listener for buttons SCalcListener bl = new SCalcListener(); plusButton.addActionListener(bl); minusButton.addActionListener(bl); multButton.addActionListener(bl); divButton.addActionListener(bl); sqrtButton.addActionListener(bl); expButton.addActionListener(bl); sinButton.addActionListener(bl); cosButton.addActionListener(bl); piButton.addActionListener(bl); eButton.addActionListener(bl); pushButton.addActionListener(bl); popButton.addActionListener(bl); initButton.addActionListener(bl); inputNumber.requestFocus(); // Set focus to input number field } public void paint(Graphics g) { int x = leftMargin + 2 * (buttonWidth + horSkip); int y = topMargin + headSkip + vertSkip + // Skip headline 2 * (buttonHeight + vertSkip); // Skip result & input fields int stackTop = y + buttonHeight + vertSkip; int stackLeft = x; int stackWidth = 0; int stackHeight = vertSkip; g.setColor(Color.red); g.drawString("Stack: Depth = " + stack.depth(), x, y + 18); FontMetrics fm = g.getFontMetrics(); for (int i = 0; i < stack.depth(); i++) { String s = "" + stack.elementAt(i); // Convert number to string g.drawString( s, stackLeft + horSkip, stackTop + stackDy*i + 20 ); int w = fm.stringWidth(s); if (w > stackWidth) stackWidth = w; } stackWidth += 2*horSkip; if (stack.depth() > 0) { stackHeight = stack.depth()*stackDy; } else { stackTop += vertSkip; } if (stackWidth < 40) stackWidth = 40; g.drawLine( stackLeft, stackTop, stackLeft, stackTop + stackHeight ); g.drawLine( stackLeft, stackTop + stackHeight, stackLeft + stackWidth, stackTop + stackHeight ); g.drawLine( stackLeft + stackWidth, stackTop + stackHeight, stackLeft + stackWidth, stackTop ); } public void start() { } // Action listeners class SCalcListener implements ActionListener { public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == plusButton) { onPlus(); } else if (source == minusButton) { onMinus(); } else if (source == multButton) { onMult(); } else if (source == divButton) { onDiv(); } else if (source == sqrtButton) { onSqrt(); } else if (source == expButton) { onExp(); } else if (source == sinButton) { onSin(); } else if (source == cosButton) { onCos(); } else if (source == piButton) { onPi(); } else if (source == eButton) { onE(); } else if (source == pushButton) { onPush(); } else if (source == popButton) { onPop(); } else if (source == initButton) { onInit(); } inputNumber.requestFocus(); } } void onPlus() { if (stack.depth() < 2) { showMessage("Cannot perform operation: Stack depth < 2"); return; } try { double x2 = stack.pop(); double x1 = stack.pop(); double res = x1 + x2; stack.push(res); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onMinus() { if (stack.depth() < 2) { showMessage("Cannot perform operation: Stack depth < 2"); return; } try { double x2 = stack.pop(); double x1 = stack.pop(); double res = x1 - x2; stack.push(res); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onMult() { if (stack.depth() < 2) { showMessage("Cannot perform operation: Stack depth < 2"); return; } try { double x2 = stack.pop(); double x1 = stack.pop(); double res = x1 * x2; stack.push(res); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onDiv() { if (stack.depth() < 2) { showMessage("Cannot perform operation: Stack depth < 2"); return; } try { double x2 = stack.top(); if (x2 == 0.) { System.out.println("Zero division"); showMessage("Zero division"); return; } stack.pop(); double x1 = stack.pop(); double res = x1 / x2; stack.push(res); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onSqrt() { if (stack.empty()) { showMessage("Cannot perform operation: Stack empty"); return; } try { double x = stack.top(); if (x < 0.) { System.out.println("Square root of negative number"); showMessage("Square root of negative number"); return; } stack.pop(); double res = Math.sqrt(x); stack.push(res); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onExp() { if (stack.empty()) { showMessage("Cannot perform operation: Stack empty"); return; } try { double x = stack.pop(); double res = Math.exp(x); stack.push(res); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onSin() { if (stack.empty()) { showMessage("Cannot perform operation: Stack empty"); return; } try { double x = stack.pop(); double res = Math.sin(x); stack.push(res); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onCos() { if (stack.empty()) { showMessage("Cannot perform operation: Stack empty"); return; } try { double x = stack.top(); stack.pop(); double res = Math.cos(x); stack.push(res); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onPi() { try { stack.push(Math.PI); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onE() { try { stack.push(Math.E); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } void onPush() { input(); if (numberSet) { try { stack.push(number); inputNumber.setText(""); numberSet = false; number = 0.; showResult(); } catch (StackException e) { System.out.println(e.toString()); } } } void onPop() { if (stack.depth() > 0) { try { stack.pop(); showResult(); } catch (StackException e) { System.out.println(e.toString()); } } } void onInit() { stack.init(); number = 0.; numberSet = false; inputNumber.setText(""); resultNumber.setText(""); repaint(); } void input() { number = 0.; String text = inputNumber.getText(); if (text.equals("")) { numberSet = false; return; } try { number = Double.valueOf(text).doubleValue(); numberSet = true; } catch (NumberFormatException e) { // System.out.println("Input number: Illegal format: " + e.toString()); showMessage("Input number: Illegal format"); numberSet = false; } } void showResult() { if (stack.depth() > 0) { try { resultNumber.setText("" + stack.top()); } catch (StackException e) { System.out.println(e.toString()); } } else { resultNumber.setText(""); } repaint(); } void showMessage(String m) { resultNumber.setText(m); repaint(); } } class DoubleStack { final int MAX_DEPTH = 1024; double stack[] = new double[MAX_DEPTH]; int depth = 0; public DoubleStack() { init(); } public void init() { depth = 0; } int depth() { return depth; } boolean empty() { return (depth == 0); } double pop() throws StackException { if (depth <= 0) { throw new StackException("Stack is empty"); } else { double ret = stack[depth - 1]; depth--; return ret; } } double top() throws StackException { if (depth <= 0) { throw new StackException("Stack is empty"); } else { return stack[depth - 1]; } } void push(double x) throws StackException { if (depth >= MAX_DEPTH) { throw new StackException("Stack overflow"); } else { stack[depth] = x; depth++; } } // Return the element at the depth i (zero is a top of stack) double elementAt(int i) { if (i >= depth) return 0.; else return stack[depth - 1 - i]; } } class StackException extends Exception { String reason = "Stack is empty"; public StackException() {} public StackException(String cause) { reason = cause; } public String toString() { return ("StackException: " + reason); } }