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 match(self, lexer: Lexer, debug: int = 0, partial=True): """ try to match lexer's current token with a production list in productions return AST instance: match SUCCESS with a production list in productions return None: match FAILED with whole productions """ tree = Ast(self.name, lexer.current_position(), grammars=[]) recursive_productions = [] for production_list in self.productions: lexer.anchor() if debug: print(' ' * ( debug - 1) + f'### {self.name}.match() with production_list: {production_list}') # productions: [[G1, G2], [G3, G4], ...] <-> G1 G2 | G3 G4 | ... # # try to match all tokes with a production_list, mark the tracker # case 1: matched & break loop # case 2: unmatched, try next production_list in productions until # loop ends and function returns `None` success = self.build_ast(tree, lexer, production_list, recursive_productions, debug) if debug else self.build_ast(tree, lexer, production_list, recursive_productions) if success is True or success is None: # success case or Epsilon case if debug: print( ' ' * (debug - 1) + f'+++ {self.name}.match() SUCCESS') break else: # failed case continue else: if debug: print(' ' * (debug - 1) + f'--- {self.name}.match() FAILED') return None # one production_list is fully matched, pop anchor stack by one lexer.release_anchor() if lexer.current_token is None or tree.children or partial: return tree return None