All --

I have fixed the macro facility in the assembler (there was a goof
in argument processing in expand_macro). I discovered this while
implementing label arithmetic for the assembler so all the tests
in t/basic.t could be enabled. It now works, and as an added
bonus, the net result is "poor man's subroutines". See the attached
file call.pasm for an example.


Regards,

-- Gregor
 _____________________________________________________________________ 
/     perl -e 'srand(-2091643526); print chr rand 90 for (0..4)'      \

   Gregor N. Purdy                          [EMAIL PROTECTED]
   Focus Research, Inc.                http://www.focusresearch.com/
   8080 Beckett Center Drive #203                   513-860-3570 vox
   West Chester, OH 45069                           513-860-3579 fax
\_____________________________________________________________________/
? ChangeLog
? asm.patch
? call.pasm
Index: disassemble.pl
===================================================================
RCS file: /home/perlcvs/parrot/disassemble.pl,v
retrieving revision 1.13
diff -a -u -r1.13 disassemble.pl
--- disassemble.pl      2001/09/30 20:25:22     1.13
+++ disassemble.pl      2001/10/03 16:59:42
@@ -221,10 +221,10 @@
     printf "#\n";
     printf "# Segments:\n";
     printf "#\n";
-    printf "#   * Magic Number: %8d bytes\n", sizeof('iv');
+    printf "#   * Magic Number: %8d bytes\n", sizeof('intval');
     printf "#   * Fixup Table:  %8d bytes\n", $pf->fixup_table->packed_size;
     printf "#   * Const Table:  %8d bytes\n", $pf->const_table->packed_size;
-    printf "#   * Byte Code:    %8d bytes (%d IVs)\n", length($pf->byte_code), 
length($pf->byte_code) / sizeof('iv');
+    printf "#   * Byte Code:    %8d bytes (%d IVs)\n", length($pf->byte_code), 
+length($pf->byte_code) / sizeof('intval');
 
     dump_const_table($pf);
     disassemble_byte_code($pf);
Index: Parrot/Assembler.pm
===================================================================
RCS file: /home/perlcvs/parrot/Parrot/Assembler.pm,v
retrieving revision 1.1
diff -a -u -r1.1 Assembler.pm
--- Parrot/Assembler.pm 2001/09/30 20:25:23     1.1
+++ Parrot/Assembler.pm 2001/10/03 16:59:43
@@ -9,6 +9,7 @@
 #
 
 use strict;
+use Carp qw(&confess);
 
 
 ###############################################################################
@@ -423,9 +424,34 @@
     add_line_to_listing( sprintf( "\t%08x   %s\n", $label{$_}, $_ ) );
   }
 
+  #
+  # Resolve label arithmetic:
+  #
+
+  foreach my $label (keys %fixup) {
+    next unless $label =~ m/^\[(.*)\]$/;
+
+    my $exp = $1;
+
+    $exp =~ s/([A-Za-z_][A-Za-z0-9_]*)/$label{$1}/g;
+
+    my $result = (eval $exp) / sizeof('intval');
+
+    while (scalar(@{$fixup{$label}})) {
+      my $offset = shift @{$fixup{$label}};
+      substr($bytecode, $offset, sizeof('intval')) = pack_arg('intval', $result);
+    }
+
+    delete $fixup{$label};
+  }
+
+  #
+  # Complain about undefined symbols:
+  #
+
   return unless keys %fixup;
 
-  print STDERR "SQUAK!  These symbols were referenced but not defined:\n";
+  print STDERR "These symbols were referenced but not defined:\n";
 
   add_line_to_listing( "\nUNDEFINED SYMBOLS:\n" );
 
@@ -437,8 +463,10 @@
     print STDERR "\n";
     add_line_to_listing( "\t$_\n" );
   }
+
+  # TODO: some day, unresolved symbols won't be an error!
 
-  exit; # some day, unresolved symbols won't be an error!
+  error("Cannot assemble with unresolved symbols!\n", $file, $line);
 }
 
 
@@ -548,6 +576,9 @@
     }
 
     $code = replace_constants($code);
+
+    while ($code =~ s/\[([^\] \t]*)\s+/[$1/) { };  # Erase all space within label 
+arithmetic
+
     $code =~ s/,/ /g;
     $code =~ s/#.*$//; # strip end of line comments
 
@@ -556,6 +587,7 @@
     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] = '';
@@ -667,7 +699,7 @@
     $macros{$name} = [ [split( /,\s*/, $args)], [] ];
     while( 1 ) {
       if( !scalar( @program ) ) {
-        error( "The end of the macro was never seen" );
+        error( "The end of the macro was never seen", $file, $line);
       }
       my $l = shift( @program );
       ($file, $line, $pline, $sline) = @$l;
@@ -675,7 +707,7 @@
         last;
       }
       elsif( $pline =~ /^\S+\s+macro/ ) {
-        error( "Cannot define a macro inside of another macro" );
+        error( "Cannot define a macro inside of another macro", $file, $line );
       }
       else {
         push( @{$macros{$cur_macro}[1]}, $l );
@@ -699,48 +731,66 @@
 
 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
+
+  #
+  # Local labels (begin with '$'):
+  #
+
+  if ($label =~ /^\$/) {
     if( exists( $local_label{ $label } ) ) {
       error( "local label '$label' already defined in $last_label!", $file, $line );  
    
     }
+
     if( exists( $local_fixup{ $label } ) ) {
       # backpatch everything with this PC.
       while(scalar(@{$local_fixup{$label}})) {
         my $op_pc=shift(@{$local_fixup{$label}});
         my $offset=shift(@{$local_fixup{$label}});
-        substr($bytecode,$offset,sizeof('i'))=pack_arg('i', ($pc-$op_pc)/sizeof('i'));
+        substr($bytecode,$offset,sizeof('i')) = pack_arg('i', 
+($pc-$op_pc)/sizeof('i'));
       }
+
       delete($local_fixup{$label});  
     }
+
     $local_label{$label} = $pc;
   }
+
+  #
+  # Global labels:
+  #
+
   else {
-    # a global label
     if( exists( $label{ $label } ) ) {
       error( "'$label' already defined!", $file, $line );
     }
+
     if( exists( $fixup{$label} ) ) {
       # backpatch everything with this PC.
       while( scalar( @{ $fixup{ $label } } ) ) {
         my $op_pc = shift( @{ $fixup{ $label } } );
         my $offset = shift( @{ $fixup{ $label } } );
-        substr($bytecode,$offset,sizeof('i'))=pack_arg('i', ($pc-$op_pc)/sizeof('i'));
+        substr($bytecode,$offset,sizeof('i')) = pack_arg('i', 
+($pc-$op_pc)/sizeof('i'));
       }
+
       delete($fixup{$label});  
     }
+
+    #
+    # Clear out any local labels
+    #
 
-    # clear out any local labels
     %local_label = ();
+
     if( keys( %local_fixup ) ) {
       # oops, some local labels are unresolved
       error( "These local labels were undefined in $last_label: " .
              join( ",", sort( keys( %local_fixup ) ) ), $file, $line );
     }
+
     $label{ $label } = $pc; # store it
     $last_label = $label;
   }
+
   return $code;
 }
 
@@ -755,23 +805,31 @@
 =cut
 
 sub expand_macro {
-  my ($opcode, @args) = shift;
+  my ($opcode, @args) = @_;
+
   my (@margs) = @{ $macros{$opcode}[0] };
   my (@macro);
+
   # we have to make sure to copy the macro, to avoid mangling the
   # original macro definition.
+
   foreach (@{ $macros{ $opcode }[1] } ) {
     push( @macro, [@$_] );
-  }
-  if( scalar(@margs) != scalar(@args) ) {
-    error( "Wrong number of arguments to macro '$opcode'", $file, $line );
   }
+
+  my $nargs = scalar(@args);
+  my $eargs = scalar(@margs);
+
+  error( "Wrong number ($nargs) of arguments to macro '$opcode' (expected $eargs)", 
+$file, $line )
+    if $eargs != $nargs;
+
   #fixup parameters.
+
   while( my $marg = shift( @margs ) ) {
     my $param = shift( @args );
     foreach( @macro ) {
-      $_->[2] =~ s/([\s,])$marg\b/$1$param/g;
-      $_->[3] =~ s/([\s,])$marg\b/$1$param/g;
+      $_->[2] =~ s|([^A-Za-z0-9_])$marg\b|$1$param|g;
+      $_->[3] =~ s|([^A-Za-z0-9_])$marg\b|$1$param|g;
     }
   }
 
@@ -844,11 +902,13 @@
     } elsif (m/^\[([a-z]+):(\d+)\s*\]$/) {             # constant (sc or nc for now)
       push @arg_t, $1;
     } elsif(m/^((-?\d+)|(0b[01]+)|(0x[0-9a-f]+))$/i) { # integer
+      push @arg_t,'ic';
+    } elsif(m/^\[.*\]$/) {                                      # label arithmetic
       push @arg_t,'ic';
-    } elsif(m/^[\$A-Za-z_][\w]*$/i) {                  # label
+    } elsif(m/^\$?[A-Za-z_][\w]*$/i) { # label
       push @arg_t,'ic';
     } else {
-      error("Unrecognized argument '$_'!");
+      error("Unrecognized argument '$_'!", $file, $line);
     }
   }  
 
@@ -971,20 +1031,44 @@
   my ($code, $opcode, @args) = @_;
 
   foreach (0..$#args) {
-    my($rtype)= $opcodes{$opcode}{TYPES}[$_];
+    my $rtype = $opcodes{$opcode}{TYPES}[$_];
 
+    #
+    # Register arguments:
+    #
+
     if($rtype eq "I" || $rtype eq "N" || $rtype eq "P" || $rtype eq "S") {
       # its a register argument
 
       $args[$_] =~ s/^[INPS](\d+)$/$1/i
-        or error("Expected m/[INPS]\\d+/, but got '$args[$_]'!");
+        or error("Expected m/[INPS]\\d+/, but got '$args[$_]'!", $file, $line);
 
       error("Register $1 out of range (should be 0-31) in '$opcode'",$file,$line) if 
$1 < 0 or $1 > 31;
     }
+
+    #
+    # Destination arguments:
+    #
+
     elsif($rtype eq "D") {
-      # a destination
-      if( $args[$_] =~ /^\$/ ) {
-        # a local label
+      #
+      # Label arithmetic:
+      #
+
+      if ($args[$_] =~ m/^\[(.*)\]$/) {
+        my $mult = sizeof('intval');
+        $args[$_] =~ s/(\d+)/$mult * $1/eg;                  # Hard-coded INTVAL 
+offsets ---> byte offsets
+        $args[$_] =~ s/[\@]/$op_pc/;                         # Map '@' to $op_pc
+
+        push @{$fixup{$args[$_]}}, $pc;
+        $args[$_] = 0xffffffff;
+      }
+
+      #
+      # Local labels:
+      #
+
+      elsif ($args[$_] =~ /^\$/) {
         if( !exists($local_label{$args[$_]}) ) {
           # we have not seen it yet...put it on the fixup list
           push(@{$local_fixup{$args[$_]}},$op_pc,$pc);
@@ -994,6 +1078,11 @@
           $args[$_] = ($local_label{$args[$_]}-$op_pc)/sizeof('i');
         }
       }
+
+      #
+      # Regular labels:
+      #
+
       else {
         if( !exists($label{$args[$_]}) ) {
           # we have not seen it yet...put it on the fixup list
@@ -1005,14 +1094,46 @@
         }
       }
     }
-    elsif($rtype eq 's') {
+
+    #
+    # String arguments:
+    #
+
+    elsif ($rtype eq 's') {
       $args[$_] =~ s/[\[]sc:(.*)[\]]/$1/;
     }
-    elsif($rtype eq 'n') {
+
+    #
+    # Number arguments:
+    #
+
+    elsif ($rtype eq 'n') {
       $args[$_] =~ s/[\[]nc:(.*)[\]]/$1/;
     }
-    else {
-      if ($args[$_] =~ /^0b[01]+$/i) {
+
+    #
+    # Integer arguments:
+    #
+
+    elsif ($rtype eq 'i') {
+      #
+      # Label arithmetic:
+      #
+
+      if ($args[$_] =~ m/^\[(.*)\]$/) {
+        my $mult = sizeof('intval');
+        $args[$_] =~ s/(\d+)/$mult * $1/eg;                  # Hard-coded INTVAL 
+offsets ---> byte offsets
+        $args[$_] =~ s/[\@]/$op_pc/;                         # Map '@' to $op_pc
+
+        push @{$fixup{$args[$_]}}, $pc;
+        $args[$_] = 0xffffffff;
+      }
+
+      #
+      # Handle conversions of hexadecimal and octal:
+      #
+
+      elsif ($args[$_] =~ /^0b[01]+$/i) {
         $args[$_] = from_binary( $args[$_] );
       }
       elsif ($args[$_] =~ /^0x?[0-9a-f]*$/i) {
@@ -1020,6 +1141,20 @@
       }
     }
 
+    #
+    # Unknown argument types:
+    #
+
+    else {
+      error("Unrecognized argument type '$rtype'!\n", $file, $line);
+    }
+
+    #
+    # Continue:
+    #
+    # NOTE: Too bad $rtype wouldn't be visible in a continue block...
+    #
+
     $pc       += sizeof($rtype);
     $bytecode .= pack_arg($rtype, $args[$_]);
   }
@@ -1065,8 +1200,14 @@
 =cut
 
 sub error {
-    my($message,$file,$line)=@_;
+    my ($message, $file, $line) = @_;
+
+    die("\$message undefined!") unless defined $message;
+    die("\$file undefined!")    unless defined $file;
+    die("\$line undefined!")    unless defined $line;
+
     print STDERR "Error ($file:$line): $message\n";
+
     exit 1;
 }
 
@@ -1161,6 +1302,7 @@
        my($sline)=$_;
        s/^\s*//;
        s/\s*$//;
+
        push(@lines,[$file,$line,$_,$sline]);
        if(m/^INCLUDE\s+['"](.+)["']/i) {
            my $newfile=$1;
Index: t/op/basic.t
===================================================================
RCS file: /home/perlcvs/parrot/t/op/basic.t,v
retrieving revision 1.2
diff -a -u -r1.2 basic.t
--- t/op/basic.t        2001/09/25 09:12:57     1.2
+++ t/op/basic.t        2001/10/03 16:59:43
@@ -27,17 +27,34 @@
        end
 CODE
 
-SKIP: {
-    skip( "label constants unimplemented in assembler", 1 );
 output_is( <<'CODE', <<OUTPUT, "jump" );
-       set     I4, 42
-       set     I5, HERE
-       jump    I5
-       set     I4, 1234
-HERE:
-       print   I4
-       end
+neg         macro   R
+            set     I0, R
+            set     R, 0
+            sub     R, R, I0
+endm
+
+call        macro   R, D
+            set     R, [D - @ - 3]
+            jump    R
+endm
+
+return      macro   R, D
+            neg     R
+            inc     R, [D - @ - 1]
+            jump    R
+endm
+
+MAIN:       set     I1, 42
+            call    I31, PRINTIT
+            set     I1, 1234
+            call    I31, PRINTIT
+            end
+
+PRINTIT:    print        I1
+            print   "\n"
+            return  I31, PRINTIT
 CODE
-I reg 4 is 42
+42
+1234
 OUTPUT
-}
neg         macro   R
            set     I0, R
            set     R, 0
            sub     R, R, I0
endm

call        macro   R, D
            set     R, [D - @ - 3]
            jump    R
endm

return      macro   R, D
            neg     R
            inc     R, [D - @ - 1]
            jump    R
endm

MAIN:       set     I1, 42
            call    I31, PRINTIT
            set     I1, 1234
            call    I31, PRINTIT
            end

PRINTIT:    print        I1
            print   "\n"
            return  I31, PRINTIT

Reply via email to