/* * 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.smtinterpol.smtlib2; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Reader; import java.util.ArrayDeque; import java.util.Deque; import java.util.Locale; import java.util.Map; import de.uni_freiburg.informatik.ultimate.logic.PrintTerm; import de.uni_freiburg.informatik.ultimate.logic.QuotedObject; import de.uni_freiburg.informatik.ultimate.logic.SMTLIBException; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.smtinterpol.Config; import de.uni_freiburg.informatik.ultimate.smtinterpol.option.FrontEndOptions; import de.uni_freiburg.informatik.ultimate.smtinterpol.option.OptionMap; import de.uni_freiburg.informatik.ultimate.smtinterpol.util.MySymbolFactory; public class ParseEnvironment { final Script mScript; private File mCwd = null; // What to do when script exits private ExitHook mExitHook; // Initialize this lazily. private Deque<Long> mTiming; private final FrontEndOptions mOptions; private Lexer mLexer = null; private boolean mVersion25 = true; public ParseEnvironment(Script script, OptionMap options) { this(script, null, options); } public ParseEnvironment(Script script, ExitHook exit, OptionMap options) { mScript = script; mExitHook = exit; mOptions = options.getFrontEndOptions(); if (!mOptions.isFrontEndActive()) { throw new IllegalArgumentException("Front End not active!"); } } public Script getScript() { return mScript; } static boolean convertSexp(StringBuilder sb, Object o, int level) { if (o instanceof Object[]) { if (Config.RESULTS_ONE_PER_LINE && level > 0) { sb.append(System.getProperty("line.separator")); for (int i = 0; i < level; ++i) { sb.append(' '); } } sb.append('('); final Object[] array = (Object[])o; boolean subarray = false; String sep = ""; for (final Object el : array) { sb.append(sep); subarray |= convertSexp(sb, el, level + Config.INDENTATION); sep = " "; } if (subarray && Config.RESULTS_ONE_PER_LINE) { sb.append(System.getProperty("line.separator")); for (int i = 0; i < level; ++i) { sb.append(' '); } } sb.append(')'); return true; } else { sb.append(o); } return false; } public void parseScript(String filename) throws SMTLIBException { final File oldcwd = mCwd; Reader reader = null; boolean closeReader = false; try { if (filename.equals("<stdin>")) { reader = new InputStreamReader(System.in); } else { File script = new File(filename); if (!script.isAbsolute()) { script = new File(mCwd, filename); } mCwd = script.getParentFile(); try { reader = new FileReader(script); closeReader = true; } catch (final FileNotFoundException ex) { throw new SMTLIBException("File not found: " + filename); } } parseStream(reader, filename); } finally { mCwd = oldcwd; if (closeReader) { try { reader.close(); } catch (final IOException ex) { } } } } public void parseStream(Reader reader, String streamname) throws SMTLIBException { final MySymbolFactory symfactory = new MySymbolFactory(); final Lexer last = mLexer; mLexer = new Lexer(reader); mLexer.setSymbolFactory(symfactory); final Parser parser = new Parser(mLexer, symfactory); parser.setFileName(streamname); parser.setParseEnvironment(this); try { parser.parse(); } catch (final Exception ex) { System.err.println("Unexpected Exception: " + ex); throw new SMTLIBException(ex); } finally { mLexer = last; } } public void include(String filename) throws SMTLIBException { final ExitHook oldexit = mExitHook; mExitHook = new ExitHook() { @Override public void exitHook() { /* ignore exit */ } }; final File oldcwd = mCwd; parseScript(filename); mCwd = oldcwd; mExitHook = oldexit; } public void printSuccess() { if (mOptions.isPrintSuccess()) { final PrintWriter out = mOptions.getOutChannel(); out.println("success"); out.flush(); } } public void printError(String message) { final PrintWriter out = mOptions.getOutChannel(); out.print("(error \""); out.print(message); out.println("\")"); out.flush(); if (!mOptions.continueOnError()) { System.exit(1); } } public void printValues(Map<Term, Term> values) { final PrintTerm pt = new PrintTerm(); final PrintWriter out = mOptions.getOutChannel(); out.print('('); String sep = ""; final String itemSep = Config.RESULTS_ONE_PER_LINE ? System.getProperty("line.separator") + " " : " "; for (final Map.Entry<Term, Term> me : values.entrySet()) { out.print(sep); out.print('('); pt.append(out, me.getKey()); out.print(' '); pt.append(out, me.getValue()); out.print(')'); sep = itemSep; } out.println(')'); out.flush(); } public void printResponse(Object response) { final PrintWriter out = mOptions.getOutChannel(); if (!mOptions.isPrintTermsCSE()) { if (response instanceof Term) { new PrintTerm().append(out, (Term) response); out.println(); out.flush(); return; } else if (response instanceof Term[]) { printTermResponse((Term[])response); out.flush(); return; } } if (response instanceof Object[]) { final StringBuilder sb = new StringBuilder(); convertSexp(sb, response, 0); out.println(sb.toString()); } else if (response instanceof Iterable) { final Iterable<?> it = (Iterable<?>) response; out.print("("); for (final Object o : it) { printResponse(o); } out.println(")"); } else if (response instanceof QuotedObject) { out.println(((QuotedObject) response).toString(mVersion25)); } else { out.println(response); } out.flush(); } public void printInfoResponse(String info, Object response) { final PrintWriter out = mOptions.getOutChannel(); final StringBuilder sb = new StringBuilder(); sb.append('(').append(info).append(' '); convertSexp(sb, response, 0); out.println(sb.append(')').toString()); out.flush(); } /** * Direct printing of a term array response. This function is introduced to * satisfy the requirement of the SMTLIB standard for the get-assertions * command. We have to print the terms "as they are asserted", i.e., * without introducing let terms via cse. * @param response The response to print. */ public void printTermResponse(Term[] response) { final StringBuilder sb = new StringBuilder(); final PrintTerm pt = new PrintTerm(); sb.append('('); String sep = ""; final String itemSep = Config.RESULTS_ONE_PER_LINE ? System.getProperty("line.separator") + " " : " "; for (final Term t : response) { sb.append(sep); pt.append(sb, t); sep = itemSep; } sb.append(')'); mOptions.getOutChannel().println(sb.toString()); mOptions.getOutChannel().flush(); } public void exit() { if (mExitHook == null) { mScript.exit(); Runtime.getRuntime().exit(0); } else { mExitHook.exitHook(); } } public void setInfo(String info, Object value) { if (info.equals(":smt-lib-version")) { final String svalue = String.valueOf(value); if ("2.5".equals(svalue)) { mVersion25 = true; mLexer.setVersion25(true); } else if ("2.0".equals(svalue)) { mVersion25 = false; mLexer.setVersion25(false); } else { printError("Unknown SMTLIB version"); } } else if (info.equals(":error-behavior")) { if ("immediate-exit".equals(value)) { mScript.setOption(":continue-on-error", false); } else if ("continued-execution".equals(value)) { mScript.setOption(":continue-on-error", true); } } mScript.setInfo(info, value); } public Object getInfo(String info) { if (info.equals(":error-behavior")) { return mOptions.continueOnError() ? "continued-execution" : "immediate-exit"; } return mScript.getInfo(info); } public void startTiming() { if (mTiming == null) { mTiming = new ArrayDeque<Long>(); } mOptions.getOutChannel().print('('); mTiming.push(System.nanoTime()); } public void endTiming() { final long old = mTiming.pop(); final long duration = System.nanoTime() - old; final double secs = duration / 1000000000.0; // NOCHECKSTYLE mOptions.getOutChannel().printf((Locale) null, " :time %.3f)", secs); mOptions.getOutChannel().println(); mOptions.getOutChannel().flush(); } public boolean isContinueOnError() { return mOptions.continueOnError(); } }