Mercurial > repo
comparison shove @ 2021:909b62d951cb
<oerjan> fetch http://oerjan.nvg.org/esoteric/shove/shove
author | HackBot |
---|---|
date | Wed, 06 Feb 2013 23:57:49 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2020:37f8c80f6bf3 | 2021:909b62d951cb |
---|---|
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 $debug = ($#ARGV >= 0 and $ARGV[0] eq '-d' and shift and 1); | |
21 my @program = ($#ARGV >= 0) ? @ARGV : <>; | |
22 chomp for @program; | |
23 | |
24 my $x = 0; | |
25 my $y = 0; | |
26 my $width = 0; $width = ($width < length $_ ? length $_ : $width) for @program; | |
27 my $height = scalar @program; | |
28 my $totalrotation = 0; | |
29 my @stack = (); | |
30 # always going right, we rotate the program if necessary to ensure this | |
31 | |
32 # Pads its argument to width $width. | |
33 sub widthpad { | |
34 my $s = shift; | |
35 return $s . (' ' x ($width - length $s)); | |
36 } | |
37 | |
38 # Rotates the program clockwise (arg = 1), 180 degrees (arg = 2), | |
39 # or anticlockwise (arg = 3) | |
40 sub rotateprogram { | |
41 my $amount = shift; | |
42 $amount or return; | |
43 $totalrotation += $amount; | |
44 $totalrotation %= 4; | |
45 if ($amount >= 2) { | |
46 @program = reverse @program; | |
47 $_ = reverse widthpad $_ for @program; | |
48 $x = $width - 1 - $x; | |
49 $y = $height - 1 - $y; | |
50 tr/<v>^AV()/>^<vVA)(/ for @program; | |
51 $amount == 2 and return; | |
52 } else { | |
53 $_ = widthpad $_ for @program; | |
54 } | |
55 my @newprog = (); | |
56 # We repeatedly move the leftmost column of @program to the top row | |
57 # of @newprog. | |
58 while (length $program[0]) { | |
59 my $build=''; | |
60 $build = (substr $_, 0, 1, '') . $build for @program; | |
61 push @newprog, $build; | |
62 } | |
63 @program = @newprog; | |
64 tr/<^>v(A)V/^>v<A)V(/ for @program; | |
65 ($width, $height) = ($height, $width); | |
66 ($x, $y) = ($width - 1 - $y, $x); | |
67 } | |
68 | |
69 sub shove { | |
70 my $sx = shift; | |
71 my $sy = shift; | |
72 if($sx < 0) { | |
73 $_ = ' '.$_ for @program; | |
74 $x++; | |
75 $sx++; | |
76 $width++; | |
77 } | |
78 if($sx >= $width) { | |
79 $width++; | |
80 } | |
81 if($sy < 0) { | |
82 unshift @program, ""; | |
83 $y++; | |
84 $sy++; | |
85 $height++; | |
86 } | |
87 if($sy >= $height) { | |
88 push @program, ""; | |
89 $height++; | |
90 } | |
91 scalar @stack or die "Empty stack when shoving."; | |
92 $program[$sy] = widthpad $program[$sy]; | |
93 ($x > $sx && $y == $sy) and $x += length $stack[0]; | |
94 substr $program[$sy], $sx, 0, shift @stack; | |
95 $program[$sy] =~ s/\ +$//; | |
96 $width < length $program[$sy] and $width = length $program[$sy]; | |
97 } | |
98 | |
99 sub showprogram { | |
100 my $tr = $totalrotation; | |
101 print "\nactual size: ($width, $height), pos: ($x, $y)\n"; | |
102 rotateprogram ((4-$tr)%4); | |
103 $program[$y] = widthpad $program[$y]; | |
104 my $c = substr $program[$y], $x, 1, '*'; | |
105 print "rotated for viewing; pos: ($x, $y), dir: $tr\n"; | |
106 print "stack: "; | |
107 print "{$_} " for @stack; | |
108 print "\n"; | |
109 print "$_\n" for @program; | |
110 substr $program[$y], $x, 1, $c; | |
111 rotateprogram $tr; | |
112 scalar <>; | |
113 } | |
114 | |
115 while ($x < $width && $y < $height && $x >= 0 && $y >= 0) { | |
116 showprogram if $debug; | |
117 my $cmd = substr $program[$y], $x, 1; | |
118 # $cmd eq '>' is a nop | |
119 $cmd eq '^' and rotateprogram 1; | |
120 $cmd eq '<' and rotateprogram 2; | |
121 $cmd eq 'v' and rotateprogram 3; | |
122 $cmd eq '(' and shove $x-1, $y; | |
123 $cmd eq ')' and shove $x+1, $y; | |
124 $cmd eq 'A' and shove $x, $y-1; | |
125 $cmd eq 'V' and shove $x, $y+1; | |
126 $cmd eq 'S' and print $stack[0]; | |
127 $cmd eq 'n' and print '\n'; | |
128 if ($cmd eq '!') { | |
129 substr $_, 0, $x, '' for @program; | |
130 $width -= $x; | |
131 $x = 0; | |
132 } | |
133 if ($cmd eq '"' || $cmd eq "'") { | |
134 my $quotecount = 1; | |
135 my $lws = $cmd eq "'"; | |
136 my $newpush = ""; | |
137 while($quotecount) { | |
138 $x++; | |
139 $x < $width or die "Unterminated string."; | |
140 $cmd = substr $program[$y], $x, 1; | |
141 $cmd eq "'" and ($quotecount += ($lws ? -1 : 1)), ($lws = !$lws); | |
142 $cmd eq '"' and ($quotecount += ($lws ? 1 : -1)), ($lws = !$lws); | |
143 $quotecount and $newpush .= $cmd; | |
144 } | |
145 unshift @stack, $newpush; | |
146 } | |
147 $x++; # move to next command | |
148 } |