Dsl syntax

caution

This doc is written manually. The implementation may differ. If it does, then either this doc is wrong or the implementation is wrong. In any case, them disagreeing is a bug. Please file an issue!

warning

While something may be valid to be parsed, it may not be valid as a construct and may generate an error deeper down.

Top-level item is Device.

  • '*' is used to signal 0 or more instances.
  • '?' is used to signal 0 or 1 instances.
  • '|' is used as an 'or'. One of the options in the chain can be used.
  • '( )' is used to group things together.
  • Any keyword or brackets in the grammer use backticks just like word 'keyword' on this line.

This doesn't map perfectly on the YAML and JSON inputs, but they should be made as close as possible.

Device:

GlobalConfigList
ObjectList

GlobalConfigList:

(config { GlobalConfig* })?

GlobalConfig:

(type DefaultRegisterAccess = Access;)
| (type DefaultFieldAccess = Access;)
| (type DefaultBufferAccess = Access;)
| (type DefaultByteOrder = ByteOrder;)
| (type DefaultBitOrder = BitOrder;)
| (type RegisterAddressType = IntegerType;)
| (type CommandAddressType = IntegerType;)
| (type BufferAddressType = IntegerType;)
| (type NameWordBoundaries = NameWordBoundaries;)
| (type DefmtFeature = String;)

NameWordBoundaries: This specifies the input, not the output. Only applies to object and field names.

[Boundary*]
| String

ObjectList:

(Object(, Object)*,?)?

Object:

Block
| Register
| Command
| Buffer
| RefObject

RefObject: An object that is a copy of another object. Any items in the object are overrides.

AttributeList ref IDENTIFIER = Object

AttributeList:

Attribute*

Attribute: Used for documentation and conditional compilation

(# [ doc = STRING])
| (# [ cfg ( ConfigurationPredicate) ])

Block:

AttributeList
block IDENTIFIER { BlockItemList ObjectList }

BlockItemList:

BlockItem*

BlockItem:

(const ADDRESS_OFFSET = INTEGER;)
| (const Repeat)

Register:

AttributeList
register IDENTIFIER { RegisterItemList FieldList }

RegisterItemList:

RegisterItem*

RegisterItem:

(type Access = Access;)
| (type ByteOrder = ByteOrder;)
| (type BitOrder = BitOrder;)
| (const ADDRESS = INTEGER;)
| (const SIZE_BITS = INTEGER;)
| (const RESET_VALUE = INTEGER | U8_ARRAY;)
| (const Repeat)
| (const ALLOW_BIT_OVERLAP = BOOL;)
| (const ALLOW_ADDRESS_OVERLAP = BOOL;)

Access:

(ReadWrite|RW)
| (ReadOnly|RO)
| (WriteOnly|WO)

ByteOrder:

LE|BE

BitOrder:

LSB0|MSB0

FieldList:

(Field (, Field)* ,?)

Field:

AttributeList
IDENTIFIER: Access? BaseType FieldConversion? = FieldAddress

FieldConversion:

(as try? TYPE_PATH)
| (as try? enum IDENTIFIER { EnumVariantList})

EnumVariantList:

EnumVariant(, EnumVariant)*,?

EnumVariant:

AttributeList
IDENTIFIER (= EnumValue)?

EnumValue:

INTEGER|default|catch_all

FieldAddress:

INTEGER
| (INTEGER..INTEGER)
| (INTEGER..=INTEGER)

BaseType:

bool | uint | int

Command:

AttributeList
command IDENTIFIER CommandValue?

CommandValue:

(= INTEGER)
| ({ CommandItemList (in { FieldList } ,?)? (out { FieldList } ,?)? })

CommandItemList:

CommandItem*

CommandItem: Commands have data going in and out, so they need two separate data field types. If no in fields, then no data is sent. If no out fields, then no data is returned.

(type ByteOrder = ByteOrder;)
| (type BitOrder = BitOrder;)
| (const ADDRESS = INTEGER;)
| (const SIZE_BITS_IN = INTEGER;)
| (const SIZE_BITS_OUT = INTEGER;)
| (const Repeat)
| (const ALLOW_BIT_OVERLAP = BOOL;)
| (const ALLOW_ADDRESS_OVERLAP = BOOL;)

Repeat:

REPEAT = { count : INTEGER, stride : INTEGER,? } ;

Buffer:

AttributeList
buffer IDENTIFIER(: Access)? (= INTEGER)?