-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathlist.pl
executable file
·185 lines (161 loc) · 4.75 KB
/
list.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#!/usr/bin/perl -w
use strict;
# Beeb Utilities to manipulate MMB and SSD files
# Copyright (C) 2012 Stephen Harris
#
# See file "COPYING" for GPLv2 licensing
use FindBin;
use lib "$FindBin::Bin";
use BeebUtils;
sub syntax()
{
print STDERR "Syntax: $BeebUtils::PROG filename [-o #] [-t variant]\n";
print STDERR " Known variants (default 'basic2'):\n";
foreach (sort keys %BeebUtils::basic_tokens)
{
next if $_ eq '_BASE_';
print STDERR " $_\n";
}
exit(255);
}
@ARGV=BeebUtils::init_ssd(@ARGV);
my $filename=$BeebUtils::BBC_FILE;
syntax unless $filename;
my $listo=0;
my $variant="basic2";
while(@ARGV)
{
if (@ARGV > 1 && $ARGV[0] eq "-o") { $listo=$ARGV[1]; shift @ARGV;shift @ARGV;}
elsif (@ARGV && $ARGV[0] =~ /-o(\d+)$/) { $listo=$1; shift @ARGV;}
elsif (@ARGV > 1 && $ARGV[0] eq "-t") { $variant=$ARGV[1]; shift @ARGV;shift @ARGV;}
elsif (@ARGV && $ARGV[0] =~ /-t(.+)$/) { $variant=$1; shift @ARGV;}
else { die "Unexpected arguments: $ARGV[0]\n"; }
}
$variant=lc($variant);
my $basic=$BeebUtils::basic_tokens{$variant};
my $extended=$BeebUtils::extended_tokens{$variant};
my $alt=$BeebUtils::alt_line{$variant} || 0;
die "Unknown variant: $variant\n" unless defined($basic);
# Merge later versions of the language
my $tokens=$BeebUtils::basic_tokens{"_BASE_"};
foreach (keys %$basic)
{
$tokens->{$_}=$basic->{$_};
}
my %indent = ( 'FOR' => 0, 'REPEAT' => 0);
open(F,"<$filename") or die "$filename: $!\n";
while (!eof(F))
{
my %nextindent = ( 'FOR' => 0, 'REPEAT' => 0);
my $ch;
my $line;
my $len;
# There are two ways a line can be read; the Beeb way or the z80/b4w way.
if (!$alt)
{
# The beeb way
# First char of each line should be ^M
read F,$ch,1; die "Bad program (expected ^M)\n" unless defined($ch) && $ch eq "\015";
# next two bytes are line number or end of program
read F,$ch,1; die "Bad program (line number high)\n" unless defined($ch);
last if $ch eq "\xff"; # end of program
$line=ord($ch)*256;
read F,$ch,1; die "Bad program (line number low)\n" unless defined($ch);
$line+=ord($ch);
# next byte is length of line
read F,$ch,1; die "Bad program (length)\n" unless defined($ch);
$len=ord($ch)-4; die "Bad program (bad length)\n" if $len <0; # Already got 4 bytes
}
else
{
# z80 way
# First character is line length;
read F,$ch,1; die "Bad program (length)\n" unless defined($ch);
$len=ord($ch)-3;
# next two bytes are line number or end of program
read F,$ch,1; die "Bad program (line number low)\n" unless defined($ch);
$line=ord($ch);
read F,$ch,1; die "Bad program (line number high)\n" unless defined($ch);
$line+=ord($ch)*256;
last if $line == 65535;
die "Bad program (bad length)\n" if $len <0; # Needs at least 3 bytes
}
# rest of line
my $raw=0; # Set to 1 if in quotes
my $decode="";
my $prevchar="";
my $pos=1;
while ($pos++ <= $len)
{
read F,$ch,1;
die "Bad program (reading line)\n" unless defined($ch);
my $d;
if ($raw) { $d = $ch; }
elsif (!$prevchar && $ch eq "\x8D")
{ # Line token
my $lno;
read F,$lno,3; die "Bad program (line token)\n" unless length($lno) == 3;
$pos+=3;
# This comes from page 41 of "The BASIC ROM User Guide"
my ($n1,$n2,$n3)=map { ord($_) } split(//,$lno);
$n1=($n1*4)&255;
my $low=($n1 & 192) ^ $n2;
$n1=($n1*4)&255;
my $high=$n1 ^ $n3;
$lno=$high*256+$low;
$d=$lno;
}
else
{
$d="";
if ($prevchar)
{
$d=$extended->{ord($prevchar)}->{ord($ch)} if ($prevchar);
if (!$d)
{
# Not an extended 2-byte code
seek F,-1,1; # Go back one character to re-read it
$pos--;
$d=$tokens->{ord($prevchar)};
}
$prevchar="";
}
if (!$d)
{
if (defined($extended->{ord($ch)}))
{
$prevchar=$ch;
next;
}
$d=$tokens->{ord($ch)};
}
if ($d)
{
$d=(@$d)[0];
$d .= " " if $listo & 8;
}
else
{
$d=$ch;
}
}
$raw=1-$raw if $ch eq '"';
die "trap" unless defined($d);
$decode .= $d;
if ($d eq 'REPEAT' && $listo & 4) { $nextindent{REPEAT}++; }
elsif ($d eq 'UNTIL' && $listo & 4) { $nextindent{REPEAT}--; }
elsif ($d eq 'FOR' && $listo & 2) { $nextindent{FOR}++; }
elsif ($d eq 'NEXT' && $listo & 2) { $nextindent{FOR}--; }
}
my $i=substr(" "x255,1,$indent{FOR}*2+$indent{REPEAT}*2+($listo&1));
if ($line)
{
printf("%5d%s%s\n",$line,$i,$decode);
}
else
{
printf(" %s%s\n",$i,$decode);
}
$indent{FOR}+=$nextindent{FOR}; $indent{FOR}=0 if $indent{FOR}<0;
$indent{REPEAT}+=$nextindent{REPEAT}; $indent{REPEAT}=0 if $indent{REPEAT}<0;
}