Commit 2fbcd7e5 authored by Damien Lefortier's avatar Damien Lefortier
Browse files

Add support for ELTL (AST & parser), and an adaptation of LaCIM

for ELTL.  This is a new version of the work started in 2008 with
LTL and ELTL formulae now sharing the same class hierarchy.

* configure.ac: Adjust for src/eltlparse/ and src/eltltest/
directories, and call AX_BOOST_BASE.
* m4/boost.m4: New file defining AX_BOOST_BASE([MINIMUM-VERSION]).
* src/Makefile.am: Add eltlparse and eltltest.
* src/eltlparse/: New directory.  Contains the ELTL parser.
* src/eltltest/: New directory.  Contains tests related to
ELTL (parser and AST).
* src/ltlast/Makefile.am: Adjust for ELTL AST files.
* src/ltlast/automatop.cc, src/ltlast/automatop.hh: New files.
Represent automaton operators nodes used in ELTL ASTs.
* src/ltlast/nfa.cc, src/ltlast/nfa.hh: New files.  Represent
simple NFAs used internally by automatop nodes.
* src/ltlast/allnode.hh, src/ltlast/predecl.hh,
src/ltlast/visitor.hh: Adjust for automatop.
* src/ltlvisit/basicreduce.cc, src/ltlvisit/clone.cc,
src/ltlvisit/clone.hh, src/ltlvisit/contain.cc,
src/ltlvisit/dotty.cc, src/ltlvisit/nenoform.cc,
src/ltlvisit/postfix.cc, src/ltlvisit/postfix.hh,
src/ltlvisit/reduce.cc, src/ltlvisit/syntimpl.cc,
src/ltlvisit/tostring.cc: Because LTL and ELTL formulae share the
same class hierarchy, LTL visitors need to handle automatop nodes
to compile.  When it's meaningful the visitor applies on automatop
nodes or simply assert(0) otherwise.
* src/tgba/tgbabddconcretefactory.cc (create_anonymous_state),
src/tgba/tgbabddconcretefactory.hh (create_anonymous_state): New
function used by the LaCIM translation algorithm for ELTL.
* src/tgbaalgos/Makefile.am: Adjust for eltl2tgba_lacim* files.
* src/tgbaalgos/eltl2tgba_lacim.cc,
src/tgbaalgos/eltl2tgba_lacim.hh: New files.  Implementation of
the LaCIM translation algorithm for ELTL.
* src/tgbaalgos/ltl2tgba_fm.cc, src/tgbaalgos/ltl2tgba_lacim.cc:
Handle automatop nodes in the translation by an assert(0).
* src/tgbatest/Makefile.am: Adjust for eltl2tgba.* files.
* src/src/tgbatest/eltl2tgba.cc, src/tgbatest/eltl2tgba.test: New
files
parent 90332d8d
2009-03-26 Damien Lefortier <dam@lrde.epita.fr>
Add support for ELTL (AST & parser), and an adaptation of LaCIM
for ELTL.
* configure.ac: Adjust for src/eltlparse/ and src/eltltest/
directories, and call AX_BOOST_BASE.
* m4/boost.m4: New file defining AX_BOOST_BASE([MINIMUM-VERSION]).
* src/Makefile.am: Add eltlparse and eltltest.
* src/eltlparse/: New directory. Contains the ELTL parser.
* src/eltltest/: New directory. Contains tests related to
ELTL (parser and AST).
* src/ltlast/Makefile.am: Adjust for ELTL AST files.
* src/ltlast/automatop.cc, src/ltlast/automatop.hh: New files.
Represent automaton operators nodes used in ELTL ASTs.
* src/ltlast/nfa.cc, src/ltlast/nfa.hh: New files. Represent
simple NFAs used internally by automatop nodes.
* src/ltlast/allnode.hh, src/ltlast/predecl.hh,
src/ltlast/visitor.hh: Adjust for automatop.
* src/ltlvisit/basicreduce.cc, src/ltlvisit/clone.cc,
src/ltlvisit/clone.hh, src/ltlvisit/contain.cc,
src/ltlvisit/dotty.cc, src/ltlvisit/nenoform.cc,
src/ltlvisit/postfix.cc, src/ltlvisit/postfix.hh,
src/ltlvisit/reduce.cc, src/ltlvisit/syntimpl.cc,
src/ltlvisit/tostring.cc: Because LTL and ELTL formulae share the
same class hierarchy, LTL visitors need to handle automatop nodes
to compile. When it's meaningful the visitor applies on automatop
nodes or simply assert(0) otherwise.
* src/tgba/tgbabddconcretefactory.cc (create_anonymous_state),
src/tgba/tgbabddconcretefactory.hh (create_anonymous_state): New
function used by the LaCIM translation algorithm for ELTL.
* src/tgbaalgos/Makefile.am: Adjust for eltl2tgba_lacim* files.
* src/tgbaalgos/eltl2tgba_lacim.cc,
src/tgbaalgos/eltl2tgba_lacim.hh: New files. Implementation of
the LaCIM translation algorithm for ELTL.
* src/tgbaalgos/ltl2tgba_fm.cc, src/tgbaalgos/ltl2tgba_lacim.cc:
Handle automatop nodes in the translation by an assert(0).
* src/tgbatest/Makefile.am: Adjust for eltl2tgba.* files.
* src/src/tgbatest/eltl2tgba.cc, src/tgbatest/eltl2tgba.test: New
files.
2009-03-25 Alexandre Duret-Lutz <adl@lrde.epita.fr>
* src/evtgbaparse/evtgbaparse.yy: Stay on 80 columns.
......
......@@ -44,6 +44,7 @@ AC_LANG(C++)
AX_CHECK_BUDDY
AX_CHECK_LBTT
AX_CHECK_GSPNLIB
AX_BOOST_BASE([1.34])
AC_CHECK_FUNCS([srand48 drand48])
......@@ -86,6 +87,9 @@ AC_CONFIG_FILES([
iface/nips/nipstest/Makefile
iface/nips/nipstest/defs
src/Makefile
src/eltlparse/Makefile
src/eltltest/Makefile
src/eltltest/defs
src/evtgba/Makefile
src/evtgbaalgos/Makefile
src/evtgbaparse/Makefile
......
##### http://autoconf-archive.cryp.to/ax_boost_base.html
#
# SYNOPSIS
#
# AX_BOOST_BASE([MINIMUM-VERSION])
#
# DESCRIPTION
#
# Test for the Boost C++ libraries of a particular version (or newer)
#
# If no path to the installed boost library is given the macro
# searchs under /usr, /usr/local, /opt and /opt/local and evaluates
# the $BOOST_ROOT environment variable. Further documentation is
# available at <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
#
# And sets:
#
# HAVE_BOOST
#
# LAST MODIFICATION
#
# 2007-07-28
#
# COPYLEFT
#
# Copyright (c) 2007 Thomas Porschberg <thomas@randspringer.de>
#
# Copying and distribution of this file, with or without
# modification, are permitted in any medium without royalty provided
# the copyright notice and this notice are preserved.
AC_DEFUN([AX_BOOST_BASE],
[
AC_ARG_WITH([boost],
AS_HELP_STRING([--with-boost@<:@=DIR@:>@], [use boost (default is yes) - it is possible to specify the root directory for boost (optional)]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ac_boost_path=""
else
want_boost="yes"
ac_boost_path="$withval"
fi
],
[want_boost="yes"])
if test "x$want_boost" = "xyes"; then
boost_lib_version_req=ifelse([$1], ,1.20.0,$1)
boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'`
boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'`
boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
if test "x$boost_lib_version_req_sub_minor" = "x" ; then
boost_lib_version_req_sub_minor="0"
fi
WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor`
AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req)
succeeded=no
dnl first we check the system location for boost libraries
dnl this location ist chosen if boost libraries are installed with the --layout=system option
dnl or if you install boost with RPM
if test "$ac_boost_path" != ""; then
BOOST_LDFLAGS="-L$ac_boost_path/lib"
BOOST_CPPFLAGS="-I$ac_boost_path/include"
else
for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then
BOOST_LDFLAGS="-L$ac_boost_path_tmp/lib"
BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
break;
fi
done
fi
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@%:@include <boost/version.hpp>
]], [[
#if BOOST_VERSION >= $WANT_BOOST_VERSION
// Everything is okay
#else
# error Boost version is too old
#endif
]])],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
dnl if we found no boost with system layout we search for boost libraries
dnl built and installed without the --layout=system option or for a staged(not installed) version
if test "x$succeeded" != "xyes"; then
_version=0
if test "$ac_boost_path" != ""; then
BOOST_LDFLAGS="-L$ac_boost_path/lib"
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "$V_CHECK" = "1" ; then
_version=$_version_tmp
fi
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
done
fi
else
for ac_boost_path in /usr /usr/local /opt /opt/local ; do
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "$V_CHECK" = "1" ; then
_version=$_version_tmp
best_path=$ac_boost_path
fi
done
fi
done
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
BOOST_LDFLAGS="-L$best_path/lib"
if test "x$BOOST_ROOT" != "x"; then
if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/lib" && test -r "$BOOST_ROOT/stage/lib"; then
version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
V_CHECK=`expr $stage_version_shorten \>\= $_version`
if test "$V_CHECK" = "1" ; then
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
BOOST_CPPFLAGS="-I$BOOST_ROOT"
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/lib"
fi
fi
fi
fi
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@%:@include <boost/version.hpp>
]], [[
#if BOOST_VERSION >= $WANT_BOOST_VERSION
// Everything is okay
#else
# error Boost version is too old
#endif
]])],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
fi
if test "$succeeded" != "yes" ; then
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
if test "$_version" = "0" ; then
AC_MSG_ERROR([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
else
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
fi
else
AC_SUBST(BOOST_CPPFLAGS)
AC_SUBST(BOOST_LDFLAGS)
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
fi
fi
])
......@@ -23,10 +23,10 @@ AUTOMAKE_OPTIONS = subdir-objects
# List directories in the order they must be built.
# Keep tests at the end.
SUBDIRS = misc ltlenv ltlast ltlvisit ltlparse \
SUBDIRS = misc ltlenv ltlast ltlvisit ltlparse eltlparse \
tgba tgbaalgos tgbaparse \
evtgba evtgbaalgos evtgbaparse . \
ltltest tgbatest evtgbatest sanity
ltltest eltltest tgbatest evtgbatest sanity
lib_LTLIBRARIES = libspot.la
libspot_la_SOURCES =
......@@ -37,6 +37,7 @@ libspot_la_LIBADD = \
ltlparse/libltlparse.la \
ltlvisit/libltlvisit.la \
ltlast/libltlast.la \
eltlparse/libeltlparse.la \
tgba/libtgba.la \
tgbaalgos/libtgbaalgos.la \
tgbaparse/libtgbaparse.la \
......
## Copyright (C) 2008 Laboratoire d'Informatique de Paris 6 (LIP6),
## dpartement Systmes Rpartis Coopratifs (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 2 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 Spot; see the file COPYING. If not, write to the Free
## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
## 02111-1307, USA.
AM_CPPFLAGS = -I$(srcdir)/..
AM_CXXFLAGS = #$(WARNING_CXXFLAGS)
eltlparsedir = $(pkgincludedir)/eltlparse
noinst_LTLIBRARIES = libeltlparse.la
ELTLPARSE_YY = eltlparse.yy
FROM_ELTLPARSE_YY_MAIN = eltlparse.cc
FROM_ELTLPARSE_YY_OTHERS = \
stack.hh \
position.hh \
location.hh \
eltlparse.hh
FROM_ELTLPARSE_YY = $(FROM_ELTLPARSE_YY_MAIN) $(FROM_ELTLPARSE_YY_OTHERS)
BUILT_SOURCES = $(FROM_ELTLPARSE_YY)
MAINTAINERCLEANFILES = $(FROM_ELTLPARSE_YY)
$(FROM_ELTLPARSE_YY_MAIN): $(srcdir)/$(ELTLPARSE_YY)
## We must cd into $(srcdir) first because if we tell bison to read
## $(srcdir)/$(ELTLPARSE_YY), it will also use the value of $(srcdir)/
## in the generated include statements.
cd $(srcdir) && \
bison -Wall -Werror --report=all \
$(ELTLPARSE_YY) -o $(FROM_ELTLPARSE_YY_MAIN)
$(FROM_ELTLPARSE_YY_OTHERS): $(ELTLPARSE_YY)
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) $(FROM_ELTLPARSE_YY_MAIN)
EXTRA_DIST = $(ELTLPARSE_YY)
libeltlparse_la_SOURCES = \
fmterror.cc \
$(FROM_ELTLPARSE_YY) \
eltlscan.ll \
parsedecl.hh
eltlparse_HEADERS = \
public.hh \
location.hh \
position.hh
/* Copyright (C) 2008 Laboratoire d'Informatique de
** Paris 6 (LIP6), dpartement Systmes Rpartis Coopratifs (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 2 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 Spot; see the file COPYING. If not, write to the Free
** Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
** 02111-1307, USA.
*/
%language "C++"
%locations
%defines
%name-prefix "eltlyy"
%debug
%error-verbose
%code requires
{
#include <string>
#include <sstream>
#include <limits>
#include <cerrno>
#include "public.hh"
#include "ltlast/allnodes.hh"
#include "ltlvisit/destroy.hh"
// Implementation details for error handling.
namespace spot
{
namespace eltl
{
struct parse_error_list_t
{
parse_error_list list_;
std::string file_;
};
}
}
#define PARSE_ERROR(Loc, Msg) \
pe.list_.push_back \
(parse_error(Loc, spair(pe.file_, Msg)))
}
%parse-param {spot::eltl::nfamap& nmap}
%parse-param {spot::eltl::parse_error_list_t &pe}
%parse-param {spot::ltl::environment &parse_environment}
%parse-param {spot::ltl::formula* &result}
%lex-param {spot::eltl::parse_error_list_t &pe}
%expect 0
%pure-parser
%union
{
int ival;
std::string* sval;
spot::ltl::nfa* nval;
spot::ltl::automatop::vec* aval;
spot::ltl::formula* fval;
}
%code {
/* ltlparse.hh and parsedecl.hh include each other recursively.
We mut ensure that YYSTYPE is declared (by the above %union)
before parsedecl.hh uses it. */
#include "parsedecl.hh"
using namespace spot::eltl;
using namespace spot::ltl;
}
/* All tokens. */
%token <sval> ATOMIC_PROP "atomic proposition"
IDENT "identifier"
%token <ival> ARG "argument"
STATE "state"
OP_OR "or operator"
OP_XOR "xor operator"
OP_AND "and operator"
OP_IMPLIES "implication operator"
OP_EQUIV "equivalent operator"
OP_NOT "not operator"
%token ACC "accept"
EQ "="
LPAREN "("
RPAREN ")"
COMMA ","
END_OF_FILE "end of file"
CONST_TRUE "constant true"
CONST_FALSE "constant false"
/* Priorities. */
/* Logical operators. */
%left OP_OR
%left OP_XOR
%left OP_AND
%left OP_IMPLIES OP_EQUIV
%nonassoc OP_NOT
%type <nval> nfa_def
%type <fval> subformula
%type <aval> arg_list
%destructor { delete $$; } "atomic proposition"
%destructor { spot::ltl::destroy($$); } subformula
%printer { debug_stream() << *$$; } "atomic proposition"
%%
result: nfa_list subformula
{
result = $2;
YYACCEPT;
}
;
/* NFA definitions. */
nfa_list: /* empty. */
| nfa_list nfa
;
nfa: IDENT "=" "(" nfa_def ")"
{
$4->set_name(*$1);
nmap[*$1] = nfa::ptr($4);
delete $1;
}
;
nfa_def: /* empty. */
{
$$ = new nfa();
}
| nfa_def STATE STATE ARG
{
if ($4 == -1 || $3 == -1 || $2 == -1)
{
std::string s = "out of range integer";
PARSE_ERROR(@1, s);
YYERROR;
}
$1->add_transition($2, $3, $4);
$$ = $1;
}
| nfa_def STATE STATE CONST_TRUE
{
$1->add_transition($2, $3, -1);
$$ = $1;
}
| nfa_def ACC STATE
{
$1->set_final($3);
$$ = $1;
}
;
/* Formulae. */
subformula: ATOMIC_PROP
{
$$ = parse_environment.require(*$1);
if (!$$)
{
std::string s = "unknown atomic proposition `";
s += *$1;
s += "' in environment `";
s += parse_environment.name();
s += "'";
PARSE_ERROR(@1, s);
delete $1;
YYERROR;
}
else
delete $1;
}
| ATOMIC_PROP "(" arg_list ")"
{
nfamap::iterator i = nmap.find(*$1);
if (i == nmap.end())
{
std::string s = "unknown automaton operator `";
s += *$1;
s += "'";
PARSE_ERROR(@1, s);
delete $1;
YYERROR;
}
automatop* res = automatop::instance(i->second, $3);
if (res->size() != i->second->arity())
{
std::ostringstream oss1;
oss1 << res->size();
std::ostringstream oss2;
oss2 << i->second->arity();
std::string s(*$1);
s += " is used with ";
s += oss1.str();
s += " arguments, but has an arity of ";
s += oss2.str();
PARSE_ERROR(@1, s);
delete $1;
delete $3;
YYERROR;
}
delete $1;
$$ = res;
}
| CONST_TRUE
{ $$ = constant::true_instance(); }
| CONST_FALSE
{ $$ = constant::false_instance(); }
| "(" subformula ")"
{ $$ = $2; }
| subformula OP_AND subformula
{ $$ = multop::instance(multop::And, $1, $3); }
| subformula OP_OR subformula
{ $$ = multop::instance(multop::Or, $1, $3); }
| subformula OP_XOR subformula
{ $$ = binop::instance(binop::Xor, $1, $3); }
| subformula OP_IMPLIES subformula
{ $$ = binop::instance(binop::Implies, $1, $3); }
| subformula OP_EQUIV subformula
{ $$ = binop::instance(binop::Equiv, $1, $3); }
| OP_NOT subformula
{ $$ = unop::instance(unop::Not, $2); }
;
arg_list: subformula
{
// TODO: delete it whenever a parse error occurs on a subformula.
$$ = new automatop::vec;
$$->push_back($1);
}
| arg_list "," subformula
{
$1->push_back($3);
$$ = $1;
}
;
%%
void
eltlyy::parser::error(const location_type& loc, const std::string& s)
{
PARSE_ERROR(loc, s);
}
namespace spot
{
namespace eltl
{
formula*
parse_file(const std::string& name,
parse_error_list& error_list,
environment& env,
bool debug)
{
if (flex_open(name))
{
error_list.push_back
(parse_error(eltlyy::location(),
spair("-", std::string("Cannot open file ") + name)));
return 0;
}
formula* result = 0;
nfamap nmap;
parse_error_list_t pe;
pe.file_ = name;
eltlyy::parser parser(nmap, pe, env, result);
parser.set_debug_level(debug);
parser.parse();
error_list = pe.list_;
flex_close();
return result;
}
formula*
parse_string(const std::string& eltl_string,
parse_error_list& error_list,
environment& env,
bool debug)
{
flex_scan_string(eltl_string.c_str());
formula* result = 0;
nfamap nmap;
parse_error_list_t pe;
eltlyy::parser parser(nmap, pe, env, result);