/* * Copyright (C) 2009-2012 University of Freiburg * * This file is part of SMTInterpol. * * SMTInterpol is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * SMTInterpol 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with SMTInterpol. If not, see <http://www.gnu.org/licenses/>. */ package de.uni_freiburg.informatik.ultimate.logic; import java.util.ArrayDeque; /** * This class does a recursive algorithm by using an explicit stack on * the heap. * * If you need a stateless walker, you can just implement Walker. If * your goal is to walk terms, then TermWalker may help you, as it already * dispatches the walk function based on the type of the term. A simple * term walker can be created as: * * <pre> * class MyWalker extends TermWalker { * MyWalker(Term term) { super(term) } * walk(NonRecursiveWalker walker, final ApplicationTerm appTerm) { * walker.addWorkItem(new NonRecursive.Walker() { * public void walk(NonRecursiveWalker walker) { * // ... code that should run after parameters are processed * } * } * for (Term param : appTerm.getParameters()) { * walker.enqueueWalker(new MyWalker(param)); * } * } * walk(... // handle other term classes... * </pre> * * For stateful walker you need to extend the class NonRecursive. In * addition you still need a Walker class that does the job. It can * access the state by casting NonRecursive. * * Results can be added in a stateful walker to an additional result * stack. See FormulaUnLet as an example. * * @see ComputeFreeVariables * @see FormulaUnLet * @author Jochen Hoenicke */ public class NonRecursive { /* This class iterates the term in a non-recursive way. To achieve this * it uses a todo stack, which contains terms and a small info how much * of this term was already processed. Additionally it uses a convert * stack that contains the most recent converted terms, which is used * to collect the arguments of function calls and the subterm of other * terms. */ /** * The todo stack. It contains the terms to convert and some info how much * was already processed of this term. */ private final ArrayDeque<Walker> mTodo = new ArrayDeque<Walker>(); /** * Walker that does some piece of work. This can be added to * the todo stack to be executed later. * * @author hoenicke */ protected interface Walker { /** * Do one step of the recursive algorithm. This may enqueue new * walkers that do the remaining steps. * @param engine The non recursive engine where new walkers * can be enqueued. */ public void walk(NonRecursive engine); } /** * Manually reset this walker. This function can be used to clear the * todo stack when an exception is raised by a walker. This exception will * terminate the non-recursive walk but will leave some walker in the todo * stack. */ protected void reset() { mTodo.clear(); } /** * Enqueues a walker on the todo stack. * @param item the walker to enqueue. */ public void enqueueWalker(Walker item) { mTodo.addLast(item); } /** * The main work horse. This will repeat doing work items until the * todo stack is empty. * @param item the walker to execute initially. */ public void run(Walker item) { mTodo.addLast(item); run(); } /** * The main work horse. This will repeat doing work items until the * todo stack is empty. This method expects that some Walker are on * the todo stack. */ public void run() { while (!mTodo.isEmpty()) { mTodo.removeLast().walk(this); } } @Override public String toString() { return mTodo.toString(); } /** * Walker that walks non-recursively over terms. * This dispatches the walk function. You still have to provide * the code that chooses which sub terms to walk. * * @author hoenicke */ public static abstract class TermWalker implements Walker { protected Term mTerm; public TermWalker(Term term) { mTerm = term; } @Override public void walk(NonRecursive walker) { if (mTerm instanceof ApplicationTerm) { walk(walker, (ApplicationTerm) mTerm); } else if (mTerm instanceof LetTerm) { walk(walker, (LetTerm) mTerm); } else if (mTerm instanceof AnnotatedTerm) { walk(walker, (AnnotatedTerm) mTerm); } else if (mTerm instanceof QuantifiedFormula) { walk(walker, (QuantifiedFormula) mTerm); } else if (mTerm instanceof ConstantTerm) { walk(walker, (ConstantTerm) mTerm); } else if (mTerm instanceof TermVariable) { walk(walker, (TermVariable) mTerm); } } public abstract void walk(NonRecursive walker, ConstantTerm term); public abstract void walk(NonRecursive walker, AnnotatedTerm term); public abstract void walk(NonRecursive walker, ApplicationTerm term); public abstract void walk(NonRecursive walker, LetTerm term); public abstract void walk(NonRecursive walker, QuantifiedFormula term); public abstract void walk(NonRecursive walker, TermVariable term); public Term getTerm() { return mTerm; } @Override public String toString() { return getClass().getSimpleName() + ":" + mTerm; } } }