Variable and Type Declarations
The following sections describe Pascal variable and type declarations in EQUEL.
Declaring the EQUEL Runtime Routines
The EQUEL generated runtime routines can be declared to the compiler in either of two ways: with the EQUEL declare statement or with the Pascal inherit attribute, which accesses an environment file containing the routines. The runtime routines must be declared by one of these methods at the program level prior to any EQUEL statements.
The Declare Statement
EQUEL/Pascal is delivered with a Pascal include file that contains external procedure and function declarations for the EQUEL runtime library. The EQUEL declare statement generates a Pascal %include statement for this file in order to make these declarations visible to the Pascal compiler. This statement must appear in the program's declaration section.
## program something;
## var
## row : integer;
## name : packed array[1..20] of Char;
## declare {Include EQUEL procedures}
## begin
...
## end.
The Inherit Attribute
EQUEL/Pascal also comes with a Pascal environment file that has the same declarations in the compiled include file. By means of the VMS Pascal inherit attribute, you can use this environment file instead of issuing a declare statement. Compilation should be slightly faster with this technique. The syntax for inheriting the EQUEL runtime routines is:
## [inherit('EQUEL')] program_heading;
## [inherit('EQUEL')] program test( input, output );
## var
## msg : varying[100] of Char;
## begin
## forms
msg := 'No DECLARE statement was issued';
## message msg
## end.
For information on installing the environment file, see
Precompiling, Compiling, and Linking an EQUEL Program.
Declaring Types and Variables to EQUEL
EQUEL statements use Pascal variables to transfer data from a database or a form into the program and conversely. You must declare Pascal variables to EQUEL before using them in EQUEL statements. Pascal variables are declared to EQUEL by preceding the declaration with the ## mark. The declaration must be in a position syntactically correct for the Pascal language. Similarly, constants, types, and formal parameters used in EQUEL must be made known to EQUEL by preceding their declarations with the ## mark.
In general, each declared object can be referred to in the scope of the enclosing compilation unit. An object name cannot be redeclared in the same compilation unit scope. For details on the scope of types and variables, see
Compilation Units and the Scope of Objects.
Reserved Words in Declarations and Program Units
All EQUEL keywords are reserved; therefore, you cannot declare variables with the same names as those keywords. In addition, the following Pascal words, used in declarations and program units, are reserved and cannot be used elsewhere, except in quoted string literals:
The word module cannot be used as an identifier in EQUEL/Pascal, although it is allowed in Pascal. The EQUEL preprocessor does not distinguish between uppercase and lower case in keywords.
Data Types and Constants
The EQUEL/Pascal preprocessor accepts the data types in the following table. The types are mapped to their corresponding Ingres type categories. For exact type mapping, see
Data Type Conversion.
Pascal Data Types and Corresponding Ingres Types
Your program should not redefine any of the above types.
The following table maps the Pascal constants to their corresponding Ingres type categories.
Pascal Constants and Corresponding Ingres Types
The Integer Data Types
Several Pascal types are considered as integer types by the preprocessor as shown in the following table.
Pascal Integer Types
All integer types are accepted by the preprocessor. Even though some integer types have Pascal constraints, such as the subranges and enumerations, EQUEL does not check these constraints, either during preprocessing or at runtime.
The type boolean is handled as a special type of integer. EQUEL treats the boolean type as an enumerated type and generates the correct code in order to use this type to interact with an Ingres integer. Enumerated types are described in more detail later.
The Indicator Type
An indicator type is a 2-byte integer type. There are three possible ways to use these in an application:
• In a statement that retrieves data from Ingres, you can use an indicator type to determine if its associated host variable was assigned a null.
• In a statement that sets data to Ingres, you can use an indicator type to assign a null to the database column, form field, or table field column.
• In a statement that retrieves character data from Ingres, you can use the indicator type as a check that the associated host variable is large enough to hold the full length of the returned character string.
EQUEL/Pascal predefines the 2-byte integer type indicator. As with other types, you should not redefine the indicator type. This type definition is in the file that is included when preprocessing the EQUEL declare or inherit directives. The type declaration syntax is:
type
Indicator = [word] -32768..32767;
Because the type definition is in the referenced include file, you can only declare variables of type indicator after you have issued declare or inherit. This declaration does not preclude you from declaring indicator types of other 2-byte integer types.
The Floating-point Data Types
There are three floating-point types that are accepted by the preprocessor. The types
single and
real are the 4-byte floating-point types. The type
double is the 8-byte floating-point type. Note that, although the preprocessor accepts
quadruple data type declarations, it does not accept references to variables of type
quadruple. (For more information on record types, see
Record Type Definition.)
The Double Storage Format
EQUEL requires that the storage representation for double variables be d_float, because the EQUEL runtime system uses that format for floating-point conversions. If your EQUEL program has double variables that interact with the EQUEL runtime system, you must make sure they are stored in the d_float format. Because the default Pascal format is d_float, your program will automatically use the correct storage representation unless you use the g_floating compiler option. Any module compiled with this option must not use double variables or float literals to interact with Ingres. Float literals are treated as double precision numbers by Ingres. Note that EQUEL recognizes only single, and not double or quadruple, exponential notation for real constants. Thus, any real constants passed to Ingres are always single precision and are unaffected by the g_floating compiler option.
The Character Data Types
Three Pascal data types are compatible with Ingres string objects: char, packed array of char, and varying of char. Note that literal string constants are of type packed array of char. EQUEL allows only regular Pascal string literals: sequences of printing characters enclosed in single quotes. The VMS Pascal extensions of parenthesized string constructors and of nonprinting characters represented by their ASCII values in parentheses are not allowed.
The char data type does have some restrictions. Because of the mechanism used to pass string-valued arguments to the EQUEL runtime library, you cannot use a member of a packed array of char or varying of char to interact with Ingres. Also plain array of char (for example, not packed or varying) is not compatible with Ingres string objects; an element of such an array, however, is a char and as such is compatible.
For example, given the following legal declarations:
## type
## Alpha = 'a'..'z'; {1 character}
## Packed_6 = packed array[1..6] of Char;
## {6-char string}
## Vary_6 = varying[6] of Alpha; {6-char string}
## Array_6 = array[1..6] of Char;
## {1-dimensional array}
## var
## letter: Alpha; {1 character}
## p_str_arr: array[1..5] of Packed_6;
## {Array of strings}
## chr_arr: array[1..6] of Char;
## {1-dimensional array}
## two_arr: array[1..5] of Array_6;
{2-dimensional array of char}
## v_string : Vary_6; {String}
these usages are legal:
## message letter {a char is a string}
## message chr_arr[3] {a char is a string}
## message two_arr[2][5 {a char is a string}
## message v_string {a varying array is a string}
## message p_str_arr[2] {a packed array is a string}
but these usages are illegal:
## message chr_arr {an array of chars is not a string}
## message v_string[2] {cannot index a varying array}
## message p_str_arr[2][3] {Cannot index a packed array}
Declaration Syntax
The following sections describe the declaration syntax.
Attributes
In type definitions, EQUEL allows VMS Pascal attributes both at the beginning of the definition and just before the type name. The only attributes the preprocessor recognizes in type definitions are byte, word, and long. Any optional storage unit constant "(n)" appearing with the attribute is ignored by the preprocessor. The preprocessor also ignores all other attributes, although it allows them.
The following example shows how to use the byte attribute in order to convert a 4-byte integer subrange into a 1-byte variable.
## var
## v_i1 : [byte] -128..127;
Note that Pascal requires that a size attribute be at least as large as the size of its type. Therefore, the following declaration would be illegal, because 400 will not fit into one byte:
## var
## v_i1 : [byte] 0..400;
EQUEL/Pascal does not allow explicit attribute size conflicts, as, for example:
## type
## i1 = [byte] -128..127;
## var
## v_i2 : [word] i1;
In addition to appearing in type definitions, attributes can also precede a compilation unit, where they are ignored by the preprocessor, with the exception of the attribute "[inherit('EQUEL')]", which has the same effect as an EQUEL
declare statement in the declaration section of the compilation unit. The
inherit attribute should appear alone, because the preprocessor discards any attributes that appear with it. For more information using this attribute in EQUEL, see
The Inherit Attribute.
Label Declarations
EQUEL/Pascal no longer requires the use of EQUEL
label declarations, required in earlier versions. As a better alternative, you should place the EQUEL ## mark before the header of each EQUEL compilation unit (
program,
module,
procedure, or
function) and the opening
begin and closing
end statements. If you do not either use the
label declaration or mark the compilation unit header, you will get an error message if the preprocessor needs to generate labels, and the resulting code will not compile. For more information on compilation unit syntax, see
Compilation Units and the Scope of Objects.
The Syntax of Label Declarations
Earlier versions of EQUEL/Pascal allowed the declaration of program-declared labels without a terminating semicolon:
## label
## start, stop
EQUEL/Pascal still allows this syntax but generates a warning. You can avoid the warning by terminating the label with a semicolon:
## label
## start, stop;
You need not use a semicolon if you do not declare any labels yourself:
## label
Constant Declarations
The syntax for a constant declaration is:
const constant_name = constant_expr;
{constant_name = constant_expr;}
where a constant_expr is one of the following:
[+|-] constant_number
[+|-] constant_name
string_constant
Constants can be used to set Ingres values but cannot be assigned values from Ingres.
Syntax Notes:
1. A constant_name must be a legal Pascal identifier beginning with an alphabetic character or an underscore.
2. A constant_number can be either an integer or real number. It cannot be a numeric expression.
3. EQUEL/Pascal recognizes only single, and not double or quadruple, exponential notation for constants of type real.
4. The type of a constant_name is determined from the type of its constant_expr.
5. If a constant_name used as a constant_expr is preceded by a '+' or '-', it must be numeric.
6. EQUEL/Pascal does not support the declaration of arbitrary constant expressions.
## const
## min_sal = 15000.00; {Real}
## pi = 3.14159; {Real}
## max_emps = +99; {Integer}
## max_credit = 100000.00; {Real}
## max_debt = -max_credit; {Real}
## yes = 'y'; {Char}
Type Declarations
An EQUEL/Pascal type declaration has the following syntax:
type type_name = type_definition;
{type_name = type_definition;}
where type_definition is any in the following table.
Type Definitions
Each of these type definitions is discussed in its own section below. All type names must be legal Pascal identifiers beginning with an alphabetic character or an underscore.
Renaming Type Definition
The declaration for the renaming of a type uses the following syntax:
type new_type_name = type_name;
Syntax Notes:
1. The type_name must be either an EQUEL/Pascal type or a type name already declared to EQUEL such as integer or real.
2. The new_type_name cannot be integer, real, or char, or any other type listed at the beginning of this section.
## type
## NaturalInt = Integer; {A "natural" sized integer}
Enumeration Type Definition
The declaration for an enumeration type definition has the following syntax:
type type_name = ( enum_identifier {, enum_identifier} );
Syntax Notes:
1. An enum_identifier must be a legal Pascal identifier beginning with an alphabetic character or underscore.
2. The enum_identifiers are treated as 4-byte integer constant identifiers.
3. The type_name maps to a 1-byte integer if there are fewer than 257 enumerated identifiers. Otherwise, it maps to a 2-byte integer.
4. When an enumerated identifier is used as a value in an EQUEL statement, only the ordinal position of the identifier in the original enumerated list is important. In assigning a value to a variable of enumeration type, EQUEL passes the variable by address and assumes that the value is a legal one for the variable.
The following is an example of an enumeration type definition:
## type
## Table_Field_States =
## (UNDEFINED, NEWROW, UNCHANGED, CHANGED, DELETED);
Subrange Type Definition
The syntax for declaring a subrange type definition is either:
type type_name = [+|-]integer_const .. [+|-]integer_const;
or
type type_name = string_const .. string_const;
Syntax Notes:
1. An integer_const may be either an integer literal or a named integer constant.
2. A string_const must be either a string literal or the name of a string constant. Although the preprocessor accepts any length string constant, the compiler requires the constant to be a single character.
## type
## Alpha = 'a' .. 'z';
## Months = 1 .. 12;
## MinMax = -Value .. Value; {"Value" is an
## integer constant}
## Updated_States = CHANGED .. DELETED;
Pointer Type Definition
The declaration for a pointer type definition has the following syntax:
type pointer_name = ^type_name;
Syntax Note:
The type_name can be either a previously defined type or a type not yet defined. If the type has not yet been defined, the pointer type definition is a forward pointer definition. In that case, EQUEL requires that the type_name be defined before a variable of type pointer_name is used in an EQUEL statement.
The following example illustrates the use of the pointer type definition:
## type
## EmpPtr =^EmpRecord;
## {Forward pointer declaration}
## EmpRecord = record
## e_name : varying[40] of Char;
## e_salary : Real;
## e_id : Integer;
## e_next : EmpPtr;
## end;
## var
## empnode = EmpPtr;
...
## retrieve (empnode^ .e_ename = emp.name,
## empnode^.e_salary = emp.salary,
## empnode^.e_id = emp.id)
Varying Length String Type Definition
The declaration for a varying length string type definition has the following syntax:
type varying_type_name = varying [upper_bound] of char_type_name;
Syntax Notes:
1. The upper_bound of a varying length string specification is not parsed by the EQUEL preprocessor. Consequently, an illegal upper bound (such as a non-numeric expression) will be accepted by the preprocessor but will later cause Pascal compiler errors. For example, both of the following type declarations are accepted, even though only the first is legal in Pascal:
## type
## String20 = varying[20] of Char;
## What = varying['upperbound'] of Char;
2. EQUEL/Pascal treats a variable of type varying of char as a string, not an array.
## type
## Pname = varying[100] of Char;
## var
## user_name : Pname;
...
## append to person (name = user_name)
Array Type Definition
The declaration for an array type definition has the following syntax:
type type_name = [packed] array [dimensions] of type_definition;
Syntax Notes:
1. The dimensions of an array specification are not parsed by the EQUEL preprocessor. Consequently, an illegal dimension (such as a non-numeric expression) will be accepted by the preprocessor but will later cause Pascal compiler errors. For example, both of the following type declarations are accepted, even though only the first is legal in Pascal:
## type
## Square = array[1..10, 1..10] of Integer;
## What = array['dimensions'] of Real;
The preprocessor only verifies that an array variable is followed by brackets when used (except packed array of char—see below).
2. EQUEL/Pascal treats a variable of type packed array of char as a string, not an array. Therefore, it is not followed by brackets when used.
3. Components of a packed array cannot be passed to the EQUEL runtime routines. Therefore, you should not declare packed arrays to EQUEL, except for packed arrays of char, which are passed as a whole (for example, as character strings).
The following example illustrates the use of the array type definition:
## type
## Ssid = packed array [1..9] of Char;
## var
## user_ssid : Ssid;
...
## append to person (ssno = user_ssid)
Record Type Definition
The declaration for a record type definition has the following syntax:
type record_type_name =
record
field_list [;]
end;
where field_list is:
field_element {; field_element}
[case [tag_name :] type_name of
[case_element {; case_element}]
[otherwise ( field_list )]]
where field_element is:
field_name {, field_name} : type_definition
and case_element is:
case_label {, case_label} : ( field_list )
Syntax Notes:
1. All clauses of a record component have the same rules and restrictions as they do in a regular type declaration. For example, as with regular declarations, the preprocessor does not check dimensions for correctness.
2. In the case list, the case_labels may be numbers or names. The names need not be known to EQUEL.
3. Pascal host code is not a legal EQUEL record component. Consequently, all components of the record must be preceded by the ## mark. To minimize the effect of this restriction, the types quadruple and set of are allowed as legal types in an EQUEL record declaration. It is, however, an error to use variables of those types in EQUEL statements.
4. Components of a packed record cannot be passed to the EQUEL runtime routines. Therefore, you should not declare packed records to EQUEL.
The following example illustrates the use of a record type definition:
## type
## AddressRec = record
## street: packed array[1..30] of Char;
## town: packed array[1..10] of Char;
## zip: 1 .. 9999;
## end;
## EmployeeRec = record
## name: packed array[1..20] of Char;
## age: [byte] 0 .. 128;
## salary: Real;
## address: AddressRec;
## checked: Boolean;
## scale: Quadruple;
{Requires ##, but cannot be used by EQUEL}
## end;
File Type Definition
The declaration for a file type definition has the following syntax:
type type_name = file of type_definition;
Syntax Notes:
1. A variable of type file can only be used with EQUEL through the file buffer. A file buffer for a given type_definition is referenced in the same manner as a pointer to the same type.
2. Components of a packed file cannot be passed to the EQUEL runtime routines. Therefore, you should not declare packed files to EQUEL.
The following example illustrates the use of a file type definition:
## var
## myfile : file of Integer;
## begin
...
get (myfile);
## append to emp (floor = myfile^);
...
## retrieve (myfile^ = emp.floor)
## begin
put (myfile);
## end;
Set Type Definition
The declaration for a set type definition has the following syntax:
type type_name = set of type_definition;
Syntax Note:
1. Although set definitions are accepted by the preprocessor, no set variables can be used in EQUEL statements. As discussed in the section above on record declarations, set declarations are accepted only because all record components must be declared to EQUEL.
Variable Declarations
An EQUEL/Pascal variable declaration has the following syntax:
var var_name {, var_name} : type_definition [:= initial_value];
{var_name {, var_name} : type_definition [:= initial_value];}
Syntax Notes:
1. See the previous section for information on the type_definition.
2. The initial_value is not parsed by the preprocessor. Consequently, any initial value is accepted, even if it later causes a Pascal compiler error. Furthermore, the preprocessor accepts an initial value with any variable declaration, even where not allowed by the compiler. For example, both of the following initializations are accepted, even though only the first is legal in Pascal:
## var
## rowcount: Integer := 1;
## msgbuf: packed array[1..100] of Char := 2;
The following is an example of a variable declaration:
## var
## rows, records: 0..500 := 0;
## was_error: Boolean;
## msgbuf: varying[100] of Char := ' ';
## operators: array[1..6] of packed array[1..2] :=
## ('= ', '!=', '< ', '> ', '<=', '>=');
## employees : array[1..100] of EmployeeRec;
## emp_ptr : ^EmployeeRec;
## work_days : (MON, TUE, WED, THU, FRI);
## day_name : varying[8] of Char;
## random_ints file of Integer;
## null_ind: Indicator;
Formal Parameter Declarations
Most VMS Pascal formal parameter declarations are acceptable to EQUEL. Declared formal parameters are treated as local variables by EQUEL. Note that host code is not allowed in an EQUEL formal parameter section; therefore, all formal parameters to a procedure or function known to EQUEL must be preceded by the ## mark.
An EQUEL/Pascal formal parameter declaration has the following syntax:
formal_param_section {; formal_param_section}
where formal_param_section is:
formal_var | formal_routine [:= [%mechanism] default_value]
A formal_var has the syntax:
[var | %mechanism] identifier {, identifier} : typename_or_schema
where typename_or_schema is one of the following:
type_name
varying [upper_bound_identifier] of type_name
packed array [schema_dimensions] of typename_or_schema
array [schema_dimensions {; schema_dimensions}] of
typename_or_schema
where schema_dimensions is:
lower_bound_identifier .. upper_bound_identifier : scalar_type_name
A formal_routine has the syntax:
[%mechanism] routine_header
where routine_header is one of the following:
procedure proc_name ( [formal_parameter_declaration] )
function func_name ( [formal_parameter_declaration] ) :
return_type_name
In a subprogram declaration, the syntax of a formal parameter declaration is:
procedure proc_name ( formal_parameter_declaration );
...
or:
function func_name ( formal_parameter_declaration ) : return_type_name;
...
Syntax Notes:
1. The EQUEL preprocessor ignores the names of procedures and functions used as formal parameters, but checks their formal parameters for legality.
2. The default_value is not parsed by the preprocessor. Consequently, any default value is accepted, even if it later causes a Pascal compiler error. For example, both of the following parameter default values are accepted, even though only the first is legal in Pascal:
## procedure Load_Table
## (clear_it: Boolean := TRUE;
## var is_error: Boolean := 'FALSE');
...
3. Any mechanism specification is ignored.
The following example contains formal parameter declarations:
## function GetEquelError( buf:varying[ub] of Char )
## : Boolean;
## procedure HandleError( procedure errorHandle(err : Integer);
## var errNum : Integer );
## function DoAppend( emp_id, floor : Integer;
## name : varying[ub] of Char;
## salary : Real ) : Integer;
Assembling and Declaring External Compiled Forms
You can pre-compile your forms in the Visual Forms Editor (VIFRED). This saves the time otherwise required at runtime to extract the form's definition from the database forms catalogs. When you compile a form in VIFRED, VIFRED creates a file in your directory describing the form in the VAX-11 MACRO language. VIFRED prompts you for the name of the file with the MACRO description. After the file is created, use the following command to assemble it into a linkable object module with the VMS command:
macro filename
This command produces an object file containing a global symbol with the same name as your form. Before the EQUEL/FORMS statement addform can refer to this global object, it must be declared in an EQUEL declaration section. The Pascal compiler requires that this be an external declaration. The syntax for a compiled form declaration is:
## var
## formname: [external] Integer;
Syntax Notes:
1. The formname is the actual name of the form. VIFRED gives this name to the address of the external object. The formname is also used as the title of the form in other EQUEL/FORMS statements. In all statements other than addform that use formname as an argument you must differentiate the name with a # sign.
2. The external attribute associates the object with the external form definition.
The example below shows a typical form declaration and illustrates the difference between using the form's object definition and the form's name.
## var
## empform: [external] Integer;
...
## addform empform {the global object}
## display #empform {the name of the form}
...
Concluding Example
The following example demonstrates some simple EQUEL/Pascal declarations:
## program Concluding_Example( input, output );
## const
## MAX_PERSONS = 1000;
## type
## ShortShortInteger = [byte] -128 .. 127;
## ShortInteger = [word] -32768 .. 32767;
{same as Indicator type}
## String9 = packed array[1..9] of Char;
## String12 = packed array[1..12] of Char;
## String20 = packed array[1..20] of Char;
## String30 = packed array[1..30] of Char;
## VarString = varying[40] of Char;
## record Datatypes_Rec = {Structure of all types}
## d_byte : ShortShortInteger;
## d_word : ShortInteger;
## d_long : Integer;
## d_single : Real;
## d_double : Double;
## d_string : String20;
## end;
## record Persontype_Rec = {Variant record}
## age : ShortShortInteger;
## flags : Integer;
## case married : Boolean of
## TRUE : (spouse_name : String30);
## FALSE : (dog_name : String12);
## end;
## var
## empform, deptform : [external] Integer; {Compiled forms}
## dbname : String9;
## formname, tablename, columnname : String12;
## salary : Real;
## d_rec : Datatypes_Rec;
## person : Persontype_Rec;
## person_store : array[1..MAX_PERSONS]
## of Persontype_Rec;
## person_null: array[1..10] of Indicator;
## begin
dbname := 'personnel';
...
## end. {Concluding_Example}