diff --git a/lab3/programm/grammar.py b/lab3/programm/grammar.py index 02db6fe..80fff75 100644 --- a/lab3/programm/grammar.py +++ b/lab3/programm/grammar.py @@ -1,3 +1,4 @@ +import random import re from collections import OrderedDict @@ -316,3 +317,61 @@ class Grammar: ) return rules_applied + + def generate(self, symbol: str | None = None) -> tuple[list[str], list[int]]: + """Генерирует предложение по заданной грамматике. Возвращает список терминалов + и список номеров применённых правил.""" + + if symbol is None: + return self.generate(self.start_symbol) + + # Если символ - терминал, возвращаем его + if symbol not in self.productions: + return [symbol], [] + + # Выбираем случайное правило для нетерминала + rules = self.productions[symbol] + chosen_rule = random.choice(rules) + + # Получаем номер выбранного правила + rule_number = self.rule_numbers[(symbol, tuple(chosen_rule))] + + # Инициализируем результаты + terminals = [] + rule_numbers = [rule_number] + + # Разворачиваем каждый символ в правой части правила + for s in chosen_rule: + sub_terminals, sub_rules = self.generate(s) + terminals.extend(sub_terminals) + rule_numbers.extend(sub_rules) + + return terminals, rule_numbers + + def generate_derivation_steps(self, rule_numbers: list[int]) -> list[str]: + """Преобразует список номеров правил в последовательность шагов вывода. + Возвращает список строк, представляющих каждый шаг вывода.""" + + # Получаем соответствие между номерами правил и самими правилами + rule_details = {num: rule for rule, num in self.rule_numbers.items()} + + # Начинаем с начального символа + current = self.start_symbol + steps = [current] + + # Применяем каждое правило по порядку + for rule_num in rule_numbers: + if rule_num in rule_details: + non_terminal, replacement = rule_details[rule_num] + + # Находим первое вхождение нетерминала и заменяем его + words = current.split() + for i, word in enumerate(words): + if word == non_terminal: + words[i : i + 1] = replacement + break + + current = " ".join(words) + steps.append(current) + + return steps diff --git a/lab3/programm/main.py b/lab3/programm/main.py index bb4addd..9d14ef4 100644 --- a/lab3/programm/main.py +++ b/lab3/programm/main.py @@ -34,8 +34,6 @@ print(f"Analyzing input '{input_string}':") parse_result = grammar.analyze(input_string) print(f"Applied rules: {parse_result}") -rule_details = {num: rule for rule, num in grammar.rule_numbers.items()} - with open("analysis_result.txt", "w", encoding="utf-8") as f: f.write(f"Input: {input_string}\n") f.write("Applied rules: ") @@ -43,19 +41,33 @@ with open("analysis_result.txt", "w", encoding="utf-8") as f: f.write("\n\n") f.write("Derivation steps:\n") - current = grammar.start_symbol - f.write(f"{current}\n") - - for rule_num in parse_result: - non_terminal, replacement = rule_details[rule_num] - - words = current.split() - for i, word in enumerate(words): - if word == non_terminal: - words[i : i + 1] = replacement - break - - current = " ".join(words) - f.write(f"{current}\n") + derivation_steps = grammar.generate_derivation_steps(parse_result) + for step in derivation_steps: + f.write(f"{step}\n") print("Результат анализа сохранен в analysis_result.txt") + +# Тестирование функции генерации строк +print("\nГенерация строк по грамматике:") +for i in range(5): + terminals, rules = grammar.generate() + generated_string = " ".join(terminals) + print(f"Сгенерированная строка {i+1}: {generated_string}") + print(f"Применённые правила: {rules}") + +# Запись одной сгенерированной строки в файл +with open("generation_result.txt", "w", encoding="utf-8") as f: + terminals, rules = grammar.generate() + generated_string = " ".join(terminals) + + f.write(f"Generated string: {generated_string}\n") + f.write("Applied rules: ") + f.write(str(rules)) + f.write("\n\n") + f.write("Derivation steps:\n") + + derivation_steps = grammar.generate_derivation_steps(rules) + for step in derivation_steps: + f.write(f"{step}\n") + +print("Результат генерации сохранен в generation_result.txt")