Beispiel #1
0
def _prepare_entry_and_reentry(analyzer, OnBegin, OnStep):
    """Prepare the entry and re-entry doors into the initial state
    of the loop-implementing initial state.

                   .----------.
                   | on_entry |
                   '----------'
                        |         .------------.
                        |<--------| on_reentry |<-----.
                        |         '------------'      |
                .----------------.                    |
                |                +-----> Terminal ----+----> Exit
                |      ...       |
                |                +-----> Terminal - - 
                '----------------'

       RETURNS: DoorID of the re-entry door which is used to iterate in 
                the loop.
    """
    # Entry into state machine
    entry            = analyzer.init_state().entry
    init_state_index = analyzer.init_state_index
        
    # OnEntry
    ta_on_entry              = entry.get_action(init_state_index, 
                                                E_StateIndices.BEFORE_ENTRY)
    ta_on_entry.command_list = OpList.concatinate(ta_on_entry.command_list, 
                                                       OnBegin)

    # OnReEntry
    tid_reentry = entry.enter_OpList(init_state_index, index.get(), 
                                          OpList.from_iterable(OnStep))
    entry.categorize(init_state_index)

    return entry.get(tid_reentry).door_id
Beispiel #2
0
def _prepare_entry_and_reentry(analyzer, OnBegin, OnStep):
    """Prepare the entry and re-entry doors into the initial state
    of the loop-implementing initial state.

                   .----------.
                   | on_entry |
                   '----------'
                        |         .------------.
                        |<--------| on_reentry |<-----.
                        |         '------------'      |
                .----------------.                    |
                |                +-----> Terminal ----+----> Exit
                |      ...       |
                |                +-----> Terminal - - 
                '----------------'

       RETURNS: DoorID of the re-entry door which is used to iterate in 
                the loop.
    """
    # Entry into state machine
    entry = analyzer.init_state().entry
    init_state_index = analyzer.init_state_index

    # OnEntry
    ta_on_entry = entry.get_action(init_state_index,
                                   E_StateIndices.BEFORE_ENTRY)
    ta_on_entry.command_list = OpList.concatinate(ta_on_entry.command_list,
                                                  OnBegin)

    # OnReEntry
    tid_reentry = entry.enter_OpList(init_state_index, index.get(),
                                     OpList.from_iterable(OnStep))
    entry.categorize(init_state_index)

    return entry.get(tid_reentry).door_id
Beispiel #3
0
    def add_state(self, StateIndex, OnSuccessDoorId, OnFailureDoorId, BeforeReload=None):
        """Adds a state from where the reload state is entered. When reload is
        done it jumps to 'OnFailureDoorId' if the reload failed and to 'OnSuccessDoorId'
        if the reload succeeded.

        RETURNS: DoorID into the reload state. Jump to this DoorID in order
                 to trigger the reload for the state given by 'StateIndex'.
        """
        assert BeforeReload is None or isinstance(BeforeReload, OpList) 
        # Before reload: prepare after reload, the jump back to the reloading state.
        before_cl = OpList(Op.PrepareAfterReload(OnSuccessDoorId, OnFailureDoorId))
        if BeforeReload is not None:
            # May be, add additional commands
            before_cl = before_cl.concatinate(BeforeReload)

        # No two transitions into the reload state have the same OpList!
        # No two transitions can have the same DoorID!
        # => it is safe to assign a new DoorID withouth .categorize()
        ta         = TransitionAction(before_cl)
        # Assign a DoorID (without categorization) knowing that no such entry
        # into this state existed before.
        ta.door_id = dial_db.new_door_id(self.index)

        assert not self.entry.has_transition(self.index, StateIndex) # Cannot be in there twice!
        self.entry.enter(self.index, StateIndex, ta)

        return ta.door_id
Beispiel #4
0
 def __init__(self, InitOpList=None):
     # NOTE: 'DoorId' is not accepted as argument. Is needs to be assigned
     #       by '.categorize()' in the action_db. Then, transition actions
     #       with the same OpList-s share the same DoorID.
     assert InitOpList is None or isinstance(InitOpList, OpList), "%s: %s" % (InitOpList.__class__, InitOpList)
     self.door_id = None 
     if InitOpList is None: self._command_list = OpList() 
     else:                       self._command_list = InitOpList
Beispiel #5
0
 def create_DropOut(self, SM_State):
     if SM_State.is_acceptance():
         incidence_id = self.__incidence_id_of_bipd
         return OpList(
             Op.QuexDebug(
                 'pattern %i: backward input position detected\\n' %
                 incidence_id), Op.Increment(E_R.InputP),
             Op.GotoDoorId(DoorID.bipd_return(incidence_id)))
     else:
         return OpList(Op.QuexAssertNoPassage())
Beispiel #6
0
    def _finalize_configure_global_drop_out(self, CompressionType, TheAnalyzer):
        """Upon 'drop-out', or when the reload fails the MegaState's drop-out
        section is entered. Then, it must be routed to the represented state
        based upon the state key. The routing command is setup in the MegaState-s
        drop-out. That is,
                        
                        Global Drop-Out
                       .--------------------------------- - -  -
                     .---------------.       on state-key
        drop-out --->| MegaState's   |       .---.
                     | DropOut-Door  |------>| 0 |-----> Drop-out of state[0]
                     '---------------'       | 1 |-----> Drop-out of state[1]
                       |                     | : |
                       :                     '---'
                       '--------------------------------- - -  -

        The Op, which does that is the RouterOnStateKey. It contains the 
        'StateKeyRegister' which tells the code generator which state key to
        take as a basis for routing.
        """
        if not self.transition_map.has_drop_out():
            return

        cmd = Op.RouterOnStateKey(CompressionType, self.index,
                               self.ski_db.iterable_state_key_state_index_pairs(),
                               lambda state_index: TheAnalyzer.drop_out_DoorID(state_index))
        TheAnalyzer.drop_out.entry.enter_OpList(E_StateIndices.DROP_OUT, self.index, 
                                                     OpList(cmd))
        TheAnalyzer.drop_out.entry.categorize(E_StateIndices.DROP_OUT)
Beispiel #7
0
    def prepare_state(self, OldState, StateIndex):
        """REQUIRES: 'self.init_state_forward_f', 'self.engine_type', 'self.__from_db'.
        """
        state = AnalyzerState.from_State(OldState, StateIndex, self.engine_type)

        cmd_list = []
        if self.engine_type.is_BACKWARD_PRE_CONTEXT():
            cmd_list.extend(
                 Op.PreContextOK(cmd.acceptance_id()) 
                 for cmd in OldState.single_entry.get_iterable(SeAccept)
            )

        if state.transition_map is None and False: 
            # NOTE: We need a way to disable this exception for PathWalkerState-s(!)
            #       It's safe, not to allow it, in general.
            #------------------------------------------------------------------------
            # If the state has no further transitions then the input character does 
            # not have to be read. This is so, since without a transition map, the 
            # state immediately drops out. The drop out transits to a terminal. 
            # Then, the next action will happen from the init state where we work
            # on the same position. If required the reload happens at that moment,
            # NOT before the empty transition block.
            #
            # This is not true for Path Walker States, so we offer the option 
            # 'ForceInputDereferencingF'
            assert StateIndex != self.init_state_index # Empty state machine! --> impossible

            if self.engine_type.is_FORWARD(): cmd_list.append(Op.InputPIncrement())
            else:                             cmd_list.append(Op.InputPDecrement())
        else:
            if self.engine_type.is_FORWARD(): cmd_list.extend([Op.InputPIncrement(), Op.InputPDereference()])
            else:                             cmd_list.extend([Op.InputPDecrement(), Op.InputPDereference()])

        ta = TransitionAction(OpList.from_iterable(cmd_list))

        # NOTE: The 'from reload transition' is implemented by 'prepare_for_reload()'
        for source_state_index in self.__from_db[StateIndex]: 
            assert source_state_index != E_StateIndices.BEFORE_ENTRY
            state.entry.enter(StateIndex, source_state_index, ta.clone())

        if StateIndex == self.init_state_index:
            if self.engine_type.is_FORWARD():
                ta = TransitionAction(OpList(Op.InputPDereference()))
            state.entry.enter_state_machine_entry(self.__state_machine_id, 
                                                  StateIndex, ta)

        return state
Beispiel #8
0
def get_Analyzer(StatesDescription):
    """StatesDescription: List of pairs:
         
           (state index, transition map)

       That is, it tells what state of a given state index has what transition
       map. The transition map is a list of pairs

           (interval, target state index)
    """
    # Use 'BACKWARD_PRE_CONTEXT' so that the drop-out objects are created
    # without larger analysis.
    init_state_index = 7777L
    analyzer = Analyzer(engine.BACKWARD_PRE_CONTEXT, init_state_index)
    all_state_index_set = set()
    for state_index, transition_map in StatesDescription:
        assert isinstance(state_index, long)
        assert isinstance(transition_map, list)
        tm = TransitionMap.from_iterable(transition_map)
        tm.fill_gaps(E_StateIndices.DROP_OUT,
                     Setup.buffer_codec.drain_set.minimum(),
                     Setup.buffer_codec.drain_set.supremum())
        analyzer.state_db[state_index] = get_AnalyzerState(state_index, tm)
        all_state_index_set.update(x[1] for x in transition_map)

    # 'Dummy' transitions from init state to all
    analyzer.state_db[init_state_index] = get_AnalyzerState_Init(
        init_state_index, [x[0] for x in StatesDescription])

    # Make sure, that all states mentioned in the transition map really exist.
    for i in all_state_index_set:
        if i in analyzer.state_db: continue
        analyzer.state_db[i] = get_AnalyzerState(
            i, TransitionMap.from_iterable([]))

    # Make sure, that the transitions appear in the 'entry' member of the
    # states. Collect transition information.
    for state_index, transition_map in StatesDescription:
        for interval, target_index in transition_map:
            if not isinstance(target_index, (long, int)): continue
            analyzer.state_db[target_index].entry.enter(
                target_index, state_index, TransitionAction())
        analyzer.state_db[state_index].entry.enter(state_index,
                                                   init_state_index,
                                                   TransitionAction())

    for state in analyzer.state_db.itervalues():
        state.entry.categorize(state.index)

    # Make sure that every state has its entry into drop-out
    empty_cl = OpList()
    for i in analyzer.state_db.iterkeys():
        analyzer.drop_out.entry.enter_OpList(E_StateIndices.DROP_OUT, i,
                                             copy(empty_cl))
    analyzer.drop_out.entry.categorize(E_StateIndices.DROP_OUT)

    analyzer.prepare_DoorIDs()

    return analyzer
Beispiel #9
0
    def prepare_state(self, OldState, StateIndex, OnBeforeEntry):
        """REQUIRES: 'self.init_state_forward_f', 'self.engine_type', 'self.__from_db'.
        """
        state = AnalyzerState.from_State(OldState, StateIndex, self.engine_type)

        cmd_list = []
        if self.engine_type.is_BACKWARD_PRE_CONTEXT():
            cmd_list.extend(
                 Op.PreContextOK(cmd.acceptance_id()) 
                 for cmd in OldState.single_entry.get_iterable(SeAccept)
            )

        if state.transition_map is None and False: 
            # NOTE: We need a way to disable this exception for PathWalkerState-s(!)
            #       It's safe, not to allow it, in general.
            #------------------------------------------------------------------------
            # If the state has no further transitions then the input character does 
            # not have to be read. This is so, since without a transition map, the 
            # state immediately drops out. The drop out transits to a terminal. 
            # Then, the next action will happen from the init state where we work
            # on the same position. If required the reload happens at that moment,
            # NOT before the empty transition block.
            #
            # This is not true for Path Walker States, so we offer the option 
            # 'ForceInputDereferencingF'
            assert StateIndex != self.init_state_index # Empty state machine! --> impossible

            if self.engine_type.is_FORWARD(): 
                cmd_ext = [ Op.Increment(E_R.InputP) ]
            else:                             
                cmd_ext = [ Op.Decrement(E_R.InputP) ]
        else:
            if self.engine_type.is_FORWARD(): 
                cmd_ext = [ Op.Increment(E_R.InputP), Op.InputPDereference() ]
            else:                             
                cmd_ext = [ Op.Decrement(E_R.InputP), Op.InputPDereference() ]

        cmd_list.extend(cmd_ext)

        ta = TransitionAction(OpList.from_iterable(cmd_list))

        # NOTE: The 'from reload transition' is implemented by 'prepare_for_reload()'
        for source_state_index in self.__from_db[StateIndex]: 
            assert source_state_index != E_StateIndices.BEFORE_ENTRY
            state.entry.enter(StateIndex, source_state_index, ta.clone())

        if StateIndex == self.init_state_index:
            if self.engine_type.is_FORWARD():
                on_entry_op_list = OnBeforeEntry.clone()
                on_entry_op_list.append(Op.InputPDereference())
                ta = TransitionAction(on_entry_op_list)
            state.entry.enter_state_machine_entry(self.__state_machine_id, 
                                                  StateIndex, ta)

        return state
Beispiel #10
0
def get_OpList(TheAccepter, TheTerminalRouter):
    """If there is no stored acceptance involved, then one can directly
    conclude from the pre-contexts to the acceptance_id. Then the drop-
    out action can be described as a sequence of checks

       # [0] Check          [1] Position and Goto Terminal
       if   pre_context_32: input_p = x; goto terminal_893;
       elif pre_context_32: goto terminal_893;
       elif pre_context_32: input_p = x; goto terminal_893;
       elif pre_context_32: goto terminal_893;

    Such a configuration is considered trivial. No restore is involved.

    RETURNS: None                                          -- if not trivial
             list((acceptance_condition_set, TerminalRouterElement)) -- if trivial
    """
    # If the 'last_acceptance' is not determined in this state, then it
    # must bee derived from previous storages. We cannot simplify here.
    if TheAccepter is None:
        return OpList(TheTerminalRouter)

    elif not TheAccepter.content.has_acceptance_without_pre_context():
        # If no pre-context is met, then 'last_acceptance' needs to be
        # considered.
        return OpList(TheAccepter, TheTerminalRouter)

    def router_element(TerminalRouter, AcceptanceId):
        for x in TerminalRouter:
            if x.acceptance_id == AcceptanceId: return x
        assert False  # There MUST be an element for each acceptance_id!

    router = TheTerminalRouter.content

    return OpList.from_iterable(
        Op.IfPreContextSetPositionAndGoto(
            check.acceptance_condition_set,
            router_element(router, check.acceptance_id))
        for check in TheAccepter.content)
Beispiel #11
0
    def __init__(self, ColumnNPerCodeUnit, LexemeEndCheckF, MaintainLexemeF, 
                 EngineType, ReloadStateExtern, UserOnLoopExit): 
        """ColumnNPerCodeUnit is None => no constant relationship between 
                                         column number and code unit.
        """
        self.column_number_per_code_unit = ColumnNPerCodeUnit
        self.lexeme_end_check_f          = LexemeEndCheckF
        self.reload_state_extern         = ReloadStateExtern
        self.engine_type                 = EngineType

        # Counting Actions upon: loop entry/exit; before/after reload
        #
        on_loop_entry_count,    \
        on_loop_exit_count,     \
        on_before_reload_count, \
        on_after_reload_count   = self.__prepare_count_actions(self.column_number_per_code_unit)

        # Input pointer positioning: loop entry/exit; before/after reload
        #
        on_loop_reentry_pos,  \
        on_loop_exit_pos      = self.__prepare_positioning_at_loop_begin_and_exit()
        on_before_reload_pos, \
        on_after_reload_pos   = self.__prepare_positioning_before_and_after_reload(MaintainLexemeF) 

        # _____________________________________________________________________
        #
        self.on_loop_entry    = OpList.concatinate(on_loop_reentry_pos, 
                                                   on_loop_entry_count)
        self.on_loop_reentry  = OpList.from_iterable(on_loop_reentry_pos)
        self.on_loop_exit     = OpList.concatinate(on_loop_exit_pos, 
                                                   on_loop_exit_count, 
                                                   UserOnLoopExit)
        self.on_before_reload = OpList.concatinate(on_before_reload_pos, 
                                                   on_before_reload_count)
        self.on_after_reload  = OpList.concatinate(on_after_reload_pos, 
                                                   on_after_reload_count)
Beispiel #12
0
    def from_StateMachine(cls,
                          SM,
                          EngineType,
                          ReloadStateExtern=None,
                          OnBeforeEntry=None):
        """ReloadStateExtern is only to be specified if the analyzer needs
        to be embedded in another one.
        """
        if OnBeforeEntry is None: OnBeforeEntry = OpList()

        result = cls(EngineType, SM.init_state_index)
        result._prepare_state_information(SM, OnBeforeEntry)
        result._prepare_reload_state(ReloadStateExtern, EngineType)
        result._prepare_entries_and_drop_out(EngineType, SM)
        return result
Beispiel #13
0
    def __init__(self, ColumnNPerCodeUnit, LexemeEndCheckF, MaintainLexemeF,
                 EngineType, ReloadStateExtern, UserOnLoopExit):
        """ColumnNPerCodeUnit is None => no constant relationship between 
                                         column number and code unit.
        """
        self.column_number_per_code_unit = ColumnNPerCodeUnit
        self.lexeme_end_check_f = LexemeEndCheckF
        self.reload_state_extern = ReloadStateExtern
        self.engine_type = EngineType

        # Counting Actions upon: loop entry/exit; before/after reload
        #
        on_loop_entry_count,    \
        on_loop_exit_count,     \
        on_before_reload_count, \
        on_after_reload_count   = self.__prepare_count_actions(self.column_number_per_code_unit)

        # Input pointer positioning: loop entry/exit; before/after reload
        #
        on_loop_reentry_pos,  \
        on_loop_exit_pos      = self.__prepare_positioning_at_loop_begin_and_exit()
        on_before_reload_pos, \
        on_after_reload_pos   = self.__prepare_positioning_before_and_after_reload(MaintainLexemeF)

        # _____________________________________________________________________
        #
        self.on_loop_entry = OpList.concatinate(on_loop_reentry_pos,
                                                on_loop_entry_count)
        self.on_loop_reentry = OpList.from_iterable(on_loop_reentry_pos)
        self.on_loop_exit = OpList.concatinate(on_loop_exit_pos,
                                               on_loop_exit_count,
                                               UserOnLoopExit)
        self.on_before_reload = OpList.concatinate(on_before_reload_pos,
                                                   on_before_reload_count)
        self.on_after_reload = OpList.concatinate(on_after_reload_pos,
                                                  on_after_reload_count)
Beispiel #14
0
class TransitionAction(object):
    """Object containing information about commands to be executed upon
       transition into a state.

       .command_list  --> list of commands to be executed upon the transition.
       .door_id       --> An 'id' which is supposed to be unique for a command list. 
                          It is (re-)assigned during the process of 
                          'EntryActionDB.categorize()'.
    """
    __slots__ = ("door_id", "_command_list")
    def __init__(self, InitOpList=None):
        # NOTE: 'DoorId' is not accepted as argument. Is needs to be assigned
        #       by '.categorize()' in the action_db. Then, transition actions
        #       with the same OpList-s share the same DoorID.
        assert InitOpList is None or isinstance(InitOpList, OpList), "%s: %s" % (InitOpList.__class__, InitOpList)
        self.door_id = None 
        if InitOpList is None: self._command_list = OpList() 
        else:                       self._command_list = InitOpList
 
    @property
    def command_list(self): 
        return self._command_list

    @command_list.setter
    def command_list(self, CL): 
        assert isinstance(CL, OpList) or CL is None
        self._command_list = CL
        
    def clone(self):
        result = TransitionAction(self._command_list.clone())
        result.door_id = self.door_id  # DoorID-s are immutable
        return result

    # Make TransitionAction usable for dictionary and set
    def __hash__(self):      
        return hash(self._command_list)

    def __eq__(self, Other):
        return self._command_list == Other._command_list

    def __repr__(self):
        return "(%s: [%s])" % (self.door_id, self._command_list)
Beispiel #15
0
    def from_DFA(cls,
                 SM,
                 EngineType,
                 ReloadStateExtern=None,
                 OnBeforeEntry=None,
                 dial_db=None):
        """ReloadStateExtern is only to be specified if the analyzer needs
        to be embedded in another one.
        """
        if OnBeforeEntry is None: OnBeforeEntry = OpList()

        result = cls(EngineType, SM.init_state_index, dial_db)
        result._prepare_state_information(SM, OnBeforeEntry)
        result._prepare_reload_state(ReloadStateExtern, EngineType)
        if EngineType.requires_detailed_track_analysis():
            result._prepare_entries_and_drop_out(EngineType, SM)
        else:
            result._prepare_entries_and_drop_out_without_analysis(
                EngineType, SM)
        return result
Beispiel #16
0
    def add_mega_state(self, MegaStateIndex, StateKeyRegister, Iterable_StateKey_Index_Pairs, 
                       TheAnalyzer):
        """Implement a router from the MegaState-s door into the Reloader to
        the doors of the implemented states. 
        
                        Reload State
                       .--------------------------------- - -  -
                     .--------------.    on state-key
          reload --->| MegaState's  |       .---.
                     | Reload Door  |------>| 0 |-----> Reload Door of state[0]
                     '--------------'       | 1 |-----> Reload Door of state[1]
                       |                    | : |
                       :                    '---'
                       '--------------------------------- - -  -

        """
        def DoorID_provider(state_index):
            door_id = self.entry.get_door_id(self.index, state_index)
            if door_id is None:
                # The state implemented in the MegaState did not have a 
                # transition to 'ReloadState'. Thus, it was a total drop-out.
                # => Route to the state's drop-out.
                door_id = TheAnalyzer.drop_out_DoorID(state_index)
            return door_id

        cmd = Op.RouterOnStateKey(
            StateKeyRegister, MegaStateIndex,
            Iterable_StateKey_Index_Pairs,
            DoorID_provider
        )

        ta         = TransitionAction(OpList(cmd))
        # Assign a DoorID (without categorization) knowing that no such entry
        # into this state existed before.
        ta.door_id = dial_db.new_door_id(self.index)

        assert not self.entry.has_transition(self.index, MegaStateIndex) # Cannot be in there twice!
        self.entry.enter(self.index, MegaStateIndex, ta)

        return ta.door_id
Beispiel #17
0
    def __init__(self, ColumnNPerCodeUnit, UserBeforeEntryOpList,
                 UserOnLoopExitDoorId):
        # Counting Actions upon: loop entry/exit; before/after reload
        #
        on_loop_entry_count,    \
        on_loop_exit_count,     \
        on_before_reload_count, \
        on_after_reload_count   = self.__prepare_count_actions(ColumnNPerCodeUnit)

        # Input pointer positioning: loop entry/exit; before/after reload
        #
        on_loop_entry,            \
        on_loop_reentry_pos,      \
        on_loop_exit_pos          = self.__prepare_positioning_at_loop_begin_and_exit(ColumnNPerCodeUnit)

        on_before_reload_pos,     \
        on_after_reload_pos       = self.__prepare_positioning_before_and_after_reload()
        on_before_reload_pos_apx, \
        on_after_reload_pos_apx   = self.__prepare_positioning_before_and_after_reload(AppendixSmF=True)

        # _____________________________________________________________________
        #
        if UserBeforeEntryOpList is None: UserBeforeEntryOpList = []
        self.on_loop_entry = OpList.concatinate(on_loop_entry,
                                                on_loop_reentry_pos,
                                                on_loop_entry_count,
                                                UserBeforeEntryOpList)
        self.on_loop_reentry = OpList.from_iterable(on_loop_reentry_pos)
        self.on_loop_exit = OpList.concatinate(
            on_loop_exit_pos, on_loop_exit_count,
            [Op.GotoDoorId(UserOnLoopExitDoorId)])

        self.on_before_reload = OpList.concatinate(on_before_reload_pos,
                                                   on_before_reload_count)
        self.on_before_reload_in_appendix = OpList.from_iterable(
            on_before_reload_pos_apx)

        self.on_after_reload = OpList.concatinate(on_after_reload_pos,
                                                  on_after_reload_count)
        self.on_after_reload_in_appendix = OpList.from_iterable(
            on_after_reload_pos_apx)
Beispiel #18
0
 def create_DropOut(self, SM_State):
     return OpList(Op.GotoDoorId(DoorID.global_end_of_pre_context_check()))
Beispiel #19
0
def do(CcFactory,
       AfterBeyond,
       LexemeEndCheckF=False,
       EngineType=None,
       ReloadStateExtern=None,
       LexemeMaintainedF=False,
       ParallelSmTerminalPairList=None):
    """Generates a (pseudo-one-state) state machine with the properties:
        
               Buffer Limit Code --> Reload
               Loop Character    --> Loop Entry
               Else              --> Exit Loop

    NOTE: This function does NOT code the FAILURE terminal. The caller needs to 
          do this if required.

    Generate code to iterate over the input stream until

           -- A character occurs not in CharacterSet, or
           -- [optional] the 'LexemeEnd' is reached.

    That is, simplified:
                             input in Set
                             .--<--.
                            |      |  LexemeEnd
                            |      +----->------> (Exit)
                          .----.   |
               --------->( Loop )--+----->------> Exit
                          '----'       input 
                                     not in Set
        
    At the end of the iteration, the 'input_p' points to (the begin of) the
    first character which is not in CharacterSet (or the LexemeEnd).

            [i][i][i]..................[i][i][X][.... 
                                             |
                                          input_p
            
    During the 'loop' possible line/column count commands may be applied. To
    achieve the iteration, a simplified pattern matching engine is implemented:

              transition
              map
              .------.  
              |  i0  |----------> Terminal0: OpList0   
              +------+
              |  i1  |----------> Terminal1: OpList1   
              +------+
              |  X2  |----------> Terminal Beyond: input_p--; goto TerminalExit;
              +------+
              |  i2  |----------> Terminal2: OpList2
              +------+
    """
    assert EngineType is not None
    # NOT: assert (not EngineType.subject_to_reload()) or ReloadStateExtern is None
    # This would mean, that the user has to make these kinds of decisions. But,
    # we are easily able to ignore meaningless ReloadStateExtern objects.

    # (*) Construct State Machine and Terminals _______________________________
    #
    parallel_sm_list = None
    if ParallelSmTerminalPairList is not None:
        parallel_sm_list = [sm for sm, terminal in ParallelSmTerminalPairList]

    CsSm = CharacterSetStateMachine.from_CountOpFactory(
        CcFactory, LexemeMaintainedF, ParallelSmList=parallel_sm_list)

    analyzer = analyzer_generator.do(
        CsSm.sm,
        EngineType,
        ReloadStateExtern,
        OnBeforeReload=OpList.from_iterable(CsSm.on_before_reload),
        OnAfterReload=OpList.from_iterable(CsSm.on_after_reload))

    # -- The terminals
    #
    door_id_loop = _prepare_entry_and_reentry(analyzer, CsSm.on_begin,
                                              CsSm.on_step)

    def get_LexemeEndCheck_appendix(ccfactory, CC_Type):
        if not LexemeEndCheckF:
            return [Op.GotoDoorId(door_id_loop)]
        #
        #       .---------------.        ,----------.   no
        #   --->| Count Op |-------< LexemeEnd? >------> DoorIdOk
        #       '---------------'        '----+-----'
        #                                     | yes
        #                              .---------------.
        #                              |  Lexeme End   |
        #                              | Count Op |----> DoorIdOnLexemeEnd
        #                              '---------------'
        #
        elif ccfactory.requires_reference_p(
        ) and CC_Type == E_CharacterCountType.COLUMN:
            return [
                Op.GotoDoorIdIfInputPNotEqualPointer(door_id_loop,
                                                     E_R.LexemeEnd),
                Op.ColumnCountReferencePDeltaAdd(
                    E_R.InputP, ccfactory.column_count_per_chunk, False),
            ] + AfterBeyond
        else:
            return [
                Op.GotoDoorIdIfInputPNotEqualPointer(door_id_loop,
                                                     E_R.LexemeEnd),
            ] + AfterBeyond

    terminal_list = CcFactory.get_terminal_list(CsSm.on_end + AfterBeyond,
                                                CsSm.incidence_id_beyond,
                                                get_LexemeEndCheck_appendix)
    if ParallelSmTerminalPairList is not None:
        terminal_list.extend(terminal
                             for sm, terminal in ParallelSmTerminalPairList)

    # (*) Generate Code _______________________________________________________
    txt = _get_source_code(CcFactory, analyzer, terminal_list)

    return txt, DoorID.incidence(CsSm.incidence_id_beyond)
Beispiel #20
0
def do(CcFactory, AfterBeyond, LexemeEndCheckF=False, EngineType=None, ReloadStateExtern=None, LexemeMaintainedF=False,
       ParallelSmTerminalPairList=None):
    """Generates a (pseudo-one-state) state machine with the properties:
        
               Buffer Limit Code --> Reload
               Loop Character    --> Loop Entry
               Else              --> Exit Loop

    NOTE: This function does NOT code the FAILURE terminal. The caller needs to 
          do this if required.

    Generate code to iterate over the input stream until

           -- A character occurs not in CharacterSet, or
           -- [optional] the 'LexemeEnd' is reached.

    That is, simplified:
                             input in Set
                             .--<--.
                            |      |  LexemeEnd
                            |      +----->------> (Exit)
                          .----.   |
               --------->( Loop )--+----->------> Exit
                          '----'       input 
                                     not in Set
        
    At the end of the iteration, the 'input_p' points to (the begin of) the
    first character which is not in CharacterSet (or the LexemeEnd).

            [i][i][i]..................[i][i][X][.... 
                                             |
                                          input_p
            
    During the 'loop' possible line/column count commands may be applied. To
    achieve the iteration, a simplified pattern matching engine is implemented:

              transition
              map
              .------.  
              |  i0  |----------> Terminal0: OpList0   
              +------+
              |  i1  |----------> Terminal1: OpList1   
              +------+
              |  X2  |----------> Terminal Beyond: input_p--; goto TerminalExit;
              +------+
              |  i2  |----------> Terminal2: OpList2
              +------+
    """
    assert EngineType is not None
    # NOT: assert (not EngineType.subject_to_reload()) or ReloadStateExtern is None
    # This would mean, that the user has to make these kinds of decisions. But, 
    # we are easily able to ignore meaningless ReloadStateExtern objects.

    # (*) Construct State Machine and Terminals _______________________________
    #
    parallel_sm_list = None
    if ParallelSmTerminalPairList is not None:
        parallel_sm_list = [ sm for sm, terminal in ParallelSmTerminalPairList ]

    CsSm = CharacterSetStateMachine.from_CountOpFactory(CcFactory, 
                                                         LexemeMaintainedF,
                                                         ParallelSmList=parallel_sm_list)

    analyzer = analyzer_generator.do(CsSm.sm, EngineType,
                                     ReloadStateExtern,
                                     OnBeforeReload = OpList.from_iterable(CsSm.on_before_reload), 
                                     OnAfterReload  = OpList.from_iterable(CsSm.on_after_reload))

    # -- The terminals 
    #
    door_id_loop = _prepare_entry_and_reentry(analyzer, CsSm.on_begin, CsSm.on_step) 

    def get_LexemeEndCheck_appendix(ccfactory, CC_Type):
        if not LexemeEndCheckF: 
            return [ Op.GotoDoorId(door_id_loop) ]
        #
        #       .---------------.        ,----------.   no
        #   --->| Count Op |-------< LexemeEnd? >------> DoorIdOk
        #       '---------------'        '----+-----'
        #                                     | yes
        #                              .---------------.
        #                              |  Lexeme End   |
        #                              | Count Op |----> DoorIdOnLexemeEnd
        #                              '---------------'
        #  
        elif ccfactory.requires_reference_p() and CC_Type == E_CharacterCountType.COLUMN: 
            return [
                Op.GotoDoorIdIfInputPNotEqualPointer(door_id_loop, E_R.LexemeEnd),
                Op.ColumnCountReferencePDeltaAdd(E_R.InputP, ccfactory.column_count_per_chunk, False),
            ] + AfterBeyond
        else:
            return [
                Op.GotoDoorIdIfInputPNotEqualPointer(door_id_loop, E_R.LexemeEnd),
            ] + AfterBeyond

    terminal_list = CcFactory.get_terminal_list(CsSm.on_end + AfterBeyond,
                                                CsSm.incidence_id_beyond,
                                                get_LexemeEndCheck_appendix)
    if ParallelSmTerminalPairList is not None:
        terminal_list.extend(
            terminal for sm, terminal in ParallelSmTerminalPairList
        )

    # (*) Generate Code _______________________________________________________
    txt = _get_source_code(CcFactory, analyzer, terminal_list)
    
    return txt, DoorID.incidence(CsSm.incidence_id_beyond)
Beispiel #21
0
    def prepare_for_reload(self, TheAnalyzer, BeforeReloadOpList=None, 
                           AfterReloadOpList=None):
        """Prepares state for reload. Reload procedure

            .- State 'X' ---.               
            |               |                .-- Reloader------. 
            | BUFFER LIMIT  |              .----------------.  |
            | CODE detected ------->-------| Door from X:   |  |
            |               |              | Actions before |  |
            |               |              | reload.        |  |
            |               |              '----------------'  |
            |               |                |        |        |
            |               |                |  reload buffer> |
            |    .----------------.          |        |        |
            |    | Door for       |---<-------(good)--*        |
            |    | RELOAD SUCCESS:|          |        |        |
            |    | Actions after  |          |      (bad)      |
            |    | Reload.        |          '------- |--------'
            |    '----------------'                   |
            |               |                .----------------.
            '---------------'                | Door for       |
                                             | RELOAD FAILURE |
                                             '----------------'
                                   
        (1) Create 'Door for RELOAD SUCCESS'. 
        (2) Determine 'Door for RELOAD FAILURE'.
        (3) Create 'Door from X' in Reloader.
        (4) Adapt state X's transition map, so that:
              BUFFER LIMIT CODE --> reload procedure.
        """
        assert self.transition_map is not None
        assert BeforeReloadOpList is None or isinstance(BeforeReloadOpList, OpList)
        assert AfterReloadOpList  is None or isinstance(AfterReloadOpList, OpList)

        if not TheAnalyzer.engine_type.subject_to_reload():
            # Engine type does not require reload => no reload. 
            return

        elif self.transition_map.is_only_drop_out():
            # If the state drops out anyway, then there is no need to reload.
            # -- The transition map is not adapted.
            # -- The reloader is not instrumented to reload for that state.
            return                      

        assert self.index in TheAnalyzer.state_db
        reload_state = TheAnalyzer.reload_state
        assert reload_state.index in (E_StateIndices.RELOAD_FORWARD, 
                                      E_StateIndices.RELOAD_BACKWARD)

        # (1) Door for RELOAD SUCCESS
        #
        after_cl = []
        if TheAnalyzer.engine_type.is_FORWARD(): pass # after_cl.append(Op.Increment(E_R.InputP))
        else:                                    pass # after_cl.append(Op.Decrement(E_R.InputP))
        after_cl.append(Op.InputPDereference())
        if AfterReloadOpList is not None:
            after_cl.extend(AfterReloadOpList)

        self.entry.enter_OpList(self.index, reload_state.index, OpList.from_iterable(after_cl))
        self.entry.categorize(self.index) # Categorize => DoorID is available.
        on_success_door_id = self.entry.get_door_id(self.index, reload_state.index)

        # (2) Determine Door for RELOAD FAILURE
        #
        if TheAnalyzer.is_init_state_forward(self.index):
            on_failure_door_id = DoorID.incidence(E_IncidenceIDs.END_OF_STREAM)
        else:
            on_failure_door_id = TheAnalyzer.drop_out_DoorID(self.index)
            if on_failure_door_id is None:
                on_failure_door_id = DoorID.incidence(E_IncidenceIDs.END_OF_STREAM)

        # (3) Create 'Door from X' in Reloader
        assert on_failure_door_id != on_success_door_id
        reload_door_id = reload_state.add_state(self.index, 
                                                on_success_door_id, 
                                                on_failure_door_id, 
                                                BeforeReloadOpList)

        # (4) Adapt transition map: BUFFER LIMIT CODE --> reload_door_id
        #
        self.transition_map.set_target(Setup.buffer_limit_code, reload_door_id)
        return
Beispiel #22
0
def do(ModeName, CaMap, OpenerPattern, CloserPattern, DoorIdExit, ReloadState,
       dial_db):
    """
                                    .---<---+----------<------+------------------.
                                    |       |                 |                  |
                                    |       | not             | open_n += 1      |  
                                  .------.  | Closer[0]       |                  |
       -------------------------->| Loop +--'                 |                  |
                                  |      |                    | yes              | 
                                  |      |                    |                  |
                                  |      |          .-------------.              |
                                  |      +----->----| Opener[1-N] |              |
                                  |      |          |      ?      |              |
                                  |      |          '-------------'              |
                                  |      |                                       | open_n > 0
                                  |      |          .-------------.              | 
                                  |      +----->----| Closer[1-N] |--------------+------> RESTART
                                  |      |          |      ?      | open_n -= 1    else
                                  |      |          '-------------'             
                                  |      |                             
                                  |  BLC +-->-.  
                              .->-|      |     \                 Reload State 
            .-DoorID(S, 1)--./    '------'      \            .------------------.
         .--| after_reload  |                    \          .---------------.   |
         |  '---------------'                     '---------| before_reload |   |
         |                                                  '---------------'   |
         '---------------------------------------------------|                  |
                                                     success '------------------'     
                                                                     | failure      
                                                                     |            
                                                              .---------------.       
                                                              | SkipRangeOpen |       
                                                              '---------------'                                                                   

    """
    psml, \
    iid_aux_reentry = _get_state_machine_vs_terminal_list(CloserPattern, OpenerPattern,
                                                          DoorIdExit, dial_db)

    if ReloadState: engine_type = ReloadState.engine_type
    else: engine_type = None

    # The first opening pattern must have matched --> counter = 1
    entry_op_list = OpList(Op.AssignConstant(E_R.Counter, 1))

    analyzer_list,         \
    terminal_list,         \
    loop_map,              \
    door_id_loop,          \
    required_register_set, \
    run_time_counter_f     = loop.do(CaMap,
                                     BeforeEntryOpList          = entry_op_list,
                                     OnLoopExitDoorId           = DoorIdExit,
                                     EngineType                 = engine_type,
                                     ReloadStateExtern          = ReloadState,
                                     ParallelSmTerminalPairList = psml,
                                     dial_db                    = dial_db,
                                     ModeName                   = ModeName)

    reentry_op_list = [Op.GotoDoorId(door_id_loop)]
    terminal_list.append(
        Terminal(CodeTerminal(Lng.COMMAND_LIST(reentry_op_list, dial_db)),
                 Name="<SKIP NESTED RANGE REENTRY>",
                 IncidenceId=iid_aux_reentry,
                 dial_db=dial_db))

    required_register_set.add(E_R.Counter)
    return analyzer_list, \
           terminal_list, \
           required_register_set, \
           run_time_counter_f