3.2 Data Types
This section discusses the basic data types in e.
3.2.1 Scalar Types
Scalar types in e are one of the following:
-
Numeric
-
Boolean
-
Enumerated
3.2.1.1 Numeric and Boolean Scalar Types
Table 3-6 shows predefined numeric and boolean types in e.
Table 3-6. Scalar Types
Type Name |
Function |
Usage Example |
---|---|---|
int |
Represents numeric data, both negative and non-negative integers. Default Size = 32 bits |
length: int; |
uint |
Represents unsigned numeric data, non-negative integers only. Default Size = 32 bits |
delay: uint; |
bit |
An unsigned integer in the range 0–1. Size = 1 bit |
valid: bit; // 1-bit field |
byte |
An unsigned integer in the range 0–255. Size = 8 bits |
data: byte; // 8-bit field |
time |
An integer in the range 0–263-1. Default Size = 64 bits |
delay: time; //64-bit time variable |
bool |
Represents truth (logical) values, TRUE (1) and FALSE (0). Default Size = 1 bit |
frame_valid: bool; //TRUE or |
3.2.1.2 Enumerated Scalar Types
Enumerated types define the valid values for a variable or field as a list of symbolic constants. For example, the following declaration defines the variable instr_kind as having two legal values.
<' //Implicit enumerated type. immediate=0, register=1 type instr_kind: [immediate, register]; '>
These symbolic constants have associated unsigned integer values. By default, the first name in the list is assigned the value zero. Subsequent names are assigned values based upon the maximum value of the previously defined enumerated items + 1.
It is also possible to assign explicit unsigned integer values to the symbolic constants. This method is used when the enumerated types may not be defined in a particular order.
<' //Explicit enumerated type. immediate=4, register=8 type instr_kind: [immediate=4, register=8]; '>
It is sometimes convenient to introduce a named enumerated type as an empty type.
'> type packet_protocol: []; //Define empty type '>
Once the protocols that are meaningful in the program are identified the definition of the type can be extended.
'> //Extend this type in a separate file. //No need to touch the original file. extend packet_protocol : [Ethernet, IEEE, foreign]; //Define a struct that uses a field of the above type. struct packet { kind: packet_protocol; //Define a field of type //packet_protocol. Three possible values. }; '>
3.2.1.3 Scalar Subtypes
A subtype can be created from one of the following:
-
A predefined numeric or boolean type (int, uint, bool, bit, byte, time)
-
A previously defined enumerated type
-
A previously defined scalar subtype
Creation of subtypes is shown in the example below.
<' //Define an enumerated type opcode type opcode: [ADD, SUB, OR, AND]; //Define a subtype using the previously defined type //This subtype includes opcodes for logical operations //OR, AND type logical_opcode: opcode [OR, AND]; //Define a subtype of a predefined scalar type, 4 bit //unsigned vector type small: uint(bits:4); //Define a struct that uses the above types struct instruction { op1: opcode; //Field of type opcode op2: logical_opcode; //Field of type logical_opcode length: small; //4 bit unsigned vector }; '>
3.2.2 List Types
List types hold ordered collections of data elements. Items in a list can be indexed with the subscript operator [ ], by placement of a non-negative integer expression in the brackets. List indexes start at zero. You can select an item from a list by specifying its index. For example, my_list[0] refers to the first item in the list named my_list. Lists can be of any type. However, a list of lists is not allowed. All items in a list must be of the same type. Lists are dynamically resizable and they come with many predefined methods.
Lists are defined by using the list of keyword in a variable or a field definition.
<' struct packet { addr: uint(bits:8); // 8-bit vector data1: list of byte; //List of 8-bit values }; struct sys { packets[10]: list of packet; //List of 10 packet structures values: list of uint(bits:128); //List of 128-bit vectors }; '>
e does not support multidimensional lists (lists of lists). To create a list with sublists in it, you can create a struct to contain the sublists, and then create a list of such structs as the main list. In the example above, the packet struct contains a list of bytes. In sys struct, there is a list of 10 packets. Thus, sys contains a list of lists.
3.2.2.1 Keyed Lists
A keyed list data type is similar to hash tables or association lists found in other programming languages. Keyed lists are defined with the keyword key. The declaration below specifies that packets is a list of packets, and that the protocol field in the packet type is used as the hash key. Keyed lists are very useful for searching through a list with a key.
<' type packet_protocol : [Ethernet, IEEE, foreign]; struct packet { protocol: packet_protocol; }; struct dtypes { m() is { //Method definition explained later in book // Define local variable, keyed list var packets : list (key: protocol) of packet; }; }; '>
3.2.3 The String Type
A string data type contains a series of ASCII characters enclosed by quotes (“ ”). An example of string declaration and initialization is shown below.
<' struct dtypes { m() is { //Define a method (procedure) var message: string; //Define a variable of type string message = "Beginning initialization sequence..."; //String value print message; //Print string }; }; '>