Google
 

Trailing-Edge - PDP-10 Archives - tops20-v7-ft-dist1-clock - 7-sources/diupar.bli
There are 4 other files named diupar.bli in the archive. Click here to see a list.
MODULE DIUPAR (ident = '253'
               %REQUIRE ('DIUPATSWITCH')
		) =
BEGIN

!++
!	COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1986.
!	ALL RIGHTS RESERVED.
!
!	THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED  AND
!	COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH
!	THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.   THIS  SOFTWARE  OR
!	ANY  OTHER  COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE
!	AVAILABLE TO ANY OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE
!	SOFTWARE IS HEREBY TRANSFERRED.
!
!	THE INFORMATION IN THIS SOFTWARE IS  SUBJECT  TO  CHANGE  WITHOUT
!	NOTICE  AND  SHOULD  NOT  BE CONSTRUED AS A COMMITMENT BY DIGITAL
!	EQUIPMENT CORPORATION.
!
!	DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF
!	ITS SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
!
! FACILITY:	PAT Parser
!
! ABSTRACT:
!
! 	PATPARSER.BLI is the parser.
!
! ENVIRONMENT:	VAX/VMS user mode
!
! AUTHORS:  C. Mitchell, H. Alcabes, CREATION DATE:  25-Feb-80
!
! ACKNOWLEDGEMENT: The local error recovery algorithm used in this module
!	is based in part on an algorithm developed by Dr. Gerald Fisher as part
!	of the Ada project at the Courant Institute at New York Univerisity.
!
! MODIFIED BY:
!
!	Charlie Mitchell, 02-Nov-1981 : VERSION x2-001
! 001 -	Final packaging and modification to use PATDATA.
! 002 - (11/83) Fix bug that gave bad "when expecting" symbols in
!	global error recovery message.  Minor mod to eliminate
!	warning from BLISS V4.
! 003 - (12/83) Add BASIC bug fix.  Reset LATEST_TOKEN_PTR after
!	global error recovery.
! 004 - Remove VMS dependencies.  C. Richardson 29-May-84
!
!  253  Rename file to DIUPAR.
!       Gregory A. Scott 1-Jul-86
!
!--
!
! INCLUDE FILES:
!

require 'DIUPATPROLOG';

library 'BLI:XPORT';

library 'DIUPATPARSER';

library 'DIUPATDATA';                   ! DIUPAT interface

library 'DIUPATLANGSP';                 ! Language Specific functions

library 'DIUPATERROR';                  ! Error recovery

library 'DIUPATTOKEN';

library 'DIUPATLRTUNE';

library 'DIUDEB';                       ! Debugging

library 'DIUPATDEB';                    ! Parser debugging
!
! TABLE OF CONTENTS OF INTERNAL ROUTINES:
!

forward routine
    ERROR_RECOVERY : novalue,			! Main error recovery driver
    PARSE;					! PAT parser

%if PATBLSEXT_LOCAL_RECOVERY
%then

forward routine
    DOWN_CASE : novalue,			! Convert string to lowercase
    FIND_BACKUP_ORDER,				! Determine order of corrections
    LOCAL_RECOVERY,				! Local/scope recovery driver
    MERGE_TOKENS,				! What do tokens merge to
    NEVER_INSERT_BEFORE,			! When not to insert a token
    PARSE_AHEAD,				! Try parsing ahead
    PARSE_AHEAD_INIT : novalue,			! Initialize for parse ahead
    RESTORE_STATE : novalue,			! Restore parse state
    SAVE_STATE : novalue,			! Save parse state
    SCOPE_RECOVERY,				! Try insertions to close scope
    STRONG_LOCAL_RECOVERY,			! Strong local error recovery
    SYNTHESIZE_TOKEN,				! Create synthetic token
    TRY_CORRECT_SPELLING,			! Try correcting spelling
    TRY_DELETE,					! Try deleting a token
    TRY_EOL_CORRECTION,				! End Of Line correction
    TRY_INSERT,					! Try inserting a token
    TRY_MERGE,					! Try merging tokens
    TRY_SUBSTITUTE,				! Try substituting new token
    WEAK_LOCAL_RECOVERY;			! Weak local error recovery

%fi
! MACROS:

macro
    CLEAR (START, BYTES) =
!	ZEROBYTE (BYTES, START) %;
	begin
	    incr counter from 0 to (bytes-1) do start [.counter] = 0
	end %;

macro
    BLOCK_COPY (SRC, DST, BYTES) =
	begin

	bind
	    SBV = SRC : bitvector [],					! [004]
	    DBV = DST : bitvector [];					! [004]

	incr OFFSET from 0 to (BYTES - 1) do
	    DBV [.OFFSET] = .SBV [.OFFSET];
	end
    %;

macro
    COUNT (START, BITS) =
	begin

	local
	    TOT;

	TOT = 0;
	incr LOOP_INDEX from 0 to (BITS - 1) do
	    if .START [.LOOP_INDEX] then TOT = .TOT + 1;
	.TOT
	end
    %;

macro
    BLOCK_AND (SRC1, SRC2, DST, BYTES) =
	begin

	bind
	    SBV1 = SRC1 : bitvector [],				! 004
	    SBV2 = SRC2 : bitvector [],				! 004
	    DBV = DST : bitvector [];				! 004

	incr OFFSET from 0 to (BYTES - 1) do
	    DBV [.OFFSET] = .SBV1 [.OFFSET] and .SBV2 [.OFFSET];
	end
    %;

macro
    WHICH_TERM (START, BITS) =
	begin
	incr LOOP_INDEX from 0 to (BITS - 1) do
	    if .START [.LOOP_INDEX] then exitloop .LOOP_INDEX
	end
    %;
macro
    MOVE_TOKEN (SRC, DST) =
	begin

	bind
	    srctok = (src): block [PATSTK_STR_SIZE/%upval]
		field (PATSTK_FIELDS),
	    dsttok = (dst): block [PATSTK_STR_SIZE/%upval]
		field (PATSTK_FIELDS);

	dsttok [PATSTK_LOCATOR]		= .srctok [PATSTK_LOCATOR];
	%if PATBLSEXT_EXTRA_STACK_FIELD
	%then
	dsttok [PATSTK_EXTRA_INFO]	= .srctok [PATSTK_EXTRA_INFO];
	%fi
	dsttok [PATSTK_SYMBOL]		= .srctok [PATSTK_SYMBOL];
	dsttok [PATSTK_TOKEN]		= .srctok [PATSTK_TOKEN];
	dsttok [PATSTK_ERRORMARK]	= .srctok [PATSTK_ERRORMARK];
	dsttok [PATSTK_STATE]		= .srctok [PATSTK_STATE];
	end
%;
! EQUATED SYMBOLS:

literal
!    NUM_BYTES = ((PAT$DATA_NUM_TERM + (%bpval - 1))/%bpval)*%upval,
    NUM_BYTES = PAT$DATA_NUM_TERM,
    NO_MERGE = -1,
    NO_INITIAL_SYMBOL = -4,
    VALUE_TO_BE_IGNORED = -99,
    MAX_NUM_SYN_TOKS = 10;
! OWN STORAGE:

%if PATBLSEXT_LOCAL_RECOVERY
%then

own
    SAVED_PAR_LOOKAHEAD_F,
    SAVED_STACK_PTR,
    SAVED_REDUCTION_CODE,
    LOCAL_ATTEMPT_STATUS,
    SYN_TOK_STORAGE : blockvector [MAX_NUM_SYN_TOKS, LS_TKN_SIZE],
    NEXT_SYN_TOK_INDEX;

%fi

global
    PAT$STACK_P : ref PATSTK_STR;

own
    CURRENT_SYMBOL,
    CURRENT_SYMBOL_IS_TERMINAL,
    PAR_LOOKAHEAD_F,
    STACK_PTR,
    REDUCTION_CODE,
    REF_PARSE_STACK : ref PATSTK_STR,
    PREV_STACK_PTR,
    PREV_STACK_RECORD : block [PATSTK_STR_SIZE/%upval] field (PATSTK_FIELDS),
    PREV_STATUS,
    PREV_WILL_BE_VALID,
    VALID_PREV : initial (FALSE),
    VALID_PREV_PREV : initial (FALSE),
    GLOBAL_MSG_STATUS,
    GLOBAL_MSG_SYMBOL,
    GLOBAL_MSG_INIT_STATE,
    HAVE_INITIAL_SYMBOL,
    INITIAL_SYMBOL,
    LATEST_TOKEN_PTR,
    PRIOR_TOKEN_PTR,
    ORIGINAL_STACK_PTR;

%if PATBLSEXT_LOCAL_RECOVERY
%then

own
    REF_ALT_PARSE_STACK : ref PATSTK_STR,
    PREV_PREV_STACK_PTR,
    PREV_PREV_STACK_RECORD : block [PATSTK_STR_SIZE/%upval] field (PATSTK_FIELDS),
    PREV_PREV_STATUS;

%fi

ENUMERATION ('backup_order', 1, ORDER_A,
    ORDER_B,
    ORDER_BC);

literal
    MAX_BUFFERED_TOKENS = 12;

external routine lex_init: novalue;
global routine PAT$PARSER (STARTING_TOKEN_PTR, ANNOUNCE_ABBREVIATIONS,
	RESULT, SYNTAX_ONLY, file) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	PAT$PARSER is the parser.
!
! FORMAL PARAMETERS:
!
!	STARTING_TOKEN_PTR	- Pointer to initial token; if NULL
!				  then initial token is to be obtained
!				  from the lexical analyzer
!
!	ANNOUNCE_ABBREVIATIONS	- TRUE iff an error message should be
!				  printed when an abbreviation is corrected
!				  during error recovery.
!
!	RESULT			- Address where action routine should place
!				  root of tree
!
!	SYNTAX_ONLY		- TRUE if parse is for syntax only (build no
!				  structures)
!
!	FILE			- Address of an XPORT IOB for the file
!				  containing the input to be parsed.  The file
!				  should already be open, and should be closed
!				  by the caller of PAT$PARSER.
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	TRUE	- A compilation unit was parsed.
!	FALSE	- A compilation unit wasn't parsed.  At end of file.
!
! SIDE EFFECTS:
!
!	PAT$PARSER calls the lexical analyzer which reads the source
!	file.  PAR_ABST is called to build the abstract syntax tree.
!
!--

    begin

    LS_PARSE_STACK_DECL				! Normally expands to local
	PARSE_STACK : PATSTK_STR;		! Normal parse stack

%if PATBLSEXT_LOCAL_RECOVERY
%then
    local
	ALT_PARSE_STACK : PATSTK_STR;		! Alternate parse stack used for local error recovery
%fi

! Initialize the lexical machine to read the input file to be parsed:

    LEX_INIT (.file);

! Initialize own and local variables

    PAR_LOOKAHEAD_F = FALSE;
    PREV_STATUS = SAVED_INFO_NOT_VALID;
    PREV_WILL_BE_VALID = FALSE;
    GLOBAL_MSG_STATUS = SAVED_INFO_NOT_VALID;
    LATEST_TOKEN_PTR = NULL;
    PRIOR_TOKEN_PTR = NULL;
    CURRENT_SYMBOL_IS_TERMINAL = TRUE;
    PAT$TOKEN_INIT_BUFFER ();
    REF_PARSE_STACK = PARSE_STACK;

%if PATBLSEXT_LOCAL_RECOVERY
%then
    PREV_PREV_STATUS = SAVED_INFO_NOT_VALID;
    REF_ALT_PARSE_STACK = ALT_PARSE_STACK;
%fi

    if .STARTING_TOKEN_PTR eql NULL
    then
	begin					! Read in initial token
	PAT$TOKEN_GET (TRUE);
%if PATBLSEXT_DEBUGGING
%then
	PAT$DEB_TOKEN (TRUE);
%fi
	end
    else
	PAT$TOKEN_CURRENT_PTR = .STARTING_TOKEN_PTR;	! Called with initial token

    if ls_lex_term (PAT$TOKEN_CURRENT_PTR) eqlu T_EOF	! Nothing here but EOF
	then return FALSE;
    LATEST_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
    CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);
						! Current symbol comes from the current lexical token
    REDUCTION_CODE = -1;			! Haven't done a reduction
    PAT$STACK_P = PARSE_STACK;			! Point at normal parse stack

%if PATBLSEXT_EXTRA_STACK_FIELD
%then

    incr I from 0 to LS_PARSE_STACK_SIZE - 1 do
	PARSE_STACK [.I, PATSTK_EXTRA_INFO] = 0;	! Clear extra info field

%fi

    STACK_PTR = 0;				! Set parse stack pointer and
    PAT$STACK_P [.STACK_PTR, PATSTK_STATE] = 0;	! stack initial state

%if PATBLSEXT_LOCAL_RECOVERY
%then

! Initialize scope recovery

    SCOPE_RECOVERY (TRUE);
%fi

    while TRUE do
	begin
	if PARSE (.result, .syntax_only)
	then
	    begin
	    DEB_EVENT ('PAR_RECOVERY_INFO',
		PUT_MSG_EOL ('Compilation unit successfully parsed.'),
		PUT_EOL ());
	    return TRUE;			! Have parsed a compilation unit
	    end
	else 					! Invoke parser error recovery
	    ERROR_RECOVERY (.ANNOUNCE_ABBREVIATIONS);
	end

    end;					! Of routine PAT$PARSER
routine PARSE (result, syntax_only) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Does the actual work of parsing.
!
! FORMAL PARAMETERS:
!
!	result		Address where action routine should place root
!			of tree.
!
!	syntax_only	TRUE if parse is for syntax only (build no
!			structures).
!
! IMPLICIT INPUTS:
!
!	PAT$STACK_P
!	STACK_PTR
!	PREV_WILL_BE_VALID
!	CURRENT_SYMBOL
!
! IMPLICIT OUTPUTS:
!
!	Same as inputs.
!
! ROUTINE VALUE:
!
!	Returns TRUE if parsed input until finding the STOP-PARSING non-
!	terminal.  Returns FALSE if a parse error or parse stack overflow.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	R,
	STATUS,
	ACTION_CODE,
	ACTION_ROUTINE_ALLOWS_BACKUP,
	RIGHT_TOKEN_PTR,
	LHS_SYMBOL,
	RHS_COUNT,
	SEMACT,
	NEW_PTR;
    while TRUE do
	begin

%if PATBLSEXT_DEBUGGING
%then
	PAT$DEB_STATE (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE], TRUE);
%fi

! If this is the STOP_PARSING non-terminal, we are done.

	if .CURRENT_SYMBOL eql LS_STOP_PARSING_NT then return TRUE;

! Determine what to do based on the current action:

	ACTION_CODE = PAT$DATA_MOVE_ACTION (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE], .CURRENT_SYMBOL);
	if PAT$DATA_ACTION_IS (.ACTION_CODE, 'ERROR')
	then
	    return FALSE
	else
	    begin

	    if PAT$DATA_ACTION_IS (.ACTION_CODE, 'SHIFT')	! Shift
	    then
		begin

		! Save the symbol that was found on the stack and push the
		! new state on the stack.

		PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL] = .CURRENT_SYMBOL;

		if .CURRENT_SYMBOL_IS_TERMINAL
		then
		    begin
		    STATUS = CONSUME_TERM_ON_SHIFT;
		    PREV_WILL_BE_VALID = TRUE;

%if PATBLSEXT_EXTRA_STACK_FIELD
%then
		    PAT$STACK_P [.STACK_PTR, PATSTK_EXTRA_INFO] = LS_LEX_EXTRA_INFO (PAT$TOKEN_CURRENT_PTR);
%fi

		    PAT$STACK_P [.STACK_PTR, PATSTK_LOCATOR] = LS_LEX_LOCATOR (PAT$TOKEN_CURRENT_PTR);
		    end
		else if not .VALID_PREV
		    then begin
		    move_token (PAT$STACK_P [.STACK_PTR, PATSTK_BASE],
			PREV_STACK_RECORD [PATSTK_BASE]);
		    prev_status = CONSUME_NONTERM_ON_SHIFT;
		    prev_stack_ptr = .stack_ptr;
		    valid_prev = TRUE;
		    prev_will_be_valid = FALSE;
		    end;

		if .STACK_PTR geq (LS_PARSE_STACK_SIZE - 1)
		then
		    begin
		    LS_ERROR_PARSE_STACK_OVERFLOW (LS_LEX_LOCATOR (PAT$TOKEN_CURRENT_PTR));
		    return FALSE
		    end
		else
		    begin
		    STACK_PTR = .STACK_PTR + 1;
		    PAT$STACK_P [.STACK_PTR, PATSTK_STATE] = PAT$DATA_AC_TO_SHIFT_STATE (.ACTION_CODE);
						! Now this is the current state
		    end;

		CURRENT_SYMBOL = PAT$TOKEN_GET_CONSUME;
		if .PAT$TOKEN_CURRENT_PTR neq .LATEST_TOKEN_PTR
		then

		! A token has been read that was not read (for a look
		! ahead reduction) earlier. Keep track of the new token
		! and the one read prior to it for use by local error
		! recovery backup.

		    begin
		    PRIOR_TOKEN_PTR = .LATEST_TOKEN_PTR;
		    LATEST_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
		    end;

%if PATBLSEXT_DEBUGGING
%then
		PAT$DEB_TOKEN (TRUE);
%fi

		CURRENT_SYMBOL_IS_TERMINAL = TRUE;
		end
	    else 				! action is reduce or look-ahead
		begin

		if PAT$DATA_ACTION_IS (.ACTION_CODE, 'LOOK_AHEAD')
		then

		! This is a look ahead reduction.

		    begin

		    if .CURRENT_SYMBOL_IS_TERMINAL
		    then
			begin

%if PATBLSEXT_EXTRA_STACK_FIELD
%then
			PAT$STACK_P [.STACK_PTR, PATSTK_EXTRA_INFO] = 0;
%fi

			PAT$STACK_P [.STACK_PTR, PATSTK_LOCATOR] = LS_LEX_LOCATOR (PAT$TOKEN_CURRENT_PTR);
			end;

		    RIGHT_TOKEN_PTR = .PRIOR_TOKEN_PTR;
		    REDUCTION_CODE = PAT$DATA_AC_TO_LA_PRODUCTION_NO (.ACTION_CODE);
		    PAT$DATA_GET_REDUCTION_INFO (.REDUCTION_CODE, LHS_SYMBOL, RHS_COUNT, SEMACT);
		    PAR_LOOKAHEAD_F = TRUE;
		    PAT$TOKEN_SAVE_PERMANENT (.PAT$TOKEN_CURRENT_PTR);
		    NEW_PTR = .STACK_PTR - .RHS_COUNT;

		    if .RHS_COUNT eql 0 then R = .NEW_PTR else R = .NEW_PTR + .RHS_COUNT - 1;

		    end
		else 				! action is reduce
		    begin
		    PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL] = .CURRENT_SYMBOL;
						! Save the right-most symbol on the rhs

		    if .CURRENT_SYMBOL_IS_TERMINAL
		    then
			begin
			PREV_WILL_BE_VALID = TRUE;
			STATUS = CONSUME_TERM_ON_REDUCTION;

%if PATBLSEXT_EXTRA_STACK_FIELD
%then
			PAT$STACK_P [.STACK_PTR, PATSTK_EXTRA_INFO] = LS_LEX_EXTRA_INFO (PAT$TOKEN_CURRENT_PTR
			);
%fi

			PAT$STACK_P [.STACK_PTR, PATSTK_LOCATOR] = LS_LEX_LOCATOR (PAT$TOKEN_CURRENT_PTR);
			end;

		    RIGHT_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
		    REDUCTION_CODE = PAT$DATA_AC_TO_PRODUCTION_NO (.ACTION_CODE);
		    PAT$DATA_GET_REDUCTION_INFO (.REDUCTION_CODE, LHS_SYMBOL, RHS_COUNT, SEMACT);
		    PAR_LOOKAHEAD_F = FALSE;
		    NEW_PTR = .STACK_PTR - .RHS_COUNT + 1;
		    R = .NEW_PTR + .RHS_COUNT - 1;
		    end;

%if PATBLSEXT_DEBUGGING
%then
		PAT$DEB_REDUCE (.LHS_SYMBOL, .SEMACT, TRUE);
%fi

		if .SEMACT eql PAT$DATA_NULL_SEMACT
		then
		    ACTION_ROUTINE_ALLOWS_BACKUP = (if .RHS_COUNT gtr 1 then LS_REDUCE_NO_ACTION (.NEW_PTR,
			    .R) else TRUE)
		else
		    ACTION_ROUTINE_ALLOWS_BACKUP = LS_REDUCE_ACTION (.SEMACT, .NEW_PTR, .R,
			.PAT$STACK_P [.NEW_PTR, PATSTK_LOCATOR], .RIGHT_TOKEN_PTR);

		CURRENT_SYMBOL = .LHS_SYMBOL;
		REDUCTION_CODE = -1;

		if (.NEW_PTR lss .PREV_STACK_PTR) or ( not .ACTION_ROUTINE_ALLOWS_BACKUP)
		then 				! May not back up past this point
		    begin

		    if .PREV_STATUS neq REDUCT_AFTER_BACKUP_NOT_ALLOWED or
			.STATUS eql CONSUME_TERM_ON_REDUCTION
		    then

		    ! This code saves information to be used (only) for the
		    ! global error message.  It is executed the first time
		    ! a reduction that can not be backed up over occurs
		    ! after a terminal has been consumed.  Its purpose
		    ! is to save enough info so that the list of symbols
		    ! that were expected before the reduction could be
		    ! reconstructed.  If a terminal is actually being
		    ! consumed (as opposed to being seen by look ahead)
		    ! then the state of the parse when it was consumed is
		    ! saved.  Otherwise the state when the last terminal
		    ! was consumed is saved.

			if .CURRENT_SYMBOL_IS_TERMINAL and not .PAR_LOOKAHEAD_F
			then
			    begin
			    GLOBAL_MSG_STATUS = CONSUME_TERM_ON_REDUCTION;
			    GLOBAL_MSG_SYMBOL = .CURRENT_SYMBOL;
			    GLOBAL_MSG_INIT_STATE = .PAT$STACK_P [.STACK_PTR, PATSTK_STATE];
			    end
			else
			    begin
			    GLOBAL_MSG_STATUS = .PREV_STATUS;
			    GLOBAL_MSG_SYMBOL = .PREV_STACK_RECORD [PATSTK_SYMBOL];
			    GLOBAL_MSG_INIT_STATE = .PREV_STACK_RECORD [PATSTK_STATE];
			    end;

		    PREV_WILL_BE_VALID = TRUE;
		    PREV_STATUS = SAVED_INFO_NOT_VALID;
		    STATUS = REDUCT_AFTER_BACKUP_NOT_ALLOWED;
		    end
		else

%if PATBLSEXT_LOCAL_RECOVERY
%then

		    if .NEW_PTR lss .PREV_PREV_STACK_PTR then PREV_PREV_STATUS = SAVED_INFO_NOT_VALID;

%else
		FALSE;
%fi

		STACK_PTR = .NEW_PTR;	! Now the current state is .PAT$STACK_P [.STACK_PTR, PATSTK_STATE]
		PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL] = .CURRENT_SYMBOL;	! The lhs symbol
		CURRENT_SYMBOL_IS_TERMINAL = FALSE;
		if (.stack_ptr lss .prev_stack_ptr) or
		    (not .action_routine_allows_backup)
		    then begin
		    valid_prev = FALSE;
		    valid_prev_prev = FALSE;
		    prev_will_be_valid = FALSE;
		    end
		else
		    if .stack_ptr lss .prev_prev_stack_ptr
			then valid_prev_prev = FALSE;
		end;

	    end;
	if .PREV_WILL_BE_VALID
	then
	    begin

%if PATBLSEXT_LOCAL_RECOVERY
%then
	    PREV_PREV_STATUS = .PREV_STATUS;

	    if .PREV_PREV_STATUS neq SAVED_INFO_NOT_VALID
	    then
		begin
		PREV_PREV_STACK_PTR = .PREV_STACK_PTR;
		move_token (prev_stack_record [PATSTK_BASE],
		    prev_prev_stack_record [PATSTK_BASE]);
		end;
	    valid_prev_prev = .valid_prev;
%fi

	    PREV_STATUS = .STATUS;
	    PREV_STACK_PTR = .STACK_PTR;
	    move_token (pat$stack_p [.stack_ptr, PATSTK_BASE],
		prev_stack_record [PATSTK_BASE]);
	    valid_prev = TRUE;
	    PREV_WILL_BE_VALID = FALSE;
	    end;

	end;

    return FALSE;
    end;					! Of routine PARSE
routine ERROR_RECOVERY (ANNOUNCE_ABBREVIATIONS) : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!	ERROR_RECOVERY causes parser error recovery to occur.
!	It is called when a parse error has been
!	encountered.  It uses information about the state of the parse
!	to recover from the error, but the only data items that may be
!	altered are the token buffer and the stack pointer.
!	One of the macros LS_LOCAL_RECOVERY_INFORM or
!	LS_GLOBAL_RECOVERY_INFORM will be called to make any other
!	adjustments that are required by the recovery.	Thus the parse
!	can be resumed after this routine resumes by reading from the
!	token buffer (which the parser does anyway).
!
! FORMAL PARAMETERS:
!
!	ANNOUNCE_ABBREVIATIONS	- TRUE iff an error message should be printed
!				  when an abbreviation is corrected.
!
! IMPLICIT INPUTS:
!
!	Token buffer
!
!	Stack pointer
!
!	Parse stack
!
!	State information
!
! IMPLICIT OUTPUTS:
!
!	Token buffer
!
!	Stack pointer
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS:
!
!	The token buffer will be altered to correct the error.
!	LS_*_RECOVERY_INFORM may cause other side effects.
!
!--

    begin

    local
	SUCCESS;

    DEB_EVENT ('PAR_RECOVERY_START',
	PUT_MSG_EOL ('Starting parser error recovery')

%if PATBLSEXT_LOCAL_RECOVERY
%then
    ,
	PAT$DUMP_BACKUP_INFO ()
%fi

    );
    LS_SAVE_TOKEN (.PAT$TOKEN_CURRENT_PTR);	! Save the error token
    ORIGINAL_STACK_PTR = .STACK_PTR;

%if PATBLSEXT_LOCAL_RECOVERY
%then
    SUCCESS = LOCAL_RECOVERY (.ANNOUNCE_ABBREVIATIONS);
%else
    SUCCESS = FALSE;
%fi

    if not .SUCCESS
    then
	begin
	PAT$ERROR_GLOBAL_RECOVERY (
	! Input parameters
	    PREV_STACK_RECORD,
	    .PREV_STATUS,
	    .GLOBAL_MSG_STATUS,
	    .GLOBAL_MSG_SYMBOL,
	    .GLOBAL_MSG_INIT_STATE,
	    LS_RETURN_SAVED_TOKEN,
	! Output parameters
	    STACK_PTR, CURRENT_SYMBOL);
	LS_GLOBAL_RECOVERY_INFORM (.STACK_PTR, .ORIGINAL_STACK_PTR);

	!   When global error recovery occurs, reset LATEST_TOKEN_PTR
	!   to the current pointer, since its old value is no
	!   longer valid.

	LATEST_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;

	end;

    PREV_STATUS = SAVED_INFO_NOT_VALID;

%if PATBLSEXT_LOCAL_RECOVERY
%then
    PREV_PREV_STATUS = SAVED_INFO_NOT_VALID;
%fi

    DEB_EVENT ('PAR_RECOVERY_END',
	PUT_MSG ('Ending parser error recovery.  Resume parse on:  '),
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL)),
	PUT_EOL (),
	PUT_EOL ());
    end;					! Of routine ERROR_RECOVERY
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine LOCAL_RECOVERY (ANNOUNCE_ABBREVIATIONS) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	LOCAL_RECOVERY is the main driver for local and scope
!	recovery.
!
! FORMAL PARAMETERS:
!
!	ANNOUNCE_ABBREVIATIONS	- TRUE iff an error message should be printed
!				  when an abbreviation is corrected.
!
! IMPLICIT INPUTS:
!
!	Token buffer
!
!	Stack pointer
!
!	Parse stack
!
!	State information
!
! IMPLICIT OUTPUTS:
!
!	Token buffer
!
!	Stack pointer
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS:
!
!	The token buffer will be altered to correct the error.
!	LS_*_RECOVERY_INFORM may cause other side effects.
!
!--

    begin

    local
	ORDER,
	SUCCESS,
!	error_token_ptr,
!	error_detected_state,
!	error_prev_state,
!	backup_possible,
	SAVED_STACK_RECORD : block [PATSTK_STR_SIZE/%upval] field (PATSTK_FIELDS);
! Set up for local error recovery:

!error_token_ptr = .pat$token_current_ptr;
!error_detected_state = .pat$stack_p [.stack_ptr, PATSTK_STATE];
!error_prev_state =
!    (if .valid_prev
!	then .prev_stack_record [PATSTK_STATE]
!	else .error_detected_state);
!original_stack_ptr = .stack_ptr;
!move_token (pat$stack_p [.stack_ptr, PATSTK_BASE],
!    saved_stack_record [PATSTK_BASE]);
!
! Try recovery from state B:
!
!if .valid_prev and (.prev_status neq CONSUME_NONTERM_ON_SHIFT)
!    then begin		! Try from state B
!    stack_ptr = .prev_stack_ptr;
!    move_token (prev_stack_record [PATSTK_BASE],
!	pat$stack_p [.stack_ptr, PATSTK_BASE]);
!    end;
!local_attempt_status = .prev_status;
!backup_possible = .valid_prev and (.prev_status eql CONSUME_TERM_ON_REDUCTION);
!if .backup_possible
!    then parse_ahead_init (.prev_stack_record [PATSTK_SYMBOL])
!    else parse_ahead_init (NO_INITIAL_SYMBOL);
!deb_event ('PAR_LOCAL_REC_B_S',
!    put_msg_eol ('Begin local error recovery in state B.'));
!success = strong_local_recovery (FALSE, .announce_abbreviations);
!if not .success
!    then success = weak_local_recovery (FALSE);
!if .success
!    then ls_local_recovery_inform (FALSE, TRUE,
!	(.stack_ptr neq .original_stack_ptr), .stack_ptr, .original_stack_ptr);
!deb_event ('PAR_LOCAL_REC_B_E',
!    put_msg_eol ('End local error recovery in state B.'));
!! Try recovery from state C:
!
!if (.valid_prev_prev) and (not .success)
!    then begin		! Try from state C
!    local_attempt_status = .prev_prev_status;
!    pat$token_save (.error_token_ptr, TRUE);	! Save error token in token buffer
!    pat$token_current_ptr = .prior_token_ptr;
!    current_symbol = ls_lex_term (pat$token_current_ptr);
!    stack_ptr = .prev_prev_stack_ptr;
!    move_token (prev_prev_stack_record [PATSTK_BASE],
!	pat$stack_p [.stack_ptr, PATSTK_BASE]);
!    if (.prev_prev_status eql CONSUME_TERM_ON_REDUCTION)
!	then parse_ahead_init (.prev_prev_stack_record [PATSTK_SYMBOL])
!	else parse_ahead_init (NO_INITIAL_SYMBOL);
!    deb_event ('PAR_LOCAL_REC_C_S',
!	put_msg_eol ('Begin local error recovery in state C.'));
!    success = strong_local_recovery (TRUE, .announce_abbreviations);
!    if not .success
!	then success = weak_local_recovery (TRUE);
!    if not .success
!	then pat$token_get (TRUE)	! Remove error token from token list
!	else ls_local_recovery_inform (TRUE, TRUE, TRUE, .stack_ptr,
!	    .original_stack_ptr);
!    deb_event ('PAR_LOCAL_REC_C_E',
!	put_msg_eol ('End local error recovery in state C.'));
!    end;
!! Try recovery from state A:
!
!if (.backup_possible and (not .success))
!    then begin		! Try from state A (no backup, getting default reductions)
!    local_attempt_status = ERROR_ENCOUNTERED;
!    pat$token_current_ptr = .error_token_ptr;
!    current_symbol = ls_lex_term (pat$token_current_ptr);
!    stack_ptr = .original_stack_ptr;
!    move_token (saved_stack_record [PATSTK_BASE],
!	pat$stack_p [.stack_ptr, PATSTK_BASE]);
!    parse_ahead_init (NO_INITIAL_SYMBOL);
!    deb_event ('PAR_LOCAL_REC_A_S',
!	put_msg_eol ('Begin local error recovery in state A.'));
!    success = strong_local_recovery (FALSE, .announce_abbreviations);
!    if not .success
!	then success = weak_local_recovery (FALSE);
!    if .success
!	then ls_local_recovery_inform (FALSE, FALSE, FALSE,
!	    VALUE_TO_BE_IGNORED, VALUE_TO_BE_IGNORED);
!    deb_event ('PAR_LOCAL_REC_A_E',
!	put_msg_eol ('End local error recovery in state A.'));
!    end;
!
!valid_prev = FALSE;
!valid_prev_prev = FALSE;
!
!! Clean up after failure of local recovery:
!
!if not .success
!    then begin
!    stack_ptr = .original_stack_ptr;
!    move_token (saved_stack_record [PATSTK_BASE],
!	pat$stack_p [.stack_ptr, PATSTK_BASE]);
!    end;
!
!return .success;
!end;
    SUCCESS = FALSE;
    ORDER = FIND_BACKUP_ORDER (.PREV_STATUS, .PREV_PREV_STATUS);

    ! Attempt strong local error recovery (types of corrections
    ! that have a strong chance of being correct)

!    selectone .ORDER of
!	set
!
!	[ORDER_A] :
!
!	    ! Start from state A (state when error was encountered--no backup)
!
!	    begin
!	    LOCAL_ATTEMPT_STATUS = ERROR_ENCOUNTERED;
!	    PARSE_AHEAD_INIT (NO_INITIAL_SYMBOL);
!	    SUCCESS = STRONG_LOCAL_RECOVERY (FALSE, .ANNOUNCE_ABBREVIATIONS);
!
!	    if .SUCCESS
!	    then
!		LS_LOCAL_RECOVERY_INFORM (FALSE, FALSE, FALSE, VALUE_TO_BE_IGNORED,
!		    VALUE_TO_BE_IGNORED);
!
!	    end;
!
!	[otherwise] :
!	;
!	tes;
    if not .SUCCESS
    then

	selectone .ORDER of
	    set

	    [ORDER_B, ORDER_BC] :

		! Try from state B (error state, before default reductions)

		begin
		deb_event ('PAR_LOCAL_REC_B_S_S',
		    put_msg_eol ('Begin strong recovery in state B.'));
		LOCAL_ATTEMPT_STATUS = .PREV_STATUS;
		STACK_PTR = .PREV_STACK_PTR;
		move_token (PAT$STACK_P [.STACK_PTR, PATSTK_BASE],
		    SAVED_STACK_RECORD [PATSTK_BASE]);
		move_token (PREV_STACK_RECORD [PATSTK_BASE],
		    PAT$STACK_P [.STACK_PTR, PATSTK_BASE]);

		selectone .PREV_STATUS of
		    set

		    [CONSUME_TERM_ON_REDUCTION, REDUCT_AFTER_BACKUP_NOT_ALLOWED] :
			PARSE_AHEAD_INIT (.PREV_STACK_RECORD [PATSTK_SYMBOL]);

		    [otherwise] :
			PARSE_AHEAD_INIT (NO_INITIAL_SYMBOL);
		    tes;

		SUCCESS = STRONG_LOCAL_RECOVERY (FALSE, .ANNOUNCE_ABBREVIATIONS);

		if .SUCCESS
		then
		    LS_LOCAL_RECOVERY_INFORM (FALSE, TRUE, (.STACK_PTR neq .ORIGINAL_STACK_PTR),
			.STACK_PTR, .ORIGINAL_STACK_PTR)
		else
		    move_token (SAVED_STACK_RECORD [PATSTK_BASE],
			PAT$STACK_P [.STACK_PTR, PATSTK_BASE]);

		deb_event ('PAR_LOCAL_REC_B_S_E',
		    put_msg_eol ('End strong recovery from state B.'));
		end;

	    [otherwise] :
	    ;
	    tes;
    if not .SUCCESS
    then

	selectone .ORDER of
	    set

	    [ORDER_BC] :

		! Try from state C (token before error, before default reductions)

		begin
		deb_event ('PAR_LOCAL_REC_C_S_S',
		    put_msg_eol ('Begin strong local recovery in state C'));
		LOCAL_ATTEMPT_STATUS = .PREV_PREV_STATUS;
		PAT$TOKEN_SAVE (.LATEST_TOKEN_PTR, TRUE);	! Save error token in token buffer
		PAT$TOKEN_CURRENT_PTR = .PRIOR_TOKEN_PTR;
		CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);
		STACK_PTR = .PREV_PREV_STACK_PTR;
		move_token (PAT$STACK_P [.STACK_PTR, PATSTK_BASE],
		    SAVED_STACK_RECORD [PATSTK_BASE]);
		move_token (PREV_PREV_STACK_RECORD [PATSTK_BASE],
		    PAT$STACK_P [.STACK_PTR, PATSTK_BASE]);

		selectone .PREV_PREV_STATUS of
		    set

		    [CONSUME_TERM_ON_REDUCTION, REDUCT_AFTER_BACKUP_NOT_ALLOWED] :
			PARSE_AHEAD_INIT (.PREV_PREV_STACK_RECORD [PATSTK_SYMBOL]);

		    [otherwise] :
			PARSE_AHEAD_INIT (NO_INITIAL_SYMBOL);
		    tes;

		SUCCESS = STRONG_LOCAL_RECOVERY (TRUE, .ANNOUNCE_ABBREVIATIONS);

		if .SUCCESS
		then
		    LS_LOCAL_RECOVERY_INFORM (TRUE, TRUE, TRUE, .STACK_PTR, .ORIGINAL_STACK_PTR)
		else
		    begin
		    move_token (SAVED_STACK_RECORD [PATSTK_BASE],
			PAT$STACK_P [.STACK_PTR, PATSTK_BASE]);
		    PAT$TOKEN_GET (TRUE);	! Get error token back from token buffer
		    end;
		deb_event ('PAR_LOCAL_REC_C_S_E',
		    put_msg_eol ('End strong local recovery in state C.'));

		end;

	    [otherwise] :
	    ;
	    tes;
if not .SUCCESS	! Move this code here.  Always try A afer BC and B!

	then

	    ! Start from state A (state when error was encountered--no backup)

	    begin
	    deb_event ('PAR_LOCAL_REC_A_S_S',
		put_msg_eol ('Begin strong local recovery in state A.'));
	    LOCAL_ATTEMPT_STATUS = ERROR_ENCOUNTERED;
	    PARSE_AHEAD_INIT (NO_INITIAL_SYMBOL);
	    SUCCESS = STRONG_LOCAL_RECOVERY (FALSE, .ANNOUNCE_ABBREVIATIONS);

	    if .SUCCESS
	    then
		LS_LOCAL_RECOVERY_INFORM (FALSE, FALSE, FALSE, VALUE_TO_BE_IGNORED,
		    VALUE_TO_BE_IGNORED);

	    deb_event ('PAR_LOCAL_REC_A_S_E',
		put_msg_eol ('End strong local recovery from state A.'));
	    end;
!    if not .SUCCESS
!    then
!
!    ! Attempt weak local error recovery (types of corrections
!    ! that have a weak chance of being correct)
!
!	selectone .ORDER of
!	    set
!
!	    [ORDER_A] :
!
!		! Start from state A (state when error was encountered--no backup)
!
!		begin
!		LOCAL_ATTEMPT_STATUS = ERROR_ENCOUNTERED;
!		PARSE_AHEAD_INIT (NO_INITIAL_SYMBOL);
!		SUCCESS = WEAK_LOCAL_RECOVERY (FALSE);
!
!		if .SUCCESS
!		then
!		    LS_LOCAL_RECOVERY_INFORM (FALSE, FALSE, FALSE, VALUE_TO_BE_IGNORED,
!			VALUE_TO_BE_IGNORED);
!
!		end;
!
!	    [otherwise] :
!	    ;
!	    tes;
! Attempt weak local error recovery (types of corrections
! that have a weak chance of being correct)

    if not .SUCCESS
    then

	selectone .ORDER of
	    set

	    [ORDER_B, ORDER_BC] :

		! Try from state B (error state, before default reductions)

		begin
		deb_event ('PAR_LOCAL_REC_B_W_S',
		    put_msg_eol ('Begin weak local recovery in state B.'));
		LOCAL_ATTEMPT_STATUS = .PREV_STATUS;
		STACK_PTR = .PREV_STACK_PTR;
		move_token (PAT$STACK_P [.STACK_PTR, PATSTK_BASE],
		    SAVED_STACK_RECORD [PATSTK_BASE]);
		move_token (PREV_STACK_RECORD [PATSTK_BASE],
		    PAT$STACK_P [.STACK_PTR, PATSTK_BASE]);

		selectone .PREV_STATUS of
		    set

		    [CONSUME_TERM_ON_REDUCTION, REDUCT_AFTER_BACKUP_NOT_ALLOWED] :
			PARSE_AHEAD_INIT (.PREV_STACK_RECORD [PATSTK_SYMBOL]);

		    [otherwise] :
			PARSE_AHEAD_INIT (NO_INITIAL_SYMBOL);
		    tes;

		SUCCESS = WEAK_LOCAL_RECOVERY (FALSE);

		if .SUCCESS
		then
		    LS_LOCAL_RECOVERY_INFORM (FALSE, TRUE, (.STACK_PTR neq .ORIGINAL_STACK_PTR),
			.STACK_PTR, .ORIGINAL_STACK_PTR)
		else
		    move_token (SAVED_STACK_RECORD [PATSTK_BASE],
			PAT$STACK_P [.STACK_PTR, PATSTK_BASE]);

		deb_event ('PAR_LOCAL_REC_B_W_E',
		    put_msg_eol ('End weak local recovery in state B.'));
		end;

	    [otherwise] :
	    ;
	    tes;
    if not .SUCCESS
    then

	selectone .ORDER of
	    set

	    [ORDER_BC] :

		! Try from state C (token before error state, before any default reductions)

		begin
		deb_event ('PAR_LOCAL_REC_C_W_S',
		    put_msg_eol ('Begin weak local recovery in state C.'));
		LOCAL_ATTEMPT_STATUS = .PREV_PREV_STATUS;
		PAT$TOKEN_SAVE (.LATEST_TOKEN_PTR, TRUE);	! Save error token in token buffer
		PAT$TOKEN_CURRENT_PTR = .PRIOR_TOKEN_PTR;
		CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);
		STACK_PTR = .PREV_PREV_STACK_PTR;
		move_token (PAT$STACK_P [.STACK_PTR, PATSTK_BASE],
		    SAVED_STACK_RECORD [PATSTK_BASE]);
		move_token (PREV_PREV_STACK_RECORD [PATSTK_BASE],
		    PAT$STACK_P [.STACK_PTR, PATSTK_BASE]);

		selectone .PREV_PREV_STATUS of
		    set

		    [CONSUME_TERM_ON_REDUCTION, REDUCT_AFTER_BACKUP_NOT_ALLOWED] :
			PARSE_AHEAD_INIT (.PREV_PREV_STACK_RECORD [PATSTK_SYMBOL]);

		    [otherwise] :
			PARSE_AHEAD_INIT (NO_INITIAL_SYMBOL);
		    tes;

		SUCCESS = WEAK_LOCAL_RECOVERY (TRUE);

		if .SUCCESS
		then
		    LS_LOCAL_RECOVERY_INFORM (TRUE, TRUE, TRUE, .STACK_PTR, .ORIGINAL_STACK_PTR)
		else
		    begin
		    move_token (SAVED_STACK_RECORD [PATSTK_BASE],
			PAT$STACK_P [.STACK_PTR, PATSTK_BASE]);
		    PAT$TOKEN_GET (TRUE);	! Get error token back from token buffer
		    end;

		deb_event ('PAR_LOCAL_REC_C_W_E',
		    put_msg_eol ('End weak local recovery in state C.'));
		end;

	    [otherwise] :
	    ;
	    tes;
    if not .SUCCESS	! Move this code here.  Always true A after BC and B

    then

		! Start from state A (state when error was encountered--no backup)

		begin
		deb_event ('PAR_LOCAL_REC_A_W_S',
		    put_msg_eol ('Begin weak local recovery in state A.'));
		LOCAL_ATTEMPT_STATUS = ERROR_ENCOUNTERED;
		PARSE_AHEAD_INIT (NO_INITIAL_SYMBOL);
		SUCCESS = WEAK_LOCAL_RECOVERY (FALSE);

		if .SUCCESS
		then
		    LS_LOCAL_RECOVERY_INFORM (FALSE, FALSE, FALSE, VALUE_TO_BE_IGNORED,
			VALUE_TO_BE_IGNORED);

		deb_event ('PAR_LOCAL_REC_A_W_E',
		    put_msg_eol ('End weak local recovery in state A.'));
		end;
    if not .SUCCESS
    then
	begin
	PAT$TOKEN_CURRENT_PTR = .LATEST_TOKEN_PTR;
	CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);
	STACK_PTR = .ORIGINAL_STACK_PTR;
	end;

    return .SUCCESS
    end;					! Of routine LOCAL_RECOVERY
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine PARSE_AHEAD (TOKENS_TO_TRY) =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Try to parse ahead after a trial error recovery.
!
! FORMAL PARAMETERS:
!
!	TOKENS_TO_TRY	Number of tokens to parse ahead.
!
! IMPLICIT INPUTS:
!
!	STACK_PTR
!	INITIAL_SYMBOL
!	PAT$STACK_P
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! ROUTINE VALUE:
!
!	TRUE if parse ahead succeeded; FALSE if produced an error or
!	overflowed the parse stack.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    macro
	RESET_STACK =
	    begin
	    STACK_PTR = .SAVED_STACK_PTR;
	    incr P from 1 to (.STACK_PTR + 1) do
		begin
		ref_alt_parse_stack [.P-1, PATSTK_LOCATOR]
		    = .ref_parse_stack [.P-1, PATSTK_LOCATOR];
		%if PATBLSEXT_EXTRA_STACK_FIELD
		%then
		ref_alt_parse_stack [.P-1, PATSTK_EXTRA_INFO]
		    = .ref_parse_stack [.P-1, PATSTK_EXTRA_INFO];
		%fi
		ref_alt_parse_stack [.P-1, PATSTK_SYMBOL]
		    = .ref_parse_stack [.P-1, PATSTK_SYMBOL];
		ref_alt_parse_stack [.P-1, PATSTK_TOKEN]
		    = .ref_parse_stack [.P-1, PATSTK_TOKEN];
		ref_alt_parse_stack [.P-1, PATSTK_ERRORMARK]
		    = .ref_parse_stack [.P-1, PATSTK_ERRORMARK];
		ref_alt_parse_stack [.P-1, PATSTK_STATE]
		    = .ref_parse_stack [.P-1, PATSTK_STATE];
		end;
	    end%;
    local
	CURRENT_SYMBOL_IS_TERMINAL,
	SAVED_TEMP_HEAD,
	ACTION_CODE,
	TOKENS_TRIED,
	HOLDING_SECOND_TOKEN,
	SECOND_TOKEN_PTR,
	LHS_SYMBOL,
	RHS_COUNT,
	SEMACT,
	NEW_PTR;

    SAVED_TEMP_HEAD = PAT$TOKEN_TEMP_HEAD ();
    TOKENS_TRIED = 0;

    if .HAVE_INITIAL_SYMBOL
    then
	begin
	SECOND_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
	HOLDING_SECOND_TOKEN = TRUE;
	CURRENT_SYMBOL = .INITIAL_SYMBOL;
	CURRENT_SYMBOL_IS_TERMINAL = FALSE;
	end
    else
	begin
	HOLDING_SECOND_TOKEN = FALSE;
	CURRENT_SYMBOL_IS_TERMINAL = TRUE;
	end;

    while (.TOKENS_TO_TRY gtr .TOKENS_TRIED) do
	begin

%if PATBLSEXT_DEBUGGING
%then
	PAT$DEB_STATE (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE], FALSE);
%fi

	if .CURRENT_SYMBOL eql LS_STOP_PARSING_NT
	then 					! Compilation complete
	    begin
	    PAT$TOKEN_SET_TEMP_HEAD (.SAVED_TEMP_HEAD);
	    RESET_STACK;
	    return TRUE;
	    end;

	ACTION_CODE = PAT$DATA_MOVE_ACTION (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE], .CURRENT_SYMBOL);

	if PAT$DATA_ACTION_IS (.ACTION_CODE, 'ERROR')
	then
	    begin
	    PAT$TOKEN_SET_TEMP_HEAD (.SAVED_TEMP_HEAD);
	    RESET_STACK;
	    return FALSE;
	    end
	else
	    begin

	    if PAT$DATA_ACTION_IS (.ACTION_CODE, 'SHIFT')
	    then
		begin

		! Save the symbol that was found on the stack and push the
		! new state on the stack.

		PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL] = .CURRENT_SYMBOL;

		if .CURRENT_SYMBOL_IS_TERMINAL
		then
		    PAT$STACK_P [.STACK_PTR, PATSTK_LOCATOR] = LS_LEX_LOCATOR (PAT$TOKEN_CURRENT_PTR);

		if .STACK_PTR geq (LS_PARSE_STACK_SIZE - 1)
		then
		    begin

		    ! Stack overflow so parse ahead not successful.

		    PAT$TOKEN_SET_TEMP_HEAD (.SAVED_TEMP_HEAD);
		    RESET_STACK;
		    return FALSE;
		    end
		else
		    begin
		    STACK_PTR = .STACK_PTR + 1;
		    PAT$STACK_P [.STACK_PTR, PATSTK_STATE] = PAT$DATA_AC_TO_SHIFT_STATE (.ACTION_CODE);
						! Now this is the current state
		    end;

		if .HOLDING_SECOND_TOKEN
		then
		    begin
		    PAT$TOKEN_CURRENT_PTR = .SECOND_TOKEN_PTR;
		    CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);
		    HOLDING_SECOND_TOKEN = FALSE;
		    end
		else
		    begin
		    CURRENT_SYMBOL = PAT$TOKEN_GET (FALSE);
		    TOKENS_TRIED = .TOKENS_TRIED + 1;
		    end;

%if PATBLSEXT_DEBUGGING
%then
		PAT$DEB_TOKEN (FALSE);
%fi

		CURRENT_SYMBOL_IS_TERMINAL = TRUE;
		end
	    else 				! action is reduce or look-ahead
		begin

		if PAT$DATA_ACTION_IS (.ACTION_CODE, 'LOOK_AHEAD')
		then

		! This is a look ahead reduction.

		    begin

		    if .CURRENT_SYMBOL_IS_TERMINAL then PAT$STACK_P [.STACK_PTR, PATSTK_LOCATOR] = 0;

		    REDUCTION_CODE = PAT$DATA_AC_TO_LA_PRODUCTION_NO (.ACTION_CODE);
		    PAT$DATA_GET_REDUCTION_INFO (.REDUCTION_CODE, LHS_SYMBOL, RHS_COUNT, SEMACT);
		    PAR_LOOKAHEAD_F = TRUE;
		    DEB_ASSERT (( not .HOLDING_SECOND_TOKEN),
			'Trying to save token while holding second token.');
		    PAT$TOKEN_SAVE (.PAT$TOKEN_CURRENT_PTR, FALSE);
		    TOKENS_TRIED = .TOKENS_TRIED - 1;
		    NEW_PTR = .STACK_PTR - .RHS_COUNT;
		    end
		else 				! action is reduce
		    begin
		    PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL] = .CURRENT_SYMBOL;
						! Save the right-most symbol on the rhs

		    if .CURRENT_SYMBOL_IS_TERMINAL
		    then
			PAT$STACK_P [.STACK_PTR, PATSTK_LOCATOR] = LS_LEX_LOCATOR (PAT$TOKEN_CURRENT_PTR);

		    REDUCTION_CODE = PAT$DATA_AC_TO_PRODUCTION_NO (.ACTION_CODE);
		    PAT$DATA_GET_REDUCTION_INFO (.REDUCTION_CODE, LHS_SYMBOL, RHS_COUNT, SEMACT);
		    PAR_LOOKAHEAD_F = FALSE;
		    NEW_PTR = .STACK_PTR - .RHS_COUNT + 1;
		    end;

%if PATBLSEXT_DEBUGGING
%then
		PAT$DEB_REDUCE (.LHS_SYMBOL, .SEMACT, FALSE);
%fi

		CURRENT_SYMBOL = .LHS_SYMBOL;
		REDUCTION_CODE = -1;
		STACK_PTR = .NEW_PTR;	! Now the current state is .PAT$STACK_P [.STACK_PTR, PATSTK_STATE]
		PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL] = .CURRENT_SYMBOL;	! the lhs symbol
		CURRENT_SYMBOL_IS_TERMINAL = FALSE;
		end;

	    end

	end;

    PAT$TOKEN_SET_TEMP_HEAD (.SAVED_TEMP_HEAD);
    RESET_STACK;
    return TRUE
    end;					! Of routine PARSE_AHEAD
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine PARSE_AHEAD_INIT (INIT_SYMBOL) : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Initialize for parse ahead during error recovery.
!
! FORMAL PARAMETERS:
!
!	INIT_SYMBOL	potential initial token.
!
! IMPLICIT INPUTS:
!
!	INITIAL_SYMBOL
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin
    HAVE_INITIAL_SYMBOL = (.INIT_SYMBOL neq NO_INITIAL_SYMBOL);
    if .HAVE_INITIAL_SYMBOL
	then INITIAL_SYMBOL = .INIT_SYMBOL;
    end;					! Of routine PARSE_AHEAD_INIT
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine STRONG_LOCAL_RECOVERY (HAVE_BACKED_UP_OVER_A_TOKEN, ANNOUNCE_ABBREVIATIONS) =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Try corrections that have a strong chance of being correct:
!		End-of-line corrections (if this is first token on a new line)
!		Token merging
!		Spelling corrections
!
! FORMAL PARAMETERS:
!
!	HAVE_BACKED_UP_OVER_A_TOKEN	(not used)
!	ANNOUNCE_ABBREVIATIONS		Parameter to TRY_CORRECT_SPELLING
!
! IMPLICIT INPUTS:
!
!	PAT$STACK_P
!	HAVE_INITIAL_SYMBOL
!	INITIAL_SYMBOL
!
! IMPLICIT OUTPUTS:
!
!	CURRENT_SYMBOL_IS_TERMINAL
!	CURRENT_SYMBOL
!
! ROUTINE VALUE:
!
!	TRUE if error recovery was successful, otherwise FALSE.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	SUCCESS;

    label
	TRYS;

    PAT$TOKEN_SAVE (.PAT$TOKEN_CURRENT_PTR, TRUE);	! Save error token
    SAVE_STATE ();				! Save state of the parse
    PAT$STACK_P = .REF_ALT_PARSE_STACK;		! Use alternate parse stack
    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_MSG_EOL ('-----------------------------------------------------'),
	PUT_MSG ('Starting strong local recovery - the current state is '),
	PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]),
	PUT_MSG_EOL ('.'),
	PUT_MSG ('Current symbol is '),
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL)),
	PUT_MSG_EOL ('.'));
TRYS :
    begin

    if LS_LEX_START_LINE (PAT$TOKEN_CURRENT_PTR)
    then
	begin
	if (SUCCESS = TRY_EOL_CORRECTION ()) then leave TRYS;
	RESTORE_STATE ();
	end;

    if (SUCCESS = TRY_MERGE ()) then leave TRYS;

    RESTORE_STATE ();

    if (SUCCESS = TRY_CORRECT_SPELLING (.ANNOUNCE_ABBREVIATIONS)) then leave TRYS;

    RESTORE_STATE ();
    end;					! Of loop TRYS

    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_EOL (),

	if .SUCCESS
	then
	    PUT_MSG_EOL ('Strong local error recovery successful')
	else
	    PUT_MSG_EOL ('Strong local error recovery not successful'),

	PUT_MSG_EOL ('-----------------------------------------------------'),
	PUT_EOL ());
    RESTORE_STATE ();
    PAT$STACK_P = .REF_PARSE_STACK;		! Use normal parse stack

    if (.HAVE_INITIAL_SYMBOL and .SUCCESS)
    then
	begin
	CURRENT_SYMBOL = .INITIAL_SYMBOL;
	CURRENT_SYMBOL_IS_TERMINAL = FALSE;
	end
    else
	begin
	CURRENT_SYMBOL = PAT$TOKEN_GET (TRUE);
	CURRENT_SYMBOL_IS_TERMINAL = TRUE;
	end;

    return .SUCCESS
    end;					! Of routine STRONG_LOCAL_RECOVERY
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine WEAK_LOCAL_RECOVERY (HAVE_BACKED_UP_OVER_A_TOKEN) =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Try corrections that have a weak chance of being correct:
!		token substitutions
!		token insertions
!		scope recovery
!		token deletion
!
! FORMAL PARAMETERS:
!
!	HAVE_BACKED_UP_OVER_A_TOKEN	TRUE if have backed up
!					over a token.
!
! IMPLICIT INPUTS:
!
!	PAT$STACK_P
!	INITIAL_SYMBOL
!
! IMPLICIT OUTPUTS:
!
!	CURRENT_SYMBOL
!	CURRENT_SYMBOL_IS_TERMINAL
!
! ROUTINE VALUE:
!
!	TRUE if recovery succeeded, otherwise FALSE.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	SUCCESS;

    label
	TRYS;

    PAT$TOKEN_SAVE (.PAT$TOKEN_CURRENT_PTR, TRUE);	! Save error token
    SAVE_STATE ();				! Save state of the parse
    PAT$STACK_P = .REF_ALT_PARSE_STACK;		! Use alternate parse stack
    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_MSG_EOL ('-----------------------------------------------------'),
	PUT_MSG ('Starting weak local recovery - the current state is '),
	PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]),
	PUT_MSG_EOL ('.'),
	PUT_MSG ('Current symbol is '),
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL)),
	PUT_MSG_EOL ('.'));
TRYS :
    begin

    incr PRIORITY from 1 to 4 do
	begin

	if LR_SUB_PRIORITY eql .PRIORITY
	then
	    begin
	    if (SUCCESS = TRY_SUBSTITUTE ()) then leave TRYS;
	    RESTORE_STATE ()
	    end;

	if LR_INSERT_PRIORITY eql .PRIORITY
	then
	    begin
	    if (SUCCESS = TRY_INSERT ()) then leave TRYS;
	    RESTORE_STATE ()
	    end;

	if (LR_SCOPE_PRIORITY eql .PRIORITY) and not .HAVE_BACKED_UP_OVER_A_TOKEN
	then
	    begin
	    if (SUCCESS = SCOPE_RECOVERY (FALSE)) then leave TRYS;
	    RESTORE_STATE ();
	    end;

	if LR_DELETE_PRIORITY eql .PRIORITY
	then
	    begin
	    if (SUCCESS = TRY_DELETE ()) then leave TRYS;
	    RESTORE_STATE ()
	    end;

	end;

    end;					! Of loop TRYS
    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_EOL (),

	if .SUCCESS
	then
	    PUT_MSG_EOL ('Weak local error recovery successful')
	else
	    PUT_MSG_EOL ('Weak local error recovery not successful'),

	PUT_MSG_EOL ('-----------------------------------------------------'),
	PUT_EOL ());
    RESTORE_STATE ();
    PAT$STACK_P = .REF_PARSE_STACK;		! Use normal parse stack

    if (.HAVE_INITIAL_SYMBOL and .SUCCESS)
    then
	begin
	CURRENT_SYMBOL = .INITIAL_SYMBOL;
	CURRENT_SYMBOL_IS_TERMINAL = FALSE;
	end
    else
	begin
	CURRENT_SYMBOL = PAT$TOKEN_GET (TRUE);
	CURRENT_SYMBOL_IS_TERMINAL = TRUE;
	end;

    return .SUCCESS
    end;					! Of routine WEAK_LOCAL_RECOVERY
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine TRY_EOL_CORRECTION =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Attempt an end-of-line correction by seeing what happens if the previous
!	text line ends with an end-of-statement token.
!
!   This routine is never called if LS_LEX_START_LINE always returns
!   FALSE.
!
! FORMAL PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	PAT$TOKEN_CURRENT_PTR
!
! IMPLICIT OUTPUTS:
!
!	CURRENT_SYMBOL
!
! ROUTINE VALUE:
!
!	Returns TRUE if the result parsed, FALSE otherwise.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	NEW_TOKEN,
	ERROR_LOC;

    DEB_ASSERT (LS_LEX_START_LINE (PAT$TOKEN_CURRENT_PTR), '[TRY_EOL_CORRECTION]');
    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_EOL (),
	PUT_MSG_EOL ('Trying end of line correction'));
    PAT$TOKEN_GET (FALSE);			! Examine error token
    ERROR_LOC = LS_LEX_LOCATOR (PAT$TOKEN_CURRENT_PTR);
    PAT$TOKEN_RESET_BUFFER ();
    NEW_TOKEN = SYNTHESIZE_TOKEN (LS_T_SEMICOLON);
    PAT$TOKEN_CURRENT_PTR = .NEW_TOKEN;
    CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);

    if PARSE_AHEAD (PARSE_AHEAD_EOL)
    then
	begin
	PAT$TOKEN_SAVE (.NEW_TOKEN, TRUE);
	DEB_EVENT ('PAR_RECOVERY_LOCAL',
	    PUT_MSG ('Successful insertion of '),
	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_T_SEMICOLON)),
	    PUT_EOL ());
	LS_ERROR_EOL (.ERROR_LOC);
	return TRUE;
	end;

    return FALSE
    end;					! Of routine TRY_EOL_CORRECTION
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine TRY_MERGE =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Try to correct syntax by merging tokens.  The actual work
!	is done by the MERGE_TOKENS routine.
!
! FORMAL PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	PAT$TOKEN_CURRENT_PTR
!
! IMPLICIT OUTPUTS:
!
!	CURRENT_SYMBOL
!	PAT$TOKEN_CURRENT_PTR
!
! ROUTINE VALUE:
!
!	Returns TRUE if the result parsed, FALSE otherwise.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	TERM,
	ERROR_LOC,
	NUM_SAVED,
	FIRST_TOKEN_PTR,
	SECOND_TOKEN_PTR,
	NEW_TOKEN;

    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_EOL (),
	PUT_MSG_EOL ('Trying to merge tokens'));
    NUM_SAVED = PAT$TOKEN_SAVE_BUF (2);
    PAT$TOKEN_GET (FALSE);			! Get first token
    FIRST_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
    PAT$TOKEN_GET (FALSE);			! Get second token
    SECOND_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
    TERM = MERGE_TOKENS (.FIRST_TOKEN_PTR, .SECOND_TOKEN_PTR);
    if .TERM neq NO_MERGE
    then
	begin
	NEW_TOKEN = SYNTHESIZE_TOKEN (.TERM);
	PAT$TOKEN_CURRENT_PTR = .NEW_TOKEN;	! Try replacing 2 tokens with merged token
	CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);

	if PARSE_AHEAD (PARSE_AHEAD_MERGE)
	then
	    begin
	    PAT$TOKEN_GET (TRUE);		! Drop error token for real
	    PAT$TOKEN_GET (TRUE);		! Drop next token for real
	    PAT$TOKEN_SAVE (.NEW_TOKEN, TRUE);	! Insert merged token
	    DEB_EVENT ('PAR_RECOVERY_LOCAL',
		PUT_MSG ('Successful merge of '),
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_LEX_TERM (FIRST_TOKEN_PTR))),

		if LS_IS_IDENTIFIER (LS_LEX_TERM (FIRST_TOKEN_PTR))
		then
		    begin
		    PUT_MSG (' "');
		    PUT_STRING (LS_LEX_TEXT (FIRST_TOKEN_PTR));
		    PUT_MSG ('"');
		    end
	    ,
		PUT_MSG (' and '),
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_LEX_TERM (SECOND_TOKEN_PTR))),

		if LS_IS_IDENTIFIER (LS_LEX_TERM (SECOND_TOKEN_PTR))
		then
		    begin
		    PUT_MSG (' "');
		    PUT_STRING (LS_LEX_TEXT (SECOND_TOKEN_PTR));
		    PUT_MSG ('"');
		    end
	    ,
		PUT_MSG (' to form '),
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (.TERM)),
		PUT_EOL ());
	    ERROR_LOC = LS_LEX_LOCATOR (FIRST_TOKEN_PTR);
	    LS_ERROR_MERGE (.ERROR_LOC, .FIRST_TOKEN_PTR, .SECOND_TOKEN_PTR, .TERM);
	    return TRUE
	    end;

	end;

    PAT$TOKEN_RESTORE_BUF (.NUM_SAVED);
    return FALSE
    end;					! Of routine TRY_MERGE
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine MERGE_TOKENS (FIRST_TOKEN_PTR, SECOND_TOKEN_PTR) =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Does the work for TRY_MERGE.
!
! FORMAL PARAMETERS:
!
!	FIRST_TOKEN_PTR		First token to try merging
!	SECOND_TOKEN_PTR	Second token to try merging
!
! IMPLICIT INPUTS:
!
!	PAT$LR_IDENTIFIER_MERGE_TABLE
!	PAT$LR_SYMBOL_MERGE_TABLE
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! ROUTINE VALUE:
!
!	Returns the merged token if there is one, or NO_MERGE if not.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    map
	FIRST_TOKEN_PTR,
	SECOND_TOKEN_PTR;

    if LS_IS_IDENTIFIER (LS_LEX_TERM (FIRST_TOKEN_PTR))
    then
	begin

	if LS_IS_IDENTIFIER (LS_LEX_TERM (SECOND_TOKEN_PTR))
	then

	    incr COUNTER from 0 to (LR_NUM_IM - 1) do

		if $str_eql (STRING1=LS_LEX_TEXT (FIRST_TOKEN_PTR),	! 004
			STRING2=.PAT$LR_IDENTIFIER_MERGE_TABLE[.COUNTER,! 004
			    LR_IM_FIRST_ID]) and
		    $str_eql (STRING1=LS_LEX_TEXT (SECOND_TOKEN_PTR), 	! 004
			STRING2=.PAT$LR_IDENTIFIER_MERGE_TABLE [.COUNTER, LR_IM_SECOND_ID])	! 004
		then
		    return .PAT$LR_IDENTIFIER_MERGE_TABLE [.COUNTER, LR_IM_MERGED_TERM];

	end
    else

	incr COUNTER from 0 to (LR_NUM_SM - 1) do

	    if (LS_LEX_TERM (FIRST_TOKEN_PTR) eql .PAT$LR_SYMBOL_MERGE_TABLE [.COUNTER, LR_SM_FIRST_TERM]) and
		(LS_LEX_TERM (SECOND_TOKEN_PTR) eql .PAT$LR_SYMBOL_MERGE_TABLE [.COUNTER, LR_SM_SECOND_TERM])
	    then
		return .PAT$LR_SYMBOL_MERGE_TABLE [.COUNTER, LR_SM_MERGED_TERM];

    return NO_MERGE
    end;
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine TRY_CORRECT_SPELLING (ANNOUNCE_ABBREVIATIONS) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Try correcting spelling of the erroneous input.
!	The following types of corrections are tried:
!	1.  Wrong case (not used for some grammars whose lexical machines
!	    convert to all one case).
!	2.  Abbreviation of a reserved word to 2 or more characters, if the
!	    characters in the error token match the start of a reserved
!	    word.
!	3.  One letter wrong for a reserved word.
!	4.  One letter missing in a reserved word.
!	5.  One extra letter in a reserved word.
!	6.  Two adjacent letters transposed in a reserved word.
!
! FORMAL PARAMETERS:
!
!	ANNOUNCE_ABBREVIATIONS	TRUE if a message should tell
!				the user we replaced an abbreviation.
!
! IMPLICIT INPUTS:
!
!	PAT$TOKEN_CURRENT_PTR
!
! IMPLICIT OUTPUTS:
!
!	CURRENT_SYMBOL
!
! ROUTINE VALUE:
!
!	Returns TRUE if the result parsed, FALSE otherwise.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	TERM,
	ERROR_LOC,
	ABBREVIATION,
	CORRECTION,
	NUM_SAVED,
	OFFSET,
	REM_LEN,
	ID_TOKEN_PTR,
	ORIG_IDENTIFIER : ref $STR_DESCRIPTOR (),			! 004
	RESERVED_WORD : ref $STR_DESCRIPTOR (),				! 004
	NEW_TOKEN;

    own
	IDENTIFIER_TEXT : vector [CH$ALLOCATION (132)],			! 004
	IDENTIFIER:$STR_DESCRIPTOR(string=(132,ch$ptr(identifier_text)));! 004
    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_EOL (),
	PUT_MSG_EOL ('Trying spelling correction'));
    NUM_SAVED = PAT$TOKEN_SAVE_BUF (1);
    CURRENT_SYMBOL = PAT$TOKEN_GET (FALSE);	! Try dropping error token

    if LS_IS_IDENTIFIER (.CURRENT_SYMBOL) and
	( not LS_LEX_SYNTHETIC (PAT$TOKEN_CURRENT_PTR))
    then
	begin
	ERROR_LOC = LS_LEX_LOCATOR (PAT$TOKEN_CURRENT_PTR);
	ID_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
	ORIG_IDENTIFIER = LS_LEX_TEXT (PAT$TOKEN_CURRENT_PTR);
	DOWN_CASE (.ORIG_IDENTIFIER, IDENTIFIER);
	PAT$ERROR_GET_NEXT_TRANS_INIT (.LOCAL_ATTEMPT_STATUS, .PAT$STACK_P [.STACK_PTR, PATSTK_STATE],
	    .PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL]);
	while (TERM = PAT$ERROR_GET_NEXT_TRANSITION (TRUE)) neq PAT$ERROR_NO_MORE_TRANSITIONS do
	    begin

	    if LS_IS_RESERVED_WORD (.TERM)	! Reserved word
	    then
		begin
		NEW_TOKEN = SYNTHESIZE_TOKEN (.TERM);
		PAT$TOKEN_CURRENT_PTR = .NEW_TOKEN;	! Try inserting reserved word
		CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);

		if PARSE_AHEAD (PARSE_AHEAD_SPELLING)
		then
		    begin
		    ABBREVIATION = FALSE;
		    CORRECTION = FALSE;
		    RESERVED_WORD = PAT$DATA_SYMBOL_TEXT (.TERM);

		    ! Check for same spelling (error could be due to incorrect
		    ! capitalization.

		    if ch$eql (.RESERVED_WORD [STR$H_LENGTH],		! 004
			    .RESERVED_WORD [STR$A_POINTER],		! 004
			    .IDENTIFIER [STR$H_LENGTH],			! 004
			    .IDENTIFIER [STR$A_POINTER])		! 004
		    then
			begin
			CORRECTION = TRUE;
			end
		    else

		    ! Check for abbreviation

			if (.IDENTIFIER [STR$H_LENGTH] gtr 2) and 	! 004
			    (.IDENTIFIER [STR$H_LENGTH] lss .RESERVED_WORD [STR$H_LENGTH]) and 	! 004
			    ch$eql (.IDENTIFIER [STR$H_LENGTH], .RESERVED_WORD [STR$A_POINTER],	! 004
				.IDENTIFIER [STR$H_LENGTH], .IDENTIFIER [STR$A_POINTER])	! 004
			then
			    begin
			    ABBREVIATION = TRUE;
			    CORRECTION = TRUE;
			    end;
!		    if not .CORRECTION and
!			(.RESERVED_WORD [STR$H_LENGTH] + 1) geq (.IDENTIFIER [STR$H_LENGTH])	! 004
!		    then
!			begin
!
!			local
!			    POSSIBILITIES,
!			    MATCHES;
!
!			MATCHES = 0;
!
!			if ch$eql (1, .RESERVED_WORD [STR$A_POINTER], 1, .IDENTIFIER [STR$A_POINTER])	! 004
!			then
!			    MATCHES = .MATCHES + 1;
!
!			incr RW_PTR from .RESERVED_WORD [STR$A_POINTER] to 	! 004
!				(.RESERVED_WORD [STR$A_POINTER] + .RESERVED_WORD [STR$H_LENGTH] - 2) do	! 004
!
!			    incr ID_PTR from .IDENTIFIER [STR$A_POINTER] to 	! 004
!				    (.IDENTIFIER [STR$A_POINTER] + .IDENTIFIER [STR$H_LENGTH] - 2) do	! 004
!
!				if ch$eql (2, .RW_PTR, 2, .ID_PTR) then MATCHES = .MATCHES + 1;
!
!			if ch$eql (1, (.RESERVED_WORD [STR$A_POINTER] + .RESERVED_WORD [STR$H_LENGTH]), 1,	! 004
!				(.IDENTIFIER [STR$A_POINTER] + .IDENTIFIER [STR$H_LENGTH]))	! 004
!			then
!			    MATCHES = .MATCHES + 1;
!
!			POSSIBILITIES = max (.RESERVED_WORD [STR$H_LENGTH], .IDENTIFIER [STR$H_LENGTH]) + 1;	! 004
!
!			if ((.MATCHES*100)/.POSSIBILITIES) gtr 40
!			then
!			    CORRECTION = TRUE;
!
!			end;
! If the identifier is n, n+1, or n-1 characters in length, where n is the
! number of characters in the reserved word, then test for one of the following
! conditions:
! 1.  One letter wrong (length: n)
! 2.  One letter missing (length: n-1)
! 3.  An extra character inserted (length: n+1)
! 4.  Two adjacent characters transposed (length: n)

if (not .correction) and
    (.identifier [str$h_length] geq .reserved_word [str$h_length] - 1)
    and (.identifier [str$h_length] leq .reserved_word [str$h_length] + 1)
    then begin		! Find first invalid character in the identifier
	offset = 0;
	while (.offset leq .reserved_word [str$h_length]) and
	    ch$eql (1, ch$plus (.identifier [str$a_pointer] , .offset),
		1, ch$plus (.reserved_word [str$a_pointer], .offset))
	    do offset = .offset + 1;
	rem_len = .reserved_word [str$h_length] - .offset;
	if (selectone (.identifier [str$h_length] -
	    .reserved_word [str$h_length]) of
	    set

	    [1]:		! Extra character
	    if ch$eql (.rem_len,
		ch$plus (.identifier [str$a_pointer], .offset + 1),
		.rem_len,
		ch$plus (.reserved_word [str$a_pointer], .offset))
		then TRUE else FALSE;

	    [0]:		! Wrong or transposed characters
	    if ch$eql (.rem_len - 1,
		ch$plus (.identifier [str$a_pointer], .offset + 1),
		.rem_len - 1,
		ch$plus (.reserved_word [str$a_pointer], .offset + 1))
		then TRUE	! One wrong character
		else if ch$eql (.rem_len - 2,
		    ch$plus (.identifier [str$a_pointer], .offset + 2),
		    .rem_len - 2,
		    ch$plus (.reserved_word [str$a_pointer], .offset + 2))
		    and
		    ch$eql (1, ch$plus (.identifier [str$a_pointer], .offset),
			1, ch$plus (.reserved_word [str$a_pointer], .offset+1))
		    and
		    ch$eql (1, ch$plus (.identifier [str$a_pointer], .offset+1),
			1, ch$plus (.reserved_word [str$a_pointer], .offset))
		    then TRUE else FALSE;

	    [-1]:		! One missing character
	    if ch$eql (.rem_len - 1,
		ch$plus (.identifier [str$a_pointer], .offset),
		.rem_len - 1,
		ch$plus (.reserved_word [str$a_pointer], .offset + 1))
		then TRUE else FALSE;

	    tes)
	    then begin
		CORRECTION = TRUE;
	    end;
	end;
		    if .CORRECTION
		    then
			begin
			RESTORE_STATE ();
			PAT$TOKEN_GET (TRUE);	! Drop error token
			PAT$TOKEN_SAVE (.NEW_TOKEN, TRUE);

			if .ABBREVIATION
			then
			    begin

			    if .ANNOUNCE_ABBREVIATIONS
			    then
				begin
				DEB_EVENT ('PAR_RECOVERY_LOCAL',
				    PUT_MSG_EOL ('Successful abbreviation correction:'),
				    PUT_MSG ('replaced '),
				    PUT_STRING (.ORIG_IDENTIFIER),
				    PUT_MSG (' with '),
				    PUT_STRING (.RESERVED_WORD),
				    PUT_EOL ());
				LS_ERROR_ABBREV (.ERROR_LOC, .ID_TOKEN_PTR, .NEW_TOKEN);
				end
			    else
				DEB_EVENT ('PAR_RECOVERY_LOCAL',
				    PUT_MSG_EOL ('Successful unannounced abbreviation correction:'),
				    PUT_MSG ('replaced '),
				    PUT_STRING (.ORIG_IDENTIFIER),
				    PUT_MSG (' with '),
				    PUT_STRING (.RESERVED_WORD),
				    PUT_EOL ())

			    end
			else 			! Spelling error
			    begin
			    DEB_EVENT ('PAR_RECOVERY_LOCAL',
				PUT_MSG_EOL ('Successful spelling correction:'),
				PUT_MSG ('replaced '),
				PUT_STRING (.ORIG_IDENTIFIER),
				PUT_MSG (' with '),
				PUT_STRING (.RESERVED_WORD),
				PUT_EOL ());
			    LS_ERROR_SPELL (.ERROR_LOC, .ID_TOKEN_PTR, .NEW_TOKEN);
			    end;

			return TRUE
			end;

		    end;

		end;

	    end;

	end;

    PAT$TOKEN_RESTORE_BUF (.NUM_SAVED);
    return FALSE
    end;					! Of routine TRY_CORRECT_SPELLING
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine TRY_SUBSTITUTE =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Try to get input to parse by substituting tokens.
!
! FORMAL PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	PAT$TOKEN_CURRENT_PTR
!	PAT$STACK_P
!	PAT$LR_PREFERRED_INSERTIONS
!	PAT$LR_NEVER_SUBSTITUTE_FOR
!
! IMPLICIT OUTPUTS:
!
!	PAT$TOKEN_CURRENT_PTR
!	CURRENT_SYMBOL
!
! ROUTINE VALUE:
!
!	Returns TRUE if the result parsed, FALSE otherwise.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	TERM,
	ERROR_LOC,
	NUM_SUBS,
	NUM_SAVED,
	INITIAL_TOKEN_PTR,
	NEW_TOKEN_PTR,
	POSS_SUBS : bitvector [PAT$DATA_NUM_TERM],
	PREF_SUBS : bitvector [PAT$DATA_NUM_TERM];
    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_EOL (),
	PUT_MSG_EOL ('Trying token substitution'));
    NUM_SAVED = PAT$TOKEN_SAVE_BUF (1);
    CLEAR (POSS_SUBS, NUM_BYTES);
    PAT$TOKEN_GET (FALSE);			! Find type of error token
    INITIAL_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
    PAT$TOKEN_RESET_BUFFER ();
    if ( not .PAT$LR_NEVER_SUBSTITUTE_FOR [LS_LEX_TERM (INITIAL_TOKEN_PTR)]) and
	( not LS_IS_EOF (LS_LEX_TERM (INITIAL_TOKEN_PTR)))	! Don't substitute for EOF
    then
	begin
	PAT$ERROR_GET_NEXT_TRANS_INIT (.LOCAL_ATTEMPT_STATUS, .PAT$STACK_P [.STACK_PTR, PATSTK_STATE],
	    .PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL]);

	while (TERM = PAT$ERROR_GET_NEXT_TRANSITION (TRUE)) neq PAT$ERROR_NO_MORE_TRANSITIONS do
	    if (.TERM neq LS_T_ERRORMARK) and 		! Don't replace with errormark
		(not LS_IS_EOF (.TERM)) 		! Don't replace with end-of-file
!		and (not LS_IS_RESERVED_WORD (.TERM))	! Don't replace with reserved word
	    then
		begin
		PAT$TOKEN_GET (FALSE);		! Try dropping error token
		PAT$TOKEN_CURRENT_PTR = SYNTHESIZE_TOKEN (.TERM);	! Try replacement for error token
		CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);
		if PARSE_AHEAD (PARSE_AHEAD_SUBSTITUTION)
		    then POSS_SUBS [.TERM] = TRUE;
		RESTORE_STATE ();
		end;
	NUM_SUBS = COUNT (POSS_SUBS, PAT$DATA_NUM_TERM);
	if .NUM_SUBS gtr 1
	then
	    begin
	    BLOCK_AND (POSS_SUBS, PAT$LR_PREFERRED_INSERTIONS, PREF_SUBS, NUM_BYTES);
	    NUM_SUBS = COUNT (PREF_SUBS, PAT$DATA_NUM_TERM);
	    end
	else
	    BLOCK_COPY (POSS_SUBS, PREF_SUBS, NUM_BYTES);
	if (.NUM_SUBS neq 1) and
	    (.POSS_SUBS [LS_T_IDENTIFIER]) and
	    LS_IS_RESERVED_WORD (LS_LEX_TERM (INITIAL_TOKEN_PTR))
	then
	    begin
	    CLEAR (PREF_SUBS, NUM_BYTES);
	    PREF_SUBS [LS_T_IDENTIFIER] = TRUE;
	    NUM_SUBS = 1;
	    end;
	if .NUM_SUBS eql 1
	then
	    begin
	    PAT$TOKEN_GET (TRUE);		! Really drop error token
	    NEW_TOKEN_PTR = SYNTHESIZE_TOKEN (WHICH_TERM (PREF_SUBS, PAT$DATA_NUM_TERM));
						! Get terminal selected
	    PAT$TOKEN_SAVE (.NEW_TOKEN_PTR, TRUE);	! Substitute correction token
	    DEB_EVENT ('PAR_RECOVERY_LOCAL',
		PUT_MSG ('Successfully substituted '),
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_LEX_TERM (NEW_TOKEN_PTR))),
		PUT_MSG (' for '),
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_LEX_TERM (INITIAL_TOKEN_PTR))),
		PUT_EOL ());
	    ERROR_LOC = LS_LEX_LOCATOR (INITIAL_TOKEN_PTR);
	    LS_ERROR_SUBST (.ERROR_LOC, .INITIAL_TOKEN_PTR, .NEW_TOKEN_PTR);
	    return TRUE
	    end;
	end
    else
	DEB_EVENT ('PAR_RECOVERY_LOCAL',
	    PUT_MSG ('No substitutions are allowed for the token '),
	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_LEX_TERM (INITIAL_TOKEN_PTR))),
	    PUT_EOL ());
    PAT$TOKEN_RESTORE_BUF (.NUM_SAVED);
    return FALSE
    end;					! Of routine TRY_SUBSTITUTE
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine TRY_INSERT =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Try to get input to parse by inserting a token.
!
! FORMAL PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	PAT$TOKEN_CURRENT_PTR
!	PAT$STACK_P
!	PAT$LR_PREFERRED_INSERTIONS
!
! IMPLICIT OUTPUTS:
!
!	PAT$TOKEN_CURRENT_PTR
!	CURRENT_SYMBOL
!
! ROUTINE VALUE:
!
!	Returns TRUE if the result parsed, FALSE otherwise.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	TERM,
	ERROR_LOC,
	NUM_INSERT,
	FOLLOW_TOKEN_1,
	FOLLOW_TOKEN_2,
	ENCOUNTERED_TOKEN_PTR,
	NEW_TOKEN_PTR,
	POSS_INSERT : bitvector [PAT$DATA_NUM_TERM],
	PREF_INSERT : bitvector [PAT$DATA_NUM_TERM];
    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_EOL (),
	PUT_MSG_EOL ('Trying token insertion'));

    CLEAR (POSS_INSERT, NUM_BYTES);
    FOLLOW_TOKEN_1 = PAT$TOKEN_GET (FALSE);	! Find type of error token
    ENCOUNTERED_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
    FOLLOW_TOKEN_2 = PAT$TOKEN_GET (FALSE);	! Find type of following token
    PAT$TOKEN_RESET_BUFFER ();
    PAT$ERROR_GET_NEXT_TRANS_INIT (.LOCAL_ATTEMPT_STATUS, .PAT$STACK_P [.STACK_PTR, PATSTK_STATE],
	.PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL]);

    while (TERM = PAT$ERROR_GET_NEXT_TRANSITION (TRUE)) neq PAT$ERROR_NO_MORE_TRANSITIONS do

	if ( not NEVER_INSERT_BEFORE (.TERM, .FOLLOW_TOKEN_1, .FOLLOW_TOKEN_2)) and
						! Don't insert if in table
	    (.TERM neq LS_T_ERRORMARK) and 	! Don't insert ERRORMARK
	    ( not LS_IS_EOF (.TERM))		! Don't insert end-of-file
	then
	    begin
	    PAT$TOKEN_CURRENT_PTR = SYNTHESIZE_TOKEN (.TERM);	! Try inserting new token
	    CURRENT_SYMBOL = LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR);

	    if PARSE_AHEAD (PARSE_AHEAD_INSERTION)
		then POSS_INSERT [.TERM] = TRUE;

	    RESTORE_STATE ();
	    end;
    NUM_INSERT = COUNT (POSS_INSERT, PAT$DATA_NUM_TERM);

    if .NUM_INSERT gtr 1
    then
	begin
	BLOCK_AND (POSS_INSERT, PAT$LR_PREFERRED_INSERTIONS, PREF_INSERT, NUM_BYTES);
	NUM_INSERT = COUNT (PREF_INSERT, PAT$DATA_NUM_TERM);
	end
    else
	BLOCK_COPY (POSS_INSERT, PREF_INSERT, NUM_BYTES);

    if .NUM_INSERT eql 1
    then
	begin
	NEW_TOKEN_PTR = SYNTHESIZE_TOKEN (WHICH_TERM (PREF_INSERT, PAT$DATA_NUM_TERM));
						! Get terminal selected
	PAT$TOKEN_SAVE (.NEW_TOKEN_PTR, TRUE);	! Insert correcting token
	DEB_EVENT ('PAR_RECOVERY_LOCAL',
	    PUT_MSG ('Successful insertion of '),
	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_LEX_TERM (NEW_TOKEN_PTR))),
	    PUT_EOL ());
	ERROR_LOC = LS_LEX_LOCATOR (ENCOUNTERED_TOKEN_PTR);
	LS_ERROR_INSERT (.ERROR_LOC, .NEW_TOKEN_PTR, .ENCOUNTERED_TOKEN_PTR);
	return TRUE
	end;

    return FALSE
    end;					! Of routine TRY_INSERT
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine NEVER_INSERT_BEFORE (INSERTION, FIRST_FOLLOWING, SECOND_FOLLOWING) =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	During an attempt to get user input to parse, determine if nothing
!	should ever be inserted before the token.
!
! FORMAL PARAMETERS:
!
!	INSERTION		the token to attept to insert
!	FIRST_FOLLOWING		the original error token
!	SECOND_FOLLOWING	the following token
!
! IMPLICIT INPUTS:
!
!	PAT$LR_NEVER_INSERT_BEFORE
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! ROUTINE VALUE:
!
!	Returns TRUE if no insertion should be done, FALSE otherwise.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    incr COUNTER from 0 to (LR_NUM_NIB - 1) do

	if (.INSERTION eql .PAT$LR_NEVER_INSERT_BEFORE [.COUNTER, LR_NIB_INSERTION]) and
	    (.FIRST_FOLLOWING eql .PAT$LR_NEVER_INSERT_BEFORE [.COUNTER, LR_NIB_CURTOK]) and
	    (.SECOND_FOLLOWING eql .PAT$LR_NEVER_INSERT_BEFORE [.COUNTER, LR_NIB_NEXTTOK])
	then
	    return TRUE;

    return FALSE
    end;
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine TRY_DELETE =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Try to get input to parse by deleting a token.
!
! FORMAL PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	PAT$TOKEN_CURRENT_PTR
!
! IMPLICIT OUTPUTS:
!
!	CURRENT_SYMBOL
!
! ROUTINE VALUE:
!
!	Returns TRUE if the result parsed, FALSE otherwise.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin
    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_EOL (),
	PUT_MSG_EOL ('Trying token deletion'));
    CURRENT_SYMBOL = PAT$TOKEN_GET (FALSE);	! Try dropping error token
    CURRENT_SYMBOL = PAT$TOKEN_GET (FALSE);	! Start with following token

    ! Add check to NEVER_DELETE (for generality) and
    ! PAT$LR_NEVER_DEL_UNLESS_ERR_TOK (for backtracking)

    if PARSE_AHEAD (PARSE_AHEAD_DELETION)
    then
	begin
	CURRENT_SYMBOL = PAT$TOKEN_GET (TRUE);	! Drop error token for real

	DEB_EVENT ('PAR_RECOVERY_LOCAL',
	    PUT_MSG ('Successful deletion of '),
	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL)),
	    PUT_EOL ());
	LS_ERROR_DELETED (LS_LEX_LOCATOR (PAT$TOKEN_CURRENT_PTR), .PAT$TOKEN_CURRENT_PTR);
	return TRUE
	end
    else
	return FALSE

    end;					! Of routine TRY_DELETE
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine SCOPE_RECOVERY (INIT_ONLY) =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Try to get input to parse by correcting scope errors.
!
! FORMAL PARAMETERS:
!
!	INIT_ONLY	TRUE if routine is being initialized only
!
! IMPLICIT INPUTS:
!
!	PAT$STACK_P
!	PRIOR_TOKEN_PTR
!	PAT$TOKEN_CURRENT_PTR
!	PAT$LR_ONLY_CLOSE_BEFORE
!	PAT$LR_CLOSER_TOKENS
!	PAT$LR_POINT_AT_PREV_TOKEN
!	PAT$LR_CLOSER_MATCH
!
! IMPLICIT OUTPUTS:
!
!	CURRENT_SYMBOL
!
! ROUTINE VALUE:
!
!	Returns TRUE if the result parsed, FALSE otherwise.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	SAVED_TEMP_HEAD,
	NUM_TOKENS,
	MATCH_LOC,
	ERROR_LOC,
	ENCOUNTERED_TOKEN_PTR,
	PREVIOUS_TOKEN_PTR,
	TEMP_STACK_PTR;

    own
	LAST_ERROR_LOCATOR;
    ! If only initializing, then initialize LAST_ERROR_LOCATOR.
    ! If there are two consecutive scope recoveries, the locator
    ! of the last error is used since the current token is a
    ! synthetic one.

    if .INIT_ONLY
    then
	begin
	LAST_ERROR_LOCATOR = 0;
	return FALSE
	end;

    ! If don't have a prior token, must be at the start of the source
    ! file so it's silly to try scope recovery.

    if .PRIOR_TOKEN_PTR eql NULL then return FALSE;

    DEB_EVENT ('PAR_RECOVERY_LOCAL',
	PUT_EOL (),
	PUT_MSG_EOL ('Trying scope recovery'));
    PAT$TOKEN_GET (FALSE);			! Get error token for locator info
    ENCOUNTERED_TOKEN_PTR = .PAT$TOKEN_CURRENT_PTR;
    PREVIOUS_TOKEN_PTR = .PRIOR_TOKEN_PTR;
    PAT$TOKEN_RESET_BUFFER ();
! Try inserting each scope closer:

    incr CLOSER from FIRST_LR_CLOSER to LAST_LR_CLOSER do

	if .PAT$LR_ONLY_CLOSE_BEFORE [.CLOSER, LS_LEX_TERM (ENCOUNTERED_TOKEN_PTR)]
	then
	    begin

	    decr COUNTER from .PAT$LR_CLOSER_TOKENS [.CLOSER, LR_NUM_TOKS_INDEX] to 1 do
		PAT$TOKEN_SAVE
		(SYNTHESIZE_TOKEN (.PAT$LR_CLOSER_TOKENS [.CLOSER, .COUNTER]),
		    FALSE);

	    SAVED_TEMP_HEAD = PAT$TOKEN_TEMP_HEAD ();
	    CURRENT_SYMBOL = PAT$TOKEN_GET (FALSE);

	    ! Don't use closer if it's meant for providing an error message
	    ! indicating an insertion before the token preceding the error
	    ! AND that token is not the same terminal as the last symbol
	    ! in the closer.

	    if not (.PAT$LR_POINT_AT_PREV_TOKEN [.CLOSER] and
		(LS_LEX_TERM (PREVIOUS_TOKEN_PTR) neq
		.PAT$LR_CLOSER_TOKENS [.CLOSER,
		    .PAT$LR_CLOSER_TOKENS [.CLOSER, LR_NUM_TOKS_INDEX]]))
	    then

		if PARSE_AHEAD (.PAT$LR_CLOSER_TOKENS [.CLOSER, LR_NUM_TOKS_INDEX])
		then
		    begin

		    ! Change the effect to the above calls to
		    ! PAT$TOKEN_SAVE (..., FALSE) to
		    ! PAT$TOKEN_SAVE (..., TRUE) by modifying the
		    ! head of the token buffer.

		    PAT$TOKEN_SET_HEAD (.SAVED_TEMP_HEAD);
		    ERROR_LOC = LS_LEX_LOCATOR (ENCOUNTERED_TOKEN_PTR);

		    if .PAT$LR_POINT_AT_PREV_TOKEN [.CLOSER]
		    then
			ERROR_LOC = LS_LEX_LOCATOR (PREVIOUS_TOKEN_PTR);

		    if .ERROR_LOC eql 0
		    then
			begin
			DEB_ASSERT (.LAST_ERROR_LOCATOR neq 0, 'LAST_ERROR_LOCATOR is 0');
			ERROR_LOC = .LAST_ERROR_LOCATOR;
			end
		    else
			LAST_ERROR_LOCATOR = .ERROR_LOC;

		    if .PAT$LR_CLOSER_MATCH [.CLOSER, LR_CLOSERS_STACK]
			   eql LR_NOT_MATCHED
		    then
			LS_ERROR_SCOPE_NO_MATCH (.ERROR_LOC, .PAT$LR_CLOSER_MESSAGE [.CLOSER],
			    .ENCOUNTERED_TOKEN_PTR)
		    else
			begin
			TEMP_STACK_PTR = .STACK_PTR;

			while ((TEMP_STACK_PTR = .TEMP_STACK_PTR - 1) neq -1) do

			    if .PAT$STACK_P [.TEMP_STACK_PTR, PATSTK_SYMBOL] eql
				.PAT$LR_CLOSER_MATCH [.CLOSER, LR_CLOSERS_STACK]
			    then
				begin
				MATCH_LOC = .PAT$STACK_P [.TEMP_STACK_PTR, PATSTK_LOCATOR];
				exitloop;
				end;

			! It's possible that there isn't a scope
			! opener on the stack since sometimes there
			! isn't a begin that goes with "end".  e.g.
			!
			!	package foo x:integer;
			!	<end-of-file>	-- missing "end;"

			if .TEMP_STACK_PTR eql -1 then return FALSE;

			LS_ERROR_SCOPE_MATCH (.ERROR_LOC,
			    .PAT$LR_CLOSER_MESSAGE [.CLOSER],
			    .PAT$LR_CLOSER_MATCH [.CLOSER, LR_CLOSERS_TERMINAL],
			    .MATCH_LOC);
			end;

		    return TRUE;
		    end;

	    RESTORE_STATE ();
	    end;

    return FALSE
    end;					! Of routine SCOPE_RECOVERY
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine FIND_BACKUP_ORDER (P_STATUS, P_P_STATUS) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Called from LOCAL_RECOVERY to determine from what states we should
!	begin local error recovery:
!	ORDER_A:	The current state where the error occurred, with
!			no backup (state A).
!	ORDER_B:	The error state, before any default reductions
!			(state B).
!	ORDER_BC:	The token before the error, before any default
!			reductions (state C), and then state B.
!
! FORMAL PARAMETERS:
!
!	P_STATUS	previous status (prior to error)
!	P_P_STATUS	previous status to P_STATUS
!
! IMPLICIT INPUTS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! ROUTINE VALUE:
!
!	ORDER_A, ORDER_B, or ORDER_BC, or FALSE if previous parse
!	state is not legal.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    selectone .P_STATUS of
	set

	[CONSUME_TERM_ON_SHIFT, CONSUME_TERM_ON_REDUCTION] :

	    if .P_P_STATUS eql SAVED_INFO_NOT_VALID
	    then
		return ORDER_B
	    else
		return ORDER_BC;

	[REDUCT_AFTER_BACKUP_NOT_ALLOWED] :
	    return ORDER_B;

	[SAVED_INFO_NOT_VALID, CONSUME_NONTERM_ON_SHIFT] :
	    return ORDER_A;
	tes;

    DEB_ASSERT (FALSE, 'Previous status is of illegal status type');
    return FALSE;
    end;					! Of routine FIND_BACKUP_ORDER
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine SYNTHESIZE_TOKEN (TERM_TYPE) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	SYNTHESIZE_TOKEN creates a synthetic lexical token.
!
! FORMAL PARAMETERS:
!
!	TERM_TYPE	Initial terminal symbol for the token.
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NEW_TOKEN_PTR	Pointer to synthetic token created by this routine.
!
! SIDE EFFECTS:
!
!	The TKN_TERM and TKN_SYNTHETIC fields of NEW_TOKEN_PTR are set.
!
!--

    begin

    local
	NEW_TOKEN_PTR;

    NEW_TOKEN_PTR = SYN_TOK_STORAGE [.NEXT_SYN_TOK_INDEX, 0, 0, 0, 0];
    LS_LEX_SET_SYNTHETIC (NEW_TOKEN_PTR);
    LS_LEX_SET_TERM (NEW_TOKEN_PTR, .TERM_TYPE);
    NEXT_SYN_TOK_INDEX = .NEXT_SYN_TOK_INDEX + 1;

    if .NEXT_SYN_TOK_INDEX eql MAX_NUM_SYN_TOKS then NEXT_SYN_TOK_INDEX = 0;

    return .NEW_TOKEN_PTR
    end;
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine SAVE_STATE : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Save the state of the parse stack.  This state can be restored
!	by the routine RESTORE_STATE.
!
! FORMAL PARAMETERS:
!
!	NONE
!
! IMPLICIT INPUTS:
!
!	STACK_PTR
!
!	PAR_LOOKAHEAD_F
!
!	REDUCTION_CODE
!
! IMPLICIT OUTPUTS:
!
!	SAVED_STACK_PTR
!
!	SAVED_PAR_LOOKAHEAD_F
!
!	SAVED_REDUCTION_CODE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS:
!
!	NONE
!
!--

    begin
    SAVED_STACK_PTR = .STACK_PTR;
    incr p from 1 to (.STACK_PTR + 1) do
	begin
	ref_alt_parse_stack [.P-1, PATSTK_LOCATOR]
	    = .ref_parse_stack [.P-1, PATSTK_LOCATOR];
	%if PATBLSEXT_EXTRA_STACK_FIELD
	%then
	ref_alt_parse_stack [.P-1, PATSTK_EXTRA_INFO]
	    = .ref_parse_stack [.P-1, PATSTK_EXTRA_INFO];
	%fi
	ref_alt_parse_stack [.P-1, PATSTK_SYMBOL]
	    = .ref_parse_stack [.P-1, PATSTK_SYMBOL];
	ref_alt_parse_stack [.P-1, PATSTK_TOKEN]
	    = .ref_parse_stack [.P-1, PATSTK_TOKEN];
	ref_alt_parse_stack [.P-1, PATSTK_ERRORMARK]
	    = .ref_parse_stack [.P-1, PATSTK_ERRORMARK];
	ref_alt_parse_stack [.P-1, PATSTK_STATE]
	    = .ref_parse_stack [.P-1, PATSTK_STATE];
	end;
    SAVED_PAR_LOOKAHEAD_F = .PAR_LOOKAHEAD_F;
    SAVED_REDUCTION_CODE = .REDUCTION_CODE;
    PAT$TOKEN_RESET_BUFFER ();
    end;					! Of routine SAVE_STATE
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine RESTORE_STATE : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Restore the state that the parse stack was in before SAVE_STATE
!	was last called.
!
! FORMAL PARAMETERS:
!
!	NONE
!
! IMPLICIT INPUTS:
!
!	SAVED_STACK_PTR
!
!	SAVED_PAR_LOOKAHEAD_F
!
!	SAVED_REDUCTION_CODE
!
! IMPLICIT OUTPUTS:
!
!	STACK_PTR
!
!	PAT$TOKEN_CURRENT_PTR
!
!	PAR_LOOKAHEAD_F
!
!	REDUCTION_CODE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS:
!
!	NONE
!
!--

    begin
    STACK_PTR = .SAVED_STACK_PTR;
    PAR_LOOKAHEAD_F = .SAVED_PAR_LOOKAHEAD_F;
    REDUCTION_CODE = .SAVED_REDUCTION_CODE;
    PAT$TOKEN_RESET_BUFFER ();
    end;					! Of routine RESTORE_STATE
%fi
%if PATBLSEXT_LOCAL_RECOVERY
%then
routine DOWN_CASE (IN, OUT) : novalue =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Converts a string to lower case.
!
! FORMAL PARAMETERS:
!
!	IN		XPORT descriptor of original string
!	OUT		XPORT descriptor of resulting string
!
! IMPLICIT INPUTS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    bind
		    DOWNCASE_TABLE = ch$transtable (! 004
		    %c' ', %c' ', %c' ', %c' ',	! 004 NUL, SOH, STX, ETX
		    %c' ', %c' ', %c' ', %c' ',	! 004 EOT, ENQ, ACK, BEL
		    %c' ', %c' ', %c' ', %c' ',	! 004  BS,  HT,  LF,  VT
		    %c' ', %c' ', %c' ', %c' ',	! 004  FF,  CR,  SO,  SI
		    %c' ', %c' ', %c' ', %c' ',	! 004 DLE, DC1, DC2, DC3
		    %c' ', %c' ', %c' ', %c' ',	! 004 DC4, NAK, SYN, ETB
		    %c' ', %c' ', %c' ', %c' ',	! 004 CAN,  EM, SUB, ESC
		    %c' ', %c' ', %c' ', %c' ',	! 004  FS,  GS,  RS,  US
		    %c' ', %c' ', %c' ', %c' ',	! 004  SP,   !,   ",   #
		    %c'$', %c' ', %c' ', %c' ',	! 004   $,   %,   &,   '
		    %c' ', %c' ', %c' ', %c' ',	! 004   (,   ),   *,   +
		    %c' ', %c'-', %c'.', %c' ',	! 004   ,,   -,   .,   /
		    %c'0', %c'1', %c'2', %c'3',	! 004   0,   1,   2,   3
		    %c'4', %c'5', %c'6', %c'7',	! 004   4,   5,   6,   7
		    %c'8', %c'9', %c' ', %c' ',	! 004   8,   9,   :,   ;
		    %c' ', %c' ', %c' ', %c' ',	! 004   <,   =,   >,   ?
		    %c' ', %c'a', %c'b', %c'c',	! 004   @,   A,   B,   C
		    %c'd', %c'e', %c'f', %c'g',	! 004   D,   E,   F,   G
		    %c'h', %c'i', %c'j', %c'k',	! 004   H,   I,   J,   K
		    %c'l', %c'm', %c'n', %c'o',	! 004   L,   M,   N,   O
		    %c'p', %c'q', %c'r', %c's',	! 004   P,   Q,   R,   S
		    %c't', %c'u', %c'v', %c'w',	! 004   T,   U,   V,   W
		    %c'x', %c'y', %c'z', %c' ',	! 004   X,   Y,   Z,   [
		    %c' ', %c' ', %c' ', %c'_',	! 004   \,   ],   ^,   _
		    %c' ', %c'a', %c'b', %c'c',	! 004   `,   a,   b,   c
		    %c'd', %c'e', %c'f', %c'g',	! 004   d,   e,   f,   g
		    %c'h', %c'i', %c'j', %c'k',	! 004   h,   i,   j,   k
		    %c'l', %c'm', %c'n', %c'o',	! 004   l,   m,   n,   o
		    %c'p', %c'q', %c'r', %c's',	! 004   p,   q,   r,   s
		    %c't', %c'u', %c'v', %c'w',	! 004   t,   u,   v,   w
		    %c'x', %c'y', %c'z', %c' ',	! 004   x,   y,   z,   {
		    %c' ', %c' ', %c' ', %c' ');! 004   |,   },   ~, DEL

    map
	IN: ref $STR_DESCRIPTOR (),					! 004
	OUT: ref $STR_DESCRIPTOR ();					! 004

    OUT [STR$H_LENGTH] = .IN [STR$H_LENGTH];				! 004
    ch$translate (DOWNCASE_TABLE, .IN [STR$H_LENGTH], .IN [STR$A_POINTER], ! 004
	0, .OUT [STR$H_LENGTH], .OUT [STR$A_POINTER]);			! 004
    end;					! Of routine DOWN_CASE
%fi
%if PATBLSEXT_DEBUGGING
%then

global routine PAT$DUMP_TOKS : novalue =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Debugging routine to  output several tokens
!	and symbols which are relevant to the state of the parse.
!
! FORMAL PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	PAT$DATA_SYMBOL_TEXT
!	PAT$TOKEN_CURRENT_PTR
!	LATEST_TOKEN_PTR
!	PRIOR_TOKEN_PTR
!
! IMPLICIT OUTPUTS:
!
!	None
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	Displays lexical token information on the terminal.
!
!--

    begin
    PUT_MSG_EOL ('PAT$DUMP_TOKS :');
    PUT_MSG ('Current symbol:	');
    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL));
    PUT_EOL ();
    PUT_EOL ();

    if .HAVE_INITIAL_SYMBOL
    then
	begin
	PUT_MSG ('Initial symbol:	');
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.INITIAL_SYMBOL));
	PUT_EOL ();
	end
    else
	PUT_MSG_EOL ('No initial symbol');

    PUT_EOL ();
    PUT_MSG_EOL ('Current lexical token (PAT$TOKEN_CURRENT_PTR):');
    LS_DUMP_TOK (.PAT$TOKEN_CURRENT_PTR);
    PUT_EOL ();
    PUT_MSG_EOL ('Most recently read lexical token (LATEST_TOKEN_PTR):');

    if .LATEST_TOKEN_PTR neq NULL
    then
	begin
	LS_DUMP_TOK (.LATEST_TOKEN_PTR);
	PUT_EOL ();
	end
    else
	PUT_MSG_EOL ('NULL');

    PUT_EOL ();
    PUT_MSG_EOL ('Lexical token read prior to one above (PRIOR_TOKEN_PTR):');

    if .PRIOR_TOKEN_PTR neq NULL
    then
	begin
	LS_DUMP_TOK (.PRIOR_TOKEN_PTR);
	PUT_EOL ();
	end
    else
	PUT_MSG_EOL ('NULL');

    PUT_EOL ();
    end;					! Of PAT$DUMP_TOKS

%fi
%if PATBLSEXT_DEBUGGING and PATBLSEXT_LOCAL_RECOVERY
%then

global routine PAT$DUMP_BACKUP_INFO : novalue =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Displays backup information useful in understanding
!	the order in which error recovery will perform backup.
!
! FORMAL PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	Writes to the user's terminal.
!
!--

    begin

    local
	STATUS,
	ORDER;

    macro
	PUT_STATUS (STAT) =
	    selectone (STAT) of
		set
		[CONSUME_TERM_ON_REDUCTION] :
		    PUT_MSG ('"consuming a terminal on a reduction"');

		[CONSUME_TERM_ON_SHIFT] :
		    PUT_MSG ('"consuming a terminal on a shift"');

		[REDUCT_AFTER_BACKUP_NOT_ALLOWED] :
		    PUT_MSG ('"reduction disallowed further backup"');

		[SAVED_INFO_NOT_VALID] :
		    PUT_MSG ('"saved information is not valid for further backup"');

		[ERROR_ENCOUNTERED] :
		    PUT_MSG ('"error encountered"');
		tes %;
    ORDER = FIND_BACKUP_ORDER (.PREV_STATUS, .PREV_PREV_STATUS);
    PUT_MSG_EOL ('PAT$DUMP_BACKUP_INFO :');
    PUT_MSG_EOL ('If local error recovery were to begin now, the following');
    PUT_MSG_EOL ('state(s) would be tried in the order indicated below.');
    PUT_MSG_EOL ('Strong local recovery would be tried from all of those states,');
    PUT_MSG_EOL ('then weak local recovery would be tried from the same states.');
    PUT_EOL ();

!    selectone .ORDER of
!	set
!
!	[ORDER_A] :
!
!	    ! Start from state A (state when error encountered)
!
!	    begin
!	    PUT_MSG_EOL ('(A)  [State where error was encountered.]');
!	    PUT_MSG ('     The current symbol was ');
!	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL));
!	    PUT_MSG (' and the state was ');
!	    PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]);
!	    PUT_EOL ();
!	    PUT_EOL ();
!	    end;
!
!	[otherwise] :
!	;
!	tes;
    selectone .ORDER of
	set

	[ORDER_B, ORDER_BC] :

	    ! Try from state B (error state prior to default reductions)

	    begin
	    PUT_MSG_EOL ('(B)  [Error state prior to default reductions.]');
	    PUT_MSG ('     The current symbol was ');

	    selectone .PREV_STATUS of
		set

		[CONSUME_TERM_ON_REDUCTION, REDUCT_AFTER_BACKUP_NOT_ALLOWED] :
		    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.PREV_STACK_RECORD [PATSTK_SYMBOL]));

		[otherwise] :
		    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL));
		tes;

	    PUT_MSG ('.  At that point the state was ');
	    PUT_NUMBER (.PAT$STACK_P [.PREV_STACK_PTR, PATSTK_STATE]);
	    PUT_EOL ();
	    PUT_MSG ('     and the most recent status was ');
	    PUT_STATUS (.PREV_STATUS);
	    PUT_MSG_EOL ('.');
	    PUT_EOL ();
	    end;

	[otherwise] :
	;
	tes;
    selectone .ORDER of
	set

	[ORDER_BC] :

	    ! Try from state C (one token before error token, prior to default reductions)

	    begin
	    PUT_MSG_EOL ('(C)  [Before reading latest token, prior to default reductions.]');
	    PUT_MSG ('     The current symbol was ');

	    selectone .PREV_PREV_STATUS of
		set

		[CONSUME_TERM_ON_REDUCTION, REDUCT_AFTER_BACKUP_NOT_ALLOWED] :
		    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.PREV_PREV_STACK_RECORD [PATSTK_SYMBOL]));

		[otherwise] :
		    PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_LEX_TERM (PRIOR_TOKEN_PTR)));
		tes;

	    PUT_MSG ('.  At that point the state was ');
	    PUT_NUMBER (.PAT$STACK_P [.PREV_PREV_STACK_PTR, PATSTK_STATE]);
	    PUT_EOL ();
	    PUT_MSG ('     and the most recent status was ');
	    PUT_STATUS (.PREV_PREV_STATUS);
	    PUT_MSG_EOL ('.');
	    PUT_MSG ('     The token which will be read next is ');
	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_LEX_TERM (LATEST_TOKEN_PTR)));
	    PUT_EOL ();
	    PUT_EOL ();
	    end;

	[otherwise] :
	;
	tes;
! Move this code here to reflect that we will always try from state A.

	    ! Start from state A (state when error encountered)

	    PUT_MSG_EOL ('(A)  [State where error was encountered.]');
	    PUT_MSG ('     The current symbol was ');
	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL));
	    PUT_MSG (' and the state was ');
	    PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]);
	    PUT_EOL ();
	    PUT_EOL ();
    PUT_MSG ('Global error recovery will always begin in state ');
    PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]);
    PUT_EOL ();
    PUT_MSG ('with the current symbol ');
!    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL));
    PUT_STRING (PAT$DATA_SYMBOL_TEXT (LS_LEX_TERM (PAT$TOKEN_CURRENT_PTR)));
    PUT_MSG_EOL ('.  The global recovery');
    PUT_MSG ('error message will indicate symbols expected in state ');
    if .PREV_STATUS eql SAVED_INFO_NOT_VALID
    then
	begin
	PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]);
	PUT_EOL ();
	PUT_MSG ('with the status ');
	STATUS = ERROR_ENCOUNTERED;
	PUT_STATUS (.STATUS);
	PUT_EOL ();
	PUT_MSG ('and the current symbol ');
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL));
	end
    else
	begin
	PUT_NUMBER (.PREV_STACK_RECORD [PATSTK_STATE]);
	PUT_EOL ();
	PUT_MSG ('with the status ');
	PUT_STATUS (.PREV_STATUS);
	PUT_EOL ();
	PUT_MSG ('and the current symbol ');
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.PREV_STACK_RECORD [PATSTK_SYMBOL]));
	end;

    PUT_EOL ();

    if .PREV_STATUS eql REDUCT_AFTER_BACKUP_NOT_ALLOWED
    then
	begin
	PUT_MSG ('and state ');
	PUT_NUMBER (.GLOBAL_MSG_INIT_STATE);
	PUT_MSG_EOL (' with the status ');
	PUT_STATUS (.GLOBAL_MSG_STATUS);
	PUT_MSG (' and the current symbol ');
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.GLOBAL_MSG_SYMBOL));
	PUT_EOL ();
	end;

    end;					! Of PAT$DUMP_BACKUP_INFO

%fi
%if PATBLSEXT_DEBUGGING
%then

global routine PAT$DUMP_PARSE_STACK : novalue =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Debugging routine to display the contents of the parse stack.
!
! FORMAL PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	STACK_PTR
!	PAT$STACK_P
!
! IMPLICIT OUTPUTS:
!
!	None
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	Contents of the parse stack are displayed on the terminal.
!
!--
    begin

    macro
	SPACE =
	    ' ' %;
    macro
	TAB =
	    '	' %;
    local
	S_PTR,
	SYMBOL,
	ACTION_NUM,
	LHS_SYMBOL,
	RHS_COUNT,
	SEMACT,
	NEW_PTR;

    if .REDUCTION_CODE lss 0
    then
	NEW_PTR = -1
    else
	begin
	PAT$DATA_GET_REDUCTION_INFO (.REDUCTION_CODE, LHS_SYMBOL, RHS_COUNT, SEMACT);
	if .PAR_LOOKAHEAD_F then NEW_PTR = .STACK_PTR - .RHS_COUNT else NEW_PTR = .STACK_PTR - .RHS_COUNT + 1;
	end;
    PUT_MSG_EOL ('PAT$DUMP_PARSE_STACK:');
    PUT_MSG_EOL ('stack	state');

%if PATBLSEXT_EXTRA_STACK_FIELD
%then
    PUT_MSG_EOL ('index	index	locator  comment  symbol');
%else
    PUT_MSG_EOL ('index	index	locator  symbol');
%fi

    incr I from 0 to .STACK_PTR - 1 do
	begin
	PUT_NUMBER (.I);
	PUT_MSG (TAB);
	S_PTR = .I;
	SYMBOL = .PAT$STACK_P [.S_PTR, PATSTK_SYMBOL];
	PUT_NUMBER (.PAT$STACK_P [.S_PTR, PATSTK_STATE]);
	PUT_MSG (TAB);
	PUT_HEX_LONG (.PAT$STACK_P [.S_PTR, PATSTK_LOCATOR]);
	PUT_MSG (SPACE);

%if PATBLSEXT_EXTRA_STACK_FIELD
%then
	PUT_HEX_LONG (.PAT$STACK_P [.S_PTR, PATSTK_EXTRA_INFO]);
	PUT_MSG (SPACE);
%fi

	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.SYMBOL));

	if .I eql .NEW_PTR
	then
	    begin
	    PUT_MSG ('	Reduce to:  ');
	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.LHS_SYMBOL));
	    end;

	PUT_EOL ();
	end;

    PUT_NUMBER (.STACK_PTR);
    PUT_MSG (TAB);
    PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]);

    if .REDUCTION_CODE geq 0
    then

    ! Process the top-most stack entry for a reduction.

	begin
	PUT_MSG (TAB);
	PUT_HEX_LONG (.PAT$STACK_P [.STACK_PTR, PATSTK_LOCATOR]);

%if PATBLSEXT_EXTRA_STACK_FIELD
%then
	PUT_MSG (SPACE);
	PUT_HEX_LONG (.PAT$STACK_P [.STACK_PTR, PATSTK_EXTRA_INFO]);
%fi

	if .NEW_PTR eql .STACK_PTR
	then

	! NEW_PTR is the same as STACK_PTR if this is a lookahead
	! epsilon reduction or if it's a non-lookahead reduction
	! with one symbol on the right hand side.

	    if .RHS_COUNT eql 0
	    then
		begin
		! This is a lookahead epsilon reduction.
		PUT_MSG (SPACE);
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (.LHS_SYMBOL));
		PUT_MSG ('	Reduction:  ');
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (.LHS_SYMBOL));
		PUT_MSG (' = epsilon');
		end
	    else
		if .RHS_COUNT eql 1
		then
		    begin
		    ! This is a non-lookahead reduction with one symbol on the rhs
		    PUT_MSG (SPACE);
		    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL]));
		    PUT_MSG ('	Reduce to:  ');
		    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.LHS_SYMBOL));
		    end
		else
		    PUT_MSG_EOL ('PAT$DUMP_PARSE_STACK makes an incorrect assumption about the parse stack!')
	else

	! This is a another kind of reduction.

	    if not .PAR_LOOKAHEAD_F
	    then
		begin
		PUT_MSG (SPACE);
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (.PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL]));
		end;
	end;

    PUT_EOL ();
    end;					! Of routine PAT$DUMP_PARSE_STACK

%fi
%if PATBLSEXT_DEBUGGING
%then

global routine PAT$DUMP_REDUCTION : novalue =

!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Debugging routine to do a symbolic display of the
!	current reduction, including the contents of the current
!	parse stack.
!
! FORMAL PARAMETERS:
!
!	None.
!
! IMPLICIT INPUTS:
!
!	STACK_PTR
!	PAT$STACK_P
!
! IMPLICIT OUTPUTS:
!
!	None
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	Reduction information is displayed on the terminal.
!
!--

    begin

    literal
	CONT_INDENT = 17;

    local
	pblank: $STR_DESCRIPTOR (string=' '),				! 004
	S_PTR,
	L_PTR,
	R_PTR,
	SYMBOL,
	LHS_SYMBOL,
	RHS_COUNT,
	SEMACT,
	ACTION_NUM;

    if .REDUCTION_CODE lss 0
    then
	begin
	PUT_MSG_EOL ('PAT$DUMP_REDUCTION:  There is no current reduction.');
	return
	end;

    PAT$DATA_GET_REDUCTION_INFO (.REDUCTION_CODE, LHS_SYMBOL, RHS_COUNT, SEMACT);

    if .PAR_LOOKAHEAD_F
    then
	begin
	L_PTR = .STACK_PTR - .RHS_COUNT;
	R_PTR = .STACK_PTR - 1;
	end
    else
	begin
	L_PTR = .STACK_PTR - .RHS_COUNT + 1;
	R_PTR = .STACK_PTR;
	end;

    PUT_MSG ('  Reduction:    ');
    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.LHS_SYMBOL));
    PUT_MSG (' = ');

    if .RHS_COUNT eql 0
    then
	PUT_MSG ('epsilon')
    else
	begin
	PUT_START_AUTOEOL (CONT_INDENT,					! 004
	    .pblank [STR$H_LENGTH], .pblank [STR$A_POINTER]);		! 004

	incr I from .L_PTR to .R_PTR do
	    begin
	    S_PTR = .I;
	    SYMBOL = .PAT$STACK_P [.S_PTR, PATSTK_SYMBOL];
	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.SYMBOL));
	    end;

	PUT_END_AUTOEOL ();
	end;

    PUT_EOL ();
    PUT_MSG ('  Parse stack:  ');
    PUT_START_AUTOEOL (CONT_INDENT, pblank);				! 004

    incr I from 0 to .L_PTR - 1 do
	begin
	S_PTR = .I;
	SYMBOL = .PAT$STACK_P [.S_PTR, PATSTK_SYMBOL];
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.SYMBOL));
	end;

    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.LHS_SYMBOL));
    PUT_END_AUTOEOL ();
    PUT_EOL ();
    end;					! Of routine PAT$DUMP_REDUCTION

%fi

end						! End of module

eludom