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 _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 prepare_state(self, OldState, StateIndex, OnBeforeEntry): """Prepares states to increment the input/read pointer and dereferences it to access the lexatom for the state transition triggering. REQUIRES: 'self.init_state_forward_f', 'self.engine_type', 'self.__from_db'. """ state = FSM_State.from_State(OldState, StateIndex, self.engine_type, self.dial_db) 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 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 __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 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 __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 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(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)