Mercurial > repo
view interps/clc-intercal/CLC-INTERCAL-Base-1.-94.-2/INTERCAL/Backend/ListObject.pm @ 12518:2d8fe55c6e65 draft default tip
<int-e> learn The password of the month is release incident pilot.
author | HackEso <hackeso@esolangs.org> |
---|---|
date | Sun, 03 Nov 2024 00:31:02 +0000 |
parents | 859f9b4339e6 |
children |
line wrap: on
line source
package Language::INTERCAL::Backend::ListObject; # Produce a (non-executable) listing of an object # 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/Backend/ListObject.pm 1.-94.-2") =~ /\s(\S+)$/; use Carp; use Language::INTERCAL::Exporter '1.-94.-2'; use Language::INTERCAL::ByteCode '1.-94.-2', qw(:BC bc_xtype bc_skip is_constant is_multibyte bc_forall reg_decode); use Language::INTERCAL::Object '1.-94.-2'; use constant default_suffix => 'iasm'; use constant default_mode => 0666; use constant BYTES_PER_LINE => 8; sub generate { @_ == 4 || @_ == 5 or croak "Usage: BACKEND->generate(INTERPRETER, NAME, FILEHANDLE)"; my ($class, $int, $name, $fh, $options) = @_; _generate($int, $fh); } sub _generate { my ($int, $fh) = @_; my $object = $int->object; my ($perversion) = $Language::INTERCAL::Object::PERVERSION =~ /\s(\S+)$/; $fh->read_text("CLC-INTERCAL $perversion Object List\n\n"); # object flags $fh->read_text("FLAGS:\n"); for my $fn (sort { lc($a) cmp lc($b) } $object->all_flags) { my $fv = $object->flag_value($fn); $fh->read_text(" $fn <- $fv\n"); } $fh->read_text("\n"); # code listing $fh->read_text("CODE:\n"); my ($cs, $ch) = $object->code; my $source = $object->source; for my $sp (sort { $a <=> $b } keys %$ch) { for my $p (@{$ch->{$sp}}) { my ($ju, $sl, $ls, $ll, $ds, $dl, $ge, $ab, $qu, $xs, $xl, @ru) = @$p; my $se = $sp + $sl - 1; my $s = ''; if ($source ne '') { $s = substr($source, $sp, $sl); $s =~ s/\s+/ /g; $s =~ s/^ //; $s =~ s/ $//; } _fold($fh, " \@$sp..$se", $s); if ($ll > 0) { $fh->read_text(" LABEL:\n"); _list_code($fh, $cs, $ls, $ls + $ll); } elsif ($ls > 0) { $fh->read_text(" LABEL: $ls\n"); } if ($dl > 0) { $fh->read_text(" DSX:\n"); _list_code($fh, $cs, $ds, $ds + $dl); } elsif ($ds > 0) { $fh->read_text(" DSX: $ds\n"); } $ju = $ju ? "; COMMENT($ju)" : ''; $ab = $ab ? '; INITIALLY ABSTAINED FROM' : ''; $qu = $qu ? "; QUANTUM" : ""; my ($gn) = bytedecode($ge); $gn = defined $gn ? " ($gn)" : ""; $fh->read_text(" GERUND: $ge$gn$ju$ab$qu\n"); _fold($fh, " DEPENDS ON", join(' ', @ru)); _list_code($fh, $cs, $xs, $xs + $xl); $fh->read_text("\n"); } } # grammar and symbol table listing $fh->read_text("SYMBOL TABLE:\n"); _list_symbols($fh, $object->symboltable); $fh->read_text("\n"); for (my $p = 1; $p <= $object->num_parsers; $p++) { $fh->read_text("GRAMMAR #$p:\n"); _list_grammar($fh, $int, $p, $object->symboltable, $object->parser($p)); $fh->read_text("\n"); } # register listing $fh->read_text("REGISTERS:\n"); my $rcode = sub { my ($rname, $rvalue) = @_; my $d = reg_decode($rname); $rname = "$d ($rname)" if $d ne $rname; $fh->read_text(" $rname\n"); _fold($fh, " ", $rvalue->print) if $d !~ /^\@/; }; $int->allreg($rcode, 'n'); $fh->read_text("\n"); # XXX optimiser listing } sub _fold { my ($fh, $first, $text) = @_; $first .= ': ' if $first =~ /\S/ && $text =~ /\S/; my $space = 74 - length($first); while (length($text) > $space) { my $l = substr($text, 0, $space); $l =~ s/\S+$//; $l =~ s/\s+$//; $l = substr($text, 0, $space) if $l eq ''; $fh->read_text($first . $l . "\n"); $first = ' ' x length $first; substr($text, 0, length $l) = ''; $text =~ s/^\s+//; } $fh->read_text($first . $text . "\n"); } sub _code_text { my ($fh, $cs, $cp, $ep) = @_; my $len = bc_skip($cs, $cp, $ep); if (! defined $len) { _code_line($fh, $cs, $cp, 1, '???', 0); return 1; } my $v = ord(substr($cs, $cp, 1)); my ($op, $desc, $type, $value, $args, $function) = bytedecode($v); my $sp = 0; if ($len >= BYTES_PER_LINE) { _code_line($fh, $cs, $cp, 1, $op, 0); $cp++; $type = $args; $sp = 2; } my @text = (); my $co = sub { my ($byte, $name) = @_; if (defined $name) { push @text, $name; } else { if (@text) { my $text = join(' ', @text); $text =~ s/<\s+/</g; $text =~ s/\s+>/>/g; _code_line($fh, $cs, $cp, $byte - $cp, $text, $sp); @text = (); } $cp = $byte; } }; bc_forall($type, $cs, $cp, $ep, $co); return $len; } sub _list_code { my ($fh, $cs, $cp, $ep) = @_; while ($cp < $ep) { $cp += _code_text($fh, $cs, $cp, $ep); } } sub _code_line { my ($fh, $cs, $cp, $cl, $ts, $sp) = @_; while ($cl > 0 || $ts ne '') { my $code = sprintf(" %04X", $cp); my $c = $cl > BYTES_PER_LINE ? BYTES_PER_LINE : $cl; $cl -= $c; while ($c-- > 0) { my $byte = ord(substr($cs, $cp++, 1)); $code .= sprintf(" %02X", $byte); } $code .= ' ' x (40 + $sp - length $code); my $text = substr($ts, 0, 32 - $sp); $text =~ s/\S+$// if $text ne $ts; $text =~ s/\s+$//; $text = substr($ts, 0, 32 - $sp) if $text eq ''; $fh->read_text($code . $text . "\n"); $ts = substr($ts, length $text); $ts =~ s/^\s+//; } } sub _list_symbols { my ($fh, $table) = @_; my %s = map { ($table->symbol($_) => $_) } (1..$table->max); my $lk = 0; my $lv = 0; for my $s (keys %s) { $lk = length($s) if $lk < length($s); $lv = length($s{$s}) if $lv < length($s{$s}); } my $ll = $lk + $lv + 3; my @s0 = map { sprintf("%-${ll}s", "$_: $s{$_}") } sort { lc($a) cmp lc($b) } keys %s; my @s1 = map { sprintf("%${lv}d: %s", $s{$_}, $_) } sort { $s{$a} <=> $s{$b} } keys %s; while (@s0) { $fh->read_text(" " . shift(@s0) . " " . shift(@s1) . "\n"); } } sub _list_grammar { my ($fh, $int, $gra, $table, $grammar) = @_; my $rules = $int->getrules($gra); my $code = sub { my ($g, $s, $prodnum, $sym, $left, $right) = @_; # determine if these rules are enabled my $enab = $rules->[$prodnum] && ${$rules->[$prodnum]} ? "ENABLED" : "DISABLED"; $fh->read_text(" #$prodnum $enab\n"); my $start = " ?" . $table->symbol($sym); my $data = ''; $data .= ' ,,' unless @$left; for my $l (@$left) { my ($t, $v, $c) = @$l; if ($t eq 's') { $data .= ' ?' . $table->symbol($v); } else { $data .= ' ,'; $data .= '!' if $t eq 'r'; if ($v =~ /^[^\W_]+$/) { $data .= $v; } else { $data .= join(' + ', map { "#$_" } unpack('C*', $v)); } $data .= ','; } $data .= '=' . $c if $c && $c < 65535; $data .= '=*' if $c == 65535; } $data .= ' ==>'; while (@$right) { my ($t, $c, $v) = @{shift @$right}; if ($t eq 's' || $t eq 'n') { $data .= ' '; $data .= $t eq 'n' ? '!' : '?'; $data .= $table->symbol($v); } elsif ($t eq 'c' || $t eq 'r') { $data .= ' ,'; $data .= '!' if $t eq 'r'; if ($v =~ /^[^\W_]+$/) { $data .= $v; } else { $data .= join(' + ', map { "#$_" } unpack('C*', $v)); } $data .= ','; } elsif ($t eq 'b') { if ($c eq '') { $data .= ' ,,'; } else { my $plus = ' '; for my $u (unpack('C*', $c)) { $data .= $plus; $data .= bytedecode($u) || "?#$u"; $plus = ' + '; } } next; } elsif ($t eq 'm') { unshift @$right, @$c; next; } elsif ($t eq '*') { $data .= ' *'; next; } else { $data .= '???'; } $data .= ' #' . $c; } $data =~ s/^ //; _fold($fh, $start, $data); }; $grammar->forall($code); } 1; __END__ sub _list_right { my ($indent, $left, $right, $s, $fh) = @_; my $i = $indent; for (my $ep = 0; $ep < @$right; $ep++) { my ($type, $value) = @{$right->[$ep]}; if ($type eq 's' || $type eq 'n') { my $w = $value + 1; my $bang = $type eq 'n' ? '!' : ''; $fh->read_text("$i$bang$s->[$left->[$value][1]]($w)"); } elsif ($type eq 'r') { my $v = $left->[$value][1]; $v =~ s/([\\\@])/\\$1/g; $v =~ s/\n/\\n/g; $v =~ s/\t/\\t/g; $v =~ s/([\000-\037\177-\377])/ sprintf "\\%03o", ord($1)/ge; my $w = $value + 1; $fh->read_text("$i\@$v\@($w)"); } elsif ($type eq 'c') { my $v = $left->[$value][1]; $v =~ s/([\\"])/\\$1/g; $v =~ s/\n/\\n/g; $v =~ s/\t/\\t/g; $v =~ s/([\000-\037\177-\377])/ sprintf "\\%03o", ord($1)/ge; my $w = $value + 1; $fh->read_text("$i\"$v\"($w)"); } elsif ($type eq 'b') { $fh->read_text("$i\{\n"); $ep++; while ($ep < @$right && $right->[$ep][0] eq 'b') { $value .= $right->[$ep][1]; $ep++; } $ep--; _list_code($value, $fh, $indent . ' '); $fh->read_text("$indent}"); } elsif ($type eq 'm') { $fh->read_text("$i\{{\n"); _list_right($indent . ' ', $left, $value, $s, $fh); $fh->read_text("$indent}}"); } $i = ' ' ; } $fh->read_text("\n"); } 1;