import re from collections import defaultdict from Parser import RecursiveDescentParser from ParserOutput import TreeNode, ParserOutput class Grammar: def __init__(self): self.nonterminals = set() self.terminals = set() self.productions = defaultdict(list) self.start_symbol = None def read_from_file(self, filename): with open(filename, 'r') as file: lines = file.readlines() grammar_header = lines[0].strip() match = re.match(r"G\s*=\s*\(\s*\{([^}]*)\}\s*,\s*\{([^}]*)\}\s*,\s*P\s*,\s*([^)]+)\s*\)", grammar_header) if not match: raise ValueError("Invalid grammar format in the first line.") self.nonterminals = set([x.strip() for x in set(match.group(1).split(', '))]) self.terminals = set([x.strip() for x in set(match.group(2).split(', '))]) self.start_symbol = match.group(3) # Parse the productions for line in lines[1:]: line = line.strip() if line.startswith("P :"): line = line[3:].strip() if "->" in line: lhs, rhs = line.split('->') lhs = lhs.strip() self.nonterminals.add(lhs) for production in rhs.split('|'): production = production.strip() self.productions[lhs].append(production.strip()) def print_nonterminals(self): print("Nonterminals:", self.nonterminals) def print_terminals(self): print("Terminals:", self.terminals) def print_productions(self): for lhs, rhs in self.productions.items(): print(f"{lhs} -> {' | '.join(rhs)}") def get_productions_for(self, nonterminal): return self.productions.get(nonterminal, []) def is_cfg(self): for lhs, rhs_list in self.productions.items(): if lhs not in self.nonterminals: print(f"Invalid nonterminal: {lhs}") return False for rhs in rhs_list: rhs_symbols = rhs.split() for symbol in rhs_symbols: if symbol not in self.terminals and symbol not in self.nonterminals: print(f"Invalid symbol in RHS: {symbol}") return False return True def menu(): g = Grammar() #g.read_from_file("g2.txt") parser = None while True: print("1. Read grammar from file") print("2. Print nonterminals") print("3. Print terminals") print("4. Print productions") print("5. Get productions for a nonterminal") print("6. Check if the grammar is CFG") print("7. Parse input string") print("0. Exit") input_command = input("Enter your command: ") match input_command: case "1": filename = input("Enter the filename: ") g.read_from_file(filename) case "2": g.print_nonterminals() case "3": g.print_terminals() case "4": g.print_productions() case "5": nonterminal = input("Enter the nonterminal: ") print(g.get_productions_for(nonterminal)) case "6": print(g.is_cfg()) case "7": input_string = input("Enter the input string: ") parser = RecursiveDescentParser(g, input_string) if parser.parse(): print(parser.print_parse_tree()) parser.save_parse_tree("out1.txt") else: print("The input string is not in the language") print(parser.stack) print(parser.parsed_stack) case "0": return case _: print("Invalid command") if __name__ == '__main__': menu() # g = Grammar() # g.read_from_file("g1.txt") # parser = RecursiveDescentParser(g, "a a b") # parser.expand("S", 0) # print(parser.current_pos) # print(parser.stack) # print(parser.parsed_stack) # parser.advance() # print(parser.current_pos) # print(parser.stack) # print(parser.parsed_stack) # parser.expand("A", 1) # print(parser.current_pos) # print(parser.stack) # print(parser.parsed_stack) # parser.advance() # print(parser.current_pos) # print(parser.stack) # print(parser.parsed_stack) # parser.back() # print(parser.current_pos) # print(parser.stack) # print(parser.parsed_stack) # parser.another_try("A",1) # print(parser.current_pos) # print(parser.stack) # print(parser.parsed_stack) # parser.advance() # print(parser.current_pos) # print(parser.stack) # print(parser.parsed_stack) # parser.advance() # print(parser.current_pos) # print(parser.stack) # print(parser.parsed_stack) # print(parser.success()) # print(parser.current_pos) # print(parser.stack) # print(parser.parsed_stack)