Modula-2 (на английском языке) (1161147), страница 3
Текст из файла (страница 3)
CASE Tag : INTEGER OF
1: R : REAL; |
2: L : LONGREAL;
ELSE
END;
END;
VAR
A : VARREC;
B : POINTER TO VARREC;
BEGIN
NEW(B);
B^ := A; (* Correct *)
NEW(B, 1);
B^ := A; (* Incorrect *)
END;
Procedure types
Procedure type objects have the addresses of procedures as values. Specify procedure types as follows:
PROCEDURE [(ParameterList) [: ReturnType] ]
ParameterList is:
[Parameter {,Parameter}]
Parameter is:
[VAR] [ARRAY OF {ARRAY OF}] TypeName
For detailed information on the VAR, INOUT, OUT, FAR, NEAR, VALUE and NOHIGH identifiers see the Procedures topic of this file.
ReturnType is the type of value returned by procedures. It must be a type name and may be qualified by a module name.
Example:
TYPE Func = PROCEDURE(REAL) : REAL;
Variables of procedure types can be assigned the value of a procedure that has the same types of parameters and return value, and the same attributes.
Only procedures that are not contained in other procedures can be assigned as the values of procedure variables. Standard procedures cannot be assigned as the values of procedure variables.
Using procedure types
Procedure types are often used as parameters to other procedures. This is useful when the procedure specifies an algorithm that involves calling another procedure or function, and the called procedure or function varies from one call to the next.
A good example of the use of procedure types is a numeric integration procedure. The procedure implements the algorithm of numeric integration but the function being integrated is passed in as a parameter:
PROCEDURE Integrate(X1, X2 : REAL;
NumPoints : CARDINAL;
Function : Func) : REAL;
VAR
Sum : REAL;
i : CARDINAL;
X, DX : REAL;
BEGIN
DX := (X2-X1)/FLOAT(NumPoints-1);
X := X1;
Sum := 0.0;
FOR i := 1 TO NumPoints-1 DO
Sum := Sum + Function(X) * DX;
X := X + DX;
END;
RETURN Sum;
END Integrate;
Variable declarations
Variables are objects that have values that change during the execution of a program. Variables are created by a variable declaration. The format of the variable declaration is:
VAR {identifier {,identifier}: TypeSpecification;}
Each of the identifiers to the left of the colon is declared as a variable of the type that is specified to the right of the colon. TypeSpecification can be either a type name or a new type.
The following are examples of variable declarations:
VAR
I, J : INTEGER;
MAT : ARRAY [1..3],[1..3] OF REAL;
BackGround, ForeGround : Color;
PossibleColors : SET OF Color;
RecordPointer : POINTER TO RecType;
Absolute variables
You can give the absolute address of a variable as follows:
VAR identifier [MAKEADR(constant)] : TypeSpecifiation;
VAR identifier [MAKEADR(constant, constant)] : TypeSpecifiation;
MAKEADR is imported from the ISO module SYSTEM. The two different forms of MAKEADR are due to the segmented nature of the 80x86 processor. If MAKEADR is passed a single constant the value represents the offset of the address relative to the data segment. When two constants are passed they are the segment and the offset, respectively, of the absolute address.
When you give an absolute address, the compiler does not allocate space for the variable, but refers to the address you specify.
Example:
VAR screen [MAKEADR(0B800H,0)] : ScreenType;
The variable screen refers to the screen memory of the color display adaptor in an IBM PC.
Expressions
Expressions are constructs used to create new objects by operating on existing objects. The simplest expression names an existing object (a variable or a constant). Operators are used to perform computations on objects.
Operators specify that an operation is performed on one or two objects. The objects are called operands. Operands can be variables, constants, results of another operator, or results of function calls.
Expressions - Operands
Operands can be any of the following:
-
Integer constants
-
Real constants
-
Complex constants
-
String constants
-
Set constructors
-
Variable designators
-
Procedure designators
-
Function calls
-
Type casts
Each operand has a type associated with it that determines what operators can apply to it.
For Integer constants, Real constants, Complex constants see Type declarations: basic types.
Character and string constants
String constants are specified by enclosing a string of characters in either single or double quotes. A string constant with N characters has the type:
ARRAY [0..N-1] OF CHAR
String constants with exactly one character are also compatible with the CHAR type.
String constants are compatible with ARRAYs that have an element type of CHAR.
Note: for ease of interfacing with operating systems and other languages, string constants are always followed in memory by a byte containing the NUL character (0 decimal).
A string constant with no characters (represented by two adjacent quotes, "") is allocated one byte and has the value NUL. If this string is passed to a procedure expecting an ARRAY OF CHAR, the upper bound will be zero, which indicates a string with one character. In this case, the one character is NUL.
You can use set, array and record constants in expressions using the same syntax for the value as used in constant declarations.
SET, ARRAY and RECORD value constructors
This creates a constant value from expressions that cannot be computed at compile time. A value constructor can only be used in expressions that are part of a statement.
SET, ARRAY and RECORD value constructors have the same syntax as SET, ARRAY and RECORD constants, however you can use non compile time values for any of the elements in the constructor.
BITSET{x..y}
Matrix{{InitialValue BY 10}BY 10}
If you use the BY keyword in an ARRAY value constructor, the BY repeat expression must still be a compile time constant.
Variable designators
A variable designator refers to the current value of a variable. The syntax of a variable designator is:
[modulename.]variablename{qualifier}
If the modulename is specified, the variablename exported from that module is used. Otherwise, the variablename is interpreted in the current scope.
Qualifier is:
[ field | subscript | dereference | subarray | coercion ]
Field qualifier
The field qualifier is specified by:
designator.identifier
The field qualifier can be applied to a variable designator that refers to a record type. The new designator refers to the field of the record named by the identifier.
Subscript qualifier
The subscript qualifier is specified by:
designator[expression{,expression}]
The subscript qualifier can be applied to a variable designator that is an array type. The resulting designator refers to the component of the array selected by the index values specified by the expressions.
An expression of the form:
A[e1, e2]
is equivalent to:
A[e1][e2]
Dereference qualifier
Dereference qualifierThe dereference qualifier is specified by:
designator^
The dereference qualifier can be applied to any designator that refers to a pointer type. The resulting designator refers to the object pointed to by the pointer variable.
Procedure designators
A procedure designator is simply the name of the procedure. A procedure designator refers to the address of the procedure and can only be passed as a parameter or assigned to a procedure variable.
Function calls
A procedure designator followed by parentheses is a function call. The procedure must be a function procedure; that is, its declaration must include a return type.
A function call is specified by:
FunctionName([expression{,expression}])
The list of expressions are the actual parameters of the function. The actual parameters are matched in order with the formal parameters.
The requirements for the actual parameters depend on how the formal parameter was declared:
-
For value parameters, the expression must result in a type assignable to the type of the formal parameter.
-
For VAR parameters, the expression must be a variable designator having the same type as the formal parameter.
-
For open array parameters, the actual parameter must be an array variable having the same element type as the formal parameter, or an open array parameter of the same type.
-
For procedure type parameters, the actual parameter can be either a variable of a compatible procedure type, or the name of a procedure compatible with the procedure type.
Formal parameter types are discussed in depth in the Procedures topic in this document.
The value of a function call is the value returned on the return statement in the function procedure.
Type cast
You can force an expression to be interpreted as a type other than its usual type by using a type cast.
A type cast takes the following form:
CAST(TypeName, expression)
The expression is evaluated, then forced to be interpreted as the type specified by TypeName. No conversion of data is done by type transfers. The raw data is interpreted as the new type. The CAST function is imported from the SYSTEM module.
This means that type transfers are dependent on the data representation used by an implementation, and are therefore not transportable.
For this reason, type conversion procedures are preferred when applicable. See the Standard Procedures chapter of this manual for information about type conversion procedures.
Type transfers from a shorter to a longer type are allowed, however a warning is generated because the excess bits are undefined.
Example:
VAR
X : BITSET;
BEGIN
X := BITSET{1, 2, 4};
WriteCard(CAST(CARDINAL16, X), 0);
The value written is 22, because the BITSET has bits 1, 2, and 4 set. When interpreted as a CARDINAL this makes the number 22.
Expressions - Operators
Integer operators
The following binary operators apply to all signed and unsigned integer types:
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Integer division |
REM | Integer remainder |
DIV | Division with modulus |
MOD | Integer modulus operation |
Both operands of a binary operator must be compatible; that is, you cannot add an INTEGER to a CARDINAL. You can use type conversion procedures or type transfers to combine operands of different types.
Unary + can be used on all the types. Unary - can be used on signed integer types.
The result type of all the integer operators is the same as the type of the operands. If the result of the operator is outside the allowable range of the type, overflow occurs.
Stony Brook M2 users: The result of an overflow depends on the qualifiers used when compiling. If overflow checking is on, a runtime error is signaled, otherwise, the low-order bits of the result are produced without any error.
Real operators
The following binary operators apply to operands of type REAL and LONGREAL:
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Division |
Both operands of an operator must be the same type.
Unary + and unary - also apply to both real types.
The result type of all the real operators is the same as the operands.
Boolean operators
The following operators apply to Boolean types. This includes the extended syntax boolean types, however the result of those expressions still return type BOOLEAN.
(NOT, ~) | Boolean negation |
(AND, &) | Boolean conjunction |
OR | Boolean disjunction |
The operators are defined as follows:
NOT A | is TRUE if A is FALSE, FALSE if A is TRUE. |
A AND B | is TRUE if and only if both A and B are TRUE. |
A OR B | is TRUE if and only if either A is TRUE or B is TRUE. |
All the boolean operators produce results of type BOOLEAN.
Set operators
The following operators apply to set types. Both operands must be the same set type:
+ | set union |
- | set difference |
* | set intersection |
/ | set symmetric difference |
The operations are defined as follows:
A + B | the set of elements in either A or B |
A - B | is the set of elements that are in A and are not in B |
A * B | is the set of elements in both A and B |
A / B | is the set of elements that are in either A or B but not in both A and B |
Set union is equivalent to a bit-by-bit OR operation.