Remove SMT1 parser. (#3228)
[cvc5.git] / src / main / driver_unified.cpp
1 /********************* */
2 /*! \file driver_unified.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Morgan Deters, Tim King, Liana Hadarean
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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.\endverbatim
11 **
12 ** \brief Driver for CVC4 executable (cvc4) unified for both
13 ** sequential and portfolio versions
14 **/
15
16 #include <stdio.h>
17 #include <unistd.h>
18
19 #include <cstdlib>
20 #include <cstring>
21 #include <fstream>
22 #include <iostream>
23 #include <memory>
24 #include <new>
25
26 #include "cvc4autoconfig.h"
27
28 #include "api/cvc4cpp.h"
29 #include "base/configuration.h"
30 #include "base/output.h"
31 #include "expr/expr_iomanip.h"
32 #include "expr/expr_manager.h"
33 #include "main/command_executor.h"
34 #include "main/interactive_shell.h"
35 #include "main/main.h"
36 #include "options/options.h"
37 #include "options/set_language.h"
38 #include "parser/parser.h"
39 #include "parser/parser_builder.h"
40 #include "parser/parser_exception.h"
41 #include "smt/command.h"
42 #include "util/result.h"
43 #include "util/statistics_registry.h"
44
45 // The PORTFOLIO_BUILD is defined when compiling pcvc4 (the parallel version of
46 // CVC4) and undefined otherwise. The macro can only be used in
47 // driver_unified.cpp because we do not recompile all files for pcvc4.
48 #ifdef PORTFOLIO_BUILD
49 # include "main/command_executor_portfolio.h"
50 #endif
51
52 using namespace std;
53 using namespace CVC4;
54 using namespace CVC4::parser;
55 using namespace CVC4::main;
56
57 namespace CVC4 {
58 namespace main {
59 /** Global options variable */
60 thread_local Options* pOptions;
61
62 /** Full argv[0] */
63 const char *progPath;
64
65 /** Just the basename component of argv[0] */
66 const std::string *progName;
67
68 /** A pointer to the CommandExecutor (the signal handlers need it) */
69 CVC4::main::CommandExecutor* pExecutor = NULL;
70
71 /** A pointer to the totalTime driver stat (the signal handlers need it) */
72 CVC4::TimerStat* pTotalTime = NULL;
73
74 }/* CVC4::main namespace */
75 }/* CVC4 namespace */
76
77
78 void printUsage(Options& opts, bool full) {
79 stringstream ss;
80 ss << "usage: " << opts.getBinaryName() << " [options] [input-file]"
81 << endl << endl
82 << "Without an input file, or with `-', CVC4 reads from standard input."
83 << endl << endl
84 << "CVC4 options:" << endl;
85 if(full) {
86 Options::printUsage( ss.str(), *(opts.getOut()) );
87 } else {
88 Options::printShortUsage( ss.str(), *(opts.getOut()) );
89 }
90 }
91
92 int runCvc4(int argc, char* argv[], Options& opts) {
93
94 // Timer statistic
95 pTotalTime = new TimerStat("totalTime");
96 pTotalTime->start();
97
98 // For the signal handlers' benefit
99 pOptions = &opts;
100
101 // Initialize the signal handlers
102 cvc4_init();
103
104 progPath = argv[0];
105
106 // Parse the options
107 vector<string> filenames = Options::parseOptions(&opts, argc, argv);
108
109 # ifndef PORTFOLIO_BUILD
110 if( opts.wasSetByUserThreads() ||
111 opts.wasSetByUserThreadStackSize() ||
112 (! opts.getThreadArgv().empty()) ) {
113 throw OptionException("Thread options cannot be used with sequential CVC4. Please build and use the portfolio binary `pcvc4'.");
114 }
115 # endif
116
117 string progNameStr = opts.getBinaryName();
118 progName = &progNameStr;
119
120 if( opts.getHelp() ) {
121 printUsage(opts, true);
122 exit(1);
123 } else if( opts.getLanguageHelp() ) {
124 Options::printLanguageHelp(*(opts.getOut()));
125 exit(1);
126 } else if( opts.getVersion() ) {
127 *(opts.getOut()) << Configuration::about().c_str() << flush;
128 exit(0);
129 }
130
131 segvSpin = opts.getSegvSpin();
132
133 // If in competition mode, set output stream option to flush immediately
134 #ifdef CVC4_COMPETITION_MODE
135 *(opts.getOut()) << unitbuf;
136 #endif /* CVC4_COMPETITION_MODE */
137
138 // We only accept one input file
139 if(filenames.size() > 1) {
140 throw Exception("Too many input files specified.");
141 }
142
143 // If no file supplied we will read from standard input
144 const bool inputFromStdin = filenames.empty() || filenames[0] == "-";
145
146 // if we're reading from stdin on a TTY, default to interactive mode
147 if(!opts.wasSetByUserInteractive()) {
148 opts.setInteractive(inputFromStdin && isatty(fileno(stdin)));
149 }
150
151 // Auto-detect input language by filename extension
152 std::string filenameStr("<stdin>");
153 if (!inputFromStdin) {
154 // Use swap to avoid copying the string
155 // TODO: use std::move() when switching to c++11
156 filenameStr.swap(filenames[0]);
157 }
158 const char* filename = filenameStr.c_str();
159
160 if(opts.getInputLanguage() == language::input::LANG_AUTO) {
161 if( inputFromStdin ) {
162 // We can't do any fancy detection on stdin
163 opts.setInputLanguage(language::input::LANG_CVC4);
164 } else {
165 unsigned len = filenameStr.size();
166 if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
167 opts.setInputLanguage(language::input::LANG_SMTLIB_V2_6);
168 } else if((len >= 2 && !strcmp(".p", filename + len - 2))
169 || (len >= 5 && !strcmp(".tptp", filename + len - 5))) {
170 opts.setInputLanguage(language::input::LANG_TPTP);
171 } else if(( len >= 4 && !strcmp(".cvc", filename + len - 4) )
172 || ( len >= 5 && !strcmp(".cvc4", filename + len - 5) )) {
173 opts.setInputLanguage(language::input::LANG_CVC4);
174 } else if((len >= 3 && !strcmp(".sy", filename + len - 3))
175 || (len >= 3 && !strcmp(".sl", filename + len - 3))) {
176 opts.setInputLanguage(language::input::LANG_SYGUS);
177 //since there is no sygus output language, set this to SMT lib 2
178 //opts.setOutputLanguage(language::output::LANG_SMTLIB_V2_0);
179 }
180 }
181 }
182
183 if(opts.getOutputLanguage() == language::output::LANG_AUTO) {
184 opts.setOutputLanguage(language::toOutputLanguage(opts.getInputLanguage()));
185 }
186
187 // Determine which messages to show based on smtcomp_mode and verbosity
188 if(Configuration::isMuzzledBuild()) {
189 DebugChannel.setStream(&CVC4::null_os);
190 TraceChannel.setStream(&CVC4::null_os);
191 NoticeChannel.setStream(&CVC4::null_os);
192 ChatChannel.setStream(&CVC4::null_os);
193 MessageChannel.setStream(&CVC4::null_os);
194 WarningChannel.setStream(&CVC4::null_os);
195 }
196
197 // important even for muzzled builds (to get result output right)
198 (*(opts.getOut())) << language::SetLanguage(opts.getOutputLanguage());
199
200 // Create the expression manager using appropriate options
201 std::unique_ptr<api::Solver> solver;
202 # ifndef PORTFOLIO_BUILD
203 solver.reset(new api::Solver(&opts));
204 pExecutor = new CommandExecutor(solver.get(), opts);
205 # else
206 OptionsList threadOpts;
207 parseThreadSpecificOptions(threadOpts, opts);
208
209 bool useParallelExecutor = true;
210 // incremental?
211 if(opts.wasSetByUserIncrementalSolving() &&
212 opts.getIncrementalSolving() &&
213 (! opts.getIncrementalParallel()) ) {
214 Notice() << "Notice: In --incremental mode, using the sequential solver"
215 << " unless forced by...\n"
216 << "Notice: ...the experimental --incremental-parallel option.\n";
217 useParallelExecutor = false;
218 }
219 // proofs?
220 if(opts.getCheckProofs()) {
221 if(opts.getFallbackSequential()) {
222 Warning() << "Warning: Falling back to sequential mode, as cannot run"
223 << " portfolio in check-proofs mode.\n";
224 useParallelExecutor = false;
225 }
226 else {
227 throw OptionException("Cannot run portfolio in check-proofs mode.");
228 }
229 }
230 // pick appropriate one
231 if (useParallelExecutor)
232 {
233 solver.reset(new api::Solver(&threadOpts[0]));
234 pExecutor = new CommandExecutorPortfolio(solver.get(), opts, threadOpts);
235 }
236 else
237 {
238 solver.reset(new api::Solver(&opts));
239 pExecutor = new CommandExecutor(solver.get(), opts);
240 }
241 # endif
242
243 std::unique_ptr<Parser> replayParser;
244 if (opts.getReplayInputFilename() != "")
245 {
246 std::string replayFilename = opts.getReplayInputFilename();
247 ParserBuilder replayParserBuilder(solver.get(), replayFilename, opts);
248
249 if( replayFilename == "-") {
250 if( inputFromStdin ) {
251 throw OptionException("Replay file and input file can't both be stdin.");
252 }
253 replayParserBuilder.withStreamInput(cin);
254 }
255 replayParser.reset(replayParserBuilder.build());
256 pExecutor->setReplayStream(new Parser::ExprStream(replayParser.get()));
257 }
258
259 int returnValue = 0;
260 {
261 // Timer statistic
262 RegisterStatistic statTotalTime(&pExecutor->getStatisticsRegistry(),
263 pTotalTime);
264
265 // Filename statistics
266 ReferenceStat<std::string> s_statFilename("filename", filenameStr);
267 RegisterStatistic statFilenameReg(&pExecutor->getStatisticsRegistry(),
268 &s_statFilename);
269 // set filename in smt engine
270 pExecutor->getSmtEngine()->setFilename(filenameStr);
271
272 // Parse and execute commands until we are done
273 Command* cmd;
274 bool status = true;
275 if(opts.getInteractive() && inputFromStdin) {
276 if(opts.getTearDownIncremental() > 0) {
277 throw OptionException(
278 "--tear-down-incremental doesn't work in interactive mode");
279 }
280 #ifndef PORTFOLIO_BUILD
281 if(!opts.wasSetByUserIncrementalSolving()) {
282 cmd = new SetOptionCommand("incremental", SExpr(true));
283 cmd->setMuted(true);
284 pExecutor->doCommand(cmd);
285 delete cmd;
286 }
287 #endif /* PORTFOLIO_BUILD */
288 InteractiveShell shell(solver.get());
289 if(opts.getInteractivePrompt()) {
290 Message() << Configuration::getPackageName()
291 << " " << Configuration::getVersionString();
292 if(Configuration::isGitBuild()) {
293 Message() << " [" << Configuration::getGitId() << "]";
294 }
295 Message() << (Configuration::isDebugBuild() ? " DEBUG" : "")
296 << " assertions:"
297 << (Configuration::isAssertionBuild() ? "on" : "off")
298 << endl << endl;
299 Message() << Configuration::copyright() << endl;
300 }
301 if(replayParser) {
302 // have the replay parser use the declarations input interactively
303 replayParser->useDeclarationsFrom(shell.getParser());
304 }
305
306 while(true) {
307 try {
308 cmd = shell.readCommand();
309 } catch(UnsafeInterruptException& e) {
310 (*opts.getOut()) << CommandInterrupted();
311 break;
312 }
313 if (cmd == NULL)
314 break;
315 status = pExecutor->doCommand(cmd) && status;
316 if (cmd->interrupted()) {
317 delete cmd;
318 break;
319 }
320 delete cmd;
321 }
322 } else if( opts.getTearDownIncremental() > 0) {
323 if(!opts.getIncrementalSolving() && opts.getTearDownIncremental() > 1) {
324 // For tear-down-incremental values greater than 1, need incremental
325 // on too.
326 cmd = new SetOptionCommand("incremental", SExpr(true));
327 cmd->setMuted(true);
328 pExecutor->doCommand(cmd);
329 delete cmd;
330 // if(opts.wasSetByUserIncrementalSolving()) {
331 // throw OptionException(
332 // "--tear-down-incremental incompatible with --incremental");
333 // }
334
335 // cmd = new SetOptionCommand("incremental", SExpr(false));
336 // cmd->setMuted(true);
337 // pExecutor->doCommand(cmd);
338 // delete cmd;
339 }
340
341 ParserBuilder parserBuilder(solver.get(), filename, opts);
342
343 if( inputFromStdin ) {
344 #if defined(CVC4_COMPETITION_MODE) && !defined(CVC4_SMTCOMP_APPLICATION_TRACK)
345 parserBuilder.withStreamInput(cin);
346 #else /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
347 parserBuilder.withLineBufferedStreamInput(cin);
348 #endif /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
349 }
350
351 vector< vector<Command*> > allCommands;
352 allCommands.push_back(vector<Command*>());
353 std::unique_ptr<Parser> parser(parserBuilder.build());
354 if(replayParser) {
355 // have the replay parser use the file's declarations
356 replayParser->useDeclarationsFrom(parser.get());
357 }
358 int needReset = 0;
359 // true if one of the commands was interrupted
360 bool interrupted = false;
361 while (status)
362 {
363 if (interrupted) {
364 (*opts.getOut()) << CommandInterrupted();
365 break;
366 }
367
368 try {
369 cmd = parser->nextCommand();
370 if (cmd == NULL) break;
371 } catch (UnsafeInterruptException& e) {
372 interrupted = true;
373 continue;
374 }
375
376 if(dynamic_cast<PushCommand*>(cmd) != NULL) {
377 if(needReset >= opts.getTearDownIncremental()) {
378 pExecutor->reset();
379 for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
380 if (interrupted) break;
381 for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j)
382 {
383 Command* cmd = allCommands[i][j]->clone();
384 cmd->setMuted(true);
385 pExecutor->doCommand(cmd);
386 if(cmd->interrupted()) {
387 interrupted = true;
388 }
389 delete cmd;
390 }
391 }
392 needReset = 0;
393 }
394 allCommands.push_back(vector<Command*>());
395 Command* copy = cmd->clone();
396 allCommands.back().push_back(copy);
397 status = pExecutor->doCommand(cmd);
398 if(cmd->interrupted()) {
399 interrupted = true;
400 continue;
401 }
402 } else if(dynamic_cast<PopCommand*>(cmd) != NULL) {
403 allCommands.pop_back(); // fixme leaks cmds here
404 if (needReset >= opts.getTearDownIncremental()) {
405 pExecutor->reset();
406 for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
407 for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j)
408 {
409 Command* cmd = allCommands[i][j]->clone();
410 cmd->setMuted(true);
411 pExecutor->doCommand(cmd);
412 if(cmd->interrupted()) {
413 interrupted = true;
414 }
415 delete cmd;
416 }
417 }
418 if (interrupted) continue;
419 (*opts.getOut()) << CommandSuccess();
420 needReset = 0;
421 } else {
422 status = pExecutor->doCommand(cmd);
423 if(cmd->interrupted()) {
424 interrupted = true;
425 continue;
426 }
427 }
428 } else if(dynamic_cast<CheckSatCommand*>(cmd) != NULL ||
429 dynamic_cast<QueryCommand*>(cmd) != NULL) {
430 if(needReset >= opts.getTearDownIncremental()) {
431 pExecutor->reset();
432 for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
433 for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j)
434 {
435 Command* cmd = allCommands[i][j]->clone();
436 cmd->setMuted(true);
437 pExecutor->doCommand(cmd);
438 if(cmd->interrupted()) {
439 interrupted = true;
440 }
441 delete cmd;
442 }
443 }
444 needReset = 0;
445 } else {
446 ++needReset;
447 }
448 if (interrupted) {
449 continue;
450 }
451
452 status = pExecutor->doCommand(cmd);
453 if(cmd->interrupted()) {
454 interrupted = true;
455 continue;
456 }
457 } else if(dynamic_cast<ResetCommand*>(cmd) != NULL) {
458 pExecutor->doCommand(cmd);
459 allCommands.clear();
460 allCommands.push_back(vector<Command*>());
461 } else {
462 // We shouldn't copy certain commands, because they can cause
463 // an error on replay since there's no associated sat/unsat check
464 // preceding them.
465 if(dynamic_cast<GetUnsatCoreCommand*>(cmd) == NULL &&
466 dynamic_cast<GetProofCommand*>(cmd) == NULL &&
467 dynamic_cast<GetValueCommand*>(cmd) == NULL &&
468 dynamic_cast<GetModelCommand*>(cmd) == NULL &&
469 dynamic_cast<GetAssignmentCommand*>(cmd) == NULL &&
470 dynamic_cast<GetInstantiationsCommand*>(cmd) == NULL &&
471 dynamic_cast<GetAssertionsCommand*>(cmd) == NULL &&
472 dynamic_cast<GetInfoCommand*>(cmd) == NULL &&
473 dynamic_cast<GetOptionCommand*>(cmd) == NULL &&
474 dynamic_cast<EchoCommand*>(cmd) == NULL) {
475 Command* copy = cmd->clone();
476 allCommands.back().push_back(copy);
477 }
478 status = pExecutor->doCommand(cmd);
479 if(cmd->interrupted()) {
480 interrupted = true;
481 continue;
482 }
483
484 if(dynamic_cast<QuitCommand*>(cmd) != NULL) {
485 delete cmd;
486 break;
487 }
488 }
489 delete cmd;
490 }
491 } else {
492 if(!opts.wasSetByUserIncrementalSolving()) {
493 cmd = new SetOptionCommand("incremental", SExpr(false));
494 cmd->setMuted(true);
495 pExecutor->doCommand(cmd);
496 delete cmd;
497 }
498
499 ParserBuilder parserBuilder(solver.get(), filename, opts);
500
501 if( inputFromStdin ) {
502 #if defined(CVC4_COMPETITION_MODE) && !defined(CVC4_SMTCOMP_APPLICATION_TRACK)
503 parserBuilder.withStreamInput(cin);
504 #else /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
505 parserBuilder.withLineBufferedStreamInput(cin);
506 #endif /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
507 }
508
509 std::unique_ptr<Parser> parser(parserBuilder.build());
510 if(replayParser) {
511 // have the replay parser use the file's declarations
512 replayParser->useDeclarationsFrom(parser.get());
513 }
514 bool interrupted = false;
515 while (status)
516 {
517 if (interrupted) {
518 (*opts.getOut()) << CommandInterrupted();
519 pExecutor->reset();
520 break;
521 }
522 try {
523 cmd = parser->nextCommand();
524 if (cmd == NULL) break;
525 } catch (UnsafeInterruptException& e) {
526 interrupted = true;
527 continue;
528 }
529
530 status = pExecutor->doCommand(cmd);
531 if (cmd->interrupted() && status == 0) {
532 interrupted = true;
533 break;
534 }
535
536 if(dynamic_cast<QuitCommand*>(cmd) != NULL) {
537 delete cmd;
538 break;
539 }
540 delete cmd;
541 }
542 }
543
544 Result result;
545 if(status) {
546 result = pExecutor->getResult();
547 returnValue = 0;
548 } else {
549 // there was some kind of error
550 returnValue = 1;
551 }
552
553 #ifdef CVC4_COMPETITION_MODE
554 opts.flushOut();
555 // exit, don't return (don't want destructors to run)
556 // _exit() from unistd.h doesn't run global destructors
557 // or other on_exit/atexit stuff.
558 _exit(returnValue);
559 #endif /* CVC4_COMPETITION_MODE */
560
561 ReferenceStat< Result > s_statSatResult("sat/unsat", result);
562 RegisterStatistic statSatResultReg(&pExecutor->getStatisticsRegistry(),
563 &s_statSatResult);
564
565 pTotalTime->stop();
566
567 // Tim: I think that following comment is out of date?
568 // Set the global executor pointer to NULL first. If we get a
569 // signal while dumping statistics, we don't want to try again.
570 pExecutor->flushOutputStreams();
571
572 #ifdef CVC4_DEBUG
573 if(opts.getEarlyExit() && opts.wasSetByUserEarlyExit()) {
574 _exit(returnValue);
575 }
576 #else /* CVC4_DEBUG */
577 if(opts.getEarlyExit()) {
578 _exit(returnValue);
579 }
580 #endif /* CVC4_DEBUG */
581 }
582
583 // On exceptional exit, these are leaked, but that's okay... they
584 // need to be around in that case for main() to print statistics.
585 delete pTotalTime;
586 delete pExecutor;
587
588 pTotalTime = NULL;
589 pExecutor = NULL;
590
591 cvc4_shutdown();
592
593 return returnValue;
594 }