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
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
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
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())
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)
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
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
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
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)
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)
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
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)
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
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
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)
def create_DropOut(self, SM_State): return OpList(Op.GotoDoorId(DoorID.global_end_of_pre_context_check()))
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)
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)
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
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