/******************************************************************************* * LastCalc - The last calculator you'll ever need * Copyright (C) 2011, 2012 Uprizer Labs LLC * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Affero General Public License for more * details. ******************************************************************************/ package com.lastcalc.engines; import java.util.*; import com.google.common.collect.*; import com.lastcalc.TokenList; import com.lastcalc.engines.ParserPickerFactory.ParserPicker; import com.lastcalc.parsers.*; import com.lastcalc.parsers.Parser.ParseResult; public class BacktrackingParseEngine extends ParseEngine { private final ParserPickerFactory ppf; public BacktrackingParseEngine(final ParserPickerFactory ppf) { this.ppf = ppf; } private int lastParseStepCount = 0; private boolean dumpSteps = false; public void setDumpSteps(final boolean dumpSteps) { this.dumpSteps = dumpSteps; } @Override public LinkedList<ParseStep> parse(final TokenList input, final ParserContext context, final TokenList... alternateInputs) { lastParseStepCount = 0; final TreeSet<ParseStep> candidates = Sets.<ParseStep> newTreeSet(); final ParserPicker picker = ppf.getPicker(); candidates.add(new ParseStep(input, NoopParser.singleton, ParseResult.success(input), null, 0)); for (final TokenList alternateTL : alternateInputs) { candidates.add(new ParseStep(alternateTL, NoopParser.singleton, ParseResult.success(alternateTL), null, 0)); } final long startTime = System.currentTimeMillis(); ParserContext subContext; try { subContext = (ParserContext) context.clone(); } catch (final CloneNotSupportedException e) { throw new RuntimeException(e); } subContext.timeout = context.timeout / 5; final Set<ParseStep> exhausted = Sets.newHashSet(); outer: while (System.currentTimeMillis() - startTime < context.timeout && !candidates.first().isMinimal()) { for (final ParseStep candidateStep : candidates) { if (exhausted.contains(candidateStep)) { continue; } final ParseStep nextStep = picker.pickNext(subContext, candidateStep); if (nextStep != null && nextStep.result.isSuccess()) { lastParseStepCount++; if (dumpSteps) { System.out.println(lastParseStepCount + "\t" + nextStep); } candidates.add(nextStep); continue outer; } else { exhausted.add(candidateStep); } } break outer; } final LinkedList<ParseStep> steps = Lists.newLinkedList(); ParseStep bestStep = candidates.first(); bestStep.isMinimal(); while (bestStep != null) { steps.addFirst(bestStep); bestStep = bestStep.previous; } return steps; } public int getLastParseStepCount() { return lastParseStepCount; } }