Previous Up Next

The screen management module
(screen)

Introduction

The objectives of the screen management module are to display to the user the scanning/parsing and generation process, and to help him correct errors in the input file.

The module makes use of a primitive terminal interface module that implements escape sequences for a VT100 terminal. The VT100 terminal supports a subset of the ANSI standard. The standard SMG facility on the VAX/VMS operating system has not been used, because it does not provide the required operations, especially those used for moving the stack. This approach has the disadvantage that implementations on other terminals require a completely new primitive terminal interface module, or could even require the screen management module to be modified.

The module has the capability to switch off the graphical features, allowing it to be used with any common terminal.

The module is constructed in such a way that it can easily be used in other programs as well. The module can also be used as a debugging tool for those who are constructing a program, or even other programs that use recursive procedures. In the third section some advice is given how this could be done.

1 Functionality

The module is designed to give a visual representation of the scanning and parsing process, with the possibility to signal errors, and to display the generation process. We first describe its function when using a VT100 terminal.

The scanning process tries to recognize lexical symbols in the stream of characters from the input file. The module provides a number of procedures to display the input file on the screen, together with line numbers, and the possibility to mark the last scanned symbol, by means of highlighting.

The parsing process is the process that checks whether the sequence of lexical symbols, read by the scanning process, satisfies a given (context free) grammar. The two most widely used parsing methods are LL(1) and LALR(1). Both of these methods use a stack. The LL(1) method works top down, so we could display all the (non)terminals from the root symbol to the current (non)terminal in the form of an upside down stack. The LALR(1) method works with a state stack, which could also be displayed on the screen.

The module provides a visual stack on the screen, with the top of the stack at the bottom, and no limit on the numbers of elements in the stack (except the physical memory space). Each element of the stack is composed of two parts, namely the name part and the information part. The name part is used for the identification of the element at creation time, and cannot be changed. The information part is used to display any information that the program wants to display. It does not have to be filled, and can be changed as often as desired.

Both the scanning and parsing process can detect syntactical and semantical errors. The scanner can find strings of characters that are not correct symbols. The parser can find symbols that are not allowed according to the grammar. In this case it can either insert missing symbols or skip symbols in order to come back on the rails again.

The module provides procedures to display both the skipping of symbols (by underlining them) and signaling all other errors by a one line error message at the bottom line of the screen, together with a beep signal and the blinking of the last scanned symbol. It also pauses a given time, which allows the user to press a no-scroll key, to inspect the error message and find the cause of the error.

During the generation process the generated symbols can be shown on the screen in the same way as they are generated in the output file.

The module also provides other facilities. Firstly, it displays the name of the program on the first line, together with an elapsed run time that can be updated as often as one wishes. Secondly, there is a wait procedure to slow down the displaying process in certain critical areas.

When a lot of information is displayed, this leads to a lower running speed of the program that uses the module, due to terminal limitations. The module has the option to reduce the amount of information that is displayed. In this mode highlighting of the last scanned symbol and displaying the stack is suppressed until an error is detected. Whenever this happens the top of the stack scrolls down and the error message is displayed, and after a pause it scrolls up again. It is possible to implement this feature as a option that can be given by the user. This allows the user to decide which mode is desired, depending on the expected number of errors. We call the normal way of operating tracing mode, and the other mode fast mode.

The module also has the option to operate in vt100 mode or not, as explained earlier. It is possible and recommended to let the user control this option, allowing the program to operate on any kind of terminal. When not in vt100 mode, the different kinds of actions on the screen are displayed on separate lines, giving almost the same quality as when in vt100 mode. Sometimes it is better not to use vt100 mode at all, to make the program faster. When vt100 mode is switched off, both trace mode and fast mode can still be used.

1.1 Layout of the terminal screen

When in vt100 mode the screen is split into four different screens. The top two lines form the header screen. The following part of the terminal screen is used as the stack screen. The stack screen is not always visible, and its length can vary. The rest of the screen, except the bottom line, is used for the listing screen. The bottom line contains the error screen.

2 Description

In this section we describe the procedures in the screen management module, and how they should be used. In the third subsection we present a grammar that describes the order in which all the procedures need to be called.

2.1 General procedures

We begin with a number of general procedures. The following procedures are used to establish a screen session. Within the screen session all other procedures can be called. It is possible to have a sequence of screen sessions within one program. Most of the procedures described here change the header screen.

2.1.1 Initialize screen

In the procedure initialize screen a screen session is started. The header of this procedure is:

If the second parameter vt100 used is equal to TRUE then vt100 mode is used, otherwise not. The procedure resets the elapsed time to 0.

When in vt100 mode this procedure clears the screen, and writes the heading of the screen, which is made out of two screen lines. The top line will contain the text of the first parameter name, together with the text 'elapsed time ', followed by the elapsed time. The second line of the screen is filled with a highlighted (bold) straight line. The cursor will be positioned at the first position of the third line. It is now possible to use the normal input and output to the terminal, which uses the bottom part of the screen.

When not in vt100 mode the text 'SCREEN: ', followed by the value of the parameter name is printed on the terminal. On the next line the text 'elapsed time ', followed by the elapsed time, is displayed.

2.1.2 Write elapsed time

The elapsed time can be updated by calling the procedure write elapsed time. The header of this procedure is:

The procedure updates the elapsed time in the header of the screen, when in vt100 mode, otherwise the text 'elapsed time ', followed by the elapsed time, is printed on a separate line. Whenever it is used in a screen session, the cursor position will not be affected.

2.1.3 Add screen info

The following procedure can be used to change the text in the header of the screen. The header of this procedure is:

When in vt100 mode this procedure updates the header with the text of the parameter name, otherwise the text 'SCREEN INFO: ', followed by the value of name is displayed on a separate line on the terminal.

2.1.4 Inform screen

Before we start a stack screen session (see next section) we can inform the module whether we want to work in normal mode or tracing mode by calling the following procedure:

This procedure is used to inform the stack whether it has to work in tracing mode or in fast mode. Stack mode is set if the parameter new tracing is equal to TRUE, otherwise fast mode is set.

This procedure need not be called, in which case fast mode is the default mode. If it is called more than once, which is allowed, the last value is taken.

2.1.5 Finalize screen

To finish a screen session we use the following procedure:

This procedure finalizes a screen session. The only thing it does is restore the terminal to the normal setting.

2.1.6 Wait

The last procedure we describe in this general part is the procedure wait, which has the following header:

When used in normal operation mode, this procedure causes the program to pause for a number of seconds equal to the value of the parameter sec. In fast mode this procedure does not pause.

2.2 The stack screen

In this section we describe the procedures that are used for a stack session, in which we make use of the stack screen. The stack screen is that part of the screen that is used to represent the stack. Outside of the stack session we cannot make use of the procedures to manipulate the stack.

The stack is also called a level stack, because it displays the nesting levels of all the nested calls. In vt100 mode the stack screen is situated at the top of the screen below the header screen. On entering a level it grows downward, until a certain depth (the value of the constant stack size [4.1]) is reached. Instead of growing further when this depth is reached, the whole stack scrolls up, and the freed line is used for the new top line. When leaving a level the reverse happens, as long as the stack is too deep to fit on the stack screen it will scroll downwards again.

When fast mode is used in combination with vt100 mode the contents of the stack screen is not shown until an error is reported. The changes as described here, when in tracing mode, are not displayed. Each time an error is reported the stack screen is displayed with the same contents as it would have had in tracing mode, when the error occurred.

When fast mode is used with vt100 mode switched off, none of the messages described below is displayed. Whenever an error message is given the contents of the stack is printed just above the error message itself.

2.2.1 Init level stack

The first procedure we give here initializes the level stack:

When in vt100 mode this procedure displays the stack screen, which is still completely empty. This is done by changing the second and third line of the screen, with some highlighted border lines of the visual representation of the stack. When not in vt100 mode nothing happens.

2.2.2 Purge level stack

To remove the level stack we use the procedure:

When in vt100 mode this procedure removes the stack screen. This is done by clearing the third line of the screen, and restoring the second line in a highlighted straight line. When not in vt100 mode nothing happens.

2.2.3 Enter and exit level

There are two procedures that control adding and removing a level on the level stack. First we give the procedure to add a new level (or element) on the stack. The header of this procedure is:

In vt100 mode this procedure generates a new line in the stack screen, and the name part is filled with the contents of the parameter level. When not in vt100 mode the text 'Enter level: ', followed by the value of level, is displayed on a separate line.

It is also possible to fill the information part of the stack. The following procedure fills the information part of the top of the stack, and can be called more than once for each level, in which case the old information is overwritten.

In vt100 mode the procedure fills the information part of the top of the stack (the bottom line of the stack screen) with the text of the parameter info. When not in vt100 mode the text 'level info: ', followed by the value of info, is displayed on a separate line.

To exit a level the following procedure has to be called.

This procedure pops a line of the stack screen when in vt100 mode. When not in vt100 mode the text 'Exit  level: ', followed by the value of the parameter level of the pair-wise call of the procedure enter level, is displayed on a separate line.

2.3 Calling order of the procedures

In this section we give detailed information on the calling order of the procedures described in the previous two sections. We give this order by a context-free grammar with meta-symbols, added with a new meta-symbol called 'MIXED'. This new meta-symbol is used to express that a certain (non)terminal may be mixed at any place in a part of the grammar. For example, we could define that a space symbol may be added at any place between the symbols defined by 'expr', by using 'expr  MIXED  space symbol'.

As terminals we use the procedure names. We begin with the top level, in which several screen sessions are possible. The root symbol of the grammar is program. The production rule with this nonterminal is:

This rule indicates that there are a number of screen sessions, in which we can use the procedure write elapsed time at any moment, and that the procedure wait can be called anywhere in the program.

We now give the rule for a screen session, saying that it may consist of one or more stack sessions.

This rule indicates that the procedure inform screen may be called several times before each stack session, but not within it.

Finally we describe a stack session, as being nested calls of adding and removing a level.

These rules says that at a certain level it is possible to several times enter a deeper level, or display new level information.

2.4 The listing screen

The listing screen is used for two processes. Firstly, it is used to display input lines that are read, and processed by the scanning and parsing process. Secondly, it is used to display the generation process. In vt100 mode it uses the part of the screen under the stack screen except the bottom line, which is used for error messages. The stack screen disappears under the stack screen when they reach each other. It is only possible to add new lines at the bottom of the listing screen, and to mark symbols in this bottom line.

The procedures in this section can be used anywhere in a screen session, there is no restriction to the calling order.

2.4.1 Echoing an input line on screen

The first procedure we describe is the procedure to add a new line at the bottom of the listing screen. The first 4 characters are used to represent the input line number. The rest of the characters, (depending on the value of the constant max line len, which contains the physical screen size) are used to display the first part of the input line. The marking only takes place on the visual part of the displayed input line.

This procedure displays the text of the parameter line on the screen, preceded by the line number line number. A line number equal to 0 represents the absence of a line number. In this case no line number is displayed. Only line numbers ranging 1..999 are displayed correctly. The text line is stored in an internal buffer, which is used by the marking procedures.

When vt100 mode is not used the line with its line number is displayed on a separate line.

2.4.2 Marking a symbol

Marking of symbols is only possible in vt100 mode. The marking of symbols requires two actions. Firstly, the position of the symbol on the last line of the listing screen has to be given. Secondly, the symbol can be marked by informing the module of the marking kind. To inform the position of the symbol to be marked the following procedures have to be used.

This procedure sets the begin position of the symbol equal to the value of the parameter begin pos and the length of the symbol equal to the value of the parameter length.

When the position of the symbol is known, it can be showed in the desired marking kind. Whether the actual marking is displayed depends on the operation mode. In fast mode some markings are not shown.

This procedure shows the last symbol, in the marking kind that is given by parameter mark. The procedure can be called more than once after each call of the procedure mark last sym, in which case the different kinds of markings are accumulated, as explained below. The following marking kinds exists:

mark normal :Causes the last symbol to be shown without any special markings. Overrules a previous skip marking, when it was given after the last call of mark last sym.
mark reset :Removes any special marking given before, except the underlining caused by a possible skip marking. It does nothing if in fast mode and no error marking had been given after the last call of mark last sym.
mark error :Causes the last symbol to be shown in highlighted blinking.
mark skip :Causes the last symbol to be underlined.
mark point :Causes the last symbol to be highlighted. Ignored when in fast mode.

Nothing happens when the procedure show last symbol is called, when no marking position was set yet for the current bottom listing line, by calling the procedure mark last symbol.

2.4.3 Writing in the listing screen

The following procedures could be used to write text to the listing screen. They can be used to display the generation process. It is impossible to mark any text in the listing screen that was written by these procedures. The following two procedures write text to the listing screen. The headers of these procedures are:

The procedures writes the text of the (default) parameter info to the listing screen, starting from the previous writing position on the bottom line of the listing screen. The procedure writeln screen proceeds on a newline after the text has been written. When not in vt100 mode the character '|' is used to show cutting points whenever anything else was displayed in between on a single listing line.

After text has been read from the terminal by using the standard procedure readln, the listing will proceed on the following line. It is necessary to restore the internal administration of the module by calling the procedure writecr screen after each read operation. The header of the procedure is:

2.5 The error screen

The error screen consists of the bottom line of the screen. There is one procedure to display error messages on the error screen. The header of this procedure is:

When in vt100 mode this procedure gives a beep signal, the error message text of the parameter error is displayed in inverse video on the bottom screen and pauses for a time equal to the value of the parameter delay in seconds. In fast mode the stack screen is displayed first and removed afterwards.

When not in vt100 mode, the position of the last marked symbol is shown by writing the character '^' under it. In fast mode the contents of the level stack is printed. The procedure gives a beep signal and displays the error message. It does not pause.

3 Usage

This section describes how to use the procedures defined by this module, together with some ideas on how to implement the procedures in an already existing program.

3.1 The procedure writev

One of the features that can be used is that of the procedure writev. This standard VAX-Pascal procedure allows one to write anything into a variable of type varying of char, with the same conventions as the standard procedure write. In the following example we show how a real number could be displayed on the screen using the procedure add level information. In this example we want to use only 10 characters for the information part in a procedure called inform real:

The argument 'error := continue' in the call of the procedure writev traps the system error in case the real number could not be represented in 10 characters.

3.2 General procedures

Normally, the procedure initialize screen is called at the beginning of the main program (or procedure). Following this, there is an optional question to the user whether he want to use tracing mode or fast mode, and signaling this to the module by the procedure inform screen. The last procedure to be called is finalize screen.

Between the call of the procedure inform screen and the procedure finalize, several stack sessions can occur by consecutive calls of the procedures init level stack and purge level stack. For example, a simple parsing program could have the following form:

The function yes asks for a yes/no answer on the question stated by its argument.

3.3 Stack procedures

In every procedure for which one wants to display a recursive call one can use a call to the procedure enter level at the beginning of the body and a call to the procedure exit level at the end of the body. The procedure add level information can be used to display the values of the parameters on entering the procedure and the results before leaving the procedure (followed by a pause). The following example illustrates the usage of these procedures:

3.4 Listing screen procedures

The listing screen procedures are normally called from the scanner module. They have to be inserted at the right places. Before markings can be displayed on the listing screen the procedure echo line on screen has to be called with the contents of the current input line. Normally, this procedure is called together with the procedure that echoes the current input line in the listing, just after it has been read into the internal buffer from the input file.

In the procedure that scans the next symbol from the current input line the actual marking procedures have to be called. We give an example of how the procedures should be called in the scanning procedure that is called nextsym here. In this example, the variable line pos contains the position of the next character to be read from the current input line. The body of the procedure is:

So far we have handled all normal kinds of markings. The remaining two kinds of markings are skip-marking and error-marking. Error-marking could be signaled from the error procedure, which will be dealt with in the next section. Skip-marking is given in the procedures that does the skipping. We explain how this could be done in an example of a skipping procedure:

3.5 Error procedures

The easiest way to incorporate the display of error messages by the screen management module is to use a variable (error mess in our example) in the error procedure, which is first filled with an appropriate error message. This message is then written to both the listing module and the screen management module. The following example illustrates this:

4 Implementation aspects

In this section we describe some aspects of the implementation. The internal behaviour of the program does not depend on whether it operates in vt100 mode or not. It is purely a matter of display. Because of this, all the descriptions are given as if the module operated in vt100 mode. The variable vt100 is equal to TRUE whenever vt100 mode is selected, otherwise it is equal to FALSE.

4.1 Graphical representation

In this subsection we describe how the terminal screen is divided into the separate screens, and how the dimensions are determined by the constants and variables.

4.1.1 Horizontal subdivision

The following constants describe the sizes and positions of the different screens on the screen of the terminal:

These constants define the horizontal subdivision of the screen in the different screens in the following way:

- header screen :  from the first line (numbered one) up to the line with the number of the constant stack_origin.
- stack screen :from the line with the number of the constant stack origin to the line with the number of the constant stack bottom. The size of the stack screen is equal to value of the constant stack size.
- listing screen :from the line with the number of one larger than constant stack bottom to the line with the number of the constant listing bottom. The listing screen is actually larger if the stack screen does not use its full potential size. The actual border is determined by the variable down counter, which is described below.
- error screen :from the line with the number of the constant error top to the line with the number of the constant error bottom.

4.1.2 Size and display of the stack screen

The variable down counter contains the absolute line number of the lowest line on the screen that is used for the stack screen. The variable is manipulated by the procedures init level stack, push stack screen down and pop stack screen up.

Whether the stack screen is really displayed on the screen depends on whether fast mode or trace mode is used. In tracing mode the variable tracing is equal to TRUE, and in fast mode it is equal to FALSE.

The variable dept counter contains the line number of the lowest line on the screen that is used by the stack screen, if it would have been displayed. It is the internal equivalent of the variable down counter. In fast mode the stack screen is only displayed with errors. Only then is the value of the variable down counter equal to the variable dept counter. The rest of the time it is equal to the constant stack origin. In trace mode the variables dept counter and down counter have the same value after each operation on the stack.

4.1.3 Vertical subdivision of the stack screen

The following constants determine the vertical division of the screen:

The number of characters on each line that is used is determined by the constant max line len. If the value of this constant is larger than 80, the 132 column mode of the vt100 terminal is used.

The stack screen is divided into two parts [2.2]. The constant max level name determines the length of the level name part of the stack screen, and the constant max info name determines the length of the info part of the stack screen. In this case the rest of the stack screen.

4.2 Internal stack representation

The stack is stored in a double linked list. The following type declaration describes the elements of this list:

The record field lower points to the stack element below this element, assuming the stack grows downwards. This field is equal to NIL for the top element of the stack.The record field higher points to the stack element above this element. This field is equal to NIL for the bottom element of the stack.

The variable old stack line of type ptr stack line points to the pool of used stack elements. This variable is used by the procedures create line and purge line.

The variables stack top line and stack down line point to those stack elements that are displayed as the highest and lowest stack elements on the stack screen whenever this stack is really displayed on the screen.

The variable stack down line can also be considered as the top of the stack (remember that the stack is displayed upside-down, growing downwards). The variable stack top line does not always point to the bottom of the stack, because the bottom can be off the screen.

4.3 Listing screen

The input lines that are displayed on the listing screen using the procedure echo line on screen (see Section 2.4.1) are stored into an internal buffer that is also used by the procedure show last symbol (see Section 2.4.2). The variable last line of type listing line contains the bottom line of the listing screen.

The positions of the symbols in the listing screen to be marked are stored in the following variables:

The variable symbol active is reset to FALSE after each call to the procedure echo line on screen, indicating that there is no active symbol in the new bottom line of the screen. After a call to the procedure mark last symbol the value is set to TRUE again. The variables first pos symbol and last pos symbol contain the values as given by the last call of the procedure mark last symbol on the bottom line. In case there is no active symbol they contain the default values 1 and 0 (respectively). The variable previous pos symbol contains the previous value of the variable last pos symbol incremented by one. In case there is no active symbol, it has the default value 1.

The procedure show last symbol makes use of global booleans. These are:

Both of these variables are reset to FALSE after each call to the procedure mark last symbol. The variable error is set to TRUE when the current symbol is displayed with error marking. The variable preserve is used to remember that the symbol was displayed with skipping marking.

4.3.1 Writing procedures

There are two global variables that are used by the procedures write screen, writeln screen and writesc screen. These are declared by:

The variable current listing pos keeps the current writing position for the procedures. The boolean variable listing interrupted represents whether there has been an interruption in the writing process by calling any of the other procedures that manipulate the screen. This variable is set by calling the procedure set listing interrupt.

5 Interface

The following module is used :

5.1 Exported type declarations

The following type definitions are exported by this module:

5.2 Exported procedures and functions

The following procedures and functions are exported by this module:

This procedure initiates an screen session. See subsection 2.2.1

This procedure updates the elapsed time in the header of the screen. Whenever it is used in a screen session, the cursor position will not be affected. See subsection 2.1.2

This procedure changes the header of the screen. See subsection 2.1.3

This procedure is used to inform the stack whether it has to work tracing mode or normal mode. See subsection 2.1.4

This procedure finalizes a screen session. It does nothing else then that it sets the terminal in the normal setting, so that it can be used again in the normal way. See subsection 2.1.5

This procedure causes the program to wait for sec seconds. See subsection 2.1.6

This procedure initializes a stack screen. It is described in subsection 2.2.1

This procedure removes the stack screen. It is described in subsection 2.2.2

This procedure generates a new line in the stack screen, and the name part is fills with contents of the parameter level. See subsection 2.2.3

This procedure fills the information part of the top of the stack (the bottom line of the stack screen) with the text represented by the parameter info. See subsection 2.2.3

This procedure pops a line of the stack screen. It is described in subsection 2.2.3

This procedure adds the contents of the parameter info at the end of the listing screen. See subsection 2.4.3

This procedure adds the contents of the parameter info followed by a newline at the end of the listing screen. See subsection 2.4.3

This procedure can be considered as writing a carriage return to the listing screen and should be used after one has read from the screen. See subsection 2.4.3

This procedure displays the text represented by line on the screen, preceded by the line number line number. This procedure is described in subsection 2.4.1

This procedure tells the begin position begin pos and the length of the symbol in the last line displayed by the procedure echo line on screen, so that it can be pointed to by the procedure show_last_symbol. See subsection 2.4.2

This procedure show the last symbol, in the marking that is represented by the parameter mark. See subsection 2.4.2

This procedure displays an error on the bottom screen. It is described in subsection 2.5

5 Listing

[INHERIT     ('vt100.pen'),
 ENVIRONMENT ('screen.pen')]

MODULE screen(output);

(*      See for description the file SCREEN.HLP .                             *)

(* ADAPTION: If one wants to have a 132 column version, change the constant   *)
(*           max_line_len into 132.                                           *)

[HIDDEN]
CONST
  chr_beep       = chr(7);

(* All the following constants describe the sizes of how the different        *)
(* virtual screens are displayed on the screen of the terminal. The current   *)
(* values are for the vt100 terminal with a screen of 80 characters on 24     *)
(* lines.                                                                     *)
(* The screen is vertically divided into 4 areas :                            *)
(* - top line       : line 1 till stack_origin                                *)
(* - stack screen   : stack_origin to stack_bottom                            *)
(*                    (with the size equal to stack_size)                     *)
(* - listing screen : stack_bottom + 1 to listing bottom                      *)
(*                    (the listing screen is actually larger if the stack     *)
(*                     screen does not fill it full potential size. The       *)
(*                     border is determined by the variable down_counter).    *)
(* - error screen   : error_top to error_bottom                               *)
  stack_origin   = 3;
  stack_size     = 14;
  stack_bottom   = stack_origin + stack_size;
  listing_bottom = 23;
  error_top      = 24;
  error_bottom   = 24;
(* The stack is horizontal divided in 2 parts :                               *)
(* - the stack name column, with length max_level_name.                       *)
(* - the information column, with length max_info_name.                       *)
(* The total size is determined by max_line_len.                              *)
  max_line_len   = 80;
  max_level_name = 25;
  max_info_name  = max_line_len-7-max_level_name;

TYPE
  text_line             = VARYING[max_line_len] OF char;
  text_level            = VARYING[max_level_name] OF char;
  text_info             = VARYING[max_info_name] OF char;
  listing_line          = VARYING[140] OF CHAR;

(* kind of markings that is used : *)
  kind_of_marking       = (mark_normal, mark_error, mark_skip, mark_point
                          ,mark_reset
                          );

(* Internal representation of the stack : *)
  ptr_stack_line        = [HIDDEN]
                          ^type_stack_line;
  type_stack_line       = [HIDDEN]
                          RECORD
                            lower  ,
                            higher : ptr_stack_line;
                            level  : text_level;
                            info   : text_info
                          END;

[HIDDEN]
VAR
(* The option whether a vt100 terminal is used or not : *)
  vt100                 ,

(* The option whether tracing is on or not : *)
  tracing               : boolean;

(* The variables for the header screen                                        *)

(* To hold the elapsed time : *)
  hclock                : integer;

(* To hold the length of the current header info : *)
  header_info_length    : integer;

(* The variables for the stack screen                                         *)

(* There is a pointer to the pool of used (internal) stack lines, which is    *)
(* manipulated by the procedures create_ and purge_line.                      *)
  old_stack_lines       : ptr_stack_line;

(* There are 2 pointers that point to the highest (internal) stack line :     *)
(* stack_top_line, and the lowest (internal) stack line : stack_down_line of  *)
(* those lines that are displayed or would be displayed if tracing is TRUE.   *)
(* stack_down_line can also be considered as the top of the stack (remember   *)
(* that the stack is displayed upside-down, growing downwards). The           *)
(* stack_top_variable does not always point to the bottom of the stack,       *)
(* because the bottom can be off the screen.                                  *)
  stack_top_line        ,
  stack_down_line       : ptr_stack_line;

(* There are 2 counters for the size of the stack. One holds the absolute     *)
(* position of the lowest line of the stack that is displayed : down_counter. *)
(* (remember that the stack is not displayed when tracing is FALSE). This     *)
(* variable is manipulated by the drawing procedures push_stack_screen_down   *)
(* and pop_stack_screen_up. The other is the internal equivalent that tells   *)
(* how deep the stack is, if it were displayed on the screen : depth_counter. *)
(* This variable is manipulated by enter_level and exit_level. Both are       *)
(* initialized by init_level_stack.                                           *)
  dept_counter          ,
  down_counter          : integer;

(* The variables for the listing screen                                       *)

(* First of all there is an internal buffer for the listing screen, which is  *)
(* only the last/bottom line of the listing screen called last_line.          *)
  last_line             : listing_line;

(* Secondly there is a variable that keeps the current writing position for   *)
(* write(ln)_screen procedures, and a variable that represents whether there  *)
(* has been an interruption in the writing process.                           *)
  current_listing_pos   : integer;
  listing_interrupted   : boolean;

(* There are a number of variables that take care for the whole displaying of *)
(* symbols in the last line of the listing. First of all there are some       *)
(* indices that are used to point at the symbols. They updated set by a call  *)
(* of mark_last_symbol and echo_line_on_screen. Previous_pos_symbol holds the *)
(* previous value of last_pos_symbol incremented with one.                    *)
  first_pos_symbol      ,
  last_pos_symbol       ,
  previous_pos_symbol   : integer;

(* There are also a number of booleans that control the displaying. The       *)
(* boolean symbol_active is set TRUE a symbol in the last line is marked by a *)
(* call of mark_last_symbol. Error is set for a symbol when a error marking   *)
(* has been given. Preserve is used to remember that a skipping marking has   *)
(* been given for a symbol.                                                   *)
  symbol_active         ,
  error                 ,
  preserve              : boolean;


  [INITIALIZE,HIDDEN] PROCEDURE init;
  BEGIN
    symbol_active := FALSE;
    last_line := '';
    current_listing_pos := 0;
    listing_interrupted := TRUE;
  END;

  [HIDDEN] PROCEDURE set_listing_interrupt;
  (* This procedure sets the variable listing_interrupt true. If vt100 is     *)
  (* FALSE and listing_interrupt was FALSE, a writeln(output) is preformed.   *)
  BEGIN
    IF   NOT ( listing_interrupted OR vt100)
    THEN writeln(output);
    listing_interrupted := TRUE
  END;

5.1 Stack drawing procedures

This page contains the procedures for all the line and border drawing, together with all the procedures that take care for the visual representation of the stack.

[HIDDEN]
PROCEDURE make_straight_line;
(* makes a straight bold line on the screen on that line where the cursor is  *)
(* currently positioned in the first column.                                  *)
VAR
  i : integer;
BEGIN
  set_character_sets(0, char_set_special);
  set_character_attr([char_attr_bold]);
  FOR i := 1 TO max_line_len DO write_scr_chr('q');
  set_character_sets(0, char_set_normal_US);
  set_character_attr([char_attr_none])
END;

[HIDDEN]
PROCEDURE make_empty_top_stack;
(* makes the top of an empty stack, which consists of 2 lines.                *)

  PROCEDURE make_stack_box_line(outs,left,middle,right : char);
  (* This procedure makes a line on the screen for the bold boxing of the     *)
  (* stack, where outs, left, middle and right determine the kind of borders. *)
  (* The line is made on the line where the cursor is in the first column.    *)
  VAR
    i : integer;
  BEGIN
    write_scr_chr(outs);
    write_scr_chr(outs);
    write_scr_chr(left);
    FOR i := 1 TO max_level_name DO write_scr_chr('q');
    write_scr_chr(middle);
    FOR i := 1 TO max_info_name  DO write_scr_chr('q');
    write_scr_chr(right);
    write_scr_chr(outs);
    write_scr_chr(outs)
  END;

BEGIN
  set_term_setting(dec_origin_mode,FALSE);
  set_scroll_region;
  set_cursor_at_pos(pred(stack_origin));
  set_character_sets(0, char_set_special);
  set_character_attr([char_attr_bold]);
  make_stack_box_line('q','w','w','w');
  make_stack_box_line(' ','m','v','j');
  set_character_sets(0, char_set_normal_US);
  set_character_attr([char_attr_none]);
  set_term_setting(dec_origin_mode)
END;

[HIDDEN]
PROCEDURE make_stack_line(stack_line : ptr_stack_line);
(* This procedure displays the line represented by stack_line on the line     *)
(* where the cursor is currently in the first column, with the appropriate    *)
(* bold boxing around it.                                                     *)
CONST
  to_begin = max_level_name + max_info_name + 2;
BEGIN
  set_character_sets(0, char_set_special);
  set_character_attr([char_attr_bold]);
  move_cursor_rel(2, cursor_forward);
  write_scr_chr('x');
  move_cursor_rel(max_level_name, cursor_forward);
  write_scr_chr('x');
  move_cursor_rel(max_info_name, cursor_forward);
  write_scr_chr('x');
  move_cursor_rel(to_begin, cursor_backward);
  set_character_sets(0, char_set_normal_US);
  set_character_attr([char_attr_none]);
  WITH stack_line^
  DO BEGIN
       write_scr(level);
       IF   info <> ''
       THEN BEGIN
              move_cursor_rel(succ(max_level_name)-level.length,cursor_forward);
              write_scr(info)
            END
     END
END;

[HIDDEN]
PROCEDURE remove_empty_stack;
(* This procedure removes the boxing of an empty stack.                       *)
BEGIN
  set_scroll_region(pred(stack_origin),error_bottom);
  move_cursor_rel(1, cursor_down);
  delete_line;
  set_term_setting(dec_origin_mode, FALSE);
  set_scroll_region;
  set_cursor_at_pos(pred(stack_origin));
  make_straight_line;
  set_term_setting(dec_origin_mode);
  set_scroll_region(stack_origin);
  move_cursor_rel(max_screen_length, cursor_down)
END;

[HIDDEN]
PROCEDURE fill_level_info(info : text_info);
(* This procedure fills the info on the right place on the bottom line of the *)
(* stack, within the boxing.                                                  *)
BEGIN
  set_scroll_region(stack_origin, stack_bottom);
  IF   pred(down_counter) > stack_origin
  THEN move_cursor_rel(pred(down_counter) - stack_origin, cursor_down);
  move_cursor_rel(4 + max_level_name, cursor_forward);
  write_scr(info)
END;

[HIDDEN]
PROCEDURE push_stack_screen_down;
(* This procedure takes care for the pushing down of the stack boxing.        *)
BEGIN
  down_counter := succ(down_counter);
  set_scroll_region(pred(down_counter), down_counter);
  move_cursor_scroll(cursor_reverse)
END;

[HIDDEN]
PROCEDURE pop_stack_screen_up;
(* This procedure takes care for the poping up of the stack boxing.           *)
BEGIN
  down_counter := pred(down_counter);
  set_scroll_region(down_counter, succ(down_counter));
  move_cursor_rel(1, cursor_down);
  move_cursor_scroll(cursor_next_line)
END;

[HIDDEN]
PROCEDURE scroll_stack_screen_up;
(* This procedure scrolls the displayed stack on the screen, up.              *)
BEGIN
  set_scroll_region(stack_origin, pred(stack_bottom));
  move_cursor_rel(pred(stack_bottom) - stack_origin, cursor_down);
  move_cursor_scroll(cursor_next_line)
END;

[HIDDEN]
PROCEDURE scroll_stack_screen_down;
(* This procedure scrolls the displayed stack on the screen, down.            *)
BEGIN
  set_scroll_region(stack_origin, pred(stack_bottom));
  insert_line
END;

5.2 Initialization procedures

PROCEDURE write_elapsed_time;
(* This procedure updates the elapsed time in the header of the screen.       *)
(* Whenever it is used in a screen session, the cursor position will not be   *)
(* affected.                                                                  *)
VAR
  text : VARYING[21] OF CHAR;
BEGIN
  set_listing_interrupt;
  writev(text,'elapsed time ',(clock - hclock)/1000 : 8 : 3);
  IF  vt100
  THEN BEGIN
         save_terminal_setting;
         set_term_setting(dec_origin_mode, FALSE);
         set_scroll_region;
         move_cursor_rel(max_line_len-30, cursor_forward);
         write_scr(text);
         set_term_setting(dec_origin_mode);
         set_scroll_region(down_counter, listing_bottom);
         restore_terminal_setting
       END
  ELSE writeln(output, text);
END;

PROCEDURE initialize_screen(name : text_level; vt100_used : boolean);
(* This procedure has to be used at the beginning of a screen session.        *)
(* When vt100_used is TRUE than vt100 mode will be used to display everything *)
(* otherwise normal output will be generated.                                 *)
(* Several screen sessions can appear in one program. It will clear the       *)
(* screen, and write the heading of the screen, which is made out of to       *)
(* screen lines. The top line will contain the text of the variable name,     *)
(* together with the text 'elapsed time ', followed by the elapsed time,      *)
(* which is reset to 0, at the call of this procedure. The second line of the *)
(* screen is filled with a highlighted (bold) straight line.                  *)
(* And the cursor will be positioned at the first position of the third line. *)
(* It is possible now to use normal the input and output to the terminal,     *)
(* which will use the bottom part of the screen.                              *)
BEGIN
  vt100 := vt100_used;
  IF   vt100
  THEN BEGIN
         set_term_setting(dec_column_mode, max_line_len > 80);
         set_term_setting(dec_origin_mode, TRUE);
         set_cursor_at_pos(2);
         make_straight_line;
         set_cursor_at_pos;
         write_scr(name);
         set_scroll_region(stack_origin,23)
       END
  ELSE BEGIN
         writeln;
         writeln('SCREEN : ',name)
       END;
  header_info_length := name.length;
  hclock := clock;
  down_counter := stack_origin;
  write_elapsed_time;
  tracing := FALSE
END;

PROCEDURE add_screen_info(name : text_info);
(* This procedure changes the header of the screen.                           *)
VAR
  hulp_name : text_info;
BEGIN
  IF   vt100
  THEN BEGIN
         set_scroll_region;
         set_cursor_at_pos;
         hulp_name := name;
         WHILE hulp_name.length < header_info_length
         DO hulp_name := hulp_name + ' ';
         write_scr(hulp_name);
         set_scroll_region(down_counter,23)
       END
  ELSE BEGIN
         writeln;
         writeln('SCREEN INFO : ',name)
       END;
  header_info_length := name.length;
  write_elapsed_time
END;

PROCEDURE inform_screen(new_tracing : BOOLEAN);
(* This procedure is used to inform the stack whether it has to work tracing  *)
(* mode or normal mode. stack mode is set when new_tracing is TRUE, otherwise *)
(* normal mode is set.                                                        *)
BEGIN
  tracing := new_tracing
END;

PROCEDURE finalize_screen;
(* This procedure finalizes a screen session. It does nothing else then that  *)
(* it sets the terminal in the normal setting, so that it can be used again   *)
(* in the normal way.                                                         *)
BEGIN
  IF   vt100
  THEN BEGIN
         set_term_setting(dec_origin_mode, FALSE);
         set_scroll_region;
         set_cursor_at_pos(max_screen_length);
       END
  ELSE writeln('END OF SCREEN')
END;

[HIDDEN]
FUNCTION lib$wait(VAR sec : real) : unsigned; EXTERN;

PROCEDURE wait(sec : real := 1.0);
(* This procedure causes the program to wait for sec seconds.                 *)
BEGIN
  IF tracing
  THEN lib$wait(sec)
END;

5.3 Stack line procedures

This page contains 2 procedures that provide an efficient way of allocating so called screen lines, for the internal representation of the stack.

[HIDDEN]
PROCEDURE create_line(VAR stack_line : ptr_stack_line);
(* This procedure generates a new screen line. works together with purge_line *)
(* on the global variable old_stack_lines.                                    *)
BEGIN
  IF   old_stack_lines = NIL
  THEN new(stack_line)
  ELSE BEGIN
         stack_line := old_stack_lines;
         old_stack_lines := old_stack_lines^.higher
       END;
  WITH stack_line^
  DO BEGIN
       higher := NIL;
       lower  := NIL;
       level  := '';
       info   := ''
     END;
END;

PROCEDURE purge_line(VAR stack_line : ptr_stack_line);
(* this procedure purges a screen line by storing it in old_stack_lines.     *)
BEGIN
  stack_line^.higher := old_stack_lines;
  old_stack_lines := stack_line;
  stack_line := NIL
END;

5.4 Stack screen

PROCEDURE init_level_stack;
(* This procedure initializes a stack screen. It makes an empty stack on the  *)
(* screen, which is nothing else than an changing of the second and third     *)
(* line of the screen, with some highlighted border lines of the visual       *)
(* representation of the stack. These are removed by purge_level_stack.       *)
VAR
  i : integer;
BEGIN
  IF   vt100
  THEN make_empty_top_stack;
  stack_top_line  := NIL;
  stack_down_line := NIL;
  dept_counter := stack_origin;
  down_counter := stack_origin;
END;

PROCEDURE enter_level(level : text_level);
(* This procedure generates a new line in the stack screen, and the name     *)
(* part is fills with level.                                                 *)
VAR
  new_line : ptr_stack_line;
BEGIN
(* make new line for internal representation of the stack *)
  create_line(new_line);
  IF   stack_down_line = NIL
  THEN stack_top_line := new_line
  ELSE stack_down_line^.lower := new_line;
  new_line^.higher := stack_down_line;
  new_line^.level  := level;
  stack_down_line := new_line;
(* manipulate screen *)
  set_listing_interrupt;
  IF   dept_counter = stack_bottom
  THEN (* stack screen at bottom of stack area, scroll up *)
       BEGIN
         stack_top_line := stack_top_line^.lower;
         IF   tracing AND vt100
         THEN scroll_stack_screen_up
       END
  ELSE (* stack screen not yet at bottom of stack area, move stack down *)
       BEGIN
         dept_counter := succ(dept_counter);
         IF   tracing AND vt100
         THEN push_stack_screen_down
       END;
(* fill in level name in empty screen line of the stack area*)
  IF   tracing
  THEN IF   vt100
       THEN make_stack_line(stack_down_line)
       ELSE writeln(output, 'Enter level : ',level)
END;

PROCEDURE exit_level;
(* This procedure pops a line of the stack screen.                           *)
VAR
  hulp : ptr_stack_line;
BEGIN
  IF   stack_down_line = NIL
  THEN (* pop on empty stack screen *)
  ELSE BEGIN
         set_listing_interrupt;
         IF   tracing AND NOT vt100
         THEN writeln(output, 'Exit  level : ', stack_down_line^.level);
         IF   stack_top_line^.higher = NIL
         THEN (* whole stack in stack area on the screen, move stack up *)
              BEGIN
                dept_counter := pred(dept_counter);
                IF   tracing AND vt100
                THEN pop_stack_screen_up
              END
         ELSE (* not whole stack in stack area on the screen, scroll down *)
              BEGIN
                stack_top_line := stack_top_line^.higher;
                IF   tracing AND vt100
                THEN BEGIN
                       scroll_stack_screen_down;
                       make_stack_line(stack_top_line);
                     END
              END;
         hulp := stack_down_line;
         stack_down_line := stack_down_line^.higher;
         purge_line(hulp)
       END;
END;

PROCEDURE add_level_info(info : text_info);
(* This procedure fills the information part of the top of the stack (the     *)
(* bottom line of the stack screen) with the text of info.                    *)
VAR
  old_length : integer;
BEGIN
  set_listing_interrupt;
  old_length := length(stack_down_line^.info);
  stack_down_line^.info := info;
  IF   tracing
  THEN IF   vt100
       THEN BEGIN
              (* Add spaces to overwrite previous level information *)
              WHILE old_length > length(info)
              DO info := info + ' ';
              fill_level_info(info)
            END
       ELSE writeln(output, 'level  info : ',info)
END;

PROCEDURE purge_level_stack;
(* This procedure removes the stack screen. The only thing it does is         *)
(* clearing the third line, and restore the second line in a highlighted      *)
(* straight line.                                                             *)
BEGIN
  IF   vt100
  THEN remove_empty_stack
END;

[HIDDEN]
PROCEDURE flap_down_stack;
(* This procedure flaps the stack screen down. Used when in normal mode.      *)
VAR
  hulp_stack_line : ptr_stack_line;
BEGIN
  set_listing_interrupt;
  hulp_stack_line := stack_top_line;
  IF   NOT vt100
  THEN writeln(output, 'Top of the stack :');
  WHILE hulp_stack_line <> NIL
  DO BEGIN
       IF  vt100
       THEN BEGIN
              push_stack_screen_down;
              make_stack_line(hulp_stack_line)
            END
       ELSE WITH hulp_stack_line^
            DO writeln(output, level : max_level_name, ' | ', info);
       hulp_stack_line := hulp_stack_line^.lower
     END
END;

[HIDDEN]
PROCEDURE flap_up_stack;
(* This procedure flaps the stack up. Used when in normal mode.               *)
BEGIN
  IF   vt100
  THEN WHILE down_counter <> stack_origin
       DO pop_stack_screen_up
END;

5.5 Listing procedures

PROCEDURE write_screen(info : VARYING[len] OF char := '');
(* This procedure adds info at the end of the bottom line in the listing on   *)
(* the screen when in vt100 mode, otherwise it is just printed.               *)
VAR
  i : integer;
BEGIN
  IF   vt100
  THEN BEGIN
         set_scroll_region(succ(down_counter), listing_bottom);
         move_cursor_rel(pred(listing_bottom) - down_counter, cursor_down);
         move_cursor_rel(current_listing_pos,cursor_forward);
         FOR i := 1 TO min(max_line_len - current_listing_pos, len)
         DO BEGIN
              write_scr_chr(info[i]);
              current_listing_pos := current_listing_pos + 1
            END;
       END
  ELSE BEGIN
         IF   listing_interrupted AND (current_listing_pos > 0)
         THEN write(output, '|':current_listing_pos);
         write(output, info);
         current_listing_pos := current_listing_pos + len
       END;
  listing_interrupted := FALSE;
  last_line := ''
END;

PROCEDURE writeln_screen(info : VARYING[len] OF char := '');
(* This procedure adds info at the end of the bottom line in the listing on   *)
(* the screen and goes to a new line when in vt100 mode, otherwise it is just *)
(* printed with a newline.                                                    *)
VAR
  i : integer;
BEGIN
  IF   vt100
  THEN BEGIN
         set_scroll_region(succ(down_counter), listing_bottom);
         move_cursor_rel(pred(listing_bottom) - down_counter, cursor_down);
         move_cursor_rel(current_listing_pos,cursor_forward);
         FOR i := 1 TO min(max_line_len - current_listing_pos, len)
         DO write_scr_chr(info[i]);
         move_cursor_scroll(cursor_next_line)
       END
  ELSE BEGIN
         IF   listing_interrupted
         THEN write(output, '|':current_listing_pos);
         writeln(output, info)
       END;
  current_listing_pos := 0;
  listing_interrupted := FALSE;
  last_line := ''
END;

PROCEDURE writecr_screen;
(* This procedure can be considered as writing a carriage return to the screen*)
(* and should be used after one has read from the screen. It does nothing     *)
(* else than resetting the current_listing_pos.                               *)
BEGIN
  current_listing_pos := 0;
  last_line := ''
END;


(*   The procedures on this page are used for displaying the listing on the   *)
(*   screen and pointing at the last scanned symbol.                          *)

PROCEDURE echo_line_on_screen(line_number : integer:= 0; line : listing_line);
(* This procedure displays the text line on the screen, preceded by the       *)
(* line number line_number. The line number 0 is regarded to represent the    *)
(* absence of a line number. In this case no line numbers is displayed.       *)
(* Only line numbers ranging 1.999 are displayed correctly.                   *)
(* The text line is stored in an internal buffer.                             *)
VAR
  text_number : VARYING[3]OF CHAR; i : integer;
BEGIN
  first_pos_symbol      := 1;
  last_pos_symbol       := 0;
  previous_pos_symbol   := 1;
  last_line             := line;
  symbol_active         := FALSE;
  preserve              := FALSE;
  error                 := FALSE;
  IF   line_number = 0
  THEN text_number := '   '
  ELSE writev(text_number, line_number : 3, error:=continue);
  IF   vt100
  THEN BEGIN
          set_scroll_region(succ(down_counter), listing_bottom);
          move_cursor_rel(pred(listing_bottom) - down_counter, cursor_down);
          move_cursor_scroll(cursor_next_line);
          write_scr(text_number);
          move_cursor_rel(1,cursor_forward);
          FOR i := 1 TO min(max_line_len - 4, line.length)
          DO write_scr_chr(line[i]);
        END
  ELSE writeln(output, text_number, ' ', line);
  current_listing_pos := 4 + line.length
END;

PROCEDURE mark_last_symbol(begin_pos, length : integer);
(* This procedure tells the begin position begin_pos and the length of the    *)
(* symbol in the last line displayed by echo_line_on_screen, so that it can   *)
(* be pointed at by the procedure show_last_symbol.                           *)
BEGIN
  previous_pos_symbol := succ(last_pos_symbol);
  first_pos_symbol    := begin_pos;
  last_pos_symbol     := begin_pos + pred(length);
  preserve            := FALSE;
  error               := FALSE;
  symbol_active       := TRUE
END;

[HIDDEN]
PROCEDURE marking(start : integer; kind_of : set_of_char_attr);
(* This procedure causes the actual marking of the last marked symbol in the  *)
(* line, by rewritting it in the right mode.                                  *)
VAR
  i : integer;
BEGIN
  IF  last_line.length > 0
  THEN BEGIN
         set_character_attr(kind_of);
         set_scroll_region(listing_bottom, succ(listing_bottom));
         move_cursor_rel(min(start + 3,max_line_length), cursor_forward);
         FOR i := start TO min(max_line_len - 4, last_pos_symbol)
         DO IF   i <= last_line.length
            THEN write_scr_chr(last_line[i])
            ELSE write_scr_chr(' ');
         set_character_attr([char_attr_none])
       END
END;

PROCEDURE show_last_symbol(mark : kind_of_marking);
(* This procedure show the last symbol, in the marking that is given by mark, *)
(* whereby marking can be one of the following things :                       *)
(*   mark_normal : Causes the last symbol to be shown without any special     *)
(*                 markings. Overrules a previous skip marking.               *)
(*   mark_reset  : Causes the last symbol to be shown without any special     *)
(*                 marking, beside an underlining when a skip marking had     *)
(*                 been given. Doesn't do anything if in normal mode and no   *)
(*                 error marking had been given.                              *)
(*   mark_error  : Causes the last symbol to be shown in highlighted blinking.*)
(*   mark_skip   : Causes the last symbol to be underlined.                   *)
(*   mark_point  : Causes the last symbol to be highlighted. Ignored when in  *)
(*                 normal mode.                                               *)
(* In case there had been no marking on the last line (after the last call to *)
(* echo_line_on_screen or before any call to echo_line_on_screen) by the      *)
(* procedure mark_last_symbol, nothing happens.                               *)
BEGIN
  IF   symbol_active AND vt100
  THEN BEGIN
         CASE mark OF
           mark_normal : marking(first_pos_symbol, [char_attr_none]);
           mark_error  : BEGIN
                            marking(first_pos_symbol,
                                    [char_attr_blink, char_attr_bold]);
                            error := TRUE
                         END;
           mark_skip   : BEGIN
                           marking(previous_pos_symbol, [char_attr_under]);
                           preserve := TRUE
                         END;
           mark_point  : IF   tracing
                         THEN marking(first_pos_symbol, [char_attr_bold]);
           mark_reset  : IF   tracing OR error
                         THEN IF   preserve
                              THEN marking(first_pos_symbol,
                                           [char_attr_none, char_attr_under])
                              ELSE marking(first_pos_symbol, [char_attr_none])
         END;
       END
END;

5.6 Error procedures

PROCEDURE display_error_on_screen(error : listing_line; delay : real := 1);
(* This procedure displays an error on the bottom screen.                     *)
(* When in normal mode the procedure takes care for flapping down and up of   *)
(* the stack screen.                                                          *)
(* It beeps and displays the error message error in inverse video on the      *)
(* bottom line of the screen, and waits for delay seconds.                    *)
VAR
  i : integer;
BEGIN
  set_listing_interrupt;
  IF   NOT vt100
  THEN BEGIN
         write(output, ' ':first_pos_symbol+3);
         FOR i := first_pos_symbol TO last_pos_symbol
         DO write(output, '^');
         writeln(output)
       END;
  IF   NOT tracing
  THEN flap_down_stack;
  IF   vt100
  THEN BEGIN
         show_last_symbol(mark_error);
         set_scroll_region(1,error_bottom);
         set_cursor_at_pos(error_bottom);
         set_character_attr([char_attr_reverse]);
         write_scr_chr(chr_beep);
         write_scr(error);
         lib$wait(delay);
         set_character_attr([char_attr_none]);
         erase_line(erase_to_cursor)
       END
  ELSE writeln(output, chr_beep, error);
  IF   NOT tracing
  THEN BEGIN
         flap_up_stack;
         show_last_symbol(mark_reset)
       END
END;

END.


My life as a hacker | My home page