* reviewed BooleanSimplification, added documentation & unit test
authorMorgan Deters <mdeters@gmail.com>
Sat, 23 Apr 2011 05:15:56 +0000 (05:15 +0000)
committerMorgan Deters <mdeters@gmail.com>
Sat, 23 Apr 2011 05:15:56 +0000 (05:15 +0000)
* work around a lexer ambiguity in CVC grammar
* add support for tracing antlr parser/lexer
* add parsing support for more language features
* initial parameterized types parsing work to support Andy's work

31 files changed:
contrib/switch-config
src/expr/expr_template.cpp
src/expr/expr_template.h
src/parser/Makefile.am
src/parser/Makefile.antlr_tracing [new file with mode: 0644]
src/parser/antlr_tracing.h [new file with mode: 0644]
src/parser/bounded_token_buffer.cpp
src/parser/cvc/Cvc.g
src/parser/cvc/Makefile.am
src/parser/cvc/README [new file with mode: 0644]
src/parser/cvc/cvc_input.cpp
src/parser/parser.h
src/parser/smt/Makefile.am
src/parser/smt/Smt.g
src/parser/smt2/Makefile.am
src/parser/smt2/Smt2.g
src/printer/cvc/cvc_printer.cpp
src/util/Assert.h
src/util/Makefile.am
src/util/boolean_simplification.cpp [new file with mode: 0644]
src/util/boolean_simplification.h
src/util/output.h
src/util/subrange_bound.h [new file with mode: 0644]
test/regress/regress0/Makefile.am
test/regress/regress0/subranges.cvc [new file with mode: 0644]
test/regress/run_regression
test/unit/Makefile.am
test/unit/expr/expr_manager_public.h
test/unit/parser/parser_black.h
test/unit/util/boolean_simplification_black.h [new file with mode: 0644]
test/unit/util/subrange_bound_white.h [new file with mode: 0644]

index 83351da29e070468344f2874974cba2b6b550dae..98ed1032956614d6353323fc8b86928aa84c82dd 100755 (executable)
@@ -38,7 +38,7 @@ if ! [ -e builds/current ]; then
   exit 1
 fi
 
-current=(`grep '^CURRENT_BUILD' builds/current | sed 's,^CURRENT_BUILD *= *\([^/]\+\)/\(.*\),\1 \2,'`)
+current=(`grep '^CURRENT_BUILD' builds/current | sed 's,^CURRENT_BUILD *= *\([^/]*\)/\(.*\),\1 \2,'`)
 arch=${current[0]}
 build=${current[1]}
 
index 74bfd3f2b09787baec39b419fdac30c15fd93375..b7000fea629b4e0f683677ac740d01003e147307 100644 (file)
@@ -188,11 +188,11 @@ size_t Expr::getNumChildren() const {
   return d_node->getNumChildren();
 }
 
-Expr Expr::getChild(unsigned int i) const {
+Expr Expr::operator[](unsigned i) const {
   ExprManagerScope ems(*this);
   Assert(d_node != NULL, "Unexpected NULL expression pointer!");
   Assert(i >= 0 && i < d_node->getNumChildren(), "Child index out of bounds");
-  return Expr(d_exprManager,new Node((*d_node)[i]));
+  return Expr(d_exprManager, new Node((*d_node)[i]));
 }
 
 bool Expr::hasOperator() const {
index 291016044a6083c91d1dbd34dbd80514f3fa635d..24cb6dc5db63da8c393512f03548cdc0d34df297 100644 (file)
@@ -267,7 +267,7 @@ public:
    * @param i the index of the child to retrieve
    * @return the child
    */
-  Expr getChild(unsigned int i) const;
+  Expr operator[](unsigned i) const;
 
   /**
    * Check if this is an expression that has an operator.
index 9ec8774f034389f2c6f690457f84a983ae790253..2b90da502c094023d8ba111dd3cf87ad29974230 100644 (file)
@@ -53,7 +53,8 @@ libcvc4parser_la_SOURCES = \
        parser.cpp \
        parser_builder.h \
        parser_builder.cpp \
-       parser_exception.h
+       parser_exception.h \
+       antlr_tracing.h
 
 libcvc4parser_noinst_la_SOURCES = \
        antlr_input.h \
@@ -71,5 +72,8 @@ libcvc4parser_noinst_la_SOURCES = \
        parser.cpp \
        parser_builder.h \
        parser_builder.cpp \
-       parser_exception.h
+       parser_exception.h \
+       antlr_tracing.h
 
+EXTRA_DIST = \
+       Makefile.antlr_tracing
diff --git a/src/parser/Makefile.antlr_tracing b/src/parser/Makefile.antlr_tracing
new file mode 100644 (file)
index 0000000..087554c
--- /dev/null
@@ -0,0 +1,21 @@
+# -*-makefile-*-
+#
+# This makefile is included from parser directories in order to
+# do antlr tracing.  THIS IS VERY MUCH A HACK, and is only enabled
+# if CVC4_TRACE_ANTLR is defined (and not 0).  In ANTLR 3.2, we
+# have to #define 
+#
+
+ifeq ($(CVC4_TRACE_ANTLR),)
+else
+
+ifeq ($(CVC4_TRACE_ANTLR),0)
+else
+
+AM_CPPFLAGS += -DCVC4_TRACE_ANTLR
+ANTLR_OPTS += -trace
+
+endif
+
+endif
+
diff --git a/src/parser/antlr_tracing.h b/src/parser/antlr_tracing.h
new file mode 100644 (file)
index 0000000..2c3e66c
--- /dev/null
@@ -0,0 +1,87 @@
+/*********************                                                        */
+/*! \file antlr_tracing.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011  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 [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#ifndef __CVC4__PARSER__ANTLR_TRACING_H
+#define __CVC4__PARSER__ANTLR_TRACING_H
+
+// only enable the hack with -DCVC4_TRACE_ANTLR
+#ifdef CVC4_TRACE_ANTLR
+
+#include <iostream>
+#include <string>
+#include "util/output.h"
+
+/* The ANTLR lexer generator, as of v3.2, puts Java trace commands
+ * into our beautiful generated C lexer!  How awful!  This is clearly
+ * a bug (the parser generator traces with printf()), but we have to
+ * do something about it.  Basically, the things look like this:
+ *
+ *   System.out.println("something"+somethingElse+"another thing");
+ *
+ * What to do to make this C++?!  Alas, you cannot
+ * "#define System.out.println", because it has dots in it.
+ * So we do the following.  Sigh.
+ *
+ * This is all C++, and the generated lexer/parser is C++, but that's
+ * ok here, we use the C++ compiler anyway!  Plus, this is only code
+ * for **debugging** lexers and parsers.
+ */
+
+/** A "System" object, just like in Java! */
+static struct __Cvc4System {
+  /**
+   * Helper class just to handle arbitrary string concatenation
+   * with Java syntax.  In C++ you cannot do "char*" + "char*",
+   * so instead we fool the type system into calling
+   * JavaPrinter::operator+() for each item successively.
+   */
+  struct JavaPrinter {
+    template <class T>
+    JavaPrinter operator+(const T& t) const {
+      ::CVC4::Message() << t;
+      return JavaPrinter();
+    }
+  };/* struct JavaPrinter */
+
+  /** A "System.out" object, just like in Java! */
+  struct {
+    /**
+     * By the time println() is called, we've completely
+     * evaluated (and thus printed) its entire argument, thanks
+     * to the call-by-value semantics of C.  All that's left to
+     * do is print the newline.
+     */
+    void println(JavaPrinter) { ::CVC4::Message() << std::endl; }
+  } out;
+} System;
+
+// Now define println(): this kicks off the successive operator+() calls
+// Also define "failed" because ANTLR 3.3 uses "failed" improperly.
+// These are highly dependent on the bugs in a particular ANTLR release.
+// These seem to work with ANTLR 3.3 as of 4/23/2011.  A different trick
+// works with ANTLR 3.2.  EXPECT LOTS OF COMPILER WARNINGS.
+#define println(x) println(({int failed=0;__Cvc4System::JavaPrinter()+x;}))
+#undef ANTLR3_FPRINTF
+#define ANTLR3_FPRINTF(args...) {int failed=0;fprintf(args);}
+#undef ANTLR3_PRINTF
+#define ANTLR3_PRINTF(args...) {int failed=0;printf(args);}
+
+#endif /* CVC4_TRACE_ANTLR */
+
+#endif /* __CVC4__PARSER__ANTLR_TRACING_H */
index 6a94d877ababa61229636e86da6315bb29bdcb6b..d77f72bfa8cac06233b87546d47b20bbb219d599 100644 (file)
@@ -5,7 +5,7 @@
  ** Major contributors: none
  ** Minor contributors (to current version): mdeters
  ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010  The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009, 2010, 2011  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
@@ -385,7 +385,8 @@ dbgLA  (pANTLR3_INT_STREAM is, ANTLR3_INT32 i)
 static ANTLR3_MARKER
 mark   (pANTLR3_INT_STREAM is)
 {
-  Unreachable();
+  is->lastMarker = is->index(is);
+  return  is->lastMarker;
 }
 
 /// As per mark() but with a call to tell the debugger we are doing this
@@ -435,7 +436,7 @@ rewindLast  (pANTLR3_INT_STREAM is)
 static void                
 rewindStream   (pANTLR3_INT_STREAM is, ANTLR3_MARKER marker)
 {
-  Unreachable();
+    is->seek(is, (ANTLR3_UINT32)(marker));
 }
 static void                
 dbgRewindStream        (pANTLR3_INT_STREAM is, ANTLR3_MARKER marker)
@@ -446,7 +447,13 @@ dbgRewindStream    (pANTLR3_INT_STREAM is, ANTLR3_MARKER marker)
 static void                
 seek   (pANTLR3_INT_STREAM is, ANTLR3_MARKER index)
 {
-    Unreachable();
+    pANTLR3_COMMON_TOKEN_STREAM cts;
+    pANTLR3_TOKEN_STREAM        ts;
+
+    ts      = (pANTLR3_TOKEN_STREAM)        is->super;
+    cts     = (pANTLR3_COMMON_TOKEN_STREAM) ts->super;
+
+    cts->p  = (ANTLR3_UINT32)index;
 }
 static void                
 dbgSeek        (pANTLR3_INT_STREAM is, ANTLR3_MARKER index)
index 543538f3227b0d47d1e0699efbc5cc8bc176783b..bd0524f6189f05df42241663cde4e6f5aea326a9 100644 (file)
@@ -11,9 +11,9 @@
  ** See the file COPYING in the top-level source directory for licensing
  ** information.\endverbatim
  **
- ** \brief Parser for CVC-LIB input language.
+ ** \brief Parser for CVC presentation input language
  **
- ** Parser for CVC-LIB input language.
+ ** Parser for CVC input language.
  **/
 
 grammar Cvc;
@@ -26,16 +26,63 @@ options {
   // defaultErrorHandler = false;
 
   // Only lookahead of <= k requested (disable for LL* parsing)
-  k = 2;
-}
+  // Note that CVC4's BoundedTokenBuffer requires a fixed k !
+  // If you change this k, change it also in cvc_input.cpp !
+  k = 3;
+}/* options */
 
 tokens {
-  // Keywords
+  /* commands */
 
-  AND_TOK = 'AND';
   ASSERT_TOK = 'ASSERT';
-  BOOLEAN_TOK = 'BOOLEAN';
+  QUERY_TOK = 'QUERY';
   CHECKSAT_TOK = 'CHECKSAT';
+  OPTION_TOK = 'OPTION';
+  PUSH_TOK = 'PUSH';
+  POP_TOK = 'POP';
+  POPTO_TOK = 'POPTO';
+  PUSH_SCOPE_TOK = 'PUSH_SCOPE';
+  POP_SCOPE_TOK = 'POP_SCOPE';
+  POPTO_SCOPE_TOK = 'POPTO_SCOPE';
+  RESET_TOK = 'RESET';
+  DATATYPE_TOK = 'DATATYPE';
+  END_TOK = 'END';
+  CONTEXT_TOK = 'CONTEXT';
+  FORGET_TOK = 'FORGET';
+  GET_TYPE_TOK = 'GET_TYPE';
+  CHECK_TYPE_TOK = 'CHECK_TYPE';
+  GET_CHILD_TOK = 'GET_CHILD';
+  GET_OP_TOK = 'GET_OP';
+  SUBSTITUTE_TOK = 'SUBSTITUTE';
+  DBG_TOK = 'DBG';
+  TRACE_TOK = 'TRACE';
+  UNTRACE_TOK = 'UNTRACE';
+  HELP_TOK = 'HELP';
+  TRANSFORM_TOK = 'TRANSFORM';
+  PRINT_TOK = 'PRINT';
+  PRINT_TYPE_TOK = 'PRINT_TYPE';
+  CALL_TOK = 'CALL';
+  ECHO_TOK = 'ECHO';
+  INCLUDE_TOK = 'INCLUDE';
+  DUMP_PROOF_TOK = 'DUMP_PROOF';
+  DUMP_ASSUMPTIONS_TOK = 'DUMP_ASSUMPTIONS';
+  DUMP_SIG_TOK = 'DUMP_SIG';
+  DUMP_TCC_TOK = 'DUMP_TCC';
+  DUMP_TCC_ASSUMPTIONS_TOK = 'DUMP_TCC_ASSUMPTIONS';
+  DUMP_TCC_PROOF_TOK = 'DUMP_TCC_PROOF';
+  DUMP_CLOSURE_TOK = 'DUMP_CLOSURE';
+  DUMP_CLOSURE_PROOF_TOK = 'DUMP_CLOSURE_PROOF';
+  WHERE_TOK = 'WHERE';
+  ASSERTIONS_TOK = 'ASSERTIONS';
+  ASSUMPTIONS_TOK = 'ASSUMPTIONS';
+  COUNTEREXAMPLE_TOK = 'COUNTEREXAMPLE';
+  COUNTERMODEL_TOK = 'COUNTERMODEL';
+  ARITH_VAR_ORDER_TOK = 'ARITH_VAR_ORDER';
+
+  /* operators */
+
+  AND_TOK = 'AND';
+  BOOLEAN_TOK = 'BOOLEAN';
   ECHO_TOK = 'ECHO';
   ELSEIF_TOK = 'ELSIF';
   ELSE_TOK = 'ELSE';
@@ -46,22 +93,13 @@ tokens {
   INT_TOK = 'INT';
   LET_TOK = 'LET';
   NOT_TOK = 'NOT';
-  OPTION_TOK = 'OPTION';
   OR_TOK = 'OR';
-  POPTO_TOK = 'POPTO';
-  POP_TOK = 'POP';
-  PRINT_TOK = 'PRINT';
-  PUSH_TOK = 'PUSH';
-  QUERY_TOK = 'QUERY';
   REAL_TOK = 'REAL';
   THEN_TOK = 'THEN';
   TRUE_TOK = 'TRUE';
   TYPE_TOK = 'TYPE';
   XOR_TOK = 'XOR';
 
-  DATATYPE_TOK = 'DATATYPE';
-  END_TOK = 'END';
-
   ARRAY_TOK = 'ARRAY';
   OF_TOK = 'OF';
   WITH_TOK = 'WITH';
@@ -86,8 +124,6 @@ tokens {
   RBRACKET = ']';
   SEMICOLON = ';';
   BAR = '|';
-  DOT = '.';
-  DOTDOT = '..';
   UNDERSCORE = '_';
 
   SQHASH = '[#';
@@ -95,6 +131,9 @@ tokens {
   PARENHASH = '(#';
   HASHPAREN = '#)';
 
+  DOT = '.';
+  DOTDOT = '..';
+
   // Operators
 
   ARROW_TOK = '->';
@@ -158,7 +197,7 @@ tokens {
   BVSGT_TOK = 'BVSGT';
   BVSLE_TOK = 'BVSLE';
   BVSGE_TOK = 'BVSGE';
-}
+}/* tokens */
 
 @parser::members {
 
@@ -171,7 +210,7 @@ bool isRightToLeft(int type) {
   case IMPLIES_TOK: return true;
   default: return false;
   }
-}
+}/* isRightToLeft() */
 
 int getOperatorPrecedence(int type) {
   switch(type) {
@@ -247,7 +286,7 @@ int getOperatorPrecedence(int type) {
   default:
     Unhandled(CvcParserTokenNames[type]);
   }
-}
+}/* getOperatorPrecedence() */
 
 Kind getOperatorKind(int type, bool& negate) {
   negate = false;
@@ -276,7 +315,7 @@ Kind getOperatorKind(int type, bool& negate) {
   case DIV_TOK: return kind::DIVISION;
   case EXP_TOK: Unhandled(CvcParserTokenNames[type]);
 
-    // concatBitwiseBinop
+    // bvBinop
   case CONCAT_TOK: return kind::BITVECTOR_CONCAT;
   case BAR: return kind::BITVECTOR_OR;
   case BVAND_TOK: return kind::BITVECTOR_AND;
@@ -284,7 +323,7 @@ Kind getOperatorKind(int type, bool& negate) {
   default:
     Unhandled(CvcParserTokenNames[type]);
   }
-}
+}/* getOperatorKind() */
 
 unsigned findPivot(const std::vector<unsigned>& operators,
                    unsigned startIndex, unsigned stopIndex) {
@@ -305,7 +344,7 @@ unsigned findPivot(const std::vector<unsigned>& operators,
     }
   }
   return pivot;
-}
+}/* findPivot() */
 
 Expr createPrecedenceTree(ExprManager* em,
                           const std::vector<CVC4::Expr>& expressions,
@@ -327,7 +366,7 @@ Expr createPrecedenceTree(ExprManager* em,
                       createPrecedenceTree(em, expressions, operators, startIndex, pivot),
                       createPrecedenceTree(em, expressions, operators, pivot + 1, stopIndex));
   return negate ? em->mkExpr(kind::NOT, e) : e;
-}
+}/* createPrecedenceTree() recursive variant */
 
 Expr createPrecedenceTree(ExprManager* em,
                           const std::vector<CVC4::Expr>& expressions,
@@ -348,7 +387,7 @@ Expr createPrecedenceTree(ExprManager* em,
     Debug("prec") << "=> " << e << std::endl;
   }
   return e;
-}
+}/* createPrecedenceTree() base variant */
 
 /** Add n NOTs to the front of e and return the result. */
 Expr addNots(ExprManager* em, size_t n, Expr e) {
@@ -356,22 +395,23 @@ Expr addNots(ExprManager* em, size_t n, Expr e) {
     e = em->mkExpr(kind::NOT, e);
   }
   return e;
-}
+}/* addNots() */
 
 }/* @parser::members */
 
 @header {
 /**
  ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010  The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009, 2010, 2011  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.
  **/
-}
+}/* @header */
 
 @lexer::includes {
+
 /** This suppresses warnings about the redefinition of token symbols between different
   * parsers. The redefinitions should be harmless as long as no client: (a) #include's
   * the lexer headers for two grammars AND (b) uses the token symbol definitions. */
@@ -383,11 +423,20 @@ Expr addNots(ExprManager* em, size_t n, Expr e) {
  * Otherwise, we have to let the lexer detect the encoding at runtime.
  */
 #define ANTLR3_INLINE_INPUT_ASCII
-}
+
+#include "parser/antlr_tracing.h"
+#include "util/integer.h"
+#include "parser/antlr_input.h"
+#include "parser/parser.h"
+
+}/* @lexer::includes */
 
 @parser::includes {
+
 #include "expr/command.h"
 #include "parser/parser.h"
+#include "util/subrange_bound.h"
+#include "parser/antlr_tracing.h"
 
 namespace CVC4 {
   class Expr;
@@ -402,27 +451,55 @@ namespace CVC4 {
        * them to be constructible by a uintptr_t.  So we derive the string
        * class to provide just such a conversion.
        */
-      class mystring : public std::string {
+      class myString : public std::string {
       public:
-        mystring(const std::string& s) : std::string(s) {}
-        mystring(uintptr_t) : std::string() {}
-        mystring() : std::string() {}
-      };/* class mystring */
+        myString(const std::string& s) : std::string(s) {}
+        myString(uintptr_t) : std::string() {}
+        myString() : std::string() {}
+      };/* class myString */
+
+      /**
+       * Just exists to give us the uintptr_t construction that
+       * ANTLR requires.
+       */
+      class mySubrangeBound : public CVC4::SubrangeBound {
+      public:
+        mySubrangeBound() : CVC4::SubrangeBound() {}
+        mySubrangeBound(uintptr_t) : CVC4::SubrangeBound() {}
+        mySubrangeBound(const Integer& i) : CVC4::SubrangeBound(i) {}
+        mySubrangeBound(const SubrangeBound& b) : CVC4::SubrangeBound(b) {}
+      };/* class mySubrangeBound */
     }/* CVC4::parser::cvc namespace */
   }/* CVC4::parser namespace */
 }/* CVC4 namespace */
 
-}
+}/* @parser::includes */
 
 @parser::postinclude {
+
 #include "expr/expr.h"
 #include "expr/kind.h"
 #include "expr/type.h"
 #include "parser/antlr_input.h"
 #include "parser/parser.h"
 #include "util/output.h"
+
 #include <vector>
 
+#define REPEAT_COMMAND(k, CommandCtor)                      \
+  ({                                                        \
+    unsigned __k = (k);                                     \
+    (__k <= 1)                                              \
+      ? (Command*) new CommandCtor                          \
+      : ({                                                  \
+          CommandSequence* __seq = new CommandSequence();   \
+          while(__k-- > 0) {                                \
+            __seq->addCommand(new CommandCtor);             \
+          }                                                 \
+          (Command*) __seq;                                 \
+        });                                                 \
+  })
+
 using namespace CVC4;
 using namespace CVC4::parser;
 
@@ -436,8 +513,9 @@ using namespace CVC4::parser;
 #define MK_EXPR EXPR_MANAGER->mkExpr
 #undef MK_CONST
 #define MK_CONST EXPR_MANAGER->mkConst
-}
+#define UNSUPPORTED PARSER_STATE->unimplementedFeature
 
+}/* @parser::postinclude */
 
 /**
  * Parses an expression.
@@ -453,30 +531,78 @@ parseExpr returns [CVC4::Expr expr]
  * @return the command of the benchmark
  */
 parseCommand returns [CVC4::Command* cmd]
-  : c = command { $cmd = c; }
+  : c=command { $cmd = c; }
+  | EOF { $cmd = NULL; }
   ;
 
 /**
  * Matches a command of the input. If a declaration, it will return an empty
  * command.
  */
-command returns [CVC4::Command* cmd = 0]
+command returns [CVC4::Command* cmd = NULL]
+  : ( mainCommand[cmd] SEMICOLON
+    | SEMICOLON
+    | LET_TOK { PARSER_STATE->pushScope(); }
+      typeOrVarLetDecl[CHECK_DECLARED] ( COMMA typeOrVarLetDecl[CHECK_DECLARED] )*
+      IN_TOK c=command
+      { $cmd = c;
+        PARSER_STATE->popScope();
+      }
+    )
+    { if($cmd == NULL) {
+        cmd = new EmptyCommand();
+      }
+    }
+  ;
+
+typeOrVarLetDecl[CVC4::parser::DeclarationCheck check]
+options { backtrack = true; }
+  : letDecl | typeLetDecl[check]
+  ;
+
+mainCommand[CVC4::Command*& cmd]
 @init {
   Expr f;
   SExpr sexpr;
-  std::string s;
+  std::string id;
   Type t;
   std::vector<CVC4::Datatype> dts;
   Debug("parser-extra") << "command: " << AntlrInput::tokenText(LT(1)) << std::endl;
+  std::string s;
+  k = 0;
 }
-  : ASSERT_TOK formula[f] SEMICOLON { cmd = new AssertCommand(f); }
-  | QUERY_TOK formula[f] SEMICOLON { cmd = new QueryCommand(f); }
-  | CHECKSAT_TOK formula[f] SEMICOLON { cmd = new CheckSatCommand(f); }
-  | CHECKSAT_TOK SEMICOLON { cmd = new CheckSatCommand(MK_CONST(true)); }
-  | OPTION_TOK STRING_LITERAL symbolicExpr[sexpr] SEMICOLON
-    { cmd = new SetOptionCommand(AntlrInput::tokenText($STRING_LITERAL), sexpr); }
-  | PUSH_TOK SEMICOLON { cmd = new PushCommand(); }
-  | POP_TOK SEMICOLON { cmd = new PopCommand(); }
+    /* our bread & butter */
+  : ASSERT_TOK formula[f] { cmd = new AssertCommand(f); }
+
+  | QUERY_TOK formula[f] { cmd = new QueryCommand(f); }
+  | CHECKSAT_TOK formula[f] { cmd = new CheckSatCommand(f); }
+  | CHECKSAT_TOK { cmd = new CheckSatCommand(MK_CONST(true)); }
+
+    /* options */
+  | OPTION_TOK
+    ( str[s] | IDENTIFIER { s = AntlrInput::tokenText($IDENTIFIER); } )
+    symbolicExpr[sexpr]
+    { cmd = new SetOptionCommand(s, sexpr); }
+
+    /* push / pop */
+  | PUSH_TOK k=numeral?
+    { cmd = REPEAT_COMMAND(k, PushCommand()); }
+  | POP_TOK k=numeral?
+    { cmd = REPEAT_COMMAND(k, PopCommand()); }
+  | POPTO_TOK k=numeral?
+    { UNSUPPORTED("POPTO command"); }
+
+    /* push / pop scopes */
+  | PUSH_SCOPE_TOK k=numeral?
+    { UNSUPPORTED("PUSH_SCOPE command"); }
+  | POP_SCOPE_TOK k=numeral?
+    { UNSUPPORTED("POP_SCOPE command"); }
+  | POPTO_SCOPE_TOK k=numeral?
+    { UNSUPPORTED("POPTO_SCOPE command"); }
+
+  | RESET_TOK
+    { UNSUPPORTED("RESET command"); }
+
     // Datatypes can be mututally-recursive if they're in the same
     // definition block, separated by a comma.  So we parse everything
     // and then ask the ExprManager to resolve everything in one go.
@@ -485,24 +611,117 @@ command returns [CVC4::Command* cmd = 0]
       PARSER_STATE->pushScope(); }
     datatypeDef[dts]
     ( COMMA datatypeDef[dts] )*
-    END_TOK SEMICOLON
+    END_TOK
     { PARSER_STATE->popScope();
       cmd = new DatatypeDeclarationCommand(PARSER_STATE->mkMutualDatatypeTypes(dts)); }
+
+  | CONTEXT_TOK
+    ( ( str[s] | IDENTIFIER { s = AntlrInput::tokenText($IDENTIFIER); } )
+      { UNSUPPORTED("CONTEXT command"); }
+    | { UNSUPPORTED("CONTEXT command"); }
+    )
+
+  | FORGET_TOK identifier[id,CHECK_NONE,SYM_VARIABLE]
+    { UNSUPPORTED("FORGET command"); }
+
+  | GET_TYPE_TOK formula[f]
+    { UNSUPPORTED("GET_TYPE command"); }
+
+  | CHECK_TYPE_TOK formula[f] COLON type[t,CHECK_DECLARED]
+    { UNSUPPORTED("CHECK_TYPE command"); }
+
+  | GET_CHILD_TOK formula[f] k=numeral
+    { UNSUPPORTED("GET_CHILD command"); }
+
+  | GET_OP_TOK formula[f]
+    { UNSUPPORTED("GET_OP command"); }
+
+  | SUBSTITUTE_TOK identifier[id,CHECK_NONE,SYM_VARIABLE] COLON type[t,CHECK_DECLARED] EQUAL_TOK
+    formula[f] LBRACKET identifier[id,CHECK_NONE,SYM_VARIABLE] ASSIGN_TOK formula[f] RBRACKET
+    { UNSUPPORTED("SUBSTITUTE command"); }
+
+    /* Like the --debug command line option, DBG turns on both tracing
+     * and debugging. */
+  | DBG_TOK
+    ( ( str[s] | IDENTIFIER { s = AntlrInput::tokenText($IDENTIFIER); } )
+      { Debug.on(s); Trace.on(s); }
+    | { Message() << "Please specify what to debug." << std::endl; }
+    )
+
+  | TRACE_TOK
+    ( ( str[s] | IDENTIFIER { s = AntlrInput::tokenText($IDENTIFIER); } )
+      { Trace.on(s); }
+    | { Message() << "Please specify something to trace." << std::endl; }
+    )
+  | UNTRACE_TOK
+    ( ( str[s] | IDENTIFIER { s = AntlrInput::tokenText($IDENTIFIER); } )
+      { Trace.off(s); }
+    | { Message() << "Please specify something to untrace." << std::endl; }
+    )
+
+  | HELP_TOK
+    ( ( str[s] | IDENTIFIER { s = AntlrInput::tokenText($IDENTIFIER); } )
+      { Message() << "No help available for `" << s << "'." << std::endl; }
+    | { Message() << "Please use --help at the command line for help." << std::endl; }
+    )
+
+  | TRANSFORM_TOK formula[f]
+    { UNSUPPORTED("TRANSFORM command"); }
+
+  | PRINT_TOK formula[f]
+    { UNSUPPORTED("PRINT command"); }
+  | PRINT_TYPE_TOK type[t,CHECK_DECLARED]
+    { UNSUPPORTED("PRINT_TYPE command"); }
+
+  | CALL_TOK identifier[id,CHECK_NONE,SYM_VARIABLE] formula[f]
+    { UNSUPPORTED("CALL command"); }
+
+  | ECHO_TOK
+    ( ( str[s] | IDENTIFIER { s = AntlrInput::tokenText($IDENTIFIER); } )
+      { CVC4::Message() << s << std::endl; }
+    | { CVC4::Message() << std::endl; }
+    )
+
+  | INCLUDE_TOK
+    ( ( str[s] | IDENTIFIER { s = AntlrInput::tokenText($IDENTIFIER); } )
+      { UNSUPPORTED("INCLUDE command"); }
+    | { PARSER_STATE->parseError("No filename given to INCLUDE command"); }
+    )
+
+  | ( DUMP_PROOF_TOK
+    | DUMP_ASSUMPTIONS_TOK
+    | DUMP_SIG_TOK
+    | DUMP_TCC_TOK
+    | DUMP_TCC_ASSUMPTIONS_TOK
+    | DUMP_TCC_PROOF_TOK
+    | DUMP_CLOSURE_TOK
+    | DUMP_CLOSURE_PROOF_TOK
+    ) { UNSUPPORTED("DUMP* command"); }
+
+    /* these are all synonyms */
+  | ( WHERE_TOK | ASSERTIONS_TOK | ASSUMPTIONS_TOK )
+    { cmd = new GetAssertionsCommand(); }
+
+  | COUNTEREXAMPLE_TOK
+    { UNSUPPORTED("COUNTEREXAMPLE command"); }
+  | COUNTERMODEL_TOK
+    { UNSUPPORTED("COUNTERMODEL command"); }
+
+  | ARITH_VAR_ORDER_TOK LPAREN formula[f] ( COMMA formula[f] )* RPAREN
+    { UNSUPPORTED("ARITH_VAR_ORDER command"); }
+
   | toplevelDeclaration[cmd]
-  | SEMICOLON c=command { $cmd = c; }
-  | EOF
   ;
 
 symbolicExpr[CVC4::SExpr& sexpr]
 @declarations {
   std::vector<SExpr> children;
+  std::string s;
 }
-  : INTEGER_LITERAL
-    { sexpr = SExpr(AntlrInput::tokenText($INTEGER_LITERAL)); }
-  | DECIMAL_LITERAL
-    { sexpr = SExpr(AntlrInput::tokenText($DECIMAL_LITERAL)); }
-  | STRING_LITERAL
-    { sexpr = SExpr(AntlrInput::tokenText($STRING_LITERAL)); }
+  : INTEGER_LITERAL ('.' DIGIT+)?
+    { sexpr = SExpr((const char*)$symbolicExpr.text->chars); }
+  | str[s]
+    { sexpr = SExpr(s); }
   | IDENTIFIER
     { sexpr = SExpr(AntlrInput::tokenText($IDENTIFIER)); }
   | LPAREN (symbolicExpr[sexpr] { children.push_back(sexpr); } )* RPAREN
@@ -520,7 +739,7 @@ toplevelDeclaration[CVC4::Command*& cmd]
 }
   : identifierList[ids,CHECK_NONE,SYM_VARIABLE] COLON
     ( declareVariables[t,ids,true] { cmd = new DeclarationCommand(ids, t); }
-    | declareTypes[ids] { cmd = new DeclarationCommand(ids, EXPR_MANAGER->kindType()); } ) SEMICOLON
+    | declareTypes[ids] { cmd = new DeclarationCommand(ids, EXPR_MANAGER->kindType()); } )
   ;
 
 /**
@@ -681,7 +900,6 @@ identifierList[std::vector<std::string>& idList,
     ( COMMA identifier[id,check,type] { idList.push_back(id); } )*
   ;
 
-
 /**
  * Matches an identifier and returns a string.
  */
@@ -774,6 +992,7 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
 }
     /* named types */
   : identifier[id,check,SYM_SORT]
+    parameterization[check]?
     { if(check == CHECK_DECLARED ||
          PARSER_STATE->isDeclared(id, SYM_SORT)) {
         t = PARSER_STATE->getSort(id);
@@ -788,15 +1007,23 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
 
     /* subtypes */
   | SUBTYPE_TOK LPAREN formula[f] ( COMMA formula[f] )? RPAREN
-    { PARSER_STATE->unimplementedFeature("subtypes not supported yet");
+    { UNSUPPORTED("subtypes not supported yet");
       t = Type(); }
 
     /* subrange types */
-/* parsing not working -- some kind of conflict betw [0..1] and 0.0
-  | bounds
-    { PARSER_STATE->unimplementedFeature("subranges not supported yet");
+  | LBRACKET k1=bound DOTDOT k2=bound RBRACKET
+    { std::stringstream ss;
+      ss << "subranges not supported yet: [" << k1 << ":" << k2 << ']';
+      UNSUPPORTED(ss.str());
+      if(k1.hasBound() && k2.hasBound() &&
+         k1.getBound() > k2.getBound()) {
+        ss.str("");
+        ss << "Subrange [" << k1.getBound() << ".." << k2.getBound()
+           << "] inappropriate: range must be nonempty!";
+        PARSER_STATE->parseError(ss.str());
+      }
+      Debug("subranges") << ss.str() << std::endl;
       t = Type(); }
-*/
 
     /* tuple types / old-style function types */
   | LBRACKET type[t,check] { types.push_back(t); }
@@ -817,7 +1044,7 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
     /* record types */
   | SQHASH identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check]
     ( COMMA identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check] )* HASHSQ
-    { PARSER_STATE->unimplementedFeature("records not supported yet");
+    { UNSUPPORTED("records not supported yet");
       t = Type(); }
 
     /* bitvector types */
@@ -839,26 +1066,19 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
     }
   ;
 
-/**
- * Matches a type identifier.  Returns the identifier.  If the type is
- * declared, returns the Type in the 't' parameter; otherwise a null
- * Type is returned in 't'.  If 'check' is CHECK_DECLARED and the type
- * is not declared, an exception is thrown.
- *
- * @return the type identifier
- */
-typeSymbol[CVC4::Type& t,
-           CVC4::parser::DeclarationCheck check] returns [CVC4::parser::cvc::mystring id]
+parameterization[CVC4::parser::DeclarationCheck check]
 @init {
-  Debug("parser-extra") << "type symbol: " << AntlrInput::tokenText(LT(1)) << std::endl;
+  Type t;
 }
-  : identifier[id,check,SYM_SORT]
-    { bool isNew = (check == CHECK_UNDECLARED || check == CHECK_NONE) &&
-                   !PARSER_STATE->isDeclared(id, SYM_SORT);
-      t = isNew ? Type() : PARSER_STATE->getSort(id);
-    }
+  : LBRACKET restrictedType[t,check] ( COMMA restrictedType[t,check] )* RBRACKET
+    { UNSUPPORTED("parameterized types not yet supported"); }
   ;
 
+bound returns [CVC4::parser::cvc::mySubrangeBound bound]
+  : UNDERSCORE { $bound = SubrangeBound(); }
+  | k=integer { $bound = SubrangeBound(k); }
+;
+
 typeLetDecl[CVC4::parser::DeclarationCheck check]
 @init {
   Type t;
@@ -934,14 +1154,14 @@ prefixFormula[CVC4::Expr& f]
     boundVarDecl[ids,t] (COMMA boundVarDecl[ids,t])* RPAREN
     COLON instantiationPatterns? formula[f]
     { PARSER_STATE->popScope();
-      PARSER_STATE->unimplementedFeature("quantifiers not supported yet");
+      UNSUPPORTED("quantifiers not supported yet");
       f = EXPR_MANAGER->mkVar(EXPR_MANAGER->booleanType());
     }
   | EXISTS_TOK { PARSER_STATE->pushScope(); } LPAREN
     boundVarDecl[ids,t] (COMMA boundVarDecl[ids,t])* RPAREN
     COLON instantiationPatterns? formula[f]
     { PARSER_STATE->popScope();
-      PARSER_STATE->unimplementedFeature("quantifiers not supported yet");
+      UNSUPPORTED("quantifiers not supported yet");
       f = EXPR_MANAGER->mkVar(EXPR_MANAGER->booleanType());
     }
 
@@ -968,7 +1188,7 @@ prefixFormula[CVC4::Expr& f]
   | ARRAY_TOK { PARSER_STATE->pushScope(); } LPAREN
     boundVarDecl[ids,t] RPAREN COLON formula[f]
     { PARSER_STATE->popScope();
-      PARSER_STATE->unimplementedFeature("array literals not supported yet");
+      UNSUPPORTED("array literals not supported yet");
       f = EXPR_MANAGER->mkVar(EXPR_MANAGER->mkArrayType(t, f.getType()));
     }
   ;
@@ -1055,16 +1275,40 @@ arithmeticBinop[unsigned& op]
   | EXP_TOK
   ;
 
-/** Parses an array store term. */
+/** Parses an array assignment term. */
 storeTerm[CVC4::Expr& f]
+  : uminusTerm[f]
+    ( WITH_TOK arrayStore[f] ( COMMA arrayStore[f] )* )*
+  ;
+
+/**
+ * Parses just part of the array assignment (and constructs
+ * the store terms).
+ */
+arrayStore[CVC4::Expr& f]
 @init {
   Expr f2, f3;
+  std::vector<Expr> dims;
 }
-  : uminusTerm[f] ( WITH_TOK
-    LBRACKET formula[f2] RBRACKET ASSIGN_TOK uminusTerm[f3]
-    { f = MK_EXPR(CVC4::kind::STORE, f, f2, f3); }
-    ( COMMA LBRACKET formula[f2] RBRACKET ASSIGN_TOK uminusTerm[f3]
-      { f = MK_EXPR(CVC4::kind::STORE, f, f2, f3); } )* )*
+  : ( LBRACKET formula[f2] { dims.push_back(f2); } RBRACKET )+
+    ASSIGN_TOK uminusTerm[f3]
+    { Assert(dims.size() >= 1);
+      // these loops are a bit complicated; they're only used for the
+      // multidimensional ...WITH [a][b] :=... syntax
+      for(unsigned i = 0; i < dims.size() - 1; ++i) {
+        f = MK_EXPR(CVC4::kind::SELECT, f, dims[i]);
+      }
+      // a[i][j][k] := v  turns into
+      // store(a, i, store(a[i], j, store(a[i][j], k, v)))
+      for(unsigned i = dims.size() - 1; i > 0; --i) {
+        f3 = MK_EXPR(CVC4::kind::STORE, f, dims[i], f3);
+        // strip off one layer of the select
+        f = f[0];
+      }
+
+      // outermost wrapping
+      f = MK_EXPR(CVC4::kind::STORE, f, dims[0], f3);
+    }
   ;
 
 /** Parses a unary minus term. */
@@ -1073,29 +1317,28 @@ uminusTerm[CVC4::Expr& f]
   unsigned minusCount = 0;
 }
     /* Unary minus */
-  : (MINUS_TOK { ++minusCount; })+ concatBitwiseTerm[f]
+  : (MINUS_TOK { ++minusCount; })+ bvBinaryOpTerm[f]
     { while(minusCount > 0) { --minusCount; f = MK_EXPR(CVC4::kind::UMINUS, f); } }
-  | concatBitwiseTerm[f]
+  | bvBinaryOpTerm[f]
   ;
 
-/** Parses bitvectors. */
-
-concatBitwiseTerm[CVC4::Expr& f]
+/** Parses bitvectors.  Starts with binary operators @, &, and |. */
+bvBinaryOpTerm[CVC4::Expr& f]
 @init {
   std::vector<CVC4::Expr> expressions;
   std::vector<unsigned> operators;
   unsigned op;
 }
   : bvNegTerm[f] { expressions.push_back(f); }
-    ( concatBitwiseBinop[op] bvNegTerm[f] { operators.push_back(op); expressions.push_back(f); } )*
+    ( bvBinop[op] bvNegTerm[f] { operators.push_back(op); expressions.push_back(f); } )*
     { f = createPrecedenceTree(EXPR_MANAGER, expressions, operators); }
   ;
-concatBitwiseBinop[unsigned& op]
+bvBinop[unsigned& op]
 @init {
   op = LT(1)->getType(LT(1));
 }
   : CONCAT_TOK
-  | BAR
+  | BAR // bitwise OR
   | BVAND_TOK
   ;
 
@@ -1103,7 +1346,7 @@ bvNegTerm[CVC4::Expr& f]
     /* BV neg */
   : BVNEG_TOK bvNegTerm[f]
     { f = MK_EXPR(CVC4::kind::BITVECTOR_NOT, f); }
-  | selectExtractShift[f]
+  | postfixTerm[f]
   ;
 
 /**
@@ -1115,11 +1358,12 @@ bvNegTerm[CVC4::Expr& f]
  * brackets ], so we left-factor as much out as possible to make ANTLR
  * happy.
  */
-selectExtractShift[CVC4::Expr& f]
+postfixTerm[CVC4::Expr& f]
 @init {
   Expr f2;
   bool extract, left;
   std::vector<Expr> args;
+  std::string id;
 }
   : bvTerm[f]
     ( /* array select / bitvector extract */
@@ -1172,7 +1416,21 @@ selectExtractShift[CVC4::Expr& f]
           Unhandled(t);
         }
       }
+
+      /* record / tuple select */
+    | DOT
+      ( identifier[id,CHECK_NONE,SYM_VARIABLE]
+        { UNSUPPORTED("record select not implemented yet");
+          f = Expr(); }
+      | k=numeral
+        { UNSUPPORTED("tuple select not implemented yet");
+          // This will assert-fail if k too big or f not a tuple
+          // that's ok for now, once a TUPLE_SELECT operator exists,
+          // that will do any necessary type checking
+          f = EXPR_MANAGER->mkVar(TupleType(f.getType()).getTypes()[k]); }
+      )
     )*
+    typeAscription[f]?
   ;
 
 bvTerm[CVC4::Expr& f]
@@ -1315,6 +1573,7 @@ simpleTerm[CVC4::Expr& f]
   std::string name;
   std::vector<Expr> args;
   Debug("parser-extra") << "term: " << AntlrInput::tokenText(LT(1)) << std::endl;
+  Type t;
 }
     /* if-then-else */
   : iteTerm[f]
@@ -1334,8 +1593,11 @@ simpleTerm[CVC4::Expr& f]
   | TRUE_TOK  { f = MK_CONST(true); }
   | FALSE_TOK { f = MK_CONST(false); }
     /* arithmetic literals */
-  | INTEGER_LITERAL { f = MK_CONST( AntlrInput::tokenToInteger($INTEGER_LITERAL) ); }
-  | DECIMAL_LITERAL { f = MK_CONST( AntlrInput::tokenToRational($DECIMAL_LITERAL) ); }
+    /* syntactic predicate: never match INTEGER.DIGIT as an integer and a dot!
+     * This is a rational constant!  Otherwise the parser interprets it as a tuple
+     * selector! */
+  | (INTEGER_LITERAL DOT DIGIT)=> r=decimal_literal { f = MK_CONST(r); }
+  | INTEGER_LITERAL { f = MK_CONST(AntlrInput::tokenToInteger($INTEGER_LITERAL)); }
     /* bitvector literals */
   | HEX_LITERAL
     { Assert( AntlrInput::tokenText($HEX_LITERAL).find("0hex") == 0 );
@@ -1347,22 +1609,43 @@ simpleTerm[CVC4::Expr& f]
       f = MK_CONST( BitVector(binString, 2) ); }
     /* record literals */
   | PARENHASH recordEntry (COMMA recordEntry)+ HASHPAREN
-    { PARSER_STATE->unimplementedFeature("records not implemented yet");
+    { UNSUPPORTED("records not implemented yet");
       f = Expr(); }
 
     /* variable / zero-ary constructor application */
   | identifier[name,CHECK_DECLARED,SYM_VARIABLE]
-    { f = PARSER_STATE->getVariable(name);
-      // datatypes: zero-ary constructors
-      Type t = PARSER_STATE->getType(name);
-      if(t.isConstructor() && ConstructorType(t).getArity() == 0) {
-        // don't require parentheses, immediately turn it into an
-        // apply
+    /* ascriptions will be required for parameterized zero-ary constructors */
+    { f = PARSER_STATE->getVariable(name); }
+    { // datatypes: zero-ary constructors
+      Type t2 = PARSER_STATE->getType(name);
+      if(t2.isConstructor() && ConstructorType(t2).getArity() == 0) {
+        // don't require parentheses, immediately turn it into an apply
         f = MK_EXPR(CVC4::kind::APPLY_CONSTRUCTOR, f);
       }
     }
   ;
 
+/**
+ * Matches (and performs) a type ascription.
+ * The f arg is the term to check (it is an input-only argument).
+ */
+typeAscription[const CVC4::Expr& f]
+@init {
+  Type t;
+}
+  : COLON COLON type[t,CHECK_DECLARED]
+    { if(f.getType() != t) {
+        std::stringstream ss;
+        ss << Expr::setlanguage(language::output::LANG_CVC4)
+           << "type ascription not satisfied\n"
+           << "term:     " << f << '\n'
+           << "has type: " << f.getType() << '\n'
+           << "ascribed: " << t;
+        PARSER_STATE->parseError(ss.str());
+      }
+    }
+  ;
+
 /**
  * Matches an entry in a record literal.
  */
@@ -1409,9 +1692,16 @@ iteElseTerm[CVC4::Expr& f]
  */
 datatypeDef[std::vector<CVC4::Datatype>& datatypes]
 @init {
-  std::string id;
+  std::string id, id2;
 }
+    /* This really needs to be CHECK_NONE, or mutually-recursive datatypes
+     * won't work, because this type will already be "defined" as an
+     * unresolved type; don't worry, we check below. */
   : identifier[id,CHECK_NONE,SYM_SORT]
+    ( LBRACKET identifier[id2,CHECK_NONE,SYM_SORT]
+      ( COMMA identifier[id2,CHECK_NONE,SYM_SORT] )* RBRACKET
+      { UNSUPPORTED("parameterized datatypes not yet supported"); }
+    )?
     { datatypes.push_back(Datatype(id));
       if(!PARSER_STATE->isUnresolvedType(id)) {
         // if not unresolved, must be undeclared
@@ -1453,7 +1743,7 @@ constructorDef[CVC4::Datatype& type]
 selector[CVC4::Datatype::Constructor& ctor]
 @init {
   std::string id;
-  Type t;
+  Type t, t2;
 }
   : identifier[id,CHECK_UNDECLARED,SYM_SORT] COLON type[t,CHECK_NONE]
     { ctor.addArg(id, t);
@@ -1465,12 +1755,24 @@ selector[CVC4::Datatype::Constructor& ctor]
  * Matches an identifier from the input. An identifier is a sequence of letters,
  * digits and "_", "'", "." symbols, starting with a letter.
  */
-IDENTIFIER : ALPHA (ALPHA | DIGIT | '_' | '\'' | '.')*;
+IDENTIFIER : (ALPHA | '_') (ALPHA | DIGIT | '_' | '\'' | '\\' | '?' | '$' | '~')*;
 
 /**
  * Matches an integer literal.
  */
-INTEGER_LITERAL: DIGIT+;
+INTEGER_LITERAL
+  : ( '0'
+    | '1'..'9' DIGIT*
+    )
+  ;
+
+/**
+ * Matches a decimal literal.
+ */
+decimal_literal returns [CVC4::Rational r]
+  : k=(INTEGER_LITERAL '.' DIGIT+)
+    { $r = AntlrInput::tokenToRational($k); }
+  ;
 
 /**
  * Same as an integer literal converted to an unsigned int, but
@@ -1484,9 +1786,25 @@ numeral returns [unsigned k]
   ;
 
 /**
- * Matches a decimal literal.
+ * Similar to numeral but for arbitrary-precision, signed integer.
  */
-DECIMAL_LITERAL: DIGIT+ DOT DIGIT+;
+integer returns [CVC4::Integer k]
+  : INTEGER_LITERAL
+    { $k = AntlrInput::tokenToInteger($INTEGER_LITERAL); }
+  | MINUS_TOK INTEGER_LITERAL
+    { $k = -AntlrInput::tokenToInteger($INTEGER_LITERAL); }
+  ;
+
+/**
+ * Similar to numeral but for strings.
+ */
+str[std::string& s]
+  : STRING_LITERAL
+    { s = AntlrInput::tokenText($STRING_LITERAL);
+      /* strip off the quotes */
+      s = s.substr(1, s.size() - 2);
+    }
+  ;
 
 /**
  * Matches a hexadecimal constant.
@@ -1514,21 +1832,24 @@ STRING_LITERAL: '"' (ESCAPE | ~('"'|'\\'))* '"';
 fragment ALPHA : 'a'..'z' | 'A'..'Z';
 
 /**
- * Matches the digits (0-9)
+ * Matches the decimal digits (0-9)
  */
 fragment DIGIT : '0'..'9';
 
+/**
+ * Matches the hexidecimal digits (0-9, a-f, A-F)
+ */
 fragment HEX_DIGIT : DIGIT | 'a'..'f' | 'A'..'F';
 
 /**
  * Matches and skips whitespace in the input and ignores it.
  */
-WHITESPACE : (' ' | '\t' | '\f' | '\r' | '\n')+ { SKIP();; };
+WHITESPACE : (' ' | '\t' | '\f' | '\r' | '\n')+ { SKIP(); };
 
 /**
  * Matches the comments and ignores them
  */
-COMMENT : '%' (~('\n' | '\r'))* { SKIP();; };
+COMMENT : '%' (~('\n' | '\r'))* { SKIP(); };
 
 /**
  * Matches an allowed escaped character.
index ea67ef35629ba7eae9c06fcdd02363f99fb132f8..f20406c20fce4e010300a974666a2a6932b223da 100644 (file)
@@ -7,6 +7,11 @@ AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN) -Wno-unused-f
 CC=$(CXX)
 AM_CFLAGS = $(AM_CXXFLAGS)
 
+ANTLR_OPTS =
+
+# hide this included makefile from automake
+@mk_include@ @srcdir@/../Makefile.antlr_tracing
+
 noinst_LTLIBRARIES = libparsercvc.la
 
 ANTLR_TOKEN_STUFF = \
@@ -30,7 +35,9 @@ libparsercvc_la_SOURCES = \
 
 BUILT_SOURCES = $(ANTLR_STUFF) @srcdir@/stamp-generated
 
-EXTRA_DIST = @srcdir@/stamp-generated
+EXTRA_DIST = \
+       @srcdir@/stamp-generated \
+       README
 
 MAINTAINERCLEANFILES = $(ANTLR_STUFF)
 maintainer-clean-local:
@@ -44,7 +51,7 @@ maintainer-clean-local:
 # antlr doesn't overwrite output files, it just leaves them.  So we have to delete them first.
 @srcdir@/generated/CvcLexer.h: Cvc.g @srcdir@/stamp-generated
        -$(AM_V_at)rm -f $(ANTLR_STUFF)
-       $(AM_V_GEN)$(ANTLR) -o "@srcdir@/generated" "@srcdir@/Cvc.g"
+       $(AM_V_GEN)$(ANTLR) $(ANTLR_OPTS) -o "@srcdir@/generated" "@srcdir@/Cvc.g"
 
 # These don't actually depend on CvcLexer.h, but if we're doing parallel
 # make and the lexer needs to be rebuilt, we have to keep the rules
diff --git a/src/parser/cvc/README b/src/parser/cvc/README
new file mode 100644 (file)
index 0000000..513a8e8
--- /dev/null
@@ -0,0 +1,98 @@
+Notes on CVC4's CVC language parser.
+
+This language parser attempts to maintain some backward compatibility
+with previous versions of the language.  However, as the language
+evolves, new features need to be supported, and deprecated,
+difficult-to-maintain, or grammar-conflicting syntax and features
+need to be removed.
+
+In order to support our users, we have tried to parse what CVC3 could
+and (at least) offer an error when a feature is unavailable or
+unimplemented.  But this is not always possible.  Please report a
+bug if a particular discrepancy between CVC3 and CVC4 handling of
+the CVC language is a concern to you; we may be able to add a
+compatibility mode, or at least offer better warnings or errors.
+
+Below is a list of the known differences between CVC3's and CVC4's
+version of the CVC language.  This is the list of differences in
+language design and parsing ONLY.  The featureset of CVC4 is
+rapidly expanding, but does not match CVC3's breadth yet.  However,
+CVC4 should tell you of an unimplemented feature if you try to use
+it (rather than giving a cryptic parse or assertion error).
+
+* CVC4 does not add the current assumptions to the scope after
+  SAT/INVALID responses like CVC3 did.
+
+* CVC4 no longer supports the "old" function syntax:
+
+    f : [INT -> INT];
+
+  This syntax was deprecated in CVC3, and will no longer be
+  supported.  Functions are now written as follows:
+
+    unary : INT -> INT;
+    binary : (INT, INT) -> INT;
+    ternary : (INT, INT, INT) -> INT;
+
+* QUERY and CHECKSAT do not add their argument to the current
+  list of assertions like CVC3 did.
+
+* CVC4 allows datatypes to hold complex types that contain self-
+  or mutual references.  For example,
+
+    DATATYPE tree = node(children:ARRAY INT OF tree) | leaf(data:INT) END;
+
+  is permissible in CVC4 but not in CVC3.
+
+* CVC4 supports parameterized types in datatype definitions, e.g.
+
+    DATATYPE list[T] = cons(car:T) | nil END;
+
+  You can then declare "x : list[INT];" or "x : list[list[INT]];",
+  for example.
+
+* CVC4 supports type ascriptions, e.g.
+
+    U : TYPE;
+    f : INT -> U;
+    QUERY f(5) : U = f(6);
+    QUERY f(5) : U = f(6) : U;
+    QUERY ( f(5) = f(6) ) : BOOLEAN;
+    QUERY f(5) : U = f(6) : U : BOOLEAN;
+
+  You probably won't need it that much, but it can be handy for
+  debugging.  If a term (or formula) isn't the same type as its
+  ascription, and it cannot be "up-casted" safely, an error is
+  immediately generated at parse time.  Sometimes this up-cast is
+  necessary; consider the "nil" constructor of list[T] above.
+  To use "nil," you must cast it to something:
+
+    DATATYPE Item = Carrots | Butter | Milk | Bread END;
+    groceries : list[Item] = cons(Butter, cons(Bread, nil:list[INT]));
+
+* CVC4 supports stronger distinction between type and variable names.
+  This means that CVC4 may allow you to declare things that CVC3 does
+  not:
+
+    a : TYPE;
+    a : INT; % CVC3 complains
+    a : a; % CVC4 complains, `a' cannot both be INT and `a'
+    b : a; % No problem, `a' is both the type of `b', and an INT
+
+* CVC4 supports a command-level LET syntax, e.g.:
+
+    LET double = LAMBDA(x:INT) : 2*x IN
+      QUERY double(5) = 10;
+
+  It works for types also, and mixes of the two:
+
+    LET x = INT, y = 5, z = x IN
+      w : x = y;
+    QUERY y = 5; % error: y undefined
+    QUERY w = 5; % valid
+
+  The scope of such a LET is exactly one command (until a semicolon).
+  (It would conflict with POP_SCOPE if it lasted longer.)
+
+-- Morgan Deters <mdeters@cs.nyu.edu>  Wed, 20 Apr 2011 18:32:32 -0400
+
index 3532b8aa7fea33a822ff59b311245c63a78fae35..541ac0eac7670ca320c633d49794b2cf1bcbfc55 100644 (file)
@@ -28,9 +28,9 @@
 namespace CVC4 {
 namespace parser {
 
-/* Use lookahead=2 */
+/* Use lookahead=3 */
 CvcInput::CvcInput(AntlrInputStream& inputStream) :
-  AntlrInput(inputStream,2) {
+  AntlrInput(inputStream,6) {
   pANTLR3_INPUT_STREAM input = inputStream.getAntlr3InputStream();
   AlwaysAssert( input != NULL );
 
index 033abb42a9e5304260258e9e0f23c3bb6c858845..6509b192be0f0b20afd5442ef57909d2b8d18da5 100644 (file)
@@ -434,7 +434,7 @@ public:
    */
   inline void unimplementedFeature(const std::string& msg) throw(ParserException) {
     if(!d_parseOnly) {
-      parseError(msg);
+      parseError("Unimplemented feature: " + msg);
     }
   }
 
index 19665b0f79f274a06bdb0e311896e417535ed276..236416c1ac27dc91c8aa2b2d80440bc2cbf3f659 100644 (file)
@@ -7,6 +7,11 @@ AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN) -Wno-unused-f
 AM_CFLAGS = $(AM_CXXFLAGS)
 CC=$(CXX)
 
+ANTLR_OPTS =
+
+# hide this included makefile from automake
+@mk_include@ @srcdir@/../Makefile.antlr_tracing
+
 noinst_LTLIBRARIES = libparsersmt.la
 
 ANTLR_TOKEN_STUFF = \
@@ -46,7 +51,7 @@ maintainer-clean-local:
 # antlr doesn't overwrite output files, it just leaves them.  So we have to delete them first.
 @srcdir@/generated/SmtLexer.h: Smt.g @srcdir@/stamp-generated
        -$(AM_V_at)rm -f $(ANTLR_STUFF)
-       $(AM_V_GEN)$(ANTLR) -o "@srcdir@/generated" "@srcdir@/Smt.g"
+       $(AM_V_GEN)$(ANTLR) $(ANTLR_OPTS) -o "@srcdir@/generated" "@srcdir@/Smt.g"
 
 # These don't actually depend on SmtLexer.h, but if we're doing parallel
 # make and the lexer needs to be rebuilt, we have to keep the rules
index 86682f9a9474b1f1e170ba00fcfd08d2d6b013a5..e964c020aa22003ad9d98f20f69b3f6284e3dccd 100644 (file)
 grammar Smt;
 
 options {
-  language = 'C';                  // C output for antlr
-//  defaultErrorHandler = false;      // Skip the default error handling, just break with exceptions
+  // C output for antlr
+  language = 'C';
+
+  // Skip the default error handling, just break with exceptions
+  // defaultErrorHandler = false;
+
+  // Only lookahead of <= k requested (disable for LL* parsing)
+  // Note that CVC4's BoundedTokenBuffer requires a fixed k !
+  // If you change this k, change it also in smt_input.cpp !
   k = 2;
 }
 
 @header {
 /**
  ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010  The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009, 2010, 2011  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
@@ -49,11 +56,14 @@ options {
  * Otherwise, we have to let the lexer detect the encoding at runtime.
  */
 #define ANTLR3_INLINE_INPUT_ASCII
+
+#include "parser/antlr_tracing.h"
 }
 
 @parser::includes {
 #include "expr/command.h"
 #include "parser/parser.h"
+#include "parser/antlr_tracing.h"
 
 namespace CVC4 {
   class Expr;
index 99ff0dabaf38bba6a442e769b1edcbaebef62436..85b511f405856a37b2337fb4048bd95b74e753c3 100644 (file)
@@ -7,6 +7,11 @@ AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN) -Wno-unused-f
 AM_CFLAGS = $(AM_CXXFLAGS)
 CC=$(CXX)
 
+ANTLR_OPTS =
+
+# hide this included makefile from automake
+@mk_include@ @srcdir@/../Makefile.antlr_tracing
+
 noinst_LTLIBRARIES = libparsersmt2.la
 
 ANTLR_TOKEN_STUFF = \
@@ -46,7 +51,7 @@ maintainer-clean-local:
 # antlr doesn't overwrite output files, it just leaves them.  So we have to delete them first.
 @srcdir@/generated/Smt2Lexer.h: Smt2.g @srcdir@/stamp-generated
        -$(AM_V_at)rm -f $(ANTLR_STUFF)
-       $(AM_V_GEN)$(ANTLR) -o "@srcdir@/generated" "@srcdir@/Smt2.g"
+       $(AM_V_GEN)$(ANTLR) $(ANTLR_OPTS) -o "@srcdir@/generated" "@srcdir@/Smt2.g"
 
 # These don't actually depend on SmtLexer.h, but if we're doing parallel
 # make and the lexer needs to be rebuilt, we have to keep the rules
index 4f141891bf4395c1f24838e8801b48e44f35a3f6..9466f8753ff73b2dd34e0963eefc5506834d996b 100644 (file)
 grammar Smt2;
 
 options {
-  language = 'C'; // C output for antlr
-  //defaultErrorHandler = false; // Skip the default error handling, just break with exceptions
+  // C output for antlr
+  language = 'C';
+
+  // Skip the default error handling, just break with exceptions
+  // defaultErrorHandler = false;
+
+  // Only lookahead of <= k requested (disable for LL* parsing)
+  // Note that CVC4's BoundedTokenBuffer requires a fixed k !
+  // If you change this k, change it also in smt2_input.cpp !
   k = 2;
 }
 
@@ -50,6 +57,8 @@ options {
  * Otherwise, we have to let the lexer detect the encoding at runtime.
  */
 #define ANTLR3_INLINE_INPUT_ASCII
+
+#include "parser/antlr_tracing.h"
 }
 
 @lexer::postinclude {
@@ -57,6 +66,7 @@ options {
 
 #include "parser/smt2/smt2.h"
 #include "parser/antlr_input.h"
+#include "parser/antlr_tracing.h"
 
 using namespace CVC4;
 using namespace CVC4::parser;
index b83fd42dc3d61a11a5db99a2760654d43c3e4ffa..77696465ca9502d28854dd0cc9cb8d2e0a48af80 100644 (file)
@@ -289,19 +289,31 @@ void CvcPrinter::toStream(std::ostream& out, TNode n,
         // collapse NOT-over-EQUAL
         out << n[0][0] << " /= " << n[0][1];
       } else if(n.getNumChildren() == 2) {
-        // infix operator
+        // infix binary operator
         out << '(' << n[0] << ' ' << n.getOperator() << ' ' << n[1] << ')';
+      } else if(n.getKind() == kind::AND ||
+                n.getKind() == kind::OR) {
+        // infix N-ary operator
+        TNode::iterator i = n.begin();
+        out << '(' << *i++;
+        while(i != n.end()) {
+          out << ' ' << n.getOperator() << ' ' << *i++;
+        }
+        out << ')';
       } else if(k == kind::BITVECTOR_NOT) {
         // precedence on ~ is a little unexpected; add parens
         out << "(~(" << n[0] << "))";
       } else {
-        // prefix operator
-        out << n.getOperator() << ' ';
-        if(n.getNumChildren() > 0) {
+        // prefix N-ary operator for N != 2
+        if(n.getNumChildren() == 0) {
+          // no parens or spaces
+          out << n.getOperator();
+        } else {
+          out << '(' << n.getOperator() << ' ';
           if(n.getNumChildren() > 1) {
             copy(n.begin(), n.end() - 1, ostream_iterator<TNode>(out, " "));
           }
-          out << n[n.getNumChildren() - 1];
+          out << n[n.getNumChildren() - 1] << ')';
         }
       }
     }
index ec942e00b61ee09734269a1025ba9921ccde2420..0ff89bedfd67d8d3686e2b91e69dcb2cd97c78cd 100644 (file)
@@ -250,8 +250,8 @@ void debugAssertionFailed(const AssertionException& thisException,
       if(EXPECT_FALSE( ! (cond) )) {                                    \
         /* save the last assertion failure */                           \
         const char* lastException = s_debugLastException;               \
-        AssertionException exception(#cond, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
-        debugAssertionFailed(exception, lastException);                 \
+        CVC4::AssertionException exception(#cond, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
+        CVC4::debugAssertionFailed(exception, lastException);                 \
       }                                                                 \
     } while(0)
 
@@ -261,27 +261,27 @@ void debugAssertionFailed(const AssertionException& thisException,
 #  define AlwaysAssert(cond, msg...)                                    \
      do {                                                               \
        if(EXPECT_FALSE( ! (cond) )) {                                   \
-         throw AssertionException(#cond, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
+         throw CVC4::AssertionException(#cond, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
        }                                                                \
      } while(0)
 #endif /* CVC4_DEBUG */
 
 #define Unreachable(msg...) \
-  throw UnreachableCodeException(__PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
+  throw CVC4::UnreachableCodeException(__PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
 #define Unhandled(msg...) \
-  throw UnhandledCaseException(__PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
+  throw CVC4::UnhandledCaseException(__PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
 #define Unimplemented(msg...) \
-  throw UnimplementedOperationException(__PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
+  throw CVC4::UnimplementedOperationException(__PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
 #define InternalError(msg...) \
-  throw InternalErrorException(__PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
+  throw CVC4::InternalErrorException(__PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
 #define IllegalArgument(arg, msg...) \
-  throw IllegalArgumentException(#arg, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
+  throw CVC4::IllegalArgumentException(#arg, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg)
 #define CheckArgument(cond, arg, msg...)         \
   AlwaysAssertArgument(cond, arg, ## msg)
 #define AlwaysAssertArgument(cond, arg, msg...)  \
   do { \
     if(EXPECT_FALSE( ! (cond) )) { \
-      throw IllegalArgumentException(#cond, #arg, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
+      throw CVC4::IllegalArgumentException(#cond, #arg, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
     } \
   } while(0)
 
index aaf9ca03be890add346fcd6933fb99132aa08b65..e76858d80716cba0c931b6504d178d315a2a89f5 100644 (file)
@@ -46,9 +46,11 @@ libutil_la_SOURCES = \
        dynamic_array.h \
        language.h \
        triple.h \
+       subrange_bound.h \
        trans_closure.h \
        trans_closure.cpp \
-       boolean_simplification.h
+       boolean_simplification.h \
+       boolean_simplification.cpp
 
 libutil_la_LIBADD = \
        @builddir@/libutilcudd.la
diff --git a/src/util/boolean_simplification.cpp b/src/util/boolean_simplification.cpp
new file mode 100644 (file)
index 0000000..a154f34
--- /dev/null
@@ -0,0 +1,45 @@
+/*********************                                                        */
+/*! \file boolean_simplification.cpp
+ ** \verbatim
+ ** Original author: taking
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011  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 Simple routines for Boolean simplification
+ **
+ ** Simple, commonly-used routines for Boolean simplification.
+ **/
+
+#include "util/boolean_simplification.h"
+
+namespace CVC4 {
+
+void
+BooleanSimplification::push_back_associative_commute_recursive
+    (Node n, std::vector<Node>& buffer, Kind k, Kind notK, bool negateNode)
+    throw(AssertionException) {
+  Node::iterator i = n.begin(), end = n.end();
+  for(; i != end; ++i){
+    Node child = *i;
+    if(child.getKind() == k){
+      push_back_associative_commute_recursive(child, buffer, k, notK, negateNode);
+    }else if(child.getKind() == kind::NOT && child[0].getKind() == notK){
+      push_back_associative_commute_recursive(child, buffer, notK, k, !negateNode);
+    }else{
+      if(negateNode){
+        buffer.push_back(negate(child));
+      }else{
+        buffer.push_back(child);
+      }
+    }
+  }
+}/* BooleanSimplification::push_back_associative_commute_recursive() */
+
+}/* CVC4 namespace */
+
index 95d5fb4353f6733537ea598fd9cb674c10055f6f..e938a2b38236937757e9eef2f1f2685ab3c2069f 100644 (file)
  ** See the file COPYING in the top-level source directory for licensing
  ** information.\endverbatim
  **
- ** \brief [[ Add one-line brief description here ]]
+ ** \brief Simple routines for Boolean simplification
  **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
+ ** Simple, commonly-used routines for Boolean simplification.
  **/
 
 #include "cvc4_private.h"
 #ifndef __CVC4__BOOLEAN_SIMPLIFICATION_H
 #define __CVC4__BOOLEAN_SIMPLIFICATION_H
 
-#include "expr/node.h"
-#include "util/Assert.h"
 #include <vector>
+#include <algorithm>
 
+#include "expr/node.h"
+#include "util/Assert.h"
 
 namespace CVC4 {
 
+/**
+ * A class to contain a number of useful functions for simple
+ * simplification of nodes.  One never uses it as an object (and
+ * it cannot be constructed).  It is used as a namespace.
+ */
 class BooleanSimplification {
+  // cannot construct one of these
+  BooleanSimplification() CVC4_UNUSED;
+  BooleanSimplification(const BooleanSimplification&) CVC4_UNUSED;
+
+  static void push_back_associative_commute_recursive
+    (Node n, std::vector<Node>& buffer, Kind k, Kind notK, bool negateNode)
+    throw(AssertionException);
+
 public:
 
+  /**
+   * The threshold for removing duplicates.  (See removeDuplicates().)
+   */
   static const uint32_t DUPLICATE_REMOVAL_THRESHOLD = 10;
 
-  static void removeDuplicates(std::vector<Node>& buffer){
-    if(buffer.size() < DUPLICATE_REMOVAL_THRESHOLD){
+  /**
+   * Remove duplicate nodes from a vector, modifying it in-place.
+   * If the vector has size >= DUPLICATE_REMOVAL_THRESHOLD, this
+   * function is a no-op.
+   */
+  static void removeDuplicates(std::vector<Node>& buffer)
+      throw(AssertionException) {
+    if(buffer.size() < DUPLICATE_REMOVAL_THRESHOLD) {
       std::sort(buffer.begin(), buffer.end());
-      std::vector<Node>::iterator new_end = std::unique(buffer.begin(), buffer.end());
+      std::vector<Node>::iterator new_end =
+        std::unique(buffer.begin(), buffer.end());
       buffer.erase(new_end, buffer.end());
     }
   }
 
-  static Node simplifyConflict(Node andNode){
-    Assert(andNode.getKind() == kind::AND);
+  /**
+   * Takes a node with kind AND, collapses all AND and (NOT OR)-kinded
+   * children of it (as far as possible---see
+   * push_back_associative_commute()), removes duplicates, and returns
+   * the resulting Node.
+   */
+  static Node simplifyConflict(Node andNode) throw(AssertionException) {
+    AssertArgument(!andNode.isNull(), andNode);
+    AssertArgument(andNode.getKind() == kind::AND, andNode);
+
     std::vector<Node> buffer;
-    push_back_associative_commute(andNode, buffer, kind::AND, kind::OR, false);
+    push_back_associative_commute(andNode, buffer, kind::AND, kind::OR);
 
     removeDuplicates(buffer);
 
@@ -54,10 +85,18 @@ public:
     return nb;
   }
 
-  static Node simplifyClause(Node orNode){
-    Assert(orNode.getKind() == kind::OR);
+  /**
+   * Takes a node with kind OR, collapses all OR and (NOT AND)-kinded
+   * children of it (as far as possible---see
+   * push_back_associative_commute()), removes duplicates, and returns
+   * the resulting Node.
+   */
+  static Node simplifyClause(Node orNode) throw(AssertionException) {
+    AssertArgument(!orNode.isNull(), orNode);
+    AssertArgument(orNode.getKind() == kind::OR, orNode);
+
     std::vector<Node> buffer;
-    push_back_associative_commute(orNode, buffer, kind::OR, kind::AND, false);
+    push_back_associative_commute(orNode, buffer, kind::OR, kind::AND);
 
     removeDuplicates(buffer);
 
@@ -66,34 +105,63 @@ public:
     return nb;
   }
 
-  static Node simplifyHornClause(Node implication){
-    Assert(implication.getKind() == kind::IMPLIES);
+  /**
+   * Takes a node with kind IMPLIES, converts it to an OR, then
+   * simplifies the result with simplifyClause().
+   *
+   * The input doesn't actually have to be Horn, it seems, but that's
+   * the common case(?), hence the name.
+   */
+  static Node simplifyHornClause(Node implication) throw(AssertionException) {
+    AssertArgument(implication.getKind() == kind::IMPLIES, implication);
+
     TNode left = implication[0];
     TNode right = implication[1];
-    Node notLeft = NodeBuilder<1>(kind::NOT)<<left;
-    Node clause = NodeBuilder<2>(kind::OR)<< notLeft << right;
+
+    Node notLeft = negate(left);
+    Node clause = NodeBuilder<2>(kind::OR) << notLeft << right;
+
     return simplifyClause(clause);
   }
 
-  static void push_back_associative_commute(Node n, std::vector<Node>& buffer, Kind k, Kind notK, bool negateNode){
-    Node::iterator i = n.begin(), end = n.end();
-    for(; i != end; ++i){
-      Node child = *i;
-      if(child.getKind() == k){
-        push_back_associative_commute(child, buffer, k, notK, negateNode);
-      }else if(child.getKind() == kind::NOT && child[0].getKind() == notK){
-        push_back_associative_commute(child, buffer, notK, k, !negateNode);
-      }else{
-        if(negateNode){
-          buffer.push_back(negate(child));
-        }else{
-          buffer.push_back(child);
-        }
-      }
-    }
-  }
+  /**
+   * Aids in reforming a node.  Takes a node of (N-ary) kind k and
+   * copies its children into an output vector, collapsing its k-kinded
+   * children into it.  Also collapses negations of notK.  For example:
+   *
+   *   push_back_associative_commute( [OR [OR a b] [OR b c d] [NOT [AND e f]]],
+   *                                  buffer, kind::OR, kind::AND )
+   *   yields a "buffer" vector of [a b b c d e f]
+   *
+   * @param n the node to operate upon
+   * @param buffer the output vector (must be empty on entry)
+   * @param k the kind to collapse (should equal the kind of node n)
+   * @param notK the "negation" of kind k (e.g. OR's negation is AND),
+   * or kind::UNDEFINED_KIND if none.
+   */
+  static inline void
+  push_back_associative_commute(Node n, std::vector<Node>& buffer,
+                                Kind k, Kind notK)
+      throw(AssertionException) {
+    AssertArgument(buffer.empty(), buffer);
+    AssertArgument(!n.isNull(), n);
+    AssertArgument(k != kind::UNDEFINED_KIND && k != kind::NULL_EXPR, k);
+    AssertArgument(notK != kind::NULL_EXPR, notK);
+    AssertArgument(n.getKind() == k, n,
+                   "expected node to have kind %s", kindToString(k).c_str());
+
+    push_back_associative_commute_recursive(n, buffer, k, notK, false);
+  }/* push_back_associative_commute() */
+
+  /**
+   * Negates a node, doing all the double-negation elimination
+   * that's possible.
+   *
+   * @param n the node to negate (cannot be the null node)
+   */
+  static Node negate(TNode n) throw(AssertionException) {
+    AssertArgument(!n.isNull(), n);
 
-  static Node negate(TNode n){
     bool polarity = true;
     TNode base = n;
     while(base.getKind() == kind::NOT){
index 0b1c86afd897e28ce0106a1b90b6f10e72566539..d3eb3a83179f6962e5b69aacb2335023eefb7a95 100644 (file)
@@ -273,7 +273,7 @@ public:
 /** The debug output singleton */
 extern DebugC DebugChannel CVC4_PUBLIC;
 #ifdef CVC4_DEBUG
-#  define Debug DebugChannel
+#  define Debug CVC4::DebugChannel
 #else /* CVC4_DEBUG */
 #  define Debug CVC4::__cvc4_true() ? CVC4::debugNullCvc4Stream : CVC4::DebugChannel
 #endif /* CVC4_DEBUG */
@@ -290,7 +290,7 @@ extern ChatC Chat CVC4_PUBLIC;
 /** The trace output singleton */
 extern TraceC TraceChannel CVC4_PUBLIC;
 #ifdef CVC4_TRACING
-#  define Trace TraceChannel
+#  define Trace CVC4::TraceChannel
 #else /* CVC4_TRACING */
 #  define Trace CVC4::__cvc4_true() ? CVC4::debugNullCvc4Stream : CVC4::TraceChannel
 #endif /* CVC4_TRACING */
diff --git a/src/util/subrange_bound.h b/src/util/subrange_bound.h
new file mode 100644 (file)
index 0000000..fc6a259
--- /dev/null
@@ -0,0 +1,94 @@
+/*********************                                                        */
+/*! \file subrange_bound.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011  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 Representation of subrange bounds
+ **
+ ** Simple class to represent a subrange bound, either infinite
+ ** (no bound) or finite (an arbitrary precision integer).
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef __CVC4__SUBRANGE_BOUND_H
+#define __CVC4__SUBRANGE_BOUND_H
+
+#include "util/integer.h"
+#include "util/Assert.h"
+
+namespace CVC4 {
+
+/**
+ * Representation of a subrange bound.  A bound can either exist and be
+ * a finite arbitrary-precision integer, or not exist (and thus be
+ * an infinite bound).  For example, the CVC language subrange [-5.._]
+ * has a lower bound of -5 and an infinite upper bound.
+ */
+class SubrangeBound {
+  bool d_nobound;
+  Integer d_bound;
+
+public:
+
+  /** Construct an infinite SubrangeBound. */
+  SubrangeBound() throw() :
+    d_nobound(true),
+    d_bound() {
+  }
+
+  /** Construct a finite SubrangeBound. */
+  SubrangeBound(const Integer& i) throw() :
+    d_nobound(false),
+    d_bound(i) {
+  }
+
+  ~SubrangeBound() throw() {
+  }
+
+  /** Get the finite SubrangeBound, failing an assertion if infinite. */
+  Integer getBound() const throw(IllegalArgumentException) {
+    CheckArgument(!d_nobound, this, "SubrangeBound is infinite");
+    return d_bound;
+  }
+
+  /** Returns true iff this is a finite SubrangeBound. */
+  bool hasBound() const throw() {
+    return !d_nobound;
+  }
+
+  /** Test two SubrangeBounds for equality. */
+  bool operator==(const SubrangeBound& b) const throw() {
+    return hasBound() == b.hasBound() &&
+      (!hasBound() || getBound() == b.getBound());
+  }
+
+  /** Test two SubrangeBounds for disequality. */
+  bool operator!=(const SubrangeBound& b) const throw() {
+    return !(*this == b);
+  }
+
+};/* class SubrangeBound */
+
+inline std::ostream&
+operator<<(std::ostream& out, const SubrangeBound& bound) throw() {
+  if(bound.hasBound()) {
+    out << bound.getBound();
+  } else {
+    out << '_';
+  }
+
+  return out;
+}
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__SUBRANGE_BOUND_H */
index 12e2bb347856b2840e06106fcb061ccc8d7d7c16..323e61ca455dab41f2a46d015815b5c41db31c7d 100644 (file)
@@ -38,6 +38,7 @@ SMT2_TESTS = \
 
 # Regression tests for PL inputs
 CVC_TESTS = \
+       subranges.cvc \
        boolean-prec.cvc \
        hole6.cvc \
        ite.cvc \
diff --git a/test/regress/regress0/subranges.cvc b/test/regress/regress0/subranges.cvc
new file mode 100644 (file)
index 0000000..d8351c7
--- /dev/null
@@ -0,0 +1,17 @@
+% COMMAND-LINE: --parse-only
+% EXPECT: 
+% EXIT: 0
+
+A : [0..0];
+B : [ -5 .. 8];
+C : [1..3];
+D : [1..2];
+E : [-100 ..-1];
+F : [-100 ..0];
+G : [-100 ..1];
+H : [-1 ..1];
+I : [0..10];
+J : [-10..-9];
+J : [-10..-10];
+
+QUERY TRUE;
index a7a6630b9a7f5b85d4f77bf78d7452251374eb24..8f2e385d7d7a661df1453bfc0db6e4d53718b128 100755 (executable)
@@ -114,12 +114,13 @@ elif expr "$benchmark" : '.*\.smt2$' &>/dev/null; then
     error "cannot determine status of \`$benchmark'"
   fi
 elif expr "$benchmark" : '.*\.cvc$' &>/dev/null; then
-  expected_output=`grep '^% EXPECT: ' "$benchmark" | sed 's,^% EXPECT: ,,'`
+  expected_output=$(grep '^% EXPECT: ' "$benchmark")
   expected_error=`grep '^% EXPECT-ERROR: ' "$benchmark" | sed 's,^% EXPECT-ERROR: ,,'`
   if [ -z "$expected_output" -a -z "$expected_error" ]; then
     error "cannot determine expected output of \`$benchmark': " \
           "please use \`% EXPECT:' and/or \`% EXPECT-ERROR:' gestures"
   fi
+  expected_output=$(echo "$expected_output" | sed 's,^% EXPECT: ,,;s,\r,,')
   expected_exit_status=`grep -m 1 '^% EXIT: ' "$benchmark" | sed 's,^% EXIT: ,,;s,\r,,'`
   if [ -z "$expected_exit_status" ]; then
     error "cannot determine expected exit status of \`$benchmark': please use \`% EXIT:' gesture"
index 646ebf9bbcad296742ecf484c90caf10b428297c..13d28f3bb0ead16d4c28dc989723c0b38edef759 100644 (file)
@@ -44,6 +44,8 @@ UNIT_TESTS = \
        util/rational_white \
        util/stats_black \
        util/trans_closure_black \
+       util/boolean_simplification_black \
+       util/subrange_bound_white \
        main/interactive_shell_black
 
 export VERBOSE = 1
index 3b1e96084138fe28d795acecd3f8583f3f1c8260..e37c197ab2ee07ab24c876873c0c2a0e914f9329 100644 (file)
@@ -46,7 +46,7 @@ private:
       worklist.pop_back();
       if( current.getKind() == kind ) {
         for( unsigned int i = 0; i < current.getNumChildren(); ++i ) {
-          worklist.push_back( current.getChild(i) );
+          worklist.push_back( current[i] );
         }
       } else {
         childrenFound++;
index 632db2b91a1f4504ddd70b7e1180466e862b7363..53050eece76df8796dee66ac68066b7b702dd7f4 100644 (file)
@@ -27,6 +27,7 @@
 #include "parser/parser_builder.h"
 #include "parser/smt2/smt2.h"
 #include "expr/command.h"
+#include "util/options.h"
 #include "util/output.h"
 #include "util/language.h"
 
@@ -40,6 +41,8 @@ class ParserBlack {
   ExprManager *d_exprManager;
 
 protected:
+  Options d_options;
+
   /* Set up declaration context for expr inputs */
   virtual void setupContext(Parser& parser) {
     /* a, b, c: BOOLEAN */
@@ -69,6 +72,7 @@ protected:
         Parser *parser =
           ParserBuilder(d_exprManager,"test")
             .withStringInput(goodInput)
+            .withOptions(d_options)
             .withInputLanguage(d_lang)
             .build();
         TS_ASSERT( !parser->done() );
@@ -96,6 +100,7 @@ protected:
     Parser *parser =
       ParserBuilder(d_exprManager,"test")
         .withStringInput(badInput)
+        .withOptions(d_options)
         .withInputLanguage(d_lang)
         .withStrictMode(strictMode)
         .build();
@@ -118,6 +123,7 @@ protected:
         Parser *parser =
           ParserBuilder(d_exprManager,"test")
             .withStringInput(goodExpr)
+            .withOptions(d_options)
             .withInputLanguage(d_lang)
             .build();
 
@@ -155,6 +161,7 @@ protected:
       Parser *parser =
         ParserBuilder(d_exprManager,"test")
           .withStringInput(badExpr)
+          .withOptions(d_options)
           .withInputLanguage(d_lang)
           .withStrictMode(strictMode)
           .build();
@@ -177,6 +184,7 @@ protected:
 
   void setUp() {
     d_exprManager = new ExprManager;
+    d_options.parseOnly = true;
   }
 
   void tearDown() {
@@ -217,6 +225,14 @@ public:
     tryGoodInput("% a comment\nASSERT TRUE; %a command\n% another comment");
     tryGoodInput("a : BOOLEAN; a: BOOLEAN;"); // double decl, but compatible
     tryGoodInput("a : INT = 5; a: INT;"); // decl after define, compatible
+    tryGoodInput("a : TYPE; a : INT;"); // ok, sort and variable symbol spaces distinct
+    tryGoodInput("a : TYPE; a : INT; b : a;"); // ok except a is both INT and sort `a'
+    tryGoodInput("a : [0..0]; b : [-5..5]; c : [-1..1]; d : [ _ .._];"); // subranges
+    tryGoodInput("a : [ _..1]; b : [_.. 0]; c :[_..-1];");
+    tryGoodInput("DATATYPE list = nil | cons(car:INT,cdr:list) END; DATATYPE cons = null END;");
+    tryGoodInput("DATATYPE tree = node(data:list), list = cons(car:tree,cdr:list) END;");
+    tryGoodInput("DATATYPE tree = node(data:[list,list,ARRAY tree OF list]), list = cons(car:ARRAY list OF tree,cdr:BITVECTOR(32)) END;");
+    tryGoodInput("DATATYPE trex = Foo | Bar END; DATATYPE tree = node(data:[list,list,ARRAY trex OF list]), list = cons(car:ARRAY list OF tree,cdr:BITVECTOR(32)) END;");
   }
 
   void testBadCvc4Inputs() {
@@ -232,6 +248,14 @@ public:
     tryBadInput("A : TYPE; A: TYPE;"); // types can't be double-declared
     tryBadInput("a : INT; a: INT = 5;"); // can't define after decl
     tryBadInput("a : INT = 5; a: BOOLEAN;"); // decl w/ incompatible type
+    tryBadInput("a : TYPE; a : INT; a : a;"); // ok except a is both INT and sort `a'
+    tryBadInput("a : [1..-1];"); // bad subrange
+    tryBadInput("a : [0. .0];"); // bad subrange
+    tryBadInput("a : [..0];"); // bad subrange
+    tryBadInput("a : [0.0];"); // bad subrange
+    tryBadInput("DATATYPE list = nil | cons(car:INT,cdr:list) END; DATATYPE list = nil | cons(car:INT,cdr:list) END;");
+    tryBadInput("DATATYPE list = nil | cons(car:INT,cdr:list) END; DATATYPE list2 = nil END;");
+    tryBadInput("DATATYPE tree = node(data:(list,list,ARRAY trex OF list)), list = cons(car:ARRAY list OF tree,cdr:BITVECTOR(32)) END;");
   }
 
   void testGoodCvc4Exprs() {
diff --git a/test/unit/util/boolean_simplification_black.h b/test/unit/util/boolean_simplification_black.h
new file mode 100644 (file)
index 0000000..8dafd20
--- /dev/null
@@ -0,0 +1,224 @@
+/*********************                                                        */
+/*! \file boolean_simplification_black.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011  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 Black box testing of CVC4::BooleanSimplification
+ **
+ ** Black box testing of CVC4::BooleanSimplification.
+ **/
+
+#include "context/context.h"
+#include "util/language.h"
+#include "expr/node.h"
+#include "expr/kind.h"
+#include "expr/node_manager.h"
+#include "util/boolean_simplification.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace CVC4;
+using namespace CVC4::context;
+using namespace std;
+
+class BooleanSimplificationBlack : public CxxTest::TestSuite {
+
+  Context* d_context;
+  NodeManager* d_nm;
+  NodeManagerScope* d_scope;
+
+  Node a, b, c, d, e, f, g, h;
+  Node fa, fb, fc, ga, ha, hc, ffb, fhc, hfc, gfb;
+  Node ac, ffbd, efhc, dfa;
+
+  // assert equality up to commuting children
+  void ASSERT_NODES_EQUAL(TNode n1, TNode n2) {
+    cout << "ASSERTING: " << n1 << endl
+         << "        ~= " << n2 << endl;
+    TS_ASSERT_EQUALS( n1.getKind(), n2.getKind() );
+    TS_ASSERT_EQUALS( n1.getNumChildren(), n2.getNumChildren() );
+    vector<TNode> v1(n1.begin(), n1.end());
+    vector<TNode> v2(n2.begin(), n2.end());
+    sort(v1.begin(), v1.end());
+    sort(v2.begin(), v2.end());
+    TS_ASSERT_EQUALS( v1, v2 );
+  }
+
+  // assert that node's children have same elements as the set
+  // (so no duplicates); also n is asserted to have kind k
+  void ASSERT_NODE_EQUALS_SET(TNode n, Kind k, set<TNode> elts) {
+    vector<TNode> v(n.begin(), n.end());
+
+    // BooleanSimplification implementation sorts its output nodes, BUT
+    // that's an implementation detail, not part of the contract, so we
+    // should be robust to it here; this is a black-box test!
+    sort(v.begin(), v.end());
+
+    TS_ASSERT_EQUALS( n.getKind(), k );
+    TS_ASSERT_EQUALS( elts.size(), n.getNumChildren() );
+    TS_ASSERT( equal(n.begin(), n.end(), elts.begin()) );
+  }
+
+public:
+
+  void setUp() {
+    d_context = new Context();
+    d_nm = new NodeManager(d_context, NULL);
+    d_scope = new NodeManagerScope(d_nm);
+
+    a = d_nm->mkVar("a", d_nm->booleanType());
+    b = d_nm->mkVar("b", d_nm->booleanType());
+    c = d_nm->mkVar("c", d_nm->booleanType());
+    d = d_nm->mkVar("d", d_nm->booleanType());
+    e = d_nm->mkVar("e", d_nm->booleanType());
+    f = d_nm->mkVar("f", d_nm->mkFunctionType(d_nm->booleanType(),
+                                              d_nm->booleanType()));
+    g = d_nm->mkVar("g", d_nm->mkFunctionType(d_nm->booleanType(),
+                                              d_nm->booleanType()));
+    h = d_nm->mkVar("h", d_nm->mkFunctionType(d_nm->booleanType(),
+                                              d_nm->booleanType()));
+    fa = d_nm->mkNode(kind::APPLY_UF, f, a);
+    fb = d_nm->mkNode(kind::APPLY_UF, f, b);
+    fc = d_nm->mkNode(kind::APPLY_UF, f, c);
+    ga = d_nm->mkNode(kind::APPLY_UF, g, a);
+    ha = d_nm->mkNode(kind::APPLY_UF, h, a);
+    hc = d_nm->mkNode(kind::APPLY_UF, h, c);
+    ffb = d_nm->mkNode(kind::APPLY_UF, f, fb);
+    fhc = d_nm->mkNode(kind::APPLY_UF, f, hc);
+    hfc = d_nm->mkNode(kind::APPLY_UF, h, fc);
+    gfb = d_nm->mkNode(kind::APPLY_UF, g, fb);
+
+    ac = d_nm->mkNode(kind::IFF, a, c);
+    ffbd = d_nm->mkNode(kind::IFF, ffb, d);
+    efhc = d_nm->mkNode(kind::IFF, e, fhc);
+    dfa = d_nm->mkNode(kind::IFF, d, fa);
+
+    // this test is designed for >= 10 removal threshold
+    TS_ASSERT_LESS_THAN_EQUALS(10u,
+      BooleanSimplification::DUPLICATE_REMOVAL_THRESHOLD);
+
+    cout << Expr::setdepth(-1)
+         << Expr::setlanguage(language::output::LANG_CVC4);
+  }
+
+  void tearDown() {
+    a = b = c = d = e = f = g = h = Node();
+    fa = fb = fc = ga = ha = hc = ffb = fhc = hfc = gfb = Node();
+    ac = ffbd = efhc = dfa = Node();
+
+    delete d_scope;
+    delete d_nm;
+    delete d_context;
+  }
+
+  void testNegate() {
+    Node in, out;
+
+    in = d_nm->mkNode(kind::NOT, a);
+    out = a;
+    ASSERT_NODES_EQUAL( out, BooleanSimplification::negate(in) );
+    ASSERT_NODES_EQUAL( in, BooleanSimplification::negate(out) );
+
+    in = fa.andNode(ac).notNode().notNode().notNode().notNode();
+    out = fa.andNode(ac).notNode();
+    ASSERT_NODES_EQUAL( out, BooleanSimplification::negate(in) );
+
+#ifdef CVC4_ASSERTIONS
+    in = Node();
+    TS_ASSERT_THROWS( BooleanSimplification::negate(in), IllegalArgumentException );
+#endif /* CVC4_ASSERTIONS */
+  }
+
+  void testRemoveDuplicates() {
+  }
+
+  void testPushBackAssociativeCommute() {
+  }
+
+  void testSimplifyClause() {
+    Node in, out;
+
+    in = a.orNode(b);
+    out = in;
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyClause(in));
+
+    in = d_nm->mkNode(kind::OR, a, d.andNode(b));
+    out = in;
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyClause(in));
+
+    in = d_nm->mkNode(kind::OR, a, d.orNode(b));
+    out = d_nm->mkNode(kind::OR, a, d, b);
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyClause(in));
+
+    in = d_nm->mkNode(kind::OR, fa, ga.orNode(c).notNode(), hfc, ac, d.andNode(b));
+    out = NodeBuilder<>(kind::OR) << fa << ga.orNode(c).notNode() << hfc << ac << d.andNode(b);
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyClause(in));
+
+    in = d_nm->mkNode(kind::OR, fa, ga.andNode(c).notNode(), hfc, ac, d.andNode(b));
+    out = NodeBuilder<>(kind::OR) << fa << ga.notNode() << c.notNode() << hfc << ac << d.andNode(b);
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyClause(in));
+
+#ifdef CVC4_ASSERTIONS
+    in = d_nm->mkNode(kind::AND, a, b);
+    TS_ASSERT_THROWS( BooleanSimplification::simplifyClause(in), IllegalArgumentException );
+#endif /* CVC4_ASSERTIONS */
+  }
+
+  void testSimplifyHorn() {
+    Node in, out;
+
+    in = a.impNode(b);
+    out = a.notNode().orNode(b);
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyHornClause(in));
+
+    in = a.notNode().impNode(ac.andNode(b));
+    out = d_nm->mkNode(kind::OR, a, ac.andNode(b));
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyHornClause(in));
+
+    in = a.andNode(b).impNode(d_nm->mkNode(kind::AND, fa, ga.orNode(c).notNode(), hfc.orNode(ac), d.andNode(b)));
+    out = d_nm->mkNode(kind::OR, a.notNode(), b.notNode(), d_nm->mkNode(kind::AND, fa, ga.orNode(c).notNode(), hfc.orNode(ac), d.andNode(b)));
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyHornClause(in));
+
+    in = a.andNode(b).impNode(d_nm->mkNode(kind::OR, fa, ga.orNode(c).notNode(), hfc.orNode(ac), d.andNode(b).notNode()));
+    out = NodeBuilder<>(kind::OR) << a.notNode() << b.notNode() << fa << ga.orNode(c).notNode() << hfc << ac << d.notNode();
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyHornClause(in));
+
+#ifdef CVC4_ASSERTIONS
+    in = d_nm->mkNode(kind::OR, a, b);
+    TS_ASSERT_THROWS( BooleanSimplification::simplifyHornClause(in), IllegalArgumentException );
+#endif /* CVC4_ASSERTIONS */
+  }
+
+  void testSimplifyConflict() {
+    Node in, out;
+
+    in = a.andNode(b);
+    out = in;
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyConflict(in));
+
+    in = d_nm->mkNode(kind::AND, a, d.andNode(b));
+    out = d_nm->mkNode(kind::AND, a, d, b);
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyConflict(in));
+
+    in = d_nm->mkNode(kind::AND, fa, ga.orNode(c).notNode(), fa, hfc.orNode(ac), d.andNode(b));
+    out = NodeBuilder<>(kind::AND) << fa << ga.notNode() << c.notNode() << hfc.orNode(ac) << d << b;
+    ASSERT_NODES_EQUAL(out, BooleanSimplification::simplifyConflict(in));
+
+#ifdef CVC4_ASSERTIONS
+    in = d_nm->mkNode(kind::OR, a, b);
+    TS_ASSERT_THROWS( BooleanSimplification::simplifyConflict(in), IllegalArgumentException );
+#endif /* CVC4_ASSERTIONS */
+  }
+
+};/* class BooleanSimplificationBlack */
+
diff --git a/test/unit/util/subrange_bound_white.h b/test/unit/util/subrange_bound_white.h
new file mode 100644 (file)
index 0000000..a41f75a
--- /dev/null
@@ -0,0 +1,77 @@
+/*********************                                                        */
+/*! \file subrange_bound_white.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011  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 White box testing of CVC4::SubrangeBound
+ **
+ ** White box testing of CVC4::SubrangeBound.
+ **/
+
+#include "util/subrange_bound.h"
+#include "util/integer.h"
+
+#include <string>
+#include <sstream>
+
+using namespace CVC4;
+using namespace std;
+
+class SubrangeBoundWhite : public CxxTest::TestSuite {
+  stringstream ss;
+
+public:
+
+  void testInfinite() {
+    SubrangeBound b;
+    TS_ASSERT( ! b.hasBound() );
+    TS_ASSERT_THROWS( b.getBound(), IllegalArgumentException );
+    ss.str(""); ss << b;
+    TS_ASSERT_EQUALS( ss.str(), "_" );
+  }
+
+  void testZero() {
+    SubrangeBound b1(0), b2(string("0")), b3(Integer("1"));
+    TS_ASSERT( b1.hasBound() && b2.hasBound() && b3.hasBound() );
+    TS_ASSERT( b1.getBound() == 0 && b2.getBound() == 0 && b3.getBound() == 1 );
+    TS_ASSERT( b1 == b2 ); TS_ASSERT( b2 == b1 );
+    TS_ASSERT( !(b1 == b3) ); TS_ASSERT( !(b3 == b1) );
+    TS_ASSERT( !(b2 == b3) ); TS_ASSERT( !(b3 == b2) );
+    TS_ASSERT( !(b1 != b2) ); TS_ASSERT( !(b2 != b1) );
+    TS_ASSERT( b1 != b3 ); TS_ASSERT( b3 != b1 );
+    TS_ASSERT( b2 != b3 ); TS_ASSERT( b3 != b2 );
+    ss.str(""); ss << b1;
+    TS_ASSERT( ss.str() == "0" );
+    ss.str(""); ss << b2;
+    TS_ASSERT( ss.str() == "0" );
+    ss.str(""); ss << b3;
+    TS_ASSERT( ss.str() == "1" );
+  }
+
+  void testOne() {
+    SubrangeBound b(string("1"));
+    TS_ASSERT( b.hasBound() );
+    TS_ASSERT( b.getBound() == 1 );
+    ss.str(""); ss << b;
+    TS_ASSERT( ss.str() == "1" );
+  }
+
+  void testMinusOne() {
+  }
+
+  void testLarge() {
+  }
+
+  void testSmall() {
+  }
+
+};/* class SubrangeBoundWhite */
+