Commit 6c62362f authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

parseaut: add support for negated properties

* spot/parseaut/parseaut.yy: Here.
* tests/core/parseaut.test: Test it.
* NEWS: Mention it.
parent da391492
......@@ -74,14 +74,18 @@ New in spot 1.99.6a (not yet released)
acc_cond::is_ff() -> acc_cond::is_f()
parse_acc_code() -> acc_cond::acc_code(...)
* Automata property bits (those that tell whether the automaton is
deterministic, weak, stutter-invariant, etc.) are now stored using
three-valued logic: in addition to "maybe"/"yes" they can now also
represent "no". This is some preparation for the upcomming
support of the HOA v1.1 format, but it also saves some time in
some algorithms (e.g, is_deterministic() can now return
immediately on automata marked as not deterministic).
support of the HOA v1.1 format, but it also saves time in some
algorithms (e.g, is_deterministic() can now return immediately on
automata marked as not deterministic).
* The automaton parser now accept negated properties as they will be
introduced in HOA v1.1, and will check for some inconsistencies.
These properties are stored and used when appropriate, but they
are not yet output by the HOA printer.
Python:
......
......@@ -97,7 +97,16 @@ extern "C" int strverscmp(const char *s1, const char *s2);
std::vector<state_info> info_states; // States declared and used.
std::vector<std::pair<spot::location, unsigned>> start; // Initial states;
std::unordered_map<std::string, bdd> alias;
std::unordered_map<std::string, spot::location> props;
struct prop_info
{
spot::location loc;
bool val;
operator bool() const
{
return val;
};
};
std::unordered_map<std::string, prop_info> props;
spot::location states_loc;
spot::location ap_loc;
spot::location state_label_loc;
......@@ -138,6 +147,14 @@ extern "C" int strverscmp(const char *s1, const char *s2);
std::map<std::string, spot::location> labels;
prop_info prop_is_true(const std::string& p)
{
auto i = props.find(p);
if (i == props.end())
return prop_info{spot::location(), false};
return i->second;
}
~result_()
{
delete namer;
......@@ -323,52 +340,52 @@ header: format-version header-items
}
// Process properties.
{
auto explicit_labels = res.props.find("explicit-labels");
auto implicit_labels = res.props.find("implicit-labels");
if (implicit_labels != res.props.end() && res.opts.want_kripke)
error(implicit_labels->second,
"Kripke structure may not use implicit labels");
auto explicit_labels = res.prop_is_true("explicit-labels");
auto implicit_labels = res.prop_is_true("implicit-labels");
if (implicit_labels != res.props.end())
if (implicit_labels)
{
if (explicit_labels == res.props.end())
{
res.label_style = Implicit_Labels;
}
else
if (res.opts.want_kripke)
error(implicit_labels.loc,
"Kripke structure may not use implicit labels");
if (explicit_labels)
{
error(implicit_labels->second,
error(implicit_labels.loc,
"'properties: implicit-labels' is incompatible "
"with...");
error(explicit_labels->second,
error(explicit_labels.loc,
"... 'properties: explicit-labels'.");
}
else
{
res.label_style = Implicit_Labels;
}
}
auto trans_labels = res.props.find("trans-labels");
auto state_labels = res.props.find("state-labels");
auto trans_labels = res.prop_is_true("trans-labels");
auto state_labels = res.prop_is_true("state-labels");
if (trans_labels != res.props.end() && res.opts.want_kripke)
error(trans_labels->second,
"Kripke structure may not use transition labels");
if (trans_labels != res.props.end())
if (trans_labels)
{
if (state_labels == res.props.end())
if (res.opts.want_kripke)
error(trans_labels.loc,
"Kripke structure may not use transition labels");
if (state_labels)
{
if (res.label_style != Implicit_Labels)
res.label_style = Trans_Labels;
error(trans_labels.loc,
"'properties: trans-labels' is incompatible with...");
error(state_labels.loc,
"... 'properties: state-labels'.");
}
else
{
error(trans_labels->second,
"'properties: trans-labels' is incompatible with...");
error(state_labels->second,
"... 'properties: state-labels'.");
if (res.label_style != Implicit_Labels)
res.label_style = Trans_Labels;
}
}
else if (state_labels != res.props.end())
else if (state_labels)
{
if (res.label_style != Implicit_Labels)
{
......@@ -376,9 +393,9 @@ header: format-version header-items
}
else
{
error(state_labels->second,
error(state_labels.loc,
"'properties: state-labels' is incompatible with...");
error(implicit_labels->second,
error(implicit_labels.loc,
"... 'properties: implicit-labels'.");
}
}
......@@ -387,35 +404,35 @@ header: format-version header-items
error(@$,
"Kripke structure should use 'properties: state-labels'");
auto state_acc = res.props.find("state-acc");
auto trans_acc = res.props.find("trans-acc");
if (trans_acc != res.props.end())
auto state_acc = res.prop_is_true("state-acc");
auto trans_acc = res.prop_is_true("trans-acc");
if (trans_acc)
{
if (state_acc == res.props.end())
if (state_acc)
{
res.acc_style = Trans_Acc;
error(trans_acc.loc,
"'properties: trans-acc' is incompatible with...");
error(state_acc.loc,
"... 'properties: state-acc'.");
}
else
{
error(trans_acc->second,
"'properties: trans-acc' is incompatible with...");
error(state_acc->second,
"... 'properties: state-acc'.");
res.acc_style = Trans_Acc;
}
}
else if (state_acc != res.props.end())
else if (state_acc)
{
res.acc_style = State_Acc;
}
}
{
unsigned ss = res.start.size();
auto det = res.props.find("deterministic");
auto det = res.prop_is_true("deterministic");
if (ss > 1)
{
if (det != res.props.end())
if (det)
{
error(det->second,
error(det.loc,
"deterministic automata should have at most "
"one initial state");
}
......@@ -427,12 +444,12 @@ header: format-version header-items
// wrong, or unless we are building a Kripke structure.
res.deterministic = !res.opts.want_kripke;
}
auto complete = res.props.find("complete");
auto complete = res.prop_is_true("complete");
if (ss < 1)
{
if (complete != res.props.end())
if (complete)
{
error(complete->second,
error(complete.loc,
"complete automata should have at least "
"one initial state");
}
......@@ -447,9 +464,8 @@ header: format-version header-items
// if ap_count == 0, then a Kripke structure could be
// declared complete, although that probably doesn't
// matter.
if (res.opts.want_kripke && complete != res.props.end()
&& res.ap_count > 0)
error(complete->second,
if (res.opts.want_kripke && complete && res.ap_count > 0)
error(complete.loc,
"Kripke structure may not be complete");
}
if (res.opts.trust_hoa)
......@@ -457,25 +473,68 @@ header: format-version header-items
auto& a = res.aut_or_ks;
auto& p = res.props;
auto e = p.end();
if (p.find("stutter-invariant") != e)
auto si = p.find("stutter-invariant");
if (si != e)
{
a->prop_stutter_invariant(true);
a->prop_stutter_invariant(si->second.val);
auto i = p.find("stutter-sensitive");
if (i != e)
error(i->second,
if (i != e && si->second.val == i->second.val)
error(i->second.loc,
"automaton cannot be both stutter-invariant"
"and stutter-sensitive");
}
if (p.find("stutter-sensitive") != e)
a->prop_stutter_invariant(false);
if (p.find("inherently-weak") != e)
a->prop_inherently_weak(true);
if (p.find("weak") != e)
a->prop_weak(true);
if (p.find("terminal") != e)
a->prop_terminal(true);
if (p.find("unambiguous") != e)
a->prop_unambiguous(true);
else
{
auto ss = p.find("stutter-sensitive");
if (ss != e)
a->prop_stutter_invariant(!ss->second.val);
}
auto iw = p.find("inherently-weak");
auto w = p.find("weak");
auto t = p.find("terminal");
if (iw != e)
{
a->prop_inherently_weak(iw->second.val);
if (w != e && !iw->second.val && w->second.val)
{
error(w->second.loc, "'properties: weak' contradicts...");
error(iw->second.loc,
"... 'properties: !inherently-weak' given here");
}
if (t != e && !iw->second.val && t->second.val)
{
error(t->second.loc,
"'properties: terminal' contradicts...");
error(iw->second.loc,
"... 'properties: !inherently-weak' given here");
}
}
if (w != e)
{
a->prop_weak(w->second.val);
if (t != e && !w->second.val && t->second.val)
{
error(t->second.loc,
"'properties: terminal' contradicts...");
error(w->second.loc,
"... 'properties: !weak' given here");
}
}
if (t != e)
a->prop_terminal(t->second.val);
auto u = p.find("unambiguous");
if (u != e)
{
a->prop_unambiguous(u->second.val);
auto d = p.find("deterministic");
if (d != e && !u->second.val && d->second.val)
{
error(d->second.loc,
"'properties: deterministic' contradicts...");
error(u->second.loc,
"... 'properties: !unambiguous' given here");
}
}
}
}
......@@ -654,9 +713,34 @@ acc-spec: | acc-spec BOOLEAN
}
properties: | properties IDENTIFIER
{
res.props.emplace(*$2, @2);
auto pos = res.props.emplace(*$2, result_::prop_info{@2, true});
if (!pos.first->second.val)
{
std::ostringstream out(std::ios_base::ate);
error(@2, std::string("'properties: ")
+ *$2 + "' contradicts...");
error(pos.first->second.loc,
std::string("... 'properties: !") + *$2
+ "' previously given here.");
}
delete $2;
}
| properties '!' IDENTIFIER
{
auto loc = @2 + @3;
auto pos =
res.props.emplace(*$3, result_::prop_info{loc, false});
if (pos.first->second.val)
{
std::ostringstream out(std::ios_base::ate);
error(loc, std::string("'properties: !")
+ *$3 + "' contradicts...");
error(pos.first->second.loc,
std::string("... 'properties: ") + *$3
+ "' previously given here.");
}
delete $3;
}
header-spec: | header-spec BOOLEAN
| header-spec INT
| header-spec STRING
......@@ -918,22 +1002,20 @@ states: | states state
if (res.deterministic && !det)
{
res.deterministic = false;
auto p = res.props.find("deterministic");
if (p != res.props.end())
if (auto p = res.prop_is_true("deterministic"))
{
error(@2, "automaton is not deterministic...");
error(p->second,
error(p.loc,
"... despite 'properties: deterministic'");
}
}
if (res.complete && available != bddfalse)
{
res.complete = false;
auto p = res.props.find("complete");
if (p != res.props.end())
if (auto p = res.prop_is_true("complete"))
{
error(@2, "automaton is not complete...");
error(p->second, "... despite 'properties: complete'");
error(p.loc, "... despite 'properties: complete'");
}
}
}
......@@ -950,7 +1032,7 @@ state: state-name labeled-edges
{
error(@2, "these transitions have implicit labels but the"
" automaton is...");
error(res.props["state-labels"], "... declared with "
error(res.props["state-labels"].loc, "... declared with "
"'properties: state-labels'");
// Do not repeat this message.
res.label_style = Mixed_Labels;
......@@ -1019,11 +1101,11 @@ state-label_opt: { res.has_state_label = false; }
error(@$,
"state label used although the automaton was...");
if (res.label_style == Trans_Labels)
error(res.props["trans-labels"],
error(res.props["trans-labels"].loc,
"... declared with 'properties: trans-labels'"
" here");
else
error(res.props["implicit-labels"],
error(res.props["implicit-labels"].loc,
"... declared with 'properties: implicit-labels'"
" here");
// Do not show this error anymore.
......@@ -1045,11 +1127,11 @@ trans-label: label
error(@$, "transition label used although the "
"automaton was...");
if (res.label_style == State_Labels)
error(res.props["state-labels"],
error(res.props["state-labels"].loc,
"... declared with 'properties: state-labels' "
"here");
else
error(res.props["implicit-labels"],
error(res.props["implicit-labels"].loc,
"... declared with 'properties: implicit-labels'"
" here");
// Do not show this error anymore.
......@@ -1094,7 +1176,7 @@ state-acc_opt:
if (res.acc_style == Trans_Acc)
{
error(@$, "state-based acceptance used despite...");
error(res.props["trans-acc"],
error(res.props["trans-acc"].loc,
"... declaration of transition-based acceptance.");
res.acc_style = Mixed_Acc;
}
......@@ -1110,7 +1192,7 @@ trans-acc_opt:
if (res.acc_style == State_Acc)
{
error(@$, "trans-based acceptance used despite...");
error(res.props["state-acc"],
error(res.props["state-acc"].loc,
"... declaration of state-based acceptance.");
res.acc_style = Mixed_Acc;
}
......
......@@ -374,8 +374,8 @@ cat >input<<EOF
Start: 0
acc-name: generalized-Buchi 2
Acceptance: 2 (Inf(0) & Inf(1))
properties: implicit-labels explicit-labels /* ? */ complete
properties: trans-acc state-acc /* ? */
properties: !foo implicit-labels explicit-labels /* ? */ complete
properties: trans-acc state-acc /* ? */ !complete foo
AP: 2 "a" "b"
--BODY--
State: 0 "foo" { 0 }
......@@ -415,6 +415,7 @@ cat >input<<EOF
acc-name: generalized-Buchi 2
Acceptance: 2 (Inf(0) & Inf(1))
properties: implicit-labels trans-acc
properties: deterministic !unambiguous
AP: 2 "a" "b"
--BODY--
State: 0 "foo" { 0 }
......@@ -430,16 +431,22 @@ cat >input<<EOF
EOF
expecterr input <<EOF
input:7.17-31: 'properties: implicit-labels' is incompatible with...
input:7.33-47: ... 'properties: explicit-labels'.
input:8.45-53: 'properties: !complete' contradicts...
input:7.62-69: ... 'properties: complete' previously given here.
input:8.55-57: 'properties: foo' contradicts...
input:7.17-20: ... 'properties: !foo' previously given here.
input:7.22-36: 'properties: implicit-labels' is incompatible with...
input:7.38-52: ... 'properties: explicit-labels'.
input:8.17-25: 'properties: trans-acc' is incompatible with...
input:8.27-35: ... 'properties: state-acc'.
input:16.7: too many transitions for this state, ignoring this one
input:28.33-44: 'properties: state-labels' is incompatible with...
input:28.17-31: ... 'properties: implicit-labels'.
input:50.20-24: state-based acceptance used despite...
input:48.17-29: 'properties: deterministic' contradicts...
input:48.31-42: ... 'properties: !unambiguous' given here
input:51.20-24: state-based acceptance used despite...
input:47.33-41: ... declaration of transition-based acceptance.
input:58.7-9: transition label used although the automaton was...
input:59.7-9: transition label used although the automaton was...
input:47.17-31: ... declared with 'properties: implicit-labels' here
EOF
......@@ -1814,6 +1821,24 @@ State: 9
[0&!1] 9
[0&!1] 5
--END--
HOA: v1
States: 1
Start: 0
AP: 0
Acceptance: 0 t
properties: !inherently-weak !weak terminal
--BODY--
State: 0 0
--END--
HOA: v1
States: 1
Start: 0
AP: 0
Acceptance: 0 t
properties: !inherently-weak weak
--BODY--
State: 0 0
--END--
EOF
expecterr input <<EOF
......@@ -1821,6 +1846,12 @@ input:3.1-8: initial state 0 has no definition
input:13.9: state 2 has no definition
input:17.7: state 5 has no definition
input:14.9: state 8 has no definition
input:36.36-43: 'properties: terminal' contradicts...
input:36.13-28: ... 'properties: !inherently-weak' given here
input:36.36-43: 'properties: terminal' contradicts...
input:36.30-34: ... 'properties: !weak' given here
input:45.30-33: 'properties: weak' contradicts...
input:45.13-28: ... 'properties: !inherently-weak' given here
EOF
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment