line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Imager::Expr::Assem; |
2
|
3
|
|
|
3
|
|
56818
|
use 5.006; |
|
3
|
|
|
|
|
16
|
|
3
|
3
|
|
|
3
|
|
12
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
61
|
|
4
|
3
|
|
|
3
|
|
708
|
use Imager::Expr; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
79
|
|
5
|
3
|
|
|
3
|
|
20
|
use Imager::Regops; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
3807
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = "1.004"; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our @ISA = qw(Imager::Expr); |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
__PACKAGE__->register_type('assem'); |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub compile { |
14
|
1
|
|
|
1
|
1
|
3
|
my ($self, $expr, $opts) = @_; |
15
|
1
|
|
|
|
|
9
|
my %nregs; |
16
|
1
|
|
|
|
|
6
|
my @vars = $self->_variables(); |
17
|
1
|
|
|
|
|
3
|
my @nregs = (0) x @vars; |
18
|
1
|
|
|
|
|
3
|
my @cregs; |
19
|
|
|
|
|
|
|
my %vars; |
20
|
1
|
|
|
|
|
3
|
@vars{@vars} = map { "r$_" } 0..$#vars; |
|
2
|
|
|
|
|
7
|
|
21
|
1
|
|
|
|
|
4
|
my %labels; |
22
|
|
|
|
|
|
|
my @ops; |
23
|
1
|
|
|
|
|
0
|
my @msgs; |
24
|
1
|
|
|
|
|
3
|
my $attr = \%Imager::Regops::Attr; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# initially produce [ $linenum, $result, $opcode, @parms ] |
27
|
1
|
|
|
|
|
2
|
my $lineno = 0; |
28
|
1
|
|
|
|
|
7
|
while ($expr =~ s/^([^\n]+)(?:\n|$)//) { |
29
|
10
|
|
|
|
|
14
|
++$lineno; |
30
|
10
|
|
|
|
|
16
|
my $line = $1; |
31
|
10
|
|
|
|
|
19
|
$line =~ s/#.*//; |
32
|
10
|
100
|
|
|
|
25
|
next if $line =~ /^\s*$/; |
33
|
9
|
|
|
|
|
17
|
for my $op (split /;/, $line) { |
34
|
10
|
100
|
|
|
|
31
|
if (my ($name, $type) = $op =~ /^\s*var\s+([^:]+):(\S+)\s*$/) { |
35
|
3
|
50
|
|
|
|
6
|
if (exists $vars{$name}) { |
36
|
0
|
|
|
|
|
0
|
push(@msgs, "$lineno: duplicate variable name '$name'"); |
37
|
0
|
|
|
|
|
0
|
next; |
38
|
|
|
|
|
|
|
} |
39
|
3
|
100
|
66
|
|
|
29
|
if ($type eq 'num' || $type eq 'n') { |
|
|
50
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
40
|
2
|
|
|
|
|
8
|
$vars{$name} = 'r'.@nregs; |
41
|
2
|
|
|
|
|
10
|
push(@nregs, undef); |
42
|
2
|
|
|
|
|
6
|
next; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
elsif ($type eq 'pixel' || $type eq 'p' || $type eq 'c') { |
45
|
1
|
|
|
|
|
3
|
$vars{$name} = 'p'.@cregs; |
46
|
1
|
|
|
|
|
2
|
push(@cregs, undef); |
47
|
1
|
|
|
|
|
5
|
next; |
48
|
|
|
|
|
|
|
} |
49
|
0
|
|
|
|
|
0
|
push(@msgs, "$lineno: unknown variable type $type"); |
50
|
0
|
|
|
|
|
0
|
next; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
# any statement can have a label |
53
|
7
|
100
|
|
|
|
18
|
if ($op =~ s/^\s*(\w+):\s*//) { |
54
|
1
|
50
|
|
|
|
3
|
if ($labels{$1}) { |
55
|
0
|
|
|
|
|
0
|
push(@msgs, |
56
|
|
|
|
|
|
|
"$lineno: duplicate label $1 (previous on $labels{$1}[1])"); |
57
|
0
|
|
|
|
|
0
|
next; |
58
|
|
|
|
|
|
|
} |
59
|
1
|
|
|
|
|
3
|
$labels{$1} = [ scalar @ops, $lineno ]; |
60
|
|
|
|
|
|
|
} |
61
|
7
|
100
|
|
|
|
15
|
next if $op =~ /^\s*$/; |
62
|
|
|
|
|
|
|
# jumps have special operand handling |
63
|
6
|
50
|
|
|
|
60
|
if ($op =~ /^\s*jump\s+(\w+)\s*$/) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
64
|
0
|
|
|
|
|
0
|
push(@ops, [$lineno, "", "jump", $1]); |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
elsif (my ($code, $reg, $targ) = |
67
|
|
|
|
|
|
|
($op =~ /^\s*(jumpz|jumpnz)\s+(\S+)\s+(\S+)\s*$/)) { |
68
|
1
|
|
|
|
|
7
|
push(@ops, [$lineno, "", $code, $reg, $targ]); |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
elsif ($op =~ /^\s*print\s+(\S+)\s*/) { |
71
|
0
|
|
|
|
|
0
|
push(@ops, [$lineno, "", 'print', $1 ]); |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
elsif ($op =~ /^\s*ret\s+(\S+)\s*/) { |
74
|
1
|
|
|
|
|
6
|
push(@ops, [$lineno, "", 'ret', $1]); |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
elsif ($op =~ s/\s*(\S+)\s*=\s*(\S+)\s*$//) { |
77
|
|
|
|
|
|
|
# simple assignment |
78
|
1
|
|
|
|
|
7
|
push(@ops, [$lineno, $1, "set", $2]); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
elsif ($op =~ s/\s*(\S+)\s*=\s*(\S+)\s*//) { |
81
|
|
|
|
|
|
|
# some normal ops finally |
82
|
3
|
|
|
|
|
11
|
my ($result, $opcode) = ($1, $2); |
83
|
3
|
50
|
|
|
|
10
|
unless ($attr->{$opcode}) { |
84
|
0
|
|
|
|
|
0
|
push(@msgs, "$lineno: unknown operator $opcode"); |
85
|
0
|
|
|
|
|
0
|
next; |
86
|
|
|
|
|
|
|
} |
87
|
3
|
|
|
|
|
4
|
my @oper; |
88
|
3
|
|
|
|
|
9
|
while ($op =~ s/(\S+)\s*//) { |
89
|
6
|
|
|
|
|
19
|
push(@oper, $1); |
90
|
|
|
|
|
|
|
} |
91
|
3
|
|
|
|
|
15
|
push(@ops, [$lineno, $result, $opcode, @oper]); |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
else { |
94
|
0
|
|
|
|
|
0
|
push(@msgs, "$lineno: invalid statement '$op'"); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
1
|
|
|
|
|
3
|
my $max_opr = $Imager::Regops::MaxOperands; |
100
|
1
|
|
|
|
|
6
|
my $numre = $self->numre; |
101
|
|
|
|
|
|
|
my $trans = |
102
|
|
|
|
|
|
|
sub { |
103
|
|
|
|
|
|
|
# translate a name/number to a |
104
|
13
|
|
|
13
|
|
44
|
my ($name) = @_; |
105
|
|
|
|
|
|
|
$name = $self->{constants}{$name} |
106
|
13
|
100
|
|
|
|
28
|
if exists $self->{constants}{$name}; |
107
|
13
|
100
|
|
|
|
79
|
if ($vars{$name}) { |
|
|
50
|
|
|
|
|
|
108
|
10
|
|
|
|
|
26
|
return $vars{$name}; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
elsif ($name =~ /^$numre$/) { |
111
|
3
|
|
|
|
|
15
|
$vars{$name} = 'r'.@nregs; |
112
|
3
|
|
|
|
|
7
|
push(@nregs, $name); |
113
|
3
|
|
|
|
|
9
|
return $vars{$name}; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
else { |
116
|
0
|
|
|
|
|
0
|
push(@msgs, "$lineno: undefined variable $name"); |
117
|
0
|
|
|
|
|
0
|
return ''; |
118
|
|
|
|
|
|
|
} |
119
|
1
|
|
|
|
|
6
|
}; |
120
|
|
|
|
|
|
|
# now to translate symbols and so on |
121
|
1
|
|
|
|
|
10
|
OP: for my $op (@ops) { |
122
|
6
|
|
|
|
|
8
|
$lineno = shift @$op; |
123
|
6
|
50
|
|
|
|
22
|
if ($op->[1] eq 'jump') { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
124
|
0
|
0
|
|
|
|
0
|
unless (exists $labels{$op->[2]}) { |
125
|
0
|
|
|
|
|
0
|
push(@msgs, "$lineno: unknown label $op->[2]"); |
126
|
0
|
|
|
|
|
0
|
next; |
127
|
|
|
|
|
|
|
} |
128
|
0
|
|
|
|
|
0
|
$op = [ 'jump', "j$labels{$op->[2]}[0]", (0) x $max_opr ]; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
elsif ($op->[1] =~ /^jump/) { |
131
|
1
|
50
|
|
|
|
4
|
unless (exists $labels{$op->[3]}) { |
132
|
0
|
|
|
|
|
0
|
push(@msgs, "$lineno: unknown label $op->[2]"); |
133
|
0
|
|
|
|
|
0
|
next; |
134
|
|
|
|
|
|
|
} |
135
|
1
|
|
|
|
|
3
|
$op = [ $op->[1], $trans->($op->[2]), "j$labels{$op->[3]}[0]", |
136
|
|
|
|
|
|
|
(0) x ($max_opr-1) ]; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
elsif ($op->[1] eq 'print') { |
139
|
0
|
|
|
|
|
0
|
$op = [ $op->[1], $trans->($op->[2]), (0) x $max_opr ]; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
elsif ($op->[1] eq 'ret') { |
142
|
1
|
|
|
|
|
3
|
$op = [ 'ret', $trans->($op->[2]), (0) x $max_opr ]; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
else { |
145
|
|
|
|
|
|
|
# a normal operator |
146
|
4
|
|
|
|
|
9
|
my ($result, $name, @parms) = @$op; |
147
|
|
|
|
|
|
|
|
148
|
4
|
50
|
|
|
|
56
|
if ($result =~ /^$numre$/) { |
149
|
0
|
|
|
|
|
0
|
push(@msgs, "$lineno: target of operator cannot be a constant"); |
150
|
0
|
|
|
|
|
0
|
next; |
151
|
|
|
|
|
|
|
} |
152
|
4
|
|
|
|
|
10
|
$result = $trans->($result); |
153
|
4
|
|
|
|
|
8
|
for my $parm (@parms) { |
154
|
7
|
|
|
|
|
8
|
$parm = $trans->($parm); |
155
|
|
|
|
|
|
|
} |
156
|
4
|
|
|
|
|
8
|
push(@parms, (0) x ($max_opr-@parms)); |
157
|
4
|
|
|
|
|
14
|
$op = [ $op->[1], @parms, $result ]; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# more validation than a real assembler |
162
|
|
|
|
|
|
|
# not trying to solve the halting problem... |
163
|
1
|
50
|
33
|
|
|
18
|
if (@ops && $ops[-1][0] ne 'ret' && $ops[-1][0] ne 'jump') { |
|
|
|
33
|
|
|
|
|
164
|
0
|
|
|
|
|
0
|
push(@msgs, ": the last instruction must be ret or jump"); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
1
|
|
|
|
|
6
|
$self->{nregs} = \@nregs; |
168
|
1
|
|
|
|
|
2
|
$self->{cregs} = \@cregs; |
169
|
|
|
|
|
|
|
|
170
|
1
|
50
|
|
|
|
12
|
if (@msgs) { |
171
|
0
|
|
|
|
|
0
|
$self->error(join("\n", @msgs)); |
172
|
0
|
|
|
|
|
0
|
return 0; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
1
|
|
|
|
|
23
|
return \@ops; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
1; |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
__END__ |