From 6337c74e632d50e8dc816bfd9c74d16a9d1d2b17 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sat, 29 Jul 2017 21:37:55 -0700 Subject: [PATCH] Replace the old TreeBuilder with the new TreeBuilder. --- src/org/nwapw/abacus/Abacus.java | 45 ++--- src/org/nwapw/abacus/tree/TreeBuilder.java | 210 --------------------- 2 files changed, 14 insertions(+), 241 deletions(-) delete mode 100644 src/org/nwapw/abacus/tree/TreeBuilder.java diff --git a/src/org/nwapw/abacus/Abacus.java b/src/org/nwapw/abacus/Abacus.java index eacc0d8..a5c61bb 100644 --- a/src/org/nwapw/abacus/Abacus.java +++ b/src/org/nwapw/abacus/Abacus.java @@ -1,15 +1,15 @@ package org.nwapw.abacus; import org.nwapw.abacus.config.ConfigurationObject; -import org.nwapw.abacus.function.Operator; import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NumberInterface; +import org.nwapw.abacus.parsing.LexerTokenizer; +import org.nwapw.abacus.parsing.ShuntingYardParser; +import org.nwapw.abacus.parsing.TreeBuilder; import org.nwapw.abacus.plugin.ClassFinder; -import org.nwapw.abacus.plugin.PluginListener; import org.nwapw.abacus.plugin.PluginManager; import org.nwapw.abacus.plugin.StandardPlugin; import org.nwapw.abacus.tree.NumberReducer; -import org.nwapw.abacus.tree.TreeBuilder; import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.window.Window; @@ -23,7 +23,7 @@ import java.lang.reflect.InvocationTargetException; * for piecing together all of the components, allowing * their interaction with each other. */ -public class Abacus implements PluginListener { +public class Abacus { /** * The default implementation to use for the number representation. @@ -44,11 +44,6 @@ public class Abacus implements PluginListener { * and getting functions from them. */ private PluginManager pluginManager; - /** - * Tree builder built from plugin manager, - * used to construct parse trees. - */ - private TreeBuilder treeBuilder; /** * The reducer used to evaluate the tree. */ @@ -57,6 +52,11 @@ public class Abacus implements PluginListener { * The configuration loaded from a file. */ private ConfigurationObject configuration; + /** + * The tree builder used to construct a tree + * from a string. + */ + private TreeBuilder treeBuilder; /** * Creates a new instance of the Abacus calculator. @@ -67,8 +67,12 @@ public class Abacus implements PluginListener { numberReducer = new NumberReducer(this); configuration = new ConfigurationObject(CONFIG_FILE); configuration.save(CONFIG_FILE); + LexerTokenizer lexerTokenizer = new LexerTokenizer(); + ShuntingYardParser shuntingYardParser = new ShuntingYardParser(this); + treeBuilder = new TreeBuilder<>(lexerTokenizer, shuntingYardParser); - pluginManager.addListener(this); + pluginManager.addListener(lexerTokenizer); + pluginManager.addListener(shuntingYardParser); pluginManager.addInstantiated(new StandardPlugin(pluginManager)); try { ClassFinder.loadJars("plugins") @@ -129,7 +133,6 @@ public class Abacus implements PluginListener { * @return the resulting tree, null if the tree builder or the produced tree are null. */ public TreeNode parseString(String input){ - if(treeBuilder == null) return null; return treeBuilder.fromString(input); } @@ -156,26 +159,6 @@ public class Abacus implements PluginListener { return null; } - @Override - public void onLoad(PluginManager manager) { - treeBuilder = new TreeBuilder(this); - for(String function : manager.getAllFunctions()){ - treeBuilder.registerFunction(function); - } - for(String operator : manager.getAllOperators()){ - Operator operatorObject = manager.operatorFor(operator); - treeBuilder.registerOperator(operator, - operatorObject.getAssociativity(), - operatorObject.getType(), - operatorObject.getPrecedence()); - } - } - - @Override - public void onUnload(PluginManager manager) { - treeBuilder = null; - } - public static void main(String[] args){ try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); diff --git a/src/org/nwapw/abacus/tree/TreeBuilder.java b/src/org/nwapw/abacus/tree/TreeBuilder.java deleted file mode 100644 index 13ac266..0000000 --- a/src/org/nwapw/abacus/tree/TreeBuilder.java +++ /dev/null @@ -1,210 +0,0 @@ -package org.nwapw.abacus.tree; - -import org.nwapw.abacus.Abacus; -import org.nwapw.abacus.function.OperatorAssociativity; -import org.nwapw.abacus.function.OperatorType; -import org.nwapw.abacus.lexing.Lexer; -import org.nwapw.abacus.lexing.pattern.Match; -import org.nwapw.abacus.lexing.pattern.Pattern; - -import java.util.*; - -/** - * The builder responsible for turning strings into trees. - */ -public class TreeBuilder { - - /** - * The lexer used to get the input tokens. - */ - private Lexer lexer; - /** - * The map of operator precedences. - */ - private Map precedenceMap; - /** - * The map of operator associativity. - */ - private Map associativityMap; - /** - * The map of operator types. - */ - private Map typeMap; - /** - * The abacus instance required to interact with - * other components of the calculator. - */ - private Abacus abacus; - - /** - * Comparator used to sort token types. - */ - protected static Comparator tokenSorter = Comparator.comparingInt(e -> e.priority); - - /** - * Creates a new TreeBuilder. - */ - public TreeBuilder(Abacus abacus){ - this.abacus = abacus; - lexer = new Lexer(){{ - register(" ", TokenType.WHITESPACE); - register(",", TokenType.COMMA); - register("[0-9]*(\\.[0-9]+)?", TokenType.NUM); - register("\\(", TokenType.OPEN_PARENTH); - register("\\)", TokenType.CLOSE_PARENTH); - }}; - precedenceMap = new HashMap<>(); - associativityMap = new HashMap<>(); - typeMap = new HashMap<>(); - } - - /** - * Registers a function with the TreeBuilder. - * @param function the function to register. - */ - public void registerFunction(String function){ - lexer.register(Pattern.sanitize(function), TokenType.FUNCTION); - } - - /** - * Registers an operator with the TreeBuilder. - * @param operator the operator to register. - * @param precedence the precedence of the operator. - * @param associativity the associativity of the operator. - */ - public void registerOperator(String operator, OperatorAssociativity associativity, - OperatorType operatorType, int precedence){ - lexer.register(Pattern.sanitize(operator), TokenType.OP); - precedenceMap.put(operator, precedence); - associativityMap.put(operator, associativity); - typeMap.put(operator, operatorType); - } - - /** - * Tokenizes a string, converting it into matches - * @param string the string to tokenize. - * @return the list of tokens produced. - */ - public List> tokenize(String string){ - return lexer.lexAll(string, 0, tokenSorter); - } - - /** - * Rearranges tokens into a postfix list, using Shunting Yard. - * @param from the tokens to be rearranged. - * @return the resulting list of rearranged tokens. - */ - public List> intoPostfix(List> from){ - ArrayList> output = new ArrayList<>(); - Stack> tokenStack = new Stack<>(); - while(!from.isEmpty()){ - Match match = from.remove(0); - TokenType matchType = match.getType(); - if(matchType == TokenType.NUM) { - output.add(match); - } else if(matchType == TokenType.FUNCTION) { - output.add(new Match<>("" , TokenType.INTERNAL_FUNCTION_END)); - tokenStack.push(match); - } else if(matchType == TokenType.OP){ - String tokenString = match.getContent(); - OperatorType type = typeMap.get(tokenString); - int precedence = precedenceMap.get(tokenString); - OperatorAssociativity associativity = associativityMap.get(tokenString); - - if(type == OperatorType.UNARY_POSTFIX){ - output.add(match); - continue; - } - - while(!tokenStack.empty()) { - Match otherMatch = tokenStack.peek(); - TokenType otherMatchType = otherMatch.getType(); - if(!(otherMatchType == TokenType.OP || otherMatchType == TokenType.FUNCTION)) break; - - if(otherMatchType == TokenType.OP){ - int otherPrecedence = precedenceMap.get(match.getContent()); - if(otherPrecedence < precedence || - (associativity == OperatorAssociativity.RIGHT && otherPrecedence == precedence)) { - break; - } - } - output.add(tokenStack.pop()); - } - tokenStack.push(match); - } else if(matchType == TokenType.OPEN_PARENTH){ - tokenStack.push(match); - } else if(matchType == TokenType.CLOSE_PARENTH || matchType == TokenType.COMMA){ - while(!tokenStack.empty() && tokenStack.peek().getType() != TokenType.OPEN_PARENTH){ - output.add(tokenStack.pop()); - } - if(tokenStack.empty()) return null; - if(matchType == TokenType.CLOSE_PARENTH){ - tokenStack.pop(); - } - } - } - while(!tokenStack.empty()){ - Match match = tokenStack.peek(); - TokenType matchType = match.getType(); - if(!(matchType == TokenType.OP || matchType == TokenType.FUNCTION)) return null; - output.add(tokenStack.pop()); - } - return output; - } - - /** - * Constructs a tree recursively from a list of tokens. - * @param matches the list of tokens from the source string. - * @return the construct tree expression. - */ - public TreeNode fromStringRecursive(List> matches){ - if(matches.size() == 0) return null; - Match match = matches.remove(0); - TokenType matchType = match.getType(); - if(matchType == TokenType.OP){ - String operator = match.getContent(); - OperatorType type = typeMap.get(operator); - if(type == OperatorType.BINARY_INFIX){ - TreeNode right = fromStringRecursive(matches); - TreeNode left = fromStringRecursive(matches); - if(left == null || right == null) return null; - else return new BinaryInfixNode(operator, left, right); - } else { - TreeNode applyTo = fromStringRecursive(matches); - if(applyTo == null) return null; - else return new UnaryPrefixNode(operator, applyTo); - } - } else if(matchType == TokenType.NUM){ - return new NumberNode(abacus.numberFromString(match.getContent())); - } else if(matchType == TokenType.FUNCTION){ - String functionName = match.getContent(); - FunctionNode node = new FunctionNode(functionName); - while(!matches.isEmpty() && matches.get(0).getType() != TokenType.INTERNAL_FUNCTION_END){ - TreeNode argument = fromStringRecursive(matches); - if(argument == null) return null; - node.prependChild(argument); - } - if(matches.isEmpty()) return null; - matches.remove(0); - return node; - } - return null; - } - - /** - * Creates a tree node from a string. - * @param string the string to create a node from. - * @return the resulting tree. - */ - public TreeNode fromString(String string){ - List> matches = tokenize(string); - if(matches == null) return null; - matches.removeIf(m -> m.getType() == TokenType.WHITESPACE); - matches = intoPostfix(matches); - if(matches == null) return null; - - Collections.reverse(matches); - return fromStringRecursive(matches); - } - -}