3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 10:25:18 +00:00

Merge branch 'develop' into upstream-master

Conflicts:
	.gitignore
	README
	src/ast/ast_smt2_pp.h
	src/ast/ast_smt_pp.cpp
	src/ast/reg_decl_plugins.cpp
	src/cmd_context/cmd_context.cpp
	src/parsers/smt2/smt2parser.cpp
This commit is contained in:
Murphy Berzish 2016-06-01 17:30:25 -04:00
commit d79837eed0
17 changed files with 5647 additions and 8 deletions

8
.gitignore vendored
View file

@ -86,3 +86,11 @@ src/*/*/CMakeLists.txt
src/*/*/*/CMakeLists.txt
src/api/dotnet/cmake_install_gac.cmake.in
src/api/dotnet/cmake_uninstall_gac.cmake.in
# reference code for z3str2
Z3-str
Z3-str/**
# test cases
tests
tests/**

View file

@ -17,6 +17,7 @@ Revision History:
--*/
#include<sstream>
#include<cstring>
#include"ast.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
@ -58,6 +59,7 @@ parameter& parameter::operator=(parameter const& other) {
case PARAM_SYMBOL: new (m_symbol) symbol(other.get_symbol()); break;
case PARAM_RATIONAL: new (m_rational) rational(other.get_rational()); break;
case PARAM_DOUBLE: m_dval = other.m_dval; break;
case PARAM_STRING: m_string = other.m_string; break;
case PARAM_EXTERNAL: m_ext_id = other.m_ext_id; break;
default:
UNREACHABLE();
@ -90,6 +92,7 @@ bool parameter::operator==(parameter const & p) const {
case PARAM_SYMBOL: return get_symbol() == p.get_symbol();
case PARAM_RATIONAL: return get_rational() == p.get_rational();
case PARAM_DOUBLE: return m_dval == p.m_dval;
case PARAM_STRING: return (m_string == NULL && p.m_string == NULL) || strcmp(m_string, p.m_string)==0;
case PARAM_EXTERNAL: return m_ext_id == p.m_ext_id;
default: UNREACHABLE(); return false;
}
@ -103,6 +106,7 @@ unsigned parameter::hash() const {
case PARAM_SYMBOL: b = get_symbol().hash(); break;
case PARAM_RATIONAL: b = get_rational().hash(); break;
case PARAM_DOUBLE: b = static_cast<unsigned>(m_dval); break;
case PARAM_STRING: /* TODO */ b = 42; break;
case PARAM_EXTERNAL: b = m_ext_id; break;
}
return (b << 2) | m_kind;
@ -115,6 +119,7 @@ std::ostream& parameter::display(std::ostream& out) const {
case PARAM_RATIONAL: return out << get_rational();
case PARAM_AST: return out << "#" << get_ast()->get_id();
case PARAM_DOUBLE: return out << m_dval;
case PARAM_STRING: return out << m_string;
case PARAM_EXTERNAL: return out << "@" << m_ext_id;
default:
UNREACHABLE();

View file

@ -87,6 +87,7 @@ public:
PARAM_SYMBOL,
PARAM_RATIONAL,
PARAM_DOUBLE,
PARAM_STRING,
// PARAM_EXTERNAL is used for handling decl_plugin specific parameters.
// For example, it is used for handling mpf numbers in float_decl_plugin,
// and irrational algebraic numbers in arith_decl_plugin.
@ -105,6 +106,7 @@ private:
char m_symbol[sizeof(symbol)]; // for PARAM_SYMBOL
char m_rational[sizeof(rational)]; // for PARAM_RATIONAL
double m_dval; // for PARAM_DOUBLE (remark: this is not used in float_decl_plugin)
const char* m_string; // for PARAM_STRING
unsigned m_ext_id; // for PARAM_EXTERNAL
};
@ -117,6 +119,9 @@ public:
explicit parameter(symbol const & s): m_kind(PARAM_SYMBOL) { new (m_symbol) symbol(s); }
explicit parameter(rational const & r): m_kind(PARAM_RATIONAL) { new (m_rational) rational(r); }
explicit parameter(double d):m_kind(PARAM_DOUBLE), m_dval(d) {}
explicit parameter(const char *s):m_kind(PARAM_STRING), m_string(s) {
TRACE("parse_string", tout << "parameter(const char *): " << s << "\n";);
}
explicit parameter(unsigned ext_id, bool):m_kind(PARAM_EXTERNAL), m_ext_id(ext_id) {}
parameter(parameter const&);
@ -130,6 +135,7 @@ public:
bool is_symbol() const { return m_kind == PARAM_SYMBOL; }
bool is_rational() const { return m_kind == PARAM_RATIONAL; }
bool is_double() const { return m_kind == PARAM_DOUBLE; }
bool is_string() const { return m_kind == PARAM_STRING; }
bool is_external() const { return m_kind == PARAM_EXTERNAL; }
bool is_int(int & i) const { return is_int() && (i = get_int(), true); }
@ -137,6 +143,7 @@ public:
bool is_symbol(symbol & s) const { return is_symbol() && (s = get_symbol(), true); }
bool is_rational(rational & r) const { return is_rational() && (r = get_rational(), true); }
bool is_double(double & d) const { return is_double() && (d = get_double(), true); }
// TODO is_string(char*)
bool is_external(unsigned & id) const { return is_external() && (id = get_ext_id(), true); }
/**
@ -156,6 +163,7 @@ public:
symbol const & get_symbol() const { SASSERT(is_symbol()); return *(reinterpret_cast<const symbol *>(m_symbol)); }
rational const & get_rational() const { SASSERT(is_rational()); return *(reinterpret_cast<const rational *>(m_rational)); }
double get_double() const { SASSERT(is_double()); return m_dval; }
const char * get_string() const { SASSERT(is_string()); return m_string; }
unsigned get_ext_id() const { SASSERT(is_external()); return m_ext_id; }
bool operator==(parameter const & p) const;

View file

@ -304,6 +304,18 @@ format * smt2_pp_environment::mk_float(rational const & val) const {
return mk_string(get_manager(), s.c_str());
}
format * smt2_pp_environment::pp_str_literal(app * t) {
TRACE("parse_string", tout << "pp_str_literal\n";);
str_util & u = get_strutil();
SASSERT(u.is_string(t));
const char * val;
u.is_string(t, &val);
ast_manager & m = get_manager();
string_buffer<> buf;
buf << "\"" << val << "\"";
return mk_string(m, buf.c_str());
}
format * smt2_pp_environment::pp_arith_literal(app * t, bool decimal, unsigned decimal_prec) {
arith_util & u = get_autil();
SASSERT(u.is_numeral(t) || u.is_irrational_algebraic_numeral(t));
@ -614,6 +626,9 @@ class smt2_printer {
else if (m_env.get_dlutil().is_numeral(c)) {
f = m_env.pp_datalog_literal(c);
}
else if (m_env.get_strutil().is_string(c)) {
f = m_env.pp_str_literal(c);
}
else {
buffer<symbol> names;
if (m().is_label_lit(c, names)) {

View file

@ -30,6 +30,7 @@ Revision History:
#include"fpa_decl_plugin.h"
#include"dl_decl_plugin.h"
#include"seq_decl_plugin.h"
#include"str_decl_plugin.h"
#include"smt2_util.h"
class smt2_pp_environment {
@ -49,12 +50,14 @@ public:
virtual array_util & get_arutil() = 0;
virtual fpa_util & get_futil() = 0;
virtual seq_util & get_sutil() = 0;
virtual str_util & get_strutil() = 0;
virtual datalog::dl_decl_util& get_dlutil() = 0;
virtual bool uses(symbol const & s) const = 0;
virtual format_ns::format * pp_fdecl(func_decl * f, unsigned & len);
virtual format_ns::format * pp_bv_literal(app * t, bool use_bv_lits, bool bv_neg);
virtual format_ns::format * pp_arith_literal(app * t, bool decimal, unsigned prec);
virtual format_ns::format * pp_float_literal(app * t, bool use_bv_lits, bool use_float_real_lits);
virtual format_ns::format * pp_str_literal(app * t);
virtual format_ns::format * pp_datalog_literal(app * t);
virtual format_ns::format * pp_string_literal(app * t);
virtual format_ns::format * pp_sort(sort * s);
@ -74,15 +77,17 @@ class smt2_pp_environment_dbg : public smt2_pp_environment {
array_util m_arutil;
fpa_util m_futil;
seq_util m_sutil;
str_util m_strutil;
datalog::dl_decl_util m_dlutil;
public:
smt2_pp_environment_dbg(ast_manager & m):m_manager(m), m_autil(m), m_bvutil(m), m_arutil(m), m_futil(m), m_sutil(m), m_dlutil(m) {}
smt2_pp_environment_dbg(ast_manager & m):m_manager(m), m_autil(m), m_bvutil(m), m_arutil(m), m_futil(m), m_sutil(m), m_strutil(m), m_dlutil(m) {}
virtual ast_manager & get_manager() const { return m_manager; }
virtual arith_util & get_autil() { return m_autil; }
virtual bv_util & get_bvutil() { return m_bvutil; }
virtual seq_util & get_sutil() { return m_sutil; }
virtual array_util & get_arutil() { return m_arutil; }
virtual fpa_util & get_futil() { return m_futil; }
virtual str_util & get_strutil() { return m_strutil; }
virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; }
virtual bool uses(symbol const & s) const { return false; }
};

View file

@ -24,6 +24,7 @@ Revision History:
#include"ast_smt_pp.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"str_decl_plugin.h"
#include"array_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"fpa_decl_plugin.h"
@ -164,8 +165,10 @@ class smt_printer {
bv_util m_bvutil;
seq_util m_sutil;
fpa_util m_futil;
str_util m_strutil;
family_id m_basic_fid;
family_id m_bv_fid;
family_id m_str_fid;
family_id m_arith_fid;
family_id m_array_fid;
family_id m_dt_fid;
@ -406,6 +409,7 @@ class smt_printer {
void visit_app(app* n) {
rational val;
const char *str;
bool is_int, pos;
buffer<symbol> names;
unsigned bv_size;
@ -469,6 +473,9 @@ class smt_printer {
m_out << ") bv1[1])";
}
}
else if (m_strutil.is_string(n, &str)) {
m_out << "\"" << str << "\"";
}
else if (m_manager.is_label(n, pos, names) && names.size() >= 1) {
if (m_is_smt2) {
m_out << "(! ";
@ -832,6 +839,7 @@ public:
m_bvutil(m),
m_sutil(m),
m_futil(m),
m_strutil(m),
m_logic(logic),
m_AUFLIRA("AUFLIRA"),
// It's much easier to read those testcases with that.
@ -844,6 +852,7 @@ public:
m_bv_fid = m.mk_family_id("bv");
m_arith_fid = m.mk_family_id("arith");
m_array_fid = m.mk_family_id("array");
m_str_fid = m.mk_family_id("str");
m_dt_fid = m.mk_family_id("datatype");
m_fpa_fid = m.mk_family_id("fpa");
}

View file

@ -26,6 +26,7 @@ Revision History:
#include"seq_decl_plugin.h"
#include"pb_decl_plugin.h"
#include"fpa_decl_plugin.h"
#include"str_decl_plugin.h"
void reg_decl_plugins(ast_manager & m) {
if (!m.get_plugin(m.mk_family_id(symbol("arith")))) {
@ -52,4 +53,7 @@ void reg_decl_plugins(ast_manager & m) {
if (!m.get_plugin(m.mk_family_id(symbol("pb")))) {
m.register_plugin(symbol("pb"), alloc(pb_decl_plugin));
}
if (!m.get_plugin(m.mk_family_id(symbol("str")))) {
m.register_plugin(symbol("str"), alloc(str_decl_plugin));
}
}

185
src/ast/str_decl_plugin.cpp Normal file
View file

@ -0,0 +1,185 @@
/*++
Module Name:
str_decl_plugin.h
Abstract:
<abstract>
Author:
Murphy Berzish (mtrberzi) 2015-09-02.
Revision History:
--*/
#include<sstream>
#include"str_decl_plugin.h"
#include"string_buffer.h"
#include"warning.h"
#include"ast_pp.h"
#include"ast_smt2_pp.h"
str_decl_plugin::str_decl_plugin():
m_strv_sym("String"),
m_str_decl(0),
m_concat_decl(0),
m_length_decl(0),
m_arith_plugin(0),
m_arith_fid(0),
m_int_sort(0){
}
str_decl_plugin::~str_decl_plugin(){
}
void str_decl_plugin::finalize(void) {
#define DEC_REF(decl) if (decl) { m_manager->dec_ref(decl); } ((void) 0)
DEC_REF(m_str_decl);
DEC_REF(m_concat_decl);
DEC_REF(m_length_decl);
DEC_REF(m_int_sort);
}
void str_decl_plugin::set_manager(ast_manager * m, family_id id) {
decl_plugin::set_manager(m, id);
m_str_decl = m->mk_sort(symbol("String"), sort_info(id, STRING_SORT));
m->inc_ref(m_str_decl);
sort * s = m_str_decl;
SASSERT(m_manager->has_plugin(symbol("arith")));
m_arith_fid = m_manager->mk_family_id("arith");
m_arith_plugin = static_cast<arith_decl_plugin*>(m_manager->get_plugin(m_arith_fid));
SASSERT(m_arith_plugin);
m_int_sort = m_manager->mk_sort(m_arith_fid, INT_SORT);
SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before str_decl_plugin.
m_manager->inc_ref(m_int_sort);
sort * i = m_int_sort;
#define MK_OP(FIELD, NAME, KIND, SORT) \
FIELD = m->mk_func_decl(symbol(NAME), SORT, SORT, SORT, func_decl_info(id, KIND)); \
m->inc_ref(FIELD)
MK_OP(m_concat_decl, "Concat", OP_STRCAT, s);
m_length_decl = m->mk_func_decl(symbol("Length"), s, i, func_decl_info(id, OP_STRLEN)); m_manager->inc_ref(m_length_decl);
}
decl_plugin * str_decl_plugin::mk_fresh() {
return alloc(str_decl_plugin);
}
sort * str_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
switch (k) {
case STRING_SORT: return m_str_decl;
default: return 0;
}
}
func_decl * str_decl_plugin::mk_func_decl(decl_kind k) {
switch(k) {
case OP_STRCAT: return m_concat_decl;
case OP_STRLEN: return m_length_decl;
default: return 0;
}
}
func_decl * str_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (k == OP_STR) {
m_manager->raise_exception("OP_STR not yet implemented in mk_func_decl!");
return 0;
}
if (arity == 0) {
m_manager->raise_exception("no arguments supplied to string operator");
return 0;
}
return mk_func_decl(k);
}
app * str_decl_plugin::mk_string(std::string & val) {
std::map<std::string, app*>::iterator it = string_cache.find(val);
//if (it == string_cache.end()) {
if (true) {
char * new_buffer = alloc_svect(char, (val.length() + 1));
strcpy(new_buffer, val.c_str());
parameter p[1] = {parameter(new_buffer)};
func_decl * d;
d = m_manager->mk_const_decl(m_strv_sym, m_str_decl, func_decl_info(m_family_id, OP_STR, 1, p));
app * str = m_manager->mk_const(d);
string_cache[val] = str;
return str;
} else {
return it->second;
}
}
app * str_decl_plugin::mk_string(const char * val) {
std::string key(val);
return mk_string(key);
}
app * str_decl_plugin::mk_fresh_string() {
// cheating.
// take the longest string in the cache, append the letter "A", and call it fresh.
std::string longestString = "";
std::map<std::string, app*>::iterator it = string_cache.begin();
for (; it != string_cache.end(); ++it) {
if (it->first.length() > longestString.length()) {
longestString = it->first;
}
}
longestString += "A";
return mk_string(longestString);
}
void str_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
op_names.push_back(builtin_name("Concat", OP_STRCAT));
op_names.push_back(builtin_name("Length", OP_STRLEN));
}
void str_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
sort_names.push_back(builtin_name("String", STRING_SORT));
}
bool str_decl_plugin::is_value(app * e) const {
if (e->get_family_id() != m_family_id) {
return false;
}
switch (e->get_decl_kind()) {
case OP_STR:
return true;
default:
return false;
}
}
bool str_recognizers::is_string(expr const * n, const char ** val) const {
if (!is_app_of(n, m_afid, OP_STR))
return false;
func_decl * decl = to_app(n)->get_decl();
*val = decl->get_parameter(0).get_string();
return true;
}
bool str_recognizers::is_string(expr const * n) const {
const char * tmp = 0;
return is_string(n, & tmp);
}
std::string str_recognizers::get_string_constant_value(expr const *n) const {
const char * cstr = 0;
bool isString = is_string(n, & cstr);
SASSERT(isString);
std::string strval(cstr);
return strval;
}
str_util::str_util(ast_manager &m) :
str_recognizers(m.mk_family_id(symbol("str"))),
m_manager(m) {
SASSERT(m.has_plugin(symbol("str")));
m_plugin = static_cast<str_decl_plugin*>(m.get_plugin(m.mk_family_id(symbol("str"))));
}

109
src/ast/str_decl_plugin.h Normal file
View file

@ -0,0 +1,109 @@
/*++
Module Name:
str_decl_plugin.h
Abstract:
<abstract>
Author:
Murphy Berzish (mtrberzi) 2015-09-02.
Revision History:
--*/
#ifndef _STR_DECL_PLUGIN_H_
#define _STR_DECL_PLUGIN_H_
#include"ast.h"
#include"arith_decl_plugin.h"
#include<map>
enum str_sort_kind {
STRING_SORT,
};
enum str_op_kind {
OP_STR, /* string constants */
//
OP_STRCAT,
OP_STRLEN,
LAST_STR_OP
};
class str_decl_plugin : public decl_plugin {
protected:
symbol m_strv_sym;
sort * m_str_decl;
func_decl * m_concat_decl;
func_decl * m_length_decl;
arith_decl_plugin * m_arith_plugin;
family_id m_arith_fid;
sort * m_int_sort;
std::map<std::string, app*> string_cache;
virtual void set_manager(ast_manager * m, family_id id);
func_decl * mk_func_decl(decl_kind k);
public:
str_decl_plugin();
virtual ~str_decl_plugin();
virtual void finalize();
virtual decl_plugin * mk_fresh();
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
app * mk_string(const char * val);
app * mk_string(std::string & val);
app * mk_fresh_string();
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app * e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
// TODO
};
class str_recognizers {
family_id m_afid;
public:
str_recognizers(family_id fid):m_afid(fid) {}
family_id get_fid() const { return m_afid; }
family_id get_family_id() const { return get_fid(); }
bool is_string(expr const * n, const char ** val) const;
bool is_string(expr const * n) const;
std::string get_string_constant_value(expr const *n) const;
// TODO
};
class str_util : public str_recognizers {
ast_manager & m_manager;
str_decl_plugin * m_plugin;
public:
str_util(ast_manager & m);
ast_manager & get_manager() const { return m_manager; }
str_decl_plugin & plugin() { return *m_plugin; }
app * mk_string(const char * val) {
return m_plugin->mk_string(val);
}
app * mk_string(std::string & val) {
return m_plugin->mk_string(val);
}
app * mk_fresh_string() {
return m_plugin->mk_fresh_string();
}
// TODO
};
#endif /* _STR_DECL_PLUGIN_H_ */

View file

@ -26,6 +26,7 @@ Notes:
#include"seq_decl_plugin.h"
#include"pb_decl_plugin.h"
#include"fpa_decl_plugin.h"
#include"str_decl_plugin.h"
#include"ast_pp.h"
#include"var_subst.h"
#include"pp.h"
@ -248,6 +249,8 @@ protected:
array_util m_arutil;
fpa_util m_futil;
seq_util m_sutil;
str_util m_strutil;
datalog::dl_decl_util m_dlutil;
format_ns::format * pp_fdecl_name(symbol const & s, func_decls const & fs, func_decl * f, unsigned & len) {
@ -268,7 +271,7 @@ protected:
}
public:
pp_env(cmd_context & o):m_owner(o), m_autil(o.m()), m_bvutil(o.m()), m_arutil(o.m()), m_futil(o.m()), m_sutil(o.m()), m_dlutil(o.m()) {}
pp_env(cmd_context & o):m_owner(o), m_autil(o.m()), m_bvutil(o.m()), m_arutil(o.m()), m_futil(o.m()), m_sutil(o.m()), m_strutil(o.m()), m_dlutil(o.m()) {}
virtual ~pp_env() {}
virtual ast_manager & get_manager() const { return m_owner.m(); }
virtual arith_util & get_autil() { return m_autil; }
@ -276,6 +279,7 @@ public:
virtual array_util & get_arutil() { return m_arutil; }
virtual fpa_util & get_futil() { return m_futil; }
virtual seq_util & get_sutil() { return m_sutil; }
virtual str_util & get_strutil() { return m_strutil; }
virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; }
virtual bool uses(symbol const & s) const {
return
@ -593,6 +597,10 @@ bool cmd_context::logic_has_fpa() const {
return !has_logic() || logic_has_fpa_core(m_logic);
}
bool cmd_context::logic_has_str() const {
return !has_logic() || m_logic == "QF_S";
}
bool cmd_context::logic_has_array_core(symbol const & s) const {
return
s == "QF_AX" ||
@ -640,6 +648,7 @@ void cmd_context::init_manager_core(bool new_manager) {
register_plugin(symbol("pb"), alloc(pb_decl_plugin), !has_logic());
register_plugin(symbol("fpa"), alloc(fpa_decl_plugin), logic_has_fpa());
register_plugin(symbol("datalog_relation"), alloc(datalog::dl_decl_plugin), !has_logic());
register_plugin(symbol("str"), alloc(str_decl_plugin), logic_has_str());
}
else {
// the manager was created by an external module
@ -653,7 +662,7 @@ void cmd_context::init_manager_core(bool new_manager) {
load_plugin(symbol("datatype"), logic_has_datatype(), fids);
load_plugin(symbol("seq"), logic_has_seq(), fids);
load_plugin(symbol("fpa"), logic_has_fpa(), fids);
load_plugin(symbol("str"), logic_has_str(), fids);
svector<family_id>::iterator it = fids.begin();
svector<family_id>::iterator end = fids.end();
for (; it != end; ++it) {
@ -705,7 +714,8 @@ bool cmd_context::supported_logic(symbol const & s) const {
return s == "QF_UF" || s == "UF" ||
logic_has_arith_core(s) || logic_has_bv_core(s) ||
logic_has_array_core(s) || logic_has_seq_core(s) ||
logic_has_horn(s) || logic_has_fpa_core(s);
logic_has_horn(s) || logic_has_fpa_core(s) ||
s == "QF_S";
}
bool cmd_context::set_logic(symbol const & s) {

View file

@ -261,6 +261,7 @@ protected:
bool logic_has_array() const;
bool logic_has_datatype() const;
bool logic_has_fpa() const;
bool logic_has_str() const;
bool supported_logic(symbol const & s) const;
void print_unsupported_msg() { regular_stream() << "unsupported" << std::endl; }

View file

@ -23,6 +23,7 @@ Revision History:
#include"bv_decl_plugin.h"
#include"arith_decl_plugin.h"
#include"seq_decl_plugin.h"
#include"str_decl_plugin.h"
#include"ast_pp.h"
#include"well_sorted.h"
#include"pattern_validation.h"
@ -67,6 +68,8 @@ namespace smt2 {
scoped_ptr<bv_util> m_bv_util;
scoped_ptr<arith_util> m_arith_util;
scoped_ptr<seq_util> m_seq_util;
scoped_ptr<str_util> m_str_util;
scoped_ptr<pattern_validator> m_pattern_validator;
scoped_ptr<var_shifter> m_var_shifter;
@ -284,6 +287,12 @@ namespace smt2 {
return *(m_bv_util.get());
}
str_util & strutil() {
if (m_str_util.get() == 0)
m_str_util = alloc(str_util, m());
return *(m_str_util.get());
}
pattern_validator & pat_validator() {
if (m_pattern_validator.get() == 0) {
m_pattern_validator = alloc(pattern_validator, m());
@ -1073,10 +1082,29 @@ namespace smt2 {
next();
}
// sorry, breaking theory_seq for a bit
/*
void parse_string_const() {
SASSERT(curr() == scanner::STRING_TOKEN);
expr_stack().push_back(sutil().str.mk_string(symbol(m_scanner.get_string())));
TRACE("smt2parser", tout << "new string: " << mk_pp(expr_stack().back(), m()) << "\n";);
next();
}
*/
void parse_string_const() {
parse_string();
}
void parse_string() {
SASSERT(curr() == scanner::STRING_TOKEN);
char const *original_token = m_scanner.get_string();
size_t bufsize = strlen(original_token);
char * buf = alloc_svect(char, bufsize + 1);
strncpy(buf, original_token, bufsize);
buf[bufsize] = '\0';
TRACE("parse_string", tout << "new string constant: " << buf << " length=" << bufsize << "\n";);
expr_stack().push_back(strutil().mk_string(buf));
next();
}
@ -1739,6 +1767,9 @@ namespace smt2 {
case scanner::BV_TOKEN:
parse_bv_numeral();
break;
case scanner::STRING_TOKEN:
parse_string();
break;
case scanner::LEFT_PAREN:
push_expr_frame(m_num_expr_frames == 0 ? 0 : static_cast<expr_frame*>(m_stack.top()));
break;

View file

@ -33,6 +33,7 @@ Revision History:
#include"theory_seq.h"
#include"theory_pb.h"
#include"theory_fpa.h"
#include"theory_str.h"
namespace smt {
@ -120,6 +121,8 @@ namespace smt {
setup_QF_FP();
else if (m_logic == "QF_FPBV" || m_logic == "QF_BVFP")
setup_QF_FPBV();
else if (m_logic == "QF_S")
setup_QF_S();
else
setup_unknown();
}
@ -161,6 +164,8 @@ namespace smt {
setup_QF_BVRE();
else if (m_logic == "QF_AUFLIA")
setup_QF_AUFLIA(st);
else if (m_logic == "QF_S")
setup_QF_S();
else if (m_logic == "AUFLIA")
setup_AUFLIA(st);
else if (m_logic == "AUFLIRA")
@ -700,6 +705,11 @@ namespace smt {
m_context.register_plugin(alloc(smt::theory_fpa, m_manager));
}
void setup::setup_QF_S() {
setup_QF_LRA();
m_context.register_plugin(alloc(smt::theory_str, m_manager));
}
bool is_arith(static_features const & st) {
return st.m_num_arith_ineqs > 0 || st.m_num_arith_terms > 0 || st.m_num_arith_eqs > 0;
}
@ -827,6 +837,11 @@ namespace smt {
m_context.register_plugin(alloc(theory_fpa, m_manager));
}
void setup::setup_str() {
setup_arith();
m_context.register_plugin(alloc(theory_str, m_manager));
}
void setup::setup_unknown() {
setup_arith();
setup_arrays();
@ -836,6 +851,7 @@ namespace smt {
setup_seq();
setup_card();
setup_fpa();
setup_str();
}
void setup::setup_unknown(static_features & st) {
@ -937,6 +953,8 @@ namespace smt {
return;
}
// TODO setup_str() by features
setup_unknown();
}

View file

@ -77,6 +77,7 @@ namespace smt {
void setup_QF_AUFLIA(static_features const & st);
void setup_QF_FP();
void setup_QF_FPBV();
void setup_QF_S();
void setup_LRA();
void setup_AUFLIA(bool simple_array = true);
void setup_AUFLIA(static_features const & st);
@ -98,6 +99,7 @@ namespace smt {
void setup_i_arith();
void setup_mi_arith();
void setup_fpa();
void setup_str();
public:
setup(context & c, smt_params & params);

4965
src/smt/theory_str.cpp Normal file

File diff suppressed because it is too large Load diff

253
src/smt/theory_str.h Normal file
View file

@ -0,0 +1,253 @@
/*++
Module Name:
theory_str.h
Abstract:
String Theory Plugin
Author:
Murphy Berzish (mtrberzi) 2015-09-03
Revision History:
--*/
#ifndef _THEORY_STR_H_
#define _THEORY_STR_H_
#include"smt_theory.h"
#include"trail.h"
#include"th_rewriter.h"
#include"value_factory.h"
#include"smt_model_generator.h"
#include"arith_decl_plugin.h"
#include<set>
#include<stack>
namespace smt {
class str_value_factory : public value_factory {
str_util m_util;
public:
str_value_factory(ast_manager & m, family_id fid) :
value_factory(m, fid),
m_util(m) {}
virtual ~str_value_factory() {}
virtual expr * get_some_value(sort * s) {
return m_util.mk_string("some value");
}
virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
v1 = m_util.mk_string("value 1");
v2 = m_util.mk_string("value 2");
return true;
}
virtual expr * get_fresh_value(sort * s) {
// TODO this may be causing crashes in model gen? investigate
//return m_util.mk_fresh_string();
NOT_IMPLEMENTED_YET();
}
virtual void register_value(expr * n) { /* Ignore */ }
};
class theory_str : public theory {
struct T_cut
{
int level;
std::map<expr*, int> vars;
T_cut() {
level = -100;
}
};
protected:
bool search_started;
arith_util m_autil;
str_util m_strutil;
int sLevel;
// TODO make sure that all generated expressions are saved into the trail
expr_ref_vector m_trail; // trail for generated terms
str_value_factory * m_factory;
ptr_vector<enode> m_basicstr_axiom_todo;
svector<std::pair<enode*,enode*> > m_str_eq_todo;
ptr_vector<enode> m_concat_axiom_todo;
int tmpStringVarCount;
int tmpXorVarCount;
int tmpLenTestVarCount;
int tmpValTestVarCount;
std::map<std::pair<expr*, expr*>, std::map<int, expr*> > varForBreakConcat;
bool avoidLoopCut;
bool loopDetected;
std::map<expr*, std::stack<T_cut *> > cut_var_map;
std::set<expr*> variable_set;
std::set<expr*> internal_variable_set;
std::map<int, std::set<expr*> > internal_variable_scope_levels;
obj_hashtable<expr> internal_lenTest_vars;
obj_hashtable<expr> internal_valTest_vars;
std::set<expr*> input_var_in_len;
std::map<expr*, unsigned int> fvar_len_count_map;
std::map<expr*, ptr_vector<expr> > fvar_lenTester_map;
std::map<expr*, expr*> lenTester_fvar_map;
std::map<expr*, std::map<int, svector<std::pair<int, expr*> > > > fvar_valueTester_map;
std::map<expr*, expr*> valueTester_fvar_map;
std::map<expr*, int_vector> val_range_map;
char * char_set;
std::map<char, int> charSetLookupTable;
int charSetSize;
protected:
void assert_axiom(expr * e);
void assert_implication(expr * premise, expr * conclusion);
app * mk_strlen(expr * e);
expr * mk_concat(expr * n1, expr * n2);
expr * mk_concat_const_str(expr * n1, expr * n2);
app * mk_int(int n);
void check_and_init_cut_var(expr * node);
void add_cut_info_one_node(expr * baseNode, int slevel, expr * node);
void add_cut_info_merge(expr * destNode, int slevel, expr * srcNode);
bool has_self_cut(expr * n1, expr * n2);
void track_variable_scope(expr * var);
app * mk_str_var(std::string name);
app * mk_nonempty_str_var();
app * mk_internal_xor_var();
expr * mk_internal_valTest_var(expr * node, int len, int vTries);
bool is_concat(app const * a) const { return a->is_app_of(get_id(), OP_STRCAT); }
bool is_concat(enode const * n) const { return is_concat(n->get_owner()); }
bool is_string(app const * a) const { return a->is_app_of(get_id(), OP_STR); }
bool is_string(enode const * n) const { return is_string(n->get_owner()); }
bool is_strlen(app const * a) const { return a->is_app_of(get_id(), OP_STRLEN); }
bool is_strlen(enode const * n) const { return is_strlen(n->get_owner()); }
void instantiate_concat_axiom(enode * cat);
void instantiate_basic_string_axioms(enode * str);
void instantiate_str_eq_length_axiom(enode * lhs, enode * rhs);
void set_up_axioms(expr * ex);
void handle_equality(expr * lhs, expr * rhs);
app * mk_value_helper(app * n);
expr * get_eqc_value(expr * n, bool & hasEqcValue);
bool in_same_eqc(expr * n1, expr * n2);
bool get_value(expr* e, rational& val) const;
bool get_len_value(expr* e, rational& val);
bool lower_bound(expr* _e, rational& lo);
bool upper_bound(expr* _e, rational& hi);
bool can_two_nodes_eq(expr * n1, expr * n2);
bool can_concat_eq_str(expr * concat, std::string str);
bool can_concat_eq_concat(expr * concat1, expr * concat2);
void get_nodes_in_concat(expr * node, ptr_vector<expr> & nodeList);
expr * simplify_concat(expr * node);
void simplify_parent(expr * nn, expr * eq_str);
void simplify_concat_equality(expr * lhs, expr * rhs);
void solve_concat_eq_str(expr * concat, expr * str);
bool is_concat_eq_type1(expr * concatAst1, expr * concatAst2);
bool is_concat_eq_type2(expr * concatAst1, expr * concatAst2);
bool is_concat_eq_type3(expr * concatAst1, expr * concatAst2);
bool is_concat_eq_type4(expr * concatAst1, expr * concatAst2);
bool is_concat_eq_type5(expr * concatAst1, expr * concatAst2);
bool is_concat_eq_type6(expr * concatAst1, expr * concatAst2);
void process_concat_eq_type1(expr * concatAst1, expr * concatAst2);
void process_concat_eq_type2(expr * concatAst1, expr * concatAst2);
void process_concat_eq_type3(expr * concatAst1, expr * concatAst2);
void process_concat_eq_type4(expr * concatAst1, expr * concatAst2);
void process_concat_eq_type5(expr * concatAst1, expr * concatAst2);
void process_concat_eq_type6(expr * concatAst1, expr * concatAst2);
bool new_eq_check(expr * lhs, expr * rhs);
void group_terms_by_eqc(expr * n, std::set<expr*> & concats, std::set<expr*> & vars, std::set<expr*> & consts);
int ctx_dep_analysis(std::map<expr*, int> & strVarMap, std::map<expr*, int> & freeVarMap,
std::map<expr*, std::set<expr*> > & unrollGroupMap);
void classify_ast_by_type(expr * node, std::map<expr*, int> & varMap,
std::map<expr*, int> & concatMap, std::map<expr*, int> & unrollMap);
void classify_ast_by_type_in_positive_context(std::map<expr*, int> & varMap,
std::map<expr*, int> & concatMap, std::map<expr*, int> & unrollMap);
expr * mk_internal_lenTest_var(expr * node, int lTries);
expr * gen_len_val_options_for_free_var(expr * freeVar, expr * lenTesterInCbEq, std::string lenTesterValue);
void process_free_var(std::map<expr*, int> & freeVar_map);
expr * gen_len_test_options(expr * freeVar, expr * indicator, int tries);
expr * gen_free_var_options(expr * freeVar, expr * len_indicator,
std::string len_valueStr, expr * valTesterInCbEq, std::string valTesterValueStr);
expr * gen_val_options(expr * freeVar, expr * len_indicator, expr * val_indicator,
std::string lenStr, int tries);
void print_value_tester_list(svector<std::pair<int, expr*> > & testerList);
bool get_next_val_encode(int_vector & base, int_vector & next);
std::string gen_val_string(int len, int_vector & encoding);
bool free_var_attempt(expr * nn1, expr * nn2);
void more_len_tests(expr * lenTester, std::string lenTesterValue);
void more_value_tests(expr * valTester, std::string valTesterValue);
expr * get_alias_index_ast(std::map<expr*, expr*> & aliasIndexMap, expr * node);
expr * getMostLeftNodeInConcat(expr * node);
expr * getMostRightNodeInConcat(expr * node);
void get_var_in_eqc(expr * n, std::set<expr*> & varSet);
expr * eval_concat(expr * n1, expr * n2);
// strRegex
void get_eqc_allUnroll(expr * n, expr * &constStr, std::set<expr*> & unrollFuncSet);
void dump_assignments();
void initialize_charset();
public:
theory_str(ast_manager & m);
virtual ~theory_str();
virtual char const * get_name() const { return "strings"; }
protected:
virtual bool internalize_atom(app * atom, bool gate_ctx);
virtual bool internalize_term(app * term);
virtual enode* ensure_enode(expr* e);
virtual theory_var mk_var(enode * n);
virtual void new_eq_eh(theory_var, theory_var);
virtual void new_diseq_eh(theory_var, theory_var);
virtual theory* mk_fresh(context*) { return alloc(theory_str, get_manager()); }
virtual void init_search_eh();
virtual void relevant_eh(app * n);
virtual void assign_eh(bool_var v, bool is_true);
virtual void push_scope_eh();
virtual void pop_scope_eh(unsigned num_scopes);
virtual void reset_eh();
virtual bool can_propagate();
virtual void propagate();
virtual final_check_status final_check_eh();
virtual void attach_new_th_var(enode * n);
virtual void init_model(model_generator & m);
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
virtual void finalize_model(model_generator & mg);
};
};
#endif /* _THEORY_STR_H_ */

View file

@ -13,8 +13,9 @@ Copyright (c) 2015 Microsoft Corporation
void test_print(Z3_context ctx, Z3_ast a) {
Z3_set_ast_print_mode(ctx, Z3_PRINT_SMTLIB2_COMPLIANT);
char const* spec1 = Z3_benchmark_to_smtlib_string(ctx, "test", 0, 0, 0, 0, 0, a);
std::cout << spec1 << "\n";
std::cout << "spec1: benchmark->string\n" << spec1 << "\n";
std::cout << "attempting to parse spec1...\n";
Z3_ast b =
Z3_parse_smtlib2_string(ctx,
spec1,
@ -24,14 +25,14 @@ void test_print(Z3_context ctx, Z3_ast a) {
0,
0,
0);
std::cout << "parse successful, converting ast->string\n";
char const* spec2 = Z3_ast_to_string(ctx, b);
std::cout << spec2 << "\n";
std::cout << "spec2: string->ast->string\n" << spec2 << "\n";
}
void test_parseprint(char const* spec) {
Z3_context ctx = Z3_mk_context(0);
std::cout << spec << "\n";
std::cout << "spec:\n" << spec << "\n";
Z3_ast a =
Z3_parse_smtlib2_string(ctx,
@ -43,8 +44,12 @@ void test_parseprint(char const* spec) {
0,
0);
std::cout << "done parsing\n";
test_print(ctx, a);
std::cout << "done printing\n";
Z3_del_context(ctx);
}
@ -104,6 +109,12 @@ void tst_smt2print_parse() {
test_parseprint(spec5);
// Test strings
char const* spec6 =
"(assert (= \"abc\" \"abc\"))";
test_parseprint(spec6);
// Test ?
}