Google
 

Trailing-Edge - PDP-10 Archives - FORTRAN-10_V7wLink_Feb83 - sta2.bli
There are 26 other files named sta2.bli in the archive. Click here to see a list.
!THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
!  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.

!COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1972, 1983
!AUTHOR: F.J. INFANTE, D. B. TOLMAN/DCE/SJW/EGM/CKS/AHM/TFV

MODULE STA2(RESERVE(0,1,2,3),SREG=#17,FREG=#16,VREG=#15,DREGS=4,GLOROUTINES)=
BEGIN


GLOBAL BIND STA2V = 7^24 + 0^18 + #1704;	! Version Date: 21-Dec-82

%(

***** Begin Revision History *****

36	-----	-----	ADD THE INCLUDE STATEMENT SEMANTICS ROUTINE

37	-----	-----	ALLOW LITSTRINGS IN THE PARAMETER STATEMENT

38	-----	-----	FIX REAL*8 X*4  SO IT WORKS

			ALLOW SIGNED CONSTANTS IN THE PARAMETER STATEMENT
39	-----	-----	THE "CLEVER" WAY OF DEALING WITH THE LOOKUP
			SKIP RETURN WAS OPTIMIZED AWAY BY 5(122)
			SO WE MUST NOT BE SO CLEVER THIS TIME

40	-----	-----	FIX UP INCLUDE A LITTLE
41	320	16787	CATCH COMMON STATEMENTS LIKE /X/A(5)B(5) AS ERRORS, (JNT)
42	402	18917	RESTORE FLAGS CORRECTLY AFTER INCLUDE FILE, (DCE)
43	467	VER5	REQUIRE FTTENX.REQ ,(SJW)
44	533	21796	FIX OUTPUT BUFFER PTR FOR INCLUDE FILE TO BE 0., (DCE)
45	540	22096	ICE CAUSED BY BAD COMMON DECLARATION, (DCE)

***** Begin Version 5B *****

46	722	28072	ADD /NOCREF TO INCLUDE FILE PROCESSING, (DCE)
47	755	13884	Allow lower case for INCLUDE/NOLIST/NOCREF under TENEX,
			(EGM)

***** Begin version 6 *****

48	1000	EGM	27-Jun-80	10-29620
	Flag error if no name is given on PROGRAM statement

***** Begin Version 7 *****

49	1213	TFV	6-May-81	------
	Modify ASTER to handle CHARACTER*(*), CHARACTER*n, and CHARACTER*(n).
	The length for character data gets put on the stack.  Fix TYPDECLARE
	to handle CHARACTER decl's.  Add CHARSTA the CHARACTER decl semantic
	routine. Move ACTLDATYPE and CHDLEN to GLOBAL.BLI. Add a second 
	argument to FUNCGEN to distinguish 'datatype FUNCTION ...' from
	'FUNCTION ...'.  The first case puts CHLEN on the stack.

50      1214     CKS	1-Jun-81
	Prohibit ENTRY statement in range of block IF as well as DO

51      1224     CKS    12-Jun-81
        Use "LTLSIZ-1" instead of "2" to free up literal node

52	1232	TFV	24-Jun-81	------
	CHARSTA sets CHDECL flag if a character declaration is seen. Used
	in MRP3R and MRP3G to test if we have to scan the symbol table to
	generate high seg character descriptors.

53	1256	CKS	8-Sep-81
	Modify COMMSTA to read the modified output of SYNTAX for the modified
	common statement.  The difference is that COMMON // X is returned with
	a concatenation lexeme instead of two slashes.

54	1267	AHM	6-Oct-81	------
	Define a stub routine SAVESTA for the SAVE statement so we don't
	get undefined symbols when linking.

55	1434	TFV	14-Dec-81	------
	Modify  ENTRSTA   to   handle  multi-entry   function   subprograms.
	Character  and  numeric  entry  points  cannot  occur  in  the  same
	subprogram.  All character  entry points  must be  the same  length;
	they share the descriptor for the function result. All numeric entry
	points are  equivalenced using  the EQUIVALENCE  statement  semantic
	routine.

56	1466	CDM	1-Feb-82
	Added warning for using SAVE statement.  Not yet implemented.

1511	CDM	18-March-82
	Added code for SAVE statement in SAVESTA.
	Added routine LKSVCOMMON for linking common blocks together for
	SAVE statement processing.

1527	CKS	9-Apr-82
	Rewrite ASTER to allow expressions as length specifiers.  Modify
	PARASTA to allow expressions in parameter statements.

1531	CDM	4-May-82
	Changes for code review of SAVE.

1566	CDM	24-Jun-82
	Remove warning for SAVE processing with overlays.

1575	TFV	7-Jul-82
	Modify TYPEDECLARE and ASTER to accept 'var * len (subs) * len'.

1646	TFV	18-Oct-82
	Fix ASTER to give  an error for character  lengths less than  or
	equal to 0.

1656	CKS	25-Oct-82
	Modify parameter statement semantic routine PARASTA to do nothing.
	It's all handled in action routine PARMASSIGN.

1667	TFV	9-Nov-82
	Fix ASTER to give a better  found when expecting error for  type
	declarations.

1704	TFV	21-Dec-82
	Fix type declarations to allow optional comma after the optional
	*size specifier.   The comma  is only  allowed if  the *size  is
	specified.

***** End Revision History *****

)%

REQUIRE  FTTENX.REQ;
SWITCHES NOLIST;
REQUIRE LEXNAM.BLI;
REQUIRE FIRST.BLI;
REQUIRE TABLES.BLI;
REQUIRE META72.BLI;
REQUIRE ASHELP.BLI;
SWITCHES LIST;

!THE NUMBER IN COMMENT'S IS THE STATEMENTS LOCATION
!IN THE HASH TABLE .
FORWARD
% 16%	SUBRSTA,	!SUBROUTINE 
% 19%	INTESTA,	!INTEGER 
% 29%	LOGISTA,	!LOGICAL - P.30
% 51%	DIMESTA,	!DIMENSION 
% 56%	DOUBSTA,	!DOUBLEPRECISION - P.31
% 64%	ENTRSTA,	!ENTRY 
% 75%	BLOCSTA,	!BLOCKDATA - P.38
% 81%	FUNCSTA,	!FUNCTION 
% 86%	REALSTA,	!REAL - P.29
% 93%	COMMSTA,	!COMMON 
% 96%	COMPSTA,	!COMPLEX - P.32
%121%	PROGSTA,	!PROGRAM 
	PARASTA,	!PARAMETER STATEMENT
% 13%	SAVESTA,	![1267] SAVE STATEMENT
%1511%	LKSVCOMMON;	! Links together Common blocks for SAVE processing

EXTERNAL
%1232%	CHDECL,		! Flag for character declaration seen
%1527%	CNVCONST,	! Convert constant to desired type
	CORMAN,		! Routine to get space from free memory
	DOIFSTK,
	E178,		! Error - character and numeric entry points cannot
			! be mixed.
	E179,		! Error - character entry points must have the same
			! length.
%1531%	E192,		! "Illegal in SAVE statement"
	ENTRY,		! Parameter for TBLSEARCH
	EQUISTA,	! Routine to do semantic processing for EQUIVALENCE
%1511%	FATLERR,	! Error routine
	FUNCGEN,	! Routine to  processes  the argument  list  for  an
			! ENTRY, FUNCTION or SUBROUTINE statement
	NAMDEF,
	NAME,		! Parameter for TBLSEARCH
%1511%	NUMSAVCOMMON,	! Number of commons to SAVE.
%1531%	PTRSAVCOMMON,	! Linked list of commons to SAVE.
	SAVSPACE,	! Routine to return space to free memory
%1511%	SAVALL,		! SAVE with no arguments specified
%1511%	SAVBLC,		! SAVE blank common
%1511%	SAVLOC,		! SAVE local variables
%1511%	SAVNED,		! SAVE rel block is needed
	STK,
	TBLSEARCH,	! Routine to lookup a symbol table entry
	TYPE,
	WARNLEX;

GLOBAL ROUTINE INCLSTA=
BEGIN	% INCLUDE STATEMENT%

	GLOBAL SVFLG2;
	EXTERNAL EOPSVPOOL,POOL,EOPRESTORE;
	EXTERNAL LEXICAL,GSTCSCAN,GSTSSCAN,LOOK4CHAR,LEXEMEGEN,GSTEOP;
	BIND EOF = #200;
	MACHOP  LOOKUP = #076, OPEN = #050, JFCL = #255;
	OWN TMP;
	MACRO  DEFAULT =  TMP<LEFT>$,
%[722]%		NOLST =	TMP<0,1>$,
%[722]%		NOCRF =	TMP<1,1>$;
	EXTERNAL SAVFLG;
	MACRO	PROJNUM = DIRECTORY(ICL)<LEFT>$,
		PROGNUM = DIRECTORY(ICL)<RIGHT>$,
		ERRORR(X) = RETURN FATLEX(X<0,0>)$;

	FORWARD
		PPN,PPNUM,SCANFIL,FILSP,SWITCH;

ROUTINE  FILSP  =
BEGIN IF NOT FTTENEX THEN BEGIN
	REGISTER R;

	%GET DEVICE OR FILE NAME%
	WHILE 1 DO
	BEGIN
		EXTERNAL  E122;

		IF (R_SCANFIL())  EQL  0  THEN RETURN 0;
		LOOK4CHAR _ ":";
		IF LEXICAL(.GSTCSCAN)  EQL  0
		THEN
		BEGIN	%FILE NAME%
			EXITLOOP
		END
		ELSE
		BEGIN	%DEVICE NAME%
			IF .DEVICE(ICL)  NEQ  0
			THEN	RETURN  FATLEX( SIXBIT'DEVICE', E122<0,0>);
			DEVICE(ICL)  _ .R
		END
	END	%LOOP%  ;

	%STORE FILE NAME%
	IF .FILENAME(ICL)  NEQ  0
	THEN	RETURN  FATLEX( SIXBIT'FILE', E122<0,0>);
	FILENAME(ICL) _ .R;

	LOOK4CHAR _ ".";
	IF LEXICAL(.GSTCSCAN)  EQL  0
	THEN
	BEGIN
		%DEFAULT%
		DEFAULT _ 1;
		(FILENAME(ICL)+1)  _ SIXBIT'FOR';
	END
	ELSE
	BEGIN
		DEFAULT _ 0;
		(FILENAME(ICL)+1)  _ SCANFIL()
	END;
	RETURN 1
END END;


ROUTINE  PPN  =
BEGIN IF NOT FTTENEX THEN BEGIN	%PICK UP THE PPN%

	LOOK4CHAR _ "[";
	IF LEXICAL (.GSTCSCAN) EQL  0
	THEN	( DIRECTORY(ICL) _ 0;
		  RETURN  0	!NONE
		);

	IF (PROJNUM _ PPNUM() )  EQL 0
	THEN  RETURN -1;	!ERROR
	LOOK4CHAR _ ",";
	IF LEXICAL(.GSTCSCAN)  EQL  0
	THEN	RETURN -1;	!ERROR
	IF ( PROGNUM _ PPNUM() )  EQL  0
	THEN RETURN -1;	!ERROR
	LOOK4CHAR _ "]";
	IF LEXICAL(.GSTCSCAN) EQL  0
	THEN RETURN -1;	!ERROR

	RETURN 1	!GOT ONE
END END;

ROUTINE  PPNUM  =
BEGIN IF NOT FTTENEX THEN BEGIN	%GET PPN%
	REGISTER NUM,C;
	NUM _ 0;
	LOOK4CHAR _ "?D";
	UNTIL  ( C _ LEXICAL(.GSTCSCAN) ) EQL  0
	DO	NUM _ .NUM*8 + .C -"0";
	RETURN .NUM
END END;

ROUTINE  SCANFIL  =
BEGIN IF NOT FTTENEX THEN BEGIN
	%GET FILE NAME%
	REGISTER SIX,C;

	DECR SHIFT FROM  30 TO 0 BY 6
	DO
	BEGIN
		MACHOP  ADDI=#271;
		SIX _ .SIX^6;
		LOOK4CHAR _ "?L";
		IF ( C _ LEXICAL(.GSTCSCAN) )  EQL 0
		THEN
		BEGIN
			LOOK4CHAR _ "?D";
			IF ( C_ LEXICAL(.GSTCSCAN))  EQL  0
			THEN	RETURN  SIX_.SIX^.SHIFT;
		END;
		ADDI(SIX,-" ",C)
	END;
	WHILE 1 DO
	BEGIN	%SKIP ANY MORE CHARACTERS%
		LOOK4CHAR _ "?L";
		IF LEXICAL(.GSTCSCAN)  EQL  0
		THEN
		BEGIN
			LOOK4CHAR _ "?D";
			IF LEXICAL(.GSTCSCAN) EQL 0
			THEN  RETURN .SIX
		END
	END
END END;


ROUTINE   SWITCH =
BEGIN IF NOT FTTENEX THEN BEGIN
![722] REWRITE SWITCH PROCESSING TO ALLOW /NOCREF ON INCLUDE STATEMENT
%[722]%	% GET /NOLIST OR /NOCREF OR BOTH %
%[722]%	LOOK4CHAR_"/";
%[722]%
%[722]%	IF LEXICAL(.GSTCSCAN) EQL 0 THEN RETURN 0;
%[722]%	DO
%[722]%	BEGIN
%[722]%
%[722]%		LOOK4CHAR_PLIT'NOLIST'<36,7>;
%[722]%		IF LEXICAL(.GSTSSCAN) NEQ 0
%[722]%		THEN NOLST_1  !FOUND /NOLIST
%[722]%		ELSE  !TRY NOCREF
%[722]%		BEGIN
%[722]%			LOOK4CHAR_PLIT'NOCREF'<36,7>;
%[722]%			IF LEXICAL(.GSTSSCAN) NEQ 0
%[722]%			THEN NOCRF_1  !FOUND /NOCREF
%[722]%			ELSE RETURN -1    !ERROR
%[722]%		END;
%[722]%		LOOK4CHAR_"/"
%[722]%	END UNTIL LEXICAL(.GSTCSCAN) EQL 0;
%[722]%
%[722]%	RETURN 1;
END END;



	%LETS DO IT%

	IF .FLGREG<ININCLUD>  THEN  RETURN FATLEX(E120<0,0>);

	IF NOT FTTENEX THEN
	BEGIN


	FILENAME(ICL)  _ 0;
	TMP _ 0;
	DIRECTORY(ICL) _ 0;
	DEVICE(ICL) _ 0;

	%GET THE INITIAL ' %
	LOOK4CHAR  _ "'";
	IF LEXICAL(.GSTCSCAN)  EQL  0
	THEN
	BEGIN
		EXTERNAL LEXNAME;
		LEXEMEGEN();
		RETURN FATLEX(PLIT'''',.LEXNAME[.VREG<LEFT>],E0<0,0>);
	END;

	BEGIN
		LABEL  SPEC,LOOP,LOK,CHK;

		SPEC:BEGIN
			WHILE 1 DO
			BEGIN	%GET THE SPEC%
				LOOP:BEGIN
					IF  .FILENAME(ICL) EQL  0 OR .DEVICE(ICL) EQL 0
					THEN	IF  FILSP()  EQL  1
						THEN  LEAVE LOOP	!FOUND ONE
						ELSE	IF .VREG LSS 0 
							THEN RETURN .VREG;
					IF .DIRECTORY(ICL)  EQL  0
					THEN	IF  PPN() EQL  1
						THEN	LEAVE LOOP
						ELSE	IF .VREG  LSS 0
							THEN	ERRORR(E117);

					IF SWITCH()  LSS 0
					THEN ERRORR(E116)
					ELSE	IF .VREG  EQL  1
						THEN LEAVE LOOP;

					LEAVE SPEC	!NOTHING ELSE RECOGNIZABLE
				END %LOOP%
			END %WHILE 1%
		END ;	%SPEC%

		%GET THE FINAL ' %
		LOOK4CHAR  _ "'";
		IF LEXICAL(.GSTCSCAN)  EQL  0
		THEN
		BEGIN
			EXTERNAL LEXNAME;
			LEXEMEGEN();
			RETURN FATLEX(PLIT'''',.LEXNAME[.VREG<LEFT>],E0<0,0>);
		END;
			
		IF LEXEMEGEN()  NEQ  EOSLEX^18
		THEN RETURN  NOEOSERRV;

		%NOW LETS TRY AND OPEN THE FILE%
		IF .DEVICE(ICL)  EQL  0
		  THEN DEVICE(ICL) _ SIXBIT'DSK';
		BEGIN	%MAKE SURE THAT THE DEVICE IS A DISK%
			MACHOP  DEVCHR = #047;
			EXTERNAL  E124;
			VREG _ .DEVICE(ICL);
			DEVCHR ( VREG,4);
			IF NOT .VREG<34,1>  %DISK DEVICE%
			THEN	RETURN  FATLERR(.ISN,E124<0,0>)
		END;

		IF .FILENAME(ICL)  EQL  0
		THEN	ERRORR(E118);	!NO FILE NAME

		STATUS(ICL) _ 0;	!ASCII
		BUFFERS(ICL) _ BUFHDR(ICL)<0,0>;

		OPEN  (ICL, STATUS(ICL));
		JFCL(0,0);

		LOK:BEGIN
		WHILE 1 DO
		BEGIN
	
			VREG _ -1;
			LOOKUP(ICL,FILENAME(ICL));
			VREG _ 0;	!FILE NOT FOUND
			IF .VREG  NEQ 0 THEN LEAVE LOK;	!OK FOUND THE FILE

			%TRY WITHOUT .FOR %
			IF .DEFAULT  NEQ 0
			THEN
			BEGIN
				EXTENSION(ICL) _ 0;
				DEFAULT _ 0
			END
			ELSE	ERRORR(E119)
		END	%WHILE 1%
		END	%LOK%
	END;

	END
	ELSE
	BEGIN	%FTTENEX%

		EXTERNAL OPNICL,E138;
		GLOBAL  ICLPTR;		!FILESPEC POINTER
		LOCAL BASE LIT;
		EXTERNAL LITPOINTER;
		LOCAL	LITPNTSAV,VAL;

		LITPNTSAV _ .LITPOINTER;	!SAVE SO LITERAL CAN BE DELETED

		%PICK UP THE LITSTRING SPEC%
		LIT _ LEXICAL(.GSTLEXEME);
		IF .LIT<LEFT>  NEQ  LITSTRING
		THEN	FATLEX(.LEXNAM[LITSTRING],.LEXNAM[.LIT<LEFT>],E0<0,0>);

		%CHECK FOR EOS%
		IF LEXICAL(.GSTLEXEME ) NEQ  EOSLEX^18
		THEN	RETURN  NOEOSERRV;

		ICLPTR _ ( LIT[LIT1] )<36,7>;		!SPEC POINTER
		VAL _ OPNICL();	!OPEN THE FILE

		IF .VAL  NEQ 0	!WAS THERE AN ERROR
		THEN	RETURN  FATLERR(.VAL,.ISN,E138<0,0>);	
				%MESSAGE POINTER GIVEN IN VREG%

![722] REWRITE SO THAT /NOCREF ALLOWED ON INCLUDE STATEMENT
%[722]%		% OK, GOT IT, NOW LOOK FOR /NOLIST OR /NOCREF %
%[722]%
%[722]%		NOLST_0;
%[722]%		NOCRF_0;
%[722]%
%[722]%		WHILE ..ICLPTR EQL "/"
%[722]%		DO
%[722]%		BEGIN
%[722]%			% SEE WHAT THE SWITCH IS %
%[722]%
%[722]%			LABEL CHKLST;
%[722]%			LOCAL PNT,SAVICL;
%[755]%			REGISTER CHAR;
%[755]%			MACRO UPLOW(L) = %( CONVERT LOWER CASE TO UPPER )%
%[755]%				BEGIN
%[755]%				VREG=L;
%[755]%				IF .VREG GEQ #141 %( LOWER CASE A )% AND
%[755]%				   .VREG LEQ #172 %( LOWER CASE Z )%
%[755]%				THEN VREG=.VREG-#40; %( UPPER CASE )%
%[755]%				.VREG
%[755]%				END$;
%[722]%
%[722]%			%TRY /NOLIST %
%[722]%			VAL_0; !NOLST NOT FOUND YET ON THIS PASS
%[722]%			PNT_(PLIT'NOLIST')<36,7>;
%[722]%			SAVICL_.ICLPTR;
%[722]%		CHKLST:	BEGIN
%[755]%				UNTIL (CHAR_SCANI(PNT)) EQL 0
%[755]%				DO IF .CHAR NEQ UPLOW(SCANI(ICLPTR))
%[722]%					THEN LEAVE CHKLST;
%[722]%				NOLST_1; VAL_1;  !WE FOUND /NOLIST
%[722]%				SCANI(ICLPTR);  !BUMP POINTER
%[722]%			END;
%[722]%
%[722]%			IF .VAL EQL 0 THEN  !TRY FOR /NOCREF
%[722]%			BEGIN
%[722]%				ICLPTR_.SAVICL;  !BACK UP THE POINTER
%[722]%				PNT_(PLIT'NOCREF')<36,7>;
%[722]%
%[755]%				UNTIL (CHAR_SCANI(PNT)) EQL 0
%[722]%				DO
%[722]%				BEGIN
%[755]%					IF .CHAR NEQ UPLOW(SCANI(ICLPTR))
%[722]%					THEN (	EXTERNAL CLOICL;
%[722]%						FATLEX(E116<0,0>);!BAD SWITCH
%[722]%						CLOICL();
%[722]%						RETURN )
%[722]%				END;
%[722]%				NOCRF_1;  !WE FOUND /NOCREF
%[722]%				SCANI(ICLPTR)
%[722]%			END;
%[722]%		END;

		%FREE UP THE LITERAL%
%[1224]%	SAVSPACE( .LIT[LITSIZ]+LTLSIZ-1 , @LIT );
		LITPOINTER _ .LITPNTSAV;
		IF .LITPOINTER<RIGHT> NEQ 0 THEN (@LITPOINTER)<RIGHT> _ 0;

	END;	%FTTENEX%



	%OK WE GOT THE FILE%
	%SAVE THE CURRENT BUFFERS%
	LEXICAL (.GSTEOP);	!TERMINATE CURRENT STATEMENT
	EOPSVPOOL();

	%SAVE THE INFO%
	BEGIN
		GLOBAL  SVINCL[8];
		EXTERNAL LINENO;
		EXTERNAL  EOPSAVE,CURPOOLEND,CURPTR,STLPTR,STPTR,LINEPTR,SEQLAST,LINELINE,CHARPOS;

		SVINCL[0] _ .EOPSAVE;
		SVINCL[1] _ .CURPOOLEND;
		SVINCL[2] _ .CURPTR;
		SVINCL[3] _ .STLPTR;
		SVINCL[4] _ .STPTR;
		SVINCL[5] _ .LINEPTR;
		IF .SEQLAST  NEQ  0
		THEN	SVINCL[6] _ .LINELINE	!LINESEQUENCE NUMBER
		ELSE	SVINCL[6] _ 0;
		SVINCL[7] _ .CHARPOS;
		IF .CHARPOS  NEQ 72
		THEN	LINELINE _ .LINELINE+1;	!MULTIPLE STATEMENTS ON LINE
		SAVFLG _ .FLGREG<0,36>;
		FLGREG<ININCLUD> _ 1;
		FLGREG<EOCS> _ 1;
![722] HANDLE NO CREFFING TOO
%[722]%		IF .NOCRF THEN  FLGREG<CROSSREF> _ 0;
		IF .NOLST THEN  FLGREG<LISTING> _ 0;
		SVFLG2 _ .FLAGS2;
		FLAGS2<TTYINPUT> _ 0;

		%SET LINENO[1] SO THAT AN * WILL APPEAR NEXT TO THE
			INCLUDED CODES LINE NUMBER %
		LINENO[1] _ '*	';

		CURPOOLEND _ POOL<0,0>;
		IF EOPRESTORE()  EQL  EOF
		THEN
		BEGIN
			EXTERNAL  POSTINCL;
			POSTINCL();	!RESTORE
		END
	END

END;	! of INCLSTA


GLOBAL ROUTINE POSTINCL=
BEGIN
	%RESTORE THE WORLD AFTER AN INCLUDED FILE %
	EXTERNAL  SVINCL[8];
	EXTERNAL  EOPSAVE,CURPOOLEND,CURPTR,STLPTR,STPTR,LINEPTR,SEQLAST,LINELINE;
	EXTERNAL  EOPRESTORE,SVFLG2;

	EXTERNAL LINENO;
	EXTERNAL SAVFLG,GSTEOP,LEXICAL,CHARPOS;
	MACHOP  CLOSE = #070;

	% CLEAN UP LAST LINE%
	LEXICAL(.GSTEOP);

	IF NOT FTTENEX 
	THEN
		CLOSE (ICL,0)	!CLOSE THE FILE
	ELSE
		( EXTERNAL CLOICL;
		  CLOICL();
		);


	EOPSAVE _ .SVINCL[0];
	CURPOOLEND  _ .SVINCL[1];
	CURPTR _ .SVINCL[2];
	STLPTR _ .SVINCL[3];
	STPTR _ .SVINCL[4];
	LINEPTR _ .SVINCL[5];
	IF .SVINCL[6] NEQ  0
	THEN	LINELINE _ .SVINCL[6];	!LINESEQUENCE NUMBER
	CHARPOS _ .SVINCL[7];

	SEQLAST  _ 1;	!SO NO ONE WILL MESS WITH THE LINELINE
	LINENO[1] _ '	';	!RESET LINENO TO TAB

	!KEEP VALUES OF SOME FLAGS WHICH MAY HAVE CHANGED
	! DURING PROCESSING OF THE INCLUDE FILE, AND WHOSE NEW
	! VALUES WE REALLY WANT TO KEEP!

	SAVFLG<BTTMSTFL> _ .FLGREG<BTTMSTFL>; !IF 16 CLOBBERED
	SAVFLG<WARNGERR> _ .FLGREG<WARNGERR>; !WARNINGS GIVEN
	SAVFLG<FATALERR> _ .FLGREG<FATALERR>; !FATAL ERRORS GIVEN
	SAVFLG<LABLDUM> _ .FLGREG<LABLDUM>; !LABELS PASSED AS ARGS
	FLGREG<0,36> _ .SAVFLG;
	FLAGS2 _ .SVFLG2;
	EOPRESTORE();	!RESTORE THE BUFFERS

END;	! of POSTINCL


GLOBAL ROUTINE ASTER(TYPE) =		! [1527] Rewritten
BEGIN
	!***************************************************************
	! This routine will scan for the *length construct following the
	! data type name in type or IMPLICIT or FUNCTION statements, and
%1575%	! for the forms 'var * len  (subs) * len' in type  declarations.
	! The parameter TYPE  is based  upon the data  type name.   This
	! routine will return as its value:
	!	1. The amended TYPE if a valid * construct was found
	!	2. TYPE if no * construct was found
	!	3. -1 if there was some error in the * construct
	!
%1575%	! Two words are deposited on STK:
%1575%	!	length for character data or 0
%1575%	!	flag = 1 if *size was specified
	!***************************************************************

	MACRO	ERR50(X) = FATLEX( .CHLEN, X<0,0>, E50<0,0>)$,
		ERR24(X) = WARNLEX( X<0,0>, .CHLEN, E24<0,0>)$;

	REGISTER
		BASE T1,
		D;

	EXTERNAL
		CONSTEXPR,
		CHLEN,
		CHDLEN,
		ACTLDATYPE;

%1575%	! Put the default character length on  STK and also a zero  word
%1575%	! for the flag word for *size was specified

%1575%	STK[SP = .SP + 1] = CHLEN = .CHDLEN;
%1575%	STK[SP = .SP + 1] = 0;
	
	! Look at upcoming character.  If '*', continue below, otherwise return

	IF .LSAVE  EQL  0
	THEN
	BEGIN
		LOOK4CHAR = "*";
		IF LEXICAL( .GSTCSCAN ) EQL 0 THEN RETURN .TYPE;
	END
	ELSE
	BEGIN
		IF .LEXL<LEFT> NEQ ASTERISK THEN RETURN .TYPE;
		LSAVE = 0;
	END;

	! Got an *, set the flag for *size specified and check for '(*)'

%1575%	STK[.SP] = 1;
	LOOK4CHAR = (UPLIT ASCIZ '(*)')<36,7>;

	IF LEXICAL(.GSTSSCAN) NEQ 0
	THEN
	BEGIN
		IF .TYPE NEQ CHARACTER 
		THEN RETURN FATLEX (UPLIT'constant',UPLIT'(*)',E0<0,0>);
		CHLEN = LENSTAR;
	END
	ELSE
	BEGIN	! digits for length

		LOOK4CHAR = "?D";	! any digit
		IF (D = LEXICAL(.GSTCSCAN)) NEQ 0
		THEN
		BEGIN	! *digits
			CHLEN = .D - "0";
			WHILE (D = LEXICAL(.GSTCSCAN)) NEQ 0
			DO CHLEN = .CHLEN*10 + .D - "0";
		END	! *digits
		ELSE

		BEGIN	! *(expression)
			LOOK4CHAR = "(";
			IF LEXICAL(.GSTCSCAN) NEQ 0
			THEN			
			BEGIN	
				IF CONSTEXPR() LSS 0 THEN RETURN .VREG;

				IF .LSAVE NEQ 0 THEN LSAVE = 0
						ELSE LEXL = LEXEMEGEN();

				IF .LEXL<LEFT> NEQ RPAREN
				THEN RETURN ERR0L(RPARPLIT);

				T1 = .STK[.SP];
				SP = .SP - 1;
				CHLEN = .T1[CONST2];
			END
			ELSE
%1667%			BEGIN	! error - give found when expecting error

%1667%				IF .LSAVE EQL 0
%1667%				THEN
%1667%				BEGIN
%1667%					LEXL = LEXEMEGEN();
%1667%					LSAVE = -1;
%1667%				END;

%1667%				RETURN ERR0L(UPLIT ASCIZ'integer constant or "("');

			END;	! error - give found when expecting error

		END;	! *(expression)

%1646%		! Give Illegal CHARACTER size modifier is less than 1

%1646%		IF .CHLEN LEQ 0 THEN RETURN ERR50(CHARPLIT);

	END;

	STK[.SP - 1] = .CHLEN;		! Set size specifier on STK

	! Check the specified size to see if it is legal.  Do the  check
	! on the basis of ACTLDATYPE of the statement in order to  allow
	! REAL*8 X*4  and to  exclude doubleprecision  X*4.  Return  the
	! datatype.

	SELECT .ACTLDATYPE OF NSET

	INTEGER:(
		IF .CHLEN EQL 2
		THEN
		BEGIN
			ERR24(INTGPLIT);
			RETURN .ACTLDATYPE
		END;

		IF .CHLEN EQL 4	THEN RETURN .ACTLDATYPE;

		RETURN ERR50(INTGPLIT);
		);

	REAL:(
		IF .CHLEN EQL 4 THEN RETURN .ACTLDATYPE;

	  	IF .CHLEN EQL 8 THEN RETURN DOUBLPREC;	

	  	IF .CHLEN EQL 16
		THEN
		BEGIN
			ERR24(REALPLIT);
			RETURN .ACTLDATYPE
		END;

		RETURN ERR50(REALPLIT)
		);

	COMPLEX:(
		IF .CHLEN EQL 8 THEN RETURN .ACTLDATYPE;

		IF .CHLEN EQL 16
		THEN
		BEGIN
			ERR24(COMPLIT);
			RETURN .ACTLDATYPE
		END;

		IF .CHLEN EQL 32
		THEN
		BEGIN
			ERR24(COMPLIT);
			RETURN .ACTLDATYPE
		END;

		RETURN ERR50(COMPLIT)
		);

	LOGICAL:(
		IF .CHLEN EQL 4 THEN RETURN .ACTLDATYPE;

		IF .CHLEN EQL 1
		THEN
		BEGIN
			ERR24(LOGIPLIT);
			RETURN .ACTLDATYPE
		END;

		RETURN ERR50(LOGIPLIT)
		);

	DOUBLPREC:(RETURN ERR50(DOUBPLIT));

	CHARACTER:(RETURN .ACTLDATYPE);

	TESN

END;	! of  ASTER

GLOBAL ROUTINE TYPDECLARE(DTYPE)=
BEGIN
	!***************************************************************
	! Called  by  INTESTA,  REALSTA,  LOGIST,  DOUBST,  COMPST,  and
	! CHARSTA statement routines.   It handles  the *size  modifier,
	! then uses  the  syntax  of DECLARESPEC  to  parse  a  function
	! declaration or an  explicit type declaration.   It then  calls
	! either FUNCGEN or TYPEGEN to handle the semantics.
	!***************************************************************

	EXTERNAL LSAVE;
	EXTERNAL FUNCGEN,TYPEGEN,SAVSPACE,TYPE,STK;
	EXTERNAL PST1ST,PSTATE,PSTIMPL,PSTSPF,ENDSTA;
%1213%	EXTERNAL CHDLEN,ACTLDATYPE;
	REGISTER BASE T1;

	ACTLDATYPE _ .DTYPE;		!SAVE ACTUAL TYPE IDENTIFIER CODE

%1213%	! Default length for character data is 1.
%1213%	CHDLEN _ 1;

	! PICK UP THE *N CONSTRUCT IF ANY

	LSAVE _ 0;	
	IF ( IDTYPE _ ASTER ( .DTYPE )) LSS  0  THEN  RETURN .IDTYPE;

%1575%	! ASTER leaves two words on STK:
%1575%	!	length for character data
%1575%	!	flag = 1 if *size was specified

%1704%	! Scan for optional comma after optional *n construct

%1704%	IF .STK[.SP] EQL 1
%1704%	THEN
%1704%	BEGIN	! *size was specified, look for optional comma

%1704%		IF .LSAVE  EQL  0
%1704%		THEN
%1704%		BEGIN
%1704%			LOOK4CHAR = ",";
%1704%			LEXICAL( .GSTCSCAN );	! Skip comma
%1704%		END
%1704%		ELSE
%1704%		BEGIN
%1704%			IF .LEXL<LEFT> EQL COMMA
%1704%			THEN LSAVE = 0;
%1704%		END;

%1704%	END;	! *size was specified, look for optional comma

%1575%	! Fetch default length for character data left on stack by ASTER

%1575%	IF .IDTYPE EQL CHARACTER
%1575%	THEN CHDLEN _ .STK[.SP - 1]
%1575%	ELSE CHDLEN _ 0;

%1575%	SP = .SP - 2;		! Discard the two words ASTER put on STK

	IF SYNTAX( DECLARESPEC) LSS  0  THEN  RETURN .VREG;
	TYPE _ 4;
	T1_ .STK[0];
	 IF .T1[ELMNT] EQL 1
		THEN
		BEGIN	% FUNCTION %
			% CHECK THE STATEMENT ORDERING %
			IF .PSTATE EQL  PST1ST<0,0> 
			THEN
			BEGIN	% FINE ITS THE 1ST STATEMENT %
				PSTATE _ PSTIMPL<0,0>;	! ADJUST PSTATE TO IMPLICIT
				FLGREG<PROGTYP> _ FNPROG;

%1213%			! Add second parameter to FUNCGEN; this is the
%1213%			! 'datatype FUNCTION ....' case
%1213%			FUNCGEN(@.T1[ELMNT1], 1)
			END
			ELSE
			BEGIN	% MISSING END STATEMENT %
				RETURN ENDSTA()
			END
		END
		ELSE
		BEGIN	% TYPE DECLARATION %
			IF .PSTATE EQL  PST1ST<0,0>
			THEN	PSTATE _ PSTSPF<0,0>;	! SPECIFICATION STATE
			TYPEGEN(.T1[ELMNT1])
		END;
	SAVSPACE(.STK[0]<LEFT>,.STK[0])

END;	! of TYPDECLARE


! TYPE STATEMENTS  *************

MACRO DATATYPE ( DTYPE )  =
BEGIN
	RETURN  TYPDECLARE( DTYPE )
END
$;

GLOBAL ROUTINE	INTESTA  =	DATATYPE ( INTEGER );

GLOBAL ROUTINE	REALSTA  =	DATATYPE ( REAL ) ;

GLOBAL ROUTINE 	LOGISTA	=	DATATYPE ( LOGICAL )  ;

GLOBAL ROUTINE	DOUBSTA	=	DATATYPE ( DOUBLPREC ) ;

GLOBAL ROUTINE	COMPSTA	=	DATATYPE ( COMPLEX ) ;

GLOBAL ROUTINE	CHARSTA	=
BEGIN

%1213%	! Add CHARSTA for character declaration


	! Set flag for character declaration seen used
	! in MRP3R and MRP3G to test if we have to scan
	! the symbol table to generate high seg
	! character descriptors.

	CHDECL _ -1;

	DATATYPE ( CHARACTER ) ;	! Now process the character statement

END;	! of CHARSTA

GLOBAL ROUTINE FUNCSTA=
BEGIN
	EXTERNAL STK,
		FUNCGEN %()%,
		SAVSPACE %(SIZE,LOC)%,
		TYPE;
	REGISTER BASE T1;

!SEMANTIC ANALYSIS BEGINS
	T1_.STK[0];
	IDTYPE_-1;
	TYPE_4;
	FLGREG<PROGTYP> _ FNPROG;

%[1213]%	! Add second parameter to FUNCGEN; this is 'FUNCTION ...' case
%[1213]%	FUNCGEN(.T1[ELMNT], 0);
	SAVSPACE(0,@STK[0]);
	.VREG

END;	! of FUNCSTA

GLOBAL ROUTINE SUBRSTA=
BEGIN
	EXTERNAL STK,FUNCGEN %()%,SAVSPACE %(SIZE,LOC)%,TYPE;
	REGISTER BASE T1;
!SEMANTIC ANALYSIS BEGINS
	T1_.STK[0];IDTYPE_-1;TYPE_0;
	FLGREG<PROGTYP> _ SUPROG;

%[1213]%	! Add second parameter to FUNCGEN; this is 'SUBROUTINE ...' case
%[1213]%	FUNCGEN(.T1[ELMNT], 0);
	SAVSPACE(0,@STK[0]);
	.VREG

END;	! of SUBRSTA

GLOBAL ROUTINE ENTRSTA=
BEGIN
	! Process an ENTRY statement

%1434%	! Rewritten by TFV on 14-Dec-81

	REGISTER
		BASE FUNCID,	! Name of this function subprogram
		BASE IDSYM,	! Name of the entry point
		BASE PTR,	! Pointer to the syntactic output
		BASE TREE;	! Pointer to the block to  pass  to  the
				! EQUIVALENCE statement semantic routine

	LOCAL
		VAL;		! Used to avoid VREG usage

	! Check for error -  entry illegal inside a do or block if

	IF .DOIFSTK NEQ 0 THEN FATLEX(E75<0,0>);

	! Check for error - entry illegal in main program

	IF .FLGREG<PROGTYP> EQL MAPROG THEN RETURN FATLEX(E114<0,0>);

	IDTYPE = -1;		! Flag for FUNCGEN
	FLGREG<MULTENT> = 1;	! Set entries in subroutine flag
	PTR = .STK[0];		! Pointer to syntactic output

	IDSYM = @.PTR[ELMNT];	! Symbol table entry for this
				! entry point

%1531%	! An ENTRY point can not be in a SAVE statement.

%1531%	IF .IDSYM[IDSAVVARIABLE]
%1531%	THEN	FATLERR(.IDSYM[IDSYMBOL],UPLIT(ASCIZ'ENTRY name'),
%1531%		.ISN,E192<0,0>);

	! Equivalence a  numeric function  and  its entry  names,  character
	! functions and their entry points just share the descriptor for the
	! result.

	IF .FLGREG<PROGTYP> EQL FNPROG
	THEN
	BEGIN	! Function subprogram

		ENTRY = .PROGNAME;	! Name of this subprogram
		NAME = IDTAB;
		FUNCID = TBLSEARCH();	! Lookup symbol table entry for
					! the subprogram name

		IF .FUNCID[VALTYPE] NEQ CHARACTER
		THEN
		BEGIN	! Numeric function subprogram

			! Give an error if this is a character entry  point.
			! If it is numeric, pretend  that we are the  syntax
			! analyzer and  generate  an  EQUIVALENCE  statement
			! syntax tree  and  then  give  it  to  EQUISTA  for
			! semantic processing.

			! Check for error - character and numeric entry
			! points cannot be mixed.

			IF .IDSYM[VALTYPE] EQL CHARACTER
			THEN RETURN FATLEX(E178<0,0>);

			NAME<LEFT> = 9;			! Size of syntax tree
			STK[0] = TREE = CORMAN();	! Get some space

			(.TREE)[0] = .TREE + 1;		! List pointer
			(.TREE)[1] = 1^18 + .TREE + 2;	! All pointer
			(.TREE)[2] = 1^18 + .TREE + 4;	! All pointer
			(.TREE)[3] = .TREE + 6;		! List pointer
			(.TREE)[4] = .FUNCID;		! Function name
			(.TREE)[4]<LEFT> = IDENTIFIER;
			(.TREE)[5] = 0;			! Option
			(.TREE)[6] = 1^18 + .TREE + 7;	! All pointer
			(.TREE)[7] = .IDSYM;		! Entry name
			(.TREE)[8] = 0;			! Option

			! Now process the syntax tree using the EQUIVALENCE
			! statement semantic routine.

			IF (VAL =  EQUISTA()) LSS 0 THEN RETURN .VAL;

		END	! Numeric function subprogram
		ELSE
		BEGIN	! Character function subprogram

			! Check for error - character and numeric entry
			! points cannot be mixed.

			IF .IDSYM[VALTYPE] NEQ CHARACTER
			THEN RETURN FATLEX(E178<0,0>);

			! Check for error - Character entry points must have
			! the same length.

			IF .IDSYM[IDCHLEN] NEQ .FUNCID[IDCHLEN]
			THEN RETURN FATLEX(E179<0,0>);

			IDTYPE = CHARACTER;		! used by funcgen

		END;	! Character function subprogram

	END;	! Function subprogram

	TYPE = 1;

%1213%	! Add second parameter to FUNCGEN; this is 'ENTRY ...' case

%1213%	FUNCGEN(.PTR[ELMNT],0);
	SAVSPACE(0,@PTR)

END;	! of ENTRSTA

GLOBAL ROUTINE PROGSTA=
BEGIN
	EXTERNAL NAMDEF;
	EXTERNAL PROGNAME;
	LEXL_LEXEMEGEN();
	IF .LEXL<LEFT> EQL IDENTIFIER
%[1000]% THEN
%[1000]% BEGIN
%[1000]%	LOCAL BASE PR1;
		PR1_ .LEXL<RIGHT>;
		PROGNAME_.PR1[IDSYMBOL];
		NAMDEF( ENTRYDEF, .PR1 );	! DEFINITION OF PROGNAME
		PR1[IDATTRIBUT(FENTRYNAME)] _ 1;	! SET ENTRY POINT FLAG
		LEXL_LEXEMEGEN();
%[1000]% END
%[1000]% ELSE RETURN ERR0L(PLIT 'PROGRAM name');	! Flag missing name

	IF .LEXL<LEFT> NEQ LINEND
	THEN
	BEGIN	%SKIP ANYTHING LEFT FOR CDC COMPATIBILITY%
		EXTERNAL FATLEX,E134;
		DO LEXEMEGEN() UNTIL .VREG<LEFT> EQL LINEND;
		FATLEX(E134<0,0>)
	END;
	.VREG

END;	! of PROGSTA

GLOBAL ROUTINE PARASTA=

! Parameter statement.
! [1656] All semantics are done in action routines; just return.

RETURN 0;				! RETURN SUCCESS

GLOBAL ROUTINE BLOCSTA=
BEGIN
	EXTERNAL PROGNAME,STK,NAMDEF;
	LEXL_LEXEMEGEN();
	IF .LEXL<LEFT> EQL IDENTIFIER
	  THEN(LOCAL BASE PR1;
		PR1_ .LEXL<RIGHT>;
		PROGNAME_.PR1[IDSYMBOL];
		NAMDEF( ENTRYDEF, .PR1 );	! DEFINITION OF NAME
		PR1[IDATTRIBUT(FENTRYNAME)] _ 1;	!ENTRY POINT FLAG
		LEXL_LEXEMEGEN();
		)
	  ELSE PROGNAME _ SIXBIT'.BLOCK';
	FLGREG<PROGTYP> _ BKPROG;	!BLOCK DATA SUBPROGRAM FLAG
	IF .LEXL<LEFT> NEQ LINEND THEN	RETURN NOEOSERRL;
	.VREG

END;	! of BLOCSTA

GLOBAL ROUTINE DIMESTA=
BEGIN
	EXTERNAL STK,BLDARRAY %(LIST OF ONEARRAY'S)%,SAVSPACE %(SIZE,LOC)%,TYPE;
	REGISTER BASE T1;
!SEMANTIC ANALYSIS BEGINS
	IDTYPE_-1;TYPE_0;T1_@STK[0];BLDARRAY(.T1[ELMNT]);
	SAVSPACE(0,@STK[0]);
	.VREG

END;	! of DIMESTA

GLOBAL ROUTINE COMMSTA=
BEGIN
	EXTERNAL NAMDEF;
	EXTERNAL STK,
		BLDARRAY %(ONEARRAY LIST)%,
		SAVSPACE %(SIZE,LOC)%,
		TYPE,
		IDTYPE,
		BLKSRCH %(NAME)%;
	EXTERNAL FATLEX,
		E0;
	REGISTER BASE T1;
	LOCAL BASE T2;
	REGISTER BASE R1:R2;

!SEMANTIC ANALYSIS BEGINS
!-----------------------------------------------------------------------------------
!THE FIRST LOCATION OF THE LEXEME STACK (STK[0])
!POINTS TO THE LIST OF COMMON GROUPS TO BE SCANNED.
!-----------------------------------------------------------------------------------
	R1_.STK[0];
	STK[1]_.R1[ELMNT];
	SAVSPACE(0,@R1);
	INCR CLST FROM @STK[1] TO @STK[1]+.STK[1]<LEFT> DO
	BEGIN
		MAP BASE CLST;
		R1_.CLST[ELMNT];
		IF .R1[ELMNT] EQL 0 THEN ! BLANK COMMON
		BEGIN
			IF .CLST EQL @STK[1]	!IF WE ARE STILL AT THE BEGINNING OF THE LIST
			THEN
%1511%			BEGIN	!IT'S OK
				R2_BLKSRCH(SIXBIT '.COMM.');
%1511%				! We need a SAVE rel block
%1511%				SAVBLC _ TRUE;
%1511%				SAVNED _ TRUE;
%1511%			END
			ELSE	!SOMEONE FORGOT A COMMA
				FATLEX(PLIT ', OR /',PLIT 'IDENTIFIER',E0<0,0>)
		END
		ELSE !SLASHS SEEN GET BLOCK NAME IF THERE
		BEGIN
%1256%			IF .R1[ELMNT] EQL 2 
				! OPTION 2, // SEEN.  MEANS BLANK COMMON
%1256%			THEN
%1511%			BEGIN
			 	R2_BLKSRCH(SIXBIT '.COMM.');
%1511%				! Need to rel block to SAVE this
%1511%				SAVBLC _ TRUE;
%1511%				SAVNED _ TRUE;
%1511%			END
			ELSE	! OPTION 1, /IDENTIFIER/ SEEN.
			BEGIN
				T1_.R1[ELMNT1];
				T2_.T1[ELMNT1];SAVSPACE(.T1<LEFT>,@T1);
				%CHECK AND DEFINE THE NAME %
				IF NAMDEF( CMNBLK, .T2 ) LSS 0 THEN RETURN .VREG;

				T2[IDATTRIBUT(COMBL)] _ 1; !SET COMMONBLOCK NAME BIT

				R2_BLKSRCH(.T2[IDSYMBOL]);
				R1_.R1+1; !INCR PTR IF SLASHES FOR CALL TO BLDARRAY COMING UP
			END;
		END;
		IDTYPE_-1;
		TYPE_5;
		STK[2]<LEFT>_.R2[COMFIRST];

		!MUST BE VERY CAREFUL IF BLDARRAY FAILS, FOR UNDER SOME
		! CIRCUMSTANCES, STK[2] WILL CONTAIN -1 WHICH KILLS US
		STK[2]<RIGHT>_.R2[COMLAST];
		IF BLDARRAY(.R1[ELMNT1]) GEQ 0 
		THEN
		BEGIN
			!---------------------------------------------------------------------------

			!STK[2]  CONTAINS  THE   INFORMATION  REQUIRED   BY
			!BLDARRAY TO LINK ELEMENTS OF THE COMMON BLOCK.  IT
			!IS UPDATED  BY BLDARRAY  TO CONTAIN  LINKS TO  THE
			!FIRST   AND   LAST    ELEMENT   IN   THE    BLOCK.
			!--------------------------------------------------------------------------
			R2[COMFIRST]_.STK[2]<LEFT>;
			R2[COMLAST]_.STK[2]<RIGHT>;
			R1 _ .R2[COMFIRST]; !FIRST ITEM IN BLOCK
				DO
				   R1[IDCOMMON] _ .R2  !PUTTING PTR TO BLOCK IN EACH ITEM
				  WHILE (R1 _ .R1[IDCOLINK]) NEQ 0;
		END %OF FIXING UP COMMON POINTERS%

	END;
	T1_.STK[1];SAVSPACE(.T1<LEFT>,@T1);
	.VREG

END;	! of COMMSTA

GLOBAL ROUTINE SAVESTA=	![1511] New  [1531] Rewrite

! Processes SAVE statements

BEGIN
	REGISTER BASE PTR1;	! Pointer to something
	REGISTER BASE PTR2;	! Pointer to something
	REGISTER BASE SYMTAB;	! Symbol table entry
	

	SAVNED = TRUE;	! We need a save statement

	! STK[0]
	! | len-1,,ptr | ---> | 0=no args 	   |
	!		      +--------------------+
	!		      | len-1,,ptr to args |

	PTR1 = .STK<RIGHT>;

	IF .PTR1[ELMNT] EQL 0
	THEN	! No arguments given, set global flag.
	BEGIN
		SAVALL = TRUE;	! Save everything possible
		SAVLOC = TRUE;	! Save locals (non-commons)
	END
	ELSE
	BEGIN	! Arguments are given, process them.

		PTR1 = .PTR1[ELMNT1];	! Get the pointer

		INCR ARG FROM .PTR1<RIGHT> TO .PTR1<RIGHT> + .PTR1<LEFT>
			BY 2 DO
		BEGIN	! For each argument to SAVE

			MAP BASE ARG;

			! | len-1,,ptr to args | ---> | 1=var, 2=common	|
			!			      +-----------------+
			!			      | len-1,,ptr	|

			IF .ARG[ELMNT] EQL 1
			THEN
			BEGIN	! Variable or array

				SYMTAB = .ARG[ELMNT1];		! Symbol table
				SYMTAB[IDSAVVARIABLE] = 1;	! Found in SAVE
				SAVLOC = TRUE;			! Save locals

				! If this variable is declared in a common,
				! then give an error.
				IF .SYMTAB[IDATTRIBUT(INCOM)]
				THEN 	FATLERR(.SYMTAB[IDSYMBOL],
					UPLIT(ASCIZ'COMMON variable'),
					.ISN,E192<0,0>);

				! Dummy's are illegal.
				IF .SYMTAB[IDATTRIBUT(DUMMY)]
				THEN	FATLERR(.SYMTAB[IDSYMBOL],
					UPLIT(ASCIZ'Dummy argument'),
					.ISN,E192<0,0>);

				! External function name is illegal
				IF .SYMTAB[IDATTRIBUT(INEXTERN)] OR
				   .SYMTAB[IDATTRIBUT(USERFUNCTION)]
				THEN 	FATLERR(.SYMTAB[IDSYMBOL],
					UPLIT(ASCIZ'External name'),
					.ISN,E192<0,0>);

			END	! Variable or array
			ELSE
			BEGIN	! Named common block name

				! | len-1,,ptr | ---> | 23 octal (/)	  |
				! 		      +-------------------+
				! 		      | ptr to symbol tbl |
				!		      +-------------------+
				! 		      | 23 octal (/)	  |

				PTR2 = .ARG[ELMNT1];
				SYMTAB = .PTR2[ELMNT1];	! Symbol table

				! Don't link this  name if  it was  already
				! specified in a SAVE.
				IF NOT .SYMTAB[IDSAVCOMMON]
				THEN	LKSVCOMMON(.SYMTAB);	! Link it in

			END;	! Named common block name
					
		END;	! For each argument to SAVE

	END;	! Arguments are given, process them.


END;	! of SAVESTA

GLOBAL ROUTINE LKSVCOMMON(SYMTAB)=	![1531] Rewrite
BEGIN
	! Put passed  common  symbol  table pointer  into  linked  list  of
	! commons for SAVE statement processing.

	REGISTER BASE NEWLINK;	! New link to be added to PTRSAVCOMMON

	MAP BASE SYMTAB;	! Passed argument - symbol table entry to 
				! be added.


	! Get one word for the link
	NAME<LEFT> = 1;
	NEWLINK = CORMAN();

	! Place in ptr to symbol table
	NEWLINK[CW0L] = .SYMTAB;

	! Place in ptr to previous common symbol or 0
	NEWLINK[CLINK] =  .PTRSAVCOMMON;
	PTRSAVCOMMON = .NEWLINK;

	! Bump count of commons by one
	NUMSAVCOMMON = .NUMSAVCOMMON + 1;

	! Mark that this common is to be SAVE-d
	SYMTAB[IDSAVCOMMON] = 1;

END;	! of LKSVCOMMNON

END
ELUDOM