1 // Show ToC at a specific location for a GitHub rendering
10 // This is to mimic what GitHub does so that anchors work in an offline
21 image::normand-logo.png[]
24 image:https://img.shields.io/pypi/v/normand.svg?label=Latest%20version[link="https://pypi.python.org/pypi/normand"]
27 _**Normand**_ is a text-to-binary processor with its own language.
29 This package offers both a portable {py3} module and a command-line
32 WARNING: This version of Normand is 0.20, meaning both the Normand
33 language and the module/CLI interface aren't stable.
36 // ToC location for a GitHub rendering
42 The purpose of Normand is to consume human-readable text representing
43 bytes and to produce the corresponding binary data.
47 Consider the following Normand input:
50 4f 55 32 bb $167 fe %10100111 a9 $-32
53 The generated nine bytes are:
56 4f 55 32 bb a7 fe a7 a9 e0
60 As you can see in the last example, the fundamental unit of the Normand
61 language is the _byte_. The order in which you list bytes will be the
62 order of the generated data.
64 The Normand language is more than simple lists of bytes, though. Its
67 Comments, including a bunch of insignificant symbols which may improve readability::
72 ff bb %1101:0010 # This is a comment
73 78 29 af $192 # This too # 99 $-80
74 fe80::6257:18ff:fea3:4229
76 10839636-5d65-4a68-8e6a-21608ddf7258
82 ff bb d2 78 29 af c0 99 b0 fe 80 62 57 18 ff fe
83 a3 42 29 60 57 18 a3 42 29 10 83 96 36 5d 65 4a
84 68 8e 6a 21 60 8d df 72 58
87 Hexadecimal, decimal, and binary byte constants::
92 aa bb $247 $-89 %0011_0010 %11.01= 10/10
107 u16le"stress\nverdict 🤣"
108 s:latin3{hex(ICITTE)}
114 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 00 73 00 74 ┆ hello world!•s•t
115 00 72 00 65 00 73 00 73 00 0a 00 76 00 65 00 72 ┆ •r•e•s•s•••v•e•r
116 00 64 00 69 00 63 00 74 00 20 00 3e d8 23 dd 30 ┆ •d•i•c•t• •>•#•0
120 Labels: special variables holding the offset where they're defined::
123 <beg> b2 52 e3 bc 91 05
124 $100 $50 <chair> 33 9f fe
131 5e 65 {tower = 47} c6 7f f2 c4
132 44 {hurl = tower - 14} b5 {tower = hurl} 26 2d
135 The value of a variable assignment is the evaluation of a valid {py3}
136 expression which may include label and variable names.
138 Fixed-length number with a given length (8{nbsp}bits to 64{nbsp}bits) and byte order::
144 {be} 67 <lbl> 44 $178 {(end - lbl) * 8 + strength : 16} $99 <end>
152 67 44 b2 00 2c 63 37 f8 ff ff 7f bd c2 82 fb 21
156 The encoded number is the evaluation of a valid {py3} expression which
157 may include label and variable names.
159 https://en.wikipedia.org/wiki/LEB128[LEB128] integer::
164 aa bb cc {-1993 : sleb128} <meow> dd ee ff
165 {meow * 199 : uleb128}
171 aa bb cc b7 70 dd ee ff e3 07
174 The encoded integer is the evaluation of a valid {py3} expression which
175 may include label and variable names.
198 aa bb cc 66 6f 6f 66 69 67 68 74 66 6f 6f 66 69 ┆ •••foofightfoofi
199 67 68 74 66 6f 6f 62 61 72 66 6f 6f 62 61 72 ┆ ghtfoobarfoobar
207 aa bb * 5 cc <zoom> "yeah\0" * {zoom * 3}
217 aa bb bb bb bb bb cc 79 65 61 68 00 79 65 61 68 ┆ •••••••yeah•yeah
218 00 79 65 61 68 00 79 65 61 68 00 79 65 61 68 00 ┆ •yeah•yeah•yeah•
219 79 65 61 68 00 79 65 61 68 00 79 65 61 68 00 79 ┆ yeah•yeah•yeah•y
220 65 61 68 00 79 65 61 68 00 79 65 61 68 00 79 65 ┆ eah•yeah•yeah•ye
221 61 68 00 79 65 61 68 00 79 65 61 68 00 79 65 61 ┆ ah•yeah•yeah•yea
222 68 00 79 65 61 68 00 79 65 61 68 00 79 65 61 68 ┆ h•yeah•yeah•yeah
223 00 79 65 61 68 00 79 65 61 68 00 79 65 61 68 00 ┆ •yeah•yeah•yeah•
224 ff ee 6a 75 69 63 65 ff ee 6a 75 69 63 65 ff ee ┆ ••juice••juice••
225 6a 75 69 63 65 ┆ juice
244 00 00 00 c7 00 00 00 00 00 00 00 00 00 00 00 2b
245 ff 85 ff ff 00 00 15 d0
267 ef be ad de 37 f8 09 00 00 00 00 00 00 00 00 00 ┆ ••••7•••••••••••
268 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ┆ ••••••••••••••••
269 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ┆ ••••••••••••••••
270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ┆ ••••••••••••••••
271 40 6d 65 6f 77 20 6d 69 78 ff ff ff ff ff ff ff ┆ @meow mix•••••••
272 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ┆ ••••••••••••••••
273 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ┆ ••••••••••••••••
274 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ┆ ••••••••••••••••
275 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ┆ ••••••••••••••••
276 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ┆ ••••••••••••••••
277 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ┆ ••••••••••••••••
278 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ┆ ••••••••••••••••
279 ff ff ff ff ff ff ff ff c8 ┆ •••••••••
282 Multilevel grouping::
287 ff ((aa bb "zoom" cc) * 5) * 3 $-34 * 4
293 ff aa bb 7a 6f 6f 6d cc aa bb 7a 6f 6f 6d cc aa ┆ •••zoom•••zoom••
294 bb 7a 6f 6f 6d cc aa bb 7a 6f 6f 6d cc aa bb 7a ┆ •zoom•••zoom•••z
295 6f 6f 6d cc aa bb 7a 6f 6f 6d cc aa bb 7a 6f 6f ┆ oom•••zoom•••zoo
296 6d cc aa bb 7a 6f 6f 6d cc aa bb 7a 6f 6f 6d cc ┆ m•••zoom•••zoom•
297 aa bb 7a 6f 6f 6d cc aa bb 7a 6f 6f 6d cc aa bb ┆ ••zoom•••zoom•••
298 7a 6f 6f 6d cc aa bb 7a 6f 6f 6d cc aa bb 7a 6f ┆ zoom•••zoom•••zo
299 6f 6d cc aa bb 7a 6f 6f 6d cc de de de de ┆ om•••zoom•••••
309 !if world " world" !end
314 m:hello({ICITTE > 15 and ICITTE < 60})
321 ff ff ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 6c ┆ ••••hello••••hel
322 6c 6f ff ff ff ff 68 65 6c 6c 6f 20 77 6f 72 6c ┆ lo••••hello worl
323 64 ff ff ff ff 68 65 6c 6c 6f 20 77 6f 72 6c 64 ┆ d••••hello world
324 ff ff ff ff 68 65 6c 6c 6f 20 77 6f 72 6c 64 ff ┆ ••••hello world•
325 ff ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 6c 6c ┆ •••hello••••hell
326 6f ff ff ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 ┆ o••••hello••••he
327 6c 6c 6f ff ff ff ff 68 65 6c 6c 6f ff ff ff ff ┆ llo••••hello••••
328 68 65 6c 6c 6f ff ff ff ff 68 65 6c 6c 6f ff ff ┆ hello••••hello••
329 ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 6c 6c 6f ┆ ••hello••••hello
330 ff ff ff ff 68 65 6c 6c 6f ff ff ff ff 68 65 6c ┆ ••••hello••••hel
331 6c 6f ff ff ff ff 68 65 6c 6c 6f ┆ lo••••hello
334 Precise error reporting::
337 /tmp/meow.normand:10:24 - Expecting a bit (`0` or `1`).
341 /tmp/meow.normand:32:6 - Unexpected character `k`.
345 /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`}.
349 /tmp/meow.normand:32:19 - While expanding the macro `meow`:
350 /tmp/meow.normand:35:5 - While expanding the macro `zzz`:
351 /tmp/meow.normand:18:9 - Value 315 is outside the 8-bit range when evaluating expression `end - ICITTE`.
354 You can use Normand to track data source files in your favorite VCS
355 instead of raw binary files. The binary files that Normand generates can
356 be used to test file format decoding, including malformatted data, for
357 example, as well as for education.
359 See <<learn-normand>> to explore all the Normand features.
363 Normand requires Python ≥ 3.4.
368 $ python3 -m pip install --user normand
372 https://packaging.python.org/en/latest/tutorials/installing-packages/#installing-to-the-user-site[Installing to the User Site]
373 to learn more about a user site installation.
377 Normand has a single module file, `normand.py`, which you can copy as is
378 to your project to use it (both the <<python3-api,`normand.parse()`>>
379 function and the <<command-line-tool,command-line tool>>).
381 `normand.py` has _no external dependencies_, but if you're using
382 Python{nbsp}3.4, you'll need a local copy of the standard `typing`
388 The design goals of Normand are:
391 We're making sure `normand.py` works with Python{nbsp}≥{nbsp}3.4 and
392 doesn't have any external dependencies so that you may just copy the
393 module as is to your own project.
396 The most basic Normand input is a sequence of hexadecimal constants
397 (for example, `4e6f726d616e64`) which produce exactly what you'd
400 Most Normand features map to programming language concepts you already
401 know and understand: constant integers, literal strings, variables,
402 conditionals, repetitions/loops, and the rest.
404 Concise and readable input::
405 We could have chosen XML or YAML as the input format, but having a
406 DSL here makes a Normand input compact and easy to read, two
407 important traits when using Normand to write tests, for example.
409 Compare the following Normand input and some hypothetical XML
410 equivalent, for example:
412 .Actual normand input.
414 ff dd 01 ab $192 $-128 %1101:0011
421 # five times because xyz
423 "hello world " {iter:8}
431 .Hypothetical Normand XML input.
434 <?xml version="1.0" encoding="utf-8" ?>
436 <byte base="x" val="ff" />
437 <byte base="x" val="dd" />
438 <byte base="x" val="1" />
439 <byte base="x" val="ab" />
440 <byte base="d" val="192" />
441 <byte base="d" val="-128" />
442 <byte base="b" val="11010011" />
443 <fixed-len-num expr="end" len="8" />
444 <var-assign name="iter" expr="1" />
445 <cond expr="not something">
446 <!-- five times because xyz -->
448 <str>hello world </str>
449 <fixed-len-num expr="iter" len="8" />
450 <var-assign name="iter" expr="iter + 1" />
459 A Normand text input is a sequence of items which represent a sequence
462 [[state]] During the processing of items to data, Normand relies on a
467 |State variable |Description |Initial value: <<python3-api,{py3} API>> |Initial value: <<command-line-tool,CLI>>
469 |[[cur-offset]] Current offset
471 The current offset has an effect on the value of <<label,labels>> and of
472 the special `ICITTE` name in <<fixed-length-number,fixed-length
473 number>>, <<leb-128-integer,LEB128 integer>>, <<string,string>>,
474 <<filling,filling>>, <<variable-assignment,variable assignment>>,
475 <<conditional-block,conditional block>>, <<repetition-block,repetition
476 block>>, <<macro-expansion,macro expansion>>, and
477 <<post-item-repetition,post-item repetition>> expression evaluation.
479 Each generated byte increments the current offset.
481 A <<current-offset-setting,current offset setting>> may change the
482 current offset without generating data.
484 An <<current-offset-alignment,current offset alignment>> generates
485 padding bytes to make the current offset satisfy a given alignment.
486 |`init_offset` parameter of the `parse()` function.
489 |[[cur-bo]] Current byte order
491 The current byte order has an effect on the encoding of
492 <<fixed-length-number,fixed-length numbers>>.
494 A <<current-byte-order-setting,current byte order setting>> may change
495 the current byte order.
496 |`init_byte_order` parameter of the `parse()` function.
497 |`--byte-order` option.
500 |Mapping of label names to integral values.
501 |`init_labels` parameter of the `parse()` function.
502 |One or more `--label` options.
504 |<<variable-assignment,Variables>>
505 |Mapping of variable names to integral or floating point number values.
506 |`init_variables` parameter of the `parse()` function.
507 |One or more `--var` or `--var-str` options.
510 The available items are:
512 * A <<byte-constant,constant integer>> representing one or more
515 * A <<literal-string,literal string>> representing a constant sequence
516 of bytes encoding UTF-8, UTF-16, UTF-32, or Latin-1 to Latin-10 data.
518 * A <<current-byte-order-setting,current byte order setting>> (big or
521 * A <<fixed-length-number,fixed-length number>> (integer or
522 floating point) using the <<cur-bo,current byte order>> and of which
523 the value is the result of a {py3} expression.
525 * An <<leb128-integer,LEB128 integer>> of which the value is the result
526 of a {py3} expression.
528 * A <<string,string>> representing a sequence of bytes encoding UTF-8,
529 UTF-16, UTF-32, or Latin-1 to Latin-10 data, and of which the value is
530 the result of a {py3} expression.
532 * A <<current-offset-setting,current offset setting>>.
534 * A <<current-offset-alignment,current offset alignment>>.
536 * A <<filling,filling>>.
538 * A <<label,label>>, that is, a named constant holding the current
541 This is similar to an assembly label.
543 * A <<variable-assignment,variable assignment>> associating a name to
544 the integral result of an evaluated {py3} expression.
546 * A <<group,group>>, that is, a scoped sequence of items.
548 * A <<conditional-block,conditional block>>.
550 * A <<repetition-block,repetition block>>.
552 * A <<macro-definition-block,macro definition block>>.
554 * A <<macro-expansion,macro expansion>>.
556 Moreover, you can repeat many items above a constant or variable number
557 of times with the ``pass:[*]`` operator _after_ the item to repeat. This
558 is called a <<post-item-repetition,post-item repetition>>.
560 A Normand comment may exist pretty much anywhere between tokens.
562 A comment is anything between two ``pass:[#]`` characters on the same
563 line, or from ``pass:[#]`` until the end of the line. Whitespaces are
564 also considered comments. The following symbols are also considered
565 comments around and between items, as well as between hexadecimal
566 nibbles and binary bits of <<byte-constant,byte constants>>:
569 / \ ? & : ; . , [ ] _ = | -
572 The latter serve to improve readability so that you may write, for
573 example, a MAC address or a UUID as is.
575 [[const-int]] Many items require a _constant integer_, possibly
576 negative, in which case it may start with `-` for a negative integer. A
577 positive constant integer is any of:
580 One or mode digits (`0` to `9`).
585 * The `0x` or `0X` prefix followed with one or more hexadecimal digits
586 (`0` to `9`, `a` to `f`, or `A` to `F`).
587 * One or more hexadecimal digits followed with the `h` or `H` suffix.
592 * The `0o` or `0O` prefix followed with one or more octal digits
594 * One or more octal digits followed with the `o`, `O`, `q`, or `Q`
600 * The `0b` or `0B` prefix followed with one or more bits (`0` or `1`).
601 * One or more bits followed with the `b` or `B` suffix.
603 You can test the examples of this section with the `normand`
604 <<command-line-tool,command-line tool>> as such:
607 $ normand file | hexdump -C
610 where `file` is the name of a file containing the Normand input.
614 A _byte constant_ represents one or more constant bytes.
619 Two consecutive hexadecimal digits representing a single byte.
622 One or more digits after the `$` prefix representing a single byte.
624 Binary form:: {empty}
627 . __**N**__ `%` prefixes (at least one).
629 The number of `%` characters is the number of subsequent expected bytes.
631 . __**N**__{nbsp}×{nbsp}8 bits (`0` or `1`).
652 $192 %1100/0011 $ -77
666 58f64689-6316-4d55-8a1a-04cada366172
667 fe80::6257:18ff:fea3:4229
673 58 f6 46 89 63 16 4d 55 8a 1a 04 ca da 36 61 72 ┆ X•F•c•MU•••••6ar
674 fe 80 62 57 18 ff fe a3 42 29 ┆ ••bW••••B)
682 %01110011 %01100001 %01101100 %01110101 %01110100
683 %%%1101:0010 11111111 #A#11 #B#00 #C#011 #D#1
689 73 61 6c 75 74 d2 ff c7 ┆ salut•••
695 A _literal string_ represents the encoded bytes of a literal string
696 using the UTF-8, UTF-16, UTF-32, or Latin-1 to Latin-10 encoding.
698 The string to encode isn't implicitly null-terminated: use `\0` at the
699 end of the string to add a null character.
703 . **Optional**: one of the following encodings instead of the default
759 . The ``pass:["]`` prefix.
761 . A sequence of zero or more characters, possibly containing escape
764 An escape sequence is the ``\`` character followed by one of:
770 `b`:: Backspace (U+0008)
771 `e`:: Escape (U+001B)
772 `f`:: Form feed (U+000C)
773 `n`:: End of line (U+000A)
774 `r`:: Carriage return (U+000D)
775 `t`:: Character tabulation (U+0009)
776 `v`:: Line tabulation (U+000B)
777 ``\``:: Reverse solidus (U+005C)
778 ``pass:["]``:: Quotation mark (U+0022)
781 . The ``pass:["]`` suffix.
787 "coucou tout le monde!"
793 63 6f 75 63 6f 75 20 74 6f 75 74 20 6c 65 20 6d ┆ coucou tout le m
794 6f 6e 64 65 21 ┆ onde!
802 u16le"I am not young enough to know everything."
808 49 00 20 00 61 00 6d 00 20 00 6e 00 6f 00 74 00 ┆ I• •a•m• •n•o•t•
809 20 00 79 00 6f 00 75 00 6e 00 67 00 20 00 65 00 ┆ •y•o•u•n•g• •e•
810 6e 00 6f 00 75 00 67 00 68 00 20 00 74 00 6f 00 ┆ n•o•u•g•h• •t•o•
811 20 00 6b 00 6e 00 6f 00 77 00 20 00 65 00 76 00 ┆ •k•n•o•w• •e•v•
812 65 00 72 00 79 00 74 00 68 00 69 00 6e 00 67 00 ┆ e•r•y•t•h•i•n•g•
821 s:u32be "\"illusion is the first\nof all pleasures\" 🦉"
827 00 00 00 22 00 00 00 69 00 00 00 6c 00 00 00 6c ┆ •••"•••i•••l•••l
828 00 00 00 75 00 00 00 73 00 00 00 69 00 00 00 6f ┆ •••u•••s•••i•••o
829 00 00 00 6e 00 00 00 20 00 00 00 69 00 00 00 73 ┆ •••n••• •••i•••s
830 00 00 00 20 00 00 00 74 00 00 00 68 00 00 00 65 ┆ ••• •••t•••h•••e
831 00 00 00 20 00 00 00 66 00 00 00 69 00 00 00 72 ┆ ••• •••f•••i•••r
832 00 00 00 73 00 00 00 74 00 00 00 0a 00 00 00 6f ┆ •••s•••t•••••••o
833 00 00 00 66 00 00 00 20 00 00 00 61 00 00 00 6c ┆ •••f••• •••a•••l
834 00 00 00 6c 00 00 00 20 00 00 00 70 00 00 00 6c ┆ •••l••• •••p•••l
835 00 00 00 65 00 00 00 61 00 00 00 73 00 00 00 75 ┆ •••e•••a•••s•••u
836 00 00 00 72 00 00 00 65 00 00 00 73 00 00 00 22 ┆ •••r•••e•••s•••"
837 00 00 00 20 00 01 f9 89 ┆ ••• ••••
845 s:latin1 "Paul Piché"
851 50 61 75 6c 20 50 69 63 68 e9 ┆ Paul Pich•
855 === Current byte order setting
857 This special item sets the <<cur-bo,_current byte order_>>.
859 The two accepted forms are:
862 ``pass:[{be}]``:: Set the current byte order to big endian.
863 ``pass:[{le}]``:: Set the current byte order to little endian.
865 === Fixed-length number
867 A _fixed-length number_ represents a fixed number of bytes encoding
870 * An unsigned or signed integer (two's complement).
872 The available lengths are 8, 16, 24, 32, 40, 48, 56, and 64.
874 * A floating point number
875 (https://standards.ieee.org/standard/754-2008.html[IEEE{nbsp}754-2008]).
877 The available length are 32 (_binary32_) and 64 (_binary64_).
879 The value is the result of evaluating a {py3} expression using the
880 <<cur-bo,current byte order>>.
882 A fixed-length number is:
884 . The ``pass:[{]`` prefix.
886 . A valid {py3} expression.
888 For a fixed-length number at some source location{nbsp}__**L**__, this
889 expression may contain the name of any accessible <<label,label>> (not
890 within a nested group), including the name of a label defined
891 after{nbsp}__**L**__, as well as the name of any
892 <<variable-assignment,variable>> known at{nbsp}__**L**__.
894 The value of the special name `ICITTE` (`int` type) in this expression
895 is the <<cur-offset,current offset>> (before encoding the number).
899 . An encoding length in bits amongst:
902 The expression evaluates to an `int` or `bool` value::
903 `8`, `16`, `24`, `32`, `40`, `48`, `56`, and `64`.
905 NOTE: Normand automatically converts a `bool` value to `int`.
907 The expression evaluates to a `float` value::
934 # String length in bits
935 {8 * (str_end - str_beg) : 16}
946 00 60 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 ┆ •`hello world!
954 {20 - ICITTE : 8} * 10
960 14 13 12 11 10 0f 0e 0d 0c 0b
981 An _LEB128 integer_ represents a variable number of bytes encoding an
982 unsigned or signed integer which is the result of evaluating a {py3}
983 expression following the https://en.wikipedia.org/wiki/LEB128[LEB128]
986 An LEB128 integer is:
988 . The ``pass:[{]`` prefix.
990 . A valid {py3} expression of which the evaluation result type
991 is `int` or `bool` (automatically converted to `int`).
993 For an LEB128 integer at some source location{nbsp}__**L**__, this
994 expression may contain:
997 * The name of any <<label,label>> defined before{nbsp}__**L**__
998 which isn't within a nested group.
999 * The name of any <<variable-assignment,variable>> known
1003 The value of the special name `ICITTE` (`int` type) in this expression
1004 is the <<cur-offset,current offset>> (before encoding the integer).
1006 . The `:` character.
1012 `uleb128`:: Use the unsigned LEB128 format.
1013 `sleb128`:: Use the signed LEB128 format.
1039 {-981238311 + (meow * -23) : sleb128}
1046 aa bb cc dd ee ff fd fa 8d ac 7c 68 65 6c 6c 6f ┆ ••••••••••|hello
1052 A _string_ represents a variable number of bytes encoding a string which
1053 is the result of evaluating a {py3} expression using the UTF-8, UTF-16,
1054 UTF-32, or Latin-1 to Latin-10 encoding.
1056 A string has two possible forms:
1058 Encoding prefix form:: {empty}
1060 . An encoding amongst:
1115 . The ``pass:[{]`` prefix.
1117 . A valid {py3} expression of which the evaluation result type
1118 is `bool`, `int`, `float`, or `str` (the first three automatically
1119 converted to `str`).
1121 For a string at some source location{nbsp}__**L**__, this expression may
1125 * The name of any <<label,label>> defined before{nbsp}__**L**__
1126 which isn't within a nested group.
1127 * The name of any <<variable-assignment,variable>> known
1131 The value of the special name `ICITTE` (`int` type) in this expression
1132 is the <<cur-offset,current offset>> (before encoding the string).
1136 Encoding suffix form:: {empty}
1138 . The ``pass:[{]`` prefix.
1140 . A valid {py3} expression of which the evaluation result type
1141 is `bool`, `int`, `float`, or `str` (the first three automatically
1142 converted to `str`).
1144 For a string at some source location{nbsp}__**L**__, this expression may
1148 * The name of any <<label,label>> defined before{nbsp}__**L**__
1149 which isn't within a nested group.
1150 * The name of any <<variable-assignment,variable>> known
1154 The value of the special name `ICITTE` (`int` type) in this expression
1155 is the <<cur-offset,current offset>> (before encoding the string).
1157 . The `:` character.
1159 . A string encoding amongst:
1226 31 20 32 20 33 20 34 20 35 20 36 20 37 20 38 20 ┆ 1 2 3 4 5 6 7 8
1227 39 20 31 30 20 ┆ 9 10
1235 {meow = 'salut jérémie'}
1236 {meow.upper() : s:latin1}
1242 53 41 4c 55 54 20 4a c9 52 c9 4d 49 45 ┆ SALUT J•R•MIE
1246 === Current offset setting
1248 This special item sets the <<cur-offset,_current offset_>>.
1250 A current offset setting is:
1254 . A <<const-int,positive constant integer>> which is the new current
1264 <0x61> {ICITTE : 8} * 8
1270 00 01 02 03 04 05 06 07 61 62 63 64 65 66 67 68 ┆ ••••••••abcdefgh
1278 aa bb cc dd <meow> ee ff
1279 <12> 11 22 33 <mix> 44 55
1280 {meow : 8} {mix : 8}
1286 aa bb cc dd ee ff 11 22 33 44 55 04 0f ┆ •••••••"3DU••
1290 === Current offset alignment
1292 A _current offset alignment_ represents zero or more padding bytes to
1293 make the <<cur-offset,current offset>> meet a given
1294 https://en.wikipedia.org/wiki/Data_structure_alignment[alignment] value.
1296 More specifically, for an alignment value of{nbsp}__**N**__{nbsp}bits,
1297 a current offset alignment represents the required padding bytes until
1298 the current offset is a multiple of __**N**__{nbsp}/{nbsp}8.
1300 A current offset alignment is:
1304 . A <<const-int,positive constant integer>> which is the alignment value
1307 This value must be greater than zero and a multiple of{nbsp}8.
1312 . The ``pass:[~]`` prefix.
1313 . A <<const-int,positive constant integer>> which is the value of the
1314 byte to use as padding to align the <<cur-offset,current offset>>.
1317 Without this section, the padding byte value is zero.
1323 11 22 (@32 aa bb cc) * 3
1329 11 22 00 00 aa bb cc 00 aa bb cc 00 aa bb cc
1339 @32~0xcc {-893.5:32}
1346 77 88 cc cc 00 60 5f c4 55 55 55 55 55 55 55 55 ┆ w••••`_•UUUUUUUU
1347 6d 65 6f 77 ┆ meow
1355 aa bb cc <29> @64~255 "zoom"
1361 aa bb cc ff ff ff 7a 6f 6f 6d ┆ ••••••zoom
1367 A _filling_ represents zero or more padding bytes to make the
1368 <<cur-offset,current offset>> reach a given value.
1372 . The ``pass:[+]`` prefix.
1376 ** A <<const-int,positive constant integer>> which is the current offset
1379 ** The ``pass:[{]`` prefix, a valid {py3} expression of which the
1380 evaluation result type is `int` or `bool` (automatically converted to
1381 `int`), and the ``pass:[}]`` suffix.
1383 For a filling at some source location{nbsp}__**L**__, this expression
1387 * The name of any <<label,label>> defined before{nbsp}__**L**__
1388 which isn't within a nested group.
1389 * The name of any <<variable-assignment,variable>> known
1393 The value of the special name `ICITTE` (`int` type) in this expression
1394 is the <<cur-offset,current offset>> (before handling the items to
1397 ** A valid {py3} name.
1399 For the name `__NAME__`, this is equivalent to the
1400 `pass:[{]__NAME__pass:[}]` form above.
1403 This value must be greater than or equal to the current offset where
1409 . The ``pass:[~]`` prefix.
1410 . A <<const-int,positive constant integer>> which is the value of the
1411 byte to use as padding to reach the current offset target.
1414 Without this section, the padding byte value is zero.
1428 aa bb cc dd 00 00 00 00 00 00 00 00 00 00 00 00 ┆ ••••••••••••••••
1429 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ┆ ••••••••••••••••
1430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ┆ ••••••••••••••••
1431 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ┆ ••••••••••••••••
1432 68 65 6c 6c 6f 20 77 6f 72 6c 64 ┆ hello world
1440 !macro part(iter, fill)
1441 <0> "particular security " {ord('0') + iter : 8} +fill~0x80
1447 m:part(iter, {32 + 4 * iter})
1455 70 61 72 74 69 63 75 6c 61 72 20 73 65 63 75 72 ┆ particular secur
1456 69 74 79 20 31 80 80 80 80 80 80 80 80 80 80 80 ┆ ity 1•••••••••••
1457 80 80 80 80 70 61 72 74 69 63 75 6c 61 72 20 73 ┆ ••••particular s
1458 65 63 75 72 69 74 79 20 32 80 80 80 80 80 80 80 ┆ ecurity 2•••••••
1459 80 80 80 80 80 80 80 80 80 80 80 80 70 61 72 74 ┆ ••••••••••••part
1460 69 63 75 6c 61 72 20 73 65 63 75 72 69 74 79 20 ┆ icular security
1461 33 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ┆ 3•••••••••••••••
1462 80 80 80 80 80 80 80 80 70 61 72 74 69 63 75 6c ┆ ••••••••particul
1463 61 72 20 73 65 63 75 72 69 74 79 20 34 80 80 80 ┆ ar security 4•••
1464 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ┆ ••••••••••••••••
1465 80 80 80 80 80 80 80 80 70 61 72 74 69 63 75 6c ┆ ••••••••particul
1466 61 72 20 73 65 63 75 72 69 74 79 20 35 80 80 80 ┆ ar security 5•••
1467 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ┆ ••••••••••••••••
1468 80 80 80 80 80 80 80 80 80 80 80 80 ┆ ••••••••••••
1474 A _label_ associates a name to the <<cur-offset,current offset>>.
1476 All the labels of a whole Normand input must have unique names.
1478 A label must not share the name of a <<variable-assignment,variable>>
1485 . A valid {py3} name which is not `ICITTE`.
1489 === Variable assignment
1491 A _variable assignment_ associates a name to the integral result of an
1492 evaluated {py3} expression.
1494 A variable assignment is:
1496 . The ``pass:[{]`` prefix.
1498 . A valid {py3} name which is not `ICITTE`.
1500 . The `=` character.
1502 . A valid {py3} expression of which the evaluation result type is `int`,
1503 `float`, or `bool` (automatically converted to `int`), or `str`.
1505 For a variable assignment at some source location{nbsp}__**L**__, this
1506 expression may contain:
1509 * The name of any <<label,label>> defined before{nbsp}__**L**__
1510 which isn't within a nested group.
1511 * The name of any <<variable-assignment,variable>> known
1515 The value of the special name `ICITTE` (`int` type) in this expression
1516 is the <<cur-offset,current offset>>.
1525 {meow = 42} 11 22 {meow:8} 33 {meow = ICITTE + 17}
1526 "yooo" {meow + mix : 16}
1532 11 22 2a 33 79 6f 6f 6f 7a 00 ┆ •"*3yoooz•
1538 A _group_ is a scoped sequence of items.
1540 The <<label,labels>> within a group aren't visible outside of it.
1542 The main purpose of a group is to <<post-item-repetition,repeat>> more
1543 than a single item and to isolate labels.
1547 . The `(`, `!group`, or `!g` opening.
1549 . Zero or more items.
1551 . Depending on the group opening:
1566 ((aa bb cc) dd () ee) "leclerc"
1572 aa bb cc dd ee 6c 65 63 6c 65 72 63 ┆ •••••leclerc
1581 (aa bb cc) * 3 dd ee
1588 aa bb cc aa bb cc aa bb cc dd ee aa bb cc aa bb
1589 cc aa bb cc dd ee aa bb cc aa bb cc aa bb cc dd
1590 ee aa bb cc aa bb cc aa bb cc dd ee aa bb cc aa
1591 bb cc aa bb cc dd ee
1601 <str_beg> u16le"sébastien diaz" <str_end>
1602 {ICITTE - str_beg : 8}
1603 {(end - str_beg) * 5 : 24}
1611 73 00 e9 00 62 00 61 00 73 00 74 00 69 00 65 00 ┆ s•••b•a•s•t•i•e•
1612 6e 00 20 00 64 00 69 00 61 00 7a 00 1c 00 01 e0 ┆ n• •d•i•a•z•••••
1613 73 00 e9 00 62 00 61 00 73 00 74 00 69 00 65 00 ┆ s•••b•a•s•t•i•e•
1614 6e 00 20 00 64 00 69 00 61 00 7a 00 1c 00 01 40 ┆ n• •d•i•a•z••••@
1615 73 00 e9 00 62 00 61 00 73 00 74 00 69 00 65 00 ┆ s•••b•a•s•t•i•e•
1616 6e 00 20 00 64 00 69 00 61 00 7a 00 1c 00 00 a0 ┆ n• •d•i•a•z•••••
1620 === Conditional block
1622 A _conditional block_ represents either the bytes of zero or more items
1623 if some expression is true, or the bytes of zero or more other items if
1626 A conditional block is:
1628 . The `!if` opening.
1632 ** The ``pass:[{]`` prefix, a valid {py3} expression of which the
1633 evaluation result type is `int` or `bool` (automatically converted to
1634 `int`), and the ``pass:[}]`` suffix.
1636 For a conditional block at some source location{nbsp}__**L**__, this
1637 expression may contain:
1640 * The name of any <<label,label>> defined before{nbsp}__**L**__
1641 which isn't within a nested group.
1642 * The name of any <<variable-assignment,variable>> known
1646 The value of the special name `ICITTE` (`int` type) in this expression
1647 is the <<cur-offset,current offset>> (before handling the contained
1650 ** A valid {py3} name.
1652 For the name `__NAME__`, this is equivalent to the
1653 `pass:[{]__NAME__pass:[}]` form above.
1655 . Zero or more items to be handled when the condition is true.
1659 .. The `!else` opening.
1660 .. Zero or more items to be handled when the condition is false.
1662 . The `!end` closing.
1680 !if {at < rep_count} 20 !end
1689 6d 65 6f 77 20 7a 6f 6f 6d 20 6d 65 6f 77 20 7a ┆ meow zoom meow z
1690 6f 6f 6d 20 6d 65 6f 77 20 7a 6f 6f 6d 20 6d 65 ┆ oom meow zoom me
1691 6f 77 20 6d 69 78 20 6d 65 6f 77 20 6d 69 78 20 ┆ ow mix meow mix
1692 6d 65 6f 77 20 6d 69 78 20 6d 65 6f 77 20 6d 69 ┆ meow mix meow mi
1693 78 20 6d 65 6f 77 20 6d 69 78 20 6d 65 6f 77 20 ┆ x meow mix meow
1706 !if {str_end - str_beg > 10}
1714 6d 00 65 00 6f 00 77 00 20 00 6d 00 69 00 78 00 ┆ m•e•o•w• •m•i•x•
1715 21 00 20 42 49 47 ┆ !• BIG
1719 === Repetition block
1721 A _repetition block_ represents the bytes of one or more items repeated
1722 a given number of times.
1724 A repetition block is:
1726 . The `!repeat` or `!r` opening.
1730 ** A <<const-int,positive constant integer>> which is the number of
1731 times to repeat the previous item.
1733 ** The ``pass:[{]`` prefix, a valid {py3} expression of which the
1734 evaluation result type is `int` or `bool` (automatically converted to
1735 `int`), and the ``pass:[}]`` suffix.
1737 For a repetition block at some source location{nbsp}__**L**__, this
1738 expression may contain:
1741 * The name of any <<label,label>> defined before{nbsp}__**L**__
1742 which isn't within a nested group.
1743 * The name of any <<variable-assignment,variable>> known
1747 The value of the special name `ICITTE` (`int` type) in this expression
1748 is the <<cur-offset,current offset>> (before handling the items to
1751 ** A valid {py3} name.
1753 For the name `__NAME__`, this is equivalent to the
1754 `pass:[{]__NAME__pass:[}]` form above.
1756 . Zero or more items.
1758 . The `!end` closing.
1760 You may also use a <<post-item-repetition,post-item repetition>> after
1761 some items. The form ``!repeat{nbsp}__X__{nbsp}__ITEMS__{nbsp}!end``
1762 is equivalent to ``(__ITEMS__){nbsp}pass:[*]{nbsp}__X__``.
1769 {end - ICITTE - 1 : 8}
1778 ff fe fd fc fb fa f9 f8 f7 f6 f5 f4 f3 f2 f1 f0 ┆ ••••••••••••••••
1779 ef ee ed ec eb ea e9 e8 e7 e6 e5 e4 e3 e2 e1 e0 ┆ ••••••••••••••••
1780 df de dd dc db da d9 d8 d7 d6 d5 d4 d3 d2 d1 d0 ┆ ••••••••••••••••
1781 cf ce cd cc cb ca c9 c8 c7 c6 c5 c4 c3 c2 c1 c0 ┆ ••••••••••••••••
1782 bf be bd bc bb ba b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 ┆ ••••••••••••••••
1783 af ae ad ac ab aa a9 a8 a7 a6 a5 a4 a3 a2 a1 a0 ┆ ••••••••••••••••
1784 9f 9e 9d 9c 9b 9a 99 98 97 96 95 94 93 92 91 90 ┆ ••••••••••••••••
1785 8f 8e 8d 8c 8b 8a 89 88 87 86 85 84 83 82 81 80 ┆ ••••••••••••••••
1786 7f 7e 7d 7c 7b 7a 79 78 77 76 75 74 73 72 71 70 ┆ •~}|{zyxwvutsrqp
1787 6f 6e 6d 6c 6b 6a 69 68 67 66 65 64 63 62 61 60 ┆ onmlkjihgfedcba`
1788 5f 5e 5d 5c 5b 5a 59 58 57 56 55 54 53 52 51 50 ┆ _^]\[ZYXWVUTSRQP
1789 4f 4e 4d 4c 4b 4a 49 48 47 46 45 44 43 42 41 40 ┆ ONMLKJIHGFEDCBA@
1790 3f 3e 3d 3c 3b 3a 39 38 37 36 35 34 33 32 31 30 ┆ ?>=<;:9876543210
1791 2f 2e 2d 2c 2b 2a 29 28 27 26 25 24 23 22 21 20 ┆ /.-,+*)('&%$#"!
1792 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 ┆ ••••••••••••••••
1793 0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 ┆ ••••••••••••••••
1812 11 22 !repeat times 33 !end
1823 aa bb cc dd ee ff ee ff ee ff ee ff ee ff 11 22 ┆ •••••••••••••••"
1824 33 ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ 3•••••••••••••••
1825 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
1826 ff ee ff ee ff 11 22 33 33 ee ff ee ff ee ff ee ┆ ••••••"33•••••••
1827 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
1828 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
1829 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
1830 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
1831 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
1832 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
1833 ff ee ff ee ff ee ff ee ff ee ff ee ff 11 22 33 ┆ ••••••••••••••"3
1834 33 33 63 6f 75 63 6f 75 21 ┆ 33coucou!
1838 === Macro definition block
1840 A _macro definition block_ associates a name and parameter names to
1843 A macro definition block doesn't lead to generated bytes itself: a
1844 <<macro-expansion,macro expansion>> does so.
1846 A macro definition may only exist at the root level, that is, not within
1847 a <<group,group>>, a <<repetition-block,repetition block>>, a
1848 <<conditional-block,conditional block>>, or another
1849 <<macro-definition-block,macro definition block>>.
1851 All macro definitions must have unique names.
1853 A macro definition is:
1855 . The `!macro` or `!m` opening.
1857 . A valid {py3} name (the macro name).
1859 . The `(` parameter name list prefix.
1861 . A comma-separated list of zero or more unique parameter names,
1862 each one being a valid {py3} name.
1864 . The `)` parameter name list suffix.
1866 . Zero or more items except, recursively, a macro definition block.
1868 . The `!end` closing.
1873 {le} {ICITTE * 8 : 16}
1874 u16le"predict explode"
1881 !macro nail(rep, with_extra, val)
1885 {val + iter : uleb128}
1899 A _macro expansion_ expands the items of a defined
1900 <<macro-definition-block,macro>>.
1902 The macro to expand must be defined _before_ the expansion.
1904 The <<state,state>> before handling the first item of the chosen macro
1907 <<cur-offset,Current offset>>::
1910 <<cur-bo,Current byte order>>::
1914 The only available variables initially are the macro parameters.
1919 The state after having handled the last item of the chosen macro is:
1922 The one before handling the first item of the macro plus the size
1923 of the generated data of the macro expansion.
1925 IMPORTANT: This means <<current-offset-setting,current offset setting>>
1926 items within the expanded macro don't impact the final current offset.
1928 Current byte order::
1929 The one before handling the first item of the macro.
1932 The ones before handling the first item of the macro.
1935 The ones before handling the first item of the macro.
1937 A macro expansion is:
1941 . A valid {py3} name (the name of the macro to expand).
1943 . The `(` parameter value list prefix.
1945 . A comma-separated list of zero or more unique parameter values.
1947 The number of parameter values must match the number of parameter
1948 names of the definition of the chosen macro.
1950 A parameter value is one of:
1953 * A <<const-int,constant integer>>, possibly negative.
1955 * A constant floating point number.
1957 * The ``pass:[{]`` prefix, a valid {py3} expression of which the
1958 evaluation result type is `int` or `bool` (automatically converted to
1959 `int`), and the ``pass:[}]`` suffix.
1961 For a macro expansion at some source location{nbsp}__**L**__, this
1962 expression may contain:
1964 ** The name of any <<label,label>> defined before{nbsp}__**L**__
1965 which isn't within a nested group.
1966 ** The name of any <<variable-assignment,variable>> known
1970 The value of the special name `ICITTE` (`int` type) in this expression
1971 is the <<cur-offset,current offset>> (before handling the items of the
1974 * A valid {py3} name.
1976 For the name `__NAME__`, this is equivalent to the
1977 `pass:[{]__NAME__pass:[}]` form above.
1980 . The `)` parameter value list suffix.
1987 {le} {ICITTE * 8 : 16}
1988 u16le"predict explode"
1991 "hello [" m:bake() "] world"
1999 68 65 6c 6c 6f 20 5b 38 00 70 00 72 00 65 00 64 ┆ hello [8•p•r•e•d
2000 00 69 00 63 00 74 00 20 00 65 00 78 00 70 00 6c ┆ •i•c•t• •e•x•p•l
2001 00 6f 00 64 00 65 00 5d 20 77 6f 72 6c 64 70 01 ┆ •o•d•e•] worldp•
2002 70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
2003 65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 70 02 ┆ e•x•p•l•o•d•e•p•
2004 70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
2005 65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 70 03 ┆ e•x•p•l•o•d•e•p•
2006 70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
2007 65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 70 04 ┆ e•x•p•l•o•d•e•p•
2008 70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
2009 65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 70 05 ┆ e•x•p•l•o•d•e•p•
2010 70 00 72 00 65 00 64 00 69 00 63 00 74 00 20 00 ┆ p•r•e•d•i•c•t• •
2011 65 00 78 00 70 00 6c 00 6f 00 64 00 65 00 ┆ e•x•p•l•o•d•e•
2019 !macro A(val, is_be)
2029 !macro B(rep, is_be)
2033 m:A({iter * 3}, is_be)
2045 00 03 00 06 00 09 00 0c 00 0f 03 00 06 00 09 00
2053 !macro flt32be(val) {be} {val : 32} !end
2063 43 48 45 45 54 4f 53 c2 28 ae 14 3b b8 41 25 ┆ CHEETOS•(••;•A%
2067 === Post-item repetition
2069 A _post-item repetition_ represents the bytes of an item repeated a
2070 given number of times.
2072 A post-item repetition is:
2074 . One of those items:
2076 ** A <<byte-constant,byte constant>>.
2077 ** A <<literal-string,literal string>>.
2078 ** A <<fixed-length-number,fixed-length number>>.
2079 ** An <<leb128-integer,LEB128 integer>>.
2080 ** A <<string,string>>.
2081 ** A <<macro-expansion,macro-expansion>>.
2082 ** A <<group,group>>.
2084 . The ``pass:[*]`` character.
2088 ** A positive integer (hexadecimal starting with `0x` or `0X` accepted)
2089 which is the number of times to repeat the previous item.
2091 ** The ``pass:[{]`` prefix, a valid {py3} expression of which the
2092 evaluation result type is `int` or `bool` (automatically converted to
2093 `int`), and the ``pass:[}]`` suffix.
2095 For a post-item repetition at some source location{nbsp}__**L**__, this
2096 expression may contain:
2099 * The name of any <<label,label>> defined before{nbsp}__**L**__
2100 which isn't within a nested group and
2101 which isn't part of the repeated item.
2102 * The name of any <<variable-assignment,variable>> known
2103 at{nbsp}__**L**__, which isn't part of its repeated item, and which
2107 The value of the special name `ICITTE` (`int` type) in this expression
2108 is the <<cur-offset,current offset>> (before handling the items to
2111 ** A valid {py3} name.
2113 For the name `__NAME__`, this is equivalent to the
2114 `pass:[{]__NAME__pass:[}]` form above.
2116 You may also use a <<repetition-block,repetition block>>. The form
2117 ``__ITEM__{nbsp}pass:[*]{nbsp}__X__`` is equivalent to
2118 ``!repeat{nbsp}__X__{nbsp}__ITEM__{nbsp}!end``.
2124 {end - ICITTE - 1 : 8} * 0x100 <end>
2130 ff fe fd fc fb fa f9 f8 f7 f6 f5 f4 f3 f2 f1 f0 ┆ ••••••••••••••••
2131 ef ee ed ec eb ea e9 e8 e7 e6 e5 e4 e3 e2 e1 e0 ┆ ••••••••••••••••
2132 df de dd dc db da d9 d8 d7 d6 d5 d4 d3 d2 d1 d0 ┆ ••••••••••••••••
2133 cf ce cd cc cb ca c9 c8 c7 c6 c5 c4 c3 c2 c1 c0 ┆ ••••••••••••••••
2134 bf be bd bc bb ba b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 ┆ ••••••••••••••••
2135 af ae ad ac ab aa a9 a8 a7 a6 a5 a4 a3 a2 a1 a0 ┆ ••••••••••••••••
2136 9f 9e 9d 9c 9b 9a 99 98 97 96 95 94 93 92 91 90 ┆ ••••••••••••••••
2137 8f 8e 8d 8c 8b 8a 89 88 87 86 85 84 83 82 81 80 ┆ ••••••••••••••••
2138 7f 7e 7d 7c 7b 7a 79 78 77 76 75 74 73 72 71 70 ┆ •~}|{zyxwvutsrqp
2139 6f 6e 6d 6c 6b 6a 69 68 67 66 65 64 63 62 61 60 ┆ onmlkjihgfedcba`
2140 5f 5e 5d 5c 5b 5a 59 58 57 56 55 54 53 52 51 50 ┆ _^]\[ZYXWVUTSRQP
2141 4f 4e 4d 4c 4b 4a 49 48 47 46 45 44 43 42 41 40 ┆ ONMLKJIHGFEDCBA@
2142 3f 3e 3d 3c 3b 3a 39 38 37 36 35 34 33 32 31 30 ┆ ?>=<;:9876543210
2143 2f 2e 2d 2c 2b 2a 29 28 27 26 25 24 23 22 21 20 ┆ /.-,+*)('&%$#"!
2144 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 ┆ ••••••••••••••••
2145 0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 ┆ ••••••••••••••••
2157 (ee ff) * {here + 1}
2167 aa bb cc dd ee ff ee ff ee ff ee ff ee ff 11 22 ┆ •••••••••••••••"
2168 33 ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ 3•••••••••••••••
2169 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
2170 ff ee ff ee ff 11 22 33 33 ee ff ee ff ee ff ee ┆ ••••••"33•••••••
2171 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
2172 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
2173 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
2174 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
2175 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
2176 ff ee ff ee ff ee ff ee ff ee ff ee ff ee ff ee ┆ ••••••••••••••••
2177 ff ee ff ee ff ee ff ee ff ee ff ee ff 11 22 33 ┆ ••••••••••••••"3
2178 33 33 63 6f 75 63 6f 75 21 ┆ 33coucou!
2182 == Command-line tool
2184 If you <<install-normand,installed>> the `normand` package, then you
2185 can use the `normand` command-line tool:
2188 $ normand <<< '"ma gang de malades"' | hexdump -C
2192 00000000 6d 61 20 67 61 6e 67 20 64 65 20 6d 61 6c 61 64 |ma gang de malad|
2196 If you copy the `normand.py` module to your own project, then you can
2197 run the module itself:
2200 $ python3 -m normand <<< '"ma gang de malades"' | hexdump -C
2204 00000000 6d 61 20 67 61 6e 67 20 64 65 20 6d 61 6c 61 64 |ma gang de malad|
2208 Without a path argument, the `normand` tool reads from the standard
2211 The `normand` tool prints the generated binary data to the standard
2214 Various options control the initial <<state,state>> of the processor:
2215 use the `--help` option to learn more.
2219 The whole `normand` package/module public API is:
2224 class ByteOrder(enum.Enum):
2236 def line_no(self) -> int:
2241 def col_no(self) -> int:
2245 # Parsing error message.
2246 class ParseErrorMessage:
2252 # Source text location.
2254 def text_location(self):
2259 class ParseError(RuntimeError):
2260 # Parsing error messages.
2262 # The first message is the most _specific_ one.
2268 # Variables dictionary type (for type hints).
2269 VariablesT = typing.Dict[str, typing.Union[int, float]]
2272 # Labels dictionary type (for type hints).
2273 LabelsT = typing.Dict[str, int]
2280 def data(self) -> bytearray:
2283 # Updated variable values.
2285 def variables(self) -> SymbolsT:
2288 # Updated main group label values.
2290 def labels(self) -> SymbolsT:
2295 def offset(self) -> int:
2300 def byte_order(self) -> typing.Optional[ByteOrder]:
2304 # Parses the `normand` input using the initial state defined by
2305 # `init_variables`, `init_labels`, `init_offset`, and `init_byte_order`,
2306 # and returns the corresponding parsing result.
2307 def parse(normand: str,
2308 init_variables: typing.Optional[SymbolsT] = None,
2309 init_labels: typing.Optional[SymbolsT] = None,
2310 init_offset: int = 0,
2311 init_byte_order: typing.Optional[ByteOrder] = None) -> ParseResult:
2315 The `normand` parameter is the actual <<learn-normand,Normand input>>
2316 while the other parameters control the initial <<state,state>>.
2318 The `parse()` function raises a `ParseError` instance should it fail to
2319 parse the `normand` string for any reason.
2323 Normand is a https://python-poetry.org/[Poetry] project.
2325 To develop it, install it through Poetry and enter the virtual
2331 $ normand <<< '"lol" * 10 0a'
2334 `normand.py` is processed by:
2336 * https://microsoft.github.io/pyright/[Pyright]
2337 * https://github.com/psf/black[Black]
2338 * https://pycqa.github.io/isort/[isort]
2342 Use https://docs.pytest.org/[pytest] to test Normand once the package is
2343 part of your virtual environment, for example:
2347 $ poetry run pip3 install pytest
2351 The `pytest` project is currently not a development dependency in
2352 `pyproject.toml` due to backward compatibiliy issues with
2355 In the `tests` directory, each `*.nt` file is a test. The file name
2356 prefix indicates what it's meant to test:
2359 Everything above the `---` line is the valid Normand input
2362 Everything below the `---` line is the expected data
2363 (whitespace-separated hexadecimal bytes).
2366 Everything above the `---` line is the invalid Normand input
2369 Everything below the `---` line is the expected error message having
2378 Normand uses https://review.lttng.org/admin/repos/normand,general[Gerrit]
2381 To report a bug, https://github.com/efficios/normand/issues/new[create a