S8) Patterns, Captures, and Templates

Advanced Pattern Matching Mechanisms

Simple rules (S -> A B C) are everyday fare. But when music demands structural transformations — inversions, permutations, recurring patterns with variations — more powerful tools are needed.

Where does this article fit in?

This article covers BPscript’s advanced mechanisms, all inherited from BP3. For the foundations in BP3, see B6. Here we will see how BPscript exposes them with its own syntax.


Before going into detail, let’s clarify three mechanisms that are easily confused, as all three resemble “variables.” They actually address three distinct needs — and do not act at the same time relative to derivation:

  • ? (wildcard)capture what is already there and re-inject it. Acts on a string already produced by a previous derivation.
  • |x| (variable)derive content once during derivation, then repeat it identically.
  • $ / & (homomorphism) — repeat a pattern by transforming it: the structure is laid out during derivation, then the transformation is applied to the derived pattern.

We will look at them in this order.


Wildcards ? — capture what is there, re-inject it

Sometimes, we want a rule to apply regardless of the concrete symbol, or to move a fragment without having to name it. This is the role of wildcards ?, numbered ?1, ?2… They function like the capture groups of a regular expression: to the left of ->, ?1 captures what is present; to the right, it re-injects it.

Echo — a complete scene where a pattern is captured between two boundaries and replayed:

 

@mode:ord
S -> debut motif fin
motif -> Sa Re Ga
-----
@mode:ord
debut ?1 fin -> ?1 ?1

 

Output: Sa Re Ga Sa Re Ga?1 captures what was derived between debut and fin (here Sa Re Ga) and replays it; the boundaries are consumed.

The same number refers to the same content: ?1 on the right is equal to what ?1 captured on the left. A permutation, for example, is written ?1 ?2 -> ?2 ?1 (“Sa Re” → “Re Sa”, regardless of the two notes). The compiler translates ?n to BP3’s metavariables (rewrite variables).

When? The wildcard acts as a rewrite rule applied to a string already produced by a previous derivation: it captures and re-injects, without deriving anything itself. It is the tool for local transformations: permuting, replacing, adjusting a parameter regardless of the symbol concerned.


Variables |x| — derive once, repeat identically

A context-free grammar (CFG) cannot say “do exactly the same thing again.” Yet this is ubiquitous in music: the tihāī (a pattern repeated three times to conclude a cycle), a refrain, an echo response. This is the role of the variable |x|.

|x| is neither a terminal nor a non-terminal: it is a binding. When? Everything happens during derivation: the first occurrence is derived (via the grammar), its result is frozen, and each subsequent |x| replays that content identically.

 

@mode:ord
S -> |x| - |x| - |x|
|x| -> Sa Re Ga

 

Output: Sa Re Ga - Sa Re Ga - Sa Re Ga|x| is derived once as Sa Re Ga, then replayed twice identically, separated by rests: a tihāī.

Variable ≠ non-terminal — a non-terminal (S, A) is re-derived independently at each appearance: three As can yield three different results. A variable |x| is derived only once; subsequent occurrences are exact copies of it. And the pipes |…| are written at each occurrence — there is no “declaration” followed by a bare name.

This is precisely what goes beyond context-free: requiring an exact copy (the language ww, a word followed by its copy) is not expressible by a CFG (see B6).


Homomorphisms $ and & — repeat by transforming

Where the variable |x| repeats identically, the homomorphism repeats by transforming. An homomorphism is a transformation that preserves structure and applies symbol by symbol.

In BPscript: $X is the master pattern, &X is its reprise, and a substitution table is attached to the reprise with [sub:table]. The table — in lib/sub.json — specifies how to transform each symbol:

 

@mode:ord
S -> $X tin &X[sub:abc]
X -> a b c

 

Output: a b c tin a' b' c' — the master pattern a b c, a tin, then its reprise where each symbol is substituted according to the abc table (a→a', b→b', c→c'). Without [sub:…], the reprise would be identical to the master (a b c tin a b c).

A table encodes any symbol-to-symbol transformation: transposition, inversion, or — a classic case in tabla — the change from resonant strokes to dry strokes (dha��ta, dhin→tin).

Current Status: the [sub:…] substitution is defined in the language (tables in lib/sub.json) but is not yet wired into the pipeline — currently, the reprise replays identically. We are exposing the principle here.

$X and &X are RHS elements: they are written in any rule, independently of the arrow (->, <-, <>). The master can also be an inline group (${a b c} / &{a b c}); parentheses are only used for reprise parameters (&X(tempo:60)).

Rules:

  • $X is always the master pattern, wherever it appears;
  • &X is always a reprise (slave); multiple &Xs can refer to the same $X.

When? The structure — where the pattern repeats — is laid out during derivation; the transformation that distinguishes the reprise from the original (transpose, invert, retrograde) is applied to the pattern once derived. In BPscript’s design, this resolution is delegated downstream (see B6).

This is the tool for musical forms — ABA, rondo, theme and variations — where the same pattern reappears, transformed. (Formally, a morphism of free monoids: a transformation that respects concatenation.)


Contexts () and #() — conditions on neighbors

A context is a condition for rule application. During derivation, when the engine seeks to apply a rule, it first checks the context: the rule only applies if the symbol’s neighbors match. The context is only tested — never modified or produced.

Positive Context

 

@mode:ord
S -> Pa Dha Re Dha
-----
@mode:ord
(Pa) Dha -> Dha Ni Sa

 

Output: Pa Dha Ni Sa Re Dhaonly the first Dha (preceded by Pa) expands to Dha Ni Sa; the second (preceded by Re) remains unchanged. Pa is tested, not consumed: it remains in the output. This is the context sensitivity of a raga — the same note is prolonged differently depending on what precedes it.

Negative Context

 

@mode:ord
S -> Sa Ga Re Ga
-----
@mode:ord
#(Sa) Ga -> Ga Pa

 

Output: Sa Ga Re Ga Pa#(Sa) means “unless preceded by Sa”: the Ga immediately after the tonic is left as is; the other Ga expands to Ga Pa.

Combination

Both sides can be combined: (Pa) Dha #(Sa) -> Dha Ni only applies the rule if Dha is preceded by Pa and not followed by Sa.

Contexts are the tool for context-sensitivity (see L1). They allow for the construction of grammars whose rules depend on the local environment — which makes BP3 grammars more powerful than simple context-free grammars (CFG, Chomsky Type 2).


Summary: Which Tool for Which Need?

Need Tool Example
Capture a present symbol, re-inject it wildcard ? ?1 ?2 -> ?2 ?1
Repeat a pattern identically variable $\vert$x$\vert$ S -> $\vert$x$\vert$ - $\vert$x$\vert$
Repeat a pattern by transforming it

homomorphism `# S8) Patterns, Captures, and Templates

Advanced Pattern Matching Mechanisms

Simple rules (S -> A B C) are everyday fare. But when music demands structural transformations — inversions, permutations, recurring patterns with variations — more powerful tools are needed.

Where does this article fit in?

This article covers BPscript’s advanced mechanisms, all inherited from BP3. For the foundations in BP3, see B6. Here we will see how BPscript exposes them with its own syntax.


Before going into detail, let’s clarify three mechanisms that are easily confused, as all three resemble “variables.” They actually address three distinct needs — and do not act at the same time relative to derivation:

  • ? (wildcard)capture what is already there and re-inject it. Acts on a string already produced by a previous derivation.
  • |x| (variable)derive content once during derivation, then repeat it identically.
  • $ / & (homomorphism) — repeat a pattern by transforming it: the structure is laid out during derivation, then the transformation is applied to the derived pattern.

We will look at them in this order.


Wildcards ? — capture what is there, re-inject it

Sometimes, we want a rule to apply regardless of the concrete symbol, or to move a fragment without having to name it. This is the role of wildcards ?, numbered ?1, ?2… They function like the capture groups of a regular expression: to the left of ->, ?1 captures what is present; to the right, it re-injects it.

Echo — a complete scene where a pattern is captured between two boundaries and replayed:

 

 

Output: Sa Re Ga Sa Re Ga?1 captures what was derived between debut and fin (here Sa Re Ga) and replays it; the boundaries are consumed.

The same number refers to the same content: ?1 on the right is equal to what ?1 captured on the left. A permutation, for example, is written ?1 ?2 -> ?2 ?1 (“Sa Re” → “Re Sa”, regardless of the two notes). The compiler translates ?n to BP3’s metavariables (rewrite variables).

When? The wildcard acts as a rewrite rule applied to a string already produced by a previous derivation: it captures and re-injects, without deriving anything itself. It is the tool for local transformations: permuting, replacing, adjusting a parameter regardless of the symbol concerned.


Variables |x| — derive once, repeat identically

A context-free grammar (CFG) cannot say “do exactly the same thing again.” Yet this is ubiquitous in music: the tihāī (a pattern repeated three times to conclude a cycle), a refrain, an echo response. This is the role of the variable |x|.

|x| is neither a terminal nor a non-terminal: it is a binding. When? Everything happens during derivation: the first occurrence is derived (via the grammar), its result is frozen, and each subsequent |x| replays that content identically.

 

 

Output: Sa Re Ga - Sa Re Ga - Sa Re Ga|x| is derived once as Sa Re Ga, then replayed twice identically, separated by rests: a tihāī.

Variable ≠ non-terminal — a non-terminal (S, A) is re-derived independently at each appearance: three As can yield three different results. A variable |x| is derived only once; subsequent occurrences are exact copies of it. And the pipes |…| are written at each occurrence — there is no “declaration” followed by a bare name.

This is precisely what goes beyond context-free: requiring an exact copy (the language ww, a word followed by its copy) is not expressible by a CFG (see B6).


Homomorphisms $ and & — repeat by transforming

Where the variable |x| repeats identically, the homomorphism repeats by transforming. An homomorphism is a transformation that preserves structure and applies symbol by symbol.

In BPscript: $X is the master pattern, &X is its reprise, and a substitution table is attached to the reprise with [sub:table]. The table — in lib/sub.json — specifies how to transform each symbol:

 

 

Output: a b c tin a' b' c' — the master pattern a b c, a tin, then its reprise where each symbol is substituted according to the abc table (a→a', b→b', c→c'). Without [sub:…], the reprise would be identical to the master (a b c tin a b c).

A table encodes any symbol-to-symbol transformation: transposition, inversion, or — a classic case in tabla — the change from resonant strokes to dry strokes (dha��ta, dhin→tin).

Current Status: the [sub:…] substitution is defined in the language (tables in lib/sub.json) but is not yet wired into the pipeline — currently, the reprise replays identically. We are exposing the principle here.

$X and &X are RHS elements: they are written in any rule, independently of the arrow (->, <-, <>). The master can also be an inline group (${a b c} / &{a b c}); parentheses are only used for reprise parameters (&X(tempo:60)).

Rules:

  • $X is always the master pattern, wherever it appears;
  • &X is always a reprise (slave); multiple &Xs can refer to the same $X.

When? The structure — where the pattern repeats — is laid out during derivation; the transformation that distinguishes the reprise from the original (transpose, invert, retrograde) is applied to the pattern once derived. In BPscript’s design, this resolution is delegated downstream (see B6).

This is the tool for musical forms — ABA, rondo, theme and variations — where the same pattern reappears, transformed. (Formally, a morphism of free monoids: a transformation that respects concatenation.)


Contexts () and #() — conditions on neighbors

A context is a condition for rule application. During derivation, when the engine seeks to apply a rule, it first checks the context: the rule only applies if the symbol’s neighbors match. The context is only tested — never modified or produced.

Positive Context

 

 

Output: Pa Dha Ni Sa Re Dhaonly the first Dha (preceded by Pa) expands to Dha Ni Sa; the second (preceded by Re) remains unchanged. Pa is tested, not consumed: it remains in the output. This is the context sensitivity of a raga — the same note is prolonged differently depending on what precedes it.

Negative Context

 

 

Output: Sa Ga Re Ga Pa#(Sa) means “unless preceded by Sa”: the Ga immediately after the tonic is left as is; the other Ga expands to Ga Pa.

Combination

Both sides can be combined: (Pa) Dha #(Sa) -> Dha Ni only applies the rule if Dha is preceded by Pa and not followed by Sa.

Contexts are the tool for context-sensitivity (see L1). They allow for the construction of grammars whose rules depend on the local environment — which makes BP3 grammars more powerful than simple context-free grammars (CFG, Chomsky Type 2).


Summary: Which Tool for Which Need?

Need Tool Example
Capture a present symbol, re-inject it wildcard ? ?1 ?2 -> ?2 ?1
Repeat a pattern identically variable $\vert$x$\vert$ S -> $\vert$x$\vert$ - $\vert$x$\vert$
Repeat a pattern by transforming it homomorphism / &[sub:…] | S -> $X &X[sub:abc]`
Condition by neighbors context () (A) C -> D E
Exclude a neighbor negation #() #(X) Z -> W

Key Takeaways

  1. ? wildcards — capture a symbol already present and re-inject it (capture groups); local transformations
  2. |x| variables — derive content only once and repeat it identically (tihāī); to be distinguished from non-terminals, which are re-derived each time
  3. $/& homomorphisms — repeat a pattern by transforming it (master/slave → (=)/(:)); musical forms (ABA, theme and variations)
  4. () is a condition for rule application (positive neighborhood), #() its negation — tested during derivation
  5. These mechanisms make BPscript grammars more powerful than CFGs — they are context-sensitive (Type 1+)

Glossary

  • Wildcard: joker ? / ?n that captures a symbol already present (on the left) and re-injects it (on the right) — like a regular expression capture group
  • Variable: |x| — a binding whose first occurrence derives content and freezes it; subsequent occurrences replicate it identically. Distinct from a non-terminal, which is re-derived independently each time
  • Homomorphism: a structure-preserving transformation, denoted $ (master) and & (reprise) → (=) / (:) in BP3; the reprise applies a substitution table via [sub:table] (lib/sub.json) that transforms each symbol (transposition, minorization, resonant strokes→dry strokes…)
  • Context: a condition for rule application, based on neighboring symbols — positive (A B) or negative #(A B) — tested during derivation, never modified
  • Context-sensitive: a grammar whose rules depend on the local environment of the rewritten symbol (Chomsky Type 1)

Links in the Series

  • S5 — Derivation directions and the _ prolongation
  • S6 — Guards [] as another conditional mechanism (on global state, not neighbors)
  • B6 — Homomorphisms, variables, and context in BP3
  • L1 — Context-free vs context-sensitive in Chomsky’s hierarchy

Prerequisites: S5, B6
Reading time: 12 min
Tags: #BPscript #pattern-matching #homomorphisms #templates #BP3


Next article: S9 (coming soon) — The Six Layers: From Note to Sound


Back to index