// InfixEvalDemo // Demonstates the buildFromInfix and evaluation routines in // Expression.java // James Brink, Revised June 21, 2008, June 17, 2013 import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.event.*; /** * An applet which demonstrates the abilities of the buildFromInfix and * evaluate methods in the ExprEvaluator package. It can be run using * InfixEvalDemo.HTML with either the AppletViewer or a browser. *

* An infix expression is the typical way we write algebraic expressions * that uses binary operators between the values they operate on and * uses parenthesis to help determine the order of evaluation and specify * arguments for functions. For example: *
x * y + 20 *
(x-10)/(x+5) *
10 * sqrt(x^2 + y^2) *

* There are three modes of operation.

*

* If "Use variables t, x, y without '='" is selected, then there are text boxes * dedicated to the variables t, x, and y. 4 distinct ExprEvaluators objects * are uses to evaluate the expressions in the 4 text boxes. Using "=" is of * no particular benefit.

*

* If "Use variables a, b, ..., z with '='" is selected, then there are no dedicated * text boxes. One needs to use "=" to assign values to the variables. Only * one ExprEvaluator object is used. *

* If "Create a table" is selected, then the user can supply up to 4 functions * and a table of values will be printed for x = 0, 1, 2, 3, and 4. In this * mode, a tree is built for each of the functions. *

* Requires: *
ExprEvaluator.java *
EasyFormat.java *
DoubleScanner.java * @author James Brink, brinkje@plu.edu * @version 6/21/2008 */ public class InfixEvalDemo extends JApplet implements ActionListener, ItemListener, FocusListener { JRadioButton txyVarRad = new JRadioButton("Use variables t, x, y without '='"); JRadioButton allVarRad = new JRadioButton("Use variables a, b, ..., z with '='"); JRadioButton tableRad = new JRadioButton("Create a table"); JTextField infixTxt = new JTextField(20); JTextField tTxt = new JTextField(5); JTextField xTxt = new JTextField(10); JTextField yTxt = new JTextField(10); JLabel tLbl = new JLabel("t"); JLabel xLbl = new JLabel("x"); JLabel yLbl = new JLabel("y"); JLabel infixLbl = new JLabel("Infix"); double tVal = 0, xVal = 0, yVal = 0, infixVal = 0; String expression = ""; ExprEvaluator tTree = new ExprEvaluator(); // tree for t ExprEvaluator xTree = new ExprEvaluator(); // tree for x ExprEvaluator yTree = new ExprEvaluator(); // tree for y ExprEvaluator infixTree = new ExprEvaluator(); // tree for infix exp. JButton helpBtn = new JButton("Help"); JButton evalBtn = new JButton("Evaluate"); JCheckBox debugChk = new JCheckBox("Debug"); JCheckBox stackChk = new JCheckBox("Stacks"); JTextArea outputTxtA = new JTextArea(20, 40); JScrollPane outputPane = new JScrollPane(outputTxtA, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); /** * Create a inputPnl, a panel used for getting input. */ public void init() { // set up top panel for instructions JLabel titleLbl = new JLabel("Infix Expression Evaluator"); titleLbl.setHorizontalAlignment(JLabel.CENTER); titleLbl.setFont(titleLbl.getFont().deriveFont(Font.BOLD,20)); titleLbl.setForeground(Color.BLUE); JPanel inputPnl = new JPanel(); JPanel instPnl = new JPanel(new GridLayout(2, 1)); JLabel inst1Lbl = new JLabel("Enter any new values or expresions."); JLabel inst3Lbl = new JLabel("Then click \"evaluate\" or press the \"Enter\" key."); instPnl.add(inst1Lbl); instPnl.add(inst3Lbl); // set up radioPnl JPanel radioPnl = new JPanel(); radioPnl.add(txyVarRad); radioPnl.add(allVarRad); radioPnl.add(tableRad); ButtonGroup radioGrp = new ButtonGroup(); radioGrp.add(txyVarRad); radioGrp.add(allVarRad); radioGrp.add(tableRad); txyVarRad.setSelected(true); // set up panels for input of t, x, and y values and infix expression JPanel tPnl = new JPanel(); tPnl.add(tLbl); tPnl.add(tTxt); JPanel xPnl = new JPanel(); xPnl.add(xLbl); xPnl.add(xTxt); JPanel yPnl = new JPanel(); yPnl.add(yLbl); yPnl.add(yTxt); JPanel infixPnl = new JPanel(); infixPnl.add(infixLbl); infixPnl.add(infixTxt); JPanel buttonPnl = new JPanel(); buttonPnl.add(evalBtn); buttonPnl.add(helpBtn); buttonPnl.add(stackChk); buttonPnl.add(debugChk); // combine the panels inputPnl.setLayout(new GridLayout(8, 1)); inputPnl.add(titleLbl); inputPnl.add(instPnl); inputPnl.add(radioPnl); inputPnl.add(tPnl); inputPnl.add(xPnl); inputPnl.add(yPnl); inputPnl.add(infixPnl); inputPnl.add(buttonPnl); // add the panels to complete GUI add(inputPnl, "North"); add(outputPane, "Center"); // add actionListeners helpBtn.addActionListener(this); evalBtn.addActionListener(this); tTxt.addActionListener(this); xTxt.addActionListener(this); yTxt.addActionListener(this); infixTxt.addActionListener(this); // add itemListeners debugChk.addItemListener(this); stackChk.addItemListener(this); txyVarRad.addItemListener(this); allVarRad.addItemListener(this); tableRad.addItemListener(this); // add FocusListeners tTxt.addFocusListener(this); xTxt.addFocusListener(this); yTxt.addFocusListener(this); infixTxt.addFocusListener(this); evalBtn.addFocusListener(this); helpBtn.addFocusListener(this); // add mnenonics evalBtn.setMnemonic(KeyEvent.VK_E); helpBtn.setMnemonic(KeyEvent.VK_H); stackChk.setMnemonic(KeyEvent.VK_S); debugChk.setMnemonic(KeyEvent.VK_D); // add tool tips tTxt.setToolTipText("An expression for the value of t"); xTxt.setToolTipText("An expression for the value of x"); yTxt.setToolTipText("An expression for the value of y"); infixTxt.setToolTipText("The expression to be evaluated"); evalBtn.setToolTipText("Evaluate the expression"); helpBtn.setToolTipText("Show help on using InfixEvalDemo"); debugChk.setToolTipText ("Sends debug output to standard output"); stackChk.setToolTipText ("Sends stack info to standard output after every step"); } // end init private void initExpression() { tTxt.setText(""); xTxt.setText(""); yTxt.setText(""); infixTxt.setText(""); } // initExpression /** * Evaluates the expression using one of the private methods txyEvaluate * or allEvaluate. */ public void evaluate() { if (txyVarRad.isSelected()) txyEvaluate(); else if (tableRad.isSelected()) tableEvaluate(); else allEvaluate(); // set cursor to end of item to cause it to scroll to last line outputTxtA.setCaretPosition(outputTxtA.getDocument().getLength()); } // evaluate // textArea.setCaretPosition(textArea.getDocument().getLength()); /** * Evaluates the expressions for t, x, y, and infix in that order * for the txyVar mode. Uses four distinct trees, one each for * t, x, y, z. */ private void txyEvaluate() { String input = ""; resetInput(); try { if (! tTxt.getText().equals("")) { input = tTxt.getText(); tTree.buildFromInfix(input); tVal = tTree.evaluate(tVal, xVal, yVal); } else tVal = 0; if (! xTxt.getText().equals("")) { input = xTxt.getText(); xTree.buildFromInfix(input); xVal = xTree.evaluate(tVal, xVal, yVal); } else xVal = 0; if (! yTxt.getText().equals("")) { input = yTxt.getText(); yTree.buildFromInfix(input); yVal = yTree.evaluate(tVal, xVal, yVal); } else yVal = 0; if (! infixTxt.getText().equals("")) { input = infixTxt.getText(); infixTree.buildFromInfix(input); infixVal = infixTree.evaluate(tVal, xVal, yVal); } else { infixVal = 0; input = ""; } // output the results outputTxtA.append( "\n\nt = " + tVal + ", x = " + xVal + ", and y = " + yVal); if (!input.equals("")) outputTxtA.append( "\nFor expression " + input + "\nthe expression tree is: \n" + infixTree.toString() + "The value is " + infixVal); System.out.println("Expression: " + infixTree.getInputStr()); System.out.println("User function: " + infixTree.getUserFunction()); if (infixTree.getInputStr().indexOf("user") >= 0) outputTxtA.append("\nUser function: " + infixTree.getUserFunction()); } catch (ArrayIndexOutOfBoundsException e) { outputTxtA.append( "\nInvalid expression. Possible causes:" + "\n Missing numbers, identifiers, or \"(\"" + "\n Extra operators or commas" + "\n Using variable names other than 'x' and 'y'" + "\nin the expression \"" + input + "\""); } catch (Exception e) { // any other error outputTxtA.append("\n"+ e.getMessage()); } } // end txyEvaluate /** * Evaluates the expressions for 1st, 2nd, 3rd, and infix in that order * for the allVar mode. All expressions are evaluated in sequence in the * same ExprEvaluator so that values set in one text field are available * in the next evaluation. */ private void allEvaluate() { String input = ""; try { if (! tTxt.getText().equals("")) { input = tTxt.getText(); // 1st infixTree.buildFromInfix(input); tVal = infixTree.evaluate(); outputTxtA.append( "\n\n1st calculation: " + input + " = " + tVal); } if (! xTxt.getText().equals("")) { input = xTxt.getText(); // 2nd infixTree.buildFromInfix(input); xVal = infixTree.evaluate(); outputTxtA.append( "\n2nd calculation: " + input + " = " + xVal); } if (! yTxt.getText().equals("")) { input = yTxt.getText(); // 3rd infixTree.buildFromInfix(input); yVal = infixTree.evaluate(); outputTxtA.append( "\n3rd calculation: " + input + " =" + yVal); } if (! infixTxt.getText().equals("")) { input = infixTxt.getText(); // infix infixTree.buildFromInfix(input); infixVal = infixTree.evaluate(); outputTxtA.append("\n" + infixTree.toString()); outputTxtA.append( "\ninfix calculation: " + input + " = " + infixVal); } } catch (Exception e) { outputTxtA.append(e.getMessage()); } } // allEvaluate private void tableEvaluate() { ExprTree [] fTree = new ExprTree[4]; double fVal; String [] fStr = new String [4]; double x; int i = 0; fStr[0] = tTxt.getText(); fStr[1] = xTxt.getText(); fStr[2] = yTxt.getText(); fStr[3] = infixTxt.getText(); try { // build the trees for (i = 0; i < 4; i++) { if (! fStr[i].equals("")) fTree[i] = infixTree.buildFromInfix(fStr[i]); } // print headings outputTxtA.append("\nx"); for (i = 0; i < 4; i++) { if (! fStr[i].equals("") && fStr[i].indexOf("define") < 0) outputTxtA.append("\tf" + (i+1) + "(x)"); } outputTxtA.append("\n"); outputTxtA.append("--"); for (i = 0; i < 4; i++) { if (! fStr[i].equals("") && fStr[i].indexOf("define") < 0) outputTxtA.append("\t------"); } outputTxtA.append("\n"); x = 0; for (x = 0; x < 5; x++) { infixTree.setX(x); outputTxtA.append("" + x); for (i = 0; i < 4; i++) if (! fStr[i].equals("") && fStr[i].indexOf("define") < 0) { fVal = infixTree.evaluate(fTree[i]); outputTxtA.append("\t" + EasyFormat.format(fVal,3)); } outputTxtA.append("\n"); } } catch (Exception e) { outputTxtA.append("f" + (i+1) + "(x): " + e.getMessage() + "\n"); } } // tableEvaluate /** * Implements the evaluate operations and the help button. */ public void actionPerformed(ActionEvent event) { String txyHelpMsg = "InfixEvalDemo Beta 4.5\n" + "Demonstrates the buildFromInfix and evaluate methods in " + "ExprEvaluator.java.\n" + "\n" + "The expression in \"Infix\" can depend on the values of t, x, " + "and y. Actually t, x, and y are\n" + "evaluated the same way and can also depend on t, x, and y. " + "For example, this allows y to\n" + "be a function of x or x and y be functions of paramter t. " + "One can do such things as \ndefine x as x + 1 which increments " + "x every time the items are evaluated. It doesn't\nhelp " + "to use '=' operators.\n" + "\n" + "Order of evaluation: t, x, y, and finally infix.\n" + "\n" + "Infix strings like x * log(y + 2) / (25 + 2^3) " + "(as well expressions for t, x, and y) may include: \n" + " variables: t, x, and y\n"; String allHelpMsg = "InfixEvalDemo Beta 4.5\n" + "Demonstrates the buildFromInfix and evaluate methods in " + "ExprEvaluator.java\n" + "\n" + "The expression in \"Infix\" can depend on the values of all " + "26 variables 'a', 'b',...., 'z'.\nTo use variables, you will " + "need to assign them values using the '=' operator.\n" + "\n" + "The expressions are evaluated in the order 1st, 2nd, 3rd, infix " + "all using the same \nExprEvaluator object so any variable " + "assigned a value in one text box will retain\nthat value when " + "the following text boxes are evaluated.\n" + "\n" + "Infix strings like x * log(y + 2) / (25 + 2^3) " + "(as well expressions for t, x, and y) may include: \n" + ExprEvaluator.varHelp; String tableHelpMsg = "InfixEvalDemo Beta 4.5\n" + "Demonstrates calculating multiple functions.\n" + "Supply as many of the functions as desired and a table of values " + " will be printed.\n" + "You can define the user function before it is used.\n\n" + infixTree.introHelp + infixTree.varHelp + infixTree.infixHelp; String helpMsg; if (txyVarRad.isSelected()) helpMsg = txyHelpMsg + ExprEvaluator.infixHelp; else if (tableRad.isSelected()) helpMsg = tableHelpMsg; else helpMsg = allHelpMsg + ExprEvaluator.infixHelp; Object eventSource = event.getSource(); if (eventSource == helpBtn) JOptionPane.showMessageDialog(this, helpMsg, "Infix help", JOptionPane.INFORMATION_MESSAGE); else if (eventSource == evalBtn || eventSource == tTxt || eventSource == xTxt || eventSource == yTxt || eventSource == infixTxt) evaluate(); } // end actionPerformed /** * Implements the actions of the check boxes. */ public void itemStateChanged(ItemEvent event) { Object eventSource = event.getSource(); if (eventSource == debugChk) infixTree.debugMode(debugChk.isSelected()); else if (eventSource == stackChk) infixTree.displayStacks(stackChk.isSelected()); else if (eventSource == txyVarRad) setTxyVarMode(); else if (eventSource == allVarRad) setAllVarMode(); else if (eventSource == tableRad) setTableMode(); } // end itemStateChanged /** * Used to select all the text whenever a JTextField gets the focus * and let buttons respond to the "Enter" key. */ public void focusGained(FocusEvent e) { JTextField txt; Object source; source = e.getSource(); if (source == tTxt || source == xTxt || source == yTxt || source == infixTxt) { txt = (JTextField)(e.getSource()); txt.selectAll(); } else if (source == evalBtn || source == helpBtn) { getRootPane().setDefaultButton((JButton)source); } } // focusGained /** * Removes the keyboard focus (actually only needed for helpBtn). */ public void focusLost(FocusEvent e) { getRootPane().setDefaultButton(null); } // focusLost /** * Sets the focus on tTxt. (Used as a convience for users). */ private void resetInput() { tTxt.requestFocusInWindow(); } // end resetInput /** * Sets the GUI for the txyVar mode - shows text fields for t, x, and y. * = signs are not used. */ private void setAllVarMode() { tTxt.setColumns(20); xTxt.setColumns(20); yTxt.setColumns(20); tLbl.setText("1st (use var = ...)"); xLbl.setText("2nd (use var = ...)"); yLbl.setText("3rd (use var = ...)"); infixLbl.setText("Infix"); tTxt.setToolTipText("The first expression"); xTxt.setToolTipText("The second expression"); yTxt.setToolTipText("The third expression"); infixTxt.setToolTipText("The last expression to be evaluated"); } /** * Sets the GUI for the allVar mode - show text fields for all 26 variables * = signs are needed. */ private void setTxyVarMode() { tTxt.setColumns(5); xTxt.setColumns(10); yTxt.setColumns(10); tLbl.setText("t"); xLbl.setText("x"); yLbl.setText("y"); infixLbl.setText("Infix"); tTxt.setToolTipText("An expression for the value of t"); xTxt.setToolTipText("An expression for the value of x"); yTxt.setToolTipText("An expression for the value of y"); infixTxt.setToolTipText("The expression to be evaluated"); } /** * Set the GUI for the table mode */ private void setTableMode() { tTxt.setColumns(20); xTxt.setColumns(20); yTxt.setColumns(20); tLbl.setText("f1(x)"); xLbl.setText("f2(x)"); yLbl.setText("f3(x)"); infixLbl.setText("f4(x)"); tTxt.setToolTipText("An expression for f1(x)"); xTxt.setToolTipText("An expression for f2(x)"); yTxt.setToolTipText("An expression for f3(x)"); infixTxt.setToolTipText("An expression for f4(x)"); } // end setTableMode } // end class InfixEvalDemo