Commit 2da0053c authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

dstarparse: Preliminary work on a parser for ltl2dstar.

Supports reading Rabin and Streett automata, and converting them to
nondeterministic Büchi automata (for Rabin) or TGBA (for Streett).

* src/dstarparse/Makefile.am, src/dstarparse/dstarparse.yy,
src/dstarparse/dstarscan.ll, src/dstarparse/fmterror.cc,
src/dstarparse/parsedecl.hh, src/dstarparse/public.hh,
src/dstarparse/nra2nba.cc, src/dstarparse/nsa2tgba.cc: New files.
* configure.ac, src/Makefile.am, README: Adjust.
* src/tgbatest/ltl2tgba.cc: Add options -XD, -XDB.
* src/tgbatest/dstar.test: New file.
* src/tgbatest/Makefile.am (TESTS): Add it.
parent 5a3b1a99
...@@ -157,6 +157,7 @@ Core directories ...@@ -157,6 +157,7 @@ Core directories
src/ Sources for libspot. src/ Sources for libspot.
bin/ User tools built using the Spot library. bin/ User tools built using the Spot library.
man/ Man pages for the above tools. man/ Man pages for the above tools.
dstarparse/ Parser for the output of ltl2dstar.
eltlparse/ Parser for ELTL formulae. eltlparse/ Parser for ELTL formulae.
eltltest/ Tests for ELTL nodes in ltlast/ and eltlparse/. eltltest/ Tests for ELTL nodes in ltlast/ and eltlparse/.
kripke/ Kripke Structure interface. kripke/ Kripke Structure interface.
......
...@@ -147,6 +147,7 @@ AC_CONFIG_FILES([ ...@@ -147,6 +147,7 @@ AC_CONFIG_FILES([
lib/Makefile lib/Makefile
src/bin/Makefile src/bin/Makefile
src/bin/man/Makefile src/bin/man/Makefile
src/dstarparse/Makefile
src/eltlparse/Makefile src/eltlparse/Makefile
src/eltltest/defs src/eltltest/defs
src/eltltest/Makefile src/eltltest/Makefile
......
...@@ -26,14 +26,15 @@ AUTOMAKE_OPTIONS = subdir-objects ...@@ -26,14 +26,15 @@ AUTOMAKE_OPTIONS = subdir-objects
# end, after building '.' (since the current directory contains # end, after building '.' (since the current directory contains
# libspot.la needed by the tests) # libspot.la needed by the tests)
SUBDIRS = misc priv ltlenv ltlast ltlvisit ltlparse eltlparse tgba \ SUBDIRS = misc priv ltlenv ltlast ltlvisit ltlparse eltlparse tgba \
tgbaalgos tgbaparse ta taalgos kripke saba sabaalgos \ tgbaalgos tgbaparse ta taalgos kripke saba sabaalgos \
neverparse kripkeparse . bin ltltest eltltest tgbatest \ neverparse kripkeparse dstarparse . bin ltltest eltltest \
sabatest sanity kripketest tgbatest sabatest kripketest sanity
lib_LTLIBRARIES = libspot.la lib_LTLIBRARIES = libspot.la
libspot_la_SOURCES = libspot_la_SOURCES =
libspot_la_LDFLAGS = $(BUDDY_LDFLAGS) -no-undefined libspot_la_LDFLAGS = $(BUDDY_LDFLAGS) -no-undefined
libspot_la_LIBADD = \ libspot_la_LIBADD = \
dstarparse/libdstarparse.la \
eltlparse/libeltlparse.la \ eltlparse/libeltlparse.la \
kripke/libkripke.la \ kripke/libkripke.la \
kripkeparse/libkripkeparse.la \ kripkeparse/libkripkeparse.la \
......
position.hh
dstarparse.cc
dstarparse.output
dstarparse.hh
dstarscan.cc
stack.hh
location.hh
## -*- coding: utf-8 -*-
## Copyright (C) 2013 Laboratoire de Recherche et Développement de
## l'Epita (LRDE).
##
## 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 <http://www.gnu.org/licenses/>.
AM_CPPFLAGS = -I$(srcdir)/.. -I.. $(BUDDY_CPPFLAGS) -DYY_NO_INPUT
# Disable -Werror because too many versions of flex yield warnings.
AM_CXXFLAGS = $(WARNING_CXXFLAGS:-Werror=)
dstarparsedir = $(pkgincludedir)/dstarparse
dstarparse_HEADERS = public.hh
noinst_LTLIBRARIES = libdstarparse.la
DSTARPARSE_YY = dstarparse.yy
FROM_DSTARPARSE_YY_MAIN = dstarparse.cc
FROM_DSTARPARSE_YY_OTHERS = \
stack.hh \
dstarparse.hh
FROM_DSTARPARSE_YY = $(FROM_DSTARPARSE_YY_MAIN) $(FROM_DSTARPARSE_YY_OTHERS)
BUILT_SOURCES = $(FROM_DSTARPARSE_YY)
MAINTAINERCLEANFILES = $(FROM_DSTARPARSE_YY)
$(FROM_DSTARPARSE_YY_MAIN): $(srcdir)/$(DSTARPARSE_YY)
## We must cd into $(srcdir) first because if we tell bison to read
## $(srcdir)/$(DSTARPARSE_YY), it will also use the value of $(srcdir)/
## in the generated include statements.
cd $(srcdir) && \
bison -Wall -Werror --report=all \
$(DSTARPARSE_YY) -o $(FROM_DSTARPARSE_YY_MAIN)
$(FROM_DSTARPARSE_YY_OTHERS): $(DSTARPARSE_YY)
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) $(FROM_DSTARPARSE_YY_MAIN)
EXTRA_DIST = $(DSTARPARSE_YY)
libdstarparse_la_SOURCES = \
fmterror.cc \
nra2nba.cc \
nsa2tgba.cc \
$(FROM_DSTARPARSE_YY) \
dstarscan.ll \
parsedecl.hh
/* -*- coding: utf-8 -*-
** Copyright (C) 2013 Laboratoire de Recherche et Développement de
** l'Epita (LRDE).
**
** 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 <http://www.gnu.org/licenses/>.
*/
%language "C++"
%locations
%defines
%expect 0 // No shift/reduce
%name-prefix "dstaryy"
%debug
%error-verbose
%lex-param { spot::dstar_parse_error_list& error_list }
%define api.location.type "spot::location"
%code requires
{
#include <string>
#include <cstring>
#include "ltlast/constant.hh"
#include "public.hh"
typedef std::map<int, bdd> map_t;
struct result_
{
spot::dstar_aut* d;
spot::ltl::environment* env;
std::vector<bdd> guards;
std::vector<bdd>::const_iterator cur_guard;
map_t dest_map;
int cur_state;
unsigned state_count;
std::vector<std::string> aps;
bool state_count_seen:1;
bool accpair_count_seen:1;
bool start_state_seen:1;
bool aps_seen:1;
result_() :
state_count_seen(false),
accpair_count_seen(false),
start_state_seen(false),
aps_seen(false)
{
}
};
}
%parse-param {spot::dstar_parse_error_list& error_list}
%parse-param {result_& result}
%union
{
std::string* str;
unsigned int num;
}
%code
{
#include <sstream>
/* dstarparse.hh and parsedecl.hh include each other recursively.
We must ensure that YYSTYPE is declared (by the above %union)
before parsedecl.hh uses it. */
#include "parsedecl.hh"
static void fill_guards(result_& res);
}
%token DRA "DRA"
%token DSA "DSA"
%token V2 "v2"
%token EXPLICIT "explicit"
%token ACCPAIRS "Acceptance-Pairs:"
%token AP "AP:";
%token START "Start:";
%token STATES "States:";
%token STATE "State:";
%token ACCSIG "Acc-Sig:";
%token ENDOFHEADER "---";
%token EOL "new line";
%token <str> STRING "string";
%token <num> NUMBER "number";
%type <num> sign
%destructor { delete $$; } <str>
%printer {
if ($$)
debug_stream() << *$$;
else
debug_stream() << "\"\""; } <str>
%printer { debug_stream() << $$; } <num>
%%
dstar: header ENDOFHEADER eols states
eols : EOL | eols EOL
opt_eols: | opt_eols EOL
auttype: DRA { result.d->type = spot::Rabin; }
| DSA { result.d->type = spot::Streett; }
header: auttype opt_eols V2 opt_eols EXPLICIT opt_eols sizes
{
bool err = false;
if (!result.state_count_seen)
{
error(@5, "missing state count");
err = true;
}
if (!result.accpair_count_seen)
{
error(@5, "missing acceptance-pair count");
err = true;
}
if (!result.start_state_seen)
{
error(@5, "missing start-state number");
err = true;
}
if (!result.aps_seen)
{
error(@5, "missing atomic proposition definition");
err = true;
}
if (err)
{
delete result.d->aut;
result.d->aut = 0;
YYABORT;
}
fill_guards(result);
}
aps:
| aps STRING opt_eols
{
result.aps.push_back(*$2);
delete $2;
}
sizes:
| sizes error eols
{
error(@2, "unknown header ignored");
}
| sizes ACCPAIRS opt_eols NUMBER opt_eols
{
result.d->accpair_count = $4;
result.accpair_count_seen = true;
}
| sizes STATES opt_eols NUMBER opt_eols
{
result.state_count = $4;
result.state_count_seen = true;
}
| sizes START opt_eols NUMBER opt_eols
{
result.d->aut->set_init_state($4);
result.start_state_seen = true;
}
| sizes AP opt_eols NUMBER opt_eols aps
{
int announced = $4;
int given = result.aps.size();
if (given != announced)
{
std::ostringstream str;
str << announced << " atomic propositions announced but "
<< given << " given";
error(@4 + @6, str.str());
}
if (given > 31)
{
error(@4 + @6,
"ltl2star does not support more than 31 atomic propositions");
}
result.aps_seen = true;
}
opt_name: | STRING opt_eols
{
delete $1;
}
state_id: STATE opt_eols NUMBER opt_eols opt_name
{
if (result.cur_guard != result.guards.end())
error(@1, "not enough transitions for previous state");
if ($3 >= result.state_count)
{
std::ostringstream o;
if (result.state_count > 0)
{
o << "state numbers should be in the range [0.."
<< result.state_count - 1<< "]";
}
else
{
o << "no states have been declared";
}
error(@3, o.str());
}
result.cur_guard = result.guards.begin();
result.dest_map.clear();
result.cur_state = $3;
}
sign: '+' { $$ = 0; }
| '-' { $$ = 1; }
// Membership to a pair is represented as (+NUM,-NUM)
accsigs: opt_eols
| accsigs sign NUMBER opt_eols
{
if ((unsigned) result.cur_state >= result.state_count)
break;
assert(result.d->accsets);
if ($3 < result.d->accpair_count)
{
result.d->accsets->at(result.cur_state * 2 + $2).set($3);
}
else
{
std::ostringstream o;
if (result.d->accpair_count > 0)
{
o << "acceptance pairs should be in the range [0.."
<< result.d->accpair_count - 1<< "]";
}
else
{
o << "no acceptance pairs have been declared";
}
error(@3, o.str());
}
}
state_accsig: ACCSIG accsigs
transitions:
| transitions NUMBER opt_eols
{
std::pair<map_t::iterator, bool> i =
result.dest_map.insert(std::make_pair($2, *result.cur_guard));
if (!i.second)
i.first->second |= *result.cur_guard;
++result.cur_guard;
}
states:
| states state_id state_accsig transitions
{
for (map_t::const_iterator i = result.dest_map.begin();
i != result.dest_map.end(); ++i)
{
spot::tgba_explicit_number::transition* t =
result.d->aut->create_transition(result.cur_state, i->first);
t->condition = i->second;
}
}
%%
static void fill_guards(result_& r)
{
spot::bdd_dict* d = r.d->aut->get_dict();
size_t nap = r.aps.size();
int* vars = new int[nap];
// Get a BDD variable for each atomic proposition
for (size_t i = 0; i < nap; ++i)
{
const spot::ltl::formula* f = r.env->require(r.aps[i]);
vars[nap - 1 - i] = d->register_proposition(f, r.d->aut);
f->destroy();
}
// build the 2^nap possible guards
r.guards.reserve(1U << nap);
for (size_t i = 0; i < (1U << nap); ++i)
r.guards.push_back(bdd_ibuildcube(i, nap, vars));
delete[] vars;
r.cur_guard = r.guards.end();
r.d->accsets = spot::make_bitvect_array(r.d->accpair_count,
2 * r.state_count);
}
void
dstaryy::parser::error(const location_type& location,
const std::string& message)
{
error_list.push_back(spot::dstar_parse_error(location, message));
}
namespace spot
{
dstar_aut*
dstar_parse(const std::string& name,
dstar_parse_error_list& error_list,
bdd_dict* dict,
ltl::environment& env,
bool debug)
{
if (dstaryyopen(name))
{
error_list.push_back
(dstar_parse_error(spot::location(),
std::string("Cannot open file ") + name));
return 0;
}
result_ r;
r.d = new dstar_aut;
r.d->aut = new tgba_explicit_number(dict);
r.d->accsets = 0;
r.env = &env;
dstaryy::parser parser(error_list, r);
parser.set_debug_level(debug);
parser.parse();
dstaryyclose();
if (!r.d->aut || !r.d->accsets)
{
delete r.d;
return 0;
}
return r.d;
}
}
// Local Variables:
// mode: c++
// End:
/* Copyright (C) 2013 Laboratoire de Recherche et Dveloppement
** de l'Epita (LRDE).
**
** 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 <http://www.gnu.org/licenses/>.
*/
%option noyywrap
%option prefix="dstaryy"
%option outfile="lex.yy.c"
/* %option debug */
%{
#include <string>
#include "dstarparse/parsedecl.hh"
#define YY_USER_ACTION yylloc->columns(yyleng);
#define YY_NEVER_INTERACTIVE 1
typedef dstaryy::parser::token token;
%}
eol \n|\r|\n\r|\r\n
%x in_COMMENT in_STRING
%%
%{
std::string s;
yylloc->step();
%}
{eol} yylloc->lines(yyleng); return token::EOL;
/* skip blanks and comments */
[ \t]+ yylloc->step();
"/*" BEGIN(in_COMMENT);
"//".* continue;
"Comment:".* yylloc->step();
"DRA" return token::DRA;
"DSA" return token::DSA;
"v2" return token::V2;
"explicit" return token::EXPLICIT;
"Acceptance-Pairs:" return token::ACCPAIRS;
"AP:" return token::AP;
"Start:" return token::START;
"States:" return token::STATES;
"State:" return token::STATE;
"Acc-Sig:" return token::ACCSIG;
"---" return token::ENDOFHEADER;
[0-9]+ {
errno = 0;
unsigned long n = strtoul(yytext, 0, 10);
yylval->num = n;
if (errno || yylval->num != n)
{
error_list.push_back(
spot::dstar_parse_error(*yylloc,
"value too large"));
yylval->num = 0;
}
return token::NUMBER;
}
"\"" BEGIN(in_STRING);
<in_COMMENT>{
[^*\n]* continue;
"*"+[^*/\n]* continue;
"\n"+ yylloc->end.column = 1; yylloc->lines(yyleng);
"*"+"/" BEGIN(INITIAL);
<<EOF>> {
error_list.push_back(
spot::dstar_parse_error(*yylloc,
"unclosed comment"));
return 0;
}
}
<in_STRING>{
\" {
BEGIN(INITIAL);
yylval->str = new std::string(s);
return token::STRING;
}
\\\" s += '"';
\\. s += yytext[1];
[^\\\"]+ s.append(yytext, yyleng);
<<EOF>> {
error_list.push_back(
spot::dstar_parse_error(*yylloc,
"unclosed string"));
return 0;
}
}
. return *yytext;
%{
/* Dummy use of yyunput to shut up a gcc warning. */
(void) &yyunput;
%}
%%
namespace spot
{
int
dstaryyopen(const std::string &name)
{
// yy_flex_debug = 1;
if (name == "-")
{
yyin = stdin;
}
else
{
yyin = fopen(name.c_str(), "r");
if (!yyin)
return 1;
}
// Reset the lexer in case a previous parse
// ended badly.
YY_NEW_FILE;
BEGIN(INITIAL);
return 0;
}
void
dstaryyclose()
{
fclose(yyin);
}
}
// Copyright (C) 2013 Laboratoire de Recherche et Dveloppement de
// l'Epita (LRDE).
//
// 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 <http://www.gnu.org/licenses/>.
#include <ostream>
#include "public.hh"
namespace spot
{
bool
format_dstar_parse_errors(std::ostream& os,
const std::string& filename,
dstar_parse_error_list& error_list)
{
bool printed = false;
spot::dstar_parse_error_list::iterator it;
for (it = error_list.begin(); it != error_list.end(); ++it)
{
if (filename != "-")
os << filename << ":";
os << it->first << ": ";
os << it->second << std::endl;
printed = true;
}
return printed;
}
}
// Copyright (C) 2013 Laboratoire de Recherche et Développement de
// l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//