// Copyright (C) 2009, 2011, 2012 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
#include
#include
#include "bdd.h"
#include "tgba/sba.hh"
#include "neverclaim.hh"
#include "tgba/bddprint.hh"
#include "reachiter.hh"
#include "ltlvisit/tostring.hh"
#include "tgba/formula2bdd.hh"
namespace spot
{
namespace
{
class never_claim_bfs : public tgba_reachable_iterator_breadth_first
{
public:
never_claim_bfs(const tgba* a, std::ostream& os,
const ltl::formula* f, bool comments)
: tgba_reachable_iterator_breadth_first(a),
os_(os), f_(f), accept_all_(-1), fi_needed_(false),
comments_(comments), all_acc_conds_(a->all_acceptance_conditions()),
sba_(dynamic_cast(a))
{
}
void
start()
{
os_ << "never {";
if (f_)
{
os_ << " /* ";
to_string(f_, os_);
os_ << " */";
}
os_ << '\n';
init_ = aut_->get_init_state();
}
void
end()
{
if (fi_needed_)
os_ << " fi;\n";
if (accept_all_ != -1)
os_ << "accept_all:\n skip\n";
os_ << "}" << std::endl;
init_->destroy();
}
bool
state_is_accepting(const state *s)
{
// If the automaton is a SBA, it's easier to just query the
// state_is_accepting() method.
if (sba_)
return sba_->state_is_accepting(s);
// Otherwise, since we are dealing with a degeneralized
// automaton nonetheless, the transitions leaving an accepting
// state are either all accepting, or all non-accepting. So
// we just check the acceptance of the first transition. This
// is not terribly efficient since we have to create the
// iterator.
tgba_succ_iterator* it = aut_->succ_iter(s);
it->first();
bool accepting =
!it->done() && it->current_acceptance_conditions() == all_acc_conds_;
delete it;
return accepting;
}
std::string
get_state_label(const state* s, int n)
{
std::string label;
if (s->compare(init_) == 0)
if (state_is_accepting(s))
label = "accept_init";
else
label = "T0_init";
else
{
std::ostringstream ost;
ost << n;
std::string ns(ost.str());
if (state_is_accepting(s))
{
tgba_succ_iterator* it = aut_->succ_iter(s);
it->first();
if (it->done())
label = "accept_S" + ns;
else
{
state* current = it->current_state();
if (it->current_condition() != bddtrue
|| s->compare(current) != 0)
label = "accept_S" + ns;
else
label = "accept_all";
current->destroy();
}
delete it;
}
else
label = "T0_S" + ns;
}
return label;
}
void
process_state(const state* s, int n, tgba_succ_iterator*)
{
tgba_succ_iterator* it = aut_->succ_iter(s);
it->first();
if (it->done())
{
if (fi_needed_ != 0)
os_ << " fi;\n";
os_ << get_state_label(s, n) << ":";
if (comments_)
os_ << " /* " << aut_->format_state(s) << " */";
os_ << "\n if\n :: (0) -> goto "
<< get_state_label(s, n) << '\n';
fi_needed_ = true;
}
else
{
state* current =it->current_state();
if (state_is_accepting(s)
&& it->current_condition() == bddtrue
&& s->compare(init_) != 0
&& s->compare(current) == 0)
accept_all_ = n;
else
{
if (fi_needed_)
os_ << " fi;\n";
os_ << get_state_label(s, n) << ":";
if (comments_)
os_ << " /* " << aut_->format_state(s) << " */";
os_ << "\n if\n";
fi_needed_ = true;
}
current->destroy();
}
delete it;
}
void
process_link(const state*, int in, const state*, int out,
const tgba_succ_iterator* si)
{
if (in != accept_all_)
{
os_ << " :: (";
const ltl::formula* f = bdd_to_formula(si->current_condition(),
aut_->get_dict());
to_spin_string(f, os_, true);
f->destroy();
state* current = si->current_state();
os_ << ") -> goto " << get_state_label(current, out) << '\n';
current->destroy();
}
}
private:
std::ostream& os_;
const ltl::formula* f_;
int accept_all_;
bool fi_needed_;
state* init_;
bool comments_;
bdd all_acc_conds_;
const sba* sba_;
};
} // anonymous
std::ostream&
never_claim_reachable(std::ostream& os, const tgba* g,
const ltl::formula* f, bool comments)
{
assert(g->number_of_acceptance_conditions() <= 1);
never_claim_bfs n(g, os, f, comments);
n.run();
return os;
}
}