Extend the ELTL parser to support more complex aliases of

automaton operators such as Strong=G(F($0))->G(F($1)) and
G=R(false, $0).

* src/eltlparse/eltlparse.yy, src/eltlparse/eltlscan.ll: Add
support for more complex aliases.
* src/eltltest/acc.cc, src/eltltest/acc.test: Adjust.
* src/ltlast/nfa.cc, src/ltlast/nfa.hh (arity): Now returns an
unsigned value.
* src/tgbatest/eltl2tgba.test: Adjust.
* src/tgbalagos/eltl2tgba_lacim.cc: Fix sanity.
This commit is contained in:
Damien Lefortier 2009-04-18 16:24:18 +02:00
parent bbbc1acc14
commit b06c9cd563
10 changed files with 188 additions and 66 deletions

View file

@ -1,3 +1,17 @@
2009-04-18 Damien Lefortier <dam@lrde.epita.fr>
Extend the ELTL parser to support more complex aliases of
automaton operators such as Strong=G(F($0))->G(F($1)) and
G=R(false, $0).
* src/eltlparse/eltlparse.yy, src/eltlparse/eltlscan.ll: Add
support for more complex aliases.
* src/eltltest/acc.cc, src/eltltest/acc.test: Adjust.
* src/ltlast/nfa.cc, src/ltlast/nfa.hh (arity): Now returns an
unsigned value.
* src/tgbatest/eltl2tgba.test: Adjust.
* src/tgbalagos/eltl2tgba_lacim.cc: Fix sanity.
2009-04-09 Guillaume SADEGH <sadegh@lrde.epita.fr> 2009-04-09 Guillaume SADEGH <sadegh@lrde.epita.fr>
Minor fixes to compile with GCC 4.4. Minor fixes to compile with GCC 4.4.

View file

@ -57,26 +57,24 @@ namespace spot
struct alias_not : alias struct alias_not : alias
{ {
alias_ptr s; alias_ptr child;
}; };
struct alias_binary : alias struct alias_binop : alias
{ {
virtual ~alias_binary() = 0; // Should not be instanciate binop::type op;
alias_ptr lhs; alias_ptr lhs;
alias_ptr rhs; alias_ptr rhs;
}; };
struct alias_binop : alias_binary struct alias_multop : alias
{ {
binop::type ty; multop::type op;
}; alias_ptr lhs;
struct alias_multop : alias_binary alias_ptr rhs;
{
multop::type ty;
}; };
struct alias_nfa : alias struct alias_nfa : alias
{ {
std::vector<alias_ptr> children;
spot::ltl::nfa::ptr nfa; spot::ltl::nfa::ptr nfa;
std::list<alias_ptr> s;
}; };
struct alias_arg : alias struct alias_arg : alias
{ {
@ -93,28 +91,32 @@ namespace spot
std::string file_; std::string file_;
}; };
/// TODO: maybe implementing a visitor could be better than
/// dynamic casting all the time here.
/// Instanciate the formula corresponding to the given alias. /// Instanciate the formula corresponding to the given alias.
static formula* static formula*
alias2formula(alias_ptr ap, spot::ltl::automatop::vec* v) alias2formula(const alias_ptr ap, spot::ltl::automatop::vec* v)
{ {
if (alias_not* a = dynamic_cast<alias_not*>(ap.get())) if (alias_not* a = dynamic_cast<alias_not*>(ap.get()))
return unop::instance(unop::Not, alias2formula(a->s, v)); return unop::instance(unop::Not, alias2formula(a->child, v));
if (alias_arg* a = dynamic_cast<alias_arg*>(ap.get())) if (alias_arg* a = dynamic_cast<alias_arg*>(ap.get()))
return a->i == -1 ? constant::true_instance() : v->at(a->i); return a->i == -1 ? constant::true_instance() :
a->i == -2 ? constant::false_instance() : v->at(a->i);
if (alias_nfa* a = dynamic_cast<alias_nfa*>(ap.get())) if (alias_nfa* a = dynamic_cast<alias_nfa*>(ap.get()))
{ {
automatop::vec* va = new automatop::vec; automatop::vec* va = new automatop::vec;
std::list<alias_ptr>::const_iterator i = a->s.begin(); std::vector<alias_ptr>::const_iterator i = a->children.begin();
while (i != a->s.end()) while (i != a->children.end())
va->push_back(alias2formula(*i++, v)); va->push_back(alias2formula(*i++, v));
return automatop::instance(a->nfa, va, false); return automatop::instance(a->nfa, va, false);
} }
if (alias_binop* a = dynamic_cast<alias_binop*>(ap.get())) if (alias_binop* a = dynamic_cast<alias_binop*>(ap.get()))
return binop::instance(a->ty, return binop::instance(a->op,
alias2formula(a->lhs, v), alias2formula(a->lhs, v),
alias2formula(a->rhs, v)); alias2formula(a->rhs, v));
if (alias_multop* a = dynamic_cast<alias_multop*>(ap.get())) if (alias_multop* a = dynamic_cast<alias_multop*>(ap.get()))
return multop::instance(a->ty, return multop::instance(a->op,
alias2formula(a->lhs, v), alias2formula(a->lhs, v),
alias2formula(a->rhs, v)); alias2formula(a->rhs, v));
@ -124,29 +126,74 @@ namespace spot
/// Get the arity of a given alias. /// Get the arity of a given alias.
static size_t static size_t
arity(alias_ptr ap) arity(const alias_ptr ap)
{ {
if (alias_not* a = dynamic_cast<alias_not*>(ap.get())) if (alias_not* a = dynamic_cast<alias_not*>(ap.get()))
return arity(a->s); return arity(a->child);
if (alias_arg* a = dynamic_cast<alias_arg*>(ap.get())) if (alias_arg* a = dynamic_cast<alias_arg*>(ap.get()))
return a->i + 1; return std::max(a->i + 1, 0);
if (alias_nfa* a = dynamic_cast<alias_nfa*>(ap.get())) if (alias_nfa* a = dynamic_cast<alias_nfa*>(ap.get()))
{ {
size_t res = 0; size_t res = 0;
std::list<alias_ptr>::const_iterator i = a->s.begin(); std::vector<alias_ptr>::const_iterator i = a->children.begin();
while (i != a->s.end()) while (i != a->children.end())
res = std::max(arity(*i++), res); res = std::max(arity(*i++), res);
return res; return res;
} }
if (alias_binary* a = dynamic_cast<alias_binary*>(ap.get())) if (alias_binop* a = dynamic_cast<alias_binop*>(ap.get()))
return std::max(arity(a->lhs), arity(a->rhs));
if (alias_multop* a = dynamic_cast<alias_multop*>(ap.get()))
return std::max(arity(a->lhs), arity(a->rhs)); return std::max(arity(a->lhs), arity(a->rhs));
/* Unreachable code. */ /* Unreachable code. */
assert(0); assert(0);
} }
/// Create a new alias from an existing one according to \a v. /// Alias an existing alias, as in Strong=G(F($0))->G(F($1)),
/// TODO. /// where F is an alias.
///
/// \param ap The original alias.
/// \param v The arguments of the new alias.
static alias_ptr
realias(const alias_ptr ap, std::vector<alias_ptr> v)
{
if (alias_not* a = dynamic_cast<alias_not*>(ap.get()))
{
alias_not* res = new alias_not;
res->child = realias(a->child, v);
return alias_ptr(res);
}
if (alias_arg* a = dynamic_cast<alias_arg*>(ap.get())) // Do it.
return a->i < 0 ? ap : v.at(a->i);
if (alias_nfa* a = dynamic_cast<alias_nfa*>(ap.get()))
{
alias_nfa* res = new alias_nfa;
std::vector<alias_ptr>::const_iterator i = a->children.begin();
while (i != a->children.end())
res->children.push_back(realias(*i++, v));
res->nfa = a->nfa;
return alias_ptr(res);
}
if (alias_binop* a = dynamic_cast<alias_binop*>(ap.get()))
{
alias_binop* res = new alias_binop;
res->op = a->op;
res->lhs = realias(a->lhs, v);
res->rhs = realias(a->rhs, v);
return alias_ptr(res);
}
if (alias_multop* a = dynamic_cast<alias_multop*>(ap.get()))
{
alias_multop* res = new alias_multop;
res->op = a->op;
res->lhs = realias(a->lhs, v);
res->rhs = realias(a->rhs, v);
return alias_ptr(res);
}
/* Unreachable code. */
assert(0);
}
} }
} }
@ -156,7 +203,7 @@ namespace spot
#define CHECK_EXISTING_NMAP(Loc, Ident) \ #define CHECK_EXISTING_NMAP(Loc, Ident) \
{ \ { \
nfamap::iterator i = nmap.find(*Ident); \ nfamap::const_iterator i = nmap.find(*Ident); \
if (i == nmap.end()) \ if (i == nmap.end()) \
{ \ { \
std::string s = "unknown automaton operator `"; \ std::string s = "unknown automaton operator `"; \
@ -308,7 +355,7 @@ nfa: IDENT "=" "(" nfa_def ")"
nfa_def: /* empty */ nfa_def: /* empty */
{ {
$$ = new nfa(); $$ = new nfa;
} }
| nfa_def STATE STATE nfa_arg | nfa_def STATE STATE nfa_arg
{ {
@ -324,59 +371,86 @@ nfa_def: /* empty */
nfa_alias: IDENT "(" nfa_alias_arg_list ")" nfa_alias: IDENT "(" nfa_alias_arg_list ")"
{ {
aliasmap::iterator i = amap.find(*$1); aliasmap::const_iterator i = amap.find(*$1);
if (i != amap.end()) if (i != amap.end())
assert(0); // FIXME {
CHECK_ARITY(@1, $1, $3->children.size(), arity(i->second));
// Hack to return the right type without screwing with the
// boost::shared_ptr memory handling by using get for
// example. FIXME: Wait for the next version of boost and
// modify the %union to handle alias_ptr.
alias_not* tmp1 = new alias_not;
tmp1->child = realias(i->second, $3->children);
alias_not* tmp2 = new alias_not;
tmp2->child = alias_ptr(tmp1);
$$ = tmp2;
delete $3;
}
else else
{ {
CHECK_EXISTING_NMAP(@1, $1); CHECK_EXISTING_NMAP(@1, $1);
nfa::ptr np = nmap[*$1]; nfa::ptr np = nmap[*$1];
CHECK_ARITY(@1, $1, $3->s.size(), CHECK_ARITY(@1, $1, $3->children.size(), np->arity());
static_cast<unsigned>(np->arity()));
$3->nfa = np; $3->nfa = np;
$$ = $3; $$ = $3;
} }
delete $1; delete $1;
} }
/// TODO
// | IDENT "(" nfa_alias ")" // Should be a list
// {
// assert(0);
// }
| OP_NOT nfa_alias | OP_NOT nfa_alias
{ {
alias_not* a = new alias_not; alias_not* res = new alias_not;
a->s = alias_ptr($2); res->child = alias_ptr($2);
$$ = a; $$ = res;
} }
| nfa_alias OP_IMPLIES nfa_alias
{
alias_binop* res = new alias_binop;
res->op = binop::Implies;
res->lhs = alias_ptr($1);
res->rhs = alias_ptr($3);
$$ = res;
}
// More TBD here.
nfa_alias_arg: nfa_arg
{
alias_arg* res = new alias_arg;
res->i = $1;
$$ = res;
}
| CONST_FALSE
{
alias_arg* res = new alias_arg;
res->i = -2;
$$ = res;
}
| OP_NOT nfa_alias_arg
{
alias_not* res = new alias_not;
res->child = alias_ptr($2);
$$ = res;
}
// More TBD here.
nfa_alias_arg_list: nfa_alias_arg nfa_alias_arg_list: nfa_alias_arg
{ {
$$ = new alias_nfa; $$ = new alias_nfa;
$$->s.push_back(alias_ptr($1)); $$->children.push_back(alias_ptr($1));
}
| nfa_alias // Cannot factorize because <pval> != <bval>.
{
$$ = new alias_nfa;
$$->children.push_back(alias_ptr($1));
} }
| nfa_alias_arg_list "," nfa_alias_arg | nfa_alias_arg_list "," nfa_alias_arg
{ {
$1->s.push_back(alias_ptr($3)); $1->children.push_back(alias_ptr($3));
$$ = $1; $$ = $1;
} }
; ;
nfa_alias_arg: nfa_arg
{
alias_arg* a = new alias_arg;
a->i = $1;
$$ = a;
}
| OP_NOT nfa_alias_arg
{
alias_not* a = new alias_not;
a->s = alias_ptr($2);
$$ = a;
}
// TODO: factoring with nfa_alias
nfa_arg: ARG nfa_arg: ARG
{ {
if ($1 == -1) if ($1 == -1)
@ -449,8 +523,7 @@ subformula: ATOMIC_PROP
CHECK_EXISTING_NMAP(@1, $1); CHECK_EXISTING_NMAP(@1, $1);
nfa::ptr np = nmap[*$1]; nfa::ptr np = nmap[*$1];
CHECK_ARITY(@1, $1, $3->size(), CHECK_ARITY(@1, $1, $3->size(), np->arity());
static_cast<unsigned>(np->arity()));
$$ = automatop::instance(np, $3, false); $$ = automatop::instance(np, $3, false);
} }
delete $1; delete $1;

View file

@ -105,6 +105,9 @@ eol \n|\r|\n\r|\r\n
<INITIAL>[tT][rR][uU][eE] { <INITIAL>[tT][rR][uU][eE] {
return token::CONST_TRUE; return token::CONST_TRUE;
} }
<INITIAL>[fF][aA][lL][sS][eE] {
return token::CONST_FALSE;
}
<INITIAL>[a-zA-Z][a-zA-Z0-9_]* { <INITIAL>[a-zA-Z][a-zA-Z0-9_]* {
yylval->sval = new std::string(yytext, yyleng); yylval->sval = new std::string(yytext, yyleng);

View file

@ -22,6 +22,9 @@
#include <iostream> #include <iostream>
#include <cassert> #include <cassert>
#include "eltlparse/public.hh" #include "eltlparse/public.hh"
#include "ltlvisit/destroy.hh"
#include "ltlvisit/lunabbrev.hh"
#include "ltlvisit/nenoform.hh"
int int
main(int argc, char** argv) main(int argc, char** argv)
@ -37,6 +40,12 @@ main(int argc, char** argv)
return 1; return 1;
} }
const spot::ltl::formula* f1 = spot::ltl::unabbreviate_logic(f);
const spot::ltl::formula* f2 = spot::ltl::negative_normal_form(f1);
spot::ltl::destroy(f1);
assert(f != 0); assert(f != 0);
std::cout << f->dump() << std::endl; std::cout << f->dump() << std::endl;
assert(f2 != 0);
std::cout << f2->dump() << std::endl;
} }

View file

@ -22,6 +22,18 @@ A(1,a,a|b)&X(!f)
EOF EOF
run 0 ./acc input || exit 1 run 0 ./acc input || exit 1
cat >input <<EOF
include prelude
A=(
0 1 \$2
1 2 \$0
accept 0
)
%
A(1,a)
EOF
run 1 ./acc input || exit 1
cat >input <<EOF cat >input <<EOF
X=( X=(
0 1 true 0 1 true

View file

@ -27,7 +27,7 @@ namespace spot
namespace ltl namespace ltl
{ {
nfa::nfa() nfa::nfa()
: is_(), si_(), arity_(-1), name_(), init_(0), finals_() : is_(), si_(), arity_(0), name_(), init_(0), finals_()
{ {
} }
@ -68,8 +68,8 @@ namespace spot
t->dst = add_state(dst); t->dst = add_state(dst);
t->label = label; t->label = label;
s->push_back(t); s->push_back(t);
if (label > arity_) if (label >= arity_)
arity_ = label; arity_ = label + 1;
} }
void void
@ -96,10 +96,10 @@ namespace spot
return finals_.empty(); return finals_.empty();
} }
int unsigned
nfa::arity() nfa::arity()
{ {
return arity_ + 1; return arity_;
} }
const nfa::state* const nfa::state*

View file

@ -74,7 +74,7 @@ namespace spot
bool is_loop(); bool is_loop();
/// \brief Get the `arity' i.e. max t.cost, for each transition t. /// \brief Get the `arity' i.e. max t.cost, for each transition t.
int arity(); unsigned arity();
/// \brief Return an iterator on the first succesor (if any) of \a state. /// \brief Return an iterator on the first succesor (if any) of \a state.
/// ///

View file

@ -228,13 +228,14 @@ namespace spot
fact_.constrain_relation(bdd_apply(bdd_ithvar(v1), tmp1, bddop_biimp)); fact_.constrain_relation(bdd_apply(bdd_ithvar(v1), tmp1, bddop_biimp));
if (is_loop) if (is_loop)
{ {
fact_.constrain_relation(bdd_apply(bdd_ithvar(v2), tmp2, bddop_invimp));
acc &= bdd_ithvar(v2) | !tmpacc; acc &= bdd_ithvar(v2) | !tmpacc;
fact_.constrain_relation(
bdd_apply(bdd_ithvar(v2), tmp2, bddop_invimp));
} }
else else
{ {
fact_.constrain_relation(bdd_apply(bdd_ithvar(v2), tmp2, bddop_imp));
acc &= bdd_nithvar(v2) | tmpacc; acc &= bdd_nithvar(v2) | tmpacc;
fact_.constrain_relation(bdd_apply(bdd_ithvar(v2), tmp2, bddop_imp));
} }
return m[s]; return m[s];

View file

@ -95,7 +95,6 @@ main(int argc, char** argv)
input += spot::ltl::to_string(f, true); input += spot::ltl::to_string(f, true);
spot::ltl::destroy(f); spot::ltl::destroy(f);
// std::cerr << input << std::endl;
f = spot::eltl::parse_string(input, p, env, false); f = spot::eltl::parse_string(input, p, env, false);
formula_index = 2; formula_index = 2;
} }

View file

@ -37,6 +37,7 @@ G=(
0 0 \$0 0 0 \$0
) )
F=U(true, \$0) F=U(true, \$0)
Strong=G(F(\$0))->G(F(\$1))
R=!U(!\$0, !\$1) R=!U(!\$0, !\$1)
EOF EOF
@ -114,6 +115,16 @@ check_construct input
check_true 'Fa' check_true 'Fa'
check_false '!Fa' check_false '!Fa'
cat >input <<EOF
include input1
%
Strong(a,b)
EOF
check_construct input
check_true 'G(F(a))->G(F(b))'
check_false '!(G(F(a))->G(F(b)))'
cat >input <<EOF cat >input <<EOF
include input1 include input1
% %