bin: overhaul default input selection

If no input have been specified, and the standard input is not a tty all
tools now default to reading it.  If standard input is a tty, all tools
display an error message.  Additionally, - is now a shorthand for -F- in
all tools.

* NEWS: Summarize this.
* bin/common_finput.cc, bin/common_finput.hh (check_no_formulas,
check_no_automaton): New functions that implement the above istty()
logic.
* bin/autfilt.cc, bin/dstar2tgba.cc, bin/ltl2tgba.cc, bin/ltl2tgta.cc,
bin/ltlcross.cc, bin/ltldo.cc, bin/ltlgrind.cc: Use these function,
and recognize '-' if it was not the case.
* tests/core/acc_word.test, tests/core/ltldo.test,
tests/core/minusx.test, tests/core/readsave.test,
tests/core/unambig.test: Adjust some tests to exercise this.
* doc/org/autfilt.org, doc/org/csv.org, doc/org/dstar2tgba.org,
doc/org/ltl2tgba.org, doc/org/ltlcross.org, doc/org/ltlfilt.org,
doc/org/oaut.org: Adjust the documentation and simplify some
examples.
This commit is contained in:
Alexandre Duret-Lutz 2016-07-19 21:55:12 +02:00
parent abff7eba8e
commit dd6875d5fe
22 changed files with 119 additions and 54 deletions

26
NEWS
View file

@ -2,6 +2,32 @@ New in spot 2.0.3a (not yet released)
Command-line tools: Command-line tools:
* All tools that input formulas or automata (i.e., autfilt,
dstar2tgba, ltl2tgba, ltl2tgta, ltlcross, ltldo, ltlfilt,
ltlgrind) now have a more homogeneous handling of the default
input.
- If no formula/automaton have been specified, and the standard
input is a not a tty, then the default is to read that. This is a
change for ltl2tgba and ltl2tgta. In particular, it simplifies
genltl --dac | ltl2tgba -F- | autfilt ...
into
genltl --dac | ltl2tgba | autfilt ...
- If standard input is a tty and no other input has been
specified, then an error message is printed. This is a change for
autfilt, dstar2tgba, ltlcross, ltldo, ltlfilt, ltlgrind, that used
to expect the user to type formula or automata at the terminal,
confusing people.
- All tools now accept - as a shorthand for -F-, to force reading
input from the standard input (regardless of whether it is a tty
or not). This is a change for ltl2tgba, ltl2tgta, ltlcross, and
ltldo.
* ltldo has a new option --errors=... to specify how to deal * ltldo has a new option --errors=... to specify how to deal
with errors from executed tools. with errors from executed tools.

View file

@ -1116,8 +1116,7 @@ main(int argc, char** argv)
if (pref_set && !level_set) if (pref_set && !level_set)
level = spot::postprocessor::High; level = spot::postprocessor::High;
if (jobs.empty()) check_no_automaton();
jobs.emplace_back("-", true);
if (opt->are_isomorphic) if (opt->are_isomorphic)
{ {

View file

@ -18,10 +18,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "common_finput.hh" #include "common_finput.hh"
#include "common_setup.hh"
#include "error.h" #include "error.h"
#include <fstream> #include <fstream>
#include <cstring> #include <cstring>
#include <unistd.h>
enum { enum {
OPT_LBT = 1, OPT_LBT = 1,
@ -353,3 +355,25 @@ job_processor::run()
} }
return error; return error;
} }
void check_no_formula()
{
if (!jobs.empty())
return;
if (isatty(STDIN_FILENO))
error(2, 0, "No formula to translate? Run '%s --help' for help.\n"
"Use '%s -' to force reading formulas from the standard "
"input.", program_name, program_name);
jobs.emplace_back("-", true);
}
void check_no_automaton()
{
if (!jobs.empty())
return;
if (isatty(STDIN_FILENO))
error(2, 0, "No automaton to process? Run '%s --help' for help.\n"
"Use '%s -' to force reading automata from the standard "
"input.", program_name, program_name);
jobs.emplace_back("-", true);
}

View file

@ -77,3 +77,8 @@ public:
char* prefix; char* prefix;
char* suffix; char* suffix;
}; };
// Report and error message or add a default job depending on whether
// the input is a tty.
void check_no_formula();
void check_no_automaton();

View file

@ -180,8 +180,7 @@ main(int argc, char** argv)
if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr)) if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr))
exit(err); exit(err);
if (jobs.empty()) check_no_automaton();
jobs.emplace_back("-", true);
spot::postprocessor post(&extra_options); spot::postprocessor post(&extra_options);
post.set_pref(pref | comp | sbacc); post.set_pref(pref | comp | sbacc);

View file

@ -97,7 +97,10 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
// FIXME: use stat() to distinguish filename from string? // FIXME: use stat() to distinguish filename from string?
jobs.emplace_back(arg, false); if (*arg == '-' && !arg[1])
jobs.emplace_back(arg, true);
else
jobs.emplace_back(arg, false);
break; break;
default: default:
@ -164,9 +167,7 @@ main(int argc, char** argv)
if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr)) if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr))
exit(err); exit(err);
if (jobs.empty()) check_no_formula();
error(2, 0, "No formula to translate? Run '%s --help' for usage.",
program_name);
try try
{ {

View file

@ -24,6 +24,7 @@
#include <fstream> #include <fstream>
#include <argp.h> #include <argp.h>
#include <unistd.h>
#include "error.h" #include "error.h"
#include "common_setup.hh" #include "common_setup.hh"
@ -147,7 +148,10 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
// FIXME: use stat() to distinguish filename from string? // FIXME: use stat() to distinguish filename from string?
jobs.emplace_back(arg, false); if (*arg == '-' && !arg[1])
jobs.emplace_back(arg, true);
else
jobs.emplace_back(arg, false);
break; break;
default: default:
@ -226,9 +230,7 @@ main(int argc, char** argv)
if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr)) if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr))
exit(err); exit(err);
if (jobs.empty()) check_no_formula();
error(2, 0, "No formula to translate? Run '%s --help' for usage.",
program_name);
try try
{ {

View file

@ -408,7 +408,10 @@ parse_opt(int key, char* arg, struct argp_state*)
products = 0; products = 0;
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
translators.push_back(arg); if (arg[0] == '-' && !arg[1])
jobs.emplace_back(arg, true);
else
translators.push_back(arg);
break; break;
case OPT_AUTOMATA: case OPT_AUTOMATA:
opt_automata = true; opt_automata = true;
@ -1443,8 +1446,7 @@ main(int argc, char** argv)
if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr)) if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr))
exit(err); exit(err);
if (jobs.empty()) check_no_formula();
jobs.emplace_back("-", 1);
if (translators.empty()) if (translators.empty())
error(2, 0, "No translator to run? Run '%s --help' for usage.", error(2, 0, "No translator to run? Run '%s --help' for usage.",

View file

@ -146,7 +146,10 @@ parse_opt(int key, char* arg, struct argp_state*)
errors_opt = XARGMATCH("--errors", arg, errors_args, errors_types); errors_opt = XARGMATCH("--errors", arg, errors_args, errors_types);
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
translators.push_back(arg); if (arg[0] == '-' && !arg[1])
jobs.emplace_back(arg, true);
else
translators.push_back(arg);
break; break;
default: default:
return ARGP_ERR_UNKNOWN; return ARGP_ERR_UNKNOWN;
@ -356,8 +359,7 @@ main(int argc, char** argv)
if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr)) if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr))
exit(err); exit(err);
if (jobs.empty()) check_no_formula();
jobs.emplace_back("-", 1);
if (translators.empty()) if (translators.empty())
error(2, 0, "No translator to run? Run '%s --help' for usage.", error(2, 0, "No translator to run? Run '%s --help' for usage.",

View file

@ -189,8 +189,7 @@ main(int argc, char* argv[])
mut_opts |= opt_all; mut_opts |= opt_all;
if (jobs.empty()) check_no_formula();
jobs.push_back(job("-", true));
mutate_processor processor; mutate_processor processor;
if (processor.run()) if (processor.run())

View file

@ -739,7 +739,7 @@ of the form =cycle{b}=, and display the associated formula (which was
stored as the name of the automaton by =ltl2tgba=). stored as the name of the automaton by =ltl2tgba=).
#+BEGIN_SRC sh :results verbatim :exports both #+BEGIN_SRC sh :results verbatim :exports both
randltl -n -1 a b | ltlfilt --simplify --uniq | ltl2tgba -F- | randltl -n -1 a b | ltlfilt --simplify --uniq | ltl2tgba |
autfilt --accept-word='a&!b;cycle{!a&!b}' --accept-word='!a&!b;cycle{a&b}' \ autfilt --accept-word='a&!b;cycle{!a&!b}' --accept-word='!a&!b;cycle{a&b}' \
--reject-word='cycle{b}' --stats=%M -n 10 --reject-word='cycle{b}' --stats=%M -n 10
#+END_SRC #+END_SRC

View file

@ -45,7 +45,7 @@ formulas, and show the resulting number of states (=%s=) and edges
(=%e=) of the automaton constructed for each formula. (=%e=) of the automaton constructed for each formula.
#+BEGIN_SRC sh :results verbatim :exports both #+BEGIN_SRC sh :results verbatim :exports both
genltl --and-gf=1..5 --u-left=1..5 | ltl2tgba -F- --stats '%f,%s,%e' genltl --and-gf=1..5 --u-left=1..5 | ltl2tgba --stats '%f,%s,%e'
#+END_SRC #+END_SRC
#+RESULTS: #+RESULTS:
#+begin_example #+begin_example

View file

@ -421,9 +421,9 @@ For instance here is a complex command that will
1. generate an infinite stream of random LTL formulas with [[file:randltl.org][=randltl=]], 1. generate an infinite stream of random LTL formulas with [[file:randltl.org][=randltl=]],
2. use [[file:ltlfilt.org][=ltlfilt=]] to rewrite the W and M operators away (=--remove-wm=), 2. use [[file:ltlfilt.org][=ltlfilt=]] to rewrite the W and M operators away (=--remove-wm=),
simplify the formulas (=-r=), remove duplicates (=u=) as well as simplify the formulas (=-r=), remove duplicates (=u=) as well as
formulas that have a size less then 3 (=--size-min=3=), formulas that have a size less then 3 (=--size-min=3=), and
3. use =head= to keep only 10 of such formula keep only the 10 first formulas (=-n 10=)
4. loop to process each of these formula: 3. loop to process each of these formula:
- print it - print it
- then convert the formula into =ltl2dstar='s input format, process - then convert the formula into =ltl2dstar='s input format, process
it with =ltl2dstar= (using =ltl2tgba= as the actual LTL->BA it with =ltl2dstar= (using =ltl2tgba= as the actual LTL->BA
@ -438,8 +438,7 @@ deterministic, and =%p= whether the automaton is complete.
#+BEGIN_SRC sh :results verbatim :exports both #+BEGIN_SRC sh :results verbatim :exports both
randltl -n -1 --tree-size=10..14 a b c | randltl -n -1 --tree-size=10..14 a b c |
ltlfilt --remove-wm -r -u --size-min=3 | ltlfilt --remove-wm -r -u --size-min=3 -n 10 |
head -n 10 |
while read f; do while read f; do
echo "$f" echo "$f"
ltlfilt -l -f "$f" | ltlfilt -l -f "$f" |

View file

@ -835,7 +835,7 @@ For instance we can study the size of the automata generated for the
right-nested =U= formulas as follows: right-nested =U= formulas as follows:
#+BEGIN_SRC sh :results verbatim :exports both #+BEGIN_SRC sh :results verbatim :exports both
genltl --u-right=1..8 | ltl2tgba -F - --stats '%s states and %e edges for "%f"' genltl --u-right=1..8 | ltl2tgba --stats '%s states and %e edges for "%f"'
#+END_SRC #+END_SRC
#+RESULTS: #+RESULTS:
: 2 states and 2 edges for "p1" : 2 states and 2 edges for "p1"
@ -847,7 +847,11 @@ genltl --u-right=1..8 | ltl2tgba -F - --stats '%s states and %e edges for "%f"'
: 7 states and 28 edges for "p1 U (p2 U (p3 U (p4 U (p5 U (p6 U p7)))))" : 7 states and 28 edges for "p1 U (p2 U (p3 U (p4 U (p5 U (p6 U p7)))))"
: 8 states and 36 edges for "p1 U (p2 U (p3 U (p4 U (p5 U (p6 U (p7 U p8))))))" : 8 states and 36 edges for "p1 U (p2 U (p3 U (p4 U (p5 U (p6 U (p7 U p8))))))"
Here =-F -= means that formulas should be read from the standard input. Note that because no formula have been passed as argument to
=ltl2tgba=, it defaulted to reading them from standard input. Such a
behaviour can be requested explicitly with =-F -= if needed (e.g., to
read from standard input in addition to processing other formula
supplied with =-f=).
When computing the size of an automaton, we distinguish /transitions/ When computing the size of an automaton, we distinguish /transitions/
and /edges/. An edge between two states is labeled by a Boolean and /edges/. An edge between two states is labeled by a Boolean

View file

@ -44,8 +44,9 @@ The core of =ltlcross= is a loop that does the following steps:
* Formula selection * Formula selection
Formulas to translate should be specified using the [[file:ioltl.org][common input options]]. Formulas to translate should be specified using the [[file:ioltl.org][common input
Standard input is read if no =-f= or =-F= option is given. options]]. Standard input is read if it is not connected to a terminal,
and no =-f= or =-F= options are given.
* Configuring translators * Configuring translators

View file

@ -15,8 +15,9 @@ formulas.) It can be used to perform a number of tasks. Essentially:
Because it read and write formulas, =ltlfilt= accepts Because it read and write formulas, =ltlfilt= accepts
all the [[file:ioltl.org][common input and output options]]. all the [[file:ioltl.org][common input and output options]].
Additionally, if no =-f= or =-F= option is specified, =ltlfilt= Additionally, if no =-f= or =-F= option is specified, and =ltlfilt=
will read formulas from the standard input. will read formulas from the standard input if it is not connected to a
terminal.
For instance the following will convert two LTL formulas expressed For instance the following will convert two LTL formulas expressed
using infix notation (with different names supported for the same using infix notation (with different names supported for the same

View file

@ -1015,18 +1015,18 @@ using =autfilt -n5=.
#+BEGIN_SRC sh :results verbatim :exports both #+BEGIN_SRC sh :results verbatim :exports both
randltl -n -1 a b | randltl -n -1 a b |
ltl2tgba -F- | ltl2tgba |
autfilt --states=3 --stats='!(%M)' | autfilt --states=3 --stats='!(%M)' |
ltl2tgba -F- | ltl2tgba |
autfilt --states=3 --stats=%M -n5 autfilt --states=3 --stats=%M -n5
#+END_SRC #+END_SRC
#+RESULTS: #+RESULTS:
: G(F!a & XF(a | G!b)) : G(b | F(b & Fa))
: GFb | G(!b & FG!b) : (!a | b | (!b & (b W Ga))) & (a | (!b & (b | (!b M F!a))))
: !a & F((a | b) & (!a | !b)) : (!a | (!a R b)) & (a | (a U !b))
: !a | (b R a) : !a & F((!a | FG!a) & (a | GFa))
: !b & X(!b U a) : X(!b W a)
Note that the above result can also be obtained without using Note that the above result can also be obtained without using
=autfilt= and automata names. We can use the fact that =ltl2tgba =autfilt= and automata names. We can use the fact that =ltl2tgba
@ -1045,13 +1045,15 @@ head -n5 | cut -d, -f2 # return the five first formulas
#+END_SRC #+END_SRC
#+RESULTS: #+RESULTS:
: G(F!a & XF(a | G!b)) : G(b | F(b & Fa))
: GFb | G(!b & FG!b) : (!a | b | (!b & (b W Ga))) & (a | (!b & (b | (!b M F!a))))
: !a & F((!a | !b) & (a | b)) : (!a | (!a R b)) & (a | (a U !b))
: !a | (b R a) : !a & F((!a | FG!a) & (a | GFa))
: !b & X(!b U a) : X(!b W a)
Note that the =-F-= argument in the first call to =ltl2tgba= is
superfluous as the tool default to reading from its standard input.
But we put it there for symmetry with the second call.
# LocalWords: num toc html syntaxes ltl tgba sed utf UTF lbtt SCCs # LocalWords: num toc html syntaxes ltl tgba sed utf UTF lbtt SCCs
# LocalWords: GraphViz's hoaf HOA LBTT's neverclaim ba SPOT's Gb cn # LocalWords: GraphViz's hoaf HOA LBTT's neverclaim ba SPOT's Gb cn

View file

@ -34,7 +34,7 @@ ltl2tgba -f 'a U b' |
ltl2tgba -f 'a U b' | autfilt --accept-word='cycle{!b}' -q && exit 1 ltl2tgba -f 'a U b' | autfilt --accept-word='cycle{!b}' -q && exit 1
# An example from the documentation: # An example from the documentation:
randltl -n -1 a b | ltlfilt --simplify --uniq | ltl2tgba -F- | randltl -n -1 a b | ltlfilt --simplify --uniq | ltl2tgba |
autfilt --accept-word='a&!b;cycle{!a&!b}' --accept-word='!a&!b;cycle{a&b}' \ autfilt --accept-word='a&!b;cycle{!a&!b}' --accept-word='!a&!b;cycle{a&b}' \
--reject-word='cycle{b}' --stats=%M -n 3 > out --reject-word='cycle{b}' --stats=%M -n 3 > out
cat >expect <<EOF cat >expect <<EOF

View file

@ -44,7 +44,7 @@ diff output expected
# Test timeouts. This test should take 2*2 seconds. # Test timeouts. This test should take 2*2 seconds.
$genltl --or-g=1..2 | $genltl --or-g=1..2 |
run 0 $ltldo -F- -t 'sleep 10; echo %f' -T1 -t 'sleep 10; echo %f' \ run 0 $ltldo -t 'sleep 10; echo %f' -T1 -t 'sleep 10; echo %f' \
>output 2>stderr >output 2>stderr
test -z "`cat output`" test -z "`cat output`"
test 4 = `grep -c warning: stderr` test 4 = `grep -c warning: stderr`

View file

@ -22,7 +22,7 @@
set -e set -e
# make sure option -x reports unknown arguments # make sure option -x reports unknown arguments
ltl2tgba -F- -x foo </dev/null 2>error && exit 1 ltl2tgba - -x foo </dev/null 2>error && exit 1
grep "ltl2tgba: option 'foo' was not used" error grep "ltl2tgba: option 'foo' was not used" error
ltl2tgba -F- -x ba-simul,foo,bar </dev/null 2>error && exit 1 ltl2tgba -F- -x ba-simul,foo,bar </dev/null 2>error && exit 1
grep -v 'ba-simul' error grep -v 'ba-simul' error

View file

@ -115,9 +115,8 @@ diff stdout stdout2
# exercise both %M and %m. The nonexistant file should never be # exercise both %M and %m. The nonexistant file should never be
# open, because the input stream is infinite and autfilt should # open, because the input stream is infinite and autfilt should
# stop after 10 automata. # stop after 10 automata.
randltl -n -1 a b | randltl -n -1 a b | ltl2tgba |
ltl2tgba -H -F - | autfilt -F - -F nonexistant --states=3 --edges=..10 --acc-sets=1.. \
autfilt -F- -F nonexistant --states=3 --edges=..10 --acc-sets=1.. \
--name='%M, %S states' --stats='<%m>, %e, %a' -n 10 > output --name='%M, %S states' --stats='<%m>, %e, %a' -n 10 > output
cat >expected <<EOF cat >expected <<EOF
<F(b | Ga), 3 states>, 5, 1 <F(b | Ga), 3 states>, 5, 1
@ -278,7 +277,7 @@ autfilt --merge -Hm input --name="%E->%e edges, %T->%t transitions" > output
diff output expected diff output expected
cat <<EOF | ltl2tgba -x degen-lskip=1 -F- --ba -H > tmp.hoa ltl2tgba -x degen-lskip=1 --ba > tmp.hoa <<EOF
a U b a U b
false false
!b && Xb && GFa !b && Xb && GFa

View file

@ -152,7 +152,7 @@ run 0 $autfilt --check input > output
test `grep -c unambiguous output` = 0 test `grep -c unambiguous output` = 0
# Check 1000 random PSL formulas # Check 1000 random PSL formulas
randltl --psl -n 1000 3 | $ltl2tgba -U -F- -H | randltl --psl -n 1000 3 | $ltl2tgba -U -H |
$autfilt -v --is-unamb --stats=%M && exit 1 $autfilt -v --is-unamb --stats=%M && exit 1
cat >input <<EOF cat >input <<EOF