16 KiB
Packet Description Language
[TOC]
Notation
Notation | Example | Meaning |
---|---|---|
ANY | ANY | Any character |
CAPITAL | IDENTIFIER, INT | A token production |
snake_case | declaration, constraint | A syntactical production |
string |
enum , = |
The exact character(s) |
\x | \n, \r, \t, \0 | The character represented by this escape |
x? | , ? |
An optional item |
x* | ALPHANUM* | 0 or more of x |
x+ | HEXDIGIT+ | 1 or more of x |
x | y | ALPHA | DIGIT, 0x | 0X |
Either x or y |
[x-y] | [a -z ] |
Any of the characters in the range from x to y |
!x | !\n | Negative Predicate (lookahead), do not consume input |
() | (, enum_tag) |
Groups items |
WHITESPACE and COMMENT are implicitly inserted between every item and repetitions in syntactical rules (snake_case).
file: endianess declaration*
behaves like:
file: (WHITESPACE | COMMENT)* endianess (WHITESPACE | COMMENT)* (declaration | WHITESPACE | COMMENT)*
File
file:
endianess declaration*endianess:
little_endian_packets
|big_endian_packets
The structure of a .pdl
file is:
- A declaration of the protocol endianess:
little_endian_packets
orbig_endian_packets
. Followed by - Declarations describing the structure of the protocol.
// The protocol is little endian
little_endian_packets
// Brew a coffee
packet Brew {
pot: 8, // Output Pot: 8bit, 0-255
additions: CoffeeAddition[2] // Coffee Additions: array of 2 CoffeeAddition
}
Identifiers
-
Identifiers can denote a field; an enumeration tag; or a declared type.
-
Field identifiers declared in a packet (resp. struct) belong to the scope that extends to the packet (resp. struct), and all derived packets (resp. structs).
-
Field identifiers declared in a group belong to the scope that extends to the packets declaring a group field for this group.
-
Two fields may not be declared with the same identifier in any packet scope.
-
Two types may not be declared width the same identifier.
Declarations
declaration: {#declaration}
enum_declaration |
packet_declaration |
struct_declaration |
group_declaration |
checksum_declaration |
custom_field_declaration |
test_declaration
A declaration defines a type inside a .pdl
file. A declaration can reference
another declaration appearing later in the file.
A declaration is either:
- an Enum declaration
- a Packet declaration
- a Struct declaration
- a Group declaration
- a Checksum declaration
- a Custom Field declaration
- a Test declaration
Enum
enum_declaration:
enum
IDENTIFIER:
INTEGER{
enum_tag_list
}
enum_tag_list:
enum_tag (,
enum_tag)*,
?enum_tag:
IDENTIFIER=
INTEGER
An enumeration or for short enum, is a declaration of a set of named integer constants.
The integer following the name specifies the bit size of the values.
enum CoffeeAddition: 3 {
Empty = 0,
Cream = 1,
Vanilla = 2,
Chocolate = 3,
Whisky = 4,
Rum = 5,
Kahlua = 6,
Aquavit = 7
}
Packet
packet_declaration:
packet
IDENTIFIER
(:
IDENTIFIER
((
constraint_list)
)?
)?
{
field_list?
}
A packet is a declaration of a sequence of fields.
A packet can optionally inherit from another packet declaration. In this case the packet inherits the parent's fields and the child's fields replace the _payload_ or _body_ field of the parent.
When inheriting, you can use constraints to set values on parent fields. See constraints for more details.
packet Error {
code: 32,
_payload_
}
packet ImATeapot: Error(code = 418) {
brand_id: 8
}
Struct
struct_declaration:
struct
IDENTIFIER
(:
IDENTIFIER
((
constraint_list)
)?
)?
{
field_list?
}
A struct follows the same rules as a packet with the following differences:
- It inherits from a struct declaration instead of packet declaration.
- A typedef field can reference a struct.
Group
group_declaration:
group
IDENTIFIER{
field_list
}
A group is a sequence of fields that expand in a packet or struct when used.
See also the Group field.
group Paged {
offset: 8,
limit: 8
}
packet AskBrewHistory {
pot: 8, // Coffee Pot
Paged
}
behaves like:
packet AskBrewHistory {
pot: 8, // Coffee Pot
offset: 8,
limit: 8
}
Checksum
checksum_declaration:
checksum
IDENTIFIER:
INTEGER STRING
A checksum is a native type (not implemented in PDL). See your generator documentation for more information on how to use it.
The integer following the name specify the bit size of the checksum value. The string following the size is a value defined by the generator implementation.
checksum CRC16: 16 "crc16"
Custom Field
custom_field_declaration:
custom_field
IDENTIFIER (:
INTEGER)? STRING
A custom field is a native type (not implemented in PDL). See your generator documentation for more information on how to use it.
If present, the integer following the name specify the bit size of the value. The string following the size is a value defined by the generator implementation.
custom_field URL "url"
Test
test_declaration:
test
IDENTIFIER{
test_case_list
}
test_case_list:
test_case (,
test_case)*,
?test_case:
STRING
A test declares a set of valid octet representations of a packet identified by its name. The generator implementation defines how to use the test data.
A test passes if the packet parser accepts the input; if you want to test the values returned for each field, you may specify a derived packet with field values enforced using constraints.
packet Brew {
pot: 8,
addition: CoffeeAddition
}
test Brew {
"\x00\x00",
"\x00\x04"
}
// Fully Constrained Packet
packet IrishCoffeeBrew: Brew(pot = 0, additions_list = Whisky) {}
test IrishCoffeeBrew {
"\x00\x04"
}
Constraints
constraint:
IDENTIFIER=
IDENTIFIER | INTEGERconstraint_list:
constraint (,
constraint)*,
?
A constraint defines the value of a parent field. The value can either be an enum tag or an integer.
group Additionable {
addition: CoffeAddition
}
packet IrishCoffeeBrew {
pot: 8,
Additionable {
addition = Whisky
}
}
packet Pot0IrishCoffeeBrew: IrishCoffeeBrew(pot = 0) {}
Fields
field_list:
field (,
field)*,
?field:
checksum_field |
padding_field |
size_field |
count_field |
payload_field |
body_field |
fixed_field |
reserved_field |
array_field |
scalar_field |
typedef_field |
group_field
A field is either:
- a Scalar field
- a Typedef field
- a Group field
- an Array field
- a Size field
- a Count field
- a Payload field
- a Body field
- a Fixed field
- a Checksum field
- a Padding field
- a Reserved field
Scalar
scalar_field:
IDENTIFIER:
INTEGER
A scalar field defines a numeric value with a bit size.
struct Coffee {
temperature: 8
}
Typedef
typedef_field:
IDENTIFIER:
IDENTIFIER
A typedef field defines a field taking as value either an enum, struct, checksum or a custom_field.
packet LastTimeModification {
coffee: Coffee,
addition: CoffeeAddition
}
Array
array_field:
IDENTIFIER:
INTEGER | IDENTIFIER[
SIZE_MODIFIER | INTEGER
]
An array field defines a sequence of N
elements of type T
.
N
can be:
- An integer value.
- A size modifier.
- Unspecified: In this case the array is dynamically sized using a _size_ or a _count_.
T
can be:
- An integer denoting the bit size of one element.
- An identifier referencing an enum, a struct or a custom field type.
packet Brew {
pots: 8[2],
additions: CoffeeAddition[2],
extra_additions: CoffeeAddition[],
}
Group
group_field:
IDENTIFIER ({
constraint_list}
)?
A group field inlines all the fields defined in the referenced group.
If a constraint list constrains a scalar field or typedef field with an enum type, the field will become a fixed field. The fixed field inherits the type or size of the original field and the value from the constraint list.
See Group Declaration for more information.
Size
size_field:
_size_
(
IDENTIFIER |_payload_
|_body_
)
:
INTEGER
A _size_ field is a scalar field with as value the size in octet of the designated array, _payload_ or _body_.
packet Parent {
_size_(_payload_): 2,
_payload_
}
packet Brew {
pot: 8,
_size_(additions): 8,
additions: CoffeeAddition[]
}
Count
count_field:
_count_
(
IDENTIFIER)
:
INTEGER
A _count_ field is a scalar field with as value the number of elements of the designated array.
packet Brew {
pot: 8,
_count_(additions): 8,
additions: CoffeeAddition[]
}
Payload
payload_field:
_payload_
(:
[
SIZE_MODIFIER]
)?
A _payload_ field is a dynamically sized array of octets.
It declares where to parse the definition of a child packet or struct.
A _size_ or a _count_ field referencing the payload induce its size.
If used, a size modifier can alter the octet size.
Body
body_field:
_body_
A _body_ field is like a _payload_ field with the following differences:
- The body field is private to the packet definition, it's accessible only when inheriting.
- The body does not accept a size modifier.
Fixed
fixed_field:
_fixed_
=
( INTEGER:
INTEGER ) |
( IDENTIFIER:
IDENTIFIER )
A _fixed_ field defines a constant with a known bit size. The constant can be either:
packet Teapot {
_fixed_ = 42: 8,
_fixed_ = Empty: CoffeeAddition
}
Checksum
checksum_field:
_checksum_start_
(
IDENTIFIER)
A _checksum_start_ field is a zero sized field that acts as a marker for the beginning of the fields covered by a checksum.
The _checksum_start_ references a typedef field with a checksum type that stores the checksum value and selects the algorithm for the checksum.
checksum CRC16: 16 "crc16"
packet CRCedBrew {
crc: CRC16,
_checksum_start_(crc),
pot: 8,
}
Padding
padding_field:
_padding_
[
INTEGER]
A _padding_ field adds a number of octet of padding.
packet Padded {
_padding_[1] // 1 octet/8bit of padding
}
Reserved
reserved_field:
_reserved_
:
INTEGER
A _reserved_ field adds reserved bits.
packet DeloreanCoffee {
_reserved_: 2014
}
Tokens
Integer
INTEGER:
HEXVALUE | INTVALUEHEXVALUE:
0x
|0X
HEXDIGIT+INTVALUE:
DIGIT+HEXDIGIT:
DIGIT | [a
-f
] | [A
-F
]DIGIT:
[0
-9
]
A integer is a number in base 10 (decimal) or in base 16 (hexadecimal) with
the prefix 0x
String
STRING:
"
(!"
ANY)*"
A string is sequence of character. It can be multi-line.
Identifier
IDENTIFIER:
ALPHA (ALPHANUM |_
)*ALPHA:
[a
-z
] | [A
-Z
]ALPHANUM:
ALPHA | DIGIT
An identifier is a sequence of alphanumeric or _
characters
starting with a letter.
Size Modifier
SIZE_MODIFIER:
+
|-
|*
|/
DIGIT |+
|-
|*
|/
Part of a arithmetic expression where the missing part is a size
For example:
+ 2
defines that the size is 2 octet bigger than the real size* 8
defines that the size is 8 times bigger than the real size
Comment
COMMENT:
BLOCK_COMMENT | LINE_COMMENTBLOCK_COMMENT:
/*
(!*/
ANY)*/
LINE_COMMENT:
//
(!\n ANY)//
Whitespace
WHITESPACE:
|
\t
|\n