Modula-2 (на английском языке) (1161147), страница 2
Текст из файла (страница 2)
F1 : INTEGER;
CASE : BOOLEAN OF
TRUE : X : REAL; |
FALSE: Y : LONGINT;
END;
END;
CONST
varrecf = varrec{1, FALSE, 12};
varrect = varrec{1, TRUE, 1.5};
Set constants
Set constants have the following syntax:
SetType {element {,element}}
element is:
expression [..expression]
where expression is a compile time constant expression assignable to the base type of the set.
If the .. form is used, all elements within the range of the two expressions are included in the set.
Examples:
BITSET{1, 3..5}
ColorSet{Red, Blue}
ColorSet{Red..Blue}
Type declarations
Type declarations create new named data types. The format for type declarations is:
TYPE {Name = TypeSpecification;}
Name is the name of the new type.
TypeSpecification can be:
-
a type name
-
a basic type
-
an enumeration type
-
a subrange
-
a pointer type
-
a set type
-
an array type
-
a record type
-
a procedure type
If the TypeSpecification is a type name, the new type is equivalent to the named type. Otherwise, a new type is created.
Examples:
TYPE
Integer = INTEGER;
SmallInt = [-10..10];
Color = (Red, Green, Blue);
CharPointer = POINTER TO CHAR;
ColorSet = SET OF COLOR;
String = ARRAY [0..255] OF CHAR;
Complex = RECORD A,B : REAL; END;
RealFunc = PROCEDURE(REAL) : REAL;
Basic types- ISO Standard Defined Types
The following table lists the pre-declared types in the Modula-2 language. The identifiers for these types are automatically defined in every Modula-2 module.
Type | Storage size | Range |
INTEGER | 16-bit compiler: 2 bytes | -32768 to 32767 |
CARDINAL | 16-bit compiler: 2 bytes | 0 to 65535 |
REAL | 4 bytes | Real numbers with an approximate range of 8.43E-37 to 3.37E+38 and an accuracy of about 7 decimal digits |
LONGREAL | 8 bytes | Real numbers with an approximate range of 4.19E-307 to 1.67E+308 and an accuracy of about 16 decimal digits |
COMPLEX | 8 bytes | Complex numbers where the real and imaginary Components are of type REAL |
LONGCOMPLEX | 16 bytes | Complex numbers where the real and imaginary Components are of type LONGREAL |
BOOLEAN | 1 byte | An enumeration type with the values FALSE and TRUE |
CHAR | ANSI (8-bit): 1 byte | A character in the ANSI (8-bit) or Unicode (16-bit) character set. |
BITSET | 2 bytes | A PACKEDSET type with an ordinal range of CARDINAL[0..15] |
Enumerations
An enumeration is a list of identifiers that denote the values which constitute a data type. These identifiers are used as constants in the program. They, and no other values, belong to this type. The values are ordered, and the ordering relation is defined by their sequence in the enumeration. The ordinal number of the first value is 0.
enumeration = "(" IdentList ")".
IdentList = ident {" ," ident}.
Examples of enumerations:
(red, green, blue)
(club, diamond, heart, spade)
(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday)
Subrange types
You can create subranges of any signed integer, unsigned integer, character and enumeration type. The subrange type restricts the values allowed for the type, but leaves the same operations applicable.
To specify a subrange type, use the following format:
[typename][expression..expression]
The two expressions must be constructed solely of constants. The first expression specifies the lowest value of the subrange and the second specifies the highest value of the subrange.
If you do not specify typename, the two expressions must be compatible and the subrange must be a subrange of the type of the expressions.
If the expressions are both integer expressions, use the following rules to determine the type from which the subrange is derived:
-
If the lower bound is greater than or equal to zero:
-
if the upper bound is less than or equal to the maximum of type CARDINAL, the subrange will be of type CARDINAL.
-
otherwise, the type is LONGINT
-
If the lower bound is less than zero:
-
if both bounds are within the range of type INTEGER, the type is INTEGER.
-
otherwise, the type is LONGINT.
You can specify typename to override the above conventions or for documentary purposes. If typename is specified, both expressions must be compatible with it.
Examples:
TYPE
SmallInt = [-128..128];
SmallCard = [0..255];
UpperCaseLetters = CHAR['A'..'Z']
Pointer types
Pointer types have values that are memory addresses. A pointer type is bound to a specific object type, so the value of the pointer is the address of an object of a specific type.
To specify pointer types, use:
POINTER TO TypeName
Example:
POINTER TO CHAR
The constant NIL is compatible with all pointer types, and designates a pointer that does not point to any object. NIL can be assigned to any pointer type, and any pointer type can be compared to NIL.
Allocating pointers
Generally, pointers are set by allocating a block of memory for the object that they point to. The NEW standard procedure and the ALLOCATE procedure in the ISO module Storage performs this function. You can deallocate the memory with the DISPOSE standard procedure, or the DEALLOCATE procedure. The ALLOCATE and DEALLOCATE procedures are exported from the ISO module Storage.
Dereferencing pointers
Dereferencing is used to refer to the object that a pointer variable points to. You dereference a pointer as follows:
variable^
Note: Be sure to assign a value to a pointer before dereferencing it. If an uninitialized pointer is dereferenced, it might refer to any location in memory which will probably result in a runtime error.
Set types
Set types have values that specify a subset of a set of objects. The objects can be:
-
positive integers
-
characters
-
an enumeration type
-
a subrange of any of the above
To specify a set type, use:
SET OF TypeSpecification;
PACKEDSET OF TypeSpecification;
TypeSpecification is called the base type of the set.
You can think of a set type as having a Boolean membership flag for each value in the base type.
Modula-2 supports two different types of sets, SET and PACKEDSET. The only difference between the two is how a compiler is allowed to implement a set type. PACKEDSET types are implemented such that each ordinal value in the set maps directly to individual bits in the memory storage for the set type. The first ordinal value occupies the first bit and this continues until the last bit. A compiler is allowed to implement the SET type in any way it chooses.
Note: Stony Brook Modula-2 implements the SET type the same as the PACKEDSET type.
Example:
SET OF CHAR
SET OF [0..65535]
SET OF ['A'..'Z']
SET OF (Red, Green, Blue)
An object with the type of the last example above can have any of the following values:
{}
{Red}
{Green}
{Red, Green}
{Blue}
{Red, Blue}
{Green, Blue}
{Red, Green, Blue}
Array types
An array type is a sequence of components of some other type. The components of an array are distinguished by an index, which also has a specific type. You can define arrays of arrays to represent two or greater than two-dimensional structures.
To define arrays, use:
ARRAY indextype {,indextype} OF elementtype
Each indextype must be BOOLEAN, CHAR, an enumeration type, or a subrange type. A component of the array is defined for each combination of index values.
The elementtype can be any type, including array types. An array type with multiple indextypes is simply shorthand for an array type with an array type as the element type.
Examples:
ARRAY [1..10] OF REAL;
ARRAY INTEGER[1..10] OF REAL;
ARRAY CHAR OF BOOLEAN;
ARRAY [1..10], [1..10] OF REAL;
Subscripting
You refer to a component of an array by subscripting an array variable. Subscripting is specified as follows:
variable[expression{,expression}]
The expressions must be assignable to the index types with which the array variable was declared. The values of the expressions must lie within the range specified by the index type.
If an index expression is outside the range of the index type, and the module was compiled with index checking turned on, the program generates a runtime error.
Record types
Record types are structures that contain named components. The named components can be of different types. The components of a record are called fields.
Parts of a record can have multiple definitions to allow the information stored in a record to vary according to different needs. These parts are called variant sections.
The identifier following CASE in variant sections is called the tag field of the variant section. Its value indicates which variant is present in the record.
To specify record types, use:
RECORD
FieldListSequence
END
FieldListSequence is:
FieldList {;FieldList}
FieldList is either of the following:
identifier {,identifier}: TypeSpecification
or
CASE [identifier] : TypeName OF
variant {|variant}
[ELSE FieldListSequence]
END
Variant is:
[ CaseRange {,CaseRange}: FieldListSequence ]
CaseRange is:
expression [..expression] {, expression [..expression]}
Examples:
RECORD
X, Y : REAL;
END
This record has two fields, X and Y, both of type REAL. This record might be used to represent a point in a plane.
RECORD
NEXT : NodePointer;
CASE NT : NodeType OF
Operator:
op : OperatorType;
left, right : NodePointer;
|
Operand:
value : REAL;
END;
END
This record has one field, NEXT, followed by a variant section. The variant section has two variants, one for the NodeType Operator and one for Operand.
A variant in a RECORD must handle all possible values of the tag field type. Thus if the CASE selector arms do not handle all possible values you must have an ELSE section in the CASE. The ELSE section can be empty. In this way you are informing the compiler you understand that all values are not handled and this is the necessary behavior.
Field selection
You can select a field of a record type variable as follows:
variable.field
Where variable is a record variable and field is the name of the field.
If the field is a part of a variant section with a tag field specified, it is an error to refer to any field in a variant other than the one specified by the tag field.
If you refer to a field in an incorrect variant, and the module was compiled with variant checking on, the program generates a runtime error.
Copying of variant records
The compiler allocates variables of variant record types the maximum amount of memory needed by any variant. These variables are, therefore, capable of holding any variant, and copying one record to another will work correctly.
If you use the NEW standard procedure to allocate a variant record and specify the values of the tag fields, the compiler allocates only enough memory for the specific variants you selected.
You cannot do assignments of the entire record to records allocated in that way, because the amount of space allocated might not be large enough to hold the record you are assigning.
If you intend to do an assignment of the whole record, use NEW without specifying any tags. In this case, the compiler allocates space for the largest variant.
Example:
TYPE VARREC =
RECORD