Beispiel #1
0
    def __initial_split(self):
        """Returns the set of states that are 'acceptance'. If the optional     
           argument 'ReturnNonAcceptanceTooF' is specified, then the non-
           acceptance states are also returned.

        """
        self.state_set_list = []

        # (1) Split according to acceptance and non-acceptance
        self.state_set_list.append([])  # state set '0': non-acceptance states
        acceptance_state_set = []  # acceptance states
        for state_index, state in self.sm.states.items():
            if state.is_acceptance():
                acceptance_state_set.append(state_index)
            else:
                self.state_set_list[0].append(
                    state_index)  # put state into state set 0
                self.map[
                    state_index] = 0  # note, that it is stored in state set '0'

        # NOTE: Under normal conditions, there **must** be at least one non-acceptance state,
        #       which happens to be the initial state (otherwise nothing would be acceptable).
        #       But, for unit tests etc. we need to live with the possibility that the there
        #       might be no non-acceptance states.
        if len(self.state_set_list[0]) == 0: del self.state_set_list[0]
        # ... size matters from now on!
        self.size = len(self.state_set_list)

        # (2) Split the acceptance states according to their origin. An acceptance
        #     state maching the, for example, an identifier is not equivalent an
        #     acceptance state thate that matches a number.
        db = {}

        def db_add(key, state_index):
            if db.has_key(key): db[key].append(state_index)
            else: db[key] = [state_index]

        for state_index in acceptance_state_set:
            state = self.sm.states[state_index]
            origin_state_machine_ids = map(
                lambda origin: origin.state_machine_id,
                state.origins().get_list())
            state_combination_id = map_state_combination_to_index(
                origin_state_machine_ids)
            db_add(state_combination_id, state_index)

        # (2b) Enter the splitted acceptance state sets.
        for state_set in db.values():
            self.__add_state_set(state_set)
    def __initial_split(self):
        """Returns the set of states that are 'acceptance'. If the optional     
           argument 'ReturnNonAcceptanceTooF' is specified, then the non-
           acceptance states are also returned.

        """   
        self.state_set_list = []

        # (1) Split according to acceptance and non-acceptance
        self.state_set_list.append([])  # state set '0': non-acceptance states
        acceptance_state_set = []       # acceptance states
        for state_index, state in self.sm.states.items():
            if state.is_acceptance(): 
                acceptance_state_set.append(state_index)
            else:                     
                self.state_set_list[0].append(state_index)  # put state into state set 0
                self.map[state_index] = 0                   # note, that it is stored in state set '0'

        # NOTE: Under normal conditions, there **must** be at least one non-acceptance state,
        #       which happens to be the initial state (otherwise nothing would be acceptable).
        #       But, for unit tests etc. we need to live with the possibility that the there 
        #       might be no non-acceptance states.
        if len(self.state_set_list[0]) == 0: del self.state_set_list[0]
        # ... size matters from now on!
        self.size = len(self.state_set_list)

        # (2) Split the acceptance states according to their origin. An acceptance
        #     state maching the, for example, an identifier is not equivalent an 
        #     acceptance state thate that matches a number.
        db = {}   
        def db_add(key, state_index):
            if db.has_key(key): db[key].append(state_index)
            else:               db[key] = [ state_index ]                             

        for state_index in acceptance_state_set:
            state = self.sm.states[state_index]
            origin_state_machine_ids = map(lambda origin: origin.state_machine_id, 
                                           state.origins().get_list())
            state_combination_id = map_state_combination_to_index(origin_state_machine_ids) 
            db_add(state_combination_id, state_index)

        # (2b) Enter the splitted acceptance state sets.
        for state_set in db.values():
            self.__add_state_set(state_set)
Beispiel #3
0
def do(SM):
    """Creates a deterministic finite automaton (DFA) from the current state 
       machine - which may be a NFA (non-deterministic finite automaton). This is
       a generlized version of the 'subset construction' algorithm. Where 
       subsection construction focusses on letters of an alphabet for the
       investigation of transitions, this algorithm focusses on elementary
       trigger sets. A very good description of the subset construction 
       algorithm can be found in 'Engineering a Compiler' by Keith Cooper.
    """
    # (*) create the result state machine
    initial_state_epsilon_closure = SM.get_epsilon_closure(SM.init_state_index) 

    # NOTE: Later on, state machines with an initial acceptance state are forbidden.
    #       So, acceptance is not a question here. Think about setting it to false anyway.
    result = StateMachine(Core = SM.core())

    # (*) initial state of resulting DFA = epsilon closure of initial state of NFA
    #     -- add the origin list of all states in the epsilon closure
    new_init_state = result.get_init_state()
    for state in map(lambda idx: SM.states[idx], initial_state_epsilon_closure):
        new_init_state.merge(state)

    # (*) prepare the initial worklist
    worklist = [ ( result.init_state_index, initial_state_epsilon_closure) ]

    epsilon_closure_db = SM.get_epsilon_closure_db()

    while worklist != []:
        # 'start_state_index' is the index of an **existing** state in the state machine.
        # It was either created above, in StateMachine's constructor, or as a target
        # state index.
        start_state_index, start_state_combination = worklist.pop()
 
        # (*) compute the elementary trigger sets together with the 
        #     epsilon closure of target state combinations that they trigger to.
        #     In other words: find the ranges of characters where the state triggers to
        #     a unique state combination. E.g:
        #                Range        Target State Combination 
        #                [0:23]   --> [ State1, State2, State10 ]
        #                [24:60]  --> [ State1 ]
        #                [61:123] --> [ State2, State10 ]
        #
        elementary_trigger_set_infos = SM.get_elementary_trigger_sets(start_state_combination,
                                                                      epsilon_closure_db)
        ## DEBUG_print(start_state_combination, elementary_trigger_set_infos)

        # (*) loop over all elementary trigger sets
        for epsilon_closure_of_target_state_combination, trigger_set in elementary_trigger_set_infos:
            #  -- if there is no trigger to the given target state combination, then drop it
            if trigger_set.is_empty(): continue

            # -- add a new target state representing the state combination
            #    (if this did not happen yet)
            target_state_index = \
                 map_state_combination_to_index(epsilon_closure_of_target_state_combination)

            # -- if target state combination was not considered yet, then create 
            #    a new state in the state machine
            if result.states.has_key(target_state_index):
                # -- add only a transition 'start state to target state'
                result.add_transition(start_state_index, trigger_set, target_state_index)
            else:
                # -- add the transition 'start state to target state'
                #    (create implicitly the new target state in the state machine)
                result.add_transition(start_state_index, trigger_set, target_state_index)
                # -- merge informations of combined states inside the target state
                new_target_state = result.states[target_state_index]
                for state in map(lambda idx: SM.states[idx], epsilon_closure_of_target_state_combination):
                    new_target_state.merge(state)

                worklist.append((target_state_index, epsilon_closure_of_target_state_combination))  

    return result 
Beispiel #4
0
def do(SM):
    """Creates a deterministic finite automaton (DFA) from the current state 
       machine - which may be a NFA (non-deterministic finite automaton). This is
       a generlized version of the 'subset construction' algorithm. Where 
       subsection construction focusses on letters of an alphabet for the
       investigation of transitions, this algorithm focusses on elementary
       trigger sets. A very good description of the subset construction 
       algorithm can be found in 'Engineering a Compiler' by Keith Cooper.
    """
    # (*) create the result state machine
    initial_state_epsilon_closure = SM.get_epsilon_closure(SM.init_state_index)

    # NOTE: Later on, state machines with an initial acceptance state are forbidden.
    #       So, acceptance is not a question here. Think about setting it to false anyway.
    result = StateMachine(Core=SM.core())

    # (*) initial state of resulting DFA = epsilon closure of initial state of NFA
    #     -- add the origin list of all states in the epsilon closure
    new_init_state = result.get_init_state()
    for state in map(lambda idx: SM.states[idx],
                     initial_state_epsilon_closure):
        new_init_state.merge(state)

    # (*) prepare the initial worklist
    worklist = [(result.init_state_index, initial_state_epsilon_closure)]

    epsilon_closure_db = SM.get_epsilon_closure_db()

    while worklist != []:
        # 'start_state_index' is the index of an **existing** state in the state machine.
        # It was either created above, in StateMachine's constructor, or as a target
        # state index.
        start_state_index, start_state_combination = worklist.pop()

        # (*) compute the elementary trigger sets together with the
        #     epsilon closure of target state combinations that they trigger to.
        #     In other words: find the ranges of characters where the state triggers to
        #     a unique state combination. E.g:
        #                Range        Target State Combination
        #                [0:23]   --> [ State1, State2, State10 ]
        #                [24:60]  --> [ State1 ]
        #                [61:123] --> [ State2, State10 ]
        #
        elementary_trigger_set_infos = SM.get_elementary_trigger_sets(
            start_state_combination, epsilon_closure_db)
        ## DEBUG_print(start_state_combination, elementary_trigger_set_infos)

        # (*) loop over all elementary trigger sets
        for epsilon_closure_of_target_state_combination, trigger_set in elementary_trigger_set_infos:
            #  -- if there is no trigger to the given target state combination, then drop it
            if trigger_set.is_empty(): continue

            # -- add a new target state representing the state combination
            #    (if this did not happen yet)
            target_state_index = \
                 map_state_combination_to_index(epsilon_closure_of_target_state_combination)

            # -- if target state combination was not considered yet, then create
            #    a new state in the state machine
            if result.states.has_key(target_state_index):
                # -- add only a transition 'start state to target state'
                result.add_transition(start_state_index, trigger_set,
                                      target_state_index)
            else:
                # -- add the transition 'start state to target state'
                #    (create implicitly the new target state in the state machine)
                result.add_transition(start_state_index, trigger_set,
                                      target_state_index)
                # -- merge informations of combined states inside the target state
                new_target_state = result.states[target_state_index]
                for state in map(lambda idx: SM.states[idx],
                                 epsilon_closure_of_target_state_combination):
                    new_target_state.merge(state)

                worklist.append((target_state_index,
                                 epsilon_closure_of_target_state_combination))

    return result