Google
 

Trailing-Edge - PDP-10 Archives - BB-JF18A-BM - sources/diu/diuper.bli
There are 4 other files named diuper.bli in the archive. Click here to see a list.
MODULE DIUPER (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:
!
! 	PATERROR.BLI contains routines that are common to both
!	local and global error recovery.
!
! ENVIRONMENT:	VAX/VMS user mode
!
! AUTHORS:  H. Alcabes, C. Mitchell, CREATION DATE:  25-Feb-80
!
! MODIFIED BY:
!
!  253  Rename file to DIUPER.
!       Gregory A. Scott 1-Jul-86
!
! 002 - C. Richardson 13 Aug 85
!	Allow debug compilation without debug output
!
! 	Charlie Mitchell, 02-Nov-1981 : VERSION X2-001
! 001 -	Modify to use new PATDATA; reorganize to just contain routines
!	common to both local and global error recovery.
!
! 002 - Remove VMS dependencies.  C. Richardson 29-May-84
!--
!
! INCLUDE FILES:
!

require 'DIUPATPROLOG';

library 'BLI:XPORT';				! 002

library 'DIUPATERROR';

library 'DIUPATDATA';                   ! PAT/BLISS interface

library 'DIUPATLANGSP';                 ! Language Specific functions

library 'DIUPATPARSER';                 ! Parser driver

library 'DIUPATTOKEN';

library 'DIUDEB';                       ! Debugging

!
! TABLE OF CONTENTS FOR INTERNAL ROUTINES
!

forward routine
    EXPLORE_TRANSITIONS : novalue,		! Set tables for a transition
    FIND_NEXT_REDUCTION,			! Result of next reduction
    GNT_PARSE_UNTIL_SHIFT;			! Parse until shift occurs

!
! MACROS:
!

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

literal
    GNT_MAX_PARSE_STACK_INDEX = 4;

!
! OWN STORAGE:
!

own
    GNT_STATUS,
    GNT_LAST_TRANSITION,
    GNT_PARSE_STACK_INDEX,
    GNT_PARSE_STACK : vector [GNT_MAX_PARSE_STACK_INDEX + 1];
global routine PAT$ERROR_GLOBAL_RECOVERY (PREV_STACK_RECORD, PREV_STATUS, GLOBAL_MSG_STATUS, GLOBAL_MSG_SYMBOL
    , GLOBAL_MSG_INIT_STATE, ERROR_TOKEN_PTR, REF_STACK_PTR, REF_CURRENT_SYMBOL) : novalue =

!++
!
! FUNCTIONAL DESCRIPTION:
!
! Called when a syntax error that local and scope recovery cannot repair
! has occurred; it skips over source until a synchronizing token is found.
!
! FORMAL PARAMETERS:
!
!	PREV_STACK_RECORD	?
!	PREV_STATUS		?
!	GLOBAL_MSG_STATUS	?
!	GLOABL_MSG_SYMBOL	?
!	GLOBAL_MSG_INIT_STATE	?
!	ERROR_TOKEN_PTR		?
!	REF_STACK_PTR		?
!	REF_CURRENT_SYMBOL	?
!
! IMPLICIT INPUTS:
!
!	?
!
! IMPLICIT OUTPUTS:
!
!	?
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    map
	PREV_STACK_RECORD : ref block [PATSTK_STR_SIZE/%upval] field (PATSTK_FIELDS);

    bind
	STACK_PTR = .REF_STACK_PTR,
	CURRENT_SYMBOL = .REF_CURRENT_SYMBOL;

    field
	FOLLOWER_FIELDS =
	    set
		FOLLOWER_F	= [$INTEGER],	! Terminal that can follow errormark
		STACKPTR_F	= [$INTEGER],	! The parse stack pointer of the ERRORMARKed state
		ERRORMARK_F	= [$INTEGER],	! (Not used)
		INDEX_F		= [$INTEGER]	! The state which the ERRORMARK transition shifts to
	    tes;

    literal
	follower_size		= $field_set_size * %upval;

    local
	FOLLOWER_TABLE : blockvector [PAT$DATA_NUM_TERM, follower_size]
	    field (FOLLOWER_FIELDS),
	STATE_INDEX,
	FOLLOWER_TOP,
	RESULT,
	SAVE_SP,
	TERMINAL,
	ACTION_CODE,
	BACK_STATE,
	BACK_SYMBOL,
	BAD_NON_TERM,
	ERRORMARK_STACK : bitvector [LS_PARSE_STACK_SIZE],
	TERMS_TO_PRINT : bitvector [PAT$DATA_NUM_TERM],
	GROUP_NONTERMS_SEEN : bitvector [LS_NUM_GROUP_NONTERMS];

    label
	SEARCH;

    DEB_EVENT ('PAR_RECOVERY_GLOBAL',
	PUT_MSG_EOL ('-----------------------------------------------------'),
	PUT_MSG ('Starting global recovery - CURRENTSTATE  is '),
	PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]),
	PUT_MSG ('.  Current symbol is '),
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL)),
	PUT_EOL (),
	PUT_EOL (),
	PAT$DUMP_PARSE_STACK (),
	PUT_EOL ());
!    CLEAR (ERRORMARK_STACK, %allocation (ERRORMARK_STACK));
    CLEAR (ERRORMARK_STACK, LS_PARSE_STACK_SIZE);
    BACK_STATE = .PREV_STACK_RECORD [PATSTK_STATE];
    BACK_SYMBOL = .PREV_STACK_RECORD [PATSTK_SYMBOL];
    FOLLOWER_TOP = -1;				! Empty the follower table
    SAVE_SP = .STACK_PTR;
! For each entry in the parse stack check if any of the ERRORMARK terminals
! can follow as legal transitions. If so then collect the terminals
! which may follow each.

    do
	begin
	ACTION_CODE = PAT$DATA_MOVE_ACTION (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE], LS_T_ERRORMARK);

!! Currently the only ERRORMARKS that recovery can take place on
!! are those on which a SHIFT occurs.  This can be improved
!! so that global error recovery can be even more effective.

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

	    ! This state has an ERRORMARK transition associated with it -
	    ! this must be a SHIFT transition otherwise its position within
	    ! the syntax definition is incorrect.

	    DEB_EVENT ('PAR_RECOVERY_GLOBAL',
		PUT_MSG ('Parse stack entry '),
		PUT_NUMBER (.STACK_PTR),
		PUT_MSG (' has an ERRORMARK transition from index '),
		PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]),
		PUT_EOL ());

	    ! Mark this state in a stack parallel to the parse stack
	    ! as having an ERRORMARK transition

	    ERRORMARK_STACK [.STACK_PTR] = TRUE;
	    ! Perform the ERRORMARK shift and collect all the terminals that
	    ! can follow it in FOLLOWER_TABLE, taking care not to duplicate any
	    ! terminals already entered there from a higher stacked state.

	    PAT$ERROR_GET_NEXT_TRANS_INIT (CONSUME_TERM_ON_SHIFT, .ACTION_CODE, LS_UNAVAILABLE_NT);

	    while (TERMINAL = PAT$ERROR_GET_NEXT_TRANSITION (TRUE)) neq PAT$ERROR_NO_MORE_TRANSITIONS do
SEARCH :
		begin

		incr I from 0 to .FOLLOWER_TOP do

		    if .FOLLOWER_TABLE [.I, FOLLOWER_F] eqlu .TERMINAL then leave SEARCH;

		! Enter this terminal in FOLLOWER_TABLE along with the stack
		! pointer and errormark values.

		DEB_EVENT ('PAR_RECOVERY_GLOBAL',
		    PUT_MSG ('	Adding new synchronizing symbol '),
		    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.TERMINAL)),
		    PUT_EOL ());
		FOLLOWER_TABLE [(FOLLOWER_TOP = .FOLLOWER_TOP + 1), FOLLOWER_F] = .TERMINAL;
		FOLLOWER_TABLE [.FOLLOWER_TOP, STACKPTR_F] = .STACK_PTR;
		FOLLOWER_TABLE [.FOLLOWER_TOP, INDEX_F] = .ACTION_CODE;
		end;

	    end;

	end
    until (STACK_PTR = .STACK_PTR - 1) eql -1;

    ! Have now collected the list of all follower terminals for all ERRORMARKed
    ! states in the parse stack.  Throw away source until one the these is
    ! found.  NOTE that EOF had better be there.

    while (incr I from 0 to .FOLLOWER_TOP do
	    if .FOLLOWER_TABLE [.I, FOLLOWER_F] eql .CURRENT_SYMBOL then
		begin
		STATE_INDEX = .I;
		exitloop FALSE;
		end
	) do
	begin
	DEB_EVENT ('PAR_RECOVERY_GLOBAL',
	    PUT_MSG ('Skipping symbol '),
	    PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL)),
	    PUT_EOL ());
	CURRENT_SYMBOL = PAT$TOKEN_GET (TRUE);
	end;
    ! FOLLOWER_TABLE [state_index] contains the stack pointer at which the
    ! match occurred.  Because of the way the table was constructed this will
    ! be the topmost state in the stack where this transition is legal. For
    ! all the intervening errormarked stack entries generate the errormark
    ! actions.

    DEB_EVENT ('PAR_RECOVERY_GLOBAL',
	PUT_MSG ('Current symbol is '),
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL)),
	PUT_MSG_EOL (' which is a synchronizing symbol'));
    STACK_PTR = .SAVE_SP;
    ERRORMARK_STACK [.STACK_PTR] = FALSE;
    STACK_PTR = .STACK_PTR - 1;

    while .STACK_PTR geq 0 do
	begin
	ERRORMARK_STACK [.STACK_PTR] = FALSE;

	if .STACK_PTR geq .FOLLOWER_TABLE [.STATE_INDEX, STACKPTR_F]
	then
	    DEB_EVENT ('PAR_RECOVERY_GLOBAL',
		PUT_MSG ('Popping state associated with '),
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (.PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL])),
		PUT_EOL ());

	STACK_PTR = .STACK_PTR - 1;
	end;
    ! Now reset the parsing variables to the state they would be in if
    ! ERRORMARK had been parsed from the recovered state.

    STACK_PTR = .FOLLOWER_TABLE [.STATE_INDEX, STACKPTR_F];
    PAT$STACK_P [.STACK_PTR, PATSTK_SYMBOL] = LS_T_ERRORMARK;
    STACK_PTR = .STACK_PTR + 1;
    PAT$STACK_P [.STACK_PTR, PATSTK_STATE] = .FOLLOWER_TABLE [.STATE_INDEX, INDEX_F];	! set current state
    BAD_NON_TERM = FIND_NEXT_REDUCTION (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE], .CURRENT_SYMBOL);
!    CLEAR (TERMS_TO_PRINT, %allocation (TERMS_TO_PRINT));
    CLEAR (TERMS_TO_PRINT, PAT$DATA_NUM_TERM);
!    CLEAR (GROUP_NONTERMS_SEEN, %allocation (GROUP_NONTERMS_SEEN));
    CLEAR (GROUP_NONTERMS_SEEN, LS_NUM_GROUP_NONTERMS);

    if .PREV_STATUS eql SAVED_INFO_NOT_VALID
    then
	EXPLORE_TRANSITIONS (ERROR_ENCOUNTERED,
	    .PAT$STACK_P [.STACK_PTR, PATSTK_STATE], .CURRENT_SYMBOL, GROUP_NONTERMS_SEEN, TERMS_TO_PRINT)
    else
	EXPLORE_TRANSITIONS (.PREV_STATUS, .BACK_STATE, .BACK_SYMBOL, GROUP_NONTERMS_SEEN, TERMS_TO_PRINT);

    if .PREV_STATUS eql REDUCT_AFTER_BACKUP_NOT_ALLOWED
    then
	EXPLORE_TRANSITIONS (.GLOBAL_MSG_STATUS,
	    .GLOBAL_MSG_INIT_STATE, .GLOBAL_MSG_SYMBOL, GROUP_NONTERMS_SEEN, TERMS_TO_PRINT);

    LS_GLOBAL_ERROR_MSG (.BAD_NON_TERM, .ERROR_TOKEN_PTR, GROUP_NONTERMS_SEEN, TERMS_TO_PRINT,
!	%allocation (TERMS_TO_PRINT));
	PAT$DATA_NUM_TERM);
    DEB_EVENT ('PAR_RECOVERY_GLOBAL',
	PUT_MSG ('Global recovery complete - CURRENTSTATE  is '),
	PUT_NUMBER (.PAT$STACK_P [.STACK_PTR, PATSTK_STATE]),
	PUT_MSG ('.  Current symbol is '),
	PUT_STRING (PAT$DATA_SYMBOL_TEXT (.CURRENT_SYMBOL)),
	PUT_EOL (),
	PUT_EOL (),
	PAT$DUMP_PARSE_STACK (),
	PUT_MSG_EOL ('-----------------------------------------------------'));
    end;					! Of routine PAT$ERROR_GLOBAL_RECOVERY
routine EXPLORE_TRANSITIONS (STATUS, STATE, SYMBOL, REF_GROUP_NONTERMS_SEEN, REF_TERMS_TO_PRINT) : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!	EXPLORE_TRANSITIONS is used by PAT$ERROR_GLOBAL_RECOVERY to examine the
!	transitions that could occur when the parse in in the state
!	indicated by STATUS, STATE and SYMBOL.  It sets fields in the
!	tables pointed to by REF_GROUP_NONTERMS_SEEN and REF_TERMS_TO_PRINT
!	appropriately.
!
! FORMAL PARAMETERS:
!
!	STATUS			- Parse status
!
!	STATE			- Parse state
!
!	SYMBOL			- Corresponding terminal or non-terminal symbol
!
!	REF_GROUP_NONTERMS_SEEN	- Pointer to table of grouping non-terminals,
!				  indicating which have been seen
!
!	REF_TERMS_TO_PRINT	- Pointer to table of terminals, indicating
!				  which should be printed
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS:
!
!	NONE
!
!--

    begin

    local
	SYM;

    if .STATE eql PAR_NO_SAVED_STATE then return;

    PAT$ERROR_GET_NEXT_TRANS_INIT (.STATUS, .STATE, .SYMBOL);

    while ((SYM = PAT$ERROR_GET_NEXT_TRANSITION (FALSE)) neq PAT$ERROR_NO_MORE_TRANSITIONS) do
	LS_EXPECTED_SYMBOL (.SYM, .REF_GROUP_NONTERMS_SEEN, .REF_TERMS_TO_PRINT);

    end;					! Of routine EXPLORE_TRANSITIONS
routine FIND_NEXT_REDUCTION (CURRENT_STATE, CURRENT_SYMBOL) =
!++
!
! FUNCTIONAL DESCRIPTION:
!
!	?
!
! FORMAL PARAMETERS:
!
!	CURRENT_STATE	?
!	CURRENT_SYMBOL	?
!
! IMPLICIT INPUTS:
!
!	?
!
! IMPLICIT OUTPUTS:
!
!	?
!
! ROUTINE VALUE:
!
!	?
!
! SIDE EFFECTS:
!
!	None.
!
!--

    begin

    local
	NEXT_STATE,
	IS_REDUCTION,
	REDUCTION_CODE,
	ACTION_CODE,
	LHS_SYMBOL,
	RHS_COUNT,
	SEMACT;

    ACTION_CODE = PAT$DATA_MOVE_ACTION (.CURRENT_STATE, .CURRENT_SYMBOL);

    if PAT$DATA_ACTION_IS (.ACTION_CODE, 'LOOK_AHEAD')
    then
	begin
	REDUCTION_CODE = PAT$DATA_AC_TO_LA_PRODUCTION_NO (.ACTION_CODE);
	IS_REDUCTION = TRUE;
	end
    else

	if ( not PAT$DATA_ACTION_IS (.ACTION_CODE, 'ERROR')) and ( not PAT$DATA_ACTION_IS (.ACTION_CODE,
		'SHIFT'))
	then 					! it's a non-lookahead reduction
	    begin
	    REDUCTION_CODE = -.ACTION_CODE;
	    IS_REDUCTION = TRUE;
	    end
	else
	    IS_REDUCTION = FALSE;

    if .IS_REDUCTION
    then
	PAT$DATA_GET_REDUCTION_INFO (.REDUCTION_CODE, LHS_SYMBOL, RHS_COUNT, SEMACT)
    else
	LHS_SYMBOL = LS_UNAVAILABLE_NT;

    return .LHS_SYMBOL
    end;					!  Of routine FIND_NEXT_REDUCTION
%if PATBLSEXT_DEBUGGING %then

global routine PAT$ERROR_PUT_STATUS (STAT) : novalue =
!++
!
! FUNCTIONAL DESCRIPTION:
!
!	Debugging routine to display error status on terminal.
!
! FORMAL PARAMETERS:
!
!	STAT		Error status.
!
! IMPLICIT INPUTS:
!
!	None.
!
! IMPLICIT OUTPUTS:
!
!	None.
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	Displays error status on the terminal.
!
!--

    begin

    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;

    end;					! end of PAT$ERROR_PUT_STATUS

%fi
global routine PAT$ERROR_GET_NEXT_TRANS_INIT (STATUS, STATE, SYMBOL) : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine initializes state variables for routine
!	PAT$ERROR_GET_NEXT_TRANSITION.  It is necessary to call
!	this routine before calling PAT$ERROR_GET_NEXT_TRANSITION
!	for a particular state.
!
!	This routine and PAT$ERROR_GET_NEXT_TRANSITION are used
!	to find the set of symbols that are "expected".
!	These routines are used during local error recovery to
!	determine the set of terminal symbols that are candidates for
!	insertion or for replacing an error token.  They are
!	also used in generating global error messages of the
!	form:
!
!		Found ... when expecting ...
!
!	These routines account for the effects of default lookahead
!	reductions and for the fact that the state saved after
!	a reduction is not the correct state from which to
!	collect the set of expected symbols.  This is accomplished
!	by a subset parsing routine (GNT_PARSE_UNTIL_SHIFT) that
!	uses a three element parse stack (GNT_PARSE_STACK) and a stack
!	index (GNT_PARSE_STACK_INDEX).
!
!	The easiest way to understand these routines is to
!	run PAT over the following grammar with the option
!	that prints the symbolic version of the parse tables
!	in the listing.
!
!		terminal
!		end;
!
!		begin
!		WHOLETHING	= PROGRAM goalsy ;
!
!		PROGRAM		= begin OPT_DECL STM 'end' ;
!
!		OPT_DECL	= DECL
!				| { epsilon };
!
!		STM		= NAME ':=' NAME ';'
!				| CALL_STM ';' ;
!
!		CALL_STM	= NAME ;
!
!		NAME		= ID ;
!
!		ID		= identifier ;
!
!		end.
!
!
!	Assume the state was saved immediately after "begin" is
!	consumed on a shift.  Then notice from the parse tables
!	that a default reduction
!
!		OPT_DECL	= { epsilon }
!
!	and a shift on OPT_DECL have to be done before
!	arriving at the state that allows us to construct the
!	set of terminals that are expected:  { identifier }.
!
!	Next assume the input A := B;  Assume the state was
!	saved after the reduction
!
!		ID = identifier
!
!	for the identifier "A".  Thus, the saved status would be
!	CONSUME_TERM_ON_REDUCTION.  Notice what has to be done to
!	construct the set of terminals that are expected:  {":=" and ";"}.
!	It is first necessary to reduce ID to NAME and to do a shift
!	on NAME to see the terminal ":=".  Then it is
!	necessary to do a default lookahead reduction from NAME
!	to CALL_STM to arrive in a state with a transition on ";".
!
! FORMAL PARAMETERS:
!
!	STATUS	- status_type (CONSUME_TERM_ON_SHIFT, etc.)
!
!	STATE	- State index associated with STATUS
!
!	SYMBOL	- If STATUS is CONSUME_TERM_ON_REDUCTION or
!		  REDUCT_AFTER_BACKUP_NOT_ALLOWED, the non-terminal after
!		  the reduction occurred.  Otherwise, LS_UNAVAILABLE_NT.
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	Initialize the small parse stack (GNT_PARSE_STACK,
!	GNT_PARSE_STACK_INDEX) for routines PAT$ERROR_GET_NEXT_TRANSITION
!	and GNT_PARSE_UNTIL_SHIFT.  Initialize GNT_LAST_TRANSITION
!	to indicate that want to find the first transition in the
!	state.  Initialize GNT_STATUS to the status.
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS:
!
!	NONE
!
!--

    begin

    ! First save the status and set up the stack with the
    ! initial state.

    GNT_STATUS = .STATUS;
    GNT_PARSE_STACK_INDEX = 0;
    GNT_PARSE_STACK [.GNT_PARSE_STACK_INDEX] = .STATE;
    GNT_LAST_TRANSITION = PAT$DATA_FIND_FIRST_TRANSITION;
    DEB_EVENT ('PAR_GET_NEXT_TRANSITION',
	PUT_MSG_EOL ('PAT$ERROR_GET_NEXT_TRANS_INIT'),
	PUT_MSG ('  Status = '),
%if PATBLSEXT_DEBUGGING %then
	PAT$ERROR_PUT_STATUS (.STATUS),
%fi
	PUT_MSG ('  State = '),
	PUT_NUMBER (.STATE),
	PUT_MSG ('  Symbol = '),

	if (.STATUS eql CONSUME_TERM_ON_REDUCTION) or
	    (.STATUS eql REDUCT_AFTER_BACKUP_NOT_ALLOWED)
	then

	    if .SYMBOL eql LS_UNAVAILABLE_NT
	    then
		PUT_MSG ('**UNAVAILABLE**')
	    else
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (.SYMBOL))
	else

	    PUT_MSG ('[not used]'),

	PUT_EOL ());

    selectone .STATUS of
	set

	[CONSUME_TERM_ON_REDUCTION, REDUCT_AFTER_BACKUP_NOT_ALLOWED] :
	    begin

	    ! If save the state after a reduction, need to
	    ! parse, starting with the symbol on the left hand
	    ! side of the production, until do a shift.  If
	    ! can't, then aren't able to figure out what's
	    ! expected since don't have enough information.

	    if not GNT_PARSE_UNTIL_SHIFT (PAT$DATA_MOVE_ACTION (.STATE, .SYMBOL))
	    then
		GNT_STATUS = SAVED_INFO_NOT_VALID;

	    end;
	tes;

    end;					! Of routine PAT$ERROR_GET_NEXT_TRANS_INIT
global routine PAT$ERROR_GET_NEXT_TRANSITION (ONLY_TERMINALS) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine is called to fetch the next terminal (or non-
!	terminal) symbol which is a legal transition from a particular
!	state.  PAT$ERROR_GET_NEXT_TRANS_INIT must be called before
!	calling this routine.  See documentation for
!	PAT$ERROR_GET_NEXT_TRANS_INIT.
!
! FORMAL PARAMETERS:
!
!	ONLY_TERMINALS	- If TRUE, this routine returns only
!			  terminals.  Otherwise, it returns
!			  terminals and non-terminals.
!
! IMPLICIT INPUTS:
!
!	GNT_PARSE_STACK
!
!	GNT_PARSE_STACK_INDEX
!
!	GNT_STATUS
!
! IMPLICIT OUTPUTS:
!
!	GNT_PARSE_STACK, GNT_PARSE_STACK_INDEX,
!	and GNT_LAST_TRANSITION are not modified directly by this routine
!	but are modified by  calls to GNT_PARSE_UNTIL_SHIFT.  GNT_STATUS
!	is set to SAVED_INFO_NOT_VALID when finished.
!
! ROUTINE VALUE:
!
!	Terminal or non-terminal symbol id.  Returns
!	PAT$ERROR_NO_MORE_TRANSITIONS when at the end of the state.
!
! SIDE EFFECTS:
!
!	NONE
!
!--

    begin

    local
	SYMBOL,
	MORE_TO_DO,
	ACTION_CODE;

    if .GNT_STATUS eql SAVED_INFO_NOT_VALID then return PAT$ERROR_NO_MORE_TRANSITIONS;

    MORE_TO_DO = TRUE;

    while .MORE_TO_DO do
	begin
	PAT$DATA_NEXT_TRANSITION (.GNT_PARSE_STACK [.GNT_PARSE_STACK_INDEX], .ONLY_TERMINALS,
	    GNT_LAST_TRANSITION, ACTION_CODE, SYMBOL);

	if .SYMBOL eql PAT$DATA_NO_MORE_TRANSITIONS
	then
	    MORE_TO_DO = GNT_PARSE_UNTIL_SHIFT (.ACTION_CODE)
	else
	    begin
	    DEB_EVENT ('PAR_GET_NEXT_TRANSITION',
		PUT_MSG ('  Returning symbol '),
		PUT_STRING (PAT$DATA_SYMBOL_TEXT (.SYMBOL)),
		PUT_EOL ());
	    return .SYMBOL;
	    end;

	end;

    GNT_STATUS = SAVED_INFO_NOT_VALID;
    return PAT$ERROR_NO_MORE_TRANSITIONS
    end;					! Of routine PAT$ERROR_GET_NEXT_TRANSITION
routine GNT_PARSE_UNTIL_SHIFT (ACTION) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine is called to parse until a shift occurs.
!	This routine is designed for use only by PAT$ERROR_GET_NEXT_TRANSITION
!	and PAT$ERROR_GET_NEXT_TRANS_INIT.
!
! FORMAL PARAMETERS:
!
!	ACTION	- Initial action code from PAT_ACT_TABLE.
!
! IMPLICIT INPUTS:
!
!	GNT_PARSE_STACK
!
!	GNT_PARSE_STACK_INDEX
!
! IMPLICIT OUTPUTS:
!
!	GNT_PARSE_STACK and GNT_PARSE_STACK_INDEX are modified to
!	as reductions and shifts are done.
!	GNT_LAST_TRANSITION is set to indicate that on the
!	next call to PAT$DATA_NEXT_TRANSITION we want the first
!	transition.  (When we return, we are either done or we
!	have changed parse table states.)
!
! ROUTINE VALUE:
!
!	TRUE	- Able to do a shift
!
!	FALSE	- Unable to do a shift because of stack underflow or
!		  overflow or because called with status of
!		  SAVED_INFO_NOT_VALID.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    begin

    local
	ACTION_CODE,
	LHS_SYMBOL,
	RHS_COUNT,
	SEMACT,
	REDUCTION_CODE,
	NEW_PTR;

    macro
	RET (VAL) =
	    begin
	    GNT_LAST_TRANSITION = PAT$DATA_FIND_FIRST_TRANSITION;
	    return (VAL)
	    end
	%;

    if .GNT_STATUS eql SAVED_INFO_NOT_VALID then RET (FALSE);

    ACTION_CODE = .ACTION;

    while TRUE do
	begin

	if PAT$DATA_ACTION_IS (.ACTION_CODE, 'ERROR')
	then
	    RET (FALSE)
	else

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

		if .GNT_PARSE_STACK_INDEX lss GNT_MAX_PARSE_STACK_INDEX
		then
		    begin
		    GNT_PARSE_STACK_INDEX = .GNT_PARSE_STACK_INDEX + 1;
		    GNT_PARSE_STACK [.GNT_PARSE_STACK_INDEX] = PAT$DATA_AC_TO_SHIFT_STATE (.ACTION_CODE);
		    RET (TRUE);
		    end
		else
		    RET (FALSE)

	    else
		begin

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

		    ! This is a lookahead reduction.

		    REDUCTION_CODE = PAT$DATA_AC_TO_LA_PRODUCTION_NO (.ACTION_CODE);
		    PAT$DATA_GET_REDUCTION_INFO (.REDUCTION_CODE, LHS_SYMBOL, RHS_COUNT, SEMACT);
		    NEW_PTR = .GNT_PARSE_STACK_INDEX - .RHS_COUNT;
		    end
		else
		    begin			! ACTION IS 'REDUCE'

		    ! This is a non-lookahead reduction.

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

		if .NEW_PTR lss 0
		then
		    RET (FALSE)
		else
		    begin
		    GNT_PARSE_STACK_INDEX = .NEW_PTR;
		    ACTION_CODE = PAT$DATA_MOVE_ACTION (.GNT_PARSE_STACK [.GNT_PARSE_STACK_INDEX],
			.LHS_SYMBOL);
		    end;

		end;

	end;

    return FALSE
    end;					! Of routine GNT_PARSE_UNTIL_SHIFT
end						! End of module

eludom