/// <summary> /// Insert operation in a operation tree using priorities /// </summary> /// <param name="lastOperation">Previous builded operation</param> /// <param name="operation">Current operation</param> /// <param name="rootOperation">Root operation of a tree</param> private void InsertOperationInTree <T>(ref OperationElement lastOperation, ref T operation, ref OperationElement rootOperation) where T : OperationElement { if (operation.Priority > lastOperation.Priority || (operation.OperationName == lastOperation.OperationName && !OperationPriority.IsCompareToThisAsLessPriority[operation.OperationName])) { operation.SetChild(0, lastOperation.Child(1)); lastOperation.SetChild(1, operation); } else { if (lastOperation.Parent() != null) { OperationElement parentOperation = (OperationElement)lastOperation.Parent(); InsertOperationInTree(ref parentOperation, ref operation, ref rootOperation); } else { operation.SetChild(0, lastOperation); rootOperation = lastOperation = operation; } } }
/// <summary> /// Takes value and insert it in a operation /// </summary> /// <param name="operation">Used operation</param> /// <param name="value">Used value</param> /// <param name="right">If true a value will be inserted as right operand, false - as left</param> private void InsertValInTree(OperationElement operation, ValueElement value, bool right = true) { if (right) { if (operation.HasRightOperand) { if (operation.Child(1) == null) { operation.SetChild(1, value); } else { Compilation.WriteError("Operation '" + operation.OperationName + "' already has right operand", value.Line); } } else { Compilation.WriteError("Operation '" + operation.OperationName + "' hasn't right operand", value.Line); } } else { if (operation.HasLeftOperand) { if (operation.Child(0) == null) { operation.SetChild(0, value); } else { Compilation.WriteError("Operation '" + operation.OperationName + "' already has left operand", value.Line); } } else { Compilation.WriteError("Operation '" + operation.OperationName + "' hasn't left operand", value.Line); } } }
/// <summary> /// Build expression element /// </summary> /// <param name="lexemes">List of lexemes</param> /// <param name="pos">Position of current parsed lexeme</param> /// <param name="endPos">Position at which function breaks. Pass -1 to parse until the end</param> /// <param name="flags">Control flags. ExpressionFlags.None to ignore all flags</param> /// <param name="elem"></param> /// <returns>Position of a next lexeme</returns> private int ParseExpression(List <Lexeme> lexemes, int pos, int endPos, ExpressionFlags flags, out ValueElement elem) { OperationElement lastOperation = null; OperationElement rootOperation = null; ValueElement lastValElement = null; bool breakCycle = false; if (endPos == -1) { endPos = lexemes.Count; } for (int end = endPos; !breakCycle && pos < end;) { var currentLexeme = lexemes[pos]; switch (currentLexeme.Source) { case ")": case ";": case "{": case "}": breakCycle = true; continue; case ",": Compilation.WriteError("Unexpected symbol: ','." + "Did you forget '(' ?\nExample: '( SYMBOLS, SYMBOLS )'.", lexemes[pos].Line); continue; case "+": case "-": case "*": case "/": case "^": case "=": { if (lastValElement == null && lastOperation == null) { if (lexemes[pos].Source == "-") { rootOperation = lastOperation = new UnaryMinusElement(); ++pos; continue; } else { Compilation.WriteError("Expected value or expression before '" + lexemes[pos].Source + "'", lexemes[pos].Line); } } OperationElement operation = null; switch (lexemes[pos].Source) { case "+": operation = new BinaryPlusElement(); break; case "-": operation = new BinaryMinusElement(); break; case "*": operation = new BinaryMultiplicationElement(); break; case "/": operation = new BinaryDivisionElement(); break; case "^": operation = new BinaryExponentiationElement(); break; case "=": { operation = new CopyElement(); if (lastValElement != null) { if (!(lastValElement is MultipleValElement)) { var multiple = new MultipleValElement(); multiple.AddValue(lastValElement); lastValElement = multiple; } } else { if (lastOperation != null) { var valElem = lastOperation.Child(1); if (!(valElem is MultipleValElement)) { var multiple = new MultipleValElement(); multiple.AddValue((ValueElement)valElem); lastOperation.SetChild(1, valElem); } } else { Compilation.WriteError("Expected value before '='", -1); } } } break; default: Compilation.WriteCritical("BUG: Unknown operator passed through the switch"); break; } if (lastOperation == null) { operation.SetChild(0, lastValElement); lastValElement = null; rootOperation = operation; } else { InsertOperationInTree(ref lastOperation, ref operation, ref rootOperation); } lastOperation = operation; } ++pos; break; default: pos = ParseExpressionValue(lexemes, pos, flags | ExpressionFlags.AllowDefaultValue & (~ExpressionFlags.OperationRequired), out lastValElement); if (lastValElement == null) { if (!flags.HasFlag(ExpressionFlags.AllowAutoDefault)) { Compilation.WriteError("Unknown symbol: '" + currentLexeme.Source + "'.", currentLexeme.Line); } else //used default keyword. Caller have to find result { elem = null; return(pos); } } else { if (lastOperation != null) { InsertValInTree(lastOperation, lastValElement); lastValElement = null; } } break; } } if (rootOperation == null) { if (flags.HasFlag(ExpressionFlags.OperationRequired) && !(lastValElement is FunctionCallElement)) { Compilation.WriteError("Expression must contain at least one operator", lexemes[pos].Line); } if (lastValElement == null) { Compilation.WriteError("No operation or value in expression", lexemes[pos].Line); } elem = lastValElement; } else { elem = rootOperation; } return(pos); }