VSI Pascal Reference Manual
- Software Version:
- VSI Pascal Version 6.3 for OpenVMS x86-64
VSI Pascal Version 6.2 for OpenVMS I64
VSI Pascal Version 6.2 for OpenVMS Alpha
- Operating System and Version:
- VSI OpenVMS x86-64 Version 9.2-1 or higher
VSI OpenVMS IA-64 Version 8.4-1H1 or higher
VSI OpenVMS Alpha Version 8.4-2L1 or higher
Preface
This manual describes the VSI Pascal programming language. It contains information on:
VSI Pascal language syntax and semantics
VSI Pascal adherence to Pascal standards
All references to OpenVMS systems refer to the OpenVMS I64, OpenVMS Alpha, and OpenVMS x86-64 operating systems unless otherwise specified.
1. About VSI
VMS Software, Inc. (VSI) is an independent software company licensed by Hewlett Packard Enterprise to develop and support the OpenVMS operating system.
2. Intended Audience
This manual is for experienced applications programmers with a basic understanding of the Pascal language. Some familiarity with your operating system is helpful. This is not a tutorial manual.
3. Document Structure
Chapter 1, Language Elements describes Pascal language standards and lexical elements.
Chapter 2, Data Types and Values describes data types and values.
Chapter 3, Declaration Section describes declaration sections.
Chapter 4, Expressions and Operators describes expressions and operators.
Chapter 5, Statements describes statements.
Chapter 6, Procedures and Functions describes user-written procedures and functions.
Chapter 7, Program Structure and Scope describes program structure and scope.
Chapter 8, Predeclared Functions and Procedures describes predeclared procedures and functions, except those that perform input and output.
Chapter 9, Input and Output Processing describes the predeclared procedures and functions that perform input and output.
Chapter 10, Attributes describes attributes.
Chapter 11, Directives describes directives.
Appendix A, Data Storage and Representation describes the storage allocation and alignment for data types and the internal representation of each data type.
Appendix B, Summary of VSI Pascal for OpenVMS Extensions describes the VSI Pascal extensions to the Pascal standards.
Appendix C, Description of Implementation Features describes the VSI Pascal implementation features that the Pascal standards allow each implementation to define.
Appendix D, Compiler and Run-Time System Error Detection describes how the VSI Pascal compiler detects errors defined by the Pascal standard.
4. Related Documents
VSI Pascal User Manual—Provides information about programming tasks, about using features in conjunction with one another, and about increasing the efficiency of program execution.
VSI Pascal Installation Guide—Provides information on how to install VSI Pascal on your operating system.
5. VSI Encourages Your Comments
You may send comments or suggestions regarding this manual or any VSI document by sending electronic mail to the following Internet address: <docinfo@vmssoftware.com>
. Users who have VSI OpenVMS support contracts through VSI can contact <support@vmssoftware.com>
for help with this product.
6. OpenVMS Documentation
The full VSI OpenVMS documentation set can be found on the VMS Software Documentation webpage at https://docs.vmssoftware.com.
7. Conventions
The following conventions are used in this manual:
Convention |
Meaning |
---|---|
Ctrl/x |
A sequence such as Ctrl/x indicates that you must hold down the key labeled Ctrl while you press another key or a pointing device button. |
PF1 x |
A sequence such as PF1 x indicates that you must first press and release the key labeled PF1 and then press and release another key or a pointing device button. |
... |
A horizontal ellipsis in examples indicates one of the
following possibilities:
|
. . . |
A vertical ellipsis indicates the omission of items from a code example or command format; the items are omitted because they are not important to the topic being discussed. |
( ) |
In command format descriptions, parentheses indicate that you must enclose choices in parentheses if you specify more than one. |
[ ] | In command format descriptions, brackets indicate optional choices. You can choose one or more items or no items. Do not type the brackets on the command line. However,you must include the brackets in the syntax for OpenVMS directory specifications and for a substring specification in an assignment statement. |
| | In command format descriptions, vertical bars separate choices within brackets or braces. Within brackets, the choices are optional; within braces, at least one choice is required. Do not type the vertical bars on the command line. |
{ } |
In command format descriptions, braces indicate required choices; you must choose at least one of the items listed. Do not type the braces on the command line. |
bold type |
Bold type represents the name of an argument, an attribute, or a reason. |
italic type | Italic type indicates important information, complete titles of manuals, or variables. Variables include information that varies in system output (Internal error number), in command lines (/PRODUCER=name), and in command parameters in text (where dd represents the predefined code for the device type). |
UPPERCASE TYPE |
Uppercase type indicates a command, the name of a routine, the name of a file, or the abbreviation for a system privilege. |
- |
A hyphen at the end of a command format description, command line, or code line indicates that the command or statement continues on the following line. |
numbers |
All numbers in text are assumed to be decimal unless otherwise noted. Nondecimal radixes – binary, octal, or hexadecimal – are explicitly indicated. |
Chapter 1. Language Elements
1.1. Pascal Language Standards
The VSI Pascal compiler accepts programs that comply with two standards and a subset of programs that comply with a third. VSI Pascal also provides features (called extensions) that are not part of any standard. For portable code, limit your use of these extensions or isolate the extensions in separate modules.
1.1.1. Unextended Pascal Standards
American National Standard ANSI/IEEE770X3.97-1989 (ANSI)
International Standard ISO 7185-1989 (ISO)
VSI Pascal accepts programs that comply to either standard. In the VSI Pascal documentation set, the term “unextended Pascal” applies to both the ANSI and ISO standards.
VSI Pascal contains FIPS-109 (Federal Information Processing Standard) validation support.
The standards are divided into two levels of standardization: Level 0 and Level 1. An example of a technical difference between the Level 0 standard and the Level 1 standard is that Level 0 does not include conformant arrays, while Level 1 does.
VSI Pascal has passed the validation suite for Pascal compilers. It received a CLASS A certificate for both levels of the ISO standard as well as the ANSI standard. CLASS A certificates are given to compilers with a fully conforming implementation.
For More Information:
On VSI Pascal extensions to unextended Pascal (Appendix B, Summary of VSI Pascal for OpenVMS Extensions)
On VSI Pascal implementation-dependent features (Appendix C, Description of Implementation Features)
On VSI Pascal error processing as defined by the standards (Appendix D, Compiler and Run-Time System Error Detection)
On flagging nonstandard constructs during compilation (VSI Pascal User Manual)
1.1.2. Extended Pascal Standard
American National Standard ANSI/IEEE770X3.160-1989
International Standard ISO 10206-1989
In the VSI Pascal documentation set, the term Pascal standard refers to these standards. Because VSI Pascal supports most Extended Pascal standard features, it cannot compile all programs that comply with Extended Pascal.
For More Information:
On VSI Pascal support for Extended Pascal features (Appendix B, Summary of VSI Pascal for OpenVMS Extensions)
On flagging nonstandard constructs during compilation (VSI Pascal User Manual)
1.2. Lexical Elements
This section discusses lexical elements of the VSI Pascal language.
1.2.1. Character Set
Uppercase letters A through Z and lowercase letters a through z
Integers 0 through 9
Special characters, such as the ampersand (&), question mark (?), and equal sign (=)
Nonprinting characters, such as the space, tab, line feed, carriage return, and form feed (use of these characters can improve the legibility of your programs)
Extended, unspecified characters with numeric codes from 128 to 255
Each ASCII character corresponds to a numeric value.
Each element of the character set is a constant of the predefined VSI Pascal type CHAR. An ASCII decimal number is the same as the ordinal value (as returned by the Pascal ORD function) of the associated character in the type CHAR.
VSI Pascal allows full use of eight-bit characters.
PROGRAM PRogrAm program
'b' 'B' "c" "C"
1.2.2. Special Symbols
Symbol |
Name |
Symbol |
Name |
---|---|---|---|
' |
Apostrophe |
<= |
Less than or equal to |
:= |
Assignment operator |
- |
Minus sign |
[ ] or (. .) |
Brackets |
* |
Multiplication |
: |
Colon |
<> |
Not equal |
, |
Comma |
( ) |
Parentheses |
(* *) or { } |
Comments |
% |
Percent |
/ |
Division |
. |
Period |
" |
Double quote |
+ |
Plus sign |
= |
Equal sign |
^ or @ |
Pointer |
** |
Exponentiation |
; |
Semicolon |
> |
Greater than |
.. |
Subrange operator |
>= |
Greater than or equal to |
:: |
Type cast operator |
< |
Less than |
1.2.3. String Delimiters
VSI Pascal accepts single-quote and double-quote characters as string and character delimiters.
1.2.4. Embedded String Constants
Constant |
Definition |
ASCII Value |
---|---|---|
\a |
Bell character |
16#7 |
\b |
Backspace character |
16#8 |
\f |
Form-feed character |
16#C |
\n |
Line-feed character |
16#A |
\r |
Carriage-return character |
16#D |
\t |
Horizontal tab character |
16#9 |
\v |
Vertical character |
16#B |
\ \ |
Backslash character |
16#5C |
\" |
Double-quotation character |
16#22 |
\' |
Single-quotation character |
16#27 |
\nnn |
Character whose value is nnn |
nnn is an octal number from 000 to 377. Leading zeros can be omitted. |
\xnn |
Character whose value is nn |
nn is a hexadecimal number from 00 to FF. Leading zeros can be omitted. |
1.2.5. Reserved Words
%DESCR |
%DICTIONARY |
%IMMED |
%INCLUDE |
%REF |
%STDESCR |
%SUBTITLE |
%TITLE |
AND |
ARRAY |
BEGIN |
CASE |
CONST |
DIV |
DO |
DOWNTO |
ELSE |
END |
FILE |
FOR |
FUNCTION |
GOTO |
IF |
IN |
LABEL |
MOD |
NIL |
NOT |
OF |
OR |
PACKED |
PROCEDURE |
PROGRAM |
RECORD |
REPEAT |
SET |
THEN |
TO |
TYPE |
UNTIL |
VAR |
WHILE |
WITH |
The manuals in the VSI Pascal documentation set show these reserved words in uppercase letters. If you choose, you can express them in mixed case or lowercase in your programs.
AND_THEN |
BREAK |
CONTINUE |
MODULE |
OR_ELSE |
OTHERWISE |
REM |
RETURN |
VALUE |
VARYING |
Note
This table does not include statements that are only provided by VSI Pascal for compatibility with other Pascal compilers.
This manual shows redefinable reserved words in uppercase letters. If you choose, you can express them in mixed case or lowercase in your programs.
1.2.6. Identifiers
An identifier cannot start with a digit.
An identifier cannot contain spaces or special symbols.
The first 31 characters of an identifier must denote a unique name within the block in which the identifier is declared. An identifier longer than 31 characters generates a warning message. The compiler ignores characters beyond the thirty-first character
The Pascal standard dictates that an identifier cannot start or end with an underscore, nor can two adjacent underscores be used within an identifier. However, VSI Pascal allows both cases of underscore use and generates an informational message if you compile with the standard switch.
On VSI OpenVMS systems, VSI Pascal uses uppercase characters for all external user symbols by default.
If you wish to use mixed-case names for externals symbols, use the GLOBAL or EXTERNAL attribute with a quoted string. VSI Pascal passes the string unmodified to the linker.
This manual shows predeclared identifiers in uppercase letters. If you choose, you can express them in mixed case or lowercase in your programs. The following examples show valid and invalid identifiers:
Valid:
For2n8 MAX_WORDS upto LOGICAL_NAME_TABLE {Unique in first} Logical_Name_Scanner { 31 characters} SYS$CREMBX
Invalid:
4Awhile {Starts with a digit} up&to {Contains an ampersand} YEAR_END_87_MASTER_FILE_TOTAL_DISCOUNT {Not unique in first} Year_End_87_Master_File_Total_Dollars { 31 characters}
ABS |
ADD_ATOMIC |
ADD_INTERLOCKED |
ADDRESS |
AND_ATOMIC |
ARCTAN |
ARGC |
ARGUMENT |
ARGUMENT_LIST_ |
ARGV |
ASSERT | |
BARRIER |
BIN |
BIT_OFFSET |
BITNEXT |
BITSIZE |
BOOLEAN |
BYTE_OFFSET | |
CARD |
CARDINAL |
CARDINAL16 |
CARDINAL32 |
CHAR |
CHR |
CLEAR_ |
CLOCK |
C_STR |
C_STR_T |
CLOSE |
COS |
CREATE_DIRECTORY | |||
D_FLOAT |
DATE |
DBLE |
DEC |
DELETE |
DELETE_FILE |
DISPOSE |
DOUBLE |
EOF |
EOLN |
EPSDOUBLE |
EPSQUADRUPLE |
EPSREAL |
EQ |
ESTABLISH |
EXP |
EXPO |
EXTEND | ||
F_FLOAT |
FALSE |
FIND |
FIND_FIRST_BIT_ |
FIND_FIRST_BIT_SET |
FIND_MEMBER |
FIND_NONMEMBER |
FINDK |
G_FLOAT |
GE |
GET |
GETTIMESTAMP |
GT | |||
H_FLOAT |
HALT |
HEX | |
IADDRESS |
IADDRESS64 |
INDEX |
INPUT |
INT |
INTEGER |
INTEGER8 |
INTEGER16 |
INTEGER32 |
INTEGER64 |
INTEGER_ADDRESS | |
LE |
LENGTH |
LINELIMIT |
LN |
LOCATE |
LOWER |
LSHIFT |
LT |
MALLOC_C_STR |
MAX |
MAXCHAR |
MAXDOUBLE |
MAXINT |
MAXQUADRUPLE |
MAXREAL |
MAXUNSIGNED |
MIN |
MINDOUBLE |
MINQUADRUPLE |
MINREAL |
NE |
NEW |
NEXT |
NIL |
OCT |
ODD |
OPEN |
OR_ATOMIC |
ORD |
OUTPUT | ||
PACK |
PAD |
PAGE |
PAS_STR |
PAS_STRCPY |
POINTER |
PRED |
PRESENT |
PUT | |||
QUAD |
QUADRUPLE | ||
RANDOM |
READ |
READLN |
READV |
REAL |
RENAME_FILE |
RESET |
RESETK |
REVERT |
REWRITE |
ROUND |
ROUND64 |
RSHIFT | |||
S_FLOAT |
SEED |
SET_INTERLOCKED |
SIN |
SINGLE |
SIZE |
SNGL |
SQR |
SQRT |
STATUS |
STATUSV |
STRING |
SUBSTR |
SUCC |
SYSCLOCK | |
T_FLOAT |
TEXT |
TIME |
TIMESTAMP |
TRUE |
TRUNC |
TRUNC64 |
TRUNCATE |
UAND |
UDEC |
UFB |
UINT |
UNDEFINED |
UNLOCK |
UNOT |
UNPACK |
UNSIGNED |
UNSIGNED8 |
UNSIGNED16 |
UNSIGNED32 |
UNSIGNED64 |
UOR |
UPDATE |
UPPER |
UROUND |
UROUND64 |
UTRUNC |
UTRUNC64 |
UXOR | |||
WALLCLOCK |
WRITE |
WRITELN |
WRITEV |
X_FLOAT |
XOR | ||
ZERO |
Note
This table does not include predefined identifiers that are only provided by VSI Pascal for compatibility with other Pascal compilers.
For More Information:
On attributes (Chapter 10, Attributes)
1.3. Comments
Comments document the actions or elements of a program. The text of a comment can contain any ASCII character except a nonprinting control character, such as an ESCAPE character. You can place comments anywhere in a program that white space can appear.
{ This is a comment. } (* This is a comment, too. *)
{ The delimiters of this comment do not match. *) (* VSI Pascal allows you to mix delimiters in this way. }
(* Cannot { nest comments inside } of comments like this *)
%IF FALSE %THEN ...code to disable... %ENDIF
For more information on %IF, see Section 11.4, “%IF, %ELSE, %ELIF, and %ENDIF”.
VSI Pascal allows for an end-of-line comment using an exclamation point (!). If an exclamation point is encountered on a line in the source program, the remainder of that line will be treated as a comment.
This comment syntax is not recognized by SCA for report generation.
1.4. Page Breaks and Form Feeds in Programs
FF %TITLE 'Variable Declarations' end; FF FF FF VAR FF
BEGIN FF END
The page break does not affect the meaning of the program, but causes a page to eject at the corresponding line in a listing file.
Chapter 2. Data Types and Values
Every piece of data that is created or manipulated by an VSI Pascal program has a data type. The data type determines the range of values, set of valid operations, and maximum storage allocation for each piece of data.
Ordinal types (Section 2.1, “Ordinal Types”)
Real types (Section 2.2, “Real Types”)
Pointer types (Section 2.3, “Pointer Types”)
Structured types (Section 2.4, “Structured Types”)
Schema types (Section 2.5, “Schema Types”)
String schemas and types (Section 2.6, “String Types”)
Predefined TIMESTAMP type (Section 2.8, “TIMESTAMP Type”)
Static and nonstatic types (Section 2.9, “Static and Nonstatic Types”)
Rules of type compatibility (Section 2.10, “Type Compatibility”)
For More Information:
On user-defined types and the TYPE section (Section 3.5, “TYPE Section”)
On variable declarations and the VAR section (Section 3.7, “VAR Section”)
On automatic type conversions (Section 4.4, “Type Conversions”)
On type conversion functions (Chapter 8, Predeclared Functions and Procedures)
Internal representation of data types (Section A.3, “Internal Representation of Data Types”)
2.1. Ordinal Types
This section describes the ordinal types that are predefined by VSI Pascal and user-defined ordinal types (types that require you to provide identifiers or boundary values to completely define the data type).
The ranges of values for these types are ordinal in nature; the values are ordered so that each has a unique ordinal value indicating its position in a list of all the values of that type. There is a one-to-one correspondence between the values in an ordinal type and the set of positive integers.
2.1.1. Integer Types
VSI Pascal makes available the INTEGER, INTEGER64, UNSIGNED, UNSIGNED64, and INTEGER_ADDRESS predeclared types. These data types are described in Section 2.1.1.1, “INTEGER and INTEGER64 Types”, Section 2.1.1.2, “UNSIGNED and UNSIGNED64 Types”, and Section 2.1.1.4, “INTEGER_ADDRESS Type”, respectively.
2.1.1.1. INTEGER and INTEGER64 Types
VSI Pascal provides the INTEGER and INTEGER64 integer types. Also provided are the INTEGER8, INTEGER16, and INTEGER32 types, which are used as synonyms for subranges of the INTEGER type.
The range of the integer values consists of positive and negative integer values, and of the value 0. The range boundaries depend on the architecture of the machine you are using.
Data Type |
Size |
Range |
---|---|---|
INTEGER8 |
8 bits |
-128..127 16#80..16#7F |
INTEGER16 |
16 bits |
-32768..32767 16#8000..16#7FFF |
INTEGER32 |
32 bits |
-2147483648..2147483647 16#80000000..16#7FFFFFFF |
INTEGER64 |
64 bits |
|
The largest possible value of the INTEGER64 type is represented by the predefined constant MAXINT64. The smallest possible value of the INTEGER64 type is represented by the value of the expression -MAXINT64. While the value of -MAXINT64-1 can also be represented, correct results may not be produced in certain expressions.
The largest possible value of the INTEGER type is represented by the predefined constant MAXINT. The smallest possible value of the INTEGER type is represented by the value of the expression -MAXINT. While the value -MAXINT-1 can also be represented, it may not produce correct results in certain expressions.
Constant |
Size |
Value | |
---|---|---|---|
MAXINT |
32 bits |
(231)-1 |
16#7FFFFFFF |
MAXINT64 |
64 bits |
(263)-1 |
16#7FFFFFFFFFFFFFFF |
2.1.1.2. UNSIGNED and UNSIGNED64 Types
VSI Pascal provides the UNSIGNED and UNSIGNED64 types. Also provided are the UNSIGNED32, CARDINAL, CARDINAL16, and CARDINAL32 types, which are used as synonyms for subranges of the UNSIGNED type. UNSIGNED8 and UNSIGNED16 are provided as synonyms for subranges of INTEGER with positive values that correspond to an UNSIGNED subrange of the same size. The range of unsigned values consists of nonnegative integer values.
The unsigned data types are VSI Pascal extensions that are provided to facilitate systems programming using certain operating systems. Given that these data types are not standard, you should not use them for every application involving nonnegative integers.
Data Type |
Size |
Range |
---|---|---|
UNSIGNED8 |
8 bits |
0..255 0..16#FF |
UNSIGNED16, CARDINAL16 |
16 bits |
0..65535 (216-1) 0..16#FFFF |
UNSIGNED32, CARDINAL32 |
32 bits |
0..4294967295 (232)-1 0..16#FFFFFFFF |
UNSIGNED64 |
64 bits |
0..18446744073709551615 (264-1) 0..16#FFFFFFFFFFFFFFFF |
The largest possible value of the UNSIGNED64 type is represented by the predefined constant MAXUNSIGNED64. The smallest possible value of the UNSIGNED64 type is 0.
Constant |
Size |
Value | |
---|---|---|---|
MAXUNSIGNED |
32 bits |
(232)-1 |
16#FFFFFFFF |
MAXUNSIGNED64 |
64 bits |
(264)-1 |
16#FFFFFFFFFFFFFFFF |
2.1.1.3. Integer Literals
{ decimal-number } { base-number#[[']]extended-digit[[']] } {- } { } [[ { } ]] { {b } } {+ } { % {o } [[']]extended-digit[[']] } { { } } { {x } } { }
decimal-number
17 0 89324
base-number
Specifies the base, or radix, of the number. VSI Pascal accepts numbers in bases 2 through 36.
extended-digit
Specifies the notation that is appropriate for the specified base.
b
o
x
Specifies an integer in either binary (base 2), octal (base 8), or hexadecimal (base 16) notation. In VSI Pascal you can use either uppercase or lowercase letters to specify the extended-digit notation.
You can use extended-digit notation in the same way you use the conventional integer notation. The one restriction is that you cannot use extended-digit values as labels.
VSI Pascal allows the use of spaces and tabs to make the extended-digit notation easier to read. To use spaces and tabs, enclose the extended digit in single quotation marks ( ’ ’).
2#10000011 2#'1000 0011' 32#1J -16#'7FFF FFFF'
%b'1000 0011' %O'7712' -%x'DEC'When VSI Pascal processes an integer constant, its type is based on its apparent value. Table 2.5, “Data Types for Integer Constants” and Table 2.5, “Data Types for Integer Constants” describe the type that is chosen for the integer constant.
Range of Integer Values |
Data Type |
---|---|
- MAXINT64...( - MAXINT) -1 |
INTEGER64 |
- MAXINT...MAXINT |
INTEGER |
MAXINT+1...MAXINT64 |
INTEGER64 |
MAXINT64+1...MAXUNSIGNED64 |
UNSIGNED64 |
To force an INTEGER constant to become UNSIGNED, INTEGER64, or UNSIGNED64, you can use the UINT, INT64, or the UINT64 predeclared routines, respectively.
To force an UNSIGNED constant to become INTEGER64 or UNSIGNED64, you can use the INT64 or UINT64 predeclared routines, respectively.
To force an INTEGER64 constant to become UNSIGNED64, you can use the UINT64 predeclared routine.
For More Information:
On unary operators (Section 4.2, “Operators”)
On built-in routines (Chapter 8, Predeclared Functions and Procedures)
2.1.1.4. INTEGER_ADDRESS Type
The INTEGER_ADDRESS data type has the same underlying size as a pointer. INTEGER_ADDRESS is equivalent to the INTEGER data type.
For More Information:
On INTEGER notations (Section 2.1.1.1, “INTEGER and INTEGER64 Types”)
On the IADDRESS function (Chapter 8, Predeclared Functions and Procedures)
2.1.2. CHAR Type
The CHAR data type consists of single character values from the ASCII character set. The largest possible value of the CHAR type is the predefined constant MAXCHAR.
'A' 'z' '0' { This is the character 0, not the integer value 0 } '''' { The apostrophe or single quotation mark } '?'
"A" "z" "\"" { The double quotation mark } "?"
The ORD function accepts parameters of type CHAR. The function return value is the ordinal value of the character in the ASCII character set.
''(7) CHR( 7 )
"\n"
For More Information:
On the ORD function (Section 8.63, “ORD Function”)
On the CHR function (Section 8.18, “CHR Function”)
On the ASCII character set (Section 1.2.1, “Character Set”)
On character strings (Section 2.6, “String Types”)
On using escape sequences within double quotation marks for nonprinting characters (Section 1.2.4, “Embedded String Constants”)
2.1.3. BOOLEAN Type
Boolean values are the result of testing relationships for truth or validity. The BOOLEAN data type consists of the two predeclared identifiers FALSE and TRUE. The expression ORD( FALSE ) results in the value 0; ORD( TRUE ) returns the integer 1.
The relational operators operate on the ordinal, real, string, or set expressions, and produce a Boolean result.
For More Information:
On the ORD function (Section 8.63, “ORD Function”)
On relational operators (Section 4.2.2, “Relational Operators”)
2.1.4. Enumerated Types
An enumerated type is a user-defined ordered set of constant values specified by identifiers. It has the following form:
({enumerated-identifier},...)
enumerated-identifier
The identifier of the enumerated type being defined. VSI Pascal allows a maximum of 65,535 identifiers in an enumerated type.
TYPE Seasons = ( Spring, Summer, Fall, Winter ); VAR Some_Seasons : Seasons VALUE Winter; {Initialized}
In this enumerated type, Spring (value 0) and Summer (value 1) are less than Fall (value 2) because they precede Fall in the list of constant values. Winter (value 3) is greater than Fall because it follows Fall.
The ORD function accepts expressions of an enumerated type.
TYPE Seasons2 = ( Fall, Winter, Spring );
This enumerated type cannot be defined in the same block as the previous type, because the identifiers Spring, Fall, and Winter would not be unique.
For More Information:
On the ORD function (Section 8.63, “ORD Function”)
2.1.5. Subrange Types
A subrange type is user-defined and specifies a limited portion of another ordinal type (called the base type). It has the following form:
lower-bound..upper-bound
lower-bound
A constant expression or a formal discriminant identifier that establishes the lower limit of the subrange.
upper-bound
A constant expression or formal discriminant identifier that establishes the upper limit of the subrange. The value of the upper bound must be greater than or equal to the value of the lower bound.
The base type can be any enumerated or predefined ordinal type. The values in the subrange type appear in the same order as they are in the base type. For example, the result of the ORD function applied to a value of a subrange type is the ordinal value that is associated with the relative position of the value in the base type, not in the subrange type.
You can use a subrange type anywhere in a program that its base type is legal. A value of a subrange type is converted to a value of its base type before it is used in an operation. All rules that govern the operations performed on an ordinal type pertain to subranges of that type.
TYPE Day = ( Mon, Tues, Wed, Thur, Fri, Sat, Sun ); Weekday = Mon..Fri; {subrange of base type Day} Weekend = Sat..Sun; {subrange of base type Day} Digit = '0'..'9'; {subrange of base type CHAR} Month = 1..31; {subrange of base type INTEGER} National Debt = 1..92233720368 {subrange of base type INTEGER64} 5477580;
type word = [word] 0..65535; procedure take_a_word( p : word ); begin writeln(p); end; begin take_a_word(90000); end.
procedure take_a_word( p_ : integer ); var p : word; { Local copy } begin p := p_; { Make local copy and do range check from longword integer expression into word subrange on assignment } writeln(p); end;
This means that VSI Pascal will fetch an entire longword from P_ when making the local copy. If you call Pascal functions from non-Pascal routines with value parameters that are subranges, you must pass the address of a value with the size of the base type. If subrange checking is disabled, the compiler can assume that the actual parameter is in range and can only fetch a word since that is sufficient to represent all valid values.
If the parameter was a VAR parameter, then the compiler would indeed only fetch a word since the formal parameter is an alias for the actual parameter and you are not allowed to pass expressions to a VAR parameter. The compiler assumes that the VAR parameter contains a valid value of the subrange. In other words, subranges are checked at assignment time and are considered valid when fetched.
For More Information:
On ordinal types (Section 2.1, “Ordinal Types”)
On compile-time and run-time expressions (Section 4.1, “Expressions”)
On attributes (Chapter 10, Attributes)
On predeclared routines (Chapter 8, Predeclared Functions and Procedures)
On using schema types (VSI Pascal User Manual)
On the ORD function (Section 8.63, “ORD Function”)
On the TYPE section (Section 3.5, “TYPE Section”)
On discriminant identifiers in subranges (Section 2.5, “Schema Types”)
On using the CHECK attribute for subrange checking (Section 10.2.8, “CHECK”)
2.2. Real Types
VSI Pascal predefines the REAL, SINGLE, DOUBLE, and QUADRUPLE data types in the floating-point formats listed in Table 2.6, “Supported Floating-Point Formats”.
Data Type |
Format |
Precision |
Default on |
---|---|---|---|
Single-precision REAL types? |
VAX F_floating-point format? |
1 part in 223 = 7 decimal digits |
VSI OpenVMS Alpha |
IEEE S_floating-point format |
1 part in 223 = 7 decimal digits |
VSI OpenVMS I64 | |
Double-precision DOUBLE types? |
1 part 255 = 16 decimal digits |
VSI OpenVMS x86-64 | |
VAX G_floating-point format? |
1 part in 252 = 15 decimal digits |
VSI OpenVMS Alpha | |
IEEE T_floating-point format |
1 part in 252 = 15 decimal digits |
VSI OpenVMS I64 | |
QUADRUPLE |
IEEE X_floating-point format |
1 part in 2112 = 33 decimal digits |
All OpenVMS systems |
VSI Pascal provides the following built-in data types to declare variables of a specific floating point type regardless of the /FLOAT setting on the command line (or FLOAT attribute on the MODULE):
F_FLOAT
D_FLOAT
G_FLOAT
S_FLOAT
T_FLOAT
X_FLOAT
To express REAL numbers, you can use either decimal or exponential notation. To express DOUBLE or QUADRUPLE numbers, you must use exponential notation.
2.4 893.2497 8.0 0.0
2.3E2 10.0E-1 9.14159e0
Letters |
Meaning |
---|---|
E or e |
Single-precision real number. The integer exponent following this letter specifies the power of 10. |
D or d |
Double-precision real number. All double-precision numbers in your program must appear in this exponential format; otherwise, the compiler reverts to single-precision representation. |
Q or q |
Quadruple-precision real number. All quadruple-precision numbers in your program must appear in this exponential format; otherwise, the compiler reverts to single-precision format. On systems that do not support the quadruple data type, the letters Q and q are treated as double-precision numbers (D). |
To express negative real numbers in exponential notation, use the negation operator (-). Remember that a negative real number such as -4.5E+3 is not a constant, but is actually an expression consisting of the negation operator (-) and the real number 4.5E+3. Use caution when expressing negative real numbers in complex expressions.
The floating lexical functions %F_FLOAT, %D_FLOAT, %G_FLOAT, %S_FLOAT, and %T_FLOAT can be prefixed on a floating constant to select the floating type regardless of any module-level attribute or command line selection.
Identifier | Value |
---|---|
Single-Precision F_floating | |
MINREAL |
2.938736E-39 |
MAXREAL |
1.701412E+38 |
EPSREAL? |
1.192093E-07 |
IEEE Single-Precision S_floating | |
MINREAL |
1.175494E-38 |
MAXREAL |
3.402823E+38 |
EPSREAL |
1.192093E-07 |
Double-Precision D_floating | |
MINDOUBLE |
2.938735877055719E-39 |
MAXDOUBLE |
1.701411834604692E+38 |
EPSDOUBLE |
2.22044604925031E-16? |
Double-Precision G_floating | |
MINDOUBLE |
5.56268464626800E-309 |
MAXDOUBLE |
8.98846567431158E+307 |
EPSDOUBLE |
2.22044604925031E-016 |
IEEE Double-Precision T_floating | |
MINDOUBLE |
2.2250738585072014E-308 |
MAXDOUBLE |
1.7976931348623157E+308 |
EPSDOUBLE |
2.2204460492503131E-016 |
IEEE Quadruple-Precision X_floating | |
MINQUADRUPLE |
3.36210314311209350626267781732175E-4932 |
MAXQUADRUPLE |
1.18973149535723176508575932662801E+4932 |
EPSQUADRUPLE |
9.62964972193617926527988971292464E-0035 |
For More Information:
On operators (Section 4.2, “Operators”)
On floating lexicals (Section 11.10, “%FLOAT, %x_FLOAT”)
On the internal representation of real numbers (Section A.3.2, “Representation of Floating-Point Data”)
On compilation switches (VSI Pascal User Manual)
2.3. Pointer Types
A pointer type allows you to refer to a dynamic variable. Dynamic variables do not have lifetimes that are strictly related to the scope of a routine, module, or program; you can create and eliminate them at various times during program execution. Also, pointer types clearly define the type of an object, but you can create or eliminate objects during program execution.
[[attribute-list]] ^ [[attribute-list]]
base-type-identifier
attribute-list
One or more identifiers that provide additional information about the base type.
base-type-identifier
The type identifier of the dynamic variable to which the pointer refers. The base type can be any type name or schema name. (If the base type is an undiscriminated schema type, you need to supply actual discriminants when you call the NEW function.)
Unlike other variables, dynamic variables do not have identifiers. You can access them indirectly with pointers.
When you use pointers, you call the procedure NEW to allocate storage for dynamic variables. You call the procedure DISPOSE to deallocate this storage.
TYPE My_Rec = RECORD Name : STRING( 30 ); Age : INTEGER; END VALUE [Name: 'Chris Lee'; Age: 29]; {Initialized} VAR Ptr : ^My_Rec; {In executable section:} NEW( Ptr );
Ptr^ := My_Rec[Name: 'Kim Jones'; age: 65];
Pointers assume values through initialization, assignment, and the READ and NEW procedures. The value of a pointer is either the storage address of a dynamic variable or the predeclared identifier NIL. NIL indicates that the pointer does not currently refer to a dynamic variable.
A file referenced by a pointer is not closed until the execution of the program terminates or until the dynamic variable is deallocated with the DISPOSE procedure. If you do not want the file to remain open throughout program execution, you must use the CLOSE procedure to close it.
VAR Ptr : ^INTEGER VALUE NIL;
For performance reasons, on VSI OpenVMS I64 and VSI OpenVMS x86-64 systems, the VSI Pascal compiler assumes that all pointers point to objects that are aligned on at least octaword boundaries. The NEW predeclared routine always returns memory that is aligned on octaword boundaries.
For performance reasons on VSI OpenVMS Alpha systems, the VSI Pascal compiler assumes that all pointers point to objects that are aligned on at least quadword boundaries. The NEW predeclared routine always returns memory that is aligned on quadword boundaries.
var p : ^ [aligned(0)] integer; { Pointer to a byte-aligned integer }
var long_ptr : ^integer; quad_ptr : [quad] ^integer; begin new(long_ptr); quad_ptr := long_ptr; quad_ptr^ := 5; if quad_ptr <> long_ptr then quad_ptr := long_ptr; end;
When comparing a 32-bit and a 64-bit pointer, the 32-bit pointer will be sign-extended before the comparison. Also, when assigning a 32-bit pointer value into a 64-bit pointer variable, the value will be sign-extended. You cannot assign a 64-bit pointer value into a 32-bit pointer variable.
For More Information:
On the NEW procedure (Section 8.58, “NEW Procedure”)
On the DISPOSE procedure (Section 8.28, “DISPOSE Procedure”)
On records (Section 2.4.2, “RECORD Types”)
On pointers to schema types (Section 2.5, “Schema Types”)
On linked lists (VSI Pascal User Manual)
On compiler switches for selecting alignment, packing, and allocation rules for each platform (VSI Pascal User Manual)
2.3.1. POINTER Type
To assign to or from any other type of pointer, including function result variables
To compare equality with any other type of pointer
To pass actual parameters of type POINTER to VAR and value parameters of any other type of pointer
To accept parameters of any other type of pointer with formal parameters of type POINTER
2.4. Structured Types
The structured data types are user defined and consist of components. Each component of a structured data type has its own data type; components can be any type.
To express values of structured objects (arrays, records, and sets), you can use a list of values called constructors. Constructors are valid in the TYPE, CONST, VAR, and executable sections of your program. Examples of valid constructors are provided throughout the following sections. The following sections also contain examples that show how to assign values to individual components of structured objects.
To save storage space, you can specify PACKED before any structured type identifier except VARYING OF CHAR (for example, PACKED ARRAY, PACKED RECORD, and PACKED SET). Defining PACKED structured types causes the compiler to economize storage by storing the structure in as few bits as possible. Keep in mind, however, that a packed data item is not compatible with a data item that is not packed. Also, accessing components of some packed structures can be slower than accessing components of unpacked structures.
VSI Pascal also provides the predefined structured type TIMESTAMP for more easily manipulating date and time information.
For More Information:
On string data types (Section 2.6, “String Types”)
On VARYING OF CHAR (Section 2.6.2, “VARYING OF CHAR Types”)
On array constructors (Section 2.4.1.2, “ARRAY Constructors”)
On record constructors (Section 2.4.2.2, “Record Constructors”)
On set constructors (Section 2.4.3.1, “Set Constructors”)
On the TIMESTAMP type (Section 2.8, “TIMESTAMP Type”)
2.4.1. ARRAY Types
An array is a group of components (called elements) that all have the same data type and share a common identifier. An individual element of an array is referred to by an ordinal index (or subscript) that designates the element's position (or order) in the array.
[[PACKED]] ARRAY [{[[attribute-list]] index-type},...] OF [[attribute-list]] component-type
attribute-list
One or more identifiers that provide additional information about the component type.
index-type
The type of the index, which can be any ordinal type or discriminated ordinal schema type.
component-type
The type of the array components, which can be any type. The components of an array can be another array.
The indexes of an array must be of an ordinal type. However, specifying large types, such as INTEGER, as the index type can cause the memory request to exceed available memory space. To use integer values as indexes, you must specify an integer subrange in the data type definition (unless you are using a conformant-array parameter).
You can use an array component anywhere in a program that a variable of the component type is allowed. Also, the only operation defined for entire array objects is the assignment operation (:=) (unless your array components are of a FILE type).
2.4.1.1. ARRAY Components
TYPE Count = ARRAY[1..10] OF INTEGER; {Array type of 10 integers} VAR Numbers : Count; {Array variable} {In the executable section:} Numbers[5] := 18; {Assigns the value 18 to the fifth element}
VAR Tic_Tac_Toe : ARRAY[1..3] OF ARRAY['a'..'c'] OF CHAR; {Or equivalently:} Tic_Tac_Toe : ARRAY[1..3, 'a'..'c'] OF CHAR; {3x3 matrix} {In the executable section:} Tic_Tac_Toe[ 1, 'a' ] := 'X'; {Or equivalently:} Tic_Tac_Toe[1]['a'] := 'X';
For More Information:
On character-string types (Section 2.6, “String Types”)
On conformant-array parameters (Section 6.3.7.1, “Conformant Array Parameters”)
On attributes (Chapter 10, Attributes)
On the TEXT predefined data type (Section 2.4.5, “TEXT Type”)
2.4.1.2. ARRAY Constructors
{component } [[data-type]] [ [[{{ {component-subrange } },... : component-value};... ]] [[OTHERWISE component-value [[;]] ]] ]
data-type
component
component-value
OTHERWISE
Specifies a value to be assigned to all array elements that have not already been assigned values.
When using array constructors, you must initialize all elements of the array; you cannot partially initialize the array.
VAR Numbers : Count VALUE [1..3,5 : 1; 4,6 : 2; 7..9 : 3; 10 : 6]; {In the executable section, constructor type is required:} Numbers := Count[1..3,5 : 1; 4,6 : 2; 7..9 : 3; 10 : x+3];
These constructors give the first, second, third, and fifth component the value 1; the fourth and sixth component the value 2; and the seventh, eighth, and ninth components the value 3. The first constructor gives the tenth component the value 6; the second constructor, since it is in the executable section, can assign the run-time value x+3 to the tenth component.
Numbers := Count[4,6 : 2; 7..9 : 3; 10 : x+3; OTHERWISE 1];
TYPE One_Dimension = ARRAY[1..3] OF CHAR; Matrix = ARRAY['a'..'b'] OF One_Dimension; VAR Tic_Tac_Toe : Matrix; {In the executable section:} Tic_Tac_Toe := Matrix[ 1,3 : [OTHERWISE ' ']; 2 : [ 1,3 : ' '; 2 : 'X']];
For More Information:
On nonstandard array constructors (Section 2.4.6.1, “Nonstandard Array Constructors”)
2.4.2. RECORD Types
[[PACKED]] RECORD [[field-list]] END
{{{field-identifier},... : [[attribute-list]] type};... [[; variant-clause]] [[;]]} {variant-clause [[;]]}
field-identifier
The name of a field.
attribute-list
One or more identifiers that provide additional information about the field.
type
The type of the corresponding field. A field can be of any type.
variant-clause
The variant part of the record.
The names of the fields must be unique within one record type, but can be repeated in different record types. You can specify the fields by specifying the record variable name (or the name of an object whose result, when used as an expression, is of a record type), followed by a period (.), and followed by the field name. If the record is unpacked, you can use a field anywhere in a program that a variable of the field type is allowed. (This manual flags circumstances in which components of packed records cannot appear where a variable of the field type is allowed.) The only operation defined for entire records is the assignment operation (:=).
TYPE Player_Rec = RECORD Wins : INTEGER; Losses : INTEGER; Percentage : REAL; END; VAR Player1, Player2 : Player_Rec; {In the executable section:} Player1.Wins := 18; {Assigns the value 18 to the Wins field.}
VAR Player : RECORD Wins : INTEGER VALUE 18; {Initial value for one field} Losses : INTEGER; Percentage : REAL; END;
TYPE Team_Rec = RECORD Total_Wins : INTEGER; Total_Losses : INTEGER; Total_Percentage : REAL; Player1 : Player_Rec; {Defined in previous example} Player2 : Player_Rec; Player3 : Player_Rec; END; VAR Team : Team_Rec;
Team.Total_Wins := Team.Player1.Wins + Team.Player2.Wins + Team.Player3.Wins;
For More Information:
On variant clauses (Section 2.4.2.1, “Records with Variants”)
On record constructors (Section 2.4.2.2, “Record Constructors”)
On specifying record fields using the WITH statement (Section 5.15, “WITH Statement”)
On attributes (Chapter 10, Attributes)
2.4.2.1. Records with Variants
A record can include one or more fields or groups of fields called variants, which can contain different types or amounts of data at different times during program execution. When you use a record with variants, two variables of the same record type can represent different data. You can define a variant clause only for the last field in the record. The syntax for record variants is as follows:
{[[tag-identifier : ]] [[attribute-list]] tag-type-identifier } CASE {discriminant-identifier } OF {case-label-list : (field-list)};... [[ [[;]] OTHERWISE (field-list) ]]
tag-identifier
The name of the tag field.
attribute-list
One or more identifiers that provide additional information about the variant.
tag-type-identifier
The type identifier for the tag field.
discriminant-identifier
TYPE Record_Template( a : INTEGER ) = RECORD Field_1 : REAL; CASE a OF 0 : ( x : INTEGER ); 1 : ( y : REAL ); END;
case-label-list
One or more case constant values of the tag field type separated by commas. A case constant is either a single constant value (for example, 1) or a range of values (for example, 5..10). You must enumerate one label for each possible value in the tag-type-identifier.
field-list
The names, types, and attributes of one or more fields. At the end of a field list, you can specify another variant clause. The field list can be empty.
The tag field consists of the elements between the reserved words CASE and OF. The tag field is common to all variants in the record type. The tag field data type corresponds to the case label values and determines the current variant.
tag-identifier : [[attribute-list]]
The tag-identifier and tag-type-identifier define the name and type of the tag field. The tag-type-identifier must denote an ordinal type. You refer to the tag field in the same way that you refer to any other field in the record (with the record.field-identifier syntax).
The following example shows the use of the tag-identifier form:TYPE Orders = RECORD Part : 1..9999; CASE On_Order : BOOLEAN OF TRUE : ( Order_Quantity : INTEGER; Price : REAL ); FALSE : ( Rec_Quantity : INTEGER; Cost : REAL ); END;
In this example, the last two fields in the record vary depending on whether the part is on order. Records for which the value of the tag-identifier On_Order is TRUE will contain information about the current order; those for which it is FALSE, about the previous shipment.
[[attribute-list]]
In the second form, there is no tag-identifier you can evaluate to determine the current variant. If you use this form, you must keep track of the current variant yourself. The tag-type-identifier must denote an ordinal type.
The following example shows the specification of a tag field without a tag-identifier:TYPE Characters = RECORD CASE CHAR OF 'A'..'Z' : ( Capital : INTEGER ); '0'..'9' : ( Number : INTEGER ); OTHERWISE ( Misc : BOOLEAN ); END;
In this example, the last field in this record will be one of the following:The integer field Capital if the range ’A ’.. ’Z ’ is the variant most recently referred to
The integer field Number if the range ’0 ’.. ’9 ’ is the variant most recently referred to
The Boolean field Misc if the character value falls outside the previous two variants
You can refer only to the fields in the current variant. You should not change the variant while a reference exists to any field in the current variant.
You can include an OTHERWISE clause as the last case label list. OTHERWISE is equivalent to a case label list that contains tag values (if any) not previously used in the record. The variant labeled with OTHERWISE is the current variant when the tag-identifier has a value that does not occur in any of the case label lists.
VAR Hospital : RECORD Patient : Name; Birthdate : Date; Age : INTEGER; CASE Pat_Sex : Sex OF Male : (); Female : ( CASE Births : BOOLEAN OF FALSE : (); TRUE : ( Num_Kids : INTEGER )); END;
This record includes a variant field for each woman based on whether she has children. A second variant, which contains the number of children, is defined for women who have children.
For More Information:
On the syntax of a field list (Section 2.4.2, “RECORD Types”)
On conditions that establish a variable reference (Section 3.7, “VAR Section”)
On attributes (Chapter 10, Attributes)
2.4.2.2. Record Constructors
Record constructors are lists of values that you can use to initialize a record; they have the following form:
[[data-type]] [ [[{{component},... : component-value};... ]] [[ CASE [[tag-identifier :]] tag-value OF [{{component},... : component-value};...] ]] [[ OTHERWISE ZERO [[;]] ]]
data-type
Specifies the constructor's data type. If you use the constructor in the executable section or in the CONST section, a data-type identifier is required. Do not use a type identifier in initial-state specifiers elsewhere in the declaration section or in nested constructors.
component
Specifies a field in the fixed-part of the record. Fields in the constructor do not have to appear in the same order as they do in the type definition. If you choose, you can specify fields from the variant-part as long as the fields do not overlap.
component-value
Specifies a value of the same data type as the component. The value is a compile-time value; if you use the constructor in the executable section, you can also use run-time values.
CASE
Provides a constructor for the variant portion of a record. If the record contains a variant, its constructor must be the last component in the constructor list.
tag-identifier
Specifies the tag-identifier of the variant portion of the record. This is only required if the variant part contained a tag-identifier.
tag-value
Determines which component list is applicable according to the variant portion of the record.
OTHERWISE ZERO
Sets all remaining components to their binary zero value. If you use OTHERWISE ZERO, it must be the last component in the constructor.
VAR Player1 : Player_Rec VALUE [Wins: 18; Losses: 3; Percentage: 21/18]; {In executable section, constructor type is required and run-time expressions are legal:} Player1 := Player_Rec[Wins: 18; Losses: y; Percentage: y+18/18];
TYPE Team_Rec = RECORD Total_Wins : INTEGER; Total_Losses : INTEGER; Total_Percentage : REAL; Player1 : Player_Rec; Player2 : Player_Rec; Player3 : Player_Rec; END; VAR Team : Team_Rec; {In the executable section: } Team := Team_Rec[Total_Wins: 18; Total_Losses: 3; Total_Percentage: 21/18; Player1: [Wins: 6; Losses: 0; Percentage: 1.0 ]; Player2: [Wins: 5; Losses: 2; Percentage: 7/5 ]; Player3: [Wins: 7; Losses: 1; Percentage: 8/7 ]];
VAR Team : Team_Rec VALUE ZERO ; Team : Team_Rec VALUE [Total_Wins: 5; Total_Losses: 2; Total_Percentage: 7/5; Player2: [Wins: 5; Losses: 2; Percentage: 7/5 ]; OTHERWISE ZERO ]; {Initializes Player1 and Player3}
A tag-identifier and a colon (:), followed by a constant expression (if you use both a tag-identifier and a tag-type-identifier in the declaration)
A constant expression (if you use only a discriminant-identifier or a tag-type-identifier in the declaration)
TYPE Orders = RECORD Part : 1..9999; CASE On_Order : BOOLEAN OF TRUE : ( Order_Quantity : INTEGER; Price : REAL ); FALSE : ( Rec_Quantity : INTEGER; Cost : REAL ); END; VAR An_Order : Orders VALUE [Part: 2358; CASE On_Order : FALSE OF [Rec_Quantity: 10; Cost: 293.99]]; {In the executable section, constructor type is required:} An_Order := Orders [Part: 2358; CASE On_Order : FALSE OF [Rec_Quantity: 10; Cost: 293.99]];
TYPE Orders = RECORD Part : 1..9999 VALUE 25; CASE On_Order : BOOLEAN OF TRUE : ( Order_Quantity : INTEGER VALUE 18; Price : REAL VALUE 4.65 ); FALSE : ( Rec_Quantity : INTEGER VALUE 10; Cost : REAL VALUE 46.50 ); END;
For More Information:
On the ZERO function (Section 8.109, “ZERO Function”)
On nonstandard record constructors (Section 2.4.6.2, “Nonstandard Record Constructors”)
2.4.3. SET Type
A set is a collection of data items of the same ordinal type (called the base type). The SET type definition specifies the values that can be elements of a variable of that type. The SET type has the following form:
[[PACKED]] SET OF [[attribute-list]]
attribute-list
One or more identifiers that provide additional information about the base-type.
base-type
The ordinal type identifier or type definition, or discriminated schema type, from which the set elements are selected. Real numbers cannot be elements of a set type.
You define a set by listing all the values that can be its elements. A set whose base type is integer or unsigned has two restrictions. First, the set can not contain more than 256 elements. Second, the ordinal value of the elements in a set must be within the range of 0 and 255.
For sets of other ordinal base types, elements can include the full range of the type.
TYPE INTSET = SET OF 0 .. 255;
For More Information:
On the INTEGER type (Section 2.1.1.1, “INTEGER and INTEGER64 Types”)
On the UNSIGNED type (Section 2.1.1.2, “UNSIGNED and UNSIGNED64 Types”)
On the subrange type (Section 2.1.5, “Subrange Types”)
On attributes (Chapter 10, Attributes)
On schema discriminants in sets (Section 2.5, “Schema Types”)
2.4.3.1. Set Constructors
Set constructors are lists of values that you can use to initialize a set; they have the following form:
[[data-type]] [ [[{component-value},... ]] ]
data-type
The data type of the constructor. This identifier is optional when used in the CONST and executable sections; do not use this identifier in the TYPE and VAR sections or in nested constructors.
component-value
Specifies values within the range of the defined data type. Component values can be subranges (..) to indicate consecutive values that appear in the set definition. These values are compile-time values; if you use the constructor in the executable section, you can also use run-time values.
A set having no elements is called an empty set and is written as empty brackets ([]).
VAR Numbers : SET OF 35..115 VALUE [39, 67, 110..115]; {In the executable section, run-time expressions are legal:} Numbers := [39, 67, x+95, 110..115];
The set constructors contain up to nine values: 39, 67, x+95 (in the executable section only), and all the integers between 110 and 115, inclusive. If the expression x+95 evaluates to an integer outside of the range 35..115, then Pascal includes no set element for that expression.
2.4.4. FILE Type
A file is a sequence of components of the same type. The number of components is not fixed; a file can be of any length. The FILE type definition identifies the component type and has the following form:
[[PACKED]] FILE OF [[attribute-list]]
component-type
attribute-list
component-type
Nonstatic type
Structured type with a nonstatic component
File type
Structured type with a file component
The arithmetic, relational, Boolean, and assignment operators cannot be used with file variables or structures containing file components. You cannot form constructors of file types.
When you declare a file variable in your program, VSI Pascal automatically creates a file buffer variable of the component type. This variable takes on the value of one file component at a time.
To reference the file buffer variable, write the name of the associated file variable, followed by a circumflex (^). No operations can be performed on the file while a reference to the file buffer variable exists.
VAR True_False_File : FILE OF BOOLEAN; {File of TRUE and FALSE values} Experiment_Records : FILE OF RECORD {File of records} Trial : INTEGER; {To access, Experiment_Records^.Trial} Temp, Pressure : INTEGER; Yield, Purity : REAL; END;
For More Information:
On file organization (Section 9.1, “Files and File Organizations”)
On component formats (Section 9.2, “Component Formats”)
On conditions that establish a variable reference (Section 3.7, “VAR Section”)
On attributes (Chapter 10, Attributes)
2.4.5. TEXT Type
The TEXT predefined type is a file containing sequences of characters with special markers (end-of-line and end-of-file) added to the file. Although each character of a TEXT file is one file component, the end-of-line marker allows you to process the file line by line, if you choose. The TEXT type has the following form:
[[attribute-list]] TEXT
attribute-list
One or more identifiers that provide additional information about the file components.
For More Information:
On the FILE type (Section 2.4.4, “FILE Type”)
On TEXT files (Section 9.5, “TEXT Files”)
On INPUT, OUTPUT, and ERR identifiers (Section 9.5, “TEXT Files”)
2.4.6. Nonstandard Constructors
As an option, you can use another format for constructors that is provided as an VSI Pascal extension. VSI Pascal retains this format only for compatibility with programs written for use with previous versions of this product. Also, you cannot use nonstandard constructors for variables of nonstatic types.
For all nonstandard constructors, you place constant values, of the same type as the corresponding component, in a comma list within parentheses. The compiler matches the values with the components using positional syntax; you must provide a value for each component in the variable. Nested structured components are designated by another comma list inside of another set of parentheses. Nonstandard constructors are legal in the VAR and VALUE initialization sections, and in the executable section. Specifying a type identifier as part of a constructor is optional for constructors used in the VAR and VALUE initialization sections, are required for constructors in the executable section, and cannot be used for nested constructors.
For More Information:
On Pascal standards (Section 1.1, “Pascal Language Standards”)
On standard constructors (Section 2.4, “Structured Types”)
2.4.6.1. Nonstandard Array Constructors
The format for nonstandard array constructors is as follows:
[[data-type]] ( [[{component-value},... ]] [[ REPEAT component-value ]]
)
data-type
Specifies the constructor's data type. If you use the constructor in the executable section, a data-type identifier is required. Do not use a type identifier in the VAR or VALUE sections or for a nested constructor.
component-value
n OF value
VAR Array1 : ARRAY[1..4] OF INTEGER; VALUE Array1 := ( 3 OF 15, 78 );
You cannot use the OF reserved word in a REPEAT clause.
REPEAT
Specifies a value to be assigned to all array elements that have not already been assigned values.
TYPE Count = ARRAY[1..10] OF INTEGER; VAR Numbers : Count; VALUE Count := ( 3 OF 1, 2, 1, 2, 3 OF 3, 3 ); {In the executable section, constructor type is required:} Numbers := Count( 3 OF 1, 2, 1, 2, REPEAT 3 );
TYPE One_Dimension = ARRAY[1..3] OF CHAR; Matrix = ARRAY['a'..'b'] OF One_Dimension; VAR Tic_Tac_Toe : Matrix; { In the executable section: } Tic_Tac_Toe := Matrix( (3 OF ' '), (' ', 'X', ' '), (3 OF ' ') );
For More Information:
On standard array constructors (Section 2.4.1.2, “ARRAY Constructors”)
2.4.6.2. Nonstandard Record Constructors
The format for a nonstandard record constructor is as follows:
[[data-type]] ( [[{component-value},... ]] [[ tag-value, {component-value};... ]]
)
data-type
Specifies the constructor's data type. If you use the constructor in the executable section, a data-type identifier is required. Do not use a type identifier in the VAR or VALUE sections or for a nested constructor.
component-value
Specifies a compile-time value of the same data type as the component. The compiler assigns the first value to the first record component, the second value to the second record component, and so forth.
tag-value
Specifies a value for the tag-identifier of a variant record component. The value that you specify as this component of the constructor determines the types and positions of the remaining component values (according to the variant portion of the type definition).
TYPE Player_Rec = RECORD Wins : INTEGER; Losses : INTEGER; Percentage : REAL; VAR Player1 : Player_Rec := ( 18, 6, 24/18 ); {In the executable section, constructor type is required:} Player1 := Player_Rec( 18, 6, 24/18 );
TYPE Team_Rec = RECORD Total_Wins : INTEGER; Total_Losses : INTEGER; Total_Percentage : REAL; Player1 : Player_Rec; Player2 : Player_Rec; Player3 : Player_Rec; END; VAR Team : Team_Rec; {In the executable section: } Team := Team_Rec ( 18, 3, 18/21, ( 6, 0, 1.0 ), ( 5, 2, 5/7 ), ( 7, 1, 7/8 ) );
TYPE Orders = RECORD Part : 1..9999; CASE On_Order : BOOLEAN OF TRUE : ( Order_Quantity : INTEGER; Price : REAL ); FALSE : ( Rec_Quantity : INTEGER; Cost : REAL ); END; VAR An_order : Orders := ( 2358, FALSE, 10, 293.99 );
For More Information:
On standard record constructors (Section 2.4.2.2, “Record Constructors”)
On record variants (Section 2.4.2.1, “Records with Variants”)
2.5. Schema Types
A schema type is a user-defined construct that provides a template for a family of distinct data types. A schema type definition contains one or more formal discriminants that take the place of specific boundary values or variant-record selectors. By specifying boundary or selector values to a schema type, you form a valid data type; the provided boundary or selector values are called actual discriminants. Schema types have the following form:
schema-identifier ({{discriminant-identifier},... : [[attribute-list]] ordinal-type-name};... ) = [[attribute-list]] type-denoter;
schema-identifier
The name of the schema.
discriminant-identifier
The name of a formal discriminant.
attribute-list
One or more identifiers that provide additional information about the type-denoter.
ordinal-type-name
The type of the formal discriminant, which must be an ordinal type (except those types that have INTEGER64 or UNSIGNED64 base types).
type-denoter
The type definition of the components of the schema. This must define a new record, array, set, or subrange type.
TYPE Array_Template( Upper_Bound : INTEGER ) = ARRAY[1..Upper_Bound] OF INTEGER;
As the domain type of a pointer
As the type of a formal parameter
TYPE Vector( d : INTEGER ) = ARRAY[0..d-1] OF BOOLEAN; Number_Line( Starting, Distance : INTEGER ) = Starting..Starting+Distance; My_Subrange( l,u : INTEGER ) = l..u; Shift_Array_Index( l2, u2, Length : INTEGER ) = ARRAY[My_Subrange( l2+10, u2+10 )] OF STRING( Length );
TYPE Array_Template( Upper_Bound : INTEGER ) = ARRAY[1..Upper_Bound] OF INTEGER; VAR Array1 : Array_Template( 10 ); {ARRAY[1..10] OF INTEGER;} Array2 : Array_Template( x ); {Upper boundary determined at run time by variable or function call}
In the previous example, the actual discriminants 10 and x complete the boundaries for Array_Template, forming two complete data types within the same schema type family. A schema type that has been provided actual discriminants is called a discriminated schema; discriminated schema can appear in either the TYPE or VAR sections. The type specifiers Array_Template( 10 ) and Array_Template( x ) are examples of discriminated schema.
Actual discriminants can be compile- or run-time expressions. This expression must be assignment compatible with the ordinal type specified for the formal discriminant. Also, the actual discriminant value must be inside the range specified for the formal discriminant; in the case of subranges, the upper value must be greater than or equal to the lower value. In the previous example, 10 and x must be within the range -MAXINT..MAXINT.
TYPE Array_Type1 = Array_Template( 10 ); PROCEDURE Example( Param : Array_Type1 ); {Procedure body...}
TYPE My_Subrange( a, b : INTEGER ) = a..b; Sub_A = My_Subrange( 1, 5 ); Sub_B = My_Subrange( 1, 5 ); Sub_C = My_Subrange( -50, 50 );
TYPE My_Subrange( a, b : INTEGER ) = a..b; My_Array( Upper : INTEGER ) = ARRAY[1..Upper] OF INTEGER; VAR i : My_Array( 10 ); j : My_Array( 10 ); k : My_Array( 15 ); l : ARRAY[ My_Subrange( 1, 10 ) ] OF INTEGER; m : ARRAY[ My_Subrange( 1, 10 ) ] OF INTEGER; {In the executable section:} i := j; {Legal; same schema family, same actual discriminant} i := k; {Illegal; same schema family, different actual} i := l; {Illegal; different types} l := m; {Illegal; different types}
Types l and m are not assignment compatible despite having the same subrange values specified by the same schema type; the two distinct type declarations create two distinct types, regardless of the ranges of the two types.
VAR Array1 : Array_Template( 10 ); {In the executable section:} WRITELN( Array1.Upper_Bound ); {Writes 10 to the default device}
FOR i := 1 TO Array1.Upper_Bound DO Array1[i] := i;
You can use discriminated schema in the type-denoter of a schema definition. You can also discriminate a schema in the type-denoter of a schema definition, but the actual discriminants must be expressions whose values are nonvarying; the actual discriminants cannot be variables or function calls.
TYPE { Legal schema types: } Range1( a, b : INTEGER ) = SET OF a..b+1; {Run-time bounds checking} My_Record( Number_Size, Status_Size : INTEGER ) = RECORD Part_Number : PACKED ARRAY[1..Number_Size] OF INTEGER; Status : STRING( Status_Size ); {Nested schema} END; Range2( Low, Span : INTEGER ) = Low..Low + Span; My_Integer( Dummy : INTEGER ) = -MAXINT-1..MAXINT; Matrix( Bound : INTEGER ) = ARRAY[1..Bound, 1..Bound] OF REAL; { Illegal schema types (they do not form "new" types): } My_String( Len : INTEGER ) = VARYING[Len] OF CHAR; My_Integer( Dummy : INTEGER ) = INTEGER;
2.6. String Types
CHAR type
PACKED ARRAY OF CHAR user-defined types
VARYING OF CHAR user-defined types
STRING predefined schema
Objects of the CHAR data type are character strings with a length of 1 and are lowest in the order of character string complexity. You can assign CHAR data to variables of the other string types.
The PACKED ARRAY OF CHAR types allow you to specify fixed-length character strings. The VARYING OF CHAR types are a VSI Pascal extension that allows you to specify varying-length character strings with a constant maximum length. The STRING types provide a standard way for you to specify storage for varying-length character strings with a maximum length that can be specified at run time.
To provide values for variables of these types, you should use a character-string constant (or an expression that evaluates to a character string) instead of an array constructor. Using array constructors with STRING and VARYING OF CHAR types generates an error; to use array constructors with PACKED ARRAY OF CHAR types, you must specify component values for every element in the array (otherwise, you generate an error).
VAR String1 : VARYING[10] OF CHAR
Generally, you can use any member of the ASCII character set in character-string constants and expressions. However, some members of the ASCII character set, including the bell, the backspace, and the carriage return, are nonprinting characters. The extended string format for character strings with nonprinting characters is as follows:
{'printing-string'({ordinal-value},...)}...
printing-string
A character-string constant.
Two bells'(7,7)' in a null-terminated ASCII string.'(0)
string-access "[" lower-bound ".." upper-bound "]"
var s : packed array [1..10] of char; s[1..5] :='hello'; s[6..10] := 'world';
procedure do_buf(var p : packed array [1..u:integer] of char); begin p := '12345'; end; var buff : packed array [1..10] of char; do_buff(buff[1..5]); do_buff(buff[6..10); writeln(buff);
To avoid compile-time warning messages about passing components of PACKED structures to VAR parameters, use /USAGE=NOPACKED_ACTUALS to compile.
In expressions, substring access behaves much like the SUBSTR built-in.
VSI Pascal also provides features for handling null-terminated strings. These are useful for communicating with routines written in the C language.
For More Information:
On the CHAR data type (Section 2.1.2, “CHAR Type”)
On the ASCII character set (Section 1.2.1, “Character Set”)
On null-terminated strings (Section 2.7, “Null-Terminated Strings”)
2.6.1. PACKED ARRAY OF CHAR Types
User-defined packed arrays of characters with specific lower and upper bounds provide a method of specifying fixed-length character strings. The string's lower bound must equal 1. The upper bound establishes the fixed length of the string.
VAR My_String : PACKED ARRAY[1..20] OF CHAR;
Note
If the upper bound of the array exceeds 65,535, if the PACKED reserved word is not used, or if the array's components are not byte-sized characters, the compiler does not treat the array as a character string.
VAR States : PACKED ARRAY[1..20] OF CHAR VALUE 'Hello'; {Is legal} States : PACKED ARRAY[1..20] OF CHAR VALUE [1:'H';2:'e';3:'l';4:'l';5:'o'] {Generates an error} States : PACKED ARRAY[1..20] OF CHAR VALUE [1:'H';2:'e';3:'l';4:'l';5:'o'; OTHERWISE ' '] {Is legal, but awkward}
For More Information:
On arrays (Section 2.4.1, “ARRAY Types”)
2.6.2. VARYING OF CHAR Types
The VARYING OF CHAR user-defined types are an VSI Pascal extension that provides a way of declaring variable-length character strings with a constant maximum length. If you require portable code, use the STRING predefined schema types to specify variable-length character strings.
VARYING OF CHAR types have the following form:
VARYING [upper-bound] OF [[attribute-list]] CHAR
upper-bound
An unsigned integer in the range from 1 through 65,535 that indicates the length of the longest possible string.
attribute-list
One or more identifiers that provide additional information about the VARYING OF CHAR string component.
VAR String1 : VARYING[10] OF CHAR VALUE '';
RECORD LENGTH : [WORD] 0..upper-bound; {Length of current string} BODY : PACKED ARRAY[1..upper-bound] OF CHAR; {Current string} END;
VAR String1 : VARYING[10] OF CHAR VALUE 'Wolf'; {In the executable section: } Max_Length := SIZE( string1.BODY ); WRITELN( Max_Length ); {writes '10'}
To determine the current length of a VARYING OF CHAR variable, use the LENGTH predeclared function. From the previous example, the result of LENGTH( String1 ) is the same as String1.LENGTH.
String1[8] := 'L';
You cannot specify an index value that is greater than the length of the current string. VSI Pascal does not pad remaining characters in the current string with blanks ( ’ ’). If you specify an index that is greater than the current length of the string, an error occurs.
For More Information:
On arrays (Section 2.4.1, “ARRAY Types”)
On attributes (Chapter 10, Attributes)
On the SIZE predeclared function (Section 8.81, “SIZE Function”)
On the LENGTH predeclared function (Section 8.49, “LENGTH Function”)
2.6.3. STRING Schema Type
TYPE STRING( capacity : INTEGER ) = VARYING[capacity] OF CHAR;
STRING( capacity )
An unsigned integer in the range 1..65,535 that indicates the length of the longest possible string.
VAR Short_String : STRING( 5 ); {Maximum length of 5 characters} Long_String : STRING( 100 ); {Maximum length of 100 characters}
VAR Short_String : STRING( 5 ) VALUE '';
VAR String1 : STRING( 10 ) VALUE 'Wolf'; {In the executable section: } WRITELN( String1.CAPACITY ); {prints '10'} WRITELN( String1.LENGTH {prints '4'}
The value String1.BODY contains the four-character string 'Wolf' followed by whatever is currently stored in memory for the remaining six characters.
To determine the current length of a STRING variable, you can use the LENGTH predeclared function. The result of LENGTH( String1) is the same as String1.LENGTH.
String1[5] := 't';
VAR String1 : STRING( 10 ) VALUE 'Wombat'; x : CHAR; {In the executable section:} x := String1[9]; {Generates an error} x := String1.BODY[9]; {Provides whatever is in memory there} x := String1[5]; {Is legal} String1[9] := 'X'; {Generates an error}
For More Information:
On schema types (Section 2.5, “Schema Types”)
On arrays (Section 2.4.1, “ARRAY Types”)
On the SIZE predeclared function (Section 8.81, “SIZE Function”)
2.7. Null-Terminated Strings
VSI Pascal includes routines and a built-in type to better coexist with null-terminated strings in the C language.
C_STR_T = ^ ARRAY [0..0] OF CHAR;
C_STR_T is a pointer to an ARRAY OF CHARs. It does not allocate memory for any character data. C_STR_T behaves like a normal pointer type in that you can assign NIL into it and the optional pointer checking code will check for dereferencing of a NIL pointer. The individual characters can be used by dereferencing the pointer and using an array index.
In these cases, no bounds checking will be performed even if array bounds checking is enabled. However, you cannot dereference a C_STR_T pointer without also indexing a single character. If you want to access an entire null-terminated string, see the PAS_STR function.
For More Information:
On the MALLOC_C_STR function (Section 8.54, “MALLOC_C_STR Function”)
On the C_STR function (Section 8.16, “C_STR Function”)
On the PAS_STRCPY function (Section 8.66, “PAS_STR Function”)
On the PAS_STR function (Section 8.67, “PAS_STRCPY Function”)
2.8. TIMESTAMP Type
The TIMESTAMP predefined type is used in conjunction with the GETTIMESTAMP procedure and with the DATE or TIME functions. GETTIMESTAMP initializes a variable of type TIMESTAMP; DATE and TIME function parameters are of type TIMESTAMP.
TIMESTAMP = PACKED RECORD DATEVALID, TIMEVALID : BOOLEAN; YEAR : INTEGER; MONTH : 1..12; DAY : 1..31; HOUR : 0..23; MINUTE : 0..59; SECOND : 0..59; HUNDREDTH : 0..99; BINARY_TIME : [QUAD] RECORD L1,L2:INTEGER END; {64-bit VMS binary time:} DAY_OF_WEEK : 1..7; {1 is Monday and 7 is Sunday} END;
For More Information:
On the GETTIMESTAMP procedure (Section 8.38, “GETTIMESTAMP Procedure”)
On the DATE and TIME functions (Section 8.23, “DATE and TIME Functions”)
2.9. Static and Nonstatic Types
VAR a : INTEGER; b : ARRAY[1..10] OF INTEGER;
Discriminated and undiscriminated schema types
Any type that contains a nonstatic component or index type
Nonstatic types require storage allocation to hold information about the type at run time. This storage, called the control part, includes information that cannot be determined until execution time; VSI Pascal needs this information to allocate and to access variables and record fields of this type.
TYPE {Template is nonstatic:} Template( Upper : INTEGER ) = ARRAY[1..Upper] OF INTEGER; a = ^Template; {a's base type is nonstatic} b = Template( 5 ); {b is nonstatic} My_Subrange( x, y : INTEGER ) = x..y; {c is nonstatic:} c = ARRAY[My_Subrange( j, k ), My_Subrange( l, m )] OF INTEGER; d = ARRAY[1..10] OF Template( 5 ); {d is nonstatic} e = RECORD {e is nonstatic} f1 : TEMPLATE( 5 ); END; f = SET OF My_Subrange( 10, 20 ); {f is nonstatic}
Do not confuse static and nonstatic types with automatic and static variable allocation.
For More Information:
On automatic variable allocation (Section 10.2.5, “AUTOMATIC”)
On static variable allocation (Section 10.2.36, “STATIC”)
On storage representation of nonstatic types (Section A.3.3, “Representation of Nonstatic Types and Variables”)
2.10. Type Compatibility
The following sections discuss the two forms of type compatibility: structural and assignment compatibility.
2.10.1. Structural Compatibility
Two types are structurally compatible only if they have the same allocation size and the same type structure. VSI Pascal requires that the type of a variable passed to a routine as an actual parameter be structurally compatible with the type of the corresponding formal variable parameter. VSI Pascal also checks the structural compatibility of the base types when a pointer expression is assigned to a pointer variable. Structural compatibility does not apply to nonstatic types (schema types and types derived from schema types).
Two ordinal types are structurally compatible only if they have the same base type and the same allocation size.
If two ordinal types are components of packed structured types, they are structurally compatible only if the ranges of values they describe have identical upper and lower bounds.
In general, each real type is structurally compatible only with itself. However, because REAL and SINGLE are synonymous, they are structurally compatible with each other.
If both types are record types, they must have the same number of fields, and the types of corresponding fields must be structurally compatible and identically positioned. If the record types have variant parts, the corresponding variants must have identical case labels written in the same order. The types of the fields within corresponding variants must be structurally compatible.
If both types are array types, the types of their components must be structurally compatible. The index types must have identical base types and identical upper and lower bounds.
If both types are VARYING OF CHAR types, their maximum lengths must be equal. The lengths of the current values of the VARYING OF CHAR strings do not affect structural compatibility.
If two components of packed structured types are set types, their base types must have identical upper and lower bounds.
If both types are set types, file types, or pointer types, their base types must be structurally compatible. Because of the possibility that a pointer type can be defined in terms of itself, the VSI Pascal compiler begins the test for the structural compatibility of two pointer types by assuming that they are compatible. Next, the compiler tests the two base types for structural compatibility. If within the base type, the compiler encounters the same pointer types it is testing, it still follows the original assumption that the pointer types are compatible. If the base types prove to be structurally compatible, then the two pointer types are judged to be structurally compatible.
For More Information:
On attributes that affect size and structure: ALIGNED, POS, READONLY, UNALIGNED, UNSAFE, VOLATILE, and WRITEONLY (Chapter 10, Attributes)
On ordinal types (Section 2.1, “Ordinal Types”)
On real types (Section 2.2, “Real Types”)
On pointer types (Section 2.3, “Pointer Types”)
On structured types (Section 2.4, “Structured Types”)
On allocation sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
2.10.2. Assignment Compatibility
Assignment compatibility rules apply to the types of values used to initialize variables, the types of expressions assigned to variables with the assignment operator (:=), and the types of actual parameters passed to formal value parameters. A variable or formal parameter is always compatible with expressions of its type.
Type of Variable |
Type of Assignment-Compatible Expression or Parameter |
---|---|
INTEGER |
INTEGER, UNSIGNED, INTEGER64, UNSIGNED64 |
UNSIGNED |
INTEGER, UNSIGNED, INTEGER64, UNSIGNED64 |
INTEGER64 |
INTEGER, UNSIGNED, INTEGER64, UNSIGNED64 |
UNSIGNED64 |
INTEGER, UNSIGNED, INTEGER64, UNSIGNED64 |
Subrange |
Base type of the subrange |
REAL, SINGLE |
REAL, SINGLE, UNSIGNED, INTEGER, INTEGER64, UNSIGNED64 |
DOUBLE |
DOUBLE, REAL, SINGLE, UNSIGNED, INTEGER, INTEGER64, UNSIGNED64 |
QUADRUPLE |
QUADRUPLE, DOUBLE, REAL, SINGLE, UNSIGNED, INTEGER |
PACKED ARRAY OF CHAR |
CHAR, unpacked array of CHAR, PACKED ARRAY OF CHAR with the same or smaller length, VARYING or STRING string whose current length is equal to or less than the packed array |
VARYING OF CHAR |
CHAR, unpacked array of CHAR, PACKED ARRAY OF CHAR, VARYING, STRING, string whose current value does not exceed the maximum length of the variable or parameter |
STRING |
CHAR, unpacked array of CHAR, PACKED ARRAY OF CHAR, VARYING, STRING, string whose current value does not exceed the maximum length of the variable or parameter |
Pointer |
Pointer to a structurally compatible type |
Two record types or two array types are assignment compatible if they are structurally compatible. When you assign one record variable to another, or one array variable to another, the VSI Pascal compiler does not check for out-of-range assignments to record fields or array components; such assignments do not result in an error message, even if subrange checking is enabled at compile time.
A set expression is assignment compatible with a set variable if the set's base types are compatible. In addition, all elements of the set expression must be included in the range of the variable's base type.
Note that assignment operations are not allowed on objects of file types or structured types that have file components.
Two discriminated schema types are assignment compatible if they are of the same type family and if their actual discriminant values are identical. A dereferenced pointer to an undiscriminated schema type is actually referencing a discriminated schema object whose discriminants were specified in a call to the NEW function. Although STRING is a schema, the rules in Table 2.9, “Assignment Compatibility” take precedence.
For More Information:
On ordinal types (Section 2.1, “Ordinal Types”)
On real types (Section 2.2, “Real Types”)
On pointer types (Section 2.3, “Pointer Types”)
On structured types (Section 2.4, “Structured Types”)
On schema types (Section 2.5, “Schema Types”)
On string types (Section 2.6, “String Types”)
On attributes that affect assignment compatibility: POS, READONLY, and UNSAFE (Chapter 10, Attributes)
Chapter 3. Declaration Section
The declaration section contains declarations or definitions of constants, labels, user-defined data types, variables, and user-defined functions and procedures. In addition, only modules can contain initialization and finalization sections. Each appears in a subsection introduced by Pascal reserved words.
These sections appear after the header and before the executable section (if any). The TO BEGIN DO and TO END DO sections can appear only in modules and only once within a module.
The remaining sections can appear in programs, modules, functions, or procedures; they can appear more than once and in any order in a single declaration section. If you use one kind of section more than once in a declaration section, be sure to declare types, variables, and constants before you use them in subsequent sections.
For More Information:
On user-defined procedures and functions (Chapter 6, Procedures and Functions)
On program structure (Chapter 7, Program Structure and Scope)
On modules (Section 7.4, “Modules and Programs”)
3.1. CONST Section
CONST {constant-identifier = constant-expression};...
constant-identifier
The identifier of the symbolic constant being defined.
constant-expression
Any legal compile-time expression.
Once a constant identifier is associated with an expression, the identifier retains the value of that expression throughout the scope in which it was declared. You can change the value only by changing the definition in the CONST section.
TYPE array_type1 = ARRAY[1..10] OF INTEGER; CONST Year = 1984; Tiny = 1.7253; Month = 'November'; Initial = 'P'; Lie = FALSE; Untruth = Lie; Almost_Pi = 22.0/7.0; array_const = array_type1[1..3,5 : 1; 4,6 : 2; 7..9 : 3; 10 : 7];
For More Information:
On expressions (Section 4.1, “Expressions”)
On constructors (Section 2.4, “Structured Types”)
3.2. LABEL Section
LABEL {label},...;
label
A decimal integer between 0 and 9999 (as an extension, between 0 and MAXINT), or a symbolic name. When declaring several labels, you can specify them in any order. The declaration and the occurrence of the label must be at the same level in the program.
A label can appear only once within the scope of the label declaration. It can precede any executable statement in the program. Use a colon (:) to separate the label from the statement it precedes. Labels can be accessed only by GOTO statements.
LABEL marker, 5; {In the executable section: } IF a <= 150 THEN GOTO 5 ELSE GOTO marker ; . . . 5: a := a + 1; . . . marker: WHILE x < 20 DO {Statement...}
For More Information:
For information on the GOTO statement, see Section 5.8, “GOTO Statement”.
3.3. TO BEGIN DO Section
The TO BEGIN DO section allows you to specify a statement, in a module that is to be executed before the executable section of the main program; it has the following form:
TO BEGIN DO statement;
statement
A Pascal statement.
The TO BEGIN DO section can only appear in modules, can only appear once in a module, and must appear as the last section in the declaration section. (If appearing together, the TO BEGIN DO section must precede the TO END DO section at the end of the declaration section.)
MODULE x( INPUT, OUTPUT ); VAR Debug : BOOLEAN; PROCEDURE Test(...); {Executable section...} TO BEGIN DO BEGIN WRITE('Debug Module x? '); READLN( Debug ); END; END.
As a general rule, if a program or module inherits an environment file, the compiler executes the initialization section in the inherited module before the initialization section in the program or module that inherited it. If a module or program inherits more than one module that contains an initialization section, the order of execution of the inherited modules is undefined.
[ENVIRONMENT( 'Mod1' )] MODULE Mod1; VAR i : INTEGER; TO BEGIN DO i := 5; {In a separate compilation unit:} [INHERIT( 'Mod1' )] MODULE Mod2; VAR j : INTEGER; TO BEGIN DO j := i + 1; {First execute code in Mod1 for correct results}
Figure 3.1, “Order of Execution for TO BEGIN DO and TO END DO Sections” shows the order of execution of initialization and finalization sections. Each circle is a module that contains both a TO BEGIN DO and a TO END DO section, and each arrow indicates the order of inheritance for the environment files.

[ENVIRONMENT] MODULE Mod1; ... [ENVIRONMENT, INHERIT( 'Mod1' )] MODULE Mod2; ... [ENVIRONMENT, INHERIT(' Mod1' )] MODULE Mod3; ... [INHERIT( 'Mod2', 'Mod3' )] MODULE Mod4; ...
%INIT
. If you wish to provide a different name, you can use
the [GLOBAL] attribute on the top of the module to specify a different name. For
example:[ENVIRONMENT,GLOBAL(MYINIT)] MODULE Mod1; ...
This alternate name is encoded in the resulting environment file so all modules that inherit this environment will automatically call the initializaton routine by its new alternate name.
For More Information:
On modules (Section 7.4, “Modules and Programs”)
On environment files (Section 7.5.1, “Environment Files”)
3.4. TO END DO Section
TO END DO statement;
statement
A Pascal statement.
The TO END DO section can only appear in modules, can only appear once in a module, and must appear as the last section in the declaration section. (If appearing together, the TO END DO section must come after the TO BEGIN DO section at the end of the declaration section.)
As a general rule, if a compilation unit inherits an environment file, the finalization section in the inheriting compilation unit must be executed before the finalization section in the inherited compilation unit. Also, if more than one module with a finalization section inherits a single module, the order of finalization of the inheriting modules cannot be determined. Figure 3.1, “Order of Execution for TO BEGIN DO and TO END DO Sections” shows an example of the order of execution of TO END DO sections.
The compiler implements a TO END DO section by creating an invisible TO BEGIN DO section if TO BEGIN DO wasn't used or by augmenting an existing TO BEGIN DO section with a call to the Pascal Run-Time Library to register the finalization routine.
MODULE File_Output; VAR Out_File : TEXT; t : TIMESTAMP; PROCEDURE Test(...); {Executable section...} TO BEGIN DO OPEN( Out_File, 'foo.dat' ); TO END DO BEGIN GETTIMESTAMP( t ); WRITELN( 'foo.dat closed at', TIME( t ) ); CLOSE( Out_File ) END; END.
For More Information:
On modules (Section 7.4, “Modules and Programs”)
On environment files (Section 7.5.1, “Environment Files”)
3.5. TYPE Section
The TYPE section introduces the name and set of values for a user-defined type or schema declaration.
[[type-attribute-list]] TYPE {type-identifier = [[attribute-list]] type-denoter } { {schema-declaration } { } [[VALUE initial-state-specifier]]};...
type-attribute-list
One or more attributes that apply to the entire TYPE section. Only the ALIGN, ENUMERATION_SIZE, or HIDDEN attributes can be specified here.
type-identifier
The identifier of the type being defined.
attribute-list
One or more identifiers that provide additional information about the type-denoter.
type-denoter
Any legal Pascal type syntax.
schema-declaration
The declaration of a schema type.
initial-state-specifier
A compile-time expression that is assignment compatible with a variable of the TYPE identifier being defined. VSI Pascal initializes all variables declared to be of this type with the constant value or values provided (unless there is an overriding initial-state-specifier in the variable declaration).
You must initialize a type with a compile-time expression of an assignment-compatible type. Scalar types require scalar constants; structured types require constant constructors.
You cannot initialize file types or types containing file components.
The predeclared function ZERO can be used to initialize an entire type (except file types and TIMESTAMP types) to binary zero.
The constant identifier NIL or a call to the ZERO function are the only values with which you can initialize a pointer type.
TYPE Days_of_Week = ( Sun, Mon, Tues, Wed, Thurs, Fri, Sat ) VALUE Mon; Array_Template( Upper_Bound : INTEGER ) = ARRAY [1..Upper_Bound] OF INTEGER; VAR {Declaring variables of user-defined types:} week1, week2, week3, week4 : Days_of_Week; {Initial value: Mon} week5 : Days_of_Week VALUE Sun; {Initial value: Sun} array_type2 : array_template( x ); {x is a run-time expression}
TYPE Ptr_to_Movie = ^Movie; {Movie is defined later} Name = PACKED ARRAY[1..20] OF CHAR; {Defined before used} Movie = RECORD Title, Director : Name; Year : INTEGER; Stars : FILE OF Name; Next : Ptr_to_Movie; END;
For More Information
On data types (Chapter 2, Data Types and Values)
On schema types (Section 2.5, “Schema Types”)
On pointers (Section 2.3, “Pointer Types”)
On attributes (Chapter 10, Attributes)
3.6. VALUE Section
VALUE {variable-identifier := constant-expression};...
variable-identifier
The name of the variable to be initialized. You cannot specify a list of variable identifiers. You can initialize a variable or variable component only once in the VALUE section. Any variables appearing in the VALUE section must appear in a previous VAR section.
constant-expression
Any constant expression that is assignment compatible with the variable identifier.
Unlike other declaration sections, the VALUE section can appear only in a program or module declaration section. You cannot use the VALUE declaration section in procedures or functions. If you wish to initialize variables in procedures and functions, use an initial-state specifier (by using the VALUE reserved word in either the TYPE or VAR section).
You can assign values to complete structured variables or to a single component of that variable.
For More Information:
On data types (Chapter 2, Data Types and Values)
On expressions (Section 4.1, “Expressions”)
3.7. VAR Section
The VAR section declares variables and associates each variable with an identifier, a type, and an optional initial value.
[[var-attribute-list]] VAR {{variable-identifier},... : [[attribute-list]] type-denoter {:= } [[ {VALUE } initial-state-specifier ]] };...
var-attribute-list
One or more attributes that apply to the entire VAR section. Only the ALIGN, ENUMERATION_SIZE or HIDDEN attributes can be specified here.
variable-identifier
The identifier of the variable being declared.
attribute-list
One or more identifiers that provide additional information about the variable.
type-denoter
Any legal Pascal type syntax.
initial-state-specifier
Any constant expression that is assignment compatible with the variable identifier. The variable is initialized to this expression.
You can combine several identifiers in the same variable declaration if the variables are of the same type and are being initialized either with the same value or not at all.
TYPE Hours_Worked = ARRAY[1..10] OF INTEGER; VAR Answer, Rumor : BOOLEAN; Temp : INTEGER VALUE 60; Grade : 'A'..'D'; Weekly_Hours : Hours_Worked VALUE [1..3 : 7; OTHERWISE 5];
You must initialize a variable with a constant expression of an assignment-compatible type. Scalar variables require scalar constants; structured variables require constant constructors.
You cannot initialize file variables or variables containing file components.
You can use the predeclared function ZERO to initialize all or part of a variable (except file variables and components) to binary zero.
The constant identifier NIL or a call to the ZERO function are the only values with which you can initialize a pointer variable.
The variable or one of its components is passed as a VAR, %REF, or %DESCR parameter. The reference lasts throughout the call to the corresponding routine.
The variable or one of its components is used on the left side of an assignment statement. The reference lasts throughout the execution of the statement.
The variable or one of its components is accessed by a WITH statement. The reference lasts throughout the execution of the statement.
The existence of a variable reference sometimes prohibits certain operations from being performed on the variable. Such restrictions are noted throughout this manual.
For More Information:
On constructors (Section 2.4, “Structured Types”)
On data types (Chapter 2, Data Types and Values)
On attributes (Chapter 10, Attributes)
On the ZERO function (Section 8.109, “ZERO Function”)
On pointers and NIL (Section 2.3, “Pointer Types”)
On the assignment and WITH statements (Chapter 5, Statements)
Chapter 4. Expressions and Operators
4.1. Expressions
Pascal expressions consist of one or more operands that result in a single value. If the expression contains more than one operand, the operands are separated by operators. Operands include numbers, strings, constants, variables, and function designators. Operators include arithmetic, relational, logical, string, set, and typecast operators.
Variable references
Schema discriminants
Bound identifiers from conformant parameters
Calls to user-defined functions
Calls to EOF and EOLN predeclared functions
Constructors of schema types or of types containing schema components
Run-time expressions result in a value at the time you execute your program. These expressions can contain variables, predeclared functions, user-declared functions, and everything that a constant expression cannot contain.
When you form an expression, the operands must be of the same data type. Under some circumstances, the compiler performs data type conversions and allows you to form an expression with operands of different types.
Pascal does not evaluate expressions contained within a single statement in a predictable order. Also, the compiler does not always evaluate all expressions in a single statement if the correct execution of the statement can be determined by evaluation of fewer expressions. For example, some IF statement conditions can be determined TRUE or FALSE by only evaluating one of the Boolean expressions in the condition. Do not write code that depends on the evaluation order of expressions, and, in some cases, on the evaluation of all expressions in a single statement. If you require a predictable order of evaluation, you can use the AND_THEN and OR_ELSE operators.
For More Information:
On data type conversion (Section 4.4, “Type Conversions”)
On data types (Chapter 2, Data Types and Values)
On evaluation of IF statement conditions (Section 5.9, “IF Statement”)
On the AND_THEN and OR_ELSE logical operators (Section 4.2.3, “Logical Operators”)
4.2. Operators
Pascal provides several classes of operators. You can form complex expressions by using operators to combine constants, constant identifiers, variables, and function designators.
Pascal also provides the assignment operator (:=) for use in assignment statements.
For More Information:
On precedence of operators (Section 4.2.7, “Precedence of Operators”)
On assignment statements (Section 5.1, “Assignment Statement”)
4.2.1. Arithmetic Operators
An arithmetic operator provides a formula for calculating a value.
Operator |
Example |
Result |
---|---|---|
+ |
A+B |
Sum of A and B |
- |
A-B |
B subtracted from A |
* |
A*B |
Product of A and B |
** |
A**B |
A raised to the power of B |
/ |
A/B |
A divided by B |
DIV |
A DIV B |
Result of A divided by B truncated toward zero |
REM |
A REM B |
Remainder of A divided by B |
MOD |
A MOD B |
MOD function of A with respect to B |
The +, –, *, ** Operators
You can use addition, subtraction, multiplication, and exponentiation operators on integer, unsigned, real, DOUBLE, and QUADRUPLE operands. These operators produce a result of the same type as the values. In exponentiation operations, if the data types of the operands are not the same, the operand of the less precise type is converted and the result is of the more precise type.
Base |
Exponent |
Result |
---|---|---|
0 |
Negative or 0 |
Error |
1 |
Negative |
1 |
-1 |
Negative and odd |
-1 |
-1 |
Negative and even |
1 |
Any other integer |
Negative |
0 |
For example, the expression 1(-3) equals 1; (-1)(-3) equals -1; (-1)(-4) equals 1; and 3(-3) equals 0.
The / Operator
You can use the division operator (/) on integer, unsigned, real, DOUBLE, and QUADRUPLE operands. The division operator always produces a real result. This result can reflect in some loss of precision as the compiler converts integer and unsigned operands to their real equivalents. With one or more operands of higher precision, the result is of the higher-precision type.
DIV, REM, MOD Operators
You can use the DIV, REM, and MOD operators only on integer and unsigned operands. DIV divides one integer or unsigned operand by the other, producing an integer or unsigned result. DIV truncates toward zero any remaining fraction and does not round the result. For example, the expression 23 DIV 12 equals 1, and (-5) DIV 3 equals -1.
REM returns the remainder after dividing the first operand by the second. Thus, 5 REM 3 evaluates to 2. Similarly, 3 REM 3 evaluates to 0 and (-4) REM 3 evaluates to -1.
If A is greater than B, then B is subtracted repeatedly from A until the result is a nonnegative integer less than B.
If A is less than B and not negative, the result is A.
If A is less than zero, B is added repeatedly to A until the result is a nonnegative integer less than B.
For example, 5 MOD 3 equals 2, (-4) MOD 3 equals 2, and 2 MOD 5 equals 2.
When both operands are positive, the REM and MOD operators return the same result. For example, 28 REM 5 equals 3 and 28 MOD 5 equals 3. However, when the first operand is negative, REM produces a negative or zero result, while MOD produces a positive or zero result. For example, (-42) REM 8 equals -2 and (-42) MOD 8 equals 6.
Enabling subrange checking ensures that a MOD operation is legal by verifying at run time that B is a positive integer.
Note that the use of negative integer and real number constants as operands in MOD and exponentiation operations can not produce the results you expect because the minus sign (-) is actually a negation operator. For example, the expression -2.0 * *2 is equivalent to the expression -(2.0 * *2) and produces the result -4.0. Therefore, you should enclose a negative constant in parentheses to make sure that it is interpreted as you intend. The expression (-2.0) * *2 produces the result 4.0.
Operator |
Type of Operands |
Result Type |
---|---|---|
|
INTEGER, INTEGER64, UNSIGNED, UNSIGNED64 REAL, DOUBLE, QUADRUPLE |
Same as the operands if both are of the same type; otherwise, the operand of the lower-ranked type is converted and the result is of the higher-ranked type. |
/ |
INTEGER, INTEGER64, UNSIGNED, UNSIGNED64, REAL, DOUBLE, QUADRUPLE |
One of the real types—REAL if the operands are of type REAL (or SINGLE) or a lower-ranked type; otherwise, the operand of the lower-ranked type is converted and the result is of the higher-ranked type. |
|
INTEGER, INTEGER64, UNSIGNED, UNSIGNED64 |
Same as the operands if both are of the same type; otherwise, the operand of the lower-ranked type is converted and the result is of the higher-ranked type. |
For More Information:
On integers (Section 2.1.1.1, “INTEGER and INTEGER64 Types”)
On real numbers (Section 2.2, “Real Types”)
On more precise and less precise operands, and on type conversions (Section 4.4, “Type Conversions”)
On using the CHECK attribute and SUBRANGE option for MOD run-time checking (Section 10.2.8, “CHECK”)
4.2.2. Relational Operators
Operator |
Example |
Result |
---|---|---|
= |
A = B |
TRUE if A is equal to B |
<> |
A <> B |
TRUE if A is not equal to B |
< |
A < B |
TRUE if A is less than B |
<= |
A <= B |
TRUE if A is less than or equal to B |
> |
A > B |
TRUE if A is greater than B |
>= |
A >= B |
TRUE if A is greater than or equal to B |
Note that operators designated with two characters must appear in the order specified and cannot be separated by a space.
For More Information:
On relational operators in string expressions (Section 4.2.4, “String Operators”)
On relational operators in set expressions (Section 4.2.5, “Set Operators”)
On the BOOLEAN data type (Section 2.1.3, “BOOLEAN Type”)
4.2.3. Logical Operators
Operator |
Example |
Result |
---|---|---|
AND |
A AND B |
TRUE if both A and B are TRUE |
OR |
A OR B |
TRUE if either A or B is TRUE, or if both are TRUE |
NOT |
NOT A |
TRUE if A is FALSE, and FALSE if A is TRUE |
AND_THEN |
A AND_THEN B |
TRUE if both A and B are TRUE; forces left-to-right evaluation order with short circuiting |
OR_ELSE |
A OR_ELSE B |
TRUE if either A or B is TRUE, or if both are TRUE; forces left-to-right evaluation order with short circuiting |
The AND, AND_THEN, OR, and OR_ELSE operators combine two conditions to form a compound condition. The NOT operator reverses the value of a single condition so that if A is TRUE, NOT A is FALSE, and vice versa.
{ Expressions: Results: } ( 4 > 3 ) AND ( 18 = 3 * 6 ) {TRUE} ( 3 > 4 ) OR ( 18 = 3 * 6 ) {TRUE} NOT ( 4 <> 5 ) {FALSE} ( i < 11 ) AND_THEN ( Array_A[i] = 0 ) {Not known} p = NIL OR_ELSE p^ = 0 {Not known}You can use Boolean variables and functions as operands in logical expressions. Consider the following example:
Flag AND ODD( i )
Suppose that Flag is a Boolean variable and ODD( i ) is a function that returns TRUE if the value of the integer variable i is odd and FALSE if the value of i is even. Both operands, Flag and ODD( i ), must be TRUE for the expression to be TRUE.
IF ( i < 11 ) AND_THEN ( Array_A[i] = 0 ) THEN WRITELN( 'Index bounds are legal and element contained 0' );
IF (PTR <> NIL) AND_THEN (P^.DATA1 = 0) AND (P^.DATA2 = 1) THEN ...
IF ((PTR <> NIL) AND_THEN (P^.DATA1 = 0)) AND (P^.DATA2 = 1) THEN ...
Given this assocation and the fact that the two operands of the AND operator can be evaluated in any order, the compiler might evaluate P^.DATA2 = 1 without it being guarded by the PTR <> NIL test.
IF (PTR <> NIL) AND_THEN ((P^.DATA1 = 0) AND (P^.DATA2 = 1)) THEN ...
IF (PTR <> NIL) AND_THEN (P^.DATA1 = 0) AND_THEN (P^.DATA2 = 1) THEN ...
For More Information:
On precedence of operators (Section 4.2.7, “Precedence of Operators”)
On the BOOLEAN data type (Section 2.1.3, “BOOLEAN Type”)
4.2.4. String Operators
Operator |
Example |
Result |
---|---|---|
+ |
A+B |
String that is the concatenation of strings A and B. |
= |
A=B |
TRUE if strings A and B have equal ASCII values. |
<> |
A <>B |
TRUE if strings A and B have unequal ASCII values. |
|
A B |
TRUE if ASCII value of string A is less than that of string B. |
= |
A =B |
TRUE if ASCII value of string A is less than or equal to that of string B. |
> |
A>B |
TRUE if ASCII value of string A is greater than that of string B. |
>= |
A>=B |
TRUE if ASCII value of string A is greater than or equal to that of string B. |
IN | A IN B | TRUE if ASCII value of string B found in string A.? |
NOT IN | A NOT IN B | TRUE if ASCII value of string B not found in string A.? |
With the plus sign (+), you can concatenate any combination of STRING and VARYING character strings, packed arrays of characters, and single characters.
'motherhood' > 'cherry pie'
'string1' < 'string2'
This expression is TRUE because the digit 1 precedes the digit 2 in the ASCII character set.
'John' < 'Johnny' 'abc' = 'abc '
The EQ, NE, GE, GT, LE, and LT predeclared routines make string comparisons that are similar to the relational operators, but these routines do not pad strings of unequal length with blanks. Instead, they halt string comparison when they detect unequal lengths.
If you are comparing the equality or inequality of very large strings, it is sometimes more efficient to use the EQ and NE functions instead of the = and <> operators. When using the operators, VSI Pascal compares each string, character by character, until detecting either a difference or the end of one string. When you use the functions, VSI Pascal sometimes detects different string lengths without comparing the strings character by character.
VAR One_String : STRING( 25 ) VALUE 'Harvey Fierstein'; {In the executable section:} WRITELN( One_String.LENGTH, LENGTH( One_String ) );
The WRITELN call writes 16 and 16 to the predeclared file OUTPUT (by default, to your terminal).
Enabling bounds checking causes the length of all character strings to be checked at run time for illegal operations.
For More Information:
On the BOOLEAN data types (Section 2.1.3, “BOOLEAN Type”)
On string data types (Section 2.6, “String Types”)
On the CHECK attribute and the BOUNDS option for run-time character-string checking (Section 10.2.8, “CHECK”)
On the EQ, NE, GE, GT, LE, and LT routines (Chapter 8, Predeclared Functions and Procedures)
4.2.5. Set Operators
Operator |
Example |
Result |
---|---|---|
+ |
A+B |
Set that is the union of sets A and B |
* |
A*B |
Set that is the intersection of sets A and B |
- |
A-B |
Set of those elements of set A that are not also in set B |
= |
A=B |
TRUE if set A is equal to set B |
<> |
A <>B |
TRUE if set A is not equal to set B |
<= |
A <=B |
TRUE if set A is a subset of set B |
>= |
A>=B |
TRUE if set B is a subset of set A |
IN |
C IN B |
TRUE if C is an element of set B |
NOT IN |
C NOT IN B |
TRUE if C is not an element of B |
2*3 IN [1..10] 5*3 NOT IN [1..10]
The result of this IN operation is TRUE because 2 * 3 evaluates to 6, which is a member of the set [1..10], and the NOT IN operation also returns TRUE because 5 * 3 evaluates to 15, which is not a member of the set [1..10].
The XOR predeclared routine can return the set of elements that do not appear in both sets.
For More Information:
On the SET data type (Section 2.4.3, “SET Type”)
On the BOOLEAN data type (Section 2.1.3, “BOOLEAN Type”)
On the XOR function (Section 8.108, “XOR Function”)
4.2.6. Type Cast Operator
Normally, VSI Pascal associates each variable with one type: the type with which the variable was declared. In some systems' programming applications, you can perform operations more efficiently by relaxing VSI Pascal's strict type-checking rules. VSI Pascal provides the type cast operator for this purpose.
{variable-identifier } {(expression) } :: type-identifier
The type cast operator (::) separates the name of a variable or an expression in parentheses from its target type, the type to which it is being cast. The operator alters the type of the cast object at that point only.
Once you cast a variable or an expression, the object has all the properties of its target type during the execution of the operation in which the type cast operator appears. A variable and its target type must have the same allocation size. Therefore, you cannot cast a conformant-array parameter, but you can cast a fixed-size component of a conformant-array parameter. A schema variable or parameter cannot be type cast since it does not have a size that is known at compile time.
When you cast an expression in parentheses, the value of that expression can be either truncated on the left or padded on the left with zeros, so that the allocation size of the expression's value and its target type become the same. The type of a cast expression cannot be VARYING OF CHAR, a conformant-array parameter, or a discriminated schema. In addition, the target type of a cast expression cannot be VARYING OF CHAR or a discriminated schema.
TYPE F_float = PACKED RECORD Frac1 : 0..127; Expo : 0..255; Sign : BOOLEAN; Frac2 : 0..65535; END; VAR A : REAL; {In the executable section:} A::F_float.Expo := A::F_float.Expo + 1;
In this example, the record type F_float shows the layout of an F_floating real number. The real variable A is cast as a record of this type, allowing you to access the fields containing the mantissa, exponent, sign, and fraction of A. Adding 1 to the field containing the exponent gives the same result as multiplying A by 2.0.
For More Information:
On data types (Chapter 2, Data Types and Values)
On the VOLATILE attribute (Section 10.2.42, “VOLATILE”)
On conformant-array parameters (Section 6.3.7.1, “Conformant Array Parameters”)
4.2.7. Precedence of Operators
Operators |
Precedence |
---|---|
:: |
Highest |
NOT | |
** | |
*, /, DIV, REM, MOD, AND, AND_THEN | |
+, –, OR, OR_ELSE, unary +, unary – | |
=, <>, <, <=, >, >=, IN |
Lowest |
In Pascal, operators of equal precedence (such as plus and minus) are combined from left to right within the expression.
a<=x AND b<=y
( a<=x ) AND ( b<=y )
In the rewritten expression, the compiler combines the Boolean values of the two relational expressions with the AND operator.
Expression |
Result |
---|---|
8 * 5 DIV 2–4 |
16 |
8 * 5 DIV (2–4) |
–20 |
8 * 5 DIV 2-4 |
16 |
8 * 5 DIV (2-4) |
-20 |
The compiler evaluates the first expression according to normal precedence rules.
First, 8 is multiplied by 5 and the result (40) is divided by 2. Then 4 is subtracted to get 16. The parentheses in the second expression, however, force the subtraction of 4 from 2 (yielding -2) to be performed before the division of 40 by -2. The result is -20.
( ( 8 * 5 ) DIV 2 ) -4
The parentheses eliminate any confusion about how the compiler associates the operands in the expression.
The desired results of your program should not depend on the order of subexpression evaluation. Unless you use the AND_THEN or OR_ELSE operators, the compiler does not guarantee the order in which subexpressions and complex expressions are evaluated. In fact, if the result of an expression can be determined without complete evaluation, VSI Pascal can partially evaluate some logical operations.
Usually the order of evaluation does not prevent the correct result from being produced. However, order of evaluation is very important when you write logical operations involving function designators that have side effects. (A side effect is an assignment to a nonlocal variable or to a variable parameter within a function block.)
IF f( a ) AND f( b ) THEN {Statement...}
The compiler can evaluate these two function designators in any order. Regardless of which function designator the compiler evaluates first, if the result is FALSE the other function designator does not have to be evaluated.
Suppose that function f assigns the value of its parameter to a nonlocal variable. Because you cannot know which function designator was evaluated first, you cannot be sure of the value of the nonlocal variable after the IF statement is performed.
For More Information:
On expressions (Section 4.1, “Expressions”)
On the AND_THEN or OR_ELSE logical operators (Section 4.2.3, “Logical Operators”)
On user-defined functions (Chapter 6, Procedures and Functions)
On optimization, compiler switches, and order of evaluation (VSI Pascal User Manual)
4.3. Structured Function-Return Values
WRITELN( Make_Node( 10 )^.Data[1] ); WRITELN( Make_Vector( 15 )[2] ); Make_Node( 10 )^.Data[1] := 42;
4.4. Type Conversions
Because VSI Pascal is a strongly typed language, you cannot normally treat a value of one type as though it were of a different type, as you can in many languages. For example, you cannot assign the character ’1 ’ to a variable of type INTEGER, because ’1 ’ is not an integer constant but a character constant. However, there are times when it makes sense to combine values of two different types because the values have some aspect in common. For example, suppose you wish to add a value of type REAL to a value of type INTEGER. This operation is legal because the value of type INTEGER is converted to its equivalent value of type REAL before the operation is performed. The result of the operation is of type REAL.
INTEGER
UNSIGNED
INTEGER64
UNSIGNED64
REAL or SINGLE
DOUBLE
QUADRUPLE
CHAR
PACKED ARRAY OF CHAR
STRING or VARYING OF CHAR strings
When values of two different arithmetic or character types are combined in an expression, the lower-ranked operand is converted to its equivalent in the higher-ranked type. The result of an operation in which conversion occurs is always of the higher-ranked type.
All conversions or assignments to values of type UNSIGNED or UNSIGNED64 are never checked for overflow. When combined with other unsigned values, negative integer values are converted to large unsigned values by the calculation of the modulus with respect to 2 **32 or 2 **64.
Conversions or assignments to values of type INTEGER or INTEGER64 can overflow. Overflow will be detected at run time if overflow checking is enabled. Overflow will occur if the value is outside the range -MAXINT to MAXINT for converting to INTEGER, or outside the range -MAXINT64 to MAXINT64 for converting to INTEGER64.
A special case of conversion can occur when you attempt to assign an expression of type VARYING OF CHAR or STRING strings to a variable of type PACKED ARRAY OF CHAR or if you try to pass a string expression to a formal value parameter of type PACKED ARRAY OF CHAR. If the varying-length string has less than or exactly the same number of components as the packed array, the varying-length string is converted to a packed array of characters before the assignment is made and padded with blanks as necessary. If you attempt to perform this assignment with a varying-length string that has more components than the packed array, a run-time error occurs.
For More Information:
On data types (Chapter 2, Data Types and Values)
Chapter 5. Statements
Assignment statement (Section 5.1, “Assignment Statement”)
BREAK statement (Section 5.2, “BREAK Statement”)
CASE statement (Section 5.3, “CASE Statement”)
Compound statement (Section 5.4, “Compound Statement”)
CONTINUE statement (Section 5.5, “CONTINUE Statement”)
Empty statement (Section 5.6, “Empty Statement”)
FOR statement (Section 5.7, “FOR Statement”)
GOTO statement (Section 5.8, “GOTO Statement”)
IF statement (Section 5.9, “IF Statement”)
Procedure call (Section 5.10, “Procedure Call”)
REPEAT statement (Section 5.11, “REPEAT Statement”)
RETURN statement (Section 5.12, “RETURN Statement”)
SELECT and SELECTONE statements (Section 5.13, “SELECT and SELECTONE Statements”)
WHILE statement (Section 5.14, “WHILE Statement”)
WITH statement (Section 5.15, “WITH Statement”)
When coding, separate statements with a semicolon (;). The semicolon is not syntactically part of a statement, so it is not included in the syntax examples in this chapter.
5.1. Assignment Statement
The assignment statement uses an assignment operator (:=) to assign a value to a variable or to a function identifier. An assignment statement has the following form:
variable-access := expression
variable-access
An identifier, array component, record component, pointer dereference, pointer-function dereference, or file buffer.
expression
A run-time expression whose type is assignment compatible with the type of the variable. The value of the expression is the value assigned to the variable.
You cannot assign values to a variable of a record type with variants if you allocated this variable using the NEW procedure. You can assign values to a field of such a record variable.
VAR x : INTEGER; y, z : RECORD f1 : real; f2 : integer END; {In the executable section:} x := 1; {type of expression is same type as the variable} y := z; {variables are assignment compatible} Func_Return_Ptr_To_Integer( 3 )^ := 19;
For More Information:
On the NEW procedure (Section 8.58, “NEW Procedure”)
On assigning constructor values to structured variables (Section 2.4, “Structured Types”)
On assignment compatibility (Section 2.10.2, “Assignment Compatibility”)
5.2. BREAK Statement
BREAK
REPEAT name := GetInput('Your name?'); IF ExitKeyPressed THEN BREAK; address := GetInput('Your address?'); IF ExitKeyPressed THEN BREAK; Person[Num].Name := name; Person[Num].Addr := address; Num := SUCC(Num); UNTIL Num > 50;
In the example, a user-defined function GetInput interacts with the user and sets a global Boolean variable ExitKeyPressed if the user presses an Exit key. The BREAK statement exits the loop here, without storing data in the array.
Use caution when using the BREAK statement because future additions to the code can result in the BREAK statement leaving a different loop than was originally intended.
5.3. CASE Statement
CASE case-selector OF [[{{case-label-list};...: statement};...]] [[ [[;]] OTHERWISE {statement};... ]] [[;]] END
case-selector
An expression of an ordinal type.
case-label-list
One or more case labels of the same ordinal type as the case selector, separated by commas. A case label can be a single constant expression, such as 1, or a range of expressions, such as 5..10.
statement
Any statement to be executed depending on the values of both the case-selector and the case-label.
You can specify case labels in any order within the case-label-list. Each case label can appear only once within a given CASE statement.
At run time, the system evaluates the case selector expression and chooses which statement to execute. If the value of the case selector does not appear in the case-label-list, the system executes the statement in the OTHERWISE clause. If you omit the OTHERWISE clause, the value of the case selector must be equal to one of the case labels. If the value is not equal to a label, the CASE statement result is undefined.
CASE Age OF 1..4 : School := 'preschool'; {Subranges} 5..8 : School := 'elementary'; 9..13 : School := 'middle'; 14..18 : BEGIN School := 'high'; WRITELN( 'Difficult years!' ); END; {Compound statements} 19 : School := 'reform'; {Single ordinal value} OTHERWISE School := 'graduated'; {If 1 > Age > 18 ...} END;
For More Information:
On ordinal values (Section 2.1, “Ordinal Types”)
On using the CHECK attribute to check selectors at run time (Section 10.2.8, “CHECK”)
5.4. Compound Statement
BEGIN {statement};... END
statement
Any Pascal statement, including other compound statements.
The statements that make up the compound statement must be separated with semicolons (;), although the semicolon before the END delimiter is optional.
IF a < 10 THEN BEGIN {A compound statement} x := 10; y := 20; z := x + y; END {No semicolon in THEN clause before an ELSE} ELSE z := 29; {A single statement}
For More Information:
On program executable sections (Section 7.4, “Modules and Programs”)
On function and procedure executable sections (Section 6.1, “Routine Declarations”)
5.5. CONTINUE Statement
The body of a FOR, WHILE, or REPEAT loop can include the CONTINUE statement. The CONTINUE statement is equivalent to a GOTO to a label placed at the end of the statements in the body of the FOR, WHILE, or REPEAT statement. The CONTINUE statement appears as a single word:
CONTINUE
In a loop that processes a series of data items, you can use the CONTINUE statement to indicate that the rest of the loop does not apply to the current item, and that the program should continue to the next statement.
Use caution when using the CONTINUE statement because future additions to the code can result in the CONTINUE statement continuing with a different loop than was originally intended.
5.6. Empty Statement
The empty statement causes no other action to occur than the advancement of program flow to the next statement. To use the empty statement, place a semicolon where the language syntax calls for a statement.
CASE Alphabetic OF 'A','E','I','O','U' : Alpha_Flag := Vowel; 'Y' : ; {Empty statement as selector; no action} OTHERWISE Alpha_Flag := Consonant; END;
5.7. FOR Statement
{TO } FOR control-variable := initial-value {DOWNTO } final-value DO statement FOR control-variable IN set-expression DO statement
control-variable
The name of a previously declared variable of an ordinal type.
initial-value
Expressions that form a range and whose type is assignment compatible with the type of the control variable.
set-expression
An expression resulting in a value of SET type. The base type of the set must be assignment compatible with the control variable.
statement
Any Pascal statement that does not change the value of the control variable.
In the TO form, Pascal checks to see if the value of the control variable is less than or equal to the final-value. If this condition is met, the control-variable takes on the value of the initial-value for the first loop iteration. During iterations, the control variable increments according to its data type. Looping ceases when the control-variable is greater than the final-value.
In the DOWNTO form, Pascal checks to see if the value of the control-variable is greater than or equal to the final-value. If this condition is met, the control variable takes on the value of the initial-value for the first loop iteration. During iterations, the control-variable decrements according to its data type. Looping ceases when the control-variable is less than the final-value.
In the set-expression form, Pascal checks to see if the set-expression is not the empty set. If this condition is met, the control-variable takes on the value of one of the members of the set. Iterations occur for each member of the set; the selection order of members of the set is undefined. Looping stops after the loop body executes for each member of the set.
After normal termination of the FOR statement, the control-variable does not retain a value. You must assign a new value to this variable before you use it elsewhere in the program. If the FOR loop terminates with a GOTO statement, the control-variable retains the last assigned value. In this case, you can use the variable again without assigning a new value.
FOR Year := 1899 DOWNTO 1801 DO {Print leap years in 1800's} IF ( Year MOD 4 ) = 0 THEN WRITELN( Year:4, ' is a leap year' ); FOR I IN Set1 DO {Set2 members are successors of Set1 members} Set2 := Set2 + [I + 1];
For More Information:
On ordinal values (Section 2.1, “Ordinal Types”)
On sets (Section 2.4.3, “SET Type”)
5.8. GOTO Statement
The GOTO statement causes an unconditional branch to a statement prefixed by a label. A GOTO statement has the following form:
GOTO label
label
An unsigned decimal integer or symbolic name that represents a statement label.
FOR I := 1 TO 10 DO BEGIN IF Real_Array[I] = 0.0 THEN BEGIN Result := 0.0; GOTO 10; {Use GOTO to exit from loop} END; Result := Result + 1.0/Real_Array[I]; {Compute sum of inverses} END; 10: Invertsum := Result;
For More Information:
On label declarations (Section 3.2, “LABEL Section”)
On exiting FOR loops using GOTO (Section 5.7, “FOR Statement”)
5.9. IF Statement
The IF statement tests a Boolean expression and performs a specified action if the result of the test is TRUE. The ELSE clause, when it appears, executes only if the test condition results to FALSE. An IF statement has the following form:
IF boolean-expression THEN statement1 [[ELSE statement2]]
boolean-expression
Any Boolean expression.
statement1
The statement to be executed if the value of the Boolean expression is TRUE.
statement2
The statement to be executed if the value of the Boolean expression is FALSE.
IF x > 10 THEN y := 4 IF x > 10 THEN BEGIN y := 4; ELSE y := 5; z := 5; END ELSE y := 5;
IF A = 1 THEN {First IF} IF B<>1 THEN {Second IF} C := 1 ELSE {Appears to modify first IF} C := 0; {Actually modifies second IF}
VSI Pascal can not always evaluate all the terms of a Boolean expression if it can evaluate the entire expression based on the value of one term. Either do not write code that depends on actual evaluation (or evaluation order) of Boolean expressions, or use the AND_THEN and OR_ELSE operators for a predictable order of evaluation.
For More Information:
On Boolean expressions (Section 2.1.3, “BOOLEAN Type”)
On forming and evaluating expressions (Section 4.1, “Expressions”)
On the AND_THEN and OR_ELSE logical operators (Section 4.2.3, “Logical Operators”)
5.10. Procedure Call
Syntactically, a procedure call is a statement. A procedure call has the following form:
routine-identifier [[({actual-parameter},...)]]
routine-identifier
The name of a procedure or function.
actual-parameter
An expression that is of a type that is compatible with the type of the formal parameter, or the name of a procedure or function.
In VSI Pascal, you can use procedure-call syntax to call a function, even though function calls are usually considered to be expressions. If you do this, the compiler invokes the function but ignores the return value.
For More Information:
On procedures and functions (Chapter 6, Procedures and Functions)
5.11. REPEAT Statement
The REPEAT statement is a looping statement and executes one or more statements until a specified condition is true. A REPEAT statement has the following form:
REPEAT {statement};... UNTIL expression
statement
Any Pascal statement.
expression
Pascal always executes a REPEAT statement for one iteration; iterations continue as long as the Boolean expression is FALSE. When specifying more than one statement as the loop body to a REPEAT statement, do not enclose the statements with the BEGIN and END reserved words. Multiple statements are legal in the REPEAT loop body.
REPEAT READ( x ); {Attempts to read at least one character} IF ( x IN ['0'..'9'] ) THEN BEGIN {Keep count of numbers and increase total} Digit_Count := Digit_Count + 1; Digit_Sum := Digit_Sum + ORD( x ) - ORD( '0' ); END ELSE Char_Count := Char_Count+1; {Count characters} UNTIL EOLN(INPUT); {Reads from default device until end of line}
For More Information:
On Boolean expressions (Section 2.1.3, “BOOLEAN Type”)
5.12. RETURN Statement
The RETURN statement passes control back to the caller of a PROCEDURE, FUNCTION, PROGRAM, or module initialization or finalization section. A RETURN statement is equivalent to a GOTO to a label placed just before the END of the body, and in a PROGRAM, has the effect of stopping the program. A RETURN statement has the following form:
RETURN [ return-value ]
return-value
Inside a FUNCTION, return-value specifies an ending value for the FUNCTION. If no return-value is provided, the last value assigned to the function identifier is used as the function result. The return-value type and function type must be the same.
Inside a PROGRAM, the return-value specifies an ending value for the PROGRAM. If you do not provide a return-value, VSI Pascal uses the value 1.
A function returns a result to its caller. A function can specify its result by assigning a value to the function identifier. This does not cause a return to the caller, and can occur many times per call. When the function finally returns, the last assignment becomes the result of the function. If a function uses the RETURN statement and includes a value, then the function returns immediately and returns the specified value. This value overrides any previous values specified by an assignment.
If a function uses the RETURN statement but does not specify a value, the return value is the last value that the function specified by assignment. If the function has not assigned a value to the function identifier during a given call to the function, VSI Pascal does not define the function result.
FUNCTION FindFirst(StartingPoint: INTEGER) : INTEGER; VAR i: INTEGER; BEGIN FOR i := StartingPoint TO MaximumNumber DO BEGIN IF Data[i] = Suitable THEN BEGIN AttributesOfDesiredData = Attributes[i]; Subscript := i; RETURN i; END; END; END;
For More Information:
On the GOTO statement (Section 5.8, “GOTO Statement”)
5.13. SELECT and SELECTONE Statements
The SELECT statement causes zero or more statements to be executed. The SELECTONE statement causes zero or one statement to be executed. Execution depends on the value of an ordinal expression called the select-selector.
A SELECT statement has the following form:
SELECT select-selector OF [[{{select-label-list},...: statement};...]] [[ [[OTHERWISE {statement};...]] [[ALWAYS {statement};...]] ]] [[;]] END
where 'select-label-list'
is expression [[.. expression]]
.
The expressions in the 'select-label-list' can be full run-time expressions.
When two expressions are provided as a lower and upper bound, they must be of the same ordinal type. There is no check to ensure that the lower bound expression is less than or equal to the upper bound expression. If that occurs, then there are simply no values of the select-selector that can be in the range.
The SELECT statement checks to see if the value of the select-selector is contained in the select-label-list. If so, then the corresponding statement is executed. The select-label-lists are checked in the same lexical order that they appear in the source file. The same value can appear in more than one select-label-list.
The optional OTHERWISE and ALWAYS clauses can appear in either order. The ALWAYS clause is always executed. The OTHERWISE clause is executed only if none of the prior statements (except for an optional ALWAYS statement) have been executed.
The syntax for the SELECTONE statement is almost identical but does not provide for an ALWAYS clause.
SELECTONE select-selector OF [[{{select-label-list},...: statement};...]] [[ OTHERWISE {statement};... ]] [[;]] END
Unlike the SELECT statement, the SELECTONE statement stops processing after it executes the first statement that corresponds to a select-label-list that contains the select-selector value.
The SELECT/SELECTONE statements can be used similar to the CASE statement. For example:
SELECT expression OF 1: WRITELN('ONE'); 2: WRITELN('TWO'); OTHERWISE WRITELN('not ONE or TWO') END
However, a more subtle (and powerful) form uses the Boolean constant 'TRUE' as the select-selector. For example:
SELECTONE True OF expression < 10: WRITELN('Value is small'); expression < 100: WRITELN('Value is medium'); expression < 1000: WRITELN('Value is big'); OTHERWISE WRITELN('Value is too big'); END SELECTONE True OF expression = "AAA": writeln('String is AAA'); expression = "BBB": writeln('String is BBB'); expression = "CCC": writeln('String is CCC'); OTHERWISE writeln('unknown string'); END FOR i := 1 TO 10 DO SELECT True OF ODD(i): WRITELN('value ',i:1,' is odd'); (i MOD 3) = 0: WRITELN('value ',i:1,' is also a multiple of 3'); END;
5.14. WHILE Statement
WHILE expression DO statement
expression
Any Boolean expression.
statement
Pascal checks the value of the Boolean expression before executing the loop body for the first time; if the expression is FALSE, the loop body is not executed. If the initial value is TRUE, loop iterations continue until the condition is FALSE. When specifying more than one statement as the loop body to a WHILE statement, enclose the statements with the BEGIN and END reserved words, since the syntax calls for a single statement to follow the DO reserved word. If you do not use a compound statement for the loop body, Pascal executes the first statement following the DO reserved word as the loop body.
WHILE NOT EOF( File1 ) DO {If EOF from the start, the loop} READLN( File1 ); { body is not executed. } WHILE NOT EOLN( INPUT ) DO BEGIN {Use compound statement:} READ( x ); IF NOT ( x IN ['A'..'Z', 'a'..'z', '0'..'9'] ) THEN Err := Err + 1; {Count odd characters as errors} END;
For More Information:
On Boolean expressions (Section 2.1.3, “BOOLEAN Type”)
On compound statements (Section 5.4, “Compound Statement”)
5.15. WITH Statement
The WITH statement provides an abbreviated notation for references to the fields of a record variable or to the formal discriminants of a discriminated schema type. A WITH statement has the following form:
{record-variable } WITH {{schema-variable }},... DO statement
record-variable
The name of the record variable being referenced.
schema-variable
The name of the variable being referenced whose type is a discriminated schema type. This underlying type of the schema can be a record.
statement
Any Pascal statement.
The WITH statement allows you to refer to the fields of a record or to a formal discriminant of a schema by their names alone, rather than by the record.field-identifier or schema-variable.formal-discriminant syntax. In effect, the WITH statement opens the scope so that references to field identifiers or to formal discriminants alone are unambiguous. When you access a variable or one of its components using a WITH statement, the reference syntax lasts throughout the execution of the statement.
{The record Dog is nested in the record Cat:} WITH Cat, Dog DO {Specify Cat before Dog} Bills := Bills + Cat_Vet + Dog_Vet; WITH Cat DO {This is equivalent to the previous WITH} WITH Dog DO Bills := Bills + Cat_Vet + Dog_Vet;
VAR x : STRING( 10 ); y : STRING( 15 ); {In the executable section:} WITH x, y DO WRITELN( CAPACITY ); {y.CAPACITY is used} {The following is equivalent:} WITH x DO WITH y DO WRITELN( CAPACITY );
For More Information:
On records (Section 2.4.2, “RECORD Types”)
On schema types (Section 2.5, “Schema Types”)
Chapter 6. Procedures and Functions
Procedures and functions are subprograms. A procedure contains one or more statements to be executed once the procedure is called. A function contains one or more statements to be executed once the function is called; in addition, functions return a single value. This manual refers to functions and procedures collectively as routines.
In addition to user-defined routines, VSI Pascal also allows you to access external routines (routines that are globally available on your system and that may or may not be written in VSI Pascal) and routines that are predeclared by the compiler.
For More Information:
On predeclared routines (Chapter 8, Predeclared Functions and Procedures)
On calling external routines (VSI Pascal User Manual)
6.1. Routine Declarations
You must declare a routine before you call it. Routine declarations have the following formats:
[[attribute-list]] PROCEDURE routine-identifier [[(formal-parameter-list)]]; {[[declaration-section]] BEGIN {statement};... END } {{ EXTERN } } {{ EXTERNAL } } {{ } } ; {{ FORTRAN } } {{ FORWARD } } [[attribute-list]] FUNCTION routine-identifier [[(formal-parameter-list)]] : [[attribute-list]] result-type-id; {[[declaration-section]] BEGIN {statement};... END } {{ EXTERN } } {{ EXTERNAL } } {{ } } ; {{ FORTRAN } } {{ FORWARD } } { }
attribute-list
One or more identifiers that provide additional information about the type-denoter.
routine-identifier
The name of the routine. If you use the routine-identifier within the routine body (with the exception of assigning a value to the routine-identifier of a function), the result is a recursive call to the routine. The routine-identifier of a procedure can be redeclared in the procedure's declaration-section. The routine-identifier of a function cannot be redeclared in the function's declaration-section; however, it can be redeclared in any nested routines within the function's declaration-section.
formal-parameter-list
A comma list of the routine's formal parameters. A procedure can have as many as 255 formal parameters. A function can also have as many as 255 formal parameters unless returning a structured type, in which case a function is limited to 254 formal parameters. Optionally, you can specify a mechanism specifier and an attribute list for each parameter.
declaration-section
A routine declaration section can include all sections except TO BEGIN DO, TO END DO, and VALUE sections. Data specified in this declaration section is local to the routine and to any nested routines; you can redeclare identifiers that are declared in an outer block. You cannot redeclare a formal parameter identifier to be a local variable in the routine.
By default, the system does not retain the values of local variables after it exits from a routine. Each call to a routine creates copies of the local variables. This means you can call a routine recursively without affecting the values held by the local variables at each activation of the routine. To preserve the value of a local variable (not the copy) from one call to the next, you must declare the local variable with the STATIC attribute.
statement
Any Pascal statement. In a function executable section, there must be either a RETURN statement containing a value, or at least one statement of the following form:
routine-identifier := result
The routine-identifier is the name of the function. The result is a value of either an ordinal, real, structured, or pointer type that VSI Pascal returns when the function is called. (This value cannot be a file type or a structured type with a file component.) This value must be of the same type as the result-type-id.
EXTERN
Predeclared identifiers that direct VSI Pascal to find the body of the routine elsewhere. The EXTERN, EXTERNAL, and FORTRAN identifiers declare routines that are independently compiled by VSI Pascal or that are written in other languages. In VSI Pascal, these identifiers are equivalent. Although not part of the Pascal standard, many Pascal compilers only accept the FORTRAN identifier for external routines actually written in FORTRAN; if portability is a concern, you may wish to use FORTRAN only for external FORTRAN routines.
The FORWARD identifier declares a routine whose block is specified in a subsequent part of the same procedure and function section, allowing you to call a routine before you specify its routine body. As an extension, VSI Pascal will allow the body to be in a different declaration part. If the body and heading are specified in different procedure and function sections, a FORWARD declared function should not be used as an actual discriminant to a schema type.
When you specify the body of the routine in subsequent code, include only the FUNCTION or PROCEDURE predeclared identifier, the routine-identifier, and the body of the routine. Do not repeat the formal-parameter, the attribute-list, or the result-type-id.
result-type-id
The type specification of the function return value. The function's result must be of this data type. This type cannot be a file type or a structured type with a file component.
{Function body contained in subsequent code:} FUNCTION Adder( Op1, Op2, Op3 : REAL ) : REAL; FORWARD; PROCEDURE Introduction; VAR a, b, c, z : REAL; {Variables local to the procedure} BEGIN WRITELN( 'This is the Inventory Program Version 5.6.' ); WRITELN; WRITELN( 'Press Ctrl/H for help. Press Return to continue.' ); a := 4.6; b := 12.1; c := 201.45; z := Adder( a, b, c ); {Call the function Adder} END; {System_Routine_Tanh available with the operating system:} FUNCTION System_Routine_Tanh( Angle : REAL ) : REAL; EXTERNAL; FUNCTION Adder; {Do not repeat attributes or parameters} BEGIN Adder := Op1 + Op2 + Op3; {Assign a function return value} END;
For More Information:
On attributes (Chapter 10, Attributes)
On declaration sections (Chapter 3, Declaration Section)
On the scope of identifiers (Section 7.2, “Scope of Identifiers”)
On parameters and passing mechanisms (Section 6.3, “Parameters”)
On recursive function calls (VSI Pascal User Manual)
On calling external routines (VSI Pascal User Manual)
6.2. Routine Calls
A routine call executes all statements in the body of the declared routine. You must declare a routine before you can call it. Syntactically, procedure calls are statements, and function calls, which return a single value, are expressions. You can call a function anywhere that an expression of the declared result type is legal. If the result of a function is irrelevant, you can call the function as a statement in the same way that you call a procedure. You can call routines in the executable section of a program or in the body of another routine. Routine calls have the following forms:
[%IMMED ] [%REF ] procedure-identifier [[({ [%DESCR ] actual-parameter},...)]] [ ] [%STDESCR ] [%IMMED ] [%REF ] function-identifier [[({ [%DESCR ] actual-parameter},...)]] [ ] [%STDESCR ]
procedure-identifier
The declared routine identifier. The scope of a routine identifier is the block in which it is declared, excluding any nested blocks that redeclare the same identifier.
actual-parameter
The actual parameter whose data type matches the type of the corresponding formal parameter. Optionally, you can specify a passing mechanism for each parameter. When a mechanism specifier appears in a call, it overrides the type, semantics, mechanism specified, and even the number of parameters in the formal parameter declaration. Thus, type checking is suspended for the parameter association to which the specifier applies.
VAR a, b, c, z : REAL; PROCEDURE Introduction; BEGIN WRITELN( 'This is the Inventory Program Version 5.6.' ); WRITELN; WRITELN( ' Press Ctrl/H for help. Press Return to continue.' ); END; FUNCTION Adder( Op1, Op2, Op3 : REAL ) : REAL; BEGIN Adder := Op1 + Op2 + Op3; {Assign a function return value} END; {In the executable section:} Introduction; {No parameters necessary in the call} a := 3.14; b := 14.78; c := 112.456; z := Adder( a, b, c ); {Function used as an expression evaluating to a REAL value}
TYPE Player_Rec = RECORD Wins : INTEGER; Losses : INTEGER; Percentage : REAL; END; VAR Number : INTEGER; FUNCTION Return_Player_Info( Player_Num : INTEGER ) : Player_Rec; {In the function body:} Return_Player_Info := Player_Rec[Wins: 3; Losses: 18; Percentage: 21/3]; {In the executable section:} WRITELN( Return_Player_Info( Number ).Losses, 'losses is poor!');
For More Information:
On expressions (Section 4.1, “Expressions”)
On structured function-return values (Section 4.3, “Structured Function-Return Values”)
On parameters and passing mechanisms (Section 6.3, “Parameters”)
6.3. Parameters
In VSI Pascal, there are two types of parameters: formal and actual parameters. A formal parameter (also called an argument) is located in the header of the routine declaration. You cannot redeclare a formal parameter in a routine's declaration section, but you can redeclare it in nested routines within the routine's declaration section.
The formal parameter establishes the semantics, the data type, and the required passing mechanism of the parameter. The general format of the formal parameter list is as follows.
{value-parameter-spec } {variable-parameter-spec } [[({ {routine-parameter-spec } };...)]] {foreign-parameter-spec }
The specific format of a formal parameter specification depends on the semantics (value, variable, routine, foreign) of the formal parameter you are declaring (conformant parameters also have a unique syntax).
Parameter Type | Description |
---|---|
Value |
Used only to provide input to the routine. After calling the routine, the value of the actual parameter remains unchanged. |
Variable |
Used to allow access to the actual parameter. If the rou-tine makes changes to the value of the formal parameter, the value of the actual parameter changes accordingly. |
Routine |
Used to call another routine. |
Foreign |
Used to call a routine written in another language. |
Mechanism | Description |
---|---|
By immediate value |
The information passed to the formal parameter is the data. |
By reference |
The information passed to the formal parameter is the address of the data. |
By descriptor |
The information passed to the formal parameter is the address of a descriptor of the data. |
Note
Depending on the environment in which you are programming, not all passing mechanisms may be supported on your system.
The actual parameter must be of the same data type and passing mechanism as the corresponding formal parameter. VSI Pascal uses the default passing mechanism for each actual parameter depending on its data type and formal definition. If the called routine is external to VSI Pascal, you can specify an explicit passing mechanism on the actual parameter that overrides the type and number of formal parameters.
For More Information:
On undiscriminated schema types (Section 2.5, “Schema Types”)
On external routines (Section 6.3.5, “Foreign Parameters”)
6.3.1. Value Parameters
By the rules of value semantics defined by the Pascal standard, a formal value parameter represents a local variable within the called routine. When you specify value semantics, the address of the actual parameter is passed to the called routine, which then copies the value from the specified address to its own local storage. The routine then uses this copy. The copy is not retained when control returns to the calling block. Therefore, if the called routine assigns a new value to the formal parameter, the change is not reflected in the value of the actual parameter.
When you do not include a reserved word before the name of a formal parameter, you automatically cause VSI Pascal to use value semantics to pass data to that parameter. A formal value parameter has the following form:
{type-identifier } {identifier},... : [[attribute-list]] {undiscriminated-schema-name } {conformant-parameter-syntax } [[:= [[mechanism-specifier]] default-value]]
identifier
The name of the formal parameter. Multiple identifiers must be separated with commas.
attribute-list
One or more identifiers that provide additional information about the formal parameter.
type-identifier
The type identifier of the parameters in this section.
undiscriminated-schema-name
The name of an undiscriminated schema type.
conformant-parameter-syntax
The type syntax of a conformant array or a conformant VARYING parameter.
mechanism-specifier
The mechanism by which a default value is to be associated with the formal parameter.
default-value
A compile-time expression representing the default value for the formal parameter.
Any attributes associated with a formal parameter become attributes of the local variable. They do not affect the values that can be passed to the parameter; they affect the behavior of the formal parameter only within the routine block. When a formal parameter has the UNSAFE attribute, the types of the actual parameters passed to it are not checked for compatibility.
An actual value parameter must be an expression whose type is assignment compatible with the type of the corresponding formal parameter. Because there is no assignment compatibility for file variables, undiscriminated schema sets, and undiscriminated schema subranges, they can never be passed as value parameters. Also, the names of routines are not allowed as value parameters.
If necessary, the type of an actual parameter is converted to the type of the formal parameter to which it is being passed. In this case, VSI Pascal follows the same type conversion rules that it uses to perform any other assignment. You may, for example, pass an integer expression to a formal parameter of a real type. If an actual parameter has the UNSAFE attribute, no conversion occurs.
If you have a user-defined, formal parameter of an undiscriminated schema type, the corresponding actual parameter must be discriminated from the same schema type as that of the formal parameter.
When you pass a string expression to a formal value parameter of type STRING, the actual parameter's current length (not its declared maximum length) becomes both the maximum length and the current length of the formal parameter.
You can also use the attributes [CLASS_S], [CLASS_A], and [CLASS_NCA] on value parameters if a routine requires a specific type of descriptor for VSI Pascal to build. A [CLASS_A], [CLASS_NCA] or [CLASS_S] formal value parameter requires the actual value parameters to be passed with the by descriptor mechanism.
VAR Old_Number, x, y : INTEGER; FUNCTION Random( Seed : INTEGER ): INTEGER; {Function body...} PROCEDURE Alpha( a, b : INTEGER; c : CHAR ); {Procedure body...} {In the executable section:} New_Number := Random( Old_Number ); Alpha ( x+y, 11, 'G' ); {Actual parameters are integer and character expressions}
For More Information:
On blocks and scope (Section 7.2, “Scope of Identifiers”)
On conformant parameters (Section 6.3.7, “Conformant Parameters”)
On default values for formal parameters (Section 6.3.9, “Default Formal Parameters”)
On mechanism specifiers (Section 6.3.5, “Foreign Parameters”)
On the UNSAFE attribute (Section 10.2.40, “UNSAFE”)
On type conversions (Section 4.4, “Type Conversions”)
6.3.2. Variable Parameters
By the rules of variable semantics defined by the Pascal standard, a formal variable parameter represents another name for a variable in the calling block. It is preceded by the reserved word VAR. When you specify variable semantics, the address of the actual parameter is passed to the called routine. In contrast to value semantics, the called routine directly accesses the actual parameter. Thus, the routine can assign a new value to the formal parameter during execution and the changed value is reflected immediately in the calling block (the value of the actual parameter changes).
{type-identifier } VAR {identifier},... : [[attribute-list]] {undiscriminated-schema-name } {conformant-parameter-syntax } [[:= [[mechanism-specifier]] default-value]]
identifier
The name of the formal parameter. Multiple identifiers must be separated with commas.
attribute-list
One or more identifiers that provide additional information about the formal parameter.
type-identifier
The type identifier of the parameters in this parameter section.
undiscriminated-schema-name
The name of an undiscriminated schema type.
conformant-parameter-syntax
The type syntax of a conformant array or a conformant VARYING parameter.
mechanism-specifier
The mechanism by which a default value is to be associated with the formal parameter. A mechanism specifier can be used only on a declaration for an external routine.
default-value
A compile-time expression representing the default value for the parameter. A default value can be used only on an external routine.
When you use variable semantics, the actual parameter must be a variable or a component of an unpacked structured variable (you can pass an entire packed structure); no expressions are allowed unless the formal parameter has the READONLY attribute. The type of a variable passed to a routine must be structurally compatible with the type of the corresponding formal parameter, except for schema parameters. For a formal parameter that is an undiscriminated schema type, the type of the variable must be discriminated from the same type as that of the formal parameter (they must be of the same schema type family). For a formal parameter that is a discriminated schema type, the type of the variable must be of the same type family and must have equivalent actual discriminants.
The names of routines are never allowed as variable parameters. In addition, you must use variable semantics when passing a file variable as an actual parameter. Also, you cannot pass the tag field of a variant record to a formal VAR parameter.
VAR My_String : VARYING [20] OF CHAR PROCEDURE Name( VAR A_String : VARYING [String_Size] OF CHAR {Body} {In the executable section:} Name( My_String ); WRITELN( 'The new name is ', My_String );
This example declares a procedure, Name, which returns a new name through the formal parameter A_String. Procedure Name modifies the value of A_String; since My_String is passed by variable semantics, upon completion of the routine the modified value is reflected in the variable My_String.
In VSI Pascal, certain attributes in a routine declaration or a routine call affect the rules of compatibility between actual and formal VAR parameters. These rules also apply to the corresponding components of structured types and to the base types of pointer types used as formal parameters. The attributes that result in rule changes are the alignment, POS, READONLY, size, UNSAFE, VOLATILE, and WRITEONLY attributes.
You can also use the attributes [CLASS_S], [CLASS_A], and [CLASS_NCA] on variable parameters if a routine requires a specific type of descriptor for VSI Pascal to build. A [CLASS_A], [CLASS_NCA] or [CLASS_S] formal variable parameter requires the actual variable parameters to be passed with the by descriptor mechanism.
For More Information:
On blocks and scope (Section 7.2, “Scope of Identifiers”)
On conformant parameters (Section 6.3.7, “Conformant Parameters”)
On default values for formal parameters (Section 6.3.9, “Default Formal Parameters”)
On mechanism specifiers (Section 6.3.5, “Foreign Parameters”)
On attributes and parameter compatibility (Chapter 10, Attributes)
On type conversions (Section 4.4, “Type Conversions”)
6.3.3. Routine Parameters
To write a routine that invokes another routine whose effect is not determined until the program is executed, use routine parameters. To declare a procedure or a function as a formal parameter to another routine, you must include a complete routine heading in the formal parameter list. You can also associate a foreign mechanism specifier and a default value with a formal procedure or function parameter.
PROCEDURE Apply( FUNCTION Operation( Left, Right : REAL ) : REAL; VAR Result : REAL ); FUNCTION Copy( PROCEDURE Get_Char( VAR c : CHAR ); PROCEDURE Put_Char( i : CHAR ) ) : BOOLEAN;
The identifiers listed as formal parameters to a formal procedure or function parameter are not accessible outside the routine declaration; they indicate the number and kind of actual parameters necessary. You refer to these identifiers only when you use nonpositional syntax to call a routine parameter.
In the previous example, the formal parameter list of Get_Char informs the compiler that Copy must pass one character parameter to Get_Char using variable semantics. Copy does not refer explicitly to the formal parameter c unless it calls Get_Char using nonpositional syntax.
Both are value parameter sections containing the same number of parameters. The types of parameters must either be compatible or be equivalent conformant parameters.
Both are variable parameter sections containing the same number of parameters. The types of the parameters must either be compatible or be equivalent conformant parameters. Any attributes associated with a formal variable parameter affect the kinds of actual parameters that can be passed to it.
Both are procedure parameter sections having either congruent formal parameter lists or no formal parameters.
Both are function parameter sections having either congruent formal parameter lists or no formal parameters, and having compatible result types.
Both are foreign parameter sections having the same mechanism specifier and the same number of parameters, and whose types must be compatible.
If one formal parameter list has a LIST attribute on its last parameter section, the other formal parameter list must also have this attribute.
VAR Costs, Pay, Fedtax, Food : REAL; Housing : INTEGER; FUNCTION Income( Salary, Tax : REAL ) : REAL; {Function body...} FUNCTION Expenses( Rent : INTEGER; Grocery : REAL ) : REAL; {Function body...} FUNCTION Budget( FUNCTION Credit( Earnings, UStax : REAL ) : REAL; FUNCTION Debit( Housing : INTEGER; Eat : REAL ) : REAL ) : REAL; VAR Deduct : REAL; BEGIN {FUNCTION Budget} Deduct := Debit( Eat := Food, Housing := Housing Budget := Credit( Pay, Fedtax ) - Deduct; END; {In the executable section:} Costs := Budget( Income, Expenses );
When the function Budget is called, the function Income is passed to the formal function parameter Credit, and the function Expenses is passed to the formal function parameter Debit. When Credit is called, the program-level variables Pay and Fedtax are substituted for Credit's formal parameters, Earnings and UStax. In the call to Debit, nonpositional syntax is used to associate Debit's formal parameters Housing and Eat with the program-level variables Housing and Food. The names of program-level variables do not conflict with formal parameters of routine parameters.
The presence of the ASYNCHRONOUS and UNBOUND attributes in routine declarations causes additional requirements to be imposed on the routines that can legally be passed as actual parameters.
For More Information:
On routine headings (Section 6.1, “Routine Declarations”)
On positional syntax (Section 6.3.8, “Parameter Association”)
On default values for formal parameters (Section 6.3.9, “Default Formal Parameters”)
On mechanism specifiers (Section 6.3.5, “Foreign Parameters”)
On conformant parameters (Section 6.3.7, “Conformant Parameters”)
On attributes (Chapter 10, Attributes)
6.3.4. Passing Predeclared Functions to Formal Function Parameters
ABS |
ARCTAN |
CHR |
CLOCK |
COS |
DBLE |
EOF |
EOLN |
EXP |
EXPO |
INT |
LN |
ODD |
ORD |
QUAD |
ROUND |
SIN |
SNGL |
SQR |
SQRT |
STATUS |
STATUSV |
TRUNC |
UAND |
UFB |
UINT |
UNDEFINED |
UNOT |
UOR |
UROUND |
UTRUNC |
UXOR |
program math(output); procedure a( function f(r:real):real ); begin writeln(f(1.0)); end; begin a(sin); a(cos); end.
6.3.5. Foreign Parameters
Passing Mechanism |
Specifiers and Attributes |
---|---|
By immediate value |
%IMMED or [IMMEDIATE] |
By reference |
%REF or [REFERENCE] |
By descriptor |
%DESCR or %STDESCR |
Note
Depending on the environment in which you are programming, not all passing-mechanism specifiers may be supported on your system.
The foreign mechanism specifier %IMMED, %REF, %DESCR or %STDESCR precedes a formal parameter in the declaration of an external routine. If the formal parameter does not represent a routine, the mechanism specifier must precede the parameter name. If the formal parameter represents a routine, the specifier must precede the reserved word PROCEDURE or FUNCTION in the parameter declaration.
In addition, it is possible to use the passing-mechanism attributes [IMMEDIATE] or [REFERENCE] in a formal parameter's attribute list to obtain the same behavior as %IMMED or %REF, respectively.
When calling an external routine, you must make sure that you pass actual parameters by the mechanism stated or implied in the routine declaration. VSI Pascal allows you to use the foreign mechanism specifiers %IMMED, %REF, %DESCR, and %STDESCR before an actual parameter in a routine call. (Passing-mechanism attributes are valid only on formal parameters.) When a mechanism specifier appears in a call, it overrides the type, semantics, mechanism specified, and even the number of parameters in the formal parameter declaration. Type checking is suspended for the parameter association to which the specifier applies.
The passing of an expression to a foreign mechanism parameter implies foreign value semantics: the calling block makes a copy of the actual parameter's value and passes this copy to the called routine. The copy is not retained when control returns to the calling block. Foreign value semantics differs from value semantics in that the calling block, not the called routine, makes the copy.
The passing of a variable to a foreign mechanism parameter (except a parameter with the %IMMED or [IMMEDIATE] specifier) implies foreign variable semantics: the variable itself is passed.
A compile-time warning occurs if the compiler must convert the value of an actual parameter variable to make it match the type of a foreign mechanism parameter. In that case, the compiler passes a copy of the converted value by foreign value semantics, using the specified mechanism. You can eliminate this warning by enclosing the actual parameter variable in parentheses; by doing so, you prevent the compiler from interpreting the actual parameter as a variable. The compiler takes the same action, whether or not it produces a warning message.
A %REF or [REFERENCE] formal parameter requires actual parameters to be passed by reference. %REF or [REFERENCE] implies variable semantics unless the actual parameter is an expression; in that case, it implies foreign value semantics.
An %IMMED or [IMMEDIATE] formal parameter requires actual parameters to be passed with the by immediate value mechanism and always implies value semantics. %IMMED or [IMMEDIATE] cannot be used on formal parameters of type VARYING, or on conformant array and conformant VARYING parameters.
A %DESCR formal parameter requires actual parameters to be passed with the by descriptor mechanism and interprets the semantics as %REF or [REFERENCE] does.
A %STDESCR formal parameter requires actual parameters to be passed with the by string descriptor mechanism. An actual parameter variable of type PACKED ARRAY OF CHAR implies variable semantics. An actual parameter expression of either type PACKED ARRAY OF CHAR or type VARYING OF CHAR implies foreign value semantics. You cannot use %STDESCR on formal procedure and function parameters.
Because the semantics are implicit in the mechanism, a formal parameter cannot be declared with both the reserved word VAR and a mechanism specifier.
Also, when passing an actual parameter to a formal foreign parameter, the VSI Pascal compiler checks for type compatibility when an external routine is called. However, at the time of the declaration, a formal parameter passed by immediate value that does not represent a routine is checked to ensure that it can be stored in 64 or fewer bits, or 32 or fewer bits, depending on the platform. A formal parameter passed by immediate value that does represent a routine must be declared with the UNBOUND attribute.
p( %IMMED f ); {Address of function f is passed}
p( %IMMED (f) ); {Result of function f is passed}
For More Information:
On conformant parameters (Section 6.3.7, “Conformant Parameters”)
On type conversions (Section 4.4, “Type Conversions”)
On attributes (Chapter 10, Attributes)
On calling external routines (VSI Pascal User Manual)
On compiler messages (VSI Pascal User Manual)
6.3.6. Schema Parameters
VSI Pascal provides a method of processing schematic arrays, records, sets, subranges, and STRINGs with potentially different actual discriminants. To do this, you can use undiscriminated schema parameters.
An undiscriminated schema formal parameter is a type name that represents a specific schema family. The actual discriminants are determined each time you pass a corresponding actual parameter. The actual discriminants are available within the routine through the formal parameter.
You cannot pass schema sets and schema subranges as value parameters, since there is no assignment compatibility for undiscriminated sets and for undiscriminated subranges.
You can pass a varying-length string expression to a formal STRING parameter (the actual parameter does not have to be of the STRING type).
TYPE Array_Template( lbnd, hbnd : INTEGER ) = ARRAY[lbnd..hbnd] OF INTEGER; VAR Even_Numbers : Array_Template( 1, 30 ); Odd_Numbers : Array_Template( 1, 60 ); PROCEDURE Print_Array( Array_To_Print : Array_Template ); VAR i : INTEGER; BEGIN WRITELN( 'The maximum number of elements is ', Array_To_Print.hbnd ); WRITELN; FOR I := LOWER( Array_To_Print ) TO UPPER( Array_To_Print ) DO WRITELN( Array_To_Print[i] ); END; {In the executable section:} Print_Array( Even_Numbers ); Print_Array( Odd_Numbers );
All passing-mechanism specifiers and attributes (%REF, %IMMED, %DESCR, %STDSCR, [REFERENCE], [IMMEDIATE], [CLASS_S], [CLASS_A], [CLASS_NCA]) are illegal on parameters of nonstatic types.
When you specify more than one formal schema parameter of the same schema type in a single parameter section, there are additional programming considerations.
TYPE Array_Template( Upper_Bound : INTEGER ) = ARRAY[1..Upper_Bound] OF INTEGER; VAR Actual_1, Actual_2 : Array_Template( 10 ); Actual_3 : Array_Template( 20 ); PROCEDURE Schema_Proc1( Only_One : Array_Template ); {Body...} PROCEDURE Schema_Proc2( One, Two : Array_Template ); {Body...} {In the executable section:} Schema_Proc1( Actual_1 ); {Legal} Schema_Proc1( Actual_3 ); {Legal} Schema_Proc2( Actual_1, Actual_2 ); {Legal} Schema_Proc2( Actual_1, Actual_3 ); {Illegal}
VAR One_String, Two_String : STRING( 15 ); Three_String : STRING( 20 ); PROCEDURE Test_Strings( One, Two : STRING ); {Body...} {In the executable section:} Test_Strings( 'a', 'b' ); {Legal} Test_Strings( 'a', 'bb' ); {Illegal} One_String := 'Hello'; Two_String := 'Hello there'; Three_String := 'olleH'; Test_Strings( One_String, Two_String ); {Illegal} Test_Strings( One_String, Three_String ); {Legal}
When using variable semantics, if you specify more than one formal parameter (separated by commas) of an undiscriminated STRING type, the corresponding discriminated STRING actual parameters must have an equivalent maximum length.
For More Information:
On user-defined schema types (Section 2.5, “Schema Types”)
On the STRING predefined schema type (Section 2.6.3, “STRING Schema Type”)
6.3.7. Conformant Parameters
VSI Pascal provides a method of processing arrays and character strings with potentially different maximum lengths. To do this, you can use conformant array parameters or conformant varying parameters.
A conformant parameter is a syntax that represents a set of types that are identical except for their bounds. The bounds of a conformant parameter are determined each time a corresponding actual parameter is passed. The bounds of an actual parameter are available within the routine through identifiers declared in the conformant parameter. A conformant parameter can appear only within a formal parameter list.
You can use conformant parameters when declaring value, variable, and foreign mechanism parameters. When you use a conformant parameter instead of a type identifier in a formal parameter declaration, a call to the routine can provide static and nonstatic arrays, VARYING OF CHAR strings, and discriminated strings (of the STRING schema family) of any size.
In addition, two conformant parameters are equivalent if they have indexes of the same ordinal type and components that either are compatible or are equivalent conformant parameters. They must also have the same number of dimensions and both must be packed or unpacked.
6.3.7.1. Conformant Array Parameters
The syntax for a conformant array has the following form:
ARRAY[{lower-bound-identifier..upper-bound-identifier : [[attribute-list]] index-type-identifier};...] OF [[attribute-list]] {type-identifier } {conformant-parameter-syntax } PACKED ARRAY[lower-bound-identifier..upper-bound-identifier : [[attribute-list]] index-type-identifier] OF [[attribute-list]] type-identifier
lower-bound-identifier
An identifier that represents the lower bound of the conformant array's index.
upper-bound-identifier
An identifier that represents the upper bound of the conformant array's index.
attribute-list
One or more identifiers that provide additional information about the conformant array.
index-type-identifier
The type identifier of the index, which must denote an ordinal type.
type-identifier
The type identifier of the array components, which can denote any type.
To specify the range and type of the index, you must use type identifiers that represent predefined or user-defined ordinal types. The identifiers that represent the index bounds can be thought of as READONLY value parameters, implicitly declared in the procedure declaration.
PACKED ARRAY[l1..u1: INTEGER; l2..u2: INTEGER] OF CHAR
ARRAY[l1..u1: INTEGER] OF PACKED ARRAY[l2..u2: INTEGER] OF CHAR
TYPE Workdays = 1..31; Feb_Days = 1..28; Mar_Days = 1..31; VAR Feb_Arr : ARRAY[Feb_Days] OF INTEGER; Mar_Arr : ARRAY[Mar_Days] OF INTEGER; Feb_Total, Mar_Total : INTEGER; FUNCTION Inventory( VAR Amt_Sold : ARRAY[First_Day..Last_Day : Workdays] OF INTEGER ) : INTEGER; {In executable section:} {Amt_Sold : ARRAY[1..28] OF INTEGER...} Feb_Total := Inventory( Feb_Arr ); {Amt_Sold : ARRAY[1..31] OF INTEGER...} Mar_Total := Inventory( Mar_Arr );
The formal parameter Amt_Sold can have index values from 1 to 31 to indicate the number of workdays in each month. Thus, an actual parameter passed to Amt_Sold could be an array whose index type is either Feb_Days or Mar_Days. Using a conformant parameter in this example allows you to write a general-purpose routine that sums the components of Amt_Sold and returns the monthly inventory total to the calling block.
For More Information:
On ordinal types (Section 2.1, “Ordinal Types”)
On arrays (Section 2.4.1, “ARRAY Types”)
On attributes (Chapter 10, Attributes)
6.3.7.2. Conformant VARYING Parameter
The syntax for a conformant VARYING string has the following form:
VARYING [upper-bound-identifier] OF [[attribute-list]] CHAR
attribute-list
One or more identifiers that provide additional information about the conformant VARYING string.
upper-bound-identifier
An identifier that represents the upper bound of the conformant VARYING OF CHAR string's index. The type of the upper-bound-identifier is always an integer.
The upper-bound-identifier specifies the maximum length of the VARYING OF CHAR string and must denote an integer. The upper-bound-identifier that represents the maximum length can be thought of as a READONLY value parameter, implicitly declared in the procedure declaration.
When you pass a string expression to a value conformant varying-length parameter, the length of the actual parameter's current value parameter (not its declared maximum length) becomes both the current length and the maximum length of the formal parameter. When you pass either a conformant VARYING OF CHAR string variable or a discriminated STRING variable to a VAR conformant varying-length parameter, the declared maximum length of the actual parameter becomes the maximum length of the formal parameter.
VAR Short_String : VARYING[40] OF CHAR := PAD( '', '-', 40 ); Long_String : VARYING[80] OF CHAR := PAD( '', '-', 80 ); PROCEDURE Dashed_Line( VAR String : VARYING[Len] OF CHAR ); {Body...} {In the executable section:} Dashed_Line( Short_String ); Dashed_Line( Long_String );
In this example, note that Len is not a previously declared identifier but is instead an additional implicit parameter defined by the procedure declaration. The upper bound of the conformant parameter String is established by the declared maximum length of the actual parameter passed to it when the procedure Dashed_Line is called. The first call to Dashed_Line passes a 40-character string, so Len has the value 40. The second call passes an 80-character string, so Len has the value 80.
For More Information:
On VARYING OF CHAR data types (Section 2.6.2, “VARYING OF CHAR Types”)
On attributes (Chapter 10, Attributes)
6.3.7.3. Conformant Parameter Sections
When you specify more than one conformant parameter of the same type in a single parameter section, there are additional programming considerations.
Equivalent current lengths (in the case of passing a string expression to a conformant PACKED array parameter of type CHAR or to a conformant VARYING OF CHAR
Indexes that are equivalent and of the same ordinal type, the same number of dimensions, and components that are compatible (in the case of passing a static or nonstatic array to a conformant array parameter)
VAR Actual_1, Actual_2 : ARRAY[1..10] OF INTEGER; Actual_3 : ARRAY[5..10] OF INTEGER; PROCEDURE TestArr( One, Two : ARRAY [L1..U1 : INTEGER] OF INTEGER ); {Procedure body...} PROCEDURE TestStr( One, Two : PACKED [L2..U2 : INTEGER] OF CHAR ); {Procedure body...} {In the executable section:} TestArr( Actual_1, Actual_2); {Legal} TestArr( Actual_2, Actual_3); {Illegal} TestStr( 'ABC', 'XYZ' ); {Legal} TestStr( 'HELLO', 'GOODBYE' ); {Illegal}
When using variable semantics, if you specify more than one formal parameter (separated by commas) of a single, user-defined, conformant parameter, the corresponding actual variable parameters must be of the same type.
For More Information:
On ordinal types (Section 2.1, “Ordinal Types”)
On static and nonstatic types (Section 2.9, “Static and Nonstatic Types”)
6.3.8. Parameter Association
In most cases, a routine call must pass exactly one actual parameter for each formal parameter. The actual parameter is either listed explicitly in the routine call or supplied by means of a default value in the routine declaration.
One way of establishing the correspondence between actual and formal parameters is to give the parameters in each list the same position. That is, the association of actual and formal parameters proceeds from left to right, item by item, through both lists. This form of association is called positional syntax.
Another way of establishing correspondence is to specify the formal parameter name and the actual parameter being passed to it. In VSI Pascal, you can associate an actual parameter with a formal parameter using the assignment operator (:=). The actual parameters in the call do not have to appear in the same order as the formal parameters appeared in the declaration. This form of association is called nonpositional syntax.
You can use both positional and nonpositional actual parameters in the same call. However, after you specify one parameter in nonpositional syntax, all remaining parameters must be in nonpositional syntax (all parameters in positional syntax must be at the front of the list).
PROCEDURE Compute_Sum( x, y : INTEGER; VAR z : INTEGER ); {Body...} {In the executable section:} {Positional syntax:} Compute_Sum( Quantity + 6, 15, Total ); {Nonpositional syntax:} Compute_Sum( z := Total, x := Quantity + 6, y := 15 {Both syntaxes:} Compute_Sum( Quantity + 6, z := Total, y := 15
For More Information:
On using the LIST and TRUNCATE attributes to specify variable-length parameter lists (Sections 10.2.24 and 10.2.37)
On scope (Section 7.2, “Scope of Identifiers”)
6.3.9. Default Formal Parameters
VSI Pascal allows you to supply default values for formal parameters. Using default parameter values, you do not need to pass actual parameters. Also, you can specify an actual parameter in the position of a formal parameter whose default value you want to override. To specify a default value, use the following format:
parameter-spec := [[mechanism-specifier]] constant-expression;
parameter-spec
The parameter specification. The syntax for a parameter specification depends on its semantics.
mechanism-specifier
The mechanism by which VSI Pascal associates a default value with a formal parameter. You can only specify a mechanism-specifier on a foreign routine.
constant-expression
A constant expression representing the default value for the formal parameter.
Formal Parameter Type |
External Routine |
VSI Pascal Routine |
---|---|---|
Variable |
Requires foreign mechanism specifier |
Error |
Value |
Allowed |
Allowed |
Routine |
Requires foreign mechanism specifier |
Error |
When you declare a formal parameter with a default value, you can either omit it from the routine call or, if you use positional syntax, you can indicate its position with a comma.
FUNCTION Net_Pay( Hours : INTEGER; Tax : REAL := 0.05; Rate : REAL; Fica : REAL := 0.07; Overtime : INTEGER ) : REAL; {Body...} {In the executable section:} {Nonpositional syntax:} Take_Home_Year := Take_Home_Year + Net_Pay ( Overtime := Overtime_Week, Rate := Pay_Rate, Hours := Hours_Week ); {Positional syntax:} Take_Home_Year := Take_Home_Year + Net_Pay( Hours_Week, , Pay_Rate, , Overtime_Week );
The formal parameters Tax and Fica are given the default values 0.05 and 0.07, respectively.
Take_Home_Year:= Take_Home_Year + Net_Pay( Hours_Week, 0.06, Pay_Rate, , Overtime_Week );
As a result of this routine call, the default value of Tax will be replaced by the value 0.06 supplied in the actual parameter list.
For More Information:
On specifying passing mechanisms (Section 6.3.5, “Foreign Parameters”)
On positional and nonpositional syntax of parameters (Section 6.3.8, “Parameter Association”)
Chapter 7. Program Structure and Scope
7.1. Blocks
A block is a declaration section and an executable section. Programs, modules, and routines are structured in blocks. A declaration section can contain routine blocks nested within the outer program or module block; routine blocks can also be nested within other routines.
The declaration section contains data definitions and declarations, and nested routine declarations that are local to the enclosing block. The executable section contains the statements that specify the block's actions. You can cause an exit from a block with the last executable statement of the block, which causes normal termination, or with a GOTO statement, which transfers control to an outer block.
For More Information:
On declaration sections (Chapter 3, Declaration Section)
On routine declarations (Section 6.1, “Routine Declarations”)
On the GOTO statement (Section 5.8, “GOTO Statement”)
7.2. Scope of Identifiers
The scope of an identifier is the part of the program in which the identifier has a particular meaning. In Pascal, the scope of an identifier is the block in which it is defined or declared, including nested blocks (but excluding any nested blocks that redeclare the same identifier). Outside its scope and assuming that it is not declared elsewhere, an identifier has no meaning; in this case, attempts to use the identifier generate an error.
An identifier can be declared only once within a particular scope.
A previously declared identifier can be redeclared in a nested block.
An identifier declared in the main program or module block is accessible in all nested blocks (except where it is redeclared).
A procedure identifier can be redeclared within its own declaration section.
A function identifier can also be redeclared, but not in a declaration section of the function's outermost block. The identifier can be redeclared only in a nested block because you need to be able to assign a value to it in the outermost block unless a RETURN statement is used.
A formal parameter name follows the same rules of scope as a function identifier and can be redeclared only in a nested block.
A label declaration must respect GOTO statement restrictions. These restrictions prevent control passing from an outer to an inner block.
7.3. Redeclaring Routine Names
Routine names can be redeclared like any other identifier. A block, in its declaration section, can specify routines with the same names as those outside the block. This changes the meaning of function and procedure calls when they occur within the block.
A procedure can redeclare its own identifier. For example, the declaration section of the procedure Sum can declare a different procedure called Sum. The scope of this second declaration is only within the first block; calls to Sum within the block are not recursive but are calls to the locally declared routine.
You can also redeclare a function identifier within its own declaration. However, the function then cannot use the function identifier in an assignment to return a value to the caller. A function that redeclares its own identifier must use the RETURN statement (see Section 5.12, “RETURN Statement”) to specify a return value.
In the declaration section you cannot redeclare an identifier used in the formal parameter list of the routine. However, a block nested in the declaration section can do so. The following example shows the scope of identifiers that appear in several blocks in a program.
Variable identifiers a and b are declared at the outer level of the example. Scope rules make them accessible throughout the example. In the main program, Level1a, and Level1b, identifiers a and b represent integers. In Level2, variable identifer a still represents an integer variable, but b is redeclared as a Boolean variable.
Type identifier c and variable identifiers d and e are declared at the next lower level, Level1a. Scope rules make them accessible only in this block. They cannot be accessed from the higher-level main program. They cannot be accessed from a lower-level block because Level1a contains no nested routine.
Formal parameter identifiers v, u, and t are declared at the same level, Level1b. They cannot be redeclared within this block. They can be redeclared as local identifiers in the nested block of FUNCTION Level2.
Procedure identifier Level1a is declared in the outermost block of the example. This identifier can be redeclared within its own declaration section.
Function identifier Level2 is declared in the next-highest level, Level1b. It cannot be declared within this block. Level2 can be redeclared as a local identifier within a nested block.

For More Information:
On scope of routine identifiers (Section 6.1, “Routine Declarations”)
On scope of formal parameters (Section 6.3, “Parameters”)
On scope of labels and GOTO statements (Section 5.8, “GOTO Statement”)
7.4. Modules and Programs
A module is a set of instructions that can be compiled, but not executed, by itself. Module blocks contain only a declaration section and TO BEGIN DO and TO END DO sections. A program is a set of instructions that can be compiled and executed by itself. Program blocks contain a declaration and an executable section. A compilation unit is a unit of VSI Pascal code that can be compiled independently; the term compilation unit refers to either a program or a module.
Each module and program must be in a separate file; you cannot place multiple modules (or a module and a program) in the same file. You can compile modules and a program together or separately (the syntax of compilation depends on the operating system you are using).
[[attribute-list]] PROGRAM comp-unit-identifier [[({file-identifier},...)]]; [[declaration-section]] BEGIN {statement};... END. [[attribute-list]] MODULE comp-unit-identifier [[({file-identifier},...)]]; [[declaration-section]] [[TO BEGIN DO statement;]] [[TO END DO statement;]] END.
The module syntax of VSI Pascal is slightly different than that of Extended Pascal. However, the concepts in both languages are the same.
attribute-list
One or more identifiers that provide additional information about the compilation unit.
comp-unit-identifier
Specifies the name of the program or module. The identifier appears only in the heading and has no other purpose within the compilation unit.
file-identifier
Specifies the names of any file variables associated with the external files used by the compilation unit.
declaration-section
A Pascal declaration section.
statement
A Pascal statement.
The program or module heading includes all information preceding the program or module block. If your program contains any input or output routines, you must list all the external file variables that you are using in the compilation unit's heading. File variables listed in a heading must also be declared locally in the block, except for the predeclared file variables INPUT and OUTPUT. The INPUT identifier corresponds to a predefined external file that accepts input from the default device (usually, your terminal). The OUTPUT identifier corresponds to a predefined external file that sends output to the default device (usually, your terminal). the ERR identifier corresponds If you redeclare INPUT and OUTPUT in a nested block, you lose access to the default input and output devices.
PROGRAM Write_Var(OUTPUT); {Header} VAR {Declaration section} Number : INTEGER VALUE 3; BEGIN {Executable section} WRITELN( Number ); {Writes 3 to the default device} END.
For More Information:
On INPUT and OUTPUT (Section 9.5, “TEXT Files”)
On compilation and command-line syntax (VSI Pascal User Manual)
On the TO BEGIN DO section (Section 3.3, “TO BEGIN DO Section”)
On the TO END DO section (Section 3.4, “TO END DO Section”)
7.5. Compilation Units and Data Sharing
When dividing code into programs and modules, you may want to share declarations among compilation units. The following sections discuss ways of sharing data.
7.5.1. Environment Files
{Contained in one file:} [INHERIT ('file_name')] PROGRAM a( INPUT, OUTPUT ); BEGIN READ( Amount ); Calc; WRITELN( 'Purchase Amount: ', Amount:10:2) WRITELN( ' + ', Tax:10:2) WRITELN( 'Pay This Total: ', Total:10:2) END. {Contained in a separate file:} [ENVIRONMENT('file_name')] MODULE B; {Keep all global data in one module} CONST {Compile this unit first to create file} Rate = 0.06; VAR Amount, Total, Tax: REAL; PROCEDURE Glf; BEGIN...END; PROCEDURE Calc; BEGIN Tax := Amount * Rate; Total := Tax + Amount; Glf; END; END.
Since the declarations in module b compose the environment file to be inherited by another compilation unit, you must compile module b first to create the environment file. When compiling module b, VSI Pascal creates an environment file by the name of file_name. VSI Pascal adds a file type of .PEN (for Pascal Environment).
The environment file contains declaration information about the constant Rate; about the variables Amount, Total, and Tax; and about the procedures Glf and Calc. If there are identifiers in a compilation unit that you do not want to be included in an environment file, use the HIDDEN attribute.
When you compile program a, which contains the INHERIT attribute, VSI Pascal uses the specified environment file to allow the program access to the data and routines declared in the module. Variables that are inherited from an environment file are not newly created variables, but are the same variables that were allocated storage by the declaring compilation unit.
A compilation unit may create only one environment file, but may inherit multiple files that must have been created by earlier compilations. Declarations from inherited files are not included in any environment files created by the compilation unit. An environment file must have been created by a version of the compiler that is compatible with the version that is compiling the compilation unit.
A variable identifier can be multiply declared if all declarations of the variable have the same type, and all but one declaration at most are external.
A procedure identifier can be multiply declared if all declarations of the procedure have congruent parameter lists, and all but one declaration at most are external.
A function identifier can be multiply declared if all declarations of the function have congruent parameter lists and identical result types, and all but one declaration at most are external.
{In one compilation unit:} [ENVIRONMENT('extern.pen')] MODULE Mod1; [EXTERNAL] PROCEDURE Inst; EXTERN; END. {In another compilation unit:} [INHERIT('extern.pen')] MODULE Mod2; [GLOBAL] PROCEDURE Inst; {Body...} END.
For More Information:
On the ENVIRONMENT attribute (Section 10.2.14, “ENVIRONMENT”)
On the INHERIT attribute (Section 10.2.21, “INHERIT”)
On the HIDDEN attribute (Section 10.2.18, “HIDDEN”)
On declaration sections (Chapter 3, Declaration Section)
7.5.2. Global and External Identifiers
Global and external identifiers are accessible to other compilation units (even to compilation units written in other languages) that make up one executable unit. The GLOBAL attribute allows a declared identifier to be globally accessible by other compilation units; the EXTERNAL attribute specifies that another compilation unit allocates storage for the data or routine. The compiler does not check to make sure that global and external identifiers are declared as being of the same data type; you must ensure that the data types are compatible.
You cannot use global and external names to share the declarations of user-defined types. However, you can use the VALUE attribute to share global and external literals.
{Contained in one file:} PROGRAM a( INPUT, OUTPUT ); VAR Amount, Total, Tax : [EXTERNAL] REAL; {Defined elsewhere} [EXTERNAL] PROCEDURE Calc; EXTERNAL; {Defined elsewhere} [GLOBAL] PROCEDURE Glf; {Body...} {Available outside} BEGIN READ( Amount ); Calc; WRITELN( 'Purchase Amount: ', Amount:10:2) WRITELN( ' + ', Tax:10:2) WRITELN( 'Pay This Total: ', Total:10:2) END. {Contained in a separate file:} MODULE B; CONST Rate = 0.06; VAR Amount, Total, Tax: [GLOBAL] REAL; {Available outside} [EXTERNAL] PROCEDURE Glf; EXTERNAL; {Defined elsewhere} [GLOBAL] PROCEDURE Calc; {Available outside} BEGIN Tax := Amount * Rate; Total := Tax + Amount; Glf; END; END.
The file containing the module can be compiled separately from the file containing the program.
For More Information:
On the GLOBAL attribute (Section 10.2.17, “GLOBAL”)
On the EXTERNAL attribute (Section 10.2.15, “EXTERNAL”)
Chapter 8. Predeclared Functions and Procedures
VSI Pascal supplies predeclared procedures and functions that perform various commonly used operations. You do not have to declare these routines in order to call them from your code.
In this chapter, the routines are presented in alphabetical order. To save you the time of scrolling through all the routines, you may wish to click on the Table Of Contents entry for the desired routine.
Also in this chapter, the term arithmetic types refers to those data types you can use in arithmetic operations: the integer, unsigned, and real types.
Category |
Category Description and Routines |
---|---|
Allocation size |
Routines that provide information about the amount of storage allocated for variables and for components of various types: BITNEXT, BITSIZE, NEXT, and SIZE |
Arithmetic |
Routines that perform mathematical computations: ABS, ARCTAN, CARD, COS, EXP, EXPO, LN, LSHIFT, RSHIFT, MAX, MIN, RANDOM, SEED, SIN, SQR, SQRT, UNDEFINED, UAND, UNOT, UOR, UXOR, and XOR |
Character-string |
Routines that manipulate character strings: BIN, DEC, EQ, FIND_MEMBER, FIND_NONMEMBER, GE, GT, HEX, INDEX, LE, LENGTH, LT, NE, OCT, PAD, READV, STATUSV, SUBSTR, UDEC, and WRITEV |
Component position |
Routines that provide information about the offset of record components: BIT_OFFSET and BYTE_OFFSET |
Condition handling |
ASSERT, ESTABLISH, HALT, REVERT |
Date-time |
Routines that provide information on the calendar date and time: CLOCK, DATE, GETTIMESTAMP, SYSCLOCK, TIME, and WALLCLOCK |
Dynamic allocation |
Routines that provide for the creation and use of pointer variables: ADDRESS, DISPOSE, IADDRESS, IADDRESS64, and NEW |
File operations |
Routines that create, rename, and remove files and directories: CREATE_DIRECTORY, DELETE_FILE, RENAME_FILE |
Input and Output |
Routines that you use for I/O; these routines are not described in this chapter |
Low-level |
Routines that allow for parallel processes and for asynchronous routines to operate in a real-time or multitasking environment: ADD_ATOMIC, AND_ATOMIC, ADD_INTERLOCKED, BARRIER, CLEAR_INTERLOCKED, OR_ATOMIC and SET_INTERLOCKED |
Null-terminated strings |
Routines that operate on null-terminated strings: C_STR, MALLOC_C_STR, PAS_STRCPY, PAS_STR |
Ordinal |
Routines that provide information on the ordered sequence of values: PRED, SUCC, LOWER and UPPER, ODD |
Parameter |
Routines that give information about parameter lists: ARGC, ARGV, ARGUMENT, ARGUMENT_LIST_LENGTH, and PRESENT |
Privileged ("OpenVMS VAX systems only") |
Routines that manipulate privileged hardware registers: MFPR and MTPR |
Type conversion |
Routines that convert an actual parameter to data of another type: CHR, DBLE, INT, INT64, ORD, PACK, QUAD, ROUND, ROUND64, SNGL, TRUNC, TRUNC64, UINT, UINT64, UNPACK, UROUND, UROUND64, UTRUNC, and UTRUNC64 |
Miscellaneous |
FIND_FIRST_BIT_CLEAR, FIND_FIRST_BIT_SET, UNDEFINED, and ZERO |
Note
Not all routines are supported on all operating system and machine architecture environments. If a routine is not supported on all environments, the routine description includes any limitations.
For More Information:
On data types (Chapter 2, Data Types and Values)
On ordinal types (Section 2.1, “Ordinal Types”)
On pointers (Section 2.3, “Pointer Types”)
On arrays and records (Section 2.4, “Structured Types”)
On parameter lists (Section 6.3, “Parameters”)
On input and output routines (Section 9.8, “I/O Routines”)
On data storage (Appendix A, Data Storage and Representation)
8.1. ABS Function
ABS( x )
The parameter x can be of any arithmetic type.
8.2. ADD_ATOMIC Function
ADD_ATOMIC( e, v )
The type of the expression e must be assignment compatible with that of the variable v. The variable v must be an INTEGER, UNSIGNED, INTEGER64, or UNSIGNED variable and must be allocated on a natural boundary, such as longword for INTEGER and UNSIGNED and quadword for INTEGER64 and UNSIGNED64. The result of ADD_ATOMIC is the same type as the variable v.
Overflow and subrange checking are never performed on the ADD_ATOMIC operation, even if these options are in effect for the rest of the function or compilation unit.
The ADD_ATOMIC function does not provide memory synchronization between multiple processors. The BARRIER predeclared routine must be used for that purpose.
This function is used to access data that is shared between two or more threads of execution.
For More Information
On atomic operations (VSI Pascal User Manual)
8.3. ADD_INTERLOCKED Function
ADD_INTERLOCKED( e, v )
The type of the expression e must be assignment compatible with that of the variable v. The variable v must be an integer or an unsigned subrange; v must have an allocation size of two bytes and must be aligned on a word boundary. The type of e must be assignment compatible with that of v.
Note that unless the type of v is an integer subrange that includes negative values, the result of the ADD_INTERLOCKED function is never -1.
Overflow and subrange checking are never performed on the ADD_INTERLOCKED operation, even if these options are in effect for the rest of the function or compilation unit.
This function is used to access data that is shared between two or more threads of execution.
For More Information
On atomic operations (VSI Pascal User Manual)
8.4. ADDRESS Function
ADDRESS( x )
The parameter x can be a variable of any type except a component of a packed structured type. A compile-time warning results if x is a formal VAR parameter, a component of a formal VAR parameter, or a variable that does not have the READONLY or VOLATILE attribute.
A pointer can only refer to a VOLATILE variable or a variable allocated by the NEW procedure.
For More Information:
Pointer data types (Section 2.3, “Pointer Types”)
On the VOLATILE attribute (Section 10.2.42, “VOLATILE”)
On the NEW procedure (Section 8.58, “NEW Procedure”)
8.5. AND_ATOMIC Function
AND_ATOMIC( e, v )
The type of the expression e must be assignment compatible with that of the variable v. The variable v must be an INTEGER, UNSIGNED, INTEGER64, or UNSIGNED64 variable and must be allocated on a natural boundary, such as longword for INTEGER and UNSIGNED and quadword for INTERGER64 and UNSIGNED64. The result of AND_ATOMIC is the same type as the variable v.
The AND_ATOMIC function does not provide memory synchronization between multiple processors. The BARRIER predeclared routine must be used for that purpose.
This function is used to access data that is shared between two or more threads of execution.
For More Information
On atomic operations (VSI Pascal User Manual)
8.6. ARCTAN Function
ARCTAN( x )
The parameter x can be an integer or REAL type.
8.7. ARGUMENT Function
ARGUMENT( parameter-name, n )
The parameter-name argument specifies the name of a parameter declared with the LIST attribute. The parameter n specifies a positive integer value that identifies the argument. The first argument in a list is always 1. An error occurs if the value supplied for n is less than 1, or exceeds the ARGUMENT_LIST_LENGTH parameter (which indicates the total number of arguments).
If the LIST parameter is a value parameter, ARGUMENT indicates the corresponding value in the argument list. If the LIST parameter is a VAR parameter, ARGUMENT is a reference to the corresponding variable in the argument list.
Also, you can use the IADDRESS function with the ARGUMENT function to return the address of a selected argument.
For More Information:
On variable-length parameter lists (the example in Section 8.8, “ARGUMENT_LIST_LENGTH Function ”)
On parameters (Section 6.3, “Parameters”)
On the LIST attribute (Section 10.2.24, “LIST”)
On the IADDRESS function (Section 8.42, “IADDRESS Function”)
8.8. ARGUMENT_LIST_LENGTH Function
ARGUMENT_LIST_LENGTH( parameter-name )
The parameter-name argument specifies the name of the parameter declared with the LIST attribute.
PROGRAM Show_Arg( OUTPUT ); {Ax corresponds to any number of char. arguments} PROCEDURE Variable_Write( Fl : VARYING[len] OF CHAR; Ax : [LIST] CHAR ); VAR i : INTEGER; BEGIN WRITE( Fl, ', ' ); {For however many arguments there are:} FOR i := 1 TO ARGUMENT_LIST_LENGTH( Ax ) DO WRITE( ARGUMENT( Ax, i ) ); {Write an argument} WRITELN; END; {In the executable section:} Variable_Write( ' hello', '*' ); {One argument: Writes ' hello, *'} Variable_Write( ' hello','s','a','i','l','o','r','!' ); {Seven arguments: Writes ' hello, sailor!'}
For More Information:
On parameters (Section 6.3, “Parameters”)
On the LIST attribute (Section 10.2.24, “LIST”)
8.9. ASSERT Procedure
ASSERT(expression [[, string]])
The parameter expression is a Boolean expression that is normally true. If ASSERT evaluates the expression as false, it signals a run-time error indicating that the assertion failed.
The optional string parameter is output as part of the error message.
8.10. BARRIER Function
BARRIER
The BARRIER procedure has no parameters.
This routine is used to serialize memory writes on VSI OpenVMS I64 and VSI OpenVMS Alpha systems.
For More Information
On memory granularity (VSI Pascal User Manual)
8.11. BIN Function
BIN( x[[, length[[, digits]] ]] )
The parameter x is the expression to be converted. This parameter must have a size that is known at compile time; it cannot be VARYING OF CHAR, a conformant parameter, or a schema type.
The BIN function can also be used in compile-time expressions with ordinal-types.
Two optional integer parameters specify the length of the resulting string and the minimum number of significant digits to be returned. If you specify a length that is too short to hold the converted value, the resulting string is truncated on the left.
TYPE Month_Dates = SET OF 0..31; VAR Days_Of_Rain : Month_Dates; {In the executable section:} Days_Of_Rain := [1, 2, 6, 10, 12, 14, 18, 22, 25, 30]; Result := BIN (Days_Of_Rain, 32); {Returns '01000010010001000101010001000110', 32 characters}
The binary representation is from right to left, with the leftmost bit being bit 31 and the rightmost bit being bit 0.
For More Information:
On character strings (Section 2.6, “String Types”)
On conformant parameters (Section 6.3.7, “Conformant Parameters”)
8.12. BIT_OFFSET Function
BIT_OFFSET( t, f )
The parameter t can be of any record type or variable, and the parameter f can be any field contained in that record.
For More Information:
On records (Section 2.4.2, “RECORD Types”)
8.13. BITNEXT Function
BITNEXT( x )
The parameter x can be a variable or any type identifier.
Cells in a packed array are affected by any alignment attributes placed on them. Therefore, the size returned includes the actual size of the type or variable in addition to trailing space required to ensure proper alignment.
The BITNEXT and BITSIZE functions return the same bit size for a given type or variable, except where the components of the packed array are padded to ensure proper alignment.
For More Information:
On examples of return values for this function (Table 8.2, “Return Values of Alignment Predeclared Routines”)
On packed arrays (Section 2.4, “Structured Types”)
8.14. BITSIZE Function
BITSIZE( x )
The parameter x can be a variable or any type identifier.
Fields in a packed record are not affected by any alignment attributes placed on subsequent fields. Therefore, the size returned indicates the actual size of the type or variable.
The BITNEXT and BITSIZE functions return the same bit size for a given type or variable, except where the components of the packed array are padded to ensure proper alignment.
For More Information:
On possible return values for this function (Table 8.2, “Return Values of Alignment Predeclared Routines”)
On packed arrays (Section 2.4, “Structured Types”)
8.15. BYTE_OFFSET Function
BYTE_OFFSET(t, f)
The parameter t can be of any record type or variable, and the parameter f can be any field contained in that record.
For More Information:
On records (Section 2.4.2, “RECORD Types”)
8.16. C_STR Function
C_STR(e)
C_STR(v)
In this form, it will return a C_STR_T value that represents the first character in the string variable. It does not ensure a terminating null byte. The programmer must handle the null-termination to treat a Pascal string variable as a null-terminated string.
8.17. CARD Function
CARD( s )
The parameter s must be a set expression.
For More Information:
On sets (Section 2.4.3, “SET Type”)
8.18. CHR Function
CHR(x)
The parameter x must be integer or unsigned and have a value from 0 to 255.
For More Information:
On the ASCII character set (Section 1.2.1, “Character Set”)
8.19. CLEAR_INTERLOCKED Function
CLEAR_INTERLOCKED( b )
The parameter b must be a variable of type BOOLEAN. The variable does not have to be aligned; therefore, it can be a field of a packed record.
This function is used to access data that is shared between two or more threads of execution.
For More Information
On atomic operations (VSI Pascal User Manual)
8.20. CLOCK Function
The CLOCK function returns an integer value indicating the amount of central processor time (in milliseconds) used by the current process. This function does not have a parameter list. The result of CLOCK includes the amount of central processor time allocated to all previously executed images.
8.21. COS Function
COS( x )
The parameter x can be an integer or REAL type, and is expressed in radians.
8.22. CREATE_DIRECTORY Procedure
CREATE_DIRECTORY( file-name [[, error-return]] )
The file-name parameter must be a directory name, and optionally can contain a device name. The error-return parameter is optional, and will return an error recovery code if specified.
For More Information:
On error recovery codes ( VSI Pascal User Manual)
8.23. DATE and TIME Functions
DATE( t ) TIME( t )
The parameter t is a variable of the predeclared type TIMESTAMP. You can either call the GETTIMESTAMP procedure to initialize parameter t before you pass t to either DATE or TIME, or you can construct your own TIMESTAMP object.
VAR Time_Var : TIMESTAMP; The_Time, The_Date : STRING( 23 ); {In the executable section:} GETTIMESTAMP( Time_Var ); The_Date := DATE( Time_Var ); The_Time := TIME( Time_Var ); WRITELN( The_Date, The_Time ); {Writes: 15-JUL-1992 14:20:25.98}
For More Information:
On the GETTIMESTAMP predeclared procedure (Section 8.38, “GETTIMESTAMP Procedure”)
On the layout of the TIMESTAMP type (Section 2.8, “TIMESTAMP Type”)
8.24. DATE and TIME Procedures
DATE( str ) TIME( str )
The parameter str must be of type PACKED ARRAY[1..11] OF CHAR. After execution of the procedure, the parameter str contains either the date or the time. If the day of the month is a 1-digit number, the leading zero does not appear in the result; that is, a space appears before the date string. The time is returned in 24-hour format.
For More Information:
On standard ways to obtain the date and the time (Section 8.23, “DATE and TIME Functions”)
8.25. DBLE Function
DBLE( x )
The parameter x must be of an arithmetic type. The value of x must not be too large to be represented by a double-precision number.
For More Information:
On precision and support for the DOUBLE data type (Chapter 2, Data Types and Values)
8.26. DEC Function
DEC( x[[, length[[, digits]] ]] )
The parameter x is the expression to be converted. The DEC function can take a parameter of any type except VARYING OF CHAR, conformant parameters, or schema types. The DEC function requires the size of x to be less than or equal to the size of INTEGER64.
The DEC function can also be used in compile-time expressions.
Two optional integer parameters specify the length of the resulting string and the minimum number of significant digits to be returned. If you specify a length that is too short to hold the converted value, the resulting string is truncated on the left. If you do not specify values for the optional parameters, a default length and a default minimum number of significant digits is used.
VAR Account : INTEGER; {In the executable section:} Account := 16#F; WRITELN( DEC( Account, 8, 7 ) );
The value of the integer variable Account is converted to its decimal equivalent (15) and, in this example, printed in eight columns: seven digits, and one leading blank ( 0000015).
For More Information:
On character strings (Section 2.6, “String Types”)
On conformant parameters (Section 6.3.7, “Conformant Parameters”)
8.27. DELETE_FILE Procedure
DELETE_FILE( file-name [[, error-return]] )
The file-name specification can contain an explicit device and directory name, plus it must contain a file name, a file type or extension, and a version number. If you omit either the directory or device name, VSI Pascal uses the directory you are working in at the time of program execution.
The error return parameter returns an error recovery code if specified.
For More Information:
On error recovery codes (VSI Pascal User Manual)
8.28. DISPOSE Procedure
DISPOSE( p [[, t1,...,tn]] )
The parameter p is a pointer expression. The t parameters are constant expressions that match the corresponding t parameter used in the call to the NEW procedure that allocated the memory. If you use t parameters in a call to NEW, you must specify the same t parameters in the call to DISPOSE. If you allocated memory using d parameters, just specify the pointer variable to the corresponding DISPOSE call.
DISPOSE( Ptr ); {Ptr^ is distroyed; Ptr becomes undefined}
For More Information:
On the pointer data types (Section 2.3, “Pointer Types”)
On the NEW procedure (Section 8.58, “NEW Procedure”)
8.29. EQ Function
EQ(str1, str2)
VAR Match : BOOLEAN; {In the executable section:} Match := EQ( 'exit ', 'exit' ); {Returns FALSE; unequal lengths} Match := EQ( 'exit', 'exit' ); {Returns TRUE}
For More Information:
On string data types (Section 2.6, “String Types”)
8.30. ESTABLISH Procedure
ESTABLISH( function-identifier )
The function-identifier parameter must be the name of a function that has the ASYNCHRONOUS attribute and must return an integer value.
For More Information:
On the ASYNCHRONOUS attribute (Section 10.2.3, “ASYNCHRONOUS”)
On error and report processing (VSI Pascal User Manual)
8.31. EXP Function
EXP( x )
The parameter x can be an integer or REAL type.
8.32. EXPO Function
EXPO( x )
The parameter x can be of any real type.
For More Information:
On precision and support for real numbers (Chapter 2, Data Types and Values)
8.33. FIND_FIRST_BIT_CLEAR Function
FIND_FIRST_BIT_CLEAR( vector [[, start-index]] )
The vector parameter is a variable of type PACKED ARRAY OF BOOLEAN with an integer index type. The optional start-index parameter must be an integer expression that indexes the element at the point at which the search starts. The starting index must be greater than or equal to the vector's lower bound, and less than or equal to 1 plus the vector's upper bound; otherwise, a range violation occurs. If omitted, the starting index defaults to the vector's first element.
This function returns a value indexing the first element containing the value 0. If no bit is 0, the result is 1 plus the vector's upper bound. If the vector or the indexed part of the vector has a size of 0, the result is start-index.
8.34. FIND_FIRST_BIT_SET Function
FIND_FIRST_BIT_SET( vector [[, start-index]] )
The vector parameter is a variable of type PACKED ARRAY OF BOOLEAN with an integer index type. The optional start-index parameter must be an expression of an integer type that indexes the element at the point at which the search starts. The starting index must be greater than or equal to the vector's lower bound, and less than or equal to 1 plus the vector's upper bound; otherwise, a range violation occurs. If omitted, the starting index defaults to the vector's first element.
VAR Boo : PACKED ARRAY [0..31] OF BOOLEAN; {In the executable section:} Boo::INTEGER := 128; WRITELN( FIND_FIRST_BIT_SET( BOO ) );
For More Information:
On the type cast operator (::) (Section 4.2.6, “Type Cast Operator”)
8.35. FIND_MEMBER Function
FIND_MEMBER( string, char-set )
The string parameter is a string value, and char-set is a value of type SET OF CHAR.
For More Information:
On string types (Section 2.6, “String Types”)
On sets (Section 2.4.3, “SET Type”)
8.36. FIND_NONMEMBER Function
FIND_NONMEMBER( string, char-set )
The string parameter is a string value, and char-set is a value of type SET OF CHAR.
For More Information:
On string types (Section 2.6, “String Types”)
On sets (Section 2.4.3, “SET Type”)
8.37. GE Function
GE( str1, str2 )
VAR Match : BOOLEAN; Test : STRING(8) VALUE 'ENTRANCE'; {In the executable section:} Match := GE( 'exit', 'exit' ); {Returns TRUE} Match := GE( Test, 'EXIT' ); {'N' less-than 'X': Returns FALSE}
For More Information:
On string data types (Section 2.6, “String Types”)
8.38. GETTIMESTAMP Procedure
GETTIMESTAMP( t [[, str]] )
The parameter t is a variable of the TIMESTAMP type, which is a predeclared record type.
If you do not specify the parameter str, the GETTIMESTAMP procedure initializes the variable to be the date and time at execution of the procedure.
If you specify an invalid date, the GETTIMESTAMP procedure sets the date to be January 1, 1. If you omit the date, this procedure uses the current date. If you specify an invalid time or if you omit the time, it sets the time to be midnight.
VAR Time_Var : TIMESTAMP; The_Time, The_Date : STRING( 23 ); {In the executable section:} GETTIMESTAMP( Time_Var ); {Get current date and time} GETTIMESTAMP( Time_Var, '22-Nov-1988 12:30:15.15'); GETTIMESTAMP( Time_Var, '22-Nov-1988' ); {Midnight at that date} GETTIMESTAMP( Time_Var, '41-Nov-1988 999:999:999.99' ); {Invalid date; sets TIME_VAR to midnight on January 1, 1}
GETTIMESTAMP( Time_Var, 'TOMORROW' ); {Midnight tomorrow}
For More Information:
On the DATE and TIME functions (Section 8.23, “DATE and TIME Functions”)
On the layout of the TIMESTAMP type (Section 2.8, “TIMESTAMP Type”)
8.39. GT Function
GT( str1, str2 )
VAR Match : BOOLEAN; Test : STRING( 8 ) VALUE 'ENTRANCE'; {In the executable section:} Match := GT( 'exit', 'exit' ); {Returns FALSE} Match := GT( Test, 'EXIT' ); {'N' less-than 'X': Returns FALSE}
For More Information:
On string data types (Section 2.6, “String Types”)
8.40. HALT Procedure
The HALT procedure uses operating system resources to stop execution of your program unless you have written a condition handler (using the ESTABLISH procedure) that enables continued execution.
For More Information:
On the ESTABLISH procedure (Section 8.30, “ESTABLISH Procedure”)
8.41. HEX Function
HEX( x[[, length[[, digits]] ]] )
The parameter x is the expression to be converted. This parameter must have a size that is known at compile time; it cannot be VARYING OF CHAR, a conformant parameter, or a schema type.
The HEX function can also be used in compile-time expressions with ordinal-types.
VAR p : ^Rec; {In the executable section:} Digits := 8; NEW( p ); Result := HEX( p, 10, Digits );
In this example, the HEX function returns a string of 10 characters containing the hexadecimal equivalent of the value of the pointer variable p. The string has eight significant digits, as specified by the value of the actual parameter Digits.
8.42. IADDRESS Function
IADDRESS( x )
Note
The VSI Pascal compiler automatically assumes that all pointers refer either to dynamic variables allocated by the NEW procedure or to variables that have the VOLATILE attribute. You, therefore, should use utmost caution when using the IADDRESS function. This function does not generate compile-time warnings about volatility.
VAR Real_Addr : INTEGER_ADDRESS; Real_Var : [VOLATILE] REAL; {In the executable section:} Real_Addr := IADDRESS( Real_Var ); {Returns address of Real_Var} WRITELN( 'The address of Real_Var is', Real_Addr );
For More Information:
On the VOLATILE attribute (Section 10.2.42, “VOLATILE”)
On the ADDRESS function (Section 8.4, “ADDRESS Function”)
On the NEW procedure (Section 8.58, “NEW Procedure”)
8.43. IADDRESS64 Function
IADDRESS64( x )
The parameter x can be of any type except a component of a packed structured type.
For More Information:
On the IADDRESS function (Section 8.42, “IADDRESS Function”)
8.44. IN_RANGE Function
IN_RANGE(expression,lower-expression,upper-expression)
The parameters must be expressions of the same ordinal type. The function returns TRUE if
x
has a value that is in the range specified by
lower-expression
and upper_expression
; otherwise, the
function returns FALSE.
8.45. INDEX Function
INDEX( string, substring )
INDEX requires two character-string expressions as parameters: a string to be searched and a substring to be found.
If the substring is found, INDEX returns the string component that contains the first letter of the substring.
If the substring is not found, INDEX returns the value 0.
If the substring is an empty string, INDEX returns the value 1.
If the string to be searched is an empty string, INDEX returns the value 0 unless the substring is also empty, in which case, INDEX returns the value 1.
If the substring is found, it does not return the string component but the index (such as subscript) of the component.
The_String := 'The Pilgrims landed at Plymouth Rock'; Substring := 'Plymouth Rock'; Position := INDEX( The_String, Substring ); {Returns 24} Substring := 'Mayflower'; Position := INDEX( The_String, Substring ); {Returns 0}
For More Information:
On character strings (Section 2.6, “String Types”)
8.46. INT Function
INT( x )
The parameter x must be of an ordinal type.
Overflow can occur and is detected at runtime if overflow checking is enabled and the value of x is outside the range of INTEGER.
8.47. INT64 Function
INT64(x)
The parameter x must be of an ordinal type.
Overflow can occur and is detected at run time if overflow checking is enabled and the value of x is outside the range of INTEGER64.
8.48. LE Function
LE( str1, str2 )
The parameters str1 and str2 must be character-string expressions. VSI Pascal does not pad shorter strings with blanks.
( LENGTH( Str1 ) < LENGTH( Str2 ) ) OR ( Str1 <= Str2 )
VAR Match : BOOLEAN; Test : STRING( 8 ) VALUE 'ENTRANCE'; {In the executable section:} Match := LE( 'exit', 'exit' ); {Returns TRUE} Match := LE( Test, 'EXIT' ); {'N' less-than 'X': Returns TRUE}
For More Information:
On string data types (Section 2.6, “String Types”)
8.49. LENGTH Function
LENGTH( str )
The str parameter must be a character-string expression.
For More Information:
On character strings (Section 2.6, “String Types”)
8.50. LN Function
LN( x )
The parameter x can be an integer or REAL type. The value of x must be greater than zero.
8.51. LOWER Function
LOWER( x [[, n]] )
The parameter x is a type identifier or variable of an ordinal, SET, or ARRAY type. The parameter n is an integer constant that denotes a dimension of x, if x is an array. If x is an array and if you omit the parameter n, VSI Pascal uses the default value 1. If x is an array, LOWER returns the lower bound of the nth dimension of x. If x is an ordinal type, LOWER returns the lower bound or smallest value. If x is a SET, LOWER returns the lower bound of the SET base type.
For More Information:
On the LOWER function (Section 8.100, “UPPER Function”)
8.52. LSHIFT Function
LSHIFT (expression,expression) )
The parameters are two integer or unsigned values. The first parameter represents a value to shift; the second represents the number of bits to shift the first value to the left. LSHIFT inserts zero bits on the right as the bits shift left.
Note that shifting integers is not equivalent to multiplying or dividing by a power of two when the value of the integer is negative.
If the number of bits shifted is larger than the natural integer size of the target platform, the result is undefined.
For More Information:
On the RSHIFT function (Section 8.77, “RSHIFT Function”)
8.53. LT Function
LT( str1, str2 )
VAR Match : BOOLEAN; Test : STRING( 8 ) VALUE 'ENTRANCE'; {In the executable section:} Match := LT( 'exit', 'exit' ); {Returns FALSE} Match := LT( Test, 'EXIT' ); {'N' less than 'X': Returns TRUE}
For More Information:
On string data types (Section 2.6, “String Types”)
8.54. MALLOC_C_STR Function
MALLOC_C_STR(e)
The type of the expression e must be a Pascal string expression. The function result is a
C_STR_T pointer to the null-terminted string. The amount of memory allocated with
malloc()
is equal to the length of the string expression plus one. The memory
allocated with MALLOC_C_STR must be deallocated with the C free()
routine. The
compiler will not allow C_STR_T parameters with the NEW and DISPOSE routines.
8.55. MAX Function
MAX( x1,...,xn )
The parameters can be any arithmetic type, but they must all be of the same type.
8.56. MIN Function
MIN( x1,...,xn )
The parameters can be any arithmetic type, but must all be of the same type.
8.57. NE Function
NE( str1, str2 )
VAR Match : BOOLEAN; {In the executable section:} Match := NE( 'exit ', 'exit' ); {Returns TRUE} Match := NE( 'exit', 'exit' ); {Returns FALSE}
For More Information:
On string data types (Section 2.6, “String Types”)
8.58. NEW Procedure
{t1,...,tn } NEW( p [[, {d1,...,dn } ]] )
The parameter p is a pointer variable. If the pointer type was declared with the [QUAD] attribute, the NEW procedure allocates memory from the 64-bit process address space (p2 space).
The parameters t1,...,tn are constant expressions of an ordinal type that represent nested tag-field values, where t1 is the outermost variant.
If the object of the pointer is a non schema record type with variants, then you have two ways of allocating memory. If you do not specify t parameters, VSI Pascal allocates enough memory to hold any of the variants of the record. If you do specify t parameters, then VSI Pascal allocates enough memory to hold only the variant or variants that you specify.
Since the t parameters cause VSI Pascal to allocate memory for the variant alone and not for the whole record, you cannot assign or evaluate the record as a whole; you can assign and evaluate only the individual fields. Also, a call to NEW sets the tag fields of a variant record.
The parameters d1,...,dn are compile-time or run-time ordinal values that must be the same type as the formal discriminants of the object.
If the object of the pointer is of an undiscriminated schema type, you must specify a d parameter for each of the formal discriminants of the schema type. The d parameters discriminate the schema type in much the same way as actual discriminants in a discriminated schema. The size of the allocation is based on the value of the d parameters.
Note
If you specify t parameters to the NEW procedure, you must specify the same t parameters to the DISPOSE procedure that deallocates memory for the corresponding variable.
TYPE Meat_Type = ( Fish, Fowl, Beef ); Beef_Portion = ( Oz_10, Oz_16, Oz_32 ); Var_Record = RECORD CASE Entree : Meat_Type OF Fish : ( Fish_Type : ( Salmon, Cod, Perch, Trout ); Lemon : BOOLEAN ); Fowl : ( Fowl_Type : ( Chicken, Duck, Goose ); Sauce : ( Orange, Cherry, Raisin )); Beef : ( Beef_Type : ( Steak, Roast, Prime_Rib ); CASE size : Beef_Portion OF Oz_10, Oz_16 : ( Beef_Veg : ( Pea, Mixed )); Oz_32 : ( Stomach_Cure : ( Bicarb, Antacid, None ))); END; The_Schema( Upper_Bound : INTEGER ) = ARRAY [1..Upper_Bound] OF INTEGER; VAR To_Int : ^INTEGER; To_Var_Record : ^Var_Record; To_Schema : ^The_Schema; Bound : INTEGER VALUE 32; {In the executable section:} NEW( To_Int ); {Memory for To_Int^ allocated but not initialized} NEW( To_Var_Record, Fish ); {Memory allocated only for Fish variant} DISPOSE( To_Var_Record, Fish ); {Specify Fish to DISPOSE} NEW( To_Var_Record, Beef, Oz_32 ); {Allocates more memory this time} DISPOSE(To_Var_Record, Beef, Oz_32 ); NEW( To_Schema, Bound ); {Allocation for undisc. schema object} DISPOSE( To_Schema );
For More Information:
On variant records (Section 2.4.2.1, “Records with Variants”)
On schema types (Section 2.5, “Schema Types”)
On the DISPOSE procedure (Section 8.28, “DISPOSE Procedure”)
8.59. NEXT Function
NEXT( x )
The parameter x can be a type identifier or variable.
Cells in an unpacked array are affected by alignment attributes and, by default, are byte aligned. Therefore, the size returned includes the actual size of the type or variable, in addition to trailing space required to ensure proper alignment.
If a variable that is not allocated to an integral number of bytes is passed to NEXT, the number of bits are rounded down to the nearest byte and then the number of bytes are returned.
For More Information:
On examples of return values for this function (Section 8.81, “SIZE Function”)
On arrays (Section 2.4.1, “ARRAY Types”)
8.60. OCT Function
OCT( x[[, length[[, digits]] ]] )
The parameter x is the expression to be converted. This parameter must have a size that is known at compile time; it cannot be VARYING OF CHAR, a conformant parameter, or a schema type.
The OCT function can also be used in compile-time expressions with ordinal-types.
Int_Var := 427; Result := OCT( Int_Var, 10, 3 ); {Returns ' 653'}
For More Information:
On character strings (Section 2.6, “String Types”)
8.61. ODD Function
The parameter x must be integer or unsigned. This function returns TRUE if the value of x is odd and FALSE if the value of x is even.
8.62. OR_ATOMIC Function
OR_ATOMIC( e, v )
The type of the expression e must be assignment compatible with that of the variable v. The variable v must be an INTEGER, UNSIGNED, INTEGER64, or UNSIGNED64 variable and must be allocated on a natural boundary (such as, longword for INTEGER and UNSIGNED and quadword for INTEGER64 and UNSIGNED64). The result of OR_ATOMIC is the same type as the variable v.
The OR_ATOMIC function does not provide memory synchronization between multiple processors. The BARRIER predeclared routine must be used for that purpose.
This function is used to access data that is shared between two or more threads of execution.
For More Information
On atomic operations (VSI Pascal User Manual)
8.63. ORD Function
ORD( x )
The parameter x must be of an ordinal type. Note that the ordinal value of an INTEGER object is the integer itself. If x is of type UNSIGNED, its value must not be greater than MAXINT.
8.64. PACK Procedure
PACK( a, i, z )
The parameter a is an unpacked array. The parameter i is a value to indicate the starting value of the index of a. The parameter z is a packed array of the same component type as a.
The number of components in parameter a must be greater than or equal to the number of components in z. This procedure assigns the components of a, starting with a[i], to the array z, starting with z[low-bound], until all the components in z are filled.
VAR a : ARRAY[1..25] OF 0..15; p : PACKED ARRAY[1..20] OF 0..15; i : INTEGER; {In the executable section:} FOR i := 1 TO 20 DO READ ( a[i] ); PACK( a, 5, p ); {a[1] through a[4] are not used} PACK( a, 1, p ); {a[21] through a[25] are not used}
For More Information:
On arrays and packed arrays (Section 2.4, “Structured Types”)
8.65. PAD Function
PAD( str, fill, size )
The parameter str is a character-string value to be padded; the parameter fill is a value of type CHAR to be used as the fill character; and the parameter size is an integer value indicating the size of the final string.
This string is composed of the original string followed by the fill character, which is repeated as many times as is necessary to extend the string to its specified size. The final size must be greater than or equal to the length of the string to be padded.
For More Information:
On character strings (Section 2.6, “String Types”)
8.66. PAS_STR Function
PAS_STR(e)
The type of the expression e must be C_STR_T. It is an error if the expression is NIL.
8.67. PAS_STRCPY Function
PAS_STRCPY(v, e)
The type of the variable v must be C_STR_T. The type of the expression e must be a Pascal string expression. The Pascal string is copied into the memory pointed to by the variable v. The memory is then terminated with a null character. The function returns a C_STR_T value representing the destination (such as, the same value as contained by the variable v).
The behavior of PAS_STRCPY is undefined if the length of the Pascal string expression is greater than or equal to the amount of memory pointed to by the variable v. It is an error if the variable v is NIL.
8.68. PRED Function
PRED( x )
The parameter x can be of any ordinal type; however, there must be a predecessor value for x in the type.
8.69. PRESENT Function
PRESENT( parameter-name )
The parameter-name parameter is the name of a formal parameter with the TRUNCATE attribute. The parameter-name must be the name of a formal parameter of the function from which PRESENT is called, or from a subroutine of that function. The function result indicates whether the argument list of the containing routine specifies an actual argument corresponding to an optional parameter.
Parameters that do not have the TRUNCATE attribute, and also do not follow a parameter with the TRUNCATE attribute in the formal parameter list, are allowed; in their case, the PRESENT function always returns TRUE.
Default parameters are considered to be present in the argument list, and the PRESENT function returns TRUE when passed the name of a parameter with a default value.
For More Information:
On examples using PRESENT and TRUNCATE (Section 10.2.37, “TRUNCATE”)
On parameters (Section 6.3, “Parameters”)
8.70. QUAD Function
The parameter x must be an arithmetic type.
For More Information:
On precision and support for the QUADRUPLE data type (Chapter 2, Data Types and Values)
8.71. RANDOM Function
RANDOM[[ ( expression )]]
If present, the optional expression parameter is ignored.
For More Information:
On the SEED function (Section 8.78, “SEED Function”)
8.72. READV Procedure
READV( str, {variable-identifier[[ : radix-specifier ]]},... [[, ERROR := error-recovery ]] )
str
The str parameter is the string to be read.
variable_identifier
The variable-identifier is the name of the variable to be assigned a value from str.
radix-specifier
The radix-specifier parameter is one of the format values BIN, OCT, or HEX. These values, when used on a variable-identifier, read the variable in binary, octal, or hexadecimal, respectively. You can read a variable of any type by using a radix-specifier except a type that contains a file component.
error-recovery
The error-recovery parameter is the action to be taken if an error occurs during execution of the routine.
TYPE Color = ( Yellow, Red, Blue ); VAR Paint, Paint2 : Color; Month : VARYING[5] OF CHAR; Real_Var : REAL; Read_String : VARYING[17] OF CHAR; {In the executable section:} Read_String := 'Red July 26.33805'; READV( Read_String, Paint, Month, Real_Var ); {Paint contains Red, Month contains 'July', and Real_Var contains 26.33805} READV( Read_String, Paint, Month, Real_Var, Paint2 ); {Error: end of string reached after assigning to Real_Var} READV( Read_String, Paint, Month ); {Legal: '26.33805' is not used} READV( Read_String, Real_Var, Paint, Month ); {Error: Red is not REAL}
For More Information:
On input and output (Chapter 9, Input and Output Processing)
On character strings (Section 2.6, “String Types”)
On error recovery codes (VSI Pascal User Manual)
8.73. RENAME_FILE Procedure
RENAME_FILE( old-file-name, new-file-name [[, error-return]] )
The parameter old-file-name specifies the names of one or more files whose specifications are to be changed. The new-file-name parameter provides the new file specification to be applied. The error-return parameter contains an error recovery code if specified.
For More Information:
On error processing (VSI Pascal User Manual)
8.74. REVERT Procedure
The REVERT procedure cancels a condition handler activated by the ESTABLISH procedure. This procedure does not have a parameter list.
For More Information:
On error processing (VSI Pascal User Manual)
8.75. ROUND Function
ROUND( x )
The parameter x must be of type REAL, SINGLE, DOUBLE, or QUADRUPLE. The value of x must not be too large to be represented by an integer.
8.76. ROUND64 Function
ROUND64( x )
The parameter x must be of type REAL, SINGLE, DOUBLE, or QUADRUPLE. The value of x must not be too large to be represented by an INTEGER64.
8.77. RSHIFT Function
RSHIFT(expression, expression)
The expression parameters are two integer or unsigned values. The first parameter represents a value to shift; the second represents the number of bits to shift the first value. The RSHIFT function inserts zero bits on the left as the bits shift right.
Note that shifting integers is not equivalent to multiplying or dividing by a power of two when the value of the integer is negative.
If the number of bits shifted is larger than the natural integer size of the target platform, the result is undefined.
For More Information:
On the LSHIFT function (Section 8.52, “LSHIFT Function”)
8.78. SEED Function
SEED(expression)
The expression parameter is an integer.
For More Information:
On the RANDOM function (Section 8.71, “RANDOM Function”)
8.79. SET_INTERLOCKED Function
SET_INTERLOCKED( b )
The parameter b must be a variable of type BOOLEAN. The variable does not have to be aligned; therefore, it can be a field of a packed record.
8.80. SIN Function
SIN( x )
The parameter x can be an integer or REAL type, and is expressed in radians.
8.81. SIZE Function
SIZE( x[[,t1,...,tn]] )
The parameter x can be a type identifier or variable. If x is a type identifier, then the functions return an integer value that indicates the number of bytes that would be allocated for a variable or record field of type x. If x is a variable, then the functions return an integer value that indicates the number of bytes that are allocated for that variable.
In the case where the parameter x is a variant record variable or variant type identifier, SIZE returns an integer value that indicates the number of bytes that are allocated (for a variant record variable) or would be allocated (for a variant type identifier) for both the fixed portion of the record and the largest variant. In addition, you can supply additional parameters t1 through tn that correspond to the case labels of the record. The function returns an integer value that indicates the number of bytes that would be allocated by the NEW procedure for a dynamic variable of the specified variant.
If a variable that is not allocated to an integral number of bytes is passed to SIZE, the number of bits will be rounded up to the nearest byte and then the number of bytes will be returned.
Type or Variable |
Size in Bits |
Size in Bytes | ||
---|---|---|---|---|
BITNEXT |
BITSIZE |
NEXT |
SIZE | |
[BIT ( 1 )] BOOLEAN |
1? |
1 |
1? |
1? |
0..25 (subrange ) |
5? |
5 |
4? |
4? |
[BYTE] 0..255 (byte ) |
8 |
8 |
1 |
1 |
[BYTE, ALIGNED ( 2 )] 0..225 |
32? |
8 |
4? |
1 |
First element of: PACKED ARRAY [1..10] OF 0..25 |
5 |
5 |
0 ? |
1 ? |
PACKED ARRAY [1..10] OF 0..25 |
56? |
56? |
7 |
7 |
For More Information:
On storage allocation and alignment for data types (Appendix A, Data Storage and Representation)
8.82. SNGL Function
SNGL( x )
The parameter x must be an arithmetic type. The value of x must not be too large to be represented by a single-precision number.
8.83. SQR Function
SQR( x )
The parameter x can be any arithmetic type.
8.84. SQRT Function
SQRT( x )
The parameter x can be an INTEGER, UNSIGNED, or REAL type. If the value of x is less than zero, an error occurs.
8.85. STATUSV Function
The STATUSV function returns an integer value that specifies the status of the last READV or WRITEV procedure completed. STATUSV does not have any parameters.
VAR Vary_Src : VARYING [20] OF CHAR; Int_Result : INTEGER; {In the executable section:} Vary_Src := '255'; READV( Vary_Src, Int_Result, ERROR := CONTINUE ); IF STATUSV <> 0 THEN {0 means READV executed successfully} WRITELN( 'Error in READV' );
If, however, you have an asynchronous system trap (AST) routine condition handler in your program that uses READV and WRITEV, the call of STATUSV in your main program may not return the results you expected if an AST occurred between the READV/WRITEV procedure and the STATUSV procedure.
For More Information:
On the READV procedure (Section 8.72, “READV Procedure”)
On the WRITEV procedure (Section 8.107, “WRITEV Procedure”)
On character strings (Section 2.6, “String Types”)
8.86. SUBSTR Function
SUBSTR ( str, start, length ) SUBSTR ( str, start )
SUBSTR (str, start, length(str)-start+1)
The value of the starting position must be greater than 0.
The value of the length must be greater than or equal to 0.
There must be enough characters following the starting position to construct a substring of the specified length.
Original_String := 'This is the original string'; Start_Position := 13; Substring_Length := 15; New_String := SUBSTR( Original_String, Start_Position, Substring_Length ); {New_String contains 'original string'}
For More Information:
On character strings (Section 2.6, “String Types”)
8.87. SUCC Function
SUCC( x )
The parameter x can be of any ordinal type; however, there must be a successor value for x in the type.
8.88. SYSCLOCK Function
SYSCLOCK
For More Information:
On the WALLCLOCK function (Section 8.106, “WALLCLOCK Function”)
On the CLOCK function (Section 8.20, “CLOCK Function”)
8.89. TIME Procedure
8.90. TRUNC Function
TRUNC( x )
The parameter x must be of type REAL, SINGLE, DOUBLE, or QUADRUPLE. The value of x must not be too large to be represented by an integer.
8.91. TRUNC64 Function
TRUNC64( x )
The parameter x must be of type REAL, SINGLE, DOUBLE, or QUADRUPLE. The value of x must not be too large to be represented by an INTEGER64.
8.92. UAND Function
UAND( u1, u2 )
Result := UAND( 16#FF9, 16#703 ); {Returns 1793, which is 16#701}
For More Information:
On specifying extended-digit notation (Section 2.1.1.1, “INTEGER and INTEGER64 Types”)
8.93. UDEC Function
UDEC( x[[, length[[, digits]] ]] )
The parameter x is the expression to be converted. The UDEC function can take a parameter of any type except VARYING of CHAR, conformant parameters, or schema types. This function requires the size of the parameter x to be less than or equal to the size of INTEGER64.
The UDEC function can also be used in compile-time expressions.
Two optional integer parameters specify the length of the resulting string and the minimum number of significant digits to be returned. If you specify a length that is too short to hold the converted value, the resulting string is truncated on the left.
If you do not specify values for the optional parameters, a default length and a default minimum number of significant digits is used. If the size of the parameter x is greater than 32, the defaults are 21 characters for the length and 20 characters for the minimum number of digits. Otherwise, the defaults are 11 characters for the length and 10 characters for the minimum number of digits.
VAR Account : INTEGER; {In the executable section:} Account := 3; WRITELN( UDEC( Account ) );
For More Information:
On conformant parameters (Section 6.3.7, “Conformant Parameters”)
On VARYING OF CHAR (Section 2.6.2, “VARYING OF CHAR Types”)
8.94. UINT Function
UINT(x)
The parameter x must be of an ordinal type.
No error results if x is an integer and has a negative value. The value returned is x MOD 2 **32.
For More Information:
On range and support for the UNSIGNED data type (Chapter 2, Data Types and Values)
8.95. UINT64 Function
UINT64(x)
The parameter x must be of an ordinal type.
No error results if x is an integer and has a negative value. The value returned is x MOD 2 **64.
For More Information:
On the UNSIGNED64 data type (Chapter 2, Data Types and Values)
8.96. UNDEFINED Function
UNDEFINED( x )
The parameter x must be a variable of type REAL, SINGLE, DOUBLE, or QUADRUPLE.
The UNDEFINED routine returns FALSE if the floating-point value is finite and returns TRUE if the value is not finite.
A finite number is a floating-point value with a definite, in-range value. Specifically, all numbers in the inclusive ranges -MAX through -MIN, zero, and +MIN through +MAX, where MAX is the largest non-infinite representable floating-point number for the variable's type and MIN is the smallest non-zero representable normalized floating-point number for the variable's type. These correspond to the MINREAL, MAXREAL, MINDOUBLE, MAXDOUBLE, MINQUADRUPLE, and MAXQUADRULE predeclared constants.
For F_Float, D_Float, and G_Float, finites do not include reserved operands and dirty zeros (this differs from the VAX interpretation of dirty zeros as finite). For S_Float, T_Float, and X_Float, finites do not include infinites, NaNs, or denormals, but do include minus zero.
8.97. UNOT Function
UNOT( u )
Result := UNOT( 16#FF9 ); {Returns 16#FFFFF006}
For More Information:
On specifying extended-digit notation (Section 2.1.1.1, “INTEGER and INTEGER64 Types”)
8.98. UNPACK Procedure
UNPACK( z, a, i )
The parameter z is a packed array. The parameter a is an unpacked array variable. The parameter i is the starting value of the index of a.
The number of components in parameter a must be greater than or equal to the number of components in z. The UNPACK procedure assigns the components of z, starting with z[low-bound], to the array a, starting with a[i], until all the components in z are used.
In general, when specifying i, keep in mind that the upper bound of a (that is, n) must be greater than or equal to i + v − u, where v is the upper bound of z and u is the lower bound of z. That is, ORD (n) must be greater than or equal to ORD (i) + ORD (v) − ORD (u).
VAR p : PACKED ARRAY[1..10] OF CHAR; a : ARRAY[1..10] OF CHAR; i : INTEGER; PROCEDURE Process_Components( VAR Ch : CHAR ); {Body...} {In the executable section:} READ( p ); UNPACK( p, a, 1); FOR i := 1 TO 10 DO Process_Components( a[i] ); {Pass each component to procedure}
For More Information:
On arrays and packed arrays (Section 2.4.1, “ARRAY Types”)
8.99. UOR Function
UOR( u1, u2 )
Result := UOR( 16#FF9, 16#703 ); {Returns 16#FFB}
For More Information:
On specifying extended-digit notation (Section 2.1.1.1, “INTEGER and INTEGER64 Types”)
8.100. UPPER Function
UPPER( x [[, n]] )
TYPE A_Schema( a, b : INTEGER) = a..a+b; VAR x : A_Schema( 5, 10 ); {In the executable section:} WRITELN( UPPER( BOOLEAN ) ); {Writes TRUE} WRITELN( LOWER( x ) ); {Writes 5} WRITELN( UPPER( x ) ); {Writes 15}
8.101. UROUND Function
UROUND( x )
The parameter x must be of type REAL, SINGLE, DOUBLE, or QUADRUPLE.
No error results if the value of x is negative or greater than 4,294,967,295. In that case, the unsigned result is the rounded parameter value MOD 4,294,967,296.
For More Information:
On range and support of the UNSIGNED data type (Chapter 2, Data Types and Values)
8.102. UROUND64 Function
UROUND64( x )
The parameter x must be of type REAL, SINGLE, DOUBLE, or QUADRUPLE.
No error results if the value of x is negative or greater than MAXUNSIGNED64. In that case, the UNSIGNED64 result is the rounded parameter value MOD MAXUNSIGNED64.
For More Information:
On range and support of the UNSIGNED64 data type (Chapter 2, Data Types and Values)
8.103. UTRUNC Function
UTRUNC( x )
The parameter x must be of type REAL, SINGLE, DOUBLE, or QUADRUPLE.
No error results if the value of x is negative or greater than 4,294,967,295. In that case, the unsigned result is the truncated parameter value MOD 4,294,967,296.
For More Information:
On range and support of the UNSIGNED data type (Chapter 2, Data Types and Values)
8.104. UTRUNC64 Function
UTRUNC64( x )
The parameter x must be of type REAL, SINGLE, DOUBLE, or QUADRUPLE.
No error results if the value of x is negative or greater than MAXUNSIGNED64. In that case, the unsigned result is the truncated parameter value MOD MAXUNSIGNED64.
For More Information:
On range and support of the UNSIGNED64 data type (Chapter 2, Data Types and Values)
8.105. UXOR Function
UXOR( u1, u2 )
Result := UXOR( 16#FF9, 16#703 ); {Returns 16#8FA}
For More Information:
On specifying extended-digit notation (Section 2.1.1.1, “INTEGER and INTEGER64 Types”)
8.106. WALLCLOCK Function
WALLCLOCK
For More Information:
On the SYSCLOCK function ( Section 8.88, “SYSCLOCK Function”)
On the CLOCK function ( Section 8.20, “CLOCK Function”)
8.107. WRITEV Procedure
WRITEV( str, parameter-list [[, ERROR := error-recovery]] )
The str parameter is the string to be written to.
The parameter-list parameter is the variables to be assigned to str.
The error-recovery parameter is the action to be taken if an error occurs during execution of the routine.
TYPE Flower = ( Daisy, Lily, Orchid, Tulip ); VAR Real_Var : REAL VALUE 232.705; Write_String : VARYING[21] OF CHAR; Bouquet : Flower VALUE Orchid; {In the executable section:} WRITEV( Write_String, Daisy, Real_Var:7:3, PRED( Bouquet ) ); {Write_String contains ' DAISY232.705 LILY'} WRITEV( Write_String, Daisy, Real_Var:7:3, PRED( Bouquet ), Bouquet ); {Error: there is no more room in the string parameter}
For More Information:
On VARYING OF CHAR strings (Section 2.6.2, “VARYING OF CHAR Types”)
On formatting output (Section 9.6, “Formatting Output”)
On error recovery codes (VSI Pascal User Manual)
8.108. XOR Function
XOR( p1, p2 )
Result := XOR( ['A','B','C'],['B','C','D'] ); {Returns ['A','D']}
For More Information:
On Boolean types (Section 2.1.3, “BOOLEAN Type”)
On SET types (Section 2.4.3, “SET Type”)
8.109. ZERO Function
ZERO
If you attempt to use the ZERO function to initialize a file variable, an error occurs. Do not specify a parameter list when you call the ZERO function.
Data Type |
Value |
---|---|
All INTEGER types |
0 |
All UNSIGNED types |
0 |
CHAR |
The character NUL |
BOOLEAN |
FALSE |
Enumerated |
The enumerated element with ORD(element) = 0 |
Subrange |
0? |
REAL |
0.0 |
DOUBLE |
0.0 |
QUADRUPLE |
0.0 |
ARRAY |
ZERO applied to each component |
RECORD |
ZERO applied to each field |
VARYING OF CHAR, STRING |
The null string |
SET |
The empty set |
Pointer |
NIL |
The ZERO function is used in two ways. You can use it as a compile-time expression to initialize a variable in the TYPE, VAR, CONST, or VALUE sections. You can also use it on the right side of an assignment statement that appears in the executable section where the target is either a variable, or, within the body of a function, the function identifier.
TYPE Pre_Zeroed_Record = RECORD A: INTEGER; B: Array [1..3] of Real END VALUE ZERO; VAR An_Array : Array [1..10] of Real; Pre_Zeroed : Pre_Zeroed_Record; BEGIN An_Array :=ZERO; {Initializes all of An_Array to zeroes} . . .
For More Information:
On data initialization (Chapter 2, Data Types and Values)
Using the ZERO function with records (Section 2.4.2.2, “Record Constructors”)
Chapter 9. Input and Output Processing
The VSI Pascal I/O model provides an extensive set of predeclared routines. When programming with I/O, remember that the routines and their effects depend on the capabilities available in your environment; not all routines or organizations are available across environments.
For More Information:
On environment-specific I/O details (VSI Pascal User Manual and Appendix C, Description of Implementation Features).
9.1. Files and File Organizations
A file is an organized collection of logically related data items. Data items within files are called file components. The file organization defines the physical arrangement of the components within the physical file, what types of access information are present in each component, and how components may be accessed by a program.
The VSI Pascal I/O model includes three file organizations: sequential, relative, and indexed.
To open a file, you can call the OPEN procedure. Also, you usually call one of the EXTEND, RESET, and REWRITE procedures to establish a starting position for reading from or writing to a file. (For relative and indexed file organizations, you can use procedures to locate a specific component to access.)
VSI Pascal makes distinctions between permanent external files and temporary internal files. An external file has a name in a directory and exists outside the context of an VSI Pascal program. An internal file has no name and is deleted after the program finishes execution.
A file declared in the program heading is external by default. A file declared in a nested block is internal by default. To change the default for internal files, call the OPEN procedure or specify a file name in the EXTEND, RESET, or REWRITE procedures.
The file is then considered external and is retained with the specified name after the program has finished execution. If you open an internal file with the EXTEND, RESET, or REWRITE procedure without a file name, the file remains an internal file.
Default Information:
If you do not specify a file organization at the time of file creation (using the OPEN procedure), VSI Pascal creates a file with sequential organization.
The following sections describe file organizations.
9.1.1. Sequential File Organization
Sequential file organization specifies that file components are stored one after the other, in the order in which they were entered into the file. VSI Pascal supports this organization for files on disk. This is the only organization supported for files on magnetic tape, on terminals, on card readers, and on line printers. Figure 9.1, “Sequential File Organization” shows this file organization.

You cannot insert components between any two existing components, because no physical space separates them. You can only add records to the end of the file (the most recently added component), truncate the file from a specified component to the end of the file, or rewrite the file.
For More Information:
On component formats in sequential files (Section 9.2, “Component Formats”)
On access methods for sequential files (Section 9.3, “Component Access Modes”)
9.1.2. Relative File Organization
Relative file organization consists of a series of fixed-length component positions (called cells) numbered consecutively from 1 to n. The numbered, fixed-length cells enable VSI Pascal to calculate the component's physical position in the file. The cell numbers are called relative component numbers. VSI Pascal supports this organization on disk files only. Figure 9.2, “Relative File Organization” shows this file organization.

Each component in the file may be randomly assigned to a specific cell. You can place components in unused cells and in cells from which components have been deleted. You cannot replace a component in a cell, but you can modify an existing component.
The length of the actual component may vary even though the cell containing the component is of a fixed length. If the component is smaller than the cell, the remaining space in the cell is unused.
For More Information:
On component formats in relative files (Section 9.2, “Component Formats”)
On access methods for relative files (Section 9.3, “Component Access Modes”)
9.1.3. Indexed File Organization
Indexed file organization specifies that, in addition to the stored components, there exists at least a primary key and possibly alternate keys (first alternate key, second alternate key, and so forth). VSI Pascal uses the primary key to store components and uses a program-specified key or keys to retrieve data. VSI Pascal supports this organization on disk files only.
To define a key and certain characteristics of keys, use the KEY attribute. You can define up to 254 alternate keys.
An index is a structure that provides a component collating sequence for the file, that is, a mechanism for accessing components in different orders depending on the specified index (name, address, telephone number, and so forth).
Figure 9.3, “Indexed File Organization” shows an indexed file organization that uses only a primary key.

In Figure 9.3, “Indexed File Organization” the components are logically stored in an order that is determined by the primary index. (The actual physical location of components is transparent to your program.) Figure 9.4, “A First Alternate Key” shows the presence of a first alternate index (determined by the presence of first alternate keys in the components) that points to components stored in order by the primary key.

For More Information:
On component formats in indexed files (Section 9.2, “Component Formats”)
On access methods for indexed files (Section 9.3, “Component Access Modes”)
On the KEY attribute (Section 10.2.23, “KEY ”)
In an indexed file, each component includes one or more key fields (or simply keys) that VSI Pascal uses to build the specified indexes. Each key is identified by its location within the component, its length, and its data type.
A single, contiguous character string
A 2- or 4-byte unsigned binary number
A 1-, 2-, or 4-byte signed integer
Keys | Description |
---|---|
Sort order |
This characteristic determines how VSI Pascal creates an index, and determines the order in which VSI Pascal accesses components. The order can either be ascending or descending. If you specify ascending order, VSI Pascal considers the component with an equal or greater key value to be the next component for access. If you specify descending order, VSI Pascal considers the component with an equal or lesser key value to be the next component for access. Using different indexes and both ascending or descending order, you can use different collating sequences for a file's components according to the needs of your application. |
Duplicate keys |
This characteristic permits you to use the key value in more than one component. However, only the first component having the key value can be accessed randomly; other components having the same key value can only be accessed sequentially. |
Changeable keys |
This characteristic applies to alternate keys only. When you specify changeable keys, you can change the alternate keys in a component when you update the component. When an alternate key value changes, VSI Pascal automatically adjusts the appropriate index to reflect the new key value. |
If you do not allow duplicate keys, VSI Pascal rejects any attempt to place a component into a file if it contains a key value that is a duplicate of an existing component. If you do not explicitly create the file to accept alternate key values, then attempts to change key values generate an error.
For More Information:
On the KEY attribute (Section 10.2.23, “KEY ”)
On additional key characteristics (VSI Pascal User Manual)
9.2. Component Formats
When you declare a file variable in your program, VSI Pascal automatically creates a file buffer variable of the component type. This variable takes on the value of one file component at a time. You can access only one file component, called the current component, at a given time.
You cannot perform operations on a file while a reference to the file buffer variable exists. To dereference the file buffer variable, write the name of the file buffer variable followed by a circumflex (^), the dereferencing character.
Predeclared I/O procedures move the file position. As the file position changes, the variable in the file buffer changes. Figure 9.5, “File Buffer Contents” shows how this change occurs.

Suppose you declare a file variable Math_Scores of type FILE OF INTEGER. You might call a procedure to move the file position to the first component of this file. At this point, the file buffer variable Math_Scores^ equals the value of the first component (here, 90). If you then called a procedure to advance the file position by two components, Math_Scores^ would equal the value of the third component (here, 70).
VAR f : FILE OF INTEGER; {In the executable section:} OPEN( File_Variable := f, File_Name := 'sample.dat', History := OLD, Organization := Sequential, Access_Method := Direct; ); EXTEND( f ); F^ := 20; PUT( f );
The OPEN procedure opens the existing file, sample.dat. The EXTEND procedure positions the file after its last component. The assignment statement places the value 20 into the file buffer variable (F^). The PUT procedure writes the value of the file buffer variable at the end of the file, f.
TYPE DataRecord = RECORD {A DataRecord is a component of this} Field1: INTEGER; {file; each component contains an } Field2: REAL; {integer and a real value. } END {RECORD}; VAR DataFile = FILE OF DataRecord; {VAR gains access to the file}
RESET(DataFile); {Read component into the file buffer} MyInt := DataFile^.Field1; {Copy the integer field into MyInt} MyReal := DataFile^.Field2; {Copy the real field into MyReal}
The assignments use the FILE variable to refer to components of the file buffer.
Fixed-length format (Section 9.2.1, “Fixed-Length Component Format”)
Variable-length format (Section 9.2.2, “Variable-Length Component Format”)
Stream format (Section 9.2.3, “Stream Component Format”)
Default Information:
For new TEXT and VARYING OF CHAR files, VSI Pascal creates variable-length components by default. For other types of new files, VSI Pascal creates fixed-length components. If you access an existing file, your specified component type must match the component type specified at the creation of the file; if it does not, you generate an error.
Organization |
Supported Component Format |
---|---|
Sequential |
All component formats |
Relative? |
Fixed length |
Variable length | |
Indexed |
Fixed length |
Variable length |
For More Information:
On TEXT files (Section 9.5, “TEXT Files”)
9.2.1. Fixed-Length Component Format
Fixed-length components are all the same length. The fixed-length component format is supported in all file organizations. VSI Pascal determines the length of a component at the time of file creation. You cannot change the length of the components after you create the file.
9.2.2. Variable-Length Component Format
The variable-length component format enables components to be only as long as the data requires. The variable-length format is supported in all file organizations.
When you use OPEN to create a file of variable-length components, you can specify the value (in bytes) of the largest component permitted in the file. Any attempt to store a component containing more bytes than the specified value results in an error.
9.2.3. Stream Component Format
The stream component format is a continuous stream of bytes that contains special delimiting characters (called terminators) that separate components. In addition to being recognized as delimiters, VSI Pascal considers the terminators to be a valid part of the component data. The stream format is supported only in sequential files on disk.
Type |
Description |
---|---|
STREAM_CR |
This type recognizes a carriage-return character as the component terminator. |
STREAM_LF |
This type recognizes a line feed as the component terminator. |
STREAM |
This type uses a terminator from a limited set of special characters: the carriage return (CR ); the carriage-return/line-feed combination (CR/LF ); or the form feed (FF ). |
9.3. Component Access Modes
A component access mode is a method by which VSI Pascal retrieves components from a file. You cannot change the file organization or component format after file creation, but you can change the component access mode each time you access a file. The VSI Pascal I/O model defines two component access modes: sequential and random access. Random access can be further broken down into the categories of random access by number (also called direct access) and random access by key value (also called keyed access). The following sections describe these access methods in further detail.
You specify the access method using the OPEN procedure when you open a file. You cannot change the access method unless you first use the CLOSE routine, and then reopen the file specifying a new access method.
Before trying to use any of the access methods on a file, VSI Pascal determines the organization of the file. The organization determines how the specified access method works. For instance, sequential access on a sequentially organized file works differently than sequential access on an indexed file.
Default Information:
The default is the sequential access method.
You can always process a file using sequential access, even when the currently specified access method is one of the direct access methods.
By default, VSI Pascal does not designate a component as a starting point for access; you must do this explicitly using one of the RESET, REWRITE, or REWIND procedures, or using an access-specific procedure to locate a specified component.
Access Mode |
Sequential Organization |
Relative Organization |
Indexed Organization |
---|---|---|---|
Sequential |
Yes |
Yes |
Yes |
Random by relative component number (direct access) |
Yes? |
Yes |
No |
Random by key value (keyed access) |
No |
No |
Yes |
For More Information:
On file organizations (Section 9.1, “Files and File Organizations”)
On component formats (Section 9.2, “Component Formats”)
9.3.1. Sequential Access
Using the sequential access method, storage or retrieval begins at a designated position in the file and continues through the file according to the component's position in storage. You can specify two starting points for sequential access: the beginning of the file (using REWRITE, or RESET) or the end of the file (using EXTEND).
For More Information:
On file organization (Section 9.1, “Files and File Organizations”)
On component format (Section 9.2, “Component Formats”)
9.3.1.1. Sequential Access to Sequential Files
To retrieve a component in a sequential file, you must retrieve all components from the time you establish a current position (using either EXTEND, RESET, or REWRITE) to the desired component. After an operation to the file, VSI Pascal positions the file pointer to the next file component in anticipation of the next operation on the file.
To access a previous component, you must reopen (implicitly or explicitly) and reread the previous components; or, you can reopen the file, switching to random access mode.
You cannot add components in between any two components. You can add components only to the current end of the file.
Figure 9.6, “Sequential Access to a Sequential File” shows sequential access to sequential files.

9.3.1.2. Sequential Access to Relative Files
VSI Pascal can use sequential access for relative files as long as the components are fixed length. VSI Pascal tries to store or retrieve from the cell whose relative component number is one higher than the most recently accessed cell.
You cannot overwrite a component, but you can modify the contents of the current component. If the cell with the next highest relative component number contains a component and if you are trying to store data in that cell, you generate an error.
Figure 9.7, “Using Sequential Access to Read from a Relative File” shows the use of sequential access to read from a relative file.

Figure 9.8, “Using Sequential Access to Write to a Relative File” shows the use of sequential access to write to a relative file. In this figure, VSI Pascal writes the component to the current cell. If the program requests that another component be stored sequentially, then VSI Pascal places that component in cell 3. If the program places another request to store a component sequentially, an error occurs because cell 4 contains component B.

9.3.1.3. Sequential Access to Indexed Files
When sequentially accessing an indexed file, VSI Pascal uses a specified index to determine the order in which to sequentially process the file components. The specified keys are called the keys of reference.
If you specify ACCESS_METHOD := SEQUENTIAL when you open an indexed file, you can only access components sequentially according to the primary key. If you specify ACCESS := KEYED when you open an indexed file, you can access components sequentially according to any key.
When sequentially writing components to an indexed file, VSI Pascal stores the component according to the primary key. If your program uses secondary keys, VSI Pascal updates the secondary key pointers to include the newly stored component.
9.3.2. Random Access
Random access allows you to access file components in an order that is not dependent on the file organization or on the order in which the components are stored. Random access is available for all relative and indexed files, and for sequential files composed of fixed-length components (the fixed-length components allow VSI Pascal to count component positions in the sequential file without having to worry about variations in the lengths of the components).
Random access by relative component number (direct access)
Random access by key value (keyed access)
Random access by relative component number: | |||
---|---|---|---|
DELETE |
EOF |
FIND |
LOCATE |
UFB |
UNLOCK |
UPDATE | |
Random access by key: | |||
EOF |
FINDK |
RESETK |
UFB |
UNLOCK |
UPDATE |
For More Information:
On file organization (Section 9.1, “Files and File Organizations”)
On component format (Section 9.2, “Component Formats”)
9.3.2.1. Random Access by Relative Component Numbers (Direct Access )
VSI Pascal supports random access by relative component numbers for relative files and for sequential files with fixed-length components on disk. To access the desired component, you need to specify the relative component number of the corresponding cell; relative component numbers are relative to the beginning of the file.
Figure 9.9, “Using Random Access on Sequential and Relative Files” shows the process of randomly accessing cells in a file. For random access of sequential files, the cells must be of a fixed length.

9.3.2.2. Random Access to Indexed Files (Keyed Access)
VSI Pascal supports random access to indexed files. To retrieve a component, you must specify an index (primary index, first alternate index, second alternate index, and so forth) and a key value. To store a component, VSI Pascal determines existing keys from the file organization and stores the record (and alternate key information) according to information as it exists in the data portion of the component.
Exact match of key values.
Approximate match of key values. When accessing an index in ascending sort order, VSI Pascal returns the component that has the next higher key value (in descending order, the component with next lower key value).
Generic match of key values. Generic matching is applicable to string data-type keys only (PACKED ARRAY OF CHAR record fields). For a generic match, the program need specify only a match of some specified number of leading characters in the key.
Combination of approximate and generic match.
9.4. File Locking
Under some circumstances, if a file component is in the process of being read or written to by one program, VSI Pascal locks the component, preventing other programs from accessing the component. This prevents programs from accessing outdated or inaccurate data.
If you OPEN a file and specify that the file is not to be shared, or that reading or writing sharing is allowed, VSI Pascal may not lock the record.
Record locking occurs most often when accessing relative and indexed files, but it can happen when accessing sequential files as well. Successful calls to FIND, FINDK, GET, RESET, and RESETK lock the current component. If you want to make a locked file component available to other programs on the system, you can call the UNLOCK procedure.
For More Information:
On enabling other programs to access new files created with OPEN (Section 9.8.11, “OPEN Procedure”)
On unlocking components (Section 9.8.22, “UNLOCK Procedure ”)
9.5. TEXT Files
Files of type TEXT are sequences of characters with special markers (end-of-line and end-of-file) added to the file. Although each character of a TEXT file is one file component, the end-of-line marker allows you to process the file line by line (using READLN, WRITELN, or EOLN), if you choose.
The predeclared file variables INPUT and OUTPUT are files of type TEXT. They refer to the standard input and output files. (When executing programs at a terminal, INPUT and OUTPUT default to the terminal you are using.)
The file type FILE OF CHAR differs from TEXT files in that FILE OF CHAR allows a single character to be the unit of transfer between a program and its associated I/O devices, and that FILE OF CHAR files do not include special markers. FILE OF CHAR components are always read with the READ procedure, and must be read exclusively into variables of type CHAR, including CHAR components of structured variables. You cannot use the EOLN, READLN, and WRITELN routines on FILE OF CHAR files.
Default Information:
A new file of type TEXT or FILE OF VARYING OF CHAR is a sequential file with variable-length components.
All TEXT file routines use the predefined files INPUT and OUTPUT by default.
VSI Pascal performs an implicit call to RESET on the predeclared file INPUT and an implicit call to REWRITE on the predeclared file OUTPUT.
The default size for the output buffer is 255 characters for TEXT files.
The following are the VSI Pascal I/O routines that are used only with TEXT files: EOLN, LINELIMIT, PAGE, READLN, and WRITELN.
9.5.1. Carriage Control
OPEN Parameter Option |
Description |
---|---|
LIST |
Single spacing between components. This is the default carriage-control option for all TEXT files (including OUTPUT) and VARYING OF CHAR files. |
CARRIAGE, FORTRAN |
The first character of every output line is a carriage-control character. |
NONE, NOCARRIAGE |
No carriage control. This is the default for all files other than TEXT and VARYING OF CHAR files. |
For FORTRAN carriage control, if output is directed to devices that do not use carriage-control characters, the character is written into the file as a component and is read back when the file is opened for input. If output is directed to devices that do use carriage control, then the OPEN parameter options described previously determine the action taken by VSI Pascal.
Character | Meaning |
---|---|
’+ ’ |
Overprinting: starts output at the beginning of the current line. |
’ ’ |
Single spacing: starts output at the beginning of the next line. |
’0 ’ |
Double spacing: skips a line before starting output. |
’1 ’ |
Paging: starts output at the top of a new page. |
’$ ’ |
Prompting: starts output at the beginning of the next line and suppresses carriage return at the end of the line. |
’ ’ (0 ) |
Prompting with overprinting: suppresses line feed at the beginning of the line and carriage return at the end of the line; note that this character is the ASCII character NUL. |
9.5.2. Prompting on a Terminal
Normally, when you call the WRITE procedure to access a TEXT file connected to a terminal, VSI Pascal accumulates the characters in a line buffer until a subsequent WRITELN procedure is executed. In effect, WRITELN generates an end-of-line marker. When you complete a line or close a file, VSI Pascal writes a full line of characters to the specified TEXT file.
VSI Pascal can manipulate partial lines in a TEXT file; however, when characters are being written to a terminal output file opened with the LIST carriage-control option (LIST is the default), partial lines are written to the terminal before input is transferred from any terminal to the line buffer of a TEXT file. In this situation, VSI Pascal searches for all TEXT files opened for output on terminals; it then writes to those files any partial lines contained in the files' respective line buffers. These partial lines, called prompts, appear on the screen. You respond to a prompt by typing a line of input data terminated by pressing Return.
WRITE( 'Name three presidents:' ); READ( Pres1, Pres2, Pres3);
VSI Pascal stores the string ’Name three presidents: ’ in the output buffer; when executing the READ procedure, VSI Pascal locates the TEXT file opened for output to the appropriate terminal and the partial output buffer is written, causing the string ’Name three presidents: ’ to appear on the terminal screen. The user can then begin typing on the same line as the prompt, providing the names of three presidents. Note that prompting works only for files associated with interactive terminals. For any other files, VSI Pascal does not write output until you start the new line with a WRITELN procedure.
9.5.3. Delayed Device Access to Text Files
The Pascal standard requires that the file buffer always contain the next file component that will be processed by the program. This definition can cause problems when the input to the program depends on the output most recently generated. To alleviate such problems in the processing of the TEXT files, VSI Pascal uses a technique called delayed device access, also known as lazy lookahead.
As a result of delayed device access, VSI Pascal does not retrieve an item of data from a physical file device and does not insert it in the file buffer until the program is ready to process it. VSI Pascal fills the file buffer when the program makes the next reference to the file. A reference to the file consists of any use of the file buffer variable, including its implicit use in the GET, READ, and READLN procedures, or any test for the status of the file, namely, the EOF, EOLN, STATUS, and UFB functions.
The RESET procedure, which is required when any TEXT file is opened for input, initiates the process of delayed device access. (Note that RESET is done automatically on the predeclared file INPUT.) RESET expects to fill the file buffer with the first component of the file. However, because of delayed device access, an item of data is not supplied from the input device to fill the file buffer until the next reference to the file.
When writing a program for which the input will be supplied by a TEXT file, you should be aware that delayed device access occurs. Because RESET initiates delayed device access, and because EOF and EOLN cause the file buffer to be filled, you should place the first prompt for input before any tests for EOF or EOLN. The information you enter in response to the prompt supplies data that is retained by the file device until you make another reference to the input file.
VAR i : INTEGER; {In the executable section:} WRITE( 'Enter an integer or an empty line: ' ); WHILE NOT EOLN DO BEGIN READLN( i ); WRITELN( 'The integer was: ', i:1 ); WRITE( 'Enter an integer or an empty line: ' ); END; WRITELN( 'Done' );
The first reference to the file INPUT is the EOLN test in the WHILE statement. When the test is performed, VSI Pascal attempts to read a line of input from the TEXT file. Therefore, it is very important to prompt for the integer or empty line before testing for EOLN.
Suppose you respond to the first prompt by supplying an integer as input. Access to the input device is delayed until the EOLN function makes the first reference to the file INPUT. The EOLN function causes a line of text to be read into the internal line buffer. The subsequent READLN procedure reads the input value from the line of text and assigns it to the variable i. The WRITELN procedure writes the input value to the text file OUTPUT. The final statement in the WHILE loop is the request for another input value. The loop terminates when EOLN detects the end-of-line marker.
Enter an integer or an empty line: 10 The integer was: 10 Enter an integer or an empty line: 99 The integer was: 99 Enter an integer or an empty line: [Return] Done
WHILE NOT EOLN DO BEGIN WRITE( 'Enter an integer or an empty line: ' ); READLN( i ); WRITELN( 'The integer was: ', i:1 ); END;
The EOLN test at the beginning of the loop causes the file buffer to be filled. However, because no input has been supplied yet, the prompt does not appear on the screen until you have supplied input to fill the INPUT file buffer.
10 Enter an integer or an empty line: The integer was: 10 99 Enter an integer or an empty line: The integer was: 99 [Return]
The prompt always appears after you type a value for i.
Delayed device access can produce unexpected results if you try to use the STATUS function to test the status of a TEXT file after you have performed a READLN procedure on the file. Remember that a READLN procedure call actually performs a READ procedure on each variable listed as a parameter, then performs a READLN procedure to position the file at the beginning of the next line. Therefore, a call to STATUS after a READLN procedure actually tests whether the file was successfully positioned. To test the status of the file, STATUS causes delayed device access to occur, which fills the file buffer with the next component. If you want to test the successful reading of data from the input file, read the data with the READ procedure, call the STATUS function, and then perform a READLN procedure to advance the file to the beginning of the next line.
9.5.4. Writing Partial Lines to Terminals
OPEN( OUTPUT, RECORD_LENGTH := 512 );
CONST LF = 10; {ASCII control characters} CR = 13; {In the executable section:} OPEN( OUTPUT, CARRIAGE_CONTROL := NONE ); WRITELN( ''(LF)'Output this' ); WRITELN( 'string directly' ); WRITELN( 'to the terminal'(CR) );
This is useful when you are writing escape sequences or other graphics characters to terminal devices.
9.6. Formatting Output
Type of Item Printed |
Number of Characters |
---|---|
INTEGER |
10 |
UNSIGNED |
10 |
INTEGER64 |
19 |
UNSIGNED64 |
20 |
CHAR |
1 |
BOOLEAN |
6 |
Enumerated |
Size of the longest identifier plus 1, up to 32 |
REAL |
12 |
DOUBLE |
20 |
QUADRUPLE |
40 |
Character string |
Length of string |
9.6.1. Specifying the Field Width
When you write any value, you can specify a field width to override the default. The format is identical for the WRITE, WRITELN, and WRITEV procedures. The formats are:
REAL format
output[[:minimum[[:fraction]] ]]
INTEGER format
output[[:minimum [[:radix]] ]]
String, Boolean, and enumeration format
output:minimum
output
The expression to be written, as you would write it without specifying the field width.
minimum
A nonnegative integer expression for the minimum number of characters to be written for the value. Pascal uses a greater field width if required by the magnitude of the number to be printed.
fraction
The fraction, which is permitted only for values of real types, indicates the number of digits to be written to the right of the decimal point.
radix
The radix, which is permitted only for values of integer types, specifies the use of a base notation other than decimal.
If you try to write a number is too large to fit in the field that you specify, Pascal extends the field instead of removing digits and writing an incorrect number. If you specify a field width that is larger than necessary, Pascal prints blanks to the left of the number, right-justifying it.
If you try to write a value of an enumerated type, a Boolean value, a character, or a string value in a field that is too narrow, the value is truncated on the right. The truncated identifier is not checked for uniqueness.
9.6.2. Writing Real Numbers
WRITELN( Shoe_Size );
1.25000E+01
WRITELN( Shoe_Size:5:1 );
12.5
If the field specified is wider than necessary, the value is written with leading blanks.
If you try to write a real value in a field that is too narrow, the field width is expanded to the minimum necessary to write the value.
9.6.3. Explicitly Specifying the Base
integer-expression : fieldwidth : radix
radix
Any run-time integer expression with a value from 2 through 36 inclusive. If you specify a base greater than 10, letters A through Z denote the extra digits. For example, when you output in hexadecimal (base 16), the characters A through F are the extra six digits.
If the integer-expression denotes a negative number, a leading minus sign is printed and the absolute value of the expression is converted into the selected radix.
9.6.4. Specifying the Base with Predeclared Conversion Functions
{BIN } {DEC } WRITE( [[file_variable, ]] {UDEC } ( expression[[, length[[,digits]] ]] ) ,...) {HEX } { } {OCT }
The predeclared conversion functions convert the value of the first expression in the list to its equivalent as a binary, decimal, unsigned decimal, hexadecimal, or octal number. The resulting digits are returned in a VARYING OF CHAR string.
For every expression whose binary, decimal, unsigned decimal, hexadecimal, or octal value you wish to write, you must call the appropriate conversion function separately with an actual parameter list. You can call more than one conversion function in the same output procedure call. You can write variables of any type (including pointers) to text files in binary, decimal, unsigned decimal, hexadecimal, or octal notation.
WRITELN( HEX( i ):3 );
00
Be careful about specifying field widths with BIN, DEC, UDEC, HEX, and OCT when the converted value could exceed the field width given.
WRITE( HEX( Payroll, 10 ), HEX( Salary, 12 ) );
000031F2 000058AB
WRITELN( OCT( Social_Security, 14 ), BIN( Survey, 8 ) );
0271137762500101110
WRITEV( Final_Balance, OCT( Debits, 16 ), OCT( Credits, 16 ) );
' 77777770342 00000033766'
9.6.5. Writing Nonnumeric Types
VAR Color : ( Blue, Yellow, Black, Fire_Engine_Green ); {In the executable section:} WRITE( 'My favorite color is ', Color:15 );
My favorite color is YELLOW
My favorite color is FIRE_ENGINE_GRE
Because the field width specified in these cases is not wide enough for all 17 characters in the identifier, the identifier is truncated after the field is filled.
For More Information:
On the WRITE procedure (Section 9.8.24, “WRITE Procedure”)
On the WRITELN procedure (Section 9.8.25, “WRITELN Procedure”)
On the WRITEV procedure (Section 8.107, “WRITEV Procedure”)
On the BIN function (Section 8.11, “BIN Function”)
On the DEC function (Section 8.26, “DEC Function”)
On the UDEC function (Section 8.93, “UDEC Function”)
On the HEX function (Section 8.41, “HEX Function”)
On the OCT function (Section 8.60, “OCT Function”)
9.7. Error-Processing Parameter
For I/O procedures, the last parameter (which is optional) specifies the action to be taken should the procedure fail to execute successfully. You must use nonpositional syntax in order to pass the error-recovery parameter to the called procedure. This parameter is called ERROR and can accept two values: CONTINUE and MESSAGE.
If you specify ERROR := CONTINUE, the program continues to execute regardless of any error conditions encountered during execution of the procedure. If you specify this value, you should use the STATUS function to be certain that the I/O routine worked as expected.
If you specify ERROR := MESSAGE and if an error occurs, VSI Pascal generates an appropriate error message and program execution stops. By default, VSI Pascal displays an error message and program execution stops after the first error in an I/O operation.
You cannot use the error-recovery parameter with the I/O functions EOF, UFB, and EOLN, nor with any reference to the file buffer.
9.8. I/O Routines
VSI Pascal provides predeclared procedures and functions to perform input and output operations on file variables. These routines may operate differently depending on a file's organization and the currently defined access method.
The I/O routines in the following sections appear in alphabetical order. To save you the time of scrolling through all the routines, you may wish to click on the Table Of Contents entry for the desired routine.
At any time during the execution of a process, a file variable is considered to be in one of three modes: inspection, generation, or undefined. When a file is reading input, it is in inspection mode. When output is being written to a file, the file is in generation mode. A file in an undefined state of processing is in undefined mode. The mode often determines the valid operations for the file.
I/O Routine | Mode Before Execution | Mode After Execution | I/O Routine | Mode Before Execution | Mode After Execution |
---|---|---|---|---|---|
CLOSE |
Any |
Undefined |
READ |
Inspection |
Inspection |
DELETE |
Inspection |
Inspection |
READLN |
Inspection |
Inspection |
EOF |
Inspection or generation |
No change |
RESET |
Any |
Inspection |
EOLN |
Inspection |
Inspection |
RESETK |
Any |
Inspection |
EXTEND |
Any |
Generation |
REWRITE |
Any |
Generation |
FIND |
Any |
Inspection if successful; undefined if unsuccessful |
STATUS |
Any |
No change, unless error |
FINDK |
Any |
Inspection if successful; undefined if unsuccessful |
TRUNCATE |
Inspection |
Generation |
GET |
Inspection |
Inspection |
UFB |
Any |
No change |
LINELIMIT |
Any |
No change |
UNLOCK |
Inspection |
Inspection |
LOCATE |
Any |
Generation |
UPDATE |
Inspection |
Inspection |
OPEN |
Undefined |
Undefined |
WRITE |
Generation, unless keyed access, which may be any mode |
Generation |
PAGE |
Generation |
No change |
WRITELN |
Generation |
Generation |
PUT |
Generation |
Generation |
9.8.1. CLOSE Procedure
1. CLOSE (file_variable ,[[disposition]] ,[[user_action]] ,[[ERROR := error_recovery]] ) 2. CLOSE ( FILE_VARIABLE := file_variable [[,DISPOSITION := disposition]] [[,USER_ACTION := user_action]] [[,ERROR := error_recovery ]] ...)
file_variable
The name of the file variable associated with the file that VSI Pascal is to close.
disposition
A value that determines what VSI Pascal is to do with the file after closing it. The disposition values are the same as those used for the OPEN procedure. The disposition value in the CLOSE procedure supersedes a disposition value specified in the OPEN procedure.
user_action
A routine name that VSI Pascal calls to close the file. You can use a user-action routine to close the file using environment-specific capabilities.
error_recovery
The action to be taken if an error occurs during execution of the routine.
Execution of the CLOSE procedure causes the system to close the file and, if the file is internal, to delete it. Each file is automatically closed when control passes from the block in which it is declared.
You cannot close a file that has not been opened (either explicitly by the OPEN procedure, or implicitly by the EXTEND, RESET, or REWRITE procedure). If you try to close a file that was never opened, an error occurs.
The file can be in any mode (inspection, generation, or undefined) before the CLOSE procedure is called. Execution of CLOSE sets the mode to undefined.
For More Information:
On positional and nonpositional syntax (Section 6.3.8, “Parameter Association”)
On the OPEN procedure and parameters (Section 9.8.11, “OPEN Procedure”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.2. DELETE Procedure
DELETE( file_variable[[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the file from which a component is to be deleted.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file must be in inspection mode before DELETE is called; the mode does not change after the procedure's execution.
When the DELETE procedure is called, the current component, as indicated by the file buffer, must already have been locked by a successful FIND, FINDK, GET, RESET, or RESETK procedure before it can be deleted. After deletion, the component is unlocked and the UFB function returns TRUE.
DELETE( Accounts_Payable );
This procedure call deletes the current component. When the component has been deleted, it is unlocked and UFB( Accounts_Payable ) returns TRUE. A run-time error occurs if the current component of Accounts_Payable is not locked.
For More Information:
On file organizations (Section 9.1, “Files and File Organizations”)
On component access (Section 9.3, “Component Access Modes”)
On the UFB function (Section 9.8.21, “UFB Function”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.3. EOF Function
EOF[[(file_variable)]]
file_variable
The name of the file variable associated with the input file. If you omit the name of the file, the default is INPUT.
The file can be in either inspection or generation mode before EOF is called; however, end-of-file must be defined. The input operations GET, RESET, and FINDK are guaranteed to leave end-of-file defined. The file mode does not change after EOF has been executed.
EOF returns TRUE when the file pointer is positioned after the last component in the file, and returns FALSE up to and including the time when the last component of the input file is read into the file buffer. You must try to retrieve another file component after the last to determine whether the file is positioned at end-of-file.
When EOF is tested for a file with relative organization opened for direct access, the result is TRUE if the file is in inspection mode and the last GET or RESET operation positioned the file beyond the last existing component. If the file is in generation or undefined mode, the result of EOF is undefined.
When EOF is tested for a file with indexed organization opened for keyed access, the result is TRUE if the file is in inspection mode and the last FINDK, GET, RESET, or RESETK operation positioned the file beyond the last component with the current key number. Successful attempts at FINDK, GET, RESET, and RESETK cause EOF to be FALSE. If the file is not in inspection mode, EOF is undefined.
If you try to read a file after EOF becomes TRUE, an error results.
Coupons := 0; WHILE NOT EOF DO BEGIN READLN( Coupon_Amount ); Coupons := Coupons + Coupon_Amount; END;
This example calculates the total value of the coupons contained in the file INPUT. The loop is performed while the EOF function returns FALSE.
For More Information:
On component access (Section 9.3, “Component Access Modes”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
On retrieval of file components (Section 9.5.3, “Delayed Device Access to Text Files”)
9.8.4. EOLN Function
EOLN [[(file_variable)]]
file_variable
The name of a file variable associated with a text file. If you omit the name of the file, the default is INPUT.
The file must be in inspection mode and EOF must return FALSE before EOLN is called. EOLN leaves the file in inspection mode.
The Boolean EOLN function returns TRUE when the file pointer is positioned after the last character in a line. When the EOLN function returns TRUE, the file buffer contains a blank character.
The EOLN function returns FALSE when the last component in the line is read into the file buffer. Another character must be read to cause EOLN to return TRUE and to cause the file buffer to be positioned at the end-of-line marker following the last character of the line. If you use the EOLN function on a nontext file, an error occurs.
WHILE NOT EOF( Master_File ) DO BEGIN WHILE NOT EOLN( Master_File ) DO BEGIN READ( Master_File, x ); IF NOT (x IN ['A'..'Z','a'..'z','0'..'9']) THEN Err := Err + 1; END; READLN( Master_File ); END;
This example scans the characters on each line of a TEXT file called Master_File and checks for characters that are neither digits nor letters. If a nonnumeric or nonalphabetic character is encountered in the file, the counter Err is incremented by 1. The loop is executed until the last component in the file is read.
For More Information:
On TEXT files (Section 9.5, “TEXT Files”)
9.8.5. EXTEND Procedure
EXTEND( file_variable [[, file_name]] [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the output file.
file_name
String expression for the file name to be associated with the file_variable. If the file is already open, an error is signaled.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file can be in any mode before EXTEND is called to set the mode to generation. If the file is an external file and is not already open, EXTEND opens it using the defaults for the OPEN procedure.
After execution of EXTEND, the file is positioned after the last component and EOF and UFB return TRUE. If the file does not exist, EXTEND does not create it but returns an error at run time.
A call to EXTEND on a relative file opened for direct access positions the file after its last existing component.
A call to EXTEND on an indexed file opened for random access by key positions the file after the last component relative to the primary key.
VAR f : FILE OF INTEGER; {In the executable section:} OPEN( File_Variable := f, File_Name := 'sample.dat', History := OLD, Organization := Relative, Access_Method := Direct; ); EXTEND( f ); F^ := 20; PUT( f );
These statements open an existing relative file named sample.dat. The file will be positioned after the last record in the file. Subsequent PUT statements will append new components to the end of the file.
For More Information:
On component access (Section 9.3, “Component Access Modes”)
On default values for the OPEN procedure (Section 9.8.11, “OPEN Procedure”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.6. FIND Procedure
FIND( file_variable, component-number [[, ERROR := error-recovery]] );
file_variable
The name of a file variable associated with a file that is open for direct access.
component-number
A positive integer expression that indicates the component at which the file is to be positioned. If the component number is zero or negative, a run-time error occurs.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The FIND procedure allows direct access to the components of a file. You can use the FIND procedure to move forward or backward in a file.
After execution of the FIND procedure, the file is positioned at the specified component. The file buffer variable assumes the value of the component, and the file mode is set to inspection. If the file has relative organization, the current file component is locked. If there is no file component at the selected position, the file buffer is undefined (UFB becomes TRUE) and the mode becomes undefined. After any call to FIND, the value of EOF is undefined.
You can use the FIND procedure only when reading a file that was opened by the OPEN procedure. If the file is open because of a default open (that is, with EXTEND, RESET, or REWRITE), a call to FIND results in a run-time error because the default access method is sequential.
FIND( Albums, Current + 2 );
If the value of Current is 6, this procedure causes the file position to move to the eighth component; the file buffer variable Albums^ assumes the value of the component. If no eighth component exists, Albums^ is undefined and UFB (Albums) returns TRUE.
For More Information:
On component access (Section 9.3, “Component Access Modes”)
On the UFB function (Section 9.8.21, “UFB Function”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.7. FINDK Procedure
The FINDK procedure searches the index of an indexed file opened for keyed access and locates a specific component.
FINDK( file_variable, key-number, key-value[[, match-type]] [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the file to be searched.
key-number
A positive integer expression that indicates the key position.
key-value
An expression that indicates the key to be found; it must be assignment compatible with the key field in the specified key position.
match-type
An identifier that indicates the relationship between the key value in the FINDK procedure call and the key value of a component.
error-recovery
The action to be taken if an error occurs during execution of the routine.
When you establish key fields with the KEY attribute, you assign each one a key number from 0 to 254. Key number 0 represents the mandatory primary key of the file. Separate indexes are built for each key number in the file.
EQL—equal to the key value
NXT—the next key in the collating sequence after the key value
NXTEQL—the next or equal key in the collating sequence after the key value
If the FINDK procedure was used on an ascending collating sequence, NXT and NXTEQL would be equivalent to GTR and GEQ. If a descending collating sequence was used, it would be the same as LSS and LEQ. The match type is optional; if omitted, it defaults to EQL.
The FINDK procedure can be called for any indexed file opened for keyed access, regardless of the file's mode. If the component described exists, the file buffer is filled with that component; UFB and EOF both become FALSE. The mode is set to inspection and the component is automatically locked. If no component is found to match the description, UFB becomes TRUE and EOF is undefined. The mode is set to undefined.
FINDK( Book_Index, 1, 35, NXTEQL );
Assuming key number 1 is ascending, this procedure searches the index for key number 1 in the file Book_Index until it finds the first component whose key value is greater than or equal to 35. If the component matching the description in the FINDK statement is found, UFB( Book_Index ) and EOF( Book_Index ) return FALSE, and the component is locked. If the component cannot be found, UFB( Book_Index ) returns TRUE, and EOF( Book_Index ) is undefined. Book_Index must be an indexed file opened for keyed access.
For More Information:
On indexed files (Section 9.1.3, “Indexed File Organization”)
On random access by key (Section 9.3.2, “Random Access ”)
On the UFB function (Section 9.8.21, “UFB Function”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.8. GET Procedure
GET( file_variable [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the input file.
error-recovery
The action to be taken if an error occurs during execution of the routine.
If the file is open for sequential access, call the RESET procedure. RESET sets the mode to inspection, advances the file position to the first component, and assigns the component's value to the file buffer variable.
If the file is open for direct access, call either the RESET or the FIND procedure to position the file.
If the file is open for keyed access, call the FINDK, RESET, or RESETK procedure to position the file.
RESET( Books ); New_Rec := Books^; GET( Books );After execution of the RESET procedure, the value of the file buffer variable Books^ is equal to the value of the first component of the file. The assignment statement assigns this value to the variable New_Rec. The GET procedure then assigns the value of the second component to Books^, advancing the file position to the second component. Another GET procedure advances the file position to the Third component. Figure 9.10, “File Position After GET Procedure” shows this sequence of events.

By using the GET procedure repeatedly, you can read sequentially through a file. When called for a file with relative organization, GET skips any nonexistent components to find the next component.
When you reach the end of the file and EOF returns TRUE, a GET procedure results in a run-time error.
GET( Phones );
This example reads the next component of the file Phones into the file buffer variable Phones^. Prior to executing GET, the value of EOF (Phones) must be FALSE; if it is TRUE, an error occurs.
For More Information:
On component access (Section 9.3, “Component Access Modes”)
On the UFB function (Section 9.8.21, “UFB Function”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.9. LINELIMIT Procedure
LINELIMIT( file_variable, n [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the TEXT file to which this limit applies.
n
A positive integer expression that indicates the number of lines that can be written to the file before execution terminates.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file can be in any mode before LINELIMIT is called; the file mode does not change after LINELIMIT has been executed.
VSI Pascal first uses environment-specific means to determine if there is a default line limit. If there is no environment-specific default, there is no default line limit. You can use a call to LINELIMIT to override the default.
After the number of lines written into the file has reached the line limit, program execution terminates unless the WRITELN procedure that exceeded the line limit includes the ERROR := CONTINUE parameter.
LINELIMIT( Debts, 100 );
Execution of the program terminates after 100 lines have been written into the text file Debts.
VSI Pascal determines the default line limit by translating an environment variable or logical name as a string of decimal digits. If the environment variable or logical name has not been defined, there is no default line limit. You can override the default by calling the LINELIMIT procedure.
For More Information:
On TEXT files (Section 9.5, “TEXT Files”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.10. LOCATE Procedure
LOCATE( file_variable, component-number [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the file to be positioned.
component-number
A positive integer expression that indicates the relative component number of the component to be found.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file can be in any mode before LOCATE is called. The mode is set to generation after the procedure's execution.
The LOCATE procedure positions the file so that the next PUT procedure writes the contents of the file buffer into the selected component. After LOCATE has been performed, UFB returns TRUE and EOF is undefined. Because the LOCATE procedure does not perform an I/O operation, the value returned by the STATUS procedure is unaffected by LOCATE.
RESET( Books ); New_Rec := Books^; GET( Books );
The LOCATE procedure positions the file Accounts_Receivable before relative component number 63. The call UFB( Accounts_Receivable ) now returns TRUE and EOF( Accounts_Receivable ) is undefined. The assignment statement loads the file buffer with the contents of file position 63. The PUT operation writes the file buffer into file component number 63. UFB( Accounts_Receivable ) remains TRUE.
For More Information:
On relative files (Section 9.1.2, “Relative File Organization”)
On random access by relative component number (Section 9.3.2, “Random Access ”)
On the UFB function (Section 9.8.21, “UFB Function”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.11. OPEN Procedure
The OPEN procedure opens a file and allows you to specify file characteristics using either positional or nonpositional syntax.
1. OPEN( file_variable ,[[file_name]] ,[[history]] ,[[record_length]] ,[[access_method]] ,[[record_type]] ,[[carriage_control]] ,[[organization]] ,[[disposition]] ,[[file_sharing]] ,[[user_action]] ,[[default_file_name]] ,[[ERROR := error_recovery]] ) 2. OPEN( FILE_VARIABLE := file_variable [[,FILE_NAME := file_name]] [[,HISTORY := history]] [[,RECORD_LENGTH := record_length]] [[,ACCESS_METHOD := access_method]] [[,RECORD_TYPE := record_type]] [[,CARRIAGE_CONTROL := carriage_control]] [[,ORGANIZATION := organization]] [[,DISPOSITION := disposition]] [[,SHARING := file_sharing]] [[,USER_ACTION := user_action]] [[,DEFAULT := default_file_name]] [[,ERROR := error_recovery]] ... )
file_variable
The name of the file variable associated with the file that VSI Pascal is to open.
file_name
A character-string expression containing the external file name. VSI Pascal determines the default file name according to the environment in which you are programming.
history
A value that indicates whether the file exists or if VSI Pascal must create the file. If you specify OLD and if VSI Pascal cannot find the file, an error occurs.
Other values are READONLY and UNKNOWN. If you specify READONLY, you can only read from the file; if you attempt to write to the file, an error occurs. If you specify UNKNOWN, VSI Pascal looks for an existing file but creates a new file if an existing file does not exist. If you specify OLD or UNKNOWN and if the attempt to open the file generates a file protection error, VSI Pascal tries again using READONLY.
record_length
A positive integer that specifies the maximum size in bytes for a line in a TEXT file or a file of type FILE OF VARYING. (Record length is equivalent to component length.) The default is 255 bytes. For all other types of files, VSI Pascal ignores this parameter.
If you do not specify a length for an existing file, VSI Pascal uses the length specified at the file's creation.
If you use OPEN to create a sequentially organized file with variable-length components, VSI Pascal records the maximum length of each component in the file only if you specify a value for the record_type field.
access_method
A value that specifies the component access method to use. The possible values include SEQUENTIAL, DIRECT, and KEYED. The DIRECT access method is equivalent to random access by relative component number. The KEYED access method is equivalent to random access by key.
record_type
A value that indicates the component format. (Record format and component format are equivalent.) The available values are FIXED (fixed-length components), VARIABLE (variable-length components), STREAM (stream component format with either carriage return, combination carriage return and line feed, or form-feed delimiters), STREAM_CR (stream component format with carriage-return delimiters), and STREAM_LF (stream component format with line-feed delimiters).
carriage_control
A value that indicates the carriage-control format for the file. The value LIST indicates single spacing between components. The values CARRIAGE and FORTRAN are equivalent and indicate that the first character of every output line is a carriage-control character. The values NONE and NOCARRIAGE indicate that the file has no carriage control.
organization
A value that specifies the file organization. If you are accessing an existing file, the specified organization must match the organization of the existing file; if it does not, an error occurs. The choices for this parameter are SEQUENTIAL, RELATIVE, and INDEXED.
disposition
Disposition |
Description |
---|---|
SAVE |
VSI Pascal retains the file. |
DELETE |
VSI Pascal deletes the file. |
|
VSI Pascal prints the file on a line printer and retains the file. |
PRINT_DELETE |
VSI Pascal prints the file on a line printer and then deletes the file. |
SUBMIT |
VSI Pascal submits to a queue or places the print job in a background process and retains the file. |
SUBMIT_DELETE |
VSI Pascal submits to a queue or places the print job in a background process and deletes the file. |
file_sharing
A value that specifies whether another program can access the file while it is open. A value of READONLY indicates that other programs can read but not write to the file. A value of READWRITE indicates that a program can both read and write to the file while it is open. A value of NONE indicates that a program cannot read or write from the open file.
default_file_name
A string expression containing default file specification information. For instance, you can use this value to set a default directory specification.
user_action
A name of a user-written routine that VSI Pascal calls to open the file (instead of allowing VSI Pascal to open the file with the OPEN procedure). You can use a user-action routine to open the file using environment-specific capabilities of the I/O system underlying VSI Pascal.
error_recovery
The action to be taken if an error occurs during execution of the routine.
Using the OPEN procedure:
Before the OPEN procedure is called, the file is in undefined mode; its mode does not change after OPEN has been executed.
You cannot use OPEN on a file variable that is already open.
If you use INPUT or OUTPUT, VSI Pascal implicitly opens them just before their first use. VSI Pascal implicitly opens INPUT with a history of READONLY. If you choose, you can explicitly open INPUT or OUTPUT. To do this, call the OPEN procedure at any point in your compilation unit before you use the first I/O routine on that file.
Because the RESET, REWRITE, and EXTEND procedures implicitly open files, you need not always use the OPEN procedure. RESET, REWRITE, and EXTEND impose the same defaults as OPEN, except where noted (in the HISTORY parameter).
Create a TEXT file with fixed-length components
Create a file with relative or indexed organization
Open a file for direct or keyed access
Specify a line length other than the default for a line in a TEXT file
PROGRAM Main( User_Guide ); VAR User_Guide : TEXT; {In the executable section:} OPEN( User_Guide );
When the OPEN procedure is executed, the system first attempts to find an environment-specific translation for User_Guide. If no such translation happens, the file USER_GUIDE.DAT is created in the default device and directory on the local computer.
If User_Guide had not been specified as an external file in the program header, the OPEN procedure would have created an internal file. By default, the file is created with a record length of 255 bytes and components of variable length. The system then opens the file for sequential access.
OPEN( Journal_Accounts, 'JOURNAL.DAT', HISTORY := UNKNOWN, ACCESS_METHOD := KEYED, ORGANIZATION := INDEXED );
If the file JOURNAL.DAT already exists, this procedure opens it; otherwise, VSI Pascal creates a new file named JOURNAL.DAT with the specified characteristics. If the file does exist, it must have the same characteristics as those in the parameter list of the OPEN procedure. VSI Pascal opens the file with indexed organization for keyed access.
For More Information:
On positional and nonpositional syntax (Section 6.3.8, “Parameter Association”)
On file organizations (Section 9.1, “Files and File Organizations”)
On component format (Section 9.2, “Component Formats”)
On component access (Section 9.3, “Component Access Modes”)
On carriage control (Section 9.5.1, “Carriage Control”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.12. PAGE Procedure
PAGE( file_variable [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with a TEXT file.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file must be in generation mode before the PAGE procedure is called; the mode does not change as a result of the procedure's execution.
Execution of the PAGE procedure clears the record buffer, if it contains data, by performing a WRITELN procedure, and then advances the output to a new page of the specified TEXT file. The next component written to the file begins on the first line of a new page. You can use this procedure only on TEXT files. If you specify a file of any other type, an error occurs.
The value of the page eject component that is output to the file depends on the carriage-control format for that file. When CARRIAGE or FORTRAN is enabled, the page eject record is equivalent to the carriage-control character ’1 ’. When LIST, NOCARRIAGE, or NONE is enabled, the page eject record is a single form feed character.
PAGE( User_Guide );
This PAGE procedure causes a page eject record to be written in the text file User_Guide.
For More Information:
On TEXT files (Section 9.5, “TEXT Files”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.13. PUT Procedure
PUT( file_variable [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the output file.
error-recovery
The action to be taken if an error occurs during execution of the routine.
Before executing the first PUT procedure on a file opened for sequential access, you must execute an EXTEND, REWRITE, or TRUNCATE procedure to set the file to generation mode. EXTEND, REWRITE, and TRUNCATE set EOF to TRUE, thus preparing the file for output. ( (TRUNCATE is legal only on files with sequential organization.)) If the file has indexed organization, the components to be written must be ordered by the primary key.
Before executing the first PUT statement on a file opened for direct access, you must execute an EXTEND, REWRITE, or LOCATE procedure to position the file.
The PUT procedure writes the value of the file buffer variable at the end of the specified sequential-file or direct-access file. You can use LOCATE to position a direct-access file and then use PUT to write the value of the file buffer variable at that position. After execution of the PUT procedure, the value of the file buffer variable becomes undefined ( UFB returns TRUE ). EOF remains TRUE and the file remains in generation mode.
You can call the PUT procedure for a keyed-access file, regardless of the file's mode (inspection, generation, or undefined). PUT causes the file buffer variable to be written to the file at the position indicated by the key. If the component has more than one key, the file buffer variable is inserted in each index at the appropriate location. After execution of PUT, a keyed-access file is in generation mode.
PROGRAM Book_File( INPUT, OUTPUT, Books ); TYPE My_String = PACKED ARRAY[1..40] OF CHAR; Book_Rec = RECORD Author : My_String; Title : My_String; END; VAR New_Book : Book_Rec; Books : FILE OF Book_Rec; n : INTEGER; {In the executable section:} REWRITE( Books ); FOR n := 1 TO 10 DO BEGIN WITH New_Book DO BEGIN WRITE( 'Title:' ); READLN( Title ); WRITE( 'Author:' ); READLN( Author ); END; Books^ := New_Book; PUT( Books ); END; CLOSE( Books );
This program writes the first 10 components read from the terminal into the file Books. The component data items are typed at the terminal and assigned to the record variable New_Book. They consist of two 40-character strings denoting a book's author and title. The FOR loop accepts 10 values for New_Book, assigning each new record to the file buffer variable Books^. The PUT statement writes the value of Books^ into the file for each input record.
For More Information:
On component access (Section 9.3, “Component Access Modes”)
On the UFB function (Section 9.8.21, “UFB Function”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.14. READ Procedure
The READ procedure reads one or more file components into a variable.
READ( [[file_variable,]] {variable-identifier [[:radix-specifier]]},... [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the input file. If you omit the name of the file, the default is INPUT.
variable-identifier
The name of the variable into which a file component will be read; multiple identifiers must be separated with commas.
radix-specifier
One of the format values BIN, OCT, or HEX. These values, when used on a variable identifier, will read the variable in binary, octal, or hexadecimal radix respectively. You can use a radix specifier only when reading from a TEXT file.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file must be in inspection mode before READ is called. The file remains in inspection mode after execution of a READ procedure.
The READ procedure for a nontext file performs an assignment statement, a GET procedure, and an UNLOCK procedure for each variable.
{This call to READ...} READ( file_variable, variable-identifier ); {...is equivalent to the following code:} variable-identifier := file_variable^; GET( file_variable ); UNLOCK( file_variable );
The READ procedure reads from the file until it has found a value for each variable in the list. The first value read is assigned to the first variable in the list, the second value read is assigned to the second variable, and so on. The values and the variables must be of assignment-compatible types. Reading stops if an error occurs.
For a TEXT file, more than one component (character) can be read into a single variable. For example, many characters can be read into a string or converted into a numeric variable. The READ procedure repeats the assignment, GET, and UNLOCK process until it has read a sequence of characters that represent a legal value for the next variable in the parameter list. The procedure continues to read components from the file until it has assigned a value to each variable in the list.
After the last character has been read from a line of a TEXT file, EOLN returns TRUE and the file buffer variable contains a space. Unless you are reading into a character or string variable, a call to READ at this point skips over the end-of-line marker and positions the file at the beginning of the next line. If you are reading into a variable of type CHAR when EOLN returns TRUE, the space is read and assigned to the variable, and the file position advances. If you are reading into a string variable when EOLN becomes TRUE, the file position does not change. In the latter case, you should use the READLN procedure to advance the file position past the end-of-line marker.
Values from a TEXT file can be read into variables of integer, real, Boolean, character, string, and enumerated types. TEXT file values to be read into integer, real, Boolean, and enumerated variables can be preceded in the file by any number of spaces, tabs, and end-of-line markers. Values to be read into character variables, however, must not be separated because they are read and assigned character by character.
VAR i : INTEGER; {In the executable section:} READ( i );
If the object in the input file is 123ABC, the read stops at the character 'A', and i contains the value 123.
When reading constant identifiers of an enumerated type from a TEXT file, VSI Pascal reads all characters in the identifier, but recognizes only the first 31 characters. You need input only enough characters to make the identifier unique among the other constant identifiers of its type; text input data for enumerated types can consist of both lowercase and uppercase characters.
Boolean input data in TEXT files follow the same rules as other enumerated types. For example, the following character combinations, all of which could appear in a TEXT file, are equivalent: TRUE, True, T, t, tr.
When using a radix specifier, values from a TEXT file can be read into a variable of any type, except a type containing a file component. If the input stream does not provide sufficient data, the high-order bits are set to zero. When reading structured types, the input stream must account for any padding required for alignment.
You can use the READ procedure to read a sequence of characters from a TEXT file into a variable of type PACKED ARRAY OF CHAR. Successive characters from the file are assigned to components of the array, in order, until each component has been assigned a value. If any characters remain on the line after the array is full, the next READ procedure begins with the next character on that line. If the end of the line is encountered before the array is full, spaces are assigned to the remaining components.
You can also read TEXT file characters into a variable of types STRING or VARYING OF CHAR. Characters are assigned to a STRING or VARYING OF CHAR variable in a manner similar to that in which they are assigned to a packed array. However, if the end-of-line marker is encountered before the STRING or VARYING OF CHAR variable has been filled to its maximum length, the STRING or VARYING OF CHAR value is not padded with spaces. Instead, its current length is set equal to the number of characters that have been read into it. If you call the READ procedure with a parameter of type STRING or VARYING OF CHAR, and EOLN returns TRUE, no characters are read into the STRING or VARYING OF CHAR variable; its current length is set to zero.
Every nonempty TEXT file ends with an end-of-line marker and an end-of-file marker. Therefore, EOF never becomes TRUE when you are reading strings with the READ procedure. To test EOF when reading strings, use a READLN procedure to advance the file beyond the end-of-line marker.
READ( Temp, Age, Weight );
98.6 11 75
The variable Temp is assigned the value 98.6, Age is assigned the value 11.0, and Weight is assigned the value 75.0. You need not type all three values on the same line.
TYPE A_String = PACKED ARRAY[1..20] OF CHAR; VAR Names : TEXT; Pres, Veep : A_String; {In the executable section:} READ( Names, Pres, Veep );
John F. Kennedy Lyndon B. Johnson Lyndon B. Johnson <EOLN> Hubert H. Humphrey <EOLN> Richard M. Nixon Spiro T. Agnew <EOLN>
The first call to the READ procedure sets Pres equal to the 20-character string ’John F. Kennedy##### ’ and Veep equal to ’Lyndon B. Johnson### ’. The second call to the procedure assigns the value ’Lyndon B. Johnson### ’ to Pres and, after encountering the end-of-line marker, fills the array Veep with spaces. The file position does not advance to the beginning of the next line until a READLN is performed.
TYPE Color = ( Red, Fire_Engine_Green, Blue, Black ); VAR Light : Color; {In the executable section:} READ( Light );
In this example, if the letter R is read, the variable Light is assigned the value Red. However, if the letters Redx are read, an error occurs. If the letters Bl are read, an error also occurs because Bl is not unique. However, the letters Blu are unique and would be interpreted as the constant identifier Blue.
For More Information:
On TEXT files (Section 9.5, “TEXT Files”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
On specifying radixes for output (Section 9.6.3, “Explicitly Specifying the Base” and Section 9.6.4, “Specifying the Base with Predeclared Conversion Functions”)
9.8.15. READLN Procedure
The READLN procedure reads lines of data from a TEXT file.
READLN [[( [[file_variable,]] {variable-identifier [[:radix-specifier]]},... [[, ERROR := error-recovery]] )]];
file_variable
The name of the file variable associated with the TEXT file to be read. If you omit the name of the file, the default is INPUT.
variable-identifier
The name of the variable into which a value will be read; multiple identifiers must be separated with commas. If you do not specify any variable names, READLN skips a line in the specified file.
radix-specifier
One of the format values BIN, OCT, or HEX. These values, when used on a variable identifier, read the variable in binary, octal, or hexadecimal, respectively. You can use a radix-specifier only when reading from a TEXT file.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file must be in inspection mode before READLN is called; it remains in that mode after the procedure's execution.
The READLN procedure reads values from a TEXT file. After reading values for all the listed variables, the READLN procedure skips over any characters remaining on the current line and positions the file at the beginning of the next line. The values need not all be on a single line; READLN continues until values have been assigned to all the specified variables, even if this process results in the reading of several lines of the input file.
When applied to several variables, READLN performs the following sequence:
READ( file_variable, {variable-identifier},... ); READLN( file_variable );
EOLN returns TRUE after a READLN procedure only if the new line is empty.
You can use the READLN procedure to read integers, real numbers, Booleans, characters, strings, and constants of enumerated types. The values in the file must be separated as for the READ procedure. The rules governing the reading of values from text files are presented with the READ procedure.
TYPE String = PACKED ARRAY[1..20] OF CHAR; VAR Names : TEXT; Pres, Veep : String; {In the executable section:} READLN( Names, Pres, Veep );
John F. Kennedy Lyndon B. Johnson Lyndon B. Johnson <EOLN> Hubert H. Humphrey <EOLN> Richard M. Nixon Spiro T. Agnew <EOLN> <EOLN> <EOF>
The READLN procedure reads the values ’John F. Kennedy ’ for Pres and ’Lyndon B. Johnson ’ for Veep. It then skips to the next line, ignoring the remaining characters on the first line. Subsequent execution of the procedure assigns the value ’Hubert H. Humphrey ’ to Pres and the space detected as the end-of-line marker to Veep. A third call to the procedure reads ’Richard M. Nixon ’ into Pres and ’Spiro T. Agnew ’ into Veep. The procedure then skips past the end-of-line marker to the beginning of the next line. If you call READLN again, EOF becomes TRUE, and EOLN becomes undefined.
The READLN procedure is implemented as one or more READ calls followed by a READLN call. A STATUS call after a READLN procedure tests if the file was properly positioned, not whether the last READ was successful. To test if READLN successfully read data, replace the call to READLN with an explicit call to READ to read the line, then call STATUS to test the results of the READ, and finally call READLN to advance the file buffer variable for the next READLN.
For More Information:
On the effect of delayed device access on tests of STATUS after a READLN procedure call (Section 9.5.3, “Delayed Device Access to Text Files”)
On the READ procedure (Section 9.8.14, “READ Procedure”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
On the radix specifiers (Section 9.6.3, “Explicitly Specifying the Base” and Section 9.6.4, “Specifying the Base with Predeclared Conversion Functions”)
9.8.16. RESET Procedure
RESET( file_variable [[, file_name]] [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the input file.
file_name
String expression for the file name to be associated with the file_variable. If the file is already open, an error is signaled.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file can be in any mode before you call RESET; a call to RESET sets the file to inspection mode. If the file is an external file and is not already open, RESET opens it using the same defaults as the OPEN procedure. You cannot use RESET to create a file.
A call to RESET on a sequential file positions the file at the first component, and the file buffer variable contains the value of this component. If the file is not empty, EOF and UFB return FALSE and the first component is locked to prevent access by other processes. If the file is empty, EOF and UFB return TRUE. If the file does not exist, RESET does not create it, but returns an error at run time.
You must call RESET before reading any file with sequential organization except the predeclared file INPUT. The RESET procedure removes the end-of-file marker from any file connected to a terminal device (including INPUT), which allows reading from the file to continue. If you call RESET for the predeclared files OUTPUT or ERR, an error occurs.
A call to RESET on a relative file opened for direct access positions the file at its first existing component.
A call to RESET on an indexed file opened for keyed access positions the file at the first component relative to the primary key.
VAR f : FILE OF INTEGER; {In the executable section:} OPEN( f , 'file.dat', ACCESS_METHOD := DIRECT ); RESET( f );
RESET( Weights );
If the file variable Weights is already open, this procedure call prepares it for reading and assigns the value of the first file component to Weights^. If the file is not open, RESET causes VSI Pascal to open the file by default. If Weights is an external file, its file history will be OLD. If Weights does not exist, an error occurs.
For More Information:
On component access (Section 9.3, “Component Access Modes”)
On the default parameter values for OPEN (Section 9.8.11, “OPEN Procedure”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.17. RESETK Procedure
RESETK( file_variable, key-number[[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the input file.
key-number
A nonnegative integer expression that indicates the key position.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file can be in any mode before RESETK is called to set the mode to inspection.
You assign a key number from 0 to 254 to each key field of a file component with the KEY attribute. The file is searched for the component with the lowest value in the specified key number. This component becomes the current component in the file and is locked. The value of the current component is copied into the file buffer; EOF and UFB are set to FALSE. If the component does not exist, EOF and UFB become TRUE. Note that a RESETK procedure on key number 0 is equivalent to a RESET procedure.
RESETK( Book_Index, 0 );
This procedure searches the file Book_Index for the component with the lowest value in the primary key. If this component exists, it becomes the current file component and is locked. The function calls UFB( Book_Index ) and EOF( Book_Index ) returns FALSE. If the procedure was unable to find the component, UFB( Book_Index ) and EOF( Book_Index ) return TRUE.
For More Information:
On indexed files (Section 9.1.3, “Indexed File Organization”)
On random access by key (Section 9.3.2, “Random Access ”)
On the UFB function (Section 9.8.21, “UFB Function”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.18. REWRITE Procedure
REWRITE( file_variable [[, file_name]] [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the output file.
file_name
String expression for the file name to be associated with the file_variable. If the file is already open, an error is signaled.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file can be in any mode before REWRITE is called to set the mode to generation. If the file variable has not been opened, REWRITE creates and opens it using the same defaults as the OPEN procedure.
The REWRITE procedure truncates sequential files to length zero and sets EOF and UFB to TRUE. You can then write new components into the file with the PUT, WRITE, and WRITELN procedures (WRITELN is defined only for text files). After the file is open, successive calls to REWRITE truncate the existing file to a length of zero.
To update an existing file with sequential organization, you must either use the EXTEND procedure, use the TRUNCATE procedure, or copy the contents to another file, specifying new values for the components you need to update.
When applied to a file with relative or indexed organization, REWRITE deletes the contents of the file and sets the file position to the beginning of an empty file.
REWRITE( Storms );
If the file variable Storms is already open, this REWRITE procedure prepares the file for writing, clears it of old data, and sets the file position to the beginning of the file. If Storms is not open, a new version is created with the same defaults as for the OPEN procedure.
VAR Ratings : FILE OF INTEGER; {In the executable section:} OPEN( Ratings, 'cars.dat', HISTORY := OLD, RECORD_TYPE := FIXED ); REWRITE( Ratings );
The OPEN procedure opens the file variable Ratings, which is associated with the file cars.dat. The REWRITE procedure discards the current contents of the file f and sets the file position to the beginning of the file. After execution of this procedure, EOF( Ratings ) returns TRUE.
For More Information:
On component access (Section 9.3, “Component Access Modes”)
On the default parameters for OPEN (Section 9.8.11, “OPEN Procedure”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.19. STATUS Function
STATUS(file_variable )
file_variable
The name of the file variable associated with the file to be tested.
The file can be in any mode before STATUS is called; unless an error occurs, STATUS does not change the file mode upon execution.
Code |
Description |
---|---|
0 |
Successful operation |
-1 |
End-of-file encountered |
Positive integer? |
Error encountered |
A test by the STATUS function on a TEXT file causes delayed device access to occur, which fills the file buffer with the next file component. Therefore, EOF, EOLN, UFB, and STATUS never return an error code following a successful STATUS function call.
RESET( File1, ERROR := CONTINUE ); IF STATUS( File1 ) > 0 THEN WRITELN( 'Cannot access first record' ) ELSE IF STATUS( File1 ) < 0 THEN WRITELN( 'File is empty' ) ELSE READ( File1 );
If the RESET procedure encounters either an error condition or an end-of-file, an appropriate error message is displayed. If the STATUS function indicates that the RESET procedure was successful, the first record is read from the file.
For More Information:
On TEXT files (Section 9.5, “TEXT Files”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
On delayed device access (Section 9.5.3, “Delayed Device Access to Text Files”)
On status code translations (VSI Pascal User Manual)
9.8.20. TRUNCATE Procedure
TRUNCATE( file_variable [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the file to be truncated.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file must be in inspection mode before TRUNCATE is called. After the procedure has been executed, the mode is set to generation so that you can write to the file.
After the appropriate components have been deleted, the file remains positioned at the new end-of-file, but the file buffer itself is undefined. Thus, EOF and UFB are both set to TRUE.
TRUNCATE( Master_File );
This procedure deletes components from Master_File, beginning with the current component and continuing until EOF returns TRUE. When the operation is complete, EOF( Master_File ) and UFB( Master_File ) are TRUE, and new data can be written at the end of Master_File.
For More Information:
On sequential files (Section 9.1.1, “Sequential File Organization”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.21. UFB Function
UFB( file_variable )
file_variable
The name of the file variable associated with the file whose buffer is being tested.
The file can be in any mode before UFB is called, the execution of UFB does not change the file mode.
UFB tests the effect of the last I/O operation on the file. UFB returns FALSE if a successful GET, FIND, FINDK, RESET, or RESETK operation has filled the file buffer. GET, FIND, FINDK, RESET, and RESETK procedure calls that do not fill the file buffer due to the data not being present in the file set UFB to TRUE. GET, FIND, FINDK, RESET, and RESETK procedure calls that could not examine the file leave UFB in an unknown state. You must use the STATUS builtin to determine if the GET, FIND, FINDK, RESET, and RESETK procedure calls were able to examine the contents of the file. UFB also returns TRUE after DELETE, EXTEND, LOCATE, PUT, REWRITE, TRUNCATE, and UPDATE procedures have left the contents of the file buffer unknown.
FIND( Supplies, December ); IF NOT UFB( Supplies ) THEN Inventory := Inventory - Supplies^;
If the variable December has a value of 12, the FIND procedure attempts to find the twelfth component of the file Supplies. If the FIND procedure is successful, Supplies^ assumes the value of this component and UFB( Supplies ) is FALSE. If, however, the FIND procedure is unable to find the twelfth component of the file, UFB( Supplies ) returns TRUE. In this example, the value of Supplies^ is subtracted from the value of Inventory only if the FIND procedure is successful.
9.8.22. UNLOCK Procedure
UNLOCK( file_variable [[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the file whose component is to be unlocked.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file must be in inspection mode before UNLOCK is called; it remains in inspection mode after UNLOCK has executed.
If the component at which the file pointer is positioned has been locked, the UNLOCK procedure releases it.
UNLOCK( Sales_File );
The UNLOCK procedure releases the contents of the current component.
For More Information:
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.23. UPDATE Procedure
UPDATE( file_variable[[, ERROR := error-recovery]] );
file_variable
The name of the file variable associated with the file whose component is to be updated.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file must be in inspection mode before UPDATE is called; it remains in that mode after the procedure's execution.
The UPDATE procedure is legal for files that have been opened for random access (direct or keyed). The current component must already have been locked by a successful FIND, FINDK, GET, RESET, or RESETK procedure before the contents of the file buffer can be rewritten into it. After the update has taken place, the component is unlocked and UFB returns TRUE.
UPDATE( October_Sales );
This procedure writes the file buffer contents (October_Sales^) back into the current file component October_Sales. The component is then unlocked and UFB( October_Sales) returns TRUE.
For More Information:
On component access (Section 9.3, “Component Access Modes”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.24. WRITE Procedure
WRITE([[file_variable, ]]{expression},... [[, ERROR := error-recovery]] )
file_variable
The name of the file variable associated with the output file. If you omit the name of the file, the default is OUTPUT.
expression
An expression whose value is to be written; multiple output values must be separated with commas. An output value must have the same type as the file components; however, values written to a TEXT file can also be expressions of any ordinal, real, or string type. You can specify the output format of the expression as described in Section 9.6, “Formatting Output”.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file ( unless it is a random-access by key file ) must be in generation mode before WRITE is called; it remains in that mode after WRITE has executed.
WRITE( file_variable, expression );
file_variable^ := expression; PUT( file_variable );
For TEXT files, the WRITE procedure converts the value of each expression to a sequence of characters. It repeats the assignment and PUT process until all the values have been written to the file.
TYPE String = PACKED ARRAY[1..20] OF CHAR; VAR Names : FILE OF String; Pres : String; {In the executable section:} WRITE (Names, 'Millard Fillmore ', Pres);
This example writes two components in the file Names. The first is the 20-character string constant ’Millard Fillmore#### ’. The second is the value of the string variable Pres.
For More Information:
On TEXT files (Section 9.5, “TEXT Files”)
On component format (Section 9.2, “Component Formats”)
On output format (Section 9.6, “Formatting Output”)
On prompting from the terminal (Section 9.5.2, “Prompting on a Terminal”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
9.8.25. WRITELN Procedure
The WRITELN procedure writes a line of data to a text file.
WRITELN [[( [[file_variable,]] {expression,... [[, ERROR := error-recovery]] )]]
file_variable
The name of the file variable associated with the text file to be written. If you omit the name of the file, the default is OUTPUT.
expression
An expression whose value is to be written; multiple output values must be separated by commas. The expressions can be of any ordinal, real, or string type and are written with a default field width, which you can override as described in Section 9.6, “Formatting Output”.
error-recovery
The action to be taken if an error occurs during execution of the routine.
The file must be in generation mode before WRITELN is called; it remains in that mode after WRITELN has been executed.
WRITE (file_variable, {expression},...); WRITELN (file_variable);
WRITELN( User_Guide, 'This manual describes how to interact');
This procedure writes the string to the TEXT file User_Guide, follows it with an end-of-line marker, and skips to the next line.
WRITELN( Tree, ' ', String1, String2 );
The first item in the list is a space character. The space indicates that the values of String1 and String2 are printed on a new line when the file is written to a terminal, line printer, or similar carriage-control device.
TYPE A_String = PACKED ARRAY[1..25] OF CHAR; VAR New_Hires : TEXT; n : INTEGER; New_Rec : RECORD Id : INTEGER; Name, Address : A_String; END; {In the executable section:} OPEN( New_Hires, 'new_hires.dat', CARRIAGE_CONTROL := FORTRAN ); REWRITE( New_Hires ); WITH New_Rec DO BEGIN WRITELN( New_Hires, '1New hire # ', ID:1, ' is ', Name ); WRITELN( New_Hires, ' ', Name, 'lives at:' ); WRITELN( New_Hires, ' ' ); WRITELN( New_Hires, ' ', Address ); END;
New hire # 73 is Irving Washington Irving Washington lives at: 22 Chestnut St, Seattle
For More Information:
On TEXT files (Section 9.5, “TEXT Files”)
On carriage-control characters in new files (Section 9.8.11, “OPEN Procedure”)
On the error-processing parameter (Section 9.7, “Error-Processing Parameter”)
On formatting output (Section 9.6, “Formatting Output”)
Chapter 10. Attributes
Attribute syntax (Section 10.1, “Attribute Syntax”)
Attributes ( Section 10.2, “Attributes”)
Attribute classes (Section 10.3, “Attribute Classes”)
When an attribute is not explicitly stated, the compiler follows the default rules to assign properties to program elements. However, using attributes to override the defaults allows additional control over the properties of data items, routines, and compilation units.
For convenience in description, the attributes are grouped in attribute classes. All attributes in a given class share common characteristics (sometimes there is only one attribute to a class).
Table 10.7, “Attribute Classes” presents the attributes in each class. To save you the time of scrolling through all the attributes, you can click on the Table Of Contents entry for the desired attribute.
For More Information:
For information on environment-specific issues about attributes (Appendix A, Data Storage and Representation)
10.1. Attribute Syntax
{constant-expression } [ {identifier1 [[ ( {identifier2 } ,... ) ]] },... ] { }
identifier1
The name of the attribute.
constant-expression
A compile-time integer expression, represented in this chapter by n, that qualifies several of the VSI Pascal attributes.
identifier2
With the CHECK, OPTIMIZE, or KEY attributes.
With COMMON and PSECT attributes, indicating the name of a storage area.
With the GLOBAL, EXTERNAL, WEAK_GLOBAL, and WEAK_EXTERNAL attributes, indicating an external name. If entered as a quoted string, passed to the linker with case unmodified.
A list of attributes can appear anywhere in the VAR, TYPE, and CONST declaration sections, and anywhere in a program that a type, a type identifier, or the heading of a routine or compilation unit is legal. However, only one attribute from a particular class can appear in a given attribute list. The use of attribute lists is shown in examples throughout this chapter. The names of attributes, when used in a suitable context, cannot conflict with other identifiers with the same name in the program.
Syntactically, an attribute list can appear before a VAR, TYPE, and CONST section in the declaration section. In this case, the attributes would apply to all elements in that particular section. However, VSI Pascal only allows you to use the ALIGN, ENUMERATION_SIZE, and HIDDEN attribute in this way.
Some attributes require a special form of constant expression called a name string. The syntax of a name string differs from that of other strings in VSI Pascal only in that a name string cannot use the extended-string syntax.
Every program element must be associated with one property for each applicable attribute class. The VSI Pascal compiler automatically supplies the defaults for the unspecified classes at the time of the element's declaration. In some classes, as described in the following sections, the default property is not available through an explicit attribute.
By appearing in a type definition in a TYPE section; the item is later declared to be of that type.
By appearing in the declaration of an item preceding its type.
By appearing before the current declaration section.
Note
TYPE X = ([1] <= [2])..True;
The attributes of the type can neither conflict with nor duplicate any attributes explicitly stated in the data item's declaration.
The type cannot be used anyplace where its accompanying attributes are illegal.
TYPE A = [GLOBAL] INTEGER; B = [UNALIGNED] INTEGER; VAR A1 : [GLOBAL] A; { Illegal; duplicates GLOBAL attribute of type A } A2 : [EXTERNAL] A; { Illegal; conflicts with GLOBAL attribute of type A } B1 : ^B; { Illegal; pointer base type cannot be UNALIGNED } C : A; { Legal }
The first three variable declarations are illegal for the reasons shown in the comments. The declaration of C is legal; C is declared as a global INTEGER because of the characteristics of its type. The compiler supplies defaults for all other classes applicable to the variable C.
Attributes associated with data items usually modify type compatibility rules. These modifications are explained in the sections describing individual attributes.
For More Information:
On extended-string syntax (Section 2.6, “String Types”)
On program elements and attribute properties (Section 10.3, “Attribute Classes”)
On type compatibility (Section 2.10, “Type Compatibility”)
10.2. Attributes
The following sections describe each attribute in alphabetical order.
10.2.1. ALIGN
[ALIGN (keyword)]
The ALIGN attribute takes a single keyword parameter that has the same name and meaning as the keywords for the /ALIGN qualifier. However, specifying the ALIGN attribute overrides any value that you previously specified using the /ALIGN qualifier.
[ALIGN(VAX)] TYPE vax_type = Array [1..10] of char; TYPE alpha_type = Array [1..10] of char;
Usage and Default Information:
Table 10.1, “ALIGN Attribute Keywords” lists the keywords for the ALIGN attribute. See Section A.2.7, “Alignment Boundaries” for a complete description of the alignment rules for each platform and Section A.2.4, “Allocation Sizes of Variables” for a complete description of the allocated sizes for objects for each platform.
Keyword |
Action |
---|---|
NATURAL (default)? |
Uses natural alignment when positioning record fields or array components. Natural alignment is when a field or component is positioned on a boundary based on its size. For example, 32-bit integers would be aligned on the nearest 32-bit boundary. |
VAX |
Uses byte alignment when positioning record fields or array components. Field or components larger than 32 bits are positioned on the nearest byte boundary. |
For More Information:
On allocation sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
On storage allocation (Section A.2.5, “Storage Allocation of Types”)
10.2.2. ALIGNED
ALIGNED [[ ( n )]]
An aligned object is aligned on the memory boundary indicated by n. The constant expression n indicates that the address of the object must end in at least n zeros. ALIGNED( 0 ) specifies byte alignment, ALIGNED( 1 ) specifies word alignment, ALIGNED( 2 ) specifies longword alignment, ALIGNED( 3 ) specifies quadword alignment, ALIGNED( 4 ) specifies octaword alignment, and ALIGNED( 9 ) specifies alignment on a 512-byte boundary.
Usage and Default Information:
The default alignment of an object depends on its size.
The constant expression n must denote an integer. If you omit n, the default is 0, indicating byte alignment.
If the expression provided to the ALIGNED attribute is greater than the largest supported alignment on the target platform, the compiler will print a warning message and default to the largest supported value. (Note that ALIGNED(13) is the largest alignment allowed on VSI OpenVMS I64 and VSI OpenVMS Alpha systems and ALIGNED(9) is the largest alignment allowed on VSI OpenVMS x86-64 systems).
An automatic variable cannot have alignment greater than an octaword on VSI OpenVMS I64 systems, or a quadword on VSI OpenVMS Alpha or VSI OpenVMS x86-64 systems.
The minimum alignment for an object of a structured type is the greatest alignment specified for any of its components.
Alignment attributes are illegal on nonstatic types, components of files, and on VARYING OF CHAR strings.
The alignment of a formal VAR parameter cannot be greater than the alignment of a corresponding actual parameter, either by default or by means of an alignment attribute. In an array variable passed to a conformant formal parameter, alignment and size attributes are illegal on all dimensions of the actual parameter, except the first, that correspond to the dimensions of the formal parameter.
On OpenVMS I64 systems, the base type of a pointer variable passed to the NEW procedure cannot have alignment greater than an octaword. On OpenVMS Alpha or OpenVMS x86-64 systems, the base type of a pointer variable passed to the NEW procedure cannot have alignment greater than a quadword.
If the base type of a pointer variable has a specified alignment, then the base type of a pointer expression assigned to it must have an alignment equal to that of the variable.
Pointer types are structurally compatible only if their base types have identical alignment.
VAR Free_Buffers : [ ALIGNED( 1 ), WORD] -2**15..2**15-1; {In the executable section:} IF ADD_INTERLOCKED( -1, Free_Buffers ) <= 0 THEN {Statement:}
The predeclared function ADD_INTERLOCKED requires that the second parameter passed to it have word alignment and an allocation size of one word. In this example, the variable Free_Buffers is declared with alignment and size attributes to meet these restrictions.
For More Information:
On automatic and size attribute classes (Section 10.3, “Attribute Classes”)
On static and nonstatic types (Section 2.9, “Static and Nonstatic Types”)
On default alignments (VSI Pascal User Manual)
10.2.3. ASYNCHRONOUS
The ASYNCHRONOUS attribute indicates that a routine can be called asynchronously to the main program execution. For example, AST routines or condition handlers are asynchronous routines because they are called without an explicit procedure call in your program. Routines with the ASYNCHRONOUS attribute can only access local variables and up-level VOLATILE variables. Additionally, asynchronous routines can only call other asynchronous routines.
Usage and Default Information:
This attribute can be applied to routines and to routine parameters declared in external routines.
In the absence of the ASYNCHRONOUS attribute, the compiler assumes that the routine can be activated only by actual calls within the program.
All predeclared routines are asynchronous by default.
Any routines called from within the block of an asynchronous routine must be local to the asynchronous routine or must themselves be asynchronous, either by default or by an explicit attribute.
All nonlocal variables accessed from within the block of an asynchronous routine must be declared VOLATILE or READONLY.
If a formal routine parameter is asynchronous, all actual parameters passed to it must also be asynchronous.
An asynchronous routine can be passed as an actual parameter to a formal routine parameter that does not have this attribute.
PROCEDURE Do_Something; VAR i : [VOLATILE] INTEGER; j : INTEGER [ASYNCHRONOUS] FUNCTION Handler {Two array parameters} : BOOLEAN; BEGIN i := i + 1; {Remaining function body...} {In the executable section of the procedure:} ESTABLISH( Handler );
This example shows the declaration of the asynchronous function Handler. The executable section of Handler cannot access variables declared in the enclosing block of the procedure Do_Something unless those variables are declared VOLATILE. Handler can access the variable i, which has the VOLATILE attribute, but cannot access the variable j.
For More Information:
On the VOLATILE attribute (Section 10.2.42, “VOLATILE”)
On the READONLY attribute (Section 10.2.34, “READONLY”)
On the ESTABLISH procedure (Section 8.30, “ESTABLISH Procedure”)
10.2.4. AT
AT( n )
The exact address is specified by the constant expression n. Variables representing machine-dependent entities are frequently given the AT attribute.
Usage and Default Information:
A variable having the AT, COMMON, or PSECT attribute is implicitly static.
AT cannot be applied to routines or to compilation units.
AT cannot be applied to variables of nonstatic types.
For More Information:
On default allocation for variables declared in the outermost block of a program or in nested blocks (Section 10.2.5, “AUTOMATIC”)
On default allocation for variables declared in the outermost block of a module (Section 10.2.36, “STATIC”)
On static and nonstatic types (Section 2.9, “Static and Nonstatic Types”)
10.2.5. AUTOMATIC
The AUTOMATIC attribute specifies that storage for the variable be allocated each time the program enters the routine in which the variable is declared. The storage is deallocated each time the program exits from that routine. An automatic variable exists as long as the declaring routine remains active.
Usage and Default Information:
By default, variables declared in nested blocks are automatic.
By default, variables declared at the outermost level of a program are automatic, though for efficiency they can be made static.
By default, the control part of the nonstatic types and the pointer part of variables of nonstatic types follow the same rules as regular variables: they are static or automatic depending on the location of the declaration and the usage of the data.
Global and external variables are implicitly static. Thus, they conflict with the AUTOMATIC attribute.
Program-level variables with the AUTOMATIC attribute are not recorded in environment files.
AUTOMATIC cannot be applied to routines and compilation units.
AUTOMATIC cannot be applied to nonstatic types.
For More Information:
On an example of the STATIC attribute (Section 10.2.36, “STATIC”)
On the GLOBAL attribute (Section 10.2.17, “GLOBAL”)
On the EXTERNAL attribute (Section 10.2.15, “EXTERNAL”)
On static and nonstatic types (Section 2.9, “Static and Nonstatic Types”)
10.2.6. BIT
BIT[[ ( n )]]
The optional constant n indicates the number of bit storage units.
Usage and Default Information:
The default size of an object depends on its type.
The constant expression n must denote a positive integer. If you omit n, the default value is 1.
Objects of floating-point or pointer types must have a size equal to their allocation size.
Ordinal types cannot exceed their maximum size, which is determined by the platform and the value of the data switch for the compile command.
The amount of storage described must be large enough to contain an object of the specified type; otherwise, a compile-time error occurs.
Assignment to variables with a size attribute are zero-extended (if necessary) and all bits are written.
When you fetch from variables with a size attribute, the compiler need only reference sufficient bits to access the legal value of the type. The contents of a variable are undefined if it does not contain a zero-extended legal value of the variable's type.
A size attribute is illegal on a conformant parameter, on a component of a VARYING string, on an object of a structured type having a file component, or on a nonstatic type. In an array variable passed to a conformant formal parameter, size and alignment attributes are illegal on all dimensions of the actual parameter, except the first, that correspond to the dimensions of the formal parameter.
Two variables of the same type that have different allocation sizes are assignment compatible but are not structurally compatible.
For More Information:
On alignment attributes (Section 10.3, “Attribute Classes”)
On type compatibility (Section 2.10, “Type Compatibility”)
On size attributes and return values of size functions (Section 8.81, “SIZE Function”)
On allocation sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
10.2.7. BYTE
BYTE [[ ( n )]]
The optional constant n indicates the number of byte storage units.
For More Information:
On allocation sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
On size allocation restriction (Section 10.2.6, “BIT”)
10.2.8. CHECK
CHECK [[ ( {identifier},... )]]
An identifier specifies an option to be enabled. If you omit the list of options, all available positive options are enabled.
Option | Action | Negation |
---|---|---|
ALL |
Enables all forms of checking. |
NONE |
BOUNDS |
Verifies that an index expression is within the bounds of an array's index type and that character-string sizes are compatible with the operations being performed and that schema types are compatible. |
NOBOUNDS |
CASE_SELECTORS |
Verifies that the value of a case selector is contained in the corresponding case label list. |
NOCASE_SELECTORS |
DECLARATIONS |
Verifies that schema definitions yield valid types and that uses of GOTO from one block to an enclosing block are correct. |
NODECLARATIONS |
OVERFLOW |
Verifies that the result of an integer computation does not exceed the machine representation. |
NOOVERFLOW |
POINTERS |
Verifies that the value of a pointer variable is not NIL. |
NOPOINTERS |
SUBRANGE |
Verifies that values assigned to variables of subrange types are within the subrange; verifies that a set expression is assignment compatible with a set variable. |
NOSUBRANGE |
Usage and Default Information:
This attribute can be applied to routines and compilation units.
- If not specified on a routine, or compilation unit, the CHECK qualifier or switch value is used as the default. If you specify options for CHECK, VSI Pascal enables only the specified options. Consider the following example:
[CHECK] { is equivalent to } [CHECK( ALL )] [CHECK( option )] { is equivalent to } [CHECK( NONE, option )]
PROGRAM Check_Features; [CHECK( POINTERS, CASE_SELECTORS )] PROCEDURE Linked_List (VAR Client : Info_Rec); {Body of the procedure...} [CHECK( OVERFLOW )] FUNCTION Integer_Compute (VAR Int1, Int2, Int3 : INTEGER) : INTEGER; {Body of the function...} PROCEDURE Bounds_Check (VAR A_String : VARYING[30] OF CHAR; VAR Char_Array : ARRAY[1..25] OF CHAR; VAR Half_Alpha : 'A'..'M'); {Body...}
For the routines Linked_List and Integer_Compute, VSI Pascal enables only the specified options. The procedure Bounds_Check has only the BOUNDS, and DECLARATIONS options enabled by default (unless you use a compilation switch to override the default).
For More Information:
On type compatibility ( Section 2.10, “Type Compatibility”)
10.2.9. CLASS_A
The CLASS_A attribute causes a formal parameter to be passed by an array descriptor that describes contiguous arrays of atomic data types or contiguous arrays of fixed-length strings. This attribute is illegal on parameters of schema types.
PROCEDURE Test2( P3 : [CLASS_S] PACKED ARRAY[L..U : INTEGER] OF CHAR; P4 : [CLASS_A] ARRAY[L2..U2 : INTEGER] OF REAL); EXTERN;
This example defines a procedure Test2, which has two parameters. The first parameter, P3, is passed by descriptor of CLASS_S. The second parameter, P4, is passed by a CLASS_A descriptor.
For More Information:
On VSI Pascal parameter defaults (Section 6.3, “Parameters”)
On CLASS_A descriptors (VSI OpenVMS Calling Standard)
10.2.10. CLASS_NCA
The CLASS_NCA attribute causes a formal parameter to be passed by a noncontiguous array descriptor. This attribute is illegal on parameters of schema types.
For More Information:
On VSI Pascal parameter defaults (Section 6.3, “Parameters”)
On CLASS_NCA descriptors (VSI OpenVMS Calling Standard)
10.2.11. CLASS_S
The CLASS_S attribute causes a formal parameter to be passed by a single descriptor form that is used for scalar data and fixed-length strings. On VSI OpenVMS systems, this attribute allows routines written in VSI Pascal to accept actual parameters from languages such as FORTRAN that generate CLASS_S descriptors.
Usage and Default Information:
In order to pass a CLASS_S string descriptor, you must use a packed conformant array of characters.
This attribute is illegal on parameters of schema types.
When the packed conformant array is passed by CLASS_S descriptor, the lower bound of the conformant schema is always 1 and the upper bound of the conformant schema is the length of the string being passed.
PROCEDURE Print_String( String_Parm : [CLASS_S] PACKED ARRAY[LOW..HIGH : INTEGER] OF CHAR ); BEGIN WRITELN( 'The CLASS_S string is', String_Parm ); WRITELN( 'The lowerbound is', Low ); WRITELN( 'The upperbound is', High ); END;
The previous example defines the procedure Print_String, which has one parameter. The CLASS_S attribute on the VSI Pascal routine specifies that the calling routine passes the String_Parm parameter by a CLASS_S descriptor.
For More Information:
On VSI Pascal parameter defaults (Section 6.3, “Parameters”)
On mixed-language programming (VSI Pascal User Manual)
On CLASS_A and CLASS_S descriptors (VSI OpenVMS Calling Standard)
10.2.12. COMMON
The COMMON attribute specifies that storage for a variable be allocated in an overlaid program section called a common block.
[ COMMON [[ ( { identifier } ) ]] ]
identifier
An identifier that indicates the name of the common block. If you omit the identifier, the name of the variable is used as the name of the common block.
This attribute allows you to share variables with other VSI languages, such as VSI Fortran.
Usage and Default Information:
A variable having the AT, COMMON, or PSECT attribute is implicitly static.
The COMMON attribute can be applied only to variables.
Only one variable can be allocated in a particular common block. Therefore, the name of the common block cannot be used as the name of another common block or program section.
If an VSI Pascal program shares a record variable with a FORTRAN program, the fields must be laid out identically in both common blocks.
Variables declared with the COMMON attribute are longword aligned by default for compatibility with other VSI languages.
For More Information:
On default allocation for variables declared in the outermost block of a program or in nested blocks (Section 10.2.5, “AUTOMATIC”)
On default allocation for variables declared in the outermost block of a module (Section 10.2.36, “STATIC”)
On environment-specific information on common blocks (Appendix A, Data Storage and Representation)
10.2.13. ENUMERATION_SIZE
The ENUMERATION_SIZE attribute controls the allocation size of unpacked enumerated types and Booleans, which are considered enumerated types containing two elements. The ENUMERATION_SIZE attribute can be used on compilation units, TYPE sections, and VAR sections. When used before a TYPE or VAR section, the allocation size for enumerated types is modified only for the duration of the TYPE or VAR section. Note that specifying the ENUMERATION_SIZE attribute overrides any value that you previously specified with the /ENUMERATION_SIZE qualifier.
[ENUMERATION_SIZE (keyword)]
[ENUMERATION_SIZE(Byte))] TYPE enum = (red, blue, green) enum2 = (circle, square, triangle);Table 10.3, “ENUMERATION_SIZE Attribute Keywords” lists the keywords for the ENUMERATION_SIZE attributes.
Keyword |
Description |
---|---|
BYTE |
Allocates unpacked enumerated types with fewer than 255 elements and Booleans in a 8-bit byte. Otherwise, the enumerated types are allocated in a 16-bit word. |
LONG (default) |
Allocates all unpacked enumerated types and Booleans in a 32-bit longword. |
10.2.14. ENVIRONMENT
ENVIRONMENT [[ ( name-string )]]
If the name string is omitted, the name of the source file is used as the environment file name.
The declarations and definitions made at the outermost level of the compilation unit (provided they do not have the AUTOMATIC or HIDDEN attribute) are saved in a newly created environment file. If the name string is specified, you must include a legal file specification.
Usage and Default Information:
There is a default file type of .PEN for environment files if a file name is specified.
- If you do not specify a file name with the [ENVIRONMENT] attribute, then the file name of the source file is used with a .PEN extension for the name of the environment file. For example:
{ Module share_data.pas } [ENVIRONMENT] Module Share_Data; CONST Rate_For_Q1 = 0.1211; Rate_For_Q2 = 0.1156; END.
The above module, when compiled, would result in the creation of an environment file named “share_data.pen.”
The ENVIRONMENT attribute can not be specified on a program that declares nonstatic types or variables of nonstatic types at the outermost level.
The ENVIRONMENT attribute can be specified on a module that declares nonstatic types or variables of nonstatic types at the outermost level.
Programs and modules can access definitions and declarations in a created environment file by using the INHERIT attribute.
For More Information:
On name-string syntax (Section 10.1, “Attribute Syntax”)
On static and nonstatic types (Section 2.9, “Static and Nonstatic Types”)
On programs and modules (Section 7.4, “Modules and Programs”)
On examples of separate compilation (VSI Pascal User Manual)
10.2.15. EXTERNAL
The EXTERNAL attribute indicates a variable or routine that is assumed to be global in another independently compiled unit.
{identifier } [ EXTERNAL [[ ( {'string-literal' } ) ]] ] { }
identifier
Identifier passed to the linker. It is passed in uppercase. If you omit the identifier, the name of the variable is used as the name of the common block.
string-literal
Passes the specified string-literal to the linker unmodified.
If you specify an identifier with EXTERNAL, VSI Pascal supplies that name, rather than the identifier being declared, to the linker.
Usage and Default Information:
The names available to the linker for corresponding global and external variables and routines must be identical.
Global and external variables are implicitly static. Thus, they conflict with the AUTOMATIC attribute.
Compilation units cannot have the EXTERNAL or WEAK_EXTERNAL attribute.
By default, global and external routines have the characteristics of unbound routines.
External routines must be followed by the directive EXTERN, EXTERNAL, or FORTRAN when they are declared.
PROGRAM Freshman_Class; [GLOBAL( Sort_Students )] PROCEDURE Class_List( VAR Register_List, Sorted_List : Student_Rec ); {Procedure body...} {In another compilation unit:} MODULE Senior_Class; [EXTERNAL( Sort_Students )] PROCEDURE Roll_Call( VAR Start_List, End_List : Senior_Rec ); EXTERNAL;
This example shows the global declaration of a procedure with the name Sort_Students and an external reference to the same procedure in a different compilation unit.
For More Information:
On default visibility attribute information (Section 10.2.25, “LOCAL”)
On the GLOBAL attribute (Section 10.2.17, “GLOBAL”)
On the AUTOMATIC attribute (Section 10.2.5, “AUTOMATIC”)
On the UNBOUND attribute (Section 10.2.39, “UNBOUND”)
On compiling and linking (VSI Pascal User Manual)
10.2.16. FLOAT
[FLOAT(keyword)]You can specify the following keywords for this attribute:
D_FLOAT yields REAL=F_FLOATING, DOUBLE=D_FLOATING
G_FLOAT yields REAL=F_FLOATING, DOUBLE=G_FLOATING
IEEE_FLOAT yields REAL=S_FLOATING, DOUBLE=T_FLOATING
For More Information:
On floating-point numbers (Section 2.2, “Real Types”)
10.2.17. GLOBAL
The GLOBAL attribute provides a strong definition of a variable or routine so that other independently compiled units can refer to it.
{identifier } [ GLOBAL [[ ( {'string-literal' } ) ]] ] { }
identifier
Identifier passed to the linker. It is passed in uppercase. If you omit the identifier, the name of the variable is used as the name of the common block.
string-literal
Literal passed, unmodified, to the linker.
Usage and Default Information:
You can apply the GLOBAL attribute to variables, routines, and compilation units. When used on a MODULE, the GLOBAL attribute changes the name of the compiler-generated TO BEGIN DO section if present.
Global and external variables are implicitly static. Thus, they conflict with the AUTOMATIC attribute.
By default, global and external routines have the characteristics of unbound routines.
You cannot apply the GLOBAL attribute to variables of nonstatic types.
For More Information:
On default visibility attribute information (Section 10.2.25, “LOCAL”)
On an example of GLOBAL and on the EXTERNAL attribute (Section 10.2.15, “EXTERNAL”)
On compiling and linking (VSI Pascal User Manual)
10.2.18. HIDDEN
The HIDDEN attribute prevents information concerning a constant definition or a type, variable, procedure, or function declaration from being included in a generated environment file. You can only use the HIDDEN attribute on objects at the outermost level of the compilation unit.
It is possible to prevent all declarations within a declaration section from being included in the environment file by preceding the reserved word CONST, TYPE, or VAR with the HIDDEN attribute.
For More Information:
On environment files (Section 10.2.14, “ENVIRONMENT”)
10.2.19. IDENT
IDENT( name-string )
The name-string can contain additional information whose use is implementation specific. The VSI Pascal compiler uses this string to supply identification information to the linker.
[IDENT( '100.5' ),ENVIRONMENT( 'sample.pen' )] MODULE SAMPLE;
In this example, the IDENT string ’100.5 ’ is supplied to the linker.
For More Information:
On name-string syntax (Section 10.1, “Attribute Syntax”)
On compiling and linking (VSI Pascal User Manual)
10.2.20. IMMEDIATE
Note
The IMMEDIATE attribute is not allowed on formal parameters of schema types.
For More Information:
On default parameter passing (Section 6.3, “Parameters”)
On an example of IMMEDIATE and on the REFERENCE attribute (Section 10.2.35, “REFERENCE”)
10.2.21. INHERIT
The INHERIT attribute indicates the environment file or files to be inherited by a compilation unit. The environment files specified by the INHERIT attribute must already have been created in compilation units (by either the ENVIRONMENT attribute or a compilation switch).
INHERIT( {name-string},... )
Usage and Default Information:
There is a default file type of .PEN for inherited environment files.
{ Program inherit_example.pas } [INHERIT ('share_data')] Program inherit_example(output); CONST My_Rate = Rate_For_Q1*2.0; BEGIN Writeln(My_Rate) END.
When the preceding program is compiled, the compiler first attempts to open the file 'share_data' as an environment file. If 'share_data' is not found the compiler attempts to open 'share_data.pen' as an environment file. If 'share_data.pen' is not found an error message is issued and the compilation is stopped.
For More Information:
On programs and modules (Section 7.4, “Modules and Programs”)
On compilation switches and separate compilation (VSI Pascal User Manual)
10.2.22. INITIALIZE
You can apply the INITIALIZE attribute to procedures to indicate that the procedure is to be called before the main program is entered. A compilation unit might include any number of INITIALIZE procedures, all of which are called in an unspecified order before the main program is entered.
Usage and Default Information:
In the absence of the INITIALIZE attribute, the compiler assumes that a routine can be activated only by actual calls within the program.
Within modules, you should use the TO BEGIN DO section instead of the INITIALIZE attribute. All TO BEGIN DO clauses are executed before INITIALIZE routines.
By default, INITIALIZE procedures have the characteristics of unbound routines.
An INITIALIZE procedure cannot have a formal parameter list.
An INITIALIZE procedure cannot be external.
PROGRAM Routine_Activate; [INITIALIZE] PROCEDURE Check_Open; {Procedure body...} {In the executable section:} BEGIN {VSI Pascal activates Check_Open} {Body of program...}
In this example, the body of the INITIALIZE procedure Check_Open is executed before the main program is activated.
For More Information:
On procedures (Section 6.1, “Routine Declarations”)
On the UNBOUND attribute (Section 10.2.39, “UNBOUND”)
10.2.23. KEY
You can apply the KEY attribute to record fields to indicate that the field is to be used as a key field when the record is part of an indexed file.
{n [[, {options},... ]] } KEY [[( {{options},... } )]] { }
n
The parameter n represents the key number. A key number of 0 indicates that the field is the primary key of the record. All other key numbers indicate alternate keys. The key number must be a constant expression that denotes an integer value in the range from 0 through 254.
options
The options parameter lets you specify certain characteristics of the record key by listing the desired options on the KEY attribute.
Table 10.4, “KEY Attribute Options” lists the possible KEY attribute options.
Option | Action | Negation |
---|---|---|
ASCENDING | Specifies an ascending collating sequence | DESCENDING |
CHANGES | Specifies that changes can be performed on the key | NOCHANGES |
DUPLICATES | Specifies that duplicates of the key are allowed | NODUPLICATES |
Usage and Default Information:
If you omit the key number, the default value is 0.
By default, the primary key is ASCENDING, NOCHANGES, and NODUPLICATES. It is possible to override these defaults, with the exception of the NOCHANGES option. It is illegal to specify CHANGES on the primary key.
The default for an alternate key is ASCENDING, CHANGES, and DUPLICATES.
When you create a new indexed file with more than one key field, you cannot omit any key numbers in the range from 0 through the highest key number specified.
The KEY attribute is ignored except when the record is a component of a file.
A key field can be of any ordinal type or of type PACKED ARRAY OF CHAR. If the key field is of type PACKED ARRAY OF CHAR, its length cannot exceed 255 characters.
A key field of an ordinal type must be allocated in exactly one byte, one word, one longword, or one quadword.
An integer key field that is allocated one byte cannot have negative values.
TYPE Register = RECORD Student_No : [KEY( 0, DESCENDING )] INTEGER; Student_Name : RECORD Last_Name : PACKED ARRAY[1..20] OF CHAR; First_Name : PACKED ARRAY[1..15] OF CHAR; Initial : CHAR; END; Course_Load : INTEGER; Grade_Average : REAL; Class : [KEY( 1 )] PACKED ARRAY[1..9] OF CHAR; END;
This example defines the identifier Register to denote a record type. The first field, Student_No is the primary key of the record. It has been defined as a DESCENDING, NOCHANGES, and NODUPLICATES key. Register contains another field, Class, which is established as the alternate ASCENDING, CHANGES, and DUPLICATES key.
For More Information:
On indexed files (Section 9.1.3, “Indexed File Organization”)
On the UNALIGNED attribute (Section 10.2.38, “UNALIGNED”)
10.2.24. LIST
You can apply the LIST attribute to a formal parameter of a routine and indicates that the routine can be called with multiple actual parameters that correspond to the last formal parameter named in the routine heading.
You can also use the ARGUMENT and ARGUMENT_LIST_LENGTH predeclared routines when writing procedures and functions that use the LIST attribute.
Usage and Default Information:
In the absence of a LIST attribute, an error results if the number of actual parameters exceeds the number of formal parameters.
You can apply the LIST attribute only to the last formal parameter in a parameter list.
You can supply zero, one, or more than one actual parameter to correspond to a LIST formal parameter, but you must use positional syntax when supplying them. The number of actual parameters you can supply is limited to 255.
You can use the LIST attribute on the parameter list of a routine parameter, but you must use positional syntax when specifying them. Using the LIST attribute on routine parameters is allowed only on external routines.
You can use the LIST attribute on conformant parameters to indicate that an external routine can take an arbitrary number of arrays or VARYING OF CHAR parameters, respectively. Using the LIST attribute on conformant parameters is allowed only on external routines.
All actual parameters that correspond to a LIST formal parameter must be compatible or congruent with the type of the formal parameter.
- For formal and actual parameter lists of routine parameters to be congruent, the actual routine parameter and the corresponding formal routine parameter must either both have the LIST attribute or both lack the LIST attribute. Consider the following example:
PROCEDURE Foo( PROCEDURE q( x : [LIST] CHAR ) );
This defines the routine Foo with the formal routine parameter q that defines the formal list parameter x. Consider the following example:PROCEDURE Bar( x : [LIST] CHAR );
This defines Bar to have a formal list parameter x. Consider this call to Foo:Foo( Bar );
This calls Foo passing the actual routine parameter Bar. The formal parameters of q and Bar contain the LIST attribute, so this is a legal call.
PROGRAM Use_List(OUTPUT); FUNCTION Average ( P: [list] INTEGER): REAL; VAR SUM: REAL VALUE 0.0; I: INTEGER; BEGIN FOR I:= 1 TO ARGUMENT_LIST_LENGTH(P) DO SUM:= SUM + ARGUMENT (P,I); AVERAGE:= SUM/ARGUMENT_LIST_LENGTH(P); END; BEGIN WRITELN(AVERAGE(3,6,9),AVERAGE(10,3,4,17)); END.
For More Information:
On the ARGUMENT function (Section 8.7, “ARGUMENT Function”)
On the ARGUMENT_LIST_LENGTH function (Section 8.8, “ARGUMENT_LIST_LENGTH Function ”)
On type compatibility (Section 2.10, “Type Compatibility”)
10.2.25. LOCAL
The LOCAL attribute indicates that an object is unavailable to other independently compiled units.
Usage and Default Information:
By default, all variables and routines are local.
Variables with any visibility attribute other than LOCAL are implicitly static.
Routines with any visibility attribute other than LOCAL cannot refer to automatic variables declared in enclosing blocks and can call only those routines that are local, predeclared, or unbound. (By default, routines declared at program or module level have the characteristics of unbound routines.)
For More Information:
On the AUTOMATIC attribute (Section 10.2.5, “AUTOMATIC”)
On static and nonstatic types (Section 10.2.36, “STATIC”)
On the UNBOUND attribute (Section 10.2.39, “UNBOUND”)
10.2.26. LONG
LONG [[ ( n )]]
The optional constant n indicates the number of longword storage units.
PROGRAM Size; TYPE Status = [LONG] BOOLEAN; VAR Return_Status : Status; FUNCTION Example( Param1, Param2 : INTEGER ) : Status; EXTERNAL; {Function body...}
The program Size defines a BOOLEAN type Status and declares a variable Return_Status of this type. So, the result type of the function is declared to have a size of one longword. The machine code that references the result type can not copy the entire longword, however, if the default size for a Boolean is less than a longword.
For More Information:
On allocation sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
On size allocation restriction (Section 10.2.6, “BIT”)
ACCURATE (Default)
FAST
10.2.27. NOOPTIMIZE
The NOOPTIMIZE attribute prohibits the compiler from optimizing code for the compilation unit or routine.
The NOOPTIMIZE attribute guarantees full evaluation of both operands of the AND and OR Boolean operators to aid in diagnosing all potential programming errors.
If you wish to have short circuit evaluation even with the NOOPTIMIZE attribute, then use the AND_THEN and OR_ELSE Boolean operators.
For More Information:
On the OPTIMIZE attribute (Section 10.2.29, “OPTIMIZE”)
On the AND_THEN and OR_ELSE logical operators (Section 4.2.3, “Logical Operators”)
10.2.28. OCTA
OCTA [[ ( n )]]
The optional constant n indicates the number of octaword storage units.
For More Information:
On allocation sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
On size allocation restriction (Section 10.2.6, “BIT”)
10.2.29. OPTIMIZE
OPTIMIZE [[( {identifier},... )]]
Option |
Action |
---|---|
[OPTIMIZE], [OPTIMIZE(ALL)] |
Enables all optimization components. Inline expansion of user-defined routines is enabled in automatic selection mode. |
[OPTIMIZE(NOINLINE)] |
Disables inline expansion for user-defined routines. All other optimization components are enabled or disabled according to the command line or the setting of the OPTIMIZE attribute on an enclosing scope routine. |
[OPTIMIZE(INLINE)] |
Enables preferential inline expansion of user-defined routines. All other optimization components are enabled/disabled according to the command line on an enclosing scope routine. |
[OPTIMIZE(ALL,NOINLINE)] |
Enables all optimization components, disables inline expansion for user-defined routines. |
[OPTIMIZE(NONE,INLINE)] |
Disables all optimization components, enables inline expansion of user-defined routines. |
[NOOPTIMIZE],[OPTIMIZE(NONE)] |
Disables all optimization components, disables inline expansion of user-defined routines. |
Usage and Default Information:
This attribute can be applied to routines and compilation units.
Optimization features specified with the OPTIMIZE attribute override command-line settings and settings inherited from outer scopes.
The INLINE option specifies that a routine should be inlined preferentially, regardless of the results of heuristics that are normally used to automatically determine if a routine is to be inlined. There are cases where a routine that is marked as INLINE preferred will not be inline expanded, such as routines that have formal parameters of nonstatic types, or that declare or access nonstatic types.
If no OPTIMIZE attribute is specified for a routine in a nested scope, the OPTIMIZE attribute settings from the enclosing routine are used.
Usage and Default Information
If the OPTIMIZE attribute is used on a routine, only the INLINE and NOINLINE keywords are processed. The other forms of the OPTIMIZE attribute are parsed, but perform no function. You cannot modifiy the optimization settings of individual routines on these systems.
For More Information:
On the NOOPTIMIZE attribute (Section 10.2.27, “NOOPTIMIZE”)
On the rules for routine inlining (VSI Pascal User Manual)
10.2.30. PEN_CHECKING_STYLE
VSI Pascal in cooperation with the VSI OpenVMS Linker performs compile-time and link-time checks to ensure that all compilations that inherit environment files actually used the same environment file definition. Information is placed in the object file such that the VSI OpenVMS Linker will perform the same check between each object file that inherited environment files.
By default, compilation units that inherit an environment file compare the embedded compilation time inside the environment file against uses found in any other environment files that are also inherited. If the times are different, a compile-time message is displayed. This happens on all systems.
This checking can be disabled or modified by using the PEN_CHECKING_STYLE attribute in the Pascal source file that created the environment file. Once the environment file exists, its selected checking style will be performed at each use.
PEN_CHECKING_STYLE(keyword)
COMPILATION_TIME
Uses the compilation time of the environment file in all subsequent compile-time checking for users of this environment file. This is the default.
IDENT_STRING
Uses the [IDENT()] string of the environment file in all subsequent compile-time checking for users of this environment file.
NONE
Disables all compile-time checking for users of this environment file.
10.2.31. POS
POS( n )
n
The constant expression n specifies the bit location, relative to the beginning of the record, at which the field begins.
Usage and Default Information:
You can apply the POS attribute to a field of a packed or an unpacked record.
The constant expression n cannot denote a negative integer.
The beginning position of a field must be greater than the ending position of the field preceding it.
The POS attribute cannot be used on a field that follows (not necessarily immediately) a field whose type has run-time size and is nonstatic.
Inside a record variant, the beginning position of a field must be greater than the ending position of the preceding field within the same variant. The variants themselves can overlap.
A field whose allocation size is greater than 32 bits must be positioned according to the allocation size rules for the platform.
A record variable containing a field of a file type cannot include a POS attribute for any field.
The specified bit position must not conflict with the alignment explicitly required by an alignment attribute.
Two record types in which corresponding fields are not identically positioned are neither assignment compatible nor structurally compatible.
TYPE Control = RECORD Flag_1 : [ BIT, POS( 0 ) ] BOOLEAN; Flag_2 : [ BIT, POS( 1 ) ] BOOLEAN; Count : [ BYTE, ALIGNED ] 0..100; Error : [ BIT, POS( 31 ) ] BOOLEAN; END;
This example uses the POS attribute to position the fields of an unpacked record such that Flag_1 occupies bit 0, Flag_2 occupies bit 1, and Error occupies bit 31. Because the Count field has size and alignment attributes, it is allocated one byte of storage and is aligned on the byte boundary following Flag_2; that is, storage for Count occupies bits 8 through 15. Bits 2 through 7 and 16 through 30 are left empty; you cannot refer to them.
For More Information:
On allocation sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
On alignment boundaries in packed and unpacked records (Section A.2.7, “Alignment Boundaries”)
On static and nonstatic types (Section 2.9, “Static and Nonstatic Types”)
On type compatibility (Section 2.10, “Type Compatibility”)
10.2.32. PSECT
The PSECT attribute is useful for placing static variables and executable blocks in program sections that are shared among executable images.
[ PSECT [[ ( { identifier } ) ]] ]
identifier
Identifier passed designating the program section in which storage for a variable, routine, or compilation is to be allocated. If you omit the identifier, the name of the variable is used as the name of the program section.
Usage and Default Information:
A variable having the AT, COMMON, or PSECT attribute is implicitly static.
PSECT is the only allocation attribute that can be applied to routines and compilation units.
For More Information:
On default allocation for variables declared in the outermost block of a program or in nested blocks (Section 10.2.5, “AUTOMATIC”)
On default allocation for variables declared in the outermost block of a module (Section 10.2.36, “STATIC”)
On program sections (Appendix A, Data Storage and Representation)
10.2.33. QUAD
QUAD [[ ( n )]]
The optional constant n indicates the number of quadword storage units.
For More Information:
On storage allocation for objects (Section A.2.5, “Storage Allocation of Types”)
On default sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
On size allocation restriction (Section 10.2.6, “BIT”)
10.2.34. READONLY
The READONLY attribute specifies that an object can be read by a program but it cannot have values assigned to it.
Usage and Default Information:
You can apply this attribute to variables, formal parameters, the base types of pointer variables, and components of structured variables.
By default, an object can be both read and written.
No value of any type is assignment compatible with a read-only object.
The presence of a read-only component in an object of a structured type prohibits the object from having values assigned to it.
You can only pass a read-only actual VAR parameter to a read-only formal VAR parameter.
A pointer expression whose base type is read-only is assignment compatible only with a pointer variable whose base type is also read-only.
TYPE t = RECORD i : INTEGER; END; P_Read_Only = ^ [READONLY] t; VAR Pro : P_Read_Only; Prw : ^ T; PROCEDURE q( p : P_Read_Only); VAR x : INTEGER; BEGIN x := p^.i; {More statements...} END; {In the executable section:} NEW( Pro ): NEW( Prw ); Q( Pro ); Q( Prw ); Prw^.I := 0;
This example shows the declaration of two pointer variables, Pro and Prw, and the calls to NEW that create the dynamic variables Pro^ and Prw^. The type of the formal parameter p requires that a corresponding actual parameter have read access; therefore, both Pro and Prw can legally be passed to Q as actual parameters. Because P is a READONLY parameter, the value of the dynamic variable P^ (which corresponds to either Pro^ or Prw^) can be assigned to a variable, as shown in the assignment statement in the body of Q. However, only Prw^ can have values assigned to it, as shown in the last statement.
For More Information:
On the NEW procedure (Section 8.58, “NEW Procedure”)
On parameters (Section 6.3, “Parameters”)
On type compatibility (Section 2.10, “Type Compatibility”)
10.2.35. REFERENCE
The REFERENCE attribute causes the formal parameter value in a routine to be passed by reference using foreign semantics.
Usage and Default Information:
The REFERENCE attribute is not allowed on formal parameters of schema types.
PROCEDURE Test1( P1 : [REFERENCE] INTEGER; P2 : [IMMEDIATE] INTEGER ); EXTERNAL;
This example defines a procedure, Test1, which has two parameters. The first parameter, P1, is passed by reference. The second parameter, P2, is passed by immediate value.
For More Information:
On default parameter passing (Section 6.3, “Parameters”)
On the IMMEDIATE attribute (Section 10.2.20, “IMMEDIATE”)
10.2.36. STATIC
The STATIC attribute causes VSI Pascal to create a static object, which is allocated only once and exists as long as the executable image in which it is allocated remains active.
Usage and Default Information:
You can override the default (automatic) for variables declared in nested blocks or in the outermost level of compilation units by specifying the STATIC attribute on the variable.
By default, variables declared at the outermost level of a module are static.
Global and external variables are implicitly static so they conflict with the AUTOMATIC attribute.
A variable having the AT, COMMON, or PSECT attribute is implicitly static.
Allocation attributes can not be applied to nonstatic types.
PROGRAM Print_Random( OUTPUT ); VAR i : [AUTOMATIC] INTEGER; FUNCTION Random : INTEGER; VAR x : [STATIC] INTEGER VALUE 15; BEGIN x := (( 9 * x ) + 7 ) MOD 11; Random := x; END; {In the executable section:} FOR i := 1 TO 20 DO WRITELN( Random ); END.
The program Print_Random includes a function that generates a random integer. Because the variable x is declared STATIC, its value is preserved from one activation of the function to the next. By default, the storage for x would have been deallocated when control returned to the main program. Because x is static, it retains the value it had when Random ended and assumes this value the next time Random is called. In the program Print_Random, the program-level variable i is declared AUTOMATIC.
For More Information:
On the AUTOMATIC attribute (Section 10.2.5, “AUTOMATIC”)
On allocation attributes (Section 10.3, “Attribute Classes”)
On default storage of objects (Section A.3, “Internal Representation of Data Types”)
10.2.37. TRUNCATE
The TRUNCATE attribute indicates that an actual parameter list for a routine can be truncated at the point that the attribute was specified. You can use TRUNCATE with the PRESENT function.
Usage and Default Information:
PROCEDURE p( a : [TRUNCATE] CHAR := 'a'; b : CHAR := 'b'; c : [TRUNCATE] CHAR := 'c'; d : CHAR := 'd' );
You can specify the TRUNCATE attribute on a formal parameter in a routine declaration.
- If a parameter with the TRUNCATE attribute is present in the actual parameter list (explicitly with a null actual parameter, or by being skipped over by a nonpositional actual parameter), then the list is not truncated at the TRUNCATE parameter. All parameters (including the current TRUNCATE parameter) up to the next parameter that specifies TRUNCATE must be present or have a default value. The first parameter is present in this call from Example 10.1, “Using the TRUNCATE Attribute” so the list is not truncated at the first parameter. The second parameter has a default value so it is included in the result. The third parameter, however, is not present in the actual parameter list so the parameter list is truncated:
p(); { DEFAULT a AND b--TRUNCATE AT c "ab" }
- If a parameter with the TRUNCATE attribute is present by default, the list is not truncated at that point. In this line of code from Example 10.1, “Using the TRUNCATE Attribute”, the first, second, and third parameters are present by default. Because the third parameter is present, the parameter list is not truncated and all four parameters are present in the result.
p(,,); { DEFAULT a, b, c AND d "abcd" }
- You can specify actual parameters either positionally or nonpositionally; it is the order in the formal parameter list that is used to determine where the list has been truncated and which parameters are required. Because c, the third parameter, is present in the actual list, the parameter list is not truncated.
p( c := y ); { DEFAULT a, b AND d "abyd" }
If a parameter is positioned after the TRUNCATE parameter in the formal parameter list and is present (explicitly with a null actual parameter or by being skipped over by a nonpositional actual parameter), then the list is not truncated at the TRUNCATE parameter. Any parameters after the TRUNCATE parameter must be present or have a default value.
In Example 10.1, “Using the TRUNCATE Attribute”, each call to procedure p in the main body of the program has a comment that shows the expected parameter list behavior and the expected output. The parameter list is truncated at either parameter a or parameter c.
PROGRAM Trunc( OUTPUT ); VAR w : CHAR VALUE 'w'; x : CHAR VALUE 'x'; y : CHAR VALUE 'y'; z : CHAR VALUE 'z'; PROCEDURE p( a : [TRUNCATE] CHAR := 'a'; b : CHAR := 'b'; c : [TRUNCATE] CHAR := 'c'; d : CHAR := 'd' ); BEGIN IF PRESENT( a ) THEN WRITE( a ); IF PRESENT( b ) THEN WRITE( b ); IF PRESENT( c ) THEN WRITE( c ); IF PRESENT( d ) THEN WRITE( d ); WRITELN; END; {In the executable section:} { CALL LIST RESULT } p; { NO PARAMETERS--TRUNCATE AT a "" } p(); { DEFAULT a AND b--TRUNCATE AT c "ab" } p(,); { DEFAULT a AND b--TRUNCATE AT c "ab" } p(,,); { DEFAULT a, b, c AND d "abcd" } p(,,,); { DEFAULT a, b, c AND d "abcd" } p( w ); { DEFAULT b--TRUNCATE AT c "wb" } p( w, x ); { TRUNCATE AT c "wx" } p( w, x, y ); { DEFAULT d "wxyd" } p( w, x, y, z ); { NO DEFAULTS "wxyz" } p( a := w ); { DEFAULT b--TRUNCATE AT c "wb" } p( b := x ); { DEFAULT a--TRUNCATE AT c "ax" } p( c := y ); { DEFAULT a, b AND d "abyd" } p( d := z ); { DEFAULT a, b AND c "abcz" }
For More Information:
On the PRESENT function (Section 8.69, “PRESENT Function ”)
On parameters (Section 6.3, “Parameters”)
10.2.38. UNALIGNED
The UNALIGNED attribute specifies that an object can be aligned on any bit boundary.
Usage and Default Information:
Alignment attributes are illegal on nonstatic types, components of files, and on VARYING OF CHAR strings.
An unaligned variable must have an allocation size that conforms to the rules for the platform.
A formal parameter cannot be unaligned so an unaligned variable cannot be passed to a formal variable parameter.
The base type of a pointer variable passed to the NEW procedure cannot have alignment greater than a quadword, nor can it be unaligned.
For More Information:
On allocation size attributes (Section 10.3, “Attribute Classes”)
On VSI Pascal alignment rules (Section A.2.7, “Alignment Boundaries”)
On allocation sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
10.2.39. UNBOUND
The UNBOUND attribute specifies that a routine does not access automatic variables outside the scope in which it is declared. That is, the bound procedure value of an unbound routine does not include the static scope pointer.
Usage and Default Information:
You can apply this attribute to routines and formal routine parameters.
In the absence of an UNBOUND attribute, the compiler assumes that the bound procedure value of a routine includes the static scope pointer.
By default, all predeclared routines and all routines declared at program or module level have the characteristics of unbound routines. All routines declared in nested blocks are considered bound unless they have an UNBOUND, GLOBAL, WEAK_GLOBAL, or INITIALIZE attribute.
All routines called from within the block of an unbound routine must be local to the unbound routine, or be unbound, whether by default or by an explicit attribute.
Nonlocal variables accessed from within the block of an unbound routine cannot have automatic allocation.
If a formal routine parameter is unbound, all actual routine parameters passed to it must also be unbound.
You can pass an unbound routine as an actual parameter to a formal routine parameter that is not unbound.
[EXTERNAL] FUNCTION f( [IMMEDIATE, UNBOUND] PROCEDURE Count ) : BOOLEAN; EXTERNAL; PROCEDURE a; VAR i : [STATIC] INTEGER; b : BOOLEAN; [UNBOUND] PROCEDURE p; BEGIN i := i + 1; {Additional statements...} END; b := f( p ); END;
This example shows the declaration of the unbound procedure p and the unbound formal procedure parameter Count. The executable section of p cannot access variables declared in the enclosing block of procedure a unless those variables are statically allocated. Procedure p can access the variable i, which is declared with the STATIC attribute, but it cannot access the variable b that is automatically allocated. Because the formal parameter Count is unbound, only other unbound routines (such as p) can be passed to function f as actual parameters. Count must be declared UNBOUND because it is passed by immediate value.
For More Information:
On the AUTOMATIC attribute (Section 10.2.5, “AUTOMATIC”)
On parameters (Section 6.3, “Parameters”)
10.2.40. UNSAFE
The UNSAFE attribute indicates that an object can accept values of any type without type checking. The exact properties of an unsafe object depend on the object's machine representation.
Usage and Default Information:
You can apply this attribute to variables, formal parameters, formal discriminants, the base types of pointer variables, components of structured variables, function results, and the types of other data items listed in Table 10.9, “Attributes on Data Items”.
A conformant VARYING parameter or a formal schema parameter cannot be declared UNSAFE.
UNSAFE is the only attribute allowed on schema formal discriminants.
- An expression of any type is assignment compatible with an unsafe object. However, neither the expression nor the object can contain a file component. If the machine representations of the expression and the unsafe object differ, the compiler forces them to have the same number of bits by modifying the value of the expression as follows:
Assignment to a variable with the UNSAFE attribute causes the value of the right-hand side to be truncated or zero-extended to the bit size of the left-hand variable. Note this can not always be its natural bit size; for example, if the variable you are assigning a value to was declared with an explicit size attribute. If that value is the legal value of the left-hand type, then the assignment occurs; otherwise, the variable is undefined.
The UNSAFE attribute has no effect on variable fetches.
Consider the following example:v : [LONG, UNSAFE] ( aa, bb, cc );
As an enumeration of less than 256 elements, its natural size can be less than a longword. Because of the LONG attribute, it is allocated a longword in memory. However, fetches from the variable might be smaller because the explicit size attribute has no effect on any fetches. Assignments correctly assign the natural size portion of V, but the contents of the extra bits are zero-extended at the assignment.
A pointer expression is assignment compatible with a pointer variable whose base type is unsafe only if the base types have the same allocation size and if they have compatible alignment, READONLY, VOLATILE, and WRITEONLY attributes.
You can pass an actual parameter variable to an unsafe formal VAR parameter if the types have the same allocation size and if they have compatible alignment, READONLY, VOLATILE, and WRITEONLY attributes.
When a formal parameter is an unsafe conformant array, the VSI Pascal compiler must be able to establish bounds for the corresponding actual parameter that exactly describe the amount of storage the parameter occupies. If the conformant array is one-dimensional, the actual parameter need not be an array. The compiler constructs the bounds of the formal array so that the actual parameter and the formal array have the same size.
For this construction to be possible, the size of the actual parameter must be an exact multiple of the size of the formal array component. The compiler chooses the low bound of the formal parameter's index to be the smallest possible value of the index type. If the formal conformant parameter is a multidimensional array with n dimensions, the actual parameter must be an array having no fewer than n −1 dimensions. The first n −1 dimensions of the two arrays will have identical array bounds. The compiler chooses bounds for the last dimension of the conformant array so that the conformant as a whole describes the exact size of the actual parameter.
VSI Pascal allows you to pass an actual parameter of a schema type to the an unsafe conformant array; however, because VSI Pascal cannot determine the size of the actual parameter until run time, you must be sure that the actual parameter is an exact multiple of the size of the formal array component.
PROGRAM Output_Buffer( Data_File ); TYPE Natural = 0..MAXINT; VAR Data_File : FILE OF ARRAY[0..511] OF CHAR; Int_Array : ARRAY[0..1023] OF INTEGER; A_String : VARYING[2048] OF CHAR; Chr_Array : ARRAY[0..4095] OF CHAR; Status : BOOLEAN; FUNCTION Put_Buf( VAR Buffer : [UNSAFE] ARRAY[ a..b : Natural ] OF CHAR ) : BOOLEAN; VAR Cur : [STATIC] INTEGER VALUE 0; i : INTEGER; BEGIN FOR i := a TO b DO BEGIN Data_File^[Cur] := Buffer[i]; Cur := Cur + 1; IF Cur > 511 THEN BEGIN PUT( Data_File); Cur := 0; END; END; Put_Buf := (Cur = 0); END; {In the executable section:} Status := Put_Buf( Int_Array ); Status := Put_Buf( A_String ); Status := Put_Buf( Chr_Array );
The function Put_Buf assigns successive components of the conformant array parameter to the file buffer variable of Data_File. If Data_File^ is filled, the function returns TRUE; otherwise, it returns FALSE.
The program issues three calls to Put_Buf. In the first and second calls, the actual parameters are not of the same type as the formal parameter Buffer. However, because Buffer has the UNSAFE attribute, it accepts an actual parameter of any type and treats it as though it were an array of characters. The third call to Put_Buf passes an actual parameter of the same type as the formal parameter.
For More Information:
On type compatibility (Section 2.10, “Type Compatibility”)
On machine representation of data (Section A.3, “Internal Representation of Data Types”)
10.2.41. VALUE
The VALUE attribute causes the variable to be a reference to an external constant or to be the defining point of a global constant.
Usage and Default Information:
You can only use the VALUE attribute on a variable that has the EXTERNAL or GLOBAL attribute.
A value variable with global visibility must be initialized in the VAR, TYPE, or VALUE declaration sections.
You cannot apply the VALUE attribute to variables larger than 64 bits.
The VALUE attribute is legal only on ordinal or real types.
The VALUE attribute causes the READONLY attribute to be placed on the variable.
PROGRAM Value_Test( OUTPUT ); VAR CLI$_PRESENT : [VALUE, EXTERNAL] INTEGER; My_Global : [VALUE, GLOBAL] INTEGER VALUE 1985; {In the executable section:} WRITELN( 'The value is', CLI$_PRESENT );
For More Information:
On the EXTERNAL attribute (Section 10.2.15, “EXTERNAL”)
On the GLOBAL attribute (Section 10.2.17, “GLOBAL”)
On the READONLY attribute (Section 10.2.34, “READONLY”)
10.2.42. VOLATILE
When another value is assigned to it
When it is passed as a writable VAR parameter
When it is read into by a READ, READLN, or READV procedure
When it is used as the control variable of a FOR loop
In addition, the compiler expects to evaluate the object only when it appears in an expression.
The value of a volatile object can change as the result of an action not directly specified in the program. Thus, the compiler assumes that the value of a volatile object can be changed or evaluated at any time during program execution. Consequently, a volatile object does not participate in any optimization based on assumptions about its value.
The behavior of many device registers, and modifications by asynchronous processes and exception handlers, are two examples that demonstrate volatile behavior.
Usage and Default Information:
You can apply this attribute to variables, formal parameters, the base types of pointer variables, components of structured variables, and function results.
By default, objects are not volatile.
An object of a structured type that has a volatile component is volatile as a whole. However, the presence of a volatile component does not make other components of the same variable volatile.
The presence of the VOLATILE attribute guarantees that operations are performed on scalar objects in an atomic fashion. Because operations on structured objects can require many more instructions, the use of the VOLATILE attribute on an object of a structured type can not produce the expected results, if the data is accessed asynchronously.
A volatile variable is structurally compatible only with a formal variable parameter that is volatile. The compiler does not allow a volatile variable to be passed to a nonvolatile formal VAR parameter because the called routine did not guarantee that it could handle volatile parameters.
Formal VAR parameters with the VOLATILE attribute can accept both volatile and nonvolatile actual parameters; treating a nonvolatile variable as volatile never produces the wrong answer.
A pointer expression whose base type is volatile is assignment compatible only with a pointer variable whose base type is volatile.
Two pointer types are structurally compatible only if their base types have identical volatility.
The VOLATILE attribute ensures true atomic accesses for bytes, aligned words, aligned longwords, and aligned quadwords. For unaligned words, unaligned longwords, or unaligned quadwords that are marked VOLATILE, the compiler will issue a warning message indicating that the resulting code sequence is not an atomic sequence and contains a timing window where incorrect results can occur if an asychronous thread writes to the unaligned volatile storage.
See the VSI Pascal User Manual for information on how to enable/disable the message.
VOLATILE accesses of items larger than 64 bits (strings, entire records, entire arrays, and other such items) have never been atomic in nature and are not flagged by the compiler. The VOLATILE attribute ensures atomic access for all objects 32 bits or less.
Actual |
Formal Parameter | ||
---|---|---|---|
Parameter |
VAR |
VAR [VOLATILE] |
[VOLATILE] |
Volatile |
No |
Yes |
Yes |
Nonvolatile |
Yes |
Yes |
Yes |
VAR x : CHAR; a : [VOLATILE] RECORD CASE BOOLEAN OF FALSE : ( i : INTEGER ); TRUE : ( c : CHAR ); END; {In the executable section:} a.c := 'A'; {TRUE becomes the current variant} a.i := 66; {Assignment makes FALSE the current variant} x := a.c; {TRUE is again the current variant; X is assigned the value 'B', which has an ordinal value of 66}
As the comments in this example show, a reference to one field identifier causes the corresponding variant to become the current variant. In addition, each reference immediately causes the other variant to become undefined. So, when the assignment a.i := 66 is made, the reference to a.i causes FALSE to become the current variant and a.c to become undefined. As a result of the statement x := a.c, the value last assigned to the variant is assigned to x. Ordinarily the compiler could assume that a.c had retained the value ’A ’, because no further assignments had been made directly to a.c. However, the value of a.c changed unexpectedly through the assignment to a.i. Therefore, unless the record a is declared VOLATILE, the result of the assignment x := a.c would be undefined because the compiler's legitimate assumptions had been incorrect.
PROGRAM Volatility( OUTPUT ); VAR Pint : ^[VOLATILE] INTEGER; i : INTEGER; j : [VOLATILE] INTEGER; a : ARRAY[0..10] OF INTEGER; {In the executable section:} NEW( Pint ); i := 0; j := 0; Pint^ := 0; {Compiler may assume i = 0, makes no assumptions about j} WRITELN( i, j, Pint^, a[i] ); {Values are 0, 0, 0, a[0] } Pint := ADDRESS( j ); {Pint^ now = j} Pint^ := 1; {Therefore j now = 1} {Compiler may assume i = 0, makes no assumptions about j} WRITELN( i, j, Pint^, a[i] ); {Values are 0, 1, 1, a[0]} Pint := ADDRESS( i ); {Causes a warning message because i is not VOLATILE} Pint^ := 2; {Compiler may assume i = 0 and a[I] = a[0], May make no assumptions about j} WRITELN( i, j, Pint^, a[i] ); {Actual values are 2, 1, 2, a[2]}
This example assigns values to the variables i and j and to the newly created variable Pint^. The comments show the difference between the assumptions the compiler can legally make about the values of the variables and the values actually contained in the variables. The compiler's assumption about the value of i was incorrect because the value of i changed unexpectedly. The ADDRESS( i ) call caused Pint to point to i (that is, Pint^ and i became the same variable). When Pint^ was assigned the value 2, the variable i also received the value 2. Since i had been initialized to 0 and was not directly referred to in the rest of the program, the compiler assumed that a reference to i at this point would be equivalent to a reference to 0. Likewise, the compiler also assumed that a reference to a[i] would be equivalent to a reference to a[0]. However, when execution ceases, the value of i is 2 and the value of a[i] is the value of a[2].
Depending on the optimizations the compiler made based on the value of i, any operations performed after the unanticipated assignment to i could yield unexpected results. Because j was declared VOLATILE, the compiler did not optimize code based on the value of j. Therefore, any reference to j yields the expected results.
The ADDRESS( i ) call in this program causes a warning message. The VSI Pascal compiler assumes that pointer variables point only to variables in heap-allocated storage and not to statically allocated, nonvolatile variables such as i. So, ADDRESS( i ) in this case differs from the expected usage.
For More Information:
On use of VOLATILE with the ASYNCHRONOUS attribute (Section 10.2.3, “ASYNCHRONOUS”)
On exception handlers (VSI Pascal User Manual)
On volatility (VSI Pascal User Manual)
10.2.43. WEAK_EXTERNAL
The WEAK_EXTERNAL attribute specifies that a variable or routine is not critical to the linking operation. To resolve a weak reference, the linker searches only the named input modules. You can specify an identifier with this attribute to indicate the name by which the corresponding object is known to the linker.
{identifier } [ WEAK_EXTERNAL [[ ( {'string-literal' } ) ]] ] { }
identifier
Identifier passed to the linker. If you omit the identifier, the name of the variable is used as the name of the common block.
string-literal
Passes the specified string-literal to the linker unmodified.
Compilation units cannot have the EXTERNAL or WEAK_EXTERNAL attribute.
For More Information:
On the EXTERNAL attribute (Section 10.2.15, “EXTERNAL”)
On linking (VSI Pascal User Manual)
10.2.44. WEAK_GLOBAL
The WEAK_GLOBAL attribute specifies that an object is linked only when it is specifically included in the linking operation. To resolve a weak reference, the linker searches only the named input modules. You can specify an identifier to indicate the name by which the corresponding object is known to the linker.
{identifier } [ WEAK_GLOBAL [[ ( {'string-literal' } ) ]] ] { }
identifier
Identifier passed to the linker. If you omit the identifier, the name of the variable is used as the name of the common block.
string-literal
Passes the specified string-literal to the linker unmodified.
For More Information:
On the GLOBAL attribute (Section 10.2.17, “GLOBAL”)
On linking (VSI Pascal User Manual)
10.2.45. WORD
WORD [[ ( n )]]
The optional constant n indicates the number of word storage units.
For More Information:
On allocation sizes of objects (Section A.2.4, “Allocation Sizes of Variables”)
On size attribute restriction (Section 10.2.6, “BIT”)
10.2.46. WRITEONLY
The WRITEONLY attribute specifies that an object can have values assigned to it but cannot be read by a program.
Usage and Default Information:
You can apply this attribute to variables, formal parameters, the base types of pointer variables, and components of structured variables.
By default, objects can be both read and written.
A write-only object cannot be used in expressions.
A write-only component in an object of a structured type prohibits the object from being read.
A write-only actual variable parameter can be passed only to a formal variable parameter that is write-only.
A pointer expression whose base type is write-only is assignment compatible only with a pointer variable whose base type is write-only.
PROGRAM SAMPLE; TYPE W_Only = [WRITEONLY] INTEGER; VAR Writ_Int : W_Only; Norm_Int : INTEGER; PROCEDURE Try_Access( VAR Write_Param : W_Only ); EXTERNAL; {In the executable section:} Writ_Int := SQR( Norm_Int ); Try_Access( Writ_Int );
This example shows legal statements involving write-only variables. The write-only variable Writ_Int is assigned the result of the square root operation, and is then passed as an actual parameter to a write-only formal parameter.
For More Information:
For information on the READONLY attribute (Section 10.2.34, “READONLY”)
10.3. Attribute Classes
Class |
Attributes |
Description of Attributes |
---|---|---|
Alignment |
ALIGN, ALIGNED, UNALIGNED |
Indicate whether the object should be aligned on a specific address boundary in memory. |
Allocation |
AT, AUTOMATIC, COMMON, STATIC, PSECT |
Indicate the form of storage that the object should occupy. |
Asynchronous |
ASYNCHRONOUS |
Indicates that the routine can be called by an asynchronous event, such as a condition handler. |
Check |
CHECK |
Indicates error-checking options to be enabled or disabled. |
Double precision |
FLOAT |
Indicates the type of precision to use for objects of type DOUBLE. |
Enumeration |
ENUMERATION_SIZE |
Indicates the sizes used for enumerated types and Boolean types. |
Environment |
ENVIRONMENT, PEN_CHECKING_STYLE |
Indicate that VSI Pascal creates an environment file, which allows compilation units to share data definitions and declarations. |
Hidden |
HIDDEN |
Indicates exclusion of a declaration or definition from a created environment file. |
Ident |
IDENT |
Indicates the identification of a compilation unit to be passed to the linker. |
Inherit |
INHERIT |
Indicates that the compilation unit can use the definitions and declarations specified in the inherited environment file. |
Initialize |
INITIALIZE |
Indicates that the procedure is to be called before execution of the main program. |
Key |
KEY |
Indicates key information for a record field that is used when accessing data in an indexed file. |
List |
LIST |
Indicates that the routine can be called with actual parameter lists of various lengths. |
Optimization |
OPTIMIZE, NOOPTIMIZE |
Indicate whether VSI Pascal should optimize code. |
Parameter passing |
CLASS_A, CLASS_NCA, CLASS_S, IMMEDIATE, REFERENCE |
Indicate the passing mechanism to be used for a parameter. |
Position |
POS |
Indicates that a record field should be forced to a specific bit position. |
Read-only |
READONLY |
Indicates that the object can be read but cannot be written to. |
Size |
BIT, BYTE, WORD, LONG, QUAD, OCTA |
Indicate the amount of storage to be reserved for the object. |
Truncate |
TRUNCATE |
Indicates that the actual parameter list can be truncated at the position of this attribute in the formal parameter list. |
Unbound |
UNBOUND |
Indicates that the routine does not access automatic variables outside its scope. |
Unsafe |
UNSAFE |
Indicates that an object can accept values of any type without type checking. |
Value |
VALUE |
Indicates that the variable is a reference to an external constant or is the defining point of a global constant. |
Visibility |
LOCAL, EXTERNAL, GLOBAL, WEAK_EXTERNAL, WEAK_GLOBAL |
Indicate the ability of an object to be shared by compilation units. |
Volatile |
VOLATILE |
Indicates that the value of an object can change at unusual points in program execution. |
Write-only |
WRITEONLY |
Indicates that the object can be written to but cannot be read. |
Class |
Program Element | ||
---|---|---|---|
Routine Parameter |
Routine |
Compilation Unit | |
Allocation |
No |
Yes? |
Yes? |
Asynchronous |
Yes |
Yes |
No |
Check |
No |
Yes |
Yes |
Double precision |
No |
No |
Yes |
Enumeration |
No |
No |
Yes |
Environment |
No |
No |
Yes |
Ident |
No |
No |
Yes |
Inherit |
No |
No |
Yes |
Initialize |
No |
Yes |
No |
List |
Yes? |
No |
No |
Optimization |
No |
Yes |
Yes |
Truncate |
Yes |
No |
No |
Unbound |
Yes |
Yes |
No |
Visibility |
No |
Yes |
Yes? |
Class |
Data Item | |||||
---|---|---|---|---|---|---|
Variable |
Formal Parameter |
Pointer Base Type |
Component? |
Function Result |
Various Items? | |
Alignment |
Yes? |
Yes? |
Yes? |
Yes? |
Yes |
No |
Allocation |
Yes? |
No |
No |
No |
No |
No |
Hidden |
Yes |
No |
Yes |
No |
No |
No |
Key |
No |
No |
No |
Yes? |
No |
No |
List |
No |
Yes? |
No |
No |
No |
No |
Parameter passing |
No |
Yes? |
No |
No |
No |
No |
Pos |
No |
No |
No |
Yes? |
No |
No |
Read-only |
Yes |
Yes |
Yes |
Yes |
No |
No |
Size |
Yes? |
Yes? |
Yes |
Yes? |
Yes |
No |
Truncate |
No |
Yes |
No |
No |
No |
No |
Unsafe ? |
Yes |
Yes? |
Yes |
Yes |
Yes |
Yes |
Value |
Yes? |
No |
No |
No |
No |
No |
Visibility ? |
Yes |
No |
No |
No |
No |
No |
Volatile |
Yes |
Yes |
Yes |
Yes |
Yes |
No |
Write-only |
Yes |
Yes |
Yes |
Yes |
No |
No |
Chapter 11. Directives
Your source code can contain embedded directives, which will be evaluated at compile time. These directives can appear in any column and do not have to be on a line by themselves. You can use directives to control your compilation, and to extract immediate information at compile time.
Directives |
Section |
---|---|
%INCLUDE | |
%DICTIONARY | |
%TITLE and %SUBTITLE | |
%IF, %ELSE, %ELIF, and %ENDIF | |
%DEFINED | |
%ERROR, %WARN, %INFO, and %MESSAGE | |
%ARCH_NAME, %SYSTEM_NAME, and %SYSTEM_VERSION | |
%DATE, %TIME, and %COMPILER_VERSION | |
%LINE, %FILE, %ROUTINE, %MODULE, and %IDENT | |
%FLOAT, %F_FLOAT, %D_FLOAT, %G_FLOAT, %S_FLOAT, and %T_FLOAT | 11.10 |
11.1. %INCLUDE
%INCLUDE 'file-spec [[/[[NO]]LIST]]'
file-spec
The name of the file to be included.
/[[NO]]LIST
The /LIST qualifier indicates that the included file should be printed in the listing of the program if a listing is being generated.
If you do not specify the /LIST qualifier, the default is determined by the use of compilation switches. Use of this parameter overrides compilation switches.
This directive can appear anywhere that a comment is legal.
In the following example, the %INCLUDE directive specifies the file CONDEF.PAS, which contains constant definitions:
In the Program:
PROGRAM Student_Courses( INPUT, OUTPUT, Sched ); CONST %INCLUDE 'CONDEF.PAS/LIST' TYPE Schedules = RECORD Year : ( Fr, So, Jr, Sr ); Name : PACKED ARRAY[1..30] OF CHAR; Parents : PACKED ARRAY[1..40] OF CHAR; College : ( Arts, Engineering, Architecture, Agriculture, Hotel ); END;
File CONDEF.PAS:
Max_Class = 300; N_Profs = 140; Frosh = 3000;
PROGRAM Student_Courses( INPUT, OUTPUT, Sched ); CONST Max_Class = 300; N_Profs = 140; Frosh = 3000; TYPE Schedules = RECORD Year : ( Fr, So, Jr, Sr ); Name : PACKED ARRAY[1..30] OF CHAR; Parents : PACKED ARRAY[1..40] OF CHAR; College : ( Arts, Engineering, Architecture, Agriculture, Hotel ); END;
You can use the %INCLUDE directive in another included file; however, two files cannot attempt to include each other.
A file included at the outermost level of a program is said to be included at the first level. A file included by a first-level file is said to be included at the second level, and so on. In general, a program may not include any files beyond the fifth level; it may not include any files beyond the fourth level if you have included a %DICTIONARY directive in the fourth level. Nesting levels may be further restricted by the number of files you are allowed to have open at one time.
Figure 11.1, “%INCLUDE File Levels” shows the legal levels of included files.

For More Information:
On the Oracle CDD/Repository (CDD) ( Section 11.2, “%DICTIONARY”)
On default file specifications and on including text libraries ( VSI Pascal User Manual)
11.2. %DICTIONARY
%DICTIONARY 'cdd-path-name [[/[[NO]]LIST]] '
cdd-path-name
A character string that represents the full or relative path name of a CDD record description to be extracted. The resulting path name must conform to the rules for forming CDD path names.
A full path name is one that begins with CDD$TOP and specifies the names of all its descendants; it is a complete path to the record definition. Descendant names are separated from each other by a period.
A relative path name begins with any generation other than CDD$TOP, and specifies the names of the descendants after that point. You can create a relative path by establishing a default directory with a logical name.
/[[NO]]LIST
Indicates that the included declarations should be printed in the listing of the program if a listing is being generated. If not specified, the default is determined by compilation switches. Use of this parameter overrides compilation switches.
For More Information:
On using the Oracle CDD/Repository with VSI Pascal (VSI Pascal User Manual)
11.3. %TITLE and %SUBTITLE
%TITLE and %SUBTITLE allow you to specify a compile-time string expression for the listing title and subtitle lines; they have the following form:
%TITLE 'character string' %SUBTITLE 'character string'
The compiler listing header includes the %TITLE and %SUBTITLE strings in the title and subtitle sections. If you do not specify these directives, VSI Pascal fills the %TITLE field with blanks and the first %SUBTITLE field with ’source listing ’. If a specified character string is too long to fit in the predefined title and subtitle sections, the string will be truncated on the right without warning.
If a %TITLE directive appears on the first line of a page, it sets the title area for the current page and any following pages until the compiler encounters another %TITLE directive. If the %TITLE directive does not appear on the first line of a page, then the title area is not set until the next page.
The %SUBTITLE directive affects only the subtitle area in the source listing section. If a %SUBTITLE directive appears on the first or second line of a page, then the subtitle area is set for the current page. If the %SUBTITLE directive does not appear in the first two lines of a page, then the subtitle area is not set until the next page.
On OpenVMS VAX systems, if either of these directives is used and if a listing is being generated, VSI Pascal generates a table of contents page by default. It appears first in the listing, preceding the source listing section. To disable the table of contents option, you must use a compilation switch.
For More Information:
On creating listings and on using compilation switches (VSI Pascal User Manual)
11.4. %IF, %ELSE, %ELIF, and %ENDIF
The %IF family of directives is used to conditionally compile specified sections of source code. These directives are useful if you need to compile the same source code for various configurations or environments.
The %IF directive family has the following syntax:
%IF compile-time-expression %THEN Pascal tokens . . . [%ELIF compile-time-expression %THEN Pascal tokens . . . ] . . . [%ELSE Pascal tokens . . . ] %ENDIF
A %IF directive can have zero or more %ELIF parts and zero or one %ELSE parts.
%IF directives can be nested up to 32 deep.
Note that skipped sections of source code must still be valid VSI Pascal tokens. The skipped tokens are not processed semantically by the compiler except for control expressions of nested %IF directives. All control expressions are semantically processed to ensure they result in a Boolean result. %INCLUDE and %DICTIONARY directives encountered while skipping tokens do not attempt to open the file name or access the dictionary path. Instead, they return the token TRUE.
CONST Debug_Flag := true; { or false } VAR I : integer; I := %IF Debug_Flag %THEN 12 %ELSE 1 %ENDIF; %IF Debug_Flag %THEN writeln('Debug: the value of I is ',i:2); %ENDIF
TYPE Configs = (Config1, Config2, Config3); CONST Config = Config1; { or Config2 or Config3 } %IF Config = Config1 %THEN { Code for Config1... } %ELIF Config = Config2 %THEN { Code for Config2... } %ELSE Config = Config3 { Code for Config3...} %ENDIF
Note that the compile-time expression for the %IF statement is the same compile-time expression that can be used anywhere in VSI Pascal. You can use any operator or builtin routine in a %IF control expression, as you can in any constant expression.
One use of %IF is to compile for various configurations or environments (as shown in the preceding example).
Rather than defining a constant in the Pascal source as shown in the examples here, you might want to define the constant from the command line with the /CONSTANT qualifier. See the description of the /CONSTANT qualifier for more information.
11.5. %DEFINED
%IF %DEFINED(X) %THEN writeln(x); %ENDIF
11.6. %ERROR, %WARN, %INFO, and %MESSAGE
These directives will accept one or more string expressions, and at compile time will produce an error message, warning message, informational message, or terminal-only output (respectively).
The syntax is as follows:
%ERROR ( string-expression, . . . ) %WARN ( string-expression, . . . ) %INFO ( string-expression, . . . ) %MESSAGE ( string-expression, . . . )
TYPE Some_Type = ...; %IF SIZE(Some_Type) > 8 %THEN %ERROR ('We do not handle types greater than 8 bytes') %ENDIF
%IF Config = Config1 %THEN { Code for Config1... } %ELIF (Config = Config2) or (Config = Config3) %THEN { Code for Config2/Config3... } %ELSE %WARN ('Config not supported, defaulting to generic') { Code for generic config... } %ENDIF
%IF Debug_Mode %THEN %INFO('Building application with debug code inserted') %ENDIF
%IF DEBUG_MODE %THEN %MESSAGE ('Debug-mode is enabled') %ENDIF
11.7. %ARCH_NAME, %SYSTEM_NAME, and %SYSTEM_VERSION
%ARCH_NAME returns a string containing “IA64”, “Alpha”, or “x86-64” depending on the architecture of the system on which the compilation is taking place.
%SYSTEM_NAME returns a string containing “OpenVMS”.
%SYSTEM_VERSION returns a string containing the value of SYI$_VERSION from the $GETSYI system service.
program example(output); begin writeln('Program running on ',%system_name, ' ',%arch_name, ' ',%system_version); end.
%if %arch_name = "Alpha" %then var handle : integer := 0; %elif %arch_name = "IA64" %then var handle : integer64 := 0; %endif
11.8. %DATE, %TIME, and %COMPILER_VERSION
%DATE returns a string containing the date at the beginning point of the compilation.
%TIME returns a string containing the time at the beginning point of the compilation.
%COMPILER_VERSION returns a string containing the version string of the VSI Pascal compiler performing the compilation.
11.9. %LINE, %FILE, %ROUTINE, %MODULE, and %IDENT
%LINE returns an integer that denotes the current line number in the source file.
%FILE returns a string containing the file name that is currently being compiled. The string contains a full VSI OpenVMS file specification including the disk, directory, file name, file type, and version fields.
%ROUTINE returns a string with the name of the routine that is currently being compiled. If used in the executable portion of a program, the program's name is returned. If used in the declaration section of a MODULE/PROGRAM, the name of the MODULE/PROGRAM is returned.
%MODULE returns a string containing the name of the module/program that is currently being compiled.
%IDENT returns a string that contains the ident string of the compilation that is set with the [IDENT()] attribute.
11.10. %FLOAT, %x_FLOAT
The %FLOAT directive expands to either "VAX_FLOAT" or "IEEE_FLOAT" depending on the setting of the /FLOAT DCL qualifier or the [FLOAT] module-level attribute.
The %F_FLOAT, %D_FLOAT, %G_FLOAT, %S_FLOAT, and %T_FLOAT will create floating point literals of the specified type regardless of the current default floating type. For example, you can do the following:
lib$wait(%f_float 1.0);
Appendix A. Data Storage and Representation
Program sections (Section A.1, “Program Sections”)
Storage allocation and alignment for variables (Section A.2, “Storage Allocation”)
Internal representation of data types (Section A.3, “Internal Representation of Data Types”)
A.1. Program Sections
This chapter describes how to establish program sections and program section properties. The VSI Pascal compiler uses contiguous areas of memory, called program sections, to store information about a program.
The compiler writes these program sections to the object file. When constructing an executable image, the OpenVMS Linker divides the image into sections. Each image section contains program sections that have the same properties. The linker controls memory allocation by arranging image sections according to program section properties. You can use special linker options to change program section properties and to influence the memory allocation in the image. You include these options in a linker options file, which is input to the linker.
The OpenVMS Linker refers to the various characteristics of program sections as attributes. This chapter uses the term properties to avoid confusion with the VSI Pascal attribute classes.
Property | Description |
---|---|
PIC/NOPIC |
Position independent or position dependent |
CON/OVR |
Concatenated or overlaid |
REL/ABS |
Relocatable or absolute |
GBL/LCL |
Global or local scope |
EXE/NOEXE |
Executable or nonexecutable |
RD/NORD |
Readable or nonreadable |
WRT/NOWRT |
Writable or nonwritable |
SHR/NOSHR |
Shareable or nonshareable |
For More Information:
On program sections and linker options (VSI OpenVMS Linker Utility Manual)
A.1.1. Establishing Program Sections
Program Section |
Data |
---|---|
$ABS$ |
No data is allocated in this program section. It is used for defining global literals (variables declared with the GLOBAL and VALUE attributes). |
$BSS$ |
Zeroed static storage. |
$CODE$? |
Machine instructions. |
$DATA$ |
Nonexternal static types; writable variables declared with the STATIC attribute; writable variables that use default allocation and are declared at program or module level of a nonoverlaid compilation unit. All such variables must be larger than 64 bits in size. |
LIB$INITIALIZE |
Addresses of routines declared with the INITIALIZE attribute and compiler-generated routines to perform module initialization. |
$LINK$ |
Small literals. |
$LITERAL$? |
Constants needing storage; nonvolatile, readonly, static variables. |
Program Section |
Data |
---|---|
$ABS$ |
No data is allocated in this program section. It is used for defining global literals (variables declared with the GLOBAL and VALUE attributes). |
$BSS$ |
Zeroed static storage. |
$CODE$? |
Machine instructions. |
$DATA$ |
Nonexternal static types; writable variables declared with the STATIC attribute; writable variables that use default allocation and are declared at program or module level of a nonoverlaid compilation unit. |
LIB$INITIALIZE |
Addresses of routines declared with the INITIALIZE attribute and compiler-generated routines to perform module initialization. |
$LINK$ |
Procedure descriptors and small literals. |
$LITERAL$? |
Constants needing storage; nonvolatile, readonly, static variables. |
Program Section |
Data |
---|---|
$ABS$ |
No data is allocated in this program section. It is used for defining global literals (variables declared with the GLOBAL and VALUE attributes). |
$BSS$ |
Zeroed static storage. |
Machine instructions. | |
LIB$INITIALIZE |
Addresses of routines declared with the INITIALIZE attribute and compiler-generated routines to perform module initialization. |
$LINK$ |
Small literals. |
.rodata? |
Constants needing storage; nonvolatile, readonly, static variables. |
You can also establish user-defined program sections with the VSI Pascal PSECT and COMMON attributes. The PSECT attribute directs the compiler to establish a separate program section for static variables or executable blocks. In this way, you can ensure particular program section properties for these objects. You can also choose to group them with related static variables and blocks to reduce the amount of paging overhead.
The COMMON attribute directs the compiler to establish a particular program section called a common block. A common block is an overlaid program section that contains one variable. By storing variables in common blocks, a VSI Pascal program can share variables with programs written in other VSI languages.
The following example uses a common block to pass information between VSI Pascal and VSI Fortran:
VSI Pascal for OpenVMS Program:
PROGRAM Common_Example (OUTPUT); VAR Myrec : [COMMON(Example)] RECORD Intfld : INTEGER; Strfld : PACKED ARRAY [1..10] OF CHAR; END; [EXTERNAL] PROCEDURE Call_Fort; EXTERNAL; BEGIN Myrec := ZERO; Call_Fort; WRITELN('Intfld = ',Myrec.Intfld); WRITELN('Strfld = ',Myrec.Strfld); END.
VSI Fortran Subroutine:
SUBROUTINE CALL_FORT C STRUCTURE /TEST/ INTEGER*4 ITEM CHARACTER * 10 ITEM_NAME END STRUCTURE C RECORD /TEST/ VAR COMMON /EXAMPLE/ VAR C VAR.ITEM = 10 VAR.ITEM_NAME = '0123456789' END
The VSI Pascal program initializes the common record, Myrec, to zero, then calls the VSI Fortran routine, Call_Fort, to assign the desired values to the elements within the common record. The VSI Pascal program then writes the assigned values to your terminal.
Only one variable can be allocated in a particular VSI Pascal common block. To share more than one data item in the same common block, the record variable containing all shareable items is declared and used.
For More Information:
On the PSECT and COMMON attributes (Chapter 10, Attributes)
A.1.2. Establishing Program Section Properties
The first time the compiler encounters the name of a particular program section (including a common block), it initializes the program section to be readable, nonwritable, shareable, and nonexecutable. Thus, the program section's initial properties are LCL, NOEXE, NOWRT, CON, PIC, RD, REL, and SHR.
If storage for any writable object (except common blocks on OpenVMS VAX) is allocated in the same program section, the program section instantly becomes writable and nonshareable. Thus, the program section's write property changes from NOWRT to WRT, and its share property changes from SHR to NOSHR.
On OpenVMS VAX, if storage for a writable object in a common block is allocated in the same program section, the program section becomes writable and retains the shareable property. Thus, the program section's write property changes from NOWRT to WRT, and its share property remains SHR.
f you want to guarantee that read-only variables can never be modified, you can allocate storage exclusively for them in a separate program section that will always remain nonwritable.
A.2. Storage Allocation
The following sections discuss storage allocation of variables, symbolic constants, and executable blocks. Static types require no allocation. Nonstatic data types require allocation to store possible run-time values. Section A.2.3, “Allocation Example” gives an example.
For More Information:
On allocation for nonstatic data types (Section A.2.1, “Allocation of Variables”)
A.2.1. Allocation of Variables
If the variable is declared with an allocation attribute, the attribute specifies the variable's allocation.
If the variable is declared with a visibility attribute other than LOCAL, its allocation is static.
If the variable is declared in a routine, its allocation is automatic.
If the variable is declared at the outermost level of a module, its allocation is static.
If the variable is declared at the outermost level of a program, the compiler must choose between static and automatic allocation. Whenever possible, the compiler uses automatic allocation for variables that are referred to only in the body of the main program because automatic allocation is more efficient. The compiler uses static allocation if the variable is declared with the VOLATILE attribute, initialized at its declaration, referred to in a nested block, or if the program has an ENVIRONMENT attribute. Because program-level variables can be statically allocated, VSI Pascal does not support recursive calls on the main program block.
If the variable has the COMMON attribute, storage is allocated in a common block that has either the same name as the variable, or the name specified by the identifier that accompanies the attribute.
If the variable has the PSECT attribute, the identifier that accompanies the attribute supplies the name of the program section in which storage is to be allocated.
If the variable does not have the COMMON, PSECT, or STATIC attribute, but is declared at the outermost level of an overlaid compilation unit, storage is allocated in the program section PAS$GLOBAL.
If the variable has the READONLY attribute but does not have the PSECT, COMMON, or VOLATILE attributes, its storage is allocated in the program section $LITERAL$ on OpenVMS Alpha and OpenVMS I64 systems; on OpenVMS x86-64 systems, its storage is allocated in the program section .rodata.
All other static variables are allocated in the program section $DATA$.
For More Information:
On attributes (Chapter 10, Attributes)
A.2.2. Allocation of Symbolic Constants and Executable Blocks
When allocating storage for symbolic constants and executable blocks, the compiler determines the appropriate program section by applying the same rules of scope to program section names that it applies to identifiers. The compiler always allocates storage in the program section whose name appeared in the most recent heading of a routine or compilation unit.
Table A.3, “Program Section Data on VSI OpenVMS Alpha Systems” and Table A.4, “Program Section Data on OpenVMS x86-64 Systems” describe the program sections established for each kind of data in a program unless a PSECT attribute appears in the heading of routine or compilation unit and directs that storage to be allocated in a different program section.
For More Information:
On the scope of VSI Pascal identifiers (Section 7.2, “Scope of Identifiers”)
On the PSECT attribute (Section 10.2.32, “PSECT”)
On the INITIALIZE attribute (Section 10.2.22, “INITIALIZE”)
On LIB$INITIALIZE (VSI OpenVMS Programming Concepts Manual)
A.2.3. Allocation Example
PROGRAM Allocate_Variables (INPUT,OUTPUT); CONST Message_String = 'Random String Literal'; { $LITERAL$ on OpenVMS I64 } { $LITERAL$ on OpenVMS Alpha } { .rodata on OpenVMS x86-64 } VAR Magic_Number : [READONLY,PSECT(Magic)] INTEGER VALUE 42; { Magic } Local_Variable : INTEGER; { $SDATA$ on OpenVMS I64 } { $DATA$ on OpenVMS Alpha } { $DATA$ on OpenVMS x86-64 } [PSECT(Error_Routines)] PROCEDURE User_Error; CONST User_Error_Message = 'Internal Error'; { Error_Routines } VAR Error_Count : [STATIC] INTEGER VALUE 0; { $SDATA$ on OpenVMS I64 } { $DATA$ on OpenVMS Alpha } { $DATA$ on OpenVMS x86-64 } Message_Buffer : VARYING [132] OF CHAR; { Automatic Storage } BEGIN { Error_Routines } Error_Count := Error_Count + 1; Local_Variable := Error_Count; END; BEGIN { $CODE or $CODE$ } . . . END.
Storage for all variables with static allocation is allocated in $SDATA$, $DATA$. Storage for the executable block of the main program is allocated in $CODE or $CODE$. Storage for the symbolic constant Message_String is allocated in $LITERAL$ on VSI OpenVMS I64 and VSI OpenVMS Alpha systems and in .rodata on VSI OpenVMS x86-64 systems. Storage is allocated in the user-created program section, Error_Routines, for the symbolic constant User_Error_Message and the executable block of User_Error. Storage for Local_Variable is in $SDATA$ on VSI OpenVMS I64 systems, $DATA$ on VSI OpenVMS Alpha and VSI OpenVMS x86-64 systems because it is referred to in a nested block. Storage for Magic_Number is in the user-created program section, Magic. Since Magic_Number was declared with the READONLY attribute, the program section has the NOEXE, NOWRT, RD, and SHR properties.
A.2.4. Allocation Sizes of Variables
For every VSI Pascal data type, the compiler calculates the allocation size required when a variable of the type occurs in either an unpacked or a packed context. The unpacked size is always represented in bytes, while the packed size is represented in bits.
A component whose length is 32 bits or fewer is packed into as few bits as possible and can be unaligned.
A component whose length is greater than 32 bits is allocated the smallest number of bytes possible and must be at least byte aligned.
If one of the size attributes (BIT, BYTE, WORD, LONG, QUAD, or OCTA) is applied to the variable, the size specified by the attribute represents the variable's packed size. Objects of floating point or pointer types must have a size equal to their allocation size. Ordinal types cannot exceed their maximum size, which is determined by the platform and the value of the data switch for the compile command. If no size attribute is applied to the variable, the compiler calculates the unpacked size so that it is structurally compatible with the base type of the variable's type.
Storage for variables of type VARYING OF CHAR is allocated as one byte per character, with an initial field of two bytes to indicate the total length. Storage allocation for a variable of type VARYING OF CHAR whose maximum length is less than or equal to 32 bits follows the 32-bit rules in that the variable can be unaligned. Variables of type VARYING OF CHAR that need alignment are aligned on a word boundary.
Structured objects (ARRAY and RECORD) take their maximum alignment from their components, for example, if the largest object is a word, the structure is aligned on a word boundary.
The maximum size for any variable is 2 31-1 bits.
A.2.5. Storage Allocation of Types
Data Type |
Unpacked Size in Bytes |
Packed Size in Bits |
---|---|---|
|
4 |
32 |
|
8 |
64 |
CHAR |
1 |
8 |
BOOLEAN |
1 or 4? |
1 |
Enumerated? |
1, if 256 elements or fewer; 2, if more than 256 elements, or 4? |
log2 (number of elements )? + 1 |
Subrange |
The size of the base type |
If either the upper or lower bounds contain a reference to a formal discriminant, then the size of the base type, otherwise the minimum number in which the upper and lower bounds can be expressed? |
REAL or SINGLE |
4 |
32 |
DOUBLE |
8 |
64 |
QUADRUPLE |
16 |
128 |
Pointer |
4 or 8? |
32 or 64? |
Unpacked ARRAY |
The sum of the unpacked sizes in bytes of all components, plus the sum of the sizes in bytes of any holes created to meet alignment requirements |
Unpacked size in bytes * 8 |
Unpacked RECORD |
The sum of the unpacked sizes in bytes of the fields in the fixed part and the largest variant, plus the sum of the sizes in bytes of any holes created to meet alignment requirements |
Unpacked size in bytes * 8 |
PACKED ARRAY |
The sum of the packed sizes in bits of all components, plus the sum of sizes in bits of any holes created to meet alignment requirements; this sum is rounded up to a multiple of 8 and then divided by 8 |
The sum of the packed sizes in bits of all components, plus the sum of sizes in bits of any holes created to meet alignment requirements; if the sum is greater than 32, the sum is rounded up to the next multiple of 8 |
PACKED RECORD |
The sum of the packed sizes in bits of all fields in the fixed part and the largest variant, plus the sum of sizes in bits of any holes created to meet alignment requirements; this sum is rounded up to a multiple of 8 and then divided by 8 |
The sum of the packed sizes in bits of all fields in the fixed part and the largest variant, plus the sum of sizes in bits of any holes created to meet alignment requirements; if the sum is greater than 32, the sum is rounded up to the next multiple of 8 |
STRING, VARYING OF CHAR |
Maximum length + 2 |
(Maximum length + 2) * 8 |
Nonstatic PACKED SET, Unpacked SET? |
32, if the set base type is a subrange of INTEGER or UNSIGNED; else, compute (ORD(upper-bound of ordinal type that is base type of set's base type) + 8) DIV 8, and if this result is less than or equal to 8, the result is rounded up to 1, 2, 4, or 8 |
Compute (ORD (upper-bound) + 1); if the result is less than or equal to 64, the result is rounded up to 8, 16, 32, or 64, and if the result is greater than 64, the result is rounded to next higher multiple of 8 |
PACKED SET? |
The result of (ORD(upper-bound) + 8 ) DIV 8 |
Compute (ORD (upper-bound) + 1); if the result is greater than 32, the result is rounded to next higher multiple of 8 |
FILE |
Not specified |
Not specified |
IF LOW < -1 IF HIGH > 0 THEN THEN X := log2(-LOW - 1) + 1 Y := log2(HIGH) + 1 ELSE ELSE X := 0; Y := 0; IF LOW >= 0 THEN Z := 0 ELSE Z := 1;
BITNEXT returns an integer value that indicates what the packed size would be for an array component of the type.
BITSIZE returns an integer value that indicates what the packed size would be for a record field of the type.
NEXT returns an integer value that indicates what the unpacked size would be for an array component of the type.
SIZE returns an integer value that indicates what the unpacked size would be for a variable or record field of the type.
The maximum size for any variable is 2 31-1 bits.
For More Information:
On size attributes (Chapter 10, Attributes)
On predeclared functions (Chapter 8, Predeclared Functions and Procedures)
A.2.6. Allocation Size Examples
Note
Although packing records and arrays does save storage space and can be necessary for compatibility with other code, note that accessing unaligned variables takes many more instructions than accessing variables with natural alignment, such as those in unpacked records and arrays.
Example 1
TYPE Internal_Arr = ARRAY[1..5] of 0..6; VAR Samp1_Arr : PACKED ARRAY[1..5] OF Internal_Arr;
Each component of an array of type Internal_Arr is stored in a longword. Each component of Samp1_Arr, in turn, requires five longwords, which is enough storage space for five components of type Internal_Arr. The entire array Samp1_Arr occupies 25 longwords (800 bits).
Example 2
VAR Samp1_Arr : ARRAY[1..5] OF PACKED ARRAY[1..5] OF 0..6;
Each PACKED ARRAY[1..5] of 0..6 requires 15 bits (the range 0..6 requires 3 bits; five 3-bit components requires 15 bits). Because the packed arrays are components of an unpacked array, their size is rounded up to an even 16 bits. The total size of Samp1_Arr is 80 bits.
Example 3
TYPE Internal_Arr = PACKED ARRAY[1..5] OF 0..6; VAR Samp2_Arr : PACKED ARRAY[1..5] OF Internal_Arr; Samp3_Arr : PACKED ARRAY[1..5,1..5] OF 0..6;
In this example, every component of Internal_Arr requires only three bits because the array is packed. Each component of Samp2_Arr and Samp3_Arr can be stored in 15 bits, and each array occupies 75 bits. The specification of PACKED for an array with multiple indexes results in packing at every level. The two arrays in this example are equivalent.
Example 4
VAR Sample : PACKED ARRAY[1..5,1..5,1..5] OF 0..6;
This example shows space savings for arrays of more than two dimensions when PACKED is specified at every level. The subrange 0..6 requires 3 bits; five 3-bit components require 15 bits. This size describes the innermost dimension of Sample. Next, five 15-bit components require 75 bits. Because of the 32-bit rules, each 75-bit component is rounded up to 80 bits. This size describes the middle and inner dimensions of Sample. Finally, five 80-bit components require 400 bits (50 bytes). The entire array Sample then requires 400 bits.
Example 5
VAR Sample_Rec : PACKED RECORD Field_1 : BOOLEAN; Field_2 : INTEGER32; Field_3 : DOUBLE; END;
In this example, Field_1 requires only 1 bit of storage. Field_2 is 32 bits in size (declared as INTEGER32) and starts immediately following Field_1. Because Field_3 is larger than 32 bits, it will start on the next byte boundary. The entire record Sample_Rec, therefore, requires 104 bits.
A.2.7. Alignment Boundaries
Object |
Arguments to the Alignment Switch | |
---|---|---|
NATURAL? |
VAX | |
Variable declared with an alignment attribute |
Specified alignment |
Specified alignment |
Variable declared without an alignment attribute |
Natural alignment |
Byte alignment? |
Component of an unpacked array or record variable |
Natural alignment |
Byte alignment |
Component of a packed array or record variable |
Follows the 32-bit rules? |
Follows the 32-bit rules |
Dynamic variables allocated by the NEW procedure |
Octaword alignment on OpenVMS I64 and OpenVMS x86-64; quadword alignment on OpenVMS Alpha |
Quadword alignment |
You can save storage space by packing variables of structured types, but you must be careful to pack at the proper level. Except for its alignment, a record field whose type is an unpacked array, set, or record occupies the same amount of space in a packed or an unpacked record variable. To pack such a field, you must explicitly declare its type to be packed.
When packing multidimensional arrays, you must specify packing at the innermost level to gain any significant space advantage. For example, there is no advantage in packing an array of an unpacked structured type; the unpacked components will still be aligned on byte boundaries, which leaves holes in the storage space. To gain storage space, you must specify a packed array of a packed structured type.
Note
Although packing records and arrays does save storage space and can be necessary for compatibility with other code, note that accessing unaligned variables takes many more instructions than accessing variables with natural alignment, such as those in unpacked records and arrays.
Example 1
VAR X : [STATIC, ALIGNED(3)] INTEGER; { QUADWORD ALIGNED } { $SDATA$ on OpenVMS I64 } { $DATA$ on OpenVMS Alpha } { $DATA$ on OpenVMS x86-64 }
In this example, X is declared a static variable that is aligned on a QUADWORD boundary.
Example 2
VAR X : PACKED RECORD { AUTOMATIC } Field1 : BOOLEAN; Field2 : REAL; Field3 : BOOLEAN; Field4 : DOUBLE; END;
In this example, Field1 begins at bit position 0 and is 1 bit long. Field2 begins at bit position 1 and is 32 bits long. Field3 begins at bit position 33 and is 1 bit long. However, because Field4 is greater than 32 bits long (DOUBLE requires 64 bits) Field4 must be byte aligned. For this reason, Field4 begins on bit position 40 and is 64 bits long.
Example 3
VAR X : RECORD { AUTOMATIC } Field1 : [BIT(3)] 0..7; Field2 : [UNALIGNED] INTEGER32; END;
In this example, Field1 of record X is declared to begin on bit position 0 and is 3 bits long. Due to the use of the UNALIGNED attribute on Field2, Field2 begins on bit position 3 and is 32 bits long. You can obtain the same behavior by packing record X.
Without using the UNALIGNED attribute, or without X being a PACKED record, Field2 would have been longword aligned; that is, it would have started on bit position 32. You cannot use the UNALIGNED attribute with INTEGER64 because of the 32-bit rules, which states that variables greater than 32 bits must be at least byte-aligned.
For More Information:
On ranges and precision of integer and real types (Chapter 2, Data Types and Values)
On the representation of data types (Section A.3, “Internal Representation of Data Types”)
On the 32-bit rules (Section A.2.4, “Allocation Sizes of Variables”)
On the ALIGNED and UNALIGNED attributes (Chapter 10, Attributes)
A.3. Internal Representation of Data Types
The following sections summarize the internal representation of the VSI Pascal data types.
A.3.1. Representation of Varying Data
RECORD Length : [WORD] 0..Maxlength; Body : PACKED ARRAY[1..Maxlength] OF CHAR; END;
Figure A.1, “Storage of Varying Data” shows the storage allocated for a variable of type VARYING[8] OF CHAR.

The predefined schema type STRING uses VARYING OF CHAR as its underlying data type, so Figure A.1, “Storage of Varying Data” also represents the STRING type.
For More Information:
On VSI Pascal varying data types (Section 2.6.2, “VARYING OF CHAR Types”)
On the UNALIGNED attribute (Section 10.2.38, “UNALIGNED”)
On VSI Pascal string data types (Section 2.6, “String Types”)
A.3.2. Representation of Floating-Point Data
The following sections summarize the internal representation of single-precision (F_floating and S_floating), double-precision (D_floating, G_floating, and T_floating), and quadruple-precision (H_floating and X_floating) floating-point numbers.
For More Information:
On VSI Pascal floating-point data types (Section 2.2, “Real Types”)
A.3.2.1. F_floating-Point Numbers
An F_floating-point value is represented by four contiguous bytes. The bits are numbered from the right, 0 through 31, as shown in Figure A.2, “F_floating-Point Data Representation”.

Bit 15 is the sign bit.
Bits 14 through 7 are an excess 128 binary exponent.
Bits 6 through 0 and 31 through 16 are a normalized 24-bit fraction with the redundant most significant fraction bit not represented. Within the fraction, bits of increasing significance go from 16 through 31 and from 0 through 6.
For More Information:
On F_floating-point range and precision (Section 2.2, “Real Types”)
A.3.2.2. S_floating-Point Numbers
An S_floating-point value is represented by four contiguous bytes. The bits are numbered from the right, 0 through 31, as shown in Figure A.3, “S_floating-Point Data Representation”.

Bit 31 is the sign bit (0 for positive numbers, 1 for negative numbers).
Bits 30 through 23 are an excess 127 exponent.
Bits 22 through 0 are a normalized 24-bit fraction with the redundant most significant fraction bit not represented.
For More Information:
On S_floating-point range and precision (Section 2.2, “Real Types”)
A.3.2.3. D_floating-Point Numbers
A D_floating-point value is represented by eight contiguous bytes. The bits are numbered from the right, 0 through 63, as shown in Figure A.4, “D_floating-Point Data Representation”.

A D_floating-point value is specified by its address A, the address of the byte containing bit 0. The form of this value is identical to that of a F_floating-point value except for an additional 32 low-significance fraction bits. Within the fraction, bits of increasing significance are numbered 48 through 63, 32 through 47, 16 through 31, and 0 through 6.
For More Information:
On D_floating-point range and precision (Section 2.2, “Real Types”)
A.3.2.4. G_floating-Point Numbers
A G_floating-point value is represented by eight contiguous bytes. The bits are numbered from the right, 0 through 63, as shown in Figure A.5, “G_floating-Point Data Representation”.

Bit 15 is the sign bit.
Bits 14 through 4 are an excess 1024 binary exponent.
Bits 3 through 0 and 63 through 16 represent a normalized 53-bit fraction without the redundant most significant fraction bit. Within the fraction, bits of increasing significance go from 48 through 63, 32 through 47, 16 through 31, and 0 through 3.
For More Information:
On G_floating-point range and precision (Section 2.2, “Real Types”)
A.3.2.5. T_floating-Point Numbers
A T_floating-point value is represented by 8 contiguous bytes. The bits are numbered from the right 0 through 63, as shown in Figure A.6, “T_floating-Point Data Representation”.

Bit 63 is the sign bit (0 for positive numbers, 1 for negative numbers).
Bits 62 through 52 are an excess 127 exponent.
Bits 51 through 0 are a normalized 53-bit fraction with the redundant most significant fraction bit not represented.
For More Information:
On T_floating-point range and precision (Section 2.2, “Real Types”)
A.3.2.6. H_floating-Point Numbers
Note
H_floating-point numbers are not supported on any VSI OpenVMS platform and are described here only for reference.
An H_floating-point value is represented by 16 contiguous bytes. The bits are numbered from the right 0 through 127, as shown in Figure A.7, “H_floating-Point Data Representation”.

Bit 15 is the sign bit.
Bits 14 through 0 are an excess 16,384 binary exponent.
Bits 127 through 16 are a normalized 113-bit fraction with the redundant most significant fraction bit not represented. Within the fraction, bits of increasing significance go from 112 through 127, 96 through 111, 80 through 95, 64 through 79, 48 through 63, 32 through 47, and 16 through 31.
A.3.2.7. X_floating-Point Numbers
An X_floating-point value is represented by 16 contiguous bytes. The bits are numbered from the right 0 through 127, as shown in Figure A.8, “X_floating-Point Data Representation”.

Bit 127 is the sign bit.
Bits 112 through 126 are an excess 16,383 binary exponent.
Bits 0 through 111 are a normalized 112-bit fraction with the redundant most significant fraction bit not represented.
For More Information:
On X_floating-point range and precision (Section 2.2, “Real Types”)
A.3.3. Representation of Nonstatic Types and Variables
This section describes the representation of nonstatic types and variables.
A.3.3.1. Representation of Nonstatic Types
Each nonstatic data type has some storage associated with it, called the control part. Figure A.9, “Storage of Nonstatic Data Types” shows the layout of a control part of a nonstatic data type.

- No information (if the schema type is simple), as follows:
TYPE A_Char( x,y : CHAR ) = x..y;
- Control parts of nested discriminated schema types, as follows:
TYPE My_Record( a, b : INTEGER ) = RECORD f1 : STRING( a ); f2 : STRING( b ); END;
- Values for all expressions appearing in the type definition, as follows:
TYPE My_Subrange( a, b : INTEGER ) = a..a+b;
VSI Pascal evaluates the expression a+b when the schema type is discriminated and saves the result in the control part.
- The total size of the data part, if it can vary based on actual discriminants, as follows:
TYPE Arr( a, b : INTEGER ) = ARRAY[a..b] OF REAL;
Note
The order of information and the content of the additional information section of the control part cannot be guaranteed.
If you declare more than one variable of a discriminated schema type, each variable shares the information in the control part for that type.
A.3.3.2. Representation of Variables of Nonstatic Types
When allocating storage for a variable of a nonstatic type, VSI Pascal allocates a pointer part and a data part. VSI Pascal allocates and initializes the pointer part (to point to the data part); you cannot access the pointer part in your program. VSI Pascal associates each object with a control part according to its data type.
TYPE Sub_Range( a, b : INTEGER ) = a..b; VAR {x requires information in two control parts:} x : ARRAY[Sub_Range( i, j ), Sub_Range( k, l )] OF INTEGER;
Figure A.10, “Storage of Variables of Nonstatic Types” shows the layout for an object of a nonstatic type.

TYPE dstr = STRING( I ); VAR ptr : ^dstr; {In the executable section:} NEW( ptr );
You cannot create variables of undiscriminated types, but you can also show the representation for pointers to nonstatic types (except undiscriminated schema).
Figure A.11, “Storage of Pointer Variables to Undiscriminated Schema Types” shows the layout for a pointer to an undiscriminated schema type.

VAR x, y, z : ^STRING; {In the executable section:} NEW( x, 10 ); {x has a control and data part} y := x; {y points to same control and data part as x} NEW( z, 10 ); {z has separate control and data parts}
Each variable created by NEW contains a unique control part attached to the data part.
A.3.3.3. Representation of Nonstatic Record Fields
If a record object contains a field of a nonstatic type, VSI Pascal stores the field in one piece of storage within the record's storage ( VSI Pascal does not create a pointer part and a data part). VSI Pascal determines the offset of the object by accessing the information in the control part of the field's data type and information in the control part of the record.
Appendix B. Summary of VSI Pascal for OpenVMS Extensions
Extensions to the unextended Pascal standards ( Section B.1, “ VSI Pascal for OpenVMS Extensions to Unextended Pascal”)
Extensions to the Extended Pascal standard ( Section B.2, “ VSI Pascal for OpenVMS Extensions to Extended Pascal”)
For More Information:
On Pascal standards ( Section 1.1, “Pascal Language Standards”)
B.1. VSI Pascal for OpenVMS Extensions to Unextended Pascal
Category |
Extension |
---|---|
Lexical and syntactical extensions |
Reserved words: BREAK, CONTINUE, ERR, EXIT, MODULE, NEXT, OTHERWISE, REM, RETURN, VALUE, VARYING, %DESCR, %STDESCR, %IMMED, %REF, %INCLUDE, %TITLE, %SUBTITLE, %DICTIONARY, %IF, %ELIF, %ENDIF, %DEFINED, %ERROR, %WARN, %INFO, %MESSAGE, %ARCH_NAME, %SYSTEM_NAME, %SYSTEM_VERSION, %DATE, %TIME, %COMPILER_VERSION, %LINE, %FILE, %ROUTINE, %MODULE, %IDENT, %FLOAT, %F_FLOAT, %D_FLOAT, %G_FLOAT, %S_FLOAT, %T_FLOAT. |
Exponentiation operator (**) | |
REM operator | |
AND_THEN and OR_ELSE operators | |
NOT IN operator | |
Type cast operator (::) for variables and expressions | |
Double quotation marks as string and character delimiters | |
Escape sequences within double quotation marks | |
%radix-specifier for binary, hexadecimal, and octal notation for integers, (#) radix-specifier for integers in bases 2 to 36 inclusive | |
Double- and quadruple-precision real numbers | |
Dollar sign ($) and underscore (_) characters in identifiers | |
Identifiers that can begin with the dollar sign or underscore characters | |
Alphanumeric strings for labels | |
Extended syntax for inclusion of nonprinting characters in single-quoted character strings | |
Compile-time constant expressions allowed anywhere a constant is allowed | |
Constructors of structured types used anywhere in place of a constant of the structured type | |
Attributes used with data items, routines, and compilation units | |
Relaxed rules for assignment compatibility | |
Structural compatibility enforced between actual and formal parameters | |
! for end-of-line comments | |
Predefined types |
ALFA, CARDINAL, CARDINAL16, C_STR_T, INTEGER_ADDRESS, CARDINAL32, INTEGER8, INTEGER16, INTEGER32, INTEGER64, INTSET, POINTER, UNIV_PTR, UNSIGNED8, UNSIGNED16, UNSIGNED32, UNSIGNED64, SINGLE (F_floating and S_floating), DOUBLE (D_floating, G_floating, and T_floating), QUADRUPLE (X_floating), STRING, TIMESTAMP |
VARYING OF CHAR structured type and concatenation operator for all strings | |
Predeclared procedures |
ARGV, ASSERT, BARRIER, CLOSE, CREATE_DIRECTORY, DATE, DELETE, DELETE_FILE, ESTABLISH, EXTEND, FIND, FINDK, GETTIMESTAMP, HALT, LINELIMIT, LOCATE, OPEN, READV, REMOVE, RENAME_FILE, RESETK, REVERT, STLIMIT, TIME, TRUNCATE, UNLOCK, UPDATE, WRITEV GETTIMESTAMP |
Predeclared functions |
Transfer functions: DBLE, INT, INT64, QUAD, ROUND64, SNGL, TRUNC, TRUNC64, UINT, UINT64, UROUND, UROUND64, UTRUNC, UTRUNC64 |
Implicitly declared type-conversion and type-casting routines for predefined data types | |
Dynamic allocation function: ADDR, ADDRESS, IADDRESS, IADDRESS64 | |
Character-string functions: BIN, DEC, HEX, INDEX, LENGTH, OCT, PAD, STATUSV, SUBSTR, UDEC, GT, GE, LT, LG, EQ, NE | |
Parameter functions: ARGUMENT, ARGUMENT_LIST_LENGTH, PRESENT | |
Privileged routines: MFPR, MTPR | |
Arithmetic functions: BITAND, BITNOT, BITOR, BITXOR, LSHFT, LSHIFT, MIN, MAX, RANDOM, RSHFT, RSHIFT, SEED, UAND, UNOT, UOR, UXOR, XOR | |
Allocation size functions: SIZE, SIZEOF, NEXT, BITSIZE, BITNEXT | |
Ordered sequence of values functions: FIRST, FIRSTOF, HBOUND, IN_RANGE, LAST, LASTOF, LBOUND | |
Low-level interlocked functions: ADD_ATOMIC, ADD_INTERLOCKED, AND_ATOMIC, CLEAR_INTERLOCKED, FIND_FIRST_BIT_CLEAR, FIND_FIRST_BIT_SET, FIND_MEMBER, FIND_NONMEMBER, OR_ATOMIC, SET_INTERLOCKED | |
Null-terminated string functions: C_STR, MALLOC_C_STR, PAS_STR, PAS_STRCPY | |
I/O functions: STATUS, UFB | |
Field position functions: BIT_OFFSET, BYTE_OFFSET | |
Additional functions: ARGC, CARD, CLOCK, EXPO, UNDEFINED, ZERO, DATE, TIME, UPPER, LOWER, SYSCLOCK, WALLCLOCK | |
READ, READLN, WRITE, WRITELN extensions |
Parameters of character-string and enumerated types for READ and READLN Parameters of enumerated types for WRITE and WRITELN Prompting at the terminal with a WRITE/READ or WRITE/READLN sequence Optional carriage-control specification for text files with WRITE and WRITELN Optional radix specification for READ and READLN Optional radix specification for WRITE and WRITELN |
Extended I/O capabilities |
Direct access and relative file organization Keyed access and indexed file organization Optional second parameter to RESET, REWRITE, and EXTEND for specifying a file name |
Declarations |
Declaration and definition sections that can appear more than once and in any order |
Initialization of variables, types, and record fields in VAR and TYPE sections of any program, module, procedure, or function | |
Schema types | |
VALUE initialization section | |
OTHERWISE clause in variant records | |
Ranges in variant label lists | |
Statements |
OTHERWISE clause in CASE statement |
Ranges in CASE label lists | |
BREAK, CONTINUE, EXIT, NEXT, RETURN, SELECT, and SELECTONE statements | |
FOR statement with SET iterations | |
Procedures and functions |
Functions that return values of structured types (other than file types) |
Functions called as procedures | |
External procedure and function declarations | |
Default values for formal parameters | |
Nonpositional parameter passing | |
Extended mechanism specifiers and parameter-passing attributes for passing parameters to external procedures and functions: %IMMED, %REF, %DESCR, %STDESCR, IMMEDIATE, REFERENCE, CLASS_S, CLASS_A, CLASS_NCA | |
Compilation |
MODULE capability for combining declarations and definitions to be compiled independently from the main program |
ENVIRONMENT and INHERIT attributes to control independent compilation | |
Module initialization and finalization |
B.2. VSI Pascal for OpenVMS Extensions to Extended Pascal
Category |
Extension |
---|---|
Lexical and syntactical extensions |
Reserved words: BREAK, CONTINUE, ERR, EXIT, NEXT, REM, RETURN, VARYING, %DESCR, %STDESCR, %IMMED, %REF, %INCLUDE, %TITLE, %SUBTITLE, %DICTIONARY, %DICTIONARY, %IF, %ELIF, %ENDIF, %DEFINED, %ERROR, %WARN, %INFO, %MESSAGE, %ARCH_NAME, %SYSTEM_NAME, %SYSTEM_VERSION, %DATE, %TIME, %COMPILER_VERSION, %LINE, %FILE, %ROUTINE, %MODULE, %IDENT, %FLOAT, %F_FLOAT, %D_FLOAT, %G_FLOAT, %S_FLOAT, %T_FLOAT. |
REM operator | |
NOT IN operator | |
Type cast operator (::) for variables and expressions | |
"%radix-specifier number" form for binary, hexadecimal, and octal notation for integers | |
Alphanumeric strings for labels | |
Double- and quadruple-precision real numbers | |
Identifiers can contain the dollar sign ($) character | |
Identifiers can begin with the dollar sign character and the underscore character | |
Double quotation marks as string and character delimiters | |
Escape sequences within double quotation marks | |
Labels can be alphanumeric strings | |
Extended syntax for inclusion of nonprinting characters in single-quoted character strings | |
Parenthetical form ( (constructor )) for constructors of structured types, used anywhere in place of a constant of the structured type | |
Attributes | |
Relaxed rules for assignment compatibility | |
Structural compatibility enforced between actual and formal parameters | |
! for end-of-line comments | |
Predefined types |
ALFA, C_STR_T, CARDINAL, CARDINAL16, CARDINAL32, INTEGER8, INTEGER16, INTEGER32, INTEGER64, INTSET, POINTER, UNIV_PTR, UNSIGNED8, UNSIGNED16, UNSIGNED32, UNSIGNED64, SINGLE (F_floating and S_floating), DOUBLE (D_floating, G_floating, and T_floating), QUADRUPLE (X_floating) |
VARYING OF CHAR structured type and concatenation operator for all strings | |
Predeclared procedures |
ARGV, ASSERT, BARRIER, CLOSE, CREATE_DIRECTORY, DATE, DELETE, DELETE_FILE, ESTABLISH, FIND, FINDK, LINELIMIT, LOCATE, NULL, OPEN, READV, REMOVE, RENAME_FILE, RESETK, REVERT, STLIMIT, TIME, TRUNCATE, UNLOCK, UPDATE, WRITEV |
Predeclared functions |
Transfer functions: DBLE, INT, INT64, QUAD, ROUND64, SNGL, TRUNC, TRUNC64, UINT, UINT64, UROUND, UROUND64, UTRUNC, UTRUNC64 |
Implicitly declared type-conversion and type-casting routines for predefined data types | |
Dynamic allocation function: ADDR, ADDRESS, IADDRESS, IADDRESS64 | |
Character-string functions: BIN, DEC, HEX, OCT, PAD, STATUSV, UDEC | |
Parameter functions: ARGUMENT, ARGUMENT_LIST_LENGTH, PRESENT | |
Arithmetic functions: BITAND, BITNOT, BITOR, BITXOR, LSHFT, LSHIFT, RANDOM, RSHFT, RSHIFT, SEED, UAND, UNOT, UOR, UXOR, XOR, MIN, MAX | |
Allocation size functions: SIZE, SIZEOF, NEXT, BITSIZE, BITNEXT | |
Ordered sequence of values functions: FIRST, FIRSTOF, HBOUND, IN_RANGE, LAST, LASTOF, LBOUND | |
Low-level interlocked functions: ADD_ATOMIC, ADD_INTERLOCKED, AND_ATOMIC, CLEAR_INTERLOCKED, FIND_FIRST_BIT_CLEAR, FIND_FIRST_BIT_SET, FIND_MEMBER, FIND_NONMEMBER, OR_ATOMIC, SET_INTERLOCKED | |
Privileged routines: MTPR, MFPR | |
I/O functions: STATUS, UFB | |
Null-terminated string functions: C_STR, MALLOC_C_STR, PAS_STR, PAS_STRCPY | |
Field position functions: BIT_OFFSET, BYTE_OFFSET | |
Additional predeclared functions: ARGC, CLOCK, EXPO, LOWER, SYSCLOCK, UNDEFINED, UPPER, WALLCLOCK, ZERO | |
READ, READLN, WRITE, WRITELN extensions |
Parameters of enumerated types for READ and READLN Parameters of enumerated types for WRITE and WRITELN Prompting at the terminal with a WRITE/READ or WRITE/READLN sequence Optional carriage-control specification for text files with WRITE and WRITELN Optional radix specification for READ and READLN Optional radix specification for WRITE and WRITELN |
Extended I/O capabilities |
Direct access and relative file organization Keyed access and indexed file organization Optional second parameter to RESET, REWRITE, and EXTEND for specifying a file name |
Declarations |
VALUE initialization section |
Statements |
BREAK, CONTINUE, EXIT, NEXT, RETURN, SELECT, and SELECTONE statements |
Procedures and functions |
Functions called as procedures External procedure and function declarations Default values for formal parameters Nonpositional parameter passing Extended mechanism specifiers and parameter-passing attributes for passing parameters to external procedures and functions: %IMMED, %REF, %DESCR, %STDESCR, IMMEDIATE, REFERENCE, CLASS_S, CLASS_A, CLASS_NCA |
Compilation |
MODULE syntax differs from the syntax provided by Extended Pascal |
ENVIRONMENT and INHERIT attributes to control independent compilation |
Appendix C. Description of Implementation Features
The standards for Pascal allow some features of the language to be defined by a particular implementation or to be dependent on an implementation.
For More Information:
On Pascal standards ( Section 1.1, “Pascal Language Standards”)
C.1. Implementation-Defined Features
The value of each character allowed in a character string
Treatment: See Section 1.2.1, “Character Set”.
The range of real number values represented by the type REAL
Treatment: See Section 2.2, “Real Types”.
The characters represented by the type CHAR and their ordinal values
Treatment: See Section 1.2.1, “Character Set”.
The point at which the REWRITE, PUT, RESET, and GET procedures are performed on a file
Treatment: Performed immediately unless the file is a terminal file, in which case delayed device access occurs (see Section 9.5.3, “Delayed Device Access to Text Files”).
The value of MAXINT
The accuracy to which the results of real-number operations are calculated
Treatment: See Table 2.6, “Supported Floating-Point Formats”.
Default field widths
Treatment: See Section 9.6, “Formatting Output”.
The number of digits used to represent the exponent of a floating-point, number
Treatment:
REAL, SINGLE (F_floating and IEEE S floating-point format) | 2 |
DOUBLE (D_floating) | 2 |
DOUBLE (G_floating and IEEE T floating point-format) | 3 |
QUADRUPLE (X_floating) | 4 |
The value of the exponent character
Explanation: ’E ’.
The case (upper or lower) in which the Boolean values TRUE and FALSE are printed as output
Explanation: Uppercase; that is, TRUE and FALSE.
The effect of the PAGE procedure
Treatment: PAGE writes a line containing only the form-feed character (ASCII value 12).
C.2. Implementation-Dependent Features
The unextended Pascal standard and the Extended Pascal standard list features that can vary from implementation to implementation. It is illegal for a program to depend on these features. VSI Pascal does not detect when a program depends on any of these features. Relying on them may yield incorrect results or unexpected program terminations.
Any or all of these implementation-dependent features may change without notice.
For those items in this section that pertain to order of evaluation, VSI Pascal does not specify the order of evaluation. Depending on several heuristics in the compiler, the order of evaluation can be left-to-right, right-to-left, or random with complete or short-circuit evaluation. The order of evaluation is allowed to vary between invocations of the compiler and even between individual uses of source language features.
The order of evaluation of the following items:
Expressions used as discriminant values
Index expressions and access to the array or string variable in a indexed variable
Index values of an array variable
Expressions d1,...,dn in new(p,d1,...,dn)
Expressions of a set member designator
Set member designators in a set constructor
Operands of a dyadic (binary) operator, except for AND_THEN and OR_ELSE
Component values of a structured value constructor
Index expressions in an indexed constant
Expressions in a set constructor
Treatment: Random order.
Order of selecting members of the set value in the FOR IN statement
Treatment: Random order.
Whether the first character read when reading an integer or real from a text file is the value of the buffer variable or the value of the next character from the input record
Treatment: VSI Pascal uses the next character in the input record and ignores the contents of the file buffer.
Order of evaluating, and accessing of actual parameters of a function call
Treatment: Random order.
Order of evaluating, and accessing of actual parameters of a procedure call
Treatment: Random order.
Order of accessing the variable and evaluating the expression in an assignment statement
Treatment: Random order.
The effect of reading a text file for which the PAGE procedure was called
Treatment: Reads a line containing only the form-feed character (ASCII value 12).
The binding of a nonfile variable whose name is listed in the program heading to entities that are external to the program
Treatment: Reported as an error at compile time.
The binding of a file variable whose name is listed in the program heading
The file name (unless it is INPUT or OUTPUT) is equated to a logical name if a translation for the file name exists. If there is no corresponding translation, the file type DAT is appended to the name listed in the heading, as in INFILE.DAT. If the file name is INPUT, the file is equated to PAS$INPUT, if PAS$INPUT is defined; otherwise, the file is equated to SYS$INPUT. Similarly, if the file name is OUTPUT, the file is equated to PAS$OUTPUT, if PAS$OUTPUT is defined; otherwise, the file is equated to SYS$OUTPUT.
Appendix D. Compiler and Run-Time System Error Detection
This appendix describes how the VSI Pascal compiler and run-time system detect violations of the Pascal language standards. Errors detected at run-time cause a program to terminate and return appropriate error messages. Errors described here as not detected cause a program to produce unexpected results.
For More Information:
On Pascal standards (Section 1.1, “Pascal Language Standards”)
On VSI Pascal error messages (VSI Pascal User Manual)
D.1. Error Message Information
The type of an index value is not assignment compatible with the index type of an array.
Detected at run time if bounds checking was enabled during compilation.
The current variant changes while a reference to it exists.
Not detected. An example of a reference to a variant is the passing of the variant to a formal VAR parameter.
The value of a variable to which a pointer refers (p^) is NIL.
Usually detected at run time. Always detected if pointers checking was enabled during compilation.
The value of a variable to which a pointer refers (p^) is undefined.
Not detected.
The DISPOSE procedure is called to dispose of a heap-allocated variable while a reference to the variable exists.
Not detected. Examples of such references are passing the variable, or a component of it, to a formal VAR parameter, or using the variable in a WITH statement (if the variable is a record).
The value of file f changes while a reference to f^ exists.
Not detected. An example of a reference to f^ is the passing of f^ by reference to a routine; until the routine has ceased execution, you cannot perform any operation on file f.
The ordinal type of an actual parameter is not assignment compatible with the type of the corresponding formal parameter.
Detected at run time if subrange checking was enabled during compilation of the called routine.
The set type of an actual parameter is not assignment compatible with the type of the corresponding formal parameter.
Detected at run time if subrange checking was enabled during compilation of the called routine.
A file is not in generation mode when a PUT, WRITE, WRITELN, or PAGE procedure is attempted.
Detected at run time.
A file is in undefined mode when a PUT, WRITE, WRITELN, or PAGE procedure is attempted.
Not detected.
The result of an EOF function is not TRUE when a PUT, WRITE, WRITELN, or PAGE procedure is attempted.
Detected at run time. The operation is illegal only when the file is accessed sequentially.
The value of the file buffer variable is undefined when a PUT procedure is attempted.
Not detected.
A file is in undefined mode when a RESET procedure is attempted.
Not detected.
A file is not in inspection mode when a GET, READ, or READLN procedure is attempted.
Detected at run time.
A file is in undefined mode when a GET, READ, or READLN procedure is attempted.
Not detected.
The result of an EOF function is TRUE when a GET, READ, or READLN procedure is attempted.
Detected at run time.
The type of the file buffer variable is not assignment compatible with the type of the variable that is a parameter to a READ or READLN procedure.
Detected at run time.
The type of the expression being written by a WRITE or WRITELN procedure is not assignment compatible with the type of the file buffer variable.
Detected at run time.
The current variant does not exist in the list of variants specified with the NEW procedure.
Not detected.
The DISPOSE( p ) procedure is called to deallocate a pointer variable that was created using the variant form of the NEW procedure.
Not detected.
The variant form of the DISPOSE procedure does not specify the disposal of the same number of variants that were created by the variant form of the NEW procedure.
Not detected.
The variant form of the DISPOSE procedure does not specify the disposal of the same variants that were created by the variant form of the NEW procedure.
Not detected.
The value of the parameter to the DISPOSE procedure is NIL.
Detected at run time.
The value of the parameter to the DISPOSE procedure is undefined.
Not detected.
A variant record created by the NEW procedure is accessed as a whole, rather than one component at a time.
Not detected.
In the PACK( a,i,z ) procedure, the type of the index value i is not assignment compatible with the index type of a.
Detected at run time if subrange checking was enabled during compilation.
The PACK procedure is attempted when the value of at least one component of a is undefined.
Not detected.
The index value i in the PACK procedure is greater than the upper bound of the index type of a.
Detected at run time if subrange checking was enabled during compilation.
In the UNPACK( z,i,a ) procedure, the type of the index value i is not assignment compatible with the index type of a.
Detected at run time if subrange checking was enabled during compilation.
The UNPACK procedure is attempted when the value of at least one component of z is undefined.
Not detected.
The index value i in the UNPACK procedure is greater than the upper bound of the index type of a.
Detected at run time if subrange checking was enabled during compilation.
The resulting value of SQR( x ) does not exist.
Detected at run time for integers if overflow checking was enabled during compilation; always detected at run time for real numbers.
In the expression LN( x ), the value of x is negative.
Detected at run time.
In the expression SQRT( x ), the value of x is negative.
Detected at run time.
The resulting value of TRUNC( x ) does not exist after the following calculations have been done: if the value of x is positive or zero, then 0 <= x-TRUNC( x ) < 1; otherwise, -1 < x-TRUNC( x ) <=0.
Detected at run time if overflow checking was enabled during compilation.
The resulting value of ROUND( x ) does not exist after the following calculations have been done: if the value of x is positive or zero, then ROUND( x ) is equivalent to TRUNC( x + 0.5 ); otherwise, ROUND( x ) is equivalent to TRUNC( x - 0.5 ).
Detected at run time if overflow checking was enabled during compilation.
The resulting value of CHR( x ) does not exist.
Detected at run time if subrange checking was enabled during compilation.
The resulting value of SUCC( x ) does not exist.
Detected at run time if subrange checking was enabled during compilation.
The resulting value of PRED( x ) does not exist.
Detected at run time if subrange checking was enabled during compilation.
The function EOF( f ) is called when the file f is undefined.
Not detected.
The function EOLN( f ) is called when the file f is undefined.
Not detected.
The function EOLN( f ) is called when the result of EOF( f ) is TRUE.
Not detected.
A variable is not initialized before it is first used.
Not detected.
In the expression x/y, the value of y is zero.
Detected at run time.
In the expression i DIV j, the value of j is zero.
Detected at run time.
In the expression i MOD j, the value of j is zero or negative.
Detected at run time if subrange checking was enabled during compilation.
An operation or function involving integers does not conform to the mathematical rules for integer arithmetic.
Detected at run time if overflow checking was enabled during compilation.
A function result is undefined when the function returns control to the calling block.
Not detected.
The ordinal type of an expression is not assignment compatible with the type of the variable or function identifier to which it is assigned.
Detected at run time if subrange checking was enabled during compilation.
The set type of an expression is not assignment compatible with the type of the variable or function identifier to which it is assigned.
Detected at run time if subrange checking was enabled during compilation.
None of the case labels is equal in value to the case selector in a CASE statement.
Detected at run time if case selector checking was enabled during compilation.
In a FOR statement, the type of the initial value is not assignment compatible with the type of the control variable, and the statement in the loop body is executed.
Detected at run time if subrange checking was enabled during compilation. Assignment compatibility is not enforced if the statement in the loop body can never be executed.
In a FOR statement, the type of the final value is not assignment compatible with the type of the control variable and the statement in the loop body is executed.
Detected at run time if subrange checking was enabled during compilation. Assignment compatibility is not enforced if the statement in the loop body can never be executed.
When an integer is being read from a text file, the digits read do not constitute a valid integer value. (Initial spaces and end-of-line markers are skipped.)
Detected at run time.
When an integer is being read from a text file, the type of the value read is not assignment compatible with the type of the variable.
Detected at run time if subrange checking was enabled during compilation.
When reading a real number from a text file, the digits read do not constitute a valid real number. (Initial spaces and end-of-line markers are skipped.)
Detected at run time.
The value of the file buffer variable is undefined when a READ or READLN procedure is performed.
Not detected.
A WRITE or WRITELN procedure specifies a field width in which the integers representing the total width and the number of fractional digits are less than 1.
Not detected.
The bounds of an array passed to a conformant array parameter are outside the range specified by the conformant array's index type.
Detected at run time if bounds checking was enabled during compilation.
Use the /FLOAT qualifier to specify the default floating-point format.
On VSI OpenVMS I64 and VSI OpenVMS x86-64 systems, F_floating, D_floating, and G_floating formats are implemented by transparently converting them to an appropriate IEEE floating format before performing any necessary operation and then transparently converting them back. This conversion to/from IEEE format might result in slightly different answers and precision than on VSI OpenVMS Alpha systems.
On VSI OpenVMS Alpha systems, D_floating is not a fully supported data type; no D_floating arithmetic operations are provided in the architecture. For backward compatibility, D_floating binary data can be processed but without the last three bits of precision by automatically converting to G_floating format, performing G_floating operations, and converting back to D_floating format.
Smallest value of the REAL, DOUBLE, and QUADRUPLE data types, such that ((1.0 + EPSREAL) > 1.0), ((1.0D0 + EPSDOUBLE) > 1.0D), and ((1.0Q0 + EPSQUADRUPLE) > 1.0Q0).
On OpenVMS Alpha, D_floating operations are performed using G_floating operations which has fewer mantissa bits. On OpenVMS I64 and OpenVMS x86-64, D_floating operations are performed using IEEE T_floating operations which has fewer mantissa bits.
A IN B is identical to INDEX(B,A) <> 0.
A NOT IN B is identical to INDEX(B,A) = 0
By default, the variable is unaligned in a packed context.
By default, the variable is byte aligned in an unpacked context.
SIZE rounds up to the nearest byte for the bit-sized objects.
Subranges assume the size of their base types in an unpacked context.
Extra space is needed to fulfill alignment requirements.
NEXT rounds down to the nearest byte for bit-sized objects.
Items larger than 32 bits must be allocated in an integral number of bytes.
Note that an ordinal target with a subrange type can be initialized outside of the subrange. The compiler treats this as an error if used in a compile-time expression.
Although the relative file organization allows variable-length components, those variable-length components are contained in a fixed-length cell that must be large enough to contain the largest stored component.
This access is permitted with a fixed-length component format on disk only.
The actual number is environment-specific and indicates the exact error that occurred.
Previous versions of VSI Pascal used ALPHA_AXP for this keyword. The NATURAL keyword is now the recommended spelling for the same behavior. The ALPHA_AXP keyword will continue to be recognized for compatibility with old source files.
PSECT is the only allocation attribute allowed.
Allowed only on EXTERNAL routine definitions.
EXTERNAL and WEAK_EXTERNAL are not allowed.
Component of a record, array, VARYING OF CHAR string, or file (includes conformant parameters).
Index of an array, tag field of a variant record (when no tag identifier is present), base type of a set, formal discriminant.
Variables of nonstatic types must be at least byte aligned.
UNALIGNED not allowed.
Not allowed on components of files or VARYING OF CHAR strings.
Not allowed on variables of nonstatic types.
Allowed only on record fields (including the tag field of a variant record).
Procedure parameters and conformant parameters are allowed only on EXTERNAL routines.
Not allowed on conformant VARYING parameters; not allowed on schematic parameters.
Not allowed on conformant parameters; not allowed on schematic parameters.
Not allowed on components of files or VARYING OF CHAR strings, or on structured types with file components.
Not allowed on variables larger than INTEGER or structured variables.
Executable code and read-only data are compiled into two separate program sections.
Executable code and read-only data are compiled into two separate program sections.
Executable code and read-only data are compiled into two separate program sections.
Code sections are placed into 64-bit P2 space by default. That behavior can be changed at LINK time with the /SEGMENT=CODE=P0 command qualifier.
It depends on the value specified for the /ENUMERATION_SIZE qualifier.
The maximum number of elements is 65,535.
This is known as the ceiling function, where the smallest integer is greater than or equal to X.
Sets of type INTEGER and UNSIGNED are limited to 256 bits.
By default, pointers are 32 bits in size. However, the QUAD attribute can be used on pointer declarations to specify 64-bit pointers. See the VSI Pascal User Manual for more information.
Previous versions of VSI Pascal used ALPHA_AXP for this keyword. The NATURAL keyword is now the recommended spelling for the same behavior. The ALPHA_AXP keyword will continue to be recognized for compatibility with old source files.
The compiler can align such variables on a larger storage boundary if it can access them more efficiently by doing so.
If a variable of type VARYING OF CHAR requires alignment, it is aligned on a word boundary.