Re: Perl 'Hard' Quiz of the Week #2005-03-22

Colin Rafferty <colin.rafferty-/PgpppG8B+R7qynMiXIxWgC/[email protected]> Wed, 23 Mar 2005 14:12:19 -0500
Newsgroups gmane.comp.lang.perl.qotw.discuss
Message-ID <[email protected]>
I've written an FSM package that tests correctness of FSM input, and
runs a machine.  Put this in FSM.pm.

%<--------%<--------%<--------%<--------%<--------%<--------%<--------

package FSM;

=head1 NAME

FSM - a module to run FSMs as defined in 2005-03-22 hard quiz.

=head1 SYNOPSIS

    my $fsm = new FSM(gen_is_divisable_fsm($N));
    $fsm->step($_) for binary_digits($input);
    print "Machine for $N ", ($fsm->ret() ? "succeeded" : "failed",
          " on input $input.\n";

=head1 DESCRIPTION

Handles all aspects of running a FSM.

=over

=cut

use Carp;
use strict;

=item new(init, states)

    my $fsm = new FSM($init, $states);

These are the results of gen_is_divisable_fsm() from the quiz
specification.  Croaks if the inputs are invalid.

=cut

sub new
{
  my ($class, $init, $states) = @_;

  croak "initial state must be in machine\n"
    if $init < 0 || $init > @$states;

  (!defined $_->{ret} ||
   @{$_->{next_states}} != 2 ||
   $_->{next_states}->[0] < 0 ||
   $_->{next_states}->[0] > @$states ||
   $_->{next_states}->[1] < 0 ||
   $_->{next_states}->[1] > @$states)
    and croak "invalid state in machine\n"
      for @$states;

  my $self = {
              init => $init,
              state => $init,
              states => $states,
             };

  bless($self, $class);
  return $self;
}

=item step(digit)

    $fsm->step('1');

Takes a single step through the FSM with the input digit.  Croaks if
the digit is neither 0 nor 1.

=cut

sub step
{
  my ($self, $digit) = @_;
  croak "invalid digit: $digit\n" unless $digit == 0 or $digit == 1;

  $self->{state} = $self->{states}->[$self->{state}]->{next_states}->[$digit];
}

=item ret()

    my $ret = $fsm->ret();

Returns the `ret' value of the current state.

=cut

sub ret
{
  my ($self) = @_;
  return $self->{states}->[$self->{state}]->{ret};
}

=item reset()

    $fsm->reset();

Resets the FSM back to its original state.

=cut

sub reset
{
  my ($self) = @_;
  $self->{state} = $self->{init};
}

=over

=head1 AUTHOR

Colin Rafferty

=cut

1;

# end file FSM.pm