Macros
Macros let a grammar defer part of its accepted vocabulary to runtime. Instead of hard-coding every possible value into the grammar, the grammar references a macro name, and the host application supplies the valid choices dynamically.
A macro is a named placeholder in the grammar. Its valid runtime choices come from a resolver registered by the host application.
Canonical syntax
${available_tasks}
${environmentNames}
${reportTemplates}
The canonical form is ${macroName}. The macro name is matched exactly against the registry. This lookup is case-sensitive.
Legacy syntax
<available_tasks>
Some environments may still preserve legacy angle-bracket syntax for backward compatibility. Use it only when you need compatibility with older grammars. New definitions should prefer ${...}.
Case sensitivity rules
- The relation between the grammar and the macro registry is case-sensitive.
- The relation between a macro choice and user input is case-insensitive token by token.
That means ${available_tasks} and ${Available_Tasks} are different macro references, while a registered choice such as full backup may still match user input written as FULL BACKUP.
Multi-word values
Macro choices may contain multiple tokens. The engine tokenizes each available choice and compares it against the current input position.
When choices share a prefix, the engine should prefer the longest matching choice in token count. This keeps overlapping choices deterministic.
Registered choices:
- backup
- full backup
- COMPLEX.TASK
Input:
EXECUTE full backup ON db01 ;
Quoted macro values
A quoted macro choice still binds its normalized semantic value. The outer quotes are not part of the bound value, and doubled apostrophes inside the quoted text become literal apostrophes.
Registered choice: 'COMPLEX.TASK'
Input: EXECUTE 'COMPLEX.TASK' ;
Bound value: COMPLEX.TASK
Dynamic resolution
Macro resolution happens during parsing, not during grammar compilation. This allows the host application to expose a runtime-controlled vocabulary while keeping the grammar structure itself stable.
For a given registry state and input, macro resolution is expected to remain deterministic.
Invalid and empty choices
- Blank or whitespace-only choices are ignored.
- Duplicate choices should be deduplicated deterministically.
- An unknown macro or a macro that yields no usable choices behaves as if no match were available at that position.
Canonical example
EXECUTE ${available_tasks} ON target_name ;
EXECUTE full backup ON db01 ;
EXECUTE backup ON db01 ;
EXECUTE 'COMPLEX.TASK' ON db01 ;
Authoring guidance
Use macros when the accepted values belong to a dynamic registry, not when the grammar should expose a stable fixed vocabulary. If the domain language itself is fixed, declare explicit keywords instead.