def testDeleteMissingVertices(self): # lhs has no vertices(!). Nothing done. g = Graph() lhs = Graph() rhs = Graph() p = Production(lhs, rhs) gen = Generator() gen._deleteMissingVertices(g, p, {}) self.assertEqual(len(g._vertices), 0) # lhs has vertices, but they all appear in the rhs. Nothing done. g.addVertex(Vertex('g0', 'A', 1)) lhs.addVertex(Vertex('l0', 'A', 1)) rhs.addVertex(Vertex('r0', 'A', 1)) p = Production(lhs, rhs) gen._deleteMissingVertices(g, p, {'l0':'g0'}) self.assertEqual(len(g._vertices), 1) # lhs has a vertex (A2) that don't appear in the rhs. It should be # deleted from g. g.addVertex(Vertex('g1', 'A', 2)) lhs.addVertex(Vertex('l1', 'A', 2)) p = Production(lhs, rhs) self.assertEqual(len(g._vertices), 2) gen._deleteMissingVertices(g, p, {'l0':'g0', 'l1':'g1'}) self.assertEqual(len(g._vertices), 1)
def testFindMatchingProductions(self): # Providing no productions should result in no matches. gen = Generator() g = Graph() self.assertEquals( len(gen._findMatchingProductions(g, [])), 0) # We have a production, but the LHS can't be found in the graph. # No solutions. g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) lhs = Graph() lhs.addEdge(Vertex('g0', 'C'), Vertex('g1', 'D')) rhs = Graph() p1 = Production(lhs, rhs) gen = Generator() self.assertEquals( len(gen._findMatchingProductions(g, [p1])), 0) # One matching production, a simple vertex "A". g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) lhs = Graph() lhs.addVertex(Vertex('g0', 'A', '1')) rhs = Graph() p1 = Production(lhs, rhs) self.assertEquals( len(gen._findMatchingProductions(g, [p1])), 1) # Two matching productions. g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) lhs = Graph() lhs.addVertex(Vertex('g0', 'A', '2')) rhs = Graph() p1 = Production(lhs, rhs) p2 = Production(lhs, rhs) self.assertEquals( len(gen._findMatchingProductions(g, [p1, p2])), 2)
def remove_left_recursion(self): non_terminals = list(self.prods.keys()) for i, non_terminal in enumerate(non_terminals): grammar_changed = True while grammar_changed: grammar_changed = False rhs_i = self.prods[non_terminal].rhses for rhs in rhs_i: for A_j in non_terminals[:i]: if rhs[0] == A_j: rhs_revised = rhs[1:] self.prods[non_terminal].rhses.remove(rhs) grammar_changed = True for prod in self.prods[A_j].rhses: self.prods[non_terminal].rhses.append(prod + rhs_revised) alpha_set = [prod[1:] for prod in self.prods[non_terminal].rhses if prod[0] == non_terminal] beta_set = [prod for prod in self.prods[non_terminal].rhses if prod[0] != non_terminal] if len(alpha_set) > 0: self.prods.pop(non_terminal) non_terminal_new = non_terminal + '.new' self.prods[non_terminal] = Production(non_terminal, [ beta_i + [non_terminal_new] if beta_i != epsilon else [non_terminal_new] for beta_i in beta_set]) self.prods[non_terminal_new] = Production(non_terminal_new, [alpha_i + [non_terminal_new] for alpha_i in alpha_set]) self.prods[non_terminal_new].rhses += [epsilon]
def left_factorize_prods(self): grammar_changed = True unchecked_prods = list(self.prods.values()) new_prods = [] while grammar_changed: grammar_changed = False for prod in list(unchecked_prods): index = 0 prefix = [] while True: if any((len(rhs) <= index or rhs == epsilon) for rhs in prod.rhses): break if all(ith_term == prod.rhses[0][index] for ith_term in list(rhs[index] for rhs in prod.rhses)): prefix.append(prod.rhses[0][index]) index += 1 else: break unchecked_prods.remove(prod) if index > 0: prefix_name = reduce(lambda str1, str2: str(str1) + str(str2), prefix) suffix_name = prod.non_terminal + "." + str(prefix_name) new_prods.append(Production(prod.non_terminal, [prefix + [suffix_name]])) new_rhses = list((epsilon if len(rhs) <= index else rhs[index:]) for rhs in prod.rhses) unchecked_prods.append(Production(suffix_name, new_rhses)) grammar_changed = True else: groups = dict() for rhs in prod.rhses: if rhs != epsilon: if not (rhs[0] in groups): groups[rhs[0]] = [] groups[rhs[0]].append(rhs) else: groups[epsilon[0]] = [epsilon] if len(groups) == len(prod.rhses): new_prods.append(prod) else: new_rhses = [] for term in groups: if term == epsilon[0]: new_rhses.append(epsilon) elif len(groups[term]) == 1: new_rhses.append(groups[term][0]) else: new_prod_name = prod.non_terminal + "." + str(term) new_rhses.append([new_prod_name]) unchecked_prods.append(Production(new_prod_name, groups[term])) unchecked_prods.append(Production(prod.non_terminal, new_rhses)) grammar_changed = True self.make_prods(new_prods)
def make_grammar(compressed_prods): start = compressed_prods[0][0] productions = [] for c_prod in compressed_prods: r = Production(c_prod[0], c_prod[1:]) productions.append(r) return Grammar(productions, start)
def testAddNewVertices(self): # Production rhs has no vertices, so nothing done. g = Graph() lhs = Graph() rhs = Graph() p = Production(lhs, rhs) gen = Generator() self.assertEqual(len(g._vertices), 0) gen._addNewVertices(g, p, {}) self.assertEqual(len(g._vertices), 0) # Production rhs has vertices, but they all appear in the LHS. Hence # they aren't new and nothing is done. lhs.addVertex(Vertex('l1', 'A', 1)) rhs.addVertex(Vertex('r1', 'A', 1)) self.assertEqual(len(g._vertices), 0) gen._addNewVertices(g, p, {}) self.assertEqual(len(g._vertices), 0) # rhs has one new vertex not in the lhs. rhsMapping = {} rhs.addVertex(Vertex('r2', 'B', 2)) self.assertEqual(len(g._vertices), 0) gen._addNewVertices(g, p, rhsMapping) self.assertEqual(len(g._vertices), 1) self.assertIn('v0', g._vertices) # new vertex is v0 self.assertEqual(g._vertices['v0'].label, 'B') # with label B self.assertEqual(g._vertices['v0'].number, 2) # with number 2 self.assertIn('r2', rhsMapping) # now appears in rhsMapping self.assertEqual(rhsMapping['r2'], 'v0') # r2 mapped to v0 (the newly added vertex) in graph
def testApplyProduction(self): # A basic test that tests all four cases: add and remove vertex, # and add and remove edge. # Graph starts with A->B g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) g1 = g._vertices['g1'] # Production lhs matches A->B lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) # Production rhs transforms that to A->C rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'C')) p = Production(lhs,rhs) gen = Generator() gen._applyProduction(g, p, {'l0':'g0','l1':'g1'}) # g has a new vertex, <v2,C>. self.assertEqual(len(g._vertices), 2) self.assertEqual(g._vertices['v1'].label, 'C') # <g0,A> points to <v2,C> self.assertEqual(len(g._edges['g0']), 1) self.assertEqual(g._edges['g0'][0].id, 'v1') self.assertEqual(g._vertices['v1'].label, 'C') # <g0,A> no longer points to <g1,B> self.assertNotIn(g1, g._edges['g0']) # Vertex <g1,B> has been deleted. self.assertNotIn('g1', g._vertices)
def testApplyProductions(self): # Start graph already has the minimum number of vertices. Nothing done. g = Graph() c = {'min_vertices':0} gen = Generator() gen.applyProductions(g, None, c) self.assertEqual(len(g._vertices), 0) # No matching productions raises an error. c = {'min_vertices':1} self.assertRaises(RuntimeError, gen.applyProductions, g, [], c) # When we're done, g has more at least min_vertices. g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'A')) c = {'min_vertices':10} # Production is A1->A2 ==> A1->A->A2 lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'A', 2)) rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'A')) rhs.addEdge('r1', Vertex('r2', 'A', 2)) p = Production(lhs, rhs) gen.applyProductions(g, [p], c) logging.debug(g) self.assertEqual(len(g._vertices), 10)
def _parseProduction(self): """ prod -> graph '==>' graph A production defines a transformation taking one graph (on the LHS) and transforming it to a different graph (RHS). """ lhs = self._parseGraph() self._match(TokenTypes.DOUBLEARROW) rhs = self._parseGraph() self.productions.append(Production(lhs, rhs))
def testApplyProduction_Blackbox2(self): # Another black-box test of _applyProduction this time with # numbered vertices. # Graph is A0->A1,A0->D g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'A')) g.addEdge('g0', Vertex('g2', 'D')) # Production is A1->A2 ==> A1->A->A2. # This production adds a new vertex "A" between the existing As, # leaving the first A still pointing to D. # Resulting graph: A1->A3->A2; A1->D lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'A', 2)) rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'A')) rhs.addEdge('r1', Vertex('r2', 'A', 2)) p = Production(lhs, rhs) gen = Generator() gen._applyProduction(g, p, {'l0':'g0','l1':'g1'}) # Result has 4 vertices. self.assertEqual(len(g._vertices), 4) # <g0,A> is still in the graph. self.assertIn('g0', g._vertices) self.assertEqual(g._vertices['g0'].label, 'A') # <v3,A> has been added. self.assertIn('v3', g._vertices) self.assertEqual(g._vertices['v3'].label, 'A') # g0->v3 self.assertIn(g._vertices['v3'], g._edges['g0']) # <g1,A> is still in the graph. self.assertIn('g1', g._vertices) self.assertEqual(g._vertices['g1'].label, 'A') # <g2,D> is still in the graph. self.assertIn('g2', g._vertices) self.assertEqual(g._vertices['g2'].label, 'D') # <g0,A>-><g2,D> self.assertIn(g._vertices['g2'], g._edges['g0']) # g0->v3 self.assertIn(g._vertices['v3'], g._edges['g0']) # Output looks fine: A1->A->A, A1->D self.assertEqual(str(g), 'digraph {\nA_v3->A_g1;\nA_g0->D_g2;\nA_g0->A_v3;\n\n}')
def makeNodes(): parent = Production("S") parent.childrens.append("z") parent.childrens.append(Production(parent, "M")) parent.childrens.append(Production(parent, "N")) parent.childrens.append("z") children = parent.childrens[1] children.childrens.append("a") children.childrens.append(Production(children, "M")) children.childrens.append("a") children2 = parent.childrens[2] children2.childrens.append("b") children2.childrens.append(Production(children2, "N")) children2.childrens.append("b") children3 = children.childrens[1] children3.childrens.append("z") children3.childrens.append(Production(children3, "M")) children4 = children3.childrens[1] children4.childrens.append("z") generateTree()
def get_productions_from_xml(path): tree = ElementTree.parse(path) root = tree.getroot() prods = root.find('m_Production') production_sym_count = [] for prod in prods.findall('Production'): count = prod.attrib['SymbolCount'] rule = prod.attrib['NonTerminalIndex'] production_sym_count.append(Production(count, rule)) return production_sym_count
def readProductions(self): try: file = open("file/grammar.txt") for line in file.readlines(): if line[-1] == "\n": line = line[:-1] left = line.split("->")[0].strip() right = line.split("->")[1].strip() production = Production(left, right.split(" ")) self.__productions.append(production) file.close() except Exception: print("打开文件时出错")
def read_Production(name): """ Read a production from 'productions\name.dot' :param name: name of production to read :return: Production object """ filename = "productions\\" + name + ".dot" left_p = pydot.graph_from_dot_file(filename)[0] right_p = pydot.graph_from_dot_file(filename)[1] l = graph_to_graph_transformation(pydot_graph_to_graph(left_p, name)) r = graph_to_graph_transformation(pydot_graph_to_graph(right_p, name)) e = read_embed_transformation(filename) return Production(l, r, e)
def testAddNewEdges(self): # rhs has no edges, so nothing changes. g = Graph() lhs = Graph() rhs = Graph() p = Production(lhs,rhs) rhsMapping = {} gen = Generator() self.assertEqual(len(g._edges), 0) gen._addNewEdges(g, p, rhsMapping) self.assertEqual(len(g._edges), 0) # rhs has an edge, but it already exists in the graph. g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'B')) lhs = Graph() rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'B', 1)) p = Production(lhs,rhs) rhsMapping = {'r0':'g0', 'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._addNewEdges(g, p, rhsMapping) self.assertEqual(len(g._edges['g0']), 1) # rhs has a new edge not in graph. g = Graph() g.addVertex(Vertex('g0', 'A')) g.addVertex(Vertex('g1', 'B')) lhs = Graph() rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'B', 1)) p = Production(lhs,rhs) rhsMapping = {'r0':'g0', 'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 0) gen._addNewEdges(g, p, rhsMapping) self.assertEqual(len(g._edges['g0']), 1) self.assertEqual(g._edges['g0'][0].id, 'g1')
def buildProList(self): for p in self.InputPro: self.pList.add(Production(p[0], p[1])) if p[0] not in self.Virables: self.Virables.append(p[0]) for p in self.InputPro: for t in p[1]: if t not in self.Virables and t not in self.Terminals and t != 'NULL': self.Terminals.append(t) self.TerAndEnd = self.Terminals.copy() self.TerAndEnd.append('#')
def delDirectRecur(self, p): v = p vPList = self.pList.getVirablePro(v) isLeftRecur = False for p in vPList: if p.left == p.right[0]: isLeftRecur = True if isLeftRecur == True: new_v = v + '1' assert new_v not in self.Virables self.Virables.append(new_v) for p in vPList: if p.left == p.right[0]: self.pList.delete(p) p.right.remove(p.left) p.right.append(new_v) self.pList.add(Production(new_v, p.right)) else: if p.right == ['NULL']: p.right = [new_v] else: p.right.append(new_v) self.pList.add(Production(v, p.right)) self.pList.add(Production(new_v, ['NULL']))
def get_production_grammar_file(gram): fin = open(gram) start = None production = [] for line in fin: l, r = line.split("->") l = l.strip() if l == "root": if start != None: raise Exception("too Many root symbol") start = 'root' for rule in r.split("|"): production.append(Production(l, rule, None)) if start == None: raise Exception("did you forget root symbol?") return production
def testApplyProduction_Blackbox(self): # Black-box test of _applyProduction. # Graph is A->C,D g = Graph() g.addEdge(Vertex('g0', 'A'), Vertex('g1', 'C')) g.addVertex(Vertex('g2', 'D')) # Production is A->C,D ==> A->B,C. # This adds vertex B, adds edge from A->B, deletes edge from A->C, # and deletes vertex D. lhs = Graph() lhs.addEdge(Vertex('l0', 'A'), Vertex('l1', 'C')) lhs.addVertex(Vertex('l2', 'D')) rhs = Graph() rhs.addEdge(Vertex('r0', 'A'), Vertex('r1', 'B')) rhs.addVertex(Vertex('r2', 'C')) p = Production(lhs, rhs) gen = Generator() gen._applyProduction(g, p, {'l0':'g0','l1':'g1','l2':'g2'}) self.assertEqual(len(g._vertices), 3) # <g0,A> is still in the graph. self.assertIn('g0', g._vertices) self.assertEqual(g._vertices['g0'].label, 'A') # <v3,B> has been added. self.assertIn('v2', g._vertices) self.assertEqual(g._vertices['v2'].label, 'B') # A->B self.assertIn(g._vertices['v2'], g._edges['g0']) # <g1,C> is still in the graph. self.assertIn('g1', g._vertices) self.assertEqual(g._vertices['g1'].label, 'C') # A->C has been removed. self.assertNotIn(g._vertices['g1'], g._edges['g0']) # <g2,D> has been removed. self.assertNotIn('g2', g._vertices) # Output looks fine. self.assertEqual(str(g), 'digraph {\nA_g0->B_v2;\n\n}')
def get_production_semantic_file(self, gram): mod = imp.load_source("*", gram) for x in dir(mod): if not x.startswith("sem_"): continue obj = getattr(mod, x) if isinstance(obj, types.FunctionType): line = obj.__doc__ sp = line.split("->") l, r = sp l = l.strip() self.nonterminal.add(l) if l == "root": self.start = "root" p = Production(l, r, obj) self.production.append(p)
def testMapRHSToGraph(self): # No vertices in rhs. Mapping returned is empty. g = Graph() lhs = Graph() rhs = Graph() p = Production(lhs, rhs) gen = Generator() rhsMapping = gen._mapRHSToGraph(g, p, {}) self.assertEqual(len(rhsMapping), 0) # rhs has vertex r1, but it doesn't appear in the lhs. Mapping returned # is empty. rhs.addVertex(Vertex('r1', 'A', '1')) rhsMapping = gen._mapRHSToGraph(g, p, {}) self.assertEqual(len(rhsMapping), 0) # rhs vertex r1 also appears in lhs as l1, which is mapped to g1. # r1 should appear in rhsMapping mapped to g1. lhs.addVertex(Vertex('l1', 'A', '1')) rhsMapping = gen._mapRHSToGraph(g, p, {'l1':'g1'}) self.assertEqual(len(rhsMapping), 1) self.assertIn('r1', rhsMapping) self.assertEqual(rhsMapping['r1'], 'g1')
from Production import Production production = [('E', 'TA'), ('A', '+TA'), ('A', '#'), ('T', 'FB'), ('B', '*FB'), ('B', '#'), ('F', '(E)'), ('F', 'i')] prod = Production(production) print(prod.showFirstAndFollow())
# end def def get_productions(production_paths): productions = [[None] * 3 for _ in production_paths] for i, production in enumerate(production_paths): productions[i][0] = graph_to_graph_transformation( str(i) + "L", read_Graph(str(i) + "L", production[0])) productions[i][1] = graph_to_graph_transformation( str(i) + "R", read_Graph(str(i) + "R", production[1])) productions[i][2] = embed_transformation(production[2]) return productions # end def hello_main() name = get_name() g_path = graph_path() p_paths = production_paths() graph = get_graph(name, g_path) prod_args = get_productions(p_paths) for prod_arg in prod_args: production = Production(prod_arg[0], prod_arg[1], prod_arg[2]) print(prod_arg[2]) graph = production.produce(graph, name) graph.view(cleanup=True) graph.render(filename="graph_photos\\" + name + ".dot", cleanup=True)
from Production import Production p = Production() p.run()
def testDeleteMissingEdges(self): # If lhs has no edges, then there's nothing missing from the rhs. # Nothing is done to the graph. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() rhs = Graph() p = Production(lhs,rhs) lhsMapping = {} rhsMapping = {} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 1) # lhs has an edge, but it also appears on the rhs. Nothing done. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) rhs = Graph() rhs.addEdge(Vertex('r0', 'A', 1), Vertex('r1', 'B', 1)) p = Production(lhs,rhs) lhsMapping = {'l0':'g0', 'l1':'g1'} rhsMapping = {'r0':'g0', 'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 1) # lhs has an edge, but the starting vertex doesn't appear in the RHS. # The edge should be deleted from the graph. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) rhs = Graph() rhs.addVertex(Vertex('r0', 'A', 2)) rhs.addVertex(Vertex('r1', 'B', 1)) p = Production(lhs,rhs) lhsMapping = {'l0':'g0', 'l1':'g1'} rhsMapping = {'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 0) # lhs has an edge, but the ending vertex doesn't appear in the RHS. # The edge should be deleted from the graph. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) rhs = Graph() rhs.addVertex(Vertex('r0', 'A', 1)) rhs.addVertex(Vertex('r1', 'B', 2)) p = Production(lhs,rhs) lhsMapping = {'l0':'g0', 'l1':'g1'} rhsMapping = {'r0':'g0'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 0) # lhs has an edge, but it's gone from the rhs. It should be deleted # from the graph. g = Graph() g.addEdge(Vertex('g0', 'A', 1), Vertex('g1', 'B', 1)) lhs = Graph() lhs.addEdge(Vertex('l0', 'A', 1), Vertex('l1', 'B', 1)) rhs = Graph() rhs.addVertex(Vertex('r0', 'A', 1)) rhs.addVertex(Vertex('r1', 'B', 1)) p = Production(lhs,rhs) lhsMapping = {'l0':'g0', 'l1':'g1'} rhsMapping = {'r0':'g0', 'r1':'g1'} gen = Generator() self.assertEqual(len(g._edges['g0']), 1) gen._deleteMissingEdges(g, p, lhsMapping, rhsMapping) self.assertEqual(len(g._edges['g0']), 0)
def __init__(self, grammar_num=1): # Grammar from task 1 used by default not LL1 if grammar_num == 1: self.grammar_productions = [ Production(20, [21, 99]), Production(21, [23, 22]), Production(22, [5, 21]), Production(22, [6, 21]), Production(22, [26]), Production(23, [24]), Production(23, [7, 23]), Production(24, [3, 21, 4]), Production(24, [25]), Production(24, [2, 10, 1]), Production(24, [2, 12, 1]), Production(24, [2, 11, 1]), Production(24, [2]), Production(25, [8]), Production(25, [9]), Production(26, []) ] # if any argument but 1 is passed to grammar will use this LL1 grammar developed in task 3 else: self.grammar_productions = [ Production(20, [21, 99]), Production(21, [23, 22]), Production(22, [5, 21]), Production(22, [6, 21]), Production(22, [26]), Production(23, [24]), Production(23, [7, 23]), Production(24, [3, 21, 4]), Production(24, [25]), Production(24, [2, 27]), Production(25, [8]), Production(25, [9]), Production(26, []), Production(27, [10, 1]), Production(27, [12, 1]), Production(27, [11, 1]), Production(27, [26]) ]
def makeCuteProduction(self): for key, value in self.Prod.items(): newVals = [] for v in value: newVals.append(v.split()) self.cuteProductions.append(Production(key, newVals))
def recursive_descent_run(self): state = State(self.__grammar.getStartSymbol()) while state.type != StateType.FINAL and state.type != StateType.ERROR: print(state) if state.type == StateType.NORMAL: if len(state.input_stack) == 0 and state.index == len( self.__input): state.type = StateType.FINAL elif len(state.input_stack) == 0: state.type = StateType.BACK else: if state.input_stack[0] in self.__grammar.getNonTerminals( ): non_term = state.input_stack[0] first_prod = self.__grammar.getProdForNT(non_term)[0] state.work_stack.append((first_prod.getLeftSide(), first_prod.getRightSide())) state.input_stack = first_prod.getRightSide( ) + state.input_stack[1:] else: if state.index == len(self.__input): state.type = StateType.BACK elif state.input_stack[0] == StateType.ERROR: state.work_stack.append(StateType.ERROR) state.input_stack = state.input_stack[1:] elif state.input_stack[0] == self.__input[state.index]: state.index += 1 state.work_stack.append(state.input_stack[0]) state.input_stack = state.input_stack[1:] else: state.type = StateType.BACK else: if state.type == StateType.BACK: if state.work_stack[-1] in self.__grammar.getTerminals(): if state.work_stack[-1] == StateType.ERROR: state.work_stack.pop(-1) else: state.index -= 1 terminal = state.work_stack.pop(-1) state.input_stack = [terminal] + state.input_stack else: last_production = state.work_stack[-1] productions = self.__grammar.getProdForNT( last_production[0]) productions = [(prod.getLeftSide(), prod.getRightSide()) for prod in productions] next_prod = self.__get_next_prod( last_production, productions) if next_prod: state.type = StateType.NORMAL state.work_stack.pop(-1) state.work_stack.append( (next_prod[0], next_prod[1])) state.input_stack = state.input_stack[ len(last_production[1]):] state.input_stack = next_prod[1] + state.input_stack elif state.index == 0 and last_production[ 0] == self.__grammar.getStartSymbol(): state.type = StateType.ERROR else: state.work_stack.pop(-1) if last_production[1] == [StateType.ERROR]: state.input_stack = [last_production[0] ] + state.input_stack else: state.input_stack = [ last_production[0] ] + state.input_stack[len(last_production[1]):] prod_rules = [] if state.type == StateType.ERROR: return False, [] else: for prod in state.work_stack: if len(prod) > 1: if Production(prod[0], prod[1]) in self.__grammar.getProductions(): prod_rules.append(prod) return True, prod_rules