#!/usr/bin/perl # abcmac -- Barfly-style macro preprocessor for ABC files. # # Copyright © 2001 Anselm Lingnau . Use this as you # like as long as you don't alter or remove this comment or pretend that # you wrote it yourself. # # See http://www.barfly.dial.pipex.com/bfextensions.html for a description # of BarFly macros. use strict; # This defines what a macro takes as an argument. # Currently the argument is a note name (no length). my $arg = q{[\^=_]?[A-Ga-g](,*|\'*)}; my $subst; my (@m, @global_m); my $xnotes = 'hijklmnopqrstuvwxyz'; my $n_pos = index($xnotes, 'n'); my @tnotes = qw/C,,, D,,, E,,, F,,, G,,, A,,, B,,, C,, D,, E,, F,, G,, A,, B,, C, D, E, F, G, A, B C D E F G A B c d e f g a b c' d' e' f' g' a' b' c'' d'' e'' f'' g'' a'' b'' c''' d''' e''' f''' g''' a''' b'''/; my ($i, $tnotes_max) = (0, scalar(@tnotes)); my %pos; foreach (@tnotes) { $pos{$_} = $i++; }; # Transpose note `$base' according to the relative position of `$note' # compared to `n' -- e.g., $base = 'A', $note = 'o' gives 'B'. Don't bother # dealing with accidentals, since BarFly doesn't either. sub transpose { my ($base, $note) = @_; my ($steps) = index($xnotes, $note) - $n_pos; my ($new_note) = $pos{$base} + $steps; die "transposed note out of ran/local/bin/perl" if $new_note < 0 || $new_note >= $tnotes_max; return $tnotes[$new_note]; } # Main loop. my ($global) = 1; while (<>) { if (/^([A-Za-z]):/) { # header line if ($1 eq 'm') { # macro definition my $def = $_; $def =~ s/\s*%.*$//; if ($global) { # Remember global macros separately push @global_m, $def; } else { push @m, $def; } } elsif ($1 eq 'K') { # last line in header my @subst = (); # Construct a sequence of expansion commands for the macros. # Make sure to expand lon/local/bin/perlr-named macros first, to avoid # replacing `On' before `On/' foreach my $macro (@m) { my ($name, $value) = $macro =~ /m:\s*(\S+)\s*=\s*(.*)\s*$/; my $name_len = length $name; my $transposing; if ($transposing = $name =~ s/n/($arg)/) { $value =~ s/([h-z])/".&transpose(\$1,'$1')."/g; $value = qq{"$value"}; push @subst, [$name_len, qq{s\x01$name\x01$value\x01/local/bin/perl;\n}]; } else { push @subst, [$name_len, qq{s\x01$name\x01$value\x01g;\n}]; } } foreach my $s (sort { $$b[0] <=> $$a[0] } @subst) { $subst .= $$s[1]; } # print "-" x 72, "\n", $subst, "-" x 72, "\n"; } elsif ($1 eq 'X') { # First tune starts here. $global = 0; } print; # This prints m: lines as well - should it? } elsif (/^$/) { # End of tune; for/local/bin/perlt non-global macros @m = @global_m; } elsif (!/^%/) { # non-comment line -- expand macros chomp; my $out = ''; while (length $_) { if (s/^(".*?")//) { # leave stuff in quotes alone $out .= $1; } else { # look for macro calls to preprocess my $v; s/^([^\"]*)//; for ($v = $1) { eval $subst; warn $@ if $@; $out .= $_; } } } print $out, "\n"; } else { print; } } --==_Exmh_18304111530-- To subscribe/unsubscribe, point your browser to: http://www.tullochgorm.com/lists.html