def parseUnit(tokens): tokens = convertToRPN(tokens) stack = [] for token in tokens: if token == UC_Common.OPERATOR_ADD: a = stack.pop() if not isinstance(a, int): raise UC_Common.UnitError(f"Expected int; received '{a}'") b = stack.pop() if not isinstance(b, int): raise UC_Common.UnitError(f"Expected int; received '{b}'") stack.append(b + a) elif token == UC_Common.OPERATOR_SUB: a = stack.pop() if not isinstance(a, int): raise UC_Common.UnitError(f"Expected int; received '{a}'") b = stack.pop() if not isinstance(b, int): raise UC_Common.UnitError(f"Expected int; received '{b}'") stack.append(b - a) elif token == UC_Common.OPERATOR_MUL: a = stack.pop() if not isinstance(a, dict): a = {a: 1} b = stack.pop() if not isinstance(b, dict): b = {b: 1} for sym, exp in b.items(): if sym not in a: a[sym] = 0 a[sym] += exp stack.append(a) elif token == UC_Common.OPERATOR_DIV: a = stack.pop() if not isinstance(a, dict): a = {a: 1} b = stack.pop() if not isinstance(b, dict): b = {b: 1} for sym, exp in a.items(): if sym not in b: b[sym] = 0 b[sym] -= exp stack.append(b) elif token == UC_Common.OPERATOR_EXP: a = stack.pop() b = stack.pop() if not isinstance(a, int): raise UC_Common.UnitError(f"Expected int; received '{a}'") stack.append({b: a}) else: if UC_Utils.isInt(token): stack.append(int(token)) else: stack.append(token) # Aggregate into a single map units = {} while stack: top = stack.pop() if isinstance(top, dict): for sym, exp in top.items(): if sym not in units: units[sym] = 0 units[sym] += exp elif UC_Utils.isValidSymbol(top): if top not in units: units[top] = 0 units[top] += 1 else: raise UC_Common.UnitError("Invalid expression") return units
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