2 # urmc - 2003-2005 (c) by Marcus Thiesen
7 urmc - This is just another little language for Parrot
11 This code is under the GPL
15 Markus Thiessen - <marcus@cpan.org>
21 use lib "$FindBin::RealBin/../../lib";
27 # $opti is localized later
29 $opti = 1; # more a debug flag
32 my ( $filename, $silent );
33 my $parrot = "$FindBin::RealBin$PConfig{slash}..$PConfig{slash}..$PConfig{slash}parrot$PConfig{exe}";
42 GetOptions( "silent" => \$silent,
48 ( qq{## Compiled by urmc $version},
49 q{## 2003 (c) by Marcus Thiesen},
50 q{## <marcus@cpan.org>},
53 qq{\tget_params "(0)", P5 # Get command line},
54 qq{\tshift S1, P5 # we don't need the scriptname},
57 my $lp = qr/\s*(\d+)\s*\:/; #line prefix (1:)
58 my (%lines, %jtarget); # tcount lines and jump targets
59 my $out_reg; # save the output registers name
63 open SOURCE, $filename or die "Can't get sourcefile $filename :$!";
65 close SOURCE; ### if gnu would hear that... :-)
72 my ($warning, $linenr) = @_;
73 print STDERR "WARNING: $warning is not standard URM at line $linenr\n";
83 for my $i (0..31) { $reg_tbl{$i} = 0; }
85 # for debugging purposes
87 print "\$stackcount:\t $stackcount\n";
90 map { print "$_\t => $reg_tbl{$_}\n"} sort { $a <=> $b } keys %reg_tbl;
93 map { print "$_\t => $look_tbl{$_}\n"} sort { $a <=> $b } keys %look_tbl;
101 ## lookup the register
102 if ((defined $look_tbl{$name}) &&
103 ($look_tbl{$name} =~ /^I(\d+)/)) {
107 ## if not on stack: get a free one
108 foreach my $reg (sort {$a <=> $b} keys %reg_tbl) {
109 unless ($reg_tbl{$reg}) {
110 $reg_tbl{$reg} = $name;
112 $lra_tbl{$time} = $reg;
113 $look_tbl{$name} = "I$reg";
118 ### no free registers left or on stack
120 if (defined $look_tbl{$name}) {
121 # get last recently allocated:
122 my @times = sort { $a <=> $b } keys %lra_tbl;
123 my $time = shift @times;
125 my $old = $lra_tbl{"$time"};
126 die "\$old undefined\n" unless defined $old;
127 delete $lra_tbl{$time};
128 # save register nr $old on stack
129 push @pasm, "\tsave I$old";
130 $look_tbl{$reg_tbl{$old}} = $stackcount;
135 # get requested register from stack
137 my $nr_on_stack = ($stackcount - $look_tbl{$name}) - 1;
138 my $rotate_more = $stackcount - 1 - $nr_on_stack - 1;
140 for my $i (0..$nr_on_stack) {
141 push @pasm, "\trotate_up $stackcount";
143 push @pasm, "\trestore I$old";
144 for my $i (0..$rotate_more) {
145 push @pasm, "\trotate_up $stackcount";
149 # push @pasm, "\tlookback I$old, $nr_on_stack";
151 $look_tbl{$name} = "I$old";
152 $lra_tbl{time()} = $old;
153 $reg_tbl{$old} = "$name";
158 # no free register left
159 # free one and call yourself
160 # get last recently allocated:
161 my @times = sort { $a <=> $b } keys %lra_tbl;
162 my $time = shift @times;
163 my $old = $lra_tbl{"$time"};
164 delete $lra_tbl{$time};
165 # save register nr $old on stack
166 push @pasm, "\tsave I$old";
167 $look_tbl{$reg_tbl{$old}} = $stackcount;
174 foreach my $line (@source) {
175 next unless defined $line;
176 next if $line =~ /^\#/; # comments
177 next if $line =~ /^\s+$/; # spacy lines
178 $line =~ s/\#.+//; # stip in line comments;
180 # parse in(r1,r2); out(r3); or out(r3); or in(r34);
181 if ( ( undef, my $in, undef, my $out ) =
182 $line =~ m/^(\s*in\(([0-9r\ ,]*?)\);)? # optional input registers
183 (\s*out\(r(\d+)\);)? # optional output register
184 \s*$ # insignificant lines are already skipped
187 $out_reg = $out if defined $out;
188 foreach ( split( /\s*,\s*/, $in ) ) {
189 my ( $in_reg ) = m/r(\d+)/;
190 my $rn = "I" . (mmu $in_reg);
191 push @pasm, "\t#get input for $_";
192 push @pasm, "\tshift S0, P5";
193 push @pasm, "\tset $rn, S0";
198 elsif ($line =~ /$lp\s*r(\d+)\s*<-\s*(\d+)\s*$/o) {
202 warning("Assigning not 0 to a register", $1);
204 ## parrot does the work for us....
207 push @pasm, "\tset I" . (mmu($2)) . ", $3\t\#$line";
211 #parse 3: if r2 = 0 goto 7
212 elsif ($line =~ /$lp\s*if\sr(\d+)\s*=\s*0\s*goto\s*(\d+)/o) {
215 push @pasm, "\teq I" . (mmu $2) . ", 0, L$3\t\#$line";
219 elsif ($line =~ /^inline_pasm:/) {
220 $line =~ s/^inline_pasm://;
224 #parse 4: r2 <- r2 +|- 1
226 /$lp\s*r(\d+)\s*<-\s*r(\d+)\s*(\+|-)\s*(?:(r(\d+))|(\d+))/o ) {
229 warning("Assigning one register to another", $1);
233 warning("Assigning sum of two registers", $1);
234 $rn3 = "I" . (mmu $6);
236 elsif ((defined $6) && ($6 != 1)) {
237 warning("Adding more than one", $1);
241 my $rn1 = "I" . (mmu $2);
242 my $rn2 = "I" . (mmu $3);
243 $rn3 = 1 unless defined $rn3;
245 push @pasm, "\tadd $rn1, $rn2, $rn3\t\#$line";
247 push @pasm, "\tsub $rn1, $rn2, $rn3\t\#$line";
252 elsif ($line =~ /$lp\s*goto\s*(\d+)/) {
255 push @pasm, "\tbranch L$2\t\#$line";
260 die "SYNTAX ERROR:\n$line\nCan't parse line\n";
267 ## clean up the labels
269 for my $line (@pasm) {
270 if ($line =~ /^L(\d+)/) {
271 push @newpasm, $line if exists $jtarget{$1};
274 push @newpasm, $line;
279 if (scalar %jtarget) {
280 foreach my $key (keys %jtarget) {
281 next if exists $lines{$key};
282 if (defined $out_reg) {
283 $out_reg = mmu($out_reg);
284 push @pasm, "L$key:";
285 push @pasm, "\tprint I$out_reg";
286 push @pasm, "\tprint \"\\n\"";
291 if (defined $out_reg) {
292 $out_reg = mmu($out_reg);
293 push @pasm, "\tprint I$out_reg";
294 push @pasm, "\tprint \"\\n\"";
299 # Consider this as a treewalker of an degenerate tree
300 print join("\n", @pasm), "\n";