Home | History | Annotate | Download | only in java_cup
      1 package java_cup;
      2 
      3 import java.util.Stack;
      4 
      5 /** This class represents an LALR item. Each LALR item consists of
      6  *  a production, a "dot" at a position within that production, and
      7  *  a set of lookahead symbols (terminal).  (The first two of these parts
      8  *  are provide by the super class).  An item is designed to represent a
      9  *  configuration that the parser may be in.  For example, an item of the
     10  *  form: <pre>
     11  *    [A ::= B * C d E  , {a,b,c}]
     12  *  </pre>
     13  *  indicates that the parser is in the middle of parsing the production <pre>
     14  *    A ::= B C d E
     15  *  </pre>
     16  *  that B has already been parsed, and that we will expect to see a lookahead
     17  *  of either a, b, or c once the complete RHS of this production has been
     18  *  found.<p>
     19  *
     20  *  Items may initially be missing some items from their lookahead sets.
     21  *  Links are maintained from each item to the set of items that would need
     22  *  to be updated if symbols are added to its lookahead set.  During
     23  *  "lookahead propagation", we add symbols to various lookahead sets and
     24  *  propagate these changes across these dependency links as needed.
     25  *
     26  * @see     java_cup.lalr_item_set
     27  * @see     java_cup.lalr_state
     28  * @version last updated: 11/25/95
     29  * @author  Scott Hudson
     30  */
     31 public class lalr_item extends lr_item_core {
     32 
     33   /*-----------------------------------------------------------*/
     34   /*--- Constructor(s) ----------------------------------------*/
     35   /*-----------------------------------------------------------*/
     36 
     37   /** Full constructor.
     38    * @param prod the production for the item.
     39    * @param pos  the position of the "dot" within the production.
     40    * @param look the set of lookahead symbols.
     41    */
     42   public lalr_item(production prod, int pos, terminal_set look)
     43     throws internal_error
     44     {
     45       super(prod, pos);
     46       _lookahead = look;
     47       _propagate_items = new Stack();
     48       needs_propagation = true;
     49     }
     50 
     51   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
     52 
     53   /** Constructor with default position (dot at start).
     54    * @param prod the production for the item.
     55    * @param look the set of lookahead symbols.
     56    */
     57   public lalr_item(production prod, terminal_set look) throws internal_error
     58     {
     59       this(prod,0,look);
     60     }
     61 
     62   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
     63 
     64   /** Constructor with default position and empty lookahead set.
     65    * @param prod the production for the item.
     66    */
     67   public lalr_item(production prod) throws internal_error
     68     {
     69       this(prod,0,new terminal_set());
     70     }
     71 
     72   /*-----------------------------------------------------------*/
     73   /*--- (Access to) Instance Variables ------------------------*/
     74   /*-----------------------------------------------------------*/
     75 
     76   /** The lookahead symbols of the item. */
     77   protected terminal_set _lookahead;
     78 
     79   /** The lookahead symbols of the item. */
     80   public terminal_set lookahead() {return _lookahead;};
     81 
     82   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
     83 
     84   /** Links to items that the lookahead needs to be propagated to. */
     85   protected Stack _propagate_items;
     86 
     87   /** Links to items that the lookahead needs to be propagated to */
     88   public Stack propagate_items() {return _propagate_items;}
     89 
     90   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
     91 
     92   /** Flag to indicate that this item needs to propagate its lookahead
     93    *  (whether it has changed or not).
     94    */
     95   protected boolean needs_propagation;
     96 
     97   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
     98 
     99   /** Add a new item to the set of items we propagate to. */
    100   public void add_propagate(lalr_item prop_to)
    101     {
    102       _propagate_items.push(prop_to);
    103       needs_propagation = true;
    104     }
    105 
    106   /*-----------------------------------------------------------*/
    107   /*--- General Methods ---------------------------------------*/
    108   /*-----------------------------------------------------------*/
    109 
    110   /** Propagate incoming lookaheads through this item to others need to
    111    *  be changed.
    112    * @params incoming symbols to potentially be added to lookahead of this item.
    113    */
    114   public void propagate_lookaheads(terminal_set incoming) throws internal_error
    115     {
    116       boolean change = false;
    117 
    118       /* if we don't need to propagate, then bail out now */
    119       if (!needs_propagation && (incoming == null || incoming.empty()))
    120     return;
    121 
    122       /* if we have null incoming, treat as an empty set */
    123       if (incoming != null)
    124     {
    125       /* add the incoming to the lookahead of this item */
    126       change = lookahead().add(incoming);
    127     }
    128 
    129       /* if we changed or need it anyway, propagate across our links */
    130       if (change || needs_propagation)
    131     {
    132           /* don't need to propagate again */
    133           needs_propagation = false;
    134 
    135       /* propagate our lookahead into each item we are linked to */
    136       for (int i = 0; i < propagate_items().size(); i++)
    137         ((lalr_item)propagate_items().elementAt(i))
    138                       .propagate_lookaheads(lookahead());
    139     }
    140     }
    141 
    142   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    143 
    144   /** Produce the new lalr_item that results from shifting the dot one position
    145    *  to the right.
    146    */
    147   public lalr_item shift() throws internal_error
    148     {
    149       lalr_item result;
    150 
    151       /* can't shift if we have dot already at the end */
    152       if (dot_at_end())
    153     throw new internal_error("Attempt to shift past end of an lalr_item");
    154 
    155       /* create the new item w/ the dot shifted by one */
    156       result = new lalr_item(the_production(), dot_pos()+1,
    157                         new terminal_set(lookahead()));
    158 
    159       /* change in our lookahead needs to be propagated to this item */
    160       add_propagate(result);
    161 
    162       return result;
    163     }
    164 
    165   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    166 
    167   /** Calculate lookahead representing symbols that could appear after the
    168    *   symbol that the dot is currently in front of.  Note: this routine must
    169    *   not be invoked before first sets and nullability has been calculated
    170    *   for all non terminals.
    171    */
    172   public terminal_set calc_lookahead(terminal_set lookahead_after)
    173     throws internal_error
    174     {
    175       terminal_set    result;
    176       int             pos;
    177       production_part part;
    178       symbol          sym;
    179 
    180       /* sanity check */
    181       if (dot_at_end())
    182     throw new internal_error(
    183       "Attempt to calculate a lookahead set with a completed item");
    184 
    185       /* start with an empty result */
    186       result = new terminal_set();
    187 
    188       /* consider all nullable symbols after the one to the right of the dot */
    189       for (pos = dot_pos()+1; pos < the_production().rhs_length(); pos++)
    190     {
    191        part = the_production().rhs(pos);
    192 
    193        /* consider what kind of production part it is -- skip actions */
    194        if (!part.is_action())
    195          {
    196            sym = ((symbol_part)part).the_symbol();
    197 
    198            /* if its a terminal add it in and we are done */
    199            if (!sym.is_non_term())
    200          {
    201            result.add((terminal)sym);
    202            return result;
    203          }
    204            else
    205          {
    206            /* otherwise add in first set of the non terminal */
    207            result.add(((non_terminal)sym).first_set());
    208 
    209            /* if its nullable we continue adding, if not, we are done */
    210            if (!((non_terminal)sym).nullable())
    211              return result;
    212          }
    213          }
    214     }
    215 
    216       /* if we get here everything past the dot was nullable
    217          we add in the lookahead for after the production and we are done */
    218       result.add(lookahead_after);
    219       return result;
    220     }
    221 
    222   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    223 
    224   /** Determine if everything from the symbol one beyond the dot all the
    225    *  way to the  end of the right hand side is nullable.  This would indicate
    226    *  that the lookahead of this item must be included in the lookaheads of
    227    *  all items produced as a closure of this item.  Note: this routine should
    228    *  not be invoked until after first sets and nullability have been
    229    *  calculated for all non terminals.
    230    */
    231   public boolean lookahead_visible() throws internal_error
    232     {
    233       production_part part;
    234       symbol          sym;
    235 
    236       /* if the dot is at the end, we have a problem, but the cleanest thing
    237      to do is just return true. */
    238       if (dot_at_end()) return true;
    239 
    240       /* walk down the rhs and bail if we get a non-nullable symbol */
    241       for (int pos = dot_pos() + 1; pos < the_production().rhs_length(); pos++)
    242     {
    243       part = the_production().rhs(pos);
    244 
    245       /* skip actions */
    246       if (!part.is_action())
    247         {
    248           sym = ((symbol_part)part).the_symbol();
    249 
    250           /* if its a terminal we fail */
    251           if (!sym.is_non_term()) return false;
    252 
    253           /* if its not nullable we fail */
    254           if (!((non_terminal)sym).nullable()) return false;
    255         }
    256     }
    257 
    258       /* if we get here its all nullable */
    259       return true;
    260     }
    261 
    262   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    263 
    264   /** Equality comparison -- here we only require the cores to be equal since
    265    *   we need to do sets of items based only on core equality (ignoring
    266    *   lookahead sets).
    267    */
    268   public boolean equals(lalr_item other)
    269     {
    270       if (other == null) return false;
    271       return super.equals(other);
    272     }
    273 
    274   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    275 
    276   /** Generic equality comparison. */
    277   public boolean equals(Object other)
    278     {
    279       if (!(other instanceof lalr_item))
    280     return false;
    281       else
    282     return equals((lalr_item)other);
    283     }
    284 
    285   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    286 
    287   /** Return a hash code -- here we only hash the core since we only test core
    288    *  matching in LALR items.
    289    */
    290   public int hashCode()
    291     {
    292       return super.hashCode();
    293     }
    294 
    295   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
    296 
    297   /** Convert to string. */
    298   public String toString()
    299     {
    300       String result = "";
    301 
    302       // additional output for debugging:
    303       // result += "(" + hashCode() + ")";
    304       result += "[";
    305       result += super.toString();
    306       result += ", ";
    307       if (lookahead() != null)
    308     {
    309       result += "{";
    310       for (int t = 0; t < terminal.number(); t++)
    311         if (lookahead().contains(t))
    312           result += terminal.find(t).name() + " ";
    313       result += "}";
    314     }
    315       else
    316     result += "NULL LOOKAHEAD!!";
    317       result += "]";
    318 
    319       // additional output for debugging:
    320       // result += " -> ";
    321       // for (int i = 0; i<propagate_items().size(); i++)
    322       //   result += propagate_items().elementAt(i).hashCode() + " ";
    323       //
    324       // if (needs_propagation) result += " NP";
    325 
    326       return result;
    327     }
    328     /*-----------------------------------------------------------*/
    329 };
    330