From d7a0e400cd9b14a9bd13763654d38fdf8e8e0b1b Mon Sep 17 00:00:00 2001 From: Arity-T Date: Wed, 14 May 2025 11:15:28 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BD=D0=BE=D1=80=D0=BC=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5?= =?UTF-8?q?=D0=B9=D1=81=20=D0=B2=20lab3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab3/programm/.gitignore | 1 + lab3/programm/grammar.py | 31 ++++++ lab3/programm/grammar.txt | 2 +- lab3/programm/main.py | 193 ++++++++++++++++++++++++++------------ 4 files changed, 167 insertions(+), 60 deletions(-) diff --git a/lab3/programm/.gitignore b/lab3/programm/.gitignore index 5f597ba..643134e 100644 --- a/lab3/programm/.gitignore +++ b/lab3/programm/.gitignore @@ -1,2 +1,3 @@ grammar_* analysis_* +generation_* \ No newline at end of file diff --git a/lab3/programm/grammar.py b/lab3/programm/grammar.py index 80fff75..70d7bf0 100644 --- a/lab3/programm/grammar.py +++ b/lab3/programm/grammar.py @@ -255,6 +255,37 @@ class Grammar: table.add_row(row) return str(table) + def format_first_sets(self) -> str: + """Форматирует множества FIRST в читаемый вид.""" + result = [] + result.append("Множества FIRST:") + result.append("=" * 40) + + # Сортируем для гарантии порядка вывода + for symbol in sorted(self.first_sets.keys()): + # Заменяем пустую строку на эпсилон для лучшей читаемости + first_set = { + self.EPSILON if item == "" else item for item in self.first_sets[symbol] + } + result.append(f"FIRST({symbol}) = {{{', '.join(sorted(first_set))}}}") + + return "\n".join(result) + + def format_follow_sets(self) -> str: + """Форматирует множества FOLLOW в читаемый вид.""" + result = [] + result.append("Множества FOLLOW:") + result.append("=" * 40) + + # Обрабатываем только нетерминалы + for non_terminal in sorted(self.productions.keys()): + follow_set = self.follow_sets.get(non_terminal, set()) + result.append( + f"FOLLOW({non_terminal}) = {{{', '.join(sorted(follow_set))}}}" + ) + + return "\n".join(result) + def analyze(self, string: str) -> list[int]: input_tokens = string.split() + ["$"] input_pos = 0 diff --git a/lab3/programm/grammar.txt b/lab3/programm/grammar.txt index bb6f1a6..0225336 100644 --- a/lab3/programm/grammar.txt +++ b/lab3/programm/grammar.txt @@ -2,7 +2,7 @@ ПрямойПорядок -> Подлежащее ДополнениеКПодлежащему Глагол ВторостепенныеЧлены Отрицание Инверсия -> Обстоятельство Глагол Подлежащее ВторостепенныеЧлены Отрицание Подлежащее -> ИменнаяГруппа ПридаточноеПредложение | Местоимение -ПридаточноеПредложение -> ", " Союз Подлежащее Глагол ВторостепенныеЧлены Отрицание ", " | epsilon +ПридаточноеПредложение -> "," Союз Подлежащее Глагол Отрицание "," | epsilon ВторостепенныеЧлены -> ВторостепенныйЧлен ВторостепенныеЧлены | epsilon ВторостепенныйЧлен -> Обстоятельство | Дополнение Обстоятельство -> ОбстоятельствоВремени | ОбстоятельствоМеста | ОбстоятельствоОбразаДействия diff --git a/lab3/programm/main.py b/lab3/programm/main.py index 9d14ef4..efa39ac 100644 --- a/lab3/programm/main.py +++ b/lab3/programm/main.py @@ -1,73 +1,148 @@ -import json - from grammar import Grammar -with open("grammar.txt", "r", encoding="utf-8") as file: - text = file.read() -# text = """ -# S -> A b B | d -# A -> C A b | B -# B -> c S d | epsilon -# C -> a | e d -# """ -# text = """ -# S -> F | ( S + F ) -# F -> 1 -# """ -grammar = Grammar(text) -print("FIRST sets:", grammar.first_sets) -print("FOLLOW sets:", grammar.follow_sets) +def load_grammar(filename: str = "grammar.txt") -> Grammar | None: + try: + with open(filename, "r", encoding="utf-8") as file: + text = file.read() + grammar = Grammar(text) -with open("grammar_rules.txt", "w", encoding="utf-8") as output_file: - output_file.write(grammar.format_rules()) - print("Правила грамматики с номерами сохранены в grammar_rules.txt") + # Сохраняем информацию о грамматике в файлы + with open("grammar_rules.txt", "w", encoding="utf-8") as output_file: + output_file.write(grammar.format_rules()) + print("Правила грамматики с номерами сохранены в grammar_rules.txt") -with open("grammar_lookup_table.txt", "w", encoding="utf-8") as output_file: - output_file.write(grammar.format_lookup_table()) - print("Таблица синтаксического анализа сохранена в grammar_lookup_table.txt") + with open("grammar_lookup_table.txt", "w", encoding="utf-8") as output_file: + output_file.write(grammar.format_lookup_table()) + print( + "Таблица синтаксического анализа сохранена в grammar_lookup_table.txt" + ) -input_string = "ich las gestern ein alt Buch" -input_string = "der alt Mann las ein Buch" -input_string = "gestern las der alt Mann ein Buch" -print(f"Analyzing input '{input_string}':") -parse_result = grammar.analyze(input_string) -print(f"Applied rules: {parse_result}") + with open("grammar_first.txt", "w", encoding="utf-8") as output_file: + output_file.write(grammar.format_first_sets()) + print("Множества FIRST сохранены в grammar_first.txt") -with open("analysis_result.txt", "w", encoding="utf-8") as f: - f.write(f"Input: {input_string}\n") - f.write("Applied rules: ") - f.write(str(parse_result)) - f.write("\n\n") - f.write("Derivation steps:\n") + with open("grammar_follow.txt", "w", encoding="utf-8") as output_file: + output_file.write(grammar.format_follow_sets()) + print("Множества FOLLOW сохранены в grammar_follow.txt") - derivation_steps = grammar.generate_derivation_steps(parse_result) - for step in derivation_steps: - f.write(f"{step}\n") + print(f"Грамматика успешно загружена из файла {filename}") + return grammar + except FileNotFoundError: + print(f"Ошибка: Файл {filename} не найден") + return None + except ValueError as e: + print(f"Ошибка при загрузке грамматики: {e}") + return None + except Exception as e: + print(f"Неизвестная ошибка: {e}") + return None -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}") +def check_string(grammar: Grammar | None, input_string: str) -> None: + if not grammar: + print("Ошибка: Грамматика не загружена") + return -# Запись одной сгенерированной строки в файл -with open("generation_result.txt", "w", encoding="utf-8") as f: - terminals, rules = grammar.generate() - generated_string = " ".join(terminals) + print(f"Проверка строки: '{input_string}'") + try: + parse_result = grammar.analyze(input_string) + print(f"Результат: Строка соответствует грамматике") + print(f"Применённые правила: {parse_result}") - 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") + # Сохраняем результат анализа в файл + with open("analysis_result.txt", "w", encoding="utf-8") as f: + f.write(f"Input: {input_string}\n") + f.write("Applied rules: ") + f.write(str(parse_result)) + 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") + derivation_steps = grammar.generate_derivation_steps(parse_result) + for step in derivation_steps: + f.write(f"{step}\n") -print("Результат генерации сохранен в generation_result.txt") + print("Подробный результат анализа сохранен в analysis_result.txt") + except ValueError as e: + print(f"Результат: Строка не соответствует грамматике") + print(f"Ошибка: {e}") + except Exception as e: + print(f"Произошла ошибка при анализе: {e}") + + +def generate_string(grammar: Grammar | None) -> None: + if not grammar: + print("Ошибка: Грамматика не загружена") + return + + try: + terminals, rules = grammar.generate() + generated_string = " ".join(terminals) + print(f"Сгенерированная строка: {generated_string}") + print(f"Применённые правила: {rules}") + + # Сохраняем результат генерации в файл + with open("generation_result.txt", "w", encoding="utf-8") as f: + 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") + except Exception as e: + print(f"Произошла ошибка при генерации: {e}") + + +def main(): + print("Программа для работы с LL(1)-грамматиками") + print("=" * 60) + print("Варианты команд:") + print(" - load <файл> - загрузить грамматику из файла (по умолчанию grammar.txt)") + print(" - check <строка> - проверить, соответствует ли строка грамматике") + print(" - generate - сгенерировать случайную строку по грамматике") + print(" - exit - выход из программы") + print("=" * 60) + + # Загружаем грамматику по умолчанию при старте + grammar = load_grammar() + + while True: + command = input("\nВведите команду: ").strip() + + if not command: + continue + + parts = command.split(maxsplit=1) + cmd = parts[0].lower() + + if cmd == "exit": + print("Выход из программы.") + break + + elif cmd == "load": + filename = "grammar.txt" + if len(parts) > 1: + filename = parts[1].strip() + grammar = load_grammar(filename) + + elif cmd == "check": + input_string = "" + if len(parts) > 1: + input_string = parts[1].strip() + check_string(grammar, input_string) + + elif cmd == "generate": + generate_string(grammar) + + else: + print(f"Неизвестная команда: {cmd}") + print("Доступные команды: load, check, generate, exit") + + +if __name__ == "__main__": + main()