Use []=> and <>=> as sugar in the output when possible.

* src/ltlast/multop.hh (is_multop): Take a constant formula as input.
* src/ltlvisit/tostring.cc (to_string_visitor::visit(multop*)):
Output []=> or <>=> when the left argument of a []-> or <>-> is
a concatenation that ends in 1.
* doc/tl/tl.tex: Document this desugaring.
This commit is contained in:
Alexandre Duret-Lutz 2012-02-16 19:24:44 +01:00
parent 5e7c0add49
commit 412f946ac0
3 changed files with 32 additions and 12 deletions

View file

@ -99,6 +99,9 @@
% rewriting rules that enlarge the formula % rewriting rules that enlarge the formula
\newcommand{\equiV}{\stackrel{\star}{\equiv}} \newcommand{\equiV}{\stackrel{\star}{\equiv}}
% marked rewriting rules
\newcommand{\equivM}{\stackrel{\dag}{\equiv}}
\def\limplies{\rightarrow} \def\limplies{\rightarrow}
\def\simp{\rightrightharpoons} \def\simp{\rightrightharpoons}
\def\Simp{\stackrel{+}{\simp}} \def\Simp{\stackrel{+}{\simp}}
@ -717,7 +720,7 @@ $b_1$, $b_2$ are assumed to be Boolean formul\ae.
\end{align*} \end{align*}
\noindent \noindent
The following rules are all valid with the two arguments swapped, except the one marked with $\stackrel{\dag}{\equiv}$. The following rules are all valid with the two arguments swapped, except the one marked with $\equivM$.
%(Even for the non-commutative operators \samp{$\CONCAT$} and %(Even for the non-commutative operators \samp{$\CONCAT$} and
%\samp{$\FUSION$}.) %\samp{$\FUSION$}.)
@ -746,7 +749,7 @@ The following rules are all valid with the two arguments swapped, except the one
b_1 \AND b_2 &\equiv b_1\ANDALT b_2 & b_1 \AND b_2 &\equiv b_1\ANDALT b_2 &
&& &&
&& &&
b:f &\stackrel{\dag}{\equiv} b\AND f\\ b:f &\equivM b\AND f\\
\end{align*} \end{align*}
\section{SERE-LTL Binding Operators} \section{SERE-LTL Binding Operators}
@ -804,14 +807,14 @@ is therefore a model of the formula \samp{$\sere{a\PLUS{};\NOT
The syntax on the left is equivalent to the syntax on the right. The syntax on the left is equivalent to the syntax on the right.
These rewritings are performed from left to right when parsing a These rewritings are performed from left to right when parsing a
formula.\spottodo{It would be nice to have the opposite rewritings on formula. Except the one marked with $\equivM$, the opposite
output.} rewritings are also preformed on output to ease reading.
\begin{align*} \begin{align*}
\sere{r}\EsuffixEQ f &\equiv \sere{r\CONCAT\1}\Esuffix f & \sere{r}\EsuffixEQ f &\equiv \sere{r\CONCAT\1}\Esuffix f &
\sere{r}\AsuffixEQ f &\equiv \sere{r\CONCAT\1}\Asuffix f\\ \sere{r}\AsuffixEQ f &\equiv \sere{r\CONCAT\1}\Asuffix f\\
\seren{r} &\equiv \sere{r}\Esuffix \1 & \seren{r} &\equiv \sere{r}\Esuffix \1 &
\sere{r}\AsuffixALTEQ f &\equiv \sere{r\CONCAT\1}\Asuffix f\\ \sere{r}\AsuffixALTEQ f &\equivM \sere{r\CONCAT\1}\Asuffix f\\
\end{align*} \end{align*}
$\AsuffixEQ$ and $\AsuffixALTEQ$ are synonyms in the same way as $\AsuffixEQ$ and $\AsuffixALTEQ$ are synonyms in the same way as

View file

@ -185,11 +185,11 @@ namespace spot
/// Returns 0 otherwise. /// Returns 0 otherwise.
inline inline
multop* multop*
is_multop(formula* f, multop::type op) is_multop(const formula* f, multop::type op)
{ {
if (f->kind() != formula::MultOp) if (f->kind() != formula::MultOp)
return 0; return 0;
multop* mo = static_cast<multop*>(f); multop* mo = static_cast<multop*>(const_cast<formula*>(f));
if (mo->op() != op) if (mo->op() != op)
return 0; return 0;
return mo; return mo;
@ -197,8 +197,8 @@ namespace spot
/// \brief Cast \a f into a multop if it has type \a op1 or \a op2. /// \brief Cast \a f into a multop if it has type \a op1 or \a op2.
/// ///
/// Cast \a f into a multop iff it is a multop instance with operator \a op1 /// Cast \a f into a multop iff it is a multop instance with
/// or \a op2. Returns 0 otherwise. /// operator \a op1 or \a op2. Returns 0 otherwise.
inline inline
multop* multop*
is_multop(const formula* f, multop::type op1, multop::type op2) is_multop(const formula* f, multop::type op1, multop::type op2)

View file

@ -122,6 +122,8 @@ namespace spot
if (!top_level) if (!top_level)
openp(); openp();
bool onelast = false;
switch (bo->op()) switch (bo->op())
{ {
case binop::UConcat: case binop::UConcat:
@ -130,6 +132,21 @@ namespace spot
os_ << "{"; os_ << "{";
in_ratexp_ = true; in_ratexp_ = true;
top_level_ = true; top_level_ = true;
{
multop* m = is_multop(bo->first(), multop::Concat);
if (m)
{
unsigned s = m->size();
if (m->nth(s - 1) == constant::true_instance())
{
formula* tmp = m->all_but(s - 1);
tmp->accept(*this);
tmp->destroy();
onelast = true;
break;
}
}
}
// fall through // fall through
default: default:
bo->first()->accept(*this); bo->first()->accept(*this);
@ -160,7 +177,7 @@ namespace spot
os_ << " M "; os_ << " M ";
break; break;
case binop::UConcat: case binop::UConcat:
os_ << "} []-> "; os_ << (onelast ? "} []=> " : "} []-> ");
in_ratexp_ = false; in_ratexp_ = false;
top_level_ = top_level; top_level_ = top_level;
break; break;
@ -171,12 +188,12 @@ namespace spot
in_ratexp_ = false; in_ratexp_ = false;
goto second_done; goto second_done;
} }
os_ << "} <>-> "; os_ << (onelast ? "} <>=> " : "} <>-> ");
in_ratexp_ = false; in_ratexp_ = false;
top_level_ = false; top_level_ = false;
break; break;
case binop::EConcatMarked: case binop::EConcatMarked:
os_ << "} <>+> "; os_ << (onelast ? "} <>=+> " : "} <>+> ");
in_ratexp_ = false; in_ratexp_ = false;
top_level_ = false; top_level_ = false;
break; break;