private void AddOperatorToStack(string @operator) { // Відкриваюча дужка "(" повинна мати найнижчий пріоритет, але записуватися в стек, нічого не виштовхуючи if (@operator == "(") { Stack.Push(new PolishNotation { Token = @operator, Type = PolishNotationTokenType.Operator }); return; } // 3. Якщо стек порожній, то поточна операція заноситься в стек if (Stack.Count == 0) { Stack.Push(new PolishNotation { Token = @operator, Type = PolishNotationTokenType.Operator }); return; } PolishNotation head = Stack.Peek(); string headToken = head.Token.StartsWith("if") ? "if" : head.Token.StartsWith("while") ? "while" : head.Token; // 2. Якщо пріоритет операції, що знаходиться в стеку, // не менший за пріоритет поточної вхідної операції, // то операція зі стека подається на вихід і п.2 повторюється, if (_operatorsPriorities[headToken] >= _operatorsPriorities[@operator]) { PolishNotation notation = Stack.Pop(); if (notation.Token != "(") // Причому "(" ніколи не передається на вихід { ReversePolishNotation.Add(notation); // операція зі стека подається на вихід } AddOperatorToStack(@operator); // п.2 повторюється return; } // інакше поточна операція заноситься в стек. if (@operator != ")") // Причому ")" ніколи не заноситься в стек { Stack.Push(new PolishNotation { Token = @operator, Type = PolishNotationTokenType.Operator }); } }
private void DijkstraStep(string input, PolishNotationTokenType type, bool isAssignmentToThisIdentifier = false) { switch (type) { // 1. Ідентифікатори та константи проходять від входу прямо до виходу case PolishNotationTokenType.Identifier: case PolishNotationTokenType.Literal: ReversePolishNotation.Add(new PolishNotation { Token = input, Type = type, IsAssignmentToThisIdentifier = isAssignmentToThisIdentifier }); break; // Операції звичайно потрапляють на вихід через магазин case PolishNotationTokenType.Operator: AddOperatorToStack(input); break; // 4. Якщо вхідний ланцюжок порожній, всі операції зі стека по черзі передаються на вихід // за ознакою кінця виразу (наприклад, ";"). case PolishNotationTokenType.Delimiter: { while (Stack.Count != 0 && !Stack.Peek().Token.StartsWith("if") && !Stack.Peek().Token.StartsWith("while")) { ReversePolishNotation.Add(Stack.Pop()); } // ReversePolishNotation.Add(new PolishNotation {Token = input, Type = type}); } break; case PolishNotationTokenType.If: Stack.Push(new PolishNotation { Token = input, Type = type }); break; // Символ then з пріоритетом 1 виштовхує зі стека всі знаки до першого // if виключно. При цьому генерується нова мітка mi й у вихідний рядок // заноситься mi УПХ. Потім мітка mi заноситься в таблицю міток і дописується у вершину стека, // таким чином, запис if у вершині стека перетворюється на запис if mi case PolishNotationTokenType.Then: { PolishNotation head = Stack.Peek(); while (!head.Token.StartsWith("if")) { ReversePolishNotation.Add(Stack.Pop()); head = Stack.Peek(); } string label = GenerateLabel(); head.Token = $"{head.Token} {label}"; ReversePolishNotation.Add(new PolishNotation { Token = $"{label}", Type = PolishNotationTokenType.Label }); ReversePolishNotation.Add(new PolishNotation { Token = "УПХ", Type = type }); } break; // Символ кінця умовного оператора (наприклад, ; або end) виштовхує зі // стека все до найближчого if. Це може бути if mi mi+1 (або if mi у разі // конструкції if <вираз> then <оператор>;). Запис видаляється зі стека, // а у вихідний рядок додається mi+1: (або mi: у випадку неповного оператора умовного переходу). case PolishNotationTokenType.Fi: { PolishNotation head = Stack.Peek(); while (!head.Token.StartsWith("if")) { ReversePolishNotation.Add(Stack.Pop()); head = Stack.Peek(); } head = Stack.Pop(); string label = head.Token.Split(" ").Last(); ReversePolishNotation.Add(new PolishNotation { Token = $"{label}", Type = PolishNotationTokenType.Label }); ReversePolishNotation.Add(new PolishNotation { Token = ":", Type = type }); _labelAddresses[label] = ReversePolishNotation.Count; } break; case PolishNotationTokenType.While: { string label = GenerateLabel(); Stack.Push(new PolishNotation { Token = $"{input} {label}", Type = type }); ReversePolishNotation.Add(new PolishNotation { Token = $"{label}", Type = PolishNotationTokenType.Label }); ReversePolishNotation.Add(new PolishNotation { Token = $":", Type = type }); _labelAddresses[label] = ReversePolishNotation.Count; } break; case PolishNotationTokenType.TechnicalDo: { PolishNotation head = Stack.Peek(); while (!head.Token.StartsWith("while")) { ReversePolishNotation.Add(Stack.Pop()); head = Stack.Peek(); } string label = GenerateLabel(); head.Token = $"{head.Token} {label}"; ReversePolishNotation.Add(new PolishNotation { Token = $"{label}", Type = PolishNotationTokenType.Label }); ReversePolishNotation.Add(new PolishNotation { Token = "УПХ", Type = type }); } break; case PolishNotationTokenType.Enddo: { PolishNotation head = Stack.Peek(); while (!head.Token.StartsWith("while")) { ReversePolishNotation.Add(Stack.Pop()); head = Stack.Peek(); } head = Stack.Pop(); string[] labels = head.Token.Split(" "); ReversePolishNotation.Add(new PolishNotation { Token = $"{labels[1]}", Type = PolishNotationTokenType.Label }); ReversePolishNotation.Add(new PolishNotation { Token = "БП", Type = type }); ReversePolishNotation.Add(new PolishNotation { Token = $"{labels.Last()}", Type = PolishNotationTokenType.Label }); ReversePolishNotation.Add(new PolishNotation { Token = $":", Type = type }); _labelAddresses[labels.Last()] = ReversePolishNotation.Count; } break; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } Trace.Add(new PolishTrace { Input = input, // Stack = new Stack<PolishNotation>(Stack), Stack = Stack.Clone(), ReversePolishNotation = new List <PolishNotation>(ReversePolishNotation) }); MoveNext(); }