Anul 3 Semestrul 1

This commit is contained in:
2025-02-06 20:33:26 +02:00
parent 0b130ee18c
commit 184f3bd92e
313 changed files with 348499 additions and 0 deletions
@@ -0,0 +1,103 @@
from ParserOutput import ParserOutput, TreeNode
class RecursiveDescentParser:
def __init__(self, grammar, input_string):
self.grammar = grammar
self.input = input_string.split()
self.current_pos = 0
self.stack = [] # Stack for backtracking
self.parsed_stack = [] # Current sequence of symbols being parsed
self.production_sequence = [] # To track applied productions
self.parse_tree = ParserOutput(self.grammar.terminals, self.grammar.nonterminals) # Parse tree output
def expand(self, nonterminal, prod_index=0):
"""Expand a nonterminal using the specified production index."""
if nonterminal in self.grammar.productions:
production = self.grammar.productions[nonterminal][prod_index]
self.stack.append((nonterminal, prod_index, self.current_pos, len(self.parsed_stack))) # Push state
self.production_sequence.append((nonterminal, production)) # Track production
self.parsed_stack = production.split() + self.parsed_stack # Add production to parsed stack
else:
raise ValueError(f"No production for {nonterminal}")
def advance(self):
if self.current_pos < len(self.input) and self.parsed_stack:
next_symbol = self.parsed_stack.pop(0)
if next_symbol == self.input[self.current_pos]:
self.current_pos += 1
return True
else:
self.parsed_stack.insert(0, next_symbol) # Push it back
return False
return False
def back(self):
if self.stack:
# Pop the last saved state
nonterminal, prod_index, prev_pos, stack_size = self.stack.pop()
# Restore the previous position in the input
self.current_pos = prev_pos
# Restore the stack to the state it was before expanding the production
self.parsed_stack = self.parsed_stack[:stack_size]
self.production_sequence.pop()
# Try the next production for the same nonterminal
return self.another_try(nonterminal, prod_index)
# If the stack is empty, backtracking is not possible
return False
def another_try(self, nonterminal, prod_index):
"""Try the next production of the nonterminal."""
prod_list = self.grammar.productions.get(nonterminal, [])
if prod_index + 1 < len(prod_list):
self.expand(nonterminal, prod_index + 1) # Expand using the next production
return True
return False
def success(self):
"""Check if parsing succeeded."""
return self.current_pos == len(self.input) and not self.parsed_stack
def parse(self):
if not self.grammar.start_symbol:
raise ValueError("Grammar must have a start symbol defined.")
self.expand(self.grammar.start_symbol)
while True:
# If parsing succeeds
if self.success():
self.parse_tree.build_tree(self.production_sequence)
return True
# If there's something to parse
if self.parsed_stack:
next_symbol = self.parsed_stack[0]
# If next symbol is a terminal, try to match it
if next_symbol in self.grammar.terminals:
if not self.advance():
# If matching fails, backtrack
if not self.back() and len(self.stack) <= 1:
return False
elif next_symbol in self.grammar.nonterminals:
# Expand nonterminal
self.parsed_stack.pop(0)
self.expand(next_symbol)
else:
# Handle unexpected symbols
print(f"Error: Unexpected symbol {next_symbol}")
return False
else:
if not self.back() and len(self.stack) <= 1:
return False
def print_parse_tree(self):
"""Prints the parse tree to the screen."""
self.parse_tree.print_to_screen()
def save_parse_tree(self, filename):
"""Saves the parse tree representation to a file."""
self.parse_tree.save_to_file(filename)