! ! module PATERROR (ident = 'X2-001' %require ('PATSWITCH_REQ') ) = begin ! ! COPYRIGHT (c) 1982 BY ! DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. ! ! 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 WHICH 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: ! ! 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. !-- ! ! ! INCLUDE FILES: ! require 'PATPROLOG_REQ'; library 'PATERROR_LIB'; library 'PATDATA_LIB'; ! PAT/BLISS interface library 'PAT_LANGSP_LIBRARY'; ! Language Specific functions library 'PATPARSER_LIB'; ! Parser driver library 'PATTOKEN_LIB'; library 'DEB_LIB'; ! 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 ! EXTERNALS external sdl$shr_address; !pointer to the sdl shared data structure ! sdl$_shr_data ! ! MACROS: ! macro CLEAR (START, BYTES) = ZEROBYTE (BYTES, START) %; ! ! 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 = !+ ! Called when a syntax error that local and scope recovery cannot repair ! has occurred; it skips over source until a synchronizing token is found. !- 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 = [0, 0, 16, 0], ! Terminal that can follow errormark STACKPTR_F = [1, 0, 16, 0], ! The parse stack pointer of the ERRORMARKed state ERRORMARK_F = [2, 0, 16, 0], ! Not used INDEX_F = [3, 0, 16, 0] ! The state which the ERRORMARK transition shifts to tes; local FOLLOWER_TABLE : blockvector [PAT$DATA_NUM_TERM, 4, 2] 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)); 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 tranisition 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 (GROUP_NONTERMS_SEEN, %allocation (GROUP_NONTERMS_SEEN)); 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)); 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) = 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 = 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 = '), ! PAT$ERROR_PUT_STATUS (.STATUS), ! 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 enuf 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; 0 end; ! Of routine GNT_PARSE_UNTIL_SHIFT end ! End of module eludom