CVC3

main.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file main.cpp
00004  * \brief Main program for cvc3
00005  * 
00006  * Author: Clark Barrett
00007  * 
00008  * Created: Wed Dec  4 17:21:10 2002
00009  *
00010  * <hr>
00011  *
00012  * License to use, copy, modify, sell and/or distribute this software
00013  * and its documentation for any purpose is hereby granted without
00014  * royalty, subject to the terms and conditions defined in the \ref
00015  * LICENSE file provided with this distribution.
00016  * 
00017  * <hr>
00018  * 
00019  */
00020 /*****************************************************************************/
00021 
00022 #include <signal.h>
00023 #include <fstream>
00024 #include <iomanip>
00025 
00026 #include "os.h"
00027 #include "vc.h"
00028 #include "parser.h"
00029 #include "vc_cmd.h"
00030 #include "command_line_flags.h"
00031 #include "statistics.h"
00032 
00033 #ifdef _MSC_VER
00034 #include <windows.h>
00035 #else
00036 #include <unistd.h>
00037 #endif
00038 
00039 
00040 using namespace std;
00041 using namespace CVC3;
00042 
00043 
00044 static void parse_args(int argc, char **argv, CLFlags &flags,
00045            string& fileName);
00046 static void printUsage(const CLFlags& flags, bool followDisplay);
00047 
00048 // Our own name 
00049 static string programName;
00050 
00051 static ValidityChecker* vc = NULL;
00052 IF_DEBUG(static DebugTimer* pRuntime = NULL;)
00053 
00054 #ifndef _MSC_VER
00055 void sighandler(int signum) {
00056   cerr << "\nInterrupted by signal " << signum;
00057   if(signum == SIGALRM)
00058     cerr << " (self-timeout)";
00059   cerr << ".  " << programName << " is aborting.\n";
00060   // Print the debugging info
00061   IF_DEBUG(if (pRuntime != NULL) CVC3::debugger.setElapsed(*pRuntime);)
00062   IF_DEBUG(debugger.printAll();)
00063   if(vc != NULL && vc->getFlags()["stats"].getBool())
00064     cout << vc->getStatistics() << endl;
00065   if(vc != NULL) {
00066     // If deletion causes another signal, don't keep trying.
00067     // This is here to ensure that logs are dumped, etc.
00068     ValidityChecker* toDelete = vc;
00069     vc = NULL;
00070     delete toDelete;
00071   }
00072   abort();
00073 }
00074 #else
00075 DWORD WINAPI thread_timeout(PVOID timeout) {
00076   Sleep((int)timeout * 1000);
00077   cerr << "(self-timeout)." << endl;
00078   if(vc != NULL && vc->getFlags()["stats"].getBool())
00079     cout << vc->getStatistics() << endl;
00080   if(vc != NULL) {
00081     // If deletion causes another signal, don't keep trying.
00082     // This is here to ensure that logs are dumped, etc.
00083     ValidityChecker* toDelete = vc;
00084     vc = NULL;
00085     delete toDelete;
00086   }
00087   ExitProcess(1);
00088 }
00089 #endif
00090 
00091 
00092 int main(int argc, char **argv)
00093 {
00094   CLFlags flags(ValidityChecker::createFlags());
00095   programName = string(argv[0]);
00096   IF_DEBUG(DebugTimer runtime(CVC3::debugger.timer("total runtime"));)
00097   IF_DEBUG(pRuntime = &runtime;)
00098 
00099 #ifndef _MSC_VER
00100   signal(SIGINT, sighandler);
00101   signal(SIGTERM, sighandler);
00102   signal(SIGQUIT, sighandler);
00103   signal(SIGALRM, sighandler);
00104   signal(SIGSEGV, sighandler);
00105 #endif
00106   
00107   string fileName("");
00108 
00109   try {
00110     parse_args(argc, argv, flags, fileName);
00111   } catch(Exception& e) {
00112     cerr << "*** " << e;
00113     cerr << "\n\nRun with -help option for usage information." << endl;
00114     exit(1);
00115   }
00116 
00117   // In SMT-LIBv2, don't save the model between distinct check-sats
00118   // (unless user specifically requested it)
00119   if(flags["lang"].getString() != "" &&
00120      getLanguage(flags["lang"].getString()) == SMTLIB_V2_LANG &&
00121      !flags["internal::userSetNoSaveModel"].getBool()) {
00122     flags.setFlag("no-save-model", true);
00123   }
00124 
00125   // Set the timeout, if given in the command line options
00126   int timeout = flags["timeout"].getInt();
00127   if(timeout > 0) {
00128 #ifndef _MSC_VER
00129     alarm(timeout);
00130 #else
00131     // http://msdn2.microsoft.com/en-us/library/ms682453.aspx
00132     CreateThread(NULL, 0, thread_timeout, (PVOID)timeout, 0, NULL);
00133 #endif
00134   }
00135 
00136   /*
00137    * Create and run the validity checker
00138    */ 
00139 
00140   // Debugging code may throw an exception
00141   try {
00142     vc = ValidityChecker::create(flags);
00143   } catch(Exception& e) {
00144     cerr << "*** Fatal exception: " << e << endl;
00145     exit(1);
00146   }
00147 
00148   // -h flag sets "help" to false (+h would make it true, but that's
00149   // not what the user normally types in).
00150   if(!vc->getFlags()["help"].getBool()) {
00151     printUsage(vc->getFlags(), true);
00152     return 0;
00153   }
00154   if(!vc->getFlags()["unsupported"].getBool()) {
00155     printUsage(vc->getFlags(), false);
00156     return 0;
00157   }
00158 #ifndef VERSION
00159 #define VERSION "unknown"
00160 #endif
00161   // Similarly, -version sets the flag "version" to false
00162   if(!vc->getFlags()["version"].getBool()) {
00163     cout << "This is CVC3 version " << VERSION
00164       IF_DEBUG( << " (debug build)")
00165    << "\n\n";
00166     cout <<
00167       "Copyright (C) 2003-2010 by the Board of Trustees of Leland Stanford Junior\n" 
00168       "University, New York University, and the University of Iowa.\n\n"
00169       "THIS SOFTWARE PROVIDED AS-IS, WITHOUT ANY WARRANTIES. "
00170       "USE IT AT YOUR OWN RISK.\n"
00171    << endl;
00172     return 0;
00173   }
00174 
00175   try {
00176     // Calling getOutputLang() tests if the output language is
00177     // correctly specified; if not, an exception will be thrown
00178     InputLanguage outlang = vc->getEM()->getOutputLang();
00179     if(outlang == SPASS_LANG &&
00180        vc->getFlags()["translate"].getBool() &&
00181        !vc->getFlags()["liftITE"].modified()) {
00182       // SPASS doesn't support ITE; make sure there are none
00183       vc->getFlags().setFlag("liftITE", true);
00184     }
00185     // Set the timer
00186     IF_DEBUG(CVC3::debugger.setCurrentTime(runtime);)
00187     // Read the input file
00188     vc->loadFile(fileName, vc->getEM()->getInputLang(),
00189                  flags["interactive"].getBool());
00190   } catch(Exception& e) {
00191     cerr << "*** Fatal exception: " << e << endl;
00192     exit(1);
00193   }
00194 
00195   IF_DEBUG(CVC3::debugger.setElapsed(runtime);)
00196 
00197   // Print the debugging info
00198   IF_DEBUG(debugger.printAll();)
00199   // Print statistics
00200   if(vc->getFlags()["stats"].getBool()) vc->printStatistics();
00201   // Destruct the system
00202   TRACE_MSG("delete", "Deleting ValidityChecker [last trace from main.cpp]");
00203   try {
00204     // The signal handler deletes the vc.  If deletion segfaults, we don't
00205     // want to try it again.
00206     ValidityChecker* toDelete = vc;
00207     vc = NULL;
00208     delete toDelete;
00209   } catch(Exception& e) {
00210     cerr << "*** Fatal exception: " << e << endl;
00211     exit(1);
00212   }
00213 
00214   return 0;
00215 }
00216 
00217 void printUsage(const CLFlags& flags, bool followDisplay) {
00218   cout << "Usage: " << programName << " [options]\n"
00219        << programName << " will read the input from STDIN and \n"
00220        << "print the result on STDOUT.\n"
00221        << "Boolean (b) options are set 'on' by +option and 'off' by -option\n"
00222        << "(for instance, +model or -model).\n"
00223        << "Integer (i), string (s) and vector (v) options \n"
00224        << "require a parameter, e.g. -width 80\n" 
00225        << "Also, (v) options can appear multiple times setting "
00226        << "args on and off,\n"
00227        << "as in +trace \"enable this\" -trace \"disable that\".\n"
00228        << "Option names can be abbreviated to the "
00229        << "shortest unambiguous prefix.\n\n"
00230        << "The options are:\n";
00231   vector<string> names;
00232   // Get all the names of options (they all match the empty string)
00233   flags.countFlags("", names);
00234   for(size_t i=0,iend=names.size(); i!=iend; ++i) {
00235     const CLFlag& f(flags[names[i]]);
00236     if (f.display() != followDisplay) continue;
00237     string tpStr; // Print type of the option
00238     string pref; // Print + or - in front of the option
00239     string name(names[i]); // Print name and optionally the value
00240     CLFlagType tp = f.getType();
00241     switch(tp) {
00242     case CLFLAG_NULL: tpStr = "(null)"; break;
00243     case CLFLAG_BOOL:
00244       tpStr = "(b)"; pref = (f.getBool())? "+" : "-";
00245       break;
00246     case CLFLAG_INT:
00247       tpStr = "(i)"; pref = "-"; name = name+" "+int2string(f.getInt());
00248       break;
00249     case CLFLAG_STRING:
00250       tpStr = "(s)"; pref = "-"; name = name+" "+f.getString();
00251       break;
00252     case CLFLAG_STRVEC:
00253       tpStr = "(v)"; pref = "-"; name = name;
00254       break;
00255     default:
00256       DebugAssert(false, "printUsage: unknown flag type");
00257     }
00258     cout << " " << tpStr << " " << pref << setw(25);
00259     cout.setf(ios::left);
00260     cout << name << " " << f.getHelp() << "\n";
00261   }
00262   cout << endl;
00263 }
00264   
00265 
00266 void parse_args(int argc, char **argv, CLFlags &flags, string& fileName) {
00267   /* skip 0'th argument */
00268   argv++;
00269   argc--;
00270   bool seenFileName(false);
00271 
00272   for( ; argc > 0; argc--, argv++) {
00273     if((*argv)[0] == '-' || (*argv)[0] == '+') {
00274       // A command-line option
00275       vector<string> names;
00276       bool val = ((*argv)[0] == '+');
00277       size_t n = flags.countFlags((*argv)+1, names);
00278       if(n == 0)
00279   throw CLException(string(*argv) + " does not match any known option");
00280       else if(n > 1) {
00281   ostringstream ss;
00282   ss << *argv << " is ambiguous.  Possible matches are:\n";
00283   for(size_t i=0,iend=names.size(); i!=iend; ++i) {
00284     ss << "  " << names[i] << "\n";
00285   }
00286   throw CLException(ss.str());
00287       } else {
00288   string name = names[0];
00289         if(name == "no-save-model") {
00290           flags.setFlag("internal::userSetNoSaveModel", true);
00291         }
00292   // Single match; process the option
00293   CLFlagType tp = flags[name].getType();
00294   switch(tp) {
00295   case CLFLAG_BOOL: flags.setFlag(name, val); break;
00296   case CLFLAG_INT:
00297     argc--;
00298     if(argc <= 0)
00299       throw CLException(string(*argv)+" (-"+name
00300             +") expects an integer argument.");
00301     argv++;
00302     // FIXME: test for *argv being an integer string
00303     flags.setFlag(name, atoi(*argv));
00304     break;
00305   case CLFLAG_STRING:
00306     argc--;
00307     if(argc <= 0)
00308       throw CLException(string(*argv)+" (-"+name
00309             +") expects a string argument.");
00310     argv++;
00311     flags.setFlag(name, *argv);
00312     break;
00313   case CLFLAG_STRVEC:
00314     argc--;
00315     if(argc <= 0)
00316       throw CLException(string(*argv)+" (-"+name
00317             +") expects a string argument.");
00318     argv++;
00319     flags.setFlag(name, pair<string,bool>(*argv,val));
00320     break;
00321   default:
00322     DebugAssert(false, "parse_args: Bad flag type: "+int2string(tp));
00323   }
00324       }
00325     } else if(seenFileName) {
00326       throw CLException("More than one file name given: "+fileName
00327       +" and "+string(*argv));
00328     } else {
00329       fileName = string(*argv);
00330       seenFileName = true;
00331     }
00332   }
00333 }