/usr/share/perl5/Language/INTERCAL/Optimiser.pm is in clc-intercal 1:1.0~4pre1.-94.-2-4.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 | package Language::INTERCAL::Optimiser;
# Optimiser for INTERCAL bytecode; see also "optimise.iacc"
# This file is part of CLC-INTERCAL
# Copyright (c) 2006-2008 Claudio Calvelli, all rights reserved.
# CLC-INTERCAL is copyrighted software. However, permission to use, modify,
# and distribute it is granted provided that the conditions set out in the
# licence agreement are met. See files README and COPYING in the distribution.
use strict;
use vars qw($VERSION $PERVERSION);
($VERSION) = ($PERVERSION = "CLC-INTERCAL/Base INTERCAL/Optimiser.pm 1.-94.-2") =~ /\s(\S+)$/;
use Carp;
use Language::INTERCAL::Exporter '1.-94.-2';
use Language::INTERCAL::Splats '1.-94.-2', qw(:SP);
use Language::INTERCAL::ByteCode '1.-94.-2', qw(:BC bc_bytype bc_match);
sub new {
@_ == 1 or croak "Usage: new Language::INTERCAL::Optimiser";
my ($class) = @_;
bless {
rules => [],
search => [],
}, $class;
}
sub add {
@_ == 3 or croak "Usage: OPTIMISER->add(PATTERN, REWRITE)";
my ($opt, $pattern, $rewrite) = @_;
push @{$opt->{rules}}, [$pattern, $rewrite];
delete $opt->{search};
$opt;
}
sub optimise {
@_ == 2 or croak "Usage: OPTIMISER->optimise(CODE)";
my ($opt, $code) = @_;
_make_search($opt);
_optimise($opt, $code);
}
sub read {
@_ == 2 or croak "Usage: OPTIMISER->read(FILEHANDLE)";
my ($opt, $fh) = @_;
_make_search($opt);
my $r = $opt->{rules};
$fh->read_binary(pack('v', scalar @$r));
for my $i (@$r) {
my ($p, $w) = @$i;
$fh->read_binary(pack('v/a* v/a*', $p, $w));
}
my $s = $opt->{search};
$fh->read_binary(pack('v', scalar @$s));
for my $i (@$s) {
$fh->read_binary(pack('v*', scalar @$i, @$i));
}
}
sub write {
@_ == 2 or croak "Usage: Language::INTERCAL::Optimiser->write(FILEHANDLE)";
my ($class, $fh) = @_;
my $nr = unpack('v', $fh->write_binary(2)) || 0;
my @rules = ();
while (@rules < $nr) {
my $pl = unpack('v', $fh->write_binary(2));
my $p = $fh->write_binary($pl);
my $wl = unpack('v', $fh->write_binary(2));
my $w = $fh->write_binary($wl);
push @rules, [$p, $w];
}
my $ns = unpack('v', $fh->write_binary(2)) || 0;
my @search = ();
while (@search < $ns) {
my $ni = unpack('v', $fh->write_binary(2));
my @i = unpack('v*', $fh->write_binary(2 * $ni));
push @search, \@i;
}
bless {
rules => \@rules,
search => \@search,
}, $class;
}
sub _make_search {
my ($opt) = @_;
return if exists $opt->{search};
my $olist = $opt->{rules};
my @search = ();
for (my $o = 0; $o < @$olist; $o++) {
my ($pattern, $rewrite) = @{$olist->[$o]};
for my $p (@$pattern) {
my ($type, $code) = @$p;
next if $code eq '';
my $e = substr($code, 0, 1);
my @s;
if ($type eq 'C') {
@s = (ord($e));
} else {
@s = bc_bytype($e);
}
push @{$search[$_]}, $o for @s;
last;
}
}
$opt->{search} = \@search;
}
sub _optimise {
my ($opt, $code) = @_;
my $olist = $opt->{rules};
return $code unless @$olist;
my $search = $opt->{search};
return $code unless @$search;
my $i = 0;
CODE: while ($i < length($code)) {
my $c = ord(substr($code, $i, 1));
$i++;
next unless $search->[$c] && @{$search->[$c]};
my $changes = 0;
RULE: for my $try (@{$search->[$c]}) {
my ($pattern, $rewrite) = @{$opt->{optimise}[$try]};
my @match = ();
my $start = $i;
for my $p (@$pattern) {
my ($type, $data) = @$p;
next if $data eq '';
my $skip;
if ($type eq 'C') {
# constant chunk of bytecode
next RULE if $data ne substr($code, $i, length $data);
$skip = length $data;
} else {
# bytecode pattern matching
$skip = bc_match($data, $code, $i);
next RULE if ! defined $skip;
}
push @match, [$i, $skip];
$i += $skip;
}
my $length = $i - $start;
# this rule matches - now do the necessary rewriting
my $newcode = '';
for my $r (@$rewrite) {
my ($type, $data) = @$r;
if ($type eq 'C') {
$newcode .= $data;
} else {
my ($pos, $skip) = @{$match[$data]};
$newcode .= substr($code, $pos, $skip);
}
}
substr($code, $start, $length) = $newcode;
$i = 0;
next CODE;
}
}
$code;
}
1;
|