comparison bin/shove @ 2020:37f8c80f6bf3

<oerjan> chmod a+x YaOJ; mv YaOJ bin/shove
author HackBot
date Wed, 06 Feb 2013 23:26:39 +0000
parents
children 99dfa6a18c7f
comparison
equal deleted inserted replaced
2019:48d54ab469c5 2020:37f8c80f6bf3
1 #!/usr/bin/env perl
2 # -*- cperl -*-
3 # Shove interpreter. By Alex Smith.
4
5 # Commands:
6 # ' " Quote a string ('' strings nest inside "" strings and vice versa)
7 # < v > ^ Change direction of execution
8 # A V ( ) Pop a string onto the playfield
9 # space NOP
10
11 # ! NOP, but tells the compiler that everything behind the IP will
12 # never be used (a useful optimisation)
13 # S NOP, but outputs TOS (without popping) on systems with output
14 # n NOP, but outputs a newline on systems with output
15
16 use strict;
17
18 # Read in the program
19
20 my @program = <>;
21 chomp for @program;
22
23 my $x = 0;
24 my $y = 0;
25 my $width = 0; $width = ($width < length $_ ? length $_ : $width) for @program;
26 my $height = scalar @program;
27 my $totalrotation = 0;
28 my @stack = ();
29 # always going right, we rotate the program if necessary to ensure this
30
31 # Pads its argument to width $width.
32 sub widthpad {
33 my $s = shift;
34 return $s . (' ' x ($width - length $s));
35 }
36
37 # Rotates the program clockwise (arg = 1), 180 degrees (arg = 2),
38 # or anticlockwise (arg = 3)
39 sub rotateprogram {
40 my $amount = shift;
41 $amount or return;
42 $totalrotation += $amount;
43 $totalrotation %= 4;
44 if ($amount >= 2) {
45 @program = reverse @program;
46 $_ = reverse widthpad $_ for @program;
47 $x = $width - 1 - $x;
48 $y = $height - 1 - $y;
49 tr/<v>^AV()/>^<vVA)(/ for @program;
50 $amount == 2 and return;
51 } else {
52 $_ = widthpad $_ for @program;
53 }
54 my @newprog = ();
55 # We repeatedly move the leftmost column of @program to the top row
56 # of @newprog.
57 while (length $program[0]) {
58 my $build='';
59 $build = (substr $_, 0, 1, '') . $build for @program;
60 push @newprog, $build;
61 }
62 @program = @newprog;
63 tr/<^>v(A)V/^>v<A)V(/ for @program;
64 ($width, $height) = ($height, $width);
65 ($x, $y) = ($width - 1 - $y, $x);
66 }
67
68 sub shove {
69 my $sx = shift;
70 my $sy = shift;
71 if($sx < 0) {
72 $_ = ' '.$_ for @program;
73 $x++;
74 $sx++;
75 $width++;
76 }
77 if($sx >= $width) {
78 $width++;
79 }
80 if($sy < 0) {
81 unshift @program, "";
82 $y++;
83 $sy++;
84 $height++;
85 }
86 if($sy >= $height) {
87 push @program, "";
88 $height++;
89 }
90 scalar @stack or die "Empty stack when shoving.";
91 $program[$sy] = widthpad $program[$sy];
92 ($x > $sx && $y == $sy) and $x += length $stack[0];
93 substr $program[$sy], $sx, 0, shift @stack;
94 $program[$sy] =~ s/\ +$//;
95 $width < length $program[$sy] and $width = length $program[$sy];
96 }
97
98 sub showprogram {
99 my $tr = $totalrotation;
100 print "\nactual size: ($width, $height), pos: ($x, $y)\n";
101 rotateprogram ((4-$tr)%4);
102 $program[$y] = widthpad $program[$y];
103 my $c = substr $program[$y], $x, 1, '*';
104 print "rotated for viewing; pos: ($x, $y), dir: $tr\n";
105 print "stack: ";
106 print "{$_} " for @stack;
107 print "\n";
108 print "$_\n" for @program;
109 substr $program[$y], $x, 1, $c;
110 rotateprogram $tr;
111 scalar <>;
112 }
113
114 while ($x < $width && $y < $height && $x >= 0 && $y >= 0) {
115 showprogram;
116 my $cmd = substr $program[$y], $x, 1;
117 # $cmd eq '>' is a nop
118 $cmd eq '^' and rotateprogram 1;
119 $cmd eq '<' and rotateprogram 2;
120 $cmd eq 'v' and rotateprogram 3;
121 $cmd eq '(' and shove $x-1, $y;
122 $cmd eq ')' and shove $x+1, $y;
123 $cmd eq 'A' and shove $x, $y-1;
124 $cmd eq 'V' and shove $x, $y+1;
125 $cmd eq 'S' and print $stack[0];
126 $cmd eq 'n' and print '\n';
127 if ($cmd eq '!') {
128 substr $_, 0, $x, '' for @program;
129 $width -= $x;
130 $x = 0;
131 }
132 if ($cmd eq '"' || $cmd eq "'") {
133 my $quotecount = 1;
134 my $lws = $cmd eq "'";
135 my $newpush = "";
136 while($quotecount) {
137 $x++;
138 $x < $width or die "Unterminated string.";
139 $cmd = substr $program[$y], $x, 1;
140 $cmd eq "'" and ($quotecount += ($lws ? -1 : 1)), ($lws = !$lws);
141 $cmd eq '"' and ($quotecount += ($lws ? 1 : -1)), ($lws = !$lws);
142 $quotecount and $newpush .= $cmd;
143 }
144 unshift @stack, $newpush;
145 }
146 $x++; # move to next command
147 }
148