
    g@                     t    d dl mZ d dlmZ d dlmZ  G d de      Z G d de      Zd Ze	d	k(  r e        y
y
)    )Nonterminal)ParserI)Treec                   Z    e Zd ZdZddZd Zd Zd Zd ZddZ	dd	Z
dd
Zd Zd Zd Zy)ShiftReduceParsera  
    A simple bottom-up CFG parser that uses two operations, "shift"
    and "reduce", to find a single parse for a text.

    ``ShiftReduceParser`` maintains a stack, which records the
    structure of a portion of the text.  This stack is a list of
    strings and Trees that collectively cover a portion of
    the text.  For example, while parsing the sentence "the dog saw
    the man" with a typical grammar, ``ShiftReduceParser`` will produce
    the following stack, which covers "the dog saw"::

       [(NP: (Det: 'the') (N: 'dog')), (V: 'saw')]

    ``ShiftReduceParser`` attempts to extend the stack to cover the
    entire text, and to combine the stack elements into a single tree,
    producing a complete parse for the sentence.

    Initially, the stack is empty.  It is extended to cover the text,
    from left to right, by repeatedly applying two operations:

      - "shift" moves a token from the beginning of the text to the
        end of the stack.
      - "reduce" uses a CFG production to combine the rightmost stack
        elements into a single Tree.

    Often, more than one operation can be performed on a given stack.
    In this case, ``ShiftReduceParser`` uses the following heuristics
    to decide which operation to perform:

      - Only shift if no reductions are available.
      - If multiple reductions are available, then apply the reduction
        whose CFG production is listed earliest in the grammar.

    Note that these heuristics are not guaranteed to choose an
    operation that leads to a parse of the text.  Also, if multiple
    parses exists, ``ShiftReduceParser`` will return at most one of
    them.

    :see: ``nltk.grammar``
    c                 @    || _         || _        | j                          y)a  
        Create a new ``ShiftReduceParser``, that uses ``grammar`` to
        parse texts.

        :type grammar: Grammar
        :param grammar: The grammar used to parse texts.
        :type trace: int
        :param trace: The level of tracing that should be used when
            parsing a text.  ``0`` will generate no tracing output;
            and higher numbers will produce more verbose tracing
            output.
        N)_grammar_trace_check_grammar)selfgrammartraces      K/var/www/openai/venv/lib/python3.12/site-packages/nltk/parse/shiftreduce.py__init__zShiftReduceParser.__init__;   s          c                     | j                   S Nr	   r   s    r   r   zShiftReduceParser.grammarL   s    }}r   c              #   &  K   t        |      }| j                  j                  |       g }|}| j                  r/t	        ddj                  |      z         | j                  ||       t        |      dkD  rG| j                  ||       | j                  ||      r	 | j                  ||      rt        |      dkD  rGt        |      dk(  rE|d   j                         | j                  j                         j                         k(  r|d    y y y w)Nz
Parsing %r r      )listr	   check_coverager
   printjoin_trace_stacklen_shift_reducelabelstartsymbol)r   tokensstackremaining_texts       r   parsezShiftReduceParser.parseO   s     f$$V,  ;;,&!112e^4 .!A%KK~.,,un5 ,,un5 .!A% u:?Qx~~4==#6#6#8#?#?#AAAh B s   B+D.D=ADc                     |j                  |d          |j                  |d          | j                  r| j                  ||       yy)a  
        Move a token from the beginning of ``remaining_text`` to the
        end of ``stack``.

        :type stack: list(str and Tree)
        :param stack: A list of strings and Trees, encoding
            the structure of the text that has been parsed so far.
        :type remaining_text: list(str)
        :param remaining_text: The portion of the text that is not yet
            covered by ``stack``.
        :rtype: None
        r   N)appendremover
   _trace_shiftr   r%   r&   s      r   r   zShiftReduceParser._shifti   sD     	^A&'nQ/0;;e^4 r   c                 N   t        |      t        |      k7  ryt        t        |            D ]v  }t        ||   t              r?t        ||   t              s y||   j                         ||   j                         k7  sS yt        ||   t              r y||   ||   k7  sv y y)a7  
        :rtype: bool
        :return: true if the right hand side of a CFG production
            matches the rightmost elements of the stack.  ``rhs``
            matches ``rightmost_stack`` if they are the same length,
            and each element of ``rhs`` matches the corresponding
            element of ``rightmost_stack``.  A nonterminal element of
            ``rhs`` matches any Tree whose node value is equal
            to the nonterminal's symbol.  A terminal element of ``rhs``
            matches any string whose type is equal to the terminal.
        :type rhs: list(terminal and Nonterminal)
        :param rhs: The right hand side of a CFG production.
        :type rightmost_stack: list(string and Tree)
        :param rightmost_stack: The rightmost elements of the parser's
            stack.
        FT)r   range
isinstancer   r   r!   r#   )r   rhsrightmost_stackis       r   
_match_rhszShiftReduceParser._match_rhs{   s    $ 3s8+s?+,A/!,d3!#a&+6 "1%++-Q@ c!fk2 "1%Q/  - r   Nc                 x   || j                   j                         }n|g}|D ]  }t        |j                               }| j	                  |j                         || d       sAt        |j                         j                         || d       }|g|| d | j                  r| j                  |||       |c S  y)a  
        Find a CFG production whose right hand side matches the
        rightmost stack elements; and combine those stack elements
        into a single Tree, with the node specified by the
        production's left-hand side.  If more than one CFG production
        matches the stack, then use the production that is listed
        earliest in the grammar.  The new Tree replaces the
        elements in the stack.

        :rtype: Production or None
        :return: If a reduction is performed, then return the CFG
            production that the reduction is based on; otherwise,
            return false.
        :type stack: list(string and Tree)
        :param stack: A list of strings and Trees, encoding
            the structure of the text that has been parsed so far.
        :type remaining_text: list(str)
        :param remaining_text: The portion of the text that is not yet
            covered by ``stack``.
        N)
r	   productionsr   r0   r3   r   lhsr#   r
   _trace_reduce)r   r%   r&   
productionr5   rhslentrees          r   r    zShiftReduceParser._reduce   s    * --335K%,K &J)*F z~~/wxAJNN,335ufWXG#'&vgh ;;&&uj.I!! & r   c                     || _         y)aP  
        Set the level of tracing output that should be generated when
        parsing a text.

        :type trace: int
        :param trace: The trace level.  A trace level of ``0`` will
            generate no tracing output; and higher trace levels will
            produce more verbose tracing output.
        :rtype: None
        N)r
   )r   r   s     r   r   zShiftReduceParser.trace   s     r   c                     d|z   dz   }|D ]L  }t        |t              r)|t        t        |j	                                     dz   z  }<|t        |      dz   z  }N |ddj                  |      z   dz   z  }t        |       y)a'  
        Print trace output displaying the given stack and text.

        :rtype: None
        :param marker: A character that is printed to the left of the
            stack.  This is used with trace level 2 to print 'S'
            before shifted stacks and 'R' before reduced stacks.
        z  z [ r   z* ]N)r/   r   reprr   r!   r   r   )r   r%   r&   markerselts         r   r   zShiftReduceParser._trace_stack   s}     6ME!C#t$T+ciik23c99T#Y_$	 
 	
TCHH^,,s22ar   c                     | j                   dkD  rt        d|d   z         | j                   dk(  r| j                  ||d       y| j                   dkD  r| j                  ||       yy)zd
        Print trace output displaying that a token has been shifted.

        :rtype: None
           z	Shift %r:Sr   N)r
   r   r   r,   s      r   r+   zShiftReduceParser._trace_shift   s^     ;;?+b	)*;;!e^S9[[1_e^4 r   c                 (   | j                   dkD  r>dj                  |j                               }t        d|j	                         d|        | j                   dk(  r| j                  ||d       y| j                   dkD  r| j                  ||       yy)z
        Print trace output displaying that ``production`` was used to
        reduce ``stack``.

        :rtype: None
        rC   r   zReduce z <- Rr   N)r
   r   r0   r   r6   r   )r   r%   r8   r&   r0   s        r   r7   zShiftReduceParser._trace_reduce   s     ;;?((:>>+,CGJNN,/tC59:;;!e^S9[[1_e^4 r   c                 6   | j                   j                         }t        t        |            D ]h  }t        |dz   t        |            D ]K  }||   j	                         }||   j	                         }|dt        |       |k(  s;t        d||   z         M j y)z
        Check to make sure that all of the CFG productions are
        potentially useful.  If any productions can never be used,
        then print a warning.

        :rtype: None
        r   NzWarning: %r will never be used)r	   r5   r.   r   r0   r   )r   r5   r2   jrhs1rhs2s         r   r   z ShiftReduceParser._check_grammar  s     mm//1 s;'(A1q5#k"23"1~))+"1~))+#d)$,:[^KL	 4 )r   r   r   )rC   )r   )__name__
__module____qualname____doc__r   r   r'   r   r3   r    r   r   r+   r7   r    r   r   r   r      sB    'R"45$B*X $55Mr   r   c                   h     e Zd ZdZd fd	Zd Zd Zd Zd Zd Z	d Z
dd	Zd
 Zd Zd Zd Z xZS )SteppingShiftReduceParsera'  
    A ``ShiftReduceParser`` that allows you to setp through the parsing
    process, performing a single operation at a time.  It also allows
    you to change the parser's grammar midway through parsing a text.

    The ``initialize`` method is used to start parsing a text.
    ``shift`` performs a single shift operation, and ``reduce`` performs
    a single reduce operation.  ``step`` will perform a single reduce
    operation if possible; otherwise, it will perform a single shift
    operation.  ``parses`` returns the set of parses that have been
    found by the parser.

    :ivar _history: A list of ``(stack, remaining_text)`` pairs,
        containing all of the previous states of the parser.  This
        history is used to implement the ``undo`` operation.
    :see: ``nltk.grammar``
    c                 P    t         |   ||       d | _        d | _        g | _        y r   )superr   _stack_remaining_text_history)r   r   r   	__class__s      r   r   z"SteppingShiftReduceParser.__init__0  s(    %(#r   c                     t        |      }| j                  |       | j                         r	 | j                         r| j                         S r   )r   
initializestepparsesr   r$   s     r   r'   zSteppingShiftReduceParser.parse6  s:    fiik iik{{}r   c                     | j                   S )zQ
        :return: The parser's stack.
        :rtype: list(str and Tree)
        )rV   r   s    r   r%   zSteppingShiftReduceParser.stack=  s    
 {{r   c                     | j                   S )z~
        :return: The portion of the text that is not yet covered by the
            stack.
        :rtype: list(str)
        )rW   r   s    r   r&   z(SteppingShiftReduceParser.remaining_textD  s     ###r   c                 .    g | _         || _        g | _        y)z
        Start parsing a given text.  This sets the parser's stack to
        ``[]`` and sets its remaining text to ``tokens``.
        N)rV   rW   rX   r^   s     r   r[   z$SteppingShiftReduceParser.initializeL  s    
 %r   c                 F    | j                         xs | j                         S )a  
        Perform a single parsing operation.  If a reduction is
        possible, then perform that reduction, and return the
        production that it is based on.  Otherwise, if a shift is
        possible, then perform it, and return True.  Otherwise,
        return False.

        :return: False if no operation was performed; True if a shift was
            performed; and the CFG production used to reduce if a
            reduction was performed.
        :rtype: Production or bool
        )reduceshiftr   s    r   r\   zSteppingShiftReduceParser.stepU  s     {{},

,r   c                     t        | j                        dk(  ry| j                  j                  | j                  dd | j                  dd f       | j                  | j                  | j                         y)a  
        Move a token from the beginning of the remaining text to the
        end of the stack.  If there are no more tokens in the
        remaining text, then do nothing.

        :return: True if the shift operation was successful.
        :rtype: bool
        r   FNT)r   rW   rX   r)   rV   r   r   s    r   rd   zSteppingShiftReduceParser.shiftd  s_     t##$)dkk!nd.B.B1.EFGDKK!5!56r   c                     | j                   j                  | j                  dd | j                  dd f       | j	                  | j                  | j                  |      }|s| j                   j                          |S )a  
        Use ``production`` to combine the rightmost stack elements into
        a single Tree.  If ``production`` does not match the
        rightmost stack elements, then do nothing.

        :return: The production used to reduce the stack, if a
            reduction was performed.  If no reduction was performed,
            return None.

        :rtype: Production or None
        N)rX   r)   rV   rW   r    pop)r   r8   
return_vals      r   rc   z SteppingShiftReduceParser.reduces  sc     	dkk!nd.B.B1.EFG\\$++t/C/CZP
MMr   c                     t        | j                        dk(  ry| j                  j                         \  | _        | _        y)a|  
        Return the parser to its state before the most recent
        shift or reduce operation.  Calling ``undo`` repeatedly return
        the parser to successively earlier states.  If no shift or
        reduce operations have been performed, ``undo`` will make no
        changes.

        :return: true if an operation was successfully undone.
        :rtype: bool
        r   FT)r   rX   rg   rV   rW   r   s    r   undozSteppingShiftReduceParser.undo  s7     t}}".2mm.?.?.A+d*r   c                     g }| j                   j                         D ][  }t        |j                               }| j	                  |j                         | j
                  | d       sK|j                  |       ] |S )z
        :return: A list of the productions for which reductions are
            available for the current parser state.
        :rtype: list(Production)
        N)r	   r5   r   r0   r3   rV   r)   )r   r5   r8   r9   s       r   reducible_productionsz/SteppingShiftReduceParser.reducible_productions  si     --335J)*Fz~~/fWX1FG"":. 6 r   c              #      K   t        | j                        dk(  rrt        | j                        dk(  rY| j                  d   j                         | j                  j                         j                         k(  r| j                  d    yyyyw)z
        :return: An iterator of the parses that have been found by this
            parser so far.
        :rtype: iter(Tree)
        r   r   N)r   rW   rV   r!   r	   r"   r#   r   s    r   r]   z SteppingShiftReduceParser.parses  sy      $$%*DKK A%A$$&$--*=*=*?*F*F*HH++a.  I & +s   BBc                     || _         y)z~
        Change the grammar used to parse texts.

        :param grammar: The new grammar.
        :type grammar: CFG
        Nr   )r   r   s     r   set_grammarz%SteppingShiftReduceParser.set_grammar  s      r   rL   r   )rM   rN   rO   rP   r   r'   r%   r&   r[   r\   rd   rc   rj   rl   r]   ro   __classcell__)rY   s   @r   rS   rS     sD    $$-& ! r   rS   c                      ddl m} m} | j                  d      }dj	                         }|j                  |d      }|j                  |      D ]  }t        |        y)z5
    A demonstration of the shift-reduce parser.
    r   )CFGr'   z
    S -> NP VP
    NP -> Det N | Det N PP
    VP -> V NP | V NP PP
    PP -> P NP
    NP -> 'I'
    N -> 'man' | 'park' | 'telescope' | 'dog'
    Det -> 'the' | 'a'
    P -> 'in' | 'with'
    V -> 'saw'
    zI saw a man in the parkrC   )r   N)nltkrr   r'   
fromstringsplitr   r   )rr   r'   r   sentparserps         r   demory     sY    
  nn
	G %**,D$$WA$6F\\$a  r   __main__N)
nltk.grammarr   nltk.parse.apir   	nltk.treer   r   rS   ry   rM   rQ   r   r   <module>r~      sJ    % " FM FMX\  1 \ H8 zF r   