2 # This file is part of Language::Befunge.
3 # Copyright (c) 2001-2008 Jerome Quelin, all rights reserved.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the same terms as Perl itself.
10 package Language
::Befunge
::IP
;
18 use Language
::Befunge
::Vector
;
19 use Storable
qw(dclone);
25 my ($class, $dims) = @_;
26 $dims = 2 unless defined $dims;
32 position
=> Language
::Befunge
::Vector
->new_zeroes($dims),
33 delta
=> Language
::Befunge
::Vector
->new_zeroes($dims),
34 storage
=> Language
::Befunge
::Vector
->new_zeroes($dims),
41 $self->{delta
}->set_component(0, 1);
43 $self->set_id( $self->_get_new_id );
49 my $clone = dclone
( $self );
50 $clone->set_id( $self->_get_new_id );
58 my @attrs = qw
[ position data delta end id libs
59 ss storage string_mode toss
];
60 foreach my $attr ( @attrs ) {
61 my $code = qq[ sub get_
$attr { return \
$_[0]->{$attr} } ];
62 $code .= qq[ sub set_
$attr { \
$_[0]->{$attr} = \
$_[1] } ];
67 sub get_dims
{ return $_[0]->{dims
} };
71 # Remember, the Stack Stack is up->bottom.
72 @_ and $self->get_ss->[0] = shift;
73 return $self->get_ss->[0];
79 return scalar @
{ $self->get_toss };
84 push @
{ $self->get_toss }, @_;
90 $self->spush($v->get_all_components);
96 foreach my $arg ( @_ ) {
98 ( ($arg =~ /^-?\d+$/) ?
100 : reverse map {ord} split //, $arg.chr(0) # A string.
107 my $val = pop @
{ $self->get_toss };
108 defined $val or $val = 0;
113 my ($self, $count) = @_;
114 my @rv = reverse map { $self->spop() } (1..$count);
120 return Language
::Befunge
::Vector
->new($self->spop_mult($self->get_dims));
127 $val = pop @
{ $self->get_toss };
128 defined $val or $val = 0;
130 } while( $val != 0 );
131 chop $str; # Remove trailing \0.
137 $self->set_toss( [] );
141 my ($self, $idx) = @_;
143 $idx = - abs( $idx );
144 return 0 unless exists $self->get_toss->[$idx];
145 return $self->get_toss->[$idx];
150 return scalar( @
{ $self->get_ss } );
154 my ( $self, $n ) = @_;
159 # Push zeroes on *current* toss (to-be soss).
160 $self->spush( (0) x
abs($n) );
162 my $c = $n - $self->scount;
165 @new_toss = splice @
{ $self->get_toss }, -$n;
167 # Transfer elems and fill with zeroes.
168 @new_toss = ( (0) x
$c, @
{ $self->get_toss } );
172 # $n == 0: do nothing
175 # Push the former TOSS on the stack stack and copy reference to
177 # For commodity reasons, the Stack Stack is oriented up->bottom
178 # (that is, a push is an unshift, and a pop is a shift).
179 unshift @
{ $self->get_ss }, $self->get_toss;
180 $self->set_toss( \
@new_toss );
184 my ( $self, $n ) = @_;
187 # Remember, the Stack Stack is up->bottom.
188 my $new_toss = shift @
{ $self->get_ss };
192 if ( scalar(@
$new_toss) >= abs($n) ) {
193 splice @
$new_toss, $n;
198 my $c = $n - $self->scount;
201 push @
$new_toss, splice( @
{ $self->get_toss }, -$n );
203 # Transfer elems and fill with zeroes.
204 push @
$new_toss, ( (0) x
$c, @
{ $self->get_toss } );
207 # $n == 0: do nothing
210 # Store the new TOSS.
211 $self->set_toss( $new_toss );
219 # Transfer from SOSS to TOSS.
220 my $c = $n - $self->soss_count;
223 @elems = splice @
{ $self->soss }, -$n;
225 @elems = ( (0) x
$c, @
{ $self->soss } );
228 $self->spush( reverse @elems );
232 # Transfer from TOSS to SOSS.
233 my $c = $n - $self->scount;
236 @elems = splice @
{ $self->get_toss }, -$n;
238 @elems = ( (0) x
$c, @
{ $self->get_toss } );
241 $self->soss_push( reverse @elems );
249 my @sizes = ( $self->scount );
251 # Store the size of each stack.
252 foreach my $i ( 1..$self->ss_count ) {
253 push @sizes, scalar @
{ $self->get_ss->[$i-1] };
262 return scalar( @
{ $self->soss } );
267 push @
{ $self->soss }, @_;
272 my ($self, $count) = @_;
273 my @rv = reverse map { $self->soss_pop() } (1..$count);
280 $self->soss_push($v->get_all_components);
286 my $val = pop @
{ $self->soss };
287 defined $val or $val = 0;
293 return Language
::Befunge
::Vector
->new($self->soss_pop_mult($self->get_dims));
305 $self->get_delta->clear;
306 $self->get_delta->set_component(0, 1);
311 $self->get_delta->clear;
312 $self->get_delta->set_component(0, -1);
317 $self->get_delta->clear;
318 $self->get_delta->set_component(1, -1);
323 $self->get_delta->clear;
324 $self->get_delta->set_component(1, 1);
329 $self->get_delta->clear;
330 $self->get_delta->set_component(2, 1);
335 $self->get_delta->clear;
336 $self->get_delta->set_component(2, -1);
341 my $nd = $self->get_dims;
342 my $dim = (0..$nd-1)[int(rand $nd)];
343 $self->get_delta->clear;
344 my $value = (-1, 1)[int(rand 2)];
345 $self->get_delta->set_component($dim, $value);
350 my $old_dx = $self->get_delta->get_component(0);
351 my $old_dy = $self->get_delta->get_component(1);
352 $self->get_delta->set_component(0, 0 + $old_dy);
353 $self->get_delta->set_component(1, 0 + $old_dx * -1);
358 my $old_dx = $self->get_delta->get_component(0);
359 my $old_dy = $self->get_delta->get_component(1);
360 $self->get_delta->set_component(0, 0 + $old_dy * -1);
361 $self->get_delta->set_component(1, 0 + $old_dx);
366 $self->set_delta(-$self->get_delta);
370 my ($self, $lib) = @_;
371 unshift @
{ $self->get_libs }, $lib;
375 my ($self, $lib) = @_;
378 foreach my $i ( 0..$#{$self->get_libs} ) {
379 $offset = $i, last if ref($self->get_libs->[$i]) eq $lib;
381 $offset == -1 and return undef;
382 splice @
{ $self->get_libs }, $offset, 1;
389 @_ ?
$self->get_data->{$lib} = shift : $self->get_data->{$lib};
396 # my $id = _get_new_id;
398 # Forge a new IP id, that will distinct it from the other IPs of the program.
410 Language::Befunge::IP - an Instruction Pointer for a Befunge-98 program.
416 This is the class implementing the Instruction Pointers. An
417 Instruction Pointer (aka IP) has a stack, and a stack of stacks that
418 can be manipulated via the methods of the class.
420 We need a class, since this is a concurrent Befunge, so we can have
421 more than one IP travelling on the Lahey space.
427 =head2 my $ip = LB::IP->new( [$dimensions] )
429 Create a new Instruction Pointer, which operates in a universe of the given
430 C<$dimensions>. If C<$dimensions> is not specified, it defaults to 2
434 =head2 my $clone = $ip->clone()
436 Clone the current Instruction Pointer with all its stacks, position,
437 delta, etc. Change its unique ID.
445 The following is a list of attributes of a Language::Befunge::IP
446 object. For each of them, a method C<get_foobar> and C<set_foobar>
452 =item $ip->get_id() / $ip->set_id($id)
454 The unique ID of the IP (an integer). Don't set the ID yourself.
457 =item $ip->get_dims()
459 The number of dimensions this IP operates in (an integer). This is
463 =item $ip->get_position() / $ip->set_position($vec)
465 The current coordinates of the IP (a C<Language::Befunge::Vector>
469 =item $ip->get_delta() / $ip->set_delta($vec)
471 The velocity of the IP (a C<Language::Befunge::Vector> object).
474 =item $ip->get_storage() / $ip->set_storage($vec)
476 The coordinates of the storage offset of the IP (a
477 C<Language::Befunge::Vector> object).
480 =item $ip->get_data() / $ip->set_data({})
482 The library private storage space (a hash reference). Don't set this
484 FIXME: not supposed to be accessible
487 =item $ip->get_string_mode() / set_string_mode($bool)
489 The string_mode of the IP (a boolean).
492 =item $ip->get_end() / $ip->set_end($bool)
494 Whether the IP should be terminated (a boolean).
497 =item $ip->get_libs() / $ip->set_libs($aref)
499 The current stack of loaded libraries (an array reference). Don't set
501 FIXME: not supposed to be accessible
504 =item $ip->get_ss() / $ip->set_ss($aref)
506 The stack of stack of the IP (an array reference). Don't set this
508 FIXME: not supposed to be accessible
511 =item $ip->get_toss() / $ip->set_toss($aref)
513 The current stack (er, TOSS) of the IP (an array reference). Don't set
515 FIXME: not supposed to be accessible
521 =head2 $ip->soss([$])
527 =head1 PUBLIC METHODS
529 =head2 Internal stack
531 In this section, I speak about the stack. In fact, this is the TOSS - that
532 is, the Top Of the Stack Stack.
534 In Befunge-98, standard stack operations occur transparently on the
535 TOSS (as if there were only one stack, as in Befunge-93).
542 Return the number of elements in the stack.
547 Push a value on top of the stack.
550 =item spush_vec( vector )
552 Push a vector on top of the stack. The x coordinate is pushed first.
555 =item spush_args ( arg, ... )
557 Push a list of argument on top of the stack (the first argument will
558 be the deeper one). Convert each argument: a number is pushed as is,
559 whereas a string is pushed as a 0gnirts.
561 B</!\> Do B<not> push references or weird arguments: this method
562 supports only numbers (positive and negative) and strings.
567 Pop a value from the stack. If the stack is empty, no error occurs and
568 the method acts as if it popped a 0.
571 =item spop_mult( <count> )
573 Pop multiple values from the stack. If the stack becomes empty, the
574 remainder of the returned values will be 0.
579 Pop a vector from the stack. Returns a Vector object.
584 Pop a 0gnirts string from the stack.
592 =item svalue( offset )
594 Return the C<offset>th value of the TOSS, counting from top of the
595 TOSS. The offset is interpreted as a negative value, that is, a call
596 with an offset of C<2> or C<-2> would return the second value on top
605 This section discusses about the stack stack. We can speak here about
606 TOSS (Top Of Stack Stack) and SOSS (second on stack stack).
612 Return the number of stacks in the stack stack. This of course does
613 not include the TOSS itself.
617 =item ss_create( count )
619 Push the TOSS on the stack stack and create a new stack, aimed to be
620 the new TOSS. Once created, transfer C<count> elements from the SOSS
621 (the former TOSS) to the TOSS. Transfer here means move - and B<not>
622 copy -, furthermore, order is preserved.
624 If count is negative, then C<count> zeroes are pushed on the new TOSS.
627 =item ss_remove( count )
629 Move C<count> elements from TOSS to SOSS, discard TOSS and make the
630 SOSS become the new TOSS. Order of elems is preserved.
633 =item ss_transfer( count )
635 Transfer C<count> elements from SOSS to TOSS, or from TOSS to SOSS if
636 C<count> is negative; the transfer is done via pop/push.
638 The order is not preserved, it is B<reversed>.
643 Return a list with all the sizes of the stacks in the stack stack
644 (including the TOSS), from the TOSS to the BOSS.
649 Return the number of elements in SOSS.
652 =item soss_push( value )
654 Push a value on top of the SOSS.
657 =item soss_pop_mult( <count> )
659 Pop multiple values from the SOSS. If the stack becomes empty, the
660 remainder of the returned values will be 0.
663 =item soss_push_vec( vector )
665 Push a vector on top of the SOSS.
671 Pop a value from the SOSS. If the stack is empty, no error occurs and
672 the method acts as if it popped a 0.
675 =item soss_pop_vec( )
677 Pop a vector from the SOSS. If the stack is empty, no error occurs
678 and the method acts as if it popped a 0. returns a Vector.
689 =head2 Changing direction
695 Implements the C<E<gt>> instruction. Force the IP to travel east.
700 Implements the C<E<lt>> instruction. Force the IP to travel west.
703 =item dir_go_north( )
705 Implements the C<^> instruction. Force the IP to travel north.
707 Not valid for Unefunge.
710 =item dir_go_south( )
712 Implements the C<v> instruction. Force the IP to travel south.
714 Not valid for Unefunge.
719 Implements the C<h> instruction. Force the IP to travel up.
721 Not valid for Unefunge or Befunge.
726 Implements the C<l> instruction. Force the IP to travel down.
728 Not valid for Unefunge or Befunge.
733 Implements the C<?> instruction. Cause the IP to travel in a random
734 cardinal direction (in Befunge's case, one of: north, south, east or
738 =item dir_turn_left( )
740 Implements the C<[> instruction. Rotate by 90 degrees on the left the
741 delta of the IP which encounters this instruction.
743 Not valid for Unefunge. For Trefunge and greater, only affects the
747 =item dir_turn_right( )
749 Implements the C<]> instruction. Rotate by 90 degrees on the right the
750 delta of the IP which encounters this instruction.
752 Not valid for Unefunge. For Trefunge and higher dimensions, only
753 affects the X and Y axes.
759 Implements the C<r> instruction. Reverse the direction of the IP, that
760 is, multiply the IP's delta by -1.
766 =head2 Libraries semantics
772 Load the given library semantics. The parameter is an extension object
773 (a library instance).
779 Unload the given library semantics. The parameter is the library name.
781 Return the library name if it was correctly unloaded, undef otherwise.
783 B</!\> If the library has been loaded twice, this method will only
784 unload the most recent library. Ie, if an IP has loaded the libraries
785 ( C<FOO>, C<BAR>, C<FOO>, C<BAZ> ) and one calls C<unload( "FOO" )>,
786 then the IP will follow the semantics of C<BAZ>, then C<BAR>, then
790 =item extdata( library, [value] )
792 Store or fetch a value in a private space. This private space is
793 reserved for libraries that need to store internal values.
795 Since in Perl references are plain scalars, one can store a reference
796 to an array or even a hash.
805 L<Language::Befunge>.
810 Jerome Quelin, E<lt>jquelin@cpan.orgE<gt>
814 =head1 COPYRIGHT & LICENSE
816 Copyright (c) 2001-2008 Jerome Quelin, all rights reserved.
818 This program is free software; you can redistribute it and/or modify
819 it under the same terms as Perl itself.