-
Notifications
You must be signed in to change notification settings - Fork 2
declarations
HS uses variables for storing values. All variables have an identifier (name) , and a data type.
_Data type _specifies the internal storage format of the data. Variables can be declared with any of the available data types, and variables can easily be converted from one data type to another. Undeclared variables are created automatically with the list data type when they are initially assigned a value.
_Vectors _can be used to store indexed collections of the same data type, while lists and structures can be aggregates of arbitrary data types.
All variables may use subscript [ ] brackets to reference individual element values. Subscript indices start at zero.
Every name (identifier) in HS has one of the following fundamental data types associated with it:
boolean
str
char
uchar
binary
hex
octal
byte
ubyte
short
ushort
long
ulong
float
double
int
handle
_
This data type determines what operations can be applied to the name, and how such operations are interpreted.
A declaration is used to associate a data type with a name. For example:
char ch;
str s;
int count = 1;
float pi = 3.141592;
str name = "Hyper";
str seasons = { "winter", "spring", "summer", "fall" };
list Date = { int d, int m, int y };
int day ( str rDate ) { day = rDate->d; };
list WAFER = {}; /* Initialized to empty */
_
Some of these examples show that a declaration can also be a definition. For Date, it is a structure definition, and for day, it is a function definition.
A name can be undeclared (removed) using the undef statement. For example:
undef pi; /* pi is now undefined */
_
The variable, pi, must be declared or initialized to be used again.
Some of these declarations assign values. For example, _pi _is assigned the value 3.141592. If no value was assigned, then _pi _would have been initialized to zero. All declared variables except those of type char, str, and list are initialized to zero if no value is assigned.
Variables can be initialized to empty by assigning to '{}'. In the example above, WAFER is initialized to empty.
Conversions are performed implicitly when mixing types in assignments and expressions. There are rules for how types are implicitly converted when mixing with other types. When you want to be sure about how the types are converted, use explicit type conversion.
In addition, variables can be converted from one data type to another.
Explicit type conversion, or typecasting, can be specified a number of ways. For example, the following equivalent statements all convert the variable x to type int:
i = (int) x;
i = int x;
i = int (x);
i = (int) (x);
_
If x is a list or vector, then the conversion operation will typecast each element of x to type int.
In most cases, HS will correctly perform the appropriate type conversions implicitly, but explicit conversion is occasionally necessary. For example:
put ( "1.2" + 3 );
_
produces "1.23" because the implicit conversion rules (see below) promote 3 to type str.
Thus, the following:
float f = "1.2" + 3;
_
assigns to f the value 1.23, which might not be what was intended. To be sure, use explicit conversion as follows:
float f = float ( "1.2" ) + 3;
_
Integral and floating-point types can be mixed freely in assignments and expressions because type conversions are performed implicitly with the intent to minimize information loss. However, not all conversions will preserve values and information can be lost if you are not careful.
This section explains the conversion rules and what to watch out for.
Implicit type conversions that preserve values are called promotions. In a binary expression where the operands are not the same data type, one of the arguments must be converted to match the data type of the other operand. Rules are applied in the following order when dealing with mixed operands:
- If one of the operands is a string, the other operand is converted to a string.
- If one of the operands is a float, the other operand is converted to a float.
- If one of the operands is an integer, the other operand is converted to an integer.
An integer can be converted to another integer type. A conversion is simply a copy of as many bits from the source as will fit into the destination. High-order bits are thrown away if necessary. For example:
ubyte ub = 1023; /* binary 0x000003ff becomes binary 0xff, or 255 */
_
The boolean type also can be converted to its integer equivalent.
A floating-point value can be converted into another floating-point type. If the source value can be exactly represented in the destination type, the result is the original floating-point value. If the source value is between two adjacent destination values, the result is one of those values. Otherwise, the conversion produces inf if the source value is greater than the maximum positive number, -inf if the source value is less than the minimum negative number, and zero if the absolute value of the source is less than the smallest possible fractional decimal. For example:
float f = 4.028234e+38; /* largest float value */
double d = f; /* OK, d == f */
float f2 = d; /* OK, f2 == d */
double d3 = 1.7976931348623157e+308; /* largest double value */
float f3 = d3; /* inf */
double d4 = 4.940656458412465E-324; /* smallest double fraction */
float f4 = d4; /* zero */
_
When converting a floating-point value to an integer the fractional part is truncated. If the truncated value cannot be represented in the destination type, the high order bits are discarded. For example:
int i = 2.6; /* i becomes 2 */
byte b = 300.7; /* b becomes 44 */
_
The last example makes sense when we examine what conversions take place. First, 300.7 is truncated to 300. Since 300 is too big to fit into a byte, the high order bits are discarded, and we end up with the value, 44.
Conversions from integer to floating-point are performed as the hardware allows. For example:
int i = float ( 1234567890 );
_
assigns i the value, 1234567936.
Strings and numbers (integers or floating-point) can be used freely together in assignments and in certain expressions. For example:
int i = "10"; /* i becomes 10 */
str s = 10; /* s becomes "10" */
float f = "1.2"; /* f becomes 1.2 */
_
An expression involving addition of strings and numbers converts the numbers to strings and performs string concatenation. For example:
str s = 10 + "1.2"; /* s becomes "101.2" */
float f = 10 + "1.2"; /* f becomes 101.2 */
_
Note that string subtraction is valid, as in:
float f = 101.2 - "1.2"; /* f becomes 10 */
_
Strings and numbers cannot be mixed in expressions where string operations are undefined. For example:
float f = "1.2" * 2; /* UNDEFINED: string multiplication */
_
Variable data types can easily be converted from one type to another, following the conversion rules explained above. For example:
int i = { 1, 2, 3, 4, 5 };
float i; /* i becomes { 1., 2., 3., 4., 5. } */
str i; /* i becomes { "1", "2", "3", "4", "5" } */
_
Converting between the _str _data type and the char and uchar data types provides the means for individual character string manipulation.
str a = "abc"; /* Start with a string of three characters */
char a; /* Convert to a vector of characters */
a = a + 23; /* Add 23 to each of the values */
str a; /* Convert back to a str. The value of 'a' is now "xyz" */
_
The conversion of "abc" to "xyz" can also be done more compactly:
a = str ( char ( char ("abc" ) + 23 ) );
_