#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @R = qw//; my @A = ( #init: 0, #asn 0,0,1,5, 0, 3,0,1,1, 0, 4,0,1,1, 2, #Flow() 3000, #iterations 4, #num events 1000, #skipto 0,1,1, 0, 1, 1, 1,1, 2,0, 1, 0, 2, 1, 1,2, 2,0, 1, 0, -.1, 1, 2,-1, 2,-2, 0, 0, 0, 1, 2,0, 1,1, 0, ); my $ptr = 0; my $limit = 10000; #kill infinite loops etc. while (1){ event(); } sub event { $limit--; dump_("LIMIT REACHED") unless $limit; my ($choice) = access_A(); $choice = $choice%3; if ($choice == 0) { assignment() } if ($choice == 1){ go() } if ($choice == 2){ flow() } } sub dump_{ my $debug = shift; print map{$_,"|"}@R; print "\ndump_ message is $debug\n"; die; } sub access_A { my $value; my $no_R = shift; #if this has a value, then we do not convert negative numbers from A to R references. This is needed for expressions. my $int = shift; defined $A[$ptr]? $value = $A[$ptr]: dump_('end'); $ptr++; unless ($no_R){ $value =$R [abs($value)] if $value < 0; #to get to R[0] this way, use -.1 or some similar value } $value = int($value) if $int; return ($value); } sub access_R{ my $ref = shift; my $value; (defined $R[$ref])? ($value = $R[$ref]): ($value = 0); $value } sub flow{ # iterations give us if() for() and while() loops all in one. # iterations = 0 gives us a while from the conditional # iterations = 1 gives us an if from conditional # iterations = >1 gives us a for loop from conditional. # with a conditional of (1) (like while (1)) you end # up with a classic for loop # # # my $iterations = access_A(0,'int'); my $num_events = access_A(0,'int'); $num_events = 1 unless $num_events; my $skipto = access_A(0,'int'); $skipto += $ptr; my $conditional_ptr = $ptr; if ($iterations){ for (1 .. $iterations){ if (conditional()){ for (1 .. $num_events){event()} }else{last} $ptr = $conditional_ptr; } }else{ while (conditional()){ for (1 .. $num_events){event()} $ptr = $conditional_ptr; } } $ptr = $skipto; } sub conditional{ my @operators = qw/== < > != <= >= and or xor/; my $truthiness = expression(\@operators); return $truthiness } sub assignment{ my @operators = qw/+ - * \/ ** %/; my $left_val_ref = access_A(); my $result = expression(\@operators); $R[$left_val_ref] = $result; } ####____ # sub expression has several routines associated with it: # rpn() # get_operator() # get_value() # val_or_operator() # # sub expression { my $operator_list = shift; my $o = access_A(0,'int');#num of ops if ($o == 0){ return get_value(); } my @a = (get_value(),get_value()); #start with two numbers my $v = $o -1; #with the two numbers above.. we reduce the value count while ($o){ if ($o == $v){ push @a, get_value();$v--; next }elsif ($v){ if (val_or_operator()){ push @a, get_value(); $v--; }else{ push @a, get_operator($operator_list); $o--; } next } push @a, get_operator($operator_list); $o--; } my $result = rpn(\@a); return $result; } sub get_operator { my $operator_list = shift; my $op = access_A(); my $operator = $operator_list->[$op % ($#$operator_list+1)]; return $operator; } sub get_value{ #in which we learn weather or not the next value is a reference to @R # then we return the result # # we don't use the "negative numbers are R refs," becuase negative nums # are kinda useful in arithmetic... go figure. my $val = access_A(); # $val is the choice between either an A value or an R value ($val% 2)? ($val = access_A("no R")): ($val = access_R(access_A())); # $val is now an arithmetic value defined($val)?return $val:return 0; } sub val_or_operator{ my $choice = access_A(); return $choice%2; } sub rpn{ my $a = shift; my @stack; for (@$a){ (/\d/)? (push @stack, $_): (push @stack, eval ((pop @stack)." $_ ".(pop @stack))); dump_("big-ass number") if ($stack[$#stack] =~/e/); #too big is too big. dump_(" DIV by ZERO is a BIG problem") if ($@=~ /Illegal/); #honestly don't need to deal with div by 0 ($stack[$#stack] = 0) unless (defined $stack[$#stack]); $stack[$#stack] = 0 if $stack[$#stack] == -0; #wierd... but I have to do it. } return $stack[0]; } # the above ends selections of routines for expression() ###__________ sub go { my $loc = access_A(); my $iterations = access_A(0,'int'); unless ($iterations){ $ptr = $loc; return } my $temp = $ptr; $ptr = $loc; for (0 .. $iterations){ event() } $ptr = $temp; }