The following patch fixes the following bugs with macros: 1) Macros with zero parameters were disallowed 2) Local branches inside macros were not being given unique names on a per-invocation basis. This made it impossible to write the following code:
--- cut here --- answer macro R eq R,42,$done print 42 $done: endm answer 41 answer 42 end --- cut here --- Because when the macro was expanded twice, two separate expansions of $done existed in the generated code, which caused an error. The presented patch fixes this naively by appending 'LOCAL_$gensym' onto the label name, creating '$LOCAL_0_done' in the first expansion, '$LOCAL_1_done' for the second expansion, and so on. A slightly cleaner solution would be to alter the parser to allow labels of the form 'LOCAL_0_$done' so that an author would stand a much lower risk of colliding with compiler-generated labels. On the upside, this patch allows me to continue to add new instructions to the compiler without fear of label collision. -- --Jeff <[EMAIL PROTECTED]>
#! perl -w use Parrot::Test tests => 6; output_is( <<'CODE', <<OUTPUT, "macro, zero parameters" ); answer macro print 42 print "\n" endm answer end CODE 42 OUTPUT output_is( <<'CODE', <<OUTPUT, "macro, one unused parameter, literal term" ); answer macro A print 42 endm answer 42 print "\n" end CODE 42 OUTPUT output_is( <<'CODE', <<OUTPUT, "macro, one unused parameter, register term" ); answer macro A print 42 endm set I0, 43 answer I0 print "\n" end CODE 42 OUTPUT output_is( <<'CODE', <<OUTPUT, "macro, one used parameter, literal" ); answer macro A print A endm answer 42 print "\n" end CODE 42 OUTPUT # # Can't test because I can't capture errors # #output_is( <<'CODE', <<OUTPUT, "macro, one parameter in call, not in def" ); #answer macro # print A #endm # answer 42 # print "\n" #end #CODE #42 #OUTPUT output_is( <<'CODE', <<OUTPUT, "macro, one used parameter, register" ); answer macro A print A endm set I0,42 answer I0 print "\n" end CODE 42 OUTPUT output_is( <<'CODE', <<OUTPUT, "macro, one used parameter, called twice" ); answer macro A print A print "\n" inc A endm set I0,42 answer I0 answer I0 end CODE 42 43 OUTPUT output_is( <<'CODE', <<OUTPUT, "macro, one used parameter, label" ); answer macro A ne I0,42,$done print A print "\n" $done: endm set I0,42 answer I0 end CODE 42 OUTPUT output_is( <<'CODE', <<OUTPUT, "macro, one used parameter run twice, label" ); answer macro A ne I0,42,$done print A print "\n" $done: endm set I0,42 answer I0 answer I0 end CODE 42 OUTPUT
diff -ru parrot_orig/Parrot/Assembler.pm parrot/Parrot/Assembler.pm --- parrot_orig/Parrot/Assembler.pm Sat Nov 3 19:04:08 2001 +++ parrot/Parrot/Assembler.pm Sat Nov 10 21:35:01 2001 @@ -581,6 +581,7 @@ =cut sub process_program_lines { + my $gensym = 0; while( my $lineinfo = shift( @program ) ) { ($file, $line, $pline, $sline) = @$lineinfo; @@ -609,7 +610,7 @@ # found a macro, expand it and append its lines to the front of # the program lines array. - my @expanded_lines = expand_macro( $opcode, @args ); + my @expanded_lines = expand_macro( $opcode, $gensym++, @args ); unshift( @program, @expanded_lines ); $lineinfo->[2] = ''; unshift( @program, $lineinfo ); @@ -687,7 +688,7 @@ =cut sub has_asm_directive { - return $_[0] =~ /^[_a-zA-Z]\w*\s+macro\s+.+$/i || + return $_[0] =~ /^[_a-zA-Z]\w*\s+macro(?:\s+.+)?$/i || $_[0] =~ /^[_a-zA-Z]\w*\s+equ\s+.+$/i; } @@ -710,11 +711,16 @@ $equate{$name} = $data; return 1; } - elsif( $line =~ /^([_a-zA-Z]\w*)\s+macro\s+(.+)$/i ) { + 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)], [] ]; + if(defined $args) { + $macros{$name} = [ [split( /,\s*/, $args)], [] ]; + } + else { + $macros{$name} = [ [], [] ]; + } while( 1 ) { if( !scalar( @program ) ) { error( "The end of the macro '$name' was never seen", $file, $line); @@ -830,8 +836,9 @@ =cut sub expand_macro { - my ($opcode, @args) = @_; + my ($opcode, $gensym, @args) = @_; + my $local_prefix = sprintf("LOCAL_%d_",$gensym); my (@margs) = @{ $macros{$opcode}[0] }; my (@macro); @@ -840,6 +847,11 @@ foreach (@{ $macros{ $opcode }[1] } ) { push( @macro, [@$_] ); + } + for(@macro) { + $_->[2]=~/\$/ and do { + $_->[2]=~s/\$/\$$local_prefix/; + }; } my $nargs = scalar(@args);