1 2 /* 3 * File SMTLIB2.hpp. 4 * 5 * This file is part of the source code of the software program 6 * Vampire. It is protected by applicable 7 * copyright laws. 8 * 9 * This source code is distributed under the licence found here 10 * https://vprover.github.io/license.html 11 * and in the source directory 12 * 13 * In summary, you are allowed to use Vampire for non-commercial 14 * purposes but not allowed to distribute, modify, copy, create derivatives, 15 * or use in competitions. 16 * For other uses of Vampire please contact developers for a different 17 * licence, which we will make an effort to provide. 18 */ 19 /** 20 * @file SMTLIB.hpp 21 * Defines class SMTLIB. 22 */ 23 24 #ifndef __SMTLIB2__ 25 #define __SMTLIB2__ 26 27 #include "Forwards.hpp" 28 29 #include "Lib/Set.hpp" 30 31 #include "Kernel/Signature.hpp" 32 #include "Kernel/Sorts.hpp" 33 #include "Kernel/Term.hpp" 34 35 #include "Shell/LispParser.hpp" 36 37 38 namespace Parse { 39 40 using namespace Lib; 41 using namespace Kernel; 42 using namespace Shell; 43 44 45 class SMTLIB2 { 46 public: 47 SMTLIB2(const Options& opts); 48 49 /** Parse from an open stream */ 50 void parse(istream& str); 51 /** Parse a ready lisp expression */ 52 void parse(LExpr* bench); 53 54 /** Formulas obtained during parsing: 55 * 1) equations collected from "define-fun" 56 * 2) general formulas collected from "assert" 57 * 58 * Global signature in env is updated on the fly. 59 * 60 * We don't know what the conjecture is. 61 **/ getFormulas() const62 UnitList* getFormulas() const { return _formulas; } 63 64 /** 65 * Return the parsed logic (or LO_INVALID if not set). 66 */ getLogic() const67 SMTLIBLogic getLogic() const { 68 return _logic; 69 } 70 getStatus() const71 const vstring& getStatus() const { 72 return _statusStr; 73 } 74 75 private: 76 77 static const char * s_smtlibLogicNameStrings[]; 78 79 /** 80 * Maps a string to a SmtlibLogic value. 81 */ 82 static SMTLIBLogic getLogicFromString(const vstring& str); 83 84 /** 85 * Have we seen "set-logic" entry yet? 86 */ 87 bool _logicSet; 88 89 /** 90 * The advertised logic. 91 */ 92 SMTLIBLogic _logic; 93 94 /** 95 * Logics which contains only reals allow numerals (like '123') to be understood as reals. 96 * When both Ints and Reals are mixed numerals are Ints and decimals (like '123.0') are reals. 97 * 98 * This is determined based on the advertised logic (and not the actual content of the file). 99 */ 100 bool _numeralsAreReal; 101 102 /** 103 * Handle "set-logic" entry. 104 */ 105 void readLogic(const vstring& logicStr); 106 107 /** Content of the ":status: info entry. */ 108 vstring _statusStr; 109 /** Content of the ":source: info entry. */ 110 vstring _sourceInfo; 111 112 enum BuiltInSorts 113 { 114 BS_ARRAY, 115 BS_BOOL, 116 BS_INT, 117 BS_REAL, 118 119 BS_INVALID 120 }; 121 static const char * s_builtInSortNameStrings[]; 122 123 /** 124 * Maps smtlib built-in sort name to BuiltInSorts value. 125 */ 126 static BuiltInSorts getBuiltInSortFromString(const vstring& str); 127 128 /** 129 * Test string for being either a built-in sort 130 * or a sort already declared or defined within this parser object. 131 */ 132 bool isAlreadyKnownSortSymbol(const vstring& name); 133 134 /** Maps smtlib name of a declared sort to its arity. 135 * 136 * Declared sorts are just names with arity-many "argument slots". 137 * However, this is just a way to make new sorts from old ones. 138 * There is no implied semantic relation to the argument sorts. 139 */ 140 DHMap<vstring,unsigned> _declaredSorts; 141 142 /** 143 * Handle "declare-sort" entry. 144 */ 145 void readDeclareSort(const vstring& name, const vstring& arity); 146 147 /** 148 * Sort definition is a macro (with arguments) for a complex sort expression. 149 * 150 * We don't parse the definition until it is used. 151 * 152 * Then a lookup context is created mapping 153 * symbolic arguments from the definition to actual arguments from the invocation 154 * and the invocation is parsed as the defined body in this context. 155 */ 156 struct SortDefinition { SortDefinitionParse::SMTLIB2::SortDefinition157 SortDefinition() : args(0), body(0) {} SortDefinitionParse::SMTLIB2::SortDefinition158 SortDefinition(LExprList* args, LExpr* body) 159 : args(args), body(body) {} 160 161 LExprList* args; 162 LExpr* body; 163 }; 164 165 /** 166 * Maps smtlib name of a defined sort to its SortDefinition struct. 167 */ 168 DHMap<vstring,SortDefinition> _sortDefinitions; 169 170 /** 171 * Handle "define-sort" entry. 172 */ 173 void readDefineSort(const vstring& name, LExprList* args, LExpr* body); 174 175 /** 176 * Take an smtlib sort expression, evaluate it in the context of previous 177 * sort declarations and definitions, 178 * register any missing sort in vampire and return vampire's sort id 179 * corresponding to the give expression. 180 */ 181 unsigned declareSort(LExpr* sExpr); 182 183 /** 184 * Some built-in symbols represent functions with result of sort Bool. 185 * They are listed here. 186 */ 187 enum FormulaSymbol 188 { 189 FS_LESS, 190 FS_LESS_EQ, 191 FS_EQ, 192 FS_IMPLIES, 193 FS_GREATER, 194 FS_GREATER_EQ, 195 FS_AND, 196 FS_DISTINCT, 197 FS_EXISTS, 198 FS_FALSE, 199 FS_FORALL, 200 FS_IS_INT, 201 FS_NOT, 202 FS_OR, 203 FS_TRUE, 204 FS_XOR, 205 206 FS_USER_PRED_SYMBOL 207 }; 208 static const char * s_formulaSymbolNameStrings[]; 209 210 /** 211 * Lookup to see if vstring is a built-in FormulaSymbol. 212 */ 213 static FormulaSymbol getBuiltInFormulaSymbol(const vstring& str); 214 215 /** 216 * Some built-in symbols represent functions with not-Bool result of sort 217 * and are listed here. 218 */ 219 enum TermSymbol 220 { 221 TS_MULTIPLY, 222 TS_PLUS, 223 TS_MINUS, 224 TS_DIVIDE, 225 TS_ABS, 226 TS_DIV, 227 TS_ITE, 228 TS_LET, 229 TS_MOD, 230 TS_SELECT, 231 TS_STORE, 232 TS_TO_INT, 233 TS_TO_REAL, 234 235 TS_USER_FUNCTION 236 }; 237 static const char * s_termSymbolNameStrings[]; 238 239 /** 240 * Lookup to see if vstring is a built-in TermSymbol. 241 */ 242 static TermSymbol getBuiltInTermSymbol(const vstring& str); 243 244 /** 245 * Is the given vstring a built-in FormulaSymbol, built-in TermSymbol or a declared function? 246 */ 247 bool isAlreadyKnownFunctionSymbol(const vstring& name); 248 249 /** <vampire signature id, is_function flag (otherwise it is a predicate) > */ 250 typedef std::pair<unsigned,bool> DeclaredFunction; 251 /** functions are implicitly declared also when they are defined (see below) */ 252 DHMap<vstring, DeclaredFunction> _declaredFunctions; 253 254 /** 255 * Given a symbol name, range sort (which can be Bool) and argSorts, 256 * register a new function (or predicate) symbol in vampire, 257 * store the ensuing DeclaredFunction in _declaredFunctions 258 * and return it. 259 */ 260 DeclaredFunction declareFunctionOrPredicate(const vstring& name, signed rangeSort, const Stack<unsigned>& argSorts); 261 262 /** 263 * Handle "declare-fun" entry. 264 * 265 * Declaring a function just extends the signature. 266 */ 267 void readDeclareFun(const vstring& name, LExprList* iSorts, LExpr* oSort); 268 269 /** 270 * Handle "define-fun" entry. 271 * 272 * Defining a function extends the signature and adds the new function's definition into _formulas. 273 */ 274 void readDefineFun(const vstring& name, LExprList* iArgs, LExpr* oSort, LExpr* body); 275 276 void readDeclareDatatypes(LExprList* sorts, LExprList* datatypes, bool codatatype = false); 277 278 TermAlgebraConstructor* buildTermAlgebraConstructor(vstring constrName, unsigned taSort, 279 Stack<vstring> destructorNames, Stack<unsigned> argSorts); 280 281 /** 282 * Parse result of parsing an smtlib term (which can be of sort Bool and therefore represented in vampire by a formula) 283 */ 284 struct ParseResult { 285 /** Construct special separator value */ ParseResultParse::SMTLIB2::ParseResult286 ParseResult() : sort(0), formula(true), frm(nullptr) {} 287 isSeparatorParse::SMTLIB2::ParseResult288 bool isSeparator() { return sort == 0 && formula && !frm; } 289 isSharedTermParse::SMTLIB2::ParseResult290 bool isSharedTerm() { return !formula && (!trm.isTerm() || trm.term()->shared()); } 291 292 /** Construct ParseResult from a formula */ ParseResultParse::SMTLIB2::ParseResult293 ParseResult(Formula* frm) : sort(Sorts::SRT_BOOL), formula(true), frm(frm) {} 294 /** Construct ParseResult from a term of a given sort */ ParseResultParse::SMTLIB2::ParseResult295 ParseResult(unsigned sort, TermList trm) : sort(sort), formula(false), trm(trm) {} 296 297 unsigned sort; 298 bool formula; 299 union { 300 Formula* frm; 301 TermList trm; 302 }; 303 304 /** 305 * Try interpreting ParseResult as a formula 306 * (which may involve unwrapping a formula special term 307 * or wrapping a Bool sorted term as BoolTermFormula) 308 * and indicate success by returning true. 309 */ 310 bool asFormula(Formula*& resFrm); 311 /** 312 * Interpret ParseResult as term 313 * and return its vampire sort (which may be Sorts::SRT_BOOL). 314 */ 315 unsigned asTerm(TermList& resTrm); 316 317 vstring toString(); 318 }; 319 320 /** Return Theory::Interpretation for overloaded arithmetic comparison operators based on their argSort (either Int or Real) */ 321 Interpretation getFormulaSymbolInterpretation(FormulaSymbol fs, unsigned firstArgSort); 322 /** Return Theory::Interpretation for overloaded unary minus operator based on its argSort (either Int or Real) */ 323 Interpretation getUnaryMinusInterpretation(unsigned argSort); 324 /** Return Theory::Interpretation for overloaded arithmetic operators based on its argSort (either Int or Real) */ 325 Interpretation getTermSymbolInterpretation(TermSymbol ts, unsigned firstArgSort); 326 327 328 // global parsing data structures -- BEGIN 329 330 /** For generating fresh vampire variables */ 331 unsigned _nextVar; 332 333 /** < termlist, vampire sort id > */ 334 typedef pair<TermList,unsigned> SortedTerm; 335 /** mast an identifier to SortedTerm */ 336 typedef DHMap<vstring,SortedTerm> TermLookup; 337 typedef Stack<TermLookup*> Scopes; 338 /** Stack of parsing contexts: 339 * for variables from quantifiers and 340 * for symbols bound by let (which are variables from smtlib perspective, 341 * but require a true function/predicate symbol by vampire ) 342 */ 343 Scopes _scopes; 344 345 /** 346 * Stack of partial results used by parseTermOrFormula below. 347 */ 348 Stack<ParseResult> _results; 349 350 /** 351 * Possible operations during parsing a term. 352 */ 353 enum ParseOperation { 354 // general top level parsing request 355 PO_PARSE, // takes LExpr* 356 // when parsing "(something args...)" the following operation will be scheduled for "something" 357 PO_PARSE_APPLICATION, // takes LExpr* (the whole term again, for better error reporting) 358 // after "(something args...)" is parsed the following makes sure that there is exactly one proper result on the result stack above a previously inserted separator 359 PO_CHECK_ARITY, // takes LExpr* (again the whole, just for error reporting) 360 // these two are intermediate cases for handling let 361 PO_LET_PREPARE_LOOKUP, // takes LExpr* (the whole let expression again, why not) 362 PO_LET_END // takes LExpr* (the whole let expression again, why not) 363 }; 364 /** 365 * Main smtlib term parsing stack. 366 */ 367 Stack<pair<ParseOperation,LExpr*> > _todo; 368 369 // global parsing data structures -- END 370 371 // a few helper functions enabling the body of parseTermOrFormula be of reasonable size 372 373 void complainAboutArgShortageOrWrongSorts(const vstring& symbolClass, LExpr* exp) NO_RETURN; 374 375 void parseLetBegin(LExpr* exp); 376 void parseLetPrepareLookup(LExpr* exp); 377 void parseLetEnd(LExpr* exp); 378 379 void parseQuantBegin(LExpr* exp); 380 381 void parseAnnotatedTerm(LExpr* exp); 382 383 /** Scope's are filled by forall, exists, and let */ 384 bool parseAsScopeLookup(const vstring& id); 385 /** Currently either numeral or decimal */ 386 bool parseAsSpecConstant(const vstring& id); 387 /** Declared or defined functions (and predicates) - which includes 0-arity ones */ 388 bool parseAsUserDefinedSymbol(const vstring& id, LExpr* exp); 389 /** Whatever is built-in and looks like a formula from vampire perspective (see FormulaSymbol) 390 * - includes the second half of parsing quantifiers */ 391 bool parseAsBuiltinFormulaSymbol(const vstring& id, LExpr* exp); 392 /** Whatever is built-in and looks like a term from vampire perspective (see TermSymbol) 393 * - excludes parts for dealing with let */ 394 bool parseAsBuiltinTermSymbol(const vstring& id, LExpr* exp); 395 396 /** Parsing things like "((_ divisible 5) x)" */ 397 void parseRankedFunctionApplication(LExpr* exp); 398 399 /** 400 * Main term parsing routine. 401 * Assumes "global parsing data structures" initialized. 402 * Returns the body's value as a ParseResult. 403 * 404 * Currently unsupported features (see http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.5-r2015-06-28.pdf): 405 * - qualified identifiers "(as f s)" 406 * - hexadecimal, binary and string spec_constants 407 * - :named expressions "(! (> x y) :named p1)" cause a user error. 408 * They could also be ignored, but smtlib dictates that 409 * 1) the named term has to be closed (needs an extra check), 410 * 2) the new name can be used elsewhere (also already in the term being parsed in the in-order traversal) 411 * So the proper behavior would be more difficult to support. 412 * - "define-funs-rec" and "define-fun-rec"; syntactically these would be fine, 413 * but any reasonable use will rely on some well-founded semantics which can only be supported with care 414 * 415 * Ignored feature: 416 * - quantifier patterns: " (forall (( x0 A) (x1 A) (x2 A)) (! (=> (and (r x0 x1) (r x1 x2 )) (r x0 x2 )) : pattern ((r x0 x1) (r x1 x2 )) : pattern ((p x0 a)) )) 417 * the patter information is lost and the pattern data is not checked semantically. 418 * 419 * Violates standard: 420 * - requires variables under a single quantifier to be distinct 421 * - the rule that "variables cannot have the same name as a theory function symbol in the same scope" is currently ignored 422 */ 423 ParseResult parseTermOrFormula(LExpr* body); 424 425 /** 426 * Handle "assert" entry. 427 * 428 * On success results in a single formula added to _formulas. 429 */ 430 void readAssert(LExpr* body); 431 432 /** 433 * Unofficial command 434 * 435 * Behaves like conjecture declaration in TPTP 436 */ 437 void readAssertNot(LExpr* body); 438 439 /** 440 * Unofficial command 441 * 442 * Behaves like conjecture declaration in TPTP 443 */ 444 void colorSymbol(const vstring& name, Color color); 445 446 /** 447 * Units collected during parsing. 448 */ 449 UnitList* _formulas; 450 451 /** 452 * To support a mechanism for dealing with large arithmetic constants. 453 * Adapted from the tptp parser. 454 */ 455 Set<vstring> _overflow; 456 457 /** 458 * Toplevel parsing dispatch for a benchmark. 459 */ 460 void readBenchmark(LExprList* bench); 461 }; 462 463 } 464 465 #endif // __SMTLIB2__ 466