// 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