z3-z3-4.13.0.src.parsers.smt2.smt2parser.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
smt2parser.h
Abstract:
SMT 2.0 parser
Author:
Leonardo de Moura (leonardo) 2011-03-01
Revision History:
--*/
#include "util/stack.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "ast/ast_pp.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/rewriter.h"
#include "ast/rewriter/var_subst.h"
#include "ast/has_free_vars.h"
#include "ast/ast_smt2_pp.h"
#include "parsers/smt2/smt2parser.h"
#include "parsers/smt2/smt2scanner.h"
#include "parsers/util/pattern_validation.h"
#include "parsers/util/parser_params.hpp"
#include
namespace smt2 {
typedef cmd_exception parser_exception;
class parser {
cmd_context & m_ctx;
params_ref m_params;
scanner m_scanner;
scanner::token m_curr;
cmd * m_curr_cmd;
stack m_stack;
struct local {
expr * m_term;
unsigned m_level;
local():m_term(nullptr), m_level(0) {}
local(expr * t, unsigned l):m_term(t), m_level(l) {}
};
symbol_table m_env;
unsigned m_num_bindings;
dictionary m_sort_id2param_idx;
dictionary m_dt_name2idx;
dictionary m_dt_name2arity;
svector m_dt_names;
scoped_ptr m_psort_stack;
scoped_ptr m_sort_stack;
scoped_ptr m_expr_stack;
unsigned m_num_expr_frames;
scoped_ptr m_pattern_stack;
scoped_ptr m_nopattern_stack;
svector m_symbol_stack;
vector m_param_stack;
scoped_ptr m_sexpr_stack;
scoped_ptr m_bv_util;
scoped_ptr m_arith_util;
scoped_ptr m_datatype_util;
scoped_ptr m_seq_util;
scoped_ptr m_pattern_validator;
scoped_ptr m_var_shifter;
symbol m_let;
symbol m_bang;
symbol m_forall;
symbol m_exists;
symbol m_lambda;
symbol m_as;
symbol m_not;
symbol m_root_obj;
symbol m_named;
symbol m_weight;
symbol m_qid;
symbol m_skid;
symbol m_pattern;
symbol m_nopattern;
symbol m_lblneg;
symbol m_lblpos;
symbol m_assert;
symbol m_check_sat;
symbol m_define_fun;
symbol m_define_const;
symbol m_model_add;
symbol m_model_del;
symbol m_declare_fun;
symbol m_declare_const;
symbol m_define_sort;
symbol m_declare_sort;
symbol m_declare_type_var;
symbol m_declare_datatypes;
symbol m_declare_datatype;
symbol m_par;
symbol m_push;
symbol m_pop;
symbol m_get_value;
symbol m_reset;
symbol m_check_sat_assuming;
symbol m_define_fun_rec;
symbol m_define_funs_rec;
symbol m_match;
symbol m_case;
symbol m_underscore;
typedef std::pair named_expr;
named_expr m_last_named_expr;
ast_manager & m() const { return m_ctx.m(); }
pdecl_manager & pm() const { return m_ctx.pm(); }
sexpr_manager & sm() const { return m_ctx.sm(); }
bool m_ignore_user_patterns;
bool m_ignore_bad_patterns;
bool m_display_error_for_vs;
bool ignore_user_patterns() const { return m_ignore_user_patterns; }
bool ignore_bad_patterns() const { return m_ignore_bad_patterns; }
bool use_vs_format() const { return m_display_error_for_vs; }
struct psort_frame {
psort_decl * m_decl;
unsigned m_spos; // position of m_psort_stack
psort_frame(parser & p, psort_decl * d, unsigned spos):
m_decl(d), m_spos(spos) {
}
};
typedef psort_frame sort_frame;
enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_MATCH, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN };
struct expr_frame {
expr_frame_kind m_kind;
expr_frame(expr_frame_kind k):m_kind(k) {}
};
struct app_frame : public expr_frame {
symbol m_f;
unsigned m_expr_spos;
unsigned m_param_spos;
bool m_as_sort;
app_frame(symbol const & f, unsigned expr_spos, unsigned param_spos, bool as_sort):
expr_frame(EF_APP),
m_f(f),
m_expr_spos(expr_spos),
m_param_spos(param_spos),
m_as_sort(as_sort) {}
};
struct quant_frame : public expr_frame {
quantifier_kind m_kind;
symbol m_qid;
symbol m_skid;
unsigned m_weight;
unsigned m_pat_spos;
unsigned m_nopat_spos;
unsigned m_sym_spos;
unsigned m_sort_spos;
unsigned m_expr_spos;
quant_frame(quantifier_kind k, unsigned pat_spos, unsigned nopat_spos, unsigned sym_spos, unsigned sort_spos, unsigned expr_spos):
expr_frame(EF_QUANT), m_kind(k), m_weight(1),
m_pat_spos(pat_spos), m_nopat_spos(nopat_spos),
m_sym_spos(sym_spos), m_sort_spos(sort_spos),
m_expr_spos(expr_spos) {}
};
struct match_frame : public expr_frame {
match_frame():expr_frame(EF_MATCH) {}
};
struct let_frame : public expr_frame {
bool m_in_decls;
unsigned m_sym_spos;
unsigned m_expr_spos;
let_frame(unsigned sym_spos, unsigned expr_spos):expr_frame(EF_LET), m_in_decls(true), m_sym_spos(sym_spos), m_expr_spos(expr_spos) {}
};
struct let_decl_frame : public expr_frame {
let_decl_frame():expr_frame(EF_LET_DECL) {}
};
struct attr_expr_frame : public expr_frame {
expr_frame * m_prev;
unsigned m_sym_spos;
unsigned m_expr_spos;
symbol m_last_symbol;
attr_expr_frame(expr_frame * prev, unsigned sym_spos, unsigned expr_spos):
expr_frame(EF_ATTR_EXPR),
m_prev(prev),
m_sym_spos(sym_spos),
m_expr_spos(expr_spos) {}
};
struct pattern_frame : public expr_frame {
unsigned m_expr_spos;
pattern_frame(unsigned expr_spos):
expr_frame(EF_PATTERN),
m_expr_spos(expr_spos) {
}
};
struct sexpr_frame {
unsigned m_spos; // position of m_sexpr_stack
sexpr_frame(unsigned spos):
m_spos(spos) {
}
};
void reset_stack() {
m_stack.reset();
}
psort_ref_vector & psort_stack() {
if (m_psort_stack.get() == nullptr)
m_psort_stack = alloc(psort_ref_vector, pm());
return *(m_psort_stack.get());
}
sort_ref_vector & sort_stack() {
if (m_sort_stack.get() == nullptr)
m_sort_stack = alloc(sort_ref_vector, m());
return *(m_sort_stack.get());
}
expr_ref_vector & expr_stack() {
if (m_expr_stack.get() == nullptr)
m_expr_stack = alloc(expr_ref_vector, m());
return *(m_expr_stack.get());
}
template
static unsigned size(scoped_ptr & v) {
return v.get() == nullptr ? 0 : v->size();
}
template
static void shrink(scoped_ptr & v, unsigned old_sz) {
if (v.get() == nullptr) {
SASSERT(old_sz == 0);
}
else {
v->shrink(old_sz);
}
}
expr_ref_vector & pattern_stack() {
if (m_pattern_stack.get() == nullptr)
m_pattern_stack = alloc(expr_ref_vector, m());
return *(m_pattern_stack.get());
}
expr_ref_vector & nopattern_stack() {
if (m_nopattern_stack.get() == nullptr)
m_nopattern_stack = alloc(expr_ref_vector, m());
return *(m_nopattern_stack.get());
}
svector & symbol_stack() {
return m_symbol_stack;
}
sexpr_ref_vector & sexpr_stack() {
if (m_sexpr_stack.get() == nullptr)
m_sexpr_stack = alloc(sexpr_ref_vector, sm());
return *(m_sexpr_stack.get());
}
arith_util & autil() {
if (m_arith_util.get() == nullptr)
m_arith_util = alloc(arith_util, m());
return *(m_arith_util.get());
}
datatype_util & dtutil() {
if (m_datatype_util.get() == nullptr)
m_datatype_util = alloc(datatype_util, m());
return *(m_datatype_util.get());
}
seq_util & sutil() {
if (m_seq_util.get() == nullptr)
m_seq_util = alloc(seq_util, m());
return *(m_seq_util.get());
}
bv_util & butil() {
if (m_bv_util.get() == nullptr)
m_bv_util = alloc(bv_util, m());
return *(m_bv_util.get());
}
pattern_validator & pat_validator() {
if (m_pattern_validator.get() == nullptr) {
m_pattern_validator = alloc(pattern_validator, m());
}
return *(m_pattern_validator.get());
}
var_shifter & shifter() {
if (m_var_shifter.get() == nullptr)
m_var_shifter = alloc(var_shifter, m());
return *(m_var_shifter.get());
}
unsigned m_cache_end;
std::vector m_cached_strings;
int m_num_open_paren;
void scan_core() {
m_cache_end = m_scanner.cache_size();
m_curr = m_scanner.scan();
}
void scan() {
switch (m_curr) {
case scanner::LEFT_PAREN: m_num_open_paren++; break;
case scanner::RIGHT_PAREN: m_num_open_paren--; break;
default: break;
}
scan_core();
}
void next() {
if (m_curr != scanner::EOF_TOKEN)
scan();
}
scanner::token curr() const { return m_curr; }
// consume garbage
// return true if managed to recover from the error...
bool sync_after_error() {
unsigned num_errors = 0;
while (num_errors < 100) {
try {
while (curr_is_rparen())
next();
if (m_num_open_paren < 0)
m_num_open_paren = 0;
if (curr() == scanner::EOF_TOKEN && m_num_open_paren == 0)
return true;
SASSERT(m_num_open_paren >= 0);
while (m_num_open_paren > 0 || !curr_is_lparen()) {
TRACE("sync", tout << "sync(): curr: " << curr() << "\n";
tout << "m_num_open_paren: " << m_num_open_paren << ", line: " << m_scanner.get_line() << ", pos: "
<< m_scanner.get_pos() << "\n";);
if (curr() == scanner::EOF_TOKEN) {
return false;
}
SASSERT(m_num_open_paren >= 0);
next();
SASSERT(m_num_open_paren >= -1);
if (m_num_open_paren < 0)
m_num_open_paren = 0;
SASSERT(m_num_open_paren >= 0);
}
return true;
}
catch (scanner_exception & ex) {
if (ex.has_pos())
error(ex.line(), ex.pos(), ex.msg());
++num_errors;
}
}
return false;
}
void check_next(scanner::token t, char const * msg) {
if (curr() == t) {
next();
return;
}
std::ostringstream str;
str << msg << " got " << curr_id();
throw parser_exception(str.str());
}
symbol const & curr_id() const { return m_scanner.get_id(); }
rational curr_numeral() const { return m_scanner.get_number(); }
unsigned curr_unsigned() {
rational n = curr_numeral();
if (!n.is_unsigned())
throw parser_exception("invalid indexed identifier, index is too big to fit in an unsigned machine integer");
return n.get_unsigned();
}
bool curr_is_identifier() const { return curr() == scanner::SYMBOL_TOKEN; }
bool curr_is_keyword() const { return curr() == scanner::KEYWORD_TOKEN; }
bool curr_is_string() const { return curr() == scanner::STRING_TOKEN; }
bool curr_is_lparen() const { return curr() == scanner::LEFT_PAREN; }
bool curr_is_rparen() const { return curr() == scanner::RIGHT_PAREN; }
bool curr_is_int() const { return curr() == scanner::INT_TOKEN; }
bool curr_is_float() const { return curr() == scanner::FLOAT_TOKEN; }
bool curr_is_bv() const { return curr() == scanner::BV_TOKEN; }
bool curr_id_is_underscore() const { SASSERT(curr_is_identifier()); return curr_id() == m_underscore; }
bool curr_id_is_as() const { SASSERT(curr_is_identifier()); return curr_id() == m_as; }
bool curr_id_is_reserved() const { return curr_id_is_underscore() || curr_id_is_as(); }
bool curr_id_is_match() const { SASSERT(curr_is_identifier()); return curr_id() == m_match; }
bool curr_id_is_case() const { return curr_id() == m_case; }
bool curr_id_is_forall() const { SASSERT(curr_is_identifier()); return curr_id() == m_forall; }
bool curr_id_is_exists() const { SASSERT(curr_is_identifier()); return curr_id() == m_exists; }
bool curr_id_is_lambda() const { SASSERT(curr_is_identifier()); return curr_id() == m_lambda; }
bool curr_id_is_bang() const { SASSERT(curr_is_identifier()); return curr_id() == m_bang; }
bool curr_id_is_let() const { SASSERT(curr_is_identifier()); return curr_id() == m_let; }
bool curr_id_is_root_obj() const { SASSERT(curr_is_identifier()); return curr_id() == m_root_obj; }
void check_lparen(char const * msg) { if (!curr_is_lparen()) throw parser_exception(msg); }
void check_lparen_next(char const * msg) { check_next(scanner::LEFT_PAREN, msg); }
void check_rparen_next(char const * msg) { check_next(scanner::RIGHT_PAREN, msg); }
void check_rparen(char const * msg) { if (!curr_is_rparen()) throw parser_exception(msg); }
void check_id_next(symbol const & id, char const * msg) {
if (!curr_is_identifier() || curr_id() != id)
throw parser_exception(msg);
next();
}
void check_underscore_next(char const * msg) { check_id_next(m_underscore, msg); }
void check_as_next(char const * msg) { check_id_next(m_as, msg); }
void check_identifier(char const * msg) { if (!curr_is_identifier()) throw parser_exception(msg); }
void check_nonreserved_identifier(char const * msg) { if (!curr_is_identifier() || curr_id_is_reserved()) throw parser_exception(msg); }
void check_keyword(char const * msg) { if (!curr_is_keyword()) throw parser_exception(msg); }
void check_string(char const * msg) { if (!curr_is_string()) throw parser_exception(msg); }
void check_int(char const * msg) { if (!curr_is_int()) throw parser_exception(msg); }
void check_int_or_float(char const * msg) { if (!curr_is_int() && !curr_is_float()) throw parser_exception(msg); }
void check_float(char const * msg) { if (!curr_is_float()) throw parser_exception(msg); }
symbol check_identifier_next(char const * msg) { check_identifier(msg); symbol s = curr_id(); next(); return s; }
char const * m_current_file;
void set_current_file(char const * s) { m_current_file = s; }
void error(unsigned line, unsigned pos, char const * msg) {
m_ctx.set_cancel(false);
if (use_vs_format()) {
m_ctx.diagnostic_stream() << "Z3(" << line << ", " << pos << "): ERROR: " << msg;
if (msg[strlen(msg)-1] != '\n')
m_ctx.diagnostic_stream() << std::endl;
}
else {
m_ctx.regular_stream() << "(error \"";
if (m_current_file) m_ctx.regular_stream() << m_current_file << ": ";
m_ctx.regular_stream()<< "line " << line << " column " << pos << ": " << escaped(msg, true) << "\")" << std::endl;
}
if (m_ctx.exit_on_error()) {
// WORKAROUND: ASan's LeakSanitizer reports many false positives when
// calling `exit()` so call `_Exit()` instead which avoids invoking leak
// checking.
_Exit(1);
}
}
void error(char const * msg) {
error(m_scanner.get_line(), m_scanner.get_pos(), msg);
}
void error_wo_pos(char const * msg) {
if (use_vs_format()) {
m_ctx.diagnostic_stream() << "Z3: ERROR: " << msg;
if (msg[strlen(msg)-1] != '\n')
m_ctx.diagnostic_stream() << std::endl;
}
else {
m_ctx.regular_stream() << "(error : " << escaped(msg, true) << "\")" << std::endl;
}
}
void unknown_sort(symbol id, char const* context = "") {
std::string msg = context;
if (context[0]) msg += ": ";
msg += "unknown sort '";
msg += id.str() + "'";
throw parser_exception(std::move(msg));
}
void consume_sexpr() {
unsigned num_parens = 0;
do {
switch (curr()) {
case scanner::LEFT_PAREN:
num_parens++;
break;
case scanner::RIGHT_PAREN:
if (num_parens == 0)
throw parser_exception("invalid s-expression, unexpected ')'");
num_parens--;
break;
case scanner::SYMBOL_TOKEN:
case scanner::KEYWORD_TOKEN:
case scanner::STRING_TOKEN:
case scanner::INT_TOKEN:
case scanner::FLOAT_TOKEN:
case scanner::BV_TOKEN:
break;
case scanner::EOF_TOKEN:
throw parser_exception("invalid s-expression, unexpected end of file");
break;
default:
throw parser_exception("invalid s-expression, unexpected input");
break;
}
next();
}
while (num_parens > 0);
}
void parse_sexpr() {
unsigned stack_pos = sexpr_stack().size();
(void)stack_pos;
unsigned num_frames = 0;
do {
unsigned line = m_scanner.get_line();
unsigned pos = m_scanner.get_pos();
switch (curr()) {
case scanner::LEFT_PAREN: {
void * mem = m_stack.allocate(sizeof(sexpr_frame));
new (mem) sexpr_frame(sexpr_stack().size());
num_frames++;
break;
}
case scanner::RIGHT_PAREN: {
if (num_frames == 0)
throw parser_exception("invalid s-expression, unexpected ')'");
num_frames--;
sexpr_frame * fr = static_cast(m_stack.top());
unsigned spos = fr->m_spos;
unsigned epos = sexpr_stack().size();
SASSERT(epos >= spos);
unsigned num = epos - spos;
sexpr * r = sm().mk_composite(num, sexpr_stack().data() + spos, line, pos);
sexpr_stack().shrink(spos);
sexpr_stack().push_back(r);
m_stack.deallocate(fr);
break;
}
case scanner::SYMBOL_TOKEN:
sexpr_stack().push_back(sm().mk_symbol(curr_id(), line, pos));
break;
case scanner::KEYWORD_TOKEN:
sexpr_stack().push_back(sm().mk_keyword(curr_id(), line, pos));
break;
case scanner::STRING_TOKEN:
sexpr_stack().push_back(sm().mk_string(m_scanner.get_string(), line, pos));
break;
case scanner::INT_TOKEN:
case scanner::FLOAT_TOKEN:
sexpr_stack().push_back(sm().mk_numeral(curr_numeral(), line, pos));
break;
case scanner::BV_TOKEN:
sexpr_stack().push_back(sm().mk_bv_numeral(curr_numeral(), m_scanner.get_bv_size(), line, pos));
break;
case scanner::EOF_TOKEN:
throw parser_exception("invalid s-expression, unexpected end of file");
break;
default:
throw parser_exception("invalid s-expression, unexpected input");
break;
}
next();
}
while (num_frames > 0);
SASSERT(sexpr_stack().size() == stack_pos + 1);
}
sort * parse_sort_name(char const* context = "") {
SASSERT(curr_is_identifier());
symbol id = curr_id();
psort_decl * d = m_ctx.find_psort_decl(id);
if (d == nullptr)
unknown_sort(id, context);
if (!d->has_var_params() && d->get_num_params() != 0)
throw parser_exception("sort constructor expects parameters");
sort * r = d->instantiate(pm());
if (r == nullptr)
throw parser_exception("invalid sort application");
next();
return r;
}
psort * parse_psort_name(bool ignore_unknown_sort = false) {
SASSERT(curr_is_identifier());
symbol id = curr_id();
psort_decl * d = m_ctx.find_psort_decl(id);
if (d != nullptr) {
if (!d->has_var_params() && d->get_num_params() != 0)
throw parser_exception("sort constructor expects parameters");
next();
return pm().mk_psort_app(d);
}
else {
int idx = 0;
if (m_sort_id2param_idx.find(id, idx)) {
next();
return pm().mk_psort_var(m_sort_id2param_idx.size(), idx);
}
else {
if (!ignore_unknown_sort) {
unknown_sort(id);
UNREACHABLE();
}
return nullptr;
}
}
}
sort * parse_indexed_sort() {
SASSERT(curr_is_identifier());
SASSERT(curr_id_is_underscore());
next();
symbol id = check_identifier_next("invalid indexed sort, symbol expected");
psort_decl * d = m_ctx.find_psort_decl(id);
if (d == nullptr)
unknown_sort(id);
sbuffer args;
while (!curr_is_rparen()) {
check_int("invalid indexed sort, integer or ')' expected");
unsigned u = curr_unsigned();
args.push_back(u);
next();
}
sort * r = d->instantiate(pm(), args.size(), args.data());
if (r == nullptr)
throw parser_exception("invalid sort application");
next();
return r;
}
void push_psort_app_frame() {
SASSERT(curr_is_identifier());
symbol id = curr_id();
psort_decl * d = m_ctx.find_psort_decl(id);
if (d == nullptr) {
unknown_sort(id);
}
next();
void * mem = m_stack.allocate(sizeof(psort_frame));
new (mem) psort_frame(*this, d, psort_stack().size());
}
void pop_psort_app_frame() {
SASSERT(curr_is_rparen());
psort_frame * fr = static_cast(m_stack.top());
psort_decl * d = fr->m_decl;
unsigned spos = fr->m_spos;
unsigned epos = psort_stack().size();
SASSERT(epos >= spos);
unsigned num = epos - spos;
if (!d->has_var_params() && d->get_num_params() != num) {
TRACE("smt2parser", tout << "num: " << num << ", d->get_num_params(): " << d->get_num_params() << "\n";);
throw parser_exception("invalid number of parameters to sort constructor");
}
psort * r = pm().mk_psort_app(m_sort_id2param_idx.size(), d, num, psort_stack().data() + spos);
psort_stack().shrink(spos);
psort_stack().push_back(r);
m_stack.deallocate(fr);
next();
}
void parse_psort(bool ignore_unknown_sort = false) {
unsigned stack_pos = psort_stack().size();
(void)stack_pos;
unsigned num_frames = 0;
do {
if (curr_is_identifier()) {
psort_stack().push_back(parse_psort_name(false));
}
else if (curr_is_rparen()) {
if (num_frames == 0)
throw parser_exception("invalid sort, unexpected ')'");
pop_psort_app_frame();
num_frames--;
}
else {
check_lparen_next("invalid sort, symbol, '_' or '(' expected");
if (!curr_is_identifier())
throw parser_exception("invalid sort, symbol or '_' expected");
if (curr_id_is_underscore()) {
psort_stack().push_back(pm().mk_psort_cnst(parse_indexed_sort()));
}
else {
push_psort_app_frame();
num_frames++;
}
}
}
while (num_frames > 0);
SASSERT(psort_stack().size() == stack_pos + 1);
}
void push_sort_app_frame() {
SASSERT(curr_is_identifier());
symbol id = curr_id();
psort_decl * d = m_ctx.find_psort_decl(id);
if (d == nullptr)
unknown_sort(id);
next();
void * mem = m_stack.allocate(sizeof(sort_frame));
new (mem) sort_frame(*this, d, sort_stack().size());
}
void pop_sort_app_frame() {
SASSERT(curr_is_rparen());
sort_frame * fr = static_cast(m_stack.top());
psort_decl * d = fr->m_decl;
unsigned spos = fr->m_spos;
unsigned epos = sort_stack().size();
SASSERT(epos >= spos);
unsigned num = epos - spos;
if (!d->has_var_params() && d->get_num_params() != num) {
TRACE("smt2parser", tout << "num: " << num << ", d->get_num_params(): " << d->get_num_params() << "\n";);
throw parser_exception("invalid number of parameters to sort constructor");
}
sort * r = d->instantiate(pm(), num, sort_stack().data() + spos);
if (r == nullptr)
throw parser_exception("invalid sort application");
sort_stack().shrink(spos);
sort_stack().push_back(r);
m_stack.deallocate(fr);
next();
}
void parse_sort(char const* context) {
unsigned stack_pos = sort_stack().size();
(void)stack_pos;
unsigned num_frames = 0;
do {
if (curr_is_identifier()) {
sort_stack().push_back(parse_sort_name(context));
}
else if (curr_is_rparen()) {
if (num_frames == 0) {
throw parser_exception(std::string(context) + " invalid sort, unexpected ')'");
}
pop_sort_app_frame();
num_frames--;
}
else {
check_lparen_next("invalid sort, symbol, '_' or '(' expected");
if (!curr_is_identifier())
throw parser_exception(std::string(context) + " invalid sort, symbol or '_' expected");
if (curr_id_is_underscore()) {
sort_stack().push_back(parse_indexed_sort());
}
else {
push_sort_app_frame();
num_frames++;
}
}
}
while (num_frames > 0);
SASSERT(sort_stack().size() == stack_pos + 1);
}
unsigned parse_sorts(char const* context) {
unsigned sz = 0;
check_lparen_next(context);
while (!curr_is_rparen()) {
parse_sort(context);
sz++;
}
next();
return sz;
}
unsigned parse_symbols() {
unsigned sz = 0;
check_lparen_next("invalid list of symbols, '(' expected");
while (!curr_is_rparen()) {
m_symbol_stack.push_back(check_identifier_next("invalid list of symbols, symbol or ')' expected"));
sz++;
}
next();
return sz;
}
ptype parse_ptype() {
SASSERT(curr_is_identifier());
psort * p = parse_psort_name(true);
ptype result;
if (p != nullptr) {
result = ptype(p);
}
else {
// parse_psort_name failed, identifier was not consumed.
int idx;
if (m_dt_name2idx.find(curr_id(), idx)) {
result = ptype(idx);
}
else {
result = ptype(curr_id());
}
SASSERT(curr_is_identifier());
next();
}
return result;
}
// [ '(' identifier sort ')' ]+
void parse_accessor_decls(paccessor_decl_ref_buffer & a_decls) {
while (!curr_is_rparen()) {
check_lparen_next("invalid datatype declaration, '(' or ')' expected");
symbol a_name = check_identifier_next("invalid accessor declaration, symbol (accessor name) expected");
if (curr_is_identifier()) {
a_decls.push_back(pm().mk_paccessor_decl(m_sort_id2param_idx.size(), a_name, parse_ptype()));
}
else {
parse_psort(true);
a_decls.push_back(pm().mk_paccessor_decl(m_sort_id2param_idx.size(), a_name, ptype(psort_stack().back())));
psort_stack().pop_back();
}
check_rparen_next("invalid accessor declaration, ')' expected");
}
}
// [ '(' identifier accessors ')' ]+
void parse_constructor_decls(pconstructor_decl_ref_buffer & ct_decls) {
while (!curr_is_rparen()) {
if (curr_is_identifier()) {
symbol ct_name = curr_id();
std::string r_str = "is-";
r_str += curr_id().str();
symbol r_name(r_str);
next();
TRACE("datatype_parser_bug", tout << ct_name << " " << r_name << "\n";);
ct_decls.push_back(pm().mk_pconstructor_decl(m_sort_id2param_idx.size(), ct_name, r_name, 0, nullptr));
}
else {
check_lparen_next("invalid datatype declaration, '(' or ')' expected");
check_identifier("invalid constructor declaration, symbol (constructor name) expected");
symbol ct_name = curr_id();
std::string r_str = "is-";
r_str += curr_id().str();
symbol r_name(r_str);
next();
paccessor_decl_ref_buffer new_a_decls(pm());
parse_accessor_decls(new_a_decls);
ct_decls.push_back(pm().mk_pconstructor_decl(m_sort_id2param_idx.size(), ct_name, r_name, new_a_decls.size(), new_a_decls.data()));
check_rparen_next("invalid constructor declaration, ')' expected");
}
}
if (ct_decls.empty())
throw parser_exception("invalid datatype declaration, datatype does not have any constructors");
}
void parse_declare_type_var() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_declare_type_var);
next();
check_nonreserved_identifier("invalid sort declaration, symbol expected");
symbol id = curr_id();
if (m_ctx.find_psort_decl(id) != nullptr)
throw parser_exception("invalid sort declaration, sort already declared/defined");
next();
check_rparen("invalid sort declaration, ')' expected");
psort_decl * decl = pm().mk_psort_type_var_decl(id);
m_ctx.insert(decl);
m_ctx.print_success();
next();
}
void parse_declare_datatypes() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_declare_datatypes);
next();
unsigned line = m_scanner.get_line();
unsigned pos = m_scanner.get_pos();
m_dt_name2idx.reset();
bool is_smt2_6 = parse_sort_decl_or_params();
unsigned i = 0;
pdatatype_decl_ref_buffer new_dt_decls(pm());
check_lparen_next("invalid datatype declaration, '(' expected");
pdatatype_decl_ref d(pm());
while (!curr_is_rparen()) {
pconstructor_decl_ref_buffer new_ct_decls(pm());
if (is_smt2_6) {
if (i >= m_dt_names.size()) {
throw parser_exception("invalid datatype declaration, too many data-type bodies defined");
}
symbol dt_name = m_dt_names[i];
parse_datatype_dec(nullptr, new_ct_decls);
d = pm().mk_pdatatype_decl(m_dt_name2arity.find(dt_name), dt_name, new_ct_decls.size(), new_ct_decls.data());
}
else {
check_lparen_next("invalid datatype declaration, '(' or ')' expected");
symbol dt_name = check_identifier_next("invalid datatype declaration, symbol (datatype name) expected");
m_dt_name2idx.insert(dt_name, i);
parse_constructor_decls(new_ct_decls);
d = pm().mk_pdatatype_decl(m_sort_id2param_idx.size(), dt_name, new_ct_decls.size(), new_ct_decls.data());
check_rparen_next("invalid datatype declaration, ')' expected");
}
new_dt_decls.push_back(d);
i++;
}
if (i < m_dt_names.size()) {
throw parser_exception("invalid datatype declaration, too few datatype definitions compared to declared sorts");
}
next();
check_rparen("invalid datatype declaration");
unsigned sz = new_dt_decls.size();
if (sz == 0) {
m_ctx.print_success();
next();
return;
}
else if (sz == 1) {
check_missing(new_dt_decls[0], line, pos);
new_dt_decls[0]->commit(pm());
}
else {
SASSERT(sz > 1);
pdatatypes_decl_ref dts(pm());
dts = pm().mk_pdatatypes_decl(m_sort_id2param_idx.size(), sz, new_dt_decls.data());
symbol missing;
if (!pm().fix_missing_refs(dts, missing)) {
std::string err_msg = "invalid datatype declaration, unknown sort '";
err_msg += missing.str();
err_msg += "'";
throw parser_exception(std::move(err_msg), line, pos);
}
dts->commit(pm());
m_ctx.insert_aux_pdecl(dts.get());
}
for (unsigned i = 0; i < sz; i++) {
pdatatype_decl * d = new_dt_decls[i];
symbol duplicated;
check_duplicate(d, line, pos);
if (!is_smt2_6) {
// datatypes are inserted up front in SMT2.6 mode, so no need to re-insert them.
m_ctx.insert(d);
}
}
TRACE("declare_datatypes", tout << "i: " << i << " new_dt_decls.size(): " << sz << "\n";
for (unsigned j = 0; j < new_dt_decls.size(); ++j) tout << new_dt_decls[j]->get_name() << "\n";);
m_ctx.print_success();
next();
}
// ( declare-datatype symbol datatype_dec)
void parse_declare_datatype() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_declare_datatype);
next();
unsigned line = m_scanner.get_line();
unsigned pos = m_scanner.get_pos();
symbol dt_name = curr_id();
check_identifier("unexpected token used as datatype name");
next();
m_dt_name2idx.reset();
m_dt_name2idx.insert(dt_name, 0);
m_sort_id2param_idx.reset();
pdatatype_decl_ref d(pm());
pconstructor_decl_ref_buffer new_ct_decls(pm());
parse_datatype_dec(&dt_name, new_ct_decls);
d = pm().mk_pdatatype_decl(m_sort_id2param_idx.size(), dt_name, new_ct_decls.size(), new_ct_decls.data());
check_missing(d, line, pos);
check_duplicate(d, line, pos);
d->commit(pm());
check_rparen("invalid end of datatype declaration, ')' expected");
m_ctx.print_success();
next();
}
// datatype_dec ::= ( constructor_dec+ ) | ( par ( symbol+ ) ( constructor_dec+ ) )
void parse_datatype_dec(symbol* dt_name, pconstructor_decl_ref_buffer & ct_decls) {
check_lparen_next("invalid datatype declaration, '(' expected");
if (curr_id() == m_par) {
next();
parse_sort_decl_params();
check_lparen_next("invalid constructor declaration after par, '(' expected");
unsigned sz = m_sort_id2param_idx.size();
if (sz > 0 && dt_name) {
m_ctx.insert(pm().mk_psort_dt_decl(sz, *dt_name));
}
parse_constructor_decls(ct_decls);
check_rparen_next("invalid datatype declaration, ')' expected");
}
else {
if (dt_name) {
m_ctx.insert(pm().mk_psort_dt_decl(0, *dt_name));
}
parse_constructor_decls(ct_decls);
}
check_rparen_next("invalid datatype declaration, ')' expected");
}
void check_missing(pdatatype_decl* d, unsigned line, unsigned pos) {
symbol missing;
if (d->has_missing_refs(missing)) {
std::string err_msg = "invalid datatype declaration, unknown sort '";
err_msg += missing.str();
err_msg += "'";
throw parser_exception(std::move(err_msg), line, pos);
}
}
void check_duplicate(pdatatype_decl* d, unsigned line, unsigned pos) {
symbol duplicated;
if (d->has_duplicate_accessors(duplicated)) {
std::string err_msg = "invalid datatype declaration, repeated accessor identifier '";
err_msg += duplicated.str();
err_msg += "'";
throw parser_exception(std::move(err_msg), line, pos);
}
}
void name_expr(expr * n, symbol const & s) {
TRACE("name_expr", tout << "naming: " << s << " ->\n" << mk_pp(n, m()) << "\n";);
if (!is_ground(n) && has_free_vars(n))
throw parser_exception("invalid named expression, expression contains free variables");
m_ctx.insert(s, 0, nullptr, n);
m_last_named_expr.first = s;
m_last_named_expr.second = n;
}
bool in_quant_ctx(attr_expr_frame * fr) {
return fr != nullptr && fr->m_prev != nullptr && fr->m_prev->m_kind == EF_QUANT;
}
void check_in_quant_ctx(attr_expr_frame * fr) {
if (!in_quant_ctx(fr))
throw parser_exception("invalid attribute, not in the scope of a quantifier");
}
void process_last_symbol(attr_expr_frame * fr) {
if (fr->m_last_symbol == symbol::null)
return;
if (fr->m_last_symbol == m_pattern) {
expr * pat = expr_stack().back();
if (pat == nullptr) {
if (!ignore_bad_patterns())
throw parser_exception("invalid empty pattern");
}
else {
if (!m().is_pattern(pat))
pat = m().mk_pattern(to_app(pat)); // unary pattern
SASSERT(m().is_pattern(pat));
pattern_stack().push_back(pat);
}
expr_stack().pop_back();
}
else if (fr->m_last_symbol == m_nopattern) {
nopattern_stack().push_back(expr_stack().back());
expr_stack().pop_back();
}
else {
UNREACHABLE();
}
}
void store_qid(attr_expr_frame * fr, symbol const & qid) {
SASSERT(in_quant_ctx(fr));
static_cast(fr->m_prev)->m_qid = qid;
}
void store_skid(attr_expr_frame * fr, symbol const & skid) {
SASSERT(in_quant_ctx(fr));
static_cast(fr->m_prev)->m_skid = skid;
}
void store_weight(attr_expr_frame * fr, unsigned w) {
SASSERT(in_quant_ctx(fr));
static_cast(fr->m_prev)->m_weight = w;
}
// parse expression state
enum pe_state {
PES_EXPR, // expecting
PES_DECL, // expecting ( )
PES_PATTERN,
PES_CONTINUE
};
pe_state consume_attributes(attr_expr_frame * fr) {
if (fr->m_expr_spos == expr_stack().size())
return PES_EXPR; // didn't parse the expression yet.
process_last_symbol(fr);
while (true) {
check_keyword("invalid attributed expression, keyword expected");
symbol id = curr_id();
fr->m_last_symbol = symbol::null;
TRACE("consume_attributes", tout << "id: " << id << ", expr_stack().size(): " << expr_stack().size() << "\n";);
if (id == m_named) {
next();
name_expr(expr_stack().back(), check_identifier_next("invalid attribute value, symbol expected"));
}
else if (id == m_lblpos || id == m_lblneg) {
next();
check_identifier("invalid attribute value, symbol expected");
if (!m().is_bool(expr_stack().back()))
throw parser_exception("invalid labeled expression, expression must have Bool sort");
expr * new_expr = m().mk_label(id == m_lblpos, curr_id(), expr_stack().back());
expr_stack().pop_back();
expr_stack().push_back(new_expr);
next();
}
else if (id == m_weight) {
check_in_quant_ctx(fr);
next();
check_int("invalid weight attribute, integer expected");
store_weight(fr, curr_unsigned());
next();
}
else if (id == m_skid) {
check_in_quant_ctx(fr);
next();
store_skid(fr, check_identifier_next("invalid attribute value, symbol expected"));
}
else if (id == m_qid) {
check_in_quant_ctx(fr);
next();
check_identifier("invalid attribute value, symbol expected");
store_qid(fr, curr_id());
next();
}
else if (id == m_pattern) {
if (!ignore_user_patterns()) {
check_in_quant_ctx(fr);
next();
fr->m_last_symbol = id;
return PES_PATTERN;
}
else {
// just consume pattern
next();
consume_sexpr();
}
}
else if (id == m_nopattern) {
if (!ignore_user_patterns()) {
check_in_quant_ctx(fr);
next();
fr->m_last_symbol = id;
return PES_EXPR;
}
else {
// just consume pattern
next();
consume_sexpr();
}
}
else {
std::ostringstream str;
str << "unknown attribute " << id;
auto msg = str.str();
warning_msg("%s", msg.c_str());
next();
// just consume the
consume_sexpr();
}
if (curr_is_rparen())
return PES_CONTINUE;
}
}
pe_state parse_expr_state() {
if (m_num_expr_frames == 0)
return PES_EXPR;
expr_frame * fr = static_cast(m_stack.top());
switch (fr->m_kind) {
case EF_LET:
return static_cast(fr)->m_in_decls ? PES_DECL : PES_EXPR;
case EF_ATTR_EXPR:
return consume_attributes(static_cast(fr));
default:
return PES_EXPR;
}
}
void parse_numeral(bool is_int) {
SASSERT(!is_int || curr_is_int());
SASSERT(is_int || curr_is_float());
TRACE("parse_numeral", tout << "curr(): " << curr() << ", curr_numeral(): " << curr_numeral() << ", is_int: " << is_int << "\n";);
expr_stack().push_back(autil().mk_numeral(curr_numeral(), is_int && !m_ctx.numeral_as_real()));
next();
}
void parse_bv_numeral() {
SASSERT(curr() == scanner::BV_TOKEN);
expr_stack().push_back(butil().mk_numeral(curr_numeral(), m_scanner.get_bv_size()));
TRACE("parse_bv_numeral", tout << "new numeral: " << mk_pp(expr_stack().back(), m()) << "\n";);
next();
}
void parse_string_const() {
SASSERT(curr() == scanner::STRING_TOKEN);
zstring zs(m_scanner.get_string());
expr_stack().push_back(sutil().str.mk_string(zs));
TRACE("smt2parser", tout << "new string: " << mk_pp(expr_stack().back(), m()) << "\n";);
next();
}
void push_pattern_frame() {
// TODO: It seems the only reliable way to parse patterns is:
// Parse as an S-Expr, then try to convert it to an useful pattern.
// If it is not possible, then discard pattern.
// After this modification, the (PROMOTE) hack below can be removed.
if (curr_is_lparen()) {
next();
}
else {
if (!ignore_bad_patterns())
throw parser_exception("invalid pattern, '(' expected");
consume_sexpr();
expr_stack().push_back(nullptr); // empty pattern
return;
}
if (curr_is_lparen()) {
// multi-pattern
void * mem = m_stack.allocate(sizeof(pattern_frame));
new (mem) pattern_frame(expr_stack().size());
m_num_expr_frames++;
}
else if (curr_is_rparen()) {
next();
expr_stack().push_back(nullptr); // empty pattern
}
else {
// unary pattern
// HACK: to consume & discard (PROMOTE)-like patterns that were incorrectly introduced in SMT-LIB 2.0
// when Simplify benchmarks were converted into SMT2 ones.
if (curr_is_identifier()) {
symbol id = curr_id();
func_decl * f = nullptr;
try {
f = m_ctx.find_func_decl(id);
}
catch (cmd_exception &) {
}
if (f && f->get_arity() == 0) {
if (!ignore_bad_patterns())
throw parser_exception("invalid constant pattern");
while (!curr_is_rparen())
consume_sexpr();
next();
expr_stack().push_back(nullptr); // empty pattern
return; // no frame is created
}
}
if (!curr_is_lparen() && !curr_is_identifier())
throw parser_exception("invalid pattern, '(' or identifier expected");
push_app_frame();
}
}
void push_let_decl_frame() {
check_lparen_next("invalid let declaration, '(' expected");
check_identifier("invalid let declaration, symbol expected");
symbol_stack().push_back(curr_id());
next();
void * mem = m_stack.allocate(sizeof(let_decl_frame));
new (mem) let_decl_frame();
m_num_expr_frames++;
}
unsigned parse_sorted_vars() {
unsigned num = 0;
unsigned sym_spos = symbol_stack().size();
unsigned sort_spos = sort_stack().size();
TRACE("parse_sorted_vars", tout << "[before] symbol_stack().size(): " << symbol_stack().size() << "\n";);
check_lparen_next("invalid list of sorted variables, '(' expected");
m_env.begin_scope();
while (!curr_is_rparen()) {
check_lparen_next("invalid sorted variable, '(' expected");
check_identifier("invalid sorted variable, symbol expected");
symbol_stack().push_back(curr_id());
TRACE("parse_sorted_vars", tout << "push_back curr_id(): " << curr_id() << "\n";);
next();
parse_sort("invalid sorted variables");
check_rparen_next("invalid sorted variable, ')' expected");
num++;
}
next();
TRACE("parse_sorted_vars", tout << "[after] symbol_stack().size(): " << symbol_stack().size() << "\n";);
symbol const * sym_it = symbol_stack().data() + sym_spos;
sort * const * sort_it = sort_stack().data() + sort_spos;
m_num_bindings += num;
unsigned i = num;
while (i > 0) {
--i;
var * v = m().mk_var(i, *sort_it);
expr_stack().push_back(v); // prevent v from being deleted
TRACE("parse_sorted_vars", tout << "registering " << *sym_it << " -> " << mk_pp(v, m()) << ", num: " << num << ", i: " << i << "\n";);
m_env.insert(*sym_it, local(v, m_num_bindings));
SASSERT(m_env.contains(*sym_it));
++sort_it;
++sym_it;
}
return num;
}
void push_let_frame() {
next();
check_lparen_next("invalid let declaration, '(' expected");
void * mem = m_stack.allocate(sizeof(let_frame));
new (mem) let_frame(symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
}
void push_bang_frame(expr_frame * curr) {
TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";);
next();
void * mem = m_stack.allocate(sizeof(attr_expr_frame));
new (mem) attr_expr_frame(curr, symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
}
void push_quant_frame(quantifier_kind k) {
SASSERT(curr_is_identifier());
SASSERT(curr_id_is_forall() || curr_id_is_exists() || curr_id_is_lambda());
SASSERT((k == forall_k) == curr_id_is_forall());
SASSERT((k == exists_k) == curr_id_is_exists());
SASSERT((k == lambda_k) == curr_id_is_lambda());
next();
void * mem = m_stack.allocate(sizeof(quant_frame));
new (mem) quant_frame(k, pattern_stack().size(), nopattern_stack().size(), symbol_stack().size(),
sort_stack().size(), expr_stack().size());
m_num_expr_frames++;
unsigned num_vars = parse_sorted_vars();
if (num_vars == 0)
throw parser_exception("invalid quantifier, list of sorted variables is empty");
}
/**
* SMT-LIB 2.6 pattern matches are of the form
*
* (match t ((p1 t1) ... (pm+1 tm+1)))
*
* precursor form is
*
* (match t (case p1 t1) (case p2 t2) ... )
*
*/
void push_match_frame() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_match);
next();
void * mem = m_stack.allocate(sizeof(match_frame));
new (mem) match_frame();
unsigned num_frames = m_num_expr_frames;
parse_expr();
expr_ref t(expr_stack().back(), m());
expr_stack().pop_back();
expr_ref_vector patterns(m()), cases(m());
sort* srt = t->get_sort();
check_lparen_next("pattern bindings should be enclosed in a parenthesis");
if (curr_id_is_case()) {
while (curr_id_is_case()) {
next();
m_env.begin_scope();
unsigned num_bindings = m_num_bindings;
parse_match_pattern(srt);
patterns.push_back(expr_stack().back());
expr_stack().pop_back();
parse_expr();
cases.push_back(expr_stack().back());
expr_stack().pop_back();
m_num_bindings = num_bindings;
m_env.end_scope();
check_rparen_next("invalid pattern binding, ')' expected");
if (curr_is_lparen()) {
next();
}
}
}
else {
while (!curr_is_rparen()) {
m_env.begin_scope();
check_lparen_next("invalid pattern binding, '(' expected");
unsigned num_bindings = m_num_bindings;
parse_match_pattern(srt);
patterns.push_back(expr_stack().back());
expr_stack().pop_back();
parse_expr();
cases.push_back(expr_stack().back());
expr_stack().pop_back();
m_num_bindings = num_bindings;
m_env.end_scope();
check_rparen_next("invalid pattern binding, ')' expected");
}
next();
}
m_num_expr_frames = num_frames + 1;
expr_stack().push_back(compile_patterns(t, patterns, cases));
}
void pop_match_frame(match_frame* fr) {
m_stack.deallocate(fr);
m_num_expr_frames--;
}
expr_ref compile_patterns(expr* t, expr_ref_vector const& patterns, expr_ref_vector const& cases) {
expr_ref result(m());
var_subst sub(m(), false);
TRACE("parse_expr", tout << "term\n" << expr_ref(t, m()) << "\npatterns\n" << patterns << "\ncases\n" << cases << "\n";);
check_patterns(patterns, t->get_sort());
for (unsigned i = patterns.size(); i > 0; ) {
--i;
expr_ref_vector subst(m());
expr_ref cond = bind_match(t, patterns[i], subst);
expr_ref new_case(m());
if (subst.empty()) {
new_case = cases[i];
}
else {
new_case = sub(cases[i], subst.size(), subst.data());
inv_var_shifter inv(m());
inv(new_case, subst.size(), new_case);
}
if (result) {
result = m().mk_ite(cond, new_case, result);
}
else {
// pattern match binding is ignored.
result = new_case;
}
}
TRACE("parse_expr", tout << result << "\n";);
return result;
}
void check_patterns(expr_ref_vector const& patterns, sort* s) {
if (!dtutil().is_datatype(s))
throw parser_exception("pattern matching is only supported for algebraic datatypes");
ptr_vector const& cons = *dtutil().get_datatype_constructors(s);
for (expr * arg : patterns) if (is_var(arg)) return;
if (patterns.size() < cons.size())
throw parser_exception("non-exhaustive pattern match");
ast_fast_mark1 marked;
for (expr * arg : patterns)
marked.mark(to_app(arg)->get_decl(), true);
for (func_decl * f : cons)
if (!marked.is_marked(f))
throw parser_exception("a constructor is missing from pattern match");
}
// compute match condition and substitution
// t is shifted by size of subst.
expr_ref bind_match(expr* t, expr* pattern, expr_ref_vector& subst) {
if (t->get_sort() != pattern->get_sort()) {
std::ostringstream str;
str << "sorts of pattern " << expr_ref(pattern, m()) << " and term "
<< expr_ref(t, m()) << " are not aligned";
throw parser_exception(str.str());
}
expr_ref tsh(m());
if (is_var(pattern)) {
shifter()(t, 1, tsh);
subst.push_back(tsh);
return expr_ref(m().mk_true(), m());
}
else {
SASSERT(is_app(pattern));
func_decl * f = to_app(pattern)->get_decl();
func_decl * r = dtutil().get_constructor_is(f);
ptr_vector const * acc = dtutil().get_constructor_accessors(f);
shifter()(t, acc->size(), tsh);
for (func_decl* a : *acc) {
subst.push_back(m().mk_app(a, tsh));
}
return expr_ref(m().mk_app(r, t), m());
}
}
/**
* parse a match pattern
* (C x1 .... xn)
* C
* _
* x
*/
void parse_match_pattern(sort * srt) {
symbol C;
svector vars;
expr_ref_vector args(m());
if (curr_is_identifier()) {
C = curr_id();
}
else if (curr_is_lparen()) {
next();
C = check_identifier_next("constructor symbol expected");
while (!curr_is_rparen()) {
symbol v(check_identifier_next("variable symbol expected"));
if (v != m_underscore && vars.contains(v)) {
throw parser_exception("unexpected repeated variable in pattern expression");
}
vars.push_back(v);
}
}
else {
throw parser_exception("expecting a constructor, _, variable or constructor application");
}
next();
// now have C, vars
// look up constructor C,
// create bound variables based on constructor type.
// store expression in expr_stack().
// ensure that bound variables are adjusted to vars
func_decl* f = nullptr;
try {
f = m_ctx.find_func_decl(C, 0, nullptr, vars.size(), nullptr, srt);
}
catch (cmd_exception &) {
if (!vars.empty()) {
throw;
}
}
if (!f && !vars.empty()) {
throw parser_exception("expecting a constructor that has been declared");
}
if (!f) {
m_num_bindings++;
var * v = m().mk_var(0, srt);
if (C != m_underscore) {
m_env.insert(C, local(v, m_num_bindings));
}
expr_stack().push_back(v);
return;
}
if (!dtutil().is_constructor(f)) {
throw parser_exception("expecting a constructor");
}
if (f->get_arity() != vars.size()) {
throw parser_exception("mismatching number of variables supplied to constructor");
}
m_num_bindings += vars.size();
for (unsigned i = 0; i < vars.size(); ++i) {
var * v = m().mk_var(i, f->get_domain(i));
args.push_back(v);
if (vars[i] != m_underscore) {
m_env.insert(vars[i], local(v, m_num_bindings));
}
}
expr_stack().push_back(m().mk_app(f, args.size(), args.data()));
}
symbol parse_indexed_identifier_core() {
check_underscore_next("invalid indexed identifier, '_' expected");
check_identifier("invalid indexed identifier, symbol expected");
symbol r = curr_id();
next();
while (!curr_is_rparen()) {
if (curr_is_int() || curr_is_bv()) {
if (!curr_numeral().is_unsigned()) {
m_param_stack.push_back(parameter(curr_numeral()));
}
else {
m_param_stack.push_back(parameter(curr_unsigned()));
}
next();
}
else if (curr_is_float()) {
m_param_stack.push_back(parameter(curr_numeral()));
next();
}
else if (curr_is_keyword()) {
m_param_stack.push_back(parameter(curr_id()));
next();
}
else if (curr_is_identifier() || curr_is_lparen()) {
m_param_stack.push_back(parameter(parse_func_decl_ref()));
}
else {
throw parser_exception("invalid indexed identifier, integer, identifier or '(' expected");
}
}
next();
return r;
}
symbol parse_indexed_identifier() {
if (curr_is_identifier()) {
symbol r = curr_id();
next();
return r;
}
check_lparen_next("invalid (indexed) identifier, '(_' or symbol expected");
return parse_indexed_identifier_core();
}
// parse:
// 'as' ')'
// '_' + ')'
// 'as' '(' '_' (|)+ ')' ')'
symbol parse_qualified_identifier_core(bool & has_as) {
SASSERT(curr_is_identifier());
SASSERT(curr_id_is_underscore() || curr_id_is_as());
if (curr_id_is_underscore()) {
has_as = false;
return parse_indexed_identifier_core();
}
else {
SASSERT(curr_id_is_as());
has_as = true;
next();
symbol r = parse_indexed_identifier();
parse_sort("Invalid qualified identifier");
check_rparen_next("invalid qualified identifier, ')' expected");
return r;
}
}
// parse:
//
// '(' 'as' ')'
// '(' '_' + ')'
// '(' 'as' (|)+ ')' ')'
symbol parse_qualified_identifier(bool & has_as) {
SASSERT(curr_is_lparen() || curr_is_identifier());
if (curr_is_identifier()) {
has_as = false;
symbol r = curr_id();
next();
return r;
}
SASSERT(curr_is_lparen());
next();
if (!curr_is_identifier() || (!curr_id_is_underscore() && !curr_id_is_as()))
throw parser_exception("invalid qualified/indexed identifier, '_' or 'as' expected");
return parse_qualified_identifier_core(has_as);
}
void unknown_var_const_name(symbol id) {
std::string msg = "unknown constant/variable '";
msg += id.str() + "'";
throw parser_exception(std::move(msg));
}
rational m_last_bv_numeral; // for bv, bvbin, bvhex
// return true if *s == [0-9]+
bool is_bv_decimal(char const * s) {
TRACE("is_bv_num", tout << "is_bv_decimal: " << s << "\n";);
SASSERT('0' <= *s && *s <= '9');
rational & n = m_last_bv_numeral;
n = rational(*s - '0');
++s;
while ('0' <= *s && *s <= '9') {
n *= rational(10);
n += rational(*s - '0');
++s;
}
if (*s != 0)
return false;
return true;
}
// return true if *s == bin[0-1]+
bool is_bv_binary(char const * s) {
SASSERT(*s == 'b');
++s;
if (*s != 'i') return false;
++s;
if (*s != 'n') return false;
++s;
rational & n = m_last_bv_numeral;
unsigned i = 0;
n = rational(0);
while (*s == '0' || *s == '1') {
n *= rational(2);
n += rational(*s - '0');
++s;
++i;
}
if (*s != 0 || i == 0)
return false;
return true;
}
// return true if *s == hex[0-9,a-f,A-F]+
bool is_bv_hex(char const * s) {
SASSERT(*s == 'h');
++s;
if (*s != 'e') return false;
++s;
if (*s != 'x') return false;
++s;
rational & n = m_last_bv_numeral;
unsigned i = 0;
n = rational(0);
while (true) {
if ('0' <= *s && *s <= '9') {
n *= rational(16);
n += rational(*s - '0');
}
else if ('a' <= *s && *s <= 'f') {
n *= rational(16);
n += rational(10 + (*s - 'a'));
}
else if ('A' <= *s && *s <= 'F') {
n *= rational(16);
n += rational(10 + (*s - 'A'));
}
else if (*s == 0) {
return i > 0;
}
else {
return false;
}
++s;
++i;
}
}
// Return true if
// n == bv[0-9]+ OR
// n == bvhex[0-9,a-f,A-F]+ OR
// n == bvbin[0-1]+
// It store the bit-vector value in m_last_bv_numeral
bool is_bv_num(symbol const & n) {
char const * s = n.bare_str();
if (*s != 'b') return false;
s++;
if (*s != 'v') return false;
s++;
if ('0' <= *s && *s <= '9')
return is_bv_decimal(s);
else if (*s == 'b')
return is_bv_binary(s);
else if (*s == 'h')
return is_bv_hex(s);
else
return false;
}
void push_local(local const & l) {
if (is_ground(l.m_term) || l.m_level == m_num_bindings) {
expr_stack().push_back(l.m_term);
}
else {
SASSERT(l.m_level <= m_num_bindings);
expr_ref new_term(m());
shifter()(l.m_term, m_num_bindings - l.m_level, new_term);
expr_stack().push_back(new_term);
}
}
// parse as expression
void parse_expr_name() {
SASSERT(curr_is_identifier());
symbol n = curr_id();
local l;
if (m_env.find(n, l)) {
push_local(l);
}
else {
expr_ref t_ref(m());
m_ctx.mk_const(n, t_ref);
expr_stack().push_back(t_ref.get());
}
next();
}
// if has_as == true, then the sort of t must be equal to sort_stack().pop_back()
// if that is the case, pop the top of sort_stack()
void check_qualifier(expr * t, bool has_as) {
if (has_as) {
sort * s = sort_stack().back();
if (s != t->get_sort())
throw parser_exception("invalid qualified identifier, sort mismatch");
sort_stack().pop_back();
}
}
// parse
// 'as' ')'
// '_' + ')'
// 'as' '(' (|)+ ')' ')'
void parse_qualified_name() {
SASSERT(curr_is_identifier());
SASSERT(curr_id_is_as() || curr_id_is_underscore());
TRACE("parse_qualified_name", tout << "parse_qualified_name() curr_id: " << curr_id() << "\n";);
unsigned param_spos = m_param_stack.size();
bool has_as;
symbol r = parse_qualified_identifier_core(has_as);
TRACE("parse_qualified_name", tout << "parse_qualified_name() r: " << r << "\n";);
expr * t;
local l;
if (m_env.find(r, l)) {
push_local(l);
t = expr_stack().back();
check_qualifier(t, has_as);
if (m_param_stack.size() != param_spos)
throw parser_exception("invalid indexed identifier, symbol is a local declaration");
return;
}
unsigned num_indices = m_param_stack.size() - param_spos;
if (is_bv_num(r)) {
if (num_indices != 1 || !m_param_stack.back().is_int())
throw parser_exception("invalid bit-vector constant, index expected");
unsigned bv_size = m_param_stack.back().get_int();
m_param_stack.pop_back();
t = butil().mk_numeral(m_last_bv_numeral, bv_size);
expr_stack().push_back(t);
check_qualifier(t, has_as);
return;
}
expr_ref t_ref(m());
m_ctx.mk_app(r, 0, nullptr, num_indices, m_param_stack.data() + param_spos, has_as ? sort_stack().back() : nullptr, t_ref);
m_param_stack.shrink(param_spos);
expr_stack().push_back(t_ref.get());
if (has_as) {
check_qualifier(t_ref.get(), has_as);
}
}
void parse_root_obj() {
SASSERT(curr_is_identifier());
SASSERT(curr_id_is_root_obj());
next();
parse_sexpr();
sexpr * p = sexpr_stack().back();
check_int("invalid root-obj, (unsigned) integer expected");
rational idx = curr_numeral();
if (!idx.is_unsigned())
throw parser_exception("invalid root-obj, index must fit in an unsigned machine integer");
unsigned u_idx = idx.get_unsigned();
if (u_idx == 0)
throw parser_exception("invalid root-obj, index must be >= 1");
next();
check_rparen_next("invalid root-obj, ')' expected");
expr_stack().push_back(autil().mk_numeral(p, u_idx));
sexpr_stack().pop_back();
}
void push_app_frame() {
SASSERT(curr_is_lparen() || curr_is_identifier());
unsigned param_spos = m_param_stack.size();
unsigned expr_spos = expr_stack().size();
bool has_as;
symbol f = parse_qualified_identifier(has_as);
void * mem = m_stack.allocate(sizeof(quant_frame));
new (mem) app_frame(f, expr_spos, param_spos, has_as);
m_num_expr_frames++;
}
void push_expr_frame(expr_frame * curr) {
SASSERT(curr_is_lparen());
next();
TRACE("push_expr_frame", tout << "push_expr_frame(), curr(): " << m_curr << "\n";);
if (curr_is_identifier()) {
TRACE("push_expr_frame", tout << "push_expr_frame(), curr_id(): " << curr_id() << "\n";);
if (curr_id_is_let()) {
push_let_frame();
}
else if (curr_id_is_forall()) {
push_quant_frame(forall_k);
}
else if (curr_id_is_exists()) {
push_quant_frame(exists_k);
}
else if (curr_id_is_lambda()) {
push_quant_frame(lambda_k);
}
else if (curr_id_is_bang()) {
push_bang_frame(curr);
}
else if (curr_id_is_as() || curr_id_is_underscore()) {
parse_qualified_name();
}
else if (curr_id_is_root_obj()) {
parse_root_obj();
}
else if (curr_id_is_match()) {
push_match_frame();
}
else {
push_app_frame();
}
}
else if (curr_is_lparen()) {
push_app_frame();
}
else {
throw parser_exception("invalid expression, '(' or symbol expected");
}
}
void pop_app_frame(app_frame * fr) {
SASSERT(expr_stack().size() >= fr->m_expr_spos);
SASSERT(m_param_stack.size() >= fr->m_param_spos);
if (expr_stack().size() == fr->m_expr_spos)
throw parser_exception("invalid function application, arguments missing");
unsigned num_args = expr_stack().size() - fr->m_expr_spos;
unsigned num_indices = m_param_stack.size() - fr->m_param_spos;
expr_ref t_ref(m());
local l;
if (m_env.find(fr->m_f, l)) {
push_local(l);
t_ref = expr_stack().back();
for (unsigned i = 0; i < num_args; ++i) {
expr* arg = expr_stack().get(fr->m_expr_spos + i);
expr* args[2] = { t_ref.get(), arg };
m_ctx.mk_app(symbol("select"),
2,
args,
0,
nullptr,
nullptr,
t_ref);
}
}
else {
m_ctx.mk_app(fr->m_f,
num_args,
expr_stack().data() + fr->m_expr_spos,
num_indices,
m_param_stack.data() + fr->m_param_spos,
fr->m_as_sort ? sort_stack().back() : nullptr,
t_ref);
}
expr_stack().shrink(fr->m_expr_spos);
m_param_stack.shrink(fr->m_param_spos);
if (fr->m_as_sort)
sort_stack().pop_back();
TRACE("pop_app_frame", tout << "new term: " << mk_pp(t_ref, m()) << "\n";);
expr_stack().push_back(t_ref.get());
m_stack.deallocate(fr);
m_num_expr_frames--;
}
void pop_let_frame(let_frame * fr) {
if (fr->m_in_decls) {
m_env.begin_scope();
fr->m_in_decls = false;
SASSERT(symbol_stack().size() >= fr->m_sym_spos);
SASSERT(expr_stack().size() >= fr->m_expr_spos);
if (symbol_stack().size() - fr->m_sym_spos != expr_stack().size() - fr->m_expr_spos) {
throw parser_exception("malformed let expression");
}
unsigned num_decls = expr_stack().size() - fr->m_expr_spos;
symbol * sym_it = symbol_stack().data() + fr->m_sym_spos;
expr ** expr_it = expr_stack().data() + fr->m_expr_spos;
expr ** expr_end = expr_it + num_decls;
for (; expr_it != expr_end; ++expr_it, ++sym_it) {
if (!(*expr_it))
throw parser_exception("invalid let expression");
TRACE("let_frame", tout << "declaring: " << *sym_it << " " << mk_pp(*expr_it, m()) << "\n";);
m_env.insert(*sym_it, local(*expr_it, m_num_bindings));
}
}
else {
// the resultant expression is on the top of the stack
TRACE("let_frame", tout << "let result expr: " << mk_pp(expr_stack().back(), m()) << "\n";);
expr_ref r(m());
if (expr_stack().size() < fr->m_expr_spos + 1)
throw parser_exception("invalid let expression");
r = expr_stack().back();
expr_stack().pop_back();
// remove local declarations from the stack
symbol_stack().shrink(fr->m_sym_spos);
expr_stack().shrink(fr->m_expr_spos);
m_env.end_scope();
// put result back on the stack
expr_stack().push_back(r.get());
m_stack.deallocate(fr);
m_num_expr_frames--;
}
}
void pop_quant_frame(quant_frame * fr) {
SASSERT(pattern_stack().size() >= fr->m_pat_spos);
SASSERT(nopattern_stack().size() >= fr->m_nopat_spos);
SASSERT(symbol_stack().size() >= fr->m_sym_spos);
SASSERT(sort_stack().size() >= fr->m_sort_spos);
SASSERT(symbol_stack().size() - fr->m_sym_spos == sort_stack().size() - fr->m_sort_spos);
SASSERT(expr_stack().size() >= fr->m_expr_spos);
unsigned num_decls = sort_stack().size() - fr->m_sort_spos;
if (expr_stack().size() - fr->m_expr_spos != num_decls /* variables */ + 1 /* result */)
//throw parser_exception("invalid quantified expression, syntax error: (forall|exists|lambda (( )*) ) expected");
throw parser_exception("invalid quantified expression, syntax error: (forall|exists (( )*) ) expected");
unsigned begin_pats = fr->m_pat_spos;
unsigned end_pats = pattern_stack().size();
unsigned j = begin_pats;
for (unsigned i = begin_pats; i < end_pats; i++) {
expr * pat = pattern_stack().get(i);
if (!pat_validator()(num_decls, pat, m_scanner.get_line(), m_scanner.get_pos())) {
if (!ignore_bad_patterns())
throw parser_exception("invalid pattern");
continue;
}
pattern_stack().set(j, pat);
j++;
}
end_pats = j;
pattern_stack().shrink(end_pats);
unsigned num_pats = end_pats - begin_pats;
unsigned num_nopats = nopattern_stack().size() - fr->m_nopat_spos;
TRACE("parse_quantifier", tout << "weight: " << fr->m_weight << "\n";);
TRACE("skid", tout << "fr->m_skid: " << fr->m_skid << "\n";);
TRACE("parse_quantifier", tout << "body:\n" << mk_pp(expr_stack().back(), m()) << "\n";);
if (fr->m_qid == symbol::null)
fr->m_qid = symbol((unsigned)m_scanner.get_line());
if (fr->m_kind != lambda_k && !m().is_bool(expr_stack().back()))
throw parser_exception("quantifier body must be a Boolean expression");
quantifier* new_q = m().mk_quantifier(fr->m_kind,
num_decls,
sort_stack().data() + fr->m_sort_spos,
symbol_stack().data() + fr->m_sym_spos,
expr_stack().back(),
fr->m_weight,
fr->m_qid,
fr->m_skid,
num_pats, pattern_stack().data() + fr->m_pat_spos,
num_nopats, nopattern_stack().data() + fr->m_nopat_spos
);
TRACE("mk_quantifier", tout << "id: " << new_q->get_id() << "\n" << mk_ismt2_pp(new_q, m()) << "\n";);
TRACE("skid", tout << "new_q->skid: " << new_q->get_skid() << "\n";);
expr_stack().shrink(fr->m_expr_spos);
pattern_stack().shrink(fr->m_pat_spos);
nopattern_stack().shrink(fr->m_nopat_spos);
symbol_stack().shrink(fr->m_sym_spos);
sort_stack().shrink(fr->m_sort_spos);
m_env.end_scope();
SASSERT(num_decls <= m_num_bindings);
m_num_bindings -= num_decls;
expr_stack().push_back(new_q);
m_stack.deallocate(fr);
m_num_expr_frames--;
}
void pop_attr_expr_frame(attr_expr_frame * fr) {
process_last_symbol(fr);
TRACE("consume_attributes", tout << "pop_attr_expr_frame, expr_stack.size(): " << expr_stack().size() << "\n";);
// the resultant expression is already on the top of the stack.
if (expr_stack().size() != fr->m_expr_spos + 1)
throw parser_exception("invalid expression");
m_stack.deallocate(fr);
m_num_expr_frames--;
}
void pop_pattern_frame(pattern_frame * fr) {
SASSERT(expr_stack().size() >= fr->m_expr_spos);
if (expr_stack().size() == fr->m_expr_spos) {
if (!ignore_bad_patterns())
throw parser_exception("invalid empty pattern");
// ignoring empty pattern
expr_stack().shrink(fr->m_expr_spos);
}
else {
unsigned num = expr_stack().size() - fr->m_expr_spos;
expr * new_pat = m().mk_pattern(num, reinterpret_cast(expr_stack().data() + fr->m_expr_spos));
expr_stack().shrink(fr->m_expr_spos);
expr_stack().push_back(new_pat);
}
m_stack.deallocate(fr);
m_num_expr_frames--;
}
void pop_expr_frame() {
SASSERT(curr_is_rparen());
expr_frame * fr = static_cast(m_stack.top());
switch (fr->m_kind) {
case EF_APP:
pop_app_frame(static_cast(fr));
break;
case EF_LET:
pop_let_frame(static_cast(fr));
break;
case EF_LET_DECL:
m_stack.deallocate(static_cast(fr));
m_num_expr_frames--;
break;
case EF_MATCH:
pop_match_frame(static_cast(fr));
break;
case EF_QUANT:
pop_quant_frame(static_cast(fr));
break;
case EF_ATTR_EXPR:
pop_attr_expr_frame(static_cast(fr));
break;
case EF_PATTERN:
pop_pattern_frame(static_cast(fr));
break;
default:
UNREACHABLE();
}
SASSERT(curr_is_rparen());
next(); // consume ')'
}
void parse_expr() {
m_num_expr_frames = 0;
do {
TRACE("parse_expr", tout << "curr(): " << curr() << ", m_num_expr_frames: " << m_num_expr_frames
<< ", expr_stack().size(): " << expr_stack().size() << "\n";);
if (curr_is_rparen()) {
if (m_num_expr_frames == 0)
throw parser_exception("invalid expression, unexpected ')'");
pop_expr_frame();
}
else {
pe_state st = parse_expr_state();
TRACE("consume_attributes", tout << "parse_expr_state: " << st << ", expr_stack.size(): " << expr_stack().size() << "\n";);
switch (st) {
case PES_EXPR:
switch (curr()) {
case scanner::SYMBOL_TOKEN:
parse_expr_name();
break;
case scanner::INT_TOKEN:
parse_numeral(true);
break;
case scanner::FLOAT_TOKEN:
parse_numeral(false);
break;
case scanner::BV_TOKEN:
parse_bv_numeral();
break;
case scanner::LEFT_PAREN:
push_expr_frame(m_num_expr_frames == 0 ? nullptr : static_cast(m_stack.top()));
break;
case scanner::KEYWORD_TOKEN:
throw parser_exception("invalid expression, unexpected keyword");
case scanner::STRING_TOKEN:
parse_string_const();
break;
default:
throw parser_exception("invalid expression, unexpected input");
}
break;
case PES_DECL:
push_let_decl_frame();
break;
case PES_PATTERN:
push_pattern_frame();
break;
case PES_CONTINUE:
// do nothing
break;
default:
UNREACHABLE();
break;
}
}
}
while (m_num_expr_frames > 0 );
SASSERT(!expr_stack().empty());
}
unsigned parse_exprs() {
unsigned sz = 0;
check_lparen_next("invalid list of terms, '(' expected");
while (!curr_is_rparen()) {
parse_expr();
sz++;
}
next();
return sz;
}
void parse_sort_decl_params() {
m_sort_id2param_idx.reset();
check_lparen_next("invalid sort declaration, parameters missing");
unsigned i = 0;
while (!curr_is_rparen()) {
check_nonreserved_identifier("invalid sort parameter, symbol or ')' expected");
m_sort_id2param_idx.insert(curr_id(), i);
i++;
next();
}
next();
}
bool parse_sort_decl_or_params() {
m_sort_id2param_idx.reset();
m_dt_name2arity.reset();
m_dt_name2idx.reset();
m_dt_names.reset();
check_lparen_next("invalid sort declaration, parameters missing");
unsigned i = 0;
bool first = true;
bool is_decl = false;
while (!curr_is_rparen()) {
if (first) {
is_decl = curr_is_lparen();
first = false;
}
if (is_decl) {
check_lparen_next("invalid sort declaration, '(' expected");
symbol dt_name = check_identifier_next("invalid sort name, identified expected");
check_int("invalid sort declaration, arity expected");
unsigned u = curr_unsigned();
next();
m_dt_name2idx.insert(dt_name, i);
m_dt_name2arity.insert(dt_name, u);
m_dt_names.push_back(dt_name);
psort_decl * decl = pm().mk_psort_dt_decl(u, dt_name);
m_ctx.insert(decl);
check_rparen("invalid sort declaration, ')' expected");
}
else {
check_identifier("invalid sort parameter, symbol or ')' expected");
m_sort_id2param_idx.insert(curr_id(), i);
}
i++;
next();
}
next();
return is_decl;
}
void parse_declare_sort() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_declare_sort);
next();
check_nonreserved_identifier("invalid sort declaration, symbol expected");
symbol id = curr_id();
if (m_ctx.find_psort_decl(id) != nullptr)
throw parser_exception("invalid sort declaration, sort already declared/defined");
next();
if (curr_is_rparen()) {
psort_decl * decl = pm().mk_psort_user_decl(0, id, nullptr);
m_ctx.insert(decl);
}
else {
check_int("invalid sort declaration, arity () or ')' expected");
unsigned u = curr_unsigned();
psort_decl * decl = pm().mk_psort_user_decl(u, id, nullptr);
m_ctx.insert(decl);
next();
check_rparen("invalid sort declaration, ')' expected");
}
m_ctx.print_success();
next();
}
void parse_define_sort() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_define_sort);
next();
check_nonreserved_identifier("invalid sort definition, symbol expected");
symbol id = curr_id();
if (m_ctx.find_psort_decl(id) != nullptr)
throw parser_exception("invalid sort definition, sort already declared/defined");
next();
parse_sort_decl_params();
parse_psort();
psort_decl * decl = pm().mk_psort_user_decl(m_sort_id2param_idx.size(), id, psort_stack().back());
psort_stack().pop_back();
m_ctx.insert(decl);
check_rparen("invalid sort definition, ')' expected");
m_ctx.print_success();
next();
}
void parse_define(bool is_fun) {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == (is_fun ? m_define_fun : m_model_add));
SASSERT(m_num_bindings == 0);
next();
check_nonreserved_identifier("invalid function/constant definition, symbol expected");
symbol id = curr_id();
next();
unsigned sym_spos = symbol_stack().size();
unsigned sort_spos = sort_stack().size();
unsigned expr_spos = expr_stack().size();
unsigned num_vars = parse_sorted_vars();
parse_sort("Invalid function definition");
parse_expr();
if (expr_stack().back()->get_sort() != sort_stack().back())
throw parser_exception("invalid function/constant definition, sort mismatch");
sort* const* sorts = sort_stack().data() + sort_spos;
expr* t = expr_stack().back();
if (is_fun) {
expr_ref _t(t, m());
if (num_vars > 1) {
// variable ordering in macros follow non-standard ordering
// we have to reverse the ordering used by the parser.
var_subst sub(m(), true);
expr_ref_vector vars(m());
for (unsigned i = 0; i < num_vars; ++i)
vars.push_back(m().mk_var(i, sorts[i]));
_t = sub(_t, vars);
}
m_ctx.insert(id, num_vars, sorts, _t);
}
else {
m_ctx.model_add(id, num_vars, sorts, t);
}
check_rparen("invalid function/constant definition, ')' expected");
// restore stacks & env
symbol_stack().shrink(sym_spos);
sort_stack().shrink(sort_spos);
expr_stack().shrink(expr_spos);
m_env.end_scope();
SASSERT(num_vars == m_num_bindings);
m_num_bindings = 0;
m_ctx.print_success();
next();
}
void parse_define_fun() {
parse_define(true);
}
void parse_model_add() {
parse_define(false);
}
void parse_model_del() {
next();
symbol id = curr_id();
func_decl * f = m_ctx.find_func_decl(id);
m_ctx.model_del(f);
next();
check_rparen_next("invalid model-del, ')' expected");
m_ctx.print_success();
}
void parse_define_fun_rec() {
// ( define-fun-rec hfun_defi )
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_define_fun_rec);
SASSERT(m_num_bindings == 0);
next();
expr_ref_vector binding(m());
svector ids;
func_decl_ref f(m());
parse_rec_fun_decl(f, binding, ids);
m_ctx.insert(f);
parse_rec_fun_body(f, binding, ids);
check_rparen("invalid function/constant definition, ')' expected");
m_ctx.print_success();
next();
}
void parse_define_funs_rec() {
// ( define-funs-rec ( hfun_decin+1 ) ( htermin+1 ) )
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_define_funs_rec);
SASSERT(m_num_bindings == 0);
next();
func_decl_ref_vector decls(m());
vector bindings;
vector > ids;
parse_rec_fun_decls(decls, bindings, ids);
for (func_decl* d : decls) {
m_ctx.insert(d);
}
parse_rec_fun_bodies(decls, bindings, ids);
check_rparen("invalid function/constant definition, ')' expected");
m_ctx.print_success();
next();
}
void parse_rec_fun_decls(func_decl_ref_vector& decls, vector& bindings, vector >& ids) {
check_lparen("invalid recursive function definition, '(' expected");
next();
while (!curr_is_rparen()) {
expr_ref_vector binding(m());
svector id;
func_decl_ref f(m());
check_lparen("invalid recursive function definition, '(' expected");
next();
parse_rec_fun_decl(f, binding, id);
decls.push_back(f);
bindings.push_back(binding);
ids.push_back(id);
check_rparen("invalid recursive function definition, ')' expected");
next();
}
next();
}
recfun::promise_def parse_rec_fun_decl(func_decl_ref& f, expr_ref_vector& bindings, svector& ids) {
SASSERT(m_num_bindings == 0);
check_identifier("invalid function/constant definition, symbol expected");
symbol id = curr_id();
next();
unsigned sym_spos = symbol_stack().size();
unsigned sort_spos = sort_stack().size();
unsigned expr_spos = expr_stack().size();
unsigned num_vars = parse_sorted_vars();
SASSERT(num_vars == m_num_bindings);
parse_sort("Invalid recursive function definition");
recfun::promise_def pdef = m_ctx.decl_rec_fun(id, num_vars, sort_stack().data() + sort_spos, sort_stack().back());
f = pdef.get_def()->get_decl();
bindings.append(num_vars, expr_stack().data() + expr_spos);
ids.append(num_vars, symbol_stack().data() + sym_spos);
symbol_stack().shrink(sym_spos);
sort_stack().shrink(sort_spos);
expr_stack().shrink(expr_spos);
m_env.end_scope();
m_num_bindings = 0;
return pdef;
}
void parse_rec_fun_bodies(func_decl_ref_vector const& decls, vector const& bindings, vector >const & ids) {
unsigned i = 0;
check_lparen("invalid recursive function definition, '(' expected");
next();
while (!curr_is_rparen() && i < decls.size()) {
parse_rec_fun_body(decls[i], bindings[i], ids[i]);
++i;
}
if (i != decls.size()) {
throw parser_exception("the number of declarations does not match number of supplied definitions");
}
check_rparen("invalid recursive function definition, ')' expected");
next();
}
void parse_rec_fun_body(func_decl* f, expr_ref_vector const& bindings, svector const& ids) {
SASSERT(m_num_bindings == 0);
expr_ref body(m());
unsigned sym_spos = symbol_stack().size();
unsigned num_vars = bindings.size();
m_env.begin_scope();
m_symbol_stack.append(ids.size(), ids.data());
m_num_bindings = num_vars;
for (unsigned i = 0; i < num_vars; ++i) {
m_env.insert(ids[i], local(bindings[i], num_vars));
}
parse_expr();
body = expr_stack().back();
expr_stack().pop_back();
symbol_stack().shrink(sym_spos);
m_env.end_scope();
m_num_bindings = 0;
if (body->get_sort() != f->get_range()) {
std::ostringstream buffer;
buffer << "invalid function definition, sort mismatch. Expcected "
<< mk_pp(f->get_range(), m()) << " but function body has sort "
<< mk_pp(body->get_sort(), m());
throw parser_exception(buffer.str());
}
m_ctx.insert_rec_fun(f, bindings, ids, body);
}
void parse_define_const() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_define_const);
SASSERT(m_num_bindings == 0);
next();
check_identifier("invalid constant definition, symbol expected");
symbol id = curr_id();
next();
parse_sort("Invalid constant definition");
parse_expr();
if (expr_stack().back()->get_sort() != sort_stack().back())
throw parser_exception("invalid constant definition, sort mismatch");
m_ctx.insert(id, 0, nullptr, expr_stack().back());
check_rparen("invalid constant definition, ')' expected");
expr_stack().pop_back();
sort_stack().pop_back();
m_ctx.print_success();
next();
}
/**
* (declare-fun f (sorts) sort)
* (declare-fun (alphas) (sorts) sort)
*/
void parse_declare_fun() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_declare_fun);
next();
check_nonreserved_identifier("invalid function declaration, symbol expected");
symbol id = curr_id();
next();
unsigned spos = sort_stack().size();
unsigned num_params = parse_sorts("Parsing function declaration. Expecting sort list '('");
parse_sort("Invalid function declaration");
func_decl_ref f(m());
f = m().mk_func_decl(id, num_params, sort_stack().data() + spos, sort_stack().back());
sort_stack().shrink(spos);
m_ctx.insert(f);
check_rparen("invalid function declaration, ')' expected");
m_ctx.print_success();
next();
}
void parse_declare_const() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_declare_const);
next();
check_nonreserved_identifier("invalid constant declaration, symbol expected");
symbol id = curr_id();
next();
parse_sort("Invalid constant declaration");
SASSERT(!sort_stack().empty());
func_decl_ref c(m());
c = m().mk_const_decl(id, sort_stack().back());
TRACE("declare_const", tout << "declaring " << id << " "; pm().display(tout, sort_stack().back()); tout << "\n";);
SASSERT(c.get() != 0);
sort_stack().pop_back();
m_ctx.insert(c);
check_rparen("invalid constant declaration, ')' expected");
m_ctx.print_success();
next();
}
unsigned parse_opt_unsigned(unsigned def) {
unsigned num;
if (!curr_is_rparen()) {
check_int("invalid push command, integer expected");
rational n = curr_numeral();
if (n.is_neg())
throw parser_exception("invalid push command, value is negative.");
if (!n.is_unsigned())
throw parser_exception("invalid push command, value is too big to fit in an unsigned machine integer");
num = n.get_unsigned();
next();
}
else {
num = def;
}
return num;
}
void parse_push() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_push);
next();
unsigned num = parse_opt_unsigned(1);
m_ctx.push(num);
check_rparen("invalid push command, ')' expected");
m_ctx.print_success();
next();
}
void parse_pop() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_pop);
next();
unsigned num = parse_opt_unsigned(1);
m_ctx.pop(num);
check_rparen("invalid pop command, ')' expected");
m_ctx.print_success();
next();
TRACE("after_pop", tout << "expr_stack.size: " << expr_stack().size() << "\n"; m_ctx.dump_assertions(tout););
}
std::string m_assert_expr;
void parse_assert() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_assert);
m_last_named_expr.first = symbol::null;
m_last_named_expr.second = 0;
if (m_ctx.interactive_mode()) {
m_scanner.start_caching();
m_cache_end = 0;
}
next();
parse_expr();
if (m_ctx.interactive_mode()) {
m_assert_expr = m_scanner.cached_str(0, m_cache_end);
m_scanner.stop_caching();
}
if (expr_stack().empty()) {
throw cmd_exception("invalid assert command, expression required as argument");
}
expr * f = expr_stack().back();
if (!f || !m().is_bool(f)) {
TRACE("smt2parser", tout << expr_ref(f, m()) << "\n";);
throw cmd_exception("invalid assert command, term is not Boolean");
}
if (f == m_last_named_expr.second) {
m_ctx.assert_expr(m_last_named_expr.first, f);
}
else {
m_ctx.assert_expr(f);
}
if (m_ctx.interactive_mode()) {
m_ctx.push_assert_string(m_assert_expr);
}
expr_stack().pop_back();
check_rparen("invalid assert command, ')' expected");
m_ctx.print_success();
next();
}
void parse_assumptions() {
while (!curr_is_rparen()) {
parse_expr();
if (!m().is_bool(expr_stack().back()))
throw parser_exception("invalid check-sat command, argument must be a Boolean literal");
}
}
void parse_check_sat() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_check_sat);
next();
unsigned spos = expr_stack().size();
parse_assumptions();
m_ctx.check_sat(expr_stack().size() - spos, expr_stack().data() + spos);
next();
expr_stack().shrink(spos);
}
void parse_check_sat_assuming() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_check_sat_assuming);
next();
unsigned spos = expr_stack().size();
check_lparen_next("invalid check-sat-assuming command, '(', expected");
parse_assumptions();
check_rparen_next("invalid check-sat-assuming command, ')', expected");
m_ctx.check_sat(expr_stack().size() - spos, expr_stack().data() + spos);
next();
expr_stack().shrink(spos);
}
void parse_get_value() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_get_value);
next();
unsigned spos = expr_stack().size();
unsigned cache_it = 0;
m_scanner.start_caching();
m_cache_end = 0;
m_cached_strings.resize(0);
check_lparen_next("invalid get-value command, '(' expected");
while (!curr_is_rparen()) {
parse_expr();
m_cached_strings.push_back(m_scanner.cached_str(cache_it, m_cache_end));
cache_it = m_cache_end;
}
m_scanner.stop_caching();
if (m_cached_strings.empty())
throw cmd_exception("invalid get-value command, empty list of terms");
next();
unsigned index = 0;
if (curr_is_keyword() && (curr_id() == ":model-index" || curr_id() == ":model_index")) {
next();
check_int("integer index expected to indexed model evaluation");
index = curr_unsigned();
next();
}
check_rparen("invalid get-value command, ')' expected");
model_ref md;
if (m_ctx.ignore_check()) {
expr_stack().shrink(spos);
next();
return;
}
if (!m_ctx.is_model_available(md) || m_ctx.get_check_sat_result() == nullptr)
throw cmd_exception("model is not available");
if (index != 0) {
m_ctx.get_opt()->get_box_model(md, index);
}
m_ctx.regular_stream() << "(";
expr ** expr_it = expr_stack().data() + spos;
expr ** expr_end = expr_it + m_cached_strings.size();
md->compress();
for (unsigned i = 0; expr_it < expr_end; expr_it++, i++) {
model::scoped_model_completion _scm(md, true);
expr_ref v = (*md)(*expr_it);
if (i > 0)
m_ctx.regular_stream() << "\n ";
m_ctx.regular_stream() << "(" << m_cached_strings[i] << " ";
m_ctx.display(m_ctx.regular_stream(), v);
m_ctx.regular_stream() << ")";
}
m_ctx.regular_stream() << ")" << std::endl;
expr_stack().shrink(spos);
next();
}
void parse_reset() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_reset);
next();
check_rparen("invalid reset command, ')' expected");
reset();
m_ctx.reset();
m_ctx.print_success();
next();
}
void parse_option_value() {
switch (curr()) {
case scanner::BV_TOKEN:
case scanner::INT_TOKEN:
case scanner::FLOAT_TOKEN:
m_curr_cmd->set_next_arg(m_ctx, m_scanner.get_number());
next();
break;
case scanner::SYMBOL_TOKEN:
m_curr_cmd->set_next_arg(m_ctx, m_scanner.get_id());
next();
break;
case scanner::STRING_TOKEN:
m_curr_cmd->set_next_arg(m_ctx, m_scanner.get_string());
next();
break;
default:
throw parser_exception("invalid option value");
}
}
// A func_decl reference is of the form:
//
// | ( (+) sort)
// | ((_ +) (+) sort)
func_decl * parse_func_decl_ref() {
if (curr_is_identifier()) {
symbol id = curr_id();
func_decl * d = m_ctx.find_func_decl(id);
next();
return d;
}
else {
check_lparen_next("invalid function declaration reference, symbol or '(' expected");
symbol id;
sbuffer indices;
if (curr_is_identifier()) {
id = curr_id();
next();
}
else {
check_lparen_next("invalid function declaration reference, symbol or '(' expected");
check_underscore_next("invalid indexed function declaration reference, '_' expected");
check_identifier("invalid indexed function declaration reference, symbol expected");
id = curr_id();
next();
while (!curr_is_rparen()) {
check_int("invalid indexed function declaration reference, integer or ')' expected");
unsigned u = curr_unsigned();
indices.push_back(u);
next();
}
if (indices.empty())
throw parser_exception("invalid indexed function declaration reference, index expected");
next();
}
unsigned spos = sort_stack().size();
parse_sorts("Invalid function name. Expecting sort list starting with '(' to disambiguate function name");
unsigned domain_size = sort_stack().size() - spos;
parse_sort("Invalid function name");
func_decl * d = m_ctx.find_func_decl(id, indices.size(), indices.data(), domain_size, sort_stack().data() + spos, sort_stack().back());
sort_stack().shrink(spos);
check_rparen_next("invalid function declaration reference, ')' expected");
return d;
}
}
void parse_func_decl_refs(ptr_buffer & flist) {
check_lparen_next("invalid list of function declaration references, '(' expected");
while (!curr_is_rparen()) {
flist.push_back(parse_func_decl_ref());
}
next();
}
void parse_next_cmd_arg() {
SASSERT(m_curr_cmd != 0);
cmd_arg_kind k = m_curr_cmd->next_arg_kind(m_ctx);
switch (k) {
case CPK_UINT: {
check_int("invalid command argument, unsigned integer expected");
unsigned u = curr_unsigned();
m_curr_cmd->set_next_arg(m_ctx, u);
next();
break;
}
case CPK_BOOL: {
check_identifier("invalid command argument, true/false expected");
symbol val = curr_id();
if (val != "true" && val != "false")
throw parser_exception("invalid command argument, true/false expected");
m_curr_cmd->set_next_arg(m_ctx, val == "true");
next();
break;
}
case CPK_NUMERAL:
check_int_or_float("invalid command argument, numeral expected");
m_curr_cmd->set_next_arg(m_ctx, curr_numeral());
next();
break;
case CPK_DECIMAL:
check_float("invalid command argument, decimal expected");
m_curr_cmd->set_next_arg(m_ctx, curr_numeral());
next();
break;
case CPK_STRING:
check_string("invalid command argument, string expected");
m_curr_cmd->set_next_arg(m_ctx, m_scanner.get_string());
next();
break;
case CPK_KEYWORD:
check_keyword("invalid command argument, keyword expected");
m_curr_cmd->set_next_arg(m_ctx, curr_id());
next();
break;
case CPK_OPTION_VALUE:
parse_option_value();
break;
case CPK_SYMBOL:
check_identifier("invalid command argument, symbol expected");
m_curr_cmd->set_next_arg(m_ctx, curr_id());
next();
return;
case CPK_SYMBOL_LIST: {
unsigned spos = m_symbol_stack.size();
unsigned num = parse_symbols();
m_curr_cmd->set_next_arg(m_ctx, num, m_symbol_stack.data() + spos);
break;
}
case CPK_SORT:
parse_sort("invalid command argument, sort expected");
m_curr_cmd->set_next_arg(m_ctx, sort_stack().back());
return;
case CPK_SORT_LIST: {
unsigned spos = sort_stack().size();
unsigned num = parse_sorts("expecting sort list starting with '('");
m_curr_cmd->set_next_arg(m_ctx, num, sort_stack().data() + spos);
break;
}
case CPK_EXPR:
parse_expr();
m_curr_cmd->set_next_arg(m_ctx, expr_stack().back());
return;
case CPK_EXPR_LIST: {
unsigned spos = expr_stack().size();
unsigned num = parse_exprs();
m_curr_cmd->set_next_arg(m_ctx, num, expr_stack().data() + spos);
break;
}
case CPK_FUNC_DECL: {
func_decl * f = parse_func_decl_ref();
m_curr_cmd->set_next_arg(m_ctx, f);
return;
}
case CPK_FUNC_DECL_LIST: {
ptr_buffer flist;
parse_func_decl_refs(flist);
m_curr_cmd->set_next_arg(m_ctx, flist.size(), flist.data());
return;
}
case CPK_SORTED_VAR:
NOT_IMPLEMENTED_YET();
break;
case CPK_SORTED_VAR_LIST:
NOT_IMPLEMENTED_YET();
break;
case CPK_SEXPR:
parse_sexpr();
m_curr_cmd->set_next_arg(m_ctx, sexpr_stack().back());
break;
case CPK_INVALID:
throw parser_exception("invalid/unexpected argument");
default:
throw parser_exception("unexpected argument");
}
}
void parse_unknown_cmd() {
SASSERT(curr_is_identifier());
symbol s = curr_id();
next();
while (!curr_is_rparen()) {
consume_sexpr();
}
m_ctx.print_unsupported(s, m_scanner.get_line(), m_scanner.get_pos());
next();
return;
}
void parse_ext_cmd(int line, int pos) {
symbol s = curr_id();
m_curr_cmd = m_ctx.find_cmd(s);
if (m_curr_cmd == nullptr) {
parse_unknown_cmd();
return;
}
next();
unsigned arity = m_curr_cmd->get_arity();
unsigned i = 0;
unsigned sort_spos = size(m_sort_stack);
unsigned expr_spos = size(m_expr_stack);
unsigned sexpr_spos = size(m_sexpr_stack);
unsigned sym_spos = m_symbol_stack.size();
m_curr_cmd->set_line_pos(line, pos);
m_curr_cmd->prepare(m_ctx);
while (true) {
if (curr_is_rparen()) {
if (arity != VAR_ARITY && i < arity)
throw parser_exception("invalid command, argument(s) missing");
m_curr_cmd->execute(m_ctx);
next();
m_curr_cmd = nullptr;
shrink(m_sort_stack, sort_spos);
shrink(m_expr_stack, expr_spos);
shrink(m_sexpr_stack, sexpr_spos);
m_symbol_stack.shrink(sym_spos);
m_num_bindings = 0;
// HACK for propagating the update of parser parameters
if (norm_param_name(s) == "set_option") {
updt_params();
}
return;
}
else {
if (arity != VAR_ARITY && i == arity)
throw parser_exception("invalid command, too many arguments");
parse_next_cmd_arg();
}
i++;
}
}
void parse_cmd() {
SASSERT(curr_is_lparen());
int line = m_scanner.get_line();
int pos = m_scanner.get_pos();
next();
check_identifier("invalid command, symbol expected");
symbol s = curr_id();
if (s == m_assert) {
parse_assert();
return;
}
if (s == m_declare_fun) {
parse_declare_fun();
return;
}
if (s == m_declare_const) {
parse_declare_const();
return;
}
if (s == m_check_sat) {
parse_check_sat();
return;
}
if (s == m_push) {
parse_push();
return;
}
if (s == m_pop) {
parse_pop();
return;
}
if (s == m_define_fun) {
parse_define_fun();
return;
}
if (s == m_define_const) {
parse_define_const();
return;
}
if (s == m_define_sort) {
parse_define_sort();
return;
}
if (s == m_declare_sort) {
parse_declare_sort();
return;
}
if (s == m_declare_type_var) {
parse_declare_type_var();
return;
}
if (s == m_declare_datatypes) {
parse_declare_datatypes();
return;
}
if (s == m_declare_datatype) {
parse_declare_datatype();
return;
}
if (s == m_get_value) {
parse_get_value();
return;
}
if (s == m_reset) {
parse_reset();
return;
}
if (s == m_check_sat_assuming) {
parse_check_sat_assuming();
return;
}
if (s == m_define_fun_rec) {
parse_define_fun_rec();
return;
}
if (s == m_define_funs_rec) {
parse_define_funs_rec();
return;
}
if (s == m_model_add) {
parse_model_add();
return;
}
if (s == m_model_del) {
parse_model_del();
return;
}
parse_ext_cmd(line, pos);
}
public:
parser(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & p, char const * filename=nullptr):
m_ctx(ctx),
m_params(p),
m_scanner(ctx, is, interactive),
m_curr(scanner::NULL_TOKEN),
m_curr_cmd(nullptr),
m_num_bindings(0),
m_let("let"),
m_bang("!"),
m_forall("forall"),
m_exists("exists"),
m_lambda("lambda"),
m_as("as"),
m_not("not"),
m_root_obj("root-obj"),
m_named(":named"),
m_weight(":weight"),
m_qid(":qid"),
m_skid(":skolemid"),
m_pattern(":pattern"),
m_nopattern(":no-pattern"),
m_lblneg(":lblneg"),
m_lblpos(":lblpos"),
m_assert("assert"),
m_check_sat("check-sat"),
m_define_fun("define-fun"),
m_define_const("define-const"),
m_model_add("model-add"),
m_model_del("model-del"),
m_declare_fun("declare-fun"),
m_declare_const("declare-const"),
m_define_sort("define-sort"),
m_declare_sort("declare-sort"),
m_declare_type_var("declare-type-var"),
m_declare_datatypes("declare-datatypes"),
m_declare_datatype("declare-datatype"),
m_par("par"),
m_push("push"),
m_pop("pop"),
m_get_value("get-value"),
m_reset("reset"),
m_check_sat_assuming("check-sat-assuming"),
m_define_fun_rec("define-fun-rec"),
m_define_funs_rec("define-funs-rec"),
m_match("match"),
m_case("case"),
m_underscore("_"),
m_num_open_paren(0),
m_current_file(filename) {
// the following assertion does not hold if ctx was already attached to an AST manager before the parser object is created.
// SASSERT(!m_ctx.has_manager());
updt_params();
}
~parser() {
reset_stack();
}
void updt_params() {
parser_params p(m_params);
m_ignore_user_patterns = p.ignore_user_patterns();
m_ignore_bad_patterns = p.ignore_bad_patterns();
m_display_error_for_vs = p.error_for_visual_studio();
}
void reset() {
reset_stack();
m_num_bindings = 0;
m_psort_stack = nullptr;
m_sort_stack = nullptr;
m_expr_stack = nullptr;
m_pattern_stack = nullptr;
m_nopattern_stack = nullptr;
m_sexpr_stack = nullptr;
m_bv_util = nullptr;
m_arith_util = nullptr;
m_seq_util = nullptr;
m_pattern_validator = nullptr;
m_var_shifter = nullptr;
m_symbol_stack .reset();
m_param_stack .reset();
m_env .reset();
m_sort_id2param_idx .reset();
m_dt_name2idx .reset();
}
void reset_input(std::istream & is, bool interactive) {
m_scanner.reset_input(is, interactive);
}
sexpr_ref parse_sexpr_ref() {
m_num_bindings = 0;
m_num_open_paren = 0;
try {
scan_core();
parse_sexpr();
if (!sexpr_stack().empty()) {
return sexpr_ref(sexpr_stack().back(), sm());
}
}
catch (z3_exception & ex) {
error(ex.msg());
}
return sexpr_ref(nullptr, sm());
}
sort_ref parse_sort_ref(char const* context) {
m_num_bindings = 0;
m_num_open_paren = 0;
try {
scan_core();
parse_sort(context);
if (!sort_stack().empty())
return sort_ref(sort_stack().back(), m());
}
catch (z3_exception & ex) {
error(ex.msg());
}
return sort_ref(nullptr, m());
}
bool operator()() {
m_num_bindings = 0;
unsigned found_errors = 0;
try {
scan_core();
}
catch (scanner_exception & ex) {
error(ex.msg());
if (!sync_after_error())
return false;
found_errors++;
}
while (true) {
try {
m_num_open_paren = 0;
while (true) {
switch (curr()) {
case scanner::LEFT_PAREN:
parse_cmd();
break;
case scanner::EOF_TOKEN:
return found_errors == 0;
default:
throw parser_exception("invalid command, '(' expected");
break;
}
}
}
catch (z3_error & ex) {
// Can't invoke error(...) when out of memory.
// Reason: escaped() string builder needs memory
m_ctx.regular_stream() << "(error \"line " << m_scanner.get_line() << " column " << m_scanner.get_pos()
<< ": " << ex.msg() << "\")" << std::endl;
exit(ex.error_code());
}
catch (const stop_parser_exception &) {
m_scanner.stop_caching();
return !found_errors;
}
catch (parser_exception & ex) {
if (ex.has_pos())
error(ex.line(), ex.pos(), ex.msg());
else
error(ex.msg());
}
catch (ast_exception & ex) {
error(ex.msg());
}
catch (z3_exception & ex) {
error(ex.msg());
}
m_scanner.stop_caching();
if (m_curr_cmd)
m_curr_cmd->failure_cleanup(m_ctx);
reset();
found_errors = true;
if (!sync_after_error())
return false;
TRACE("parser_error", tout << "after sync: " << curr() << "\n";);
SASSERT(m_num_open_paren == 0);
}
}
};
void free_parser(parser * p) { dealloc(p); }
};
bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename) {
smt2::parser p(ctx, is, interactive, ps, filename);
return p();
}
bool parse_smt2_commands_with_parser(class smt2::parser *& p, cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename) {
if (p)
p->reset_input(is, interactive);
else
p = alloc(smt2::parser, ctx, is, interactive, ps, filename);
return (*p)();
}
sort_ref parse_smt2_sort(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename) {
smt2::parser p(ctx, is, interactive, ps, filename);
return p.parse_sort_ref(filename);
}
sexpr_ref parse_sexpr(cmd_context& ctx, std::istream& is, params_ref const& ps, char const* filename) {
smt2::parser p(ctx, is, false, ps, filename);
return p.parse_sexpr_ref();
}