* configure.ac: Output src/tgbaparse/Makefile.
* src/Makefile.am (SUBDIRS): Add tgbaparse. (libspot_la_LDADD): Add tgbaparse/libtgbaparse.la. * src/tgba/tgbaexplicit.cc (tgba_explicit::get_condition, tgba_explicit::get_promise, tgba_explicit::add_neg_condition, tgba_explicit::add_neg_promise): New methods. * src/tgba/tgbaexplicit.hh: Declare them. * src/tgbaparse/Makefile.am, src/tgbaparse/fmterror.cc, src/tgbaparse/parsedecl.hh, src/tgbaparse/public.hh, src/tgbaparse/tgbaparse.yy, src/tgbaparse/tgbascan.ll, src/tgbatest/tgbaread.cc, src/tgbatest/tgbaread.test: New files. * src/tgbatest/Makefile.am (check_PROGRAMS): Add tgbaread. (TESTS): Add tgbaread.cc. (CLEANFILES): Add input. (tgbaread_SOURCES): New variable.
This commit is contained in:
parent
cebffb11e8
commit
6884a7f985
18 changed files with 495 additions and 14 deletions
16
ChangeLog
16
ChangeLog
|
|
@ -1,5 +1,21 @@
|
|||
2003-06-05 Alexandre Duret-Lutz <aduret@src.lip6.fr>
|
||||
|
||||
* configure.ac: Output src/tgbaparse/Makefile.
|
||||
* src/Makefile.am (SUBDIRS): Add tgbaparse.
|
||||
(libspot_la_LDADD): Add tgbaparse/libtgbaparse.la.
|
||||
* src/tgba/tgbaexplicit.cc (tgba_explicit::get_condition,
|
||||
tgba_explicit::get_promise, tgba_explicit::add_neg_condition,
|
||||
tgba_explicit::add_neg_promise): New methods.
|
||||
* src/tgba/tgbaexplicit.hh: Declare them.
|
||||
* src/tgbaparse/Makefile.am, src/tgbaparse/fmterror.cc,
|
||||
src/tgbaparse/parsedecl.hh, src/tgbaparse/public.hh,
|
||||
src/tgbaparse/tgbaparse.yy, src/tgbaparse/tgbascan.ll,
|
||||
src/tgbatest/tgbaread.cc, src/tgbatest/tgbaread.test: New files.
|
||||
* src/tgbatest/Makefile.am (check_PROGRAMS): Add tgbaread.
|
||||
(TESTS): Add tgbaread.cc.
|
||||
(CLEANFILES): Add input.
|
||||
(tgbaread_SOURCES): New variable.
|
||||
|
||||
* src/ltlparse/ltlparse.yy: Typo in comment.
|
||||
|
||||
* configure.ac: Output src/tgbatest/Makefile and src/tgbatest/defs.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ AC_CONFIG_FILES([
|
|||
src/ltlvisit/Makefile
|
||||
src/tgba/Makefile
|
||||
src/tgbaalgos/Makefile
|
||||
src/tgbaparse/Makefile
|
||||
src/tgbatest/Makefile
|
||||
src/tgbatest/defs
|
||||
src/misc/Makefile
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = subdir-objects
|
|||
|
||||
# List directories in the order they must be built.
|
||||
# Keep tests at the end.
|
||||
SUBDIRS = misc ltlenv ltlast ltlvisit ltlparse tgba tgbaalgos . \
|
||||
SUBDIRS = misc ltlenv ltlast ltlvisit ltlparse tgba tgbaalgos tgbaparse . \
|
||||
ltltest tgbatest
|
||||
|
||||
lib_LTLIBRARIES = libspot.la
|
||||
|
|
@ -13,4 +13,5 @@ libspot_la_LIBADD = \
|
|||
ltlvisit/libltlvisit.la \
|
||||
ltlast/libltlast.la \
|
||||
tgba/libtgba.la \
|
||||
tgbaalgos/libtgbaalgos.la
|
||||
tgbaalgos/libtgbaalgos.la \
|
||||
tgbaparse/libtgbaparse.la
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ main(int argc, char** argv)
|
|||
spot::ltl::formula* f = spot::ltl::parse(argv[formula_index],
|
||||
pel, env, debug);
|
||||
|
||||
spot::ltl::parse_error_list::iterator it;
|
||||
exit_code =
|
||||
spot::ltl::format_parse_errors(std::cerr, argv[formula_index], pel);
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ namespace spot
|
|||
return t;
|
||||
}
|
||||
|
||||
void tgba_explicit::add_condition(transition* t, ltl::formula* f)
|
||||
int tgba_explicit::get_condition(ltl::formula* f)
|
||||
{
|
||||
assert(dynamic_cast<ltl::atomic_prop*>(f));
|
||||
tgba_bdd_dict::fv_map::iterator i = dict_.var_map.find(f);
|
||||
|
|
@ -137,10 +137,20 @@ namespace spot
|
|||
{
|
||||
v = i->second;
|
||||
}
|
||||
t->condition &= ithvar(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
void tgba_explicit::add_promise(transition* t, ltl::formula* f)
|
||||
void tgba_explicit::add_condition(transition* t, ltl::formula* f)
|
||||
{
|
||||
t->condition &= ithvar(get_condition(f));
|
||||
}
|
||||
|
||||
void tgba_explicit::add_neg_condition(transition* t, ltl::formula* f)
|
||||
{
|
||||
t->condition &= ! ithvar(get_condition(f));
|
||||
}
|
||||
|
||||
int tgba_explicit::get_promise(ltl::formula* f)
|
||||
{
|
||||
tgba_bdd_dict::fv_map::iterator i = dict_.prom_map.find(f);
|
||||
int v;
|
||||
|
|
@ -154,7 +164,17 @@ namespace spot
|
|||
{
|
||||
v = i->second;
|
||||
}
|
||||
t->promise &= ithvar(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
void tgba_explicit::add_promise(transition* t, ltl::formula* f)
|
||||
{
|
||||
t->promise &= ithvar(get_promise(f));
|
||||
}
|
||||
|
||||
void tgba_explicit::add_neg_promise(transition* t, ltl::formula* f)
|
||||
{
|
||||
t->promise &= ! ithvar(get_promise(f));
|
||||
}
|
||||
|
||||
state*
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@ namespace spot
|
|||
create_transition(const std::string& source, const std::string& dest);
|
||||
|
||||
void add_condition(transition* t, ltl::formula* f);
|
||||
void add_neg_condition(transition* t, ltl::formula* f);
|
||||
void add_promise(transition* t, ltl::formula* f);
|
||||
void add_neg_promise(transition* t, ltl::formula* f);
|
||||
|
||||
// tgba interface
|
||||
virtual ~tgba_explicit();
|
||||
|
|
@ -44,6 +46,9 @@ namespace spot
|
|||
|
||||
protected:
|
||||
state* add_state(const std::string& name);
|
||||
int get_condition(ltl::formula* f);
|
||||
int get_promise(ltl::formula* f);
|
||||
|
||||
typedef std::map<const std::string, tgba_explicit::state*> ns_map;
|
||||
typedef std::map<const tgba_explicit::state*, std::string> sn_map;
|
||||
ns_map name_state_map_;
|
||||
|
|
|
|||
13
src/tgbaparse/.cvsignore
Normal file
13
src/tgbaparse/.cvsignore
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
location.hh
|
||||
tgbaparse.cc
|
||||
tgbaparse.hh
|
||||
tgbaparse.output
|
||||
tgbascan.cc
|
||||
position.hh
|
||||
stack.hh
|
||||
*.lo
|
||||
*.la
|
||||
.libs
|
||||
31
src/tgbaparse/Makefile.am
Normal file
31
src/tgbaparse/Makefile.am
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
AM_CPPFLAGS = -I$(srcdir)/..
|
||||
AM_CXXFLAGS = $(WARNING_CXXFLAGS)
|
||||
|
||||
noinst_LTLIBRARIES = libtgbaparse.la
|
||||
|
||||
TGBAPARSE_YY = tgbaparse.yy
|
||||
FROM_TGBAPARSE_YY_MAIN = tgbaparse.cc
|
||||
FROM_TGBAPARSE_YY_OTHERS = \
|
||||
stack.hh \
|
||||
position.hh \
|
||||
location.hh \
|
||||
tgbaparse.hh
|
||||
FROM_TGBAPARSE_YY = $(FROM_TGBAPARSE_YY_MAIN) $(FROM_TGBAPARSE_YY_OTHERS)
|
||||
|
||||
BUILT_SOURCES = $(FROM_TGBAPARSE_YY)
|
||||
MAINTAINERCLEANFILES = $(FROM_TGBAPARSE_YY)
|
||||
|
||||
$(FROM_TGBAPARSE_YY_MAIN): $(srcdir)/$(TGBAPARSE_YY)
|
||||
bison --defines --locations --skeleton=lalr1.cc --report=all \
|
||||
$(srcdir)/$(TGBAPARSE_YY) -o $@
|
||||
$(FROM_TGBAPARSE_YY_OTHERS): $(TGBAPARSE_YY)
|
||||
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) $(FROM_TGBAPARSE_YY_MAIN)
|
||||
|
||||
EXTRA_DIST = $(TGBAPARSE_YY)
|
||||
|
||||
libtgbaparse_la_SOURCES = \
|
||||
fmterror.cc \
|
||||
$(FROM_TGBAPARSE_YY) \
|
||||
tgbascan.ll \
|
||||
parsedecl.hh \
|
||||
public.hh
|
||||
20
src/tgbaparse/fmterror.cc
Normal file
20
src/tgbaparse/fmterror.cc
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "public.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
bool
|
||||
format_tgba_parse_errors(std::ostream& os,
|
||||
tgba_parse_error_list& error_list)
|
||||
{
|
||||
bool printed = false;
|
||||
spot::tgba_parse_error_list::iterator it;
|
||||
for (it = error_list.begin(); it != error_list.end(); ++it)
|
||||
{
|
||||
if (it->first.begin.filename != "")
|
||||
os << it->first << ": ";
|
||||
os << it->second << std::endl;
|
||||
printed = true;
|
||||
}
|
||||
return printed;
|
||||
}
|
||||
}
|
||||
32
src/tgbaparse/parsedecl.hh
Normal file
32
src/tgbaparse/parsedecl.hh
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef SPOT_TGBAPARSE_PARSEDECL_HH
|
||||
# define SPOT_TGBAPARSE_PARSEDECL_HH
|
||||
|
||||
#include <string>
|
||||
#include "tgbaparse.hh"
|
||||
#include "location.hh"
|
||||
|
||||
# define YY_DECL \
|
||||
int tgbayylex (yystype *yylval, yy::Location *yylloc)
|
||||
YY_DECL;
|
||||
|
||||
namespace spot
|
||||
{
|
||||
int tgbayyopen(const std::string& name);
|
||||
void tgbayyclose();
|
||||
}
|
||||
|
||||
|
||||
// Gross kludge to compile yy::Parser in another namespace (tgbayy::)
|
||||
// but still use yy::Location. The reason is that Bison's C++
|
||||
// skeleton does not support anything close to %name-prefix at the
|
||||
// moment. All parser are named yy::Parser which makes it somewhat
|
||||
// difficult to define multiple parsers.
|
||||
namespace tgbayy
|
||||
{
|
||||
using namespace yy;
|
||||
}
|
||||
#define yy tgbayy
|
||||
|
||||
|
||||
|
||||
#endif // SPOT_TGBAPARSE_PARSEDECL_HH
|
||||
49
src/tgbaparse/public.hh
Normal file
49
src/tgbaparse/public.hh
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef SPOT_TGBAPARSE_PUBLIC_HH
|
||||
# define SPOT_TGBAPARSE_PUBLIC_HH
|
||||
|
||||
# include "tgba/tgbaexplicit.hh"
|
||||
# include "location.hh"
|
||||
# include "ltlenv/defaultenv.hh"
|
||||
# include <string>
|
||||
# include <list>
|
||||
# include <utility>
|
||||
# include <iostream>
|
||||
|
||||
namespace spot
|
||||
{
|
||||
/// \brief A parse diagnostic with its location.
|
||||
typedef std::pair<yy::Location, std::string> tgba_parse_error;
|
||||
/// \brief A list of parser diagnostics, as filled by parse.
|
||||
typedef std::list<tgba_parse_error> tgba_parse_error_list;
|
||||
|
||||
/// \brief Build a spot::tgba_explicit from a text file.
|
||||
/// \param filename The name of the file to parse.
|
||||
/// \param error_list A list that will be filled with
|
||||
/// parse errors that occured during parsing.
|
||||
/// \param env The environment into which parsing should take place.
|
||||
/// \param debug When true, causes the parser to trace its execution.
|
||||
/// \return A pointer to the tgba built from \a filename, or
|
||||
/// 0 if the file could not be opened.
|
||||
///
|
||||
/// Note that the parser usually tries to recover from errors. It can
|
||||
/// return an non zero value even if it encountered error during the
|
||||
/// parsing of \a filename. If you want to make sure \a filename
|
||||
/// was parsed succesfully, check \a error_list for emptiness.
|
||||
///
|
||||
/// \warning This function is not reentrant.
|
||||
tgba_explicit* tgba_parse(const std::string& filename,
|
||||
tgba_parse_error_list& error_list,
|
||||
ltl::environment& env
|
||||
= ltl::default_environment::instance(),
|
||||
bool debug = false);
|
||||
|
||||
/// \brief Format diagnostics produced by spot::tgba_parse.
|
||||
/// \param os Where diagnostics should be output.
|
||||
/// \param error_list The error list filled by spot::ltl::parse while
|
||||
/// parsing \a ltl_string.
|
||||
/// \return \c true iff any diagnostic was output.
|
||||
bool format_tgba_parse_errors(std::ostream& os,
|
||||
tgba_parse_error_list& error_list);
|
||||
}
|
||||
|
||||
#endif // SPOT_TGBAPARSE_PUBLIC_HH
|
||||
128
src/tgbaparse/tgbaparse.yy
Normal file
128
src/tgbaparse/tgbaparse.yy
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
%{
|
||||
#include <string>
|
||||
#include "public.hh"
|
||||
%}
|
||||
|
||||
%parse-param {spot::tgba_parse_error_list &error_list}
|
||||
%parse-param {spot::ltl::environment &parse_environment}
|
||||
%parse-param {spot::tgba_explicit* &result}
|
||||
%debug
|
||||
%error-verbose
|
||||
%union
|
||||
{
|
||||
int token;
|
||||
std::string* str;
|
||||
std::list<std::pair<bool, spot::ltl::formula*> >* list;
|
||||
}
|
||||
|
||||
%{
|
||||
/* tgbaparse.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::ltl;
|
||||
|
||||
/* Ugly hack so that Bison use tgbayylex, not yylex.
|
||||
(%name-prefix doesn't work for the lalr1.cc skeleton
|
||||
at the time of writing.) */
|
||||
#define yylex tgbayylex
|
||||
|
||||
typedef std::pair<bool, spot::ltl::formula*> pair;
|
||||
%}
|
||||
|
||||
%token <str> STRING
|
||||
%token <str> IDENT
|
||||
%type <str> strident
|
||||
%type <list> prop_list
|
||||
|
||||
|
||||
%%
|
||||
lines:
|
||||
| lines line
|
||||
;
|
||||
|
||||
line: strident ',' strident ',' prop_list ',' prop_list ';'
|
||||
{
|
||||
spot::tgba_explicit::transition* t
|
||||
= result->create_transition(*$1, *$3);
|
||||
std::list<pair>::iterator i;
|
||||
for (i = $5->begin(); i != $5->end(); ++i)
|
||||
if (i->first)
|
||||
result->add_neg_condition(t, i->second);
|
||||
else
|
||||
result->add_condition(t, i->second);
|
||||
for (i = $7->begin(); i != $7->end(); ++i)
|
||||
if (i->first)
|
||||
result->add_neg_promise(t, i->second);
|
||||
else
|
||||
result->add_promise(t, i->second);
|
||||
delete $1;
|
||||
delete $3;
|
||||
delete $5;
|
||||
delete $7;
|
||||
}
|
||||
;
|
||||
|
||||
strident: STRING | IDENT;
|
||||
|
||||
prop_list:
|
||||
{
|
||||
$$ = new std::list<pair>;
|
||||
}
|
||||
| prop_list IDENT
|
||||
{
|
||||
$1->push_back(pair(false, parse_environment.require(*$2)));
|
||||
delete $2;
|
||||
$$ = $1;
|
||||
}
|
||||
| prop_list '!' IDENT
|
||||
{
|
||||
$1->push_back(pair(true, parse_environment.require(*$3)));
|
||||
delete $3;
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void
|
||||
yy::Parser::print_()
|
||||
{
|
||||
if (looka_ == STRING || looka_ == IDENT)
|
||||
YYCDEBUG << " '" << *value.str << "'";
|
||||
}
|
||||
|
||||
void
|
||||
yy::Parser::error_()
|
||||
{
|
||||
error_list.push_back(spot::tgba_parse_error(location, message));
|
||||
}
|
||||
|
||||
namespace spot
|
||||
{
|
||||
tgba_explicit*
|
||||
tgba_parse(const std::string& name,
|
||||
tgba_parse_error_list& error_list,
|
||||
environment& env,
|
||||
bool debug)
|
||||
{
|
||||
if (tgbayyopen(name))
|
||||
{
|
||||
error_list.push_back
|
||||
(tgba_parse_error(yy::Location(),
|
||||
std::string("Cannot open file ") + name));
|
||||
return 0;
|
||||
}
|
||||
tgba_explicit* result = new tgba_explicit;
|
||||
tgbayy::Parser parser(debug, yy::Location(), error_list, env, result);
|
||||
parser.parse();
|
||||
tgbayyclose();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: c++
|
||||
// End:
|
||||
81
src/tgbaparse/tgbascan.ll
Normal file
81
src/tgbaparse/tgbascan.ll
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
%option noyywrap
|
||||
%option prefix="tgbayy"
|
||||
%option outfile="lex.yy.c"
|
||||
|
||||
%{
|
||||
#include <string>
|
||||
#include "parsedecl.hh"
|
||||
|
||||
#define YY_USER_ACTION \
|
||||
yylloc->columns(yyleng);
|
||||
|
||||
#define YY_USER_INIT \
|
||||
do { \
|
||||
yylloc->begin.filename = current_file; \
|
||||
yylloc->end.filename = current_file; \
|
||||
} while (0)
|
||||
|
||||
#define YY_NEVER_INTERACTIVE 1
|
||||
|
||||
static std::string current_file;
|
||||
|
||||
%}
|
||||
|
||||
eol \n|\r|\n\r|\r\n
|
||||
|
||||
%%
|
||||
|
||||
%{
|
||||
yylloc->step ();
|
||||
%}
|
||||
|
||||
\"[^\"]*\" {
|
||||
yylval->str = new std::string(yytext + 1,
|
||||
yyleng - 2);
|
||||
return STRING;
|
||||
}
|
||||
|
||||
[a-zA-Z][a-zA-Z0-9_]* {
|
||||
yylval->str = new std::string(yytext);
|
||||
return IDENT;
|
||||
}
|
||||
|
||||
/* discard whitespace */
|
||||
{eol} yylloc->lines(yyleng); yylloc->step();
|
||||
[ \t]+ yylloc->step();
|
||||
|
||||
. return *yytext;
|
||||
|
||||
%{
|
||||
/* Dummy use of yyunput to shut up a gcc warning. */
|
||||
(void) &yyunput;
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
namespace spot
|
||||
{
|
||||
int
|
||||
tgbayyopen(const std::string &name)
|
||||
{
|
||||
if (name == "-")
|
||||
{
|
||||
yyin = stdin;
|
||||
current_file = "standard input";
|
||||
}
|
||||
else
|
||||
{
|
||||
yyin = fopen (name.c_str (), "r");
|
||||
current_file = name;
|
||||
if (!yyin)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
tgbayyclose()
|
||||
{
|
||||
fclose(yyin);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,3 +4,4 @@ Makefile.in
|
|||
defs
|
||||
explicit
|
||||
.libs
|
||||
tgbaread
|
||||
|
|
|
|||
|
|
@ -4,13 +4,16 @@ LDADD = ../libspot.la
|
|||
check_SCRIPTS = defs
|
||||
# Keep this sorted alphabetically.
|
||||
check_PROGRAMS = \
|
||||
explicit
|
||||
explicit \
|
||||
tgbaread
|
||||
|
||||
explicit_SOURCES = explicit.cc
|
||||
tgbaread_SOURCES = tgbaread.cc
|
||||
|
||||
TESTS = \
|
||||
explicit.test
|
||||
explicit.test \
|
||||
tgbaread.test
|
||||
|
||||
EXTRA_DIST = $(TESTS)
|
||||
|
||||
CLEANFILES = stdout expected
|
||||
CLEANFILES = inpu stdout expected
|
||||
|
|
|
|||
50
src/tgbatest/tgbaread.cc
Normal file
50
src/tgbatest/tgbaread.cc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#include <iostream>
|
||||
#include "tgbaparse/public.hh"
|
||||
#include "tgba/tgbaexplicit.hh"
|
||||
#include "tgbaalgos/dotty.hh"
|
||||
|
||||
void
|
||||
syntax(char* prog)
|
||||
{
|
||||
std::cerr << prog << " [-d] filename" << std::endl;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
int exit_code = 0;
|
||||
|
||||
if (argc < 2)
|
||||
syntax(argv[0]);
|
||||
|
||||
bool debug = false;
|
||||
int filename_index = 1;
|
||||
|
||||
if (!strcmp(argv[1], "-d"))
|
||||
{
|
||||
debug = true;
|
||||
if (argc < 3)
|
||||
syntax(argv[0]);
|
||||
filename_index = 2;
|
||||
}
|
||||
|
||||
spot::ltl::environment& env(spot::ltl::default_environment::instance());
|
||||
spot::tgba_parse_error_list pel;
|
||||
spot::tgba_explicit* a = spot::tgba_parse(argv[filename_index],
|
||||
pel, env, debug);
|
||||
|
||||
exit_code =
|
||||
spot::format_tgba_parse_errors(std::cerr, pel);
|
||||
|
||||
if (a)
|
||||
{
|
||||
spot::dotty_reachable(std::cout, *a);
|
||||
delete a;
|
||||
}
|
||||
else
|
||||
{
|
||||
exit_code = 1;
|
||||
}
|
||||
return exit_code;
|
||||
}
|
||||
31
src/tgbatest/tgbaread.test
Executable file
31
src/tgbatest/tgbaread.test
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
#!/bin/sh
|
||||
|
||||
. ./defs
|
||||
|
||||
set -e
|
||||
|
||||
cat >input <<EOF
|
||||
s1, "s2", a!b, c d;
|
||||
"s2", "state 3", a, !c;
|
||||
"state 3", s1,,;
|
||||
EOF
|
||||
|
||||
./tgbaread input > stdout
|
||||
|
||||
cat >expected <<EOF
|
||||
digraph G {
|
||||
size="7.26,10.69"
|
||||
0 [label="", style=invis]
|
||||
1 [label="s1"]
|
||||
0 -> 1
|
||||
2 [label="s2"]
|
||||
1 -> 2 [label="<a:1, b:0>\n<Prom[c]:1, Prom[d]:1>"]
|
||||
3 [label="state 3"]
|
||||
2 -> 3 [label="<a:1>\n<Prom[c]:0>"]
|
||||
3 -> 1 [label="T\nT"]
|
||||
}
|
||||
EOF
|
||||
|
||||
diff stdout expected
|
||||
|
||||
rm input stdout expected
|
||||
Loading…
Add table
Add a link
Reference in a new issue