hoaparse: rename to parseaut

Because this parser is not specific to HOA anymore.

* src/hoaparse/Makefile.am, src/hoaparse/fmterror.cc,
src/hoaparse/hoaparse.yy, src/hoaparse/parsedecl.hh,
src/parseaut/public.hh, src/hoaparse/hoascan.ll,
src/tests/hoaparse.test: Rename to...
* src/parseaut/Makefile.am, src/parseaut/fmterror.cc,
src/parseaut/parseaut.yy, src/parseaut/parsedecl.hh,
src/hoaparse/public.hh, src/parseaut/scanaut.ll,
src/tests/parseaut.test: ... these, and also adjust the name internally.
For instance hoa_aut_ptr is now parsed_aut_ptr; hoa_stream_parser is now
automaton_stream_parser, and hoa_parse() has become parse_aut().
* NEWS, README, configure.ac, doc/org/tut20.org, src/Makefile.am,
src/bin/autfilt.cc, src/bin/common_aoutput.cc,
src/bin/common_aoutput.hh, src/bin/common_conv.cc,
src/bin/ltlcross.cc, src/bin/ltldo.cc, src/tests/Makefile.am,
src/tests/complementation.cc, src/tests/ltl2tgba.cc,
src/tests/readsave.test, wrap/python/ajax/spot.in,
wrap/python/spot.py, wrap/python/spot_impl.i,
wrap/python/tests/automata-io.ipynb, wrap/python/tests/parsetgba.py:
Adjust.
This commit is contained in:
Alexandre Duret-Lutz 2015-06-11 08:42:39 +02:00
parent 60bd9dd606
commit a86391ab77
29 changed files with 158 additions and 156 deletions

7
src/parseaut/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
position.hh
parseaut.cc
parseaut.output
parseaut.hh
scanaut.cc
stack.hh
location.hh

57
src/parseaut/Makefile.am Normal file
View file

@ -0,0 +1,57 @@
## -*- coding: utf-8 -*-
## Copyright (C) 2013, 2014 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=)
parseautdir = $(pkgincludedir)/parseaut
parseaut_HEADERS = public.hh
noinst_LTLIBRARIES = libparseaut.la
HOAPARSE_YY = parseaut.yy
FROM_HOAPARSE_YY_MAIN = parseaut.cc
FROM_HOAPARSE_YY_OTHERS = \
stack.hh \
parseaut.hh
FROM_HOAPARSE_YY = $(FROM_HOAPARSE_YY_MAIN) $(FROM_HOAPARSE_YY_OTHERS)
BUILT_SOURCES = $(FROM_HOAPARSE_YY)
MAINTAINERCLEANFILES = $(FROM_HOAPARSE_YY)
$(FROM_HOAPARSE_YY_MAIN): $(srcdir)/$(HOAPARSE_YY)
## We must cd into $(srcdir) first because if we tell bison to read
## $(srcdir)/$(HOAPARSE_YY), it will also use the value of $(srcdir)/
## in the generated include statements.
cd $(srcdir) && \
$(BISON) -Wall -Werror -Wno-yacc --report=all $(BISON_EXTRA_FLAGS) \
$(HOAPARSE_YY) -o $(FROM_HOAPARSE_YY_MAIN)
$(FROM_HOAPARSE_YY_OTHERS): $(HOAPARSE_YY)
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) $(FROM_HOAPARSE_YY_MAIN)
EXTRA_DIST = $(HOAPARSE_YY)
libparseaut_la_SOURCES = \
fmterror.cc \
$(FROM_HOAPARSE_YY) \
scanaut.ll \
parsedecl.hh

42
src/parseaut/fmterror.cc Normal file
View file

@ -0,0 +1,42 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015 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/>.
#include <ostream>
#include "public.hh"
namespace spot
{
bool
format_parse_aut_errors(std::ostream& os,
const std::string& filename,
parse_aut_error_list& error_list)
{
bool printed = false;
spot::parse_aut_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;
}
}

1768
src/parseaut/parseaut.yy Normal file

File diff suppressed because it is too large Load diff

45
src/parseaut/parsedecl.hh Normal file
View file

@ -0,0 +1,45 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2014, 2015 Laboratoire de Recherche et Développement
// de l'EPITA.
//
// 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/>.
#pragma once
#include <string>
#include "parseaut.hh"
#include "misc/location.hh"
# define YY_DECL \
int hoayylex(hoayy::parser::semantic_type *yylval, \
spot::location *yylloc, \
spot::parse_aut_error_list& error_list)
YY_DECL;
namespace spot
{
void hoayyreset();
int hoayyopen(const std::string& name);
int hoayyopen(int fd);
int hoayystring(const char* data);
void hoayyclose();
// This exception is thrown by the lexer when it reads "--ABORT--".
struct hoa_abort
{
spot::location pos;
};
}

147
src/parseaut/public.hh Normal file
View file

@ -0,0 +1,147 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015 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/>.
#pragma once
#include "twa/twagraph.hh"
#include "misc/location.hh"
#include "ltlenv/defaultenv.hh"
#include <string>
#include <list>
#include <utility>
#include <iosfwd>
#include <misc/bitvect.hh>
namespace spot
{
/// \addtogroup twa_io
/// @{
#ifndef SWIG
/// \brief A parse diagnostic with its location.
typedef std::pair<spot::location, std::string> parse_aut_error;
/// \brief A list of parser diagnostics, as filled by parse.
typedef std::list<parse_aut_error> parse_aut_error_list;
#else
// Turn parse_aut_error_list into an opaque type for Swig.
struct parse_aut_error_list {};
#endif
/// \brief Temporary encoding of an omega automaton produced by
/// the parser.
struct SPOT_API parsed_aut
{
// Transition structure of the automaton.
// This is encoded as a TGBA without acceptance condition.
twa_graph_ptr aut;
bool aborted = false;
spot::location loc;
};
typedef std::shared_ptr<parsed_aut> parsed_aut_ptr;
typedef std::shared_ptr<const parsed_aut> const_parsed_aut_ptr;
class SPOT_API automaton_stream_parser
{
spot::location last_loc;
std::string filename_;
bool ignore_abort_;
public:
automaton_stream_parser(const std::string& filename,
bool ignore_abort = false);
// Read from an already open file descriptor.
// Use filename in error messages.
automaton_stream_parser(int fd, const std::string& filename,
bool ignore_abort = false);
// Read from a buffer
automaton_stream_parser(const char* data,
const std::string& filename,
bool ignore_abort = false);
~automaton_stream_parser();
parsed_aut_ptr parse(parse_aut_error_list& error_list,
const bdd_dict_ptr& dict,
ltl::environment& env =
ltl::default_environment::instance(),
bool debug = false);
// Raises a parse_error on any syntax error
twa_graph_ptr parse_strict(const bdd_dict_ptr& dict,
ltl::environment& env =
ltl::default_environment::instance(),
bool debug = false);
};
/// \brief Build a spot::twa_graph from a HOA file or a neverclaim.
/// \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 dict The BDD dictionary where to use.
/// \param env The environment of atomic proposition 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 a 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.
///
/// The specification of the HOA format can be found at
/// http://adl.github.io/hoaf/
///
/// The grammar of neverclaim will not accept every possible
/// neverclaim output. It has been tuned to accept the output of
/// spin -f, ltl2ba, ltl3ba, and modella. If you know of some other
/// tool that produce Büchi automata in the form of a neverclaim,
/// but is not understood by this parser, please report it to
/// spot@lrde.epita.fr.
///
/// \warning This function is not reentrant.
inline parsed_aut_ptr
parse_aut(const std::string& filename,
parse_aut_error_list& error_list,
const bdd_dict_ptr& dict,
ltl::environment& env = ltl::default_environment::instance(),
bool debug = false)
{
try
{
automaton_stream_parser p(filename);
return p.parse(error_list, dict, env, debug);
}
catch (std::runtime_error& e)
{
error_list.emplace_back(spot::location(), e.what());
return nullptr;
}
}
/// \brief Format diagnostics produced by spot::parse_aut.
/// \param os Where diagnostics should be output.
/// \param filename The filename that should appear in the diagnostics.
/// \param error_list The error list filled by spot::ltl::parse while
/// parsing \a ltl_string.
/// \return \c true iff any diagnostic was output.
SPOT_API bool
format_parse_aut_errors(std::ostream& os,
const std::string& filename,
parse_aut_error_list& error_list);
/// @}
}

438
src/parseaut/scanaut.ll Normal file
View file

@ -0,0 +1,438 @@
/* -*- coding: utf-8 -*-
** Copyright (C) 2014, 2015 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/>.
*/
%option noyywrap
%option prefix="hoayy"
%option outfile="lex.yy.c"
/* %option debug */
%{
#include <string>
#include <sys/stat.h>
#include "parseaut/parsedecl.hh"
#include "misc/escape.hh"
#define YY_USER_ACTION yylloc->columns(yyleng);
#define YY_NEVER_INTERACTIVE 1
typedef hoayy::parser::token token;
static unsigned comment_level = 0;
static unsigned parent_level = 0;
static int orig_cond = 0;
static bool lbtt_s = false;
static bool lbtt_t = false;
static unsigned lbtt_states = 0;
%}
eol \n+|\r+
eol2 (\n\r)+|(\r\n)+
identifier [[:alpha:]_][[:alnum:]_-]*
%x in_COMMENT in_STRING in_NEVER_PAR
%s in_HOA in_NEVER in_LBTT_HEADER
%s in_LBTT_STATE in_LBTT_INIT in_LBTT_TRANS
%s in_LBTT_T_ACC in_LBTT_S_ACC in_LBTT_GUARD
%%
%{
std::string s;
yylloc->step();
auto parse_int = [&](){
errno = 0;
char* end;
unsigned long n = strtoul(yytext, &end, 10);
yylval->num = n;
if (errno || yylval->num != n)
{
error_list.push_back(spot::parse_aut_error(*yylloc, "value too large"));
yylval->num = 0;
}
return end;
};
%}
/* skip blanks and comments */
{eol} yylloc->lines(yyleng); yylloc->step();
{eol2} yylloc->lines(yyleng / 2); yylloc->step();
[ \t\v\f]+ yylloc->step();
"/""*"+ {
orig_cond = YY_START;
BEGIN(in_COMMENT);
comment_level = 1;
}
<INITIAL>"HOA:" BEGIN(in_HOA); return token::HOA;
<INITIAL,in_HOA>"--ABORT--" BEGIN(INITIAL); throw spot::hoa_abort{*yylloc};
<INITIAL>"never" BEGIN(in_NEVER); return token::NEVER;
<INITIAL>[0-9]+[ \t][0-9]+[ts]? {
BEGIN(in_LBTT_HEADER);
char* end = 0;
errno = 0;
unsigned long n = strtoul(yytext, &end, 10);
yylval->num = n;
unsigned s = end - yytext;
yylloc->end = yylloc->begin;
yylloc->end.columns(s);
yyless(s);
if (errno || yylval->num != n)
{
error_list.push_back(
spot::parse_aut_error(*yylloc,
"value too large"));
yylval->num = 0;
}
lbtt_states = yylval->num;
return token::LBTT;
}
<in_HOA>{
"States:" return token::STATES;
"Start:" return token::START;
"AP:" return token::AP;
"Alias:" return token::ALIAS;
"Acceptance:" return token::ACCEPTANCE;
"acc-name:" return token::ACCNAME;
"tool:" return token::TOOL;
"name:" return token::NAME;
"properties:" return token::PROPERTIES;
"--BODY--" return token::BODY;
"--END--" BEGIN(INITIAL); return token::END;
"State:" return token::STATE;
[tf{}()\[\]&|!] return *yytext;
{identifier} {
yylval->str = new std::string(yytext, yyleng);
return token::IDENTIFIER;
}
{identifier}":" {
yylval->str = new std::string(yytext, yyleng - 1);
return token::HEADERNAME;
}
"@"[[:alnum:]_-]+ {
yylval->str = new std::string(yytext + 1, yyleng - 1);
return token::ANAME;
}
[0-9]+ parse_int(); return token::INT;
}
<in_NEVER>{
"skip" return token::SKIP;
"if" return token::IF;
"fi" return token::FI;
"do" return token::DO;
"od" return token::OD;
"->" return token::ARROW;
"goto" return token::GOTO;
"false"|"0" return token::FALSE;
"atomic" return token::ATOMIC;
"assert" return token::ASSERT;
("!"[ \t]*)?"(" {
parent_level = 1;
BEGIN(in_NEVER_PAR);
yylval->str = new std::string(yytext, yyleng);
}
"true"|"1" {
yylval->str = new std::string(yytext, yyleng);
return token::FORMULA;
}
[a-zA-Z][a-zA-Z0-9_]* {
yylval->str = new std::string(yytext, yyleng);
return token::IDENTIFIER;
}
}
/* Note: the LBTT format is scanf friendly, but not Bison-friendly.
If we only tokenize it as a stream of INTs, the parser will have
a very hard time recognizing what is a state from what is a
transitions. As a consequence we abuse the start conditions to
maintain a state an return integers with different sementic types
depending on the purpose of those integers. */
<in_LBTT_HEADER>{
[0-9]+[st]* {
BEGIN(in_LBTT_STATE);
auto end = parse_int();
lbtt_s = false;
lbtt_t = false;
if (end)
while (int c = *end++)
if (c == 's')
lbtt_s = true;
else // c == 't'
lbtt_t = true;
if (!lbtt_t)
lbtt_s = true;
if (lbtt_states == 0)
{
BEGIN(INITIAL);
return token::LBTT_EMPTY;
}
if (lbtt_s && !lbtt_t)
return token::INT_S;
else
return token::INT;
}
}
<in_LBTT_STATE>[0-9]+ {
parse_int();
BEGIN(in_LBTT_INIT);
return token::STATE_NUM;
}
<in_LBTT_INIT>[01] {
yylval->num = *yytext - '0';
if (lbtt_s)
BEGIN(in_LBTT_S_ACC);
else
BEGIN(in_LBTT_TRANS);
return token::INT;
}
<in_LBTT_S_ACC>{
[0-9]+ parse_int(); return token::ACC;
"-1" BEGIN(in_LBTT_TRANS); yylloc->step();
}
<in_LBTT_TRANS>{
[0-9]+ {
parse_int();
if (lbtt_t)
BEGIN(in_LBTT_T_ACC);
else
BEGIN(in_LBTT_GUARD);
return token::DEST_NUM;
}
"-1" {
if (--lbtt_states)
{
BEGIN(in_LBTT_STATE);
yylloc->step();
}
else
{
BEGIN(INITIAL);
return token::ENDAUT;
}
}
}
<in_LBTT_T_ACC>{
[0-9]+ parse_int(); return token::ACC;
"-1" BEGIN(in_LBTT_GUARD); yylloc->step();
}
<in_LBTT_GUARD>{
[^\n\r]* {
yylval->str = new std::string(yytext, yyleng);
BEGIN(in_LBTT_TRANS);
return token::STRING;
}
}
<in_COMMENT>{
"/""*"+ ++comment_level;
[^*/\n\r]* continue;
"/"[^*\n\r]* continue;
"*"+[^*/\n\r]* continue;
{eol} yylloc->lines(yyleng); yylloc->end.column = 1;
{eol2} yylloc->lines(yyleng / 2); yylloc->end.column = 1;
"*"+"/" if (--comment_level == 0) BEGIN(orig_cond);
<<EOF>> {
BEGIN(orig_cond);
error_list.push_back(
spot::parse_aut_error(*yylloc,
"unclosed comment"));
return 0;
}
}
/* matched late, so that the in_LBTT_GUARD pattern has precedence */
"\"" {
orig_cond = YY_START;
BEGIN(in_STRING);
comment_level = 1;
}
<in_STRING>{
\" {
BEGIN(orig_cond);
yylval->str = new std::string(s);
return token::STRING;
}
{eol} {
s.append(yytext, yyleng);
yylloc->lines(yyleng); yylloc->end.column = 1;
}
{eol2} {
s.append(yytext, yyleng);
yylloc->lines(yyleng / 2); yylloc->end.column = 1;
}
\\. s += yytext[1];
[^\\\"\n\r]+ s.append(yytext, yyleng);
<<EOF>> {
error_list.push_back(
spot::parse_aut_error(*yylloc,
"unclosed string"));
BEGIN(orig_cond);
yylval->str = new std::string(s);
return token::STRING;
}
}
<in_NEVER_PAR>{
"(" {
++parent_level;
yylval->str->append(yytext, yyleng);
}
/* if we match ")&&(" or ")||(", stay in <in_NEVER_PAR> mode */
")"[ \t]*("&&"|"||")[ \t!]*"(" {
yylval->str->append(yytext, yyleng);
}
")" {
yylval->str->append(yytext, yyleng);
if (!--parent_level)
{
BEGIN(in_NEVER);
spot::trim(*yylval->str);
return token::FORMULA;
}
}
{eol} {
yylval->str->append(yytext, yyleng);
yylloc->lines(yyleng); yylloc->end.column = 1;
}
{eol2} {
yylval->str->append(yytext, yyleng);
yylloc->lines(yyleng / 2); yylloc->end.column = 1;
}
[^()\n\r]+ yylval->str->append(yytext, yyleng);
<<EOF>> {
error_list.push_back(
spot::parse_aut_error(*yylloc,
"missing closing parenthese"));
yylval->str->append(parent_level, ')');
BEGIN(in_NEVER);
spot::trim(*yylval->str);
return token::FORMULA;
}
}
. return *yytext;
%{
/* Dummy use of yyunput to shut up a gcc warning. */
(void) &yyunput;
%}
%%
namespace spot
{
void
hoayyreset()
{
BEGIN(INITIAL);
comment_level = 0;
parent_level = 0;
}
int
hoayyopen(const std::string &name)
{
bool want_interactive = false;
// yy_flex_debug = 1;
if (name == "-")
{
// If the input is a pipe, make the scanner
// interactive so that it does not wait for the input
// buffer to be full to process automata.
struct stat s;
if (fstat(fileno(stdin), &s) < 0)
throw std::runtime_error("fstat failed");
if (S_ISFIFO(s.st_mode))
want_interactive = true;
// Only set yyin once we know we will use
// it, so that we do not close it otherwise.
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;
hoayyreset();
if (want_interactive)
yy_set_interactive(true);
return 0;
}
int
hoayystring(const char* data)
{
yy_scan_string(data);
hoayyreset();
return 0;
}
int
hoayyopen(int fd)
{
bool want_interactive = false;
yyin = fdopen(fd, "r");
if (!yyin)
throw std::runtime_error("fdopen failed");
// If the input is a pipe, make the scanner
// interactive so that it does not wait for the input
// buffer to be full to process automata.
struct stat s;
if (fstat(fd, &s) < 0)
throw std::runtime_error("fstat failed");
if (S_ISFIFO(s.st_mode))
want_interactive = true;
// Reset the lexer in case a previous parse
// ended badly.
YY_NEW_FILE;
hoayyreset();
if (want_interactive)
yy_set_interactive(true);
return 0;
}
void
hoayyclose()
{
if (yyin)
{
fclose(yyin);
yyin = NULL;
}
}
}