private List<Integer> upperBounds( List<GrammarProductionElement> elems, int bound, List<Integer> lowerBounds) { List<Integer> upperBounds = new ArrayList<Integer>(elems.size()); for (int i = 0; i < elems.size(); i++) { GrammarProductionElement grammarProductionElement = elems.get(i); int upperBound; if (grammarProductionElement.getKind() == GrammarElementKind.GTERMINAL) { if (terms_are_single_char) { upperBound = 1; } else { TerminalElement term = (TerminalElement) grammarProductionElement; upperBound = term.getNameNoQuotes().length(); } } else { // upperBound= bound - (size - 1);//TODO still too conservative: use the 'bounds' map upperBound = bound; } upperBounds.add(Math.max(upperBound, lowerBounds.get(i))); } return upperBounds; }
private Regexp internalGetBoundedRegexp(Grammar g, String startSymbol, int bound) { if (regexpCache.containsKeys(startSymbol, bound)) return regexpCache.get(startSymbol, bound); // removing epsilons may not succeed for start symbol. We check if that's the case. boolean canGenerateEmptyString = g.containsEpsilonProduction(startSymbol); List<Regexp> x = new ArrayList<Regexp>(); for (GrammarProduction prod : g.getRule(startSymbol).getProductions()) { List<GrammarProductionElement> elems = prod.getElements(); if (canGenerateEmptyString || elems.size() <= bound) { // uses the fact that every symbol (other than start) produces at least // one terminal List<List<Integer>> distros = new ArrayList<List<Integer>>(distributions(bound, elems)); distrosLoop: for (int j = 0; j < distros.size(); j++) { List<Integer> distro = distros.get(j); Regexp[] exps = new Regexp[distro.size()]; for (int i = 0; i < elems.size(); i++) { GrammarProductionElement elem = elems.get(i); int sizeForElem = distro.get(i); if (terms_are_single_char) { if (sizeForElem > 1 && (elem.getKind() == GrammarElementKind.GTERMINAL || elem.getKind() == GrammarElementKind.GSPECIAL)) { continue distrosLoop; // no way you can generate a string longer than 1 from a terminal } if (sizeForElem == 1 && elem.getKind() == GrammarElementKind.GTERMINAL) { TerminalElement te = (TerminalElement) elem; exps[i] = HampiConstraints.constRegexp(te.getNameNoQuotes()); } else if (sizeForElem == 1 && elem.getKind() == GrammarElementKind.GSPECIAL) { SpecialElement spec = (SpecialElement) elem; exps[i] = HampiConstraints.constRegexp(spec.getNameNoDelimiters()); } else if (elem.getKind() == GrammarElementKind.GNONTERMINAL) { NonterminalElement nt = (NonterminalElement) elem; if (bounds.containsKey(nt) && bounds.get(nt) < sizeForElem) { // cannot generate a string longer than the upper bound on // all strings generatable from the nonterminal continue distrosLoop; } Regexp subRegexp = internalGetBoundedRegexp(g, nt.getName(), sizeForElem); if (subRegexp != null) { exps[i] = subRegexp; } else { continue distrosLoop; } } else throw new IllegalStateException("expected a nonterminal or special" + elem); } else { if (elem.getKind() == GrammarElementKind.GSPECIAL) throw new UnsupportedOperationException("not implemented yet"); if (elem.getKind() == GrammarElementKind.GTERMINAL) { TerminalElement term = (TerminalElement) elem; if (term.getNameNoQuotes().length() != sizeForElem) { continue distrosLoop; // no way you can generate a string this long } else { exps[i] = HampiConstraints.constRegexp(term.getNameNoQuotes()); } } else if (elem.getKind() == GrammarElementKind.GNONTERMINAL) { NonterminalElement nt = (NonterminalElement) elem; if (bounds.containsKey(nt) && bounds.get(nt) < sizeForElem) { // cannot generate a string longer than the upper bound on // all strings generatable from the nonterminal continue distrosLoop; } Regexp subRegexp = internalGetBoundedRegexp(g, nt.getName(), sizeForElem); if (subRegexp != null) { exps[i] = subRegexp; } else { continue distrosLoop; } } else throw new IllegalStateException("expected a nonterminal or special" + elem); } } Regexp e; if (exps.length == 1) { e = exps[0]; } else { e = HampiConstraints.concatRegexp(exps); } if (!x.contains(e)) { x.add(e); } } } } Regexp result; if (x.isEmpty() && !canGenerateEmptyString) { result = null; } else if (x.isEmpty() && canGenerateEmptyString) { Hampi h = new Hampi(); result = h.constRegexp(""); } else if (x.size() == 1) { result = x.get(0); } else { Hampi h = new Hampi(); result = h.orRegexp(x.toArray(new Regexp[x.size()])); } regexpCache.put(startSymbol, bound, result); return result; }