First draft implementation of SMT v2 parser
authorChristopher L. Conway <christopherleeconway@gmail.com>
Thu, 29 Apr 2010 16:53:19 +0000 (16:53 +0000)
committerChristopher L. Conway <christopherleeconway@gmail.com>
Thu, 29 Apr 2010 16:53:19 +0000 (16:53 +0000)
13 files changed:
.cproject
src/expr/command.h
src/main/getopt.cpp
src/parser/Makefile.am
src/parser/input.cpp
src/parser/parser_options.h
src/parser/smt/Smt.g
src/parser/smt2/Makefile [new file with mode: 0644]
src/parser/smt2/Makefile.am [new file with mode: 0644]
src/parser/smt2/Smt2.g [new file with mode: 0644]
src/parser/smt2/smt2_input.cpp [new file with mode: 0644]
src/parser/smt2/smt2_input.h [new file with mode: 0644]
test/unit/parser/parser_black.h

index 0d7c6b9fc0a644d49600c9f066297ee03c6bec8d..488d7e4d47567111e05a66e7a816ce2b844b23cc 100644 (file)
--- a/.cproject
+++ b/.cproject
@@ -44,7 +44,7 @@
 </toolChain>
 </folderInfo>
 <sourceEntries>
-<entry excluding="parser" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+<entry excluding="parser|smt2" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
 </sourceEntries>
 </configuration>
 </storageModule>
index bb295a6622092aa9f0e16026029d05fc23edcd4e..3be957febae7fb8c3c6ef2fe989267d4e963101b 100644 (file)
@@ -93,6 +93,7 @@ public:
 
 class CVC4_PUBLIC DeclarationCommand : public EmptyCommand {
 public:
+  DeclarationCommand(const std::string& id, const Type& t);
   DeclarationCommand(const std::vector<std::string>& ids, const Type& t);
   void toStream(std::ostream& out) const;
 protected:
@@ -259,6 +260,12 @@ inline void CommandSequence::addCommand(Command* cmd) {
 
 /* class DeclarationCommand */
 
+inline DeclarationCommand::DeclarationCommand(const std::string& id, const Type& t) :
+  d_type(t)
+{
+  d_declaredSymbols.push_back(id);
+}
+
 inline DeclarationCommand::DeclarationCommand(const std::vector<std::string>& ids, const Type& t) :
   d_declaredSymbols(ids),
   d_type(t)
index a272aaafd81d3ed2f07e79248fe17d30eb6d7563..2ad34597e975a1f8e811da877e381446a30d0d73 100644 (file)
@@ -165,6 +165,9 @@ throw(OptionException) {
       } else if(!strcmp(optarg, "smtlib") || !strcmp(optarg, "smt")) {
         opts->lang = parser::LANG_SMTLIB;
         break;
+      } else if(!strcmp(optarg, "smtlib2") || !strcmp(optarg, "smt2")) {
+        opts->lang = parser::LANG_SMTLIB_V2;
+        break;
       } else if(!strcmp(optarg, "auto")) {
         opts->lang = parser::LANG_AUTO;
         break;
index 1464eeac0a236145586c7ef6a308021bd04261b6..380f40c6a5d43b64e52a2f55f908e322f37280b8 100644 (file)
@@ -17,7 +17,7 @@ AM_CPPFLAGS = \
        -I@srcdir@/../include -I@srcdir@/.. $(ANTLR_INCLUDES)
 AM_CXXFLAGS = -Wall $(FLAG_VISIBILITY_HIDDEN)
 
-SUBDIRS = smt cvc
+SUBDIRS = smt smt2 cvc
 
 nobase_lib_LTLIBRARIES = libcvc4parser.la
 noinst_LTLIBRARIES = libcvc4parser_noinst.la
@@ -30,7 +30,8 @@ libcvc4parser_la_LINK = $(CXXLINK)
 libcvc4parser_noinst_la_LDFLAGS = $(ANTLR_LDFLAGS)
 libcvc4parser_noinst_la_LIBADD = \
        @builddir@/smt/libparsersmt.la \
-       @builddir@/cvc/libparsercvc.la
+    @builddir@/smt2/libparsersmt2.la \
+    @builddir@/cvc/libparsercvc.la
 
 libcvc4parser_la_SOURCES =
 libcvc4parser_noinst_la_SOURCES = \
index 5df017f16ed18ce5be38ead96202c172fa41b8d0..33bee84a673026ef4c785ad42e334b47e8a60bcd 100644 (file)
@@ -27,6 +27,7 @@
 #include "expr/type.h"
 #include "parser/cvc/cvc_input.h"
 #include "parser/smt/smt_input.h"
+#include "parser/smt2/smt2_input.h"
 #include "util/output.h"
 #include "util/Assert.h"
 
@@ -182,6 +183,10 @@ Input* Input::newInput(InputLanguage lang, AntlrInputStream *inputStream) {
     input = new SmtInput(inputStream);
     break;
 
+  case LANG_SMTLIB_V2:
+    input = new Smt2Input(inputStream);
+    break;
+
   default:
     Unhandled(lang);
   }
index d593d6f5ae0df88d976f041342b7abf74c36a06a..51d28e51dda73df9ce5536f2bbf45894d2c9cbd8 100644 (file)
@@ -25,6 +25,8 @@ namespace parser {
 enum InputLanguage {
   /** The SMTLIB input language */
   LANG_SMTLIB,
+  /** The SMTLIB v2 input language */
+  LANG_SMTLIB_V2,
   /** The CVC4 input language */
   LANG_CVC4,
   /** Auto-detect the language */
index 6a34df3752678651c36af751c57b2c8ef75f9129..ba5e8abf5a353d3484698ea87736c39dfa54dd96 100644 (file)
@@ -88,7 +88,7 @@ using namespace CVC4::parser;
  * @param parser the CVC4 Parser object
  * @param name the name of the logic (e.g., QF_UF, AUFLIA)
  */
-void
+static void
 setLogic(Parser *parser, const std::string& name) {
   if( name == "QF_UF" ) {
     parser->mkSort("U");
diff --git a/src/parser/smt2/Makefile b/src/parser/smt2/Makefile
new file mode 100644 (file)
index 0000000..fc9cc6d
--- /dev/null
@@ -0,0 +1,4 @@
+topdir = ../../..
+srcdir = src/parser/smt2
+
+include $(topdir)/Makefile.subdir
diff --git a/src/parser/smt2/Makefile.am b/src/parser/smt2/Makefile.am
new file mode 100644 (file)
index 0000000..6391919
--- /dev/null
@@ -0,0 +1,51 @@
+AM_CPPFLAGS = \
+       -D__BUILDING_CVC4PARSERLIB \
+       -I@srcdir@/../../include -I@srcdir@/../.. $(ANTLR_INCLUDES)
+AM_CXXFLAGS = -Wall $(FLAG_VISIBILITY_HIDDEN) -Wno-unused-function -Wno-unused-variable
+
+# Compile generated C files using C++ compiler
+AM_CFLAGS = $(AM_CXXFLAGS)
+CC=$(CXX)
+
+noinst_LTLIBRARIES = libparsersmt2.la
+
+ANTLR_TOKEN_STUFF = \
+       @srcdir@/generated/Smt2.tokens
+ANTLR_LEXER_STUFF = \
+       @srcdir@/generated/Smt2Lexer.h \
+       @srcdir@/generated/Smt2Lexer.c \
+       $(ANTLR_TOKEN_STUFF)
+ANTLR_PARSER_STUFF = \
+       @srcdir@/generated/Smt2Parser.h \
+       @srcdir@/generated/Smt2Parser.c
+ANTLR_STUFF = \
+       $(ANTLR_LEXER_STUFF) \
+       $(ANTLR_PARSER_STUFF)
+
+libparsersmt2_la_SOURCES = \
+       Smt2.g \
+       smt2_input.h \
+       smt2_input.cpp \
+       $(ANTLR_STUFF)
+
+BUILT_SOURCES = $(ANTLR_STUFF)
+dist-hook: $(ANTLR_STUFF)
+MAINTAINERCLEANFILES = $(ANTLR_STUFF)
+maintainer-clean-local:
+       -$(AM_V_at)rmdir @srcdir@/generated
+       -$(AM_V_at)rm -f @srcdir@/stamp-generated
+
+@srcdir@/stamp-generated:
+       $(AM_V_at)mkdir -p @srcdir@/generated
+       $(AM_V_at)touch @srcdir@/stamp-generated
+
+# 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"
+
+# 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
+# from running in parallel (since the token files will be deleted &
+# recreated)
+@srcdir@/generated/Smt2Lexer.c @srcdir@/generated/Smt2Parser.h @srcdir@/generated/Smt2Parser.c $(ANTLR_TOKEN_STUFF): @srcdir@/generated/Smt2Lexer.h
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
new file mode 100644 (file)
index 0000000..44dd041
--- /dev/null
@@ -0,0 +1,462 @@
+/* *******************                                                        */
+/*  Smt2.g
+ ** Original author: cconway
+ ** 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)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.
+ **
+ ** Parser for SMT-LIB v2 input language.
+ **/
+
+grammar Smt2;
+
+options {
+  language = 'C';                  // C output for antlr
+//  defaultErrorHandler = false;      // Skip the default error handling, just break with exceptions
+  k = 2;
+}
+
+@header {
+/**
+ ** 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.
+ **/
+}
+
+@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.
+  */
+#pragma GCC system_header
+
+/* This improves performance by ~10 percent on big inputs.
+ * This option is only valid if we know the input is ASCII (or some 8-bit encoding).
+ * If we know the input is UTF-16, we can use ANTLR3_INLINE_INPUT_UTF16.
+ * Otherwise, we have to let the lexer detect the encoding at runtime.
+ */
+#define ANTLR3_INLINE_INPUT_ASCII
+}
+
+@parser::includes {
+#include "expr/command.h"
+#include "parser/parser.h"
+
+namespace CVC4 {
+  class Expr;
+}
+}
+
+@parser::postinclude {
+#include "expr/expr.h"
+#include "expr/kind.h"
+#include "expr/type.h"
+#include "parser/input.h"
+#include "parser/parser.h"
+#include "util/integer.h"
+#include "util/output.h"
+#include "util/rational.h"
+#include <vector>
+
+using namespace CVC4;
+using namespace CVC4::parser;
+
+/* These need to be macros so they can refer to the PARSER macro, which will be defined
+ * by ANTLR *after* this section. (If they were functions, PARSER would be undefined.) */
+#undef PARSER_STATE 
+#define PARSER_STATE ((Parser*)PARSER->super)
+#undef EXPR_MANAGER
+#define EXPR_MANAGER PARSER_STATE->getExprManager()
+#undef MK_EXPR
+#define MK_EXPR EXPR_MANAGER->mkExpr
+#undef MK_CONST
+#define MK_CONST EXPR_MANAGER->mkConst
+
+/**   
+ * Sets the logic for the current benchmark. Declares any logic symbols.
+ *
+ * @param parser the CVC4 Parser object
+ * @param name the name of the logic (e.g., QF_UF, AUFLIA)
+ */
+static void
+setLogic(Parser *parser, const std::string& name) {
+  if( name == "QF_UF" ) {
+    parser->mkSort("U");
+  } else if(name == "QF_LRA"){
+    parser->defineType("Real", parser->getExprManager()->realType());
+  } else{
+    // NOTE: Theory types go here
+    Unhandled(name);
+  }
+}
+}
+
+
+/**
+ * Parses an expression.
+ * @return the parsed expression, or the Null Expr if we've reached the end of the input
+ */
+parseExpr returns [CVC4::Expr expr]
+  : term[expr]
+  | EOF
+  ;
+
+/**
+ * Parses a command 
+ * @return the parsed command, or NULL if we've reached the end of the input
+ */
+parseCommand returns [CVC4::Command* cmd]
+  : LPAREN_TOK c = command RPAREN_TOK { $cmd = c; }
+  | EOF { $cmd = 0; }
+  ;
+
+/**
+ * Parse the internal portion of the command, ignoring the surrounding parentheses.
+ */
+command returns [CVC4::Command* cmd]
+@declarations {
+  std::string name;
+  BenchmarkStatus b_status;
+  Expr expr;
+  Type t;
+  std::vector<Type> sorts;
+}
+  : /* set the logic */
+    SET_LOGIC_TOK identifier[name,CHECK_NONE,SYM_VARIABLE]
+    { Debug("parser") << "set logic: '" << name << "' " << std::endl;
+      setLogic(PARSER_STATE,name);
+      $cmd = new SetBenchmarkLogicCommand(name);   }
+  | SET_INFO_TOK STATUS_TOK status[b_status]
+    { cmd = new SetBenchmarkStatusCommand(b_status); }  
+  | /* sort declaration */
+    DECLARE_SORT_TOK identifier[name,CHECK_UNDECLARED,SYM_SORT] n=NUMERAL_TOK
+    // FIXME: What does the numeral argument mean?
+    { Debug("parser") << "declare sort: '" << name << "' " << n << std::endl;
+      PARSER_STATE->mkSort(name); 
+      $cmd = new DeclarationCommand(name,EXPR_MANAGER->kindType()); }
+  | /* function declaration */
+    DECLARE_FUN_TOK identifier[name,CHECK_UNDECLARED,SYM_VARIABLE] 
+    LPAREN_TOK sortList[sorts] RPAREN_TOK 
+    sortSymbol[t]
+    { Debug("parser") << "declare fun: '" << name << "' " << std::endl;
+      if( sorts.size() > 0 ) {
+        t = EXPR_MANAGER->mkFunctionType(sorts,t);
+      }
+      PARSER_STATE->mkVar(name, t); 
+      $cmd = new DeclarationCommand(name,t); } 
+  | /* assertion */
+    ASSERT_TOK term[expr]
+    { cmd = new AssertCommand(expr);   }
+  | /* checksat */
+    CHECKSAT_TOK 
+    { cmd = new CheckSatCommand(MK_CONST(true)); }
+  ;
+
+
+/**
+ * Matches a term.
+ * @return the expression representing the formula
+ */
+term[CVC4::Expr& expr]
+@init {
+  Debug("parser") << "term: " << Input::tokenText(LT(1)) << std::endl;
+  Kind kind;
+  std::string name;
+  std::vector<Expr> args; 
+} 
+  : /* a built-in operator application */
+    LPAREN_TOK builtinOp[kind] termList[args,expr] RPAREN_TOK 
+    { if((kind == CVC4::kind::AND || kind == CVC4::kind::OR) && args.size() == 1) {
+        /* Unary AND/OR can be replaced with the argument.
+              It just so happens expr should already by the only argument. */
+        Assert( expr == args[0] );
+      } else {
+        PARSER_STATE->checkArity(kind, args.size());
+        expr = MK_EXPR(kind, args);
+      }
+    }
+
+  | /* A non-built-in function application */
+    LPAREN_TOK 
+    functionSymbol[expr]
+    { args.push_back(expr); }
+    termList[args,expr] RPAREN_TOK
+    // TODO: check arity
+    { expr = MK_EXPR(CVC4::kind::APPLY_UF,args); }
+
+  | /* An ite expression */
+    LPAREN_TOK ITE_TOK 
+    term[expr]
+    { args.push_back(expr); } 
+    term[expr]
+    { args.push_back(expr); } 
+    term[expr]
+    { args.push_back(expr); } 
+    RPAREN_TOK
+    { expr = MK_EXPR(CVC4::kind::ITE, args); }
+
+  | /* a let binding */
+    LPAREN_TOK LET_TOK LPAREN_TOK 
+    { PARSER_STATE->pushScope(); }
+    ( LPAREN_TOK identifier[name,CHECK_UNDECLARED,SYM_VARIABLE] term[expr] RPAREN_TOK
+      { PARSER_STATE->defineVar(name,expr); } )+
+    RPAREN_TOK
+    term[expr]
+    RPAREN_TOK
+    { PARSER_STATE->popScope(); }
+
+  | /* a variable */
+    identifier[name,CHECK_DECLARED,SYM_VARIABLE]
+    { expr = PARSER_STATE->getVariable(name); }
+
+    /* constants */
+  | TRUE_TOK          { expr = MK_CONST(true); }
+  | FALSE_TOK         { expr = MK_CONST(false); }
+  | NUMERAL_TOK
+    { Integer num( Input::tokenText($NUMERAL_TOK) );
+      expr = MK_CONST(num); }
+  | RATIONAL_TOK
+    { // FIXME: This doesn't work because an SMT rational is not a valid GMP rational string
+      Rational rat( Input::tokenText($RATIONAL_TOK) );
+      expr = MK_CONST(rat); }
+    // NOTE: Theory constants go here
+  ;
+
+/**
+ * Matches a sequence of terms and puts them into the formulas
+ * vector.
+ * @param formulas the vector to fill with terms
+ * @param expr an Expr reference for the elements of the sequence
+ */   
+/* NOTE: We pass an Expr in here just to avoid allocating a fresh Expr every 
+ * time through this rule. */
+termList[std::vector<CVC4::Expr>& formulas, CVC4::Expr& expr]
+  : ( term[expr] { formulas.push_back(expr); } )+
+  ;
+
+/**
+* Matches a builtin operator symbol and sets kind to its associated Expr kind.
+*/
+builtinOp[CVC4::Kind& kind]
+@init {
+  Debug("parser") << "builtin: " << Input::tokenText(LT(1)) << std::endl;
+}
+  : NOT_TOK      { $kind = CVC4::kind::NOT;     }
+  | IMPLIES_TOK  { $kind = CVC4::kind::IMPLIES; }
+  | AND_TOK      { $kind = CVC4::kind::AND;     }
+  | OR_TOK       { $kind = CVC4::kind::OR;      }
+  | XOR_TOK      { $kind = CVC4::kind::XOR;     }
+  | EQUAL_TOK    { $kind = CVC4::kind::EQUAL;   }
+  | DISTINCT_TOK { $kind = CVC4::kind::DISTINCT; }
+  | GREATER_THAN_TOK
+                 { $kind = CVC4::kind::GT; }
+  | GREATER_THAN_TOK EQUAL_TOK
+                 { $kind = CVC4::kind::GEQ; }
+  | LESS_THAN_TOK EQUAL_TOK
+                 { $kind = CVC4::kind::LEQ; }
+  | LESS_THAN_TOK
+                 { $kind = CVC4::kind::LT; }
+  | PLUS_TOK     { $kind = CVC4::kind::PLUS; }
+  | STAR_TOK     { $kind = CVC4::kind::MULT; }
+  | TILDE_TOK    { $kind = CVC4::kind::UMINUS; }
+  | MINUS_TOK    { $kind = CVC4::kind::MINUS; }
+    // NOTE: Theory operators go here
+  ;
+
+/**
+ * Matches a (possibly undeclared) function identifier (returning the string)
+ * @param check what kind of check to do with the symbol
+ */
+functionName[std::string& name, CVC4::parser::DeclarationCheck check]
+  :  identifier[name,check,SYM_VARIABLE] 
+  ;
+
+/**
+ * Matches an previously declared function symbol (returning an Expr)
+ */
+functionSymbol[CVC4::Expr& fun]
+@declarations {
+       std::string name;
+}
+  : functionName[name,CHECK_DECLARED]
+    { PARSER_STATE->checkFunction(name);
+      fun = PARSER_STATE->getVariable(name); }
+  ;
+  
+/**
+ * Matches a sequence of sort symbols and fills them into the given vector.
+ */
+sortList[std::vector<CVC4::Type>& sorts]
+@declarations {
+  Type t;
+}
+  : ( sortSymbol[t] { sorts.push_back(t); })* 
+  ;
+
+/**
+ * Matches the sort symbol, which can be an arbitrary identifier.
+ * @param check the check to perform on the name
+ */
+sortName[std::string& name, CVC4::parser::DeclarationCheck check] 
+  : identifier[name,check,SYM_SORT] 
+  ;
+
+sortSymbol[CVC4::Type& t]
+@declarations {
+  std::string name;
+}
+  : sortName[name,CHECK_NONE] 
+       { t = PARSER_STATE->getSort(name); }
+  | BOOL_TOK
+    { t = EXPR_MANAGER->booleanType(); }
+  ;
+
+/**
+ * Matches the status of the benchmark, one of 'sat', 'unsat' or 'unknown'.
+ */
+status[ CVC4::BenchmarkStatus& status ]
+  : SAT_TOK       { $status = SMT_SATISFIABLE;    }
+  | UNSAT_TOK     { $status = SMT_UNSATISFIABLE;  }
+  | UNKNOWN_TOK   { $status = SMT_UNKNOWN;        }
+  ;
+
+/**
+ * Matches an identifier and sets the string reference parameter id.
+ * @param id string to hold the identifier
+ * @param check what kinds of check to do on the symbol
+ * @param type the intended namespace for the identifier
+ */
+identifier[std::string& id,
+                  CVC4::parser::DeclarationCheck check, 
+           CVC4::parser::SymbolType type] 
+  : IDENTIFIER
+    { id = Input::tokenText($IDENTIFIER);
+      Debug("parser") << "identifier: " << id
+                      << " check? " << toString(check)
+                      << " type? " << toString(type) << std::endl;
+      PARSER_STATE->checkDeclaration(id, check, type); }
+  ;
+
+// Base SMT-LIB tokens
+ASSERT_TOK : 'assert';
+BOOL_TOK : 'Bool';
+CHECKSAT_TOK : 'check-sat';
+DECLARE_FUN_TOK : 'declare-fun';
+DECLARE_SORT_TOK : 'declare-sort';
+FALSE_TOK : 'false';
+ITE_TOK : 'ite';
+LET_TOK : 'let';
+LPAREN_TOK : '(';
+RPAREN_TOK : ')';
+SAT_TOK : 'sat';
+SET_LOGIC_TOK : 'set-logic';
+SET_INFO_TOK : 'set-info';
+STATUS_TOK : ':status';
+TRUE_TOK : 'true';
+UNKNOWN_TOK : 'unknown';
+UNSAT_TOK : 'unsat';
+
+// operators (NOTE: theory symbols go here)
+AMPERSAND_TOK     : '&';
+AND_TOK           : 'and';
+AT_TOK            : '@';
+DISTINCT_TOK      : 'distinct';
+DIV_TOK           : '/';
+EQUAL_TOK         : '=';
+EXISTS_TOK        : 'exists';
+FORALL_TOK        : 'forall';
+GREATER_THAN_TOK  : '>';
+IMPLIES_TOK       : '=>';
+LESS_THAN_TOK     : '<';
+MINUS_TOK         : '-';
+NOT_TOK           : 'not';
+OR_TOK            : 'or';
+PERCENT_TOK       : '%';
+PIPE_TOK          : '|';
+PLUS_TOK          : '+';
+POUND_TOK         : '#';
+STAR_TOK          : '*';
+TILDE_TOK         : '~';
+XOR_TOK           : 'xor';
+
+
+/**
+ * Matches an identifier from the input. An identifier is a sequence of letters,
+ * digits and "_", "'", "." symbols, starting with a letter.
+ */
+IDENTIFIER
+  :  ALPHA (ALPHA | DIGIT | '_' | '\'' | '.')*
+  ;
+
+/**
+ * Matches an identifier starting with a colon.
+ */
+ATTR_IDENTIFIER 
+  :  ':' IDENTIFIER
+  ;
+
+/**
+ * Matches and skips whitespace in the input.
+ */
+WHITESPACE
+  :  (' ' | '\t' | '\f' | '\r' | '\n')+             { $channel = HIDDEN;; }
+  ;
+
+/**
+ * Matches a numeral from the input (non-empty sequence of digits).
+ */
+NUMERAL_TOK
+  : DIGIT+
+  ;
+
+RATIONAL_TOK
+  : DIGIT+ '.' DIGIT+
+  ;
+
+/**
+ * Matches a double quoted string literal. Escaping is supported, and escape
+ * character '\' has to be escaped.
+ */
+STRING_LITERAL 
+  :  '"' (ESCAPE | ~('"'|'\\'))* '"'
+  ;
+
+/**
+ * Matches the comments and ignores them
+ */
+COMMENT 
+  : ';' (~('\n' | '\r'))*                    { $channel = HIDDEN;; }
+  ;
+
+
+/**
+ * Matches any letter ('a'-'z' and 'A'-'Z').
+ */
+fragment
+ALPHA 
+  :  'a'..'z'
+  |  'A'..'Z'
+  ;
+
+/**
+ * Matches the digits (0-9)
+ */
+fragment DIGIT :   '0'..'9';
+// fragment NON_ZERO_DIGIT : '1'..'9';
+// fragment NUMERAL_SEQ : '0' | NON_ZERO_DIGIT DIGIT*;
+
+/**
+ * Matches an allowed escaped character.
+ */
+fragment ESCAPE : '\\' ('"' | '\\' | 'n' | 't' | 'r');
+
diff --git a/src/parser/smt2/smt2_input.cpp b/src/parser/smt2/smt2_input.cpp
new file mode 100644 (file)
index 0000000..5db4a9b
--- /dev/null
@@ -0,0 +1,67 @@
+/*********************                                                        */
+/** smt2_input.cpp
+ ** Original author: cconway
+ ** 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)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.
+ **
+ ** [[ Add file-specific comments here ]]
+ **/
+
+#include <antlr3.h>
+
+#include "smt2_input.h"
+#include "expr/expr_manager.h"
+#include "parser/parser.h"
+#include "parser/parser_exception.h"
+#include "parser/smt2/generated/Smt2Lexer.h"
+#include "parser/smt2/generated/Smt2Parser.h"
+
+namespace CVC4 {
+namespace parser {
+
+/* Use lookahead=2 */
+Smt2Input::Smt2Input(AntlrInputStream *inputStream) :
+  Input(inputStream, 2) {
+  pANTLR3_INPUT_STREAM input = inputStream->getAntlr3InputStream();
+  AlwaysAssert( input != NULL );
+
+  d_pSmt2Lexer = Smt2LexerNew(input);
+  if( d_pSmt2Lexer == NULL ) {
+    throw ParserException("Failed to create SMT2 lexer.");
+  }
+
+  setAntlr3Lexer( d_pSmt2Lexer->pLexer );
+
+  pANTLR3_COMMON_TOKEN_STREAM tokenStream = getTokenStream();
+  AlwaysAssert( tokenStream != NULL );
+
+  d_pSmt2Parser = Smt2ParserNew(tokenStream);
+  if( d_pSmt2Parser == NULL ) {
+    throw ParserException("Failed to create SMT2 parser.");
+  }
+
+  setAntlr3Parser(d_pSmt2Parser->pParser);
+}
+
+
+Smt2Input::~Smt2Input() {
+  d_pSmt2Lexer->free(d_pSmt2Lexer);
+  d_pSmt2Parser->free(d_pSmt2Parser);
+}
+
+Command* Smt2Input::parseCommand() throw (ParserException) {
+  return d_pSmt2Parser->parseCommand(d_pSmt2Parser);
+}
+
+Expr Smt2Input::parseExpr() throw (ParserException) {
+  return d_pSmt2Parser->parseExpr(d_pSmt2Parser);
+}
+
+}/* CVC4::parser namespace */
+}/* CVC4 namespace */
diff --git a/src/parser/smt2/smt2_input.h b/src/parser/smt2/smt2_input.h
new file mode 100644 (file)
index 0000000..48fcb79
--- /dev/null
@@ -0,0 +1,95 @@
+/*********************                                                        */
+/** smt2_input.h
+ ** Original author: cconway
+ ** Major contributors: mdeters
+ ** Minor contributors (to current version): none
+ ** 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.
+ **
+ ** [[ Add file-specific comments here ]]
+ **/
+
+#include "cvc4parser_public.h"
+
+#ifndef __CVC4__PARSER__SMT2_INPUT_H
+#define __CVC4__PARSER__SMT2_INPUT_H
+
+#include "parser/input.h"
+#include "parser/smt2/generated/Smt2Lexer.h"
+#include "parser/smt2/generated/Smt2Parser.h"
+
+// extern void Smt2ParserSetAntlrParser(CVC4::parser::AntlrParser* newAntlrParser);
+
+namespace CVC4 {
+
+class Command;
+class Expr;
+class ExprManager;
+
+namespace parser {
+
+class Smt2Input : public Input {
+
+  /** The ANTLR3 SMT2 lexer for the input. */
+  pSmt2Lexer d_pSmt2Lexer;
+
+  /** The ANTLR3 CVC parser for the input. */
+  pSmt2Parser d_pSmt2Parser;
+
+public:
+
+  /**
+   * Create an input.
+   *
+   * @param inputStream the input stream to use
+   */
+  Smt2Input(AntlrInputStream *inputStream);
+
+  /**
+   * Create a string input.
+   *
+   * @param exprManager the manager to use when building expressions from the input
+   * @param input the string to read
+   * @param name the "filename" to use when reporting errors
+   */
+//  Smt2Input(ExprManager* exprManager, const std::string& input, const std::string& name);
+
+  /** Destructor. Frees the lexer and the parser. */
+  ~Smt2Input();
+
+protected:
+
+  /**
+   * Parse a command from the input. Returns <code>NULL</code> if
+   * there is no command there to parse.
+   *
+   * @throws ParserException if an error is encountered during parsing.
+   */
+  Command* parseCommand() throw(ParserException);
+
+  /**
+   * Parse an expression from the input. Returns a null
+   * <code>Expr</code> if there is no expression there to parse.
+   *
+   * @throws ParserException if an error is encountered during parsing.
+   */
+  Expr parseExpr() throw(ParserException);
+
+private:
+
+  /**
+   * Initialize the class. Called from the constructors once the input
+   * stream is initialized.
+   */
+  void init();
+
+};/* class Smt2Input */
+
+}/* CVC4::parser namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__PARSER__SMT2_INPUT_H */
index 9a2864781c2787f3a8d6b3c877e95d5815e4cdc5..b7fbf243f66dc92dada586d48319c8fca2ea72d5 100644 (file)
@@ -144,6 +144,69 @@ const string badSmtExprs[] = {
 
 const int numBadSmtExprs = sizeof(badSmtExprs) / sizeof(string);
 
+/************************** SMT v2 test inputs ********************************/
+
+const string goodSmt2Inputs[] = {
+    "", // empty string is OK
+    "(set-logic QF_UF)",
+    "(assert true)",
+    "(check-sat)",
+    "(assert false) (check-sat)",
+    "(declare-fun a () Bool) (declare-fun b () Bool)",
+    "(declare-fun a () Bool) (declare-fun b () Bool) (assert (=> (and (=> a b) a) b))",
+    "(declare-sort a 1) (declare-fun f (a) a) (declare-fun x () a) (assert (= (f x) x))",
+    "(declare-sort a 1) (declare-fun x () a) (declare-fun y () a) (assert (= (ite true x y) x))",
+    ";; nothing but a comment",
+    "; a comment\n(check-sat ; goodbye\n)"
+  };
+
+const int numGoodSmt2Inputs = sizeof(goodSmt2Inputs) / sizeof(string);
+
+/* The following expressions are valid after setupContext. */
+const string goodSmt2Exprs[] = {
+    "(and a b)",
+    "(or (and a b) c)",
+    "(=> (and (=> a b) a) b)",
+    "(and (= a b) (not a))",
+    "(= (xor a b) (and (or a b) (not (and a b))))",
+    "(ite a (f x) y)",
+    "1",
+    "0"// ,
+//    "1.5"
+};
+
+const int numGoodSmt2Exprs = sizeof(goodSmt2Exprs) / sizeof(string);
+
+const string badSmt2Inputs[] = {
+    "(assert)", // no args
+    "(check-sat true)", // shouldn't have an arg
+    "(declare-sort a)", // no arg
+    "(declare-sort a 1) (declare-sort a 1)", // double decl
+    "(declare-fun p Bool)" // should be "p () Bool"
+  };
+
+const int numBadSmt2Inputs = sizeof(badSmt2Inputs) / sizeof(string);
+
+/* The following expressions are invalid even after setupContext. */
+const string badSmt2Exprs[] = {
+    "(and)", // wrong arity
+    "(and a b", // no closing paren
+    "(a and b)", // infix
+    "(implies a b)", // no implies in v2
+    "(iff a b)", // no iff in v2
+    "(OR (AND a b) c)", // wrong case
+    "(a IMPLIES b)", // infix AND wrong case
+    "(not a b)", // wrong arity
+    "not a", // needs parens
+    "(ite a x)", // wrong arity
+    "(if_then_else a (f x) y)", // no if_then_else in v2
+    "(a b)", // using non-function as function
+    ".5", // rational constants must have integer prefix
+    "1." // rational constants must have fractional suffix
+};
+
+const int numBadSmt2Exprs = sizeof(badSmt2Exprs) / sizeof(string);
+
 class ParserBlack : public CxxTest::TestSuite {
   ExprManager *d_exprManager;
 
@@ -306,4 +369,20 @@ public:
   void testBadSmtExprs() {
     tryBadExprs(LANG_SMTLIB,badSmtExprs,numBadSmtExprs);
   }
+
+  void testGoodSmt2Inputs() {
+    tryGoodInputs(LANG_SMTLIB_V2,goodSmt2Inputs,numGoodSmt2Inputs);
+  }
+
+  void testBadSmt2Inputs() {
+    tryBadInputs(LANG_SMTLIB_V2,badSmt2Inputs,numBadSmt2Inputs);
+  }
+
+  void testGoodSmt2Exprs() {
+    tryGoodExprs(LANG_SMTLIB_V2,goodSmt2Exprs,numGoodSmt2Exprs);
+  }
+
+  void testBadSmt2Exprs() {
+    tryBadExprs(LANG_SMTLIB_V2,badSmt2Exprs,numBadSmt2Exprs);
+  }
 };