162 lines
5.0 KiB
Python
162 lines
5.0 KiB
Python
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)
|
|
|
|
|