Hi all, I made some little changes to pbc2c.pl to make it work with all (working) examples.
I'm sorry that it throws some nasty warnings, maybe it's possible to remove them using opcode_t * instead of int. Opinions more than welcome. Daniel Grunblatt.
#! /usr/bin/perl -w # # pbc2c.pl # # Turn a parrot bytecode file into a C program. # # Copyright (C) 2001 The Parrot Team. All rights reserved. # This program is free software. It is subject to the same license # as the Parrot interpreter. # # $Id: pbc2c.pl,v 1.3 2001/10/24 13:03:42 gregor Exp $ # use strict; use Parrot::Types; use Parrot::PackFile; use Parrot::PackFile::ConstTable; use Parrot::OpsFile; use Data::Dumper; $Data::Dumper::Useqq = 1; $Data::Dumper::Terse = 1; $Data::Dumper::Indent = 0; my $ops = new Parrot::OpsFile 'core.ops'; # # dump_const_table() # sub dump_const_table { my ($pf) = @_; my $count = $pf->const_table->const_count; if ($count < 1) { warn "Disassembling without opcode table fingerprint!"; return; } =no die "Cannot compile (differing opcode table)!" if $pf->const_table->constant(0)->data ne $opcode_fingerprint; =cut print "# Constants: $count entries\n"; print "# ID Flags Encoding Type Size Data\n"; my $constant_num = 0; foreach ($pf->const_table->constants) { printf("%04x: %08x %08x %08x %08x %s\n", $constant_num, $_->flags, $_->encoding, $_->type, $_->size, $_->data); $constant_num++; } } # # compile_byte_code() # my $pc; my $new_pc = 1; my @args = (); my @functions = (); sub compile_byte_code { my ($pf) = @_; my $nconst = $pf->const_table->const_count; print <<END_C; #include "parrot/parrot.h" #include "parrot/string.h" void start(); END_C print $ops->preamble; print <<END_C; struct Parrot_Interp * interpreter; int main(int argc, char **argv) { int i; struct PackFile_Constant * c; struct PackFile * pf; init_world(); interpreter = make_interpreter(); pf = PackFile_new(); interpreter->code = pf; END_C for(my $i = 0; $i < $nconst; $i++) { my $const = $pf->const_table->constant($i); my $value = $const->value; if ($const->type eq Parrot::PackFile::Constant::type_code('PFC_INTEGER')) { # TODO: Don't hardocde these codes. print <<END_C; c = PackFile_Constant_new_integer($value); END_C } elsif ($const->type eq Parrot::PackFile::Constant::type_code('PFC_NUMBER')) { # TODO: Don't hardocde these codes. print <<END_C; c = PackFile_Constant_new_number($value); END_C } elsif ($const->type eq Parrot::PackFile::Constant::type_code('PFC_STRING')) { # TODO: Don't hardocde these codes. my $type = $value->type; my $encoding = $value->encoding; my $size = $value->size; my $flags = $value->flags; my $data = Dumper($value->data); $data = '"' . $data . '"' unless $data =~ m/^"/; print <<END_C; c = PackFile_Constant_new_string(interpreter, string_make(interpreter, $data, $size, $encoding, $flags, $type)); END_C } else { die; } print <<END_C; PackFile_ConstTable_push_constant(pf->const_table, c); END_C } print <<END_C; start(); return 0; } END_C my $cursor = 0; my $length = length($pf->byte_code); my $offset=0; my $op_code; my $op; my $n = 0; while ($offset + sizeof('op') <= $length) { $pc = $new_pc; $op_code = unpack "x$offset l", $pf->byte_code; $op = $ops->op($op_code); $offset += sizeof('op'); $new_pc = $pc + $op->size; @args = (); foreach (1 .. scalar($op->arg_types) - 1) { die "$0: Premature end of bytecode in argument.\n" if ($offset + sizeof('op')) > $length; my $arg = unpack "x$offset l", $pf->byte_code; $offset += sizeof('op'); push @args, $arg; } my $source = $op->source(\&map_ret_abs, \&map_ret_rel, \&map_arg, \&map_res_abs, \&map_res_rel); $functions[$n++] = $pc; printf("int\nPC_%d(int cur_opcode) /* %s */\n{\n%s}\n\n", $pc, $op->full_name, $source); } print <<END_C; void start() { int (*functions[$pc])(int); int j = 1; END_C foreach (0..scalar(@functions) - 1) { print " functions[" . $functions[$_] . "] = (int (*)(int))PC_" . $functions[$_] . ";\n"; } print <<END_C; while (j) { j = (*functions[j])(j); }; exit(0); } END_C return 0; } # # map_ret_abs() # sub map_ret_abs { my ($addr) = @_; #print STDERR "pbcc: map_ret_abs($addr)\n"; return sprintf "return (" . $addr . ")"; } # # map_ret_rel() # sub map_ret_rel { my ($offset) = @_; #print STDERR "pbcc: map_ret_rel($offset)\n"; return sprintf "return (cur_opcode+" . $offset . ")"; } # # map_arg() # my %arg_maps = ( 'i' => "interpreter->int_reg->registers[%ld]", 'n' => "interpreter->num_reg->registers[%ld]", 'p' => "interpreter->pmc_reg->registers[%ld]", 's' => "interpreter->string_reg->registers[%ld]", 'ic' => "%ld", 'nc' => "interpreter->code->const_table->constants[%ld]->number", 'pc' => "%ld /* ERROR: Don't know how to handle PMC constants yet! */", 'sc' => "interpreter->code->const_table->constants[%ld]->string", ); sub map_arg { my ($type, $num) = @_; #print STDERR "pbcc: map_arg($type, $num)\n"; return sprintf($arg_maps{$type}, $args[$num - 1]); } # # map_res_abs() # sub map_res_abs { my ($addr) = @_; die "pbc2c.pl: Cannot handle RESUME ops!"; } # # map_res_rel() # sub map_res_rel { my ($offset) = @_; die "pbc2c.pl: Cannot handle RESUME ops!"; } # # compile_file() # sub compile_file { my ($file_name) = @_; my $pf = Parrot::PackFile->new; $pf->unpack_file($file_name); # dump_const_table($pf); compile_byte_code($pf); undef $pf; return; } # # MAIN PROGRAM: # @ARGV = qw(-) unless @ARGV; foreach (@ARGV) { compile_file($_) } exit 0; __END__ =head1 NAME pbcc - Parrot byte code compiler =head1 SYNOPSIS pbcc foo.pbc > foo.c =head1 DESCRIPTION Compile the Parrot Pack File listed on the command line, or from standard input if no file is named. =head1 AUTHOR Gregor N. Purdy E<lt>[EMAIL PROTECTED]<gt> =head1 COPYRIGHT Copyright (C) 2001 Gregor N. Purdy. All rights reserved. =head1 LICENSE This program is free software. It is subject to the same license as the Parrot interpreter.