Google
 

Trailing-Edge - PDP-10 Archives - BB-4157D-BM - sources/cgstmn.bli
There are 12 other files named cgstmn.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) 1972,1977 BY DIGITAL EQUIPMENT CORPORATION
!AUTHOR: S. MURPHY/HPW/DCE/SJW
MODULE	CGSTMNT(SREG=#17,VREG=#15,FREG=#16,DREGS=4,RESERVE(0,1,2,3)) =
BEGIN

GLOBAL BIND CGSTV = 5^24 + 1^18 + 131;	!VERSION DATE: 14-AUG-77

%(
REVISION HISTORY

105	-----	-----	ADD CODE GENERATION ROUTINES FOR E1LISTCALL AND
			E2LISTCALL NODES
106	-----	-----	GENERATE ZERO INCREMENT FOR E1 OR E2 LISTCALL
			NODES OUT OF LINE
107	-----	-----	GENERATE CODE FOR COMMON SUBS ON CALL STMNTS

108	-----	-----	FOR A REFERENCE TO A FORMAT STMNT, MAKE THE
			PEEPHOLE BUFFER ENTRY POINT TO THE FORMAT STMNT RATHER
			THAN SIMPLY CONTAINING THE RELATIVE ADDRESS OF THE STRING
109	-----	-----	FIX CAE1LIST AND CAE2LIST TO CALL IOPTR INSTEAD 
			OF ARGGEN
110	-----	-----	ADD CODE TO HANDLE ARBITRARY EXPRESSION AS THE VAL
			OF AN ARG TO OPEN; ADD CODE TO HANDLE ARBITRARY EXPRESSION
			AS A UNIT NUMBER

111	-----	-----	FIX BUG IN 110 (HAD LEFT OUT "FIND" AND "OPEN/CLOSE"
			FOR EXPRESSIONS AS UNIT NOS)
112	-----	-----	COMMENT OUT THE ROUTINE "CGRELS" - WE CALL
			"CGMTOP" FOR RELEASE STMNTS
113	-----	-----	FIX ERROR CALLS
114	-----	-----	FIX REFERENCES TO PROEPITYP AND PROGNAME
115	-----	-----	FIX CGDCALL TO SET INDIRECT BIT OVER FORMAL
			ARRAYS UNDER DATACALL NODES
116	-----	-----	FIX CALLS TO IOPTR IN CAE1LIST AND CAE2LIST TO
			CLEAR PBOPWD FIRST
117	-----	-----	CHANGE IOIMMED AS FOLLOWS:
			FOROTS WILL NOW PERFORM THE INDIRECT
			FOR ALL ARGUMENTS NOT IMMEDIATE MODE
			CONSTANTS
			DISTINGUISH IMMEDIATE MODE CONSTANTS FROM
			IMMEDIATE MODE ARGUMENTS IN MEMORY
			AS FOLLOWS:
				CONSTANTS HAVE AN EMPTY LEFT HALF
				OTHER VARIABLES HAVE TYPE FIELD SET
				ONLY AN ARGUMENT PASSED IN THE FIRST
					ELEMENT OF A FORMAL ARRAY
					WILL HAVE THE INDIRECT BIT
					SET
			FOROTS WILL PERFORM AN EXTRA OPERATION
			TO LOAD THE RIGHT HALF OF THE ARGUMENT
			IN MEMORY

118	-----	-----	DO NOT CALL "IOENDERR" FOR FIND STMNTS,
			SIMPLY PUT OUT 2 WDS OF 0 (THE STMNT NODE DOES NOT HAVE END/ERR FIELDS)
119	-----	-----	IN CGSTMN, IF THE FLAG "DBGTRAC" IS SET CALL
			XCTFDDT TO GENERATE "XCT FDDT."
120	-----	-----	TAKE OUT CALLS TO FIN. FOR NAMELIST READ/WRITE
122	-----	-----	DONT CALL "XCTFDDT" FOR STMNT FNS AND ENTRIES
			UNTIL AFTER THE LABELS ON THEM ARE DEFINED
123	-----	-----	FIX CODE GEN FOR "DIALOG" IN AN OPEN STMNT
124	306	16156	FIX OPEN/CLOSE TO GIVE FOROTS FORMAL ARRAYS RIGHT
125	367	18239	MAKE WRITE(3) GENERATE CORRECT CODE
126	376	18398	PREVENT CGRECNUM FROM CHANGING A1LABEL

*********** BEGIN VERSION 5A *************

127	532	20323	SET INDIRECT BIT IN ARG BLOCK FOR ARRAY
			REF AS ASSOCIATE VARIABLE
130	564	-----	MAKE CGREAD AND CGWRIT SYMMETRICAL:
			  MAKE CGREAD CHECK FOR NAMELIST ONLY IF IONAME
			  PTR NEQ 0;
			  MAKE CGWRIT GENERATE FIN CALL IF UNFORMATTED
131	607	22685	SET GLOBAL FLAG NEDZER IN CGEND, CGSTOP & CGPAUS
			  TO INDICATE ZERO-ARG-BLOCK NEEDED
)%

	FORWARD
		CGASMNT(0),CGAGO(0),CGCGO(0), CGLOGIF(0),CGARIF(0),CGASSI(0),CGCMNSUB(0),
		CGPAUSE(0),CGSTOP(0),
		CGIOLST(0),CGIOCALL(1),
		CGIOLARGS(0),CGDCALL(0),CGSLIST(0),
		CGE1LIST(1),CGE2LIST(1),
		CAE1LIST(0),CAE2LIST(0),
		BLDIOIMWD(1),
		CGMTOP(0),CGREAD(0),CGWRIT(0),CGDECO(0),CGENCO(0),CGRERE(0),
		CGUNIT(0),CGRECNUM(0),CGFIND(0),
		CGCLOS(0),CGOPEN(0),CGEND(0),
		IOPTR(1);


	EXTERNAL CGERR,OUTMOD, PEEPOPTIMZ,  CGFNCALL, CGARREF, 
		OPCMGET,OPGETA,OPGETI,OPGARI,OPGARA,OPGSTA,OPGSTI,
		OPGPAU,OPGSTP,OPGEXI,OPGIOL,OPGREL,OPGBOOL,OPGCGO,OPGCGI,
		OPGASR,OPGVTS,OPGAIF,ZERBLK,
%[607]%		NEDZER,	! FLAG TO INDICATE IF ZERO-ARG-BLOCK NEEDED
		OPGENDISP;

	EXTERNAL
		CGETVAL,CGOPGEN,
		CGARGEVAL,TREEPTR,A1NODE,A2NODE,A1LABEL,C1H,OPDSPIX,REGFORCOMP,CSTMNT;

	EXTERNAL
		CGCBOOL,GENLAB,DEFLAB,CGREL1;
	EXTERNAL CGDOLOOP,CGDOEND,CGPROEPI,CGSFN,CGSBPRGM,CGRETURN,CGARGS;
	EXTERNAL
		PBOPWD,PSYMPTR,OBUFF,OBUFFA;
EXTERNAL OPGASA,OPGASI,OPASIN;
EXTERNAL OPGAI1,OPGAI2;

SWITCHES NOLIST;
REQUIRE FIRST.BLI;
REQUIRE TABLES.BLI;
SWITCHES LIST;


MAP PEXPRNODE TREEPTR:A1NODE:A2NODE;

MAP BASE CSTMNT;

OWN BASE TOPSTMNT;	!WHEN HAVE A STATEMENT EMBEDDED INSIDE ANOTHER (EG IN 
			! LOGICAL IFS) THIS VAR PTS TO THE TOP LEVEL STMNT NODE

GLOBAL ROUTINE CGSTMNT=
%(***************************************************************************
	ROUTINE TO PERFORM CODE GENERATION FOR A STATEMENT.
	CALLED WITH THE GLOBAL CSTMNT POINTING TO THE STATEMENT FOR WHICH CODE
	IS TO BE GENERATED.
***************************************************************************)%
BEGIN
	EXTERNAL XCTFDDT;	!ROUTINE TO GENERATE "XCT FDDT."
	EXTERNAL PBFPTR;
	MAP PPEEPFRAME PBFPTR;

	%(***IF THERE IS A LABEL ON THIS STATEMENT, ASSOCIATE THAT LABEL WITH THE
		CURRENT LOCATION***)%
	IF .CSTMNT[SRCLBL] NEQ 0
	THEN DEFLAB(.CSTMNT[SRCLBL]);


	%(***SET ISN FIELD FOR NEXT INSTR TO BE GENERATED TO ISN OF THIS STMNT***)%
	PBFPTR[PBFISN]_.CSTMNT[SRCISN];

	IF .FLGREG<DBGTRAC>	!IF USER SPECIFIED /DEB:TRACE
	THEN
	( IF .CSTMNT[SRCID] NEQ ENTRID AND .CSTMNT[SRCID] NEQ SFNID
	THEN XCTFDDT());	! GENERATE "XCT FDDT."

	%(***GENERATE CODE FOR THE STATEMENT************)%
	CASE .CSTMNT[SRCID] OF SET

	CGASMNT();		!FOR AN ASSIGNMENT
	CGASSI();		! ASSIGN
	BEGIN			! CALL
		IF .CSTMNT[SRCCOMNSUB] NEQ 0
		THEN CGCMNSUB();		!IF HAVE ANY COMMON SUBS
						! GENERATE CODE FOR THEM
		CGSBPRGM(.CSTMNT[CALLIST],.CSTMNT[CALSYM]);	
	END;
	BEGIN END;		! CONTINUE
	CGDOLOOP();		! DO
	CGPROEPI();		! ENTRY
	CGASMNT();		! COMMON SUBEXPR - SAME AS ASMNT

	JRSTGEN(.CSTMNT[GOTOLBL]);	!GOTO
	CGAGO();		! ASSIGNED GOTO
	CGCGO();		! COMPUTED GOTO
	CGARIF();		!ARITHMETIC IF
	CGLOGIF();		! LOGICAL IF
	CGRETURN(.CSTMNT[RETEXPR]);	! RETURN
	CGSTOP();		! STOP

	CGREAD();		! READ
	CGWRIT();		! WRITE
	CGDECO();		! DECODE
	CGENCO();		! ENCODE
	CGRERE();		! REREAD
	CGFIND();		! FIND
	CGCLOS();		! CLOSE
	BEGIN END;		! INPUT (NOT IN RELEASE 1)
	BEGIN END;		! OUTPUT (NOT IN RELEASE 1)

	CGMTOP();		! BACKSPACE
	CGMTOP();		! BACKFILE
	CGMTOP();		! REWIND
	CGMTOP();		! SKIP FILE
	CGMTOP();		! SKIP RECORD
	CGMTOP();		! UNLOAD
	CGMTOP();		! RELEASE
	CGMTOP();		! ENDFILE

	CGEND();		! END
	CGPAUSE();		! PAUSE
	CGOPEN();		! OPEN
	CGSFN();		! STATEMENT FN
	BEGIN END;		! FORMAT - NO CODE GENERATED
	BEGIN END;		! BLT (NOT IN RELEASE 1)
	BEGIN END;		! OVERLAY ID
	TES;

	%(***IF THIS STMNT HAS A LABEL, CHECK FOR WHETHER IT ENDS A DO STMNT***)%
	IF .CSTMNT[SRCLBL] NEQ 0
	THEN CGDOEND(.CSTMNT[SRCLBL]);

END;


GLOBAL ROUTINE CGASMNT=
%(***************************************************************************
	ROUTINE TO GENERATE CODE FOR ASSIGNMENT STATEMENTS.
	CALLED WITH THE GLOBAL CSTMNT POINTING TO THE STATEMENT FOR
	WHICH CODE IS TO BE GENERATED.
***************************************************************************)%
BEGIN

	%(***COMPUTE THE VALUES OF ANY COMMON SUBEXPRS ASSOCIATED WITH THIS STATEMENT***)%
	IF .CSTMNT[SRCCOMNSUB] NEQ 0 THEN CGCMNSUB();

	%(***GET THE VALUE OF THE LEFT HAND SIDE OF THE STATEMENT AND THE ADDRESS
		OF THE RIGHT HAND SIDE WITHIN REACH OF ONE INSTRUCTION***)%
	IF .CSTMNT[A1VALFLG]
		OR (.CSTMNT[MEMCMPFLG] AND .CSTMNT[RVRSFLG])	!IF RHS IS COMPUTED DIRECTLY TO
						! MEMORY LOC OF LHS AND VAL OF LHS NEEDNT BE PRELOADED

	THEN
	BEGIN
		IF NOT .CSTMNT[A2VALFLG]
		THEN
		BEGIN
			TREEPTR_.CSTMNT[RHEXP];
			CGETVAL();
		END;
	END
	ELSE
	IF .CSTMNT[A2VALFLG]
	THEN
	BEGIN
		TREEPTR_.CSTMNT[LHEXP];
		CGETVAL();
	END
	ELSE
	IF .CSTMNT[RVRSFLG]
	THEN
	%(***IF RIGHT-HAND SIDE SHOULD BE EVALUATED FIRST***)%
	BEGIN
		TREEPTR_.CSTMNT[RHEXP];
		CGETVAL();
		TREEPTR_.CSTMNT[LHEXP];
		CGETVAL();
	END
	ELSE
	%(***IF LEFT-HAND SIDE SHOULD BE EVALUATED FIRST***)%
	BEGIN
		TREEPTR_.CSTMNT[LHEXP];
		CGETVAL();
		TREEPTR_.CSTMNT[RHEXP];
		CGETVAL();
	END;





	%(***IF THE RHS WAS NOT COMPUTED DIRECTLY INTO THE MEMORY LOC FOR THE LHS, PICK UP THE
		RHS AND STORE IT INTO THE LHS*******)%
	IF NOT .CSTMNT[MEMCMPFLG]
	THEN
	BEGIN
		REGFORCOMP_GETASMNREG(CSTMNT);
		%(***GET VAL OF RIGHT-HAND SIDE INTO REG FOR COMPUTATION OF THE STMNT***)%
		A1NODE_.CSTMNT[RHEXP];
		TREEPTR_.CSTMNT;
		OPDSPIX_GETA2OPIX(CSTMNT,A1NODE);
		CGOPGEN();

		%(***STORE THE VALUE FROM REG-FOR-COMPUTATION INTO THE ADDRESS
			SPECIFIED BY THE LEFT-HAND-SIDE***)%
		IF NOT .CSTMNT[A1SAMEFLG]
		THEN
		BEGIN
			TREEPTR_.CSTMNT[LHEXP];
			OPDSPIX_ASNOPIX(CSTMNT,TREEPTR);
			CGOPGEN();
		END;
	END;
END;

GLOBAL ROUTINE CGASSI=
%(***************************************************************************
	GENERATE CODE FOR AN ASSIGN STATEMENT.
	NOTE THAT THE VARIABLE WILL ALWAYS BE LOADED INTO REGISTER 1
***************************************************************************)%
BEGIN
	%(***IF THE ASSIGNED VAR IS AN ARRAYREF, GENERATE CODE TO COMPUTE ITS ADDR***)%
	TREEPTR_.CSTMNT[ASISYM];
	IF .TREEPTR[OPRCLS] EQL ARRAYREF
	THEN
	CGETVAL();

	%(***COMPUTE THE ASSIGN*******)%
	A1NODE_.CSTMNT[ASISYM];
	A1LABEL_.CSTMNT[ASILBL];
	OPDSPIX_OPASIN;
	CGOPGEN();
END;

GLOBAL ROUTINE CGAGO=
%(***************************************************************************
	ROUTINE TO GENERATE CODE FOR ASSIGNED GOTO STATEMENT.
	CALLED WITH "CSTMNT" POINTING TO THE STATEMENT TO BE PROCESSED.
	IF A LIST OF LABELS WAS SPECIFIED FOR THIS STMNT,
	CODE GENERATED IS:
		MOVE	1,VAR
		CAIN	1,LAB1
		JRST	LAB1
		CAIN	1,LAB2
		JRST	LAB2
		.
		.
	IF NOT, THE CODE GENERATED IS
		SKIPE	1,VAR
		JRST	0(1)
***************************************************************************)%
BEGIN

	%(***OPCODES NEEDED FOR CODE FOR ASSIGNED GOTO***)%
	BIND
		HRRZOC=#550^27,
		CAINOC=#306^27,
		SKIPEOC=#332^27;

	%(***ALWAYS USE REGISTER 1 TO HOLD THE ASSIGNED VAR***)%
	BIND AGOREG=1^23;
	BIND AGORGIX=1^18;

	OWN AGOLSTPTR;
	OWN PEXPRNODE AGOVAR;

	%(***SET UP THE GLOBALS "PBOPWD" AND "PSYMPTR" USED BY THE OUTPUT ROUTINE 
		TO INDICATE AN ADDRESS REFERENCE TO THE ASSIGNED VARIABLE***)%

	AGOVAR_.CSTMNT[AGOTOLBL];

	%(***IF ASSIGNED VAR IS AN ARRAY REFERENCE*****)%
	IF .AGOVAR[OPRCLS] EQL ARRAYREF
	THEN
	BEGIN
		TREEPTR_.AGOVAR;
		CGETVAL();

		PSYMPTR_.AGOVAR[ARG1PTR];		!SYMBOL TABLE ENTRY FOR THE
							! ARRAY
		PBOPWD_.AGOVAR[TARGET];			!ADDRESS FIELD TO REF THE ARRAY
							! ELEMENT DESIRED
	END

	%(***IF ASSIGNED VAR IS A SCALAR***)%
	ELSE
	BEGIN
		PSYMPTR_.AGOVAR;
		PBOPWD_.AGOVAR[IDADDR];
	END;


	%(****IF NO LIST OF LABELS WAS SPECIFIED******)%
	IF .CSTMNT[GOTOLIST] EQL 0
	THEN
	BEGIN
		%(***GENERATE "SKIPE 1,VAR" ***)%
		PBOPWD_.PBOPWD OR SKIPEOC OR AGOREG;
		OBUFF();

		%(***GENERATE JRST 0(1)***)%
		PSYMPTR_PBFNOSYM;
		PBOPWD_JRSTOC OR AGORGIX;
		OBUFF();
	END

	%(***IF A LIST OF LABELS WAS SPECIFIED***)%
	ELSE
	BEGIN
		%(***GENERATE HRRZ 1,VAR****)%
		PBOPWD_.PBOPWD OR HRRZOC OR AGOREG;
		OBUFF();

		%(***FOR EACH LABEL IN THE LIST, COMPARE REG 1 WITH THE LABEL AND
			IF IT IS EQUAL, TRANSFER TO THE LABEL*****)%
		AGOLSTPTR_.CSTMNT[GOTOLIST];
		DECR CT FROM (.CSTMNT[GOTONUM]-1) TO 0
		DO
		BEGIN
			PBOPWD_CAINOC OR AGOREG OR @.AGOLSTPTR;
			PSYMPTR_PBFLABREF;
			OBUFF();
			JRSTGEN(@.AGOLSTPTR);
			AGOLSTPTR_.AGOLSTPTR+1;
		END;
	END;
END;



GLOBAL ROUTINE CGCGO=
%(***************************************************************************
	ROUTINE TO GENERATE CODE FOR COMPUTED GOTO.
	CODE GENERATED IS:
		SKIPLE	01,VAL
		CAILE	01,CT
		JRST	Y
		JRST	@.(1)
		ARG	L1
		ARG	L2
		.
		.
	   Y:	1ST INSTR OF NEXT STMNT
	CALLED WITH THE GLOBAL CSTMNT POINTING TO THE COMPUTED GOTO STMNT
***************************************************************************)%
BEGIN
	OWN BASE NXTSTMNT;

	%(***DEFINE OPCODES USED FOR COMPUTED GOTO***)%
	BIND	SKIPLEOC=#333^27,
		CAILEOC=#303^27,
		SKIPAOC=#334^27,
		ARGOC=JUMPOCD^27;			!USE JUMP

	%(***ALWAYS USE REGISTER 1 TO HOLD THE COMPUTED VAL***)%
	BIND	CGOREG=1^23,
		CGORGIX=1^18;

	OWN PEXPRNODE CGOEXP;
	OWN CLOC;
	OWN CGOLSTPTR;

	%(***COMPUTE THE VALUES OF ANY COMMON SUBEXPRS ASSOCIATED WITH THIS STMNT***)%
	IF .CSTMNT[SRCCOMNSUB] NEQ 0 THEN CGCMNSUB();


	CGOEXP_.CSTMNT[CGOTOLBL];

	%(***IF THE EXPRESSION IS NOT A SCALAR OR A COMMON SUB, EVALUATE IT***)%
	IF .CGOEXP[OPRCLS] NEQ DATAOPR AND .CGOEXP[OPRCLS] NEQ CMNSUB
	THEN
	BEGIN
		TREEPTR_.CGOEXP;
		CGETVAL();
	END;

	%(***GENERATE THE SKIPLE, CAILE, JRST SEQUENCE***)%

	%(******DETERMINE WHAT THE LABEL ON THE NEXT STMNT IS, IF THERE IS NONE, GENERATE ONE***)%
	%(*******(NOTE THAT IF THIS STMNT IS EMBEDDED INSIDE AN ARITH OR LOGICAL IF, MUST
		LOOK AT THE "TOP-LEVEL" STMNT NODE TO GET A PTR TO THE NEXT STMNT)***)%
	NXTSTMNT_(IF .CSTMNT[CLINK] NEQ 0 THEN .CSTMNT[CLINK] ELSE .TOPSTMNT[CLINK]);
	A1LABEL_(IF .NXTSTMNT[SRCLBL] NEQ 0 THEN .NXTSTMNT[SRCLBL]
		 ELSE (NXTSTMNT[SRCLBL]_GENLAB() )  );

	A1NODE_.CGOEXP;
	C1H_.CSTMNT[GOTONUM];

	%(***HAVE A SPECIAL CASE WHEN THE EXPRESSION IS THE LOOP INDEX OF A LOOP IN
		WHICH THE INDEX IS STORED IN THE RIGHT HALF OF AN AC
		(IN THIS CASE GENERATE:
			MOVEI	1,0(LOOPAC)
			JUMPLE	1,Y
			CAILE	1,CT
			JRST	Y) 
	*********)%
	IF .CSTMNT[A1IMMEDFLG] AND .CGOEXP[OPRCLS] EQL REGCONTENTS
	THEN OPDSPIX_OPGCGI

	ELSE OPDSPIX_OPGCGO;
	CGOPGEN();


	%(***ASSOCIATE A LABEL WITH THE CURRENT LOC***)%
	CLOC_GENLAB();
	DEFLAB(.CLOC);

	%(***GENERATE JRST @CLOC(1)***)%
	PBOPWD_JRSTOC OR INDBIT OR CGORGIX OR .CLOC;
	PSYMPTR_PBFLABREF;
	OBUFF();

	%(***FOR EACH LABEL LISTED, GENERTAE "ARG LAB"***)%
	PSYMPTR_PBFLABREF;
	CGOLSTPTR_.CSTMNT[GOTOLIST];
	DECR CT FROM (.CSTMNT[GOTONUM]-1) TO 0
	DO
	BEGIN
		PBOPWD_ARGOC OR @.CGOLSTPTR;
		OBUFF();
		CGOLSTPTR_.CGOLSTPTR+1;
	END;

END;

GLOBAL ROUTINE CGLOGIF=
%(***************************************************************************
	ROUTINE TO GENERATE CODE FOR LOGICAL IF STATEMENTS.
	CALLED WITH THE GLOBAL CSTMNT POINTING TO THE STATEMENT FOR
	WHICH CODE IS TO BE GENERATED.
	A LOGICAL IF STATEMENT NODE MAY HAVE THE FLAG "A1NOTFLG" SET, WHICH
	MEANS TO TAKE THE "NOT" (COMPLEMENT) OF THE CONDITION SPECIFIED.
	BECAUSE "NOT" PROPAGATES OVER BOTH BOOLEANS AND RELATIONALS, IT IS ASSUMED
	THAT THIS FLAG WILL NEVER BE SET WHEN THE CONDITION IS A BOOLEAN OR RELATIONAL.
***************************************************************************)%
BEGIN
	OWN THENLAB,ELSELAB;		!NEW LABEL TABLE ENTRIES
					!WHICH WILL BE CREATED TO PROCESS
					! THIS STMNT
	OWN BASE SUBSTATMNT;		!STATEMENT TO BE EXECUTED IF CONDITION HOLDS
	OWN BASE SAVSTMNT;		!SAVE PTR TO THE LOG IF  STATEMENT
	OWN PEXPRNODE CONDEXPR;		!CONDITIONAL EXPRESSION TO BE TESTED

	%(***EVALUATE ANY COMMON SUBEXPRESSIONS UNDER THIS STATEMENT***)%
	IF .CSTMNT[SRCCOMNSUB] NEQ 0 THEN CGCMNSUB();


	SUBSTATMNT_.CSTMNT[LIFSTATE];
	CONDEXPR_.CSTMNT[LIFEXPR];
	TREEPTR_.CSTMNT[LIFEXPR];

	%(*****WHEN THE STATEMENT TO BE EXECUTED IF  CONDITION IS TRUE IS A GOTO***)%
	IF .SUBSTATMNT[SRCID] EQL GOTOID
	THEN
	BEGIN
		%(****IF THE CONDITION TO BE TESTED IS A RELATIONAL***)%
		IF .CONDEXPR[OPRCLS] EQL  RELATIONAL
		THEN
		BEGIN
			CGREL1(FALSE);		!SKIP NEXT INSTR IF REL IS FALSE
			%(***GENERATE A JRST TO THE GOTO-LABEL***)%
			JRSTGEN(.SUBSTATMNT[GOTOLBL]);
		END

		%(***IF THE CONDITION TO BE TESTED IS A BOOLEAN***)%
		ELSE
		IF .CONDEXPR[OPRCLS] EQL BOOLEAN
		THEN
		BEGIN
			ELSELAB_GENLAB();	!CREATE LABEL TABLE ENTRY FOR LABEL
						! TO GO TO IF CONDITION IS FALSE
			CGCBOOL(.SUBSTATMNT[GOTOLBL],.ELSELAB);
			DEFLAB(.ELSELAB);
		END


		ELSE
		%(***IF CONDITION IS NOT A RELATIONAL OR BOOLEAN, EVALUATE THE CONDEXPR AND
			TEST WHETHER IS IS TRUE (SIGN BIT EQUAL 1) OR FALSE(SIGN=0) ***)%
		BEGIN
			CGETVAL();

			%(***TEST VAL OF CONDEXPR,
				IF "A1NOTFLG" IS SET, TRANSFER TO GOTO-LABEL IF ARG IS
				FALSE, OTHERWISE TRANSFER TO GOTOLABEL IF ARG IS TRUE***)%
			OPDSPIX_CNDVTRIX(CONDEXPR,(IF .CSTMNT[A1NOTFLG] THEN FALSE ELSE TRUE));
			A1LABEL_.SUBSTATMNT[GOTOLBL];
			TREEPTR_.CONDEXPR;
			REGFORCOMP_GETTAC(TREEPTR);
			CGOPGEN();
		END;

	END


	%(****WHEN STATEMENT TO BE EXECUTED ON TRUE CONDITION IS NOT A GOTO***)%
	ELSE
	BEGIN
		ELSELAB_GENLAB();		!CREATE LABEL TABLE ENTRY FOR LABEL
						! TO GO TO WHEN CONDITION IS FALSE

		%(***IF CONDITION TO BE TESTED IS A RELATIONAL***)%
		IF .CONDEXPR[OPRCLS] EQL RELATIONAL
		THEN
		BEGIN
			CGREL1(TRUE);		!SKIP NEXT INSTR IF REL IS TRUE
			%(***GENERTAE CODE TO GO TO THE LABEL ON THE CODE FOLLOWING THAT
				FOR THE SUBSTATMNT OF THE IF STMNT***)%
			JRSTGEN(.ELSELAB);
		END

		%(***IF THE CONDITION TO BE TESTED IS A BOOLEAN*****)%
		ELSE
		IF .CONDEXPR[OPRCLS] EQL BOOLEAN
		THEN
		BEGIN
			THENLAB_GENLAB();	!CREATE LABEL TABLE ENTRY FOR LABEL TO
						! GO TO WHEN CONDITION IS TRUE
			CGCBOOL(.THENLAB,.ELSELAB);
			DEFLAB(.THENLAB);	!ASSOCIATE THIS LOC WITH THENLAB
		END

		%(***IF CONDITIONAL EXPRESSION IS NOT A REL OR BOOLEAN, EVALUATE IT AND
			TEST WHETHER ITS VAL IS TRUE (SIGN=1) OR FALSE (SIGN=0)***)%
		ELSE
		BEGIN
			CGETVAL();

			%(***TEST VAL OF CONDEXPR,
				IF "A1NOTFLG" IS SET, TRANSFER TO ELSELAB IF VAL IS TRUE
				OTHERWISE TRANSFER TO ELSELAB IF VAL IS FALSE***)%
			OPDSPIX_CNDVTRIX(CONDEXPR,(IF .CSTMNT[A1NOTFLG] THEN TRUE ELSE FALSE));
			A1LABEL_.ELSELAB;
			TREEPTR_.CONDEXPR;
			REGFORCOMP_GETTAC(TREEPTR);
			CGOPGEN();
		END;

		%(****GENERATE CODE FOR THE STATEMENT TO BE EXECUTED WHEN THE CONDITION IS TRUE***)%
		TOPSTMNT_.CSTMNT;	!SAVE A PTR TO THIS "TOP-LEVEL" STMNT 
		SAVSTMNT_.CSTMNT;
		CSTMNT_.SUBSTATMNT;
		CGSTMNT();
		CSTMNT_.SAVSTMNT;		!RESTORE THE GLOBAL CSTMNT

		%(***ASSOCIATE THIS LOC WITH THE LABEL TRANSFERED TO WHEN THE CONDITION
			IS FALSE****)%
		DEFLAB(.ELSELAB);

	END;

END;


GLOBAL ROUTINE CGEND=
%(*********************************************************
	TO GENERATE CODE FOR AN END STATEMENT
**********************************************************)%
BEGIN
	EXTERNAL CGEPILOGUE;
%[607]%	EXTERNAL NEDZER;	! FLAG TO INDICATE IF ZERO-ARG-BLOCK NEEDED
	EXTERNAL ZERBLK;
	!AN END TRIGGERS A CALL TO EXIT ONLY IN A MAIN
	!PROGRAM, NOT FOR A SUBPROGRAM
	!IN A SUBPROGRAM THE END TRIGGERS A RETURN.

	IF .FLGREG<PROGTYP> EQL MAPROG
	THEN
	BEGIN
%[607]%		NEDZER _ 1;		! FLAG ZERO-ARG-BLOCK NEEDED
		A1LABEL_.ZERBLK;	!ARGLIST FOR CALL TO EXIT IS ALWAYS
					! 0 FOR THE END STMNT
		OPDSPIX_OPGEXI;
		CGOPGEN();
	END
	ELSE
	!ALSO CHECK FOR A BLOCK DATA SUBPROGRAM
	IF .FLGREG<PROGTYP> NEQ BKPROG 
	THEN
	BEGIN
		!IF THERE ARE MULTIPLE ENTRIES OR LABELS AS ARGS
		IF .FLGREG<MULTENT> OR .FLGREG<LABLDUM>
						! HAS MULTIPLE ENTRIES
		THEN CGRETURN(0);		! GENERATE CODE TO "RETURN"

		!FOR A SINGLE ENTRY SUBPROGRAM GENERATE THE
		!EPILOGUE

		IF NOT .FLGREG<MULTENT>
		THEN
		BEGIN
			REGISTER BASE TSTMNT;
			TSTMNT_.SORCPTR<LEFT>;	!PTR TO 1ST STMNT IN PROG
			WHILE .TSTMNT[SRCID] NEQ ENTRID
			DO
			BEGIN
				TSTMNT_.TSTMNT[CLINK];	!(SKIP  DUMMY CONTINUES)
				IF .TSTMNT EQL 0 THEN CGERR()	!IF NEVER FIND THE ENTRY
			END;
			CGEPILOGUE(.TSTMNT);	!GENERATE THE EPILOGUE CORRESPONDING TO THIS ENTRY
		END;

	END
END;
GLOBAL ROUTINE CGSTOP=
%(***************************************************************************
	TO GENERATE CODE FOR A STOP STMNT
***************************************************************************)%
BEGIN
%[607]%	EXTERNAL NEDZER;	! FLAG TO INDICATE IF ZERO-ARG-BLOCK NEEDED
	EXTERNAL ZERBLK;
	%(***USE THE ZERO-ARG-BLOCK AS THE ARG BLOCK FOR THIS CALL TO FOROTS***)%
	A1LABEL_(IF .CSTMNT[STOPIDENT] EQL 0	!IF DO NOT HAVE A CNST
						! TO PRINT OUT, THEN ARGLIST
						! FOR EXIT WILL BE 0
%[607]%			THEN (NEDZER _ 1; .ZERBLK)	! FLAG ZERO-ARG-BLOCK NEEDED
			ELSE GENLAB() );	!IF HAVE AN ARG TO
						! PASS TO EXIT, ASSOCIATE A LABEL
						! WITH THE ARGLIST TO BE GENERATED
	CSTMNT[STOPLBL]_.A1LABEL;	!SAVE LABEL TO BE USED

	OPDSPIX_OPGSTP;
	CGOPGEN();
END;


GLOBAL ROUTINE CGPAUSE=
%(***************************************************************************
	ROUTINE TO GENERATE CODE FOR PAUSE
***************************************************************************)%
BEGIN
%[607]%	EXTERNAL NEDZER;	! FLAG TO INDICATE IF ZERO-ARG-BLOCK NEEDED
	EXTERNAL ZERBLK;

	A1LABEL_(IF .CSTMNT[PAUSIDENT] EQL 0	!IF DO NOT HAVE A CNST
						! TO PRINT OUT, THEN ARGLIST
						! FOR FOROTS "PAUSE" ROUTINE WILL BE 0
%[607]%			THEN (NEDZER _ 1; .ZERBLK)	! FLAG ZERO-ARG-BLOCK NEEDED
			ELSE GENLAB() );	!IF HAVE AN ARG TO
						! PASS TO FOROTS, ASSOCIATE A LABEL
						! WITH THE ARGLIST TO BE GENERATED
	CSTMNT[PAUSLBL]_.A1LABEL;


	OPDSPIX_OPGPAU;
	CGOPGEN();
END;
	

GLOBAL ROUTINE CGARIF=
%(***************************************************************************
	ROUTINE TO GENERATE CODE FOR AN ARITHMETIC IF STATEMENT.
	CALLED WITH THE GLOBAL CSTMNT POINTING TO THE STATEMENT
	FOR WHICH CODE IS TO BE GENERATED.
***************************************************************************)%
BEGIN
	EXTERNAL A1LABEL,A2LABEL,A3LABEL;	!GLOBALS USED BY THE CODE-GENERATION
	EXTERNAL REGFORCOMP,A1NODE,A2NODE;	! TABLE DRIVER
	EXTERNAL TREEPTR;

	MAP PEXPRNODE A1NODE:A2NODE:TREEPTR;

	OWN BASE NXTSTMNT;
	OWN PEXPRNODE CONDEXPR;		!THE ARITHMETIC EXPRESSION UNDER THIS STMNT

	%(***COMPUTE ANY COMMON SUBEXPRESSIONS UNDER THIS NODE***)%
	IF .CSTMNT[SRCCOMNSUB] NEQ 0 THEN CGCMNSUB();


	%(***DETERMINE WHICH (IF ANY) OF THE 3 LABELS ASSOCIATED WITH
		THIS NODE ARE EQUAL TO THE LABEL ON THE FOLLOWING STMNT***)%
	NXTSTMNT_.CSTMNT[SRCLINK];
	CSTMNT[AIFLBNXT]_
	BEGIN
		IF .CSTMNT[AIFLESS] EQL .NXTSTMNT[SRCLBL]
		THEN LLBNXT
		ELSE
		IF .CSTMNT[AIFEQL] EQL .NXTSTMNT[SRCLBL]
		THEN ELBNXT
		ELSE
		IF .CSTMNT[AIFGTR] EQL .NXTSTMNT[SRCLBL]
		THEN GLBNXT
		ELSE NOLBNXT
	END;


	%(***GET PTR TO THE CONDITIONAL EXPRESSION***)%
	CONDEXPR_.CSTMNT[AIFEXPR];
	TREEPTR_.CONDEXPR;
	%(***COMPUTE THE VAL OF THE ARITH EXPR, THEN TEST IT****)%

	%(***COMPUTE THE VAL OF THE ARITH EXPR***)%
	IF NOT .CSTMNT[A1VALFLG]
	THEN CGETVAL();

	%(***IF THERE IS A NEG ON THE VALUE, EXCHANGE THE GTR AND LESS LABELS***)%
	IF .CSTMNT[A1NEGFLG]
	THEN
	BEGIN
		A1LABEL_.CSTMNT[AIFGTR];
		A3LABEL_.CSTMNT[AIFLESS];
		A2LABEL_.CSTMNT[AIFEQL];

		%(***MODIFY THE "AIFLBNXT" FIELD WHICH INDICATED WHICH OF
			THE 3 LABELS IS ON THE NEXT STMNT (CHANGE "GTR LABEL NEXT"
			TO "LESS LABEL NEXT", "LESS LABEL NEXT" TO
			"GTR LABEL NXT" LEAVE OTHERS UNCHANGED
			MODIFY THE "AIFLBEQV" FIELD SO THAT "GTR LABEL SAME
			AS EQL LABEL" BECOMES "LESS LABEL SAME AS EQL LABEL"
			AND VICE-VERSA
		****)%
		SWPAIFFLGS(CSTMNT);
	END
	ELSE
	BEGIN
		A1LABEL_.CSTMNT[AIFLESS];
		A3LABEL_.CSTMNT[AIFGTR];
		A2LABEL_.CSTMNT[AIFEQL];
	END;

	%(***USE THE TABLE-DRIVER TO GENERATE CODE TO TEST THE VAL AND TRANSFER***)%
	REGFORCOMP_GETAIFREG(CSTMNT);
	OPDSPIX_AIFIX(CSTMNT,CONDEXPR);
	A1NODE_.CONDEXPR;
	CGOPGEN();
END;

GLOBAL ROUTINE CGCMNSUB=
%(***************************************************************************
	GENERATE CODE TO EVLUATE ANY COMMON SUBEXPRESSIONS THAT OCCUR UNDER
	THE STATEMENT NODE POINTED TO BY "CSTMNT"
***************************************************************************)%
BEGIN
	OWN PEXPRNODE CCMNSUB;

	%(***COMPUTE THE VALUES OF ANY COMMON SUBEXPRS ASSOCIATED WITH THIS STATEMENT***)%
	CCMNSUB_.CSTMNT[SRCCOMNSUB];
	UNTIL .CCMNSUB EQL 0
	DO
	BEGIN
		IF NOT .CCMNSUB[A2VALFLG]
		THEN
		BEGIN
			TREEPTR_.CCMNSUB[ARG2PTR];
			CGETVAL();
		END;

		%(***IF THE COMMON SUBEXPR IS TO BE LEFT IN A DIFFERENT PLACE THAN
			THAT INTO WHICH IT WAS COMPUTED, PUT IT THERE.
			NOT THAT THIS CAN ONLY OCCUR WHEN THE PLACE IN WHICH
			IT IS TO BE LEFT IS A REGISTER.
		*******)%
		IF NOT .CCMNSUB[A2SAMEFLG]
		THEN
		BEGIN
			A1NODE_.CCMNSUB[ARG2PTR];
			OPDSPIX_GETA2OPIX(CCMNSUB,A1NODE);
			REGFORCOMP_GETTAC(CCMNSUB);
			CGOPGEN();
		END;


		%(***IF THE VAL OF THIS COMMON SUB MUST BE STORED INTO A TMP, GENERATE
			CODE TO DO SO***)%
		IF .CCMNSUB[STOREFLG]
		THEN
		BEGIN
			TREEPTR_.CCMNSUB;
			REGFORCOMP_GETTAC(CCMNSUB);
			OPDSPIX_STOROPIX(CCMNSUB);
			CGOPGEN();
		END;


		CCMNSUB_.CCMNSUB[CLINK];
	END;

END;



GLOBAL ROUTINE CGIOLST=
%(***************************************************************************
	ROUTINE TO PERFORM CODE GENERATION FOR AN IOLIST.
	CALLED WITH THE GLOBAL CSTMNT POINTING TO THE STATEMENT FOR WHICH AN
	IOLIST IS TO BE PROCESSED.
	FOR EACH ELEMENT IN THE IOLIST:
		1. IF THE ELEMENT IS A "STATEMENT" (EITHER A DO, OR A CONTINUE
			WHICH TERMINATES A DO-LOOP, OR AN ASSIGNMENT),  PERFORM
			USUAL CODE GENERATION FOR THAT TYPE OF STATEMENT
		2. IF THE ELEMENT IS AN "IOLSCLS" NODE (IE A DATACALL, SLISTCALL,
			IOLSTCALL,E1LISTCALL,OR E2LISTCALL), PERFORM CODE
			GENERATION FOR ALL ELEMENTS UNDER THE NODE AND
			ALSO GENERATE:
				MOVEI	16,ARGBLKP
				PUSHJ	17,IOLST.
			WHERE ARGBLKP IS A PTR TO THE ARGBLOCK FOR THIS ELEMENT
***************************************************************************)%
BEGIN
	LOCAL SAVSTMNT;
	LOCAL BASE IOLELEM;
	EXTERNAL GENLAB;
	EXTERNAL OPDSPIX,A1LABEL,CGOPGEN,OPGFIN;

	%(***GET PTR TO 1ST ELEMENT ON THE IOLIST TO BE PROCESSED***)%
	IOLELEM_.CSTMNT[IOLIST];

	%(***SAVE PTR TO CURRENT STATEMENT (IF THERE ARE DO-STMNTS IN THE IOLIST,
		WILL CLOBBER CSTMNT) *****)%
	SAVSTMNT_.CSTMNT;

	%(***WALK THUR THE IOLIST, PROCESSING ALL ELEMENTS***)%
	UNTIL .IOLELEM EQL 0
	DO
	BEGIN
		IF .IOLELEM[OPRCLS] EQL STATEMENT
		THEN
		BEGIN
			CSTMNT_.IOLELEM;
			CGSTMNT();

			%(***IF THE LAST ELEMENT IN AN IO-LIST FOR  A GIVEN STMNT IS
				NOT OF IOLSCLS (IE DOES NOT GENERATE AN ARG-LIST)
				THEN MUST GENERATE A "PUSHJ 17,FIN."
			********)%
			IF .IOLELEM[CLINK] EQL 0
			THEN
			BEGIN
				OPDSPIX_OPGFIN;
				CGOPGEN();
			END;
		END

		ELSE
		IF .IOLELEM[OPRCLS] EQL IOLSCLS
		THEN
		BEGIN
			%(***GENERATE CODE TO EVALUATE ALL EXPRESSIONS UNDER THIS ELEMENT***)%
			CASE .IOLELEM[OPERSP] OF SET

			%(***FOR A DATACALL NODE - EVAL THE EXPR UNDER THE NODE ***)%
			BEGIN
				TREEPTR_.IOLELEM[DCALLELEM];
				IF .TREEPTR[OPRCLS] NEQ DATAOPR
				THEN
				CGETVAL();
			END;

			%(***FOR AN SLISTCALL NODE - EVAL THE EXPR FOR THE NUMBER OF ELEMS***)%
			BEGIN
				TREEPTR_.IOLELEM[SCALLCT];
				IF .TREEPTR[OPRCLS] NEQ DATAOPR
				THEN
				CGETVAL();
			END;

			%(***FOR AN IOLSTCALL NODE - EVAL ALL EXPRS UNDER IT****)%
			CGIOCALL(.IOLELEM);

			%(***FOR AN E1LISTCALL NODE - OPTIMIZED CODE ONLY***)%
			BEGIN
				LOCAL BASE SAVCSTMNT;
				SAVCSTMNT_.CSTMNT;
				CSTMNT_.IOLELEM;
				CGCMNSUB();
				CSTMNT_.SAVCSTMNT;
				CGE1LIST(.IOLELEM)
			END;

			%(**FOR AN E2LISTCALL NODE - OPTIMIZED CODE ONLY***)%
			BEGIN
				LOCAL BASE SAVCSTMNT;
				SAVCSTMNT_.CSTMNT;
				CSTMNT_.IOLELEM;
				CGCMNSUB();
				CSTMNT_.SAVCSTMNT;
				CGE2LIST(.IOLELEM)
			END

			TES;


			%(***CREATE A LABEL TABLE ENTRY FOR THE LABEL ASSOCIATED WITH
				THE ARGBLOCK FOR THIS NODE***)%
			A1LABEL_GENLAB();
			IOLELEM[IOLSTLBL]_.A1LABEL;

			%(***GENERATE CALL TO IOLST.***)%
			OPDSPIX_OPGIOL;
			CGOPGEN();
		END
		ELSE CGERR();

		%(***GO ON TO NEXT ELEMENT***)%
		IOLELEM_.IOLELEM[CLINK];
	END;

	CSTMNT_.SAVSTMNT;
END;



GLOBAL ROUTINE CGE1LIST(IOLELEM)=
%(**********************************************************************
	ROUTINE TO GENERTE IN LINE CODE FOR
	AN E1LISTCALL NODE
**********************************************************************)%
BEGIN
	MAP BASE IOLELEM;
	LOCAL BASE IOARRAY;
	TREEPTR_.IOLELEM[ECNTPTR];
	IF .TREEPTR[OPRCLS] NEQ DATAOPR
	 THEN CGETVAL();
	TREEPTR_.IOLELEM[E1INCR];
	IF .TREEPTR[OPRCLS] NEQ DATAOPR
	 THEN CGETVAL();
	IOARRAY_.IOLELEM[ELSTPTR];
	WHILE .IOARRAY NEQ 0 DO
	BEGIN
		TREEPTR_.IOARRAY[E2ARREFPTR];
		IF .TREEPTR[OPRCLS] NEQ DATAOPR
		 THEN CGETVAL();
		IOARRAY_.IOARRAY[CLINK]
	END
END;






GLOBAL ROUTINE CGE2LIST(IOLELEM)=
%(**********************************************************************
	ROUTINE TO GENERATE INLINE CODE FOR
	AN E2LISTCALL NODE
**********************************************************************)%
BEGIN
	MAP BASE IOLELEM;
	LOCAL BASE IOARRAY;
	TREEPTR_.IOLELEM[ECNTPTR];
	IF .TREEPTR[OPRCLS] NEQ DATAOPR
	 THEN CGETVAL();
	IOARRAY_.IOLELEM[ELSTPTR];
	WHILE .IOARRAY NEQ 0 DO
	BEGIN
		TREEPTR_.IOARRAY[E2INCR];
		IF .TREEPTR[OPRCLS] NEQ DATAOPR
		 THEN CGETVAL();
		IOARRAY_.IOARRAY[CLINK]
	END;
	IOARRAY_.IOLELEM[ELSTPTR];
	WHILE .IOARRAY NEQ 0 DO
	BEGIN
		TREEPTR_.IOARRAY[E2ARREFPTR];
		IF .TREEPTR[OPRCLS] NEQ DATAOPR
		 THEN CGETVAL();
		IOARRAY_.IOARRAY[CLINK]
	END
END;




GLOBAL ROUTINE CGIOCALL(IOLSNODE)=
%(***************************************************************************
	ROUTINE TO GENERATE THE CODE FOR AN IOLSTCALL NODE.
	GENERATES CODE TO EVALUATE ALL EXPRESSIONS UNDER THE
	IOLSTCALL.
***************************************************************************)%
BEGIN
	MAP BASE IOLSNODE;
	OWN BASE IOLELEM;
	OWN SAVSTMNT;

	%(***SAVE THE GLOBAL CSTMNT***)%
	SAVSTMNT_.CSTMNT;

	%(***GENERATE CODE FOR ANY COMMON SUBEXPRS UNDER THIS NODE***)%
	CSTMNT_.IOLSNODE;
	CGCMNSUB();

	%(***WALK THRU THE ELEMS UNDER THIS IOLSTCALL***)%
	IOLELEM_.IOLSNODE[IOLSTPTR];
	UNTIL .IOLELEM EQL 0
	DO
	BEGIN
		CASE .IOLELEM[OPERSP] OF SET

		%(***FOR A DATACALL****)%
		BEGIN
			TREEPTR_.IOLELEM[DCALLELEM];
			IF .TREEPTR[OPRCLS] NEQ DATAOPR
			THEN CGETVAL();
		END;

		%(***FOR AN SLISTCALL (AN SLIST THAT HAS ONLY ONE ARRAYREF, AND
			THAT ARRAYREF STARTS AT THE BASE OF THE ARRAY, AND THE
			INCREMENT IS A CONSTANT) ***)%
		BEGIN
			TREEPTR_.IOLELEM[SCALLCT];
			IF .TREEPTR[OPRCLS] NEQ DATAOPR
			THEN CGETVAL();
		END;

		%(***AN IOLSTCALL NODE UNDER ANOTHER IOLSTCALL NODE IS ILLEGAL***)%
		CGERR();

		%(***FOR AN E1LISTCALL - OPTIMIZED CODE ONLY***)%
		BEGIN
		CGE1LIST(.IOLELEM)
		END;

		%(***FOR AN E2LISTCALL - OPTIMIZED CODE ONLY***)%
		BEGIN
		CGE2LIST(.IOLELEM)
		END

		TES;

		IOLELEM_.IOLELEM[CLINK];
	END;

	%(***RESTORE CSTMNT***)%
	CSTMNT_.SAVSTMNT;
END;


MAP PEXPRNODE TREEPTR;





%(*********DEFINE MACRO TO OUTPUT A WD OF 0 IN AN ARG-BLOCK***)%
MACRO	ZIPOUT=
BEGIN
	EXTERNAL PBOPWD,PSYMPTR,OBUFFA;
	PBOPWD_0;
	PSYMPTR_PBF2NOSYM;
	OBUFFA()
END$;




GLOBAL ROUTINE CGIOLARGS=
%(***************************************************************************
	ROUTINE TO GENERATE THE ARG BLOCKS FOR AN IOLIST.
	CALLED WITH THE GLOBAL TREEPTR POINTING TO THE IOLIST.
***************************************************************************)%
BEGIN
	MAP OBJECTCODE PBOPWD;
	MAP PEXPRNODE PSYMPTR;
	OWN SAVTREEPTR;

	%(***WALK THRU ALL THE ELEMENTS ON THE IOLIST***)%
	UNTIL .TREEPTR EQL 0
	DO
	BEGIN
		%(**ONLY GENERATE ARG BLOCKS FOR NODES OF OPRCLS "IOLSCLS" (IGNORE
			STATEMENT NODES) ***)%
		IF .TREEPTR[OPRCLS] EQL IOLSCLS
		THEN
		BEGIN
			%(***OUTPUT A WORD OF 0 IN FRONT OF THE ARG-LIST
				SO THAT THE TRACE ROUTINE WONT PICK UP GARBAGE AS
				AN ARG-COUNT***)%
			ZIPOUT;
			%(***ASSOCIATE CURRENT LOC WITH THE LABEL ON THIS ARGBLOCK***)%
			DEFLAB(.TREEPTR[IOLSTLBL]);


			%(********GENERATE THE ARG BLOCK************************)%
			CASE .TREEPTR[OPERSP] OF SET

			%(***FOR DATACALL***)%
			CGDCALL();

			%(***FOR SLISTCALL***)%
			CGSLIST();

			%(***FOR IOLSTCALL***)%
			BEGIN
				%(***SAVE VAL OF TREEPTR***)%
				SAVTREEPTR_.TREEPTR;

				%(***WALK THRU THE ELEMENTS UNDER THIS NODE, GENERATING
					ARG BLOCKS FOR THEM***)%
				TREEPTR_.TREEPTR[IOLSTPTR];
				UNTIL .TREEPTR EQL 0
				DO
				BEGIN
					CASE .TREEPTR[OPERSP] OF SET
					CGDCALL();	!FOR A DATACALL
					CGSLIST();	!FOR AN SLIST
					CGERR();	!IOLSTCALL IS ILLEGAL UNDER
							! ANOTHER IOLSTCALL
					CAE1LIST();	!E1LISTCALL NODE
					CAE2LIST()	!E2LISTCALL NODE
					TES;

					TREEPTR_.TREEPTR[CLINK];
				END;

				%(***RESTORE TREEPTR***)%
				TREEPTR_.SAVTREEPTR;
			END;

			%(***FOR AN E1LISTCALL - OPTIMIZED CODE ONLY***)%
			CAE1LIST();

			%(***FOR AN E2LISTCALL - OPTIMIZED CODE ONLY***)%
			CAE2LIST()

			TES;


			%(***IF THIS IS THE LAST ARG-BLOCK FOR THIS STMNT, GENERATE A FIN-BLOCK
				AFTER IT; OTHERWISE GENERATE A ZERO-BLOCK AFTER IT***)%
			PBOPWD_(IF .TREEPTR[CLINK] EQL 0 THEN OTSFINWD ELSE OTSZERWD);
			PSYMPTR_PBF2NOSYM;
			OBUFFA();
		END;

		%(***GO ON TO NEXT ELEMENT***)%
		TREEPTR_.TREEPTR[CLINK];
	END;
END;



GLOBAL ROUTINE CGDCALL=
%(***************************************************************************
	ROUTINE TO GENERATE AN ARG BLOCK FOR A DATACALL ELEMENT IN AN IOLIST
	CALLED WITH THE GLOBAL TREEPTR POINTING TO THE DATACALL NODE FOR
	WHICH THE BLOCK IS TO BE GENERATED.
***************************************************************************)%
BEGIN
	MAP OBJECTCODE PBOPWD;
	MAP PEXPRNODE PSYMPTR;
	OWN PEXPRNODE ARGNODE;
	EXTERNAL EVALU;

	%(***GET PTR TO THE EXPRESSION-NODE WHOSE VAL IS TO BE AN ARG***)%
	ARGNODE_.TREEPTR[DCALLELEM];


	%(***INIT OUTPUT WD TO 0****)%
	PBOPWD_0;

	%(***SET ID FIELD OF OUTPUT WD TO INDICATE DATA***)%
	PBOPWD[OTSIDN]_OTSDATA;

	%(***SET TYPE FIELD OF ARG BLOCK TO THE EXTERNAL-TYPE CODE CORRESPONDING
		TO THE VALTYPE INDICATED IN ARGNODE***)%
	PBOPWD[OTSTYPE]_.EVALU[.ARGNODE[VALTYPE]];

	%(***IF THE EXPRESSION IS A SCALER VARIABLE***)%
	IF .ARGNODE[OPRCLS] EQL DATAOPR
	THEN
	BEGIN
		PBOPWD[OTSADDR]_.ARGNODE[IDADDR];
		IF .ARGNODE[OPERSP] EQL FORMLARRAY THEN
			PBOPWD[OTSIND]_1;	!SET INDIRECT OVER FORMAL ARRAY
		PSYMPTR_.ARGNODE;		!PTR TO SYMBOL TABLE ENTRY
	END

	ELSE
	%(***IF THE EXPRESSION IS AN ARRAYREF****)%
	IF .ARGNODE[OPRCLS] EQL ARRAYREF
	THEN
	BEGIN
		PBOPWD[OTSMEMRF]_.ARGNODE[TARGTMEM];
		PSYMPTR_.ARGNODE[ARG1PTR];

		%(***FOR A FORMAL ARRAY, WILL NOT WANT TO RELOCATE THE ADDRESS
			FIELD OF THE ARGUMENT - SINCE WILL HAVE COMPUTED THE ARRAY BASE
			ADDRESS INTO THE SUBSCRIPT***)%
		IF .PSYMPTR[FORMLFLG] THEN PSYMPTR_PBF2NOSYM;
	END

	ELSE
	%(***IF THE VAL OF THE EXPRESSION IS IN A REG***)%
	IF .ARGNODE[INREGFLG]
	THEN
	BEGIN
		PBOPWD[OTSADDR]_.ARGNODE[TARGADDR];
		PSYMPTR_PBF2NOSYM;
	END

	ELSE
	%(***IF THE VAL OF THE EXPRESSION IS IN A TEMP***)%
	BEGIN
		PSYMPTR_.ARGNODE[TARGADDR];
		PBOPWD[OTSADDR]_.PSYMPTR[IDADDR];
		PBOPWD[OTSIND]_.ARGNODE[TARGIF];
	END;

	OBUFFA();
END;





GLOBAL ROUTINE CGSLIST=
%(***************************************************************************
	ROUTINE TO GENERATE AN ARGUMENT BLOCK FOR AN SLIST CALL
	IN AN IOLIST.
	CALLED WITH THE GLOBAL POINTING TO THE SLISTCALL NODE.
	THIS ROUTINE IS USED ONLY FOR THE SLISTS GENERATED BY
	PHASE 1 FOR STMNTS OF THE FORM:
		READ 11,A
	WHERE A IS AN ARRAY. 
	IN A LATER RELEASE, PHASE 2 SKELETON WILL RECOGNIZE 
	IOLISTS THAT CAN BE TRANSFORMED INTO SLISTS AND WILL FORM
	"S1LISTCALL" NODES FOR THESE SLISTS (WHICH MAY HAVE MORE THAN ONE ARRAY
	AND INCREMENTS OTHER THAN 1).
***************************************************************************)%
BEGIN
	MAP OBJECTCODE PBOPWD;
	MAP PEXPRNODE PSYMPTR;
	EXTERNAL EVALU;

	%(******OUTPUT FIRST WD OF ARGBLOCK (WD CONTAINING CODE FOR SLSIST AND COUNT)*****)%

	%(***INIT OUTPUT WD TO 0***)%
	PBOPWD_0;

	%(***SET IDN FIELD TO CODE FOR SLSIST**)%
	PBOPWD[OTSIDN]_OTSSLIST;

	%(***BUILD THE WD THAT CONTAINS THE CT***)%
	BLDIOIMWD(.TREEPTR[SCALLCT]);

	OBUFFA();

	%(****OUTPUT THE 2ND WD  OF ARGBLOCK (WHICH CONTAINS THE INCREMENT 1)***)%
	PBOPWD_1;
	PSYMPTR_PBF2NOSYM;
	OBUFFA();

	%(***OUTPUT THE 3RD WD (WHICH CONTAINS A PTR TO THE ARRAY TO BE USED)*******)%

	%(***GET PTR TO SYMBOL TABLE ENTRY FOR THE ARRAY***)%
	PSYMPTR_.TREEPTR[SCALLELEM];

	%(***ADDRESS FOR ARGBLOCK IS ADDRESS INDICATED BY THE SYMBOL TABLE ENTRY***)%
	PBOPWD[OTSADDR]_.PSYMPTR[IDADDR];
	PBOPWD[OTSTYPE]_.EVALU[.PSYMPTR[VALTYPE]];

	%(***SET INDIRECT BIT FOR A FORMAL ARRAY***)%
	IF .PSYMPTR[FORMLFLG]
	THEN
	PBOPWD[OTSIND]_1;

	OBUFFA();


END;



GLOBAL ROUTINE CAE1LIST=
%(**********************************************************************
	ROUTINE TO GENERATE CODE FOR AN ARGBLK FOR AN E1LISTCALL NODE
	CALLED WITH GLOBAL POINTING TO E1LISTCALL NODE
**********************************************************************)%
BEGIN
	LOCAL PEXPRNODE IOARRAY;
	MAP OBJECTCODE PBOPWD;
	MAP PEXPRNODE PSYMPTR;

	%(***OUTPUT FIRST WORD - CONTAINS "SLIST" AND COUNT***)%

	PBOPWD_0;			!INITIALIZE WORD TO 0
	PBOPWD[OTSIDN]_OTSSLIST;	!SET ID FIELD TO SLIST
	BLDIOIMWD(.TREEPTR[ECNTPTR]);	!FILL IN THE COUNT
	OBUFFA();			!OUTPUT THE WORD

	%(***OUTPUT SECOND WORD - CONTAINS INCREMENT***)%
	IOARRAY_.TREEPTR[E1INCR];
	IF
	BEGIN
		IF .IOARRAY[OPR1] NEQ CONSTFL THEN 0 ELSE
		IF .IOARRAY[CONST1] EQL 0 AND .IOARRAY[CONST2] EQL 0
		THEN 1 ELSE 0
	END
	THEN
	BEGIN
		PSYMPTR_.IOARRAY;	!MARK SYMBOL
		PBOPWD<LEFT>_#100;	!SET INTEGER
		PBOPWD<RIGHT>_.IOARRAY[IDADDR]
	END
	ELSE
	BEGIN
		PBOPWD_0;
		BLDIOIMWD(.TREEPTR[E1INCR])	!FILL IN THE INCREMENT
	END;
	OBUFFA();			!OUTPUT THE WORD

	%(***OUTPUT ONE WORD FOR EACH ARRAYREF UNDER ELSTPTR***)%

	IOARRAY_.TREEPTR[ELSTPTR];
	WHILE .IOARRAY NEQ 0 DO
	BEGIN
		PBOPWD_0;			!CLEAR TARGET
		IOPTR(.IOARRAY[E2ARREFPTR]);	!GENERATE ARGUMENT
		IOARRAY_.IOARRAY[CLINK]
	END

END;





GLOBAL ROUTINE CAE2LIST=
%(**********************************************************************
	ROUTINE TO GENERATE CODE FOR AN ARGBLK FOR AN E2LISTCALL NODE
	CALLED WITH GLOBAL POINTING TO E2LISTCALL NODE
**********************************************************************)%
BEGIN
	LOCAL PEXPRNODE IOARRAY;
	MAP OBJECTCODE PBOPWD;
	MAP PEXPRNODE PSYMPTR;

	%(***OUTPUT FIRST WORD - CONTAINS "ELIST" AND COUNT***)%

	PBOPWD_0;			!INITIALIZE WORD TO 0
	PBOPWD[OTSIDN]_OTSELIST;	!SET ID FIELD TO ELIST
	BLDIOIMWD(.TREEPTR[ECNTPTR]);	!FILL IN THE COUNT
	OBUFFA();			!OUTPUT THE WORD

	%(***OUTPUT TWO WORD FOR EACH ARRAYREF UNDER ELSTPTR***)%

	IOARRAY_.TREEPTR[ELSTPTR];
	WHILE .IOARRAY NEQ 0 DO
	BEGIN
		LOCAL PEXPRNODE E2ARG;

		%(***OUTPUT INCREMENT***)%

		E2ARG_.IOARRAY[E2INCR];
		IF
		BEGIN
			IF .E2ARG[OPR1] NEQ CONSTFL THEN 0 ELSE
			IF .E2ARG[CONST1] EQL 0 AND .E2ARG[CONST2] EQL 0
			THEN 1 ELSE 0
		END
		THEN
		BEGIN
			PSYMPTR_.E2ARG;
			PBOPWD<LEFT>_#100;
			PBOPWD<RIGHT>_.E2ARG[IDADDR]
		END
		ELSE
		BEGIN
			PBOPWD_0;
			BLDIOIMWD(.IOARRAY[E2INCR])	!FILL IN INCREMENT
		END;
		OBUFFA();			!OUTPUT INCREMENT

		%(***OUTPUT ARRAY ADDRESS***)%

		PBOPWD_0;			!CLEAR TARGET
		IOPTR(.IOARRAY[E2ARREFPTR]);	!GENERATE ARGUMENT
		IOARRAY_.IOARRAY[CLINK]
	END

END;






GLOBAL ROUTINE BLDIOIMWD(ARGNODE)=
%(***************************************************************************
	ROUTINE TO BUILD A WD OF AN ARGUMENT BLOCK FOR FOROTS WHEN
	THAT WORD IS TO HAVE EITHER THE FORM:
		1. INDIRECT BIT=0, IMMEDIATE CONSTANT IN RIGHT HALF
	  OR	2. INDIRECT BIT=1, PTR TO VAL IN RIGHT HALF
	CALLED WITH THE ARG:
		ARGNODE - PTR TO THE EXPRESSION NODE FOR THE VAL TO
				BE REPRESENTED
	CALLED WITH PBOPWD INITIALIZED SUCH THAT THE FIRST 9 BITS HAVE
	THE VALUE DESIRED,AND THE RIGHT 27 BITS ARE 0.
***************************************************************************)%
BEGIN
	EXTERNAL EVALU;
	MAP OBJECTCODE PBOPWD;
	MAP PEXPRNODE PSYMPTR;
	MAP PEXPRNODE ARGNODE;

	%(***SET TYPE TO INDICATE IMMEDIATE ARG IN MEMORY***)%

	PBOPWD[OTSTYPE]_.EVALU[.ARGNODE[VALTYPE]];

	%(***IF THE ARG IS A CONSTANT, USE THE IMMEDIATE FORM***)%
	IF .ARGNODE[OPR1] EQL CONSTFL
	THEN
	BEGIN
		PBOPWD[OTSTYPE]_IMMEDTYPE;
		PBOPWD[OTSADDR]_.ARGNODE[CONST2];
		PSYMPTR_PBF2NOSYM;		!FLAG TO OUTMOD THAT NO SYMBOLIC
						! REPRESENTATION CAN BE USED
	END

	ELSE
	%(***IF ARG IS A VARIABLE, USE INDIRECT THRU ITS ADDR***)%
	IF .ARGNODE[OPRCLS] EQL DATAOPR
	THEN
	BEGIN
		IF .ARGNODE[OPERSP] EQL FORMLARRAY THEN PBOPWD[OTSIND]_1;
		PBOPWD[OTSADDR]_.ARGNODE[IDADDR];
		PSYMPTR_.ARGNODE;		!PTR TO SYMBOL TABLE ENTRY
	END

	ELSE
	%(***IF ARG IS AN EXPRESSION,  USE THE TEMP IN WHICH THE VAL WAS STORED***)%
	BEGIN
		%(***IF VAL WAS LEFT IN AREG***)%
		IF .ARGNODE[INREGFLG]
		THEN
		BEGIN
			PBOPWD[OTSADDR]_.ARGNODE[TARGADDR];
			PSYMPTR_PBF2NOSYM;
		END

		ELSE
		%(***IF VAL WAS LEFT IN A TEMP***)%
		BEGIN
			%(***GET PTR TO TEMPORARY TABLE ENTRY***)%
			PSYMPTR_.ARGNODE[TARGADDR];
			PBOPWD[OTSADDR]_.PSYMPTR[IDADDR];
		END;
	END;

END;




GLOBAL ROUTINE CGSTPAUARGS=
%(***************************************************************************
	ROUTINE TO GENERATE THE ARG BLOCK FOR A STOP/PAUSE STMNT.
	THIS BLOCK WILL HAVE THE FORM:
		-------------------------------
		!   ARGCT	!    0		!
		---------------------------------
	LABEL:	!     !TYPE !	!  ARGPTR	!
		----------------------------------
	WHERE "LABEL" IS THE ARG-BLOCK LABEL, ARGCT IS NEG ARGCT AND WILL ALWAYS
	BE -1 OR 0, TYPE IS THE VALUE TYPE OF THE ARG (LITERAL,OCTAL,INTEGER,REAL
	DOUBLE PREC, OR COMPLEX) AND IS IN BITS 9-12, AND ARGPTR PTS TO THE ARG

	THIS ROUTINE IS CALLED WITH THE GLOBAL "CSTMNT" POINTING TO THE STOP OR
	PAUSE STMNT FOR WHICH AN ARG-BLOCK IS TO BE GENERATED.
***************************************************************************)%
BEGIN
	EXTERNAL EVALU;			!TABLE OF EXTERNAL VALUE-TYPE CODES
	MAP OBJECTCODE PBOPWD;		!GLOBAL IN WHICH THE WD TO
					! BE OUTPUT IS PASSED TO THE ROUTINE "OBUFFA"

	MAP PEXPRNODE PSYMPTR;		!WILL PT TO THE SYMBOL TABLE ENTRY (OR
					! CONSTANT TABLE ENTRY) FOR THE ARG OF THE STOP/PAUSE


	%(***IF THE STOP/PAUSE HAD NO ARG, WILL HAVE USED "ZERBLK" FOR THE
		ARG-BLOCK. SO DONT HAVE TO GENERATE ANYTHING.***)%
	IF .CSTMNT[PAUSIDENT] EQL 0
	THEN RETURN;


	%(***IF THIS STMNT WAS ELIMINATED (BY FOLDING A LOG IF), DO NOT WANT TO
		GENERATE AN ARG LIST***)%
	IF .CSTMNT[PAUSLBL] EQL 0 THEN RETURN;


	%(***OUTPUT THE ARG-CT WD*****)%
	PSYMPTR_PBF2NOSYM;
	PBOPWD_(-1)^18;
	OBUFFA();

	%(***ASSOCIATE THE LABEL FOR THIS ARG-LIST WITH THE 2ND WD***)%
	DEFLAB(.CSTMNT[PAUSLBL]);

	%(***OUTPUT THE PTR WD***)%
	PSYMPTR_.CSTMNT[PAUSIDENT];
	PBOPWD_0;				!INIT WD TO BE OUTPUT TO 0
	PBOPWD[OTSTYPE]_.EVALU[.PSYMPTR[VALTYPE]];	!SET TYPE FIELD OF WD TO BE OUTPUT
	PBOPWD[OTSADDR]_.PSYMPTR[IDADDR];		!ADDRESS OF VAR/CONSTANT/LITERAL
							! TO BE OUTPUT
	OBUFFA();

	RETURN
END;

!AUTHOR: NORMA ABEL


!THIS FILE CONTAINS THE ROUTINES NECESSARY TO GENERATE CODE
!FOR THE I/O STATEMENTS THEMSELVES. WHERE APPROPRIATE THE ROUTINE
!CGIOLST IS CALLED TO GENERATE THE CALLS TO IOLST.

GLOBAL ROUTINE CGMTOP=
BEGIN
	!CALLS TO MTOP FOR ALL STATEMENTS BACKID THRU ENDFID

	EXTERNAL CSTMNT,GENLAB,A1LABEL,CGOPGEN,OPDSPIX;
	MAP BASE CSTMNT;

	EXTERNAL OPGMTO;

	CGUNIT();	!GENERATE CODE TO EVAL THE UNIT NUMBER (IF AN EXPRESSION)
	!FILL IN IOARGLBL FIELD
	A1LABEL_CSTMNT[IOARGLBL]_GENLAB();
	OPDSPIX_OPGMTO;
	CGOPGEN();
END;

GLOBAL ROUTINE CGENCO=
BEGIN
	!CODE GENERATION FOR ENCODE

	EXTERNAL CSTMNT,GENLAB,A1LABEL,CGOPGEN,OPDSPIX;
	MAP BASE CSTMNT;

	EXTERNAL CGIOLST,OPGENC;
	EXTERNAL TREEPTR,CGETVAL;

	%(***IF THE COUNT FIELD IS AN EXPRESSION, EVALUATE IT***)%
	TREEPTR_.CSTMNT[IOCNT];
	CGETVAL();

	%(***IF THE ENCODE VAR IS AN ARRAY-REF, GENERATE CODE FOR THE
		SS CALCULATION***)%
	TREEPTR_.CSTMNT[IOVAR];
	CGETVAL();

	!FILL IN IOARGLBL FIELD
	A1LABEL_CSTMNT[IOARGLBL]_GENLAB();
	OPDSPIX_OPGENC;
	CGOPGEN();
	CGIOLST();
END;

GLOBAL ROUTINE CGDECO=
BEGIN
	!CODE GENERATION FOR DECODE
	EXTERNAL CSTMNT,GENLAB,A1LABEL,CGOPGEN,OPDSPIX;
	MAP BASE CSTMNT;
	EXTERNAL OPGDEC,CGIOLST;

	%(***IF THE COUNT FIELD IS AN EXPRESSION, EVALUATE IT***)%
	TREEPTR_.CSTMNT[IOCNT];
	CGETVAL();


	%(***IF THE DECODE ARRAY IS AN ARRAYREF - CALCULATE THE
		OFFSET***)%
	TREEPTR_.CSTMNT[IOVAR];
	CGETVAL();

	!FILL IN IOARGLBL FIELD
	A1LABEL_CSTMNT[IOARGLBL]_GENLAB();
	OPDSPIX_OPGDEC;
	CGOPGEN();
	CGIOLST();
END;

GLOBAL ROUTINE CGRERE=
BEGIN
	!CODE GENERATION FOR REREAD

	EXTERNAL CSTMNT,GENLAB,A1LABEL,CGOPGEN,OPDSPIX;
	EXTERNAL OPGFIN;
	MAP BASE CSTMNT;
	EXTERNAL CGIOLST,OPGIN;
	CGUNIT();	!GENERATE CODE TO EVAL THE UNIT NUMBER (IF AN EXPRESSION)
	!FILL IN IOARGLBL FIELD
	A1LABEL_CSTMNT[IOARGLBL]_GENLAB();
	OPDSPIX_OPGIN;
	CGOPGEN();
	IF .CSTMNT[IOLIST]EQL 0
	THEN
	BEGIN
		%(***IF HAVE NO IOLIST GENERATE A CALL TO FIN***)%
		OPDSPIX_OPGFIN;
		CGOPGEN();
	END
	ELSE
	CGIOLST();
END;

GLOBAL ROUTINE CGUNIT=
%(***************************************************************************
	GENERATE CODE TO EVALUATE THE UNIT NUMBER  IN AN IO STMNT
	CALLED WITH CSTMNT POINTING TO AN IO STMNT
***************************************************************************)%
BEGIN
	TREEPTR_.CSTMNT[IOUNIT];	!PTR TO EXPRESSION NODE FOR UNIT
	IF .TREEPTR[OPRCLS] NEQ DATAOPR THEN CGETVAL()
END;



GLOBAL ROUTINE CGRECNUM=
%(***************************************************************************
	TO GENERATE THE CODE TO COMPUTE THE RECORD NUMBER FOR AN IO STMNT
	THAT HAS AN EXPRESSION FOR A RECORD NUMBER (UGH!!!)
***************************************************************************)%
BEGIN
	EXTERNAL CSTMNT;
	MAP PEXPRNODE CSTMNT;
	OWN PEXPRNODE RECNUM;

	IF (RECNUM_.CSTMNT[IORECORD]) NEQ 0
	THEN
	BEGIN
		IF .RECNUM[OPRCLS] NEQ DATAOPR
		THEN
		BEGIN
			TREEPTR_.RECNUM;
			CGETVAL()
		END
	END
END;

GLOBAL ROUTINE CGREAD=
BEGIN
	!CODE GENERATION FOR ALL TYPES OF READ
	EXTERNAL CSTMNT,GENLAB,A1LABEL,CGOPGEN,OPDSPIX;
	MAP BASE CSTMNT;
	EXTERNAL CGIOLST,OPGNLI,OPGIN,OPGRTB,OPGFIN;
	LOCAL BASE T1;

	CGUNIT();	!GENERATE CODE TO EVAL THE UNIT NUMBER (IF AN EXPRESSION)

	%(***IF THERE AN EXPRESSION TO BE EVALUATED FOR THE RECORD NUMBER (UGH!!!)
		GENERATE CODE TO EVALUATE IT***)%
	CGRECNUM();

	!FILL IN IOARGLBL FIELD
	A1LABEL_CSTMNT[IOARGLBL]_GENLAB();

!**[564]  CGREAD @4846  SJW  29-APR-77
![564] MAKE CGREAD AND CGWRIT SYMMETRICAL: DON'T MAKE A NAMELIST
![564]   CHECK WITHOUT CHECKING FOR IONAME PTR = 0
%[564]%	T1 _ .CSTMNT [IOFORM];			! IOFORM == IONAME
%[564]%	IF .CSTMNT [IOLIST] EQL 0		! NO IOLIST (BEWARE NAMELIST)
%[564]%	  THEN
%[564]%	    IF .T1 EQL 0			! NO FORMAT
%[564]%	      THEN BEGIN
%[564]%		OPDSPIX _ OPGRTB;		! UNFORMATTED READ
%[564]%		CGOPGEN ();
%[564]%		OPDSPIX _ OPGFIN;		! FIN CALL SINCE NO IOLIST
%[564]%		CGOPGEN ();
%[564]%	      END
%[564]%	    ELSE
%[564]%	    IF .T1 [OPRCLS] NEQ STATEMENT  AND	! CHECK FOR NAMELIST
%[564]%	       .T1 [IDATTRIBUT (NAMNAM)]
%[564]%	      THEN BEGIN
%[564]%		OPDSPIX _ OPGNLI;		! NAMELIST READ
%[564]%		CGOPGEN ();
%[564]%	      END
%[564]%	      ELSE BEGIN
%[564]%		OPDSPIX _ OPGIN;		! FORMATTED READ
%[564]%		CGOPGEN ();
%[564]%		OPDSPIX _ OPGFIN;		! FIN CALL SINCE NO IOLIST
%[564]%		CGOPGEN ();
%[564]%	      END
%[564]%	  ELSE BEGIN				! THERE IS AN IOLIST
%[564]%	    IF .T1 EQL 0			! CHECK FOR FORMAT
%[564]%	      THEN OPDSPIX _ OPGRTB		! UNFORMATTED READ
%[564]%	      ELSE OPDSPIX _ OPGIN;		! FORMATTED READ
%[564]%	    CGOPGEN ();
%[564]%	    CGIOLST ();				! PROCESS IOLIST
%[564]%	  END;

END;


GLOBAL ROUTINE CGWRIT=
BEGIN
	!CODE GENERATION FOR WRITE STATEMENTS OF ALL FORMS

	EXTERNAL CGOPGEN,OPDSPIX,A1LABEL,OPGOUT,OPGNLO,OPGWTB,GENLAB,
		CGIOLST,CSTMNT,OPGFIN;

	MAP BASE CSTMNT;

	LOCAL BASE T1;

	CGUNIT();	!GENERATE CODE TO EVAL THE UNIT NUMBER (IF AN EXPRESSION)

	%(***IF THERE AN EXPRESSION TO BE EVALUATED FOR THE RECORD NUMBER (UGH!!!)
		GENERATE CODE TO EVALUATE IT***)%
	CGRECNUM();
	!**;[376], CGWRIT @4892, DCE, 28-APR-76
	!**;[376], REORDER THINGS SO THAT THE CALL TO CGREGNUM DOES
	!**;[376], NOT OVERWRITE A1LABEL CAUSING BAD CODE
		!FILL IN IOARGLBL FIELD[376]

		A1LABEL_CSTMNT[IOARGLBL]_GENLAB(); ![376]

!**[564]  CGWRIT @4907  SJW  29-APR-77
![564] MAKE CGREAD AND CGWRIT SYMMETRICAL: GENERATE A FIN CALL
![564]   AFTER AN UNFORMATTED WRITE; REPLACE EDIT [367]
%[564]%	T1 _ .CSTMNT [IOFORM];			! IOFORM == IONAME
%[564]%	IF .CSTMNT [IOLIST] EQL 0		! NO IOLIST (BEWARE NAMELIST)
%[564]%	  THEN
%[564]%	    IF .T1 EQL 0			! NO FORMAT
%[564]%	      THEN BEGIN
%[564]%		OPDSPIX _ OPGWTB;		! UNFORMATTED WRITE
%[564]%		CGOPGEN ();
%[564]%		OPDSPIX _ OPGFIN;		! FIN CALL SINCE NO IOLIST
%[564]%		CGOPGEN ();
%[564]%	      END
%[564]%	    ELSE
%[564]%	    IF .T1 [OPRCLS] NEQ STATEMENT  AND	! CHECK FOR NAMELIST
%[564]%	       .T1 [IDATTRIBUT (NAMNAM)]
%[564]%	      THEN BEGIN
%[564]%		OPDSPIX _ OPGNLO;		! NAMELIST WRITE
%[564]%		CGOPGEN ();
%[564]%	      END
%[564]%	      ELSE BEGIN
%[564]%		OPDSPIX _ OPGOUT;		! FORMATTED WRITE
%[564]%		CGOPGEN ();
%[564]%		OPDSPIX _ OPGFIN;		! FIN CALL SINCE NO IOLIST
%[564]%		CGOPGEN ();
%[564]%	      END
%[564]%	  ELSE BEGIN				! THERE IS AN IOLIST
%[564]%	    IF .T1 EQL 0			! CHECK FOR FORMAT
%[564]%	      THEN OPDSPIX _ OPGWTB		! UNFORMATTED WRITE
%[564]%	      ELSE OPDSPIX _ OPGOUT;		! FORMATTED WRITE
%[564]%	    CGOPGEN ();
%[564]%	    CGIOLST ();				! PROCESS IOLIST
%[564]%	  END;

END;


GLOBAL ROUTINE CGOPLST=
%(***************************************************************************
	ROUTINE TO GENERATE CODE TO EVALUATE ANY EXPRESSIONS THAT
	OCCUR AS VALS OF ARGS UNDER AN OPEN/CLOSE STMNT
***************************************************************************)%
BEGIN
	OWN OPENLIST ARVALLST;	!LIST OF ARGS AND THEIR VALS UNDER THIS STMNT

	CGUNIT();	!GENERATE CODE FOR UNIT NUMBER THAT IS AN EXPRESSION


	ARVALLST_.CSTMNT[OPLST];

	INCR I FROM 0 TO (.CSTMNT[OPSIZ]-1)	!LOOK AT EACH ARG
	DO
	BEGIN
		TREEPTR_.ARVALLST[.I,OPENLPTR];	!PTR TO THE EXPRESSION NODE FOR THE VAL OF THIS ARG
		IF .TREEPTR EQL 0	!FOR "DIALOG", CAN HAVE  NULL VAL
		THEN BEGIN END
		ELSE
		IF .TREEPTR[OPRCLS] NEQ DATAOPR THEN CGETVAL()
	END
END;	!END OF ROUTINE "CGOPLST"

GLOBAL ROUTINE CGOPEN=
BEGIN
	!CODE GENERATION FOR THE CALL TO OPEN.

	EXTERNAL CGOPGEN,OPDSPIX,A1LABEL,GENLAB,OPGOPE;
	EXTERNAL CSTMNT;  MAP BASE CSTMNT;


	CGOPLST();	!GENERATE CODE TO EVAL ANY EXPRESSIONS THAT OCCUR AS VALS OF ARGS

	!FILL IN IOARGLBL FIELD

	A1LABEL_CSTMNT[IOARGLBL]_GENLAB();

	OPDSPIX_OPGOPE;
	CGOPGEN();
END;

!GLOBAL ROUTINE CGRELS=
!BEGIN
!	!CODE GENERATION FOR RELAEASE STATEMENT
!
!	EXTERNAL CSTMNT,CGOPGEN,OPDSPIX,A1LABEL,OPGREL,GENLAB;
!	MAP BASE CSTMNT;
!	!FILL IN IOARGLBL FIELD
!
!	A1LABEL_CSTMNT[IOARGLBL]_GENLAB();
!	OPDSPIX_OPGREL;
!	CGOPGEN();
!END;
!
GLOBAL ROUTINE CGFIND=
BEGIN
	!CODE GENERATION FOR FIND

	EXTERNAL CGOPGEN,CSTMNT,A1LABEL,GENLAB,OPDSPIX,OPGFND;

	MAP BASE CSTMNT;

	CGUNIT();	!GENERATE CODE FOR UNIT NUMBER

	!FILL IN IOARGLBL FIELD
	A1LABEL_CSTMNT[IOARGLBL]_GENLAB();

	%(***IF THERE AN EXPRESSION TO BE EVALUATED FOR THE RECORD NUMBER (UGH!!!)
		GENERATE CODE TO EVALUATE IT***)%
	CGRECNUM();

	OPDSPIX_OPGFND;
	CGOPGEN();
END;

GLOBAL ROUTINE CGCLOS=
BEGIN
	!CODE GENERATION FOR CLOSE STATEMENT

	EXTERNAL CSTMNT,GENLAB,A1LABEL,OPDSPIX,CGOPGEN,OPGCLO;

	MAP BASE CSTMNT;


	CGOPLST();	!GENERATE CODE TO EVAL ANY EXPRESSIONS THAT OCCUR AS VALS OF ARGS

	!FILL IN IOARGLBL FIELD

	A1LABEL_CSTMNT[IOARGLBL]_GENLAB();

	OPDSPIX_OPGCLO;
	CGOPGEN();
END;

MACRO
	IOWHOLE=0,7,0,36$,
	OPENFFIELD=0,33,3$,
	OPENGFIELD=0,27,5$,
	OPENCODE=0,0,18,18$,
	OPENARG=0,0,0,18$,
	UTILLOW=BACKID$,
	UTILHI=ENDFID$;
GLOBAL ROUTINE	CGDECARGS=
%(***************************************************************************
	TO GENERATE THE ARG BLOCK FOR AN ENCODE OR DECODE STATEMENT
	ARG BLOCK HAS THE FORM:
		--------------------------------------------------
		!	-6		!			!
		--------------------------------------------------
		!	!TYPE	!I! X	! CHAR CT (IMMED)	!
		--------------------------------------------------
		!	!TYPE	!I! X	!  END=			!
		--------------------------------------------------
		!	!TYPE	!I! X	!  ERR=			!
		--------------------------------------------------
		!	!TYPE	!I! X	!  FORMAT ADDR		!
		--------------------------------------------------
		!	!TYPE	!I! X	!  FORMAT SIZE(IMMED)	!
		--------------------------------------------------
		!	!TYPE	!I! X	!   VAR ARRAY ADDR	!
		--------------------------------------------------
	WHERE THE ARGLIST PTR POINTS TO THE WORD CONTAINING THE CHAR CT (IE
	THE -6 IS IN THE WD PRECEEDING THE ARG PTR)
***************************************************************************)%
BEGIN
	EXTERNAL IOIMMED,IOPTR;
	EXTERNAL PBOPWD,CSTMNT,PSYMPTR,OBUFF;
	EXTERNAL IOENDERR,IOFORMAT,EVALU;
	MAP PEXPRNODE CSTMNT;		!ENCODE OR DECODE STMNT FOR WHICH ARG BLOCK
					! IS TO BE GENERATED
	MAP OBJECTCODE PBOPWD;

	OWN PEXPRNODE ENCARRAY;		!ARRAY TO BE INPUT OR OUTPUT
	OWN PEXPRNODE CHARCT;		!NUMBER OF CHARS TO BE PROCESSED

	ENCARRAY_.CSTMNT[IOVAR];
	CHARCT_.CSTMNT[IOCNT];

	%(***OUTPUT WD CONTAINING THE CT OF WDS IN THE ARGLIST***)%
	PBOPWD_(-6)^18;		!CT IN LEFT HALF WD
	PSYMPTR_PBF2NOSYM;
	OBUFFA();

	%(***ASSOCIATE THE LABEL ON THE ARGLIST WITH THIS LOC***)%
	DEFLAB(.CSTMNT[IOARGLBL]);




	%(***SET UP THE COUNT OF CHARS TO BE PROCESSED IN THE 1ST WD OF THE ARG BLOCK***)%
	IOIMMED(.CHARCT);

	IOENDERR();		!OUTPUT THE END/ERROR WORDS OF THE ARG BLOCK

	IOFORMAT();		!OUTPUT THE FORMAT WDS OF THE ARG BLOCK

	%(***OUTPUT A PTR TO THE ARRAY***)%
	IOPTR(.ENCARRAY);
END;



ROUTINE	IO1ARG(NUMB)=
%(*********************
	ROUTINE TO OUTPUT 2 WDS OF THE FORM:
		--------------------------------------------------
		!	-CT		!			!
		-------------------------------------------------
	 LAB:	!	! TYPE	!I! X	!	UNIT		!
		---------------------------------------------------
	WHERE "UNIT" IS IMMEDIATE
***********************)%
BEGIN
	EXTERNAL IOIMMED;
	EXTERNAL	PBOPWD,PSYMPTR,OBUFF,CSTMNT;
	MAP	BASE	CSTMNT;
	MAP OBJECTCODE	PBOPWD;

	%(***OUTPUT MINUS THE CT OF WDS IN THE ARG BLOCK***)%
	PBOPWD_(-.NUMB)^18;	!CT IN LEFT HALF WD
	PSYMPTR_PBF2NOSYM;
	OBUFFA();

	%(***ASSOCIATE THE LABEL ON THE ARG BLOCK WITH THIS LOC***)%
	DEFLAB(.CSTMNT[IOARGLBL]);


	IOIMMED(.CSTMNT[IOUNIT]);	!GENERATE AN "IMMEDIATE" MODE
				! ARG FOR THE UNIT NUMBER
	PBOPWD_0;
END;
GLOBAL ROUTINE IOENDERR=
%(***********************
	OUTPUT THE END= AND ERR-= WORDS OF AN IO ARG BLOCK.
	THESE 2 WDS HAVE THE FORM:
		---------------------------------------------------------
		!	! TYPE	!I! X	!	IOEND			!
		---------------------------------------------------------
		!	! TYPE	!I! X	!	IOERR			!
		---------------------------------------------------------
**************************)%
BEGIN
	EXTERNAL PBOPWD,OBUFFA,PSYMPTR,CSTMNT;
	MAP BASE CSTMNT;
	MAP OBJECTCODE PBOPWD;
	%(***OUTPUT THE "END" WD***)%
	PBOPWD_0;
	IF .CSTMNT[IOEND] EQL 0
	THEN PSYMPTR_PBF2NOSYM
	ELSE
	BEGIN
		PBOPWD[OTSTYPE]_ADDRTYPE;	!TYPE IS "ADDRESS"
		PBOPWD[OTSADDR]_.CSTMNT[IOEND];
		PSYMPTR_PBFLABREF;
	END;
	OBUFFA();

	%(***OUTPUT THE "ERROR" WD***)%
	PBOPWD_0;
	IF .CSTMNT[IOERR] EQL 0
	THEN PSYMPTR_PBF2NOSYM
	ELSE
	BEGIN
		PBOPWD[OTSTYPE]_ADDRTYPE;	!TYPE IS "ADDRESS"
		PBOPWD[OTSADDR]_.CSTMNT[IOERR];
		PSYMPTR_PBFLABREF;
	END;
	OBUFFA();

	PBOPWD_0;
END;


GLOBAL ROUTINE IOFORMAT=
%(********************
	ROUTINE TO OUTPUT THE 2 FORMAT WDS OF AN IO ARG-BLOCK
	THESE WDS HAVE THE FORM:
		----------------------------------------------------------
		!	! TYPE	!I! X	!	FORMAT ADDR		!
		----------------------------------------------------------
		!	! TYPE	!I! X!	!	FORMAT SIZE		!
		----------------------------------------------------------
************************)%
BEGIN
	EXTERNAL CSTMNT,PBOPWD,OBUFFA,PSYMPTR;
	EXTERNAL ISN,FATLERR,E91;
	EXTERNAL EVALU;
	MAP BASE CSTMNT;
	MAP OBJECTCODE PBOPWD;
	MAP PEXPRNODE PSYMPTR;
	OWN BASE T:FORMATP;
	FORMATP_.CSTMNT[IOFORM];
	!IOSTATEMENT CONTAINS POINTER TO LABEL TABLES
	!OR VARIABLE

	PBOPWD_0;

	IF .FORMATP[OPRCLS] EQL LABOP
	 THEN
	%(***IF FORMAT IS A STMNT- HAVE A PTR TO THE LABEL TABLE ENTRY FOR ITS LABEL***)%
	BEGIN
		FORMATP_.FORMATP[SNHDR];

		%(***IF THE STMNT REFERENCED IS NOT A FORMAT STMNT, GIVE AN ERROR MESSAGE.***)%
		IF .FORMATP[SRCID] NEQ FORMID
		THEN
		BEGIN
			FATLERR(.FORMATP[SRCISN],E91<0,0>);

			%(***PUT OUT 2 WDS OF 0 FOR THE FORMAT WDS***)%
			ZIPOUT;
			ZIPOUT;

			RETURN;
		END;


		%(***OUTPUT THE FORMAT ADDRESS WD***)%
		PBOPWD[OTSADDR]_.FORMATP;
		PBOPWD[OTSTYPE]_ADDRTYPE;		!TYPE FIELD EQL TO "ADDRESS"
							! INDICATES THAT FORMAT IS NOT 
							! AN ARRAY
		PSYMPTR_PBFFORMAT;
		OBUFFA();

		%(***OUTPUT THE FORMAT SIZE WD***)%
		PBOPWD_.FORMATP[FORSIZ];
		PBOPWD[OTSTYPE]_IMMEDTYPE;	!SIZE IS REFERENCED IMMED
		PSYMPTR_PBF2NOSYM;
		OBUFFA();
	END
	ELSE
	%(***IF FORMAT IS AN ARRAY, HAVE A PTR TO THE SYMBOL TABLE ENTR