HP OpenVMS Systems Documentation

Content starts here

HP BASIC for OpenVMS
User Manual


Previous Contents Index

2.3 Running an HP BASIC Program

After you link your program, use the DCL command RUN to execute it. The RUN command has the following format:


RUN [/[NO]DEBUG] file-spec [/[NO]DEBUG]

/[NO]DEBUG

The /[NO]DEBUG qualifier is optional. Specify the /DEBUG qualifier to request the debugger if the image is not linked with it. You cannot use /DEBUG on images linked with the /NOTRACEBACK qualifier. If the image is linked with the /DEBUG qualifier, and you do not want the debugger to prompt, use the /NODEBUG qualifier. The default action depends on whether the file is linked with the /DEBUG qualifier.

file-spec

The name of the file you want to execute.

The following example executes the image SAMPLE.EXE without invoking the debugger:


$ RUN SAMPLE/NODEBUG

See Chapter 3 for more information about debugging programs.

During program execution, an image can generate a fatal error called an exception condition. When an exception condition occurs, HP BASIC displays an error message. Run-time errors can also be issued by other facilities, such as the OpenVMS operating system. For more information about run-time errors, see Appendix B.

2.3.1 Improving Run-Time Performance of HP BASIC Programs

Even with fast hardware and an optimizing compiler, you can still tune your code for run-time performance. This section provides recommendations to consider if further performance improvements are desirable.

To achieve the best performance for your application, it is important to let both the hardware and the optimizer/code generator take advantage of their full capabilities. This can be accomplished by minimizing, and in some cases avoiding, the use of language features and qualifiers that block optimal program execution.

2.3.1.1 Data Items

Choose data types and align data items with the following in mind:

  • Align data items in MAP, COMMON, and RECORD statements. This is the recommended first step to improve performance. For more information on alignment, see Section 2.1.2 under /WARNING = ALIGNMENT.
  • Use LONG or QUAD data items instead of BYTE and WORD; accessing LONG or QUAD items is faster than BYTE and WORD, which may require multiple hardware instructions.
  • On Alpha, use GFLOAT or TFLOAT data items instead of DOUBLE; operations are faster on GFLOAT and TFLOAT items. Operations on DOUBLE operands are performed by converting to GFLOAT, performing the operation in GFLOAT, and converting back to DOUBLE.
  • On Itanium, use IEEE data items instead of VAX floating-point data items. VAX data type operands are converted to appropriate IEEE types before being operated on.
  • Choose packed decimal lengths that are the most efficient while still meeting the needs of the application. The most efficient sizes are the default size of 15 digits (which fits exactly in a quadword) and 7 digits (which fits exactly in a longword). If you use one of these preferred sizes, it should be aligned on a quadword or longword boundary.
  • Use packed decimal only when it is the appropriate data type. For example, do not use packed decimal to specify array subscripts, which are integers.
  • Minimize mixed data type expressions, especially when you use packed decimal.

2.3.1.2 Qualifiers

On your BASIC command line, consider the following when you specify qualifiers:

  • Use overflow and bounds checking only if they are needed. (See Section 2.1.2; bounds checking is needed if your program is not thoroughly debugged.) Both of these /CHECK options are on by default and will hinder performance.
  • The use of the /LINES qualifier can impede optimization. /LINES is needed in Alpha BASIC only for the ERL function and to print BASIC line numbers in run-time error messages. /NOLINES is the default in Alpha BASIC.
  • The default optimization level, /OPTIMIZATION = LEVEL = 4, provides the highest level of optimization.
  • The /SYNCHRONOUS_EXCEPTIONS qualifier inhibits many optimizations. For more information on /SYNCHRONOUS_EXCEPTIONS, see Section 2.1.2.

2.3.1.3 Statements

The statements used in a program can affect performance, as follows:

  • If you use error handling, the default ON ERROR GO BACK has the least impact on performance. ON ERROR GOTO {target} and WHEN blocks have a greater impact. If the application spends a large percentage of time in one routine, consider writing the routine with default error handling, if possible.
  • RESUME without a target impedes optimization. (This applies only to RESUME statements that do not specify a target.)
  • A MOVE TO or FIELD statement limits optimizations in the entire routine (SUB, FUNCTION, or main) where the statement is found. There is no additional cost for any statement after the first.
  • OPTION INACTIVE = SETUP can dramatically minimize routine startup times by omitting RTL calls that initialize and close down routines. For small BASIC routines, the overhead of these RTL calls can be significant. Use this option for routines that are frequently called.
    If your routine contains any of the following elements, the compiler provides an informational diagnostic and emits calls to the RTL initialization and close-down routines:
    CHANGE statements
    DEF statements
    Dynamic string variables
    Executable DIM statements
    EXTERNAL string functions
    MAT statements
    MOVE statements for an entire array
    ON ERROR statements
    READ statements
    REMAP statements
    RESUME statements
    WHEN blocks
    String concatenation
    Built-in string functions
    Virtual arrays

    Routines using OPTION INACTIVE = SETUP cannot perform I/O and have no error-handling capabilities. If an error occurs in such a routine, the error is resignaled to the calling routine.
    Using OPTION INACTIVE = SETUP instructs the compiler not to emit code to initialize local variables. This also improves run-time performance, but impacts routines that rely upon the automatic initialization of local variables.
  • CONTINUE without a target and RETRY can limit optimizations within the scope of the WHEN blocks associated with the handler that contains these statements. This impact can be significant if the handler is associated with a large WHEN block. The code within the associated WHEN blocks will be minimally optimized.


Chapter 3
Using the OpenVMS Debugger with BASIC

This chapter discusses OpenVMS Debugger information that is specific to the BASIC language. For more information about the OpenVMS Debugger, see the HP OpenVMS Debugger Manual. Online help is available during debugging sessions.

3.1 Overview of the Debugger

A debugger is a tool to help you locate run-time errors quickly. It is used with a program that has already been compiled and linked successfully, with no errors reported, but that does not run correctly. For example, the output might be obviously wrong, the program goes into an infinite loop, or the program terminates prematurely. The debugger enables you to observe and manipulate the program's execution interactively, step by step, until you locate the point at which the program stopped working correctly.

The OpenVMS Debugger is a symbolic debugger, which means that you can refer to program locations by the symbols (names) you used for those locations in your program---the names of variables, routines, labels, and so on. You do not have to use virtual addresses to refer to memory locations.

The debugger recognizes the syntax, expressions, data typing, and other constructs of BASIC.

3.2 Compiling and Linking to Prepare for Debugging

The following example shows how to compile and link a BASIC program (consisting of a single compilation unit named INVENTORY) so that subsequently you will be able to use the debugger:


$ BASIC/DEBUG INVENTORY
$ LINK/DEBUG INVENTORY

The /DEBUG qualifier with the BASIC command instructs the compiler to write the debug symbol records associated with INVENTORY into the object module, INVENTORY.OBJ. These records allow you to use the names of variables and other symbols declared in INVENTORY in debugger commands. (If your program has several compilation units, you must compile each unit that you want to debug with the /DEBUG qualifier.)

The /DEBUG qualifier with the LINK command instructs the linker to include all symbol information that is contained in INVENTORY.OBJ in the executable image. The qualifier also causes the OpenVMS image activator to start the debugger at run time. (If your program has several object modules, you might need to specify other modules in the LINK command.)

3.3 Viewing Your Source Code

The debugger provides two methods for viewing source code: noscreen mode and screen mode. By default when you invoke the debugger, you are in noscreen mode, but you might find that it is easier to view your source code with screen mode. Both modes are described in the following sections.

3.3.1 Noscreen Mode

Noscreen mode is the default, line-oriented mode of displaying input and output. To get into noscreen mode from screen mode, enter SET MODE NOSCREEN. See the sample debugging session in Section 3.7 for a demonstration of noscreen mode.

In noscreen mode, you can use the TYPE command to display one or more source lines. For example, the following command displays line 3 of the module that is currently executing:


DBG> TYPE 3
3:    EXTERNAL SUB TRIPLE    &
DBG>

The display of source lines is independent of program execution. You can use the TYPE command to display source code from a module other than the one currently executing. In that case, you need to use a directory specification to specify the module. For example, the following command displays lines 16 to 21 of module TEST:


DBG> TYPE TEST\16:21

3.3.2 Screen Mode

To invoke screen mode, press PF3. In screen mode, by default the debugger splits the screen into three displays called SRC, OUT, and PROMPT.


--SRC: module SAMPLE$MAIN -scroll-source--------------------------
     1:  10     !SAMPLE
     2:
     3:         EXTERNAL SUB TRIPLE        &
     4:                     ,PRINT_SUB
     5:
     6:         WHEN ERROR USE HANDLER_1
  -> 7:           CALL TRIPLE
     8:           CALL PRINT_SUB
     9:
- OUT -output---------------------------------------------
stepped to SAMPLE$MAIN\%LINE 7




- PROMPT -error-program-prompt----------------------------
DBG> STEP
DBG>

The SRC display, at the top of the screen, shows the source code of the module (compilation unit) that is currently executing. An arrow in the left column points to the next line to be executed, which corresponds to the current location of the program counter (PC). The line numbers, which are assigned by the compiler, match those in a listing file.

Note

BASIC line numbers are treated as text by the debugger. In this chapter, line numbers refer to the sequential line numbers generated by the compiler. When a program includes or appends code from another file, the included lines of code are also numbered in sequence by the compiler. These line numbers are on the extreme left of a listing file. An explanation of the listing file format is in Chapter 2.

The PROMPT display, at the bottom of the screen, shows the debugger prompt (DBG>), your input, debugger diagnostic messages, and program output. In the example, the debugger commands that have been issued are shown.

The OUT display, in the center of the screen, captures the debugger's output in response to the commands that you issue.

The SRC and OUT displays are scrollable so that you can see whatever information scrolls beyond the display window's edge. Press KP8 to scroll up and KP2 to scroll down. Press KP3 to change the display to be scrolled (by default, the SRC display is scrolled). Scrolling a display does not affect program execution.

If the debugger cannot locate source lines for the currently executing module, it tries to display source lines in the next module down on the call stack for which source lines are available and issues the following message:


%DEBUG-I-SOURCESCOPE, Source lines not available for .0\%PC.
        Displaying source in a caller of the current routine.

Source lines might not be available for the following reasons:

  • The PC is within a system routine, or a shareable image routine for which no source code is available.
  • The PC is within a routine that was compiled without the /DEBUG compiler command qualifier (or with /NODEBUG).
  • The source file was moved to a different directory after it was compiled (the location of source files is embedded in the object modules). Use the SET SOURCE command to direct the debugger to the new location.

3.4 Controlling and Monitoring Program Execution

This section discusses the following:

  • Starting and resuming program execution with the GO command
  • Stepping through the program's code with the STEP command
  • Determining the current location of the program counter (PC) with the SHOW CALLS command
  • Suspending program execution with breakpoints
  • Tracing program execution with tracepoints
  • Monitoring changes in variables with watchpoints

3.4.1 Starting and Resuming Program Execution

There are two commands for starting or resuming program execution: GO and STEP. The GO command starts execution. The STEP command lets you execute a specified number of source lines or instructions.

GO Command

The GO command starts program execution, which continues until forced to stop. You will probably use the GO command most often in conjunction with breakpoints, tracepoints, and watchpoints. If you set a breakpoint in the path of execution and then enter the GO command (or press the keypad comma key that executes the GO command), execution will be suspended when the program reaches that breakpoint. If you set a tracepoint, the path of execution through that tracepoint will be monitored. If you set a watchpoint, execution will be suspended when the value of the watched variable changes.

You can also use the GO command to test for an exception condition or an infinite loop. If an exception condition that is not handled by your program occurs, the debugger will take over and display the DBG> prompt so that you can issue commands. If you are using screen mode, the pointer in the source display will indicate where execution stopped. You can then use the SHOW CALLS command (see Section 3.4.2) to identify the currently active routine calls (the call stack).

In the case of an infinite loop, the program will not terminate, so the debugger prompt will not reappear. To obtain the prompt, interrupt the program by pressing Ctrl/Y and then issue the DCL command DEBUG. You can then look at the source display and a SHOW CALLS display to locate the PC.

STEP Command

The STEP command (which you can use either by entering STEP or by pressing KP0) allows you to execute a specified number of source lines or instructions, or to execute the program to the next instruction of a particular kind, for example, to the next CALL instruction.

By default, the STEP command executes a single source line at a time. In the following example, the STEP command executes one line, reports the action ("stepped to..."), and displays the line number (27) and source code of the next line to be executed:


DBG> STEP
stepped to TEST\COUNTER\%LINE 27
     27:   X = X + 1
DBG>

The PC is now at the first machine code instruction for line 27 of the module TEST; line 27 is in COUNTER, a routine within the module TEST. TEST\COUNTER\%LINE 27 is a directory specification. The debugger uses directory specifications to refer to symbols. (However, you do not need to use a path name in referring to a symbol, unless the symbol is not unique; in that case, the debugger will issue an error message.) See the HP OpenVMS Debugger Manual or online help for more information about resolving multiply-defined symbols.

You can specify a number of lines for the STEP command to execute. In the following example, the STEP command executes three lines:


DBG> STEP 3

Note that only those source lines for which code instructions were generated by the compiler are recognized as executable lines by the debugger. The debugger skips over any other lines---for example, comment lines.

Also, if a line has more than one statement on it, the debugger will execute all the statements on that line as part of the single step.

Using the STEP/OVER command to step over a GOSUB statement will still proceed to the target of the GOSUB since this statement is just a special kind of GOTO statement and not a routine call.

You can specify different stepping modes, such as stepping by instruction rather than by line (SET STEP INSTRUCTION). To resume to the default behavior, enter the SET STEP LINE command. Also by default, the debugger steps over called routines---execution is not suspended within a called routine, although the routine is executed. By entering the SET STEP INTO command, you tell the debugger to suspend execution within called routines as well as within the currently executing module. To resume the default behavior, enter the SET STEP OVER command.

3.4.2 Determining the Current Location of the Program Counter

The SHOW CALLS command lets you determine the current location of the program counter (PC) (for example, after returning to the debugger following a Ctrl/Y interrupt). The command shows a traceback that lists the sequence of calls leading to the currently executing routine. For example:


DBG> SHOW CALLS
 module name      routine name       line     rel PC    abs PC

*TEST             PRODUCT              18    00000009  0000063C
*TEST             COUNTER              47    00000009  00000647
*MY_PROG          MY_PROG              21    0000000D  00000653
DBG>

For each routine (beginning with the currently executing routine), the debugger displays the following information:

  • Name of the module that contains the routine
  • Name of the routine

  • Line number at which the call was made (or at which execution is suspended, in the case of the current routine)
  • Corresponding PC addresses (the relative PC address from the start of the routine and the absolute PC address of the program)

This example indicates that execution is currently at line 18 of routine PRODUCT (in module TEST), which was called from line 47 of routine COUNTER (in module TEST), which was called from line 21 of routine MY_PROG (in module MY_PROG).

3.4.3 Suspending Program Execution

The SET BREAK command lets you select breakpoints, which are locations at which the program will stop running. When you reach a breakpoint, you can enter commands to check the call stack, examine the current values of variables, and so on.

A typical use of the SET BREAK command is shown in the following example:


DBG> SET BREAK COUNTER
DBG> GO
    .
    .
    .
break at TEST\COUNTER
     34:  SUB COUNTER(LONG X,Y)
DBG>

In this example, the SET BREAK command sets a breakpoint on the subprogram COUNTER; the GO command starts execution. When the subprogram COUNTER is encountered, execution is suspended, the debugger announces that the breakpoint at COUNTER has been reached (break at ...), displays the source line (34) where execution is suspended, and prompts you for another command. At this breakpoint, you can step through the subprogram COUNTER, using the STEP command, and use the EXAMINE command (see Section 3.5.1) to check on the current values of X and Y.

When using the SET BREAK command, you can specify program locations using various kinds of address expressions (for example, line numbers, routine names, instructions, virtual memory addresses). With high-level languages, you typically use routine names, labels, or line numbers, possibly with directory specifications to ensure uniqueness.

Routine names and labels should be specified as they appear in the source code. Line numbers may be derived from either a source code display or a listing file. When specifying a line number, use the prefix %LINE. (Otherwise, the debugger will interpret the line number as a memory location.) For example, the next command sets a breakpoint at line 41 of the currently executing module; the debugger will suspend execution when the PC is at the start of line 41:


DBG> SET BREAK %LINE 41

Note that you can set breakpoints only on lines that resulted in machine code instructions. The debugger warns you if you try to do otherwise (for example, on a comment line). If you want to pick a line number in a module other than the one currently executing, you need to specify the module's name in a directory specification. For example:


DBG> SET BREAK SCREEN_IO\%LINE 58

You do not always have to specify a particular program location, such as line 58 or COUNTER, to set a breakpoint. You can set breakpoints on events, such as exceptions. You can use the SET BREAK command with a qualifier, but no parameter, to break on every line, or on every CALL instruction, and so on. For example:


DBG> SET BREAK/LINE
DBG> SET BREAK/CALL

You can conditionalize a breakpoint (with a WHEN clause) or specify that a list of commands be executed at the breakpoint (with a DO clause on the debugger command). For example, the next command sets a breakpoint on the label LOOP3. The DO (EXAMINE TEMP) clause causes the value of the variable TEMP to be displayed whenever the breakpoint is triggered.


DBG> SET BREAK LOOP3 DO (EXAMINE TEMP)
DBG> GO
    .
    .
    .
break at COUNTER\LOOP3
     37:    LOOP3: FOR I = 1 TO 10
COUNTER\TEMP:   284.19
DBG>

To display the currently active breakpoints, enter the SHOW BREAK command:


DBG> SHOW BREAK
breakpoint at SCREEN_IO\%LINE 58
breakpoint at COUNTER\LOOP3
   do (EXAMINE TEMP)
    .
    .
    .
DBG>

To cancel a breakpoint, enter the CANCEL BREAK command, specifying the program location exactly as you did when setting the breakpoint. The CANCEL BREAK/ALL command cancels all breakpoints.


Previous Next Contents Index