- Startup. All standard Mac application startups work -- Select the MacSiRiL icon and then Open from the finder File menu or twiddle-O shortcut from the keyboard, or double-click the icon, or drag and drop the input file(s) (which must be TEXT) onto the icon, or double-click one or more TEXT file(s) with signature SiRi (see section 6). Otherwise MacSiRiL is not mouse-driven, and uses the keyboard and screen like a scrolling VDU -- this is pretty primitive but designed to be easily ported to other platforms.
- Input and output files. At startup, MacSiRiL brings up standard dialogue boxes for the output and input files (in that order). For output, type in a file name to create a new output file or overwrite an existing one (confirmation required), or click cancel (or hit the esc key or enter twiddle-.) for screen output. For input choose an existing file or click cancel (or esc or twiddle-.) for keyboard input. If you start MacSiRiL by drag-and-drop or double-clicking a SiRi file, the input dialogue is suppressed (the files are opened automatically as expected, but in reverse order of presentation). MacSiRiL outputs as a keyboard input prompt and adds : to the start of screen (but not disk) output lines. Keyboard input is echoed on the screen, but not to an output disk file; disk file input is not echoed at all.
- End-of-file on input (for keyboard input, the enter key on the numeric keypad signals eof) opens the next dropped or double-clicked file or (after they have all been read) brings up a dialogue box for a new input file. This gives a crude method of alternating between keyboard and disk file input.
- Input syntax. The input is free format, and whitespace (blank, tab, newline) is only needed when adjacent input tokens are both identifiers; tokens can be separated by additional whitespace for clarity (as I tend to do in the examples below). A MacSiRiL "program" consists of a series of definitions and procedure calls. The definitions are stored (see also section 18) and the procedure calls are executed immediately they are entered. The end of each definition or procedure call is marked by a semicolon.
- Procedure calls are standard identifiers followed by a single (sometimes optional) argument expression (see section 13) and terminated by a semicolon. They cause some action to be performed on the sequence of place notation defined by the argument expression. For example:
prove peal ;
- Standard procedures are:
- prove expression -- generates the rows from the place notation defined by expression and proves them. All repetitions are reported, and all the rows are counted, including the final rounds (if the touch is a round block).
- list expression -- generates the rows from the place notation defined by expression and writes them to the output file.
- test expression -- generates the rows from the place notation defined by expression but does nothing with them (I use this for quick checking of input).
- draw expression -- generates the rows from the place notation defined by expression and draws a fairly useless grid diagram that sometimes fits on the page and can't be printed or saved. One day I'll finish implementing this, but I need to learn more Macintosh internals.
- show identifier -- lists the definition (i.e. the expression, not the value) of identifier. If you omit identifier, all definitions are listed. The output is generated by decompiling the abstract syntax tree, so all your neat input layout is thrown away. Tough (I might fix this as well one day).
- save identifier -- saves the definition of identifier in a specified file (brings up the standard open output file dialogue) after which output reverts to the original output file. If you omit identifier, all definitions are saved. The format (or lack of it) is the same as for show. The saved file has the signature SiRi and will start the MacSiRiL system if double-clicked.
- clear identifier -- deletes the current definition of identifier (see also section 20). If you omit identifier all current definitions are deleted.
- quit (no argument permitted). Exits from the MacSiRiL system. This is the only way of getting out of MacSiRiL except for the Mac's standard emergency escape mechanism (option-twiddle-esc).
- Definitions are identifiers followed by a = and an expression (see section 13) and terminated by a semicolon. They define how the value of the identifier (which will be a sequence of place notation) is computed when it's used later in a procedure call or in another expression. For example:
peal = part1 , part2 ;
- Identifiers are arbitrary-length sequences of letters and digits, starting with a letter in the traditional way. MacSiRiL is case-sensitive. The names of procedures are not reserved, and they can also be used as identifiers without confusion.
- Constants. These are numbers (see section 10) or place notations. Place notations are the usual sorts of thing, enclosed in square brackets. For example:
York = [-36-14-12-36.14-14.36] & ;
Absence of places is represented by -, x or X ; adjacent sets of places are separated by . or blank; bells from 10-16 are represented by the characters 0, e, t, a, b, c and d (or their upper-case equivalents) respectively. Lead and ultimate places can be omitted. Superfluous blanks (i.e. between sets of places) are allowed. MacSiRiL won't handle more than 16 bells; this has never been a problem to me! Unlike MicroSiril, you don't actually have to tell MacSiRiL how many bells you want; it deduces this from the place notation you supply to a procedure call (but you must put the ultimate place in at least once of course).
- Actions. You can embed actions in place notation; these cause various side-effects when the notation is processed. An action sequence is a sequence of one or more letters enclosed in { }. I keep fiddling with these and haven't got them right yet; the current selection of valid letters is:
- s -- shows (prints) the last row generated. Has a rather unexpected (but logical) result if the notation appears in a folded (see section 14) expression!
- n -- new page; outputs a page break; useful with list (I use MicroSoft Word to set the rows in columns and page break starts a new column).
- u -- underlines the last row generated; forces an s when the notation is used by prove or test, but not when it's used by list. (I can't seem to get the interaction between s and u and list and prove right. Any suggestions welcome).
- p -- identifies the previous row as a part-end.
- l -- identifies the previous row as a lead-end.
- c -- identifies the previous row as a course-end.
If you use p, l and c, falseness is reported by part, course and lead number (good for spliced); if not row number is used.
- Literals. Any text enclosed in enclosed in " " marks will be shown (printed) when encountered in place-notation.
- Transpositions. As well as defining rows by place-notation; you can perform conventional transpositions. These are represented in notation as a permutation of rounds (i.e. all the digits must be present), preceded by a # character. For example:
GroupF = [#14628375{l}] ;
Here we use a transposition to define a skeleton method (with no changes in a lead, but the right lead-end) to try in peals of spliced without having to worry about the falseness of any specific method. We can also use transpositions to prove peals purely by lead-heads and lead-ends. Transpositions behave as expected (if you have any expectations!) in folded and repeated expressions, at least they did last time I tested them.
- Constant rows. You can force the next row to have any specified value. This is represented in notation as a permutation of rounds preceded by a ! character. For example:
prove [!14235678] , part , [!12436578] , part ;
You can use this feature to start a touch from a row other than rounds, or to prove separate pieces of a developing touch that don't join up yet. Constant rows aren't too useful in folded or repeated expressions!
- Expressions are formed from constants, identifiers, parentheses and the four basic operations of folding, repetition, concatenation and choice. Expressions always evaluate to sequences of place notation.
- Folding -- the & operator; this has the highest priority and you can use it in either prefix or postfix notation according to taste. Unlike MicroSiRiL, it's a genuine operator and can be applied to any expression, not just used in constant place notation; so you can easily define palindromic touches, for instance:
prove HalfPitmans4 & ;
- Repetition -- the * operator. This has the next highest priority and must be used in infix notation. Its first argument is a constant number (greater than zero and less than some value that I forget and which crashes the system relatively gracefully; I'll fix this sometime) and its second argument is an arbitrary expression. For example:
BlockB = 3 * BlockA ;
You can miss out the * and the parser will insert it for you.
- Concatenation -- the , operator. This has the lowest priority and must be used in infix notation. Its arguments are arbitrary expressions, For example:
JohnsonsVariation = BeforeBlock , 4 * MiddletonsBlock ;
You can miss out the , and the parser will insert it for you as well.
- Choice -- the construction:
< number | if-true | if-false >
has the same priority as a parenthesised expression (see section 19) and has the value of the expression if-true if the tenor (i.e. the largest bell) was in position number (an integer) in the last row generated, otherwise it has the value of the expression if-false (both may be any expression). For example:
plain = lead , [12] , < 8 | [{p}] | [ ] > ;
might be used to print out the course-ends of a peal of Major (see also section 19).
- Parentheses. These alter the evaluation order in the usual way. For example:
PlainCourse = 5 * ( HalfLead & , LeadHead ) ;
This saves you writing auxiliary definitions to get the evaluation order right as you have to in MicroSiRiL.
- Program order. The order of definitions is unimportant except that a later definition of a name replaces an earlier one (not quite so declarative). A warning message is issued if an expression in a definition uses an identifier which isn't yet defined, but the first definition is still saved. Definitions may not be directly or indirectly recursive (that is, they may not refer to themselves), and any definition which "closes the circle" of a set of recursive definitions will not be stored. The only exception to this is that the if-false part of a choice expression may be recursive. This allows constructions like:
before = lead , < 2 | [14] | [12] , before > ;
which (as you realised immediately) keeps repeating lead with 2nd's place after it (the if-false alternative) until the tenor is "before" (i.e. in 2nd's place), when 4th's place is made and the repetition is terminated (the if-true alternative). With suitable definitions, you can specify touches entirely by calling positions without having to count leads like you do in MicroSiRiL.
- Definitions for all identifiers in the argument expression of a procedure call must exist at the time of call, or it won't be executed. The value of the expression must be a non-empty notation containing at least one place (i.e. it mustn't consist entirely of x's). The number of bells assumed in the touch is the largest place in the notation.
- Disclaimer. MacSiRiL is not a proper Macintosh Application: it is extremely deficient in windows, icons and menus, and the mouse is entirely useless for driving it. Like all hackers I smugly claim my software to be entirely correct, but like all two-faced lying bastards I refuse to bet any money on this. Specifically I refuse to buy any beer whatsoever for anyone who claims to have rung a false peal as a result of proving it with MacSiRiL. I shall naturally be pleased to receive suggestions for improvements and reports of bugs, as this allows users to feel superior whilst absolving me from responsibility for proper design or testing.