Index: uspace/app/bithenge/script.c
===================================================================
--- uspace/app/bithenge/script.c	(revision c54f5d03a061e8e9f942e16a8c19519c300e536a)
+++ uspace/app/bithenge/script.c	(revision 71450c851fb728ac6d9a6f1118949d81152b67e9)
@@ -537,7 +537,32 @@
 static bithenge_expression_t *parse_postfix_expression(state_t *state)
 {
+	int rc;
 	bithenge_expression_t *expr = parse_term(state);
 	while (state->error == EOK) {
-		if (state->token == '[') {
+		if (state->token == '.') {
+			next_token(state);
+
+			const char *id = expect_identifier(state);
+
+			if (state->error != EOK) {
+				free((char *)id);
+				bithenge_expression_dec_ref(expr);
+				return NULL;
+			}
+
+			bithenge_node_t *key = NULL;
+			rc = bithenge_new_string_node(&key, id, true);
+			if (rc != EOK) {
+				error_errno(state, rc);
+				bithenge_expression_dec_ref(expr);
+				return NULL;
+			}
+
+			rc = bithenge_member_expression(&expr, expr, key);
+			if (rc != EOK) {
+				error_errno(state, rc);
+				return NULL;
+			}
+		} else if (state->token == '[') {
 			next_token(state);
 			bithenge_expression_t *start = parse_expression(state);
@@ -563,6 +588,6 @@
 				return NULL;
 			}
-			int rc = bithenge_subblob_expression(&expr, expr,
-			    start, limit, absolute_limit);
+			rc = bithenge_subblob_expression(&expr, expr, start,
+			    limit, absolute_limit);
 			if (rc != EOK) {
 				error_errno(state, rc);
Index: uspace/dist/src/bithenge/usbdesc.bh
===================================================================
--- uspace/dist/src/bithenge/usbdesc.bh	(revision c54f5d03a061e8e9f942e16a8c19519c300e536a)
+++ uspace/dist/src/bithenge/usbdesc.bh	(revision 71450c851fb728ac6d9a6f1118949d81152b67e9)
@@ -7,10 +7,14 @@
 # Originally by Vojtech Horky.
 
+# Block prefixed with a byte length
+transform block = (in.data) <- struct {
+	.bLength <- uint8;
+	.data <- known_length(.bLength - 1);
+};
+
 # USB configuration descriptor
 # This is not the full configuration descriptor (i.e. with interface
 # and endpoint descriptors included) but only the header. 
 transform usb_configuration_descriptor_bare = struct {
-	.bLength <- uint8; # assert bLength = 9
-	.bDescriptorType <- uint8; # assert: bDescriptorType == 2
 	.wTotalLength <- uint16le;
 	.bNumInterfaces <- uint8;
@@ -23,6 +27,4 @@
 # USB interface descriptor
 transform usb_interface_descriptor = struct {
-	.bLength <- uint8; # assert bLength = 9
-	.bDescriptorType <- uint8; # assert: bDescriptorType == 4
 	.bInterfaceNumber <- uint8;
 	.bAlternateSetting <- uint8;
@@ -36,6 +38,4 @@
 # USB endpoint descriptor
 transform usb_endpoint_descriptor = struct {
-	.bLength <- uint8; # assert bLength = 7
-	.bDescriptorType <- uint8; # assert: bDescriptorType == 5
 	.bEndpointAddress  <- uint8;
 	.bmAttributes <- uint8;
@@ -46,21 +46,23 @@
 # USB HID descriptor
 transform usb_hid_descriptor = struct {
-	.bLength <- uint8;
-	.bDescriptorType <- uint8; # assert: bDescriptorType == 33
 	.bcdHID <- uint16le;
 	.bCountryCode <- uint8;
 	.bNumDescriptors <- uint8;
-	# Following is repeated bNumDescriptors times
-	.bDescriptorType <- uint8;
-	.wDescriptorLength <- uint16le;
+	<- repeat(.bNumDescriptors) { struct {
+		.bDescriptorType <- uint8;
+		.wDescriptorLength <- uint16le;
+	} };
 };
 
-# Fixed configuration for QEMU USB keyboard. 
-transform qemu_usb_keyboard = struct {
-	.configuration_descriptor <- usb_configuration_descriptor_bare;
-	.interface_descriptor <- usb_interface_descriptor;
-	.hid_descriptor <- usb_hid_descriptor;
-	.endpoint_descriptor <- usb_endpoint_descriptor;
-}; 
+# USB descriptor
+transform usb_descriptor = struct {
+	.bDescriptorType <- uint8;
+	<- switch (.bDescriptorType) {
+		 2: usb_configuration_descriptor_bare;
+		 4: usb_interface_descriptor;
+		 5: usb_endpoint_descriptor;
+		33: usb_hid_descriptor;
+	};
+} <- block;
 
-transform main = qemu_usb_keyboard;
+transform main = repeat { usb_descriptor };
