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.
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.
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.
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.
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.
In the procedure initialize screen a screen session is started. The header of this procedure is:
PROCEDURE initialize_screen(name : text_level, vt100_used : boolean);
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.
The elapsed time can be updated by calling the procedure write elapsed time. The header of this procedure is:
PROCEDURE write_elapsed_time;
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.
The following procedure can be used to change the text in the header of the screen. The header of this procedure is:
PROCEDURE add_screen_info(name : text_info);
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.
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:
PROCEDURE inform_screen(new_tracing : BOOLEAN);
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.
To finish a screen session we use the following procedure:
PROCEDURE finalize_screen;
This procedure finalizes a screen session. The only thing it does is restore the terminal to the normal setting.
The last procedure we describe in this general part is the procedure wait, which has the following header:
PROCEDURE wait(sec : real := 1.0);
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.
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.
The first procedure we give here initializes the level stack:
PROCEDURE init_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.
To remove the level stack we use the procedure:
PROCEDURE purge_level_stack;
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.
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:
PROCEDURE enter_level(level : text_level);
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.
PROCEDURE add_level_info(info : text_info);
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.
PROCEDURE exit_level;
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.
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:
program : ( initialize screen , screen session MIXED write elapsed time , finalize screen ) CLOS MIXED wait .
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.
screen session : ( inform screen CLOS , init level stack , stack session , purge level stack ) CLOS .
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.
stack session : at level CLOS . at_level : enter level , ( add level information ; at level ) CLOS , exit level .
These rules says that at a certain level it is possible to several times enter a deeper level, or display new level information.
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.
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.
PROCEDURE echo_line_on_screen(line_number : integer:= 0; line : listing_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.
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.
PROCEDURE mark_last_symbol(begin_pos, length : integer);
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.
PROCEDURE show_last_symbol(mark : kind_of_marking);
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.
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:
PROCEDURE write_screen(info : VARYING[le] OF char := ''); PROCEDURE writeln_screen(info : VARYING[le] OF char := '');
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:
PROCEDURE writecr_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:
PROCEDURE display_error_on_screen(error : listing_line; delay : real := 1);
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.
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.
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:
PROCEDURE inform_real(a_real : real); VAR char_rep_of_real_in_10 : VARYING[10] OF char; BEGIN writev(char_rep_of_real_in_10, real:10, error := continue); add_level_information(char_rep_of_real_in_10) END;
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.
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:
BEGIN initialize_screen('<program name>', yes('- vt100 used '); { .... other initializations .... } inform_screen( yes('- tracing ')); init_level_stack; { .... parsing procedures that scan the input file .... } purge_level_stack; finalize_screen END.
The function yes asks for a yes/no answer on the question stated by its argument.
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:
FUNCTION parse_expression(depth : integer) : integer; VAR repr : text_info; result : integer; BEGIN enter_level('expression'); writev(repr, 'depth = ', depth:1); add_level_info(repr); { .... Body that returns the value in the variable result .... } writev(repr, 'result = ', result:1); add_level_info(repr); { Wait one second so that user can read the result. } wait; exit_level END;
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:
PROCEDURE nextsym; VAR start_pos : integer; { .... Various scanning procedures called in body of nextsym .... } BEGIN { To reset the point marking of the previous read symbol. } show_last_symbol(mark_reset); { .... Skipping spaces, comments and line feeds .... } start_pos := line_pos; { .... Body of the scanning procedure .... } { We mark the symbol, and show it in point-marking, as the last scanned symbol : } mark_last_symbol(start_pos, pred(line_pos) - start_pos); show_last_symbol(mark_point) END;
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:
PROCEDURE skip( { parameters } ); BEGIN { .... } WHILE { last scanned symbol has to be skipped } DO BEGIN show_last_symbol(mark_skip); nextsym END; { .... } END;
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:
PROCEDURE error( { parameters } ); VAR error_mes : text_line; BEGIN { .... } error_mes := 'An ERROR'; { .... } write(listing, error_mes); display_error_on_screen(error_mes) END;
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.
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.
The following constants describe the sizes and positions of the different screens on the screen of the terminal:
stack_origin = 3; stack_size = 14; stack_bottom = stack_origin + stack_size; listing_bottom = 23; error_top = 24; error_bottom = 24;
These constants define the horizontal subdivision of the screen in the different screens in the following way:
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. |
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.
The following constants determine the vertical division of the screen:
max_line_len = 80; max_level_name = 25; max_info_name = max_line_len-7-max_level_name;
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.
The stack is stored in a double linked list. The following type declaration describes the elements of this list:
ptr_stack_line = [HIDDEN] ^type_stack_line; type_stack_line = [HIDDEN] RECORD lower , higher : ptr_stack_line; level : text_level; info : text_info END;
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.
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:
symbol_active : boolean; first_pos_symbol , last_pos_symbol , previous_pos_symbol : integer;
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:
error , preserve : boolean;
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.
There are two global variables that are used by the procedures write screen, writeln screen and writesc screen. These are declared by:
current_listing_pos : integer; listing_interrupted : boolean;
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.
The following module is used :
vt100
The following type definitions are exported by this module:
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_marking = (mark_normal, mark_error, mark_skip, mark_point, mark_reset);
The following procedures and functions are exported by this module:
PROCEDURE initialize_screen(name : text_level; vt100_used : boolean);
This procedure initiates an screen session. See subsection 2.2.1
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. See subsection 2.1.2
PROCEDURE add_screen_info(name : text_info);
This procedure changes the header of the screen. See subsection 2.1.3
PROCEDURE inform_screen(new_tracing : BOOLEAN);
This procedure is used to inform the stack whether it has to work tracing mode or normal mode. See subsection 2.1.4
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. See subsection 2.1.5
PROCEDURE wait(sec : real := 1.0);
This procedure causes the program to wait for sec seconds. See subsection 2.1.6
PROCEDURE init_level_stack;
This procedure initializes a stack screen. It is described in subsection 2.2.1
PROCEDURE purge_level_stack;
This procedure removes the stack screen. It is described in subsection 2.2.2
PROCEDURE enter_level(level : text_level);
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
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 represented by the parameter info. See subsection 2.2.3
PROCEDURE exit_level;
This procedure pops a line of the stack screen. It is described in subsection 2.2.3
PROCEDURE write_screen(info : VARYING[len] OF char := '');
This procedure adds the contents of the parameter info at the end of the listing screen. See subsection 2.4.3
PROCEDURE writeln_screen(info : VARYING[len] OF char := '');
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
PROCEDURE writecr_screen;
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
PROCEDURE echo_line_on_screen(line_number : integer:= 0; line : listing_line);
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
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 the procedure echo line on screen, so that it can be pointed to by the procedure show_last_symbol. See subsection 2.4.2
PROCEDURE show_last_symbol(mark : kind_of_marking);
This procedure show the last symbol, in the marking that is represented by the parameter mark. See subsection 2.4.2
PROCEDURE display_error_on_screen(error : listing_line; delay : real := 1);
This procedure displays an error on the bottom screen. It is described in subsection 2.5
[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; |
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; |
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; |
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; |
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; |
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; |
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