This package offers both a portable {py3} module and a command-line
tool.
-WARNING: This version of Normand is 0.10, meaning both the Normand
+WARNING: This version of Normand is 0.11, meaning both the Normand
language and the module/CLI interface aren't stable.
ifdef::env-github[]
6f 6d cc aa bb 7a 6f 6f 6d cc de de de de ┆ om•••zoom•••••
----
+Macros::
++
+Input:
++
+----
+!macro hello(world)
+ "hello"
+ !if world " world" !end
+!end
+
+!repeat 17
+ ff ff ff ff
+ m:hello({ICITTE > 15 and ICITTE < 60})
+!end
+----
++
+Output:
++
+----
+ff ff ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 6c ┆ ••••hello••••hel
+6c 6f ff ff ff ff 68 65 6c 6c 6f 20 77 6f 72 6c ┆ lo••••hello worl
+64 ff ff ff ff 68 65 6c 6c 6f 20 77 6f 72 6c 64 ┆ d••••hello world
+ff ff ff ff 68 65 6c 6c 6f 20 77 6f 72 6c 64 ff ┆ ••••hello world•
+ff ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 6c 6c ┆ •••hello••••hell
+6f ff ff ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 ┆ o••••hello••••he
+6c 6c 6f ff ff ff ff 68 65 6c 6c 6f ff ff ff ff ┆ llo••••hello••••
+68 65 6c 6c 6f ff ff ff ff 68 65 6c 6c 6f ff ff ┆ hello••••hello••
+ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 6c 6c 6f ┆ ••hello••••hello
+ff ff ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 6c ┆ ••••hello••••hel
+6c 6f ff ff ff ff 68 65 6c 6c 6f ┆ lo••••hello
+----
+
Precise error reporting::
+
----
----
+
----
-/tmp/meow.normand:24:19 - Illegal (unknown or unreachable) variable/label name `meow` in expression `(meow - 45) // 8`; the legal names are {`mix`, `zoom`}.
+/tmp/meow.normand:24:19 - Illegal (unknown or unreachable) variable/label name `meow` in expression `(meow - 45) // 8`; the legal names are {`ICITTE`, `mix`, `zoom`}.
----
+
----
-/tmp/meow.normand:18:9 - Value 315 is outside the 8-bit range when evaluating expression `end - ICITTE` at byte offset 45.
+/tmp/meow.normand:18:9 - Value 315 is outside the 8-bit range when evaluating expression `end - ICITTE`.
----
You can use Normand to track data source files in your favorite VCS
number>>, <<leb-128-integer,LEB128 integer>>,
<<variable-assignment,variable assignment>>,
<<conditional-block,conditional block>>, <<repetition-block,repetition
-block>>, and <<post-item-repetition,post-item repetition>> expression
-evaluation.
+block>>, <<macro-expansion,macro expansion>>, and
+<<post-item-repetition,post-item repetition>> expression evaluation.
Each generated byte increments the current offset.
* A <<repetition-block,repetition block>>.
+* A <<macro-definition-block,macro definition block>>.
+
+* A <<macro-expansion,macro expansion>>.
+
Moreover, you can repeat many items above a constant or variable number
of times with the ``pass:[*]`` operator _after_ the item to repeat. This
is called a <<post-item-repetition,post-item repetition>>.
+
--
* The name of any <<label,label>> defined before{nbsp}__**L**__.
-* The name of any <<variable-assignment,variable>> known at{nbsp}__**L**__
- which doesn't, directly or indirectly, refer to a label
- defined after{nbsp}__**L**__.
+* The name of any <<variable-assignment,variable>> known
+ at{nbsp}__**L**__.
--
+
The value of the special name `ICITTE` (`int` type) in this expression
is `int`, `float`, or `bool` (automatically converted to `int`).
+
For a variable assignment at some source location{nbsp}__**L**__, this
-expression may contain the name of any accessible <<label,label>> (not
-within a nested group), including the name of a label defined
-after{nbsp}__**L**__, as well as the name of any
-<<variable-assignment,variable>> known at{nbsp}__**L**__.
+expression may contain:
++
+--
+* The name of any <<label,label>> defined before{nbsp}__**L**__
+ which isn't within a nested group.
+* The name of any <<variable-assignment,variable>> known
+ at{nbsp}__**L**__.
+--
+
The value of the special name `ICITTE` (`int` type) in this expression
is the <<cur-offset,current offset>>.
evaluation result type is `int` or `bool` (automatically converted to
`int`), and the ``pass:[}]`` suffix.
+
-For a repetition at some source location{nbsp}__**L**__, this expression
-may contain:
+For a conditional block at some source location{nbsp}__**L**__, this
+expression may contain:
+
--
* The name of any <<label,label>> defined before{nbsp}__**L**__
which isn't within a nested group.
* The name of any <<variable-assignment,variable>> known
- at{nbsp}__**L**__ which doesn't, directly or indirectly, refer to a
- label defined after{nbsp}__**L**__.
+ at{nbsp}__**L**__.
--
+
The value of the special name `ICITTE` (`int` type) in this expression
evaluation result type is `int` or `bool` (automatically converted to
`int`), and the ``pass:[}]`` suffix.
+
-For a repetition at some source location{nbsp}__**L**__, this expression
-may contain:
+For a repetition block at some source location{nbsp}__**L**__, this
+expression may contain:
+
--
* The name of any <<label,label>> defined before{nbsp}__**L**__
which isn't within a nested group.
* The name of any <<variable-assignment,variable>> known
- at{nbsp}__**L**__ which doesn't, directly or indirectly, refer to a
- label defined after{nbsp}__**L**__.
+ at{nbsp}__**L**__.
--
+
The value of the special name `ICITTE` (`int` type) in this expression
----
====
+=== Macro definition block
+
+A _macro definition block_ associates a name and parameter names to
+a group of items.
+
+A macro definition block doesn't lead to generated bytes itself: a
+<<macro-expansion,macro expansion>> does so.
+
+A macro definition may only exist at the root level, that is, not within
+a <<group,group>>, a <<repetition-block,repetition block>>, a
+<<conditional-block,conditional block>>, or another
+<<macro-definition-block,macro definition block>>.
+
+All macro definitions must have unique names.
+
+A macro definition is:
+
+. The `!macro` or `!m` opening.
+
+. A valid {py3} name (the macro name).
+
+. The `(` parameter name list prefix.
+
+. A comma-separated list of zero or more unique parameter names,
+ each one being a valid {py3} name.
+
+. The `)` parameter name list suffix.
+
+. Zero or more items except, recursively, a macro definition block.
+
+. The `!end` closing.
+
+====
+----
+!macro bake()
+ {le} {ICITTE * 8 : 16}
+ u16le"predict explode"
+!end
+----
+====
+
+====
+----
+!macro nail(rep, with_extra, val)
+ {iter = 1}
+
+ !repeat rep
+ {val + iter : uleb128}
+ {0xdeadbeef : 32}
+ {iter = iter + 1}
+ !end
+
+ !if with_extra
+ "meow mix\0"
+ !end
+!end
+----
+====
+
+=== Macro expansion
+
+A _macro expansion_ expands the items of a defined
+<<macro-definition-block,macro>>.
+
+The macro to expand must be defined _before_ the expansion.
+
+The <<state,state>> before handling the first item of the chosen macro
+is:
+
+<<cur-offset,Current offset>>::
+ Unchanged.
+
+<<cur-bo,Current byte order>>::
+ Unchanged.
+
+Variables::
+ The only available variables initially are the macro parameters.
+
+Labels::
+ None.
+
+The state after having handled the last item of the chosen macro is:
+
+Current offset::
+ The one before handling the first item of the macro plus the size
+ of the generated data of the macro expansion.
++
+IMPORTANT: This means <<current-offset-setting,current offset setting>>
+items within the expanded macro don't impact the final current offset.
+
+Current byte order::
+ The one before handling the first item of the macro.
+
+Variables::
+ The ones before handling the first item of the macro.
+
+Labels::
+ The ones before handling the first item of the macro.
+
+A macro expansion is:
+
+. The `m:` prefix.
+
+. A valid {py3} name (the name of the macro to expand).
+
+. The `(` parameter value list prefix.
+
+. A comma-separated list of zero or more unique parameter values.
++
+The number of parameter values must match the number of parameter
+names of the definition of the chosen macro.
++
+A parameter value is one of:
++
+--
+* A positive integer (hexadecimal starting with `0x` or `0X` accepted).
+
+* The ``pass:[{]`` prefix, a valid {py3} expression of which the
+ evaluation result type is `int` or `bool` (automatically converted to
+ `int`), and the ``pass:[}]`` suffix.
++
+For a macro expansion at some source location{nbsp}__**L**__, this
+expression may contain:
+
+** The name of any <<label,label>> defined before{nbsp}__**L**__
+ which isn't within a nested group.
+** The name of any <<variable-assignment,variable>> known
+ at{nbsp}__**L**__.
+
++
+The value of the special name `ICITTE` (`int` type) in this expression
+is the <<cur-offset,current offset>> (before handling the items of the
+chosen macro).
+
+* A valid {py3} name.
++
+For the name `__NAME__`, this is equivalent to the
+`pass:[{]__NAME__pass:[}]` form above.
+--
+
+. The `)` parameter value list suffix.
+
+====
+Input:
+
+----
+!macro bake()
+ {le} {ICITTE * 8 : 16}
+ u16le"predict explode"
+!end
+
+"hello [" m:bake() "] world"
+
+m:bake() * 5
+----
+
+Output:
+
+----
+68 65 6c 6c 6f 20 5b 38 00 70 00 72 00 65 00 64 ┆ hello [8•p•r•e•d
+00 69 00 63 00 74 00 20 00 65 00 78 00 70 00 6c ┆ •i•c•t• •e•x•p•l
+00 6f 00 64 00 65 00 5d 20 77 6f 72 6c 64 70 01 ┆ •o•d•e•] worldp•
+70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
+65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 70 02 ┆ e•x•p•l•o•d•e•p•
+70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
+65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 70 03 ┆ e•x•p•l•o•d•e•p•
+70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
+65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 70 04 ┆ e•x•p•l•o•d•e•p•
+70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
+65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 70 05 ┆ e•x•p•l•o•d•e•p•
+70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
+65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 ┆ e•x•p•l•o•d•e•
+----
+====
+
+====
+Input:
+
+----
+!macro A(val, is_be)
+ {le}
+
+ !if is_be
+ {be}
+ !end
+
+ {val : 16}
+!end
+
+!macro B(rep, is_be)
+ {iter = 1}
+
+ !repeat rep
+ m:A({iter * 3}, is_be)
+ {iter = iter + 1}
+ !end
+!end
+
+m:B(5, 1)
+m:B(3, 0)
+----
+
+Output:
+
+----
+00 03 00 06 00 09 00 0c 00 0f 03 00 06 00 09 00
+----
+====
+
=== Post-item repetition
A _post-item repetition_ represents the bytes of an item repeated a
** A <<literal-string,literal string>>.
** A <<fixed-length-number,fixed-length number>>.
** An <<leb128-integer,LEB128 integer>>.
+** A <<macro-expansion,macro-expansion>>.
** A <<group,group>>.
. The ``pass:[*]`` character.
evaluation result type is `int` or `bool` (automatically converted to
`int`), and the ``pass:[}]`` suffix.
+
-For a repetition at some source location{nbsp}__**L**__, this expression
-may contain:
+For a post-item repetition at some source location{nbsp}__**L**__, this
+expression may contain:
+
--
* The name of any <<label,label>> defined before{nbsp}__**L**__
which isn't part of the repeated item.
* The name of any <<variable-assignment,variable>> known
at{nbsp}__**L**__, which isn't part of its repeated item, and which
- doesn't, directly or indirectly, refer to a label defined
- after{nbsp}__**L**__.
+ doesn't.
--
+
The value of the special name `ICITTE` (`int` type) in this expression