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> `0x` | `0X` HEXDIGIT<sup>+</sup> 537> 538> INTVALUE:\ 539> DIGIT<sup>+</sup> 540> 541> HEXDIGIT:\ 542> DIGIT | [`a`-`f`] | [`A`-`F`] 543> 544> DIGIT:\ 545> [`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> `"` (!`"` __ANY__)* `"` 554 555A string is sequence of character. It can be multi-line. 556 557### Identifier 558 559> IDENTIFIER: \ 560> ALPHA (ALPHANUM | `_`)* 561> 562> ALPHA:\ 563> [`a`-`z`] | [`A`-`Z`] 564> 565> ALPHANUM:\ 566> 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> `+` | `-` | `*` | `/` 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> BLOCK_COMMENT | LINE_COMMENT 586> 587> BLOCK_COMMENT:\ 588> `/*` (!`*/` ANY) `*/` 589> 590> LINE_COMMENT:\ 591> `//` (!\n ANY) `//` 592 593### Whitespace 594 595> WHITESPACE:\ 596> ` ` | `\t` | `\n` 597