Beispiel #1
0
    def do_end_of_stream(self, Code, ThePattern):
        """End of Stream: The terminating zero has been reached and no further
        content can be loaded.
        """
        lexeme_begin_f,     \
        terminating_zero_f, \
        adorned_code        = self.__adorn_user_code(Code, MatchF=True)

        # No indentation handler => Empty string.
        text = [
            Lng.DEFAULT_COUNTER_CALL(),
            self.txt_indentation_handler_call,
            #
            adorned_code,
            #
            Lng.ML_COMMENT(
                "End of Stream FORCES a return from the lexical analyzer, so that no\n"
                "tokens can be filled after the termination token."),
            Lng.GOTO(DoorID.return_with_on_after_match()),
        ]

        code = CodeTerminal(text,
                            SourceReference=Code.sr,
                            PureCode=Code.get_pure_code())
        return Terminal(code, "END_OF_STREAM")
Beispiel #2
0
def get(ThePattern, ShiftF=True):
    """Line and column number actions for a pattern.

    Generates code to adapt line and column number counters when a pattern
    has matched. It tries to do as much as possible beforehand. That is, if
    the line and column increments are determined from the pattern structure
    it produces very simple and fast instructions.

    This function assumes that the 'count_info' for a pattern has been
    determined before, based on the 'counted_db'.
    
    If the adaption of line and column numbers cannot be derived from the 
    pattern itself or the lexeme length, then a call to the 'default_counter'
    is implemented. 

    ---------------------------------------------------------------------------

    RETURN: Verdict, CounterCode

        Verdict == True  --> Pattern requires run-time counting. Default
                             counter implementation required.
                   False --> It was possible to determine the increments
                             based on the pattern's structure. Non run-
                             time counting is necessary.

        CounterCode = Code to be prefixed in from of the action.
    ---------------------------------------------------------------------------
    
    The increment of line number and column number may be determined by
    'ThePattern' itself. For example the pattern "\n\n" increments the line
    number always by 2. The pattern "\n+" however increments the line number
    depending on how many '\n' it matches at runtime. These considerations
    where done by means of 

      quex.engine.state_machine.character_counter.CountInfo.from_StateMachine(...)

    It is called inside the 'prepare_count_info()' member function of the
    pattern at the time when it is communicated to the 'Mode' object from the
    'ModeDescription' object in:

              quex.input.files.mode.Mode.__init__(...)

    As a consequence of a call to '.prepare_count_info()', the pattern's 'count'
    object must be set to something not 'None'. If it is 'None', this means
    that the 'prepare_count_info()' function has not been called for it.  
    ---------------------------------------------------------------------------
    """
    
    assert type(ShiftF) == bool

    # (*) Trivial Cases _______________________________________________________
    if ThePattern.incidence_id() == E_IncidenceIDs.END_OF_STREAM:
        if ShiftF: return False, ["__QUEX_IF_COUNT_SHIFT_VALUES();\n" ]
        else:      return False, []

    if ThePattern is None:
        # 'on_failure' ... count any appearing character
        return True, [ Lng.DEFAULT_COUNTER_CALL() ]

    return do_CountInfo(ThePattern.count_info(), ShiftF)
Beispiel #3
0
    def get_counter_text(self, ThePattern):
        """Get the text of the source code required for 'counting'. This information
        has been stored along with the pattern before any transformation happened.
        No database or anything is required as this point.
        """
        if ThePattern is None:
            default_counter_f = True
            text = Lng.DEFAULT_COUNTER_CALL()
        else:
            default_counter_f, \
            text               = counter_for_pattern.get(ThePattern)

        self.required_default_counter_f |= default_counter_f
        return "".join(Lng.REPLACE_INDENT(text))
Beispiel #4
0
 def __terminate_analysis_step(self, Code, Name, Comment):
     lexeme_begin_f,     \
     terminating_zero_f, \
     adorned_code        = self.__adorn_user_code(Code, MatchF=True)
     
     # No indentation handler => Empty string.
     text = [ 
         Lng.DEFAULT_COUNTER_CALL(),
         self.txt_indentation_handler_call,
         #
         adorned_code,
         #
         Lng.ML_COMMENT(Comment),
         Lng.GOTO(DoorID.return_with_on_after_match()),
     ]
     return self.__terminal(text, Code, Name)
Beispiel #5
0
def get(CaMap, ModeName):
    """Implement the default counter for a given Counter Database. 

    In case the line and column number increment cannot be determined before-
    hand, a something must be there that can count according to the rules given
    in 'CaMap'. This function generates the code for a general counter
    function which counts line and column number increments starting from the
    begin of a lexeme to its end.

    The implementation of the default counter is a direct function of the
    'CaMap', i.e. the database telling how characters influence the
    line and column number counting. 
    
    Multiple modes may have the same character counting behavior. If so, 
    then there's only one counter implemented while others refer to it. 

    ---------------------------------------------------------------------------
    
    RETURNS: function_name, string --> Function name and the implementation 
                                       of the character counter.
             function_name, None   --> The 'None' implementation indicates that
                                       NO NEW counter is implemented. An 
                                       appropriate counter can be accessed 
                                       by the 'function name'.
    ---------------------------------------------------------------------------
    """
    if not (Setup.count_line_number_f or Setup.count_column_number_f):
        return ""

    dial_db = DialDB()

    mode_with_same_counter = DefaultCounterFunctionDB.get_mode_name(CaMap)
    if mode_with_same_counter is not None:
        # Use previously done implementation for this 'CaMap'
        return __frame(Lng.DEFAULT_COUNTER_FUNCTION_NAME(ModeName), 
                       [ Lng.DEFAULT_COUNTER_CALL(mode_with_same_counter) ], 
                       None, None, None)

    door_id_return = dial_db.new_door_id()

    analyzer_list,           \
    terminal_list,           \
    dummy_loop_map,          \
    dummy_door_id_loop,      \
    required_register_set,   \
    dummy_run_time_counter_f = loop.do(CaMap, 
                                       OnLoopExitDoorId   = door_id_return,
                                       LexemeEndCheckF    = True,
                                       EngineType         = engine.CHARACTER_COUNTER, 
                                       dial_db            = dial_db,
                                       ModeName           = ModeName, 
                                       CutSignalLexatomsF = False)

    code = generator.do_analyzer_list(analyzer_list)

    code.extend(
        generator.do_terminals(terminal_list, TheAnalyzer=None, dial_db=dial_db)
    )

    variable_db.require_registers(required_register_set)
    implementation = __frame(Lng.DEFAULT_COUNTER_FUNCTION_NAME(ModeName), code, 
                             Lng.INPUT_P(), door_id_return, dial_db) 

    DefaultCounterFunctionDB.enter(CaMap, ModeName)

    return implementation
Beispiel #6
0
def do_CountInfo(counter, ShiftF=True):
    # (*) Default Character Counter ___________________________________________
    #
    #     Used when the increments and/or setting cannot be derived from the 
    #     pattern itself. That is, if one of the following is VOID:
    if    (    counter.line_n_increment_by_lexeme_length   == E_Count.VOID \
           and counter.line_n_increment                    == E_Count.VOID)\
       or (    counter.column_n_increment_by_lexeme_length == E_Count.VOID \
           and counter.column_n_increment                  == E_Count.VOID \
           and counter.column_index                        == E_Count.VOID \
           and counter.grid_step_size_by_lexeme_length     == E_Count.VOID):
        return True, [ Lng.DEFAULT_COUNTER_CALL() ]

    # (*) Determine Line and Column Number Count ______________________________
    #    
    #     Both, for line and column number considerations the same rules hold.
    #     Those rules are defined in 'get_increment()' as shown below.
    #
    def get_increment(txt, Increment, IncrementByLexemeLength, HelpStr):
        if IncrementByLexemeLength == 0 or Increment == 0:
            return 
        elif Increment != E_Count.VOID:
            arg = Lng.VALUE_STRING(Increment)
        else:
            arg = Lng.MULTIPLY_WITH("LexemeL", IncrementByLexemeLength)

        txt.append("__QUEX_IF_COUNT_%s_ADD(%s);\n" % (HelpStr, arg))

    # Column and line counts must be shifted (begin=end) even if only
    # columns are counted. For example, even if only columns are modified
    # the old line_number_at_begin must be adapted to the current.
    if ShiftF: txt = ["__QUEX_IF_COUNT_SHIFT_VALUES();\n" ]
    else:      txt = []

    # -- Line Number Count
    get_increment(txt, counter.line_n_increment, 
                  counter.line_n_increment_by_lexeme_length, 
                  "LINES")

    # -- Column Number Count
    if  counter.column_index != E_Count.VOID:
        txt.append("__QUEX_IF_COUNT_COLUMNS_SET(%i);\n" % (counter.column_index + 1))

    elif counter.column_n_increment_by_lexeme_length != E_Count.VOID:
        get_increment(txt, counter.column_n_increment, 
                      counter.column_n_increment_by_lexeme_length, 
                      "COLUMNS")

    else:
        # Following assert results from entry check against 'VOID'
        assert counter.grid_step_size_by_lexeme_length != E_Count.VOID

        if   counter.grid_step_n == E_Count.VOID: 
            grid_step_n = "LexemeL"
        elif counter.grid_step_n != 0:
            grid_step_n = counter.grid_step_n
        else:
            grid_step_n = None

        if grid_step_n is not None:
            txt.extend(Lng.GRID_STEP("self.counter._column_number_at_end", "size_t",
                                            counter.grid_step_size_by_lexeme_length, 
                                            grid_step_n, IfMacro="__QUEX_IF_COUNT_COLUMNS"))
            txt.append("\n")

    return False, txt