spot/bench/emptchk/pml2tgba.pl

209 lines
5.2 KiB
Perl
Executable file
Raw Blame History

#!/usr/bin/perl -w
#
# Copyright (C) 2004 Stefan Schwoon
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
#
#
# This script was originally distributed by Schwoon alongside
#
# @InProceedings{ schwoon.05.tacas,
# author = {Stefan Schwoon and Javier Esparza},
# title = {A note on on-the-fly verification algorithms.},
# booktitle = {Proceedings of the 11th International Conference on Tools
# and Algorithms for the Construction and Analysis of Systems
# (TACAS'05)},
# year = {2005},
# series = {Lecture Notes in Computer Science},
# publisher = {Springer-Verlag},
# month = apr
# }
#
# It has been modified in 2005 by Alexandre Duret-Lutz to
# - extract the system's state space instead of the product space
# (we want to use the LTL->TGBA translation of Spot, not that of Spin)
# - output the state space in Spot's format
# - optionally output weak fairness constraints
use strict;
my @prop_list;
my %props;
sub usage()
{
print <<EOF;
Usage: pml2tgba.pl [-w] promela-model properties...
Extract the state-space of the promela-model, observing properties.
If -w is given, output acceptance conditions to ensure weak fairness.
EOF
exit 1;
}
sub create_2n_automaton (@)
{
my @props = @_;
my @res;
for my $p (@props)
{
if (@res)
{
@res = map { ("$_ && ($p)", "$_ && !($p)") } @res;
}
else
{
@res = ("($p)", "!($p)");
}
}
my $trans = "\n if\n";
my $nres = $#res + 1;
for my $p (@res)
{
push @prop_list, $p;
$trans .= " :: ($p) -> goto T0_init\n";
}
$trans .= " fi;\n";
if ($nres == 0)
{
push @prop_list, "(1)";
}
return "never {\nT0_init:$trans}\n";
}
usage unless @ARGV;
my $weak = 0;
if ($ARGV[0] eq '-w')
{
$weak = 1;
shift;
}
my $model = shift @ARGV;
# Find out the start of the never claim.
my $neverstartline = 3 + `wc -l <"$model"`;
# Create the automaton
open NEVER, ">never.$$";
print NEVER create_2n_automaton (@ARGV);
close NEVER;
system "spin -a -N never.$$ \"$model\"";
unlink "never.$$";
system "gcc -DCHECK -DNOREDUCE -O -o pan pan.c 2>/dev/null";
# Match B<>chi states to propositions
my $buechitrans = 'BUG';
open PAN, "./pan -d|";
while (<PAN>)
{
last if /^proctype :never/;
}
while (<PAN>)
{
next
unless (/\s+state\s+\d+\s+-\(tr\s+(\d+)\s*\)->.* line $neverstartline =>/o);
# We are assuming that transition are output by -d in the same order
# as we specified them in the neverclaim.
my $prop = shift @prop_list;
$props{$1} = $prop;
}
close PAN;
# Build the state graph from pan's DFS output
open PAN, "./pan 2>/dev/null |";
my $dfsstate = 0;
my @stack = ();
while (<PAN>) {
last if (/ New state 0/);
}
my %acc = ();
push @stack, [$dfsstate, $buechitrans, %acc];
my %allaccs = ();
my %trans_list;
my $prop = "BUG";
while (<PAN>) {
if (/^\d*: Down/) {
push @stack, [$dfsstate, $buechitrans, %acc];
} elsif (/^ New state (\d+)/) {
pop @stack;
push (@{$trans_list{$dfsstate}}, ["S$dfsstate, S$1, \"$prop\"", %acc]);
%acc = ();
$dfsstate = $1;
push @stack, [$dfsstate, $buechitrans, %acc];
} elsif (/^ (Old|Stack) state (\d+)/) {
push (@{$trans_list{$dfsstate}}, ["S$dfsstate, S$2, \"$prop\"", %acc]);
%acc = ();
} elsif (/^ *\d+: proc 0 exec (\d+), \d+ to \d+/) {
$buechitrans = $1;
$prop = $props{$buechitrans};
} elsif (/^ *\d+: proc (\d+) exec \d+, \d+ to \d+/) {
$acc{"PR$1"} = 1;
$allaccs{"PR$1"} = 1;
} elsif (/^\d*: Up/) {
pop @stack;
($dfsstate, $buechitrans, %acc) = @{$stack[$#stack]};
$prop = $props{$buechitrans};
}
}
close PAN;
unlink "pan", "pan.exe", "pan.c", "pan.h", "pan.b", "pan.t", "pan.m";
print "acc = @{[sort keys %allaccs]};\n" if $weak;
for my $state (sort {$a <=> $b} (keys %trans_list))
{
my %missing = %allaccs;
for my $t (@{$trans_list{$state}})
{
my ($trans, %acc) = @$t;
for my $key (keys %acc)
{
delete $missing{$key};
}
}
for my $t (@{$trans_list{$state}})
{
my ($trans, %acc) = @$t;
print "$trans,";
print " @{[sort keys(%acc)]} @{[sort keys(%missing)]}" if $weak;
print ";\n";
}
}
exit 0;
### Setup "GNU" style for perl-mode and cperl-mode.
## Local Variables:
## perl-indent-level: 2
## perl-continued-statement-offset: 2
## perl-continued-brace-offset: 0
## perl-brace-offset: 0
## perl-brace-imaginary-offset: 0
## perl-label-offset: -2
## cperl-indent-level: 2
## cperl-brace-offset: 0
## cperl-continued-brace-offset: 0
## cperl-label-offset: -2
## cperl-extra-newline-before-brace: t
## cperl-merge-trailing-else: nil
## cperl-continued-statement-offset: 2
## End: