1 /******************************************************************************
2 * Top contributors (to current version):
3 * Morgan Deters, Liana Hadarean, Tim King
5 * This file is part of the cvc5 project.
7 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8 * in the top-level source directory and their institutional affiliations.
9 * All rights reserved. See the file COPYING in the top-level source
10 * directory for licensing information.
11 * ****************************************************************************
13 * Driver for cvc5 executable (cvc5).
27 #include "api/cpp/cvc5.h"
28 #include "base/configuration.h"
29 #include "base/cvc5config.h"
30 #include "base/output.h"
31 #include "main/command_executor.h"
32 #include "main/interactive_shell.h"
33 #include "main/main.h"
34 #include "main/options.h"
35 #include "main/signal_handlers.h"
36 #include "main/time_limit.h"
37 #include "options/base_options.h"
38 #include "options/main_options.h"
39 #include "options/option_exception.h"
40 #include "options/options.h"
41 #include "options/options_public.h"
42 #include "options/parser_options.h"
43 #include "options/set_language.h"
44 #include "parser/parser.h"
45 #include "parser/parser_builder.h"
46 #include "smt/command.h"
47 #include "smt/smt_engine.h"
48 #include "util/result.h"
52 using namespace cvc5::parser
;
53 using namespace cvc5::main
;
61 /** Just the basename component of argv[0] */
64 /** A pointer to the CommandExecutor (the signal handlers need it) */
65 std::unique_ptr
<cvc5::main::CommandExecutor
> pExecutor
;
67 /** The time point the binary started, accessible to signal handlers */
68 std::unique_ptr
<TotalTimer
> totalTime
;
70 TotalTimer::~TotalTimer()
72 if (pExecutor
!= nullptr)
74 auto duration
= std::chrono::steady_clock::now() - d_start
;
75 pExecutor
->getSmtEngine()->setTotalTimeStatistic(
76 std::chrono::duration
<double>(duration
).count());
83 void printUsage(const api::DriverOptions
& dopts
, bool full
)
86 ss
<< "usage: " << progName
<< " [options] [input-file]" << std::endl
88 << "Without an input file, or with `-', cvc5 reads from standard "
92 << "cvc5 options:" << std::endl
;
95 main::printUsage(ss
.str(), dopts
.out());
99 main::printShortUsage(ss
.str(), dopts
.out());
103 int runCvc5(int argc
, char* argv
[], std::unique_ptr
<api::Solver
>& solver
)
105 main::totalTime
= std::make_unique
<TotalTimer
>();
107 // Initialize the signal handlers
108 signal_handlers::install();
112 // Create the command executor to execute the parsed commands
113 pExecutor
= std::make_unique
<CommandExecutor
>(solver
);
114 api::DriverOptions dopts
= solver
->getDriverOptions();
115 Options
* opts
= &pExecutor
->getOptions();
118 std::vector
<string
> filenames
= main::parse(*solver
, argc
, argv
, progName
);
120 auto limit
= install_time_limit(*opts
);
122 if (opts
->driver
.help
)
124 printUsage(dopts
, true);
127 else if (opts
->base
.languageHelp
)
129 main::printLanguageHelp(dopts
.out());
132 else if (opts
->driver
.version
)
134 dopts
.out() << Configuration::about().c_str() << flush
;
138 segvSpin
= opts
->driver
.segvSpin
;
140 // If in competition mode, set output stream option to flush immediately
141 #ifdef CVC5_COMPETITION_MODE
142 dopts
.out() << unitbuf
;
143 #endif /* CVC5_COMPETITION_MODE */
145 // We only accept one input file
146 if(filenames
.size() > 1) {
147 throw Exception("Too many input files specified.");
150 // If no file supplied we will read from standard input
151 const bool inputFromStdin
= filenames
.empty() || filenames
[0] == "-";
153 // if we're reading from stdin on a TTY, default to interactive mode
154 if (!opts
->driver
.interactiveWasSetByUser
)
156 opts
->driver
.interactive
= inputFromStdin
&& isatty(fileno(stdin
));
159 // Auto-detect input language by filename extension
160 std::string
filenameStr("<stdin>");
161 if (!inputFromStdin
) {
162 filenameStr
= std::move(filenames
[0]);
164 const char* filename
= filenameStr
.c_str();
166 if (solver
->getOption("input-language") == "LANG_AUTO")
168 if( inputFromStdin
) {
169 // We can't do any fancy detection on stdin
170 solver
->setOption("input-language", "cvc");
172 size_t len
= filenameStr
.size();
173 if(len
>= 5 && !strcmp(".smt2", filename
+ len
- 5)) {
174 solver
->setOption("input-language", "smt2");
175 } else if((len
>= 2 && !strcmp(".p", filename
+ len
- 2))
176 || (len
>= 5 && !strcmp(".tptp", filename
+ len
- 5))) {
177 solver
->setOption("input-language", "tptp");
178 } else if(( len
>= 4 && !strcmp(".cvc", filename
+ len
- 4) )
179 || ( len
>= 5 && !strcmp(".cvc4", filename
+ len
- 5) )) {
180 solver
->setOption("input-language", "cvc");
181 } else if((len
>= 3 && !strcmp(".sy", filename
+ len
- 3))
182 || (len
>= 3 && !strcmp(".sl", filename
+ len
- 3))) {
183 // version 2 sygus is the default
184 solver
->setOption("input-language", "sygus2");
189 if (solver
->getOption("output-language") == "LANG_AUTO")
191 solver
->setOption("output-language", solver
->getOption("input-language"));
193 pExecutor
->storeOptionsAsOriginal();
195 // Determine which messages to show based on smtcomp_mode and verbosity
196 if(Configuration::isMuzzledBuild()) {
197 DebugChannel
.setStream(&cvc5::null_os
);
198 TraceChannel
.setStream(&cvc5::null_os
);
199 NoticeChannel
.setStream(&cvc5::null_os
);
200 ChatChannel
.setStream(&cvc5::null_os
);
201 MessageChannel
.setStream(&cvc5::null_os
);
202 WarningChannel
.setStream(&cvc5::null_os
);
207 // notify SmtEngine that we are starting to parse
208 pExecutor
->getSmtEngine()->notifyStartParsing(filenameStr
);
210 // Parse and execute commands until we are done
211 std::unique_ptr
<Command
> cmd
;
213 if (opts
->driver
.interactive
&& inputFromStdin
)
215 if (!opts
->base
.incrementalSolvingWasSetByUser
)
217 cmd
.reset(new SetOptionCommand("incremental", "true"));
219 pExecutor
->doCommand(cmd
);
221 InteractiveShell
shell(pExecutor
->getSolver(),
222 pExecutor
->getSymbolManager());
224 CVC5Message() << Configuration::getPackageName() << " "
225 << Configuration::getVersionString();
226 if (Configuration::isGitBuild())
228 CVC5Message() << " [" << Configuration::getGitId() << "]";
230 CVC5Message() << (Configuration::isDebugBuild() ? " DEBUG" : "")
232 << (Configuration::isAssertionBuild() ? "on" : "off")
235 CVC5Message() << Configuration::copyright() << endl
;
239 cmd
.reset(shell
.readCommand());
240 } catch(UnsafeInterruptException
& e
) {
241 dopts
.out() << CommandInterrupted();
246 status
= pExecutor
->doCommand(cmd
) && status
;
247 opts
= &pExecutor
->getOptions();
248 if (cmd
->interrupted()) {
255 if (!opts
->base
.incrementalSolvingWasSetByUser
)
257 cmd
.reset(new SetOptionCommand("incremental", "false"));
259 pExecutor
->doCommand(cmd
);
262 ParserBuilder
parserBuilder(
263 pExecutor
->getSolver(), pExecutor
->getSymbolManager(), true);
264 std::unique_ptr
<Parser
> parser(parserBuilder
.build());
265 if( inputFromStdin
) {
266 parser
->setInput(Input::newStreamInput(
267 solver
->getOption("input-language"), cin
, filename
));
272 Input::newFileInput(solver
->getOption("input-language"),
274 solver
->getOption("mmap") == "true"));
277 bool interrupted
= false;
281 dopts
.out() << CommandInterrupted();
283 opts
= &pExecutor
->getOptions();
287 cmd
.reset(parser
->nextCommand());
288 if (cmd
== nullptr) break;
289 } catch (UnsafeInterruptException
& e
) {
294 status
= pExecutor
->doCommand(cmd
);
295 opts
= &pExecutor
->getOptions();
296 if (cmd
->interrupted() && status
== 0) {
301 if(dynamic_cast<QuitCommand
*>(cmd
.get()) != nullptr) {
309 result
= pExecutor
->getResult();
312 // there was some kind of error
316 #ifdef CVC5_COMPETITION_MODE
317 dopts
.out() << std::flush
;
318 // exit, don't return (don't want destructors to run)
319 // _exit() from unistd.h doesn't run global destructors
320 // or other on_exit/atexit stuff.
322 #endif /* CVC5_COMPETITION_MODE */
325 pExecutor
->flushOutputStreams();
328 if (opts
->driver
.earlyExit
&& opts
->driver
.earlyExitWasSetByUser
)
332 #else /* CVC5_DEBUG */
333 if (opts
->driver
.earlyExit
)
337 #endif /* CVC5_DEBUG */
342 signal_handlers::cleanup();