GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/main/driver_unified.cpp Lines: 69 126 54.8 %
Date: 2021-11-07 Branches: 121 416 29.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/solver_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
10370
std::string progName;
55
56
/** A pointer to the CommandExecutor (the signal handlers need it) */
57
10370
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
9312
int runCvc5(int argc, char* argv[], std::unique_ptr<api::Solver>& solver)
83
{
84
  // Initialize the signal handlers
85
9312
  signal_handlers::install();
86
87
9312
  progPath = argv[0];
88
89
  // Create the command executor to execute the parsed commands
90
9312
  pExecutor = std::make_unique<CommandExecutor>(solver);
91
9312
  api::DriverOptions dopts = solver->getDriverOptions();
92
93
  // Parse the options
94
15895
  std::vector<string> filenames = main::parse(*solver, argc, argv, progName);
95
96
13166
  auto limit = install_time_limit(solver->getOptionInfo("tlimit").uintValue());
97
98
6583
  if (solver->getOptionInfo("help").boolValue())
99
  {
100
    printUsage(dopts, true);
101
    exit(1);
102
  }
103
104
6583
  segvSpin = solver->getOptionInfo("segv-spin").boolValue();
105
106
  // If in competition mode, set output stream option to flush immediately
107
#ifdef CVC5_COMPETITION_MODE
108
  dopts.out() << unitbuf;
109
#endif /* CVC5_COMPETITION_MODE */
110
111
  // We only accept one input file
112
6583
  if(filenames.size() > 1) {
113
    throw Exception("Too many input files specified.");
114
  }
115
116
  // If no file supplied we will read from standard input
117
6583
  const bool inputFromStdin = filenames.empty() || filenames[0] == "-";
118
119
  // if we're reading from stdin on a TTY, default to interactive mode
120
6583
  if (!solver->getOptionInfo("interactive").setByUser)
121
  {
122
6583
    solver->setOption("interactive", (inputFromStdin && isatty(fileno(stdin))) ? "true" : "false");
123
  }
124
125
  // Auto-detect input language by filename extension
126
13166
  std::string filenameStr("<stdin>");
127
6583
  if (!inputFromStdin) {
128
6583
    filenameStr = std::move(filenames[0]);
129
  }
130
6583
  const char* filename = filenameStr.c_str();
131
132
6583
  if (solver->getOption("input-language") == "LANG_AUTO")
133
  {
134
6192
    if( inputFromStdin ) {
135
      // We can't do any fancy detection on stdin
136
      solver->setOption("input-language", "smt2");
137
    } else {
138
6192
      size_t len = filenameStr.size();
139
6192
      if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
140
6113
        solver->setOption("input-language", "smt2");
141
79
      } else if((len >= 2 && !strcmp(".p", filename + len - 2))
142
37
                || (len >= 5 && !strcmp(".tptp", filename + len - 5))) {
143
42
        solver->setOption("input-language", "tptp");
144
37
      } else if((len >= 3 && !strcmp(".sy", filename + len - 3))
145
                || (len >= 3 && !strcmp(".sl", filename + len - 3))) {
146
        // version 2 sygus is the default
147
37
        solver->setOption("input-language", "sygus2");
148
      }
149
    }
150
  }
151
152
6583
  if (solver->getOption("output-language") == "LANG_AUTO")
153
  {
154
6583
    solver->setOption("output-language", solver->getOption("input-language"));
155
  }
156
6583
  pExecutor->storeOptionsAsOriginal();
157
158
  // Determine which messages to show based on smtcomp_mode and verbosity
159
6583
  if(Configuration::isMuzzledBuild()) {
160
    DebugChannel.setStream(&cvc5::null_os);
161
    TraceChannel.setStream(&cvc5::null_os);
162
    MessageChannel.setStream(&cvc5::null_os);
163
    WarningChannel.setStream(&cvc5::null_os);
164
  }
165
166
6583
  int returnValue = 0;
167
  {
168
6583
    solver->setInfo("filename", filenameStr);
169
170
    // Parse and execute commands until we are done
171
13166
    std::unique_ptr<Command> cmd;
172
6583
    bool status = true;
173
6583
    if (solver->getOptionInfo("interactive").boolValue() && inputFromStdin)
174
    {
175
      if (!solver->getOptionInfo("incremental").setByUser)
176
      {
177
        cmd.reset(new SetOptionCommand("incremental", "true"));
178
        cmd->setMuted(true);
179
        pExecutor->doCommand(cmd);
180
      }
181
      InteractiveShell shell(pExecutor->getSolver(),
182
                             pExecutor->getSymbolManager(),
183
                             dopts.in(),
184
                             dopts.out());
185
186
      CVC5Message() << Configuration::getPackageName() << " "
187
                    << Configuration::getVersionString();
188
      if (Configuration::isGitBuild())
189
      {
190
        CVC5Message() << " [" << Configuration::getGitInfo() << "]";
191
      }
192
      CVC5Message() << (Configuration::isDebugBuild() ? " DEBUG" : "")
193
                    << " assertions:"
194
                    << (Configuration::isAssertionBuild() ? "on" : "off")
195
                    << endl
196
                    << endl;
197
      CVC5Message() << Configuration::copyright() << endl;
198
199
      while(true) {
200
        try {
201
          cmd.reset(shell.readCommand());
202
        } catch(UnsafeInterruptException& e) {
203
          dopts.out() << CommandInterrupted();
204
          break;
205
        }
206
        if (cmd == nullptr)
207
          break;
208
        status = pExecutor->doCommand(cmd) && status;
209
        if (cmd->interrupted()) {
210
          break;
211
        }
212
      }
213
    }
214
    else
215
    {
216
6583
      if (!solver->getOptionInfo("incremental").setByUser)
217
      {
218
5907
        cmd.reset(new SetOptionCommand("incremental", "false"));
219
5907
        cmd->setMuted(true);
220
5907
        pExecutor->doCommand(cmd);
221
      }
222
223
      ParserBuilder parserBuilder(
224
13166
          pExecutor->getSolver(), pExecutor->getSymbolManager(), true);
225
13166
      std::unique_ptr<Parser> parser(parserBuilder.build());
226
6583
      if( inputFromStdin ) {
227
        parser->setInput(Input::newStreamInput(
228
            solver->getOption("input-language"), cin, filename));
229
      }
230
      else
231
      {
232
26332
        parser->setInput(
233
13166
            Input::newFileInput(solver->getOption("input-language"),
234
                                filename,
235
13166
                                solver->getOptionInfo("mmap").boolValue()));
236
      }
237
238
6583
      bool interrupted = false;
239
477691
      while (status)
240
      {
241
242089
        if (interrupted) {
242
          dopts.out() << CommandInterrupted();
243
          pExecutor->reset();
244
          break;
245
        }
246
        try {
247
242089
          cmd.reset(parser->nextCommand());
248
242069
          if (cmd == nullptr) break;
249
        } catch (UnsafeInterruptException& e) {
250
          interrupted = true;
251
          continue;
252
        }
253
254
236293
        status = pExecutor->doCommand(cmd);
255
236293
        if (cmd->interrupted() && status == 0) {
256
          interrupted = true;
257
          break;
258
        }
259
260
236293
        if(dynamic_cast<QuitCommand*>(cmd.get()) != nullptr) {
261
739
          break;
262
        }
263
      }
264
    }
265
266
13126
    api::Result result;
267
6563
    if(status) {
268
6515
      result = pExecutor->getResult();
269
6515
      returnValue = 0;
270
    } else {
271
      // there was some kind of error
272
48
      returnValue = 1;
273
    }
274
275
#ifdef CVC5_COMPETITION_MODE
276
    dopts.out() << std::flush;
277
    // exit, don't return (don't want destructors to run)
278
    // _exit() from unistd.h doesn't run global destructors
279
    // or other on_exit/atexit stuff.
280
    _exit(returnValue);
281
#endif /* CVC5_COMPETITION_MODE */
282
283
6563
    pExecutor->flushOutputStreams();
284
285
#ifdef CVC5_DEBUG
286
    {
287
13126
      auto info = solver->getOptionInfo("early-exit");
288
6563
      if (info.boolValue() && info.setByUser)
289
      {
290
        _exit(returnValue);
291
      }
292
    }
293
#else  /* CVC5_DEBUG */
294
    if (solver->getOptionInfo("early-exit").boolValue())
295
    {
296
      _exit(returnValue);
297
    }
298
#endif /* CVC5_DEBUG */
299
  }
300
301
6563
  pExecutor.reset();
302
303
6563
  signal_handlers::cleanup();
304
305
13126
  return returnValue;
306
31110
}