/** * Much like {@link OperatorTable} this call serves as a holder for a set of other objects * and acts as an interface to allow use of them. In this case the objects are * {@link GroupingSymbol GroupingSymbols}. *

* The most common usage of {@link GroupingSymbolTable} is {@link GenericGroupingSymbolTable}. * * @author WillHolcomb */ public class GroupingSymbolTable { /** * The current maximum number of elements possible */ protected int capacity = 0; /** * The current number of elements */ protected int size = 0; /** * The elements contained in the table */ protected GroupingSymbol [] symbols; /** * Creates a new empty table with a capacity of 20 elements */ public GroupingSymbolTable() { this(20); } /** * Creates a new empty table with a capacity of i elements. * If i is 0 then the capacity is set to 1. */ public GroupingSymbolTable(int i) { capacity = i; if(capacity == 0) capacity++; symbols = new GroupingSymbol[capacity]; } /** * Adds a {@link GroupingSymbol} to the table. If there is not room in the table for * the symbol then (in the fashion of {@link java.util.Vector}) the capacity is * doubled thereby making space. * * @param o symbol to be added */ public void add(GroupingSymbol o) { if(size == capacity) { GroupingSymbol[] tempTable = new GroupingSymbol[capacity * 2]; for(int i = 0; i < size; i++) tempTable[i] = symbols[i]; symbols = tempTable; capacity *= 2; } symbols[size] = o; size++; } /** * Identifies {@link java.lang.String} token as being a symbol in the table or not. * * @param token {@link java.lang.String} to be identified * @return true if token is in the table */ public boolean isAGroupingSymbol(String token) { boolean found = false; for(int i = 0; i < size && !found; i++) if(symbols[i].openToken.equals(token) || symbols[i].closeToken.equals(token)) found = true; return found; } /** * Identifies {@link java.lang.String} token as being an opening symbol or not. * If token is not in the table then a {@link NotATableElementExcepetion} * will be thrown (once I get that running.) * * @param token {@link java.lang.String} to be identified * @return true if token may begin a group */ public boolean isAnOpeningSymbol(String token) { boolean found = false; for(int i = 0; i < size && !found; i++) if(symbols[i].openingSymbol && symbols[i].openToken.equals(token)) found = true; return found; } /** * Identifies {@link java.lang.String} token as being an closing symbol or not. * If token is not in the table then a {@link NotATableElementExcepetion} * will be thrown (once I get that running.) * * @param token {@link java.lang.String} to be identified * @return true if token may end a group */ public boolean isAClosingSymbol(String token) { boolean found = false; for(int i = 0; i < size && !found; i++) if(!symbols[i].openingSymbol && symbols[i].closeToken.equals(token)) found = true; return found; } /** * Identifies {@link java.lang.String} token and returns the appropriate * {@link GroupingSymbol}. * If token is not in the table then a {@link NotATableElementExcepetion} * will be thrown (once I get that running.) * * @param token {@link java.lang.String} to be identified * @return the {@link GroupingSymbol} for token. */ public GroupingSymbol symbolFor(String token) { int index = 0; boolean found = false; for(index = 0; index < size && !found; index++) if(symbols[index].openingSymbol && symbols[index].openToken.equals(token)) found = true; else if(!symbols[index].openingSymbol && symbols[index].closeToken.equals(token)) found = true; if(found) return symbols[index - 1]; else return null; } /** * @return a {@link java.lang.String} array contianing the tokens for the * {@link GroupingSymbol GroupingSymbols} in the table. */ public String [] getTokens() { String [] out = new String [size]; for(int i = 0; i < size; i++) if(symbols[i].openingSymbol) out[i] = symbols[i].openToken; else out[i] = symbols[i].closeToken; return out; } /** * Checks if an infix expression is balanced. An expression has balanced grouping symbols * if every grouping symbol that is opened is closed and each closing symbol closes the most * recent opening symbol. *

* For example, ((x + y) / 3) * 5 is balanced because there are two open parens '(' and two * closes and each close works on the most recently opened symbol. ([x + y] / 3) * 5 is * balanced for the same reason, but ([x + y) / 3] * 5 is not because when the closing * symbol ')' is reached the current open symbol is ']' and the two don't match. Similarly * ([x + y] / 3 * 5 is not valid because there is no close for the initial '('. * * @param s infix equation to check the balance of * @return whether s is balanced or not */ public boolean isBalanced(String s) { AdaptedStringTokenizer tokens = new AdaptedStringTokenizer(s, getTokens()); String currentToken; boolean balanced = true; ExpressionElementStack parens = new ExpressionElementStack(); while(tokens.hasMoreTokens() && balanced) { currentToken = tokens.nextToken(); if(isAnOpeningSymbol(currentToken)) parens.push(symbolFor(currentToken)); else if(isAClosingSymbol(currentToken)) if(parens.empty() || !((GroupingSymbol)parens.nextElement().content).closeToken.equals(currentToken)) balanced = false; } if(!parens.empty()) balanced = false; return balanced; } /* public boolean balance(String s) { AdaptedStringTokenizer tokens = new AdaptedStringTokenizer(s, getTokens()); String currentToken; boolean balanced = true; ExpressionElementStack parens = new ExpressionElementStack(); StringBuffer out = new StringBuffer(); StringBuffer holding = new StringBuffer(); GroupingSymbol currentOpenSymbol; while(tokens.hasMoreTokens() && balanced) { currentToken = tokens.nextToken(); if(isAnOpeningSymbol(currentToken)) { if(currentOpenSymbol != null) out.append(currentOpenSymbol.token()); currentOpenSymbol = symbolFor(currentToken); out.append(holding.toString()); holding.clear(); } else if(isAClosingSymbol(currentToken)) { if(parens.empty() || !currentOpenSymbol.closeToken.equals(currentToken)) ; } } if(!parens.empty()) balanced = false; return balanced; } */}