112 lines
3.7 KiB
Python
112 lines
3.7 KiB
Python
import string
|
|
|
|
|
|
class TreeNode:
|
|
def __init__(self, value, father=None):
|
|
self.value = value # Grammar symbol (terminal/nonterminal)
|
|
self.father = father # Parent node
|
|
self.sibling = None # Sibling node
|
|
self.children = [] # List of children for easy access
|
|
|
|
def add_child(self, child):
|
|
"""Adds a child to the current node."""
|
|
if self.children:
|
|
# Set sibling for the last child
|
|
self.children[-1].sibling = child
|
|
self.children.append(child)
|
|
|
|
def __str__(self):
|
|
"""String representation of the node."""
|
|
return self.value
|
|
|
|
|
|
class ParserOutput:
|
|
def __init__(self, terminal, nonterminal):
|
|
self.root = None # Root of the parse tree
|
|
self.terminal = terminal
|
|
self.nonterminal = nonterminal
|
|
|
|
def build_tree(self, production_sequence):
|
|
"""
|
|
Builds the parse tree from a sequence of productions.
|
|
:param production_sequence: List of (nonterminal, production) tuples
|
|
"""
|
|
if not production_sequence:
|
|
return None
|
|
|
|
stack = [] # Stack for constructing the tree
|
|
for nonterminal, production in production_sequence:
|
|
if not self.root:
|
|
# Create the root node
|
|
self.root = TreeNode(nonterminal)
|
|
stack.append(self.root)
|
|
current = stack.pop()
|
|
symbols = production.split()
|
|
for symbol in symbols:
|
|
child = TreeNode(symbol, current)
|
|
current.add_child(child)
|
|
if symbol in self.nonterminal: # Nonterminal
|
|
stack.append(child)
|
|
else:
|
|
# Create nodes based on production
|
|
current = stack.pop()
|
|
symbols = production.split()
|
|
for symbol in symbols:
|
|
child = TreeNode(symbol, current)
|
|
current.add_child(child)
|
|
if symbol in self.nonterminal: # Nonterminal
|
|
stack.append(child)
|
|
|
|
def transform_representation(self, node=None, level=0):
|
|
if node is None:
|
|
node = self.root
|
|
|
|
result = "-" * level + str(node) + "\n"
|
|
for child in node.children:
|
|
result += self.transform_representation(child, level + 1)
|
|
return result
|
|
|
|
def print_to_screen(self):
|
|
print(self.print_table())
|
|
|
|
def print_table(self):
|
|
"""
|
|
Prints a table representation of the parse tree.
|
|
"""
|
|
rows = []
|
|
index_map = {}
|
|
|
|
def traverse(node, index=1, parent_index=None):
|
|
current_index = len(rows)
|
|
index_map[node] = current_index
|
|
|
|
# Determine right sibling
|
|
sibling_index = None
|
|
if node.sibling:
|
|
sibling_index = len(rows) + 1 # Right sibling will be the next node added
|
|
|
|
rows.append((current_index, node.value, parent_index, sibling_index))
|
|
|
|
for child in node.children:
|
|
traverse(child, len(rows), current_index)
|
|
|
|
traverse(self.root)
|
|
|
|
# Print the table
|
|
s = ""
|
|
s += "+-------+-------+--------+---------------+" + "\n"
|
|
s += "| Index | Value | Parent | Right Sibling |" + "\n"
|
|
s += "+-------+-------+--------+---------------+" + "\n"
|
|
for index, value, parent, sibling in rows:
|
|
s += f"| {index:<3} | {value:<3} | {parent + 1 if parent is not None else '0':<4} | {sibling if sibling is not None else '0':<11} |" + "\n"
|
|
|
|
s += "+-------+-------+--------+---------------+" + "\n"
|
|
return s
|
|
|
|
|
|
def save_to_file(self, filename):
|
|
with open(filename, 'w') as file:
|
|
file.write(self.print_table())
|
|
|
|
|