Skip to content
roomi fields

The BP3 language · B10 · Reference

The EBNF of BP3

Discover BP3's first complete formal specification: 83 detailed EBNF productions in a unique reference format (EBNFdoc).

Published 24 March 2026 · Lire en français

Formal Grammar of a Musical Language

In L3, we learned to read EBNF grammars. In B1 to B6, we discovered BP3’s constructions one by one. This article brings it all together: the complete grammar of the BP3 language in ~83 productions, documented in a systematic reference format.

Where does this article fit in?

This article is the formal convergence point of the B series. Each construction explored individually — probabilities (B1), alphabets (B2), derivation (B3), flags (B4), polymetry (B5), homomorphisms (B6) — finds its exact place here in a single formal grammar.

It is also a direct application of L3: where L3 presented EBNF notation as an abstract tool, B10 uses it to specify a real language. Readers who master the EBNF conventions from L3 can read the productions in this article without further explanation.

B10 prepares B11 (BP3’s AST): each EBNF production corresponds to one or more node types in the abstract syntax tree. The EBNF defines what can be written; the AST defines how it is represented in memory.


Why is this important?

BP3 (Bol Processor 3, cf. I2) has existed since 1990, but its syntax has never been formalized in a complete EBNF grammar. Bernard Bel’s historical documentation describes constructions through examples and C source code — a pragmatic approach but insufficient for:

  • Implementing an alternative parser: without a formal grammar, one must read the C source code to understand what is syntactically valid.
  • Comparing BP3 with other languages: without specification, one cannot precisely measure BP3’s syntactic expressiveness against LilyPond, ABC notation, or TidalCycles.
  • Classifying BP3 in Chomsky’s hierarchy: the question “at what level of the hierarchy is BP3?” requires distinguishing the grammar of BP3 (its syntax) from the grammars within BP3 (what the user writes).

The EBNF we present here is, to our knowledge, the first complete formal specification of BP3 — and one of the few published EBNF grammars for an algorithmic composition language.

The idea in one sentence

BP3’s syntax is described in ~83 EBNF productions organized into 8 layers — global structure, grammar blocks, rules, 23 element types, special functions, templates, lexemes, and reference files — documented here in a systematic reference format (EBNFdoc).


Reading Convention (EBNFdoc format)

This article uses a systematic documentation format inspired by API references (Javadoc, MDN, Rust docs), adapted for EBNF productions. For each production:

  1. Production — the EBNF code (ISO 14977)
  2. Components — each terminal and non-terminal documented individually:
    • Exact name as it appears in the production
    • Type (INT, IDENT, non-terminal, literal)
    • Cardinality: required, optional ([ ]), repeatable ({ }, +)
    • Precise description
  3. Constraints — what EBNF cannot express (invariants, inter-production consistency)
  4. Source — reference to BP3’s C code when relevant (file:lines)
  5. Example — taken from test files (bp3-ctests/) when available

EBNF Notation Used (ISO 14977):

NotationMeaning
=Definition
,Concatenation
∣\vertAlternative
[ ... ]Optional (0 or 1)
{ ... }Repetition (0 or more)
... +Repetition (1 or more) — common extension
"..."Literal terminal
(* ... *)Comment

Layer 1 — Global Structure

bp_file

bp_file = { header } , grammar_section+ , [ template_section ] ;
  • [[#header]] (0..n) — headers preceding grammar blocks (comments, file references, initialization directives).
  • [[#grammar_section]] (1..n) — grammar blocks containing production rules. At least one block required.
  • [[#template_section]] (optional) — block of structural templates. Present only if at least one sub-grammar uses TEM mode.

Constraint: template_section can only appear if hasTEMP == TRUE (CompileGrammar.c:190).

header = comment | file_ref | init_directive ;

A header is exactly one of the following three types:

  • [[#comment]] — textual comment ignored by the parser.
  • [[#file_ref]] — reference to an external file (alphabet, settings, etc.).
  • [[#init_directive]] — initialization directive.

comment

comment = "//" , TEXT ;
  • "//" — comment start marker.
  • TEXT — free content until end of line. Ignored by the parser.

file_ref

file_ref = "-" , prefix , "." , name ;
  • "-" — file reference marker.
  • prefix : IDENT — prefix identifying the file type (see table below).
  • "." — separator.
  • name : IDENT — name of the referenced file (without extension).

Source: -BP3main.h:386-401 (FilePrefix[], FileExtension[], DocumentTypeName[])

Documented Prefixes (10):

PrefixDocumentTypeNameContentTest Occurrences
grGrammarMain grammar file (implicit)52
seSettingsTempo, MIDI channels, global configuration72
alAlphabetTerminals and MIDI or SynthDef mappings12
hoHomomorphismsNote → note substitution tables1
csCsoundCsound scores (external format)—
toTime-objectsReferences to time objects (sound, video, robot)—
tbTables/talasPredefined rhythmic structures20
soSound objectsSound-object definitions7
sc/+scScriptsExternal control scripts3
daData/itemsInternal data (items)26

Internal Prefixes (6):

PrefixDocumentTypeNameContentSource
kbKeyboardPhysical keyboard mapping to BP3 functions-BP3main.h:398
glGlossaryGlossary of terms and abbreviations-BP3main.h:398
inInteractionInteractive K parameters (dynamic weights <K1>, <K1=5>)-BP3main.h:398
mdMIDI driverMIDI driver configuration (ports, channels, timing)-BP3main.h:398
trTraceDebug log (derivations, rule applications)-BP3main.h:398
wgWeightsPredefined weight tables for RND/LIN modes-BP3main.h:398

Example:

-se.Tihai        (* loads the settings file "Tihai" *)
-al.Tabla        (* loads the alphabet "Tabla" *)

init_directive

init_directive = "INIT:" , TEXT ;
  • "INIT:" — initialization block marker.
  • TEXT — script command executed before derivation to initialize the environment (MIDI instrument, tempo, file reading, etc.). The content is passed to ExecScriptLine (CompileGrammar.c:222).

Constraint: certain script commands are forbidden in INIT: (e.g., opening a new project — ScriptUtils.c:102).

Examples:

INIT: MIDI program 110      (* selects MIDI instrument 110 *)
INIT: Play I46               (* plays interaction file I46 before derivation *)

Complete global structure example:

// Simple Tihai in ORD mode          ← comment
-se.Tihai                            ← file_ref (prefix=se, name=Tihai)
-al.Tabla                            ← file_ref (prefix=al, name=Tabla)
ORD[1]                               ← start grammar_section
gram#1[1] S --> |x| - |x| - |x|     ← rule
gram#1[2] |x| --> dha tirakita dhin  ← rule

Layer 2 — Grammar Blocks

grammar_section

grammar_section = mode_line , [ preamble ] , [ separator ] , rule+ ;
  • [[#mode_line]] — required. Declaration of the derivation mode and block index.
  • [[#preamble]] (optional) — special functions applied globally to the entire block before any rules.
  • [[#separator]] (optional) — line of dashes separating the preamble from the rules.
  • [[#rule]] (1..n) — production rules of the block. At least one rule required.

mode_line

mode_line = MODE , "[" , INT , "]" , [ IDENT ] ;
  • [[#MODE]] — required. Derivation mode of the block.
  • "[" , "]" — index delimiters.
  • [[#INT]] — required. Numerical index of the block (≥ 1). Identifies the block in gram#N references.
  • [[#IDENT]] (optional) — free label attached to the block. Does not affect derivation.

Constraint: The INT in mode_line must correspond to the N in the rule_prefix (gram#N) of the rules contained within this block.

Example: RND[2] MyBlock → RND mode, index 2, label MyBlock.

MODE

MODE = "ORD" | "RND" | "LIN" | "SUB" | "SUB1" | "TEM" | "POSLONG" ;

7 possible values:

ValueFull NameRule Selection StrategyArticle
ORDOrderedSequential, in order of declarationB3
RNDRandomWeighted random according to rules’ <N> weightsB1, B3
LINLinearCyclic (wrap-around: returns to first rule after last)B3
SUBSubstituteSimultaneous substitution of all occurrences of a non-terminalB3
SUB1Substitute firstSubstitution of the first occurrence only (leftmost)B3
TEMTemplatesSub-grammar intended for matching via the TEMPLATES: blockB3
POSLONGPositional longestLike SUB1, but selects the longest derivation (leftmost-longest match)B3

Source: -BP3main.h:125 (SubgramType[]), -BP3.h:875-881 (RNDtype=0 to POSLONGtype=6)

Constraints:

  • SUB, SUB1, and POSLONG modes prohibit /flag/ flags, _goto directives, and the “Produce all items” command (CompileGrammar.c:613-695, ProduceItems.c:757).
  • TEM mode has no specific selection logic in the computation engine (TEMtype defined but not referenced in Compute.c) — behavior is determined by the TEMP direction.

preamble

preamble = special_fn+ ;
  • [[#special_fn]] (1..n) — special functions applied globally before the block’s rules (e.g., _mm(120), _ins(Tabla)).

separator

separator = "----" , { "-" } ;
  • "----" — minimum 4 dashes.
  • "-" (0..n) — optional additional dashes (free length).

Layer 3 — Rules

rule

rule = rule_prefix , [ weight ] , [ DERIVATION_MODE ] , { flag } , lhs , ARROW , rhs , [ comment ] ;
  • [[#rule_prefix]] — required. Unique rule identifier (gram#N[M]).
  • [[#weight]] (optional) — probabilistic weight of the rule.
  • [[#DERIVATION_MODE]] (optional) — traversal direction for this rule (default: RND).
  • [[#flag]] (0..n) — conditions and variable modifications.
  • [[#lhs]] — required. Left-hand side (what is rewritten).
  • [[#ARROW]] — required. Arrow type (rule direction).
  • [[#rhs]] — required. Right-hand side (result of rewriting). Can be empty.
  • [[#comment]] (optional) — end-of-line comment.

Component Order: the order is strict. The DERIVATION_MODE comes after the weight and before the flags.

Source: Encode.c:103-725 (rule encoding)

Example: gram#3[1] <100> LEFT /x=1/ M16 <-> V16 // comment

rule_prefix

rule_prefix = "gram#" , INT , "[" , INT , "]" ;
  • "gram#" — rule marker.
  • [[#INT]] (1st) — required. Grammar number (N). Identifies the parent block.
  • "[" , "]" — delimiters.
  • [[#INT]] (2nd) — required. Rule number within the block (M).

Constraint: the 1st INT must correspond to the index of the parent grammar_section (that of mode_line).

Example: gram#3[47] → 47th rule of the 3rd block.

ARROW

ARROW = "-->" | "<->" | "<--" ;

3 possible values:

ValueNameDirectionActive in PRODActive in ANAL
-->ProductionLeft → rightyesno
<->BidirectionalBothyesyes
<--AnalysisRight → leftnoyes

Source: -BP3main.h:114 (MAXARROW=3), -BP3.h:886 (ARROWLENGTH=4)

Constraint: <-> is the most common value (217 occurrences in bp3-ctests). <-- does not appear in any test file — its actual use is an open question (cf. §13, Q4).

See also: B8 (PROD, ANAL, TEMP directions)

DERIVATION_MODE

DERIVATION_MODE = "LEFT" | "RIGHT" | "RND" ;

3 possible values. This mode is distinct from the block’s MODE (Layer 2):

  • MODE (block) = what selection strategy? (ORD, RND, LIN, SUB, SUB1, TEM, POSLONG)
  • DERIVATION_MODE (rule) = in what direction to traverse? (LEFT, RIGHT, RND)
ValueTraversal Direction
LEFTLeft to right (leftmost)
RIGHTRight to left (rightmost)
RNDRandom position (default if omitted)

Source: Encode.c:478-508, -gr.dhati:49, -gr.look-and-say

Example: gram#3[1] <100> LEFT M16 <-> V16 → left-to-right derivation.

weight

weight      = "<" , weight_expr , ">" ;
weight_expr = INT , [ "-" , INT ]
            | "K" , IDENT , [ "=" , INT ] ;
  • "<" , ">" : literals — weight delimiters.
  • weight_expr : one of the following forms:
FormComponentsSemanticsExample
INTsimple weightFixed weight. Shortcut for INT-0.<3>
INT - INTdecremented weight1st = initial value, 2nd = decrement per use.<50-12>
K IDENTbare KInteractive weight — user chooses dynamically.<K1>
K IDENT = INTK with valueRule active only if K-parameter IDENT equals INT.<K1=5>

Source: -gr.Mozart:34-44 (K with and without value)

See also: B4

flag

flag       = "/" , IDENT , [ FLAG_OP , flag_value ] , "/" ;
FLAG_OP    = "=" | "+" | "-" | ">" | "<"
           | "≥" | "≤" | "≠" ;
flag_value = INT | FLOAT
           | "K" , IDENT
           | IDENT ;
  • "/" — flag delimiters.
  • [[#IDENT]] — required. Variable (flag) name.
  • FLAG_OP (optional): operator. Absent = boolean switch.
  • flag_value (optional, required if FLAG_OP present): operation value.

Operators:

FLAG_OPSemantics
=Assignment or equality test
+Increment
-Decrement
>, <Strict comparison
≥, ≤, ≠Comparison (Unicode)

Forms of flag_value:

FormTypeSemanticsExample
INTINTLiteral integer value/x=5/
FLOATFLOATLiteral floating-point value/tempo=0.8/
K IDENT"K" + IDENTReference to an interactive K-parameter/a=Kb/
IDENTIDENTDirect reference to another flag (flag→flag)/a=otherflag/

Source: Encode.c:478-508 (flag-to-flag assignment with needsK and needsflag)

Examples:

  • /stop/ — boolean switch (no operator)
  • /section=1/ — test: rule applies only if section equals 1
  • /count+1/ — increment: count increases by 1 with each application
  • /a=Kb/ — cross-assignment via K-parameter
  • /a=otherflag/ — direct flag→flag assignment

See also: B4

Example combining block, rule, and control:

RND[2]                                   ← MODE=RND, INT=2
gram#2[1] <50-10> /section=1/ A --> do ré mi fa
gram#2[2] <30>    /section>2/ A --> sol la si do5
gram#2[3] <20>    A --> - - - -
  • Block in RND mode (weighted random selection, Layer 2).
  • Each rule uses ARROW = --> (production only).
  • Rule 1: weight = <50-10> (initial 50, decrement 10), flag = /section=1/ (active if section == 1).
  • Rule 2: weight = <30> (fixed), flag = /section>2/ (active if section > 2).
  • Rule 3: weight = <20> (fixed), no flag (always available).

Layer 4 — LHS and RHS Elements

lhs

lhs         = lhs_element+ ;
lhs_element = non_terminal | variable | wildcard | context_marker ;
  • lhs_element (1..n) — the left-hand side must contain at least one element. Each element is a [[#non_terminal]], [[#variable]], [[#wildcard]] or [[#context_marker]].

Constraint: when lhs contains more than one element, the rule becomes context-sensitive (Chomsky Type 1). The first element is the rewritten symbol, the following ones are the required context.

Context-sensitive example:

gram#3[47] |o| |miny| --> |o1| |miny|

|o| is rewritten to |o1| only if |miny| is adjacent. The |miny| in the RHS is a pass-through — it is transmitted without modification. This mechanism pushes BP3 beyond Type 2 (L1).

rhs

rhs = rhs_element* ;
  • [[#rhs_element]] (0..n) — the right-hand side can be empty (*), which corresponds to the erasure of a symbol (ε-production).

rhs_element

rhs_element = note | rest | prolongation | undetermined_rest
            | non_terminal | variable | wildcard
            | polymetric | special_fn | nil_string
            | pattern_expr | time_sig | annotation
            | quoted_symbol | tie
            | context_marker | goto_directive
            | out_time_object | sync_tag
            | speed_ratio | negation
            | beat_separator | start_symbol ;

23 possible types, organized into 4 families:

Figure 1 — The 23 types of BP3 RHS elements, organized into 4 families.


4.1 Terminals

note

note = NOTE_NAME , [ OCTAVE ] ;
  • [[#NOTE_NAME]] — required. Note name in one of the 4 notation systems.
  • [[#OCTAVE]] (optional) — digit indicating the octave (0-9). Default: octave defined in settings.

4 notation systems (-BP3.h:478-483):

SystemExamplesAlterations
Frenchdo, ré, mi, fa, sol, la, si# (sharp), b (flat)
Anglo-SaxonC, D, E, F, G, A, B#, b
Indiansa, re, ga, ma, pa, dha, nip (komal), d (tivra)
Keys (MIDI)60, 72, 48��� (direct MIDI numbers 0-127)

BP3 supports up to 100 custom scales (MAXCONVENTIONS=100) via _scale().

Constraint: Anglo-Saxon notes (C4, A8) are syntactically identical to non-terminals (UPPER_IDENT). The distinction is resolved at emission: undefined uppercase identifiers that match the pattern [A-G][#b]?\d are treated as notes. This is a syntactic ambiguity resolved by semantic context.

rest

rest = "-" ;
  • "-" — determined rest. Its duration is calculated by the temporal context.

Source: token T3/1 (BP2-info.txt)

prolongation

prolongation = "_" ;
  • "_" — prolongation. Extends the previous event without a new attack. The sound continues, no silence. Internal code: kobj=0 in FillPhaseDiagram.c.

Source: token T3/0 (BP2-info.txt)

undetermined_rest

undetermined_rest = "..." ;
  • "..." — undetermined rest. Duration calculated by the PolyMake algorithm to balance polymetric voices.

Source: token T3/0 (BP2-info.txt)

See also: B5, B13

non_terminal

non_terminal = UPPER_IDENT ;
  • [[#UPPER_IDENT]] — required. Identifier starting with an uppercase letter (S, Phrase, Tihai, A8).

4.2 Context-sensitive Extensions

variable

variable = "|" , IDENT , "|" ;
  • "|" — delimiters.
  • [[#IDENT]] — required. Variable name.

When |x| appears multiple times in the RHS, each occurrence is replaced by the same value — synchronized copy. This is the mechanism that pushes BP3 beyond Type 2 (B6).

wildcard

wildcard = "?" , [ INT ] ;
  • "?" — wildcard marker.
  • [[#INT]] (optional) — named capture index. Absent = anonymous wildcard.
FormPROD ModeANAL Mode
?Anonymous placeholderAccepts any terminal
?1Named capture — generates a patternCaptures a pattern and checks its consistency
?1 ... ?1Replication of the captured patternChecks that the same pattern appears at both positions

See also: B6, B8

nil_string

nil_string = "lambda" | "nil" | "empty" | "null" ;

4 equivalent forms for the empty production ε (erasure of a non-terminal).

Source: -BP3main.h:112

pattern_expr

pattern_expr = "(=" , rhs_element+ , ")"
             | "(:" , rhs_element+ , ")"
             | HOMO_REF ;
  • (= ...) — master: derives its content normally and freezes the result for linked slaves.
  • (: ...) — slave: copies the already derived result from the closest (= ...) master to the left whose syntactic content is identical. If a * homomorphism is defined in the alphabet, the slave applies the transformation before copying (→ pseudo-repetition).
  • HOMO_REF — reference to an external homomorphism file (-ho.).

Mechanism. The master/slave link is resolved at compilation by left-to-right linear search. Direct nesting is not supported — use intermediate non-terminals for nested patterns (e.g., chakkardar tihai).

Examples:

S --> (= A)(= B)(: A)(: B)(: A)     (* tihai: produces aabba if A→a, B→b *)
S --> (= A) (: A)                    (* strict copy: produces {ww} *)

See also: B6


4.3 Structural Constructions

polymetric

polymetric = "{" , [ ratio , "," ] , voice , { "," , voice } , "}" ;
ratio      = INT | INT "/" INT ;
voice      = rhs_element+ ;
  • "{" , "}" — polymetric block delimiters.
  • ratio (optional) — tempo factor. [[#INT]] alone = integer, [[#INT]]/[[#INT]] = fraction.
  • voice (1..n) — sequence of [[#rhs_element]] forming a voice. Multiple voices separated by ",".

Examples:

{do ré mi, sol la si do5}       (* 2 simultaneous voices, equal duration *)
{3, do ré mi fa sol la si}      (* tempo ratio: 3× *)
{2/3, mi fa sol}                (* fractional ratio *)

See also: B5, B12

time_sig

time_sig = TIME_SIG_PATTERN ;
  • [[#TIME_SIG_PATTERN]] — time signature.

annotation

annotation = "[" , TEXT , "]" ;
  • "[" , "]" — delimiters.
  • TEXT — free content. Metadata attached to the musical stream.

quoted_symbol

quoted_symbol = "'" , TEXT , "'" ;
  • "'" — delimiters.
  • TEXT — literal symbol transmitted as-is.

tie

tie = note , "&" | "&" , note ;
  • note & : tie start — the note is prolonged.
  • & note : tie continuation — the note is connected to the previous one.

Equivalent to the tie in Western musical notation.


4.4 Flow Control

context_marker

context_marker = "LEFT" ;
  • LEFT : forces the parser to consider only the left context.

Correction The original version of this article included (|symbol|), #({) and #(})as extendedcontext_marker`. These constructions do not exist in BP3’s source code. They have been removed.

goto_directive

goto_directive = "_goto(" , INT , "," , INT , ")" ;
  • [[#INT]] (1st) — required. Target block number (N).
  • [[#INT]] (2nd) — required. Target rule number (M).

Imperative jump to rule M of block N. Imperative flow control mechanism within a declarative formalism.

Constraint: forbidden in SUB, SUB1, and POSLONG blocks (Encode.c:363-365).

Source: 8 occurrences in bp3-ctests.

out_time_object

out_time_object = "<<" , ( note | IDENT ) , ">>" ;
  • "<<" , ">>" — out-of-time object delimiters.
  • [[#note]] — MIDI note played immediately out of the temporal flow (encoded as key + 16384).
  • [[#IDENT]] — reference to a sound-object in the alphabet (encoded as index).

Source: Encode.c:574-725 (token T7). The threshold 16384 distinguishes notes (x ≥ 16384 → x - 16384 = MIDI key) from sound-objects (x < 16384 → index).

sync_tag

sync_tag = "<<" , "W" , INT , ">>" ;
  • "<<" , ">>" — delimiters.
  • "W" — synchronization marker.
  • [[#INT]] — required. Synchronization point index.

Rendezvous mechanism between polymetric voices: <<W1>> in one voice waits for <<W1>> in another voice before continuing.

Source: token T8 (BP2-info.txt)

speed_ratio

speed_ratio = "/" , INT , "/"
            | "*" , INT
            | "**" , INT
            | "\" , INT ;

4 speed operators:

FormTokenSemantics
/N/T0/11Speed up — acceleration by factor N
*NT0/21Scale up — increase
**NT0/24Scale down — decrease
\NT0/25Speed down — deceleration by factor N

Source: BP2-info.txt:22,32,35, Encode.c:103-118

negation

negation = "#" ;
  • "#" — negation operator.

beat_separator

beat_separator = "." ;
  • "." — beat separator.

Source: token T0/7 (BP2-info.txt:18)

start_symbol

start_symbol = "S" ;
  • "S" — grammar start symbol.

Source: token T0/10 (BP2-info.txt:21)

concatenation — REMOVED

Correction The + is not a concatenation operator between symbols in the RHS. It only exists in the context of flags (/flag+1/), where it serves as an increment. It is not part of rhs_element. Misinterpretation of token T0/3 in the original version of this article.


Layer 5 — Special Functions

special_fn

special_fn = "_" , IDENT , [ "(" , args , ")" ] ;
args       = arg , { "," , arg } ;
arg        = INT | FLOAT | IDENT | STRING ;
  • "_" — mandatory prefix distinguishing special functions from grammatical elements.
  • [[#IDENT]] — required. Function name.
  • args (optional) — list of arguments separated by ",".
  • arg — a typed argument ([[#INT]], [[#FLOAT]], [[#IDENT]] or STRING).

BP3 defines 68 performance controls (tokens T10-T46 and T12/0-30) and 17 grammar procedures. They fall into 8 categories:

CategoryMain FunctionsNum argsLayer*
Pitch_transpose(N), _scale(name,base), _pitchbend(N), _pitchrange(N), _keyxpand(N1,N2)1-24
Velocity_vel(N), _volume(N), _rndvel(N)13
Articulation_staccato(N), _legato(N)13
Timing_mm(N), _tempo(ratio), _rndtime(N), _striated, _smooth0-15
Instruments_ins(name), _script(name), _chan(N), _part(N), _capture(N)12
MIDI_mod(N), _pitchbend(N), _press(N), _pan(N), _switchon(cc,value), _switchoff(cc,value)1-22
Structure_retro, _rotate(N), _randomize, _destru, _srand(N)0-14
Derivation_goto(N,M), _failed(N,M), _repeat(N), _stop0-25

*Layer numbers refer to the musical abstraction model (M12).

Source: StringLists.h:265-335 (function declarations with number of arguments)

Constraint: each continuous control (velocity, modulation, pitch bend, etc.) exists in 3 variants: _xxxstep (step), _xxxcont (interpolation), _xxxfixed (fixed value). These variants are MIDI implementation details.

Example:

ORD[1]
_mm(120)                             ← preamble: global tempo 120 BPM
_ins(Tabla)                          ← preamble: Tabla instrument
gram#1[1] S --> _vel(80) Tihai       ← _vel(80) applies locally

Layer 6 — Templates

template_section

template_section = "TEMPLATES:" , template_def+ ;
  • "TEMPLATES:" — section start marker.
  • [[#template_def]] (1..n) — template definitions.

Constraint: appears only if at least one sub-grammar has TEM mode and if hasTEMP == TRUE (CompileGrammar.c:190).

template_def

template_def = "[" , INT , "]" , template_pattern ;
  • "[" , "]" — index delimiters.
  • [[#INT]] — required. Template index.
  • [[#template_pattern]] — the structural skeleton.

template_pattern

template_pattern = { time_sig | speed_ratio | placeholder
                   | "(" , "@" , INT , template_body , ")"
                   | rhs_element } ;
  • [[#time_sig]] (0..n) — time signature.
  • [[#speed_ratio]] (0..n) — speed ratio (*1/1, *1/2).
  • [[#placeholder]] (0..n) — substitution position.
  • (@N ...) (0..n) — group referencing the sub-grammar of index N. [[#INT]] = sub-grammar index, [[#template_body]] = content.
  • [[#rhs_element]] (0..n) — ordinary RHS elements.

placeholder

placeholder = "_"+ ;
  • "_" (1..n) : one or more consecutive underscores. In the context of templates, _ retains its prolongation semantics (T3/0, kobj=0) — the same semantics as everywhere else in the language. There is no double semantics.

The TEMPLATES: section is ignored by the compiler (CompileGrammar.c:437-443). It serves as structural documentation, not executable code.

template_body

template_body = { placeholder | rhs_element } ;

Source: -gr.checktemplates, -gr.dhin-- (bp3-ctests)

Example:

TEMPLATES:
[1] *1/1 __*1/2 _
[5] *1/1 (@0 _)(@1 )
[1] 4+4*1/6 (@0 (@0 (@0 ______) * (@1 ))(@2 ))____ * (@3 )____

Layer 7 — Lexemes

IDENT

IDENT = letter , { letter | digit | "_" } ;
  • letter : lowercase or uppercase letter.
  • digit : digit 0-9.
  • "_" : underscore allowed in the body.

UPPER_IDENT

UPPER_IDENT = upper_letter , { letter | digit | "_" } ;
  • upper_letter : uppercase letter (A-Z). First position must be uppercase.

Used for non-terminals.

INT

INT = digit+ ;
  • digit (1..n) : one or more digits 0-9.

FLOAT

FLOAT = [ "-" ] , digit+ , "." , digit+ ;
  • "-" (optional) : negative sign.
  • digit+ : integer part.
  • "." : decimal separator.
  • digit+ : fractional part.

NOTE_NAME

NOTE_NAME    = FRENCH_NOTE | ANGLO_NOTE | INDIAN_NOTE | KEY_NOTE ;
KEY_NOTE     = INT ;
FRENCH_NOTE  = ("do"|"ré"|"re"|"mi"|"fa"|"sol"|"la"|"si") , [alteration] ;
ANGLO_NOTE   = ("C"|"D"|"E"|"F"|"G"|"A"|"B") , [alteration] ;
INDIAN_NOTE  = ("sa"|"re"|"ga"|"ma"|"pa"|"dha"|"ni") , [alteration_in] ;
alteration   = "#" | "b" ;
alteration_in = "p" | "d" ;

4 notation systems that produce the same AST node type (Note). The parser must recognize 4 musical alphabets simultaneously.

OCTAVE

OCTAVE = digit ;
  • digit : a single digit 0-9.

TIME_SIG_PATTERN

TIME_SIG_PATTERN = INT , { "+" , INT } , "/" , INT ;
  • [[#INT]] (1..n) — numerator(s). Multiple numerators added together separated by "+".
  • "/" — separator.
  • [[#INT]] — denominator.

Example: 4+4*1/6 → composite time signature.


Layer 8 — Reference Files

Preliminary formalization of the 5 most used formats. These EBNFs are derived from the analysis of the C source code and the 213 test files — they have not been exhaustively validated.

settings_file (-se.)

settings_file = { settings_line } ;
settings_line = key , ":" , value ;
key           = "tempo" | "channel" | "velocity" | "transpose"
              | "pitchbend_range" | IDENT ;
value         = INT | FLOAT | STRING ;

Key-value pairs configuring global parameters (tempo, MIDI channel, initial velocity, transposition).

alphabet_file (-al.)

alphabet_file  = { alphabet_entry } ;
alphabet_entry = terminal , mapping ;
terminal       = NOTE_NAME | IDENT ;
mapping        = midi_mapping | synthdef_mapping ;
midi_mapping   = INT ;
synthdef_mapping = "SynthDef(" , STRING , ")" ;

Correspondence between terminals and sound events (MIDI or SuperCollider SynthDefs).

homo_file (-ho.)

homo_file  = { homo_entry } ;
homo_entry = source_note , "-->" , target_note ;
source_note = NOTE_NAME ;
target_note = NOTE_NAME ;

Note → note substitution tables (B6).

csound_file (-cs.)

csound_file = CSOUND_SCORE ;

External Csound format — transmitted directly to the synthesis engine, not parsed by BP3.

timeobj_file (-to.)

timeobj_file  = { timeobj_entry } ;
timeobj_entry = IDENT , ":" , resource_ref ;
resource_ref  = file_path | url | device_ref ;

Correspondence between identifiers and external resources (audio files, videos, robotic commands). See B9.

Note: the formalization of reference files constitutes an original contribution: no published document provides a formal grammar for these auxiliary formats. These EBNFs are preliminary.


Meta — Grammar of BP3 vs. Grammars within BP3

The EBNF above (~83 productions) is the grammar of the BP3 language — it describes what a well-formed BP3 file can syntactically contain. It is a context-free grammar (Chomsky Type 2, L1).

BP3 files themselves contain grammars — the gram#N[M] rules written by the user. These internal grammars, thanks to variables, wildcards, homomorphisms, and multi-symbol LHS rules, are more powerful than Type 2: they reach the MCSL level (Mildly Context-Sensitive Languages — L9).

Figure 2 — Two levels of grammar: the grammar of BP3 (meta-level, Type 2) and the grammars within BP3 (object-level, Type 2+).


Limitations of EBNF

An EBNF grammar specifies the syntax — what constitutes a well-formed BP3 file. It does not cover:

Semantics. EBNF states that <50-12> is a valid weight, but not what “decrement by 12” means. See L6 (operational semantics), L7 (denotational semantics).

Derivation strategy. EBNF states that ORD and RND are valid modes, but not how the engine selects and applies rules. See B3.

Inter-production constraints. EBNF cannot express that the INT of rule_prefix must correspond to the index of the parent grammar_section. These invariants fall under AST specification (B11).

EBNF is a necessary but not sufficient condition: a file can be syntactically correct yet invalid (inconsistent numbers, undefined terminals, unbound variables). A real parser needs a validation phase after parsing — the 4th phase of the pipeline (B7).


Summary

LayerProductionsContentArticles
1. Global Structure5File, headers, 16 prefixes, directivesB7
2. Grammar Blocks57 modes, preamble, separatorB3
3. Rules83 arrows, 3 derivation modes, weights (K), flags (Unicode)B1, B4
4. LHS/RHS Elements23Notes, rests, polymetry, variables, wildcards, out-time, sync, T0 opsB2 to B6
5. Special Functions368 perf controls + 17 grammar procedures in 8 categoriesM12
6. Templates5TEMPLATES: section, placeholders, groups (@N)B8
7. Lexemes~14Identifiers, 4 note systems, numbersB2
8. Reference Files~10Settings, alphabet, homo, Csound, time-objectsB9
Total~83

Key Takeaways

  • BP3 is described in ~83 EBNF productions organized into 8 layers: global structure, grammar blocks, rules, LHS/RHS elements, special functions, templates, lexemes, reference files.
  • The EBNFdoc format systematically documents each production: typed components, cardinality, constraints, C source, examples.
  • 7 sub-grammar modes (ORD, RND, LIN, SUB, SUB1, TEM, POSLONG) determine the rule selection strategy at the block level.
  • 3 arrows (-->, <->, <--) control in which directions (PROD, ANAL) each rule is active.
  • 3 derivation modes per rule (LEFT, RIGHT, RND) control the traversal direction — a distinct level from the block mode.
  • 23 types of RHS elements give the language its flexibility: from notes and rests to context-sensitive variables, polymetry, sync tags, and special functions.
  • 68 performance controls and 17 grammar procedures form a performative layer that operates on 4 levels of abstraction.
  • The grammar of BP3 (this EBNF) is context-free (Type 2). The grammars within BP3 (written by the user) are Type 2+ (MCSL) thanks to variables, wildcards, and context-sensitive rules.
  • EBNF is a necessary but not sufficient condition: a real parser needs additional invariants (B11) and a validation phase (B7).

What’s Next?

EBNF is the architect’s blueprint — it tells what parts exist and how they fit together. The next step is to understand what the parser builds from this blueprint: the Abstract Syntax Tree (AST), with its 29 node types, its invariants, and its production-by-production correspondence with the EBNF. This is the subject of B11.


Glossary

  • ARROW: Type of arrow in a BP3 rule (-->, <->, <--). Determines in which directions (PROD, ANAL) the rule is active.
  • DERIVATION_MODE: Traversal direction for an individual rule (LEFT, RIGHT, RND). Distinct from the block’s MODE.
  • EBNFdoc: Systematic documentation format for EBNF productions, inspired by API references (Javadoc, MDN). Each production is documented with its typed components, constraints, C source, and examples.
  • Flag: Conditional variable attached to a rule (/name=value/). Controls activation and modifies the derivation state.
  • grammar_section: Grammar block containing a mode, an optional preamble, and rules.
  • K-parameter: Interactive weight (<K1>, <K1=5>) allowing the user to dynamically control rule selection.
  • LHS (Left-Hand Side): Left side of a rule — what is rewritten. Must contain at least one element.
  • MCSL (Mildly Context-Sensitive Languages): Class of languages between Type 2 (context-free) and Type 1 (context-sensitive). Position of grammars written within BP3.
  • MODE: Derivation mode of a grammar block (ORD, RND, LIN, SUB, SUB1, TEM, POSLONG). Determines the rule selection strategy.
  • Out-time object: <<...>> element played immediately, outside the normal temporal flow. Can be a MIDI note or a sound-object.
  • Performance control: Special function (_name(args)) controlling sound rendering (pitch, velocity, timing, etc.). 68 functions defined in BP3.
  • Weight: Numerical value <N> or <N-M> controlling the probability of rule selection in RND mode.
  • RHS (Right-Hand Side): Right side of a rule — the result of rewriting. Can be empty (ε-production). 23 possible element types.
  • rule_prefix: Unique identifier of a rule (gram#N[M]). N = block index, M = rule index within the block.
  • Sync tag: Synchronization point <<WN>> between polymetric voices. Rendezvous mechanism.
  • Template: Structural skeleton pre-calculated by the TEMP direction. Stored in the TEMPLATES: block.

Prerequisites

Direct Continuation

Connections

  • B7 (complete pipeline)
  • B8 (PROD, ANAL, TEMP)
  • B9 (-to. files)
  • B12 (symbolic time and _tempo())
  • L1 (classification)
  • L9 (MCSL)
  • M12 (abstraction layers)
  • R2 (detailed technical version)

Back


References

[Bel1990] Bel, B. (1990). Bol Processor BP1 and its music features. GRTC Research Report, Marseille.

[Bel1992] Bel, B. (1992). Symbolic and Sonic Representations of Sound-Object Structures. In M. Balaban, K. Ebcioğlu & O. Laske (Eds.), Understanding Music with AI, AAAI Press.

[Bel1998] Bel, B. (1998). Migrating musical concepts: an overview of the Bol Processor. Computer Music Journal, 22(2), 56-64.

[Bel2001] Bel, B. (2001). Rationalizing Musical Time: Syntactic and Symbolic-Numeric Approaches. In C. Music (Ed.), The Ratio Book, Den Haag: Royal Conservatory.

[ISO14977] ISO/IEC 14977:1996. Information technology — Syntactic metalanguage — Extended BNF.

[Chomsky1956] Chomsky, N. (1956). Three Models for the Description of Language. IRE Transactions on Information Theory, 2(3), 113-124.

[Kippen1992] Kippen, J. & Bel, B. (1992). Modelling Music with Grammars: Formal Language Representation in the Bol Processor. In A. Marsden & A. Pople (Eds.), Computer Representations and Models in Music, Academic Press.

[AhoUllman1972] Aho, A. V. & Ullman, J. D. (1972). The Theory of Parsing, Translation, and Compiling. Prentice-Hall.


Prerequisites: L3 (EBNF), B1 to B6 (BP3 constructions) Reading time: 20 min Tags: #EBNF #BP3 #specification #reference #EBNFdoc #formal-grammar


← Back to index