def _get_appendix_analyzers(LoopMap, EventHandler, AppendixSmList, IidLoopAfterAppendixDropOut): """Parallel state machines are mounted to the loop by cutting the first transition and implementing it in the loop. Upon acceptance of the first character the according tail (appendix) of the state machine is entered. RETURNS: [0] List of appendix state machines in terms of analyzers. [1] Appendix terminals. """ # Codec Transformation appendix_sm_list = [] for sm in AppendixSmList: if not sm.get_init_state().has_transitions(): continue verdict_f, sm = Setup.buffer_codec.do_state_machine(sm, beautifier) appendix_sm_list.append(sm) # Appendix Sm Drop Out => Restore position of last loop character. # (i) Couple terminal stored input position in 'CharacterBeginP'. # (ii) Terminal 'LoopAfterAppendixDropOut' restores that position. # Accepting on the initial state of an appendix state machine ensures # that any drop-out ends in this restore terminal. for init_state in (sm.get_init_state() for sm in appendix_sm_list): init_state.set_acceptance() init_state.mark_acceptance_id(IidLoopAfterAppendixDropOut) # Appendix Analyzer List return [ analyzer_generator.do(sm, EventHandler.engine_type, EventHandler.reload_state_extern, OnBeforeReload=EventHandler.on_before_reload, OnAfterReload=EventHandler.on_after_reload) for sm in appendix_sm_list ]
def __code_pre_context_state_machine(self): LanguageDB = self.language_db if len(self.pre_context_sm_list) == 0: return [] assert len(self.pre_context_sm.get_orphaned_state_index_list()) == 0 txt = [] if Setup.comment_state_machine_f: LanguageDB.ML_COMMENT(txt, "BEGIN: PRE-CONTEXT STATE MACHINE\n" + \ self.pre_context_sm.get_string(NormalizeF=False) + \ "END: PRE-CONTEXT STATE MACHINE") txt.append("\n") # For safety: New content may have to start in a newline, e.g. "#ifdef ..." analyzer = analyzer_generator.do(self.pre_context_sm, E_EngineTypes.BACKWARD_PRE_CONTEXT) msg = state_machine_coder.do(analyzer) txt.extend(msg) txt.append("\n%s" % LanguageDB.LABEL(E_StateIndices.END_OF_PRE_CONTEXT_CHECK)) # -- set the input stream back to the real current position. # during backward lexing the analyzer went backwards, so it needs to be reset. txt.append(" %s\n" % LanguageDB.INPUT_P_TO_LEXEME_START()) for sm_id in self.pre_context_sm_id_list: variable_db.require("pre_context_%i_fulfilled_f", Index = sm_id) return txt
def _get_analyzer_list_for_appendices(AppendixSmList, loop_config, CutSignalLexatomsF): """Parallel state machines are mounted to the loop by cutting the first transition and implementing it in the loop. Upon acceptance of the first character the according tail (appendix) of the state machine is entered. RETURNS: [0] List of appendix state machines in terms of analyzers. [1] Appendix terminals. """ # Appendix Sm Drop Out => Restore position of last loop character. # (i) Couple terminal stored input position in 'LoopRestartP'. # (ii) Terminal 'LoopAfterAppendixDropOut' restores that position. # Accepting on the initial state of an appendix state machine ensures # that any drop-out ends in this restore terminal. for init_state in (sm.get_init_state() for sm in AppendixSmList): if init_state.has_specific_acceptance_id(): continue init_state.set_acceptance() init_state.set_specific_acceptance_id( loop_config.iid_loop_after_appendix_drop_out) # Appendix FSM List return [ analyzer_generator.do( sm, loop_config.engine_type, loop_config.reload_state_extern, OnBeforeReload=loop_config.events.on_before_reload_in_appendix, OnAfterReload=loop_config.events.on_after_reload_in_appendix, dial_db=loop_config.dial_db, CutF=CutSignalLexatomsF) for sm in AppendixSmList ]
def _get_appendix_analyzers(LoopMap, EventHandler, AppendixSmList, IidLoopAfterAppendixDropOut): """Parallel state machines are mounted to the loop by cutting the first transition and implementing it in the loop. Upon acceptance of the first character the according tail (appendix) of the state machine is entered. RETURNS: [0] List of appendix state machines in terms of analyzers. [1] Appendix terminals. """ # Codec Transformation appendix_sm_list = [] for sm in AppendixSmList: if not sm.get_init_state().has_transitions(): continue verdict_f, sm = Setup.buffer_codec.do_state_machine(sm, beautifier) appendix_sm_list.append(sm) # Appendix Sm Drop Out => Restore position of last loop character. # (i) Couple terminal stored input position in 'CharacterBeginP'. # (ii) Terminal 'LoopAfterAppendixDropOut' restores that position. # Accepting on the initial state of an appendix state machine ensures # that any drop-out ends in this restore terminal. for init_state in (sm.get_init_state() for sm in appendix_sm_list): init_state.set_acceptance() init_state.mark_acceptance_id(IidLoopAfterAppendixDropOut) # Appendix Analyzer List return [ analyzer_generator.do(sm, EventHandler.engine_type, EventHandler.reload_state_extern, OnBeforeReload = EventHandler.on_before_reload, OnAfterReload = EventHandler.on_after_reload) for sm in appendix_sm_list ]
def __code_pre_context_state_machine(self): LanguageDB = self.language_db if len(self.pre_context_sm_list) == 0: return [] assert len(self.pre_context_sm.get_orphaned_state_index_list()) == 0 txt = [] if Setup.comment_state_machine_f: LanguageDB.ML_COMMENT(txt, "BEGIN: PRE-CONTEXT STATE MACHINE\n" + \ self.pre_context_sm.get_string(NormalizeF=False) + \ "END: PRE-CONTEXT STATE MACHINE") txt.append( "\n" ) # For safety: New content may have to start in a newline, e.g. "#ifdef ..." analyzer = analyzer_generator.do(self.pre_context_sm, E_EngineTypes.BACKWARD_PRE_CONTEXT) msg = state_machine_coder.do(analyzer) txt.extend(msg) txt.append("\n%s" % LanguageDB.LABEL(E_StateIndices.END_OF_PRE_CONTEXT_CHECK)) # -- set the input stream back to the real current position. # during backward lexing the analyzer went backwards, so it needs to be reset. txt.append(" %s\n" % LanguageDB.INPUT_P_TO_LEXEME_START()) for sm_id in self.pre_context_sm_id_list: variable_db.require("pre_context_%i_fulfilled_f", Index=sm_id) return txt
def __do_state_machine(SmOrSmList, EngineType, dial_db, ReloadStateForward=None, ReverseF=False): """Generates code for state machine 'sm' and the 'EngineType'. RETURNS: list of strings """ assert type(SmOrSmList) == list or len(SmOrSmList.get_orphaned_state_index_list()) == 0 # -- Analyze state machine --> optimized version analyzer = analyzer_generator.do(SmOrSmList, EngineType, ReloadStateExtern = ReloadStateForward, dial_db = dial_db, ReverseF = ReverseF) txt = [] # -- [optional] comment state machine transitions if Setup.comment_state_machine_f: if type(SmOrSmList) != list: SmOrSmList = [ SmOrSmList ] for sm in SmOrSmList: Lng.COMMENT_STATE_MACHINE(txt, sm) # -- Generate code for analyzer txt.extend( do_analyzer(analyzer) ) return txt, analyzer
def __code_main_state_machine(self): assert len(self.sm.get_orphaned_state_index_list()) == 0 LanguageDB = self.language_db txt = [] # -- [optional] comment state machine transitions if Setup.comment_state_machine_f: LanguageDB.ML_COMMENT(txt, "BEGIN: STATE MACHINE\n" + \ self.sm.get_string(NormalizeF=False) + \ "END: STATE MACHINE") txt.append("\n") # For safety: New content may have to start in a newline, e.g. "#ifdef ..." # -- implement the state machine itself analyzer = analyzer_generator.do(self.sm, E_EngineTypes.FORWARD) state_machine_code = state_machine_coder.do(analyzer) txt.extend(state_machine_code) lexeme_null_object_name = "QUEX_NAME(LexemeNullObject)" if Setup.external_lexeme_null_object != "": lexeme_null_object_name = Setup.external_lexeme_null_object # -- terminal states: execution of pattern actions terminal_code = LanguageDB["$terminal-code"](self.state_machine_name, self.action_db, self.on_failure_action, self.on_end_of_stream_action, self.pre_context_sm_id_list, self.language_db, variable_db, self.on_after_match, lexeme_null_object_name) txt.extend(terminal_code) N = len(set(analyzer.position_register_map.values())) if len(analyzer.position_register_map) == 0: variable_db.require("position", Initial = "(void*)0x0", Type = "void*") variable_db.require("PositionRegisterN", Initial = "(size_t)%i" % N) else: variable_db.require_array("position", ElementN = N, Initial = "{ " + ("0, " * (N - 1) + "0") + "}") variable_db.require("PositionRegisterN", Initial = "(size_t)%i" % N) if analyzer.last_acceptance_variable_required(): variable_db.require("last_acceptance") # -- reload definition (forward, backward, init state reload) code = LanguageDB.RELOAD() txt.extend(code) return txt
def __code_main_state_machine(self): assert len(self.sm.get_orphaned_state_index_list()) == 0 LanguageDB = self.language_db txt = [] # -- [optional] comment state machine transitions if Setup.comment_state_machine_f: LanguageDB.ML_COMMENT(txt, "BEGIN: STATE MACHINE\n" + \ self.sm.get_string(NormalizeF=False) + \ "END: STATE MACHINE") txt.append( "\n" ) # For safety: New content may have to start in a newline, e.g. "#ifdef ..." # -- implement the state machine itself analyzer = analyzer_generator.do(self.sm, E_EngineTypes.FORWARD) state_machine_code = state_machine_coder.do(analyzer) txt.extend(state_machine_code) lexeme_null_object_name = "QUEX_NAME(LexemeNullObject)" if Setup.external_lexeme_null_object != "": lexeme_null_object_name = Setup.external_lexeme_null_object # -- terminal states: execution of pattern actions terminal_code = LanguageDB["$terminal-code"]( self.state_machine_name, self.action_db, self.on_failure_action, self.on_end_of_stream_action, self.pre_context_sm_id_list, self.language_db, variable_db, self.on_after_match, lexeme_null_object_name) txt.extend(terminal_code) N = len(set(analyzer.position_register_map.values())) if len(analyzer.position_register_map) == 0: variable_db.require("position", Initial="(void*)0x0", Type="void*") variable_db.require("PositionRegisterN", Initial="(size_t)%i" % N) else: variable_db.require_array("position", ElementN=N, Initial="{ " + ("0, " * (N - 1) + "0") + "}") variable_db.require("PositionRegisterN", Initial="(size_t)%i" % N) if analyzer.last_acceptance_variable_required(): variable_db.require("last_acceptance") # -- reload definition (forward, backward, init state reload) code = LanguageDB.RELOAD() txt.extend(code) return txt
def _get_loop_analyzer(LoopMap, EventHandler): """Construct a state machine that triggers only on one character. Actions according the the triggered character are implemented using terminals which are entered upon acceptance. .------. ---->| Loop | | |----> accept A (normal loop terminals) | |----> accept B | |----> accept C : : : | |----> accept CoupleIncidenceA (couple terminals towards | |----> accept CoupleIncidenceB appendix state machines) | |----> accept CoupleIncidenceC :______: : | else |----> accept iid_loop_exit '------' RETURNS: [0] Loop analyzer (prepared state machine) [1] DoorID of loop entry """ # Loop StateMachine sm = StateMachine.from_IncidenceIdMap( (lei.character_set, lei.incidence_id) for lei in LoopMap ) # Code Transformation verdict_f, sm = Setup.buffer_codec.do_state_machine(sm, beautifier) # Loop Analyzer analyzer = analyzer_generator.do(sm, EventHandler.engine_type, EventHandler.reload_state_extern, OnBeforeReload = EventHandler.on_before_reload, OnAfterReload = EventHandler.on_after_reload, OnBeforeEntry = EventHandler.on_loop_entry) # If reload state is generated # => All other analyzers MUST use the same generated reload state. if EventHandler.reload_state_extern is None: EventHandler.reload_state_extern = analyzer.reload_state # Set the 'Re-Entry' Operations. entry = analyzer.init_state().entry tid_reentry = entry.enter_OpList(analyzer.init_state_index, index.get(), EventHandler.on_loop_reentry) entry.categorize(analyzer.init_state_index) return analyzer, entry.get(tid_reentry).door_id
def _get_loop_analyzer(LoopMap, EventHandler): """Construct a state machine that triggers only on one character. Actions according the the triggered character are implemented using terminals which are entered upon acceptance. .------. ---->| Loop | | |----> accept A (normal loop terminals) | |----> accept B | |----> accept C : : : | |----> accept CoupleIncidenceA (couple terminals towards | |----> accept CoupleIncidenceB appendix state machines) | |----> accept CoupleIncidenceC :______: : | else |----> accept iid_loop_exit '------' RETURNS: [0] Loop analyzer (prepared state machine) [1] DoorID of loop entry """ # Loop StateMachine sm = StateMachine.from_IncidenceIdMap( (lei.character_set, lei.incidence_id) for lei in LoopMap) # Code Transformation verdict_f, sm = Setup.buffer_codec.do_state_machine(sm, beautifier) # Loop Analyzer analyzer = analyzer_generator.do( sm, EventHandler.engine_type, EventHandler.reload_state_extern, OnBeforeReload=EventHandler.on_before_reload, OnAfterReload=EventHandler.on_after_reload, OnBeforeEntry=EventHandler.on_loop_entry) # If reload state is generated # => All other analyzers MUST use the same generated reload state. if EventHandler.reload_state_extern is None: EventHandler.reload_state_extern = analyzer.reload_state # Set the 'Re-Entry' Operations. entry = analyzer.init_state().entry tid_reentry = entry.enter_OpList(analyzer.init_state_index, index.get(), EventHandler.on_loop_reentry) entry.categorize(analyzer.init_state_index) return analyzer, entry.get(tid_reentry).door_id
def get_transition_function(iid_map, Codec): if Codec == "UTF8": Setup.buffer_codec_prepare("utf8", Module=utf8_state_split) else: Setup.buffer_codec_prepare("unicode") cssm = CharacterSetStateMachine(iid_map, MaintainLexemeF=False) analyzer = analyzer_generator.do(cssm.sm, engine.CHARACTER_COUNTER) tm_txt = do_analyzer(analyzer) tm_txt = Lng.GET_PLAIN_STRINGS(tm_txt) tm_txt.append("\n") label = dial_db.get_label_by_door_id(DoorID.incidence(E_IncidenceIDs.MATCH_FAILURE)) for character_set, iid in iid_map: tm_txt.append("%s return (int)%s;\n" % (Lng.LABEL(DoorID.incidence(iid)), iid)) tm_txt.append("%s return (int)-1;\n" % Lng.LABEL(DoorID.drop_out(-1))) return "".join(tm_txt)
def __code_backward_input_position_detection_core(self, SM): assert len(SM.get_orphaned_state_index_list()) == 0 txt = [] if Setup.comment_state_machine_f: Setup.language_db.ML_COMMENT(txt, "BEGIN: BACKWARD DETECTOR STATE MACHINE\n" + \ SM.get_string(NormalizeF=False) + \ "\nEND: BACKWARD DETECTOR STATE MACHINE") txt.append("\n") analyzer = analyzer_generator.do(SM, E_EngineTypes.BACKWARD_INPUT_POSITION) function_body = state_machine_coder.do(analyzer) txt.extend(function_body) return txt
def _get_analyzer_for_loop(loop_sm, loop_config, CutSignalLexatomsF): """Construct a state machine that triggers only on one character. Actions according the the triggered character are implemented using terminals which are entered upon acceptance. .------. ---->| Loop | | |----> accept A (normal loop terminals) | |----> accept B | |----> accept C : : : | |----> accept CoupleIncidenceA (couple terminals towards | |----> accept CoupleIncidenceB appendix state machines) | |----> accept CoupleIncidenceC :______: : | else |----> accept iid_loop_exit '------' RETURNS: [0] Loop analyzer (prepared state machine) [1] DoorID of loop entry """ # Loop FSM analyzer = analyzer_generator.do( loop_sm, loop_config.engine_type, loop_config.reload_state_extern, OnBeforeReload=loop_config.events.on_before_reload, OnAfterReload=loop_config.events.on_after_reload, OnBeforeEntry=loop_config.events.on_loop_entry, dial_db=loop_config.dial_db, OnReloadFailureDoorId=loop_config.door_id_on_reload_failure, CutF=CutSignalLexatomsF) # If reload state is generated # => All other analyzers MUST use the same generated reload state. if loop_config.reload_state_extern is None: loop_config.reload_state_extern = analyzer.reload_state # Set the 'Re-Entry' Operations. entry = analyzer.init_state().entry tid_reentry = entry.enter_OpList(analyzer.init_state_index, index.get(), loop_config.events.on_loop_reentry) entry.categorize(analyzer.init_state_index) return analyzer, entry.get(tid_reentry).door_id
def get_transition_function(iid_map, Codec): if Codec == "UTF8": Setup.buffer_codec_set(bc_factory.do("utf8"), 1) else: Setup.buffer_codec_set(bc_factory.do("unicode"), -1) sm = StateMachine.from_IncidenceIdMap(iid_map) dummy, sm = Setup.buffer_codec.do_state_machine(sm, beautifier) analyzer = analyzer_generator.do(sm, engine.CHARACTER_COUNTER) tm_txt = do_analyzer(analyzer) tm_txt = Lng.GET_PLAIN_STRINGS(tm_txt) tm_txt.append("\n") #label = dial_db.get_label_by_door_id(DoorID.incidence(E_IncidenceIDs.MATCH_FAILURE)) for character_set, iid in iid_map: tm_txt.append("%s return (int)%s;\n" % (Lng.LABEL(DoorID.incidence(iid)), iid)) tm_txt.append("%s return (int)-1;\n" % Lng.LABEL(DoorID.drop_out(-1))) return "".join(tm_txt)
def do_state_machine(sm, EngineType): """Generates code for state machine 'sm' and the 'EngineType'. RETURNS: list of strings """ assert len(sm.get_orphaned_state_index_list()) == 0 txt = [] # -- [optional] comment state machine transitions if Setup.comment_state_machine_f: Lng.COMMENT_STATE_MACHINE(txt, sm) # -- Analyze state machine --> optimized version analyzer = analyzer_generator.do(sm, EngineType) # -- Generate code for analyzer txt.extend(do_analyzer(analyzer)) return txt, analyzer
def get_transition_function(iid_map, Codec): if Codec == "UTF8": Setup.buffer_codec_prepare("utf8", Module=utf8_state_split) else: Setup.buffer_codec_prepare("unicode") cssm = CharacterSetStateMachine(iid_map, MaintainLexemeF=False) analyzer = analyzer_generator.do(cssm.sm, engine.CHARACTER_COUNTER) tm_txt = do_analyzer(analyzer) tm_txt = Lng.GET_PLAIN_STRINGS(tm_txt) tm_txt.append("\n") label = dial_db.get_label_by_door_id( DoorID.incidence(E_IncidenceIDs.MATCH_FAILURE)) for character_set, iid in iid_map: tm_txt.append("%s return (int)%s;\n" % (Lng.LABEL(DoorID.incidence(iid)), iid)) tm_txt.append("%s return (int)-1;\n" % Lng.LABEL(DoorID.drop_out(-1))) return "".join(tm_txt)
def do_state_machine(sm, EngineType): """Generates code for state machine 'sm' and the 'EngineType'. RETURNS: list of strings """ assert len(sm.get_orphaned_state_index_list()) == 0 txt = [] # -- [optional] comment state machine transitions if Setup.comment_state_machine_f: Lng.COMMENT_STATE_MACHINE(txt, sm) # -- Analyze state machine --> optimized version analyzer = analyzer_generator.do(sm, EngineType) # -- Generate code for analyzer txt.extend( do_analyzer(analyzer) ) return txt, analyzer
def get_transition_function(iid_map, Codec): global dial_db if Codec == "UTF8": Setup.buffer_setup("uint8_t", 1, "utf8") else: Setup.buffer_setup("uint32_t", 4, "none") Setup.bad_lexatom_detection_f = False sm = DFA.from_IncidenceIdMap(iid_map) analyzer = analyzer_generator.do(sm, engine.CHARACTER_COUNTER, dial_db=dial_db, CutF=False) tm_txt = do_analyzer(analyzer) tm_txt = Lng.GET_PLAIN_STRINGS(tm_txt, dial_db=dial_db) tm_txt.append("\n") #label = dial_db.get_label_by_door_id(DoorID.incidence(E_IncidenceIDs.MATCH_FAILURE)) for character_set, iid in iid_map: tm_txt.append("%s return (int)%s;\n" % (Lng.LABEL(DoorID.incidence(iid, dial_db)), iid)) tm_txt.append("%s return (int)-1;\n" % Lng.LABEL(DoorID.drop_out(-1, dial_db))) return "".join(tm_txt)
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: CommandList0 +------+ | i1 |----------> Terminal1: CommandList1 +------+ | X2 |----------> Terminal Beyond: input_p--; goto TerminalExit; +------+ | i2 |----------> Terminal2: CommandList2 +------+ """ 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_CountCmdFactory( CcFactory, LexemeMaintainedF, ParallelSmList=parallel_sm_list) analyzer = analyzer_generator.do( CsSm.sm, EngineType, ReloadStateExtern, OnBeforeReload=CommandList.from_iterable(CsSm.on_before_reload), OnAfterReload=CommandList.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 [GotoDoorId(door_id_loop)] # # .---------------. ,----------. no # --->| Count Command |-------< LexemeEnd? >------> DoorIdOk # '---------------' '----+-----' # | yes # .---------------. # | Lexeme End | # | Count Command |----> DoorIdOnLexemeEnd # '---------------' # elif ccfactory.requires_reference_p( ) and CC_Type == E_CharacterCountType.COLUMN: return [ GotoDoorIdIfInputPNotEqualPointer(door_id_loop, E_R.LexemeEnd), ColumnCountReferencePDeltaAdd( E_R.InputP, ccfactory.column_count_per_chunk, False), ] + AfterBeyond else: return [ 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)