Document revision date: 30 March 2001
[Compaq] [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]
[OpenVMS documentation]

Guide to the DEC Text Processing Utility


Previous Contents Index

4.9.4 Declarations and Statements

A DECTPU program can consist of a sequence of declarations and statements. These declarations and statements control the action performed in a procedure or a program. The following reserved words are the language elements that when combined properly make up the declarations and statements of DECTPU:

GLOBAL, UNIVERSAL, BEGIN, and END are words reserved for future expansion of the DECTPU language.

The DECTPU declarations and statements are reserved words that you cannot define. Any attempt to redefine these words results in a compilation error.

4.9.4.1 Module Declaration

With the MODULE/ENDMODULE declaration, you can group a series of global CONSTANT declarations, VARIABLE declarations, PROCEDURE declarations, and executable statements as one entity. After you compile a module, the compiler will generate two procedures for you. One procedure returns the identification for the module and the other contains all the executable statements for the module. The procedure names generated by the compiler are module-name_MODULE_IDENT and module-name_MODULE_INIT, respectively.

Syntax

MODULE module-name IDENT string-literal [[declarations]] [[ON_ERROR ...
ENDON_ERROR]] statement_1; . . . statement_n; ENDMODULE

The declarations part of a module can include any number of global VARIABLE, CONSTANT, and PROCEDURE declarations.

The ON_ERROR/ENDON_ERROR block, if used, must appear after the declarations and before the DECTPU statements that make up the body of the module. Statements that make up the body of a module must be separated with semicolons. For more information on error handlers, see Section 4.9.4.14.

In the following example, the compiler creates two procedures: user_mod_module_ident and user_mod_module_init. User_mod_module_ident returns the string "v1.0". User_mod_module_init calls the routine user_hello.


MODULE user_mod IDENT "v1.0" 
 
PROCEDURE user_hello 
    MESSAGE ("Hello"); 
ENDPROCEDURE; 
 
ON_ERROR 
    MESSAGE ("Good-bye"); 
END_ON_ERROR; 
 
user_hello; 
ENDMODULE 

4.9.4.2 Procedure Declaration

The PROCEDURE/ENDPROCEDURE declaration delimits a series of DECTPU statements so they can be called as a unit. With the PROCEDURE/ENDPROCEDURE combination, you can declare a procedure with a name so that you can call it from another procedure or from the command line of a DECTPU editing interface. Once you have compiled a procedure, you can enter the procedure name as a statement in another procedure, or enter the procedure name after the TPU Statement: prompt on the command line of EVE.

Syntax

PROCEDURE procedure-name [[ (parameter-list) ]] [[local-declarations]]
[[ON_ERROR ... ENDON_ERROR]] statement_1; statement_2; . . . statement_n;
ENDPROCEDURE;

The local declarations part of a procedure can include any number of LOCAL and CONSTANT declarations.

The ON_ERROR/ENDON_ERROR block, if used, must appear after the declarations and before the DECTPU statements that make up the body of the procedure. For more information on error handlers, see Section 4.9.4.14.

After the ON_ERROR/ENDON_ERROR block, you can use any kind of DECTPU language statements in the body of a procedure except another ON_ERROR/ENDON_ERROR block. Statements that make up the body of a procedure must be separated with semicolons. For example:


PROCEDURE version 
         
   MESSAGE ("This is Version 1-020"); 
 
ENDPROCEDURE; 

This procedure writes the text "This is Version 1--020" in the message area.

4.9.4.3 Procedure Names

A procedure name can be any valid identifier that is not a DECTPU reserved word. Compaq suggests that you use a convention when naming your procedures. For instance, you might prefix procedure names with your initials. In this way, you can easily distinguish procedures that you write from other procedures such as the DECTPU built-in procedures. For example, if John Smith writes a procedure that creates two windows, he might name his procedure js_two_windows. This helps ensure that his procedure name is a unique name. Most of the sample procedures in this manual have the prefix user_ with procedure names.

4.9.4.4 Procedure Parameters

Using parameters with procedures is optional. If you use parameters, they can be input parameters, output parameters, or both. For example:


PROCEDURE user_input_output (a, b) 
 
   a := a + 5; 
   b := a; 
 
ENDPROCEDURE; 

In the preceding procedure, a is an input parameter. It is also an output parameter because it is modified by the procedure input_output. In the same procedure, b is an output parameter.

The scope of procedure parameters is limited to the procedure in which they are defined. The maximum number of parameters in a parameter list is 127. A procedure can declare its parameters as required or optional. Required parameters and optional parameters are separated by a semicolon. Parameters before the semicolon are required parameters; those after the semicolon are optional. If no semicolon is specified, then the parameters are required.

Syntax

PROCEDURE proc-name [[ ( [[req-param [[...]] ]] [[;opt-param [[...]] ]] ) ]] . . .
ENDPROCEDURE;

A procedure parameter is a place holder or dummy identifier that is replaced by an actual value in the program that calls the procedure. The value that replaces a parameter is called an argument. Arguments can be expressions. There does not have to be any correlation between the names used for parameters and the values used for arguments. All arguments are passed by reference. Example 4-4 shows a simple procedure with parameters.

Example 4-4 Simple Procedure with Parameters

!This procedure adds two integers. The parameters, int1 and int2, 
!are replaced by the actual values that you supply. 
!The result of the addition is written to the message area. 
 
PROCEDURE ADD (int1, int2) 
 
   MESSAGE (STR (int1 + int2)); 
 
ENDPROCEDURE; 

For example, call the procedure ADD and specify the values 5 and 6 as arguments, as follows:


ADD (5, 6); 

The string "11" is written to the message buffer.

Any caller of a procedure must use all required parameters to call it. The caller can also use optional parameters. If the required parameters are not present or the procedure is called with too many parameters (more than the sum of the required and optional parameters), then DECTPU issues an error.

If a procedure is called with the required number of parameters, but with less than the maximum number of parameters, then the remaining parameters up to the maximum automatically become "null parameters." A null parameter is a modifiable parameter of data type unspecified. A null parameter can be assigned a value and will become the value it is assigned, but the parameter's value is discarded when the procedure exits.

Null parameters can also be explicitly passed to a procedure. You can do this by omitting a parameter when calling the procedure.

Example 4-5 shows a more complex procedure that uses optional parameters.

Example 4-5 Complex Procedure with Optional Parameters

CONSTANT 
    user_warning       := 0,        ! Warning severity code 
    user_success       := 1,        ! Success severity code 
    user_error         := 2,        ! Error severity code 
    user_informational := 3,        ! Informational severity code 
    user_fatal         := 4;        ! Fatal severity code 
! 
! Output a message with fatal/error/warning flash. 
! 
PROCEDURE user_message (the_text; the_severity) 
 
LOCAL flash_it; 
! 
! Only flash warning, error, or fatal messages. 
! 
CASE the_severity FROM user_warning TO user_fatal 
    [user_warning, user_error, user_fatal] : flash_it := TRUE; 
        
    [user_success, user_informational] : flash_it := FALSE; 
        
    [OUTRANGE] : flash_it := FALSE; 
        
ENDCASE; 
! 
! Output the message - flash it, if appropriate. 
! 
MESSAGE (the_text); 
IF flash_it 
THEN 
    SLEEP ("0 00:00:00.3"); 
    MESSAGE (""); 
    SLEEP ("0 00:00:00.3"); 
    MESSAGE (the_text); 
ENDIF; 
 
ENDPROCEDURE; 

Caution

Do not assume that the DECTPU compiler automatically evaluates parameters in the order in which you place them.

To avoid the need to rewrite code, you should write as if this compiler optimization were already implemented. If you need the compiler to evaluate parameters in a particular order, you should force the compiler to evaluate each parameter in order before calling the procedure. To do so, use each parameter in an assignment statement before calling the procedure. For example, suppose you want to call a procedure whose parameter list includes PARAM_1 and PARAM_2. Suppose, too, that PARAM_1 must be evaluated first. To get this result, you could use the following code:


partial_1 := param_1; 
partial_2 := param_2;   
my_procedure (partial_1, partial_2); 

4.9.4.5 Procedures That Return a Result

Procedures that return a result are called function procedures. Example 4-6 shows a procedure that returns a true (1) or false (0) value.

Note

All DECTPU procedures return a result. If they do not do so explicitly, DECTPU returns 0.

Example 4-6 Procedure That Returns a Result

PROCEDURE user_on_end_of_line !test if at eol, return true or false 
 
IF CURRENT_OFFSET = LENGTH (CURRENT_LINE)    ! we are on eol 
THEN 
    user_on_end_of_line := 1                   ! return true 
ELSE 
    user_on_end_of_line := 0                   ! return false 
ENDIF; 
 
ENDPROCEDURE; 

Another way of assigning a value of 1 or 0 to a procedure is to use the DECTPU RETURN language statement followed by a value. See Example 4-13.

You can use a procedure that returns a result as a part of a conditional statement to test for certain conditions. Example 4-7 shows the procedure in Example 4-6 within another procedure.

Example 4-7 Procedure Within Another Procedure

PROCEDURE user_nested_procedure 
   . 
   . 
   . 
IF user_on_end_of_line = 1              ! at the eol mark 
THEN 
    MESSAGE ("Cursor is at the end of the line") 
ELSE 
    MESSAGE ("Cursor is not at the end of the line") 
ENDIF; 
   . 
   . 
   . 
ENDPROCEDURE; 

4.9.4.6 Recursive Procedures

Procedures that call themselves are called recursive procedures. Example 4-8 shows a procedure named user_reverse that displays a list of responses to the READ_LINE built-in procedure in reverse order. Note the call to the procedure user_reverse within the procedure body.

Example 4-8 Recursive Procedure

PROCEDURE user_reverse 
LOCAL temp_string; 
 
temp_string := READ_LINE("input>");  
 
                          ! Read a response 
 
IF temp_string <> " "     ! Quit if nothing entered 
                          ! but the RETURN key. 
THEN 
    user_reverse          ! Call user_reverse recursively 
ELSE  
    RETURN                ! All done, go to display lines 
ENDIF; 
MESSAGE (temp_string);    ! Display lines typed in reverse order 
                          ! in the message window 
ENDPROCEDURE; 

4.9.4.7 Local Variables

The use of local variables in procedures is optional. If you use local variables, they hold the values that you assign them only in the procedure in which you declare them. The maximum number of local variables that you can use is 255. Local variables are initialized to 0.

Syntax

LOCAL variable-name [[,...]];

If you declare a local variable in a procedure and, in the same procedure, use the EXECUTE built-in to assign a value to a variable with the same name as the local variable, the result of the EXECUTE built-in has no effect on the local variable. Consider the following code fragment:


PROCEDURE test 
   LOCAL X; 
   EXECUTE ("X := 3"); 
   MOVE_VERTICAL (X); 
ENDPROCEDURE; 

In this fragment, when the compiler evaluates the string "X := 3", the compiler assumes X is a global variable. The compiler creates a global variable X (if none exists) and assigns the value 3 to the variable. When the MOVE_VERTICAL built-in procedure uses the local variable X, the local variable has the value 0 and the MOVE_VERTICAL built-in has no effect.

Local variables may also be declared in unbound code. See Section 4.9.5.2.

4.9.4.8 Constants

The use of constants in procedures is optional. The scope of a constant declared within a procedure is limited to the procedure in which it is defined. See Section 4.9.5.3 for more information on the CONSTANT declaration.

Syntax

CONSTANT constant-name := compile-time-constant-expression [[,...]];

4.9.4.9 ON_ERROR Statements

The use of ON_ERROR statements in procedures is optional. If you use an ON_ERROR statement, you must place it at the top of the procedure just after any LOCAL and CONSTANT declarations. The ON_ERROR statement specifies the action or actions to be taken if an ERROR or WARNING status is returned. See Section 4.9.4.14 for more information on ON_ERROR statements.

4.9.4.10 Assignment Statement

The assignment statement assigns a value to a variable. In so doing, it associates the variable with the appropriate data type.

Syntax

identifier := expression;

The assignment operator is a combination of two characters: a colon and an equal sign (:=). Do not confuse this operator with the equal sign (=), which is a relational operator that checks for equality.

DECTPU does not do any type checking on the data type being stored. Any data type may be stored in any variable. For example:


X := "abc"; 

This assignment statement stores the string "abc" in variable X.

4.9.4.11 Repetitive Statement

The LOOP/ENDLOOP statements specify the repetitive execution of a statement or statements until the condition specified by EXITIF is met.

Syntax

LOOP statement_1; statement_2; . . . EXITIF expression; statement_n;
ENDLOOP;

The EXITIF statement is the mechanism for exiting from a loop. You can place the EXITIF statement anywhere inside a LOOP/ENDLOOP combination. You can also use the EXITIF statement as many times as you like. When the EXITIF statement is true, it causes a branch to the statement following the ENDLOOP statement.

Syntax

EXITIF expression;

The expression is optional; without it, EXITIF always exits from the loop.

Any DECTPU language statement except an ON_ERROR statement can appear inside a LOOP/ENDLOOP combination. For example:


LOOP 
   EXITIF CURRENT_OFFSET = 0; 
   temp_string := CURRENT_CHARACTER; 
   EXITIF (temp_string <> " ") AND 
          (temp_string <> ASCII(9)); 
   MOVE_HORIZONTAL (-1); 
   temp_length := temp_length + 1; 
ENDLOOP; 

This procedure uses the EXITIF statement twice. Each expression following an EXITIF statement defines a condition that causes an exit from the loop. The statements in the loop are repeated until one of the EXITIF conditions is met.

4.9.4.12 Conditional Statement

The IF/THEN statement causes the execution of a statement or group of statements, depending on the value of a Boolean expression. If the expression is true, the statement is executed; otherwise, program control passes to the statement following the IF/THEN statement.

The optional ELSE clause provides an alternative group of statements for execution. The ELSE clause is executed if the test condition specified by IF/THEN is false.

The ENDIF statement specifies the end of a conditional statement.

Syntax

IF expression THEN statement_1; . . . statement_n [[ELSE alternate-statement_1;
. . . alternate-statement_n;]] ENDIF;

You can use any DECTPU language statements except ON_ERROR statements in a THEN or ELSE clause. For example:


PROCEDURE set_direct 
 
MESSAGE ("Press PF3 or PF4 to indicate direction"); 
temp_char := READ_KEY; 
IF temp_char = KP5 
THEN 
    SET (REVERSE, CURRENT_BUFFER); 
ELSE 
    IF temp_char = KP4 
    THEN 
        SET (FORWARD, CURRENT_BUFFER); 
    ENDIF; 
ENDIF; 
 
ENDPROCEDURE; 

In this example, nested IF/THEN/ELSE statements test whether a buffer direction should be forward or reverse.

Caution

Do not assume that the DECTPU compiler automatically evaluates all parts of an IF statement.

To avoid the need to rewrite code, you should write as if this compiler optimization were already implemented. If you need the compiler to evaluate all clauses of a conditional statement, you should force the compiler to evaluate each clause before using the conditional statement. To do so, use each clause in an assignment statement before using it in a conditional statement. For example, suppose you want the compiler to evaluate both CLAUSE_1 and CLAUSE_2 in a conditional statement. To get this result, you could use the following code:


relation_1 := clause_1; 
relation_2 := clause_2; 
IF relation_1 AND relation_2 
THEN 
  . 
  . 
  . 
ENDIF; 

4.9.4.13 Case Statement

The CASE statement is a selection control structure that lets you list several alternate actions and choose one of them to be executed at run time. In a CASE statement, case labels are associated with the possible executable statements or actions to be performed. The CASE statement then executes the statement or statements labeled with a value that matches the value of the case selector.

Syntax


CASE case-selector [[FROM 
lower-constant-expr, TO upper-constant-expr]]
     [constant-expr_1 [[,...]]] : statement [[,...]]; 
     [constant-expr_2 [[,...]]] : statement [[,...]]; 
          . 
          . 
          . 
 
     [constant-expr_n [[,...]]] : statement [[,...]]; 
 
 
    [[[INRANGE] : statement [[,...]] ;]]
 
    [[[OUTRANGE] : statement [[,...]] ;]]
ENDCASE; 

The single brackets are not optional for case constants. Example 4-9 shows how to use the CASE statement in a procedure.

CASE constant expressions must evaluate at compile time to either a keyword, a string constant, or an integer constant. All constant expressions in the CASE statement must be of the same data type. There are two special case constants in DECTPU: INRANGE and OUTRANGE. INRANGE matches anything that falls within the case range that does not have a case label associated with it. OUTRANGE matches anything that falls outside the case range. These special case constants are optional.

FROM and TO clauses of a CASE statement are not required. If FROM and TO clauses are not specified, INRANGE and OUTRANGE labels refer to data between the minimum and maximum specified labels.

Example 4-9 shows a sample procedure that uses the CASE statement.

Example 4-9 Procedure That Uses the CASE Statement

PROCEDURE grades 
 
answers := READ_LINE ("Enter number of correct answers:",5); 
answers := INT (answers); 
 
CASE answers FROM 0 TO 10 
                   [10] : score := "A+"; 
                    [9] : score := "A"; 
                    [8] : score := "B"; 
                    [7] : score := "C"; 
                    [6] : score := "D"; 
          [0,1,2,3,4,5] : score := "F"; 
             [OUTRANGE] : score := "Invalid entry."; 
ENDCASE; 
 
MESSAGE (score); 
 
ENDPROCEDURE; 

This CASE statement compares the value of the constant selector answers to the case labels (the numbers 0 through 10). If the value of answers is any of the numbers from 0 through 10, the statement to the right of that number is executed. If the value of answers is outside the range of 0 through 10, the statement to the right of [OUTRANGE] is executed. The value of score is written in the message area after the execution of the CASE statement.


Previous Next Contents Index

  [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]  
  privacy and legal statement  
6018PRO_008.HTML