예제 #1
0
def do(the_state_machine, min_repetition_n=0, max_repetition_n=-1):
    """ Creates a state machine that represents a repetition of the given 
        'the_state_machine'. Minimum and maximim number of repetitions can be specified.
    """
    assert min_repetition_n <= max_repetition_n or max_repetition_n == -1

    def clone_n(SM, N):
        return [SM.clone() for i in range(N)]

    # (*) if minimum number of repetitions is required, then the initial
    #     repetition is produced by sequentialization.
    initial_state_machine = None
    if min_repetition_n != 0:
        # Concatinate the state machine N times, at the beginning, so that
        # there are N repetitions at least. Any 'bail out' before the first N
        # repetitions happen from a 'non-acceptance' state => fail. Only, when
        # the first N repetitions happend, the state machines enters into the
        # following 'repetition states'.
        # NOTE: sequentialize clones the given state machines
        sm_list = clone_n(the_state_machine, min_repetition_n)
        initial_state_machine = sequentialize.do(sm_list)

    if max_repetition_n != -1:
        # if a maximum number of repetitions is given, then the state machine needs
        # to be repeated 'physically'. No new 'repeated' version of the state machine
        # is computed.
        # NOTE: sequentialize clones the given state machines
        if initial_state_machine is not None:
            sm_list = [initial_state_machine]
            sm_list.extend(
                clone_n(the_state_machine,
                        (max_repetition_n - min_repetition_n)))
            return sequentialize.do(sm_list,
                                    LeaveIntermediateAcceptanceStatesF=True)
        else:
            sm_list = clone_n(the_state_machine, max_repetition_n)
            concatenation = sequentialize.do(
                sm_list, LeaveIntermediateAcceptanceStatesF=True)
            # Here, zero initial repetitions are required, thus the initial state must be
            # an acceptance state.
            concatenation.states[
                concatenation.init_state_index].set_acceptance(True)
            return concatenation
    else:
        # (*) clone the state machine
        #     NOTE: kleene_closure() clones the state machine.
        pure_repetition = kleene_closure(the_state_machine)
        if initial_state_machine is not None:
            sm_list = [initial_state_machine, pure_repetition]
            return sequentialize.do(sm_list,
                                    LeaveIntermediateAcceptanceStatesF=True)
        else:
            return pure_repetition
예제 #2
0
파일: engine.py 프로젝트: mplucinski/quex
def snap_term(stream, PatternDict):
    """term:  primary
              primary term 
    """
    __debug_entry("term", stream)    

    # -- primary
    result = snap_primary(stream, PatternDict) 
    __debug_print("##primary(in term):", result)
    if result is None: return __debug_exit(None, stream)
    position_1 = stream.tell()

    # -- optional 'term' 
    result_2 = snap_term(stream, PatternDict) 
    __debug_print("##term(in term):",  result_2)
    if result_2 is None: 
        stream.seek(position_1)
        return __debug_exit(result, stream)
    
    ## print "##1:", result.get_string(NormalizeF=False)
    ## print "##2:", result_2.get_string(NormalizeF=False)
    result = sequentialize.do([result, result_2], 
                              MountToFirstStateMachineF=True, 
                              CloneRemainingStateMachinesF=False)    

    return __debug_exit(beautifier.do(result), stream)
예제 #3
0
파일: engine.py 프로젝트: nyulacska/gpr
def snap_term(stream, PatternDict):
    """term:  primary
              primary term 
    """
    __debug_entry("term", stream)

    # -- primary
    result = snap_primary(stream, PatternDict)
    __debug_print("##primary(in term):", result)
    if result is None: return __debug_exit(None, stream)
    position_1 = stream.tell()

    # -- optional 'term'
    result_2 = snap_term(stream, PatternDict)
    __debug_print("##term(in term):", result_2)
    if result_2 is None:
        stream.seek(position_1)
        return __debug_exit(result, stream)

    ## print "##1:", result.get_string(NormalizeF=False)
    ## print "##2:", result_2.get_string(NormalizeF=False)
    result = sequentialize.do([result, result_2],
                              MountToFirstStateMachineF=True,
                              CloneRemainingStateMachinesF=False)

    return __debug_exit(beautifier.do(result), stream)
예제 #4
0
def do(the_state_machine, pre_context_sm, BeginOfLinePreContextF):
    """Sets up a pre-condition to the given state machine. This process
       is entirely different from any sequentializing or parallelization
       of state machines. Here, the state machine representing the pre-
       condition is **not** webbed into the original state machine!

       Instead, the following happens:

          -- the pre-condition state machine is inverted, because
             it is to be walked through backwards.
          -- the inverted state machine is marked with the state machine id
             of the_state_machine.        
          -- the original state machine will refer to the inverse
             state machine of the pre-condition.
          -- the initial state origins and the origins of the acceptance
             states are marked as 'pre-conditioned' indicating the id
             of the inverted state machine of the pre-condition.             
    """
    #___________________________________________________________________________________________
    # (*) do some consistency checking   
    # -- state machines with no states are senseless here. 
    assert not the_state_machine.is_empty() 
    assert pre_context_sm is None or not pre_context_sm.is_empty()
    # -- trivial pre-conditions should be added last, for simplicity

    #___________________________________________________________________________________________
    if pre_context_sm is None:
        # NOT: 'and ...' !
        if BeginOfLinePreContextF:
            # Mark all acceptance states with the 'trivial pre-context BeginOfLine' flag
            for state in the_state_machine.get_acceptance_state_list():
                state.set_pre_context_id(E_PreContextIDs.BEGIN_OF_LINE)
        return None

    # (*) Reverse the state machine of the pre-condition 
    reverse_pre_context = reverse.do(pre_context_sm)
        
    if BeginOfLinePreContextF:
        # Extend the existing pre-context with a preceeding 'begin-of-line'.
        reverse_newline_sm  = reverse.do(StateMachine_Newline())
        reverse_pre_context = sequentialize.do([reverse_pre_context, 
                                                reverse_newline_sm])

    # (*) Once an acceptance state is reached no further analysis is necessary.
    acceptance_pruning.do(reverse_pre_context)

    # (*) Clean up what has been done by inversion (and optionally 'BeginOfLinePreContextF')
    #     AFTER acceptance_pruning (!)
    reverse_pre_context = beautifier.do(reverse_pre_context)

    # (*) let the state machine refer to it 
    #     [Is this necessary? Is it not enough that the acceptance origins point to it? <fschaef>]
    pre_context_sm_id = reverse_pre_context.get_id()

    # (*) Associate acceptance with pre-context id. 
    for state in the_state_machine.get_acceptance_state_list():
        state.set_pre_context_id(pre_context_sm_id)
    
    return reverse_pre_context
예제 #5
0
def _prepare_indentation_counter(ModeName, OptionsDb, CounterDb, IncidenceDb, MHI):
    """Prepare indentation counter. An indentation counter is implemented by 
    the following:

    'newline' pattern --> triggers as soon as an UNSUPPRESSED newline occurs. 
                      --> entry to the INDENTATION COUNTER.

    'suppressed newline' --> INDENTATION COUNTER is NOT triggered.
     
    The supressed newline pattern is longer (and has precedence) over the
    newline pattern. With the suppressed newline it is possible to write
    lines which overstep the newline (see backslahs in Python, for example).

    RETURNS: List of:
             [0] newline PPT and
             [1] optionally the PPT of the newline suppressor.

    The primary pattern action pair list is to be the head of all pattern
    action pairs.

    MHI = Mode hierarchie index defining the priority of the current mode.
    """
    ISetup = OptionsDb.value("indentation")
    if ISetup is None: return [], []

    check_indentation_setup(ISetup)

    if ISetup.sm_newline_suppressor.get() is not None:
        sm_suppressed_newline = sequentialize.do([ISetup.sm_newline_suppressor.get(),
                                                  ISetup.sm_newline.get()])
        sm_suppressed_newline = beautifier.do(sm_suppressed_newline)
    else:
        sm_suppressed_newline = None

    data = { 
        "counter_db":                    CounterDb,
        "indentation_setup":             ISetup,
        "incidence_db":                  IncidenceDb,
        "default_indentation_handler_f": IncidenceDb.default_indentation_handler_f(),
        "mode_name":                     ModeName,
        "sm_suppressed_newline":         sm_suppressed_newline,
    }

    ppt_list = [
        # 'newline' triggers --> indentation counter
        PPT_indentation_handler_newline(MHI, data, ISetup, CounterDb)
    ]

    if sm_suppressed_newline is not None:
        ppt_list.append(
            # 'newline-suppressor' followed by 'newline' is ignored (skipped)
            PPT_indentation_handler_suppressed_newline(MHI, 
                                                       sm_suppressed_newline)
        )

    return [], ppt_list
예제 #6
0
def more_DFAs(A, B):
    """RETURNS: [0] B+
                [1] B*
                [2] B*A
    """
    B_plus = repeat.do(B)
    B_star = repeat.do(B, min_repetition_n=0)
    B_star_A = beautifier.do(sequentialize.do([B_star, A]))
    return beautifier.do(B_plus), \
           beautifier.do(B_star), \
           B_star_A
예제 #7
0
def do(SM_A, SM_B):
    """\NotIn{P Q} = \NotBegin{P \Any*(Q+)}
    """
    all_star      = repeat.do(special.get_any(), min_repetition_n=0)
    sm_b_repeated = repeat.do(SM_B, min_repetition_n=1)

    tmp = sequentialize.do([all_star, sm_b_repeated], 
                           MountToFirstStateMachineF=True, 
                           CloneRemainingStateMachinesF=True)

    tmp = beautifier.do(tmp)

    # There might be many paths which have no hope to reach acceptance
    tmp.clean_up()

    return complement_begin.do(SM_A, tmp)
예제 #8
0
def do(SM_A, SM_B):
    """\NotIn{P Q} = \NotBegin{P \Any*(Q+)}
    """
    all_star = repeat.do(special.get_any(), min_repetition_n=0)
    sm_b_repeated = repeat.do(SM_B, min_repetition_n=1)

    tmp = sequentialize.do([all_star, sm_b_repeated],
                           MountToFirstStateMachineF=True,
                           CloneRemainingStateMachinesF=True)

    tmp = beautifier.do(tmp)

    # There might be many paths which have no hope to reach acceptance
    tmp.clean_up()

    return complement_begin.do(SM_A, tmp)
예제 #9
0
def _do(dfa, post_context_dfa, EndOfLinePostContextF, EndOfStreamPostContextF,
        SourceReference):
    """Appends a post context to the given state machine and changes 
       state infos as required. 

       NOTE: 

           In case that:    post_context_dfa is not None 
                         or EndOfLinePostContextF  

           The function appends something to the state machine and it is
           therefore required to pass 'NFA to DFA'--better also Hopcroft
           Minimization.
       
       ________________________________________________________________________
       This process is very similar to sequentialization. 
       There is a major difference, though:
       
       Given a state machine (e.g. a pattern) X with a post context Y, 
       a match is only valid if X is followed by Y. Let Xn be an acceptance
       state of X and Ym an acceptance state of Y: 

              ---(Xn-1)---->(Xn)---->(Y0)----> ... ---->((Ym))
                            store                       acceptance
                            input
                            position
       
       That is, it holds:

          -- The next input position is stored the position of Xn, even though
             it is 'officially' not an acceptance state.

          -- Ym will be an acceptance state, but it will not store 
             the input position!       

       The analysis of the next pattern will start at the position where
       X stopped, even though Ym is required to state acceptance.    
       
    """
    __entry_asserts(dfa, post_context_dfa)

    if post_context_dfa is None: post_context_dfa = None
    else: post_context_dfa = post_context_dfa.clone()

    # A post context with an initial state that is acceptance is not really a
    # 'context' since it accepts anything. The state machine remains un-post context.
    if     post_context_dfa is not None \
       and post_context_dfa.get_init_state().is_acceptance():
        error.warning(
            "Post context accepts anything--replaced by no post context.",
            SourceReference)
        post_context_dfa = None

    if EndOfLinePostContextF:
        if post_context_dfa is None:
            where_to_setup_eos_state_index_list = dfa.get_acceptance_state_index_list(
            )
            post_context_dfa = DFA_Newline()
        else:
            where_to_setup_eos_state_index_list = post_context_dfa.get_acceptance_state_index_list(
            )
            post_context_dfa = sequentialize.do(
                [post_context_dfa, DFA_Newline()],
                MountToFirstStateMachineF=True)
    else:
        where_to_setup_eos_state_index_list = dfa.get_acceptance_state_index_list(
        )

    if post_context_dfa is None:
        # -- Solely 'End-Of-Stream' post contexts (done at end of function)
        #
        bipd_sm_to_be_reversed = None

    elif ambiguous_post_context.detect_forward(dfa, post_context_dfa):
        # -- Seldom Exception:
        #    Pseudo-Ambiguous Post Conditions (x+/x) -- detecting the end of the
        #    core pattern after the end of the post context
        #    has been reached.
        #
        if ambiguous_post_context.detect_backward(dfa, post_context_dfa):
            # -- for post contexts that are forward and backward ambiguous
            #    a philosophical cut is necessary.
            error.warning(
                "Post context requires philosophical cut--handle with care!\n"
                "Proposal: Isolate pattern and ensure results are as expected!",
                SourceReference)
            post_context_dfa = ambiguous_post_context.philosophical_cut(
                dfa, post_context_dfa)

        # NOTE: May be, dfa does contain now an epsilon transition. See
        #       comment at entry of this function.
        bipd_sm_to_be_reversed = ambiguous_post_context.mount(
            dfa, post_context_dfa)

    else:
        # -- The 'normal' way: storing the input position at the end of the core
        #    pattern.
        #
        # (*) Need to clone the state machines, i.e. provide their internal
        #     states with new ids, but the 'behavior' remains. This allows
        #     state machines to appear twice, or being used in 'larger'
        #     conglomerates.

        # (*) collect all transitions from both state machines into a single one
        #
        #     NOTE: The start index is unique. Therefore, one can assume that each
        #           clone_list '.states' dictionary has different keys. One can simply
        #           take over all transitions of a start index into the result without
        #           considering interferences (see below)
        #
        orig_acceptance_state_id_list = dfa.get_acceptance_state_index_list()

        # -- mount on every acceptance state the initial state of the following state
        #    machine via epsilon transition
        dfa.mount_to_acceptance_states(post_context_dfa.init_state_index,
                                       CancelStartAcceptanceStateF=True)

        dfa.states.update(post_context_dfa.states)  # states are already cloned

        # -- raise at each old acceptance state the 'store input position flag'
        # -- set the post context flag for all acceptance states
        for state_idx in orig_acceptance_state_id_list:
            state = dfa.states[state_idx]
            state.set_read_position_store_f(True)

        # -- no acceptance state shall store the input position
        # -- set the post context flag for all acceptance states
        for state in dfa.get_acceptance_state_list():
            state.set_read_position_store_f(False)
            state.set_read_position_restore_f(True)

        bipd_sm_to_be_reversed = None

    if EndOfStreamPostContextF:
        for si in where_to_setup_eos_state_index_list:
            state = dfa.states[si]
            state.set_acceptance()
            state.set_acceptance_condition_id(
                E_AcceptanceCondition.END_OF_STREAM)

    # No input position backward search required
    return beautifier.do(dfa), bipd_sm_to_be_reversed
예제 #10
0
def mount(the_state_machine, PostConditionSM):
    """This function mounts a post condition to a state machine with
       a mechanism that is able to handle the pseudo ambigous post-
       condition. Note, that this mechanism can also treat 'normal'
       post-conditions. However, it is slightly less efficient.

                core-        post-    
           -----0000000000000111111111--------------

       (1)      |-------------------->
                                     acceptance

       (2)                   <-------|
                             reset input position

       The first step is performed by 'normal' lexing. The second step
       via the backward detector, which is basically an inverse state
       machine of the post-condition.

       NOTE: This function does **not** return a state machine that is
             necessarily deterministic. Run nfa_to_dfa on the result
             of this function.

       NOTE: This function is very similar to the function that mounts
             a pre-condition to a state machine. The only major difference
             is that the post condition is actually webbed into the 
             state machine for forward lexing. For backward lexing
             a reference is stored that points to the backward detecting
             state machine.
    """
    assert the_state_machine.__class__.__name__ == "DFA"
    assert PostConditionSM.__class__.__name__ == "DFA"
    # -- state machines with no states are senseless here.
    assert not the_state_machine.is_Empty()
    assert not PostConditionSM.is_Empty()

    # -- trivial pre-conditions should be added last, for simplicity
    # (*) concatinate the two state machines:
    #   -- deletes acceptance states of the core pattern
    #   -- leaves acceptance states of the post condition
    sequentialize.do([the_state_machine, PostConditionSM],
                     MountToFirstStateMachineF=True)

    # (*) The Backward Input Position detector CANNOT be inverted here.
    #     The inversion may depend on the input codec(!). So, it is
    #     done just before code generation.
    bipd_sm_to_be_reversed = PostConditionSM.clone()
    ## DOES NOT WORK: stem_and_branches.prune_branches(backward_detector_sm)

    # NOTE: We do not need to mark any origins in the backward detector,
    #       since it is not concerned with acceptance states. Its only
    #       task is to reset the input stream.
    # NOTE: It is not necessary that the state machine directly refers to
    #       the backward detector. The origins of the acceptance state will do so.
    assert the_state_machine.get_acceptance_state_list(), \
            "error: mounting pseudo-ambiguous post condition:\n" + \
            "error: no acceptance state in sequentialized state machine."

    # We cannot do a NFA to DFA and Hopcroft Optimization, because otherwise we
    # would create a new state machine. This function, though, is considered to
    # 'mount' something on an existing state machine, i.e. change the object
    # that is referenced by the first function argument 'the_state_machine'.
    return bipd_sm_to_be_reversed
예제 #11
0
#! /usr/bin/env python
import sys
import os

sys.path.insert(0, os.environ["QUEX_PATH"])

from quex.engine.state_machine.core import *
import quex.engine.state_machine.construction.sequentialize as sequentialize
from quex.engine.state_machine.TEST.test_state_machines import *

if "--hwut-info" in sys.argv:
    print "StateMachine Operations: Sequence"
    sys.exit(0)

empty_state_machine = StateMachine(7777)
print "##sm0", sm0
print "##sm1", sm1
print "##sm2", sm2
sm = sequentialize.do([
    empty_state_machine, sm0, empty_state_machine, sm1, empty_state_machine,
    sm2, empty_state_machine
])

print "-------------------------------------------------------------------------------"
print "##result = ", sm
예제 #12
0
def core(P, Q):
    Q_star, Q_plus = unary_checks(Q, __operation)

    Q_star_P = beautifier.do(sequentialize.do([Q_star, P]))
    return __binary_checks(P, Q, Q_plus, Q_star_P)
예제 #13
0
def do(the_state_machine, pre_context_sm, BeginOfLinePreContextF,
       BeginOfStreamPreContextF):
    """Sets up a pre-condition to the given state machine. This process
       is entirely different from any concatenation or parallelization
       of state machines. Here, the state machine representing the pre-
       condition is **not** webbed into the original state machine!

       Instead, the following happens:

          -- the pre-condition state machine is inverted, because
             it is to be walked through backwards.
          -- the inverted state machine is marked with the state machine id
             of the_state_machine.        
          -- the original state machine will refer to the inverse
             state machine of the pre-condition.
          -- the initial state origins and the origins of the acceptance
             states are marked as 'pre-conditioned' indicating the id
             of the inverted state machine of the pre-condition.             
    """
    #___________________________________________________________________________________________
    # (*) do some consistency checking
    # -- state machines with no states are senseless here.
    assert not the_state_machine.is_Empty()
    assert pre_context_sm is None or not pre_context_sm.is_Empty()
    # -- trivial pre-conditions should be added last, for simplicity

    #___________________________________________________________________________________________
    if pre_context_sm is None:
        # NOT: 'and ...' !
        if BeginOfLinePreContextF:
            # Set acceptance condition: 'begin of line'.
            for state in the_state_machine.get_acceptance_state_list():
                state.set_acceptance_condition_id(
                    E_AcceptanceCondition.BEGIN_OF_LINE)
        if BeginOfStreamPreContextF:
            # Set acceptance condition: 'begin of stream'.
            for state in the_state_machine.get_acceptance_state_list():
                state.set_acceptance_condition_id(
                    E_AcceptanceCondition.BEGIN_OF_STREAM)
        return None

    if BeginOfLinePreContextF:
        new_pre_context_sm = DFA_Newline()
        sequentialize.do([new_pre_context_sm, pre_context_sm],
                         MountToFirstStateMachineF=True)
        pre_context_sm = beautifier.do(new_pre_context_sm)

    # (*) Once an acceptance state is reached no further analysis is necessary.
    ## stem_and_branches.prune_branches(reverse_pre_context)
    pre_context_sm.delete_loops_to_init_state()

    if     Setup.fallback_mandatory_f \
       and pre_context_sm.longest_path_to_first_acceptance() is None:
        error.log(
            "Pre-context contains patterns of arbitrary length to first acceptance backwards."
        )

    # (*) let the state machine refer to it
    #     [Is this necessary? Is it not enough that the acceptance origins point to it? <fschaef>]
    pre_context_sm_id = pre_context_sm.get_id()

    # (*) Associate acceptance with pre-context id.
    for state in the_state_machine.get_acceptance_state_list():
        state.set_acceptance_condition_id(pre_context_sm_id)

    return pre_context_sm
예제 #14
0
def anything_containing(Q):
    tmp = sequentialize.do([DFA.Universal(), Q, DFA.Universal()])
    return beautifier.do(tmp)
예제 #15
0
def mount(the_state_machine, PostConditionSM):
    """This function mounts a post condition to a state machine with
       a mechanism that is able to handle the pseudo ambigous post-
       condition. Note, that this mechanism can also treat 'normal'
       post-conditions. However, it is slightly less efficient.

                core-        post-    
           -----0000000000000111111111--------------

       (1)      |-------------------->
                                     acceptance

       (2)                   <-------|
                             reset input position

       The first step is performed by 'normal' lexing. The second step
       via the backward detector, which is basically an inverse state
       machine of the post-condition.

       NOTE: This function does **not** return a state machine that is
             necessarily deterministic. Run nfa_to_dfa on the result
             of this function.

       NOTE: This function is very similar to the function that mounts
             a pre-condition to a state machine. The only major difference
             is that the post condition is actually webbed into the 
             state machine for forward lexing. For backward lexing
             a reference is stored that points to the backward detecting
             state machine.
    """
    assert the_state_machine.__class__.__name__ == "StateMachine"
    assert PostConditionSM.__class__.__name__ == "StateMachine"
    # -- state machines with no states are senseless here. 
    assert not the_state_machine.is_empty() 
    assert not PostConditionSM.is_empty()

    # -- trivial pre-conditions should be added last, for simplicity
    # (*) concatinate the two state machines:
    #   -- deletes acceptance states of the core pattern
    #   -- leaves acceptance states of the post condition
    sequentialize.do([the_state_machine, PostConditionSM], MountToFirstStateMachineF=True)

    # (*) The Backward Input Position detector CANNOT be inverted here.
    #     The inversion may depend on the input codec(!). So, it is 
    #     done just before code generation.
    backward_detector_sm_to_be_inverted = PostConditionSM.clone()
    ## DOES NOT WORK: acceptance_pruning.do(backward_detector_sm)

    # NOTE: We do not need to mark any origins in the backward detector,
    #       since it is not concerned with acceptance states. Its only
    #       task is to reset the input stream.
    # NOTE: It is not necessary that the state machine directly refers to
    #       the backward detector. The origins of the acceptance state will do so.
    acceptance_state_list = the_state_machine.get_acceptance_state_list()
    assert len(acceptance_state_list) != 0, \
            "error: mounting pseudo-ambiguous post condition:\n" + \
            "error: no acceptance state in sequentialized state machine."

    # We cannot do a NFA to DFA and Hopcroft Optimization, because otherwise we
    # would create a new state machine. This function, though, is considered to 
    # 'mount' something on an existing state machine, i.e. change the object
    # that is referenced by the first function argument 'the_state_machine'.
    return backward_detector_sm_to_be_inverted
예제 #16
0
def anything_ending_with(Q):
    tmp = sequentialize.do([DFA.Universal(), Q])
    return beautifier.do(tmp)
예제 #17
0
def anything_beginning_with(Q):
    tmp = sequentialize.do([Q, DFA.Universal()])
    return beautifier.do(tmp)
예제 #18
0
    sm = DFA()
    si = sm.init_state_index
    si0 = sm.add_transition(si, ord('u'))
    si1 = sm.add_transition(si0, ord('y'), AcceptanceF=True)
    si2 = sm.add_transition(si0, ord('x'))
    si2 = sm.add_transition(si2, ord('x'), si2, AcceptanceF=True)
    print "#sm:", sm

    smp = DFA()
    si = smp.init_state_index
    si0 = smp.add_transition(si, ord('x'), si)
    si1 = smp.add_transition(si, ord('y'), AcceptanceF=True)
    print "#sm2:", smp

    # return_sm = setup_post_context.do(sm, smp, False, False, SourceRef_VOID)
    print "#return_sm:", nfa_to_dfa.do(sequentialize.do([sm, smp]))
    sys.exit()

print "-------------------------------------------------------------------------------"
tiny0 = DFA()
tiny0.add_transition(tiny0.init_state_index, ord('a'), AcceptanceF=True)

tiny1 = DFA()
tiny1.add_transition(tiny1.init_state_index, ord(';'), AcceptanceF=True)

test(tiny0, tiny1)

print "-------------------------------------------------------------------------------"
sm = sm1
post_sm = sm3.clone()
예제 #19
0
def _do(the_state_machine, post_context_sm, EndOfLinePostContextF,
        SourceReference):
    """Appends a post context to the given state machine and changes 
       state infos as required. 

       NOTE: 

           In case that:    post_context_sm is not None 
                         or EndOfLinePostContextF  

           The function appends something to the state machine and
           it is therefore required to pass 'NFA to DFA'--better
           also Hopcroft Minimization.
       
       ________________________________________________________________________
       This process is very similar to sequentialization. 
       There is a major difference, though:
       
       Given a state machine (e.g. a pattern) X with a post context Y, 
       a match is only valid if X is followed by Y. Let Xn be an acceptance
       state of X and Ym an acceptance state of Y: 

              ---(Xn-1)---->(Xn)---->(Y0)----> ... ---->((Ym))
                            store                       acceptance
                            input
                            position
       
       That is, it holds:

          -- The next input position is stored the position of Xn, even though
             it is 'officially' not an acceptance state.

          -- Ym will be an acceptance state, but it will not store 
             the input position!       

       The analysis of the next pattern will start at the position where
       X stopped, even though Ym is required to state acceptance.    
       
    """
    if post_context_sm is None and EndOfLinePostContextF == False:
        return the_state_machine, None

    # State machines with no states are senseless here.
    assert not the_state_machine.is_empty(), \
           "empty state machine can have no post context."
    assert post_context_sm is None or not post_context_sm.is_empty(), \
           "empty state machine cannot be a post-context."

    # State machines involved with post condition building are part of a pattern,
    # but not configured out of multiple patterns. Thus there should be no origins.
    assert the_state_machine.has_origins() == False
    assert post_context_sm is None or not post_context_sm.has_origins()

    for state in the_state_machine.get_acceptance_state_list():
        for cmd in state.single_entry.get_iterable(SeAccept):
            assert cmd.pre_context_id() == E_PreContextIDs.NONE, \
                   "Post Contexts MUST be mounted BEFORE pre-contexts."

    if post_context_sm is None:
        assert EndOfLinePostContextF
        # Generate a new post context that just contains the 'newline'
        post_context_sm = StateMachine_Newline()

    elif EndOfLinePostContextF:
        # Mount 'newline' to existing post context
        post_context_sm = sequentialize.do(
            [post_context_sm, StateMachine_Newline()])

    # A post context with an initial state that is acceptance is not really a
    # 'context' since it accepts anything. The state machine remains un-post context.
    if post_context_sm.get_init_state().is_acceptance():
        error.warning(
            "Post context accepts anything--replaced by no post context.",
            SourceReference)
        return the_state_machine, None

    # (*) Two ways of handling post-contexts:
    #
    #     -- Seldom Exception:
    #        Pseudo-Ambiguous Post Conditions (x+/x) -- detecting the end of the
    #        core pattern after the end of the post context
    #        has been reached.
    #
    if ambiguous_post_context.detect_forward(the_state_machine,
                                             post_context_sm):
        if ambiguous_post_context.detect_backward(the_state_machine,
                                                  post_context_sm):
            # -- for post contexts that are forward and backward ambiguous
            #    a philosophical cut is necessary.
            error.warning(
                "Post context requires philosophical cut--handle with care!\n"
                "Proposal: Isolate pattern and ensure results are as expected!",
                SourceReference)
            post_context_sm = ambiguous_post_context.philosophical_cut(
                the_state_machine, post_context_sm)

        # NOTE: May be, the_state_machine does contain now an epsilon transition. See
        #       comment at entry of this function.
        bipd_sm_to_be_inverted = ambiguous_post_context.mount(
            the_state_machine, post_context_sm)
        the_state_machine = beautifier.do(the_state_machine)
        return the_state_machine, bipd_sm_to_be_inverted

    # -- The 'normal' way: storing the input position at the end of the core
    #    pattern.
    #
    # (*) Need to clone the state machines, i.e. provide their internal
    #     states with new ids, but the 'behavior' remains. This allows
    #     state machines to appear twice, or being used in 'larger'
    #     conglomerates.
    post_clone = post_context_sm.clone()

    # -- Once an acceptance state is reached no further analysis is necessary.
    ## NO: acceptance_pruning.do(post_clone)
    ## BECAUSE: it may have to compete with a pseudo-ambiguous post context

    # (*) collect all transitions from both state machines into a single one
    #
    #     NOTE: The start index is unique. Therefore, one can assume that each
    #           clone_list '.states' dictionary has different keys. One can simply
    #           take over all transitions of a start index into the result without
    #           considering interferences (see below)
    #
    orig_acceptance_state_id_list = the_state_machine.get_acceptance_state_index_list(
    )

    # -- mount on every acceptance state the initial state of the following state
    #    machine via epsilon transition
    the_state_machine.mount_to_acceptance_states(
        post_clone.init_state_index, CancelStartAcceptanceStateF=True)
    for start_state_index, state in post_clone.states.iteritems():
        the_state_machine.states[
            start_state_index] = state  # states are already cloned

    # -- raise at each old acceptance state the 'store input position flag'
    # -- set the post context flag for all acceptance states
    for state_idx in orig_acceptance_state_id_list:
        state = the_state_machine.states[state_idx]
        state.set_read_position_store_f(True)

    # -- no acceptance state shall store the input position
    # -- set the post context flag for all acceptance states
    for state in the_state_machine.get_acceptance_state_list():
        state.set_read_position_store_f(False)
        state.set_read_position_restore_f(True)

    # No input position backward search required
    return beautifier.do(the_state_machine), None
예제 #20
0
def _prepare_indentation_counter(ModeName, OptionsDb, CounterDb, IncidenceDb,
                                 MHI):
    """Prepare indentation counter. An indentation counter is implemented by 
    the following:

    'newline' pattern --> triggers as soon as an UNSUPPRESSED newline occurs. 
                      --> entry to the INDENTATION COUNTER.

    'suppressed newline' --> INDENTATION COUNTER is NOT triggered.
     
    The supressed newline pattern is longer (and has precedence) over the
    newline pattern. With the suppressed newline it is possible to write
    lines which overstep the newline (see backslahs in Python, for example).

    RETURNS: List of:
             [0] newline PPT and
             [1] optionally the PPT of the newline suppressor.

    The primary pattern action pair list is to be the head of all pattern
    action pairs.

    MHI = Mode hierarchie index defining the priority of the current mode.
    """
    ISetup = OptionsDb.value("indentation")
    if ISetup is None: return [], []

    check_indentation_setup(ISetup)

    if ISetup.sm_newline_suppressor.get() is not None:
        sm_suppressed_newline = sequentialize.do(
            [ISetup.sm_newline_suppressor.get(),
             ISetup.sm_newline.get()])
        sm_suppressed_newline = beautifier.do(sm_suppressed_newline)
    else:
        sm_suppressed_newline = None

    data = {
        "counter_db":
        CounterDb,
        "indentation_setup":
        ISetup,
        "incidence_db":
        IncidenceDb,
        "default_indentation_handler_f":
        IncidenceDb.default_indentation_handler_f(),
        "mode_name":
        ModeName,
        "sm_suppressed_newline":
        sm_suppressed_newline,
    }

    ppt_list = [
        # 'newline' triggers --> indentation counter
        PPT_indentation_handler_newline(MHI, data, ISetup, CounterDb)
    ]

    if sm_suppressed_newline is not None:
        ppt_list.append(
            # 'newline-suppressor' followed by 'newline' is ignored (skipped)
            PPT_indentation_handler_suppressed_newline(MHI,
                                                       sm_suppressed_newline))

    return [], ppt_list
예제 #21
0
def _do(the_state_machine, post_context_sm, EndOfLinePostContextF, SourceReference):
    """Appends a post context to the given state machine and changes 
       state infos as required. 

       NOTE: 

           In case that:    post_context_sm is not None 
                         or EndOfLinePostContextF  

           The function appends something to the state machine and
           it is therefore required to pass 'NFA to DFA'--better
           also Hopcroft Minimization.
       
       ________________________________________________________________________
       This process is very similar to sequentialization. 
       There is a major difference, though:
       
       Given a state machine (e.g. a pattern) X with a post context Y, 
       a match is only valid if X is followed by Y. Let Xn be an acceptance
       state of X and Ym an acceptance state of Y: 

              ---(Xn-1)---->(Xn)---->(Y0)----> ... ---->((Ym))
                            store                       acceptance
                            input
                            position
       
       That is, it holds:

          -- The next input position is stored the position of Xn, even though
             it is 'officially' not an acceptance state.

          -- Ym will be an acceptance state, but it will not store 
             the input position!       

       The analysis of the next pattern will start at the position where
       X stopped, even though Ym is required to state acceptance.    
       
    """
    if post_context_sm is None and EndOfLinePostContextF == False:
        return the_state_machine, None

    # State machines with no states are senseless here. 
    assert not the_state_machine.is_empty(), \
           "empty state machine can have no post context."
    assert post_context_sm is None or not post_context_sm.is_empty(), \
           "empty state machine cannot be a post-context."

    # State machines involved with post condition building are part of a pattern, 
    # but not configured out of multiple patterns. Thus there should be no origins.
    assert the_state_machine.has_origins() == False
    assert post_context_sm is None or not post_context_sm.has_origins()

    for state in the_state_machine.get_acceptance_state_list():
        for cmd in state.single_entry.get_iterable(SeAccept): 
            assert cmd.pre_context_id() == E_PreContextIDs.NONE, \
                   "Post Contexts MUST be mounted BEFORE pre-contexts."

    if post_context_sm is None:
        assert EndOfLinePostContextF
        # Generate a new post context that just contains the 'newline'
        post_context_sm = StateMachine_Newline() 

    elif EndOfLinePostContextF: 
        # Mount 'newline' to existing post context
        post_context_sm = sequentialize.do([post_context_sm, 
                                            StateMachine_Newline()]) 

    # A post context with an initial state that is acceptance is not really a
    # 'context' since it accepts anything. The state machine remains un-post context.
    if post_context_sm.get_init_state().is_acceptance():
        error.warning("Post context accepts anything--replaced by no post context.",
                      SourceReference)
        return the_state_machine, None
    
    # (*) Two ways of handling post-contexts:
    #
    #     -- Seldom Exception: 
    #        Pseudo-Ambiguous Post Conditions (x+/x) -- detecting the end of the 
    #        core pattern after the end of the post context
    #        has been reached.
    #
    if ambiguous_post_context.detect_forward(the_state_machine, post_context_sm):
        if ambiguous_post_context.detect_backward(the_state_machine, post_context_sm):
            # -- for post contexts that are forward and backward ambiguous
            #    a philosophical cut is necessary.
            error.warning("Post context requires philosophical cut--handle with care!\n"
                      "Proposal: Isolate pattern and ensure results are as expected!", 
                      SourceReference) 
            post_context_sm = ambiguous_post_context.philosophical_cut(the_state_machine, post_context_sm)
        
        # NOTE: May be, the_state_machine does contain now an epsilon transition. See
        #       comment at entry of this function.
        bipd_sm_to_be_inverted = ambiguous_post_context.mount(the_state_machine, post_context_sm)
        the_state_machine      = beautifier.do(the_state_machine)
        return the_state_machine, bipd_sm_to_be_inverted

    # -- The 'normal' way: storing the input position at the end of the core
    #    pattern.
    #
    # (*) Need to clone the state machines, i.e. provide their internal
    #     states with new ids, but the 'behavior' remains. This allows
    #     state machines to appear twice, or being used in 'larger'
    #     conglomerates.
    post_clone = post_context_sm.clone() 

    # -- Once an acceptance state is reached no further analysis is necessary.
    ## NO: acceptance_pruning.do(post_clone)
    ## BECAUSE: it may have to compete with a pseudo-ambiguous post context

    # (*) collect all transitions from both state machines into a single one
    #
    #     NOTE: The start index is unique. Therefore, one can assume that each
    #           clone_list '.states' dictionary has different keys. One can simply
    #           take over all transitions of a start index into the result without
    #           considering interferences (see below)
    #
    orig_acceptance_state_id_list = the_state_machine.get_acceptance_state_index_list()

    # -- mount on every acceptance state the initial state of the following state
    #    machine via epsilon transition
    the_state_machine.mount_to_acceptance_states(post_clone.init_state_index, 
                                                 CancelStartAcceptanceStateF=True)
    for start_state_index, state in post_clone.states.iteritems():        
        the_state_machine.states[start_state_index] = state # states are already cloned

    # -- raise at each old acceptance state the 'store input position flag'
    # -- set the post context flag for all acceptance states
    for state_idx in orig_acceptance_state_id_list:
        state = the_state_machine.states[state_idx]
        state.set_input_position_store_f(True)
    
    # -- no acceptance state shall store the input position
    # -- set the post context flag for all acceptance states
    for state in the_state_machine.get_acceptance_state_list():
        state.set_input_position_store_f(False)
        state.set_input_position_restore_f(True)

    # No input position backward search required
    return beautifier.do(the_state_machine), None
예제 #22
0
def do(the_state_machine, pre_context_sm, BeginOfLinePreContextF):
    """Sets up a pre-condition to the given state machine. This process
       is entirely different from any sequentializing or parallelization
       of state machines. Here, the state machine representing the pre-
       condition is **not** webbed into the original state machine!

       Instead, the following happens:

          -- the pre-condition state machine is inverted, because
             it is to be walked through backwards.
          -- the inverted state machine is marked with the state machine id
             of the_state_machine.        
          -- the original state machine will refer to the inverse
             state machine of the pre-condition.
          -- the initial state origins and the origins of the acceptance
             states are marked as 'pre-conditioned' indicating the id
             of the inverted state machine of the pre-condition.             
    """
    #___________________________________________________________________________________________
    # (*) do some consistency checking   
    # -- state machines with no states are senseless here. 
    assert not the_state_machine.is_empty() 
    assert pre_context_sm is None or not pre_context_sm.is_empty()
    # -- trivial pre-conditions should be added last, for simplicity

    #___________________________________________________________________________________________
    if pre_context_sm is None:
        # NOT: 'and ...' !
        if BeginOfLinePreContextF:
            # Mark all acceptance states with the 'trivial pre-context BeginOfLine' flag
            for state in the_state_machine.get_acceptance_state_list():
                state.set_pre_context_id(E_PreContextIDs.BEGIN_OF_LINE)
        return None

    # (*) Reverse the state machine of the pre-condition 
    reverse_pre_context = reverse.do(pre_context_sm)
        
    if BeginOfLinePreContextF:
        # Extend the existing pre-context with a preceeding 'begin-of-line'.
        reverse_newline_sm  = reverse.do(StateMachine_Newline())
        reverse_pre_context = sequentialize.do([reverse_pre_context, 
                                                reverse_newline_sm])

    # (*) Once an acceptance state is reached no further analysis is necessary.
    acceptance_pruning.do(reverse_pre_context)

    # (*) Clean up what has been done by inversion (and optionally 'BeginOfLinePreContextF')
    #     AFTER acceptance_pruning (!)
    reverse_pre_context = beautifier.do(reverse_pre_context)

    # (*) let the state machine refer to it 
    #     [Is this necessary? Is it not enough that the acceptance origins point to it? <fschaef>]
    pre_context_sm_id = reverse_pre_context.get_id()

    # (*) Associate acceptance with pre-context id. 
    for state in the_state_machine.get_acceptance_state_list():
        state.set_pre_context_id(pre_context_sm_id)
    
    return reverse_pre_context