Exemplo n.º 1
0
    def transform_to_nfa(self, regex: str) -> Optional[NFA]:
        """
        transform_to_nfa
        Main entry point to convert regex to NFA by parsing through the regex.
        Returns either the NFA or None if error occurred.

        :param regex: The regular expression to convert.
        :return: An equivalent NFA.
        """

        if not regex:
            logging.critical('Empty regex error')
            return

        # Make an NFA and initialize_nfa
        nfa = NFA()
        nfa.initialize_nfa(regex)
        self.last_state = nfa.initial_state
        self.open_groups.append(self.last_state)

        # Parse regex:
        # If I read an open grouping char (i.e. '(' or '['), add it as an open group.
        # If I read a closed grouping char (i.e. ')' or ']'), move the last open state to closed.
        # If I read an operator, apply the operator to the last closed group.
        # If there are no closed groups, there is an error.
        # If I read a character, process it and set it as the last closed group.
        for char in regex:
            # Check if it is a group
            if char in RegexChar.opening_group():
                self.open_groups.append(self.last_state)
            elif char in RegexChar.closing_group():
                # close the group
                self.last_closed_group = self.open_groups[-1]
                for union in self.union_in_progress[::-1]:
                    if union[0] == self.open_groups[-1]:
                        self.close_union(nfa)
                self.open_groups = self.open_groups[:-1]
            # check if the char is an operator
            elif char in RegexChar.operators():
                if char == RegexChar.UNION.value:
                    self.union_nfa(nfa)
                # apply the operator to the last closed group
                elif self.last_closed_group is None:
                    # Error in regex
                    logging.critical('Error applying operator: ' + str(char))
                    return
                else:
                    if char == RegexChar.STAR.value:
                        self.star_nfa(nfa)
                    elif char == RegexChar.OPTIONAL.value:
                        self.option_nfa(nfa)
                    elif char == RegexChar.PLUS.value:
                        self.plus_nfa(nfa)
            # build the state
            elif char.isalnum():
                # if alphanumeric, concatenate
                nfa = self.concatenate_nfa(nfa, char)
            else:
                # error
                logging.critical('Error reading character: ' + str(char))
                return

        # post processing
        self.last_closed_group = self.open_groups[-1]
        if self.union_in_progress:
            for union in self.union_in_progress[::-1]:
                self.close_union(nfa)
        self.open_groups = self.open_groups[:-1]
        return nfa