1
0
mirror of https://github.com/DanilaFe/abacus synced 2025-04-21 08:13:02 -07:00

add stop on node

This commit is contained in:
rileyJones 2017-08-02 11:04:35 -07:00
parent f464bcff6f
commit 051be8d49e
8 changed files with 115 additions and 70 deletions

View File

@ -53,7 +53,10 @@ public class Abacus {
* from a string. * from a string.
*/ */
private TreeBuilder treeBuilder; private TreeBuilder treeBuilder;
private Window window;
public boolean getStop(){
return window.getStop();
}
/** /**
* Creates a new instance of the Abacus calculator. * Creates a new instance of the Abacus calculator.
*/ */
@ -133,7 +136,7 @@ public class Abacus {
* @return the resulting tree, null if the tree builder or the produced tree are null. * @return the resulting tree, null if the tree builder or the produced tree are null.
*/ */
public TreeNode parseString(String input) { public TreeNode parseString(String input) {
return treeBuilder.fromString(input); return treeBuilder.fromString(input,this);
} }
/** /**
@ -165,4 +168,8 @@ public class Abacus {
} }
return null; return null;
} }
public void setWindow(Window window) {
this.window = window;
}
} }

View File

@ -1,5 +1,6 @@
package org.nwapw.abacus.parsing; package org.nwapw.abacus.parsing;
import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.tree.TreeNode;
import java.util.List; import java.util.List;
@ -18,5 +19,5 @@ public interface Parser<T> {
* @param tokens the tokens to construct a tree from. * @param tokens the tokens to construct a tree from.
* @return the constructed tree, or null on error. * @return the constructed tree, or null on error.
*/ */
public TreeNode constructTree(List<T> tokens); public TreeNode constructTree(List<T> tokens,Abacus trace);
} }

View File

@ -34,6 +34,8 @@ public class ShuntingYardParser implements Parser<Match<TokenType>>, PluginListe
*/ */
private Map<String, OperatorType> typeMap; private Map<String, OperatorType> typeMap;
//private Abacus trace;
/** /**
* Creates a new Shunting Yard parser with the given Abacus instance. * Creates a new Shunting Yard parser with the given Abacus instance.
* *
@ -116,7 +118,8 @@ public class ShuntingYardParser implements Parser<Match<TokenType>>, PluginListe
* @param matches the list of tokens from the source string. * @param matches the list of tokens from the source string.
* @return the construct tree expression. * @return the construct tree expression.
*/ */
public TreeNode constructRecursive(List<Match<TokenType>> matches) { public TreeNode constructRecursive(List<Match<TokenType>> matches,Abacus trace) {
//this.trace = trace;
if (matches.size() == 0) return null; if (matches.size() == 0) return null;
Match<TokenType> match = matches.remove(0); Match<TokenType> match = matches.remove(0);
TokenType matchType = match.getType(); TokenType matchType = match.getType();
@ -124,22 +127,22 @@ public class ShuntingYardParser implements Parser<Match<TokenType>>, PluginListe
String operator = match.getContent(); String operator = match.getContent();
OperatorType type = typeMap.get(operator); OperatorType type = typeMap.get(operator);
if (type == OperatorType.BINARY_INFIX) { if (type == OperatorType.BINARY_INFIX) {
TreeNode right = constructRecursive(matches); TreeNode right = constructRecursive(matches,trace);
TreeNode left = constructRecursive(matches); TreeNode left = constructRecursive(matches,trace);
if (left == null || right == null) return null; if (left == null || right == null) return null;
else return new BinaryInfixNode(operator, left, right); else return new BinaryInfixNode(operator, left, right,trace);
} else { } else {
TreeNode applyTo = constructRecursive(matches); TreeNode applyTo = constructRecursive(matches,trace);
if (applyTo == null) return null; if (applyTo == null) return null;
else return new UnaryPrefixNode(operator, applyTo); else return new UnaryPrefixNode(operator, applyTo,trace);
} }
} else if (matchType == TokenType.NUM) { } else if (matchType == TokenType.NUM) {
return new NumberNode(abacus.numberFromString(match.getContent())); return new NumberNode(abacus.numberFromString(match.getContent()));
} else if (matchType == TokenType.FUNCTION) { } else if (matchType == TokenType.FUNCTION) {
String functionName = match.getContent(); String functionName = match.getContent();
FunctionNode node = new FunctionNode(functionName); FunctionNode node = new FunctionNode(functionName,trace);
while (!matches.isEmpty() && matches.get(0).getType() != TokenType.INTERNAL_FUNCTION_END) { while (!matches.isEmpty() && matches.get(0).getType() != TokenType.INTERNAL_FUNCTION_END) {
TreeNode argument = constructRecursive(matches); TreeNode argument = constructRecursive(matches,trace);
if (argument == null) return null; if (argument == null) return null;
node.prependChild(argument); node.prependChild(argument);
} }
@ -151,10 +154,10 @@ public class ShuntingYardParser implements Parser<Match<TokenType>>, PluginListe
} }
@Override @Override
public TreeNode constructTree(List<Match<TokenType>> tokens) { public TreeNode constructTree(List<Match<TokenType>> tokens,Abacus trace) {
tokens = intoPostfix(new ArrayList<>(tokens)); tokens = intoPostfix(new ArrayList<>(tokens));
Collections.reverse(tokens); Collections.reverse(tokens);
return constructRecursive(tokens); return constructRecursive(tokens,trace);
} }
@Override @Override

View File

@ -1,5 +1,6 @@
package org.nwapw.abacus.parsing; package org.nwapw.abacus.parsing;
import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.tree.TreeNode;
import java.util.List; import java.util.List;
@ -41,10 +42,10 @@ public class TreeBuilder<T> {
* @param input the string to parse into a tree. * @param input the string to parse into a tree.
* @return the resulting tree. * @return the resulting tree.
*/ */
public TreeNode fromString(String input) { public TreeNode fromString(String input,Abacus trace) {
List<T> tokens = tokenizer.tokenizeString(input); List<T> tokens = tokenizer.tokenizeString(input);
if (tokens == null) return null; if (tokens == null) return null;
return parser.constructTree(tokens); return parser.constructTree(tokens,trace);
} }
} }

View File

@ -1,5 +1,7 @@
package org.nwapw.abacus.tree; package org.nwapw.abacus.tree;
import org.nwapw.abacus.Abacus;
/** /**
* A tree node that represents an operation being applied to two operands. * A tree node that represents an operation being applied to two operands.
*/ */
@ -17,6 +19,7 @@ public class BinaryInfixNode extends TreeNode {
* The right node of the operation. * The right node of the operation.
*/ */
private TreeNode right; private TreeNode right;
private Abacus trace;
private BinaryInfixNode() { private BinaryInfixNode() {
} }
@ -27,8 +30,8 @@ public class BinaryInfixNode extends TreeNode {
* *
* @param operation the operation. * @param operation the operation.
*/ */
public BinaryInfixNode(String operation) { public BinaryInfixNode(String operation,Abacus trace) {
this(operation, null, null); this(operation, null, null,trace);
} }
/** /**
@ -39,10 +42,11 @@ public class BinaryInfixNode extends TreeNode {
* @param left the left node of the expression. * @param left the left node of the expression.
* @param right the right node of the expression. * @param right the right node of the expression.
*/ */
public BinaryInfixNode(String operation, TreeNode left, TreeNode right) { public BinaryInfixNode(String operation, TreeNode left, TreeNode right,Abacus trace) {
this.operation = operation; this.operation = operation;
this.left = left; this.left = left;
this.right = right; this.right = right;
this.trace = trace;
} }
/** /**
@ -92,11 +96,16 @@ public class BinaryInfixNode extends TreeNode {
@Override @Override
public <T> T reduce(Reducer<T> reducer) { public <T> T reduce(Reducer<T> reducer) {
if(!trace.getStop()) {
T leftReduce = left.reduce(reducer); T leftReduce = left.reduce(reducer);
T rightReduce = right.reduce(reducer); T rightReduce = right.reduce(reducer);
if (leftReduce == null || rightReduce == null) return null; if (leftReduce == null || rightReduce == null) return null;
return reducer.reduceNode(this, leftReduce, rightReduce); return reducer.reduceNode(this, leftReduce, rightReduce);
} }
return null;
}
@Override @Override
public String toString() { public String toString() {

View File

@ -1,5 +1,7 @@
package org.nwapw.abacus.tree; package org.nwapw.abacus.tree;
import org.nwapw.abacus.Abacus;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -16,6 +18,7 @@ public class FunctionNode extends TreeNode {
* The list of arguments to the function. * The list of arguments to the function.
*/ */
private List<TreeNode> children; private List<TreeNode> children;
private Abacus trace;
/** /**
* Creates a function node with no function. * Creates a function node with no function.
@ -28,9 +31,10 @@ public class FunctionNode extends TreeNode {
* *
* @param function the function name. * @param function the function name.
*/ */
public FunctionNode(String function) { public FunctionNode(String function,Abacus trace) {
this.function = function; this.function = function;
children = new ArrayList<>(); children = new ArrayList<>();
this.trace = trace;
} }
/** /**

View File

@ -1,5 +1,7 @@
package org.nwapw.abacus.tree; package org.nwapw.abacus.tree;
import org.nwapw.abacus.Abacus;
public class UnaryPrefixNode extends TreeNode { public class UnaryPrefixNode extends TreeNode {
/** /**
@ -10,14 +12,15 @@ public class UnaryPrefixNode extends TreeNode {
* The tree node to apply the operation to. * The tree node to apply the operation to.
*/ */
private TreeNode applyTo; private TreeNode applyTo;
private Abacus trace;
/** /**
* Creates a new node with the given operation and no child. * Creates a new node with the given operation and no child.
* *
* @param operation the operation for this node. * @param operation the operation for this node.
*/ */
public UnaryPrefixNode(String operation) { public UnaryPrefixNode(String operation,Abacus trace) {
this(operation, null); this(operation, null,trace);
} }
/** /**
@ -26,17 +29,21 @@ public class UnaryPrefixNode extends TreeNode {
* @param operation the operation for this node. * @param operation the operation for this node.
* @param applyTo the node to apply the function to. * @param applyTo the node to apply the function to.
*/ */
public UnaryPrefixNode(String operation, TreeNode applyTo) { public UnaryPrefixNode(String operation, TreeNode applyTo,Abacus trace) {
this.operation = operation; this.operation = operation;
this.applyTo = applyTo; this.applyTo = applyTo;
this.trace = trace;
} }
@Override @Override
public <T> T reduce(Reducer<T> reducer) { public <T> T reduce(Reducer<T> reducer) {
if(!trace.getStop()) {
Object reducedChild = applyTo.reduce(reducer); Object reducedChild = applyTo.reduce(reducer);
if (reducedChild == null) return null; if (reducedChild == null) return null;
return reducer.reduceNode(this, reducedChild); return reducer.reduceNode(this, reducedChild);
} }
return null;
}
/** /**
* Gets the operation of this node. * Gets the operation of this node.

View File

@ -16,7 +16,6 @@ import java.awt.event.MouseEvent;
*/ */
public class Window extends JFrame { public class Window extends JFrame {
private boolean contComputation;
private static final String CALC_STRING = "Calculate"; private static final String CALC_STRING = "Calculate";
private static final String SYNTAX_ERR_STRING = "Syntax Error"; private static final String SYNTAX_ERR_STRING = "Syntax Error";
@ -24,7 +23,6 @@ public class Window extends JFrame {
private static final String NUMBER_SYSTEM_LABEL = "Number Type:"; private static final String NUMBER_SYSTEM_LABEL = "Number Type:";
private static final String FUNCTION_LABEL = "Functions:"; private static final String FUNCTION_LABEL = "Functions:";
private static final String STOP_STRING = "Stop"; private static final String STOP_STRING = "Stop";
private static final String STOPPED_TEXT = "Stopped";
/** /**
* Array of Strings to which the "calculate" button's text * Array of Strings to which the "calculate" button's text
* changes. For instance, in the graph tab, the name will * changes. For instance, in the graph tab, the name will
@ -124,62 +122,56 @@ public class Window extends JFrame {
*/ */
private Thread calculateThread; private Thread calculateThread;
/** /**
* Check if currently calculating * Check if currently calculating.
*/ */
private boolean calculating; private boolean calculating;
private int count;
//private Object monitor;
/** /**
* Action listener that causes the input to be evaluated. * Checks if thread should stop calculating.
*/
private boolean stopCalculating;
/**
* Test variable to check number of threads running in the calculator.
*/
private int count;
/**
* ActionListener that stops calculations.
*/ */
//*
private ActionListener stopListener = (event) -> { private ActionListener stopListener = (event) -> {
//contComputation=false; //System.out.println(count++); //Shows about how many calculation threads are running with the calculating=false command
//Long pause = Long.MAX_VALUE; //calculating = false; //Ignores result of calculation and allows for the start of a new calculation
//System.out.println(Thread.currentThread().getName()); stopCalculating = true; //Stops calculation at the next node check
//System.out.println(calculateThread.getName()); //calculateThread.stop(); //Stops thread no matter what, Unsafe
//calculateThread.suspend(); };
System.out.println(count++);
calculating = false; /**
/* * Node check to get whether nodes should continue calculating.
synchronized(calculateThread) { * @return boolean stop calculations if true.
try { */
calculateThread.wait(); public boolean getStop(){
} catch (InterruptedException e) { return stopCalculating;
e.printStackTrace();
} }
}
//*/ /**
};//*/ * ActionListener that runs all calculations.
*/
private ActionListener evaluateListener = (event) -> { private ActionListener evaluateListener = (event) -> {
//contComputation = true;
Runnable calculate = new Runnable() { Runnable calculate = new Runnable() {
public void run() { public void run() {
boolean skip = false; boolean skip = false;
calculating = true; calculating = true;
TreeNode parsedExpression = null; TreeNode parsedExpression = null;
parsedExpression = abacus.parseString(inputField.getText()); parsedExpression = abacus.parseString(inputField.getText());
if (parsedExpression == null) { if (parsedExpression == null) {
lastOutputArea.setText(SYNTAX_ERR_STRING); lastOutputArea.setText(SYNTAX_ERR_STRING);
skip = true; skip = true;
} }
/*
try {
Thread.currentThread().sleep(9999);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IllegalMonitorStateException e){
e.printStackTrace();
}
//*/
//NumberInterface numberInterface = null;
if(!skip){ if(!skip){
NumberInterface numberInterface = abacus.evaluateTree(parsedExpression); NumberInterface numberInterface = abacus.evaluateTree(parsedExpression);
if (numberInterface == null) { if (numberInterface == null) {
lastOutputArea.setText(EVAL_ERR_STRING); lastOutputArea.setText(EVAL_ERR_STRING);
calculating = false;
stopCalculating = false;
return; return;
} }
if(calculateThread.equals(Thread.currentThread())) { if(calculateThread.equals(Thread.currentThread())) {
@ -189,6 +181,7 @@ public class Window extends JFrame {
lastOutputArea.setText(lastOutput); lastOutputArea.setText(lastOutput);
inputField.setText(""); inputField.setText("");
calculating = false; calculating = false;
stopCalculating = false;
} }
} }
} }
@ -208,6 +201,14 @@ public class Window extends JFrame {
evaluateListener, evaluateListener,
null null
}; };
/**
* Array of listeners that tell the stop button how to behave
* at a given input tab.
*/
private ActionListener[] stopListeners = {
stopListener,
null
};
/** /**
* Creates a new window with the given manager. * Creates a new window with the given manager.
@ -217,6 +218,7 @@ public class Window extends JFrame {
public Window(Abacus abacus) { public Window(Abacus abacus) {
this(); this();
this.abacus = abacus; this.abacus = abacus;
abacus.setWindow(this);
} }
/** /**
@ -225,29 +227,36 @@ public class Window extends JFrame {
private Window() { private Window() {
super(); super();
contComputation = true; //variables related to when calculations occur
stopCalculating = false;
calculating = true;
lastOutput = ""; lastOutput = "";
//default window properties
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(320, 480); setSize(320, 480);
//initiates input objects
inputField = new JTextField(); inputField = new JTextField();
inputEnterButton = new JButton(CALC_STRING); inputEnterButton = new JButton(CALC_STRING);
inputStopButton = new JButton(STOP_STRING); inputStopButton = new JButton(STOP_STRING);
//adds input objects into Panel
inputPanel = new JPanel(); inputPanel = new JPanel();
inputPanel.setLayout(new BorderLayout()); inputPanel.setLayout(new BorderLayout());
inputPanel.add(inputStopButton, BorderLayout.SOUTH); inputPanel.add(inputStopButton, BorderLayout.SOUTH);
inputPanel.add(inputField, BorderLayout.NORTH); inputPanel.add(inputField, BorderLayout.NORTH);
inputPanel.add(inputEnterButton, BorderLayout.CENTER); inputPanel.add(inputEnterButton, BorderLayout.CENTER);
//initiates output objects in calculator tab
historyModel = new HistoryTableModel(); historyModel = new HistoryTableModel();
historyTable = new JTable(historyModel); historyTable = new JTable(historyModel);
historyScroll = new JScrollPane(historyTable); historyScroll = new JScrollPane(historyTable);
lastOutputArea = new JTextArea(lastOutput); lastOutputArea = new JTextArea(lastOutput);
lastOutputArea.setEditable(false); lastOutputArea.setEditable(false);
//adds output objects into Panel
calculationPanel = new JPanel(); calculationPanel = new JPanel();
calculationPanel.setLayout(new BorderLayout()); calculationPanel.setLayout(new BorderLayout());
calculationPanel.add(historyScroll, BorderLayout.CENTER); calculationPanel.add(historyScroll, BorderLayout.CENTER);
@ -286,19 +295,23 @@ public class Window extends JFrame {
int selectionIndex = pane.getSelectedIndex(); int selectionIndex = pane.getSelectedIndex();
boolean enabled = INPUT_ENABLED[selectionIndex]; boolean enabled = INPUT_ENABLED[selectionIndex];
ActionListener listener = listeners[selectionIndex]; ActionListener listener = listeners[selectionIndex];
ActionListener stopUsed = stopListeners[selectionIndex];
inputEnterButton.setText(BUTTON_NAMES[selectionIndex]); inputEnterButton.setText(BUTTON_NAMES[selectionIndex]);
inputField.setEnabled(enabled); inputField.setEnabled(enabled);
inputEnterButton.setEnabled(enabled); inputEnterButton.setEnabled(enabled);
inputStopButton.setEnabled(enabled);
for (ActionListener removingListener : inputEnterButton.getActionListeners()) { for (ActionListener removingListener : inputEnterButton.getActionListeners()) {
inputEnterButton.removeActionListener(removingListener); inputEnterButton.removeActionListener(removingListener);
inputField.removeActionListener(removingListener); inputField.removeActionListener(removingListener);
}
for(ActionListener removingListener : inputStopButton.getActionListeners()){
inputStopButton.removeActionListener(removingListener); inputStopButton.removeActionListener(removingListener);
} }
if (listener != null) { if (listener != null) {
inputEnterButton.addActionListener(listener); inputEnterButton.addActionListener(listener);
inputField.addActionListener(listener); inputField.addActionListener(listener);
inputStopButton.addActionListener(listener); inputStopButton.addActionListener(stopUsed);
} }
}); });
add(pane, BorderLayout.CENTER); add(pane, BorderLayout.CENTER);