cvsuser     01/09/26 10:38:17

  Modified:    .        assemble.pl
  Log:
  Separated code into functions and added comments.
  
  Revision  Changes    Path
  1.46      +599 -389  parrot/assemble.pl
  
  Index: assemble.pl
  ===================================================================
  RCS file: /home/perlcvs/parrot/assemble.pl,v
  retrieving revision 1.45
  retrieving revision 1.46
  diff -u -w -r1.45 -r1.46
  --- assemble.pl       2001/09/24 16:01:58     1.45
  +++ assemble.pl       2001/09/26 17:38:17     1.46
  @@ -12,6 +12,105 @@
   use Parrot::Config;
   use Symbol;
   
  +# %options holds the command line options
  +my %options = get_options();
  +# type_to_suffix is used to change from an argument
  +# type to the suffix that would be used in the
  +# name of the function that contained that
  +# argument.
  +my(%type_to_suffix)=('I'=>'i',  'N'=>'n',
  +                     'S'=>'s',  'P'=>'p',
  +                     'i'=>'ic', 'n'=>'nc',
  +                     's'=>'sc', 'D'=>'ic');
  +# @program will hold an array ref for each line in the
  +# program.  Each array ref will contain
  +# 1.) The file name in which the source line was found
  +# 2.) The line number in the file of the source line
  +# 3.) The chomped source line without beginning and ending spaces
  +# 4.) The chomped source line
  +my (@program);
  +
  +# $output will be what is output to the bytecode file.
  +# $listing will be what is output to the listing file.
  +# $bytecode is the program's bytecode (executable instructions).
  +my ($output, $listing, $bytecode) = ('', '', '');
  +
  +# $file, $line, $pline, and $sline are used to reference
  +# information from the @program array.  Please look
  +# at the comments for @program for the description
  +# of each.
  +my ($file, $line, $pline, $sline) = ('','','','');
  +
  +# %label will hold each label and the PC at which it was defined.
  +# %fixup will hold labels that have not yet been defined,
  +# where they are used in the source code, and the PC at that
  +# point.  It is used for backpatching.
  +# %macros will map a macro name to an array of program lines
  +# with the same format as @program.
  +# %local_label will hold local label definitions,
  +# %local_fixup will hold the occurances of local labels
  +# in the source file.
  +# $last_label is the name of the last label seen
  +my (%label, %fixup, %macros, %local_label, %local_fixup, $last_label);
  +
  +# pc is the current program counter.  op_pc is the program counter for the
  +# most recent operator.
  +my ($pc, $op_pc) = (0,0);
  +
  +# %constants is a map of constant name to index in the constant table
  +# @constants is an array of constant values in the same order that
  +# they should be in the constant table
  +my (%constants, @constants);
  +
  +# %equate maps assembler directives to their replacements.
  +my %equate=('*'=>sub { return $pc },
  +         '__DATE__'=>'"'.scalar(localtime).'"',
  +         '__VERSION__'=>'" $Revision: 1.46 $ "',
  +         '__LINE__' => sub { return $line },
  +         '__FILE__' => sub { return "\"$file\"" });
  +
  +my %opcodes = Parrot::Opcode::read_ops( -f "../opcode_table" ? "../opcode_table" : 
"opcode_table" );
  +
  +# initialize the assembler
  +init_assembler(@ARGV);
  +
  +# process each element in the @program array
  +process_program_lines();
  +
  +# emit the magic cookie as the first thing in the output file
  +magic_cookie();
  +
  +# fixup the bytecode
  +fixup();
  +
  +# add constants to the bytecode
  +add_constants();
  +
  +# if we are doing more than checking syntax,
  +# output the bytecode
  +if( !$options{'checksyntax'} ) {
  +  output_bytecode();
  +}
  +
  +# if the user wants a listing, output it
  +if( $options{'listing'} ) {
  +  output_listing();
  +}
  +
  +# get_options
  +# this function gets and verifies the options
  +# current options are:
  +#     checksyntax - do not emit bytecode, only check to see if the assembly is valid
  +#     help - emit a help message (usage)
  +#     version - emit the CVS revision of this file
  +#     verbose - output log messages
  +#     output - the file to output the bytecode
  +#     listing - the file to output the listing
  +#     include - a list of files to add to the source code
  +# Validation checks to make sure that if either output
  +# or listing is present, it has an argument (which
  +# is the name of the file to output to.
  +sub get_options {
   my %options;
   GetOptions(\%options,('checksyntax',
                      'help',
  @@ -27,7 +126,7 @@
   }
   
   if($options{'version'}) {
  -    print $0,'Version $Id: assemble.pl,v 1.45 2001/09/24 16:01:58 gregor Exp $ 
',"\n";
  +    print $0,'Version $Id: assemble.pl,v 1.46 2001/09/26 17:38:17 thgibbs Exp $ 
',"\n";
       exit;
   }
   
  @@ -54,61 +153,227 @@
       print STDERR "You must provide a file with --listing flag!\n";
       exit;
   }
  +  return %options;
  +}
   
  -my(%type_swap)=('I'=>'i',  'N'=>'n',
  -                'S'=>'s',  'P'=>'p',
  -                'i'=>'ic', 'n'=>'nc',
  -                's'=>'sc', 'D'=>'ic');
  +# init_assembler
  +#   1.) adds the opcode fingerprint to the constant table
  +#   2.) adds the listing header
  +#   3.) creates the program lines array from each source file passed in
  +sub init_assembler {
  +  my @cmdln = @_;
  +  constantize( Parrot::Opcode::fingerprint() ); # make it constant zero.
  +  add_line_to_listing( "PARROT ASSEMBLY LISTING - " . scalar( localtime ) . "\n\n" 
);
  +  foreach my $file( @cmdln ) {
  +    push( @program, read_source( $file ) );
  +  }
  +}
   
  -# get opcodes
  -my %opcodes = Parrot::Opcode::read_ops(-f "../opcode_table" ? "../opcode_table" : 
"opcode_table");
  +# magic_cookie
  +# emit 0x13155a1 as the first thing in the output.
  +# If this is not present, parrot will NOT process
  +# the file.
  +sub magic_cookie {
  +  $output = pack_op( 0x13155a1 );
  +}
   
  -constantize(Parrot::Opcode::fingerprint()); # Make it constant zero.
  +# fixup
  +# checks to make sure that all labels are defined.
  +# also outputs the label information to the listing.
  +sub fixup {
  +  add_line_to_listing( "\nDEFINED SYMBOLS:\n" );
  +  foreach( sort( keys( %label ) ) ) {
  +    add_line_to_listing( sprintf( "\t%08x   %s\n", $label{$_}, $_ ) );
  +  }
   
  -my $listing="PARROT ASSEMBLY LISTING - ".scalar(localtime)."\n\n";
  +  if( keys( %fixup ) ) {
  +    print STDERR "SQUAK!  These symbols were referenced but not defined:\n";
  +    add_line_to_listing( "\nUNDEFINED SYMBOLS:\n" );
  +    foreach( sort( keys( %fixup ) ) ) {
  +      print STDERR "\t$_ at pc: ";
  +      foreach my $pc (@{ $fixup{ $_ } } ) {
  +        print STDERR sprintf( "%08x ", $pc );
  +      }
  +      print STDERR "\n";
  +      add_line_to_listing( "\t$_\n" );
  +    }
  +    exit; # some day, unresolved symbols won't be an error!
  +  }
  +  else {
  +    # dump empty header
  +    $output .= pack_op(0);
  +  }
  +}
  +
  +# add_constants
  +# adds each constant to a ConstTable perl
  +# class and then adds the packed representation
  +# to the output.
  +sub add_constants {
  +  my $const_table = new Parrot::PackFile::ConstTable;
   
  +  add_line_to_listing( "\nSTRING CONSTANTS\n" );
   
  -# read source/include processing
  -my(@program);
  -foreach my $file (@ARGV) {
  -    push(@program,read_source($file));
  +  # now emit each constant
  +  my $counter = 0;
  +  for( @constants ) {
  +    add_line_to_listing( sprintf( "\t%04x %08x [[%s]]\n", $counter, length($_), $_ 
) );
  +    $counter++;
  +    $const_table->add( new Parrot::PackFile::Constant (0, 0, 0, length( $_ ), $_ ) 
);
  +  }
  +
  +  $output .= $const_table->pack;
   }
   
  +# output_bytecode
  +# writes the bytecode to the output file
  +# (or stdout if no filename was given).
  +# Ensures the file is in binmode.
  +sub output_bytecode {
  +  $output .= $bytecode;
  +  if( defined $options{'output'} and $options{'output'} ne "" ) {
  +    open O, ">$options{'output'}" || die $!;
  +    binmode O;
  +    print O $output;
  +    close O;
  +  }
  +  else {
  +    binmode STDOUT;
  +    print $output;
  +  }
  +}
   
  -# assemble
  -my $pc=0; my $op_pc=0;
  -my ($bytecode,%label,%fixup,%constants,@constants);
  -my (%local_label, %local_fixup, $last_label, %macros);
  -my ($file,$line,$pline,$sline);
  -my %equate=('*'=>sub { return $pc },
  -         '__DATE__'=>'"'.scalar(localtime).'"',
  -         '__VERSION__'=>'" $Revision: 1.45 $ "',
  -         '__LINE__' => sub { return $line },
  -         '__FILE__' => sub { return "\"$file\"" });
  +# output_listing
  +# outputs the listing information to the filename
  +# given by the listing option.
  +sub output_listing {
  +  open L, ">$options{'listing'}" or die $!;
  +  print L $listing;
  +  close L;
  +}
   
  -my($code,$in_macro,$cur_macro);
  -while(my $l=shift(@program)) {
  +# process_program_lines
  +# loops through each program line and checks for
  +# comments, labels, and assembler directives.
  +# Then, it examines the operator and arguments
  +# to find the best match.  Finally, it outputs
  +# its information to the listing.
  +sub process_program_lines {
  +  while( my $lineinfo = shift( @program ) ) {
  +    ($file, $line, $pline, $sline) = @$lineinfo;
  +    my $code = $pline;
  +    next if( is_comment($code) );
  +    $code = handle_label($code) if( has_label( $code ) );
  +    next if( !defined( $code ) || $code eq "" );
  +    if( has_asm_directive( $code ) ) {
  +      # handle_asm_directive will shift @program as needed
  +      # for macro processing.
  +      next if( handle_asm_directive($code, @program) );
  +    }
  +    $code = replace_constants( $code );
  +    $code =~ s/,/ /g;
  +    $code =~ s/#.*$//; # strip end of line comments
  +    my( $opcode, @args ) = split( /\s+/, $code );
  +    if( exists( $macros{$opcode} ) ) {
  +      # found a macro, expand it and append its lines to the front of
  +      # the program lines array.  
  +      my @expanded_lines = expand_macro( $opcode, @args );
  +      unshift( @program, @expanded_lines );
  +      $lineinfo->[2] = '';
  +      unshift( @program, $lineinfo );
  +      next;
  +    }
  +    $opcode = handle_operator( $opcode, @args );
  +    @args = handle_arguments( $opcode, @args );
  +    # add line to listing
  +    my $odata;
  +    # XXX FIXME This can't be right!
  +    foreach (unpack('l*', substr($bytecode, $op_pc) ) ) {
  +      $odata .= sprintf( "%08x ", $_ );
  +    }
  +    add_line_to_listing( sprintf( "%4d %08x %-44s %s\n", $line, $op_pc, $odata, 
$sline ) );
  +    add_line_to_listing( "\n" );
  +  }  
  +}
  +
  +# is_comment
  +# returns whether or not the entire line is a comment.
  +# This is true if the line starts with a # character
  +sub is_comment {
  +  return $_[0] =~ /^\#/ || $_[0] eq "";
  +}
  +
  +# has_label
  +# returns whether or not the line begins with a label.
  +# This is true if the line begins with a word
  +# followed by a colon.
  +sub has_label {
  +  return $_[0] =~ /^\S+:\s*(?:.+)?/;
  +}
  +
  +# replace_constants
  +# this function strips out string constants and replaces
  +# them with the string [ N ] where N is the index into
  +# the constants table where the string is located.
  +sub replace_constants {
  +  my $code = shift;
  +  $code =~ s/\"([^\\\"]*(?:\\.[^\\\"]*)*)\"/constantize($1)/eg;
  +  return $code;
  +}
  +
  +# has_asm_directive
  +# returns true if there is a macro or equ directive
  +sub has_asm_directive {
  +  return $_[0] =~ /^[_a-zA-Z]\w*\s+macro\s+.+$/i ||
  +         $_[0] =~ /^[_a-zA-Z]\w*\s+equ\s+.+$/i;
  +}
  +
  +# handle_asm_directive
  +# processes macros and equ directives.  equ directives
  +# get stored in an equ hash.  Macros store all program
  +# lines in an array.  NOTE: This function modifies @program.
  +sub handle_asm_directive {
  +  my $line = shift;
  +  if( $line =~ /^([_a-zA-Z]\w*)\s+equ\s+(.+)$/i ) {
  +    my( $name, $data ) = ($1, $2);
  +    $equate{$name} = $data;
  +    return 0;
  +  }
  +  elsif( $line =~ /^([_a-zA-Z]\w*)\s+macro\s+(.+)$/i ) {
  +    # a macro definition
  +    my ($name, $args) = ($1, $2);
  +    my $cur_macro = $name;
  +    $macros{$name} = [ [split( /,\s*/, $args)], [] ];
  +    while( 1 ) {
  +      if( !scalar( @program ) ) {
  +        error( "The end of the macro was never seen" );
  +      }
  +      my $l = shift( @program );
       ($file,$line,$pline,$sline)=@$l;
  -    if($in_macro) {
  -     if($pline=~m/^endm$/i) {
  -         # end of the macro
  -         $in_macro=0;
  -     } elsif($pline=~m/^\S+\s+macro/) {
  +      if( $pline =~ /^endm$/i ) {
  +        last;
  +      }
  +      elsif( $pline =~ /^\S+\s+macro/ ) {
            error("Cannot define a macro inside of another macro");
  -     } else {
  +      }
  +      else {
            push(@{$macros{$cur_macro}[1]},$l);
  +        add_line_to_listing( sprintf( "%4d %08x %-44s %s\n", $line, $op_pc, '', 
$sline ) );
        }
  -     $pline="";
       }
  -    if($pline=~m/^\#/ || $pline eq "") {
  -     # its a comment or blank, do nothing
  -     $code=undef;
  -    } else {
  -     my($label);
  -     if($pline=~m/^(\S+):\s*(.+)?/) {
  -         ($label,$code)=($1,$2);
  -         if(defined($label) && $label ne "") {
  -             if($label=~m/^\$/) {
  +    return 1;
  +  }
  +}
  +
  +# handle_label
  +# this function handles a label definition by storing the PC
  +# where the label was found and backpatching all previous instances
  +# of that label with the correct offset.  This function
  +# handles both local labels and global labels.
  +sub handle_label {
  +  my ($label, $code) = $pline =~ /^(\S+):\s*(.+)?/;
  +  # if the label starts with a dollar sign, then it is a local label.
  +  if( $label =~ /^\$/ ) {
                    # a local label
                    if(exists($local_label{$label})) {
                        error("local label '$label' already defined in 
$last_label!",$file,$line);
  @@ -123,7 +388,8 @@
                        delete($local_fixup{$label});  
                    }
                    $local_label{$label}=$pc;
  -             } else {
  +  }
  +  else {
                    # a global label
                    if(exists($label{$label})) {
                        error("'$label' already defined!",$file,$line);
  @@ -145,38 +411,18 @@
                        error("These local labels were undefined in $last_label: ".
                              join(",",sort(keys(%local_fixup))),$file,$line);
                    }
  -                 $label{$label}=$pc; # store it.
  +    $label{ $label } = $pc; # store it
                    $last_label=$label;
                }
  +  return $code;
            } 
  -     } else {
  -         # here's where we can catch assembler directives!
  -         if($pline=~m/^([_a-zA-Z]\w*)\s+equ\s+(.+)$/i) {
  -             my($name,$data)=($1,$2);
  -             $equate{$name}=$data;
  -         } elsif($pline=~m/^([_a-zA-Z]\w*)\s+macro\s+(.+)$/i) {
  -             # a macro definition
  -             my($name,$args)=($1,$2);
  -             $cur_macro=$name;
  -             $macros{$name}=[[split(/,\s*/,$args)],[]];
  -             $in_macro=1;
  -         } else {
  -             $code=$pline;
  -         }
  -     }
  -    }
  -    if(!defined($code)) {
  -     $listing.=sprintf("%4d %08x %-44s %s\n", $line, $op_pc, '',$sline)
  -         if($options{'listing'});
  -     next;
  -    }
   
  -    1 while $code=~s/\"([^\\\"]*(?:\\.[^\\\"]*)*)\"/constantize($1)/eg;
  -    $code=~s/,/ /g;
  -    $code =~ s/#.*$//; # Strip end-of-line comments
  -    my($opcode,@args)=split(/\s+/,$code);    
  -    if(exists($macros{$opcode})) {
  -     # found a macro
  +# expand_macro
  +# expands the macro into the @program array
  +# also replaces the macro arguments with the
  +# ones given to the macro.  NOTE: modifies @program.
  +sub expand_macro {
  +  my ($opcode, @args) = shift;
        my(@margs)=@{$macros{$opcode}[0]};
        my(@macro);
        # we have to make sure to copy the macro, to avoid mangling the
  @@ -202,14 +448,27 @@
            $_->[1]=$line;
            $_->[3]="> ".$_->[3];
        }
  -     unshift(@program,@macro);
  -
  -     # make it come out correctly on the listing.
  -     $l->[2]='';
  -     unshift(@program,$l);
  -     next;
  +  return @macro;
       }
       
  +# find_correct_opcode
  +# given an opcode like sin with arguments
  +# i n i, it will look through the opcode hash
  +# for a function that takes the correct number
  +# and types of arguments and is of the form
  +# sin(_x)* where x is one of i, n, s, p, ic, nc, or sc.
  +# It will prefer an exact argument match, but if one
  +# cannot be found, it will try to use ic for nc.
  +# It will stop on the first exact match, but will
  +# continue for non-exact matches to make sure the
  +# operator is unambiguous.
  +sub find_correct_opcode {
  +  my ($opcode,@args) = @_;
  +  my ($found_op, $ambiguous) = (0,0);
  +  my $match_level_2;
  +  my ($old_op) = $opcode;
  +  my @tests;
  +
       $opcode=lc($opcode);
       if (!exists $opcodes{$opcode}) {
        # try to determine _real_ opcode.
  @@ -222,7 +481,7 @@
                } else {
                    $_=$equate{$_};
                }
  -             s/\"([^\\\"]*(?:\\.[^\\\"]*)*)\"/constantize($1)/eg;
  +        $_ = replace_constants( $_ );
            }
            if(m/^([INPS])\d+$/) {
                # a register.
  @@ -244,15 +503,9 @@
                }
            }
        }
  -     
  -     my ($found_op, $ambiguous) = (0,0);
  -        my $match_level_2;
  -        my ($old_op) = $opcode;
  -     my @tests;
  -
  -        # grep for operators that match the OP_ic_nc format where ic and nc can be 
any
  -        # of (i n s ic nc sc p).
  -        foreach my $op ( grep ( $_ =~ /^${opcode}(?:_(?:(?:[ins]c?)|p))+$/, 
keys(%opcodes) ) ) {
  +    # grep for operators that match the OP_ic_nc format where ic and nc
  +    # can be any of (i n s p ic nc sc).
  +    foreach my $op ( grep ( $_ =~ /^$opcode(?:_(?:(?:[ins]c?)|p))+$/, 
keys(%opcodes) ) ) {
             # remember what you have examined.
             push( @tests, $op );
             # make sure the argcount is the same
  @@ -262,9 +515,9 @@
             foreach my $idx ( 0 .. $#{ $opcodes{$op}{TYPES} } ) {
               # check each arg type.  assume ic can be used for nc, but prefer
               # ic match to ic.
  -            if( $type_swap{ $opcodes{$op}{TYPES}[$idx] } ne $arg_t[$idx] ) {
  +        if( $type_to_suffix{ $opcodes{$op}{TYPES}[$idx] } ne $arg_t[$idx] ) {
                 # if they are not the same check ic/nc
  -              if( $type_swap{ $opcodes{$op}{TYPES}[$idx] } eq "nc" &&
  +          if( $type_to_suffix{ $opcodes{$op}{TYPES}[$idx] } eq "nc" &&
                     $arg_t[$idx] eq "ic" ) {
                   # got ic/nc level 2 match
                   $match = 2;
  @@ -292,31 +545,50 @@
               $found_op = 1;
             }
           }
  -
           if ($ambiguous) {
             error("Ambiguous operator $old_op matches $opcode and 
$match_level_2\n",$file,$line);
           }
       
           if ($found_op) {
            log_message("substituting $opcode for $old_op" . (scalar(@tests) ? (" ( 
tried " . join(', ', @tests) . ")") : ''),$file,$line);
  -     } else {
  +    }
  +    else {
            error("No opcode $opcode ( tried " . join(', ', @tests) . ") in 
<$pline>",$file,$line);
        }
       }
  +  return $opcode;
  +}
  +
  +# handle_operator
  +# this function finds the correct opcode for the operator
  +# and packs the opcode into the output.
  +sub handle_operator {
  +  my ($opcode,@args) = @_;
  +  $opcode = lc($opcode);
  +  if( !exists $opcodes{$opcode} ) {
  +    $opcode = find_correct_opcode( $opcode, @args );
  +  }
       if (@args != $opcodes{$opcode}{ARGS}) {
         error("Wrong arg count--got ".scalar(@args)." needed 
".$opcodes{$opcode}{ARGS}." in <$_>" ,$file,$line);
       }
       $bytecode .= pack_op($opcodes{$opcode}{CODE});
       $op_pc=$pc;
       $pc+=sizeof('op');
  +  return $opcode;
  +}
       
  +# handle_arguments
  +# packs the argument into the bytecode.
  +sub handle_arguments {
  +  my ($opcode, @args) = @_;
       foreach (0..$#args) {
        my($rtype)=$opcodes{$opcode}{TYPES}[$_];
        if($rtype eq "I" || $rtype eq "N" || $rtype eq "P" || $rtype eq "S") {
            # its a register argument
            $args[$_]=~s/^[INPS](\d+)$/$1/i;
            error("Register $1 out of range (should be 0-31) in 
'$opcode'",$file,$line) if $1 < 0 or $1 > 31;
  -     } elsif($rtype eq "D") {
  +    }
  +    elsif($rtype eq "D") {
            # a destination
            if($args[$_]=~/^\$/) {
                # a local label
  @@ -324,124 +596,50 @@
                    # we have not seen it yet...put it on the fixup list
                    push(@{$local_fixup{$args[$_]}},$op_pc,$pc);
                    $args[$_]=0xffffffff;
  -             } else {                    
  +        }
  +        else {                    
                    $args[$_]=($local_label{$args[$_]}-$op_pc)/sizeof('i');
                }
  -         } else {
  +      }
  +      else {
                if(!exists($label{$args[$_]})) {
                    # we have not seen it yet...put it on the fixup list
                    push(@{$fixup{$args[$_]}},$op_pc,$pc);
                    $args[$_]=0xffffffff;
  -             } else {                    
  +        }
  +        else {                    
                    $args[$_]=($label{$args[$_]}-$op_pc)/sizeof('i');
                }
  +      }
            }
  -     } elsif($rtype eq 's') {
  +    elsif($rtype eq 's') {
            $args[$_]=~s/[\[\]]//g;
  -     } else {
  +    }
  +    else {
            $args[$_]=oct($args[$_]) if($args[$_]=~/^0[xb]?[0-9a-f]*$/);
        }
           $pc+=sizeof($rtype);
        $bytecode .= pack_arg($rtype, $args[$_]);
  -    }
  -    if($options{'listing'}) {
  -     # add line to listing.
  -     my $odata;
  -        # XXX FIXME This can't be right!
  -     foreach (unpack('l*',substr($bytecode,$op_pc))) {
  -         $odata.=sprintf("%08x ",$_);
  -     }
  -     $listing.=sprintf("%4d %08x %-44s %s\n", $line, $op_pc, $odata,$sline);
       }
  +  return @args;
   }
  -$listing.="\n" if($options{'listing'});
  -
  -my $output;
  -
  -# build file in memory
  -
  -# MAGIC COOKIE
  -$output=pack_op(0x13155a1);
  -
   
  -# FIXUP (also, dump listing symbols)
  -if($options{'listing'}) {
  -    $listing.="\nDEFINED SYMBOLS:\n";
  -    foreach (sort(keys(%label))) {
  -     $listing.=sprintf("\t%08x   %s\n",$label{$_},$_);
  -    }
  -}
  -
  -if(keys(%fixup)) {
  -    print STDERR "SQUAWK!  These symbols were referenced but not defined:\n";
  -    foreach (sort(keys(%fixup))) {
  -        print STDERR "\t$_ at pc: ";
  -        foreach my $pc (@{$fixup{$_}}) {
  -            print STDERR sprintf("%08x ",$pc);
  -        }
  -        print STDERR "\n";
  -    }
  -    $listing.="\nUNDEFINED SYMBOLS:\n";
  -    foreach (sort(keys(%fixup))) {
  -     $listing.="\t$_\n";
  -    }
  -    exit;  # some day, unresolved symbols won't be an error!
  -} else {
  -    # dump empty header
  -    $output.=pack_op(0);
  -}
  -
  -# CONSTANTS
  -
  -my $const_table = new Parrot::PackFile::ConstTable;
  -
  -if($options{'listing'}) {
  -    $listing.="\nSTRING CONSTANTS\n";
  -}
  -
  -# Now emit each constant
  -my $counter=0;
  -for (@constants) {
  -     $listing.=sprintf("\t%04x %08x [[%s]]\n",$counter,length($_),$_) 
  -         if($options{'listing'});
  -     $counter++;
  -    $const_table->add(new Parrot::PackFile::Constant (0, 0, 0, length $_, $_));
  +# add_line_to_listing
  +# adds a line to the listing string.
  +sub add_line_to_listing {
  +  $listing .= $_[0];
   }
  -
  -$output.=$const_table->pack;
  -
  -## BYTECODE
  -$output.=$bytecode;
   
  -if(!$options{'checksyntax'}) {
  -    if(defined $options{'output'} and $options{'output'} ne "") {
  -     open O,">$options{'output'}" || die $!;
  -     binmode O;
  -     print O $output;
  -     close O;
  -    } else {
  -     binmode STDOUT;
  -     print $output;
  -    }
  -}
  -
  -
  -if($options{'listing'}) {
  -    open L,">$options{'listing'}" || die $!;
  -    print L $listing;
  -    close L;
  -}
  -
  -###############################
  -# Helper Subroutines
  -###############################
  -
  +# error
  +# outputs and error message and exits.
   sub error {
       my($message,$file,$line)=@_;
       print STDERR "Error ($file:$line): $message\n";
       exit;
   }
   
  +# log_message
  +# outputs a message to the log( STDERR ).
   sub log_message {
       my($message,$file,$line)=@_;
       if($options{'verbose'}) {
  @@ -449,7 +647,11 @@
       }
   }
   
  -
  +# constantize
  +# replaces some escape sequences in a string then adds the string
  +# to the constant array and hash, remembering the index into the array
  +# where the constant string is stored.  The hash is so duplicate strings
  +# do not get duplicated in the constants table.
   sub constantize {
       my $s = shift;
       # handle \ characters in the constant
  @@ -462,12 +664,20 @@
       return "[".$constants{$s}."]";
   }
   
  +# read source
  +# reads in a file putting the informatino gathered into the @program
  +# array.  It also processes INCLUDE directives opening the included
  +# file and recursively processing it.
   sub read_source {
       my($file,$ofile,$oline)=@_;
       my($line)=1;
       my(@lines);
       my($handle)=gensym;
       my($found);
  +    my (@include) = ('.');
  +    if( $options{'include'} ) {
  +      unshift( @include, @{$options{'include'}} );
  +    }
       foreach my $path (@include) {
        open($handle,"$path/$file") && do {
            $found=1;
  
  
  

Reply via email to