1 21 22 package net.percederberg.grammatica.parser.re; 23 24 import java.io.IOException ; 25 import java.io.PrintWriter ; 26 import java.util.BitSet ; 27 28 import net.percederberg.grammatica.parser.LookAheadReader; 29 30 38 class RepeatElement extends Element { 39 40 43 public static final int GREEDY = 1; 44 45 48 public static final int RELUCTANT = 2; 49 50 53 public static final int POSSESSIVE = 3; 54 55 58 private Element elem; 59 60 63 private int min; 64 65 68 private int max; 69 70 73 private int type; 74 75 78 private int matchStart; 79 80 84 private BitSet matches; 85 86 98 public RepeatElement(Element elem, int min, int max, int type) { 99 this.elem = elem; 100 this.min = min; 101 if (max <= 0) { 102 this.max = Integer.MAX_VALUE; 103 } else { 104 this.max = max; 105 } 106 this.type = type; 107 this.matchStart = -1; 108 this.matches = null; 109 } 110 111 119 public Object clone() { 120 return new RepeatElement((Element) elem.clone(), min, max, type); 121 } 122 123 138 public int match(Matcher m, LookAheadReader input, int start, int skip) 139 throws IOException { 140 141 if (skip == 0) { 142 matchStart = -1; 143 matches = null; 144 } 145 switch (type) { 146 case GREEDY: 147 return matchGreedy(m, input, start, skip); 148 case RELUCTANT: 149 return matchReluctant(m, input, start, skip); 150 case POSSESSIVE: 151 if (skip == 0) { 152 return matchPossessive(m, input, start, 0); 153 } 154 break; 155 } 156 return -1; 157 } 158 159 174 private int matchGreedy(Matcher m, 175 LookAheadReader input, 176 int start, 177 int skip) 178 throws IOException { 179 180 if (skip == 0) { 182 return matchPossessive(m, input, start, 0); 183 } 184 185 if (matchStart != start) { 187 matchStart = start; 188 matches = new BitSet (); 189 findMatches(m, input, start, 0, 0, 0); 190 } 191 192 for (int i = matches.size(); i >= 0; i--) { 194 if (matches.get(i)) { 195 if (skip == 0) { 196 return i; 197 } 198 skip--; 199 } 200 } 201 return -1; 202 } 203 204 219 private int matchReluctant(Matcher m, 220 LookAheadReader input, 221 int start, 222 int skip) 223 throws IOException { 224 225 if (matchStart != start) { 227 matchStart = start; 228 matches = new BitSet (); 229 findMatches(m, input, start, 0, 0, 0); 230 } 231 232 for (int i = 0; i <= matches.size(); i++) { 234 if (matches.get(i)) { 235 if (skip == 0) { 236 return i; 237 } 238 skip--; 239 } 240 } 241 return -1; 242 } 243 244 259 private int matchPossessive(Matcher m, 260 LookAheadReader input, 261 int start, 262 int count) 263 throws IOException { 264 265 int length = 0; 266 int subLength = 1; 267 268 while (subLength > 0 && count < max) { 270 subLength = elem.match(m, input, start + length, 0); 271 if (subLength >= 0) { 272 count++; 273 length += subLength; 274 } 275 } 276 277 if (min <= count && count <= max) { 279 return length; 280 } else { 281 return -1; 282 } 283 } 284 285 297 private void findMatches(Matcher m, 298 LookAheadReader input, 299 int start, 300 int length, 301 int count, 302 int attempt) 303 throws IOException { 304 305 int subLength; 306 307 if (count > max) { 309 return; 310 } 311 if (min <= count && attempt == 0) { 312 matches.set(length); 313 } 314 315 subLength = elem.match(m, input, start, attempt); 317 if (subLength < 0) { 318 return; 319 } else if (subLength == 0) { 320 if (min == count + 1) { 321 matches.set(length); 322 } 323 return; 324 } 325 326 findMatches(m, input, start, length, count, attempt + 1); 328 findMatches(m, 329 input, 330 start + subLength, 331 length + subLength, 332 count + 1, 333 0); 334 } 335 336 342 public void printTo(PrintWriter output, String indent) { 343 output.print(indent + "Repeat (" + min + "," + max + ")"); 344 if (type == RELUCTANT) { 345 output.print("?"); 346 } else if (type == POSSESSIVE) { 347 output.print("+"); 348 } 349 output.println(); 350 elem.printTo(output, indent + " "); 351 } 352 } 353 | Popular Tags |