1 2 package java_cup; 3 4 /** The "core" of an LR item. This includes a production and the position 5 * of a marker (the "dot") within the production. Typically item cores 6 * are written using a production with an embedded "dot" to indicate their 7 * position. For example: <pre> 8 * A ::= B * C d E 9 * </pre> 10 * This represents a point in a parse where the parser is trying to match 11 * the given production, and has succeeded in matching everything before the 12 * "dot" (and hence is expecting to see the symbols after the dot next). See 13 * lalr_item, lalr_item_set, and lalr_start for full details on the meaning 14 * and use of items. 15 * 16 * @see java_cup.lalr_item 17 * @see java_cup.lalr_item_set 18 * @see java_cup.lalr_state 19 * @version last updated: 11/25/95 20 * @author Scott Hudson 21 */ 22 23 public class lr_item_core { 24 25 /*-----------------------------------------------------------*/ 26 /*--- Constructor(s) ----------------------------------------*/ 27 /*-----------------------------------------------------------*/ 28 29 /** Full constructor. 30 * @param prod production this item uses. 31 * @param pos position of the "dot" within the item. 32 */ 33 public lr_item_core(production prod, int pos) throws internal_error 34 { 35 symbol after_dot = null; 36 production_part part; 37 38 if (prod == null) 39 throw new internal_error( 40 "Attempt to create an lr_item_core with a null production"); 41 42 _the_production = prod; 43 44 if (pos < 0 || pos > _the_production.rhs_length()) 45 throw new internal_error( 46 "Attempt to create an lr_item_core with a bad dot position"); 47 48 _dot_pos = pos; 49 50 /* compute and cache hash code now */ 51 _core_hash_cache = 13*_the_production.hashCode() + pos; 52 53 /* cache the symbol after the dot */ 54 if (_dot_pos < _the_production.rhs_length()) 55 { 56 part = _the_production.rhs(_dot_pos); 57 if (!part.is_action()) 58 _symbol_after_dot = ((symbol_part)part).the_symbol(); 59 } 60 } 61 62 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 63 64 /** Constructor for dot at start of right hand side. 65 * @param prod production this item uses. 66 */ 67 public lr_item_core(production prod) throws internal_error 68 { 69 this(prod,0); 70 } 71 72 /*-----------------------------------------------------------*/ 73 /*--- (Access to) Instance Variables ------------------------*/ 74 /*-----------------------------------------------------------*/ 75 76 /** The production for the item. */ 77 protected production _the_production; 78 79 /** The production for the item. */ 80 public production the_production() {return _the_production;} 81 82 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 83 84 /** The position of the "dot" -- this indicates the part of the production 85 * that the marker is before, so 0 indicates a dot at the beginning of 86 * the RHS. 87 */ 88 protected int _dot_pos; 89 90 /** The position of the "dot" -- this indicates the part of the production 91 * that the marker is before, so 0 indicates a dot at the beginning of 92 * the RHS. 93 */ 94 public int dot_pos() {return _dot_pos;} 95 96 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 97 98 /** Cache of the hash code. */ 99 protected int _core_hash_cache; 100 101 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 102 103 /** Cache of symbol after the dot. */ 104 protected symbol _symbol_after_dot = null; 105 106 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 107 108 /** Is the dot at the end of the production? */ 109 public boolean dot_at_end() 110 { 111 return _dot_pos >= _the_production.rhs_length(); 112 } 113 114 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 115 116 /** Return the symbol after the dot. If there is no symbol after the dot 117 * we return null. */ 118 public symbol symbol_after_dot() 119 { 120 /* use the cached symbol */ 121 return _symbol_after_dot; 122 } 123 124 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 125 126 /** Determine if we have a dot before a non terminal, and if so which one 127 * (return null or the non terminal). 128 */ 129 public non_terminal dot_before_nt() 130 { 131 symbol sym; 132 133 /* get the symbol after the dot */ 134 sym = symbol_after_dot(); 135 136 /* if it exists and is a non terminal, return it */ 137 if (sym != null && sym.is_non_term()) 138 return (non_terminal)sym; 139 else 140 return null; 141 } 142 143 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 144 145 /** Produce a new lr_item_core that results from shifting the dot one 146 * position to the right. 147 */ 148 public lr_item_core shift_core() throws internal_error 149 { 150 if (dot_at_end()) 151 throw new internal_error( 152 "Attempt to shift past end of an lr_item_core"); 153 154 return new lr_item_core(_the_production, _dot_pos+1); 155 } 156 157 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 158 159 /** Equality comparison for the core only. This is separate out because we 160 * need separate access in a super class. 161 */ 162 public boolean core_equals(lr_item_core other) 163 { 164 return other != null && 165 _the_production.equals(other._the_production) && 166 _dot_pos == other._dot_pos; 167 } 168 169 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 170 171 /** Equality comparison. */ 172 public boolean equals(lr_item_core other) {return core_equals(other);} 173 174 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 175 176 /** Generic equality comparison. */ 177 public boolean equals(Object other) 178 { 179 if (!(other instanceof lr_item_core)) 180 return false; 181 else 182 return equals((lr_item_core)other); 183 } 184 185 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 186 187 /** Hash code for the core (separated so we keep non overridden version). */ 188 public int core_hashCode() 189 { 190 return _core_hash_cache; 191 } 192 193 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 194 195 /** Hash code for the item. */ 196 public int hashCode() 197 { 198 return _core_hash_cache; 199 } 200 201 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 202 203 /** Convert to a string (separated out from toString() so we can call it 204 * from subclass that overrides toString()). 205 */ 206 public String to_simple_string() throws internal_error 207 { 208 String result; 209 production_part part; 210 211 if (_the_production.lhs() != null && 212 _the_production.lhs().the_symbol() != null && 213 _the_production.lhs().the_symbol().name() != null) 214 result = _the_production.lhs().the_symbol().name(); 215 else 216 result = "$$NULL$$"; 217 218 result += " ::= "; 219 220 for (int i = 0; i<_the_production.rhs_length(); i++) 221 { 222 /* do we need the dot before this one? */ 223 if (i == _dot_pos) 224 result += "(*) "; 225 226 /* print the name of the part */ 227 if (_the_production.rhs(i) == null) 228 { 229 result += "$$NULL$$ "; 230 } 231 else 232 { 233 part = _the_production.rhs(i); 234 if (part == null) 235 result += "$$NULL$$ "; 236 else if (part.is_action()) 237 result += "{ACTION} "; 238 else if (((symbol_part)part).the_symbol() != null && 239 ((symbol_part)part).the_symbol().name() != null) 240 result += ((symbol_part)part).the_symbol().name() + " "; 241 else 242 result += "$$NULL$$ "; 243 } 244 } 245 246 /* put the dot after if needed */ 247 if (_dot_pos == _the_production.rhs_length()) 248 result += "(*) "; 249 250 return result; 251 } 252 253 /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ 254 255 /** Convert to a string */ 256 public String toString() 257 { 258 /* can't throw here since super class doesn't, so we crash instead */ 259 try { 260 return to_simple_string(); 261 } catch(internal_error e) { 262 e.crash(); 263 return null; 264 } 265 } 266 267 /*-----------------------------------------------------------*/ 268 269 }; 270 271