def match(self, lexer: Lexer, debug: int = 0, partial=True): if debug: print(' ' * (debug - 1) + f'### Group {self.name}.match(), calling super\'s match()') tree = Ast(self.name, lexer.current_position(), grammars=[]) if lexer.current_token is None\ or lexer.current_token.spelling == '_EOF': if self.repeat[0] == 0: return tree return None lexer.anchor() repetition = 0 if self.repeat[1] == -1: # can repeat for infinite times: grammar* | grammar+ | grammar{a,} while True: nodes = super().match(lexer, debug) if nodes is None: break tree.extend(nodes) repetition += 1 if lexer.current_token is None: break else: # repeat for limited times: grammar{a, b} | grammar{a} | [grammar] while True: if repetition >= self.repeat[1]: break nodes = super().match(lexer, debug) if nodes is None: break tree.extend(nodes) repetition += 1 if lexer.current_token is None: break if repetition < self.repeat[0]: # if actual repetition is smaller than minimum times if debug: print( ' ' * (debug - 1) + f'--- Group {self.name}.match() FAILED in minimal repetition)' ) lexer.backward() if debug: print( f'<<< lexer backwarded, current token: {lexer.current_token}' ) return None if debug: print(' ' * (debug - 1) + f'+++ Group {self.name}.match() SUCCESS') lexer.release_anchor() return tree
def build_ast(self, tree: Ast, lexer: Lexer, production_list: list, recursive_productions: list = None, debug: int = 0): """ build ast tree on the given instance (parameter `tree`) return True: SUCCESS, tree is appended with nodes return False: FAILED, and tree is untouched return None: Epsilon """ if debug: print(' ' * (debug - 1) + f'### {self.name}.build_ast()') for grammar in production_list: nodes = grammar.match(lexer, debug + 4) if debug else grammar.match(lexer) # this grammar not matched: # 1. abandon whole production_list and skipped loop # 2. lexer setup rollback flag if nodes is None: if debug: print(' ' * ( debug - 1) + f'--- {self.name}.build_ast() with grammar <{grammar}> FAILED') tree.empty() lexer.backward() if debug: print( f'<<< lexer backwarded, current token: {lexer.current_token}') return False if nodes == '_E': # Epsilon if debug: print(' ' * (debug - 1) + f'+++ Epsilon match') tree.append(Ast('Epsilon', lexer.current_token.position, grammar='_e')) return None if isinstance(grammar, Group): # grammar is a Group if not self.ignore_set: tree.extend(nodes) else: for node in nodes: if node.name not in self.ignore_set: tree.append(node) else: # grammar is a Token, only one production hence nodes is # actually a `node` if not self.ignore_set or nodes.name not in self.ignore_set: tree.append(nodes) # all grammar in current production_list matched, operation SUCCESS if debug: print(' ' * (debug - 1) + f'+++ {self.name}.build_ast() SUCCESS') return True