Jack Campin <[EMAIL PROTECTED]> writes:
> Here's an example; the chords could hardly be simpler (play the lower
> octave along with the named note), but even here there's less to type
> and read than writing them out explicitly.
I've appended a little Perl program which will, from Jack's input, create
output that is identical to his expanded text. I don't know whether it
is general enough (it's probably too general in places) but it could
serve as a starting point.
Anselm
--
Anselm Lingnau .......................................... [EMAIL PROTECTED]
Programming graphics in X is like finding sqrt(pi) using Roman numerals.
-- Henry Spencer
#!/usr/bin/perl
# abcmac -- Barfly-style macro preprocessor for ABC files.
#
# Copyright � 2001 Anselm Lingnau <[EMAIL PROTECTED]>. Use this as you
# like as long as you don't alter or remove this comment or pretend that
# you wrote it yourself.
#
# Lines of the form `m: On/ = [n/n,/]' (where `O' is an otherwise unused
# letter in abc) define a macro which will subsequently be replaced
# by the expansion on the right of the equals sign. In the macro name,
# `n' is a placeholder for a note; instances of `n' in the expansion
# will be replaced by the actual note.
#
# Points to watch out for:
# - Right now pretty much anything can be used as a macro name. This
# should probably be tightened up to allow just the unused letters.
# - It's probably too simple-minded about where macros can be defined.
# Do macros have scope?
# - Can macros have more than one argument? What exactly is allowed as
# the argument?
#
# Implemented according to an example provided by Jack Campin.
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;
while (<>) {
if (/^([A-Za-z]):/) { # header line
if ($1 eq 'm') { # macro definition
push @m, $_;
} elsif ($1 eq 'K') { # last line in header
my @subst = ();
# Construct a sequence of expansion commands for the macros.
# Make sure to expand longer-named macros first, to avoid
# replacing `On' before `On/'
foreach my $macro (@m) {
my ($name, $value) = $macro =~ /m:\s*(\S+)\s*=\s*(.*)$/;
my $name_len = length $name;
$name =~ s/n/($arg)/;
$value =~ s/n/\$1/g;
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; # This prints �m:� lines as well - should it?
} 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; $out .= $_; }
}
}
print $out, "\n";
} else {
print;
}
}