Introduction
Here is a grammar-driven peal proving program,
available for download for free. This document describes how to write
composition specifications for it, so that you can search for touches,
quarter-peals or even peals. If you already have a composition, you can
write an explicit specification for that composition and this program will
prove it for you. It will even summarise any music the composition contains.
The simple ringing language as used in
MicroSiril and other peal provers has been in use for many years. It gives an
‘identifier = expansion’ based syntax that expands to raw place
notation for input to a peal prover program. Thus the prover need have no
concept of method structure, or of the concept of leads, blocks, and calls.
This is an ideal ringing language for proving a fixed composition, though it
doesn’t lend itself readily to back-tracking composition searches. In
particular it cannot be used to specify a constrained back-tracking search. For example, if
we wanted to search for peals based on certain fixed block patterns with
optional calling positions or choices of spliced method, we could not specify
the layout of the fixed parts of the touch in a way that would allow a
back-tracking program to perform this constrained search.
The elementary ringing language described
here is based on the concepts of MicroSiril, and adds new constructs that allow options
for changes or leads within a touch. It enables a basic round block to be used,
and options for variations to that block to be exercised. It allows two kinds
of block repetition: one that repeats the optional leads using backtracking,
and one where a repeated block must reuse the leads as set the previous time
the block was used in the proof. In short, ERIL provides features a composition
searcher might use when parts of a composition are designed, but searches need
to be made to join known blocks together, or to get the desired length.
The program eril.exe
is a parser for reading an ERIL touch specification, and proving the
set of touches that match that specification. As usual with all freeware, no
warranties are given for its performance, though I have not yet had a false
proof come out of it! The program is used in the following way.
- First, prepare your touch description file using a text editor of
your choice. The ERIL grammar rules are described later in this article.
- Run the eril.exe
program:
eril touchDescriptionFileName outputTouchFile
- Use a text editor to inspect the list of true touches in the
output touch file that match the ERIL touch specification.
The program can also take input from the
command line and display output in the command prompt window if you just leave out
the first or both arguments. Also placing the flags -d and/or
-v before the input touch description file name turn on debugging output or
verbose touch reporting output respectively. Note that you will only
wish to use -d when providing a bug report for eril which hopefully will not
occur too often!
To install the program, you will need to
download the ZIP file referred to on the Web from location:
http://www.ropley.com/eril/eril.zip
. Unzip its contents into a working directory for
your Eril program. There is a sample copy of the MicroSiril method library, as
maintained by Julian Morgan, in the file
methods.dat.
To construct a more recent one, the batch file
mkmeth.bat
produces the methods file from a more recent set of MicroSiril
method files.
Note too that this program only runs on
Windows 95 or later 32-bit editions of Windows. As the
program relies on the ability to allocate non-trivial amounts of memory, it is
very unlikely versions of this will ever be compiled to run on smaller systems.
Syntax of ERIL composition description files
Basic layout of a touch description
A touch description is broken into three
parts. First, the header describes general properties of the touch, such as the
number of bells the touch is rung on, where to find the method library, etc. At
the moment, this header only specifies the number of bells as a number followed
by a semi-colon.
Second is a sequence of substitution or macro
substitution statements. These are described below, but they provide a
description of how to expand the touch description into a sequence of place
notations.
Lastly come one or more touch specifications
themselves. These are the components that are actually proven, one at a time.
Note that touch specifications may be interspersed with substitutions and
macros, but the macros and substitutions that precede the touch specifications
must satisfy all the needs of the touch specifications at the point they
appear.
White space and comments
The use of white space characters to make
ERIL more readable is possible. White space is not treated as significant.
However, white space should not appear within place notation tokens.
Comments are placed after oblique characters
'/' and continue to the end of the line on which they appear.
Place notation tokens:
Places are made up from
1234567890ETABCD
as increasing valued ordered sets, e.g.
12 or
10 or
367T.
Note that omission of a digit/letter at the
beginning or end of the set implies the extreme position: On ten bells,
45 means
1450.
Placeless (cross-) changes consist of the token '
-', or '
X' (upper
case only). The junction between two place notation tokens is denoted by a
period '.',
but this may be omitted where the junction between
two place notations is between a change with places made and a cross-change.
Note also that the place letters for elevenths place through sixteenth are accepted
in upper case only. Lower case letters are all available for other identifiers.
Block tokens and sequences:
A sequence of place notation tokens may be
treated as a unit by linking them with plus
‘+’ symbols.
For example:
34-34.16 + -12-16-12-.
This is seldom useful on its own as the plus
operator has lower precedence than any other operator in Eril. To alter
precedence levels, place the sequence in parentheses to make a block token. Block
tokens are used where the block needs to be treated as a single entity.
Option tokens:
A choice of place notation or of block may be
denoted by the vertical bar symbol '|
'. This
means that in a backtracking program, each of the options may be tried in turn
as part of the proving process. Note that this operator has higher precedence
than the plus operator, as demonstrated in the example below of an option of a
lead starting with Kent or Oxford places:
34-34|-34- + 16-12-16-12-
Substitution or definition statements:
A new token can be defined that becomes an
alias for a sequence of one or more other tokens. This is used to simplify ERIL
touch descriptions. The syntax for this is: identifier = token-sequence ;
Note that the semi-colon at the end of
the sequence marks the end of the substitution statement. Use of semi-colons in
this way allows long token sequences to spill across multiple lines. The
identifier defined in a substitution may subsequently be used in other
statements, including other substitution definitions. Note that the plus symbol
between the substituted token and a block of place notation must be present as
below. Here is an example:
HalfLeadOfKent = 34-34.16-12-16-12-;
LeadOfKent = HalfLeadOfKent + 16-12-16-12-16.34-34.16;
Reversal statements:
Many (most) methods and principles have place
notation symmetry about the middle of a block of changes. A shorthand way of
representing a block that is the reverse of another block of place notation is
to use the reversal operator '~.
Note this is not the same as the reversal operator of the MicroSiril method
libraries, where the last place (at the half lead) is not repeated in the
reversal, and the whole expansion includes the forward as well as the
reversed sequence or places. Eril just provides the reversal
of another block via the reversal operator. Example:
HalfLeadOfKent = 34-34.16-12-16-12-;
LeadOfKent = HalfLeadOfKent + 16 + ~HalfLeadOfKent + 16;
Macro statements:
Substitution statements can also be furnished
with macro parameters. This allows a standard block to be customised where it
occurs in a touch. Example:
method(body, halfLead, leadEnd) = body + halfLead + ~body + leadEnd;
plainBody = -16-16-;
PlainBob = method( plainBody, 16, 12 );
ReverseBob = method( plainBody, 56, 16 );
DoubleBob = method( plainBody, 56, 12 );
Note that recursion in macros, as well as in
ordinary substitutions is not permitted. Recursion is where you use the same
macro or definition name in the expression to the right of the '=' as appears
at the left. Such definitions would expand to have inifinite length, which
makes them unprovable.
Method statements:
A method from a method library may be loaded
using a fully qualified method name in double quotes. This token expands to be
the method's place notation for a single lead of the method. The method name
consists of two space-separated strings. Example:
"Cambridge Surprise";
/ Expands to a lead of Cambridge found from a method library
Note that methods in a method collection are
assumed to have the names and categories as used in the MicroSiril method
collections. These are:
Plain, TrebleBob, TreblePlace, Surprise, Delight, OddHunt, Principle, Alliance,
SlowCourse. The word ‘Plain’ may be omitted in the
method name, as this is assumed to be the default if nothing else is specified.
If a prior method has been selected from the method collection, its method type
becomes the new default for later methods.
Here is an example that searches for certain
true courses of Kent and Oxford TB Major where the first and fourth leads can
be Kent or Oxford in any combination:
8; / The 1st line specifies the number of bells
K = "Kent TrebleBob"; / These 2 lines are substitution statements
O = "Oxford"; / Still treble bob as current default type
/ The actual touch specification to be proven:
K|O + O + O + K|O + O + O + K;
Repetition:
To indicate repetition of a block, an
asterisk followed by the repetition value is used. The repetition value may be
a decimal number, or a range enclosed in square brackets. (Note though that the
asterisk and repetition value must follow the block to be repeated, and cannot
precede it, as this makes the ERIL grammar ambiguous.) Examples:
8;
R = "Rutland Surprise";
CNY = "Cambridge" | "Lincolnshire" | "Yorkshire";
ShortCourse = (CNY*4+R)|(CNY*3+R+CNY)|(CNY*2+R+CNY*2)|(CNY+R+CNY*3)|(R+CNY*4);
/ 5-lead courses of up to four spliced
(R|CNY)*[3-7];
/ Finds all true bobless courses of four spliced
Pattern filters:
A common requirement is to specify that at a
particular point in a touch the lead should end with a certain pattern. For
example, in major, we might be looking for all courses that end with the tenors
at Home, or a sequence of plain leads followed by a bob at Wrong. These pattern
filters are implemented using the arrow "->" operator as follows:
(p|b|s)*[1-7]->"*78";
/ Matches all courses that end with tenors at home
p*[0-6]+b->"*7.8."|"*8.7";
/ Makes next call a bob at wrong or middle
The change patterns that follow the arrow
operator either begin or end with an asterisk '*', thus representing the first
or last several bells of a row, and have single unspecified bells represented
by a period '.'
Note that if the entire touch specification
ends with a pattern filter, the eril prover searches for any block that
ends with that pattern, rather than touches that end with rounds. This is
obvious if you think about it, as ending with a pattern that does not include
rounds as a pattern match could never yield a true touch. In this way then,
eril can be used to search for turning courses for example.
Replacement blocks:
A common requirement is to specify that a
method is like another, except for some place changes. This is particularly
true if trying to describe a call in a method, where certain rows of place
notation get replaced with other rows. Two constructs exist for permitting
this. First a construct for representing a block of changes where some of the
place notations are not described:
3.123<<1 / Last two places of a lead will be 3 and 123.
/ The other places are unspecified, as is the length.
567.1.7>>0 / First 3 changes of a lead have the specified
/ place notation. The length of the block is undefined.
14<<0 / Last place of a lead will be 14 as in a normal bob.
The rules for the above constructs
are that the offset value after the end-specifier (‘<<’ or
‘>>’) is the offset from either end to the first
place to be made in the sequence. There is no shorthand for leaving out the end
specifier, as the resulting token is an incomplete place notation sequence of
unspecified length. Its only use is as one of the two arguments to the
‘&’ operator. The two end specifiers
(‘<<’ and ‘>>’) are each higher precedence
than the ‘&’ operator, which in turn has higher precedence than
‘|’.
The grammar rules for Eril require that the
thing to the left of the '<<' or '>>' must be a place notation
block or a substitution/definition name that represents one. The thing to the
right of the '<<' or '>>' must be a positive decimal number (not a
definition or macro for one), that lies within one lead of the item to the left
of the '&' operator (discussed immediately below).
To represent a replacement
of some of the places in a method with new ones, use the ‘&’
operator as follows. Note that the
thing to the left of the '&' operator can be a library method, a '~'
expression, a block of place notation, or another '&' expression. It cannot
be multi-block expressions like '|' or '+' expressions:
7; / Touch is a touch of Triples
p = "Grandsire"; / Lookup Grandsire Triples from the plain
/ methods collection
Bob = 3.1 << 1; / Place notation alterations to use for a bob
Single = 3.123 << 1; / Place notation alterations to use for a
/ Grandsire single
b = p & Bob; / The place notation for a bobbed lead of
/ Grandsire
s = p & Single; / Likewise for a lead ending with a single
choice = (p|b|s); / What each lead may contain
choice * [3-10]; / All touches from 42 to 140 changes
Note one important feature. If a replacement
block is specified for which the number of changes spills over the end of the
block, the replacement should also carry on into the next block of changes.
Thus variations like April Day (really Reverse St. Bartholomew!) where the call
spills into the next lead across a lead end can be readily accommodated, as in
the example below. Eril can do this for you. (Note though that there is no way
of having the call at the end of a touch automatically wrap back to the first
change of the touch):
5;
Plain = "PlainBob"; / Most plain methods have ‘Bob’
/ in their name in the method library
Bob = Plain & (3.123.3 << 1); / Will spill one change into lead
/ beyond call
Opt = Bob | Plain;
Part = Opt * 3 + Plain; / Can't have calls at the last
/ lead in this kind of extent
Part * 3; / Finds all the April Day 120s
Value blocks:
In proving, if an option block occurs several
times over, all the options are retried at each point they occur. What a value
block does is to allow us to give a name to the latest value of a block already
part of the earlier changes in a touch, and to reuse the same values for the
options later in the touch. The syntax uses square braces and an optional
identifier:
KentOrOxford =
[block1 34-34|-34-] + 16-12-16-12-16-12-16-12-16 + block1 + 16;
Note that when used with the repetition
operator ‘*’
there is no need to give the value block a name. For
example, to represent a whole course of plain leads of Kent or Oxford spliced, use:
KentOrOxford*5;.
To represent a whole course of either Kent or Oxford (same method every lead), use:
[KentOrOxford]*5.
8;
k = "Kent TrebleBob";
o = "Oxford";
lead = k|o;
[lead]*7; / A whole course of either Kent or Oxford
Some examples of touch descriptions
To show the expressiveness of this as a touch
description language, here are some simple examples. The first example is a
standard 720 of Plain Bob Minor. Notice how the macro substitutes an entire
plain lead of the method with a copy of the plain lead of the method in this
format, thereby still having the desired effect:
6;
pb = "PlainBob";
p = 12<<0;
b = 14<<0;
s = 1234<<0;
course(wrong, home) = pb & wrong + pb*3 + pb & home;
part(lastCall) = course(b, b) + course(b, lastCall);
halfExtent = part(p) + part(p) + part(s);
halfExtent*2;
Second example: A search for all touches of
Plain Bob Minor that are made of bobs or singles at
Wrong and Home, and Singles at Before, and that have between six and twelve
calls:
6;
p = "PlainBob";
b = p&14<<0;
s = p&1234<<0;
plains = p*[0-4];
call(whichCall, music) = plains + whichCall->music;
wrong(bobOrSingle) = call(bobOrSingle, "*6.");
sbefore = call(s, "16*");
home(bobOrSingle) = call(bobOrSingle, "*6");
(wrong(b|s)|sbefore|home(b|s))*[6-12]+plains;
Footnotes
The Eril parser generates a 2.5 Mb file the
first time it is run. If you leave the file alone, each successive time Eril is
started it will initialise much faster. If you delete it, it will take several
extra seconds recreating it next time you run the program. What this file
contains is a table for every Major change and which change to go to next for a
given place notation. It is used internally to prove touches on fewer than 9
bells at lightning speed!
S D Smith - April 2000