Introduce [=min..max] operator.

* src/ltlast/bunop.hh: Declare bunop::Equal
* src/ltlast/bunop.cc: Handle it.
* src/ltlparse/ltlparse.yy,
src/ltlparse/ltlscan.ll: Add rules for [=min..max].
* src/tgbaalgos/ltl2tgba_fm.cc: Handle bunop::Equal in
the translation.
* src/ltltest/equals.test: Test trivial identities
for [=min..max].
* src/tgbatest/ltl2tgba.test: Add new formulae to test.
This commit is contained in:
Alexandre Duret-Lutz 2010-10-14 18:51:34 +02:00
parent d7781bc4d6
commit 8d4a413a37
7 changed files with 236 additions and 91 deletions

View file

@ -35,6 +35,7 @@
#include <string>
#include "public.hh"
#include "ltlast/allnodes.hh"
#include "ltlvisit/kind.hh"
struct minmax_t { unsigned min, max; };
}
@ -92,9 +93,10 @@ using namespace spot::ltl;
%token OP_X "next operator" OP_NOT "not operator" OP_STAR "star operator"
%token OP_PLUS "plus operator"
%token OP_STAR_OPEN "opening bracket for star operator"
%token OP_STAR_CLOSE "closing bracket for star operator"
%token <num> OP_STAR_NUM "number for star operator"
%token OP_STAR_SEP "separator for star operator"
%token OP_EQUAL_OPEN "opening bracket for equal operator"
%token OP_SQBKT_CLOSE "closing bracket"
%token <num> OP_SQBKT_NUM "number for square bracket operator"
%token OP_SQBKT_SEP "separator for square bracket operator"
%token OP_UCONCAT "universal concat operator"
%token OP_ECONCAT "existential concat operator"
%token OP_UCONCAT_NONO "universal non-overlapping concat operator"
@ -124,7 +126,7 @@ using namespace spot::ltl;
%nonassoc OP_X
/* High priority regex operator. */
%nonassoc OP_STAR OP_STAR_OPEN OP_PLUS
%nonassoc OP_STAR OP_STAR_OPEN OP_PLUS OP_EQUAL_OPEN
/* Not has the most important priority after Wring's `=0' and `=1'. */
%nonassoc OP_NOT
@ -133,7 +135,7 @@ using namespace spot::ltl;
%type <ltl> subformula booleanatom rationalexp
%type <ltl> bracedrationalexp parenthesedsubformula
%type <minmax> starargs
%type <minmax> starargs equalargs sqbracketargs
%destructor { delete $$; } <str>
%destructor { $$->destroy(); } <ltl>
@ -187,24 +189,27 @@ enderror: error END_OF_INPUT
}
OP_STAR_SEP_opt: | OP_STAR_SEP
OP_SQBKT_SEP_opt: | OP_SQBKT_SEP
error_opt: | error
sqbracketargs: OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
{ $$.min = $1; $$.max = $3; }
| OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_CLOSE
{ $$.min = $1; $$.max = bunop::unbounded; }
| OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
{ $$.min = 0U; $$.max = $2; }
| OP_SQBKT_SEP_opt OP_SQBKT_CLOSE
{ $$.min = 0U; $$.max = bunop::unbounded; }
| OP_SQBKT_NUM OP_SQBKT_CLOSE
{ $$.min = $$.max = $1; }
starargs: OP_STAR
{ $$.min = 0U; $$.max = bunop::unbounded; }
| OP_PLUS
{ $$.min = 1U; $$.max = bunop::unbounded; }
| OP_STAR_OPEN OP_STAR_NUM OP_STAR_SEP OP_STAR_NUM OP_STAR_CLOSE
{ $$.min = $2; $$.max = $4; }
| OP_STAR_OPEN OP_STAR_NUM OP_STAR_SEP OP_STAR_CLOSE
{ $$.min = $2; $$.max = bunop::unbounded; }
| OP_STAR_OPEN OP_STAR_SEP OP_STAR_NUM OP_STAR_CLOSE
{ $$.min = 0U; $$.max = $3; }
| OP_STAR_OPEN OP_STAR_SEP_opt OP_STAR_CLOSE
{ $$.min = 0U; $$.max = bunop::unbounded; }
| OP_STAR_OPEN OP_STAR_NUM OP_STAR_CLOSE
{ $$.min = $$.max = $2; }
| OP_STAR_OPEN error OP_STAR_CLOSE
| OP_STAR_OPEN sqbracketargs
{ $$ = $2; }
| OP_STAR_OPEN error OP_SQBKT_CLOSE
{ error_list.push_back(parse_error(@$,
"treating this star block as [*]"));
$$.min = 0U; $$.max = bunop::unbounded; }
@ -213,6 +218,17 @@ starargs: OP_STAR
"missing closing bracket for star"));
$$.min = $$.max = 0U; }
equalargs: OP_EQUAL_OPEN sqbracketargs
{ $$ = $2; }
| OP_EQUAL_OPEN error OP_SQBKT_CLOSE
{ error_list.push_back(parse_error(@$,
"treating this star block as [*]"));
$$.min = 0U; $$.max = bunop::unbounded; }
| OP_EQUAL_OPEN error_opt END_OF_INPUT
{ error_list.push_back(parse_error(@$,
"missing closing bracket for star"));
$$.min = $$.max = 0U; }
/* The reason we use `constant::false_instance()' for error recovery
is that it isn't reference counted. (Hence it can't leak references.) */
@ -323,6 +339,22 @@ rationalexp: booleanatom
| starargs
{ $$ = bunop::instance(bunop::Star, constant::true_instance(),
$1.min, $1.max); }
| rationalexp equalargs
{
if ((kind_of($1) & Boolean_Kind) == Boolean_Kind)
{
$$ = bunop::instance(bunop::Equal, $1, $2.min, $2.max);
}
else
{
error_list.push_back(parse_error(@1,
"not a boolean expression: [=...] can only "
"be applied to a boolean expression"));
error_list.push_back(parse_error(@$,
"treating this block as false"));
$$ = constant::false_instance();
}
}
bracedrationalexp: BRACE_OPEN rationalexp BRACE_CLOSE
{ $$ = $2; }

View file

@ -59,7 +59,7 @@ flex_set_buffer(const char* buf, int start_tok)
%}
%s not_prop
%x star
%x sqbracket
%%
@ -96,14 +96,15 @@ flex_set_buffer(const char* buf, int start_tok)
":" BEGIN(0); return token::OP_FUSION;
"*"|"[*]" BEGIN(0); return token::OP_STAR;
"[+]" BEGIN(0); return token::OP_PLUS;
"[*" BEGIN(star); return token::OP_STAR_OPEN;
<star>"]" BEGIN(0); return token::OP_STAR_CLOSE;
<star>[0-9]+ {
"[*" BEGIN(sqbracket); return token::OP_STAR_OPEN;
"[=" BEGIN(sqbracket); return token::OP_EQUAL_OPEN;
<sqbracket>"]" BEGIN(0); return token::OP_SQBKT_CLOSE;
<sqbracket>[0-9]+ {
unsigned num = 0;
try {
num = boost::lexical_cast<unsigned>(yytext);
yylval->num = num;
return token::OP_STAR_NUM;
return token::OP_SQBKT_NUM;
}
catch (boost::bad_lexical_cast &)
{
@ -114,7 +115,7 @@ flex_set_buffer(const char* buf, int start_tok)
yylloc->step();
}
}
<star>","|".." return token::OP_STAR_SEP;
<sqbracket>","|".." return token::OP_SQBKT_SEP;
/* & and | come from Spin. && and || from LTL2BA.