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