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    */
lalr_item(production prod, int pos, terminal_set look)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    */
lalr_item(production prod, terminal_set look)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    */
lalr_item(production prod)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. */
lookahead()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 */
propagate_items()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. */
add_propagate(lalr_item prop_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    */
propagate_lookaheads(terminal_set incoming)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    */
shift()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    */
calc_lookahead(terminal_set lookahead_after)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    */
lookahead_visible()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    */
equals(lalr_item other)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. */
equals(Object other)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    */
hashCode()290   public int hashCode()
291     {
292       return super.hashCode();
293     }
294 
295   /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
296 
297   /** Convert to string. */
toString()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