/// <summary> /// Ищет в контейнере последний терминальный символ, у которого нет дочерних элементов. /// </summary> /// <param name="container"></param> /// <returns></returns> private int lastIndexOfVnWithoutChilds(List <OutputTreeCell> container) { if (container.Count == 0) { //Logger.Info("-- OutputTree is empty"); return(-1); } if (container.Count == 1 & container[0].Value.Equals(SpecialSymbs.NOT_TERMINAL_SYMB)) { return(0); } if (container[container.Count - 1].Equals(SpecialSymbs.NOT_TERMINAL_SYMB)) { return(container.Count - 1); } for (int i = container.Count - 2; i >= 0; i--) { OutputTreeCell pre = container[i]; OutputTreeCell post = container[i + 1]; if (!pre.Value.Equals(SpecialSymbs.NOT_TERMINAL_SYMB)) { continue; } if (pre.Level < post.Level) { continue; } return(i); } //Logger.Info("-- All VN with child elems"); return(-1); }
/// <summary> /// Метод, используя матрицу правил и последовательность использованных правил, строит Дерево Вывода. /// </summary> /// <param name="rulesMatrix"></param> /// <param name="usedRulesList"></param> /// <returns></returns> public List <OutputTreeCell> GetOutputTree(RulesMatrix rulesMatrix, List <int> usedRulesList) { List <OutputTreeCell> treeContainer = new List <OutputTreeCell>(); OutputTreeCell root = new OutputTreeCell(0, SpecialSymbs.NOT_TERMINAL_SYMB); treeContainer.Add(root); //Logger.Info("Iteration 0, tree: {0}", string.Join(" || ", treeContainer.ToArray())); for (int ruleIdx = usedRulesList.Count - 1; ruleIdx >= 0; ruleIdx--) { int iteration = usedRulesList.Count - ruleIdx; //Logger.Info("Iteration: {0} || Rule #{1} || size of tree: {2}", iteration, usedRulesList[ruleIdx], treeContainer.Count); //Logger.Info("- Tree at start: {0}", string.Join(" ", treeContainer.ToArray())); string[] ruleSymbs = rulesMatrix.GetRuleByNumber(usedRulesList[ruleIdx]); int insertIdx = lastIndexOfVnWithoutChilds(treeContainer) + 1; if ((insertIdx - 1) < 0) { break; } //Logger.Info("-- Last index of VN without childs: {0}", insertIdx - 1); int childsLevel = treeContainer[insertIdx - 1].Level + 1; // Закидывание символов из текущего правила рядом с нетерминалом, который они раскрывают foreach (string symb in Reverse(ruleSymbs)) { treeContainer.Insert(insertIdx, new OutputTreeCell(childsLevel, symb)); } //Logger.Info("- Tree at end: {0}", string.Join(" ", treeContainer.ToArray())); } // Logger.Info("\nFull tree: {0}\n", string.Join(" || ", treeContainer.ToArray())); return(treeContainer); }
/// <summary> /// Метод, выполняющий красивую отрисвоку Дерева вывода в консоль. /// </summary> public void DrawToConsole() { if (OutputTree.Count == 0) { throw new System.Exception("Пустое дерево - нечего рисовать!"); } if (OutputTree.Count == 1) { MakeDrawing(new StringBuilder(OutputTree[0].Value)); } StringBuilder treeD = new StringBuilder(); List <int> currentChildsAtLevels = new List <int>(); for (int i = 0; i <= GetMaxLevel(); i++) { currentChildsAtLevels.Add(0); } treeD.Append(OutputTree[0].Value).Append('\n'); //Logger.Info("GetMaxLevel = {0}, Len of OutputTree = {1}", GetMaxLevel(), OutputTree.Count); int lastNodeLvl = OutputTree[0].Level; for (int i = 1; i < OutputTree.Count; i++) { OutputTreeCell currentNode = OutputTree[i]; int currentLvl = currentNode.Level; if (lastNodeLvl < currentLvl) { currentChildsAtLevels[lastNodeLvl] = FindAmountOfDirectChilds(i - 1); } //Logger.Info("Now symb: [ {0} -> {1} ], currLvl={2}, lastLvl={3} array of direct childs: {4}", //currentLvl, currentNode.Value, currentLvl, lastNodeLvl, string.Join(" ", currentChildsAtLevels.ToArray())); for (int j = 0; j < currentLvl; j++) { if (currentChildsAtLevels[j] > 0) { treeD.Append('|'); } else { treeD.Append(' '); } if (currentLvl - j > 1) { SpamSymbol(treeD, AmountOfSlashesBeforeSymbol + AmountOfSpacesBeforeSymbol, ' '); } if (currentNode.Level - 1 == j) { ReduceChildsAmountBy1(currentChildsAtLevels, currentNode.Level); } } SpamSymbol(treeD, AmountOfSlashesBeforeSymbol, '-'); SpamSymbol(treeD, AmountOfSpacesBeforeSymbol, ' '); treeD.Append(currentNode.Value); treeD.Append('\n'); lastNodeLvl = currentLvl; } MakeDrawing(treeD); }