def convertToRPN(tokens): """ Convert infix notation into Reverse Polish Notation for building the AST @param tokens: the list of tokens in infix notation order @post: this implementation uses the Shunting-yard algorithm """ outputQueue = [] operatorStack = [] for token in tokens: if token == UC_Common.BRACKET_OPEN: operatorStack.append(token) elif token == UC_Common.BRACKET_SHUT: while operatorStack and operatorStack[-1] != UC_Common.BRACKET_OPEN: outputQueue.append(operatorStack.pop()) if operatorStack.pop() != UC_Common.BRACKET_OPEN: raise UC_CommonUnitError( f"Detected mismatched parentheses: '{UC_Common.BRACKET_SHUT}'" ) elif UC_Utils.isOperator(token): while (operatorStack and operatorStack[-1] != UC_Common.BRACKET_OPEN and UC_Utils.hasHigherPrecedence(operatorStack[-1], token)): outputQueue.append(operatorStack.pop()) operatorStack.append(token) else: outputQueue.append(token) while operatorStack: if operatorStack[-1] == UC_Common.BRACKET_OPEN: raise UC_CommonUnitError( f"Detected mismatched parentheses: '{UC_Common.BRACKET_OPEN}'") outputQueue.append(operatorStack.pop()) return outputQueue
def aggregateQuantities(tokens): """ Combine tokens which constitute a quantity @param tokens: a list of tokens """ aggregatedTokens = [] needsValue = True while tokens: if UC_Utils.isOperator(tokens[0]): if needsValue: raise UC_Common.UnitError( f"Expected float; received '{tokens[0]}'") aggregatedTokens.append(tokens.pop(0)) needsValue = True elif UC_Utils.isSpecialChar(tokens[0]): aggregatedTokens.append(tokens.pop(0)) else: needsValue = False # Get value quantity = '1' try: float(tokens[0]) quantity = tokens.pop(0) except: # Inject multiplication where needed if aggregatedTokens and aggregatedTokens[ -1] == UC_Common.BRACKET_SHUT: aggregatedTokens.append(UC_Common.OPERATOR_MUL) # Get unit unit = [] if tokens and isinstance(tokens[0], list): unit = tokens.pop(0) aggregatedTokens.append((quantity, unit)) if needsValue and aggregatedTokens: raise UC_Common.UnitError(f"Expected float; no tokens received") return aggregatedTokens
def aggregateUnits(tokens): """ Combine tokens which constitute compound units @param tokens: a list of tokens """ aggregatedTokens = [] unitTokens = [] parsingExp = 0 def appendUnitTokens(aggregatedTokens, unitTokens, token=None): # Append unit tokens to list of aggregated tokens if unitTokens: if unitTokens[-1] == UC_Common.OPERATOR_MUL or unitTokens[ -1] == UC_Common.OPERATOR_DIV: operator = unitTokens.pop() aggregatedTokens.append(unitTokens) aggregatedTokens.append(operator) else: aggregatedTokens.append(unitTokens) if token is not None: # Inject multiplication if needed if ((aggregatedTokens) and (not UC_Utils.isSpecialChar(aggregatedTokens[-1])) and (token == UC_Common.BRACKET_OPEN)): aggregatedTokens.append(UC_Common.OPERATOR_MUL) aggregatedTokens.append(token) return [] def handleParseExpDecrement(tokens, unitTokens, parsingExp): # Check if multiplication needs to be injected between adjacent units if parsingExp != 1: return parsingExp if tokens: if tokens[0] == UC_Common.OPERATOR_MUL or tokens[ 0] == UC_Common.OPERATOR_DIV: unitTokens.append(tokens.pop(0)) elif UC_Utils.isValidSymbol(tokens[0]): unitTokens.append(UC_Common.OPERATOR_MUL) return 0 def handleAppendUnitSymbol(tokens, unitTokens, parsingExp): if tokens: token = tokens[0] if token == UC_Common.OPERATOR_EXP: unitTokens.append(tokens.pop(0)) return 1 elif token == UC_Common.OPERATOR_MUL or token == UC_Common.OPERATOR_DIV: unitTokens.append(tokens.pop(0)) elif UC_Utils.isValidSymbol(token): unitTokens.append(UC_Common.OPERATOR_MUL) return parsingExp while tokens: token = UC_Utils.getNextToken(tokens) if token == UC_Common.BRACKET_OPEN: if parsingExp: unitTokens.append(token) parsingExp += 1 else: unitTokens = appendUnitTokens(aggregatedTokens, unitTokens, token) elif token == UC_Common.BRACKET_SHUT: if parsingExp: unitTokens.append(token) parsingExp = handleParseExpDecrement(tokens, unitTokens, parsingExp - 1) else: unitTokens = appendUnitTokens(aggregatedTokens, unitTokens, token) elif UC_Utils.isFloat(token): if parsingExp: if not UC_Utils.isInt(token): raise UC_Common.UnitError( f"Expected int; received '{token}'") unitTokens.append(token) parsingExp = handleParseExpDecrement(tokens, unitTokens, parsingExp) else: unitTokens = appendUnitTokens(aggregatedTokens, unitTokens, token) elif UC_Utils.isValidSymbol(token): if parsingExp: raise UC_Common.UnitError(f"Expected int; received '{token}'") unitTokens.append(token) parsingExp = handleAppendUnitSymbol(tokens, unitTokens, parsingExp) elif UC_Utils.isOperator(token): if parsingExp: raise UC_Common.UnitError(f"Expected int; received '{token}'") else: unitTokens = appendUnitTokens(aggregatedTokens, unitTokens, token) else: raise UC_Common.UnitError(f"Unknown token; received '{token}'") appendUnitTokens(aggregatedTokens, unitTokens) return aggregatedTokens