Adding support for interactive mode
authorChristopher L. Conway <christopherleeconway@gmail.com>
Wed, 20 Oct 2010 20:41:03 +0000 (20:41 +0000)
committerChristopher L. Conway <christopherleeconway@gmail.com>
Wed, 20 Oct 2010 20:41:03 +0000 (20:41 +0000)
src/main/Makefile.am
src/main/interactive_shell.cpp [new file with mode: 0644]
src/main/interactive_shell.h [new file with mode: 0644]
src/main/main.cpp
src/parser/antlr_input.h
src/parser/antlr_input_imports.cpp
src/parser/input.h
src/parser/parser.h
src/parser/parser_builder.cpp

index 3cd062158891ba3f6cefdac9699b6b8ab503d19c..b6cdbb1f432ef7bab7ab56a30d648ee7655370d4 100644 (file)
@@ -6,11 +6,13 @@ AM_CXXFLAGS = -Wall -Wno-unknown-pragmas
 bin_PROGRAMS = cvc4
 
 cvc4_SOURCES = \
-       main.cpp \
        getopt.cpp \
-       util.cpp \
+       interactive_shell.h \
+       interactive_shell.cpp \
        main.h \
-       usage.h
+       main.cpp \
+       usage.h \
+       util.cpp
 
 cvc4_LDADD = \
        ../parser/libcvc4parser.la \
diff --git a/src/main/interactive_shell.cpp b/src/main/interactive_shell.cpp
new file mode 100644 (file)
index 0000000..7af72ed
--- /dev/null
@@ -0,0 +1,111 @@
+/*********************                                                        */
+/*! \file interactive_shell.cpp
+ ** \verbatim
+ ** Original author: cconway
+ ** Major contributors: 
+ ** Minor contributors (to current version): 
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010  The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Interactive shell for CVC4
+ **/
+
+#include <iostream>
+
+#include "interactive_shell.h"
+#include "expr/command.h"
+#include "parser/parser.h"
+#include "parser/parser_builder.h"
+
+using namespace std;
+
+namespace CVC4 {
+
+Command* InteractiveShell::readCommand() {
+  /* Don't do anything if the input is closed. */
+  if( d_in.eof() ) {
+    return NULL;
+  }
+
+  /* If something's wrong with the input, there's nothing we can do. */
+  if( !d_in.good() ) {
+    throw ParserException("Interactive input broken.");
+  }
+
+  string input;
+
+  /* Prompt the user for input. */
+  d_out << "CVC4> " << flush;
+  while(true) {
+    stringbuf sb;
+    string line;
+
+    /* Read a line */
+    d_in.get(sb,'\n');
+    line = sb.str();
+    // cout << "Input was '" << input << "'" << endl << flush;
+
+    /* If we hit EOF, we're done. */
+    if( d_in.eof() ) {
+      input += line;
+      break;
+    }
+
+    /* Check for failure */
+    if( d_in.fail() ) {
+      /* This should only happen if the input line was empty. */
+      Assert( line.empty() );
+      d_in.clear();
+    }
+
+    /* Extract the newline delimiter from the stream too */
+    int c = d_in.get();
+    Assert( c == '\n' );
+
+    // cout << "Next char is '" << (char)c << "'" << endl << flush;
+
+    /* Strip trailing whitespace. */
+    int n = line.length() - 1;
+    while( !line.empty() && isspace(line[n]) ) { 
+      line.erase(n,1); 
+      n--;
+    }
+
+    input += line;
+    
+    /* If the last char was a backslash, continue on the next line. */
+    if( !line.empty() && line[n] == '\\' ) {
+      n = input.length() - 1;
+      Assert( input[n] == '\\' );
+      input[n] = '\n';
+      d_out << "... > " << flush;
+    } else {
+      /* No continuation, we're done. */
+      //cout << "Leaving input loop." << endl << flush;
+      break;
+    }
+  }
+
+  Parser *parser = 
+    d_parserBuilder
+        .withStringInput(input)
+        .build();
+
+  /* There may be more than one command in the input. Build up a
+     sequence. */
+  CommandSequence *cmd_seq = new CommandSequence();
+  Command *cmd;
+
+  while( (cmd = parser->nextCommand()) ) {
+    cmd_seq->addCommand(cmd);
+  }
+
+  delete parser;
+  return cmd_seq;
+}
+
+} // CVC4 namespace
diff --git a/src/main/interactive_shell.h b/src/main/interactive_shell.h
new file mode 100644 (file)
index 0000000..6bd9db2
--- /dev/null
@@ -0,0 +1,52 @@
+/*********************                                                        */
+/*! \file interactive_shell.h
+ ** \verbatim
+ ** Original author: cconway
+ ** Major contributors: 
+ ** Minor contributors (to current version): 
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010  The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Interactive shell for CVC4
+ **/
+
+#ifndef __CVC4__INTERACTIVE_SHELL_H
+#define __CVC4__INTERACTIVE_SHELL_H
+
+#include <iostream>
+#include <string>
+
+#include "parser/parser_builder.h"
+
+namespace CVC4 {
+
+  class Command;
+
+  using namespace parser;
+
+class InteractiveShell {
+  std::istream& d_in;
+  std::ostream& d_out;
+  ParserBuilder d_parserBuilder;
+
+public:
+  InteractiveShell(std::istream& in, 
+                   std::ostream& out, 
+                   ParserBuilder& parserBuilder) : 
+    d_in(in),
+    d_out(out),
+    d_parserBuilder(parserBuilder) {
+  }
+
+  /** Read a command from the interactive shell. This will read as
+      many lines as necessary to parse a well-formed command. */
+  Command *readCommand();
+};
+
+} // CVC4 namespace
+
+#endif // __CVC4__INTERACTIVE_SHELL_H
index d879e81dffce20b39427228f62e760261b9485da..2f524c3f611ebb4d937a14dce67be6cb4a53858c 100644 (file)
 
 #include "cvc4autoconfig.h"
 #include "main.h"
+#include "interactive_shell.h"
 #include "usage.h"
 #include "parser/parser.h"
 #include "parser/parser_builder.h"
+#include "parser/parser_exception.h"
 #include "expr/expr_manager.h"
 #include "smt/smt_engine.h"
 #include "expr/command.h"
@@ -119,9 +121,13 @@ int runCvc4(int argc, char* argv[]) {
     firstArgIndex >= argc || !strcmp("-", argv[firstArgIndex]);
 
   // if we're reading from stdin, default to interactive mode
-  if(!options.interactiveSetByUser) {
-    options.interactive = inputFromStdin;
-  }
+  // [chris 10/20/10] The expected behavior of interactive is
+  // different from the expected behavior of file input from
+  // stdin, due to EOL escapes in interactive mode
+
+  // if(!options.interactiveSetByUser) {
+  //   options.interactive = inputFromStdin;
+  // }
 
   // Create the expression manager
   ExprManager exprMgr(options.earlyTypeChecking);
@@ -193,18 +199,22 @@ int runCvc4(int argc, char* argv[]) {
     parserBuilder.withStreamInput(cin);
   }
 
-  Parser *parser = parserBuilder.build();
-
   // Parse and execute commands until we are done
   Command* cmd;
   if( options.interactive ) {
-    // cout << "CVC4> " << flush;
-  }
-  while((cmd = parser->nextCommand())) {
-    if( !options.parseOnly ) {
+    InteractiveShell shell(cin,cout,parserBuilder);
+    while((cmd = shell.readCommand())) {
+      doCommand(smt,cmd);
+      delete cmd;
+    }
+  } else {
+    Parser *parser = parserBuilder.build();
+    while((cmd = parser->nextCommand())) {
       doCommand(smt, cmd);
+      delete cmd;
     }
-    delete cmd;
+    // Remove the parser
+    delete parser;
   }
 
   string result = smt.getInfo(":status").getValue();
@@ -224,9 +234,6 @@ int runCvc4(int argc, char* argv[]) {
   exit(returnValue);
 #endif
 
-  // Remove the parser
-  delete parser;
-
   ReferenceStat< Result > s_statSatResult("sat/unsat", result);
   StatisticsRegistry::registerStat(&s_statSatResult);
 
@@ -240,7 +247,12 @@ int runCvc4(int argc, char* argv[]) {
   return returnValue;
 }
 
+/** Executes a command. Deletes the command after execution. */
 void doCommand(SmtEngine& smt, Command* cmd) {
+  if( options.parseOnly ) {
+    return;
+  }
+
   CommandSequence *seq = dynamic_cast<CommandSequence*>(cmd);
   if(seq != NULL) {
     for(CommandSequence::iterator subcmd = seq->begin();
index e55e07efd2a6587104d299964c0d6039bf8dc4c5..d86a18004ada8ae1f5f0d15797822909205513ba 100644 (file)
@@ -180,6 +180,8 @@ public:
   /** Get a bitvector constant from the text of the number and the size token */
   static BitVector tokenToBitvector(pANTLR3_COMMON_TOKEN number, pANTLR3_COMMON_TOKEN size);
 
+  std::string getUnparsedText();
+
 protected:
   /** Create an input. This input takes ownership of the given input stream,
    * and will delete it at destruction time.
@@ -210,6 +212,14 @@ protected:
   virtual void setParser(Parser& parser);
 };
 
+inline std::string AntlrInput::getUnparsedText() {
+  const char *base = (const char *)d_antlr3InputStream->data;
+  const char *cur = (const char *)d_antlr3InputStream->nextChar;
+
+  return std::string(cur, d_antlr3InputStream->sizeBuf - (cur - base));
+}
+
+
 inline std::string AntlrInput::tokenText(pANTLR3_COMMON_TOKEN token) {
   ANTLR3_MARKER start = token->getStartIndex(token);
   ANTLR3_MARKER end = token->getStopIndex(token);
index a1ebee523de723e5a83c2db157c6c11565c7db2e..2805d518a4f6e06602331a202e110b9700139ae5 100644 (file)
@@ -56,6 +56,7 @@
 
 #include "antlr_input.h"
 #include "parser.h"
+#include "parser_exception.h"
 #include "util/Assert.h"
 
 using namespace std;
@@ -89,6 +90,14 @@ void AntlrInput::reportError(pANTLR3_BASE_RECOGNIZER recognizer) {
   pANTLR3_UINT8 * tokenNames = recognizer->state->tokenNames;
   stringstream ss;
 
+  // Dig the CVC4 objects out of the ANTLR3 mess
+  pANTLR3_PARSER antlr3Parser = (pANTLR3_PARSER)(recognizer->super);
+  AlwaysAssert(antlr3Parser!=NULL);
+  Parser *parser = (Parser*)(antlr3Parser->super);
+  AlwaysAssert(parser!=NULL);
+  AntlrInput *input = (AntlrInput*) parser->getInput() ;
+  AlwaysAssert(input!=NULL);
+
   // Signal we are in error recovery now
   recognizer->state->errorRecovery = ANTLR3_TRUE;
 
@@ -252,14 +261,6 @@ void AntlrInput::reportError(pANTLR3_BASE_RECOGNIZER recognizer) {
     break;
   }
 
-  // Now get ready to throw an exception
-  pANTLR3_PARSER antlr3Parser = (pANTLR3_PARSER)(recognizer->super);
-  AlwaysAssert(antlr3Parser!=NULL);
-  Parser *parser = (Parser*)(antlr3Parser->super);
-  AlwaysAssert(parser!=NULL);
-  AntlrInput *input = (AntlrInput*) parser->getInput() ;
-  AlwaysAssert(input!=NULL);
-
   // Call the error display routine
   input->parseError(ss.str());
 }
index 1a90a41917ace501408dc60018a63dfa73d66329..7cfafe429aa88204e030d689925d7c95f06db0f2 100644 (file)
@@ -47,7 +47,7 @@ public:
   virtual ~InputStreamException() throw() { }
 };
 
-/** Wrapper around an ANTLR3 input stream. */
+/** Wrapper around an input stream. */
 class InputStream {
 
   /** The name of this input stream. */
@@ -93,7 +93,7 @@ class CVC4_PUBLIC Input {
   /** The input stream. */
   InputStream *d_inputStream;
 
-  /* Since we own d_tokenStream and it needs to be freed, we need to prevent
+  /* Since we own d_inputStream and it needs to be freed, we need to prevent
    * copy construction and assignment.
    */
   Input(const Input& input) { Unimplemented("Copy constructor for Input."); }
@@ -134,9 +134,12 @@ class CVC4_PUBLIC Input {
 
 public:
 
-  /** Destructor. Frees the token stream and closes the input. */
+  /** Destructor. Frees the input stream and closes the input. */
   virtual ~Input();
 
+  /** Retrieve the remaining text in this input. */
+  virtual std::string getUnparsedText() = 0;
+
 protected:
 
   /** Create an input.
index 4d1e6417637a9331bcca6b163ee94e546e6bbd20..280bd3c97f94070024bd1cf6cb1e5297305a9211 100644 (file)
@@ -160,12 +160,6 @@ public:
     return d_input;
   }
 
-  /** Set the declaration scope manager for this input. NOTE: This should <em>only</me> be
-   * called before parsing begins. Otherwise, previous declarations will be lost. */
-/*  inline void setDeclarationScope(DeclarationScope declScope) {
-    d_declScope = declScope;
-  }*/
-
   /**
    * Check if we are done -- either the end of input has been reached, or some
    * error has been encountered.
@@ -189,7 +183,8 @@ public:
   /** Enable strict parsing, according to the language standards. */
   void enableStrictMode() { d_strictMode = true; }
 
-  /** Disable strict parsing. Allows certain syntactic infelicities to pass without comment. */
+  /** Disable strict parsing. Allows certain syntactic infelicities to
+      pass without comment. */
   void disableStrictMode() { d_strictMode = false; }
 
   bool strictModeEnabled() { return d_strictMode; }
index f53d7cc9cb3d495137293bba8d9021ad585805dc..dcc052c3af1ebc7458334004467c37551263fb09 100644 (file)
@@ -84,46 +84,20 @@ Parser *ParserBuilder::build() throw (InputStreamException,AssertionException) {
   default:
     Unreachable();
   }
+
+  Parser *parser = NULL;
   switch(d_lang) {
   case language::input::LANG_SMTLIB:
-    return new Smt(&d_exprManager, input, d_strictMode);
+    parser = new Smt(&d_exprManager, input, d_strictMode);
   case language::input::LANG_SMTLIB_V2:
-    return new Smt2(&d_exprManager, input, d_strictMode);
+    parser = new Smt2(&d_exprManager, input, d_strictMode);
   default:
-    return new Parser(&d_exprManager, input, d_strictMode);
+    parser = new Parser(&d_exprManager, input, d_strictMode);
   }
-}
-
-/*ParserBuilder& ParserBuilder::disableChecks() {
-  d_checksEnabled = false;
-  return *this;
-}
 
-ParserBuilder& ParserBuilder::disableMmap() {
-  d_mmap = false;
-  return *this;
-}
-
-ParserBuilder& ParserBuilder::disableStrictMode() {
-  d_strictMode = false;
-  return *this;
+  return parser;
 }
 
-ParserBuilder& ParserBuilder::enableChecks() {
-  d_checksEnabled = true;
-  return *this;
-}
-
-ParserBuilder& ParserBuilder::enableMmap() {
-  d_mmap = true;
-  return *this;
-}
-
-ParserBuilder& ParserBuilder::enableStrictMode() {
-  d_strictMode = true;
-  return *this;
-}*/
-
 ParserBuilder& ParserBuilder::withChecks(bool flag) {
   d_checksEnabled = flag;
   return *this;