Commit bbb645e1 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

Add support for PSL's non-length-matching And.

* src/ltlast/multop.cc, src/ltlast/multop.hh: Declare AndNML
operator.
* src/ltlparse/ltlscan.ll: Distinguish "&" and "&&".
* src/ltlparse/ltlparse.yy: Handle them both as "And" for LTL
formula, use AndNML or And for rational expressions.
* src/ltlvisit/tostring.cc: Adjust to distinguish "&" and "&&" in
rational expressions. Also use {braces} to group rational
expressions.
* src/tgbaalgos/ltl2tgba_fm.cc
(ratexp_trad_visitor::ratexp_trad_visitor): Remove the possibility
to select the empty_word should act like true, and fix the rules
for Closure and NegClosure to rely on constant_term instead.
(ratexp_trad_visitor::visit) Adjust the And translation to also
support AndNML.
(ratexp_trad_visitor::recurse_and_concat): Introduce this new
method to simplify some calls to recurse(f, to_concat_).
* src/tgbatest/ltl2tgba.test: Add more test cases.
* src/ltlvisit/basicreduce.cc, src/ltlvisit/consterm.cc,
src/ltlvisit/contain.cc, src/ltlvisit/mark.cc,
src/ltlvisit/nenoform.cc, src/ltlvisit/syntimpl.cc,
src/tgba/formula2bdd.cc, src/tgbaalgos/eltl2tgba_lacim.cc,
src/tgbaalgos/ltl2taa.cc, src/tgbaalgos/ltl2tgba_lacim.cc: Add
missing cases in switches.
parent 1ecc6984
......@@ -109,6 +109,8 @@ namespace spot
{
case And:
return "And";
case AndNLM:
return "AndNLM";
case Or:
return "Or";
case Concat:
......@@ -171,6 +173,7 @@ namespace spot
std::sort(v->begin(), v->end(), formula_ptr_less_than());
formula* neutral;
formula* neutral2;
formula* abs;
formula* abs2;
formula* weak_abs;
......@@ -178,24 +181,35 @@ namespace spot
{
case And:
neutral = constant::true_instance();
neutral2 = 0;
abs = constant::false_instance();
abs2 = 0;
weak_abs = constant::empty_word_instance();
break;
case AndNLM:
neutral = constant::true_instance();
neutral2 = constant::empty_word_instance();
abs = constant::false_instance();
abs2 = 0;
weak_abs = 0;
break;
case Or:
neutral = constant::false_instance();
neutral2 = 0;
abs = constant::true_instance();
abs2 = 0;
weak_abs = 0;
break;
case Concat:
neutral = constant::empty_word_instance();
neutral2 = 0;
abs = constant::false_instance();
abs2 = 0;
weak_abs = 0;
break;
case Fusion:
neutral = constant::true_instance();
neutral2 = 0;
abs = constant::false_instance();
abs2 = constant::empty_word_instance();
weak_abs = 0;
......@@ -203,6 +217,7 @@ namespace spot
default:
neutral = 0;
neutral2 = 0;
abs = 0;
abs2 = 0;
weak_abs = 0;
......@@ -218,7 +233,7 @@ namespace spot
bool weak_abs_seen = false;
while (i != v->end())
{
if ((*i == neutral) || (*i == last))
if ((*i == neutral) || (*i == neutral2) || (*i == last))
{
(*i)->destroy();
i = v->erase(i);
......
......@@ -41,7 +41,7 @@ namespace spot
class multop : public ref_formula
{
public:
enum type { Or, And, Concat, Fusion };
enum type { Or, And, AndNLM, Concat, Fusion };
/// List of formulae.
typedef std::vector<formula*> vec;
......@@ -80,15 +80,24 @@ namespace spot
/// are also taken care of. The following rewriting are performed
/// (the left patterns are rewritten as shown on the right):
///
/// - Concat(Exps1...,[*0],Exps2...) = Concat(Exps1...,Exps2...)
/// - Concat(Exps1...,0,Exps2...) = 0
/// - Concat(Exp) = Exp
/// - And(Exps1...,1,Exps2...) = And(Exps1...,Exps2...)
/// - And(Exps1...,0,Exps2...) = 0
/// - And(Exps1...,[*0],Exps2...) = [*0] if no Expi is 0.
/// - And(Exp) = Exp
/// - AndNLM(Exps1...,1,Exps2...) = AndNLM(Exps1...,Exps2...)
/// - AndNLM(Exps1...,0,Exps2...) = 0
/// - AndNLM(Exps1...,[*0],Exps2...) = AndNLM(Exps1...,Exps2...)
/// - AndNLM(Exp) = Exp
/// - Or(Exps1...,1,Exps2...) = 1
/// - Or(Exps1...,0,Exps2...) = And(Exps1...,Exps2...)
/// - Or(Exp) = Exp
/// - Concat(Exps1...,[*0],Exps2...) = Concat(Exps1...,Exps2...)
/// - Concat(Exps1...,0,Exps2...) = 0
/// - Concat(Exp) = Exp
/// - Fusion(Exps1...,1,Exps2...) = Concat(Exps1...,Exps2...)
/// - Fusion(Exps1...,0,Exps2...) = 0
/// - Fusion(Exps1...,[*0],Exps2...) = 0
/// - Fusion(Exp) = Exp
static formula* instance(type op, vec* v);
virtual void accept(visitor& v);
......
......@@ -78,7 +78,8 @@ using namespace spot::ltl;
%token START_RATEXP "RATEXP start marker"
%token PAR_OPEN "opening parenthesis" PAR_CLOSE "closing parenthesis"
%token BRACE_OPEN "opening brace" BRACE_CLOSE "closing brace"
%token OP_OR "or operator" OP_XOR "xor operator" OP_AND "and operator"
%token OP_OR "or operator" OP_XOR "xor operator"
%token OP_AND "and operator" OP_SHORT_AND "short and operator"
%token OP_IMPLIES "implication operator" OP_EQUIV "equivalent operator"
%token OP_U "until operator" OP_R "release operator"
%token OP_W "weak until operator" OP_M "strong release operator"
......@@ -103,7 +104,7 @@ using namespace spot::ltl;
%left OP_IMPLIES OP_EQUIV
%left OP_OR
%left OP_XOR
%left OP_AND
%left OP_AND OP_SHORT_AND
/* LTL operators. */
%left OP_U OP_R OP_M OP_W
......@@ -257,7 +258,13 @@ rationalexp: booleanatom
| rationalexp OP_AND rationalexp
{ $$ = multop::instance(multop::And, $1, $3); }
| rationalexp OP_AND error
{ missing_right_binop($$, $1, @2, "and operator"); }
{ missing_right_binop($$, $1, @2,
"length-matching and operator"); }
| rationalexp OP_SHORT_AND rationalexp
{ $$ = multop::instance(multop::AndNLM, $1, $3); }
| rationalexp OP_SHORT_AND error
{ missing_right_binop($$, $1, @2,
"non-length-matching and operator"); }
| rationalexp OP_OR rationalexp
{ $$ = multop::instance(multop::Or, $1, $3); }
| rationalexp OP_OR error
......@@ -318,6 +325,10 @@ subformula: booleanatom
{ $$ = multop::instance(multop::And, $1, $3); }
| subformula OP_AND error
{ missing_right_binop($$, $1, @2, "and operator"); }
| subformula OP_SHORT_AND subformula
{ $$ = multop::instance(multop::And, $1, $3); }
| subformula OP_SHORT_AND error
{ missing_right_binop($$, $1, @2, "and operator"); }
| subformula OP_OR subformula
{ $$ = multop::instance(multop::Or, $1, $3); }
| subformula OP_OR error
......
......@@ -97,7 +97,8 @@ flex_set_buffer(const char* buf, int start_tok)
/\, \/, and xor are from LBTT.
--> and <--> come from Goal. */
"||"|"|"|"+"|"\\/" BEGIN(0); return token::OP_OR;
"&&"|"&"|"/\\" BEGIN(0); return token::OP_AND;
"&&"|"/\\" BEGIN(0); return token::OP_AND;
"&" BEGIN(0); return token::OP_SHORT_AND;
"^"|"xor" BEGIN(0); return token::OP_XOR;
"=>"|"->"|"-->" BEGIN(0); return token::OP_IMPLIES;
"<=>"|"<->"|"<-->" BEGIN(0); return token::OP_EQUIV;
......
......@@ -786,6 +786,7 @@ namespace spot
break;
case multop::Concat:
case multop::AndNLM:
case multop::Fusion:
std::copy(res->begin(), res->end(), tmpOther->end());
break;
......
......@@ -122,6 +122,7 @@ namespace spot
return;
break;
case multop::And:
case multop::AndNLM:
case multop::Concat:
result_ &= r;
if (!result_)
......
......@@ -357,6 +357,7 @@ namespace spot
break;
case multop::Concat:
case multop::Fusion:
case multop::AndNLM:
break;
}
if (changed)
......
......@@ -203,6 +203,7 @@ namespace spot
res->push_back(recurse(mo->nth(i)));
break;
case multop::And:
case multop::AndNLM:
{
typedef std::set<std::pair<formula*, formula*> > pset;
pset Epairs, EMpairs;
......
......@@ -233,6 +233,7 @@ namespace spot
break;
case multop::Concat:
case multop::Fusion:
case multop::AndNLM:
break;
}
multop::vec* res = new multop::vec;
......@@ -249,12 +250,12 @@ namespace spot
}
case multop::Concat:
case multop::Fusion:
case multop::AndNLM:
{
for (unsigned i = 0; i < mos; ++i)
res->push_back(recurse_(mo->nth(i), false));
result_ = multop::instance(op, res);
if (negated_)
result_ = unop::instance(unop::Not, result_);
assert(!negated_);
}
}
}
......
......@@ -205,6 +205,7 @@ namespace spot
break;
case multop::Concat:
case multop::Fusion:
case multop::AndNLM:
break;
}
}
......@@ -462,6 +463,7 @@ namespace spot
break;
case multop::Concat:
case multop::Fusion:
case multop::AndNLM:
break;
}
}
......
......@@ -62,7 +62,8 @@ namespace spot
{
public:
to_string_visitor(std::ostream& os, bool full_parent = false)
: os_(os), top_level_(true), full_parent_(full_parent)
: os_(os), top_level_(true),
full_parent_(full_parent), in_ratexp_(false)
{
}
......@@ -71,6 +72,18 @@ namespace spot
{
}
void
openp() const
{
os_ << (in_ratexp_ ? "{" : "(");
}
void
closep() const
{
os_ << (in_ratexp_ ? "}" : ")");
}
void
visit(const atomic_prop* ap)
{
......@@ -93,31 +106,30 @@ namespace spot
visit(const constant* c)
{
if (full_parent_)
os_ << "(";
openp();
os_ << c->val_name();
if (full_parent_)
os_ << ")";
closep();
}
void
visit(const binop* bo)
{
bool top_level = top_level_;
top_level_ = false;
if (!top_level)
os_ << "(";
openp();
switch (bo->op())
{
case binop::UConcat:
case binop::EConcat:
case binop::EConcatMarked:
os_ << "{ ";
os_ << "{";
in_ratexp_ = true;
top_level_ = true;
bo->first()->accept(*this);
top_level_ = false;
break;
// fall through
default:
top_level_ = false;
bo->first()->accept(*this);
break;
}
......@@ -146,19 +158,25 @@ namespace spot
os_ << " M ";
break;
case binop::UConcat:
os_ << " }[]-> ";
os_ << "} []-> ";
in_ratexp_ = false;
top_level_ = top_level;
break;
case binop::EConcat:
os_ << " }<>-> ";
os_ << "} <>-> ";
in_ratexp_ = false;
top_level_ = false;
break;
case binop::EConcatMarked:
os_ << " }<>+> ";
os_ << "} <>+> ";
in_ratexp_ = false;
top_level_ = false;
break;
}
bo->second()->accept(*this);
if (!top_level)
os_ << ")";
closep();
}
void
......@@ -175,7 +193,7 @@ namespace spot
need_parent = false; // These will be printed by each subformula
if (!top_level)
os_ << "(";
openp();
}
switch (uo->op())
......@@ -199,13 +217,16 @@ namespace spot
break;
case unop::Closure:
os_ << "{";
in_ratexp_ = true;
top_level_ = true;
break;
case unop::NegClosure:
os_ << "!{";
in_ratexp_ = true;
top_level_ = true;
break;
case unop::Star:
// 1* is OK, no need to print (1)*.
// 1* is OK, no need to print {1}*.
need_parent = false;
// Do not output anything yet, star is a postfix operator.
break;
......@@ -213,10 +234,10 @@ namespace spot
top_level_ = false;
if (need_parent || full_parent_)
os_ << "(";
openp();
uo->child()->accept(*this);
if (need_parent)
os_ << ")";
if (need_parent || full_parent_)
closep();
switch (uo->op())
{
......@@ -226,6 +247,7 @@ namespace spot
case unop::Closure:
case unop::NegClosure:
os_ << "}";
in_ratexp_ = false;
top_level_ = false;
break;
default:
......@@ -233,7 +255,7 @@ namespace spot
}
if (full_parent_ && !top_level)
os_ << ")";
closep();
}
void
......@@ -264,7 +286,7 @@ namespace spot
bool top_level = top_level_;
top_level_ = false;
if (!top_level)
os_ << "(";
openp();
unsigned max = mo->size();
mo->nth(0)->accept(*this);
const char* ch = " ";
......@@ -274,6 +296,9 @@ namespace spot
ch = " | ";
break;
case multop::And:
ch = in_ratexp_ ? " && " : " & ";
break;
case multop::AndNLM:
ch = " & ";
break;
case multop::Concat:
......@@ -290,12 +315,13 @@ namespace spot
mo->nth(n)->accept(*this);
}
if (!top_level)
os_ << ")";
closep();
}
protected:
std::ostream& os_;
bool top_level_;
bool full_parent_;
bool in_ratexp_;
};
class to_spin_string_visitor : public to_string_visitor
......@@ -317,7 +343,7 @@ namespace spot
bool top_level = top_level_;
top_level_ = false;
if (!top_level)
os_ << "(";
openp();
switch (bo->op())
{
......@@ -361,17 +387,26 @@ namespace spot
break;
case binop::UConcat:
bo->first()->accept(*this);
os_ << " []-> ";
os_ << "} []-> ";
top_level_ = false;
bo->second()->accept(*this);
break;
case binop::EConcat:
in_ratexp_ = true;
top_level_ = true;
os_ << "{";
bo->first()->accept(*this);
os_ << " <>-> ";
os_ << "} <>-> ";
top_level_ = false;
bo->second()->accept(*this);
break;
case binop::EConcatMarked:
in_ratexp_ = true;
top_level_ = true;
os_ << "{";
bo->first()->accept(*this);
os_ << " <>+> ";
os_ << "} <>+> ";
top_level_ = false;
bo->second()->accept(*this);
break;
/* W and M are not supported by Spin */
......@@ -388,7 +423,7 @@ namespace spot
}
if (!top_level)
os_ << ")";
closep();
}
void
......@@ -396,7 +431,7 @@ namespace spot
{
bool top_level = top_level_;
if (full_parent_ && !top_level)
os_ << "(";
openp();
bool need_parent = false;
top_level_ = false;
......@@ -426,23 +461,24 @@ namespace spot
case unop::Closure:
os_ << "{";
top_level_ = true;
in_ratexp_ = true;
break;
case unop::NegClosure:
os_ << "!{";
top_level_ = true;
in_ratexp_ = true;
break;
case unop::Star:
// Do not output anything yet, star is a postfix operator.
need_parent = false;
break;
}
if (need_parent)
os_ << "(";
openp();
uo->child()->accept(*this);
if (need_parent)
os_ << ")";
if (uo->op() == unop::Star)
os_ << "*";
closep();
switch (uo->op())
{
......@@ -452,6 +488,7 @@ namespace spot
case unop::Closure:
case unop::NegClosure:
os_ << "}";
in_ratexp_ = false;
top_level_ = false;
break;
default:
......@@ -459,29 +496,7 @@ namespace spot
}
if (full_parent_ && !top_level)
os_ << ")";
}
void
visit(const automatop* ao)
{
// Warning: this string isn't parsable because the automaton
// operators used may not be defined.
bool top_level = top_level_;
top_level_ = false;
if (!top_level)
os_ << "(";
os_ << ao->get_nfa()->get_name() << "(";
unsigned max = ao->size();
ao->nth(0)->accept(*this);
for (unsigned n = 1; n < max; ++n)
{
os_ << ",";
ao->nth(n)->accept(*this);
}
os_ << ")";
if (!top_level)
os_ << ")";
closep();
}
void
......@@ -490,7 +505,7 @@ namespace spot
bool top_level = top_level_;
top_level_ = false;
if (!top_level)
os_ << "(";
openp();
unsigned max = mo->size();
mo->nth(0)->accept(*this);
const char* ch = " ";
......@@ -502,6 +517,9 @@ namespace spot
case multop::And:
ch = " && ";
break;
case multop::AndNLM:
ch = " & ";
break;
case multop::Concat:
ch = ";";
break;
......@@ -516,7 +534,7 @@ namespace spot
mo->nth(n)->accept(*this);
}
if (!top_level)
os_ << ")";
closep();
}
};
......
......@@ -145,6 +145,7 @@ namespace spot
break;
case multop::Concat:
case multop::Fusion:
case multop::AndNLM:
assert(!"unsupported operator");
}
assert(op != -1);
......
......@@ -162,6 +162,7 @@ namespace spot
break;
case multop::Concat:
case multop::Fusion:
case multop::AndNLM:
assert(!"unsupported operator");
}
assert(op != -1);
......
......@@ -326,6 +326,7 @@ namespace spot
return;
case multop::Concat:
case multop::Fusion:
case multop::AndNLM:
assert(!"unsupported operator");
return;
}
......
......@@ -158,7 +158,7 @@ namespace spot
}
formula*
conj_bdd_to_formula(bdd b) const
conj_bdd_to_formula(bdd b, multop::type op = multop::And) const
{
if (b == bddfalse)
return constant::false_instance();
......@@ -181,7 +181,7 @@ namespace spot
assert(b != bddfalse);
v->push_back(res);
}
return multop::instance(multop::And, v);
return multop::instance(op, v);
}
formula*
......@@ -297,12 +297,8 @@ namespace spot
class ratexp_trad_visitor: public const_visitor
{
public:
ratexp_trad_visitor(translate_dict& dict,
bool empty_word_is_true,
formula* to_concat = 0)
: dict_(dict),
empty_word_is_true_(empty_word_is_true),
to_concat_(to_concat)
ratexp_trad_visitor(translate_dict& dict, formula* to_concat = 0)
: dict_(dict), to_concat_(to_concat)
{
}
......@@ -332,7 +328,7 @@ namespace spot
if (to_concat_ && to_concat_ != constant::empty_word_instance())