(********** #File "CLIP_UNIX.PAS" (#Indent on, #Comment on) *******) (*********************************************************************) (* Program: CLIP_2 - Code from LIterate Program: 2-nd pass *) (* Purpose: Perform a run of the CLIP-system. *) (* Interface: CLIP.INI: File which contains all the information *) (* for this particular run. *) (* : Files containing the refinements. *) (* : Files containing the generated modules. *) (*********************************************************************) PROGRAM CLIP_2 (INPUT, OUTPUT); (*----------- Global parameters of the CLiP system ---------------*) CONST CLiP = 'Code from Literate Programs'; CLIP_VERSION = 'CLiP version 2.1'; (* Mod: EWvA 16/10/93 *) DFLT_INIFILE = 'CLIP.INI'; (* Mod: EWvA 16/10/93 *) DFLT_INIFILE_L = 8; (* Mod: EWvA 16/10/93 *) STRING_FIXED_L = 132; EMPTY_STRING_FIXED = ' '+ ' '+ ' '; MAX_FILE_SPEC_L = 132; MAX_NR_FILE_SPECS = 64; MAX_CHOICE_L = 100; ALLOWED_ID_CHARS = ['A'..'Z', 'a'..'z', '0'..'9', '.']; ERROR_MSG_LENGTH = 80; LOC_SPEC_L = 25; CORRUPT_INI_FILE = 1; (* Error_code used by CLIP_MNU *) FT_SIZE = MAX_NR_FILE_SPECS; MAX_LINE = 132; ST_SIZE = 30000; SP_SIZE = 65000; SYNTAX_LEN = 10; MAX_MODE_L = 16; MAX_M_D_L = 10; MAX_NR_SRC_FILES = MAX_NR_FILE_SPECS; MAX_NR_RSLT_MODULES = 10; MAX_EXTR_MODE_L = 9; MAX_FILE_EXT_L = 39; MAX_OPTION_LENGTH = 15; MAX_OPTIONS = 12; (*----------- Constants to assist implemention of ADTs -----------*) CONST MAX_NR_MESS = 35; MAX_ERROR = 100; CONST EMPTY_OPTION = ' '; (*----------- Global simple types of the CLiP system -------------*) TYPE TO_BE_DECIDED_LATER_ = (DEFINED,UNDEFINED); LONGINTEGER = -2147483647..2147483647; STRING_FIXED_ = PACKED ARRAY[1..STRING_FIXED_L] OF CHAR; FILE_MODE_ = (INSP_MODE, GEN_MODE); SPECIAL_CHOICE_ = CHAR; ALLOWED_ANSW_ = SET OF CHAR; ERROR_MSG_ = STRING_FIXED_; SEV_CODE_ = (WARN, ERR, FAIL, DUMP); LOC_SPEC_ = PACKED ARRAY[1..LOC_SPEC_L] OF CHAR; FT_INDEX_ = 0..FT_SIZE; ERROR_CODE_ = INTEGER; ST_INDEX_ = -1..ST_SIZE; SEGMENT_TYPE_ = (STUB, SLOT, CODE, END_STUB); SP_INDEX_ = -1..SP_SIZE; SYNTAX_STRING_ = STRING_FIXED_; MODE_ = STRING_FIXED_; MESSAGE_DESTINATION_ = STRING_FIXED_; EXTR_MODE_ = STRING_FIXED_; FILE_EXT_ = STRING_FIXED_; CATEGORY_ = (L1, L2, L3, L4, L5); SLT_PTR_ = ^SLOT_DES_; STB_PTR_ = ^STUB_DES_; SHADOW_PTR_ = ^SHADOW_LIST_; (*----------- Global structured types of the CLiP system ---------*) STRING132_ = RECORD BODY: STRING_FIXED_; LENGTH: INTEGER; END (*RECORD*); FILE_SPEC_ = RECORD LENGTH: INTEGER; BODY: STRING_FIXED_; END (*RECORD*); RSLT_MOD_SPEC_ = RECORD FILE_NAME: FILE_SPEC_; PATH: FILE_SPEC_; END (*RECORD*); SOURCE_FILES_ = ARRAY[1..MAX_NR_SRC_FILES] OF FILE_SPEC_; RSLT_MODULES_ = ARRAY[1..MAX_NR_RSLT_MODULES] OF RSLT_MOD_SPEC_; FILE_SPECS_ = RECORD NR_FILE_SPECS: INTEGER; FILES: SOURCE_FILES_; END (*RECORD*); LINE_DES_ = RECORD CHARS: STRING_FIXED_; INDENT: INTEGER; USED: INTEGER; ID: INTEGER; POS_OPTION_MARKER: INTEGER; END (*RECORD*); SEGMENT_DES_ = RECORD FIRST: ST_INDEX_; LAST: ST_INDEX_; END (*RECORD*); STRING_DES_ = RECORD FIRST: SP_INDEX_; LAST: SP_INDEX_; END (*RECORD*); SYNTAX_ = RECORD BODY: SYNTAX_STRING_; LENGTH: INTEGER; END (*RECORD*); RUN_INFO_ = RECORD CLIP_LPAR, CLIP_RPAR: SYNTAX_; CLIP_CC: CHAR; CLIP_END: SYNTAX_; OPTION_MARKER: CHAR; MODE: MODE_; INT_FAULT_CORR: BOOLEAN; MESSAGE_DESTINATION: MESSAGE_DESTINATION_; REPORT_FILE_SPEC: FILE_SPEC_; NR_SRC_FILES: INTEGER; SOURCE_FILES: SOURCE_FILES_; EXTR_MODE: EXTR_MODE_; NR_MODULES: INTEGER; RSLT_MODULES: RSLT_MODULES_; DFLT_EXT: FILE_EXT_; MODULE_DIRECTORY: FILE_SPEC_; END (*RECORD*); LINE_INFO_ = RECORD LINE_ID: STRING_DES_; CATEGORY: CATEGORY_; OPTIONS: BOOLEAN; END (*RECORD*); OPTIONS_ = RECORD QUICK, MULTIPLE, OPTIONAL, OVERRULE, LEADER, TRAILER, SEPARATOR, DEFAULT, LINENUMBER: BOOLEAN; INDENT, FILE_NAME, COMMENT: STRING_DES_; END (*RECORD*); STUB_DES_ = RECORD NAME: STRING_DES_ ; SRC_IMG: SEGMENT_DES_; OPTIONS: OPTIONS_ ; SLOTS: SLT_PTR_ ; NEXT_TWIN, NEXT_STUB: STB_PTR_ ; VISITED: BOOLEAN ; END (*RECORD*); SLOT_DES_ = RECORD NAME: STRING_DES_; SRC_IMG: SEGMENT_DES_; OPTIONS: OPTIONS_; STUB_REF: STB_PTR_; CODE: SEGMENT_DES_; NEXT_SLOT: SLT_PTR_; END (*RECORD*); CODE_STRUCT_ = RECORD FIRST_STUB: STB_PTR_; LAST_STUB: STB_PTR_; END (*RECORD*); SHADOW_LIST_ = RECORD STUB_POINTER: STB_PTR_; NEXT: SHADOW_PTR_; END (*RECORD*); (*----------- Types to assist implemention of ADTs ---------------*) TYPE SP_TYPE = RECORD CHARS: ARRAY[1..SP_SIZE] OF CHAR; USED : SP_INDEX_; END (*RECORD*); SP_PTR = ^SP_TYPE; TYPE OPTION_KEYWORD_ = PACKED ARRAY [1..MAX_OPTION_LENGTH] OF CHAR; (*----------- Global variables of the CLiP system ----------------*) VAR REPORT_FILE: TEXT; REPORT_OK: BOOLEAN; (*----------- Variables to assist implemention of ADTs -----------*) VAR START, STOP: LONGINTEGER; CONTINUE: BOOLEAN; RUN_INFO: RUN_INFO_; CODE_STRUCT: CODE_STRUCT_; (* STRING132: STRING132_; 22/10/93 *) (* DUMMY_LINE: LINE_DES_; 22/10/93 *) (* DUMMY_SEG: SEGMENT_DES_; 22/10/93 *) DUMMY_ERROR: INTEGER; INI_FILE: TEXT; EXT_FILE_SPEC: FILE_SPEC_; DUMMY_FILE_OK: BOOLEAN; DUMMY_ERROR_MSG: ERROR_MSG_; DUMMY_ERROR_CODE: INTEGER; ERROR_CODE: ERROR_CODE_; AUX_STRING_8: PACKED ARRAY[1..8] OF CHAR; I: INTEGER; ERROR_MSG : ERROR_MSG_; VAR FILE_TABLE: ARRAY[1..FT_SIZE] OF RECORD FILE_SPEC: FILE_SPEC_; FIRST: INTEGER; LAST: INTEGER; END (*RECORD*); LAST_LINE: INTEGER; LAST_FILE: FT_INDEX_; CURR_IN_FILE: TEXT; CURR_OUT_FILE: TEXT; SPACE: SET OF CHAR; VAR SEGMENT_TABLE: RECORD LINES: ARRAY [1..ST_SIZE] OF LINE_DES_; USED: ST_INDEX_; END (*RECORD*); LAST_READ_SEG: RECORD LAST_SEG: SEGMENT_DES_; LAST_LINE: ST_INDEX_; END (*RECORD*); VAR STRING_POOL: SP_PTR; BUFFER: STRING132_; VAR DIAG_TBL: ARRAY[1..MAX_NR_MESS] OF RECORD MESSAGE: STRING_FIXED_; MESS_LOC: LOC_SPEC_; MESS_L: INTEGER; END (*RECORD*); NO_MESSAGES: BOOLEAN; MSG_TBL: ARRAY[1..MAX_ERROR+1] OF RECORD SEV: SEV_CODE_; LOC: LOC_SPEC_; SOURCE_LINE: LINE_DES_; SEGMENT: SEGMENT_DES_; STRING132: STRING132_; LINE_ABS: INTEGER; END (*RECORD*); NR_MSG: INTEGER; VAR ALLOWED: SET OF CHAR; VAR OPTION_TABLE: ARRAY [1..MAX_OPTIONS] OF OPTION_KEYWORD_; OPT_SPACE: SET OF CHAR; OPT_CHARS: SET OF CHAR; DEFAULT_OPTIONS: OPTIONS_; PASCAL_STRING: STRING_FIXED_; FORTRAN_STRING: STRING_FIXED_; C_STRING: STRING_FIXED_; (*----------- Forward declarations -------------------------------*) PROCEDURE CLIP_STOP; FORWARD; PROCEDURE EXT_FILE_CLOSE( VAR FILE_VAR : TEXT; VAR ERROR_CODE: INTEGER); FORWARD; PROCEDURE EXT_FILE_PREP (VAR FILE_VAR: TEXT; EXT_FILE_SPEC: FILE_SPEC_; FILE_MODE: FILE_MODE_; VAR FILE_OK: BOOLEAN; VAR ERROR_CODE: INTEGER; VAR ERROR_MSG: ERROR_MSG_ ); FORWARD; PROCEDURE READ_FILE_SPEC (VAR AUX_FILE_SPEC: FILE_SPEC_; VAR FILE_SPEC_OK: BOOLEAN); FORWARD; PROCEDURE UC_WORD (VAR STR: PACKED ARRAY [ONE..LEN:INTEGER] OF CHAR); FORWARD; PROCEDURE WRITE_STRING (VAR OUT_FILE: TEXT; OUT_STRING: STRING_FIXED_; NR_CHARS: INTEGER); FORWARD; PROCEDURE WRLN_STRING (VAR OUT_FILE: TEXT; OUT_STRING: STRING_FIXED_; NR_CHARS: INTEGER; SPACE: INTEGER); FORWARD; FUNCTION CHECK_SYNTAX (LPAR, RPAR, END_STRING: SYNTAX_; CC, MARKER: CHAR): BOOLEAN; FORWARD; PROCEDURE INIT_RUN_INFO (VAR INIT_INFO: RUN_INFO_); FORWARD; PROCEDURE READ_INI_FILE (VAR INI_FILE: TEXT; VAR READ_INFO: RUN_INFO_; EXT_FILE_SPEC: FILE_SPEC_; VAR FILE_OK: BOOLEAN; VAR ERROR_MSG: ERROR_MSG_; VAR ERROR_CODE: INTEGER); FORWARD; PROCEDURE READ_LINE_SAFELY (VAR FILE_IN: TEXT); FORWARD; PROCEDURE READ_STRING (VAR IN_FILE: TEXT; VAR IN_STR_LN: INTEGER; VAR IN_STR_BODY: STRING_FIXED_; NR_CHARS_TO_READ: INTEGER); FORWARD; FUNCTION UC (INCHAR: CHAR): CHAR; FORWARD; PROCEDURE VAL_INI_DATA (VAR VAL_INFO: RUN_INFO_; VAR OK: BOOLEAN); FORWARD; FUNCTION FT_ABS_LINE_NUMBER (SOURCE_LINE: LINE_DES_): INTEGER; FORWARD; FUNCTION FT_CHECK_FILE (FILE_SPEC: FILE_SPEC_): ERROR_CODE_; FORWARD; FUNCTION FT_EOF: BOOLEAN; FORWARD; FUNCTION FT_GET_CHAR (SOURCE_LINE: LINE_DES_; INDEX: INTEGER): CHAR; FORWARD; PROCEDURE FT_GET_FILE_SPEC (SOURCE_LINE:LINE_DES_; VAR FILE_SPEC:FILE_SPEC_); FORWARD; FUNCTION FT_GET_INDENT (SOURCE_LINE: LINE_DES_): INTEGER; FORWARD; FUNCTION FT_GET_LINE_LENGTH (SOURCE_LINE: LINE_DES_): INTEGER; FORWARD; FUNCTION FT_GET_LINE_NUMBER (SOURCE_LINE: LINE_DES_): INTEGER; FORWARD; FUNCTION FT_GET_POS_OPTION_MARKER (SOURCE_LINE: LINE_DES_): INTEGER; FORWARD; FUNCTION FT_INCLOSE: ERROR_CODE_; FORWARD; PROCEDURE FT_INIT; FORWARD; PROCEDURE FT_INIT_LINE (VAR LINE: LINE_DES_); FORWARD; FUNCTION FT_INOPEN (FILE_SPEC: FILE_SPEC_): ERROR_CODE_; FORWARD; FUNCTION FT_OUTOPEN (FILE_SPEC: FILE_SPEC_): ERROR_CODE_; FORWARD; FUNCTION FT_OUTCLOSE: ERROR_CODE_; FORWARD; PROCEDURE FT_RDLN (VAR LINE: LINE_DES_); FORWARD; PROCEDURE FT_WRLN (VAR LINE: LINE_DES_; NR_BLANKS: INTEGER; DESTINATION: INTEGER); FORWARD; FUNCTION ST_ABS_SEG (SEGMENT: SEGMENT_DES_):INTEGER; FORWARD; PROCEDURE ST_GET_FILE_SPEC ( SEGMENT: SEGMENT_DES_; VAR FILE_SPEC: FILE_SPEC_); FORWARD; FUNCTION ST_GET_INDENT (SEG: SEGMENT_DES_): INTEGER; FORWARD; PROCEDURE ST_GET_LINE (VAR LINE: LINE_DES_); FORWARD; PROCEDURE ST_GET_OPTION_LINE (SEG: SEGMENT_DES_; VAR LINE: LINE_DES_); FORWARD; PROCEDURE ST_GET_SEG (SEG: SEGMENT_DES_; VAR LINE: LINE_DES_); FORWARD; PROCEDURE ST_GET_SEG_RANGE ( SEGMENT: SEGMENT_DES_; VAR FIRST, LAST:INTEGER); FORWARD; PROCEDURE ST_INIT; FORWARD; PROCEDURE ST_INIT_SEG (VAR SEG: SEGMENT_DES_); FORWARD; FUNCTION ST_IS_EMPTY_SEG (SEG: SEGMENT_DES_): BOOLEAN; FORWARD; FUNCTION ST_NUMBER_OF_LINES (SEG: SEGMENT_DES_): INTEGER; FORWARD; PROCEDURE ST_PUT_LINE (LINE: LINE_DES_; VAR SEG: SEGMENT_DES_); FORWARD; PROCEDURE ST_PUT_SEG (LINE: LINE_DES_; VAR SEG: SEGMENT_DES_); FORWARD; PROCEDURE ST_FINIT; FORWARD; FUNCTION ST_SEG_WIDTH (SEG: SEGMENT_DES_): INTEGER; FORWARD; PROCEDURE ST_WRITE_SEG (SEG: SEGMENT_DES_; BLANKS: INTEGER; DESTINATION: INTEGER); FORWARD; PROCEDURE SP_ADD_CHAR (CH: CHAR; VAR STR: STRING_DES_); FORWARD; PROCEDURE SP_CONC_STR (VAR MASTER: STRING_DES_; SLAVE: STRING_DES_); FORWARD; FUNCTION SP_EQ (STR1: STRING_DES_; STR2: STRING_DES_): BOOLEAN; FORWARD; PROCEDURE SP_EXTR_STR (STR: STRING_DES_; VAR STR132: STRING132_); FORWARD; FUNCTION SP_GET_CHAR (INDEX: INTEGER; STR: STRING_DES_): CHAR; FORWARD; PROCEDURE SP_INIT; FORWARD; PROCEDURE SP_INIT_STR (VAR STR: STRING_DES_); FORWARD; FUNCTION SP_IS_EMPTY_STR (STR: STRING_DES_): BOOLEAN; FORWARD; FUNCTION SP_LENGTH_STR (STR: STRING_DES_): INTEGER; FORWARD; PROCEDURE SP_ADD_BUFFER (VAR STR: STRING_DES_); FORWARD; PROCEDURE SP_ADD_BUFFER_CHAR (CH: CHAR); FORWARD; FUNCTION SP_GET_BUFFER_CHAR (INDEX: INTEGER): CHAR; FORWARD; PROCEDURE SP_INIT_BUFFER; FORWARD; (*----------- General routines -----------------------------------*) (*********************************************************************) (* Procedure: CLIP_STOP (VAX-version) *) (* Purpose: To halt a program without any message or dump. *) (*********************************************************************) PROCEDURE CLIP_STOP; BEGIN HALT END (*PROCEDURE CLIP_STOP*); (*********************************************************************) (* Routine: EXT_FILE_CLOSE (VAX-version) *) (* Purpose: To close an external file. *) (* Interface: FILE_VAR - Pascal file in question *) (* ERROR_CODE - Error indication to caller *) (*********************************************************************) PROCEDURE EXT_FILE_CLOSE; BEGIN CLOSE (FILE_VAR); ERROR_CODE := 0; END (*EXT_FILE_CLOSE*); (*********************************************************************) (* Procedure: EXT_FILE_PREP ( VAX-version ) *) (* Purpose: To prepare an external file for reading from it *) (* or writing to it. *) (* Interface: EXT_FILE_SPEC - VMS-file in question. *) (* FILE_MODE - Mode indicator. *) (* FILE_VAR - Pascal file in question. *) (* FILE_OK - Indicates succesfull preparation. *) (* ERROR_CODE - Error indication to caller. *) (* ERROR_MSG - Error message to caller. *) (*********************************************************************) PROCEDURE EXT_FILE_PREP; VAR AUX_FILE_SPEC: VARYING [MAX_FILE_SPEC_L] OF CHAR; BEGIN ERROR_CODE := -1; (* Initialization *) AUX_FILE_SPEC := EXT_FILE_SPEC.BODY; IF (FILE_MODE = INSP_MODE) THEN BEGIN IF (EXT_FILE_SPEC.LENGTH <> 0) THEN BEGIN (* First the file has to be opened. *) OPEN (FILE_VAR, AUX_FILE_SPEC, 'old', ERROR_CODE); IF ERROR_CODE = 0 THEN RESET (FILE_VAR); END (*IF*); END ELSE BEGIN (* FILE_MODE is gelijk aan GEN_MODE *) IF (EXT_FILE_SPEC.LENGTH <> 0) THEN BEGIN (* First the file has to be opened. *) OPEN (FILE_VAR, AUX_FILE_SPEC, 'unknown', ERROR_CODE); IF ERROR_CODE = 0 THEN REWRITE (FILE_VAR); END (*IF*); END (*IF*); (* DEFAULT CODE: *) IF NOT (ERROR_CODE = 0) THEN BEGIN FILE_OK := FALSE; (* This string is a bit too short for the assignment, *) (* but that is no problem in VAX-Pascal. *) CASE ERROR_CODE OF -1: BEGIN ERROR_MSG := 'Empty file name.'; END; 2: BEGIN ERROR_MSG := 'File not found.'; END; OTHERWISE ERROR_MSG := 'Unsuccesful performance'; END (*CASE*); END (*IF*) ELSE BEGIN FILE_OK := TRUE; ERROR_MSG := 'Succesful performance. '; ERROR_CODE := 0; END (*IF*); (* END DEFAULT CODE *) END (*EXT_FILE_PREP*); (*********************************************************************) (* Procedure: READ_FILE_SPEC *) (* Purpose: To read a filespecification from the terminal. *) (* Interface: AUX_FILE_SPEC - Returned file specification. *) (* FILE_SPEC_OK - File specification from terminal. *) (* Author/Date: Maarten Rooda, January 1991. *) (*********************************************************************) PROCEDURE READ_FILE_SPEC; VAR VAX_AUX_FILE_SPEC: VARYING [MAX_FILE_SPEC_L] OF CHAR; I: INTEGER; (* loopvariable. *) DUMMY_FILE: TEXT; FILE_OK: BOOLEAN; ERROR_CODE: INTEGER; ERROR_MSG: ERROR_MSG_; BEGIN FILE_SPEC_OK := TRUE; READLN (VAX_AUX_FILE_SPEC); FOR I := 1 TO LENGTH(VAX_AUX_FILE_SPEC) DO BEGIN AUX_FILE_SPEC.BODY[I] := VAX_AUX_FILE_SPEC[I]; END (*FOR*); AUX_FILE_SPEC.LENGTH := LENGTH(VAX_AUX_FILE_SPEC) END (*PROCEDURE READ_FILE_SPEC*); (*********************************************************************) (* Routine: UC_WORD *) (* Pupose: To convert a string to upper case . *) (* Interface: STRING - String to be converted *) (*********************************************************************) PROCEDURE UC_WORD; VAR COUNTER: INTEGER; BEGIN FOR COUNTER := ONE TO LEN DO STR[COUNTER] := UC (STR[COUNTER]); END (*UC_WORD*); (*********************************************************************) (* Procedure: WRITE_STRING (VAX-version) *) (* Purpose: Write a part of a text string to a text file *) (* Interface: OUT_FILE - The file that is written to *) (* NR_CHARS - The number of CHAR's that have to be *) (* written to the file *) (* OUT_STRING - The string to be written *) (* Author/date: Hans Rabouw, March 1992 *) (*********************************************************************) PROCEDURE WRITE_STRING; VAR I: INTEGER; BEGIN FOR I:= 1 TO NR_CHARS DO WRITE(OUT_FILE, OUT_STRING[I]); END; (*********************************************************************) (* Routine: WRLN_STRING - WRiTeLN STRING. (VAX-version) *) (* Purpose: Write a part of a text string to a text file and *) (* jump to the next line in the file after that. *) (* Interface: OUT_FILE - The file that is written to *) (* NR_CHARS - The number of CHAR's that have to be *) (* written to the file *) (* OUT_STRING - The string to be written *) (* SPACE - Number of spaces written before string. *) (* Author/date: Heleen Hollenberg, june 1992. *) (*********************************************************************) PROCEDURE WRLN_STRING; VAR I: INTEGER; BEGIN FOR I := 1 TO SPACE DO WRITE (OUT_FILE, ' ' ); FOR I:= 1 TO NR_CHARS DO WRITE (OUT_FILE, OUT_STRING[I]); WRITELN (OUT_FILE); END; (*********************************************************************) (* Routine: READ_LINE_SAFELY *) (* Purpose: To read a line from a file . *) (* Interface: FILE_IN - File to be read *) (* Author/date: Boudewijn Pelt, August 1991. *) (*********************************************************************) PROCEDURE READ_LINE_SAFELY; BEGIN IF NOT EOF (FILE_IN) THEN READLN (FILE_IN); END (*READ_LINE_SAFELY*); (*********************************************************************) (* Routine: CHECK_SYNTAX *) (* Purpose: To check the syntax parameters of CLIP. If they are *) (* not legal then the function result is FALSE *) (* Interface: LPAR - CLIP Left parenthesis definition *) (* RPAR - CLIP Right parenthesis definition *) (* END_STRING - End of stub indicator *) (* CC - CLIP Control Character *) (* MARKER - *) (* CHECK_SYNTAX - Show example of CLIP-syntax *) (* Author/date: Boudewijn Pelt, July 1991 *) (*********************************************************************) FUNCTION CHECK_SYNTAX; VAR COUNTER: INTEGER; ERROR: BOOLEAN; BEGIN ERROR := FALSE; FOR COUNTER := 1 TO SYNTAX_LEN DO IF MARKER IN [LPAR.BODY[COUNTER], RPAR.BODY[COUNTER], END_STRING.BODY[COUNTER]] THEN ERROR := TRUE; IF MARKER = CC THEN ERROR := TRUE; IF LPAR.BODY[LPAR.LENGTH] <> CC THEN ERROR := TRUE; IF RPAR.BODY[1] <> CC THEN ERROR := TRUE; WITH LPAR DO BEGIN IF LENGTH <= 1 THEN ERROR := TRUE; FOR COUNTER := 1 TO LENGTH DO IF BODY[COUNTER] IN ALLOWED_ID_CHARS THEN ERROR := TRUE; END (*WITH*); WITH RPAR DO BEGIN IF LENGTH <= 1 THEN ERROR := TRUE; FOR COUNTER := 1 TO LENGTH DO IF BODY[COUNTER] IN ALLOWED_ID_CHARS THEN ERROR := TRUE; END (*WITH*); WITH END_STRING DO BEGIN IF LENGTH <= 0 THEN ERROR := TRUE; FOR COUNTER := 1 TO LENGTH DO IF NOT (BODY[COUNTER] IN ALLOWED_ID_CHARS) THEN ERROR := TRUE; END (*WITH*); IF (CC IN ALLOWED_ID_CHARS) OR (CC = ' ') THEN ERROR := TRUE; IF (MARKER IN ALLOWED_ID_CHARS) OR (MARKER = ' ') THEN ERROR := TRUE; CHECK_SYNTAX := NOT ERROR; END (*CHECK_SYNTAX*); (*********************************************************************) (* Procedure: INIT_RUN_INFO . *) (* Purpose: To initialize the fields of a record INIT_INFO of *) (* type RUN_INFO_ to default values. *) (* Interface: INIT_INFO - Structure to initialize. *) (* Author/date: Maarten Rooda, January 1991. *) (*********************************************************************) PROCEDURE INIT_RUN_INFO; CONST AUX_STR_L = MAX_MODE_L; VAR I: INTEGER; AUX_STRING: PACKED ARRAY[1..AUX_STR_L] OF CHAR; BEGIN (******* INIT_RUN_INFO body *******) WITH INIT_INFO DO BEGIN (* additional parameters of init_info. *) CLIP_LPAR.BODY := EMPTY_STRING_FIXED; CLIP_LPAR.BODY[1] := '('; CLIP_LPAR.BODY[2] := '*'; CLIP_LPAR.BODY[3] := '*'; CLIP_LPAR.LENGTH := 3; CLIP_RPAR.BODY := EMPTY_STRING_FIXED; CLIP_RPAR.BODY[1] := '*'; CLIP_RPAR.BODY[2] := '*'; CLIP_RPAR.BODY[3] := ')'; CLIP_RPAR.LENGTH := 3; CLIP_END.BODY := EMPTY_STRING_FIXED; CLIP_END.BODY[1] := 'E'; CLIP_END.BODY[2] := 'N'; CLIP_END.BODY[3] := 'D'; CLIP_END.BODY[4] := 'O'; CLIP_END.BODY[5] := 'F'; CLIP_END.LENGTH := 5; CLIP_CC := '*'; OPTION_MARKER := '#'; (* old parameters. *) MODE := EMPTY_STRING_FIXED; AUX_STRING := 'INTERACTIVE_MODE'; FOR I := 1 TO MAX_MODE_L DO MODE[I] := AUX_STRING[I]; INT_FAULT_CORR := TRUE; MESSAGE_DESTINATION := EMPTY_STRING_FIXED; AUX_STRING := 'TERMINAL '; FOR I := 1 TO MAX_M_D_L DO MESSAGE_DESTINATION[I] := AUX_STRING[I]; REPORT_FILE_SPEC.BODY := EMPTY_STRING_FIXED; REPORT_FILE_SPEC.BODY[1] := 'C'; REPORT_FILE_SPEC.BODY[2] := 'L'; REPORT_FILE_SPEC.BODY[3] := 'I'; REPORT_FILE_SPEC.BODY[4] := 'P'; REPORT_FILE_SPEC.BODY[5] := '.'; REPORT_FILE_SPEC.BODY[6] := 'R'; REPORT_FILE_SPEC.BODY[7] := 'P'; REPORT_FILE_SPEC.BODY[8] := 'T'; REPORT_FILE_SPEC.LENGTH := 8; NR_SRC_FILES := 0; (* Default: *) EXTR_MODE := EMPTY_STRING_FIXED; AUX_STRING := 'OMITTED '; FOR I := 1 TO MAX_EXTR_MODE_L DO EXTR_MODE[I] := AUX_STRING[I]; NR_MODULES:= 0; MODULE_DIRECTORY.BODY := EMPTY_STRING_FIXED; MODULE_DIRECTORY.LENGTH := 0; END (* WITH INIT_INFO *); (***************** End of INIT_RUN_INFO body ***********************) END (*INIT_RUN_INFO*); (*********************************************************************) (* Procedure: READ_INI_FILE *) (* Purpose: To open an initializationfile and read data from *) (* it into a record READ_INFO of type RUN_INFO_ . *) (* Interface: INI_FILE: The initializationfile in question. *) (* READ_INFO: Information for a run of CLIP. *) (* EXT_FILE_SPEC: The filespecification *) (* FILE_OK: TRUE if data read successfully *) (* ERROR_MSG: Error message. *) (* ERROR_CODE: Type of error. *) (* Author/date: Maarten Rooda, February 1991. *) (*********************************************************************) PROCEDURE READ_INI_FILE; VAR DUMMY_CODE: INTEGER; (*********************************************************************) (* Procedure: READ_INI_DATA *) (* Purpose: To read data from an initializationfile into a *) (* record READ_INFO of type RUN_INFO_ . *) (* Interface: INI_FILE - INI-file to be read *) (* READ_INFO - Structure to return the data. *) (* Author/date: Boudewijn Pelt, May 1991. *) (*********************************************************************) PROCEDURE READ_INI_DATA(VAR INI_FILE: TEXT; VAR READ_INFO: RUN_INFO_); CONST SKIP_LINES = 5; VAR COUNTER: INTEGER; LETTER: STRING_FIXED_; (* This is an array that can be read by *) (* READ_STRING *) DUMMY_L: INTEGER; (* A dummy parameter for READ_STRING *) OK: BOOLEAN; AUX_STR_34 : PACKED ARRAY[1..34] OF CHAR; (*********************************************************************) (* Routine: GET_SOURCE_FILES *) (* Purpose: To read a number of filespecifications from an *) (* input file. *) (* Interface: FILE_IN - File with data to be read *) (* FILES - Data of files *) (* NR_FILES - Number of files *) (* Author/date: Boudewijn Pelt, August 1991 *) (* Modified: Hans Rabouw, March 1992 *) (*********************************************************************) PROCEDURE GET_SOURCE_FILES (VAR FILE_IN: TEXT; VAR FILES: SOURCE_FILES_; VAR NR_FILES: INTEGER); VAR I: INTEGER; READ_ON: BOOLEAN; AUX_FILE_SPEC: FILE_SPEC_; BEGIN I := 0; READ_ON := NOT (EOF (FILE_IN)); WHILE READ_ON DO BEGIN WITH AUX_FILE_SPEC DO READ_STRING(FILE_IN, LENGTH, BODY, MAX_FILE_SPEC_L); READ_LINE_SAFELY(INI_FILE); IF (AUX_FILE_SPEC.BODY[1] = '-') OR (AUX_FILE_SPEC.LENGTH = 0) THEN (* AUX_FILE_SPEC was not read successfully. *) READ_ON := FALSE ELSE IF I < MAX_NR_SRC_FILES THEN BEGIN (* AUX_FILE_SPEC was read successfully. *) I := I + 1; FILES[I] := AUX_FILE_SPEC; END (*IF.IF*); END (*WHILE*); NR_FILES := I; END (*GET_SOURCE_FILES*); (*********************************************************************) (* Routine: GET_MODULES *) (* Purpose: To read a number of filespecifications from an *) (* input file. *) (* Interface: FILE_IN - File with data to be read *) (* FILES - Data of files *) (* NR_FILES - Number of files *) (* Author/date: Boudewijn Pelt, August 1991 *) (* Modified: Hans Rabouw, March 1992 *) (*********************************************************************) PROCEDURE GET_MODULES (VAR FILE_IN: TEXT; VAR FILES: RSLT_MODULES_; VAR NR_FILES: INTEGER); VAR I: INTEGER; READ_ON: BOOLEAN; AUX_FILE_SPEC: FILE_SPEC_; AUX_PATH_SPEC: FILE_SPEC_; BEGIN I := 0; READ_ON := NOT (EOF (FILE_IN)); WHILE READ_ON DO BEGIN WITH AUX_PATH_SPEC DO READ_STRING(FILE_IN, LENGTH, BODY, MAX_FILE_SPEC_L); READ_LINE_SAFELY(INI_FILE); IF (AUX_PATH_SPEC.BODY[1] = '-') (* OR (AUX_PATH_SPEC.LENGTH = 0) (EWvA nav. HR 17/11/92) *) THEN (* AUX_PATH_SPEC was not read successfully. *) READ_ON := FALSE ELSE BEGIN WITH AUX_FILE_SPEC DO READ_STRING(FILE_IN, LENGTH, BODY, MAX_FILE_SPEC_L); READ_LINE_SAFELY(INI_FILE); IF (AUX_FILE_SPEC.BODY[1] = '-') OR (AUX_FILE_SPEC.LENGTH = 0) THEN READ_ON := FALSE ELSE IF I < MAX_NR_RSLT_MODULES THEN BEGIN (* AUX_FILE_SPEC was read successfully. *) I := I + 1; FILES[I].FILE_NAME := AUX_FILE_SPEC; FILES[I].PATH := AUX_PATH_SPEC; END (*IF.IF*); END (*IF*); END (*WHILE*); NR_FILES := I; END (*GET_MODULES*); BEGIN (******* READ_INI_DATA body *******) RESET (INI_FILE); FOR COUNTER := 1 TO SKIP_LINES DO READ_LINE_SAFELY(INI_FILE); WITH READ_INFO DO BEGIN (********************* READ_INI_DATA (1) ***********************) (** Read the data from INI_FILE into MODE, INT_FAULT_CORR, **) (** MESSAGE_DESTINATION, REPORT_FILE_SPEC, CLIP_LPAR, CLIP_- **) (** RPAR, CLIP_CC, CLIP_END, OPTION_MARKER, NR_SCR_FILES, **) (** SOURCE_FILES, NR_MODULES, EXTR_MODE, RSLT_MODULES. **) READ_STRING(INI_FILE, DUMMY_L, MODE, MAX_MODE_L); READ_LINE_SAFELY(INI_FILE); READ_STRING(INI_FILE, DUMMY_L, LETTER, 1); READ_LINE_SAFELY(INI_FILE); INT_FAULT_CORR := LETTER[1] = 'Y'; READ_STRING(INI_FILE, DUMMY_L, MESSAGE_DESTINATION, MAX_M_D_L); READ_LINE_SAFELY(INI_FILE); WITH CLIP_LPAR DO READ_STRING(INI_FILE, LENGTH, BODY, SYNTAX_LEN); READ_LINE_SAFELY(INI_FILE); WITH CLIP_RPAR DO READ_STRING(INI_FILE, LENGTH, BODY, SYNTAX_LEN); READ_LINE_SAFELY(INI_FILE); READ_STRING(INI_FILE, DUMMY_L, LETTER, 1); READ_LINE_SAFELY(INI_FILE); CLIP_CC := LETTER[1]; WITH CLIP_END DO READ_STRING(INI_FILE, LENGTH, BODY, SYNTAX_LEN); READ_LINE_SAFELY(INI_FILE); READ_STRING(INI_FILE, DUMMY_L, LETTER, 1); READ_LINE_SAFELY(INI_FILE); OPTION_MARKER := LETTER[1]; READ_STRING(INI_FILE, DUMMY_L, EXTR_MODE, MAX_EXTR_MODE_L); READ_LINE_SAFELY(INI_FILE); (************************ READ_INI_DATA (1.1) **********************) (** Read the file specifications REPORT_FILE_SPEC, **) (** SOURCE_FILES.FILES[1..NR_FILE_SPECS] **) (** RSLT_MODULES.FILES[1..NR_FILE_SPECS] from the INI_FILE. **) READ_LINE_SAFELY(INI_FILE); (* Skip -- REPORT FILE -- *) WITH REPORT_FILE_SPEC DO READ_STRING(INI_FILE, LENGTH, BODY, MAX_FILE_SPEC_L); READ_LINE_SAFELY(INI_FILE); READ_LINE_SAFELY(INI_FILE); (* skip -- INPUT FILES -- *) GET_SOURCE_FILES (INI_FILE, SOURCE_FILES, NR_SRC_FILES); GET_MODULES (INI_FILE, RSLT_MODULES, NR_MODULES); (* There is no need to skip the '--- MODULE DIRECTORY ---' line *) (* because it is read by the GET_MODULES procedure *) WITH MODULE_DIRECTORY DO READ_STRING(INI_FILE, LENGTH, BODY, MAX_FILE_SPEC_L); (***************** End of READ_INI_DATA (1.1) **********************) (************************ READ_INI_DATA (1.2) **********************) (** CLIP_LPAR and CLIP_RPAR are not complete. An CLIP_CC needs to **) (** be added. **) WITH CLIP_LPAR DO BEGIN IF LENGTH < SYNTAX_LEN THEN LENGTH := LENGTH + 1; BODY[LENGTH] := CLIP_CC; END (*WITH*); WITH CLIP_RPAR DO BEGIN LENGTH := LENGTH + 1; IF LENGTH > SYNTAX_LEN THEN LENGTH := SYNTAX_LEN; FOR COUNTER := LENGTH-1 DOWNTO 1 DO BODY[COUNTER+1] := BODY[COUNTER]; BODY[1] := CLIP_CC; END (*WITH*); (****************** End of READ_INI_DATA (1.2) *********************) (***************** End of READ_INI_DATA (1) ********************) END (*WITH*); (************************* READ_INI_DATA (2) ***********************) (** Check if READ_INFO is valid. If not display an error message **) (** and set READ_INFO to default values. **) VAL_INI_DATA (READ_INFO, OK); IF NOT OK THEN BEGIN (********************* READ_INI_DATA (2.1) *********************) (** Generate a warning message **) ERROR_CODE := CORRUPT_INI_FILE; ERROR_MSG := EMPTY_STRING_FIXED; AUX_STR_34 := 'THE SPECIFIED INI-FILE IS CORRUPT.'; FOR COUNTER := 1 TO 34 DO ERROR_MSG[COUNTER] := AUX_STR_34[COUNTER]; (***************** End of READ_INI_DATA (2.1) ******************) INIT_RUN_INFO(READ_INFO); END (*IF*); (********************* End of READ_INI_DATA (2) ********************) (***************** End of READ_INI_DATA body ***********************) END (*READ_INI_DATA*); BEGIN FILE_OK := FALSE; EXT_FILE_PREP(INI_FILE, EXT_FILE_SPEC, INSP_MODE, FILE_OK, ERROR_CODE, ERROR_MSG); IF FILE_OK THEN BEGIN READ_INI_DATA (INI_FILE, READ_INFO); (* If the INI-file contained an error, the READ_INFO record *) (* was initialized by READ_INI_DATA. *) EXT_FILE_CLOSE (INI_FILE, DUMMY_CODE); (* EWvA, 16/10/93 *) END (*IF*); END (*READ_INI_FILE*); (*********************************************************************) (* Procedure: READ_STRING *) (* Purpose: read a string from a text file and determine its *) (* length. *) (* Interface: IN_FILE - File to be read *) (* IN_STR_LN - Index in line to be read *) (* IN_STR_BODY - Body of the line *) (* Author/date: Maarten Rooda, September 1990. *) (* Modified: Boudewijn Pelt, June 1991 & July 1991. *) (* Hans Rabouw, March 1992 *) (*********************************************************************) PROCEDURE READ_STRING; VAR INDEX: INTEGER; BEGIN (* File is already open and in inspection mode. *) (* A prompt, if needed, has already been issued. *) IN_STR_LN := 0; INDEX := 1; IF NOT (EOF(IN_FILE)) OR (EOLN (IN_FILE)) THEN BEGIN WHILE NOT (EOLN (IN_FILE) OR (INDEX > NR_CHARS_TO_READ)) DO BEGIN READ(IN_FILE, IN_STR_BODY[INDEX]); INDEX := INDEX + 1; END (*WHILE*); IN_STR_LN := INDEX - 1; IF IN_STR_LN > 0 THEN WHILE (IN_STR_BODY[IN_STR_LN] = ' ') AND (IN_STR_LN > 1) DO IN_STR_LN := IN_STR_LN - 1; (* If not all of the string has been filled, write spaces to *) (* the cells that have not been filled. *) FOR INDEX := INDEX TO STRING_FIXED_L DO IN_STR_BODY[INDEX] := ' '; END (*IF*); END (*READ_STRING*); (*********************************************************************) (* Routine: UC - convert character to Upper-Case *) (* Purpose: To transform lower case letters to their uppercase *) (* equivalent. *) (* Interface: INCHAR - Character to be converted. *) (* - Converted character. *) (* Author/Date: Vamp project management, october 1983. *) (*********************************************************************) FUNCTION UC; BEGIN IF (INCHAR >= 'a') AND (INCHAR <= 'z') THEN UC := CHR (ORD(INCHAR) - ORD('a') + ORD('A')) ELSE UC := INCHAR; END (*UC*); (*********************************************************************) (* Routine: VAL_INI_DATA *) (* Purpose: Check if the run_info structure VAL_INFO is valid *) (* if this is not the case then attempt to fix it *) (* or return an error. (Make OK FALSE) *) (* Interface: VAL_INFO - Data from initialization. *) (* OK - TRUE if data OK. *) (* Author/date: Boudewijn Pelt, June 1991. *) (*********************************************************************) PROCEDURE VAL_INI_DATA; CONST AUX_STR_L = MAX_MODE_L; VAR ERROR: BOOLEAN; AUX_STRING: PACKED ARRAY [1..AUX_STR_L] OF CHAR; I: INTEGER; BEGIN ERROR := FALSE; WITH VAL_INFO DO BEGIN IF NOT (CHECK_SYNTAX(CLIP_LPAR, CLIP_RPAR, CLIP_END, CLIP_CC, OPTION_MARKER)) THEN ERROR := TRUE; (* Check MODE and set ERROR. *) IF MODE[1] IN ['I', 'i'] THEN AUX_STRING :='INTERACTIVE_MODE' ELSE IF MODE[1] IN ['A', 'a'] THEN AUX_STRING :='AUTO_MODE ' ELSE IF MODE[1] IN ['H', 'h'] THEN AUX_STRING :='HELPFUL_MODE ' ELSE IF MODE[1] IN ['D', 'd'] THEN AUX_STRING :='DEBUG_MODE ' ELSE ERROR := TRUE; IF NOT ERROR THEN FOR I := 1 TO MAX_MODE_L DO MODE[I] := AUX_STRING[I]; (* Check MESSAGE_DESTINATION and set ERROR. *) IF MESSAGE_DESTINATION[1] IN ['F', 'f'] THEN AUX_STRING := 'FILE ' ELSE IF MESSAGE_DESTINATION[1] IN ['T', 't'] THEN AUX_STRING := 'TERMINAL ' ELSE IF MESSAGE_DESTINATION[1] IN ['B', 'b'] THEN AUX_STRING := 'BOTH ' ELSE IF MESSAGE_DESTINATION[1] IN ['N', 'n'] THEN AUX_STRING := 'NONE ' ELSE ERROR := TRUE; IF NOT ERROR THEN FOR I := 1 TO MAX_M_D_L DO MESSAGE_DESTINATION[I] := AUX_STRING[I]; (* Check EXTR_MODE and set ERROR. *) IF EXTR_MODE[1] IN ['E', 'e'] THEN AUX_STRING := 'EXTRACTED ' ELSE IF EXTR_MODE[1] IN ['O', 'o'] THEN AUX_STRING := 'OMITTED ' ELSE ERROR := TRUE; IF NOT ERROR THEN FOR I := 1 TO MAX_EXTR_MODE_L DO EXTR_MODE[I] := AUX_STRING[I]; END (*WITH*); OK := NOT ERROR; END (*VAL_INI_DATA*); (*----------- File Table routines (ADT) --------------------------*) (*********************************************************************) (* Routine: FT_ABS_LINE_NUMBER - File Table ABSolute LINE NUMBER.*) (* Purpose: To return the absolute line number of a source line *) (* the source file. *) (* Interface: SOURCE_LINE - The specified source line. *) (* RETURNS - Absolute line number of the given *) (* SOURCE_LINE. *) (*********************************************************************) FUNCTION FT_ABS_LINE_NUMBER; BEGIN FT_ABS_LINE_NUMBER := SOURCE_LINE.ID; END (*FUNCTION FT_ABS_LINE_NUMBER*); (*********************************************************************) (* Routine: FT_CHECK_FILE *) (* Purpose: Checks whether a file is acccessable or not. *) (* Interface: FILE_SPEC - Specification of file to check. *) (* RETURNS - Code of a possible error. *) (* FT vars: CURR_IN_FILE. *) (*********************************************************************) FUNCTION FT_CHECK_FILE; VAR ERROR_CODE: ERROR_CODE_; DUMMY_FILE_OK: BOOLEAN; DUMMY_ERROR_MSG: ERROR_MSG_; BEGIN EXT_FILE_PREP (CURR_IN_FILE, FILE_SPEC, INSP_MODE, DUMMY_FILE_OK, ERROR_CODE, DUMMY_ERROR_MSG); IF ERROR_CODE<=0 THEN CLOSE (CURR_IN_FILE); FT_CHECK_FILE := ERROR_CODE; END (*FT_CHECK_FILE*); (*********************************************************************) (* Routine: FT_EOF *) (* Purpose: The function examines if the currently read file is *) (* exhausted. *) (* Interface: RETURNS - TRUE if the file is exhausted. *) (* FT vars: CURR_IN_FILE. *) (*********************************************************************) FUNCTION FT_EOF; BEGIN IF NOT EOF(CURR_IN_FILE) THEN FT_EOF := FALSE ELSE FT_EOF := TRUE; END (*FT_EOF*); (*********************************************************************) (* Routine: FT_GET_CHAR *) (* Purpose: To locate a character at a given position in a *) (* source_line and to return this character. *) (* Interface: SOURCE_LINE - The source line. *) (* INDEX - Index of the desired character. *) (* RETURNS - The desired character. *) (* CLIP objs: MAX_LINE. *) (*********************************************************************) FUNCTION FT_GET_CHAR; BEGIN IF (INDEX > MAX_LINE) OR (INDEX <= 0) THEN BEGIN WRITELN (OUTPUT, 'FT-GET-CHAR (a): ', 'System Failure... Call maintenance.'); CLIP_STOP; END (*IF*); IF INDEX > SOURCE_LINE.USED THEN BEGIN WRITELN (OUTPUT, 'FT-GET-CHAR (B): ', 'System Failure... Call maintenance.'); CLIP_STOP; END (*IF*); (* Index is within legal range. Proceed... *) FT_GET_CHAR := SOURCE_LINE.CHARS[INDEX]; END (*FT_GET_CHAR*); (*********************************************************************) (* Routine: FT_GET_FILE_SPEC *) (* Purpose: To return the file specification of a source line *) (* Interface: SOURCE_LINE - The source line. *) (* FILE_SPEC - The wanted file specification. *) (* FT vars: FILE_TABLE. *) (*********************************************************************) PROCEDURE FT_GET_FILE_SPEC; VAR INDEX: FT_INDEX_; BEGIN (* Beware of non-existing line identifications. *) IF (SOURCE_LINE.ID <= 0) OR (SOURCE_LINE.ID > FILE_TABLE[LAST_FILE].LAST) THEN BEGIN WRITELN (OUTPUT, 'FT-GET-FILE-SPEC: ', 'System Failure... Call maintenance.'); CLIP_STOP; END (*IF*); (* Line surely exist in FT. Find its specification. *) INDEX := 1; WHILE FILE_TABLE[INDEX].LAST < SOURCE_LINE.ID DO INDEX := INDEX+1; FILE_SPEC := FILE_TABLE[INDEX].FILE_SPEC; END (*FT_GET_FILE_SPEC*); (*********************************************************************) (* Routine: FT_GET_INDENT *) (* Purpose: To return the indentation of a line *) (* Interface: SOURCE_LINE - The source line. *) (* RETURNS - The indentation of SOURCE_LINE. *) (*********************************************************************) FUNCTION FT_GET_INDENT; BEGIN FT_GET_INDENT := SOURCE_LINE.INDENT; END (*FT_GET_INDENT*); (*********************************************************************) (* Routine: FT_GET_LINE_LENGTH *) (* Purpose: To return the length of a line *) (* Interface: SOURCE_LINE - Line-descriptor to be examined. *) (* RETURNS - Length of given line. *) (*********************************************************************) FUNCTION FT_GET_LINE_LENGTH; BEGIN FT_GET_LINE_LENGTH := SOURCE_LINE.USED; END (*FT_GET_LINE_LENGTH*); (*********************************************************************) (* Routine: FT_GET_LINE_NUMBER *) (* Purpose: To return the line number of a source line. *) (* Interface: SOURCE_LINE - The source line *) (* RETURNS - Line number or error code. *) (* FT vars: FILE_TABLE. *) (*********************************************************************) FUNCTION FT_GET_LINE_NUMBER; VAR INDEX: FT_INDEX_; BEGIN (* Beware of non-existing line identifications. *) IF (SOURCE_LINE.ID <= 0) OR (SOURCE_LINE.ID > FILE_TABLE[LAST_FILE].LAST) THEN BEGIN WRITELN (OUTPUT, 'FT_GET_LINE_NUMBER: ', 'System Failure... Call maintenance.'); CLIP_STOP; END (*IF*); (* Line surely exist in FT. Find its number. *) INDEX := 1; WHILE FILE_TABLE[INDEX].LAST < SOURCE_LINE.ID DO INDEX := INDEX + 1; FT_GET_LINE_NUMBER := SOURCE_LINE.ID - FILE_TABLE[INDEX].FIRST + 1; END (*FT_GET_LINE_NUMBER*); (*********************************************************************) (* Routine: FT_GET_POS_OPTION_MARKER *) (* Purpose: Return the value of POS_OPTION_MARKER. *) (* Interface: SOURCE_LINE - Line-descriptor to be examined. *) (* RETURNS - Position of the OPTION_MARKER. *) (*********************************************************************) FUNCTION FT_GET_POS_OPTION_MARKER; BEGIN FT_GET_POS_OPTION_MARKER := SOURCE_LINE.POS_OPTION_MARKER; END (*FT_GET_POS_MARKER*); (*********************************************************************) (* Routine: FT_INCLOSE *) (* Purpose: Close the current input file. *) (* Interface: RETURNS - Code of a possible error. *) (* FT vars: CURR_IN_FILE. *) (*********************************************************************) FUNCTION FT_INCLOSE; VAR ERROR_CODE: ERROR_CODE_; BEGIN EXT_FILE_CLOSE (CURR_IN_FILE, ERROR_CODE); FT_INCLOSE := ERROR_CODE; END (*FT_INCLOSE*); (*********************************************************************) (* Routine: FT_INIT *) (* Purpose: General initialization of the file table. It is only *) (* activated once at the start of an run. *) (* FT vars: FILE_TABLE, LAST_LINE, LAST_FILE, SPACE. *) (*********************************************************************) PROCEDURE FT_INIT; VAR K: FT_INDEX_; BEGIN FOR K := 1 TO FT_SIZE DO WITH FILE_TABLE[K] DO BEGIN FILE_SPEC.LENGTH := 0; FIRST := 0; LAST := 0; END (*WITH*); LAST_LINE := 0; LAST_FILE := 0; SPACE := [CHR(0) .. CHR(9), CHR(14) .. CHR(25), CHR(28) .. CHR(32), CHR(11), CHR(127)]; END (*FT_INIT*); (*********************************************************************) (* Routine: FT_INIT_LINE *) (* Purpose: Initialization of a LINE_DES_-object. *) (*********************************************************************) PROCEDURE FT_INIT_LINE; BEGIN WITH LINE DO BEGIN INDENT := 0; USED := 0; ID := 0; POS_OPTION_MARKER := 0; END (*WITH*); END (*FT_INIT_LINE*); (*********************************************************************) (* Routine: FT_INOPEN *) (* Purpose: Opens a new file with the given specification for *) (* read access. *) (* Interface: FILE_SPEC - Specification of file to open. *) (* RETURNS - Code of a possible error. *) (* FT vars: FILE_TABLE, LAST_FILE, CURR_IN_FILE. *) (*********************************************************************) FUNCTION FT_INOPEN; VAR ERROR_CODE: ERROR_CODE_; DUMMY_FILE_OK: BOOLEAN; DUMMY_ERROR_MSG: ERROR_MSG_; BEGIN EXT_FILE_PREP (CURR_IN_FILE, FILE_SPEC, INSP_MODE, DUMMY_FILE_OK, ERROR_CODE, DUMMY_ERROR_MSG); IF ERROR_CODE = 0 THEN BEGIN LAST_FILE := LAST_FILE+1; FILE_TABLE[LAST_FILE].FILE_SPEC := FILE_SPEC; END (*IF*); FT_INOPEN := ERROR_CODE; END (*FT_INOPEN*); (*********************************************************************) (* Routine: FT_OUTOPEN *) (* Purpose: Opens a new file with the given specification for *) (* write access. *) (* Interface: FILE_SPEC - Specification of outputfile. *) (* RETURNS - Code of a possible error. *) (* FT vars: CURR_OUT_FILE. *) (*********************************************************************) FUNCTION FT_OUTOPEN; VAR ERROR_CODE: ERROR_CODE_; DUMMY_FILE_OK: BOOLEAN; DUMMY_ERROR_MSG: ERROR_MSG_; BEGIN EXT_FILE_PREP (CURR_OUT_FILE, FILE_SPEC, GEN_MODE, DUMMY_FILE_OK, ERROR_CODE, DUMMY_ERROR_MSG); (* The opening was successfull. Make ERROR_CODE equal to *) (* STATUS (CURR_OUT_FILE) in case an error occured during the *) (* REWRITE operation (flagged by a value <> -1). *) FT_OUTOPEN := ERROR_CODE; END (*FT_OUTOPEN*); (*********************************************************************) (* Routine: FT_OUTCLOSE *) (* Purpose: Close the current output file. *) (* Interface: RETURNS - Code of a possible error. *) (* FT vars: CURR_OUT_FILE. *) (*********************************************************************) FUNCTION FT_OUTCLOSE; VAR ERROR_CODE: ERROR_CODE_; BEGIN EXT_FILE_CLOSE (CURR_OUT_FILE, ERROR_CODE); FT_OUTCLOSE := ERROR_CODE; END (*FT_OUTCLOSE*); (*********************************************************************) (* Routine: FT_RDLN *) (* Purpose: Read the next line from the current source-file. *) (* Interface: LINE - A source-line is returned in the form of a *) (* line descriptor. *) (* FT vars: SPACE *) (*********************************************************************) PROCEDURE FT_RDLN; CONST TAB = 8; VAR STR132: STRING132_; INDEX, K: INTEGER; BEGIN WITH LINE DO BEGIN INDENT := 0; USED := 0; POS_OPTION_MARKER := 0; WITH STR132 DO BEGIN BODY := EMPTY_STRING_FIXED; LENGTH := 0; WHILE (NOT EOLN(CURR_IN_FILE)) AND (LENGTH < STRING_FIXED_L) DO BEGIN LENGTH := LENGTH + 1; READ (CURR_IN_FILE, BODY[LENGTH]); END (*WHILE*); READLN (CURR_IN_FILE); (* Check spaces at beginning of string and calculate *) (* INDENT. *) INDEX := 1; WHILE (INDEX < LENGTH) AND (BODY[INDEX] IN SPACE) DO BEGIN IF BODY[INDEX] = CHR(9) THEN INDENT := INDENT + (TAB - (INDENT MOD TAB)) ELSE INDENT := INDENT + 1; INDEX := INDEX + 1; END (*WHILE*); LAST_LINE := LAST_LINE + 1; FOR K := INDEX TO LENGTH DO CHARS[K-INDEX+1] := BODY[K]; (* Remove spaces at the end of the line. *) IF LENGTH > 0 THEN BEGIN USED := LENGTH-INDEX+1; (*********************************************************************) (* Modified 14/10/93 by Mark Kramer to solve an index out of bound *) (* problem when bound checks are on. *) (* WHILE (USED >0) AND (CHARS[USED] IN SPACE) DO *) (* USED := USED-1; *) WHILE (USED > 1) AND (CHARS[USED] IN SPACE) DO USED := USED-1; IF (USED = 1) AND (CHARS[USED] IN SPACE) THEN USED := USED-1; (* End of modification 14/10/93. *) (*********************************************************************) END (*IF*); ID := LAST_LINE; END (*WITH*); (* Update the File Table. *) IF FILE_TABLE[LAST_FILE].FIRST = 0 THEN FILE_TABLE[LAST_FILE].FIRST := LAST_LINE; FILE_TABLE[LAST_FILE].LAST := LAST_LINE; END (*WITH*); END (*FT_RDLN*); (*********************************************************************) (* Routine: FT_WRLN *) (* Purpose: Write a line to the current output file. *) (* Interface: LINE - The line to be written. *) (* NR_BLANKS - The number of blanks leading the *) (* first character of LINE. *) (* DESTINATION - The destination of the line (screen, *) (* output file, reportfile etc.) *) (* REPORT_FILE - Report file for output. *) (*********************************************************************) PROCEDURE FT_WRLN; VAR INDEX: INTEGER; NR_TOTAL_BLANKS: INTEGER; BEGIN (*FT_WRLN*) NR_TOTAL_BLANKS := LINE.INDENT + NR_BLANKS; CASE DESTINATION OF 0: BEGIN FOR INDEX := 1 TO LINE.USED DO WRITE (OUTPUT, LINE.CHARS[INDEX]); WRITELN (OUTPUT); END; 1: BEGIN WRLN_STRING (CURR_OUT_FILE, LINE.CHARS, LINE.USED, NR_TOTAL_BLANKS); END; 2: BEGIN FOR INDEX := 1 TO LINE.USED DO WRITE (OUTPUT, LINE.CHARS[INDEX]); WRITELN (OUTPUT); END; 3: BEGIN WRLN_STRING (REPORT_FILE, LINE.CHARS, LINE.USED, 0); END; END (*CASE*); END (*FT_WRLN*); (*----------- Segment Table routines (ADT) -----------------------*) (*********************************************************************) (* Routine: ST_RD - Segment Table ReaD. *) (* Purpose: Read a line from the SEGMENT_TABLE. *) (* Interface: LINE - The line which is read. *) (* INDEX - The position of the line in SEGMENT_TABLE. *) (* ST vars: SEGMENT_TABLE. *) (*********************************************************************) PROCEDURE ST_RD (VAR LINE: LINE_DES_; INDEX: ST_INDEX_); BEGIN LINE := SEGMENT_TABLE.LINES[INDEX]; END (*ST_READ*); (*********************************************************************) (* Routine: ST_WR - Segment Table WRite. *) (* Purpose: Write a line to the SEGMENT_TABLE. *) (* Interface: LINE - The line which is written *) (* INDEX- The position of the LINE. *) (* ST var: SEGMENT_TABLE. *) (*********************************************************************) PROCEDURE ST_WR (LINE: LINE_DES_; INDEX: ST_INDEX_); BEGIN SEGMENT_TABLE.LINES[INDEX] := LINE; END (*ST_WR*); (*********************************************************************) (* Routine: ST_ABS_SEG - Segment Table ABSolute SEGment *) (* Purpose: To return the absolute line number of the first *) (* line of the segment. *) (* Interface: SEGMENT - Given segment *) (* Function result - The absolute line number of the *) (* first line of SEGMENT. *) (* ST vars: SEGMENT_TABLE. *) (*********************************************************************) FUNCTION ST_ABS_SEG; VAR LINE: LINE_DES_; BEGIN IF SEGMENT.FIRST > 0 THEN BEGIN ST_RD (LINE, SEGMENT.FIRST); ST_ABS_SEG := FT_ABS_LINE_NUMBER (LINE); END (*IF*) END (*ST_ABS_SEG*); (*********************************************************************) (* Routine: ST_GET_FILE_SPEC *) (* Purpose: To return the file specification of the source file *) (* of the segment. *) (* Interface: SEGMENT - Given segment. *) (* FILE_SPEC - The file specification. *) (* ST vars: SEGMENT_TABLE. *) (*********************************************************************) PROCEDURE ST_GET_FILE_SPEC; VAR LINE: LINE_DES_; BEGIN ST_RD (LINE, SEGMENT.FIRST); FT_GET_FILE_SPEC (LINE, FILE_SPEC); END (*ST_GET_FILE_SPEC*); (*********************************************************************) (* Routine: ST_GET_INDENT *) (* Purpose: Return the indentation of segment. *) (* Interface: SEG - Segment to be investigated. *) (* RETURNS - Indent value or error-code. *) (*********************************************************************) FUNCTION ST_GET_INDENT; VAR LINE: LINE_DES_; BEGIN ST_RD (LINE, SEG.FIRST); ST_GET_INDENT := FT_GET_INDENT (LINE); END (*ST_GET_INDENT*); (*********************************************************************) (* Routine: ST_GET_LINE *) (* Purpose: Retrieves next line from the currently read segment. *) (* Interface: LINE - Returned line. *) (* ST vars: SEGMENT_TABLE, LAST_READ_SEG. *) (*********************************************************************) PROCEDURE ST_GET_LINE; VAR INDEX: ST_INDEX_; BEGIN WITH LAST_READ_SEG DO BEGIN IF ST_IS_EMPTY_SEG (LAST_SEG) THEN BEGIN (* ST_GET_LINE has not properly been prepared for reading.*) WRITELN (OUTPUT, 'ST-GET-LN: ', 'System Failure... Call maintenance.'); CLIP_STOP; END ELSE BEGIN INDEX := LAST_LINE + 1; IF INDEX > LAST_SEG.LAST THEN BEGIN (* Segment exhausted. Return LINE with ID value 0. *) LINE.ID := 0; END ELSE BEGIN (* Retrieve line at position INDEX from the ST and *) (* update LAST_READ_SEG. *) ST_RD (LINE, INDEX); LAST_LINE := INDEX; END (*IF*); END (*IF*); END (*WITH*); END (*ST_GET_LINE*); (*********************************************************************) (* Routine: ST_GET_OPTION_LINE *) (* Purpose: To retrieve the first line from a segment which *) (* holds an option marker. *) (* Interface: SEG - The segment *) (* LINE - The first line holding an option marker *) (* ST vars: SEGMENT_TABLE, LAST_READ_SEG. *) (*********************************************************************) PROCEDURE ST_GET_OPTION_LINE; VAR INDEX: ST_INDEX_; POSITION: INTEGER; AUX_LINE: LINE_DES_; BEGIN INDEX := SEG.FIRST; POSITION := 0; IF INDEX > 0 THEN BEGIN WHILE (POSITION =0) AND (INDEX <= SEG.LAST) DO BEGIN ST_RD (AUX_LINE, INDEX); POSITION := FT_GET_POS_OPTION_MARKER (AUX_LINE); IF POSITION =0 THEN INDEX := INDEX + 1; END (*WHILE*); IF POSITION =0 THEN LINE.ID := 0 ELSE LINE := AUX_LINE; WITH LAST_READ_SEG DO BEGIN LAST_SEG := SEG; LAST_LINE := INDEX; END (*WITH*); END ELSE BEGIN LAST_READ_SEG.LAST_SEG.FIRST := 0; LAST_READ_SEG.LAST_SEG.LAST := 0; LAST_READ_SEG.LAST_LINE := 0; LINE.ID := 0; END (*IF*); END (*ST_GET_OPTION_LINE*); (*********************************************************************) (* Routine: ST_GET_SEG *) (* Purpose: Retrieve the first line of a given segment from ST. *) (* Interface: LINE - Returned line. *) (* SEG - Segment to read from. *) (* ST vars: SEGMENT_TABLE, LAST_READ_SEG. *) (*********************************************************************) PROCEDURE ST_GET_SEG; BEGIN IF ST_IS_EMPTY_SEG (SEG) THEN BEGIN (* Return virtual line and reset LAST_READ_SEG. *) LINE.ID := 0; ST_INIT_SEG (LAST_READ_SEG.LAST_SEG); LAST_READ_SEG.LAST_LINE := 0; END ELSE BEGIN ST_RD (LINE, SEG.FIRST); WITH LAST_READ_SEG DO BEGIN LAST_SEG := SEG; LAST_LINE := SEG.FIRST; END (*WITH*); END (*IF*); END (*ST_GET_SEG*); (*********************************************************************) (* Routine: ST_GET_SEG_RANGE - Segment Table SEGMENT RANGE *) (* Purpose: To return the first and last relative line number of *) (* a segment. *) (* Interface: SEGMENT - Given segment. *) (* FIRST - The line number of the first segment line. *) (* LAST - The line number of the last segment line. *) (* ST vars: SEGMENT_TABLE. *) (*********************************************************************) PROCEDURE ST_GET_SEG_RANGE; VAR LINE: LINE_DES_; BEGIN FIRST := 0; LAST := 0; IF SEGMENT.FIRST > 0 THEN BEGIN ST_RD (LINE, SEGMENT.FIRST); FIRST := FT_GET_LINE_NUMBER (LINE); ST_RD (LINE, SEGMENT.LAST); LAST := FT_GET_LINE_NUMBER (LINE); END (*IF*); END (*ST_GET_SEG_RANGE*); (*********************************************************************) (* Routine: ST_INIT *) (* Purpose: General initialization of the segment table. To be *) (* invoked only once at the beginning of a run. *) (* ST vars: SEGMENT_TABLE, LAST_READ_SEG. *) (*********************************************************************) PROCEDURE ST_INIT; BEGIN SEGMENT_TABLE.USED := 0; ST_INIT_SEG (LAST_READ_SEG.LAST_SEG); LAST_READ_SEG.LAST_LINE := 0; END (*ST_INIT*); (*********************************************************************) (* Routine: ST_INIT_SEG *) (* Purpose: To establish a new and empty segment. *) (* Interface: SEG - the segment to initialize. *) (*********************************************************************) PROCEDURE ST_INIT_SEG; BEGIN SEG.FIRST := 0; SEG.LAST := -1; END (*ST_INIT_SEG*); (*********************************************************************) (* Routine: ST_IS_EMPTY_SEG *) (* Purpose: To examine if a segment is empty or not. *) (* Interface: SEG - Segment to be examined. *) (*********************************************************************) FUNCTION ST_IS_EMPTY_SEG; BEGIN ST_IS_EMPTY_SEG := (ST_NUMBER_OF_LINES (SEG) <= 0); END (*ST_IS_EMPTY_SEG*); (*********************************************************************) (* Routine: ST_NUMBER_OF_LINES *) (* Purpose: To calculate the number of lines in a segment. *) (* Interface: SEG - Segment to be investigated. *) (* RETURNS - Number of lines contained by segment. *) (*********************************************************************) FUNCTION ST_NUMBER_OF_LINES; BEGIN WITH SEG DO BEGIN IF (FIRST >= 0) AND (LAST >= FIRST -1) THEN BEGIN ST_NUMBER_OF_LINES := LAST - FIRST + 1; END ELSE BEGIN WRITELN (OUTPUT, 'ST-NUMBER-OF-LINES: ', 'System Failure... Call maintenance.'); CLIP_STOP; END (*IF*); END (*WITH*); END (*ST_NUMBER_OF_LINES*); (*********************************************************************) (* Routine: ST_PUT_LINE *) (* Purpose: Add a source line to the last segment in the table. *) (* Interface: LINE - Source line to write. *) (* SEG - Segment to write to. *) (* ST vars: SEGMENT_TABLE. *) (*********************************************************************) PROCEDURE ST_PUT_LINE; BEGIN IF SEGMENT_TABLE.USED < ST_SIZE THEN BEGIN WITH SEGMENT_TABLE DO BEGIN (* Abort if the ST has become internally inconsistent. *) (* Othewise add line to the table. *) IF SEG.LAST <> USED THEN BEGIN WRITELN (OUTPUT, 'ST-PUT-LN: ', 'System Failure... Call maintenance.'); CLIP_STOP; END ELSE BEGIN USED := USED + 1; ST_WR (LINE, USED); SEG.LAST := USED; END (*IF*) END (*WITH*); END ELSE BEGIN (* Segment Table to small for this application. *) WRITELN (OUTPUT, 'ST-PUT-LN: ', 'Parameter Failure... Call maintenance.'); CLIP_STOP; END (*IF*); END (*ST_PUT_LINE*); (*********************************************************************) (* Routine: ST_PUT_SEG *) (* Purpose: Start a new segment in ST by writing its first line. *) (* Interface: LINE - The line to be written. *) (* SEG - The returned segment. *) (* ST vars: SEGMENT_TABLE, LAST_READ_SEG. *) (*********************************************************************) PROCEDURE ST_PUT_SEG; BEGIN IF SEGMENT_TABLE.USED < ST_SIZE THEN BEGIN WITH SEGMENT_TABLE DO BEGIN USED := USED + 1; ST_WR (LINE, USED); SEG.FIRST := USED; SEG.LAST := USED; END (*WITH*); END ELSE BEGIN WRITELN (OUTPUT, 'ST-PUT-SEG: ', 'Parameter Failure... Call maintenance.'); CLIP_STOP; END (*IF*); END (*ST_PUT_SEG*); (*********************************************************************) (* Routine: ST_FINIT - FINIsh Segment Table *) (* Purpose: Remove the segment-file from the directory. *) (* Interface: - *) (* ST vars: SEGMENT_TABLE. *) (*********************************************************************) PROCEDURE ST_FINIT; BEGIN END (*ST_REMOVE*); (*********************************************************************) (* Routine: ST_SEG_WIDTH - Segment Table SEGment USED. *) (* Purpose: Return the horizontal length of a segment. *) (* Interface: SEGMENT - Given segment. *) (* RETURNS - Length of the given segment. *) (* ST vars: SEGMENT_TABLE. *) (*********************************************************************) FUNCTION ST_SEG_WIDTH; VAR LINE: LINE_DES_; BEGIN ST_RD (LINE, SEG.FIRST); ST_SEG_WIDTH := FT_GET_LINE_LENGTH (LINE); END; (*********************************************************************) (* Routine: ST_WRITE_SEG *) (* Purpose: To write a segment to an output file. *) (* Interface: SEG - Segment to be written. *) (* BLANKS - Leading blanks for every line of the *) (* segment. *) (* DESTINATION - Indicates the destination of the *) (* writing action. *) (* REPORT_FILE - Report file for output. *) (*********************************************************************) PROCEDURE ST_WRITE_SEG; VAR K: ST_INDEX_; LINE: LINE_DES_; BEGIN IF SEG.FIRST >0 THEN FOR K := SEG.FIRST TO SEG.LAST DO BEGIN ST_RD (LINE, K); FT_WRLN (LINE, BLANKS, DESTINATION); END (*FOR*); END (*ST_WRITE_SEG*); (*----------- String Pool routines (ADT) -------------------------*) (*********************************************************************) (* Routine: SP_ADD_CHAR *) (* Purpose: Add character to currently written string. *) (* Interface: CH - Character to be added. *) (* STR - String to add character to. *) (*********************************************************************) PROCEDURE SP_ADD_CHAR; BEGIN WITH STRING_POOL^ DO IF USED < SP_SIZE THEN BEGIN (* SP has enough space left to accept another character. *) USED := USED + 1; CHARS[USED] := CH; IF STR.FIRST =0 THEN BEGIN (* First character of a new string. *) STR.FIRST := USED; STR.LAST := USED; END ELSE BEGIN (* The string already exists. Abort if this string is *) (* not physically the last one of the SP. *) IF STR.LAST <> USED - 1 THEN BEGIN WRITELN (OUTPUT, 'SP-ADD-CHAR: ', 'System Failure... Call maintenance.'); CLIP_STOP; END (*IF*); STR.LAST := USED; END (*IF*); END ELSE BEGIN WRITELN (OUTPUT, 'SP-ADD-CHAR: ', 'Parameter Failure... Call maintenance.'); CLIP_STOP; END (*IF.WITH*); END (*SP_ADD_CHAR*); (*********************************************************************) (* Routine: SP_CONC_STR *) (* Purpose: Concatenation of neighbouring strings. *) (* Interface: MASTER - Recieving string. *) (* SLAVE - Concatented string *) (*********************************************************************) PROCEDURE SP_CONC_STR; BEGIN IF MASTER.FIRST =0 THEN (* An empty MASTER becomes a SLAVE... *) MASTER := SLAVE ELSE IF SLAVE.FIRST =0 THEN (* but an empty SLAVE does not bother its MASTER. *) (* DO NOTHING... *) ELSE IF MASTER.FIRST <>0 THEN BEGIN (* Concatenate only if SLAVE follows MASTER immediately. *) IF MASTER.LAST + 1 = SLAVE.FIRST THEN MASTER.LAST := SLAVE.LAST ELSE BEGIN WRITELN (OUTPUT, 'SP-CONC-STR: ', 'System Failure... Call maintenance.'); CLIP_STOP; END (*IF*); END (*IF*); END (*SP_CONC_STR*); (*********************************************************************) (* Routine: SP_EQ *) (* Purpose: To decide if two strings are equal. *) (* Interface: STR1: First operand. *) (* STR2: Second operand. *) (* RETURNS: TRUE if both operands are equal. *) (* SP vars: STRING_POOL. *) (*********************************************************************) FUNCTION SP_EQ; VAR CONTINUE: BOOLEAN; INDEX: INTEGER; STR_L: INTEGER; BEGIN STR_L := SP_LENGTH_STR (STR1); IF STR_L <> SP_LENGTH_STR (STR2) THEN SP_EQ := FALSE ELSE BEGIN INDEX := 1; CONTINUE := TRUE; SP_EQ := TRUE; WHILE (CONTINUE) AND (INDEX <= STR_L) DO BEGIN IF SP_GET_CHAR (INDEX, STR1) <> SP_GET_CHAR (INDEX, STR2) THEN BEGIN CONTINUE := FALSE; SP_EQ := FALSE; END (*IF*); INDEX := INDEX + 1; END (*WHILE*); END (*IF*); END (*SP_EQ*); (*********************************************************************) (* Routine: SP_EXTR_STR *) (* Purpose: To extract a sequence of characters out of the SP *) (* and to store these characters in a packed array. *) (* Interface: STR - Descriptor of the wanted string. *) (* STR132 - The extracted characters. *) (*********************************************************************) PROCEDURE SP_EXTR_STR; VAR I: INTEGER; K: SP_INDEX_; BEGIN IF STR.FIRST= 0 THEN BEGIN STR132.LENGTH := 0; STR132.BODY := EMPTY_STRING_FIXED; END ELSE IF STR.LAST <= STRING_POOL^.USED THEN BEGIN STR132.BODY := EMPTY_STRING_FIXED; I := 0; FOR K := STR.FIRST TO STR.LAST DO BEGIN I := I + 1; STR132.BODY[I] := STRING_POOL^.CHARS[K]; END; STR132.LENGTH := I; END ELSE BEGIN WRITELN (OUTPUT, 'SP_EXTR_STR: ', 'System Failure... Call maintenance.'); CLIP_STOP; END (*IF.IF*); END; (*********************************************************************) (* Routine: SP_GET_CHAR *) (* Purpose: Get character from given position of a string. *) (* Interface: INDEX - Index of the wanted character. *) (* STR - String to be searched. *) (* RETURNS - Wanted character. *) (* SP vars: STRING_POOL. *) (* MOD1: EWvA (18/12/91) ivm probleem met SCAN_LINE (7). *) (*********************************************************************) FUNCTION SP_GET_CHAR; BEGIN WITH STR DO BEGIN (* Check if value of INDEX is within correct range. *) IF ((LAST - FIRST +1) < INDEX) OR (INDEX <= 0) THEN BEGIN (* MOD1: WRITELN (OUTPUT, 'SP-GET_CHAR: ', *) (* MOD1: 'System Failure... Call maintenance.'); *) (* MOD1: CLIP_STOP; *) SP_GET_CHAR := CHR(0); (* MOD1: *) END ELSE (* INDEX and STR are sound. Proceed to retrieve *) (* character. *) SP_GET_CHAR := STRING_POOL^.CHARS [FIRST + INDEX -1]; END (*IF*) END (*SP_GET_CHAR*); (*********************************************************************) (* Routine: SP_INIT *) (* Purpose: General initialization of the String Pool. It is *) (* only activated once at the start of an CLIP-run. *) (*********************************************************************) PROCEDURE SP_INIT; BEGIN NEW (STRING_POOL); STRING_POOL^.USED := 0; END (*SP_INIT*); (*********************************************************************) (* Routine: SP_INIT_STR *) (* Purpose: Initialize a string *) (* Interface: STR - the string to be initialized. *) (*********************************************************************) PROCEDURE SP_INIT_STR; BEGIN STR.FIRST := 0; STR.LAST := -1; END (*SP_INIT_STR*); (*********************************************************************) (* Routine: SP_IS_EMPTY_STR *) (* Purpose: The function examines if a string is empty or not. *) (* Interface: STR - string to be examined. *) (* RETURNS - TRUE if string is empty. *) (*********************************************************************) FUNCTION SP_IS_EMPTY_STR; BEGIN SP_IS_EMPTY_STR := (SP_LENGTH_STR(STR) = 0); END (*SP_IS_EMPTY_STR*); (*********************************************************************) (* Routine: SP_LENGTH_STR *) (* Purpose: To calculate the length of a string. *) (* Interface: STR: Given string. *) (* RESULT: Length of STRING. *) (*********************************************************************) FUNCTION SP_LENGTH_STR; BEGIN SP_LENGTH_STR := STR.LAST - STR.FIRST + 1; END (*SP_LENGTH_STR*); (*********************************************************************) (* Routine: SP_ADD_BUFFER *) (* Purpose: Add the buffer to a string. *) (* Interface: STR - String to which the buffer is added. *) (* SP vars: BUFFER *) (*********************************************************************) PROCEDURE SP_ADD_BUFFER; VAR I : INTEGER; BEGIN SP_INIT_STR (STR); FOR I := 1 TO BUFFER.LENGTH DO SP_ADD_CHAR (BUFFER.BODY[I], STR); END (*SP_ADD_BUFFER*); (*********************************************************************) (* Routine: SP_ADD_BUFFER_CHAR *) (* Purpose: Add a character to the buffer. *) (* Interface: CH - Character to be added. *) (* SP vars: BUFFER *) (*********************************************************************) PROCEDURE SP_ADD_BUFFER_CHAR; BEGIN WITH BUFFER DO IF LENGTH < 132 THEN BEGIN LENGTH := LENGTH + 1; BODY[LENGTH] := CH; END ELSE BEGIN WRITELN (OUTPUT,'SP_ADD_BUFFER_CHAR system failure...', 'Call maintenance'); CLIP_STOP; END (*IF*); END (*SP_ADD_BUFFER_CHAR*); (*********************************************************************) (* Routine: SP_GET_BUFFER_CHAR *) (* Purpose: Get a character from the buffer. *) (* Interface: INDEX - Index of the wanted character. *) (* SP_GET_BUFFER_CHAR - Character to get. *) (* SP vars: BUFFER *) (*********************************************************************) FUNCTION SP_GET_BUFFER_CHAR; BEGIN IF INDEX IN [1..BUFFER.LENGTH] THEN SP_GET_BUFFER_CHAR := BUFFER.BODY[INDEX] ELSE SP_GET_BUFFER_CHAR := CHR(0); END (*SP_GET_BUFFER_CHAR*); (*********************************************************************) (* Routine: SP_INIT_BUFFER *) (* Purpose: Initialize the buffer by making it empty. *) (* SP vars: BUFFER *) (*********************************************************************) PROCEDURE SP_INIT_BUFFER; BEGIN BUFFER.LENGTH := 0; END (*SP_INIT_BUFFER*); (*----------- DIAGNOSTic routines (ADT) --------------------------*) (*********************************************************************) (* Routine: DIAGNOST_INIT - INITialize the variables of DIAGNOST. *) (* Purpose: Initialize the global variables of procdure DIAG. *) (* Interface: - *) (* DIAGNOST vars: DIAG_TBL, NO_MESSAGES, NR_MSG. *) (*********************************************************************) PROCEDURE DIAGNOST_INIT; VAR K: INTEGER; TBL_FILE: TEXT; ERROR_CODE: INTEGER; DUMMY_ERROR: INTEGER; DUMMY_FILE_OK : BOOLEAN; DUMMY_ERROR_MSG : ERROR_MSG_; AUX_STRING_8: PACKED ARRAY[1..8] OF CHAR; TBL_FILE_NAME: FILE_SPEC_; MESS_CNT: INTEGER; CH : CHAR; BEGIN (******* DIAGNOST_INIT body *******) NO_MESSAGES := FALSE; NR_MSG := 0; FOR K := 1 TO MAX_NR_MESS DO DIAG_TBL[K].MESS_LOC := ' '; (* Clear the variable which is to hold the specification of the *) (* error message file. *) TBL_FILE_NAME.BODY := EMPTY_STRING_FIXED; TBL_FILE_NAME.LENGTH := 0; (******* DIAGNOST_INIT Add environment (TP) (#Opt) *******) (* Write name of message file to TBL_FLE_NAME. The length must *) (* be exactly 8 characters. *) AUX_STRING_8 := 'CLIP_MSG'; WITH TBL_FILE_NAME DO BEGIN FOR K := 1 TO 8 DO BODY[LENGTH+K] := AUX_STRING_8[K]; LENGTH := LENGTH + 8; END (* WITH *); (******* DIAGNOST_INIT Add extension (TP) (#Opt) *******) EXT_FILE_PREP (TBL_FILE, TBL_FILE_NAME, INSP_MODE, DUMMY_FILE_OK, ERROR_CODE, DUMMY_ERROR_MSG); IF ERROR_CODE <> 0 THEN BEGIN NO_MESSAGES := TRUE; WRITELN ('Error message file (logical name: CLIP_MSG) not found.'); WRITELN ('CLiP will continue without diagnostics'); WRITELN; END ELSE BEGIN NO_MESSAGES := FALSE; (********************* DIAGNOST_INIT (1) ***********************) (** Initialize DIAG_TBL by reading the TBL_FILE. **) MESS_CNT := 1; WHILE NOT EOF (TBL_FILE) DO BEGIN WITH DIAG_TBL[MESS_CNT] DO BEGIN (********************* DIAGNOST_INIT (1.1) *****************) (** Initialize DIAG_TBL[MESS_CNT].MESS_LOC. **) READ (TBL_FILE, CH); READ (TBL_FILE, CH); READ (TBL_FILE, CH); K := 1; WHILE CH <> ':' DO BEGIN MESS_LOC[K] := CH; READ (TBL_FILE, CH); K := K + 1; END (*WHILE*); (***************** End of DIAGNOST_INIT (1.1) **************) (********************* DIAGNOST_INIT (1.2) *****************) (** Initialize DIAG_TBL[MESS_CNT].MESSAGE. **) MESSAGE := EMPTY_STRING_FIXED; READ (TBL_FILE, CH); MESS_L := 1; WHILE CH <> '%' DO BEGIN IF EOLN (TBL_FILE) THEN READLN (TBL_FILE); READ (TBL_FILE, CH); IF CH <> '%' THEN BEGIN MESSAGE[MESS_L] := CH; MESS_L := MESS_L + 1; END (*IF*); END (*WHILE*); (***************** End of DIAGNOST_INIT (1.2) **************) READLN (TBL_FILE); END (*WITH*); MESS_CNT := MESS_CNT + 1; END (*WHILE*); (***************** End of DIAGNOST_INIT (1) ********************) (* Close the TBL_FILE and ignore any errors that may occur. *) EXT_FILE_CLOSE (TBL_FILE, DUMMY_ERROR); END (*IF*); (***************** End of DIAGNOST_INIT body *******************) END (*DIAGNOST_INIT*); (*********************************************************************) (* Routine: DIAG - Issue a DIAGnostic message. *) (* Purpose: Handling of all diagnostics by a message to the *) (* terminal. *) (* Interface: DIAG_TBL - Internal table with messages. *) (* MSG_TBL - Internal table with detected errors. *) (* NR_MSG - Counting error messages in MSG_TBL. *) (* SEV - Severity of the diagnostic. *) (* LOC - Program location which detected the *) (* problem. *) (* SOURCE_LINE - Source line causing the problem. *) (* SEGMENT - Segment causing the problem. *) (* STRING132 - Keyword(s) indicating the specific *) (* diagnostic. *) (*********************************************************************) PROCEDURE DIAG (SEV: SEV_CODE_; LOC: LOC_SPEC_; SOURCE_LINE: LINE_DES_; SEGMENT: SEGMENT_DES_; STRING132: STRING132_); VAR K : INTEGER; BEGIN (************************* DIAG (body) *****************************) IF NOT NO_MESSAGES THEN BEGIN IF NR_MSG < MAX_ERROR THEN BEGIN NR_MSG := NR_MSG + 1; (********************* DIAG (1) ************************) (** Store the actual parameters passed to DIAG in **) (** MSG_TBL[NR_MSG]. **) MSG_TBL[NR_MSG].SEV := SEV; MSG_TBL[NR_MSG].LOC := LOC; MSG_TBL[NR_MSG].STRING132 := STRING132; MSG_TBL[NR_MSG].SOURCE_LINE := SOURCE_LINE; MSG_TBL[NR_MSG].SEGMENT := SEGMENT; IF NOT ST_IS_EMPTY_SEG (SEGMENT) THEN MSG_TBL[NR_MSG].LINE_ABS := ST_ABS_SEG (SEGMENT) ELSE IF FT_GET_LINE_LENGTH (SOURCE_LINE) > 0 THEN MSG_TBL[NR_MSG].LINE_ABS := FT_ABS_LINE_NUMBER (SOURCE_LINE) ELSE BEGIN WRITELN ('Internal error DIAG (1)... Call maintenance'); WRITELN ('Troubles caused by an error detected by: '); FOR K := 1 TO LOC_SPEC_L DO WRITE (LOC[K]); NR_MSG := NR_MSG - 1; END (*IF.IF*); (******************* End of DIAG (1) *******************) END ELSE IF NR_MSG = MAX_ERROR THEN BEGIN WRITELN (OUTPUT, 'CLIP detected more then ', NR_MSG,' errors'); WRITELN (OUTPUT, 'Only first ', NR_MSG, ' diagnostic messages will be generated'); NR_MSG := NR_MSG + 1; END ELSE IF NR_MSG > MAX_ERROR THEN BEGIN (* Nothing remains to be done here. *) END (*IF.IF.IF*); END (*IF*); (********************* End of DIAG (body) **********************) END (*DIAG*); (*********************************************************************) (* Routine: DIAGNOST_EXIT - Exit the diagnostic table. *) (* Purpose: Generate the cumulated list of diagnostics to the *) (* termnal and, if specified, to a report file. *) (* Interface: DIAGNOST module variables *) (* REPORT_FILE - From CLIP_CDL *) (* REPORT_OK - From CLIP_CDL *) (* RUN_INFO variables *) (*********************************************************************) PROCEDURE DIAGNOST_EXIT; VAR I, K: INTEGER; MESS_INDEX: INTEGER; FILE_SPEC: FILE_SPEC_; FIRST, LAST: INTEGER; TMP_STRING_8: PACKED ARRAY [1..8] OF CHAR; J: INTEGER; BEGIN (********************* DIAGNOST_EXIT (body) ************************) IF NOT NO_MESSAGES THEN BEGIN IF NR_MSG > MAX_ERROR THEN NR_MSG := MAX_ERROR; (***************** DIAGNOST_EXIT (1) ***************************) (** Sort MSG_TBL by absolute line numbers. **) FOR K := NR_MSG DOWNTO 1 DO BEGIN FOR I := 1 TO K-1 DO BEGIN IF MSG_TBL[I].LINE_ABS > MSG_TBL[I+1].LINE_ABS THEN BEGIN MSG_TBL[MAX_ERROR+1] := MSG_TBL[I]; MSG_TBL[I] := MSG_TBL[I+1]; MSG_TBL[I+1] := MSG_TBL[MAX_ERROR+1]; END (*IF*); END (*FOR*); END (*FOR*); (***************** End of DIAGNOST_EXIT (1) ********************) (* Write the opening lines of the report(s). *) IF NR_MSG > 0 THEN BEGIN WRITELN (OUTPUT, '============================ ', 'Diagnostics ==============================='); IF REPORT_OK THEN WRITELN (REPORT_FILE, '============================ ', 'Diagnostics ==============================='); END (* IF *); (***************** DIAGNOST_EXIT (2) ***************************) (** Generate messages from MSG_TBL and DIAG_TBL to OUTPUT and **) (** also to REPORT_FILE if REPORT_OK is raised. Write a **) (** diagnostic in case of trouble, but do not abort. **) FOR K := 1 TO NR_MSG DO BEGIN MESS_INDEX := 0; (***************** DIAGNOST_EXIT (2.1) *************************) (** Search DIAG_TBL for MSG_TBL[K].LOC. Store the index in **) (** MESS_INDEX. **) FOR I := 1 TO MAX_NR_MESS DO BEGIN IF DIAG_TBL[I].MESS_LOC = MSG_TBL[K].LOC THEN MESS_INDEX := I; END (*FOR*); (**************** End of DIAGNOST_EXIT (2.1) *******************) IF MESS_INDEX = 0 THEN BEGIN WRITELN (OUTPUT, 'system error DIAGNOST_EXIT ..... call maintenance'); WRITELN ('Not able to generate diagnostic message.'); WRITE ('DIAGNOST_EXIT was called by : '); FOR I := 1 TO LOC_SPEC_L DO WRITE (MSG_TBL[K].LOC[I]); IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE, 'system error DIAGNOST_EXIT ..... call maintenance'); WRITELN (REPORT_FILE, 'Not able to generate diagnostic message.'); WRITE (REPORT_FILE, 'DIAGNOST_EXIT was called by : '); FOR I := 1 TO LOC_SPEC_L DO WRITE (REPORT_FILE, MSG_TBL[K].LOC[I]); END (* IF *); END ELSE BEGIN (***************** DIAGNOST_EXIT (2.2) *********************) (** Generate diagnostic using information stored in MSG_- **) (** TBL[K] and DIAG_TBL[MESS_INDEX]. **) WITH MSG_TBL[K] DO BEGIN CASE SEV OF WARN: TMP_STRING_8 := 'Warning '; ERR: TMP_STRING_8 := 'Error '; FAIL: TMP_STRING_8 := 'Failure '; DUMP: CLIP_STOP; END (*CASE*); WRITE (OUTPUT, TMP_STRING_8); IF REPORT_OK THEN WRITE (REPORT_FILE, TMP_STRING_8); IF NOT ST_IS_EMPTY_SEG (SEGMENT) THEN BEGIN ST_GET_SEG_RANGE (SEGMENT, FIRST, LAST); ST_GET_FILE_SPEC (SEGMENT, FILE_SPEC); WRITE (' between the lines ', FIRST:2, ' and ', LAST:2, ' of file: ' ); FOR I := 1 TO FILE_SPEC.LENGTH DO WRITE (FILE_SPEC.BODY[I]); WRITELN; WRITELN ('Source lines:'); WRITELN; (* Write segement to OUTPUT. *) ST_WRITE_SEG (SEGMENT, 0, 0); WRITELN; IF REPORT_OK THEN BEGIN WRITE (REPORT_FILE, ' between the lines ', FIRST:2, ' and ', LAST:2, ' of file: ' ); FOR I := 1 TO FILE_SPEC.LENGTH DO WRITE (REPORT_FILE, FILE_SPEC.BODY[I]); WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, 'Source lines:'); WRITELN (REPORT_FILE); (* Write segement to file variable REPORT_FILE of FT *) (* (see also DIAGNOST_EXIT (2)). *) ST_WRITE_SEG (SEGMENT, 0, 3); WRITELN (REPORT_FILE); END (* IF *); END ELSE IF FT_GET_LINE_LENGTH (SOURCE_LINE) > 0 THEN BEGIN FT_GET_FILE_SPEC (SOURCE_LINE, FILE_SPEC); WRITE ('in line ', FT_GET_LINE_NUMBER (SOURCE_LINE):4); WRITE (' of file :'); FOR I := 1 TO FILE_SPEC.LENGTH DO WRITE (FILE_SPEC.BODY[I]); WRITELN; (* Write line to OUTPUT. *) FT_WRLN (SOURCE_LINE, 0, 0); IF REPORT_OK THEN BEGIN WRITE (REPORT_FILE, 'in line ', FT_GET_LINE_NUMBER (SOURCE_LINE):4); WRITE (REPORT_FILE, ' of file :'); FOR I := 1 TO FILE_SPEC.LENGTH DO WRITE (REPORT_FILE, FILE_SPEC.BODY[I]); WRITELN (REPORT_FILE); (* Write LINE to file variable REPORT_FILE of FT *) (* (see also DIAGNOST_EXIT (2)). *) FT_WRLN (SOURCE_LINE, 0, 3); END (* IF *); END ELSE BEGIN WRITELN ('Internal error DIAG... Call maintenance'); IF REPORT_OK THEN WRITELN (REPORT_FILE, 'Internal error DIAG... Call maintenance'); END (*IF.IF*); WITH DIAG_TBL[MESS_INDEX] DO BEGIN FOR I := 1 TO MESS_L DO BEGIN IF MESSAGE[I] <> '@' THEN BEGIN WRITE (MESSAGE[I]); IF REPORT_OK THEN WRITE (REPORT_FILE, MESSAGE[I]); END ELSE BEGIN FOR J := 1 TO STRING132.LENGTH DO BEGIN WRITE (STRING132.BODY[J]); IF REPORT_OK THEN WRITE (REPORT_FILE, STRING132.BODY[J]); END (*FOR*); END (*IF*); END (*FOR*); END(*WITH*); END (*WITH*); (**************** End of DIAGNOST_EXIT (2.2) ***************) END (*IF*); WRITELN; WRITELN; WRITELN ('------------------------------------', '------------------------------------'); IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE); WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, '------------------------------------', '------------------------------------'); END (* IF *); END (*FOR*); (**************** End of DIAGNOST_EXIT (2) *********************) (* Write closing remarks of the report(s). Don't forget to close *) (* the REPORT_FILE if it has been used. Ignore closing problems. *) IF NR_MSG > 0 THEN BEGIN WRITE (OUTPUT, 'Diagnostics TOTAL of: ',NR_MSG:1); IF REPORT_OK THEN WRITE (REPORT_FILE, 'Diagnostics TOTAL of: ',NR_MSG:1); (* Print different text to distinguish between a for single *) (* error situation and a multiple error situation. *) IF NR_MSG = 1 THEN BEGIN WRITELN (' error or warning detected.'); IF REPORT_OK THEN WRITELN (REPORT_FILE, ' error or warning detected.'); END ELSE BEGIN WRITELN (' errors or warnings detected.'); IF REPORT_OK THEN WRITELN (REPORT_FILE, ' errors or warnings detected.'); END (* IF *); WRITELN; WRITELN ('============================ End of ', 'diagnostics ========================'); WRITELN; IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, '============================ End of ', 'diagnostics ========================'); WRITELN (REPORT_FILE); END (* IF *); END (*IF*); END (*IF*); (**************** End of DIAGNOST_EXIT (body) **********************) END (*DIAG*); (*----------- Main components of the CLiP system -----------------*) (*********************************************************************) (* Routine: SCN_LINE_INIT - INITialize variables of SCN_LINE. *) (* Purpose: Initialize the global variables of procedure SCAN_LINE.*) (* Interface: - *) (* SCN_LINE vars: ALLOWED *) (*********************************************************************) PROCEDURE SCN_LINE_INIT; BEGIN ALLOWED := ['A'..'Z', 'a'..'z', '0'..'9','.']; END; (*********************************************************************) (* Routine: SCAN_LINE - Scan a source line *) (* Purpose: To examine to what sort of CLIP category a source *) (* line belongs to. *) (* Interface: SOURCE_LINE: The line to be scanned. *) (* LINE_INFO: A record structure that holding all *) (* relevant info of this SOURCE_LINE. *) (* RUN_INFO: General information for this run. *) (*********************************************************************) PROCEDURE SCAN_LINE (VAR LINE_INFO: LINE_INFO_; VAR SOURCE_LINE: LINE_DES_; RUN_INFO: RUN_INFO_); VAR SCAN_LINE_CONTINUE: BOOLEAN; L2_LINE, L3_LINE, L4_LINE: BOOLEAN; LENGTH_LINE: INTEGER; START_INDEX, END_INDEX: INTEGER; SEGMENT: SEGMENT_DES_; STRING132: STRING132_; OPEN_FOUND, CLOSE_FOUND: BOOLEAN; X, Y: INTEGER; CH: CHAR; CLIP_CCL: CHAR; CLIP_CCR: CHAR; BEGIN (******* SCAN_LINE (body) *******) (************************* SCAN_LINE (1) ***************************) (** Initialize the Buffer and SCAN_LINE_CONTINUE. **) SP_INIT_BUFFER; SCAN_LINE_CONTINUE := TRUE; (********************* End of SCAN_LINE (1) ************************) (************************* SCAN_LINE (2) ***************************) (** Examine the length of SOURCE_LINE. Make SCAN_LINE_CONTINUE to **) (** FALSE if this length is shorter then that of CLIP_LPAR and **) (** CLIP_RPAR together and set LINE_INFO.CATEGORY to L5. **) WITH RUN_INFO DO BEGIN LENGTH_LINE := FT_GET_LINE_LENGTH (SOURCE_LINE); IF LENGTH_LINE < CLIP_LPAR.LENGTH+CLIP_RPAR.LENGTH THEN BEGIN LINE_INFO.CATEGORY := L5; SCAN_LINE_CONTINUE := FALSE; END (*IF*); END (*WITH*); (********************* End of SCAN_LINE (2) ************************) IF SCAN_LINE_CONTINUE THEN BEGIN (************************* SCAN_LINE (3) ***********************) (** Examine if SOURCE_LINE starts with an CLIP_LPAR and ends **) (** with an CLIP_RPAR. Set SCAN_LINE_CONTINUE to FALSE if this **) (** is not the case. Generate error message using SOURCE_LINE **) (** if only one of the two strings is detected. **) X := 1; OPEN_FOUND := TRUE; WITH RUN_INFO DO BEGIN WHILE (X <= CLIP_LPAR.LENGTH) AND (SCAN_LINE_CONTINUE) DO BEGIN CH := FT_GET_CHAR (SOURCE_LINE, X); IF CLIP_LPAR.BODY[X] <> CH THEN BEGIN SCAN_LINE_CONTINUE := FALSE; OPEN_FOUND := FALSE; END (*IF*); X := X+1; END (*WHILE*); X := LENGTH_LINE-CLIP_RPAR.LENGTH+1; Y := 1; CLOSE_FOUND := TRUE; WHILE (X <=LENGTH_LINE) DO BEGIN CH := FT_GET_CHAR (SOURCE_LINE, X); IF CLIP_RPAR.BODY[Y] <> CH THEN BEGIN CLOSE_FOUND := FALSE; SCAN_LINE_CONTINUE := FALSE; END (*IF*); X := X+1; Y := Y+1; END (*WHILE*); END (*WITH*); IF NOT SCAN_LINE_CONTINUE THEN BEGIN ST_INIT_SEG (SEGMENT); STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; IF (OPEN_FOUND) AND (NOT CLOSE_FOUND) THEN DIAG (WARN, 'SCAN_LINE (3a) ', SOURCE_LINE, SEGMENT, STRING132) ELSE IF (CLOSE_FOUND) AND (NOT OPEN_FOUND) THEN DIAG (WARN, 'SCAN_LINE (3b) ', SOURCE_LINE, SEGMENT, STRING132); END (*WITH*); (********************* End of SCAN_LINE (3) ********************) IF NOT SCAN_LINE_CONTINUE THEN LINE_INFO.CATEGORY := L5 ELSE BEGIN L3_LINE := FALSE; (********************* SCAN_LINE (4) ***********************) (** Examine the character following CLIP_LPAR and the one **) (** preceeding CLIP_RPAR. Set L3_LINE to TRUE if at least **) (** one of these characters differs from CLIP_CC. Generate **) (** an error message using SOURCE_LINE if only one CLIP_CC **) (** is detected. **) WITH RUN_INFO DO BEGIN X := CLIP_LPAR.LENGTH+1; Y := LENGTH_LINE-CLIP_RPAR.LENGTH; CLIP_CCL := FT_GET_CHAR (SOURCE_LINE, X); CLIP_CCR := FT_GET_CHAR (SOURCE_LINE, Y); IF (CLIP_CCL <> CLIP_CC) AND (CLIP_CCR <> CLIP_CC) THEN BEGIN SCAN_LINE_CONTINUE := FALSE; L3_LINE := TRUE; END ELSE IF (CLIP_CCL<>CLIP_CC) AND (CLIP_CCR=CLIP_CC) THEN BEGIN ST_INIT_SEG (SEGMENT); STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; DIAG (WARN, 'SCAN_LINE (4a) ', SOURCE_LINE, SEGMENT, STRING132); SCAN_LINE_CONTINUE := FALSE; L3_LINE := TRUE; END ELSE IF (CLIP_CCL = CLIP_CC) AND (CLIP_CCR <> CLIP_CC) THEN BEGIN ST_INIT_SEG (SEGMENT); STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; DIAG (WARN, 'SCAN_LINE (4b) ', SOURCE_LINE, SEGMENT, STRING132); SCAN_LINE_CONTINUE := FALSE; L3_LINE := TRUE; END (*IF.IF.IF*); END (*WITH*); (***************** End of SCAN_LINE (4) ********************) IF (L3_LINE) AND (LINE_INFO.OPTIONS) THEN BEGIN (* SOURCE_LINE holds only options which will be *) (* scanned in a later stadium. Nothing remains to *) (* be done here. *) END ELSE BEGIN WITH RUN_INFO DO BEGIN START_INDEX := CLIP_LPAR.LENGTH; END_INDEX := SOURCE_LINE.USED-RUN_INFO.CLIP_RPAR.LENGTH; END (*WITH*); L4_LINE := TRUE; (********************* SCAN_LINE (5) *******************) (** Examine the characters in SOURCE_LINE starting at **) (** START_INDEX until a character not equal to CLIP_CC **) (** or until END_INDEX is reached. If such a character **) (** is detected, set L4_LINE to FALSE and store its **) (** position in START_INDEX. **) WHILE (START_INDEX < END_INDEX) AND (L4_LINE) DO BEGIN CH := FT_GET_CHAR (SOURCE_LINE, START_INDEX); IF CH <> RUN_INFO.CLIP_CC THEN L4_LINE := FALSE ELSE START_INDEX := START_INDEX+1; END (*WHILE*); (***************** End of SCAN_LINE (5) ****************) IF NOT L4_LINE THEN BEGIN IF NOT L3_LINE THEN LINE_INFO.OPTIONS := FALSE; X := START_INDEX; WHILE (X <= END_INDEX) AND (NOT LINE_INFO.OPTIONS) DO BEGIN CH := FT_GET_CHAR (SOURCE_LINE, X); IF (CH IN ALLOWED) OR (CH=RUN_INFO.OPTION_MARKER) THEN BEGIN IF CH=RUN_INFO.OPTION_MARKER THEN BEGIN LINE_INFO.OPTIONS := TRUE; SOURCE_LINE.POS_OPTION_MARKER := X; END ELSE BEGIN (************* SCAN_LINE (6) ***********) (** Add CH to the Buffer String. **) SP_ADD_BUFFER_CHAR (UC (CH)); (********* End of SCAN_LINE (6) ********) END (*IF*); END (*IF*); X := X+1; END (*WHILE*); L2_LINE := TRUE; (***************** SCAN_LINE (7) *******************) (** Check if the first LENGTH (CLIP_END) chars of **) (** the Bufffer String are equal to CLIP_END. If **) (** not, set L2_LINE to FALSE. **) WITH RUN_INFO DO BEGIN X := 1; WHILE (X <= CLIP_END.LENGTH) AND (SCAN_LINE_CONTINUE) DO BEGIN CH := SP_GET_BUFFER_CHAR (X); IF UC (CLIP_END.BODY[X]) <> UC (CH) THEN L2_LINE := FALSE; X := X+1; END (*WHILE*); END (*WITH*); (*************** End of SCAN_LINE (7) **************) END (*IF*); END (*IF*); IF L4_LINE THEN LINE_INFO.CATEGORY := L4 ELSE IF L3_LINE THEN LINE_INFO.CATEGORY := L3 ELSE IF L2_LINE THEN LINE_INFO.CATEGORY := L2 ELSE LINE_INFO.CATEGORY := L1; END (*IF*); END (*IF*); (********************* End of SCAN_LINE (body) *****************) END (*PROCEDURE SCAN_LINE*); (********************************************************************) (* Routine: CONVERT_OPTION *) (* Purpose: Covert an abbreviated option to its full length. *) (* Interface: OPTION: Option to be converted. *) (* ERROR_CODE: 0 - No Problems. *) (* 1 - No Match found. *) (* -1 - More then one match found. *) (********************************************************************) PROCEDURE CONVERT_OPTION (VAR OPTION: OPTION_KEYWORD_; VAR ERROR_CODE: ERROR_CODE_); VAR K, I: INTEGER; LENGTH_OPTION: INTEGER; LOCATED: BOOLEAN; DUMMY: OPTION_KEYWORD_; NR_MATCH: INTEGER; BEGIN DUMMY := EMPTY_OPTION; K := 1; NR_MATCH := 0; WHILE OPTION[K] <> ' ' DO K := K + 1; LENGTH_OPTION := K-1; LOCATED := FALSE; I := 1; ERROR_CODE := 1; (* Assume no match found. *) WHILE (I <= MAX_OPTIONS) DO BEGIN K := 1; LOCATED := TRUE; WHILE (K <= LENGTH_OPTION) AND (LOCATED) DO BEGIN IF UC (OPTION[K]) = UC (OPTION_TABLE[I,K]) THEN LOCATED := TRUE ELSE LOCATED := FALSE; K := K + 1; END (*WHILE*); IF LOCATED THEN BEGIN IF NR_MATCH = 0 THEN BEGIN ERROR_CODE := 0; (* One match has been found. *) DUMMY := OPTION_TABLE[I]; NR_MATCH := NR_MATCH + 1; END ELSE ERROR_CODE := -1; (* More then one match found *) END (*IF*); I := I + 1; END (*WHILE*); IF ERROR_CODE = 0 THEN OPTION := DUMMY; END (*CONVERT_OPTION*); (*********************************************************************) (* Routine: SCN_OPTS_INIT - INITialize the variables of SCN_OPTS. *) (* Purpose: Initialize the global variables of SCAN_OPTIONS. *) (* Interface: - *) (* SCN_OPTS vars: OPT_SPACE, DEFAULT_OPTIONS, OPT_CHARS, *) (* PASCAL_STRING, C_STRING. *) (*********************************************************************) PROCEDURE SCN_OPTS_INIT; BEGIN OPTION_TABLE [ 1] := 'QUICK '; OPTION_TABLE [ 2] := 'MULTIPLE '; OPTION_TABLE [ 3] := 'OPTIONAL '; OPTION_TABLE [ 4] := 'FILE '; OPTION_TABLE [ 5] := 'INDENT '; OPTION_TABLE [ 6] := 'COMMENT '; OPTION_TABLE [ 7] := 'OVERRULE '; OPTION_TABLE [ 8] := 'LEADER '; OPTION_TABLE [ 9] := 'TRAILER '; OPTION_TABLE [10] := 'SEPARATOR '; OPTION_TABLE [11] := 'DEFAULT '; OPTION_TABLE [12] := 'LINENUMBER '; OPT_CHARS := ['A'..'Z', 'a'..'z', '0'..'9', '"']; WITH DEFAULT_OPTIONS DO BEGIN QUICK := FALSE; MULTIPLE := FALSE; OPTIONAL := FALSE; OVERRULE := FALSE; LEADER := FALSE; DEFAULT := FALSE; TRAILER := FALSE; SEPARATOR := FALSE; LINENUMBER := FALSE; SP_INIT_STR (FILE_NAME); SP_INIT_STR (INDENT); SP_INIT_STR (COMMENT); END; PASCAL_STRING := EMPTY_STRING_FIXED; PASCAL_STRING[1] := 'P'; PASCAL_STRING[2] := 'A'; PASCAL_STRING[3] := 'S'; PASCAL_STRING[4] := 'C'; PASCAL_STRING[5] := 'A'; PASCAL_STRING[6] := 'L'; FORTRAN_STRING := EMPTY_STRING_FIXED; FORTRAN_STRING[1] := 'F'; FORTRAN_STRING[2] := 'O'; FORTRAN_STRING[3] := 'R'; FORTRAN_STRING[4] := 'T'; FORTRAN_STRING[5] := 'R'; FORTRAN_STRING[6] := 'A'; FORTRAN_STRING[7] := 'N'; C_STRING := EMPTY_STRING_FIXED; C_STRING[1] := 'C'; END; (*********************************************************************) (* Routine: SCAN_OPTIONS - SCAN OPTIONS *) (* Purpose: To scan and store the options that are specified by *) (* a stub or slot segment. *) (* Interface: SEGMENT_OPTIONS - The structure with options. *) (* SEGMENT - The segment to be scanned. *) (* RUN_INFO - The information for this run. *) (* SEGMENT_TYPE - Type of segment to be scanned. *) (*********************************************************************) PROCEDURE SCAN_OPTIONS (VAR SEGMENT_OPTIONS: OPTIONS_; SEGMENT: SEGMENT_DES_; RUN_INFO: RUN_INFO_; SEGMENT_TYPE: SEGMENT_TYPE_); VAR OPTION_KEYWORD: OPTION_KEYWORD_; LINE: LINE_DES_; SEGMENT_EXHAUSTED: BOOLEAN; INDEX: INTEGER; CH: CHAR; LENGTH_LINE: INTEGER; OK: BOOLEAN; STRING132: STRING132_; I: INTEGER; ERROR_CODE: ERROR_CODE_; DUMMY_LINE: LINE_DES_; AUX_STRING10: PACKED ARRAY[1..10] OF CHAR; BEGIN (******* SCAN_OPTIONS (body) *******) (************************* SCAN_OPTIONS (1) ********************) (** Initialize OPTION_KEYWORD. Make SEGMENT_OPTIONS equal to **) (** DEFAULT_OPTIONS and set SEGMENT_EXHAUSTED to FALSE. **) OPTION_KEYWORD := EMPTY_OPTION; SEGMENT_OPTIONS := DEFAULT_OPTIONS; SEGMENT_EXHAUSTED := FALSE; (********************* End of SCAN_OPTIONS (1) *****************) IF NOT ST_IS_EMPTY_SEG (SEGMENT) THEN BEGIN (********************* SCAN_OPTIONS (2) ********************) (** Retrieve first line from SEGMENT which holds an option **) (** marker and store it in LINE. Set SEGMENT_EXHAUSTED to **) (** TRUE if no such LINE could be found. **) ST_GET_OPTION_LINE (SEGMENT, LINE); IF LINE.ID =0 THEN SEGMENT_EXHAUSTED := TRUE; (***************** End of SCAN_OPTIONS (2) *****************) WHILE NOT SEGMENT_EXHAUSTED DO BEGIN (********************* SCAN_OPTIONS (3) ****************) (** Scan LINE for options with their arguments and put **) (** the result in SEGMENT_OPTIONS. Generate diagnostic **) (** message using SEGMENT in case of trouble. **) INDEX := FT_GET_POS_OPTION_MARKER (LINE); IF INDEX = 0 THEN INDEX := RUN_INFO.CLIP_LPAR.LENGTH + 1; LENGTH_LINE := FT_GET_LINE_LENGTH (LINE) - RUN_INFO.CLIP_RPAR.LENGTH; CH := FT_GET_CHAR (LINE, INDEX); WHILE INDEX < LENGTH_LINE DO BEGIN WHILE (CH <> RUN_INFO.OPTION_MARKER) AND (NOT (CH IN OPT_CHARS)) AND (INDEX < LENGTH_LINE) DO BEGIN INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); IF CH = RUN_INFO.OPTION_MARKER THEN BEGIN (********************* SCAN_OPTIONS (3.1) ******************) (** Start of a new option in LINE. Check by an empty **) (** OPTION_KEYWORD if previous option is "closed" correctly **) (** and issue a diagnostic if not. Read the characters **) (** following OPTION_MARKER until the next OPT_SPACE and **) (** store them in OPTION_KEYWORD. Read a possible argument **) (** and update SEGMENT_OPTIONS. Initialize OPTION_KEYWORD **) (** if all went well. **) IF OPTION_KEYWORD <> EMPTY_OPTION THEN BEGIN (********************* SCAN_OPTIONS (3.1.1) ********************) (** Missing argument of option stored in OPTION_KEYWORD. **) (** Generate a diagnostic using OPTION_KEYWORD and SEGMENT. **) STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; FOR I := 1 TO MAX_OPTION_LENGTH DO BEGIN IF OPTION_KEYWORD[I] <> ' ' THEN BEGIN STRING132.BODY[I] := OPTION_KEYWORD[I]; STRING132.LENGTH := STRING132.LENGTH + 1; END (*IF*); END (*FOR*); DIAG (ERR, 'SCAN_OPTIONS (3.1.1) ', DUMMY_LINE, SEGMENT, STRING132); OPTION_KEYWORD := EMPTY_OPTION; (***************** End of SCAN_OPTIONS (3.1.1) *****************) END (*IF*); OK := FALSE; (********************* SCAN_OPTIONS (3.1.2) ************************) (** Store all characters following this OPTION_MARKER in OPTION_- **) (** KEYWORD until the first character that is not a member of **) (** OPT_CHARS. Try to located the option in OPTION_TABLE and make **) (** OK equal to TRUE if a match is found and store the full option **) (** in OPTION_KEYWORD. In case no match can be found generate a **) (** diagnostic message and jump to the next option marker. **) INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); WHILE NOT (CH IN OPT_CHARS) AND (CH <> RUN_INFO.OPTION_MARKER) AND (INDEX < LENGTH_LINE) DO BEGIN INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); I := 1; WHILE CH IN OPT_CHARS DO BEGIN OPTION_KEYWORD [I] := CH; I := I + 1; INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); CONVERT_OPTION (OPTION_KEYWORD, ERROR_CODE); IF ERROR_CODE <> 0 THEN BEGIN STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; FOR I := 1 TO MAX_OPTION_LENGTH DO BEGIN IF OPTION_KEYWORD[I] <> ' ' THEN BEGIN STRING132.BODY[I] := OPTION_KEYWORD[I]; STRING132.LENGTH := STRING132.LENGTH + 1; END (*IF*); END (*FOR*); IF ERROR_CODE = -1 THEN BEGIN (* More then one match found in table. *) DIAG (ERR, 'SCAN_OPTIONS (3.1.2)a ', DUMMY_LINE, SEGMENT, STRING132); OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF ERROR_CODE = 1 THEN BEGIN (* No match found in the table. *) DIAG (ERR, 'SCAN_OPTIONS (3.1.2)b ', DUMMY_LINE, SEGMENT, STRING132); OPTION_KEYWORD := EMPTY_OPTION; END (*IF.IF*); (* Jump to the next OPTION_MARKER in LINE. *) WHILE (CH <> RUN_INFO.OPTION_MARKER) AND (INDEX '"') AND (INDEX '"') AND (INDEX < LENGTH_LINE) DO BEGIN (* SP_ADD_CHAR (UC (CH), SEGMENT_OPTIONS.FILE_NAME); 14/10/93) *) SP_ADD_CHAR (CH, SEGMENT_OPTIONS.FILE_NAME); INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); IF CH = '"' THEN BEGIN INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END ELSE BEGIN SP_EXTR_STR (SEGMENT_OPTIONS.FILE_NAME, STRING132); DIAG (ERR, 'SCAN_OPTIONS (3.1.3)a ', DUMMY_LINE, SEGMENT, STRING132); SP_INIT_STR (SEGMENT_OPTIONS.FILE_NAME); OPTION_KEYWORD := EMPTY_OPTION; END (*IF*); END ELSE IF (CH IN OPT_CHARS) THEN BEGIN SP_EXTR_STR (SEGMENT_OPTIONS.FILE_NAME, STRING132); DIAG (ERR, 'SCAN_OPTIONS (3.1.3)b ', DUMMY_LINE, SEGMENT, STRING132); SP_INIT_STR (SEGMENT_OPTIONS.FILE_NAME); OPTION_KEYWORD := EMPTY_OPTION; (* Jump to the next option marker. *) WHILE (CH <> RUN_INFO.OPTION_MARKER) AND (INDEX RUN_INFO.OPTION_MARKER) DO BEGIN INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); WHILE (CH IN OPT_CHARS) AND (INDEX < LENGTH_LINE) DO BEGIN SP_ADD_CHAR (UC (CH), SEGMENT_OPTIONS.INDENT); INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); IF NOT SP_IS_EMPTY_STR (SEGMENT_OPTIONS.INDENT) THEN BEGIN SP_EXTR_STR (SEGMENT_OPTIONS.INDENT, STRING132); IF ((STRING132.BODY[1] <> 'O') OR (STRING132.BODY[2] <> 'N')) AND ((STRING132.BODY[1] <> 'O') OR (STRING132.BODY[2] <> 'F') OR (STRING132.BODY[3] <> 'F')) THEN BEGIN SP_INIT_STR (SEGMENT_OPTIONS.INDENT); OPTION_KEYWORD := EMPTY_OPTION; DIAG (ERR, 'SCAN_OPTIONS (3.1.4) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); END ELSE BEGIN (* The argument of the INDENT-option must be on the next *) (* line. Nothing remains to be done here. *) END (*IF*); (************* End of SCAN_OPTIONS (3.1.4) *****************) IF NOT SP_IS_EMPTY_STR (SEGMENT_OPTIONS.INDENT) THEN OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF OPTION_KEYWORD = OPTION_TABLE[6] THEN BEGIN (***************** SCAN_OPTIONS (3.1.5) ********************) (** Add all characters from INDEX until the next member of **) (** OPT_SPACE to SEGMENT_OPTIONS.COMMENT. Issue diagnostic **) (** and initialize OPTION_KEYWORD and SEGMENT_OPTIONS.- **) (** COMMENT in case of trouble. **) WHILE (NOT (CH IN OPT_CHARS)) AND (INDEX < LENGTH_LINE) AND (CH <> RUN_INFO.OPTION_MARKER) DO BEGIN INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); WHILE (CH IN OPT_CHARS) AND (INDEX < LENGTH_LINE) DO BEGIN SP_ADD_CHAR (UC (CH), SEGMENT_OPTIONS.COMMENT); INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); IF NOT SP_IS_EMPTY_STR (SEGMENT_OPTIONS.COMMENT) THEN BEGIN SP_EXTR_STR (SEGMENT_OPTIONS.COMMENT, STRING132); IF (STRING132.BODY = PASCAL_STRING) OR (STRING132.BODY = FORTRAN_STRING) OR (STRING132.BODY = C_STRING) THEN BEGIN DIAG (WARN, 'SCAN_OPTIONS (3.1.5)a ', DUMMY_LINE, SEGMENT, STRING132); SP_INIT_STR (SEGMENT_OPTIONS.COMMENT); OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF ((STRING132.BODY[1] <> 'O') OR (STRING132.BODY[2] <> 'N')) AND ((STRING132.BODY[1] <> 'O') OR (STRING132.BODY[2] <> 'F') OR (STRING132.BODY[3] <> 'F')) THEN BEGIN DIAG (ERR, 'SCAN_OPTIONS (3.1.5)b ', DUMMY_LINE, SEGMENT, STRING132); SP_INIT_STR (SEGMENT_OPTIONS.COMMENT); OPTION_KEYWORD := EMPTY_OPTION; END (*IF.IF*); END ELSE BEGIN (* The argument of the option COMMENT must be on the *) (* next line. Nothing remains to be done here *) END (*IF*); (************* End of SCAN_OPTIONS (3.1.5) *****************) IF NOT SP_IS_EMPTY_STR (SEGMENT_OPTIONS.COMMENT) THEN OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF OPTION_KEYWORD = OPTION_TABLE[7] THEN BEGIN SEGMENT_OPTIONS.OVERRULE := TRUE; OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF OPTION_KEYWORD = OPTION_TABLE[8] THEN BEGIN SEGMENT_OPTIONS.LEADER := TRUE; OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF OPTION_KEYWORD = OPTION_TABLE[9] THEN BEGIN SEGMENT_OPTIONS.TRAILER := TRUE; OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF OPTION_KEYWORD = OPTION_TABLE[10] THEN BEGIN SEGMENT_OPTIONS.SEPARATOR := TRUE; OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF OPTION_KEYWORD = OPTION_TABLE[11] THEN BEGIN SEGMENT_OPTIONS.DEFAULT := TRUE; OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF OPTION_KEYWORD = OPTION_TABLE[12] THEN BEGIN SEGMENT_OPTIONS.LINENUMBER := TRUE; OPTION_KEYWORD := EMPTY_OPTION; END (*IF.IF.IF.IF.IF.IF.IF.IF.IF.IF.IF.IF*); END (*IF*); (***************** End of SCAN_OPTIONS (3.1) ***************) END ELSE IF CH IN OPT_CHARS THEN BEGIN (********************* SCAN_OPTIONS (3.2) ******************) (** CH is only legal at this point as the first character **) (** of the argument of the previous option, i.e. **) (** OPTION_KEYWORD must not be empty. Read this argument. **) (** When problems arise, jump to next OPTION_MARKER and **) (** issue a diagnostic message. **) IF OPTION_KEYWORD <> EMPTY_OPTION THEN BEGIN IF OPTION_KEYWORD = OPTION_TABLE[4] THEN BEGIN (***************** SCAN_OPTIONS (3.2.1) ********************) (** Add characters from INDEX to SEGMENT_OPTIONS.FILE_NAME **) (** until the next OPT_SPACE is met. Diagnostic in case of **) (** trouble. **) WHILE (NOT (CH IN OPT_CHARS)) AND (CH <> '"') AND (INDEX < LENGTH_LINE) DO BEGIN INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); IF CH = '"' THEN BEGIN INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); WHILE (CH <> '"') AND (INDEX <= LENGTH_LINE) DO BEGIN (* SP_ADD_CHAR (UC (CH), SEGMENT_OPTIONS.FILE_NAME); 14/10/93 *) SP_ADD_CHAR (CH, SEGMENT_OPTIONS.FILE_NAME); INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); IF CH='"' THEN BEGIN INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END ELSE BEGIN SP_EXTR_STR (SEGMENT_OPTIONS.FILE_NAME, STRING132); DIAG (ERR, 'SCAN_OPTIONS (3.2.1)a ', DUMMY_LINE, SEGMENT, STRING132); SP_INIT_STR (SEGMENT_OPTIONS.FILE_NAME); OPTION_KEYWORD := EMPTY_OPTION; END (*IF*); END ELSE IF (CH IN OPT_CHARS) THEN BEGIN SP_EXTR_STR (SEGMENT_OPTIONS.FILE_NAME, STRING132); DIAG (ERR, 'SCAN_OPTIONS (3.2.1)b ', DUMMY_LINE, SEGMENT, STRING132); SP_INIT_STR (SEGMENT_OPTIONS.FILE_NAME); OPTION_KEYWORD := EMPTY_OPTION; (* Jump to the next option marker. *) WHILE (CH <> RUN_INFO.OPTION_MARKER) AND (INDEX 'O') OR (STRING132.BODY[2] <> 'N')) AND ((STRING132.BODY[1] <> 'O') OR (STRING132.BODY[2] <> 'F') OR (STRING132.BODY[3] <> 'F')) THEN BEGIN SP_INIT_STR (SEGMENT_OPTIONS.INDENT); OPTION_KEYWORD := EMPTY_OPTION; DIAG (ERR, 'SCAN_OPTIONS (3.2.2) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); END ELSE BEGIN (* The argument of the option INDENT must be on the next *) (* line. Nothing remains to be done here *) END (*IF*); (************* End of SCAN_OPTIONS (3.2.2) *****************) IF NOT SP_IS_EMPTY_STR (SEGMENT_OPTIONS.INDENT) THEN OPTION_KEYWORD := EMPTY_OPTION; END ELSE IF OPTION_KEYWORD=OPTION_TABLE[6] THEN BEGIN (***************** SCAN_OPTIONS (3.2.3) ********************) (** Add characters from INDEX to SEGMENT_OPTIONS.COMMENT **) (** until the next OPT_SPACE is met. Generate a diagnostic **) (** message and reset OPTION_KEYWORD and SEGMENT_OPTIONS.- **) (** COMMENT in case of trouble. **) WHILE (NOT (CH IN OPT_CHARS)) AND (INDEX 'O') OR (STRING132.BODY[2] <> 'N')) AND ((STRING132.BODY[1] <> 'O') OR (STRING132.BODY[2] <> 'F') OR (STRING132.BODY[3] <> 'F')) THEN BEGIN DIAG (ERR, 'SCAN_OPTIONS (3.2.3)b ', DUMMY_LINE, SEGMENT, STRING132); SP_INIT_STR (SEGMENT_OPTIONS.COMMENT); OPTION_KEYWORD := EMPTY_OPTION; END (*IF.IF*); END ELSE BEGIN (* The argument of the option COMMENT must be on the *) (* next line. Nothing remains to be done here *) END (*IF*); (************* End of SCAN_OPTIONS (3.2.3) *****************) IF NOT SP_IS_EMPTY_STR (SEGMENT_OPTIONS.COMMENT) THEN OPTION_KEYWORD := EMPTY_OPTION; END (*IF.IF.IF*); END ELSE BEGIN (********************* SCAN_OPTIONS (3.2.4) ********************) (** Character is illegal at this position. Skip to next **) (** OPTION_MARKER or to end of this line. Generate a diagnostic **) (** message using SEGMENT and LINE. **) STRING132.LENGTH := 1; STRING132.BODY[1] := CH; DIAG (ERR, 'SCAN_OPTIONS (3.2.4) ', DUMMY_LINE, SEGMENT, STRING132); OPTION_KEYWORD := EMPTY_OPTION; WHILE (CH <> RUN_INFO.OPTION_MARKER) AND (INDEX < LENGTH_LINE) DO BEGIN INDEX := INDEX + 1; CH := FT_GET_CHAR (LINE, INDEX); END (*WHILE*); (***************** End of SCAN_OPTIONS (3.2.4) *****************) END (*IF*); (***************** End of SCAN_OPTIONS (3.2) ***************) END (*IF*); END (*WHILE*); (***************** End of SCAN_OPTIONS (3) *************) (***************** SCAN_OPTIONS (4) ********************) (** Retrieve next LINE from SEGMENT. SEGMENT_EXHAUSTED **) (** becomes TRUE if the segment is exhausted. **) ST_GET_LINE (LINE); IF LINE.ID = 0 THEN SEGMENT_EXHAUSTED := TRUE; (************* End of SCAN_OPTIONS (4) *****************) END (*WHILE*); IF SEGMENT_EXHAUSTED THEN BEGIN (***************** SCAN_OPTIONS (5) ********************) (** Check SEGMENT_OPTIONS for any errors. and generate **) (** diagnostic message using SEGMENT if appropriate. **) FT_INIT_LINE (DUMMY_LINE); (* 1. Check for a missing argument of the last option. *) (* This can be detected by a non-empty OPTION_KEYWORD.*) IF OPTION_KEYWORD <> EMPTY_OPTION THEN BEGIN STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; FOR I := 1 TO MAX_OPTION_LENGTH DO BEGIN IF OPTION_KEYWORD[I] <> ' ' THEN BEGIN STRING132.BODY[I] := OPTION_KEYWORD[I]; STRING132.LENGTH := STRING132.LENGTH + 1; END (*IF*); END (*FOR*); DIAG (ERR, 'SCAN_OPTIONS (5a) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); (* 2. Check the use of stub options in a slot SEGMENT. *) IF (SEGMENT_TYPE = SLOT) OR (SEGMENT_TYPE = CODE) THEN BEGIN IF SEGMENT_OPTIONS.QUICK THEN BEGIN SEGMENT_OPTIONS.QUICK := FALSE; STRING132.BODY[1] := 'Q'; STRING132.BODY[2] := 'U'; STRING132.BODY[3] := 'I'; STRING132.BODY[4] := 'C'; STRING132.BODY[5] := 'K'; STRING132.LENGTH := 5; DIAG (ERR, 'SCAN_OPTIONS (5b) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); IF NOT (SP_IS_EMPTY_STR (SEGMENT_OPTIONS.FILE_NAME)) THEN BEGIN SP_INIT_STR (SEGMENT_OPTIONS.FILE_NAME); STRING132.BODY[1] := 'F'; STRING132.BODY[2] := 'I'; STRING132.BODY[3] := 'L'; STRING132.BODY[4] := 'E'; STRING132.LENGTH := 4; DIAG (ERR, 'SCAN_OPTIONS (5b) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); IF SEGMENT_OPTIONS.OVERRULE THEN BEGIN SEGMENT_OPTIONS.OVERRULE := FALSE; AUX_STRING10 := 'OVERRULE '; FOR I:= 1 TO 8 DO STRING132.BODY[I] := AUX_STRING10[I]; STRING132.LENGTH := 8; DIAG (ERR, 'SCAN_OPTIONS (5b) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); IF SEGMENT_OPTIONS.LEADER THEN BEGIN SEGMENT_OPTIONS.LEADER := FALSE; AUX_STRING10 := 'LEADER '; FOR I := 1 TO 6 DO STRING132.BODY[I] := AUX_STRING10[I]; STRING132.LENGTH := 6; DIAG (ERR, 'SCAN_OPTIONS (5b) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); IF SEGMENT_OPTIONS.TRAILER THEN BEGIN SEGMENT_OPTIONS.TRAILER := FALSE; AUX_STRING10 := 'TRAILER '; FOR I:= 1 TO 7 DO STRING132.BODY[I] := AUX_STRING10[I]; STRING132.LENGTH := 7; DIAG (ERR, 'SCAN_OPTIONS (5b) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); IF SEGMENT_OPTIONS.SEPARATOR THEN BEGIN SEGMENT_OPTIONS.SEPARATOR := FALSE; AUX_STRING10 := 'SEPARATOR '; FOR I := 1 TO 9 DO STRING132.BODY[I] := AUX_STRING10[I]; STRING132.LENGTH := 9; DIAG (ERR, 'SCAN_OPTIONS (5b) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); IF SEGMENT_OPTIONS.DEFAULT THEN BEGIN SEGMENT_OPTIONS.QUICK := FALSE; AUX_STRING10 := 'DEFAULT '; FOR I := 1 TO 7 DO STRING132.BODY[I] := AUX_STRING10[I]; STRING132.LENGTH := 7; DIAG (ERR, 'SCAN_OPTIONS (5b) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); END (* 3. Check the use of slot options in a stub segment. *) ELSE IF SEGMENT_TYPE = STUB THEN BEGIN IF SEGMENT_OPTIONS.MULTIPLE THEN BEGIN SEGMENT_OPTIONS.MULTIPLE := FALSE; AUX_STRING10 := 'MULTIPLE '; FOR I := 1 TO 8 DO STRING132.BODY[I] := AUX_STRING10[I]; STRING132.LENGTH := 8; DIAG (ERR, 'SCAN_OPTIONS (5c) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); IF SEGMENT_OPTIONS.OPTIONAL THEN BEGIN SEGMENT_OPTIONS.OPTIONAL := FALSE; AUX_STRING10 := 'OPTIONAL '; FOR I := 1 TO 8 DO STRING132.BODY[I] := AUX_STRING10[I]; STRING132.LENGTH := 8; DIAG (ERR, 'SCAN_OPTIONS (5c) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); END (*IF*); (* 4. Check illegal use of the options FILE, LEADER, *) (* TRAILER, SEPARATOR and DEFAULT in the segment. *) WITH SEGMENT_OPTIONS DO BEGIN IF ( (NOT SP_IS_EMPTY_STR (FILE_NAME)) AND ( (DEFAULT) OR (SEPARATOR) OR (LEADER) OR (TRAILER))) OR ( (DEFAULT) AND ( (SEPARATOR) OR (LEADER) OR (TRAILER))) OR ( (LEADER) AND ( (SEPARATOR) OR (TRAILER))) OR ( (SEPARATOR) AND (TRAILER)) THEN BEGIN DEFAULT := FALSE; SEPARATOR := FALSE; LEADER := FALSE; TRAILER := FALSE; STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; DIAG (ERR, 'SCAN_OPTIONS (5d) ', DUMMY_LINE, SEGMENT, STRING132); END (*IF*); END (*WITH*); (***************** End of SCAN_OPTIONS (5) *************) END (*IF*); END (*IF*); (***************** End of SCAN_OPTIONS (body) ******************) END (*PROCEDURE SCAN_OPTIONS*); (*********************************************************************) (* Routine: BUILD_CODE_STRUCT - BUILD the structure CODE_STRUCT. *) (* Purpose: Scan a stub block upon the different sort of *) (* segments and build the structure of stubs and slots. *) (* Interface: CODE_STRUCT: Anchors the datastructure representing *) (* the stubs and slots structure. *) (* RUN_INFO: All information concerning this run. *) (* FIRST_LINE: The first line of a stub block. *) (* LINE_INFO: Scanned information of a line. *) (*********************************************************************) PROCEDURE BUILD_CODE_STRUCT (VAR CODE_STRUCT: CODE_STRUCT_; RUN_INFO: RUN_INFO_; FIRST_LINE: LINE_DES_; LINE_INFO: LINE_INFO_); VAR SEGMENT_TYPE: SEGMENT_TYPE_; END_OF_STUB_BLOCK: BOOLEAN; SOURCE_LINE: LINE_DES_; LAST_SLOT: SLT_PTR_; STRING132: STRING132_; SEGMENT: SEGMENT_DES_; BEGIN (******* BUILD_CODE_STRUCT (body) *******) (********************* BUILD_CODE_STRUCT (1) *******************) (** FIRST_LINE marks a new stub segment. Link the stub into its **) (** position and let CODE_STRUCT.LAST_STUB refer to it. Set **) (** LAST_SLOT to NIL. Initialize LAST_STUB. Add FIRST_LINE to **) (** the segment LAST_STUB^.SRC_IMG. Use LINE_INFO to update **) (** LAST_STUB^.NAME. **) WITH CODE_STRUCT DO BEGIN LAST_SLOT := NIL; IF FIRST_STUB = NIL THEN BEGIN NEW (FIRST_STUB); LAST_STUB := FIRST_STUB; END ELSE BEGIN NEW (LAST_STUB^.NEXT_STUB); LAST_STUB := LAST_STUB^.NEXT_STUB; END (*IF*); WITH LAST_STUB^ DO BEGIN SLOTS := NIL; NEXT_STUB := NIL; NEXT_TWIN := NIL; ST_INIT_SEG (SRC_IMG); SP_INIT_STR (NAME); ST_PUT_SEG (FIRST_LINE, SRC_IMG); SP_ADD_BUFFER (LINE_INFO.LINE_ID); SP_CONC_STR (NAME, LINE_INFO.LINE_ID); END (*WITH*); END (*WITH*); (***************** End of BUILD_CODE_STRUCT (1) ****************) (* Set SEGMENT_TYPE to STUB since the first segment of a stub *) (* block must be a stub segment. Initialize END_OF_STUB_BLOCK. *) SEGMENT_TYPE := STUB; END_OF_STUB_BLOCK := FALSE; WHILE (NOT END_OF_STUB_BLOCK) AND (NOT FT_EOF) DO BEGIN FT_RDLN (SOURCE_LINE); (* Check wether or not we need to scan this line. *) WITH RUN_INFO DO BEGIN IF FT_GET_LINE_LENGTH (SOURCE_LINE) > CLIP_LPAR.LENGTH+CLIP_RPAR.LENGTH THEN SCAN_LINE (LINE_INFO, SOURCE_LINE, RUN_INFO) ELSE LINE_INFO.CATEGORY := L5; END (*WITH*); WITH CODE_STRUCT DO CASE LINE_INFO.CATEGORY OF L1: BEGIN IF LAST_SLOT = NIL THEN BEGIN (************* BUILD_CODE_STRUCT (2) ***************) (** The end of the previous stub segment. Scan the **) (** options of LAST_STUB^.SRC_IMG and store the **) (** found options in LAST_STUB^.OPTIONS. Add the **) (** buffer to LINE_INFO.LINE_ID. **) WITH LAST_STUB^ DO SCAN_OPTIONS (OPTIONS, SRC_IMG, RUN_INFO, SEGMENT_TYPE); LINE_INFO.OPTIONS := FALSE; SP_ADD_BUFFER (LINE_INFO.LINE_ID); (********* End of BUILD_CODE_STRUCT (2) ************) IF LAST_STUB^.OPTIONS.QUICK THEN BEGIN SEGMENT_TYPE := STUB; (************* BUILD_CODE_STRUCT (3) ***********) (** The end of the current stub block and the **) (** start a new one. Make an entry for this new **) (** stub, let LAST_STUB point to it and initia- **) (** lize its fields. Set LAST_SLOT to NIL. Add **) (** SOURCE_LINE to LAST_STUB^.SRC_IMG. Update **) (** LAST_STUB^.NAME with information from **) (** LINE_INFO. **) NEW (LAST_STUB^.NEXT_STUB); LAST_STUB := LAST_STUB^.NEXT_STUB; LAST_SLOT := NIL; WITH LAST_STUB^ DO BEGIN SLOTS := NIL; NEXT_STUB := NIL; NEXT_TWIN := NIL; ST_INIT_SEG (SRC_IMG); SP_INIT_STR (NAME); ST_PUT_SEG (SOURCE_LINE, SRC_IMG); SP_CONC_STR (NAME, LINE_INFO.LINE_ID); END (*WITH*); (********* End of BUILD_CODE_STRUCT (3) ********) END ELSE BEGIN SEGMENT_TYPE := SLOT; (************* BUILD_CODE_STRUCT (4) ***********) (** First slot segment of this stub block. Make **) (** entry for this new slot, let LAST_SLOT **) (** point to it and initialize its fields. Add **) (** SOURCE_LINE to segment LAST_SLOT^.SRC_IMG. **) (** Update LAST_SLOT with the information hold **) (** by LINE_INFO. **) NEW (LAST_STUB^.SLOTS); LAST_SLOT := LAST_STUB^.SLOTS; WITH LAST_SLOT^ DO BEGIN SP_INIT_STR (NAME); ST_INIT_SEG (SRC_IMG); STUB_REF := NIL; ST_INIT_SEG (CODE); NEXT_SLOT := NIL; ST_PUT_SEG (SOURCE_LINE, SRC_IMG); SP_CONC_STR (NAME, LINE_INFO.LINE_ID); END (*WITH*); (********* End of BUILD_CODE_STRUCT (4) ********) END (*IF*); END ELSE BEGIN (************* BUILD_CODE_STRUCT (5) ***************) (** End of the previous segment LAST_SLOT^.SRC_IMG. **) (** Finish the segment by scanning its options **) (** using RUN_INFO. Store found options in **) (** LAST_SLOT^.OPTIONS. Add the buffer to LINE_- **) (** INFO.LINE_ID. **) WITH LAST_SLOT^ DO SCAN_OPTIONS (OPTIONS, SRC_IMG, RUN_INFO, SEGMENT_TYPE); LINE_INFO.OPTIONS := FALSE; SP_ADD_BUFFER (LINE_INFO.LINE_ID); (********* End of BUILD_CODE_STRUCT (5) ************) IF LAST_STUB^.OPTIONS.QUICK THEN BEGIN SEGMENT_TYPE := STUB; (************* BUILD_CODE_STRUCT (6) ***********) (** End of current stub block and the start of **) (** a new one. Link this new stub into its po- **) (** sition, let LAST_STUB point to it and ini- **) (** tialize its fields. Add SOURCE_LINE to **) (** segment LAST_STUB^.SRC_IMG and update **) (** LAST_STUB^.NAME with the help of LINE_INFO. **) NEW (LAST_STUB^.NEXT_STUB); LAST_STUB := LAST_STUB^.NEXT_STUB; LAST_SLOT := NIL; WITH LAST_STUB^ DO BEGIN SLOTS := NIL; NEXT_STUB := NIL; NEXT_TWIN := NIL; ST_INIT_SEG (SRC_IMG); SP_INIT_STR (NAME); ST_PUT_SEG (SOURCE_LINE, SRC_IMG); SP_CONC_STR (NAME, LINE_INFO.LINE_ID); END (*WITH*); (********* End of BUILD_CODE_STRUCT (6) ********) END ELSE BEGIN SEGMENT_TYPE := SLOT; (************* BUILD_CODE_STRUCT (7) ***********) (** Start of a new slot segment. Link slot into **) (** its position, let LAST_SLOT point to it and **) (** initialize its fields. Add SOURCE_LINE to **) (** LAST_SLOT^.SRC_IMG and update LAST_SLOT^.- **) (** NAME with the help of LINE_INFO. **) NEW (LAST_SLOT^.NEXT_SLOT); LAST_SLOT := LAST_SLOT^.NEXT_SLOT; WITH LAST_SLOT^ DO BEGIN SP_INIT_STR (NAME); ST_INIT_SEG (SRC_IMG); STUB_REF := NIL; ST_INIT_SEG (CODE); NEXT_SLOT := NIL; ST_PUT_SEG (SOURCE_LINE, SRC_IMG); SP_CONC_STR (NAME, LINE_INFO.LINE_ID); END (*WITH*); (********* End of BUILD_CODE_STRUCT (7) ********) END (*IF*); END(*IF*); END; L2: BEGIN (***************** BUILD_CODE_STRUCT (8) ***************) (** End of the previous slot or stub segment. Scan **) (** LAST_^.SRC_IMG for options and store them in **) (** LAST_^.OPTIONS. Add the buffer to LINE_INFO.- **) (** LINE_ID after that. reads "STUB" for a stub **) (** and "SLOT" for a slot- or code-segment. **) IF (SEGMENT_TYPE = STUB) THEN BEGIN WITH LAST_STUB^ DO SCAN_OPTIONS (OPTIONS, SRC_IMG, RUN_INFO, SEGMENT_TYPE) END ELSE BEGIN WITH LAST_SLOT^ DO SCAN_OPTIONS (OPTIONS, SRC_IMG, RUN_INFO, SEGMENT_TYPE); END (*IF*); LINE_INFO.OPTIONS := FALSE; SP_ADD_BUFFER (LINE_INFO.LINE_ID); (************* End of BUILD_CODE_STRUCT (8) ************) END_OF_STUB_BLOCK := TRUE; SEGMENT_TYPE := END_STUB; (***************** BUILD_CODE_STRUCT (9) ***************) (** Start of the end segment. Link slot into its posi- **) (** tion, let LAST_SLOT point to it and initialize its **) (** fields. Add SOURCE_LINE to the segment LAST_SLOT^.- **) (** SRC_IMG and update LAST_SLOT^.NAME using the infor- **) (** mation of LINE_INFO. **) IF LAST_SLOT<>NIL THEN BEGIN NEW (LAST_SLOT^.NEXT_SLOT); LAST_SLOT := LAST_SLOT^.NEXT_SLOT; END ELSE BEGIN NEW (LAST_STUB^.SLOTS); LAST_SLOT := LAST_STUB^.SLOTS; END (*IF*); WITH LAST_SLOT^ DO BEGIN SP_INIT_STR (NAME); ST_INIT_SEG (SRC_IMG); STUB_REF := NIL; ST_INIT_SEG (CODE); NEXT_SLOT := NIL; SCAN_OPTIONS (OPTIONS, SRC_IMG, RUN_INFO, SEGMENT_TYPE); LINE_INFO.OPTIONS := FALSE; ST_PUT_SEG (SOURCE_LINE, SRC_IMG); SP_CONC_STR (NAME, LINE_INFO.LINE_ID); END; (*WITH*) (************* End of BUILD_CODE_STRUCT (9) ************) END; L3: BEGIN IF SEGMENT_TYPE = STUB THEN BEGIN (************* BUILD_CODE_STRUCT (10) **************) (** Continuation line of the stub segment. Add **) (** SOURCE_LINE to LAST_STUB^.SRC_IMG. Add buffer **) (** to LINE_INFO.LINE_ID and update LAST_STUB^.NAME **) (** using LINE_INFO. **) WITH LAST_STUB^ DO BEGIN ST_PUT_LINE (SOURCE_LINE, SRC_IMG); SP_ADD_BUFFER (LINE_INFO.LINE_ID); SP_CONC_STR (NAME, LINE_INFO.LINE_ID); END (*WITH*); (********* End of BUILD_CODE_STRUCT (10) ***********) END ELSE IF SEGMENT_TYPE = SLOT THEN BEGIN (************* BUILD_CODE_STRUCT (11) **************) (** Continuation of the current slot segment. **) (** Add SOURCE_LINE to LAST_SLOT^.SRC_IMG, add the **) (** buffer to LINE_INFO.LINE_ID and update LAST_- **) (** SLOT^.NAME using LINE_INFO. **) WITH LAST_SLOT^ DO BEGIN ST_PUT_LINE (SOURCE_LINE, SRC_IMG); SP_ADD_BUFFER (LINE_INFO.LINE_ID); SP_CONC_STR (NAME, LINE_INFO.LINE_ID); END (*WITH*); (********* End of BUILD_CODE_STRUCT (11) ***********) END ELSE BEGIN (************* BUILD_CODE_STRUCT (12) **************) (** This orphan line cannot be paste to a stub- or **) (** slot-segment. Generate an error message using **) (** the information hold by SOURCE_LINE. **) ST_INIT_SEG (SEGMENT); STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; DIAG (WARN, 'BUILD_C_S (12) ', SOURCE_LINE, SEGMENT, STRING132); (********* End of BUILD_CODE_STRUCT (12) ***********) END (*IF.IF*); END; L4: BEGIN IF SEGMENT_TYPE = STUB THEN BEGIN (************* BUILD_CODE_STRUCT (13) **************) (** Continuation ofcurrent stub segment. Add **) (** SOURCE_LINE to segment LAST_STUB^.SRC_IMG. **) WITH LAST_STUB^ DO ST_PUT_LINE (SOURCE_LINE, SRC_IMG); (********* End of BUILD_CODE_STRUCT (13) ***********) END ELSE IF SEGMENT_TYPE = SLOT THEN BEGIN (************* BUILD_CODE_STRUCT (14) **************) (** Continuation of current slot segment. Add **) (** SOURCE_LINE to segment LAST_SLOT^.SRC_IMG. **) WITH LAST_SLOT^ DO ST_PUT_LINE (SOURCE_LINE, SRC_IMG); (********* End of BUILD_CODE_STRUCT (14) ***********) END ELSE IF SEGMENT_TYPE = CODE THEN BEGIN (************* BUILD_CODE_STRUCT (15) **************) (** Continuation of current code segment. Add **) (** SOURCE_LINE to segment LAST_SLOT^.CODE. **) WITH LAST_SLOT^ DO ST_PUT_LINE (SOURCE_LINE, CODE); (********* End of BUILD_CODE_STRUCT (15) ***********) END (*IF.IF.IF*); END; L5: BEGIN IF SEGMENT_TYPE = STUB THEN BEGIN (************* BUILD_CODE_STRUCT (16) **************) (** End of previous stub segment LAST_STUB^.- **) (** SRC_IMG. Complete that segment by scanning **) (** which are stored to LAST_STUB^.OPTIONS. **) WITH LAST_STUB^ DO SCAN_OPTIONS (OPTIONS, SRC_IMG, RUN_INFO, SEGMENT_TYPE); LINE_INFO.OPTIONS := FALSE; (********* End of BUILD_CODE_STRUCT (16) ***********) IF (LAST_STUB^.OPTIONS.QUICK) AND (FT_GET_LINE_LENGTH (SOURCE_LINE) = 0) THEN BEGIN (************* BUILD_CODE_STRUCT (17) **********) (** End of current stub block. Set Boolean **) (** END_OF_STUB_BLOCK to TRUE. **) END_OF_STUB_BLOCK := TRUE; (********* End of BUILD_CODE_STRUCT (17) *******) END ELSE BEGIN SEGMENT_TYPE := CODE; (************* BUILD_CODE_STRUCT (18) **********) (** Start of a new code-segment. Link a new **) (** entry for this slot into its position. Let **) (** LAST_SLOT refer to this slot and initialize **) (** its fields. Add SOURCE_LINE to the new code **) (** segment LAST_SLOT^.CODE. **) NEW (LAST_STUB^.SLOTS); LAST_SLOT := LAST_STUB^.SLOTS; WITH LAST_SLOT^ DO BEGIN SP_INIT_STR (NAME); ST_INIT_SEG (SRC_IMG); STUB_REF := NIL; ST_INIT_SEG (CODE); NEXT_SLOT := NIL; ST_PUT_SEG (SOURCE_LINE, CODE); END (*WITH*); (********* END OF BUILD_CODE-STRUCT (18) *******) END (*IF.IF*); END ELSE IF SEGMENT_TYPE = SLOT THEN BEGIN SEGMENT_TYPE := CODE; (************* BUILD_CODE_STRUCT (19) **************) (** Start of a new code segment immediately follo- **) (** wing a slot segment. Add SOURCE_LINE to the **) (** to the code segment LAST_SLOT^.CODE. **) WITH LAST_SLOT^ DO ST_PUT_SEG (SOURCE_LINE, CODE); (********* End of BUILD_CODE_STRUCT (19) ***********) END ELSE IF SEGMENT_TYPE = CODE THEN BEGIN IF (CODE_STRUCT.LAST_STUB^.OPTIONS.QUICK) AND (FT_GET_LINE_LENGTH (SOURCE_LINE)=0) THEN BEGIN (************* BUILD_CODE_STRUCT (20) **********) (** End of current stub block. Scan options **) (** from LAST_SLOT^.SRC_IMG and store them in **) (** LAST_SLOT^.OPTIONS. **) SCAN_OPTIONS (LAST_SLOT^.OPTIONS, LAST_SLOT^.SRC_IMG, RUN_INFO, SEGMENT_TYPE); LINE_INFO.OPTIONS := FALSE; (********* End of BUILD_CODE_STRUCT (20) *******) END_OF_STUB_BLOCK := TRUE; END ELSE BEGIN (************* BUILD_CODE_STRUCT (21) **********) (** Continuation of the code segment. Add **) (** SOURCE_LINE to segment LAST_SLOT^.CODE. **) WITH LAST_SLOT^ DO ST_PUT_LINE (SOURCE_LINE, CODE); (********* End of BUILD_CODE_STRUCT (21) *******) END (*IF*); END (*IF.IF.IF*); END; END (*CASE.WITH*); END (*WHILE*); IF (NOT END_OF_STUB_BLOCK) THEN BEGIN IF (NOT CODE_STRUCT.LAST_STUB^.OPTIONS.QUICK) THEN BEGIN (************* BUILD_CODE_STRUCT (22) ******************) (** File exhausted but current stub block not closed by **) (** a line of category L2. Issue an error using **) (** FILE_SPEC. **) STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; FT_INIT_LINE (SOURCE_LINE); DIAG (WARN, 'BUILD_C_S (22) ', SOURCE_LINE, CODE_STRUCT.LAST_STUB^.SRC_IMG, STRING132); (************* End of BUILD_CODE_STRUCT (22) ***********) END ELSE IF SEGMENT_TYPE = CODE THEN BEGIN (************* BUILD_CODE_STRUCT (23) ******************) (** The last quick stub in the file didn't end with an **) (** L5-line, but with EOF. So the options from LAST_- **) (** SLOT.SRC_IMG must be scanned and stored in LAST_- **) (** SLOT.OPTIONS here. **) SCAN_OPTIONS (LAST_SLOT^.OPTIONS, LAST_SLOT^.SRC_IMG, RUN_INFO, SEGMENT_TYPE); LINE_INFO.OPTIONS := FALSE; (************* End of BUILD_CODE_STRUCT (23) ***********) END (*IF*); END (*IF*); (************* End of BUILD_CODE_STRUCT (body) *****************) END (*PROCEDURE BUILD_CODE_STRUCT*); (*********************************************************************) (* Routine: SCAN_FILES - SCAN all source FILES. *) (* Purpose: To coordinate the scanning of all the sourcefiles on *) (* file level. More detailed activities are delegated. *) (* Interface: RUN_INFO: Structure containing all needed info *) (* for this CLIP run. *) (* CODE_STRUCT: Internal representation of stub-, *) (* slot- and code-segments. *) (*********************************************************************) PROCEDURE SCAN_FILES (VAR CODE_STRUCT: CODE_STRUCT_; RUN_INFO: RUN_INFO_); VAR SCAN_FILE_STOP: BOOLEAN; FILE_CNT: INTEGER; I: INTEGER; LINE_INFO: LINE_INFO_ ; SOURCE_LINE: LINE_DES_ ; DUMMY: ERROR_CODE_; STRING132: STRING132_; SEGMENT: SEGMENT_DES_; BEGIN (******* SCAN_FILES (body) *******) SCAN_FILE_STOP := FALSE; (********************* SCAN_FILES (1) **************************) (** Try to open all source files of which the names are kept by **) (** RUN_INFO. List inaccessible files. Set SCAN_FILE_STOP to **) (** TRUE when at least one file gives a problem. **) WITH RUN_INFO DO FOR FILE_CNT := 1 TO NR_SRC_FILES DO BEGIN IF FT_CHECK_FILE (SOURCE_FILES [FILE_CNT]) <> 0 THEN BEGIN WRITE ('ERROR checking source file: '); FOR I := 1 TO SOURCE_FILES [FILE_CNT].LENGTH DO WRITE (SOURCE_FILES [FILE_CNT].BODY [I]); WRITELN; IF REPORT_OK THEN BEGIN WRITE (REPORT_FILE, 'ERROR checking source file: '); FOR I := 1 TO SOURCE_FILES [FILE_CNT].LENGTH DO WRITE (REPORT_FILE, SOURCE_FILES [FILE_CNT].BODY [I]); WRITELN (REPORT_FILE); END (*IF*); SCAN_FILE_STOP := TRUE; END (*IF*); END (*FOR.WITH*); (***************** End of SCAN_FILES (1) ***********************) IF NOT SCAN_FILE_STOP THEN BEGIN (********************* SCAN_FILES (2) **********************) (** Build CODE_STRUCT from the source files specified by **) (** RUN_INFO. **) FOR FILE_CNT := 1 TO RUN_INFO.NR_SRC_FILES DO BEGIN (* Open and reset file with given specification using *) (* the function FT_INOPEN from the module FT. *) IF FT_INOPEN (RUN_INFO.SOURCE_FILES [FILE_CNT]) <= 0 THEN BEGIN WRITE ('Scanning file: '); FOR I := 1 TO RUN_INFO.SOURCE_FILES [FILE_CNT].LENGTH DO WRITE (RUN_INFO.SOURCE_FILES [FILE_CNT].BODY[I]); WRITELN; IF REPORT_OK THEN BEGIN WRITE (REPORT_FILE, 'Scanning file: '); FOR I := 1 TO RUN_INFO.SOURCE_FILES [FILE_CNT].LENGTH DO WRITE (REPORT_FILE, RUN_INFO.SOURCE_FILES [FILE_CNT].BODY[I]); WRITELN (REPORT_FILE); END (*IF*); WHILE NOT FT_EOF DO BEGIN (* Read the next line from the source file and *) (* initialize LINE_INFO and the Buffer. *) FT_RDLN (SOURCE_LINE); WITH LINE_INFO DO OPTIONS := FALSE; SP_INIT_BUFFER; (* Determine the category this line belongs to. *) WITH RUN_INFO DO BEGIN IF SOURCE_LINE.USED > CLIP_LPAR.LENGTH + CLIP_RPAR.LENGTH THEN SCAN_LINE (LINE_INFO, SOURCE_LINE, RUN_INFO) ELSE LINE_INFO.CATEGORY := L5; END (*WITH*); (* Proces this line according to its catagory. *) CASE LINE_INFO.CATEGORY OF L1: BEGIN (************* SCAN_FILES (2.1) ********************) (** Start of a new stub. Switch to active mode and **) (** build CODE_STRUCT from successive lines using **) (** RUN_INFO, SOURCE_LINE and LINE_INFO. **) BUILD_CODE_STRUCT (CODE_STRUCT, RUN_INFO, SOURCE_LINE, LINE_INFO); (************* End of SCAN_FILES (2.1) *************) END; L2: BEGIN (************* SCAN_FILES (2.2) ********************) (** Illegal in passive mode. Generate an error from **) (** the information in SOURCE_LINE. **) ST_INIT_SEG (SEGMENT); STRING132.BODY := EMPTY_STRING_FIXED; STRING132.LENGTH := 0; DIAG (WARN, 'SCAN_FILES (2.2) ', SOURCE_LINE, SEGMENT, STRING132); (************* End of SCAN_FILES (2.2) *************) END; L3: BEGIN (************* SCAN_FILES (2.3) ********************) (** Illegal in passive mode. Generate an error from **) (** the information in SOURCE_LINE. **) ST_INIT_SEG (SEGMENT); STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; DIAG (ERR, 'SCAN_FILES (2.3) ', SOURCE_LINE, SEGMENT, STRING132); (************* End of SCAN_FILES (2.3) *************) END; L4, L5: BEGIN (* Nothing to be done. Flush this line. *) END; END (*CASE*); END (*WHILE*); DUMMY := FT_INCLOSE; END ELSE BEGIN (********************* SCAN_FILES (2.4) ********************) (** Access problem with this source file. Issue error using **) (** its specification in RUN_INFO. **) WITH RUN_INFO DO BEGIN WRITE ('ERROR opening source file: '); FOR I := 1 TO SOURCE_FILES [FILE_CNT].LENGTH DO WRITE (SOURCE_FILES [FILE_CNT].BODY [I]); WRITELN; IF REPORT_OK THEN BEGIN WRITE (REPORT_FILE, 'ERROR opening source file: '); FOR I := 1 TO SOURCE_FILES [FILE_CNT].LENGTH DO WRITE (REPORT_FILE, SOURCE_FILES [FILE_CNT].BODY [I]); WRITELN (REPORT_FILE); END (*IF*); END (*WITH*); (***************** End of SCAN_FILES (2.4) *****************) END (*IF*); END (*FOR*); (***************** End of SCAN_FILES (2) *******************) END (*IF*); (***************** End of SCAN_FILES (body) ********************) END (*PROCEDURE SCAN_FILES*); (*********************************************************************) (* Routine: CHECK_CIRC - CHECK FOR CIRCularity. *) (* Purpose: To check possible circularity of CODE_STRUCT. *) (* Interface: CODE_STRUCT - Structure to be examined. *) (* LIST_HEAD - First element of shadow list. *) (*********************************************************************) PROCEDURE CHECK_CIRC (VAR CODE_STRUCT: CODE_STRUCT_; LIST_HEAD: SHADOW_PTR_); VAR MAIN_STUB: STB_PTR_; SHADOW_STUB: SHADOW_PTR_; STUB: STB_PTR_; CIRCULARITY, REMOVED: BOOLEAN; (******* CHECK_CIRC routines *******) (*********************************************************************) (* Routine: LOCATE_CIRC - LOCATE CIRCularity. *) (* Purpose: Locate and remove circularity in CODE_STRUCT. *) (* Interface: CODE_STRUCT - The structure to be checked. *) (* STUB - The stub currently checked. *) (* CIRCULARITY - Flags if circularity is detected. *) (* REMOVED - Flags if circularity is removed. *) (*********************************************************************) PROCEDURE LOCATE_CIRC (VAR CODE_STRUCT: CODE_STRUCT_; VAR STUB: STB_PTR_; VAR CIRCULARITY: BOOLEAN; VAR REMOVED: BOOLEAN); (******* LOCATE_CIRC labels (#Quick) *******) LABEL MYEXIT; VAR SLOT: SLT_PTR_; HELP_STUB: STB_PTR_; TWIN_STUB: STB_PTR_; (******* LOCATE_CIRC routines *******) (*********************************************************************) (* Routine: TRACEBACK *) (* Purpose: -In case of an unremoved circularity: Remove circu- *) (* larity and show the responsible slot. *) (* -Show a stub of the circularity-chain. *) (* Interface: STUB - The stub, which was being checked. *) (* SLOT - The slot, at which STUB is pointing. *) (* REMOVED - Flags if the circularity is removed. *) (*********************************************************************) PROCEDURE TRACEBACK ( STUB: STB_PTR_; SLOT: SLT_PTR_; VAR REMOVED: BOOLEAN); BEGIN IF NOT REMOVED THEN BEGIN SLOT^.STUB_REF := NIL; REMOVED := TRUE; WRITELN('Circularity detected !!! TRACE BACK:'); WRITELN ('slot:'); ST_WRITE_SEG (SLOT^.SRC_IMG, 0, 0); WRITELN; IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE, 'Circularity detected !!! TRACE BACK:'); WRITELN (REPORT_FILE, 'slot:'); ST_WRITE_SEG (SLOT^.SRC_IMG, 0, 3); WRITELN (REPORT_FILE); END (*IF*); END(*IF*); IF NOT SP_IS_EMPTY_STR (STUB^.OPTIONS.FILE_NAME) THEN BEGIN WRITELN ('Main stub:'); ST_WRITE_SEG (STUB^.SRC_IMG, 0, 0); WRITELN ('------------------------------------', '------------------------------------'); IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE, 'Main stub:'); ST_WRITE_SEG (STUB^.SRC_IMG, 0, 3); WRITELN (REPORT_FILE, '------------------------------------', '------------------------------------'); END (*IF*); END ELSE BEGIN WRITELN ('Stub:'); ST_WRITE_SEG (STUB^.SRC_IMG, 0, 0); IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE, 'Stub:'); ST_WRITE_SEG (STUB^.SRC_IMG, 0, 3); END (*IF*); END (*IF*); WRITELN; END (*TRACEBACK*); (********************* End of LOCATE_CIRC routines *****************) BEGIN (******* LOCATE_CIRC (body) *******) WITH STUB^ DO BEGIN CIRCULARITY := STUB^.VISITED; IF NOT CIRCULARITY THEN BEGIN STUB^.VISITED := TRUE; SLOT := STUB^.SLOTS; (********************* LOCATE_CIRC (1) *********************) (** Check if the SLOTs of STUB are pointing at any stubs. **) (** If so, locate circularities in these stubs and their **) (** structure behind. Leave this level of the procedure **) (** through MYEXIT in case of circularity. **) WHILE SLOT <> NIL DO BEGIN IF SLOT^.STUB_REF <> NIL THEN BEGIN LOCATE_CIRC(CODE_STRUCT,SLOT^.STUB_REF, CIRCULARITY,REMOVED); IF CIRCULARITY THEN BEGIN (***************** LOCATE_CIRC (1.1) *******************) (** Remove the link causing the circularity in CODE_- **) (** STRUCT, if not removed already. Mention STUB in the **) (** traceback. If this STUB is a main stub, set CIRCU- **) (** RITY, REMOVED and VISITED of all next stubs back to **) (** FALSE and locate circularities in this new CODE_- **) (** STRUCT. Leave this level of the procedure through **) (** MYEXIT. **) TRACEBACK (STUB, SLOT, REMOVED); IF NOT SP_IS_EMPTY_STR (STUB^.OPTIONS.FILE_NAME) THEN BEGIN CIRCULARITY := FALSE; REMOVED := FALSE; HELP_STUB := STUB; WHILE HELP_STUB <> NIL DO BEGIN HELP_STUB^.VISITED := FALSE; HELP_STUB := HELP_STUB^.NEXT_STUB; END (*WHILE*); LOCATE_CIRC (CODE_STRUCT, STUB, CIRCULARITY, REMOVED); END(*IF*); GOTO MYEXIT; (************* End of LOCATE_CIRC (1.1) ****************) END (*IF*); (***************** LOCATE_CIRC (1.2) ***********************) (** Check if SLOT^.STUB_REF is pointing at any twin stubs. **) (** If so, locate circularities in these stubs. In case of **) (** circularity, remove the responsible link, if not **) (** removed already, mention STUB in the traceback and **) (** leave this level of the procedure through MYEXIT. **) TWIN_STUB := SLOT^.STUB_REF^.NEXT_TWIN; WHILE TWIN_STUB <> NIL DO BEGIN LOCATE_CIRC (CODE_STRUCT, TWIN_STUB, CIRCULARITY, REMOVED); IF CIRCULARITY THEN BEGIN TRACEBACK (STUB, SLOT, REMOVED); GOTO MYEXIT; END (*IF*); TWIN_STUB := TWIN_STUB^.NEXT_TWIN; END (*WHILE*); (************* End of LOCATE_CIRC (1.2) ********************) SLOT^.STUB_REF^.VISITED := FALSE; END (*IF*); SLOT := SLOT^.NEXT_SLOT; END (*WHILE*); (***************** End of LOCATE_CIRC (1) ******************) STUB^.VISITED := FALSE; END (*IF*); END (*WITH*); MYEXIT: (***************** End of LOCATE_CIRC (body) *******************) END (*PROCEDURE LOCATE_CIRC*); (***************** End of procedure LOCATE_CIRC ********************) BEGIN SHADOW_STUB := LIST_HEAD; WHILE SHADOW_STUB <> NIL DO BEGIN MAIN_STUB := NIL; WITH SHADOW_STUB^.STUB_POINTER^ DO BEGIN IF NOT SP_IS_EMPTY_STR (OPTIONS.FILE_NAME) THEN MAIN_STUB := SHADOW_STUB^.STUB_POINTER; END (*WITH*); IF MAIN_STUB <> NIL THEN BEGIN STUB := CODE_STRUCT.FIRST_STUB; WHILE STUB <> NIL DO BEGIN STUB^.VISITED := FALSE; STUB := STUB^.NEXT_STUB; END (*WHILE*); CIRCULARITY := FALSE; REMOVED := FALSE; LOCATE_CIRC (CODE_STRUCT, MAIN_STUB, CIRCULARITY, REMOVED); END (*IF*); SHADOW_STUB := SHADOW_STUB^.NEXT; END (*WHILE*) END (*PROCEDURE CHECK_CIRC*); (*********************************************************************) (* Routine: ORDER_TWINS - ORDER TWIN stub chains. *) (* Purpose: To (re)order the chains of twin stubs. *) (* Interface: SHADOW_LIST: The list of pointers to the first *) (* elements of the twin stub chain. *) (* CODE_STRUCT: Structure of stubs and slots. *) (* LIST_HEAD: Pointer to first element of the *) (* shadow_list. *) (*********************************************************************) PROCEDURE ORDER_TWINS (VAR SHADOW_LIST: SHADOW_LIST_; VAR CODE_STRUCT: CODE_STRUCT_; VAR LIST_HEAD: SHADOW_PTR_); VAR FIRST_TWIN: STB_PTR_; SHADOW_STUB: SHADOW_PTR_; PREV_SHADOW_STUB: SHADOW_PTR_; TWIN_STUB: STB_PTR_; PREV_TWIN: STB_PTR_; CONTINUE: BOOLEAN; LAST_TWIN: STB_PTR_; SEPARATOR_STUB: STB_PTR_; STUB_WALKER: STB_PTR_; HELP_STUB: STB_PTR_; ERROR: BOOLEAN; DUMMY_LINE: LINE_DES_; STRING132: STRING132_; BEGIN (********************* ORDER_TWINS body ************************) PREV_SHADOW_STUB := NIL; SHADOW_STUB := LIST_HEAD; WHILE SHADOW_STUB <> NIL DO BEGIN FIRST_TWIN := SHADOW_STUB^.STUB_POINTER; (************************ ORDER_TWINS (1) *********************) (** Order the twin stub chain headed by FIRST_TWIN. Make sure **) (** that its first element remains accessible through by **) (** SHADOW_STUB. **) PREV_TWIN := NIL; TWIN_STUB := FIRST_TWIN; WHILE TWIN_STUB <> NIL DO BEGIN IF TWIN_STUB^.OPTIONS.DEFAULT THEN BEGIN (********************* ORDER_TWINS (1.1) *******************) (** Remove the TWIN_STUB from the list if it is no longer **) (** needed. Update SHADOW_LIST if needed. **) IF (TWIN_STUB^.NEXT_TWIN <> NIL) AND (PREV_TWIN = NIL) THEN SHADOW_STUB^.STUB_POINTER := TWIN_STUB^.NEXT_TWIN ELSE IF (TWIN_STUB^.NEXT_TWIN <> NIL) AND (PREV_TWIN <> NIL) THEN PREV_TWIN^.NEXT_TWIN := TWIN_STUB^.NEXT_TWIN ELSE IF (TWIN_STUB^.NEXT_TWIN = NIL) AND (PREV_TWIN <> NIL) THEN PREV_TWIN^.NEXT_TWIN := NIL ELSE BEGIN (* Nothing remains to be done here. *) END(*IF.IF.IF*); (***************** End of ORDER_TWINS (1.1) ****************) END (*IF*); IF TWIN_STUB^.OPTIONS.LEADER THEN BEGIN (********************* ORDER_TWINS (1.2) *******************) (** Remove TWIN_STUB and put it ahead of the twin stub **) (** chain. Remove SHADOW_STUB from SHADOW_LIST if TWIN_STUB **) (** is no longer needed. **) IF (TWIN_STUB^.NEXT_TWIN = NIL) AND (PREV_TWIN = NIL) THEN BEGIN IF PREV_SHADOW_STUB = NIL THEN BEGIN LIST_HEAD := SHADOW_STUB^.NEXT; SHADOW_STUB := LIST_HEAD; PREV_SHADOW_STUB := NIL; END ELSE BEGIN PREV_SHADOW_STUB^.NEXT := SHADOW_STUB^.NEXT; SHADOW_STUB := PREV_SHADOW_STUB; END (*IF*); END ELSE IF (TWIN_STUB^.NEXT_TWIN <> NIL) AND (PREV_TWIN <> NIL) THEN BEGIN PREV_TWIN^.NEXT_TWIN := TWIN_STUB^.NEXT_TWIN; TWIN_STUB^.NEXT_TWIN := FIRST_TWIN; SHADOW_STUB^.STUB_POINTER := TWIN_STUB; TWIN_STUB := PREV_TWIN; FIRST_TWIN := SHADOW_STUB^.STUB_POINTER; END ELSE IF (TWIN_STUB^.NEXT_TWIN = NIL) AND (PREV_TWIN <> NIL) THEN BEGIN PREV_TWIN^.NEXT_TWIN := NIL; TWIN_STUB^.NEXT_TWIN := FIRST_TWIN; SHADOW_STUB^.STUB_POINTER := TWIN_STUB; TWIN_STUB := PREV_TWIN; FIRST_TWIN := SHADOW_STUB^.STUB_POINTER; END ELSE BEGIN (* Leader stub is in place,nothing remains to be *) (* done here. *) END (*IF.IF.IF*); (***************** End of ORDER_TWINS (1.2) ****************) END (*IF*); IF TWIN_STUB^.OPTIONS.TRAILER THEN BEGIN (********************* ORDER_TWINS (1.3) *******************) (** Remove TWIN_STUB and put it at the tail of the twin **) (** stub chain. **) (* Locate the last stub in the twin stub chain *) LAST_TWIN := TWIN_STUB; WHILE LAST_TWIN^.NEXT_TWIN <> NIL DO LAST_TWIN := LAST_TWIN^.NEXT_TWIN; IF (TWIN_STUB^.NEXT_TWIN = NIL) AND (PREV_TWIN = NIL) THEN BEGIN IF PREV_SHADOW_STUB = NIL THEN BEGIN LIST_HEAD := SHADOW_STUB^.NEXT; SHADOW_STUB := LIST_HEAD; PREV_SHADOW_STUB := NIL; END ELSE BEGIN PREV_SHADOW_STUB^.NEXT := SHADOW_STUB^.NEXT; SHADOW_STUB := PREV_SHADOW_STUB; END (*IF*); END ELSE IF (TWIN_STUB^.NEXT_TWIN <> NIL) AND (PREV_TWIN <> NIL) THEN BEGIN PREV_TWIN^.NEXT_TWIN := TWIN_STUB^.NEXT_TWIN; LAST_TWIN^.NEXT_TWIN := TWIN_STUB; LAST_TWIN := LAST_TWIN^.NEXT_TWIN; LAST_TWIN^.NEXT_TWIN := NIL; TWIN_STUB := PREV_TWIN; END ELSE IF (TWIN_STUB^.NEXT_TWIN <> NIL) AND (PREV_TWIN = NIL) THEN BEGIN SHADOW_STUB^.STUB_POINTER := TWIN_STUB^.NEXT_TWIN; LAST_TWIN^.NEXT_TWIN := TWIN_STUB; LAST_TWIN := LAST_TWIN^.NEXT_TWIN; LAST_TWIN^.NEXT_TWIN := NIL; FIRST_TWIN := SHADOW_STUB^.STUB_POINTER; TWIN_STUB := FIRST_TWIN; PREV_TWIN := NIL; END ELSE BEGIN (* Trailer stub is in position. Nothing remains *) (* to be done. *) END (*IF.IF.IF*); (***************** End of ORDER_TWINS (1.3) ****************) END (*IF*); PREV_TWIN := TWIN_STUB; TWIN_STUB := TWIN_STUB^.NEXT_TWIN; END (*WHILE*); TWIN_STUB := FIRST_TWIN; PREV_TWIN := NIL; CONTINUE := TRUE; WHILE (TWIN_STUB^.NEXT_TWIN <> NIL) AND (CONTINUE) DO BEGIN IF TWIN_STUB^.OPTIONS.SEPARATOR THEN BEGIN (********************* ORDER_TWINS (1.4) *******************) (** Copy the seperator TWIN_STUB in between all other stubs **) (** of the twin stub chain. **) IF PREV_TWIN = NIL THEN BEGIN FIRST_TWIN := TWIN_STUB^.NEXT_TWIN; SHADOW_STUB^.STUB_POINTER := FIRST_TWIN; SEPARATOR_STUB := TWIN_STUB; END ELSE BEGIN PREV_TWIN^.NEXT_TWIN := TWIN_STUB^.NEXT_TWIN; SEPARATOR_STUB := TWIN_STUB; TWIN_STUB := PREV_TWIN; END (*IF*); STUB_WALKER := FIRST_TWIN; WHILE STUB_WALKER^.NEXT_TWIN <> NIL DO BEGIN HELP_STUB := STUB_WALKER^.NEXT_TWIN; NEW (STUB_WALKER^.NEXT_TWIN); STUB_WALKER := STUB_WALKER^.NEXT_TWIN; STUB_WALKER^ := SEPARATOR_STUB^; STUB_WALKER^.NEXT_TWIN := HELP_STUB; STUB_WALKER := HELP_STUB; END (*WHILE*); (***************** End of ORDER_TWINS (1.4) ****************) CONTINUE := FALSE; END (*IF*); PREV_TWIN := TWIN_STUB; TWIN_STUB := TWIN_STUB^.NEXT_TWIN; END (*WHILE*); (************************* ORDER_TWINS (1.5) ***********************) (** Examine the twin stub chain accessible by FIRST_TWIN. Generate **) (** a diagnostic message in case the chain contains only LEADER, **) (** SEPARATOR and TRAILER stubs. **) ERROR := TRUE; STUB_WALKER := FIRST_TWIN; WHILE (STUB_WALKER <> NIL) AND (ERROR = TRUE) DO BEGIN IF (NOT STUB_WALKER^.OPTIONS.LEADER) AND (NOT STUB_WALKER^.OPTIONS.SEPARATOR) AND (NOT STUB_WALKER^.OPTIONS.TRAILER) THEN ERROR := FALSE; STUB_WALKER := STUB_WALKER^.NEXT_TWIN; END (*WHILE*); IF (STUB_WALKER = NIL) AND (ERROR) THEN BEGIN STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; FT_INIT_LINE (DUMMY_LINE); DIAG(WARN, 'ORDER_TWINS (1.5) ', DUMMY_LINE, FIRST_TWIN^.SRC_IMG, STRING132); IF PREV_SHADOW_STUB = NIL THEN BEGIN LIST_HEAD := SHADOW_STUB^.NEXT; SHADOW_STUB := LIST_HEAD; PREV_SHADOW_STUB := NIL; END ELSE BEGIN PREV_SHADOW_STUB^.NEXT := SHADOW_STUB^.NEXT; SHADOW_STUB := PREV_SHADOW_STUB; END (*IF*); END ELSE BEGIN (* The twin stub chain is ok and nothing remains to be *) (* done here. *) END (*IF*); (********************* End of ORDER_TWINS (1.5) ********************) (********************* End of ORDER_TWINS (1) ******************) PREV_SHADOW_STUB := SHADOW_STUB; SHADOW_STUB := SHADOW_STUB^.NEXT; END (*WHILE*); (***************** End of ORDER_TWINS (body) *******************) END (*PROCEDURE ORDER_TWINS*); (*********************************************************************) (* Routine: ANALYSE - ANALYSEr phase *) (* Purpose: To analyse the structure of stubs and slots. *) (* Interface: Input: CODE_STRUCT - the structure to be analyzed. *) (* Output: CODE_STRUCT - the analyzed structure. *) (*********************************************************************) PROCEDURE ANALYSE (VAR CODE_STRUCT: CODE_STRUCT_); VAR SHADOW_LIST: SHADOW_LIST_; LIST_HEAD: SHADOW_PTR_; STRING132: STRING132_; LAST_SHADOW: SHADOW_PTR_; STUB: STB_PTR_; LOCATED: BOOLEAN; SHADOW_STUB: SHADOW_PTR_; CANDIDATE_TWIN: STB_PTR_; SLOT: SLT_PTR_; STUB_REF: STB_PTR_; DUMMY_LINE: LINE_DES_; BEGIN (********************* ANALYSE body ****************************) LIST_HEAD := NIL; (************************* ANALYSE (1) *************************) (** Build SHADOW_LIST from the stub chain of CODE_STRUCT. Make **) (** first element of SHADOW_LIST accessible by LIST_HEAD **) STUB := CODE_STRUCT.FIRST_STUB; IF STUB <> NIL THEN BEGIN NEW (LIST_HEAD); LAST_SHADOW := LIST_HEAD; LAST_SHADOW^.NEXT := NIL; LAST_SHADOW^.STUB_POINTER := STUB; STUB := STUB^.NEXT_STUB; WHILE STUB <> NIL DO BEGIN (********************* ANALYSE (1.1) ***********************) (** Check if STUB^.NAME is already linked in SHADOW_LIST. **) (** If not, make a new entry for this stub in SHADOW_LIST **) (** and update LAST_SHADOW. **) IF SP_IS_EMPTY_STR (STUB^.NAME) THEN LOCATED := FALSE ELSE BEGIN SHADOW_STUB := LIST_HEAD; LOCATED := FALSE; WHILE (NOT LOCATED) AND (SHADOW_STUB <> NIL) DO BEGIN IF SP_EQ (SHADOW_STUB^.STUB_POINTER^.NAME, STUB^.NAME) THEN LOCATED := TRUE; SHADOW_STUB := SHADOW_STUB^.NEXT; END (*WHILE*); END (*IF*); IF NOT LOCATED THEN BEGIN NEW (LAST_SHADOW^.NEXT); LAST_SHADOW := LAST_SHADOW^.NEXT; LAST_SHADOW^.STUB_POINTER := STUB; LAST_SHADOW^.NEXT := NIL; END (*IF*); (***************** End of ANALYSE (1.1) ********************) STUB := STUB^.NEXT_STUB; END (*WHILE*); END (*IF*); (************************* End of ANALYSE (1) **********************) IF LIST_HEAD <> NIL THEN BEGIN (************************ ANALYSE (2) **********************) (** Link stubs with identical names into a twin stub chain **) (** using NEXT_TWIN of the stub descriptor. Start each twin **) (** stub chain with the stub accessible by SHADOW_LIST. **) SHADOW_STUB := LIST_HEAD; WHILE SHADOW_STUB <> NIL DO BEGIN STUB := SHADOW_STUB^.STUB_POINTER; IF NOT SP_IS_EMPTY_STR(STUB^.NAME) THEN WHILE STUB <> NIL DO BEGIN (***************** ANALYSE (2.1) *******************) (** Read through the list of stubs starting with **) (** STUB and set STUB^.NEXT_TWIN if a stub with **) (** the same name as STUB^.NAME found. Let **) (** CANDIDATE_TWIN refer to this stub. **) LOCATED := FALSE; CANDIDATE_TWIN := STUB^.NEXT_STUB; WHILE (CANDIDATE_TWIN <> NIL) AND (NOT LOCATED) DO BEGIN IF SP_EQ (STUB^.NAME, CANDIDATE_TWIN^.NAME) THEN BEGIN LOCATED := TRUE; STUB^.NEXT_TWIN := CANDIDATE_TWIN; END ELSE CANDIDATE_TWIN := CANDIDATE_TWIN^.NEXT_STUB; END (*WHILE*); (************* End of ANALYSE (2.1) ****************) STUB := CANDIDATE_TWIN; END (*WHILE*); SHADOW_STUB := SHADOW_STUB^.NEXT; END (*WHILE*); (********************* End of ANALYSE (2) ******************) (********************* ANALYSE (3) *************************) (** Reorder the twin stub chain by using the options of **) (** the stub. SHADOW_LIST.STUB_POINTER must always refer to **) (** the first stub of the twin stub chain. **) ORDER_TWINS (SHADOW_LIST, CODE_STRUCT, LIST_HEAD); (***************** End of ANALYSE (3) **********************) (********************* ANALYSE (4) *************************) (** Update the field STUB_REF of the slots in the structure **) (** by searching a stub with the same name as the slot in **) (** the structure. Use SHADOW_LIST to access the stubs. **) (** Check if the option SLOT^.OPTIONS.MULTIPLE is used **) (** correctly. Use SLOT^.SRC_IMG for diagnostics. **) STUB := CODE_STRUCT.FIRST_STUB; WHILE STUB <> NIL DO BEGIN SLOT := STUB^.SLOTS; WHILE SLOT <> NIL DO BEGIN (***************** ANALYSE (4.1) *******************) (** Use SHADOW_LIST to search a stub with the same **) (** name as SLOT^.NAME and update SLOT^.STUB_REF if **) (** such a stub is found. SLOT^.SRC_IMG serves for **) (** a diagnostic if multiple stubs are used in a **) (** slot without the MULTIPLE-option **) LOCATED := FALSE; SHADOW_STUB := LIST_HEAD; WHILE (SHADOW_STUB <> NIL) AND (NOT LOCATED) AND (NOT SP_IS_EMPTY_STR(SLOT^.NAME)) DO BEGIN STUB_REF := SHADOW_STUB^.STUB_POINTER; IF SP_EQ (STUB_REF^.NAME, SLOT^.NAME) THEN BEGIN LOCATED := TRUE; SLOT^.STUB_REF := STUB_REF; IF NOT SLOT^.OPTIONS.MULTIPLE THEN BEGIN IF STUB_REF^.NEXT_TWIN <> NIL THEN BEGIN STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; FT_INIT_LINE (DUMMY_LINE); DIAG (ERR, 'ANALYSE (4.1) ', DUMMY_LINE, SLOT^.SRC_IMG, STRING132); SLOT^.OPTIONS.MULTIPLE := TRUE; END (*IF*); END (*IF*); END ELSE SHADOW_STUB := SHADOW_STUB^.NEXT; END (*WHILE*); (************* End of ANALYSE (4.1) ****************) SLOT := SLOT^.NEXT_SLOT; END (*WHILE*); STUB := STUB^.NEXT_STUB; END (*WHILE*); (********************* End of ANALYSE (4) ******************) (********************* ANALYSE (5) *************************) (** Check the resulting structure of CODE_STRUCT for **) (** circularity. If circularity is detected, break the **) (** responsible chain and generate a diagnostic. **) CHECK_CIRC (CODE_STRUCT, LIST_HEAD); (********************* End of ANALYSE (5) ******************) END (*IF*) (********************* End of ANALYSE body *********************) END (*PROCEDURE ANALYSE*); (*********************************************************************) (* Routine: GENMOD - MODule GENeration phase *) (* Purpose: Generation of modules out of CODE_STRUCT. *) (* Interface: CODE_STRUCT - Representation of the stub and slot *) (* structure. *) (* RUN_INFO: User's information for this run. *) (*********************************************************************) PROCEDURE GENMOD (CODE_STRUCT: CODE_STRUCT_; RUN_INFO: RUN_INFO_); VAR STB_PTR: STB_PTR_; CONTINUE: BOOLEAN; LOCATED: BOOLEAN; OUT_FILE: TEXT; NR_OPEN_SLOTS, NR_LINES, CORRECTION, INDENT: INTEGER; AUX_STRING_132 : STRING_FIXED_; AUX_STRING_9 : PACKED ARRAY[1..9] OF CHAR; EXTRACTED: BOOLEAN; CH1, CH2: CHAR; I: INTEGER; MODULE_NR: INTEGER; ERROR_CODE: ERROR_CODE_; X: INTEGER; TEMP_FILE_SPEC: STRING132_; REAL_FILE_SPEC: FILE_SPEC_; DUMMY_LINE: LINE_DES_; STRING132: STRING132_; (************************* GENMOD routines *************************) (*********************************************************************) (* Procedure: BUILDER - BUILDER of module. *) (* Purpose: Build one single module. *) (* Interface: STUB - Pointer to the starting point of the *) (* structure. *) (* OUT_FILE - File to accept the generated code. *) (* NR_OPEN_SLOTS - Number of open slots when ready. *) (* NR_LINES - Number of generated code lines. *) (* INDENT - Current indentation level. *) (* CORRECTION - Correction value for indentation. *) (*********************************************************************) PROCEDURE BUILDER (STUB: STB_PTR_; VAR OUT_FILE: TEXT; VAR NR_OPEN_SLOTS: INTEGER; VAR NR_LINES: INTEGER; VAR INDENT: INTEGER; VAR CORRECTION: INTEGER); VAR PREV_INDENT: INTEGER; TWIN_STUB: STB_PTR_; SLOT: SLT_PTR_; FIRST, LAST: INTEGER; INFO_LINE: LINE_DES_; SEG_LENGTH: INTEGER; STRING132: STRING132_; FILE_SPEC: FILE_SPEC_; K: INTEGER; DUMMY_FILE: VARYING [80] OF CHAR; DUMMY: VARYING [132] OF CHAR; BEGIN (********************* BUILDER (body) **************************) WITH STUB^ DO BEGIN CORRECTION := ST_GET_INDENT (STUB^.SRC_IMG); INDENT := INDENT-CORRECTION; IF STUB^.OPTIONS.LINENUMBER THEN BEGIN (************************* BUILDER (1) *********************) (** Use INDENT to write file specification and line number **) (** of the source file from which STUB^.SRC_IMG is extrac- **) (** ted to OUT_FILE. **) ST_GET_SEG_RANGE (STUB^.SRC_IMG, FIRST, LAST); ST_GET_FILE_SPEC (STUB^.SRC_IMG, FILE_SPEC); FT_INIT_LINE (INFO_LINE); INFO_LINE.INDENT := ST_GET_INDENT (STUB^.SRC_IMG); (* !!! *) DUMMY_FILE := ''; FOR K := 1 TO FILE_SPEC.LENGTH DO DUMMY_FILE := DUMMY_FILE + FILE_SPEC.BODY[K]; DUMMY := ''; WRITE (DUMMY, '(** Line: ', FIRST:1, ' File: ', DUMMY_FILE); (* ISO vreemd *) SEG_LENGTH := ST_SEG_WIDTH (STUB^.SRC_IMG); FOR K := LENGTH(DUMMY) TO (SEG_LENGTH - 4) DO DUMMY := DUMMY + ' '; DUMMY := DUMMY + '**)'; FOR K := 1 TO LENGTH(DUMMY) DO INFO_LINE.CHARS[K] := DUMMY[K]; (* !!! *) INFO_LINE.USED := LENGTH(DUMMY); (* !!! *) SP_EXTR_STR (STUB^.OPTIONS.INDENT, STRING132); IF (STRING132.BODY[1] = 'O') AND (STRING132.BODY[2] = 'N') THEN FT_WRLN (INFO_LINE, INDENT,1) ELSE FT_WRLN (INFO_LINE, 0, 1); (********************* End of BUILDER (1) ******************) NR_LINES := NR_LINES+1; END (*IF*); (************************* BUILDER (2) *************************) (** Use OPTIONS.COMMENT to decide if STUB^.SRC_IMG needs to be **) (** written to OUT_FILE. If so, then increase NR_LINES accor- **) (** dingly and use INDENT to position the segment. **) SP_EXTR_STR (STUB^.OPTIONS.COMMENT, STRING132); IF (STRING132.BODY[1] = 'O') AND (STRING132.BODY[2] = 'N') THEN BEGIN SP_EXTR_STR (STUB^.OPTIONS.INDENT, STRING132); IF (STRING132.BODY[1] = 'O') AND (STRING132.BODY[2] = 'N') THEN ST_WRITE_SEG (STUB^.SRC_IMG,INDENT,1) ELSE ST_WRITE_SEG (STUB^.SRC_IMG,0,1); NR_LINES := NR_LINES + ST_NUMBER_OF_LINES (STUB^.SRC_IMG); END (*IF*); (********************* End of BUILDER (2) **********************) SLOT := STUB^.SLOTS; WHILE SLOT <> NIL DO BEGIN (************************* BUILDER (3) *********************) (** SLOT inherits the options INDENT and COMMENT from STUB **) (** when they are not redefined. SLOT also inherits STUB^.- **) (** OPTIONS.LINENUMBER. **) IF SP_IS_EMPTY_STR (SLOT^.OPTIONS.INDENT) THEN SLOT^.OPTIONS.INDENT := STUB^.OPTIONS.INDENT; IF SP_IS_EMPTY_STR (SLOT^.OPTIONS.COMMENT) THEN SLOT^.OPTIONS.COMMENT := STUB^.OPTIONS.COMMENT; SLOT^.OPTIONS.LINENUMBER := STUB^.OPTIONS.LINENUMBER; (********************* End of BUILDER (3) ******************) IF SLOT^.STUB_REF = NIL THEN BEGIN (********************* BUILDER (4) *********************) (** SLOT has no reference to a stub. Write segments **) (** SLOT^.SRC_IMG and SLOT^.CODE to OUT_FILE using **) (** COMMENT and INDENT. Update NR_LINES accodingly. **) WITH SLOT^ DO BEGIN SP_EXTR_STR (STUB^.OPTIONS.COMMENT, STRING132); IF (STRING132.BODY[1] = 'O') AND (STRING132.BODY[2] = 'N') THEN BEGIN SP_EXTR_STR (SLOT^.OPTIONS.INDENT, STRING132); IF (STRING132.BODY[1] = 'O') AND (STRING132.BODY[2] = 'N') THEN ST_WRITE_SEG (SLOT^.SRC_IMG,INDENT,1) ELSE ST_WRITE_SEG (SLOT^.SRC_IMG, 0, 1); NR_LINES := NR_LINES + ST_NUMBER_OF_LINES (SLOT^.SRC_IMG); END (*IF*); SP_EXTR_STR (SLOT^.OPTIONS.INDENT, STRING132); IF (STRING132.BODY[1] = 'O') AND (STRING132.BODY[2] = 'N') THEN ST_WRITE_SEG (CODE,INDENT,1) ELSE ST_WRITE_SEG (CODE, 0, 1); NR_LINES := NR_LINES + ST_NUMBER_OF_LINES (SLOT^.CODE); END(*WITH*); (***************** End of BUILDER (4) ******************) IF (SLOT^.NEXT_SLOT <> NIL) AND (NOT SP_IS_EMPTY_STR(SLOT^.NAME)) AND (NOT SLOT^.OPTIONS.OPTIONAL) THEN BEGIN IF NR_OPEN_SLOTS = 0 THEN BEGIN WRITELN ('The following open slots are found:'); WRITELN; IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE, 'The following open slots are found:'); WRITELN (REPORT_FILE); END (*IF*); END (*IF*); (* Write slot to terminal and to output file. *) ST_WRITE_SEG (SLOT^.SRC_IMG, INDENT, 0); WRITELN; IF REPORT_OK THEN BEGIN ST_WRITE_SEG (SLOT^.SRC_IMG, INDENT, 3); WRITELN (REPORT_FILE); END (*IF*); NR_OPEN_SLOTS := NR_OPEN_SLOTS+1; END (*IF*); END ELSE BEGIN (********************* BUILDER (5) *********************) (** SLOT^.STUB_REF inherits the options INDENT and **) (** COMMENT from SLOT if they are not redefined by **) (** SLOT^.STUB_REF. SLOT^.STUB_REF also inherits **) (** LINENUMBER from SLOT. **) IF SP_IS_EMPTY_STR (SLOT^.STUB_REF^.OPTIONS.INDENT) THEN SLOT^.STUB_REF^.OPTIONS.INDENT := SLOT^.OPTIONS.INDENT; IF SP_IS_EMPTY_STR (SLOT^.STUB_REF^.OPTIONS.COMMENT) THEN SLOT^.STUB_REF^.OPTIONS.COMMENT := SLOT^.OPTIONS.COMMENT; SLOT^.STUB_REF^.OPTIONS.LINENUMBER := SLOT^.OPTIONS.LINENUMBER; (***************** End of BUILDER (5) ******************) PREV_INDENT := INDENT; INDENT := INDENT + ST_GET_INDENT (SLOT^.SRC_IMG); BUILDER (SLOT^.STUB_REF, OUT_FILE, NR_OPEN_SLOTS, NR_LINES, INDENT, CORRECTION); TWIN_STUB := SLOT^.STUB_REF^.NEXT_TWIN; WHILE TWIN_STUB <> NIL DO BEGIN (********************* BUILDER (6) *****************) (** TWIN_STUB inherits INDENT and COMMENT from **) (** SLOT when they are not redefined locally. In **) (** addition TWIN_STUB inherits LINENUMBER from **) (** SLOT. **) IF SP_IS_EMPTY_STR (TWIN_STUB^.OPTIONS.INDENT) THEN TWIN_STUB^.OPTIONS.INDENT := SLOT^.OPTIONS.INDENT; IF SP_IS_EMPTY_STR (TWIN_STUB^.OPTIONS.COMMENT) THEN TWIN_STUB^.OPTIONS.COMMENT := SLOT^.OPTIONS.COMMENT; TWIN_STUB^.OPTIONS.LINENUMBER := SLOT^.OPTIONS.LINENUMBER; (***************** End of BUILDER (6) **************) INDENT := ST_GET_INDENT (SLOT^.SRC_IMG); BUILDER (TWIN_STUB, OUT_FILE, NR_OPEN_SLOTS, NR_LINES, INDENT, CORRECTION); TWIN_STUB := TWIN_STUB^.NEXT_TWIN; END (*WHILE*); INDENT := PREV_INDENT; (********************* BUILDER (7) *********************) (** Write the segment SLOT^.CODE to OUT_FILE using the **) (** option SLOT^.INDENT. **) SP_EXTR_STR (SLOT^.OPTIONS.INDENT, STRING132); IF (STRING132.BODY[1] = 'O') AND (STRING132.BODY[2] = 'F') AND (STRING132.BODY[3] = 'F') THEN ST_WRITE_SEG (SLOT^.CODE, 0, 1) ELSE ST_WRITE_SEG (SLOT^.CODE,INDENT,1); (***************** End of BUILDER (7) ******************) NR_LINES := NR_LINES + ST_NUMBER_OF_LINES (SLOT^.CODE); END (*IF*); SLOT := SLOT^.NEXT_SLOT; END (*WHILE*); END (*WITH*); (********************* End of BUILDER (body) *******************) END (*PROCEDURE BUILDER*); (********************* End of GENMOD routines **********************) BEGIN (********************* GENMOD (body) ***************************) AUX_STRING_9 := 'EXTRACTED'; AUX_STRING_132 := EMPTY_STRING_FIXED; FOR I:= 1 TO 9 DO AUX_STRING_132[I] := AUX_STRING_9[I]; IF (RUN_INFO.EXTR_MODE <> AUX_STRING_132) THEN EXTRACTED := FALSE ELSE EXTRACTED := TRUE; STB_PTR := CODE_STRUCT.FIRST_STUB; WHILE STB_PTR <> NIL DO BEGIN LOCATED := FALSE; WHILE (STB_PTR <> NIL) AND (NOT LOCATED) DO BEGIN (************************* GENMOD (1) **********************) (** If STB_PTR refers to a main stub then use RUN_INFO to **) (** check if the module is desired by the user. Raise **) (** LOCATED if this happens to be the case. **) WITH STB_PTR^ DO BEGIN IF NOT SP_IS_EMPTY_STR (OPTIONS.FILE_NAME) THEN BEGIN (********************* GENMOD (1.1) ************************) (** Use RUN_INFO to check if OPTIONS.FILE_NAME indicates a **) (** module that is wanted by the user. Raise LOCATED if **) (** this is the case. Default the options COMMENT and **) (** INDENT it they have not been set explictely. **) WITH RUN_INFO DO BEGIN CH1 := 'O'; CH2 := 'N'; IF SP_IS_EMPTY_STR (OPTIONS.INDENT) THEN BEGIN SP_ADD_CHAR (CH1,OPTIONS.INDENT); SP_ADD_CHAR (CH2,OPTIONS.INDENT); END (*IF*); IF SP_IS_EMPTY_STR (OPTIONS.COMMENT) THEN BEGIN SP_ADD_CHAR (CH1,OPTIONS.COMMENT); SP_ADD_CHAR (CH2,OPTIONS.COMMENT); END (*IF*); SP_EXTR_STR (STB_PTR^.OPTIONS.FILE_NAME, TEMP_FILE_SPEC); LOCATED := FALSE; FOR X := 1 TO RUN_INFO.NR_MODULES DO BEGIN IF TEMP_FILE_SPEC.BODY= RUN_INFO.RSLT_MODULES[X].FILE_NAME.BODY THEN BEGIN LOCATED := TRUE; MODULE_NR := X; END (*IF*); END (*FOR*); (* Use the value of EXTRACTED to decide *) (* whether the module is wanted or not. *) IF EXTRACTED = FALSE THEN LOCATED := NOT LOCATED; END (*WITH*); (***************** End of GENMOD (1.1) *********************) END (*IF*); END (*WITH*); (********************* End of GENMOD (1) *******************) IF NOT LOCATED THEN STB_PTR := STB_PTR^.NEXT_STUB; END (*WHILE*); IF LOCATED THEN BEGIN CONTINUE := TRUE; (************************* GENMOD (2) **********************) (** Open OUT_FILE with a name specified by this main stub. **) (** Set CONTINUE to FALSE if there is a problem. STB_PTR^.- **) (** OPTIONS.FILE_NAME caused the problem and displayed as **) (** part of an error message. **) SP_EXTR_STR (STB_PTR^.OPTIONS.FILE_NAME, TEMP_FILE_SPEC); (* The type of TEMP_FILE_SPEC is not suitable for the File Table *) (* routine which opens files. It is converted to a REAL_FILE_SPEC. *) REAL_FILE_SPEC.BODY := EMPTY_STRING_FIXED; REAL_FILE_SPEC.LENGTH := 0; IF EXTRACTED THEN BEGIN FOR I:= 1 TO RUN_INFO.RSLT_MODULES[MODULE_NR].PATH.LENGTH DO REAL_FILE_SPEC.BODY[I] := RUN_INFO.RSLT_MODULES[MODULE_NR].PATH.BODY[I]; REAL_FILE_SPEC.LENGTH := RUN_INFO.RSLT_MODULES[MODULE_NR].PATH.LENGTH; END ELSE BEGIN FOR I:= 1 TO RUN_INFO.MODULE_DIRECTORY.LENGTH DO REAL_FILE_SPEC.BODY[I] := RUN_INFO.MODULE_DIRECTORY.BODY[I]; REAL_FILE_SPEC.LENGTH := RUN_INFO.MODULE_DIRECTORY.LENGTH; END; (*IF*) X := REAL_FILE_SPEC.LENGTH; I := 1; WHILE I <= TEMP_FILE_SPEC.LENGTH DO BEGIN X:=X+1; REAL_FILE_SPEC.BODY[X] := TEMP_FILE_SPEC.BODY[I]; I:=I+1; END (*WHILE*); REAL_FILE_SPEC.LENGTH := X; ERROR_CODE := FT_OUTOPEN (REAL_FILE_SPEC); IF ERROR_CODE > 0 THEN BEGIN CONTINUE := FALSE; (********************* GENMOD (2.1) ****************************) (** Use STB_PTR^.OPTIONS.FILE_NAME and the returned ERROR_CODE **) (** to generate an error message. **) FT_INIT_LINE (DUMMY_LINE); SP_EXTR_STR (STB_PTR^.OPTIONS.FILE_NAME, STRING132); DIAG (ERR, 'GENMOD (2.1) ', DUMMY_LINE, STB_PTR^.SRC_IMG, STRING132); (********************* End of GENMOD (2.1) *********************) END (*IF*); (********************* End of GENMOD (2) *******************) IF CONTINUE THEN BEGIN NR_OPEN_SLOTS := 0; NR_LINES := 0; (********************* GENMOD (3) **********************) (** Generate the module indicated by STB_PTR into **) (** OUT_FILE. NR_OPEN_SLOTS and NR_LINES are maintained **) (** as statistical data. **) WRITE ('Generating file: '); FOR X := 1 TO REAL_FILE_SPEC.LENGTH DO WRITE (REAL_FILE_SPEC.BODY[X]); WRITELN; IF REPORT_OK THEN BEGIN WRITE (REPORT_FILE, 'Generating file: '); FOR X := 1 TO REAL_FILE_SPEC.LENGTH DO WRITE (REPORT_FILE, REAL_FILE_SPEC.BODY[X]); WRITELN (REPORT_FILE); END (*IF*); INDENT := ST_GET_INDENT (STB_PTR^.SRC_IMG); CORRECTION := 0; NR_LINES := 0; NR_OPEN_SLOTS := 0; BUILDER (STB_PTR, OUT_FILE, NR_OPEN_SLOTS, NR_LINES, INDENT, CORRECTION); (******************* End of GENMOD (3) *****************) WRITELN ('Number of open slots in this module: ', NR_OPEN_SLOTS:1); WRITELN ('Number of generated lines: ',NR_LINES:1); WRITELN ('------------------------------------', '------------------------------------'); WRITELN; IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE, 'Number of open slots', ' in this module: ', NR_OPEN_SLOTS:1); WRITELN (REPORT_FILE, 'Number of generated lines: ' ,NR_LINES:1); WRITELN (REPORT_FILE, '------------------------------------', '------------------------------------'); WRITELN (REPORT_FILE); END (*IF*); (********************* GENMOD (4) **********************) (** Close OUT_FILE. Generate an error message in case **) (** of trouble. **) ERROR_CODE := FT_OUTCLOSE; IF ERROR_CODE <> 0 THEN BEGIN (************************* GENMOD (4.1) ************************) (** Use STB_PTR^.OPTIONS.FILE_NAME and STB_PTR^.SRC_IMG to **) (** generate a diagnostic message. **) FT_INIT_LINE (DUMMY_LINE); SP_EXTR_STR (STB_PTR^.OPTIONS.FILE_NAME, STRING132); DIAG (ERR, 'GENMOD (4.1) ', DUMMY_LINE, STB_PTR^.SRC_IMG, STRING132); (********************* End of GENMOD (4.1) *********************) END(*IF*); (***************** End of GENMOD (4) *******************) END (*IF*); STB_PTR := STB_PTR^.NEXT_STUB; END (*IF*); END (*WHILE*); (********************* End of GENMOD (body) ********************) END (*GENMOD*); BEGIN (******* CLIP_2 (body) *******) CONTINUE := TRUE; (***************************** CLIP_2 (1) **************************) (** Read the contents of CLIP.INI into RUN_INFO. Set CONTINUE to **) (** FALSE in case of trouble. **) EXT_FILE_SPEC.BODY := EMPTY_STRING_FIXED; AUX_STRING_8 := DFLT_INIFILE; FOR I := 1 TO 8 DO EXT_FILE_SPEC.BODY[I] := AUX_STRING_8[I]; EXT_FILE_SPEC.LENGTH := 8; EXT_FILE_PREP (INI_FILE, EXT_FILE_SPEC, INSP_MODE, DUMMY_FILE_OK, ERROR_CODE, DUMMY_ERROR_MSG); IF ERROR_CODE > 0 THEN BEGIN WRITELN ('The initializationfile could not be read succesfully.'); CONTINUE := FALSE; END ELSE BEGIN (* EWvA: 16/10/93 *) EXT_FILE_CLOSE (INI_FILE, DUMMY_ERROR_CODE); (* EWvA: 16/10/93 *) READ_INI_FILE (INI_FILE, RUN_INFO, EXT_FILE_SPEC, DUMMY_FILE_OK, DUMMY_ERROR_MSG, DUMMY_ERROR_CODE); END (* IF *); (* EWvA: 16/10/93 *) (************************* End of CLIP_2 (1) ***********************) IF CONTINUE THEN BEGIN (************************* CLIP_2 (2) **************************) (** Initialize CODE_STRUCT and the hidden variables of FT, ST, **) (** SP, SCN_LINE, SCN_OPTS and DIAG_TBL. **) FT_INIT; ST_INIT; SP_INIT; SCN_LINE_INIT; SCN_OPTS_INIT; DIAGNOST_INIT; CODE_STRUCT.LAST_STUB := NIL; CODE_STRUCT.FIRST_STUB := NIL; (********************* End of CLIP_2 (2) ***********************) (************************* CLIP_2 (3) **************************) (** Prepare a REPORT_FILE file from RUN_INFO.REPORT_FILE_SPEC **) (** and raise REPORT_OK if this succeeded. **) (* Modified by EWvA on 16/10/93 *) IF (RUN_INFO.REPORT_FILE_SPEC.BODY <> EMPTY_STRING_FIXED) AND (RUN_INFO.MESSAGE_DESTINATION[1] IN ['R','r','F','f','B','b']) (* End of modification dd. 16/10/93 *) THEN BEGIN EXT_FILE_PREP (REPORT_FILE, RUN_INFO.REPORT_FILE_SPEC, GEN_MODE, REPORT_OK, ERROR_CODE, ERROR_MSG); IF ERROR_CODE <> 0 THEN BEGIN WRITELN (OUTPUT, ERROR_MSG); WRITELN (OUTPUT, 'Continue without report file...'); WRITELN; REPORT_OK := FALSE; END ELSE REPORT_OK := TRUE; END ELSE (* EWvA: 16/10/93 *) REPORT_OK := FALSE; (* EWvA: 16/10/93 *) (***************** End of DIAGNOST_EXIT (2) ********************) START := CLOCK; STOP := START; (************************* CLIP_2 (4) **************************) (** Scan the source files as specified in RUN_INFO and build **) (** the structure of stubs and slots CODE_STRUCT. LPT_FILE_OK **) (** decides if info for the terminal is copied to REPORT_FILE. **) WRITELN; WRITELN ('============================ ', CLIP_VERSION, ' =========================='); WRITELN; WRITELN ('============================ Busy scanning ', '============================='); IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, '============================ ', CLIP_VERSION, ' =========================='); WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, '============================ Busy scanning ', '============================='); END (*IF*); SCAN_FILES (CODE_STRUCT, RUN_INFO); WRITELN ('============================ End scanning ', '=============================='); WRITELN; IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, '============================ End scanning ', '=============================='); END (*IF*); (********************* End of CLIP_2 (4) **********************) IF CODE_STRUCT.FIRST_STUB <> NIL THEN BEGIN (************************* CLIP_2 (5) **********************) (** Analyse CODE_STRUCT. LPT_FILE_OK decides if info to the **) (** terminal is copied to REPORT_FILE also. **) WRITELN ('============================ Busy analysing ', '============================'); IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, '============================ Busy analysing ', '============================'); END (*IF*); ANALYSE (CODE_STRUCT); WRITELN ('============================ End analysing ', '============================='); WRITELN; IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, '============================ End analysing ', '============================='); END (*IF*); (********************* End of CLIP_2 (5) *******************) (************************* CLIP_2 (6) **********************) (** Generate the modules as specified in RUN_INFO out of **) (** CODE_STRUCT. LPT_FILE_OK decides if info for terminal **) (** is also copied to REPORT_FILE. **) WRITELN ('============================ Busy generating ', '==========================='); IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, '============================ Busy generating ', '==========================='); END (*IF*); GENMOD (CODE_STRUCT, RUN_INFO); WRITELN ('============================ End generating ', '============================'); WRITELN; IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE); WRITELN (REPORT_FILE, '============================ End generating ', '============================'); END (*IF*); (********************* End of CLIP_2 (6) *******************) STOP := CLOCK; END (*IF*); (*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++ EWvA, jan6, 1993: Report file ++++++++++++ FT_INIT_LINE (DUMMY_LINE); ST_INIT_SEG (DUMMY_SEG); STRING132.LENGTH := 0; STRING132.BODY := EMPTY_STRING_FIXED; DIAG (WARN, 'CLIP_2 ', DUMMY_LINE, DUMMY_SEG, STRING132); ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*) (* Generate error messages to terminal and possibly report file *) DIAGNOST_EXIT; (* Delete the segment-table. *) ST_FINIT; (* Display a goodbye message. *) WRITELN ('Used (CPU) time :', (STOP-START)/1000:4:2, ' Sec.'); WRITELN ('See you next time !'); IF REPORT_OK THEN BEGIN WRITELN (REPORT_FILE, 'Used (CPU) time :', (STOP-START)/1000:4:2, ' Sec.'); WRITELN (REPORT_FILE, 'See you next time !'); EXT_FILE_CLOSE (REPORT_FILE, DUMMY_ERROR); END (*FI*); END (*IF*); (********************* End of CLIP_2 (body) ********************) END (*CLIP_2*). (******************* End of module clip_unix.pas *******************)