Mercurial > repo
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 |