GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/main/driver_unified.cpp Lines: 74 137 54.0 %
Date: 2021-09-17 Branches: 138 458 30.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Morgan Deters, Liana Hadarean, Tim King
4
 *
5
 * This file is part of the cvc5 project.
6
 *
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
 * ****************************************************************************
12
 *
13
 * Driver for cvc5 executable (cvc5).
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 "api/cpp/cvc5.h"
27
#include "base/configuration.h"
28
#include "base/cvc5config.h"
29
#include "base/output.h"
30
#include "main/command_executor.h"
31
#include "main/interactive_shell.h"
32
#include "main/main.h"
33
#include "main/options.h"
34
#include "main/signal_handlers.h"
35
#include "main/time_limit.h"
36
#include "parser/parser.h"
37
#include "parser/parser_builder.h"
38
#include "smt/command.h"
39
#include "smt/smt_engine.h"
40
#include "util/result.h"
41
42
using namespace std;
43
using namespace cvc5;
44
using namespace cvc5::parser;
45
using namespace cvc5::main;
46
47
namespace cvc5 {
48
namespace main {
49
50
/** Full argv[0] */
51
const char* progPath;
52
53
/** Just the basename component of argv[0] */
54
9852
std::string progName;
55
56
/** A pointer to the CommandExecutor (the signal handlers need it) */
57
9852
std::unique_ptr<cvc5::main::CommandExecutor> pExecutor;
58
59
}  // namespace main
60
}  // namespace cvc5
61
62
    void printUsage(const api::DriverOptions& dopts, bool full)
63
    {
64
      std::stringstream ss;
65
      ss << "usage: " << progName << " [options] [input-file]" << std::endl
66
         << std::endl
67
         << "Without an input file, or with `-', cvc5 reads from standard "
68
            "input."
69
         << std::endl
70
         << std::endl
71
         << "cvc5 options:" << std::endl;
72
      if (full)
73
      {
74
        main::printUsage(ss.str(), dopts.out());
75
      }
76
      else
77
      {
78
        main::printShortUsage(ss.str(), dopts.out());
79
      }
80
    }
81
82
8800
int runCvc5(int argc, char* argv[], std::unique_ptr<api::Solver>& solver)
83
{
84
  // Initialize the signal handlers
85
8800
  signal_handlers::install();
86
87
8800
  progPath = argv[0];
88
89
  // Create the command executor to execute the parsed commands
90
8800
  pExecutor = std::make_unique<CommandExecutor>(solver);
91
8800
  api::DriverOptions dopts = solver->getDriverOptions();
92
93
  // Parse the options
94
14973
  std::vector<string> filenames = main::parse(*solver, argc, argv, progName);
95
96
12346
  auto limit = install_time_limit(solver->getOptionInfo("tlimit").uintValue());
97
98
6173
  if (solver->getOptionInfo("help").boolValue())
99
  {
100
    printUsage(dopts, true);
101
    exit(1);
102
  }
103
6173
  else if (solver->getOptionInfo("language-help").boolValue())
104
  {
105
    main::printLanguageHelp(dopts.out());
106
    exit(1);
107
  }
108
6173
  else if (solver->getOptionInfo("version").boolValue())
109
  {
110
    dopts.out() << Configuration::about().c_str() << flush;
111
    exit(0);
112
  }
113
114
6173
  segvSpin = solver->getOptionInfo("segv-spin").boolValue();
115
116
  // If in competition mode, set output stream option to flush immediately
117
#ifdef CVC5_COMPETITION_MODE
118
  dopts.out() << unitbuf;
119
#endif /* CVC5_COMPETITION_MODE */
120
121
  // We only accept one input file
122
6173
  if(filenames.size() > 1) {
123
    throw Exception("Too many input files specified.");
124
  }
125
126
  // If no file supplied we will read from standard input
127
6173
  const bool inputFromStdin = filenames.empty() || filenames[0] == "-";
128
129
  // if we're reading from stdin on a TTY, default to interactive mode
130
6173
  if (!solver->getOptionInfo("interactive").setByUser)
131
  {
132
6173
    solver->setOption("interactive", (inputFromStdin && isatty(fileno(stdin))) ? "true" : "false");
133
  }
134
135
  // Auto-detect input language by filename extension
136
12346
  std::string filenameStr("<stdin>");
137
6173
  if (!inputFromStdin) {
138
6173
    filenameStr = std::move(filenames[0]);
139
  }
140
6173
  const char* filename = filenameStr.c_str();
141
142
6173
  if (solver->getOption("input-language") == "LANG_AUTO")
143
  {
144
5947
    if( inputFromStdin ) {
145
      // We can't do any fancy detection on stdin
146
      solver->setOption("input-language", "cvc");
147
    } else {
148
5947
      size_t len = filenameStr.size();
149
5947
      if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
150
5087
        solver->setOption("input-language", "smt2");
151
860
      } else if((len >= 2 && !strcmp(".p", filename + len - 2))
152
819
                || (len >= 5 && !strcmp(".tptp", filename + len - 5))) {
153
41
        solver->setOption("input-language", "tptp");
154
819
      } else if(( len >= 4 && !strcmp(".cvc", filename + len - 4) )
155
16
                || ( len >= 5 && !strcmp(".cvc4", filename + len - 5) )) {
156
803
        solver->setOption("input-language", "cvc");
157
16
      } else if((len >= 3 && !strcmp(".sy", filename + len - 3))
158
                || (len >= 3 && !strcmp(".sl", filename + len - 3))) {
159
        // version 2 sygus is the default
160
16
        solver->setOption("input-language", "sygus2");
161
      }
162
    }
163
  }
164
165
6173
  if (solver->getOption("output-language") == "LANG_AUTO")
166
  {
167
6173
    solver->setOption("output-language", solver->getOption("input-language"));
168
  }
169
6173
  pExecutor->storeOptionsAsOriginal();
170
171
  // Determine which messages to show based on smtcomp_mode and verbosity
172
6173
  if(Configuration::isMuzzledBuild()) {
173
    DebugChannel.setStream(&cvc5::null_os);
174
    TraceChannel.setStream(&cvc5::null_os);
175
    NoticeChannel.setStream(&cvc5::null_os);
176
    ChatChannel.setStream(&cvc5::null_os);
177
    MessageChannel.setStream(&cvc5::null_os);
178
    WarningChannel.setStream(&cvc5::null_os);
179
  }
180
181
6173
  int returnValue = 0;
182
  {
183
6173
    solver->setInfo("filename", filenameStr);
184
185
    // Parse and execute commands until we are done
186
12346
    std::unique_ptr<Command> cmd;
187
6173
    bool status = true;
188
6173
    if (solver->getOptionInfo("interactive").boolValue() && inputFromStdin)
189
    {
190
      if (!solver->getOptionInfo("incremental").setByUser)
191
      {
192
        cmd.reset(new SetOptionCommand("incremental", "true"));
193
        cmd->setMuted(true);
194
        pExecutor->doCommand(cmd);
195
      }
196
      InteractiveShell shell(pExecutor->getSolver(),
197
                             pExecutor->getSymbolManager(),
198
                             dopts.in(),
199
                             dopts.out());
200
201
      CVC5Message() << Configuration::getPackageName() << " "
202
                    << Configuration::getVersionString();
203
      if (Configuration::isGitBuild())
204
      {
205
        CVC5Message() << " [" << Configuration::getGitId() << "]";
206
      }
207
      CVC5Message() << (Configuration::isDebugBuild() ? " DEBUG" : "")
208
                    << " assertions:"
209
                    << (Configuration::isAssertionBuild() ? "on" : "off")
210
                    << endl
211
                    << endl;
212
      CVC5Message() << Configuration::copyright() << endl;
213
214
      while(true) {
215
        try {
216
          cmd.reset(shell.readCommand());
217
        } catch(UnsafeInterruptException& e) {
218
          dopts.out() << CommandInterrupted();
219
          break;
220
        }
221
        if (cmd == nullptr)
222
          break;
223
        status = pExecutor->doCommand(cmd) && status;
224
        if (cmd->interrupted()) {
225
          break;
226
        }
227
      }
228
    }
229
    else
230
    {
231
6173
      if (!solver->getOptionInfo("incremental").setByUser)
232
      {
233
5509
        cmd.reset(new SetOptionCommand("incremental", "false"));
234
5509
        cmd->setMuted(true);
235
5509
        pExecutor->doCommand(cmd);
236
      }
237
238
      ParserBuilder parserBuilder(
239
12346
          pExecutor->getSolver(), pExecutor->getSymbolManager(), true);
240
12346
      std::unique_ptr<Parser> parser(parserBuilder.build());
241
6173
      if( inputFromStdin ) {
242
        parser->setInput(Input::newStreamInput(
243
            solver->getOption("input-language"), cin, filename));
244
      }
245
      else
246
      {
247
24692
        parser->setInput(
248
12346
            Input::newFileInput(solver->getOption("input-language"),
249
                                filename,
250
12346
                                solver->getOptionInfo("mmap").boolValue()));
251
      }
252
253
6173
      bool interrupted = false;
254
585251
      while (status)
255
      {
256
295674
        if (interrupted) {
257
          dopts.out() << CommandInterrupted();
258
          pExecutor->reset();
259
          break;
260
        }
261
        try {
262
295674
          cmd.reset(parser->nextCommand());
263
295654
          if (cmd == nullptr) break;
264
        } catch (UnsafeInterruptException& e) {
265
          interrupted = true;
266
          continue;
267
        }
268
269
290271
        status = pExecutor->doCommand(cmd);
270
290271
        if (cmd->interrupted() && status == 0) {
271
          interrupted = true;
272
          break;
273
        }
274
275
290271
        if(dynamic_cast<QuitCommand*>(cmd.get()) != nullptr) {
276
732
          break;
277
        }
278
      }
279
    }
280
281
12306
    api::Result result;
282
6153
    if(status) {
283
6115
      result = pExecutor->getResult();
284
6115
      returnValue = 0;
285
    } else {
286
      // there was some kind of error
287
38
      returnValue = 1;
288
    }
289
290
#ifdef CVC5_COMPETITION_MODE
291
    dopts.out() << std::flush;
292
    // exit, don't return (don't want destructors to run)
293
    // _exit() from unistd.h doesn't run global destructors
294
    // or other on_exit/atexit stuff.
295
    _exit(returnValue);
296
#endif /* CVC5_COMPETITION_MODE */
297
298
6153
    pExecutor->flushOutputStreams();
299
300
#ifdef CVC5_DEBUG
301
    {
302
12306
      auto info = solver->getOptionInfo("early-exit");
303
6153
      if (info.boolValue() && info.setByUser)
304
      {
305
        _exit(returnValue);
306
      }
307
    }
308
#else  /* CVC5_DEBUG */
309
    if (solver->getOptionInfo("early-exit").boolValue())
310
    {
311
      _exit(returnValue);
312
    }
313
#endif /* CVC5_DEBUG */
314
  }
315
316
6153
  pExecutor.reset();
317
318
6153
  signal_handlers::cleanup();
319
320
12306
  return returnValue;
321
29556
}