Google
 

Trailing-Edge - PDP-10 Archives - bb-h138f-bm - 7-sources/prrange.bli
There are 10 other files named prrange.bli in the archive. Click here to see a list.
 %TITLE 'PRRANGE - Parse a range'
MODULE PRRANGE (
		IDENT = '3-003'		! File: PRRANGE.B36 Edit:CJG3003
		) =
BEGIN
!COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1981, 1988.  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:	EDT -- The DEC Standard Editor
!
! ABSTRACT:
!
!	Parse a range
!
! ENVIRONMENT:	Runs on TOPS-20 only
!
! AUTHOR: Chris Gill, CREATION DATE: March 15, 1983
!
! MODIFIED BY:
!
! 3-001 - Creation. CJG 15-Mar-1983
! 3-002 - Fix "TYPE -1" so that it defaults to "TYPE .-1". CJG 9-Dec-1983
! 3-003 - Check for control-C being typed. CJG 5-Jan-1984
!--


%SBTTL 'DECLARATIONS'

!
! TABLE OF CONTENTS
!

REQUIRE 'EDTSRC:TRAROUNAM';

FORWARD ROUTINE
    PA_ENDRAN : NOVALUE,		! Complete a compound range
    EDT$$PA_RANGE;			! Parse a range specifier

!
! INCLUDE FILES:
!

REQUIRE 'EDTSRC:EDTREQ';

REQUIRE 'EDTSRC:PARLITS';

REQUIRE 'SYS:JSYS';

!
! EXTERNAL REFERENCES:
!
!	In the routines
!
! MACROS:
!

MACRO
    BITS (VAL) [] =
	+(1 ^ (VAL - 1))
	BITS (%REMAINING) %;

!
! OWN DATA
!
! This table dictates which atoms are allowed to follow which other atoms.
! The table is indexed by the number of the atom just processed and
! consists of bits indicating which atom is legal next.
!
    OWN
	RAN_NEXT_TBL : VECTOR [NUM_RAN+1] INITIAL (

	    BITS (RAN_NUMBER, RAN_DOT, RAN_STR, RAN_BEGIN, RAN_END, RAN_ORIG,
			RAN_PLUS, RAN_MINUS, RAN_LAST, RAN_BUFFER, RAN_REST,
			RAN_BEFORE, RAN_SELECT, RAN_WHOLE, RAN_ALL),	! Start
	    BITS (RAN_DOT, RAN_PLUS, RAN_MINUS),			! Number
	    BITS (RAN_PLUS, RAN_MINUS),					! "."
	    BITS (RAN_PLUS, RAN_MINUS),					! String
	    BITS (RAN_PLUS, RAN_MINUS),					! BEGIN
	    BITS (RAN_PLUS, RAN_MINUS),					! END
	    BITS (RAN_PLUS, RAN_MINUS, RAN_NUMBER),			! ORIGINAL
	    0,
	    0,								! LAST
	    BITS (RAN_ALL),						! BEFORE
	    BITS (RAN_ALL),						! REST
	    BITS (RAN_ALL),						! WHOLE
	    0,								! SELECT
	    BITS (RAN_NUMBER, RAN_STR, RAN_BEGIN, RAN_END,
			RAN_LAST, RAN_BEFORE, RAN_REST,
			RAN_WHOLE, RAN_PLUS, RAN_DOT,
			RAN_MINUS, RAN_SELECT, RAN_ALL, RAN_ORIG),	! BUFFER
	    BITS (RAN_NUMBER),						! "+"
	    BITS (RAN_NUMBER, RAN_STR),					! "-"
	    BITS (RAN_NUMBER),						! FOR
	    BITS (RAN_NUMBER, RAN_DOT, RAN_STR, RAN_BEGIN, RAN_END,
			RAN_PLUS, RAN_MINUS, RAN_ORIG),			! THRU
	    0,
	    BITS (RAN_STR),						! ALL
	    BITS (RAN_NUMBER, RAN_DOT, RAN_STR, RAN_BEGIN, RAN_END,
			RAN_PLUS, RAN_MINUS, RAN_ORIG)			! AND
	    ),

!+
! RAN_SLR_NEXT has flags which are used when a single line range has
! been completed.
!-

	RAN_SLR_NEXT : VECTOR [4] INITIAL (
	    BITS (RAN_THRU, RAN_FOR, RAN_AND, RAN_ALL),			! Initial
	    BITS (RAN_ALL),						! THRU
	    BITS (RAN_ALL),						! FOR
	    BITS (RAN_AND, RAN_ALL)					! AND
	    );

%SBTTL 'EDT$$PA_RANGE - Parse a range node'

GLOBAL ROUTINE EDT$$PA_RANGE (			! Parse a range
		LOCATION ) =			! Where to put result pointer

BEGIN

!+
! FUNCTIONAL DESCRIPTION
!
! This subroutine is called to parse a range. Ranges may consist of
! two parts - a single line range, and a range type (such as AND, FOR, and
! THRU). A buffer name may, optionally, be present. Thus, the overall
! format of a range is,
!
!		  { LAST   }
!		  { SELECT }
!		  {
!		  { BEFORE			 }
! [ BUFFER name ] { REST			 }
!		  { WHOLE			 } [ ALL string ]
!		  {	 { THRU SLR	      }  }
!		  { SLR  { AND SLR [AND ... ] }  }
!		  {      { FOR number         }  }
!
! Where, SLR refers to a single line range.
!
! Single line ranges can have the following format,
!
! { line-number }
! { .           }  { + number     }  { + ... }
! { BEGIN       }  {		  }  {       }
! { END         }  { - { number } }  { - ... }
! { string      }  {   { string } }  {       }
! { -blank-     }
!
! The type of range being parsed is held in FLAGS2 and the type of atom
! just parsed is held in PRVCMD. These are used to index the tables
! RAN_NEXT_TBL, and RAN_SLR_NEXT which indicate which atom is allowed next.
! This routine operates in a loop until an error is detected or an atom does
! not parse.
!
! ROUTINE VALUE
!
!	-1 - JSYS error or next atom is disallowed
!	0  - Reparse required
!	+1 - All correct
!-

    EXTERNAL
	PA_BUFRNG : REF NODE_BLOCK,
	PA_ANDLSTHD : REF NODE_BLOCK,
	PA_CURCMD : REF NODE_BLOCK,		! Parse node
	PA_THRURNG : REF NODE_BLOCK,
	PA_CURRNG : REF NODE_BLOCK,
	PA_NUMVAL,
	PA_ERRNO,				! Error number
	PA_CURTOK,				! Pointer to current atom
	PA_CURTOKLEN,				! And its length
	CSB : VECTOR [10],
	FD_RC1,
	FD_RC2,
	FD_RC3,
	FD_RCM,
	FD_RS1,
	FD_RS2,
	FD_RS3,
	FD_RS4,
	FD_RS5,
	FD_R81,
	FD_R82,
	FD_RNM,
	FD_RNP,
	FD_RNA,
	FD_RSR,
	FD_RNS,
	FD_RNN,
	FD_RNG,
	FD_RNK,
	FD_RN8,
	FD_RN7,
	FD_RN6,
	FD_RN5,
	FD_RN4,
	FD_RN3,
	FD_RN2,
	FD_RN1,
	FD_AND,
	FD_ANC,
	FD_VAL,
	FD_QST,
	MAX_LINES,
	LNO0 : LNOVECTOR [14],
	CC;					! Control-C flag

    EXTERNAL ROUTINE
	EDT$$CMP_LNO,				! Compare line numbers
	EDT$$PA_SCANTOK,			! Get atom length
	EDT$$PA_BUFFER,				! Get buffer name
	EDT$$PA_LINE_NUM,			! Parse aline number
	EDT$$PA_NUMBER,				! Get a number
	EDT$$PA_NEW_NOD,			! Create a new node
	EDT$$PA_CRERNGNOD;			! Create a new range node

    LOCAL
	C_FLAG,					! COMND flags
	C_DATA,					! COMND data or pointer
	C_FDB,					! FDB used in parse
	CMDTYP,					! Type of current range atom
	PRVCMD,					! Save previous node type
	FLAGS2,					! Extra flags compound ranges
	FD_PTR,					! Pointer to current FDB
	MORE,					! Set TRUE if more to parse
	THRU_SEEN,				! Set TRUE if THRU keyword seen
	FOR_SEEN,				! Set TRUE if FOR keyword seen
	AND_SEEN,				! Set TRUE if AND keyword seen
	FLAG;					! Flags for next node allowed


    MESSAGES ((QUOSTRREQ, NUMVALREQ, ERRRANSPC, NUMVALILL));


!+
! Preset the flags and (previous) command, and parse the first atom
!

    CMDTYP = 0;
    FLAG = .RAN_NEXT_TBL [0];
    FLAGS2 = 0;
    FD_PTR = FD_RNG;
    THRU_SEEN = 0;
    AND_SEEN = 0;
    FOR_SEEN = 0;
    MORE = 1;

!+
! Loop parsing range spec until error or end of specification
!-

    WHILE .MORE DO
    BEGIN
	IF (NOT COMMAND (.FD_PTR)) THEN RETURN (-1);
	IF (.CC NEQ 0) THEN RETURN (-1);

!+
! Exit loop if no parse
!-

	IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN EXITLOOP;

!+
! The atom parsed OK and it is time to do the appropriate thing with it.
!-

	IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
	IF (.C_FDB<0,18> EQL FD_RNG) THEN
	    BEGIN

!+
! If a '%' was found the rescan for the keyword
!-

	    IF (NOT COMMAND (FD_RNK)) THEN RETURN (-1);
	    IF (.CC NEQ 0) THEN RETURN (-1);
	    IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
	    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
	    END;

	PRVCMD = .CMDTYP;
	CMDTYP = (SELECTONE .C_FDB<0,18> OF
		SET
		[ FD_RNK, FD_RNA, FD_RCM, FD_RN8, FD_RSR, FD_AND ]  : .(.C_DATA)<0,18>;
		[ FD_RNN, FD_VAL, FD_RS5 ]  : RAN_NUMBER;
		[ FD_RNS, FD_QST, FD_RS4 ]  : RAN_STR;
		[ FD_RN4, FD_RNP, FD_R81, FD_RS1 ]  : RAN_PLUS;
		[ FD_RN5, FD_RNM, FD_R82, FD_RS2 ]  : RAN_MINUS;
		[ FD_RN6, FD_RS3 ]  : RAN_DOT;
		[ FD_RN1, FD_RC3 ]  : RAN_FOR;
		[ FD_RN2, FD_RC1 ]  : RAN_THRU;
		[ FD_RN3, FD_RC2, FD_ANC ]  : RAN_AND;
		[ FD_RN7 ]  : RAN_BUFFER;
		TES);

!+
! If this atom was not allowed - return an error
!-

	IF ((.FLAG AND 1 ^ (.CMDTYP - 1)) EQL 0) THEN
	    BEGIN
	    IF ((.RAN_SLR_NEXT [.FLAGS2 <0,18>] AND 1 ^ (.CMDTYP - 1)) EQL 0) THEN
		BEGIN
		PA_ERRNO = EDT$_ERRRANSPC;
		RETURN (-1);
		END;
	    PA_ENDRAN (.FLAGS2);
	    END;
	FLAG = .RAN_NEXT_TBL [.CMDTYP];

!+
! Now do the right things for each of the possible cases
!-

	CASE .CMDTYP FROM RAN_NUMBER TO NUM_RAN OF
	    SET

	[ RAN_NUMBER ] :

		BEGIN
!+
! Set up command table for legal items which can follow
!-
		IF ((.THRU_SEEN) OR (.FOR_SEEN)) THEN FD_PTR = FD_RNA ELSE
		    IF (.AND_SEEN) THEN FD_PTR = FD_AND ELSE
			FD_PTR = FD_RCM;


		IF ((.PRVCMD EQL RAN_PLUS) OR (.PRVCMD EQL RAN_MINUS) OR
			(.PRVCMD EQL RAN_FOR) OR (.PRVCMD EQL RAN_ORIG)) THEN

!+
! Treat a number following +, -, ORIGINAL, or FOR as a simple number.
!-

		    BEGIN
		    IF ((.C_DATA GEQ 2^17) OR (.C_DATA LSS 0)) THEN
			BEGIN
			PA_ERRNO = EDT$_NUMVALILL;
			RETURN (-1);
			END;
		    PA_CURRNG [RAN_VAL] = .C_DATA;
		    END
		ELSE

!+
! If the previous atom was not one of these, then build a line number
!-

		    BEGIN
		    LOCAL STS;
		    IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, .CMDTYP)) EQL 0)
			 THEN RETURN (-1);
		    STS = EDT$$PA_LINE_NUM (.C_DATA);
		    IF (.STS LEQ 0) THEN RETURN (.STS);
		    MOVELINE (PA_NUMVAL, PA_CURRNG [RAN_VAL]);
		    END;
		END;

	[ RAN_DOT ] :

		BEGIN
!+
! Set up command table for legal items which can follow
!-
		IF ((.THRU_SEEN) OR (.FOR_SEEN)) THEN FD_PTR = FD_RN8 ELSE
		    IF (.AND_SEEN) THEN FD_PTR = FD_AND ELSE
			FD_PTR = FD_RNP;

		IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, .CMDTYP)) EQL 0)
		    THEN RETURN (-1);
		END;

	[ RAN_STR ] :

		BEGIN
		IF (.PRVCMD EQL RAN_ALL) THEN MORE = 0 ELSE
		    IF (.THRU_SEEN) THEN FD_PTR = FD_RN8 ELSE
			IF (.AND_SEEN) THEN FD_PTR = FD_AND ELSE
			FD_PTR = FD_RNP;


!+
! Create a new node when necessary and store the pointer and length
!-

		IF ((.PRVCMD NEQ RAN_ALL) AND (.PRVCMD NEQ RAN_MINUS)) THEN
		    IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, .CMDTYP)) EQL 0)
			THEN RETURN (-1);
		EDT$$PA_SCANTOK (1,0);
		PA_CURRNG [RAN_VAL] = .PA_CURTOKLEN;
		PA_CURRNG [STR_PNT] = .PA_CURTOK;
		IF (.PRVCMD EQL RAN_MINUS) THEN PA_CURRNG [RAN_TYPE] = RAN_MINSTR;
		END;

	[ RAN_BEGIN, RAN_END, RAN_ORIG ] :

		BEGIN
		IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, .CMDTYP)) EQL 0)
		    THEN RETURN (-1);
		IF (.THRU_SEEN) THEN FD_PTR = FD_RN8 ELSE
		    IF (.AND_SEEN) THEN FD_PTR = FD_AND ELSE
			FD_PTR = FD_RNP;
		END;

	[ RAN_BEFORE, RAN_REST, RAN_WHOLE] :

		BEGIN
		IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, .CMDTYP)) EQL 0)
		    THEN RETURN (-1);
		FD_PTR = FD_RNA;
		END;

	[ RAN_LAST, RAN_SELECT ] :

		BEGIN
		IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, .CMDTYP)) EQL 0)
		    THEN RETURN (-1);
		MORE = 0;
		END;

	[ RAN_BUFFER ] :

		BEGIN
		LOCAL STS;

!+
! Parse a buffer name and set a flag for later
!-

		STS = EDT$$PA_BUFFER ();
		IF (.STS LEQ 0) THEN RETURN (.STS);
		FLAGS2 = .FLAGS2 OR F_BUFFER;
		END;

	[ RAN_FOR ] :

		BEGIN

!+
! Create a new node and set some flags for later. Create a default if required.
!-

		IF (.PRVCMD EQL 0) THEN
		    IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, RAN_DOT)) EQL 0)
			THEN RETURN (-1);
		IF (EDT$$PA_CRERNGNOD (.CMDTYP) EQL 0) THEN RETURN (-1);
		PA_ERRNO = EDT$_NUMVALREQ;
		FLAGS2 <0,18> = F_FOR;
		FOR_SEEN = 1;
		FD_PTR = FD_VAL;
		END;

	[ RAN_PLUS, RAN_MINUS ] :

		BEGIN

!+
! Create a default node if required.
!-

		IF (.PRVCMD EQL 0) THEN
		    IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, RAN_DOT)) EQL 0)
			THEN RETURN (-1);
		IF (EDT$$PA_CRERNGNOD (.CMDTYP) EQL 0) THEN RETURN (-1);
		FD_PTR = FD_VAL;
		END;

	[ RAN_THRU ] :

		BEGIN

!+
! Create a new node and set a flag for later. Create a default if required.
!-

		IF (.PRVCMD EQL 0) THEN
		    IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, RAN_DOT)) EQL 0)
			THEN RETURN (-1);
		IF ((PA_THRURNG = EDT$$PA_NEW_NOD (RANGE_NODE, 0)) EQL 0)
		    THEN RETURN (-1);
		PA_THRURNG [RANGE1] = .PA_CURRNG;
		FLAGS2 <0,18> = F_THRU;
		FD_PTR = FD_RSR;
		THRU_SEEN = 1;
		END;

	[ RAN_ALL ] :

		BEGIN
		LOCAL
		    SUB : REF NODE_BLOCK;

!+
! Complete any compound range outstanding and clear the flag.
! Then link the new range with the previous one
!-

		PA_ENDRAN (.FLAGS2);
		FLAGS2 <0,18> = 0;
		IF (.PRVCMD EQL 0) THEN
		    IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, RAN_WHOLE)) EQL 0)
			THEN RETURN (-1);
		SUB = .PA_CURRNG;
		IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, .CMDTYP)) EQL 0)
		    THEN RETURN (-1);
		PA_CURRNG [NEXT_RANGE] = .SUB;
		SUB [PREV_RANGE] = .PA_CURRNG;
		PA_ERRNO = EDT$_QUOSTRREQ;
		FD_PTR = FD_QST;
		END;

	[ RAN_AND ] :

!+
! Keep track of the current range for later linking
!-

		BEGIN
		IF (.PRVCMD EQL 0) THEN
		    BEGIN
		    PA_ERRNO = EDT$_ERRRANSPC;
		    RETURN (-1);
		    END;
		PA_ANDLSTHD = .PA_CURRNG;
		FLAGS2 <0,18> = F_AND;
		AND_SEEN = 1;
		FD_PTR = FD_RSR;
		END;

	[ INRANGE ] :

		;

	    TES;

    END;

!+
! Here when error parsing or logical end of specification reached
!  Complete specification and return
!-


!+
! If a buffer name was supplied, link it in now unless the last atom
! should have had something following it.
!-

    SELECTONE .CMDTYP OF
	SET

    [ 0 ] :

	BEGIN

!+
! This is a null range - make sure it is stored as such.
!-

	IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, RAN_NULL)) EQL 0)
	    THEN RETURN (-1);

	IF (.LOCATION EQL 1) THEN
	    PA_CURCMD [RANGE1] = .PA_CURRNG
	ELSE
	    PA_CURCMD [RANGE2] = .PA_CURRNG;
	RETURN (1);
	END;

    [ RAN_FOR ] :

	RETURN (-1);

    [ RAN_ALL ] :

	RETURN (-1);

    [ RAN_THRU ] :

	IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, RAN_DOT)) EQL 0)
	    THEN RETURN (-1);

    [ RAN_BUFFER ] :

	BEGIN

!+
! This is a null range - make sure it is marked as such
!-

	IF ((PA_CURRNG = EDT$$PA_NEW_NOD (RANGE_NODE, RAN_NULL)) EQL 0)
	    THEN RETURN (-1);

	IF (.LOCATION EQL 1) THEN
	    PA_CURCMD [RANGE1] = .PA_CURRNG
	ELSE
	    PA_CURCMD [RANGE2] = .PA_CURRNG;
	END;
		
    [ OTHERWISE ] :

	;

	TES;

    PA_ENDRAN (.FLAGS2);
    IF ((.FLAGS2 AND F_BUFFER) NEQ 0) THEN
	BEGIN
	IF (.PA_BUFRNG NEQ .PA_CURRNG) THEN PA_BUFRNG [RANGE1] = .PA_CURRNG;
	PA_CURRNG = .PA_BUFRNG;
	END;

!+
! Finally, link the range to the command
!-

    IF (.LOCATION EQL 1) THEN
	PA_CURCMD [RANGE1] = .PA_CURRNG
    ELSE
	PA_CURCMD [RANGE2] = .PA_CURRNG;
    RETURN (1);

END;

%SBTTL 'PA_ENDRAN - Complete a compound range'

ROUTINE PA_ENDRAN (
		FLAG) : NOVALUE = 

!+
! FUNCTIONAL DESCRIPTION
!
! This routine tidies up the compound range which was being evaluated last.
! If no such range was in the command, then the right half of FLAG will
! be zero. The tidy-up operation depends on the type of compound range
! being processed.
!


BEGIN

    EXTERNAL
	PA_THRURNG : REF NODE_BLOCK,
	PA_ANDLSTHD : REF NODE_BLOCK,
	PA_CURRNG : REF NODE_BLOCK;

	BEGIN

!+
! Complete the previous compound range node before continuing
!-

	    CASE .FLAG<0,18> FROM F_SLR TO F_AND OF
		SET

	    [ F_SLR ] :

		;				! Nothing to do

	    [ F_THRU ] :

		BEGIN

!+
! Link the THRU range node in
!-

		PA_THRURNG [RAN_TYPE] = RAN_THRU;
		IF (.PA_CURRNG NEQ .PA_THRURNG) THEN
		    PA_THRURNG [RANGE2] = .PA_CURRNG;
		PA_CURRNG = .PA_THRURNG;
		END;

	    [ F_FOR ] :

		;				! Nothing to do

	    [ F_AND ] :

		BEGIN
		LOCAL ARANGE : REF NODE_BLOCK;
		ARANGE = .PA_ANDLSTHD;

!+
! Find the last range so we can add the new one to the end
!-

		WHILE (.ARANGE [NEXT_RANGE] NEQA 0) DO
		    ARANGE = .ARANGE [NEXT_RANGE];

		ARANGE [NEXT_RANGE] = .PA_CURRNG;
		PA_CURRNG [PREV_RANGE] = .ARANGE;
		PA_CURRNG = .PA_ANDLSTHD;
		END;

		TES;

	RETURN (1);
	END;

END;

END
ELUDOM