• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Packet Description Language
2
3[TOC]
4
5## Notation
6
7|    Notation   |            Example           |                        Meaning                       |
8|:-------------:|:----------------------------:|:----------------------------------------------------:|
9| __ANY__       | __ANY__                      | Any character                                        |
10| CAPITAL       | IDENTIFIER, INT              | A token production                                   |
11| snake_case    | declaration, constraint      | A syntactical production                             |
12| `string`      | `enum`, `=`                  | The exact character(s)                               |
13| \x            | \n, \r, \t, \0               | The character represented by this escape             |
14| x?            | `,`?                         | An optional item                                     |
15| x*            | ALPHANUM*                    | 0 or more of x                                       |
16| x+            | HEXDIGIT+                    | 1 or more of x                                       |
17| x \| y        | ALPHA \| DIGIT, `0x` \| `0X` | Either x or y                                        |
18| [x-y]         | [`a`-`z`]                    | Any of the characters in the range from x to y       |
19| !x            | !\n                          | Negative Predicate (lookahead), do not consume input |
20| ()            | (`,` enum_tag)               | Groups items                                         |
21
22
23[WHITESPACE](#Whitespace) and [COMMENT](#Comment) are implicitly inserted between every item
24and repetitions in syntactical rules (snake_case).
25
26```
27file: endianess declaration*
28```
29behaves like:
30```
31file: (WHITESPACE | COMMENT)* endianess (WHITESPACE | COMMENT)* (declaration | WHITESPACE | COMMENT)*
32```
33
34## File
35
36> file:\
37>    endianess [declaration](#declarations)*
38>
39> endianess:\
40>    `little_endian_packets` | `big_endian_packets`
41
42The structure of a `.pdl`file is:
431. A declaration of the protocol endianess: `little_endian_packets` or `big_endian_packets`. Followed by
442. Declarations describing the structure of the protocol.
45
46```
47// The protocol is little endian
48little_endian_packets
49
50// Brew a coffee
51packet Brew {
52  pot: 8, // Output Pot: 8bit, 0-255
53  additions: CoffeeAddition[2] // Coffee Additions: array of 2 CoffeeAddition
54}
55```
56
57## Identifiers
58
59- Identifiers can denote a field; an enumeration tag; or a declared type.
60
61- Field identifiers declared in a [packet](#packet) (resp. [struct](#struct)) belong to the _scope_ that extends
62  to the packet (resp. struct), and all derived packets (resp. structs).
63
64- Field identifiers declared in a [group](#group) belong to the _scope_ that
65  extends to the packets declaring a [group field](#group_field) for this group.
66
67- Two fields may not be declared with the same identifier in any packet scope.
68
69- Two types may not be declared width the same identifier.
70
71## Declarations
72
73> declaration: {#declaration}\
74>    [enum_declaration](#enum) |\
75>    [packet_declaration](#packet) |\
76>    [struct_declaration](#struct) |\
77>    [group_declaration](#group) |\
78>    [checksum_declaration](#checksum) |\
79>    [custom_field_declaration](#custom-field) |\
80>    [test_declaration](#test)
81
82A *declaration* defines a type inside a `.pdl` file. A declaration can reference
83another declaration appearing later in the file.
84
85A declaration is either:
86- an [Enum](#enum) declaration
87- a [Packet](#packet) declaration
88- a [Struct](#struct) declaration
89- a [Group](#group) declaration
90- a [Checksum](#checksum) declaration
91- a [Custom Field](#custom-field) declaration
92- a [Test](#test) declaration
93
94### Enum
95
96> enum_declaration:\
97>    `enum` [IDENTIFIER](#identifier) `:` [INTEGER](#integer) `{`\
98>      enum_tag_list\
99>    `}`
100>
101> enum_tag_list:\
102>    enum_tag (`,` enum_tag)* `,`?
103>
104> enum_tag:\
105>    [IDENTIFIER](#identifier) `=` [INTEGER](#integer)
106
107An *enumeration* or for short *enum*, is a declaration of a set of named [integer](#integer) constants.
108
109The [integer](#integer) following the name specifies the bit size of the values.
110
111```
112enum CoffeeAddition: 3 {
113  Empty = 0,
114  Cream = 1,
115  Vanilla = 2,
116  Chocolate = 3,
117  Whisky = 4,
118  Rum = 5,
119  Kahlua = 6,
120  Aquavit = 7
121}
122```
123
124### Packet
125
126> packet_declaration:\
127>    `packet` [IDENTIFIER](#identifier)\
128>      (`:` [IDENTIFIER](#identifier)\
129>        (`(` [constraint_list](#constraints) `)`)?\
130>      )?\
131>    `{`\
132>      [field_list](#fields)?\
133>    `}`
134
135A *packet* is a declaration of a sequence of [fields](#fields).
136
137A *packet* can optionally inherit from another *packet* declaration. In this case the packet
138inherits the parent's fields and the child's fields replace the
139[*\_payload\_*](#fields-payload) or [*\_body\_*](#fields-body) field of the parent.
140
141When inheriting, you can use constraints to set values on parent fields.
142See [constraints](#constraints) for more details.
143
144```
145packet Error {
146  code: 32,
147  _payload_
148}
149
150packet ImATeapot: Error(code = 418) {
151  brand_id: 8
152}
153```
154
155### Struct
156
157> struct_declaration:\
158>    `struct` [IDENTIFIER](#identifier)\
159>      (`:` [IDENTIFIER](#identifier)\
160>        (`(` [constraint_list](#constraints) `)`)?\
161>      )?\
162>    `{`\
163>      [field_list](#fields)?\
164>    `}`
165
166A *struct* follows the same rules as a [*packet*](#packet) with the following differences:
167- It inherits from a *struct* declaration instead of *packet* declaration.
168- A [typedef](#fields-typedef) field can reference a *struct*.
169
170### Group
171
172> group_declaration:\
173>    `group` [IDENTIFIER](#identifier) `{`\
174>      [field_list](#fields)\
175>    `}`
176
177A *group* is a sequence of [fields](#fields) that expand in a
178[packet](#packet) or [struct](#struct) when used.
179
180See also the [Group field](#fields-group).
181
182```
183group Paged {
184  offset: 8,
185  limit: 8
186}
187
188packet AskBrewHistory {
189  pot: 8, // Coffee Pot
190  Paged
191}
192```
193behaves like:
194```
195packet AskBrewHistory {
196  pot: 8, // Coffee Pot
197  offset: 8,
198  limit: 8
199}
200```
201
202### Checksum
203
204> checksum_declaration:\
205>    `checksum` [IDENTIFIER](#identifier) `:` [INTEGER](#integer) [STRING](#string)
206
207A *checksum* is a native type (not implemented in PDL). See your generator documentation
208for more information on how to use it.
209
210The [integer](#integer) following the name specify the bit size of the checksum value.
211The [string](#string) following the size is a value defined by the generator implementation.
212
213```
214checksum CRC16: 16 "crc16"
215```
216
217### Custom Field
218
219> custom_field_declaration:\
220>    `custom_field` [IDENTIFIER](#identifier) (`:` [INTEGER](#integer))? [STRING](#string)
221
222A *custom field* is a native type (not implemented in PDL). See your generator documentation for more
223information on how to use it.
224
225If present, the [integer](#integer) following the name specify the bit size of the value.
226The [string](#string) following the size is a value defined by the generator implementation.
227
228```
229custom_field URL "url"
230```
231
232### Test
233
234> test_declaration:\
235>    `test` [IDENTIFIER](#identifier) `{`\
236>      test_case_list\
237>    `}`
238>
239> test_case_list:\
240>    test_case (`,` test_case)* `,`?
241>
242> test_case:\
243>    [STRING](#string)
244
245A *test* declares a set of valid octet representations of a packet identified by its name.
246The generator implementation defines how to use the test data.
247
248A test passes if the packet parser accepts the input; if you want to test
249the values returned for each field, you may specify a derived packet with field values enforced using
250constraints.
251
252```
253packet Brew {
254  pot: 8,
255  addition: CoffeeAddition
256}
257
258test Brew {
259  "\x00\x00",
260  "\x00\x04"
261}
262
263// Fully Constrained Packet
264packet IrishCoffeeBrew: Brew(pot = 0, additions_list = Whisky) {}
265
266test IrishCoffeeBrew {
267  "\x00\x04"
268}
269```
270
271## Constraints
272
273> constraint:\
274>    [IDENTIFIER](#identifier) `=` [IDENTIFIER](#identifier) | [INTEGER](#integer)
275>
276> constraint_list:\
277>    constraint (`,` constraint)* `,`?
278
279A *constraint* defines the value of a parent field.
280The value can either be an [enum](#enum) tag or an [integer](#integer).
281
282```
283group Additionable {
284  addition: CoffeAddition
285}
286
287packet IrishCoffeeBrew {
288  pot: 8,
289  Additionable {
290    addition = Whisky
291  }
292}
293
294packet Pot0IrishCoffeeBrew: IrishCoffeeBrew(pot = 0) {}
295```
296
297## Fields
298
299> field_list:\
300>    field (`,` field)* `,`?
301>
302> field:\
303>    [checksum_field](#fields-checksum) |\
304>    [padding_field](#fields-padding) |\
305>    [size_field](#fields-size) |\
306>    [count_field](#fields-count) |\
307>    [payload_field](#fields-payload) |\
308>    [body_field](#fields-body) |\
309>    [fixed_field](#fields-fixed) |\
310>    [reserved_field](#fields-reserved) |\
311>    [array_field](#fields-array) |\
312>    [scalar_field](#fields-scalar) |\
313>    [typedef_field](#fields-typedef) |\
314>    [group_field](#fields-group)
315
316A field is either:
317- a [Scalar](#fields-scalar) field
318- a [Typedef](#fields-typedef) field
319- a [Group](#fields-group) field
320- an [Array](#fields-array) field
321- a [Size](#fields-size) field
322- a [Count](#fields-count) field
323- a [Payload](#fields-payload) field
324- a [Body](#fields-body) field
325- a [Fixed](#fields-fixed) field
326- a [Checksum](#fields-checksum) field
327- a [Padding](#fields-padding) field
328- a [Reserved](#fields-reserved) field
329
330### Scalar {#fields-scalar}
331
332> scalar_field:\
333>    [IDENTIFIER](#identifier) `:` [INTEGER](#integer)
334
335A *scalar* field defines a numeric value with a bit size.
336
337```
338struct Coffee {
339  temperature: 8
340}
341```
342
343### Typedef {#fields-typedef}
344
345> typedef_field:\
346>    [IDENTIFIER](#identifier) `:` [IDENTIFIER](#identifier)
347
348A *typedef* field defines a field taking as value either an [enum](#enum), [struct](#struct),
349[checksum](#checksum) or a [custom_field](#custom-field).
350
351```
352packet LastTimeModification {
353  coffee: Coffee,
354  addition: CoffeeAddition
355}
356```
357
358### Array {#fields-array}
359
360> array_field:\
361>    [IDENTIFIER](#identifier) `:` [INTEGER](#integer) | [IDENTIFIER](#identifier) `[`\
362>      [SIZE_MODIFIER](#size-modifier) | [INTEGER](#integer)\
363>    `]`
364
365An *array* field defines a sequence of `N` elements of type `T`.
366
367`N` can be:
368- An [integer](#integer) value.
369- A [size modifier](#size-modifier).
370- Unspecified: In this case the array is dynamically sized using a
371[*\_size\_*](#fields-size) or a [*\_count\_*](#fields-count).
372
373`T` can be:
374- An [integer](#integer) denoting the bit size of one element.
375- An [identifier](#identifier) referencing an [enum](#enum), a [struct](#struct)
376or a [custom field](#custom-field) type.
377
378```
379packet Brew {
380   pots: 8[2],
381   additions: CoffeeAddition[2],
382   extra_additions: CoffeeAddition[],
383}
384```
385
386### Group {#fields-group}
387
388> group_field:\
389>    [IDENTIFIER](#identifier) (`{` [constraint_list](#constraints) `}`)?
390
391A *group* field inlines all the fields defined in the referenced group.
392
393If a [constraint list](#constraints) constrains a [scalar](#fields-scalar) field
394or [typedef](#fields-typedef) field with an [enum](#enum) type, the field will
395become a [fixed](#fields-fixed) field.
396The [fixed](#fields-fixed) field inherits the type or size of the original field and the
397value from the constraint list.
398
399See [Group Declaration](#group) for more information.
400
401### Size {#fields-size}
402
403> size_field:\
404>    `_size_` `(` [IDENTIFIER](#identifier) | `_payload_` | `_body_` `)` `:` [INTEGER](#integer)
405
406A *\_size\_* field is a [scalar](#fields-scalar) field with as value the size in octet of the designated
407[array](#fields-array), [*\_payload\_*](#fields-payload) or [*\_body\_*](#fields-body).
408
409```
410packet Parent {
411  _size_(_payload_): 2,
412  _payload_
413}
414
415packet Brew {
416  pot: 8,
417  _size_(additions): 8,
418  additions: CoffeeAddition[]
419}
420```
421
422### Count {#fields-count}
423
424> count_field:\
425>    `_count_` `(` [IDENTIFIER](#identifier) `)` `:` [INTEGER](#integer)
426
427A *\_count\_* field is a [*scalar*](#fields-scalar) field with as value the number of elements of the designated
428[array](#fields-array).
429
430```
431packet Brew {
432  pot: 8,
433  _count_(additions): 8,
434  additions: CoffeeAddition[]
435}
436```
437
438### Payload {#fields-payload}
439
440> payload_field:\
441>    `_payload_` (`:` `[` [SIZE_MODIFIER](#size-modifier) `]` )?
442
443A *\_payload\_* field is a dynamically sized array of octets.
444
445It declares where to parse the definition of a child [packet](#packet) or [struct](#struct).
446
447A [*\_size\_*](#fields-size) or a [*\_count\_*](#fields-count) field referencing
448the payload induce its size.
449
450If used, a [size modifier](#size-modifier) can alter the octet size.
451
452### Body {#fields-body}
453
454> body_field:\
455>    `_body_`
456
457A *\_body\_* field is like a [*\_payload\_*](#fields-payload) field with the following differences:
458- The body field is private to the packet definition, it's accessible only when inheriting.
459- The body does not accept a size modifier.
460
461### Fixed {#fields-fixed}
462
463> fixed_field:\
464>    `_fixed_` `=` \
465>      ( [INTEGER](#integer) `:` [INTEGER](#integer) ) |\
466>      ( [IDENTIFIER](#identifier) `:` [IDENTIFIER](#identifier) )
467
468A *\_fixed\_* field defines a constant with a known bit size.
469The constant can be either:
470- An [integer](#integer) value
471- An [enum](#enum) tag
472
473```
474packet Teapot {
475  _fixed_ = 42: 8,
476  _fixed_ = Empty: CoffeeAddition
477}
478```
479
480### Checksum {#fields-checksum}
481
482> checksum_field:\
483>    `_checksum_start_` `(` [IDENTIFIER](#identifier) `)`
484
485A *\_checksum_start\_* field is a zero sized field that acts as a marker for the beginning of
486the fields covered by a checksum.
487
488The *\_checksum_start\_* references a [typedef](#fields-typedef) field
489with a [checksum](#checksum) type that stores the checksum value and selects the algorithm
490for the checksum.
491
492```
493checksum CRC16: 16 "crc16"
494
495packet CRCedBrew {
496  crc: CRC16,
497  _checksum_start_(crc),
498  pot: 8,
499}
500```
501
502### Padding {#fields-padding}
503
504> padding_field:\
505>    `_padding_` `[` [INTEGER](#integer) `]`
506
507A *\_padding\_* field adds a number of **octet** of padding.
508
509```
510packet Padded {
511  _padding_[1] // 1 octet/8bit of padding
512}
513```
514
515### Reserved {#fields-reserved}
516
517> reserved_field:\
518>    `_reserved_` `:` [INTEGER](#integer)
519
520A *\_reserved\_* field adds reserved bits.
521
522```
523packet DeloreanCoffee {
524  _reserved_: 2014
525}
526```
527
528## Tokens
529
530### Integer
531
532> INTEGER:\
533>    HEXVALUE | INTVALUE
534>
535> HEXVALUE:\
536> &nbsp;&nbsp; `0x` | `0X` HEXDIGIT<sup>+</sup>
537>
538> INTVALUE:\
539> &nbsp;&nbsp; DIGIT<sup>+</sup>
540>
541> HEXDIGIT:\
542> &nbsp;&nbsp; DIGIT | [`a`-`f`] | [`A`-`F`]
543>
544> DIGIT:\
545> &nbsp;&nbsp; [`0`-`9`]
546
547A integer is a number in base 10 (decimal) or in base 16 (hexadecimal) with
548the prefix `0x`
549
550### String
551
552> STRING:\
553> &nbsp;&nbsp; `"` (!`"` __ANY__)* `"`
554
555A string is sequence of character. It can be multi-line.
556
557### Identifier
558
559> IDENTIFIER: \
560> &nbsp;&nbsp; ALPHA (ALPHANUM | `_`)*
561>
562> ALPHA:\
563> &nbsp;&nbsp; [`a`-`z`] | [`A`-`Z`]
564>
565> ALPHANUM:\
566> &nbsp;&nbsp; ALPHA | DIGIT
567
568An identifier is a sequence of alphanumeric or `_` characters
569starting with a letter.
570
571### Size Modifier
572
573> SIZE_MODIFIER:\
574> &nbsp;&nbsp; `+` | `-` | `*` | `/` DIGIT | `+` | `-` | `*` | `/`
575
576Part of a arithmetic expression where the missing part is a size
577
578For example:
579- `+ 2` defines that the size is 2 octet bigger than the real size
580- `* 8` defines that the size is 8 times bigger than the real size
581
582### Comment
583
584> COMMENT:\
585> &nbsp;&nbsp; BLOCK_COMMENT | LINE_COMMENT
586>
587> BLOCK_COMMENT:\
588> &nbsp;&nbsp; `/*` (!`*/` ANY) `*/`
589>
590> LINE_COMMENT:\
591> &nbsp;&nbsp; `//` (!\n ANY) `//`
592
593### Whitespace
594
595> WHITESPACE:\
596> &nbsp;&nbsp; ` ` | `\t` | `\n`
597