Trailing-Edge
-
PDP-10 Archives
-
BB-D480F-BB_1985_short
-
outmod.bli
There are 26 other files named outmod.bli in the archive. Click here to see a list.
!COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1973, 1985
!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 WHICH IS NOT SUPPLIED BY DIGITAL.
!AUTHOR: F. INFANTE/MD/DCE/JNG/TFV/CDM/AHM/RVM/EGM/PLB/AlB/MEM
MODULE OUTMOD(RESERVE(0,1,2,3),SREG=#17,FREG=#16,VREG=#15,DREGS=4,GLOROUTINES)=
BEGIN
GLOBAL BIND OUTMOV = #10^24 + 0^18 + #2507; ! Version Date: 20-Dec-84
%(
***** Begin Revision History *****
44 ----- ----- MODIFY "PROCEQUIV" TO TURN OFF THE "BOUNDS" FLAG
WHEN ARRXPN IS CALLED FOR AN EQUIVALENCE STMNT
45 ----- ----- MOVE DECLARATIONS OF LOADER BLOCK TYPES TO A
REQUIRE FILE.
46 ----- ----- REMOVE THE ROUTINES "ZOUTBLOCK" (WHICH
HAS MOVED TO THE MODULE "RELBUF") AND "ZDMPBLK"
(WHICH IS NO LONGER NEEDED)
ALSO REMOVE THE ROUTINE "DATAOUT" AND CHANGE "OUTDATA"
TO CALL "ZOUTBLOCK" RATHER THAN "DATAOUT". ALSO
CHANGE OUTDATA TO CALL "DMPRLBLOCK" OF "MAINRLBF"
WHEN THE BUFFER DOESNT HAVE ENOUGH ROOM RATHER
THAN CALLING "ZDMPBLK".
47 ----- ----- REMOVE DEFINITIONS OF CBLK AND ZDATCNT AND ALL
REFERENCES TO THEM.
ALSO, REMOVE ALL REFERENCES TO "RELOCPTR" AND
"RELBLOCK".
48 ----- ----- MODIFY "RELINIT" TO CALL "INITRLBUFFS" TO INITIALIZE
THE REL FILE BUFFERS.
49 ----- ----- DELETE THE ROUTINE "DMPRELONLS"
50 ----- ----- DELETE THE ROUTINES:
ZOUTMSG,ZOUTSYM,ZOUTOCT,RADIX50,ZOUDECIMAL,
ZOUOFFSET
51 ----- ----- MISSPELLED "INIRLBUFFS" (IN "RELINIT")
THESE HAVE BEEN MOVED TO THE MODULE "RELBUFF"
52 ----- ----- TAKE OUT THE DEF OF THE ROUTINE "CRLF" - IT IS
NOW A MACRO DEFINED IN THE REQUIRE FILE
"REQREL"
53 ----- ----- IN "OUTDATA", CALL "DMPMAINRLBF" TO CLEAR THE MAIN
REL FILE BUFFER RATHER THAN CALLING "DMPRLBLOCK"
DIRECTLY (SINCE DMPRLBLOCK DOES NOT REINIT THE BUFFER)
54 ----- ----- IN "DMPFORMAT", CALL "DMPMAINRLBF" RATHER THAN
DMPRLBLOCK
55 ----- ----- TAKE OUT UNUSED ROUITNE ROUIMFUN
56 ----- ----- CHANGE THE CHECKS IN VARIABLE ALLOCATION TTO
WORK PROPERLY
PUT IN LISTING HEADING CHECKS
PUT OUT A VALID ENTRY NAME BLOCK
57 ----- ----- IN "OUTDATA" PUT A CHECK FOR WHETHER A REL FILE
IS BEING PRODUCED (SINCE WANT TO EXECUTE
THE MAIN DATA STMNT PROCESSOR FOR ERROR
DETECTION EVEN IF NO REL FILE IS PRODUCED)
58 ---- ---- GRPSCAN - MAKE IT PUT THE COMMON VARIABLE IN AN
EQUIVALENCE GROUP FIRST IN THE LIST SO ITS
DISPLACEMENT WILL BE CALCULATED FIRST IF IT WAS
DELAYED.
ALSO CHECK FOR TWO COMMON VARIABLES IN EQUVALENCE
PROCEQUIV - CHECK TO BE SURE THAT AT LEAST IN THE
SINGLE SUBSCRIPT CASE THE EQUIVALENCE IS AN INTEGER
CONSTANT. NO VARIABLES OR EXPRESSIONS
59 ----- ---- CHECK POSITIVE AND NEGATIVE RANGE LIMITS
OF EQUIVALENCE SUBSCRIPTS
60 ----- ----- IN "ALLFORM", PUT THE ADDRESS OF THE FORMAT
INTO THE SNUMBER TABLE ENTRY FOR ITS LABEL
61 ----- ----- SET THE GLOBAL "ENDSCAA" TO THE ADDR AFTER END
OF ALL ARRAYS AND SCALARS
62 ----- ----- LISTSYM - SUBPROGLIST - ALLSCA
OUTPUT A WARNING PREFIX CHARACTER AFTER
VARIABLES, ARRAYS WHICH WERE NEVER EXPLICITLY
DEFINED OR WERE EXPLICITLY DEFINED BUT NEVER
REFERENCED
* - NOT EXPLICITLY DEFINED
PERCENT SIGN - DEFINED BUT NOT REFERENCED
63 236 14654 EQUIVALENCE ARRAY1-ARRAY2 FAILS AFTER ARRAY1-SCALAR,
(MD/DT)
64 241 ----- CORRECT HIGH SEG START ADDR FOR LINK
IF LOW SEG SIZE IS GREATER THAN 128K, (MD)
65 337 17305 ROUND UP IMMEDIATE CONSTANTS CORRECTLY, (DCE)
66 364 18251 CORRECT EQUIVALENCE PROCESSING, (DCE)
67 436 19427 DON'T ALLOW 2 BLOCK COMMON VARIABLES TO
BE EQUIVALENCED IF BLOCKS ARE DIFFERENT, (DCE)
68 470 20744 MAKE SURE HIGH SEG STARTS AT LEAST 1000 LOCS
ABOVE END OF LOW SEG, (JNG)
69 472 20494 IF COMMON ITEM IS LAST IN GROUP,
MOVE IT TO BEGINNING CORRECTLY, (DCE)
70 473 20478 SCALARS AND ARRAYS LISTING TOO WIDE, (DCE)
71 474 20479 SHOULD GIVE CRLF AFTER COMMON BLOCK NAMES, (DCE)
***** Begin Version 5A *****
72 604 23425 FIX LISTING OF COMMON BLOCK ELEMENTS, (DCE)
***** Begin Version 5B *****
73 636 23066 SET SNDEFINED WHEN DEFINING A LABEL, (JNG)
74 645 25249 SCALARS AND ARRAYS INCREMENTS LINE COUNT BY
ONE TOO MANY, (DCE)
75 702 ----- LISTING OF SUBPROGRAMS CALLED CAN BE INCORRECT, (DCE)
76 703 ----- LISTING OF SCALARS AND ARRAYS CAN GIVE BLANK PAGE, (DCE)
77 735 28528 CLEAN UP LISTING OF VARIOUS HEADERS, (DCE)
***** Begin Version 6 *****
78 761 TFV 1-Mar-80 -----
Clean up KISNGL to use CNSTCM. Remove KA10FLG.
Output GFLOATING FORTRAN as compiler type in .REL file
79 1003 TFV 1-Jul-80 ------
Use binds for processor type and compiler id in REL blocks.
80 1006 TFV 1-July-80 ------
Move KISNGL to UTIL.BLI (It is also in CGEXPR.BLI.)
86 1120 AHM 9-Sep-81 Q10-06505
Fix edit 735 by always clearing a flag so that the
"EQUIVALENCED VARIABLES" header is produced again.
87 1133 TFV 28-Sep-81 ------
Setup CHDSTART to be the start of the hiseg for /STATISTICS.
***** Begin version 6A *****
97 1146 EGM 5-Jan-82 20-17060
Pass the ISN of the illegal Equivalance group for error IED.
1151 EGM 25-Mar-81
Report ?Program too large for COMMON 512P and up
***** Begin Version 7 *****
81 1246 CDM 1246 ------
Edit SUBPROGLIST so that inline functions names are not printed
out in listings.
82 1232 TFV 24-Jun-81 ------
Rewrite ALLSCAA and ALCCON to handle character data and character
constants. Output character data to the .REL file. Write LSCHD to
output the descriptors to the low seg for dummy args; write HSCHD to
output descriptors to the high seg for non-dummy arg character data;
also write HSLITD to output descriptors to the high seg for character
constants. Also add a new section to the .LST file for character data.
Write LISTCHD to list character variable and array names, descriptor
locations, location and character position for the start of the data,
and the length of the data.
83 1261 CKS 17-Sep-81
Modify common and equivalence allocation to support type CHARACTER.
Have all equivalence processing done in characters instead of words.
Convert back to words at the end.
84 1262 CKS 22-Sep-81
Allow substrings in character EQUIVALENCE classes
85 1264 CDM 24-Sep-81
Revise edit to that "SUBPROGRAMS CALLED" is not put on program
listings for inline functions.
88 1272 RVM 15-Oct-81
Convert REAL constants from DOUBLE PRECISION, even if the constant
is part of a MOVEI.
89 1274 TFV 16-Oct-81 ------
Fix ALCQVARS to handle multi-word .Q variables.
90 1406 TFV 27-Oct-81 ------
Write HSDDESC to output .Dnnnn compile-time-constant character
descriptors to the .REL file. Either one word (byte pointer
only) or two words (byte pointer and length) are output based on
the flag IDGENLENFLG. One word .Dnnnn variables are used for
SUBSTRINGs with constant lower bounds and non-constant upper
bounds. Use BPGEN to create byte pointers that are output to
the .REL file.
91 1424 RVM 19-Nov-81
Precede the formats in the object program by a count of the number
of words in the format (in other words, make formats look like
BLISS-10 PLIT's). This is needed for assignable formats.
92 1434 TFV 14-Dec-81 ------
Fix multi-entry character functions. All the entry points share the
same descriptor. The descriptor is generated in ALLSCAA for the
main entry point. Fixup the other entry points so that their IDADDR
fields point to the descriptor for the main entry point. Fix HSCHD
to generate descriptors for character functions that are declared
external.
93 1443 RVM 17-Dec-81
ALLFORM never thought that there could be backwards references to
format statements, and so never set up the SNSTATUS field. With
ASSIGNed FORMATs, there can be backwards references.
94 1437 CDM 16-Dec-81
Create and initialize new global variable HIORIGIN to store the
origin of the Hi-seg.
95 1450 CKS 30-Dec-81
Detect the error in EQUIVALENCE (A(1),A(2))
96 1451 CKS 30-Dec-81
Fix HSDDESC to handle common variables as subnodes of .D descriptors.
98 1454 RVM 7-Jan-82
Consolidate the routines ALLFORM and DMPFORMAT into one routine that
both allocates addresses to the formats and (if needed) dumps the
formats to the .REL file. The new routine is called DUMPFORMAT.
99 1455 TFV 5-Jan-82 ------
Fix ALLSCAA to allocate character statement function names.
They have an extra argument. It is the descriptor for the
result. It is stored into the space allocated for the statement
function name.
1511 CDM 17-Mar-82
Count the number of COMMON blocks for a SAVE statement with no
arguments. (All common blocks must be output in the rel block
for SAVE processing). Also error processing for variables
which suddenly become in common through equivalencing.
1512 AHM 26-Mar-82
Change all calls to ZOUTBLOCK that used RSYMBOL (rel block
type 2) to call ZSYMBOL instead.
1522 TFV 29-Mar-82
Fix error diagnostic for length star variables and arrays.
Length star is legal only for dummy arguments and character
parameters. Cause an ICE if a .Dnnnn variable has a length less
than 1.
1525 AHM 1-Apr-82
Various changes for psected REL files. Suppress generation of
the type 3 HISEG block. Generate type 24 psect header blocks
for each psect. Put in a type 17 .REQUEST FORLIB:FORLIB block
for development to read in a private FORLIB that is psected
instead of being TWOSEG. Turn off KS bit in the type 6 name
block when compiling /EXTENDED.
1526 AHM 7-Apr-82
Pave the way for psected rel files by converting all calls to
ZOUTBLOCK for outputting RCODE (type 1) rel blocks to call
ZCODE instead. Use the proper relocation counter to allocate
space for each psect instead of always using HILOC to tell
ZOUTBLOCK what address is being output. Fix bug caused by
mixing edits 1261 and 1151 which caused rejection of common
blocks longer than 1/5th of a section.
1527 CKS 29-Apr-82
Do not allocate storage for PARAMETER variables. They get into
the symbol table as scalars when they appear in type declaration
statements, but no storage should be allocated for them.
1531 CDM 14-May-82
Make changes for new use of NUMSAVPTR and change error message
E192 to E197 for SAVE error processing.
1534 CKS 17-May-82
Fix output of character constants in the listing. Use uparrow
format instead of sending the control character directly.
1537 AHM 20-May-82
Prepend some innocuous entries to the BPLH UPLIT so that bad
negative character addresses propagated from users trying to
extend common blocks backward don't get junk listings of the
byte pointers.
1544 AHM 26-May-82
Output type 22 default psect index blocks for the .DATA. psect
before type 21 or 1004 sparse data blocks so that they have a
chance to work while the new psected sparse data blocks are
not in LINK. This edit is only for V8 development and will be
removed when the LINK support is finally in.
1547 AHM 1-Jun-82
Make PROCCOM change the size of a COMMON block from characters
to words before it is added into the total size of all COMMON
blocks.
1564 AHM 21-Jun-82
Don't put out a .REQUEST FORLIB:FORLIB block in RELINIT under
/EXTEND - it isn't needed anymore. Also, uncomment the
section 1 psect origins.
1567 CDM 24-Jun-82
Don't output .Dnnn variables if NOALLOC is lit.
1615 AHM 16-Aug-82
Change the default psect index to .DATA. before outputting
common block sizes in ALLCOM. LINK will be changed to
allocate common blocks in the default psect when reading
psected .REL files.
1627 CKS 31-Aug-82
Do not allocate .D variables to hold the result of CHAR function when
CHAR(constant-expr) in a PARAMETER statement has been replaced by a
simple constant.
1630 AHM 1-Sep-82
Fix bug introduced by edit 1615. Don't output a default psect
index if there is no .REL file being generated.
1666 TFV 8-Nov-82
Fix RELINIT to always use FORTRAN for the compiler id. The id
for GFLOATING FORTRAN is no longer used. Type coercion is now
used for DP actuals passed to GFLOATING formals and vice versa.
1675 RVM 11-Nov-82 Q10-03032
Implement a suggestion to include more information in the
warning message E168.
1703 CDM 17-Dec-82
Do not output any processor type to rel file. V5A only puts out
KI, and V7 will not work on a KI, so if we tell Link the truth,
users with libraries will get Link-time warnings.
***** End V7 Development *****
1733 RJD 21-Mar-83 SPR 10-33670
Set ISN to zero when in ALCCON as any over/underflows that
may occur at that time are not associated with a particular
line number.
***** Begin Version 10 *****
2207 CDM 21-Jul-83
Reformat and comment equivalence routines ALLOCAT, EQERRLIST,
LINKGROUPS, ELISTSEARCH, GRPSCAN, PROCEQUIV. Delete macro
EQGPPTR which was defined to be EQLPTR in PROCEQUIV.
2210 AHM 27-Jul-83
Rename DUMPFORMAT to DMPFORMAT to reserve DUMP?? for SIX12.
2216 PLB 27-Sep-83
Modify ZOUTBP and CHADDR2BP to handle OWGBPs, Depending on
state of OWGBPSECTION global; Create routine BPADD to replace
MACRO from TABLES.
2232 RVM 8-Nov-83
Allocate variables into the proper psect. The IDADDR and
IDPSCHARS now get their values based on the IDPSECT and
IDPSCHARS fields, respectively. IDPSECT and IDPSCHARS contain
"psect indexes," which are indexes into the vector PSECTS.
The PSECTS vector contains the next allocated offsets into the
low and high segments (/NOEXTEND) or the next allocated
offsets into .DATA., .CODE., or .LARG. psects (/EXTEND).
Pretty much, this edit consisted of replacing LOWLOC and
LARGELOC by PSECTS[.SYMBOL[IDPSECT]].
2233 AlB 9-Nov-83
Move the calculation of the total size of common from PROCCOM
to ALLCOM, so that this total will reflect any influence by
the EQUIVALENCE statement. Changes to ALLOCAT, PROCCOM, ALLCOM.
2235 AlB 10-Nov-83
1. Worry about the effect of extended addressing on EQUIVALENCE
and COMMON processing. Essentially, if any variable is
equivalenced to a common variable, the former variable takes
the psect of the common block. If any equivalence group
contains all non-common, then the psect for all items in that
group becomes .LARG. if any one of the items is .LARG., and
.DATA. otherwise.
2. Clean up some WHILE 1 DO code to better illustrate what is
happening. (Change to UNTIL x EQL 0 DO).
3. Replace all literal values associated with EQVAVAIL with
named constants.
4. Change reference to LOWLOC to refer to PSECTS table. This is
code that was not changed by Edit 2232.
Changes to ALLCOM, PROCCOM, ELISTSRCH, EQCALLOC, GRPSCAN and
PROCEQUIV
2236 AlB 11-Nov-83
Remove the code which jams PSDATA into COMPSECT. That code now
resides in NEWENTRY of module SRCA.
Routine affected: PROCCOM
2266 AHM 13-Jan-84
Change the origin of the .CODE. psect (CODEORG) in RELINIT
from 1,,140 to 1,,1000 so that the program's fake JOBDAT page
is not read only.
2271 AlB 18-Jan-84
1) If single subscript used on multi-dimensioned array in EQUIVALENCE,
put out compatibility warning.
2) Do range checking on that single subscript.
3) Generate compatibility warning if logical and numeric data are
in the same EQUIVALENCE list.
4) Change the 'Char and Non-Char' warning to be generated only if
we are doing compatibility flagging (COMMON and EQUIVALENCE).
Routines:
ALLCOM EQCALLOC PROCEQUIV
2310 CDM 13-Feb-84
Output type 1131 rel block for PSECT redirection of segments
into psects. The command scanner sets the names for the psects
and the code generator dumps the rel block. Discontinue putting
out type 22 blocks in same region of code.
2311 PLB 19-Feb-84 WAR IS PEACE
Modify symbol listings under /EXTEND
2322 CDM 27-Apr-84
Fix array subscript calculations for /EXTEND to use a full word
to calculate arithmetic. In PROCEQUIV and BLDDIM, check an
array reference against the correct maximum size of an array
declaration /EXTEND. In BLDDIM, call CNSTCM for array
calculations to give underflow/overflow messages for illegal
declarations. Otherwise arrays that are too large may not be
detected since their size will overflow.
2330 AHM 28-Mar-84
Remove all uses of global OWGBPSECTION. Use EXTENDED flag to
decide when to deal with OWGBPs instead of OWLBPs. Use
Z30CODE to generate all byte pointers. Generate 30 bit
additive fixups for OWGBPs that reference COMMON. Use EFIWs
for CHARACTER FUNCTION descriptors under /EXTEND to make
multiple sections of code work.
2342 AHM 17-Apr-84
Make DATA statements work for some variables in .LARG. Make
OUTDATA use the psect indices in the variables it is passed
instead of always using .DATA. This should allow numeric
variables in the first section of .LARG. to be statically
initialized by DATA statements.
2344 PLB 19-Apr-84
Make ZOUTBP output 0(?) if BP to output is equal to zero.
2345 AHM 20-Apr-84
Make HSCHD in OUTMOD use additive fixups to generate the
indirect words for external CHARACTER function descriptors.
This makes the code agree with the comments and design spec,
and avoids a LINK bug with deferred 30 bit chained fixups.
2346 AHM 23-Apr-84
Make ALLCOM keep separate totals of the sizes of small and
large COMMON blocks in the new globals SCOMSZ and LCOMSZ.
ALLCOM no longer has a return value, since no one cares about
the sum of the sizes of all COMMON blocks.
2356 AHM 8-May-84
Add support for individual specification of the psects for
COMMON blocks. Do it by putting the body of the outermost
loop in ALLCOM in a new routine named ALCCOMMON, and having
ALLCOM call it to walk the list of COMMON blocks once for each
of .DATA. and .LARG. Also, change the default psect origin
for .DATA. to 1000140 and .CODE. to 1300000. This way, the
impure data areas have the lowest addresses in both section 0
and non-zero sections.
2357 AHM 14-May-84
Keep LINK from getting ?LNKIPX Invalid psect index when
loading programs with COMMON blocks compiled /NOEXTEND.
During COMMON block allocation (ALLCOM) only output type 22
(RPSECTORG) REL blocks under /EXTEND.
2414 AlB 5-Jul-84
When an array is referenced in an EQUIVALENCE statement, the
subscripts are now checked for 'out of bounds'. The check used
to be done (badly) for the case of single subscripts with
multi-dimensioned arrays; it was never done for multiple subscripts.
The 'out of bounds' message is a warning only; old sources will
still work, albeit with a warning.
2423 AHM 17-Jul-84
Move OUTDATA to DATAST, where it can share secret OWNs for
buffering Ultimate Sparse Data REL blocks.
2440 RVM 1-Aug-84
Change the origin of the PSDATA psect from 1000140 to 1001000.
FORDDT and FOROTS have reserved the first page of every section
which contains code.
2446 MEM 31-JUL-84
Have RELINIT produce type 1050 rel blocks when /EXTEND is given,
instead of type 24 rel blocks. This will now store psect names up to
72 characters.
2454 RVM 28-Aug-84
Move the definition of DEFLON (the default value for LONAME)
and DEFHIN (the default value for HINAME) from CMND20 into
GLOBAL. Then make OUTMOD use DEFLON and DEFHIN where in the
twoseg redirection rel block.
2455 MEM 30-Aug-84
Replace all occurrences of VAX with VMS.
2507 CDM 20-Dec-84
Add enhancement for IMPLICIT NONE (edit 2473) after code inpsection.
Check more cases, and add a symbol table walk at the back
end to catch unreferenced variables.
***** End V10 Development *****
***** End Revision History *****
)%
SWITCHES NOLIST;
REQUIRE FIRST.BLI;
REQUIRE TABLES.BLI;
REQUIRE REQREL.BLI;
SWITCHES LIST;
FORWARD
CHADDR2BP(1),
SIZEINCHARS(1),
LSTHDR(3),
LISTSYM(1),
SUBPROGLIST,
ALLSCAA,
ALLOCAT,
ALLCOM, ! Allocates all the COMMON blocks
%2356% ALCCOMMON, ! Allocates all COMMON blocks in a given psect
%2210% DMPFORMAT, ! Allocates FORMATs and dumps them to .REL file
PROCCOM,
EQERRLIST(1),
GROUPTOCOMMON(4),
LINKGROUPS(3),
ELISTSRCH(2),
EQCALLOC(1),
GRPSCAN,
PROCEQUIV,
ALCCON,
HSLITD,
HSCHD,
HSDDESC,
HDRCHD,
TABOUT,
ZOUTBP(1),
LISTCHD(2),
ALCQVARS,
HDRTMP,
HISEGBLK,
RELINIT,
%2446% TYPE1050,
%2310% PSREDIRECT, ! Outputs PSECT redirection rel blocks
%2507% CIMPLNONE; ! Check symbols for IMPLICIT NONE
EXTERNAL
ALODIMCONSTS, ! Routine to set "CNTOBEALCFLG" in all constants used
! for dimensioning arrays that are to have bounds
! checking performed on them
ARRXPN, ! For expanding array references in EQUIVALENCE items
C2H,
C2L,
%2455% CFLAGB, ! Put out "Fortran-77 or VMS: ...." flagger warning
%1522% CGERR, ! Routine to report an internal compiler error
CHAROUT,
%1245% CHDSTART,
%1261% CNSTEVAL, ! For evaluating subscript expression if necessary
COMBLKPTR,
DANCHOR, ! Pointer to the start of the .Dnnnn variables
%2454% DEFLON, ! Default name for the data psect
%2454% DEFHIN, ! Default name for the code psect
DMPMAINRLBF, ! Routine to output the contents of the main .REL file
! buffer and reiinitialize it
%1525% DMPRLBLOCK, ! Outputs data to the object and listing files
E33,
E48,
E49,
E53,
E93,
E103,
%1261% E162,
%1261% E165,
E166,
E167,
E168,
E194,
%1531% E197, ! "<foo> EQUIVALENCE-d to COMMON is illegal"
%2455% E249, ! "VMS incompatibility: Mixing Logical and Numeric in EQUIV"
%2271% E274, ! "Extension to Fortran-77: Single dimension with multi.."
%2271% E293, ! "Subscript out of range for array xxxx"
%2507% E304, ! Warning - IMPLICIT NONE
ENDSCAA,
%1434% ENTRY, ! Pointer to a sixbit name for an identifer
EQVPTR, ! Pointer to first and last EQUIVALENCE groups
FATLERR,
FORMPTR,
%735% HDRFLG, ! Scalars and arrays listing header flag
HEADCHK, ! Checks for end of listng page
%[735]% HEADING,
HILOC, ! Next available address in the high seg
%2310% HINAME, ! Name of the high (code) PSECT in SIXBIT.
%1437% HIORIGIN, ! Start of Hi-seg
%2507% IMPNONE, ! Flag for IMPLICIT NONE
INIRLBUFFS, ! To init .REL file buffers
ISN,
%1006% KISNGL, ! KISNGL is now in UTIL.BLI
%2356% LCOMP, ! Flag for at least one COMMON block in .LARG.
%2346% LCOMSZ, ! Sum of the sizes of all large COMMON blocks in words
LITPOINTER,
%2310% LONAME, ! Name of the low (data) PSECT in SIXBIT.
LOWLOC, ! Next available address in the low seg
LSTOUT,
RELBUFF MAINRLBF, ! Main .REL file buffer
BASE MULENTRY, ! Pointer to the list of entries for this subprogram
%1434% NAME, ! Table to search for tblsearch lookups
%1511% NUMSAVCOMMON, ! Pointer to SAVE-d common blocks
PAGELINE,
PROGNAME,
%2232% PSECTS, ! Vector of next available address for each PSECT
%1274% QANCHOR,
%1274% QMAX,
RADIX50,
RDATWD,
RELBLOCK,
RELDATA,
RELOCWD,
RELOUT,
%1511% SAVALL, ! SAVE statement with no args given
%2356% SCOMP, ! Flag for at least one COMMON block in .DATA.
%2346% SCOMSZ, ! Sum of the sizes of all small COMMON blocks in words
%2507% SRCHLIB, ! Searches if a name is a library function
STRNGOUT,
%2507% SYMTBL, ! Hashed symbol table
%1434% TBLSEARCH, ! Routine to lookup symbol table entries
%1245% TCNT,
%2322% VMSIZE, ! Size of virtual memory
WARNERR,
%2330% Z30CODE, ! Outputs a word using type 1 or 1030 rel blocks
%1526% ZCODE, ! Outputs a word using type 1 or 1010 rel blocks
ZOUDECIMAL,
ZOUOFFSET,
%2311% ZOUTADDR, ! OUTPUT LONG ADDR IN R2
ZOUTBLOCK,
ZOUTMSG, ! Message outputter
ZOUTOCT, ! OUTPUT HALFWORD IN R2<LH>
ZOUTSYM,
%1512% ZSYMBOL; ! Outputs type 2 or 1070 rel blocks
MACRO MODULO (A,B) = ! [1261] Positive remainder of A / B
BEGIN
REGISTER T1;
T1 _ (A) MOD (B);
IF .T1 LSS 0 THEN T1 _ .T1 + (B);
.T1
END$;
! LEFT HALF OF OWL BYTE POINTER INDEX BY BYTE NUMBER -4:4
BIND VECTOR BPLH = 4 + UPLIT (0<29,7>,0<22,7>,0<15,7>,0<8,7>, ![1537] -4:-1
0<36,7>,0<29,7>,0<22,7>,0<15,7>,0<8,7>); ! 0:4
%2216% ! P&S FIELD OF OWG BYTE POINTERS INDEXED BY BYTE NUMBER -4:4
%2311% BIND VECTOR OWGP&S = 4 + UPLIT (#62^30,#63^30,#64^30,#65^30, ! -4:-1
%2311% #61^30,#62^30,#63^30,#64^30,#65^30); !0:4
ROUTINE CHADDR2BP (A) = ! [1261] Convert character address A to
! equivalent byte pointer
%2330% IF EXTENDED !CHECK IF MAKING OWG BPs
%2330% THEN (.A/5) OR .OWGP&S[.A MOD 5] !YES
%2216% ELSE (.A/5) OR .BPLH[.A MOD 5]; !NO, USE OWL LEFT HALF
GLOBAL ROUTINE BPADD (BP,N)= ![2216] DO ADJBP FOR OWL OR **7-BIT** OWGBP
! Example: XXX = BPADD(.SYM[IDCHBP],.SYM[IDCHLEN])
! PTR = BPADD(.PTR,-1)
! BP = byte pointer
! N = value to increment BP by
IF .N NEQ 0 !NON-ZERO ADJUSTMENT?
THEN !YES, CHECK IF USING OWG/OWL
%2330% IF EXTENDED !/EXTEND?
THEN !YES!, ADJUST OWG
BEGIN !OWG
! UGLY BUT VERY FAST CODE
VREG = .BP<0,30>; !GET 30 BIT ADDR
VREG = .VREG * 5; !MAKE CHARACTER ADDR
VREG = .VREG + .N; !ADD OFFSET
VREG = .VREG - #61; !SUBTRACT OWG OFFSET
VREG = .VREG + .BP<30,6>; !ADD OWG P&S FIELD
RETURN .OWGP&S[.VREG MOD 5] OR (.VREG/5) !CONVERT BACK
END !OWG
ELSE !NOT EXTENDED
BEGIN !OWL
MACHOP ADJBP=#133;
REGISTER T1;
T1 _ .N;
RETURN ADJBP(T1,BP)
END
ELSE !ADJUST BY ZERO
RETURN .BP; !RETURN UNCHANGED (ADJBP CONONICALIZES THO)
ROUTINE SIZEINCHARS (SYMPTR) = ! [1261] Find size of scalar or array, given
! address of its symbol table entry
BEGIN
MAP BASE SYMPTR;
IF .SYMPTR[IDDIM] NEQ 0
THEN
BEGIN !ARRAY
REGISTER BASE DIMPTR;
DIMPTR _ .SYMPTR[IDDIM];
IF .SYMPTR[VALTYPE] EQL CHARACTER
THEN .DIMPTR[ARASIZ] ! ARASIZ chars for character array
ELSE .DIMPTR[ARASIZ] * CHARSPERWORD ! ARASIZ words for numeric array
END !ARRAY
ELSE
BEGIN !SCALAR
IF .SYMPTR[VALTYPE] EQL CHARACTER
THEN .SYMPTR[IDCHLEN] ! IDCHLEN chars for character scalar
ELSE IF .SYMPTR[DBLFLG]
THEN 2 * CHARSPERWORD ! 10 chars for double word numeric
ELSE CHARSPERWORD ! 5 chars for single word numeric
END ! SCALAR
END; ! of SIZEINCHARS
GLOBAL ROUTINE LSTHDR( MINLINE, HDRLINES, HDRPTR) =
![735] THIS ROUTINE PUTS OUT VARIOUS HEADING LINES FOR THE LISTING FILE
![735] AND MAKES SURE THAT THERE IS ROOM FOR THEM ON THE CURRENT LISTING
![735] PAGE. THE PARAMETERS ARE:
![735] MINLINE - THERE MUST BE THIS MANY LINES LEFT ON THE CURRENT
![735] PAGE OR THE NEXT PAGE WILL BE STARTED - THIS MAY INCLUDE
![735] THE FIRST (OR MORE) LINE(S) AFTER THE HEADER.
![735] HDRLINES - THIS IS THE ACTUAL NUMBER OF LINES WHICH ARE
![735] CAUSED TO BE OUTPUT BY THE HEADER ALONE.
![735] HDRPTR - THIS IS A POINTER TO THE ACTUAL MESSAGE TEXT, AN
![735] ASCIZ STRING TO BE PUT INTO THE LISTING.
%[735]% IF .FLGREG<LISTING> THEN
%[735]% BEGIN
%[735]% IF .PAGELINE LEQ .MINLINE
%[735]% THEN %NO ROOM ON THIS PAGE% HEADING();
%[735]% PAGELINE _ .PAGELINE-.HDRLINES;
%[735]% STRNGOUT(.HDRPTR);
%[735]% END; ! of LSTHDR
GLOBAL ROUTINE LISTSYM(PTR)=
BEGIN
MAP BASE PTR;
LABEL BLNK;
R2 _ .PTR[IDSYMBOL];
%2311% % NOTE INSTANCES OF LARGE, NO EXPLICIT DEFINITION %
BLNK:BEGIN
%2311% IF .PTR[VALTYPE] EQL CHARACTER
%2311% THEN
%2311% BEGIN !CHECK FOR LARGE CHARACTER
%2311% IF .PTR[IDPSCHARS] EQL PSLARGE
%2311% THEN ( CHAROUT( "!" ); LEAVE BLNK ); !FLAG IT
%2311% END !CHECK FOR LARGE CHARACTER
%2311% ELSE !CHECK FOR LARGE NUMBERIC
%2311% IF .PTR[IDPSECT] EQL PSLARGE !VARIABLE IN .LARG. ?
%2311% THEN ( CHAROUT( "!" ); LEAVE BLNK ); !YES, FLAG IT
IF NOT .PTR[IDATTRIBUT(INTYPE)]
THEN IF .PTR[OPRSP1] NEQ ARRAYNM1
THEN
IF .R2<30,6> NEQ SIXBIT"." !FORGET COMPLER DEFINED VARS
THEN ( CHAROUT( "*" ); LEAVE BLNK );
CHAROUT( " " );
END; %BLNK%
ZOUTSYM();
CHR _ #11; LSTOUT(); !TAB
%2311% IF .PTR[VALTYPE] NEQ CHARACTER
%2311% THEN
%2311% BEGIN !LIST ADDR FOR NUMERIC
%2311% IF EXTENDED
%2311% THEN
%2311% BEGIN !EXTENDED
%2311% R2 _ .PTR[IDADDR]; !GET NUMERIC ADDR
%2311% ZOUTADDR(); !OUTPUT LONG ADDR
%2311% IF .PTR[IDADDR] LSS 1^21 !TOO SMALL?
%2311% THEN (CHR_#11; LSTOUT()) !ADD A TAB
%2311% END !EXTENDED
%2311% ELSE
%2311% BEGIN !NOT EXTENDED
%2311% R2<LEFT> _ .PTR[IDADDR]; !GET ADDR<RH>
%2311% ZOUTOCT() !OUTPUT 18 BITS
%2311% END !NOT EXTENDED
%2311% END !LIST ADDR FOR NUMERIC
%2311% ELSE
%2311% ZOUTBP(.PTR[IDCHBP]); !IF CHAR, LIST ADDR(POS)
CHR_#11;LSTOUT(); !TAB
END; ! of LISTSYM
ROUTINE SUBPROGLIST=
BEGIN
!
!Lists called subprograms on list device in allocation summary
!
%[735]% LOCAL BASE SYMPTR,COUNT;
%[702]% COUNT_0;
%[735]% HDRFLG _ 0; !No heading line output yet
DECR I FROM SSIZ-1 TO 0 DO
BEGIN
IF (SYMPTR _ .SYMTBL[.I]) NEQ 0
THEN DO BEGIN
!1246 Output function name only if not an inline function.
IF .SYMPTR[OPRSP1] EQL FNNAME1
THEN IF NOT .SYMPTR[IDATTRIBUT(NOALLOC)]
%1264% AND NOT .SYMPTR[IDINLINFLG]
THEN BEGIN
%[702]% IF .COUNT LEQ 0 THEN HEADCHK();
%[735]% IF .HDRFLG EQL 0 THEN
%[735]% BEGIN
%[735]% HDRFLG _ 1;
%[735]% LSTHDR(5,4,PLIT'?M?J?M?JSUBPROGRAMS CALLED?M?J?M?J?0');
%[735]% END;
R2 _ .SYMPTR[IDSYMBOL];
ZOUTSYM();
IF (COUNT _ .COUNT+1) GTR 5
%[702]% THEN (COUNT _ 0; CRLF)
ELSE (C _ #11; LSTOUT());
END;
END WHILE (SYMPTR _ .SYMPTR[CLINK]) NEQ 0;
END;
%[702]% IF .COUNT NEQ 0 THEN CRLF;
END; ! of SUBPROGLIST
ROUTINE ALLSCAA=
BEGIN
! Allocates storage to local scalars and arrays (not in common and not
! in equivalence lists). Searches SYMTBL. Assumes all fixups and
! allocation for common and equivalence have already been done.
! Allocates low seg descriptors for character dummy args. Also
! generates scalar and array section of .LST file for non-character
! data. This is done all at once since scanning the symbol table can
! be slow.
%1232% ! Routine rewritten by TFV, 24-Jun-81
%1232% ! Character data allocation added and block structure fixed up
OWN PTR,SCNT;
%2311% LOCAL HOWIDE; !NUMBER OF SYMBOLS / LISTING LINE
LOCAL BASE ARRAPT;
LABEL L1,L2;
MAP BASE PTR;
ROUTINE LSCHD=
BEGIN
! Outputs lowseg descriptor for character dummy args. IDADDR
! points to descriptor. We init the count word with the
! length unless dummy is length *
LOWLOC _ .LOWLOC + 1; ! Byte pointer to character data copied in at
! subroutine/function entrance; skip a word
! If length *, actual length copied in at subroutine/function
! entrance. Otherwise init the length word in the .REL file.
IF .PTR[IDCHLEN] NEQ LENSTAR AND .FLGREG<OBJECT>
%1526% THEN IF EXTENDED
%1526% THEN ! Use type 1010 blocks
%1526% BEGIN
%1526% DMPMAINRLBF(); ! Storing in different location
! Can't let this get appended
! to a previous type 1010 block
%1526% RDATWD _ .PTR[IDCHLEN]; ! Use declared length
%1526% ZCODE(PSABS,PSDATA); ! Output length to .DATA. using
! code block with no relocation
%1526% DMPMAINRLBF() ! Can't let this get prepended
! to the next type 1010 block
%1526% END
%1526% ELSE ! NOT EXTENDED
BEGIN ! Use type 21 blocks
IF .MAINRLBF[RDATCNT] GTR RBLKSIZ-4
THEN DMPMAINRLBF(); ! No room left in buffer for
! 2 words
RDATWD _ (1^18) + .LOWLOC; ! count,,relocatable address
! of descriptor length word
ZOUTBLOCK(RDATBLK,RELRI); ! Output using sparse data
! block, relocate the
! address
RDATWD _ .PTR[IDCHLEN]; ! Use declared length
ZOUTBLOCK(RDATBLK,RELN); ! Output length to low seg
! using sparse data block
! with no relocation
END;
LOWLOC _ .LOWLOC + 1 ! Increment LOWLOC since we
! outputted or skipped a word
END; ! of LSCHD
%[735]% ROUTINE HDRSAA= ! Routine to output scalar and array banner
%2311% IF EXTENDED
%2311% THEN
%2311% LSTHDR(5,4,PLIT '
?JSCALARS AND ARRAYS [ "*" NO EXPLICIT DEFINITION - "%" NOT REFERENCED ]
?J [ "!" VARIABLE STORED IN .LARG. ]?M?J?M?J?0')
%2311% ELSE
%[735]% LSTHDR(4,3,PLIT '?M?JSCALARS AND ARRAYS [ "*" NO EXPLICIT DEFINITION - "%" NOT REFERENCED ]?M?J?M?J?0');
%2311% IF .FLGREG<LISTING> !IF LISTING
%2311% THEN
%2311% HOWIDE = IF EXTENDED THEN 2 !3 /EXTENDED SYMBOLS / LINE
%2311% ELSE 4; !FIVE OTHERWISE
%[735]% HDRFLG_0;
SCNT_0;
DECR I FROM SSIZ-1 TO 0 DO ! Walk through hash table entries
BEGIN
PTR _ .SYMTBL[.I]; ! Entry for this hash
WHILE .PTR NEQ 0 DO ! Walk down linked list of symbols
BEGIN
IF NOT .PTR[IDATTRIBUT(INCOM)]
AND NOT .PTR[IDATTRIBUT(NAMNAM)]
%1527% AND NOT .PTR[IDATTRIBUT(PARAMT)]
%1455% AND (NOT .PTR[OPERSP] EQL FNNAME OR
%1455% (.PTR[VALTYPE] EQL CHARACTER AND .PTR[IDATTRIBUT(SFN)]))
THEN
! Neither in common, namelist, parameter, nor
! function name. Allocate character statement
! function names.
IF .PTR[IDATTRIBUT(NOALLOC)]
THEN
BEGIN
! Note names which have been declared but never
! referenced and thus never allocated.
! List never allocated character variables also
IF .FLGREG<LISTING>
THEN
BEGIN ! Output symbol to listing with '%'
IF .PTR[OPRSP1] EQL ARRAYNM1
OR .PTR[IDATTRIBUT(INTYPE)]
OR .PTR[IDATTRIBUT(DUMMY)]
THEN
BEGIN ! Declared in dimension, type, or as dummy arg
%[703]% IF .SCNT LEQ 0 THEN HEADCHK();
%[735]% IF .HDRFLG EQL 0
THEN
BEGIN
! Output Scalar and array banner
HDRFLG_1;
HDRSAA();
END;
R2_.PTR[IDSYMBOL];
CHAROUT("%"); ! Flag never referenced with '%'
ZOUTSYM();
CHAROUT(#11); ! Tab
CHAROUT(#11); ! Tab
%2311% IF EXTENDED !/EXTEND?
%2311% THEN CHAROUT(#11); !ONE MORE
%2311% IF .SCNT LSS .HOWIDE
THEN SCNT _ .SCNT+1
ELSE
BEGIN
SCNT _ 0;
CRLF;
END;
END ! Declared in dimension, type, or dummy arg
END ! Output symbol to listing with '%'
END
ELSE
BEGIN
! Symbol is defined and referenced so allocate
! space for it. Not in common, namelist, nor
! function name. Non-dummy character data gets
! allocated in the lowseg; descriptor in hiseg
! Dummy character data gets IDADDR pointing to
! the descriptor in the lowseg.
! Other data has IDADDR pointing to data
IF NOT .PTR[IDATTRIBUT(INEQV)]
! Equivalenced vars are listed but not allocated here
THEN
BEGIN ! Not equivalenced
IF .PTR[VALTYPE] EQL CHARACTER AND NOT .PTR[IDATTRIBUT(DUMMY)]
THEN
! Non-dummy arg character data.
! Byte pointer points to data
! either in the .DATA. psect
! (low segment /NOEXTEND) or in
! the .LARG. psect. Descriptor
! is allocated in high seg
! after hisg seg is inited.
%2232% PTR[IDCHBP] = BPGEN(.PSECTS[.PTR[IDPSCHARS]])
ELSE
! Dummy character data get descriptor
! allocated to lowseg and pointed to
! by IDADDR. Other data types get
! IDADDR pointing to low seg data
! under /NOEXTEND or the .DATA. or
! .LARG. psect under /EXTEND.
%2232% PTR[IDADDR] _ .PSECTS[.PTR[IDPSECT]];
IF .PTR[OPRSP1] EQL ARRAYNM1
THEN
BEGIN
! Arrays
ARRAPT _ .PTR[IDDIM]; ! Ptr to dimension node
IF .PTR[IDATTRIBUT(DUMMY)]
THEN
BEGIN
! Dummy array arg
IF NOT .ARRAPT[ADJDIMFLG] AND .PTR[VALTYPE] NEQ CHARACTER
THEN
BEGIN
! Non-adjustably dimensioned
! Non-character dummy
! arrays get pointer
! to base address for array
LOCAL BASE PTRVAR;
PTRVAR _ .ARRAPT[ARADDRVAR];
PTRVAR[IDADDR] _ .LOWLOC;
END;
IF .PTR[VALTYPE] EQL CHARACTER
THEN
! Output low seg descriptor for
! character dummy arrays
LSCHD()
ELSE
! allocate space for base address
! for non-character dummy array
LOWLOC _ .LOWLOC + 1;
END
ELSE
BEGIN
! Non-dummy arrays are allocated in the low seg under
! /NOEXTEND or in the .DATA. or .LARGE. psects under
! /EXTEND. Character data size is in characters, others
! are in words
IF .PTR[VALTYPE] EQL CHARACTER
%2232% THEN PSECTS[.PTR[IDPSCHARS]] _ .PSECTS[.PTR[IDPSCHARS]]
+ CHWORDLEN(.ARRAPT[ARASIZ])
%2232% ELSE PSECTS[.PTR[IDPSECT]] _ .PSECTS[.PTR[IDPSECT]]
+ .ARRAPT[ARASIZ];
END
END ! Arrays
ELSE
BEGIN
! Scalars
IF .PTR[VALTYPE] EQL CHARACTER
THEN
BEGIN
! Character scalar
IF .PTR[IDATTRIBUT(DUMMY)]
THEN
BEGIN
! Output low seg descriptor
! for character dummy scalars.
! Only output descriptor for
! the main entry point for multi-entry
! character functions
%1434% IF NOT .PTR[IDATTRIBUT(FENTRYNAME)] OR
%1434% .PTR[IDSYMBOL] EQL .PROGNAME
%1434% THEN LSCHD()
END
ELSE
! Non-dummy character scalars are allocated in the
! low seg./NOEXTEND or in the .DATA. or .LARG.
! psect/EXTEND. Character data size is in
! characters
%2232% PSECTS[.PTR[IDPSCHARS]] _ .PSECTS[.PTR[IDPSCHARS]]
+ CHWORDLEN(.PTR[IDCHLEN]);
END ! Character scalar
ELSE
BEGIN ! Non-character scalar
! Output one or two words based on variable size
IF .PTR[DBLFLG]
THEN PSECTS[.PTR[IDPSECT]] _ .PSECTS[.PTR[IDPSECT]] + 2
ELSE PSECTS[.PTR[IDPSECT]] _ .PSECTS[.PTR[IDPSECT]] + 1;
END; ! Non-character scalar
END; ! Scalars
END; ! Not equivalenced
IF .FLGREG<LISTING> AND .PTR[VALTYPE] NEQ CHARACTER
THEN
BEGIN
! List non-character scalars and arrays
%[703]% IF .SCNT LEQ 0 THEN HEADCHK();
%[735]% IF .HDRFLG EQL 0
THEN
BEGIN
! Output scalar and array banner
HDRFLG_1;
HDRSAA();
END;
%[703]% LISTSYM(.PTR);
%2311% IF .SCNT LSS .HOWIDE
THEN SCNT_.SCNT+1
ELSE
BEGIN
SCNT_0;
CRLF;
END;
END; ! List non-character scalars and arrays
END; ! Symbol is defined and referenced so allocate space for it.
PTR _ .PTR[CLINK]; ! Next linked list entry
END; ! Walk down linked list
END; ! Walk through hash table entries
%[703]% IF .FLGREG<LISTING> THEN IF .SCNT NEQ 0 THEN CRLF;
ENDSCAA_.LOWLOC; !LOC AFTER LAST ARRAY/SCALAR
END; ! of ALLSCAA
!***********************************************************************
! The routines in this module are for the purpose of generating the
! following things:
!
! The correct allocation of addresses to the variables, arrays
! constants, strings etc., in the subprogram being compiled.
!
! The statistics listing of the scalars, arrays, common,
! constants, temporaries etc. that the subprogram defines.
!***********************************************************************
! EQUIVALENCE processing
!***********************************************************************
! EQUIVALENCE processing is rather hairy to describe. The following description
! of the problem is adapted from Aho and Ullman, Principles of Compiler Design.
! (The algorithm is the not from that book, however.)
!
!
! The first algorithms for processing equivalence statements appeard in
! assemblers rather than compilers. Since these algorithms can be a bit
! complex, especially when interactions between COMMON and EQUIVALENCE
! statements are considered, let us treat first a situation typical of an
! assembly language, where the only EQUIVALENCE statements are of the form
!
! EQUIVALENCE A,B+offset
!
! where A and B are the names of locations. The effect of this statement is to
! make A denote the location which is OFFSET memory units beyond the location
! for B.
!
! A sequence of EQUIVALENCE statements groups names into equivalence sets whose
! positions relative to one another are all defined by the EQUIVALENCE
! statements. For example, the sequence of EQUIVALENCE statements
!
! EQUIVALENCE A,B+100
! EQUIVALENCE C,D-40
! EQUIVALENCE A,C+30
! EQUIVALENCE E,F
!
! groups names into the sets {A,B,C,D} and {E,F}. E and F denote the same
! location. C is 70 locations after B; A is 30 after C and D is 10 after A.
!
! 0 70 100 110
! ------------------------------------------------------------
! ! !
! ------------------------------------------------------------
! B C A D
!
! To compute the equivalence sets we represent each set as a linked list. We
! then look for variables which occur in more than one set and combine the sets.
! This is repeated until we get a collection of disjoint equivalence classes.
!
! In the above example, we start with
!
! {A,B+100}
! {C,D-40}
! {A,C+30}
! {E,F}
!
! First notice that A appears in the first and third sets. Combine these to
! give
!
! {A,B+100,C+30}
! {C,D-40}
! {E,F}
!
! Now C occurs in the first and second sets. If C = D-40 then C+30 = D-10 so we
! get
!
! {A,B+100,C+30,D-10}
! {E,F}
!
! These sets are disjoint, so we're done.
!
! The last union contains the calculation "if C=D-40 then C+30=D-10". In
! general, this situation occurs when the offsets in the first set are from one
! variable, A, and the offsets in the second set are from a different variable,
! C. We must first rewrite the offsets in the second set so that everything is
! in terms of A. In the terminology used by the compiler, each set has a
! "head", the first element in the set. The offsets in the set are offsets from
! the head. When we union two sets, we must rewrite the offsets in one set in
! terms of the head of the other set.
!
! There are several additional features that must be appended to this algorithm
! to make it work for FORTRAN. First, we must determine whether an equivalence
! set is in COMMON, which is true if any variable in the set has been declared
! in a COMMON statement. Second, in an assembly language, one member of an
! equivalence set will pin down the entire set to reality by being a label of a
! statement, thus allowing the addresses denoted by all names in the set to be
! computed relative to that one location. In Fortran, however, it is the
! compiler's job to determine storage locations, so an equivalence set not in
! COMMON may be viewed as "floating" until the compiler determines the position
! of the whole set. To do so correctly, the compiler needs to know the extent
! of the equivalence set, that is, the number of locations which the names in
! the set collectively occupy. To handle this problem we attach to each set two
! fields, LOW and HIGH, giving the offsets relative to the leader of the lowest
! and highest locations used by any member of the equivalence set.
!
! When we merge two sets containing the same variable, we must compute LOW and
! HIGH for the merged set.
!
!
! LOW1 HIGH1
! ------------------------------------------------------------
! ! X !
! ------------------------------------------------------------
! ^
! ^
! ------------------------------------------------------------
! ! X !
! ------------------------------------------------------------
! LOW2 HIGH2
!
! LOW = min(LOW1,LOW2+offs) HIGH = max(HIGH1,HIGH2+offs)
!
! where offs is the number added to the offsets of set 2 to convert them from
! being relative to the set 2 head to being relative to the set 1 head.
!
!
! In the compiler, there are several additional little whizzies to make life
! interesting. For variables in COMMON, the offsets aren't allowed to go
! negative, so the algorithms all have to be careful that the head of each set
! is the element of the set with the lowest address.
!
! As usual, the compiler data structures contain several fields which change
! meaning dynamically as the code goes from place to place. A summary of most
! of the relevant fields follows.
!
! All offsets and lengths are calculated in characters. (There are 5 characters
! per word. Address 0 contains characters 0-4, address 1 contains characters
! 5-9, and so on.) These character addresses are converted back to word
! addresses at the very end.
!
! Equivalence group node, one for each parenthesized list in an EQUIVALENCE stmt
!
! (The complete list of this fields can be found in FIRST.)
!
! EQVHEAD pointer to equiv list node of head of set
! EQVFIRST pointer to equiv list node of first element of set
! EQVLAST pointer to equiv list node of last element of set
! EQVADDR character displacement of class head from 0, like LOW above
! EQVLIMIT like HIGH above (chars required to allocate storage for the
! class is EQVLIMIT-EQVADDR)
! EQVALIGN contains 0 if this group can start on any byte in a word,
! or 1-5 if the group must start on that byte in order for the
! numeric variables in the group to land on word boundaries
! when addresses are assigned.
!
! Equivalence list node, one for each element of an equivalence group
!
! EQLID pointer to symbol table entry of identifier
! EQLDISPL character displacement of this symbol from group head
!
!
! Things are organized so that, after all the calculations are complete and the
! dust settles, the address to be assigned to a name is EQLDISPL + the address
! of the equivalence class. EQVADDR is set to the minimum EQLDISPL in the
! class. Thus, to actually allocate storage for a class, EQVLIMIT-EQVADDR chars
! are allocated, a variable (TLOC) is set to LOWLOC-EQVADDR, and then the
! address of each variable is given by TLOC + EQLDISPL.
!
!
!***********************************************************************
! Organization of common/equivalence processing:
!
!
! ALLOCAT is the driver routine. It calls PROCCOM, PROCEQUIV, ALLCOM.
!
! PROCCOM goes through the COMMON statements and assigns addresses to each
! variable that is explicitly declared in COMMON.
!
! PROCEQUIV goes through the EQUIVALENCE statements and
! - finds groups that are in COMMON because one of their members is declared
! in common. Sets EQVINCOM flag in such groups. [using GRPSCAN]
! - sets EQLDISPL for array elements to the word offset from the base address
! of the array to the given element. EQLDISPL for non-array elements is 0.
! - sets EQVLIMIT to max(EQVLIMIT,EQLDISPL+ARASIZ) where ARASIZ is the declared
! size of the array or 1 (or 2) for scalars
! - sets LCLHD to {either the (unique?) element of the group declared in common
! or} the one with the minimum EQLDISPL. At this point, EQLDISPL is the
! offset from the start of the array.
! - if the group contains a symbol declared in COMMON, check all other symbols
! to see that if they are also declared in common that they are in the same
! block and have the same offset. If they are not also declared in common,
! declare them in the same COMMON block as the equivalenced variable. Add
! them to the linked list of variables in the common block. Give them all the
! same IDADDR (offset from start of common) field.
! - Set in the group node: EQVADDR = min(EQLDISPL) over the group, EQVHEAD =
! symbol with the min EQLDISPL, EQVLIMIT = number of words in group
! - finds variables which occur in more than group and unions the groups
! together into classes. [ELISTSRCH] When two groups are found which
! contain the same variable, one of them is chosen to be a "class", ie, the
! one that gets the other unioned into it. The one that is the "class" has
! a magic field, EQVAVAIL, set to EQVCLASS. The one that remains a group
! has EQVAVAIL set to EQVIGNORE. At the end of this processing, the groups
! with EQVAVAIL = EQVCLASS are the ones that contain all the info from all
! the equivalence statements.
! - call EQCALLOC to allocate the classes
!
! ALLCOM is misnamed; it doesn't allocate anything but does print the common
! block info on the listing. It also converts all of the common block offsets
! from characters to words.
ROUTINE ALLOCAT=
BEGIN
!***********************************************************************
! Allocates relative addresses to all variables and storage in the low
! segment, except temporaries which are allocated after code generation.
!
! This routine controls the allocation by calling the actual routines
! that do the allocation and processing of variables, common blocks,
! equivalence groups, data fixups etc.
!***********************************************************************
%2507% ! Output warning messages for any symbols not declared in type
%2507% ! statements that should be and haven't gottten warning messages
%2507% ! yet. This catches unallocated variables (which haven't been
%2507% ! referenced). We do this here, since we want the messages before
%2507% ! other things in the listing, such as EQUIVALENCE and COMMON
%2507% ! tables.
%2507% IF .IMPNONE THEN CIMPLNONE();
%2233% PROCCOM(); ! Compute size of each COMMON block
IF .EQVPTR NEQ 0 THEN PROCEQUIV(); ! Process equivalence groups
%2233% IF .COMBLKPTR NEQ 0 ! If we have common,
%2346% THEN ALLCOM(); ! allocate it now
! Now allocate and list all variables, arrays etc. List
! subprograms called, if any
IF .FLGREG<LISTING> THEN SUBPROGLIST();
ALLSCAA(); ! Allocate scalars and arrays
END; ! of ALLOCAT
GLOBAL ROUTINE ALLCOM=
!++
! FUNCTIONAL DESCRIPTION:
!
! Allocates relative addresses to all variables declared in
! COMMON, and computes the total size of all COMMON blocks. The
! type 20 (RCOMMON) REL blocks will be output to the REL file
! with the COMMON blocks grouped together by psect.
!
! FORMAL PARAMETERS:
!
! None
!
! IMPLICIT INPUTS:
!
! F2<EXTENDFLAG> True if program is compiled with /EXTEND.
!
! FLGREG<OBJECT> True if an object file is being generated.
!
! LCOMP True if there are large COMMON blocks.
!
! SAVALL True if a SAVE without arguments was seen.
!
! SCOMP True if there are small COMMON blocks.
!
! IMPLICIT OUTPUTS:
!
! LCOMSZ Updated sum of sizes of large common blocks.
!
! NUMSAVCOMMON Number of COMMON blocks that need to be saved.
! (SAVALL causes this to be recomputed).
!
! RDATWD Smashed by object file I/O.
!
! SCOMSZ Updated sum of sizes of small common blocks.
!
! ROUTINE VALUE:
!
! None
!
! SIDE EFFECTS:
!
! Outputs type 22 (RPSECTORG) REL blocks to the object file.
! Also, outputs headers to the listing file.
!
!--
![2356] Rewritten for support of COMMON blocks in different psects
BEGIN
%1511% ! If bare SAVE, then zero count. May have specified non-bare
%1511% ! COMMON, and that would mess up our count.
%1511% IF .SAVALL
%1511% THEN NUMSAVCOMMON = 0;
%2356% IF .LCOMP ! Large COMMONs?
%2311% THEN LSTHDR(5,3, ! Yes, print larger legend
%2311% PLIT'?M?JCOMMON BLOCKS [ "!" STORED IN .LARG. ]?M?J?0')
%735% ELSE LSTHDR(5,3,PLIT'?M?JCOMMON BLOCKS?M?J?0');
! Set the default psect before we define the COMMON blocks.
! LINK will allocate COMMON blocks in the default psect when
! reading a psected REL file.
IF .SCOMP ! Are there any small COMMON blocks?
THEN ! Yes, process them
BEGIN ! Small
%1630% IF .FLGREG<OBJECT> ! Object file ?
%2357% AND EXTENDED ! and /EXTEND?
%1615% THEN ! Yes, have to set default psect
%1615% BEGIN ! OBJECT
%1615% RDATWD = PXDATA; ! Select .DATA.
%1615% ZOUTBLOCK(RPSECTORG,RELN); ! Psect index rel block
%1615% END; ! OBJECT
%2346% SCOMSZ = ALCCOMMON(PSDATA); ! Allocate small COMMON blocks
END; ! Small
IF .LCOMP ! Are there any large COMMON blocks?
THEN ! Yes, process them
BEGIN ! Large
IF .FLGREG<OBJECT> ! Object file ?
%2357% AND EXTENDED ! and /EXTEND?
THEN ! Yes, have to set default psect
BEGIN ! OBJECT
RDATWD = PXLARGE; ! Select .LARG.
ZOUTBLOCK(RPSECTORG,RELN);
END; ! OBJECT
%2346% LCOMSZ = ALCCOMMON(PSLARGE); ! Allocate large COMMON blocks
END; ! Large
END; ! of ALLCOM
GLOBAL ROUTINE ALCCOMMON(PSECT)=
!++
! FUNCTIONAL DESCRIPTION:
!
! Assigns relative addresses to all COMMON variables declared in
! a given psect. Outputs the block sizes to the object and
! listing files. Also lists the names and offsets of the
! variables. Totals the sizes of the COMMON blocks.
!
! The addresses of the variables and arrays in a COMMON block
! are relative to the beginning of the block in which they are
! declared. Each block has an origin of zero. At load time the
! loader will assign actual locations to COMMON blocks based on
! their order of appearance to LOADER. In the relocatable
! binary, references to COMMON variables will use additive
! global fixups.
!
! FORMAL PARAMETERS:
!
! PSECT Psect that is undergoing COMMON allocation.
!
! IMPLICIT INPUTS:
!
! COMBLKPTR Pointers to first and last COMMMON blocks.
! Many of the fields are used in this routine.
!
! F2<EXTENDFLAG> True if program is compiled with /EXTEND.
!
! FLGREG<LISTING> True if a listing file is being generated.
!
! FLGREG<OBJECT> True if an object file is being generated.
!
! NUMSAVCOMMON Number of COMMON blocks in SAVE statements.
!
! SAVALL True if a SAVE without arguments was seen.
!
! IMPLICIT OUTPUTS:
!
! CHR (C) Smashed during listing file I/O.
!
! COMBLOCK[COMSIZE] COMMON block gets its size converted from
! units of characters to words.
!
! ISN Smashed during compatibility flagging
!
! NUMSAVCOMMON Updated number of COMMON blocks in SAVE statements.
!
! R1, R2 Smashed during listing file I/O.
!
! RDATWD Smashed during object file I/O.
!
! ROUTINE VALUE:
!
! Total number of words used for COMMON in the given psect.
!
! SIDE EFFECTS:
!
! Outputs type 20 (RCOMMON) REL blocks to the object file.
! Also, outputs COMMON block information to the listing file.
!
!--
![2356] Added for support of COMMON blocks in different psects
BEGIN
REGISTER
BASE CCOMPTR, ! Runs through list of COMMONs
BASE CSYMPTR, ! Runs through IDCOLINK variable list
ICNT; ! Listing column counter
LOCAL
%1261% FLAGWRD, ! Contains flags defined below
TOTAL; ! Total size of COMMONs in this psect
BIND
%1261% CHARSEEN = FLAGWRD<0,1>, ! Block contains CHARACTER data
%1261% NUMSEEN = FLAGWRD<1,1>; ! Block contains numeric data
TOTAL = 0; ! No COMMONs allocated yet
CCOMPTR = .FIRCOMBLK; ! Pointer to first COMMON block
%2235% WHILE .CCOMPTR NEQ 0 ! Loop over all COMMON blocks
DO
BEGIN ! CCOMPTR NEQ 0
IF .CCOMPTR[COMPSECT] EQL .PSECT ! In the right psect?
THEN ! Yes
BEGIN ! [COMPSECT] EQL .PSECT
! First, process the COMMON block itself
%1511% ! Bare SAVE statement. Save the number of
%1511% ! COMMONs processed for later output of the
%1511% ! rel block.
%1511% IF .SAVALL
%1531% THEN NUMSAVCOMMON = .NUMSAVCOMMON + 1;
%1261% ! Convert COMSIZE back to words
%2346% CCOMPTR[COMSIZE] = CHWORDLEN(.CCOMPTR[COMSIZE]);
TOTAL = .TOTAL+.CCOMPTR[COMSIZE]; ! Total blocks
IF .FLGREG<LISTING> ! Output name of block
THEN
BEGIN ! LISTING
CRLF;
HEADCHK();
CHAROUT("/");
R2 = .CCOMPTR[COMNAME];
ZOUTSYM();
CHAROUT("/");
CHAROUT("(");
R1 = .CCOMPTR[COMSIZE];
ZOUOFFSET();
%2356% IF .PSECT EQL PSLARGE ! COMMON in .LARG.?
%2311% THEN CHAROUT("!"); ! Flag as such
CHAROUT(")");
CRLF;
HEADCHK();
%2346% ICNT = 0;
END; ! LISTING
IF .FLGREG<OBJECT> ! Relocatable binary?
THEN ! Yes, necessary
BEGIN ! OBJECT
R2 = .CCOMPTR[COMNAME]; ! For radix 50
RDATWD = RGLOBDEF+RADIX50(); ! conversion
ZOUTBLOCK(RCOMMON,RELN);
RDATWD = .CCOMPTR[COMSIZE];
ZOUTBLOCK(RCOMMON,RELN);
END; ! OBJECT
! Next, process all the variables in the COMMON block
%1261% FLAGWRD = 0; ! Clear CHARSEEN and NUMSEEN
%1261% CSYMPTR = .CCOMPTR[COMFIRST]; ! Point to first symbol
%1261% DO ! in COMMON block
%1261% BEGIN ! CSYMPTR NEQ NIL
%1261%
%1261% ! Convert IDADDR from characters to words
%1261%
%1261% IF .CSYMPTR[VALTYPE] NEQ CHARACTER
%1261% THEN
%1261% BEGIN ! NUMERIC
%1261% NUMSEEN = 1;
%1261% ! Must be word aligned
%1261% IF .CSYMPTR[IDADDR] MOD CHARSPERWORD
%1261% NEQ 0
%1261% THEN FATLERR(.CSYMPTR[IDSYMBOL],
%1261% E167<0,0>);
%1261% ! Convert character address
%1261% ! to word address
%1261% CSYMPTR[IDADDR] =
%1261% .CSYMPTR[IDADDR]/CHARSPERWORD;
%2356% CSYMPTR[IDPSECT] = .PSECT;
%1261% END ! NUMERIC
%1261% ELSE
%1261% BEGIN ! CHARACTER
%1261% CHARSEEN = 1;
%1261% ! Convert char address to byte
%1261% ! pointer and clear IDADDR,
%1261% ! which will be used for
%1261% ! address of descriptor
%1261% CSYMPTR[IDCHBP] =
%1261% CHADDR2BP(.CSYMPTR[IDADDR]);
%1261% CSYMPTR[IDADDR] = 0;
%2356% CSYMPTR[IDPSCHARS] = .PSECT;
%1261% END; ! CHARACTER
! Now list the symbol
IF .FLGREG<LISTING>
THEN
BEGIN ! LISTING
%2311% LOCAL HOWIDE; ! Symbols / line
%2311% HOWIDE = IF EXTENDED ! /EXTEND?
%2311% THEN 3 ! Only 3 fit
%2311% ELSE 5; ! 5 like good ole days
R2 = .CSYMPTR[IDSYMBOL];
ZOUTSYM(); ! Output the name
CHAROUT("?I"); ! Tab
%1261% IF .CSYMPTR[VALTYPE] NEQ CHARACTER
THEN
%2311% BEGIN ! NUMERIC
%2311% R1 = .CSYMPTR[IDADDR];
%2311% ZOUOFFSET();
%2311% IF EXTENDED
%2311% THEN IF .CSYMPTR[IDADDR]
%2311% LSS #1^18
%2311% THEN CHAROUT("?I"); ! Tab
%2311% END ! NUMERIC
%1261% ELSE
%2311% BEGIN ! CHARACTER
CHAROUT("+");
! List the byte pointer
ZOUTBP(.CSYMPTR[IDCHBP]);
%2311% IF EXTENDED
%2330% THEN IF .CSYMPTR[IDCHBP]
<OWGBPADDR>
%2330% LSS #1000
%2311% THEN CHAROUT("?I"); ! Tab
%2311% END; ! CHARACTER
ICNT = .ICNT+1;
%2311% IF .ICNT EQL .HOWIDE ! Enough on
THEN ! this line?
BEGIN ! EQL HOWIDE
ICNT = 0; ! New line
CRLF;
HEADCHK();
END ! EQL HOWIDE
ELSE CHAROUT("?I"); ! No, tab over
END; ! LISTING
CSYMPTR = .CSYMPTR[IDCOLINK];
%1261% END ! CSYMPTR NEQ 0
%1261% WHILE .CSYMPTR NEQ 0; ! Loop through all symbols in
! this COMMON block
! If doing any compatibility checking,
! complain if block contains both character &
! numeric variables
%2271% IF FLAGEITHER
%2271% THEN IF .CHARSEEN AND .NUMSEEN
%2271% THEN
%2271% BEGIN ! MIXED
%2271% ISN=0; ! Call flagger with no line number
%2271% CFLAGB(UPLIT 'mixed in COMMON?0',E168<0,0>)
%2271% END; ! MIXED
IF .FLGREG<LISTING> ! Listing file?
THEN ! Yes, finish up COMMON block
BEGIN ! LISTING
CRLF; ! Be sure to output CRLF after
HEADCHK(); ! last COMMON block name
END; ! LISTING
END; ! [COMPSECT] EQL .PSECT
%2235% CCOMPTR = .CCOMPTR[NEXCOMBLK] ! Loop until all blocks seen
%2235% END;
RETURN .TOTAL; ! Return amount of space in COMMON
END; ! of ALCCOMMON
GLOBAL ROUTINE DMPFORMAT = ![2210]
BEGIN
![1424] Rewritten by RVM on 19-Nov-81
%(**********************************************************************
This routine allocates address to formats and dumps the formats
preceded by their size words to the .REL file (if there is a .REL
file). Formats are allocated after all other low segment data.
Note that this routine should be called after the optimizer has
done its work. This routine does setup the values in the label
table entries for the format labels. This conflicts with the
optimizer, who thinks it can freely use the fields in the label
table for its own use.
After the routine is called, LOWLOC is the address of the first
word not used in the low segment.
**********************************************************************)%
%1454% REGISTER RELFILE, BASE FORMAT, BASE STMTLABEL;
!(*** Get pointer to first format in the linked list of formats ***)
FORMAT = .FORMPTR<LEFT>;
%1454% !(*** Get the flag that tells if we need a .REL file ***)
%1454% RELFILE = .FLGREG<OBJECT>;
%1454% !(*** Dump out the code block immediately ***)
%1454% IF .RELFILE THEN DMPMAINRLBF();
!(*** Loop until the end of the linked list of formats is reached ***)
WHILE .FORMAT NEQ 0
DO
BEGIN !Loop through linked list of all formats
%1454% !(*** Fill in the address word of the FORMAT entry with ***)
%1454% !(*** the address of the format text. ***)
%1454% !(*** Then fill in the label table entry for the format ***)
%1454% !(*** label. ***)
%1454% STMTLABEL = .FORMAT[SRCLBL];
%1526% STMTLABEL[SNADDR] = FORMAT[FORADDR] = .LOWLOC + 1;
%1454% STMTLABEL[SNDEFINED] = TRUE; !* Label is defined
%1454% STMTLABEL[SNSTATUS] = OUTPBUFF; !* Label is nailed down
%1454% !(*** Now, if there is a .REL file, dump the format ***)
%1454% IF .RELFILE
%1454% THEN
%1454% BEGIN
RDATWD = .FORMAT[FORSIZ]; ! Fetch size word
%1526% ZCODE(PSABS,PSDATA); ! Output it
%1526% LOWLOC = .LOWLOC+1; ! Point to next word
!(*** Loop to dump the format string ***)
INCR I FROM 0 TO .FORMAT[FORSIZ] - 1
DO
BEGIN !Dump FORMAT string
RDATWD = @(.FORMAT[FORSTRING])[.I];
%1526% ZCODE(PSABS,PSDATA);
%1526% LOWLOC = .LOWLOC + 1
END; ! of dump the format string
%1454% END ! of dump FORMAT to .REL file
%1526% ELSE LOWLOC = .LOWLOC + .FORMAT[FORSIZ] + 1; !* Bump LOWLOC
!(*** Get next format in linked list ***)
FORMAT = .FORMAT[FMTLINK];
END; ! of loop through linked list of all formats
%1454% !(*** Dump out the code block immediately. ***)
%1454% IF .RELFILE THEN DMPMAINRLBF()
END; ! of DMPFORMAT ![2210]
ROUTINE PROCCOM=
BEGIN
!***********************************************************************
! Makes a pass through the linked lists of COMMON blocks and
! associated symbol table entries computing the declared size of each
! block and assigning a temporary address to the variables in each
! block relative to the beginning of the block.
!***********************************************************************
REGISTER
CBLKSIZ, ! Size of current COMMON block
BASE CCOMPTR: ! Pointer to current COMMON block
CSYMPTR; ! Pointer to current STE
XTRAC;
CCOMPTR = .FIRCOMBLK; ! Pointer to first COMMON block
WHILE .CCOMPTR NEQ 0 DO ! Loop on list of COMMON blocks
BEGIN
CBLKSIZ = 0; ! Clear size of this COMMON block
CSYMPTR = .CCOMPTR[COMFIRST]; ! Get first STE in COMMON block
WHILE .CSYMPTR NEQ 0 ! Loop on list of symbols in block
DO
BEGIN
! If numeric (non-character) variables are encountered, place the
! start of the variable on a word boundary by rounding the offset up
! to be a multiple of 5 characters.
%1261% IF .CSYMPTR[VALTYPE] NEQ CHARACTER ! Numeric variable?
%1261% THEN CBLKSIZ = CHWORDLEN(.CBLKSIZ)*CHARSPERWORD;
! Yes, round up
! 500 Washington St, Hoboken
! A taste treat that can't be beat
%1261% CSYMPTR[IDADDR] = .CBLKSIZ; ! Set offset of this variable
%1261% CBLKSIZ = .CBLKSIZ + SIZEINCHARS(.CSYMPTR);
%1261% ! Increment offset by size of this variable
CSYMPTR = .CSYMPTR[IDCOLINK] ! Point to next variable
END; ! Loop back for more variables
CCOMPTR[COMSIZE] = .CBLKSIZ; ! Save the size of this common block
CCOMPTR = .CCOMPTR[NEXCOMBLK] ! Point to the next common block
END; ! Loop back for more common blocks
END; ! of ROUTINE
ROUTINE EQERRLIST(GROUP)=
BEGIN
!***********************************************************************
! Error routine to list the group of EQUIVALENCE variables in conflict.
!***********************************************************************
MAP BASE GROUP:R2;
LOCAL BASE SYMPTR;
%1146% FATLERR(.GROUP[EQVISN],E49<0,0>); !SAME MSG AS BELOW
IF NOT .FLGREG<LISTING> THEN RETURN;
HEADCHK();
STRNGOUT(PLIT '?M?J CONFLICTING VARIABLES( ?0');
SYMPTR _ .GROUP[EQVFIRST];
WHILE 1 DO
BEGIN
R2 _ .SYMPTR[EQLID]; ! Symbol table entry
R2 _ .R2[IDSYMBOL]; ! SIXBIT value of id
ZOUTSYM();
IF (SYMPTR _ .SYMPTR[EQLLINK]) EQL 0
THEN
BEGIN ! End of the symbols
STRNGOUT(PLIT')?M?J');
HEADCHK();
EXITLOOP
END
ELSE
BEGIN ! More symbols to come
C _ ",";
LSTOUT()
END;
END;
END; ! of EQERRLIST
ROUTINE GROUPTOCOMMON(COMSYM,NEWGRP,ELIM,GRPDISPL)=
BEGIN
!COMSYM POINTS TO SYMBOL ALREADY IN COMMON
!NEWGRP POINTS TO NEW EQV GROUP GOING TO COMMON
!ELIM IS THE EQVLIMIT OF GROUP TO WHICH COMSYM BELONGS
!GRPDISPL IS THE DISPLACEMENT OF THE MATCH ITEM IN NEWGRP
!
MAP BASE COMSYM :NEWGRP;
LOCAL BASE COMBLPTR :LASCOMSYM :DIMPTR :NEWSYM :NEWITEM;
LOCAL SYMSIZ;
NEWITEM _ .NEWGRP[EQVFIRST]; !FIRST ITEM IN NEW GROUP
WHILE 1 DO
BEGIN
NEWSYM _ .NEWITEM[EQLID]; !PTR TO SYMBOL TABLE NODE
IF .COMSYM NEQ .NEWSYM
THEN IF NOT .NEWSYM[IDATTRIBUT(INCOM)]
THEN
BEGIN
IF (NEWSYM[IDADDR] _ .COMSYM[IDADDR] + .NEWITEM[EQLDISPL] - .GRPDISPL) LSS 0
THEN
BEGIN
COMBLPTR _ .COMSYM[IDCOMMON];
RETURN FATLERR(COMBLPTR[COMNAME],.ISN,E33<0,0> );
END;
%1511% ! Give error if this symbol is in SAVE, can't also be in
%1511% ! COMMON
%1511% IF .NEWSYM[IDSAVVARIABLE]
%1511% THEN FATLERR(.NEWSYM[IDSYMBOL],
%1531% .ISN,E197<0,0>);
NEWSYM[IDATTRIBUT(INCOM)] _ 1; !PUT SYMBOL INCOMMON
COMBLPTR _ .COMSYM[IDCOMMON];
LASCOMSYM _ .COMBLPTR[COMLAST]; !LAST SYMBOL IN COMMON BLOCK
LASCOMSYM[IDCOLINK] _ .NEWSYM; !POINT TO NEW SYMBOL
NEWSYM[IDCOLINK] _ 0;
NEWSYM[IDCOMMON] _ .COMBLPTR; !SYMBOL POINTS TO COMMON BLOCK
COMBLPTR[COMLAST] _ .NEWSYM;
SYMSIZ _ IF .NEWSYM[IDDIM] NEQ 0
THEN (DIMPTR _ .NEWSYM[IDDIM]; .DIMPTR[ARASIZ])
ELSE IF .NEWSYM[DBLFLG] THEN 2 ELSE 1;
IF (.NEWITEM[EQLDISPL] + .SYMSIZ) GTR .ELIM
THEN ELIM _ (.NEWITEM[EQLDISPL] + .SYMSIZ);
IF .COMBLPTR[COMSIZE] LSS ( .NEWSYM[IDADDR] + .SYMSIZ)
THEN
COMBLPTR[COMSIZE] _ (.NEWSYM[IDADDR] + .SYMSIZ);
END
ELSE IF (.NEWSYM[IDADDR] - .NEWITEM[EQLDISPL])
NEQ (.COMSYM[IDADDR] - .GRPDISPL)
THEN ( EQERRLIST(.NEWGRP);
%2235% NEWGRP[EQVAVAIL] _ EQVERROR; RETURN -1
);
IF .NEWITEM[EQLLINK] EQL 0
THEN RETURN .ELIM
ELSE NEWITEM _ .NEWITEM[EQLLINK];
END; !OF WHILE 1
END; ! of GROUPTOCOMMON
ROUTINE LINKGROUPS(GROUP1,GROUP2,G1SYM)=
BEGIN
!***********************************************************************
!Link equivalence items in GROUP2 into GROUP1 when either group is in
!COMMON to allow for further searching of GROUP1 by later groups.
!***********************************************************************
MAP BASE GROUP1 :GROUP2 :G1SYM;
LOCAL BASE G1ITEM, ! List item in group 1
BASE G2ITEM, ! List item in group 2
BASE NEXG2ITEM; ! Next item in group 2
G2ITEM _ .GROUP2[EQVFIRST]; ! First GROUP2 list
WHILE 1 DO
BEGIN ! Each GROUP2 list
NEXG2ITEM _ .G2ITEM[EQLLINK]; ! Save next symbol in list
IF .G1SYM NEQ .G2ITEM[EQLID] ! Symbols equal
THEN
BEGIN ! Make this the last list in GROUP1.
G1ITEM _ .GROUP1[EQVLAST];
G1ITEM[EQLLINK] _ .G2ITEM;
GROUP1[EQVLAST] _ .G2ITEM;
G2ITEM[EQLLINK] _ 0;
END;
IF (G2ITEM _ .NEXG2ITEM) EQL 0 THEN RETURN .VREG;
END; ! Each GROUP2 list
END; ! of LINKGROUPS
ROUTINE ELISTSRCH(ECLASS,EGROUP)=
BEGIN
!***********************************************************************
! Tries to find overlap in the equivalence groups ECLASS and EGROUP.
! Searches each item in group EGROUP against all items in group ECLASS.
! If a match is found, links items in EGROUP into ECLASS, if neither
! EGROUP nor ECLASS is in COMMON. If either (but not both) are in
! common then add new items not in common into common block of which
! ECLASS or EGROUP items are members. Errors occur if both ECLASS and
! EGROUP are in common.
! Returns:
! 1 Successful, match found.
! 0 Unsuccessful.
! <0 Error in processing, illegal condition found.
%1511% ! Massive reformatting and indenting
%2235% LABEL ELIS1;
LOCAL EGSYM, !SYMBOL BEING SEARCHED IN GROUP
EGSYMPTR, !PTR TO SYMBOL TABLE OF SYMBOL BEING SEARCHED
EGITEM, !PTR TO CURRENT EQUIVLIST ITEM IN GROUP
CITEM, !PTR TO LIST ITEM IN CLASS ECLASS
CSYMPTR; !PTR TO SYMBOL TABLE OF ITEM IN ECLASS
MAP BASE ECLASS :EGROUP :EGSYMPTR :CITEM :CSYMPTR :EGITEM;
XTRAC; !FOR DEBUGGING TRACE
EGITEM _ .EGROUP[EQVFIRST]; ! First list item in EGROUP
! Search for match of item in ECLASS with item in EGROUP.
! Return to caller if we find no match.
%2235% !The search is terminated if a match is found
%2235% ELIS1: UNTIL .EGITEM EQL 0 DO
BEGIN ! For each item in EGROUP
EGSYMPTR _ .EGITEM[EQLID]; ! Symbol table entry
EGSYM _ .EGSYMPTR[IDSYMBOL]; ! SIXBIT symbol
CITEM _ .ECLASS[EQVFIRST]; ! First item in ECLASS
%2235% UNTIL .CITEM EQL 0 DO
BEGIN ! For each group in ECLASS
CSYMPTR _ .CITEM[EQLID]; !SYMBOL TABLE PTR
! If symbols are equal, then we found
! a common symbol between EGROUP and
! ECLASS.
IF .EGSYM EQL .CSYMPTR [IDSYMBOL]
THEN LEAVE ELIS1; ! Exit the search
%2235% CITEM = .CITEM[EQLLINK] !Next class item
%2235% END; ! For each item in ECLASS
%2235% IF (EGITEM = .EGITEM[EQLLINK]) EQL 0
THEN RETURN 0 !No match between ECLASS and EGROUP
%2235% END; ! For each item in EGROUP
! We get here if an item in EGROUP matches an item in ECLASS. CITEM
! points to the item in ECLASS and EGITEM points to the item in EGROUP.
! We now check for common equivalence interaction and decide whether to
! link the new items into ECLASS or to add new items to the common block
! of which ECLASS or EGROUP (but not both) is a part.
BEGIN
LOCAL EGDISPL,ELIM,ECDISPL;
%2235% IF .EGROUP[EQVSMALL] THEN ECLASS[EQVSMALL] = 1; !Copy 'small' flag
%2235% IF .EGROUP[EQVLARGE] THEN ECLASS[EQVLARGE] = 1; !Copy 'large' flag
IF .CSYMPTR[IDATTRIBUT(INCOM)] THEN
IF NOT .ECLASS[EQVINCOM]
THEN
BEGIN
ECLASS[EQVINCOM] _ 1;
%2235% ECLASS[EQVPSECT] = .EGROUP[EQVPSECT]; !Psect for the common
%2235% IF (ECLASS[EQVLIMIT] = GROUPTOCOMMON(.CSYMPTR,.ECLASS,.ECLASS[EQVLIMIT],.CITEM[EQLDISPL])) LSS 0
THEN RETURN -1
END;
!
!CSYMPTR CONTAINS PTR TO MATCHED SYMBOL IN ECLASS
!
ELIM _ .ECLASS[EQVLIMIT]; !LIMIT OF GROUP
EGDISPL _ .EGITEM[EQLDISPL];
ECDISPL _ .CITEM[EQLDISPL];
EGITEM _ .EGROUP[EQVFIRST];
EGSYMPTR _ .EGITEM[EQLID]; !SET PTR TO FIRST ITEM IN GROUP
%1261% ! Check that alignment requirements of class and group match each other.
%1261% ! The required condition is
%1261% ! CLASS-ALIGNMENT + CLASS-DISPL = GROUP-ALIGNMENT + GROUP-DISPL (mod 5)
%1261%
%1261% IF .ECLASS[EQVALIGN] EQL 0 ! If class has no alignment requirement
%1261% THEN IF .EGROUP[EQVALIGN] NEQ 0 ! but group does
%1261% THEN ! give group's requirement to class too
%1261% ECLASS[EQVALIGN] _ 1 +
%1261% MODULO(.EGROUP[EQVALIGN] + .EGDISPL - .ECDISPL - 1, CHARSPERWORD);
%1261%
%1261% IF .EGROUP[EQVALIGN] NEQ 0 ! If group has an alignment requirement
%1261% THEN ! check if things will still be aligned
%1261% ! when group is merged with class
%1261% IF (.ECDISPL + .ECLASS[EQVALIGN] - .EGDISPL - .EGROUP[EQVALIGN]) MOD CHARSPERWORD
%1261% NEQ 0
%1261% THEN FATLERR(.ISN,E166<0,0>); !"Numeric var must be word aligned"
!
!TEST FOR GROUP OR CLASS IN COMMON
!
IF .ECLASS[EQVINCOM] OR .EGROUP[EQVINCOM]
THEN
BEGIN ! One group in common
IF .EGROUP[EQVINCOM]
THEN
BEGIN ! Assign common addresses to ECLASS
ELIM _ .EGROUP[EQVLIMIT];
EGDISPL _ .CITEM[EQLDISPL];
ECDISPL _ .EGITEM[EQLDISPL];
CSYMPTR _ .EGITEM[EQLID];
EGITEM _ .ECLASS[EQVFIRST];
EGSYMPTR _ .EGITEM[EQLID];
END;
WHILE 1 DO %1%
BEGIN
!NOW CHECK NEW COMMON ADDRESS NOW AND LINK NEW ITEM INTO EXISTING COMMON BLOCK
IF .CSYMPTR NEQ .EGSYMPTR THEN
IF NOT (.ECLASS[EQVINCOM] AND .EGROUP[EQVINCOM]) THEN
IF NOT .EGSYMPTR[IDATTRIBUT(INCOM)]
THEN
BEGIN
LOCAL BASE CLCOMPTR :GPCOMPTR :COMSYM :ESYM;
LOCAL EGSYMSIZ;
IF (EGSYMPTR[IDADDR] _ .CSYMPTR[IDADDR] + .EGITEM[EQLDISPL] -.EGDISPL) LSS 0
THEN
BEGIN !Error equivalence item extends common backward
MAP BASE R1;
R1 _ .CSYMPTR[IDCOMMON];
RETURN FATLERR(R1[COMNAME],.ISN,E33<0,0>)
END;
%1511% ! Give error if this symbol is in SAVE, can't
%1511% ! also be in COMMON
%1511% IF .EGSYMPTR[IDSAVVARIABLE]
%1511% THEN FATLERR(.EGSYMPTR[IDSYMBOL],
%1531% .ISN,E197<0,0>);
EGSYMPTR[IDATTRIBUT(INCOM)] _ 1; !MAKE SYMBOL IN COMMON
CLCOMPTR _ .CSYMPTR[IDCOMMON]; !PTR TO COMMON BLOCK HDR
COMSYM _ .CLCOMPTR[COMLAST]; !PTR TO LAST SYMBOL IN BLOCK
COMSYM[IDCOLINK] _ .EGSYMPTR; !LINK IN NEW SYMBOL
CLCOMPTR[COMLAST] _ .EGSYMPTR;
EGSYMPTR[IDCOLINK] _ 0; !NEW END OF LINK
EGSYMPTR[IDCOMMON] _ .CLCOMPTR; !SYMBOL TO POINT TO BLOCK
! COMPUTE NEW BLOCK SIZE
%1261% EGSYMSIZ _ SIZEINCHARS(.EGSYMPTR);
IF (.EGITEM[EQLDISPL] + .EGSYMSIZ) GTR .ELIM
THEN ELIM _ (.EGITEM[EQLDISPL] + .EGSYMSIZ);
IF .CLCOMPTR[COMSIZE] LSS (R1 _ .EGSYMPTR[IDADDR] + .EGSYMSIZ)
THEN CLCOMPTR[COMSIZE] _ .R1;
END
ELSE IF (.EGSYMPTR[IDADDR]-.EGITEM[EQLDISPL])
NEQ (.CSYMPTR[IDADDR]-.EGDISPL)
THEN
BEGIN ! Testing for end of chain of group
! going into common
EQERRLIST(.EGROUP);
%2235% EGROUP[EQVAVAIL] _ EQVERROR; ! Error in group
RETURN -1 ! Error
END;
IF .EGITEM[EQLLINK] NEQ 0
THEN
BEGIN
EGITEM _ .EGITEM[EQLLINK];
EGSYMPTR _ .EGITEM[EQLID];
END
ELSE
BEGIN ! Link ECLASS and EGROUP with common symbol
! CSYMPTR.
LINKGROUPS(.ECLASS,.EGROUP,.CSYMPTR);
ECLASS[EQVINCOM] _ 1; ! In common
%2235% EGROUP[EQVAVAIL] = EQVIGNORE; ! Has been searched
EGROUP[EQVINCOM]_1; ! In common
RETURN 1 ! Success!! Merged groups
END;
END; !OF LOOP%1%
END; ! One group in common
! Here if neither EGROUP nor ECLASS in common, link items in EGROUP into
! ECLASS, mark each group unavailable.
! Check for errors of form:
! EQUIVALENCE (A(5),B(2)),(C(2),B(2)),(C(2),A(4))
! (This tries to equivalence A(4) to A(5), which is quite illegal!)
EGITEM _ .EGROUP[EQVFIRST]; ! First list of EGROUP.
WHILE 1 DO
BEGIN ! For each EGROUP
LOCAL ENEXITEM,NEWDISPL;
ENEXITEM _ .EGITEM[EQLLINK]; !PTR TO NEXT ITEM IN GROUP TO BE LINKED TO CLASS
EGSYMPTR _ .EGITEM[EQLID];
EGSYM _ .EGSYMPTR[IDSYMBOL];
!NOW SEARCH FOR EGSYM IN ECLASS
CITEM _ .ECLASS[EQVFIRST]; !PTR TO FIRST ITEM IN CLASS
NEWDISPL _ .ECDISPL + .EGITEM[EQLDISPL] -.EGDISPL;
! Find the matching id's and make sure that the displacements
! are equal.
IF WHILE 1 DO
BEGIN %2%
CSYMPTR _ .CITEM[EQLID]; ! Symbol id
! Check if symbols match
IF .EGSYM EQL .CSYMPTR[IDSYMBOL]
THEN EXITLOOP (-1); ! They do - Give a true
! End of ECLASS?
IF .CITEM[EQLLINK] EQL 0
THEN EXITLOOP (0) ! Give a false
ELSE CITEM _ .CITEM[EQLLINK] ! Next symbol
END !OF %2%
NEQ 0
THEN
BEGIN ! Make sure displacements of matching items are ok
! This is where we catch such things as equivalencing
! A(4) and A(5) to each other.
IF .NEWDISPL NEQ .CITEM[EQLDISPL]
THEN
BEGIN ! Displacements not equal.
EQERRLIST(.EGROUP); ! Conflicting equivalences
%2235% EGROUP[EQVAVAIL] = EQVERROR;
RETURN -1
END;
END ! Make sure displacements of matching items are ok
ELSE ! Put the item from the group into the class.
CITEM[EQLLINK] _ .EGITEM;
EGITEM[EQLLINK] _ 0; !CLEAR LINK
EGITEM[EQLDISPL] _ .NEWDISPL;
IF .NEWDISPL LSS .ECLASS[EQVADDR]
THEN ECLASS[EQVADDR] _ .NEWDISPL;
BEGIN !Now compute new EQVLIMIT
LOCAL BASE ESYM, EQSIZ;
%1261% EQSIZ _ SIZEINCHARS(.EGSYMPTR);
IF (.EGITEM[EQLDISPL] + .EQSIZ) GTR .ECLASS[EQVLIMIT]
THEN ECLASS[EQVLIMIT] _ (.EGITEM[EQLDISPL] + .EQSIZ);
END;
IF .ENEXITEM EQL 0
THEN RETURN 1 !Good return (all items in EGROUP linked to ECLASS)
ELSE EGITEM _ .ENEXITEM;
END; ! For each EGROUP item
END;
END; ! of ELISTSRCH
ROUTINE EQCALLOC(ECLASS)=
BEGIN
%
ALLOCATE RELOCATABLE ADDRESSES TO AN EQUIVALENCE CLASS (ECLASS)
%
MAP BASE ECLASS;
LOCAL BASE CITEM :CSYMPTR;
LOCAL TLOC;
OWN CNT;
%2311% LOCAL HOWIDE; !SYMBOLS PER LISTING LINE
%2235% LOCAL SECTION; !The psect for this group
%1261% LOCAL FLAGWRD;
%2271% BIND
%2271% CHARSEEN = FLAGWRD<0,1>, ! Block contains Character data
%2271% NUMSEEN = FLAGWRD<1,1>, ! Block contains Numeric data
%2271% LOGSEEN = FLAGWRD<2,1>; ! Block contains Logical data
%
THE ADDRESS OF ANITEM IN ECLASS IS COMPUTED AS FOLLOWS
ADDR _ .PSECTS[.SECTION] + (RELATIVE DISPLACEMENT OF ITEM IN ECLASS (CITEM[EQLDISPL]
- SMALLEST RELATIVE DISPLACEMENT IN ECLASS (ECLASS[EQVADDR])
%
%2235% IF .ECLASS[EQVLARGE]
%2235% THEN SECTION = ECLASS[EQVPSECT] = PSLARGE
%2235% ELSE SECTION = ECLASS[EQVPSECT] = PSDATA;
CNT _ 0;
IF .FLGREG<LISTING>
THEN
BEGIN
%2311% HOWIDE = IF EXTENDED THEN 2 !CAN ONLY FIT 3 SYMBOLS / LINE W/ /EXTEND
%2311% ELSE 5; !DO SIX THE REST OF THE TIME
HEADCHK();
STRNGOUT(PLIT '?M?J( ?0')
END;
%1261% ! TLOC is the CHARACTER address of the beginning of this equivalence class
%1261% IF .ECLASS[EQVALIGN] NEQ 0 ! If class must be aligned on a
%1261% THEN ! particular byte
%1261% ECLASS[EQVADDR] _ .ECLASS[EQVADDR] -
%1261% MODULO (.ECLASS[EQVADDR] + .ECLASS[EQVALIGN] - 1, CHARSPERWORD);
%2235% TLOC = .PSECTS[.SECTION] * CHARSPERWORD - .ECLASS[EQVADDR];
%2271% FLAGWRD = 0; ! Clear CHARSEEN, NUMSEEN and LOGSEEN
CITEM _ .ECLASS[EQVFIRST];
%2235% UNTIL .CITEM EQL 0 DO
BEGIN
CSYMPTR _ .CITEM[EQLID]; !PTR TO SYMBOL
CSYMPTR[IDADDR] _ .CITEM[EQLDISPL] + .TLOC;
%1261% IF .CSYMPTR[VALTYPE] NEQ CHARACTER ! CONVERT FROM CHAR ADDRESS
%1261% THEN
%1261% BEGIN
%1261% CSYMPTR[IDADDR] _ .CSYMPTR[IDADDR] / CHARSPERWORD; ! CONVERT TO WORD ADDRESS
%2235% CSYMPTR[IDPSECT] = .SECTION; !The psect
%2271% IF .CSYMPTR[VALTYPE] EQL LOGICAL
%2271% THEN LOGSEEN = 1 ! Class contains logical data
%2271% ELSE NUMSEEN = 1; ! Class contains numeric data
%1261% END
%1261% ELSE
%1261% BEGIN !CHARACTER
%1261% CSYMPTR[IDCHBP] _ CHADDR2BP(.CSYMPTR[IDADDR]); ! CONVERT TO BYTE POINTER
%1261% CSYMPTR[IDADDR] _ 0; ! AND CLEAR IDADDR, DESCRIPTOR ADDRESS
%2235% CSYMPTR[IDPSCHARS] = .SECTION; !The psect
%2235% CHARSEEN = 1; ! Remember class contains character data
%1261% END; !CHARACTER
IF .FLGREG<LISTING>
THEN(LISTSYM(.CSYMPTR);
%2311% IF .CNT LSS .HOWIDE THEN CNT _ .CNT+1
ELSE (CNT _ 0; CRLF; HEADCHK());
);
%2235% CITEM = .CITEM[EQLLINK] !Next item
%2235% END; !of loop through the items
%2235% IF .FLGREG<LISTING>
%2235% THEN (STRNGOUT(PLIT')?M?J'); HEADCHK());
%2271% IF FLAGEITHER
%2271% THEN
%2271% BEGIN ! Doing compatibility checks
%2271% ISN=0; ! ISN for any errors (error appears after allocation listing)
%2271% IF .CHARSEEN AND (.NUMSEEN OR .LOGSEEN)
%2271% THEN ! List contains both Char and Non-Char
%2271% CFLAGB(UPLIT 'EQUIVALENCE-d?0',E168<0,0>);
%2455% IF FLAGVMS ! Compatibility check for VMS
%2271% THEN IF .LOGSEEN AND .NUMSEEN ! Mixing logical and numeric
%2271% THEN WARNERR(.ISN,E249<0,0>);
%2271% END; ! Doing compatibility checks
%2235% PSECTS[.SECTION] = .PSECTS[.SECTION] +
%2235% CHWORDLEN(.ECLASS[EQVLIMIT] - .ECLASS[EQVADDR]);
!
!PSECTS[SECTION] + SPAN OF THE CLASS
!
END; ! of EQCALLOC
ROUTINE GRPSCAN=
BEGIN
!***********************************************************************
! Mark all equivalence groups that have an item (list) in COMMON.
! Force psect of groups with element in common to have the common psect.
! Set the EQVSMALL and EQVLARGE flags in group header entries.
!***********************************************************************
LOCAL BASE ECLASS :ELIST :EITEM : LAST;
%2235% LOCAL BASE COMPTR; !Pointer to common block
ECLASS _ .EQVPTR<LEFT>; ! First equivalence group
%2235% UNTIL .ECLASS EQL 0 DO
BEGIN ! Walk through all groups
LAST _ ELIST _ .ECLASS[EQVFIRST];
IF NOT .ECLASS[EQVINCOM]
THEN ! Group not already marked as in common
UNTIL .ELIST EQL 0
DO
BEGIN ! For each symbol in the group
EITEM _ .ELIST[EQLID]; ! Symbol
IF .EITEM[IDATTRIBUT(INCOM)]
THEN
BEGIN ! Symbol is in common
! Check for more than one common var
! in this group.
IF .ECLASS[EQVINCOM]
THEN
BEGIN
FATLERR(.ISN,E48<0,0>);
EXITLOOP;
END;
%2235% !Force psect to match common
%2235% COMPTR = .EITEM[IDCOMMON];
%2235% ECLASS[EQVPSECT] = .COMPTR[COMPSECT];
ECLASS[EQVINCOM] _ 1;
ECLASS[EQVHEAD] _ .ELIST;
IF .LAST NEQ .ELIST
THEN
BEGIN ! Move it to top of the list
LAST[EQLLINK] _ .ELIST[EQLLINK];
ELIST[EQLLINK] _ .ECLASS[EQVFIRST];
! If the common element was
! the last one in the group,
! then the ptr to it [EQVLAST]
! must be changed too
ECLASS[EQVFIRST] _ .ELIST;
IF .ECLASS[EQVLAST] EQL .ELIST
THEN ECLASS[EQVLAST] _ .LAST
END
END; ! Symbol is in common
%2235% ! Set either 'small' or 'large' flag in group header
%2235% ! depending upon psect for the item
%2235% IF (.EITEM[VALTYPE] EQL CHARACTER
%2235% AND .EITEM[IDPSCHARS] EQL PSLARGE)
%2235% OR (.EITEM[VALTYPE] NEQ CHARACTER
%2235% AND .EITEM[IDPSECT] EQL PSLARGE)
%2235% THEN ECLASS[EQVLARGE] = 1
%2235% ELSE ECLASS[EQVSMALL] = 1;
LAST _ .ELIST;
ELIST _ .ELIST[EQLLINK]
END; ! For each symbol in the group
%2235% ECLASS = .ECLASS[EQVLINK] !Walk through
%2235% END; ! all groups
END; ! of GRPSCAN
ROUTINE PROCEQUIV=
!++
! FUNCTIONAL DESCRIPTION:
!
! Processes equivalence groups as declared in the source.
! Resolving implicit equivalences and equivalences into common.
! Checks for allocation errors due to improper equivalences.
! Assigns temporary addresses to equivalence variables and new
! variables equivalenced into common.
!
! - finds groups that are in COMMON because one of their members
! is declared in common. Sets EQVINCOM flag in such groups.
! [using GRPSCAN]
! - sets EQLDISPL for array elements to the word offset from the
! base address of the array to the given element. EQLDISPL for
! non-array elements is 0.
! - sets EQVLIMIT to max(EQVLIMIT,EQLDISPL+ARASIZ) where ARASIZ is
! the declared size of the array or 1 (or 2) for scalars
! - sets LCLHD to {either the (unique?) element of the group
! declared in common or} the one with the minimum EQLDISPL. At
! this point, EQLDISPL is the offset from the start of the array.
! - if the group contains a symbol declared in COMMON, check all
! other symbols to see that if they are also declared in common
! that they are in the same block and have the same offset. If
! they are not also declared in common, declare them in the same
! COMMON block as the equivalenced variable. Add them to the
! linked list of variables in the common block. Give them all the
! same IDADDR (offset from start of common) field.
! - Set in the group node: EQVADDR = min(EQLDISPL) over the group,
! EQVHEAD = symbol with the min EQLDISPL, EQVLIMIT = number of
! words in group
! - finds variables which occur in more than group and unions the
! groups together into classes. [ELISTSRCH] When two groups are
! found which contain the same variable, one of them is chosen to
! be a "class", ie, the one that gets the other unioned into it.
! The one that is the "class" has a magic field, EQVAVAIL, set to
! EQVCLASS. The one that remains a group has EQVAVAIL set to
! EQVIGNORE. At the end of this processing, the groups with
! EQVAVAIL = EQVCLASS are the ones that contain all the info from
! all the equivalence statements.
! - call EQCALLOC to allocate the classes
!
! FORMAL PARAMETERS:
!
! None
!
! IMPLICIT INPUTS:
!
! Unknown
!
! IMPLICIT OUTPUTS:
!
! Unknown
!
! ROUTINE VALUE:
!
! None
!
! SIDE EFFECTS:
!
! Unknown
!
!--
BEGIN
LOCAL BASE EQVCPTR, !PTR TO CURRENT EQUIV CLASS HEADER
ECOMMPTR, !PTR COMMON ITEM IF GROUP IS IN COMMON
ECOMMHDR, !PTR TO COMMON BLOCK HDR
BASE EQLPT2, !OTHER PTR TO EQUIV LIST NODE
BASE LCLHD, !PTR TO LOCAL HEAD OF A GROUP FOR ALLOCATION PURPOSES
SAVEBOUNDSFLG, !TO SAVE THE VALUE OF THE "BOUNDS" SWITCH WHILE
! PROCESSING EQUIVALENCE STMNTS
%2235% BASE SYMPTR; !Ptr to symbol table entry
REGISTER BASE EQLPTR; !PTR TO EQUIV LIST NODE
%2235% LABEL LOOP2;
SAVEBOUNDSFLG_.FLGREG<BOUNDS>; !SAVE THE VALUE OF THE "BOUNDS" SWITCH
! (THAT SPECIFIES WHETHER ARRAY BOUNDS
! CHECKING IS TO BE PERFORMED)
FLGREG<BOUNDS>_0; !TURN OFF THE BOUNDS FLAG WHILE PROCESSING
! EQUIVALENCE STATEMENTS
%1120% HDRFLG_0; !Remember that no header has been output yet
! The first step is to compute relative displacements of each item in
! and equivalence group. This is simply 1 minus the subscript value
! of each item in the group.
! I.e. A(1) has displacement 0 and A(4) has displacement -3.
! Make sure that every group that has a symbol in COMMON is marked.
GRPSCAN();
EQVCPTR _ .EQVPTR<LEFT>; ! Ptr to first group
%2235% UNTIL .EQVCPTR EQL 0 DO
BEGIN ! For each equivalence group
ISN _ .EQVCPTR[EQVISN]; ! Set ISN in case of errors
ECOMMPTR _ 0; ! Initializing
!If group is in common then find the element in common
%2235% IF .EQVCPTR[EQVINCOM]
THEN
BEGIN ! Group has element in common
EQLPTR _ .EQVCPTR[EQVHEAD]; ! Ptr to list item that's in common
LCLHD _ .EQLPTR[EQLID]; ! Symbol table entry
ECOMMPTR _ .EQLPTR; ! Ptr to common item eql list item
ECOMMHDR _ .LCLHD[IDCOMMON]; ! Common table entry
END
ELSE LCLHD _ 0;
EQLPTR _ .EQVCPTR[EQVFIRST]; ! Ptr to first item in group
R2 _ 0; ! EQVLIMIT in R2
R1 _ 0; ! Smallest displacement in R1
%2235% LOOP2:
%2235% UNTIL .EQLPTR EQL 0 DO
BEGIN ! For each list in ECLASS
LOCAL BASE ESYM, EQSIZ;
IF .EQLPTR[EQLINDIC] NEQ 0
THEN
BEGIN ! Has dimensions
%2414% LOCAL BASE PT1:PT2:PT3:PTL:PTU:PTS; ! Scratch pointers
%2414% LOCAL NUMELM; ! Number of elements
PT1 _ .EQLPTR[EQLID]; ! Symbol table
IF .PT1[IDDIM] EQL 0 THEN
BEGIN ! Not declared with dimensions - error!
FLGREG<BOUNDS>_.SAVEBOUNDSFLG;
RETURN FATLERR(.ISN,E93<0,0>);
END;
EQLPTR[EQLINDIC] _ 0;
IF .EQLPTR[EQLLIST]^(-18) NEQ 0
THEN
BEGIN ! Multiple subscripts
%2414% ! Check the constant subscripts to verify that
%2414% ! they are within bounds.
%2414% PT3=.EQLPTR[EQLID]; ! Pointer to symbol
%2414% PT1=.EQLPTR[EQLLIST]; ! Pointer to subscripts
%2414% PT2=.PT3[IDDIM]; ! Dimension table
%2414% INCR I FROM 0 TO .PT2[DIMNUM]-1
%2414% DO
%2414% BEGIN ! Loop for subscript check
%2414% PTL=.PT2[DIMENL(.I)]; ! Lower bound
%2414% PTU=.PT2[DIMENU(.I)]; ! Upper bound
%2414% PTS=@(.PT1+.I); ! Subscript
%2414% IF .PTS[CONST2] LSS .PTL[CONST2] OR
%2414% .PTS[CONST2] GTR .PTU[CONST2]
%2414% THEN ! Subscript out of range
%2414% WARNERR(PT3[IDSYMBOL],.ISN,E293<0,0>);
%2414% END; ! Loop for subscript check
! Set EQLDISPL to negative of subscript expression
PT1 _ ARRXPN(.EQLPTR[EQLID],.EQLPTR[EQLLIST]);
IF .PT1[ARG2PTR] EQL 0
THEN EQLPTR[EQLDISPL] _ -(EXTSIGN(.PT1[TARGADDR]))
%1261% ELSE EQLPTR[EQLDISPL] _ -CNSTEVAL(.PT1[ARG2PTR])
%1261% - EXTSIGN(.PT1[TARGADDR]);
%1261% ! If noncharacter, convert words to chars
%1261% IF .PT3[VALTYPE] NEQ CHARACTER
%2271% THEN EQLPTR[EQLDISPL] = .EQLPTR[EQLDISPL] * CHARSPERWORD;
%2322% ! Check if the array reference is too large for
%2322% ! the amount of addressable memory on the
%2322% ! machine. /EXTEND allows larger arrays. If
%2322% ! too large, give a fatal error message.
%2322%
%2322% IF .EQLPTR[EQLDISPL] LEQ -(.VMSIZE * CHARSPERWORD)
%2322% OR .EQLPTR[EQLDISPL] GEQ (.VMSIZE * CHARSPERWORD)
%2322% THEN RETURN FATLERR(PT3[IDSYMBOL], .ISN, E103<0,0>);
END ! Multiple subscripts
ELSE
BEGIN ! Single subscript
PT1 _ @.EQLPTR[EQLLIST]; !POINTER TO SUBSCRIPT
IF .PT1[OPR1] NEQ CONSTFL OR .PT1[VALTYPE] NEQ INTEGER
THEN RETURN FATLERR(.ISN,E53<0,0>); !NON-CONSTANT SUBSCRIPT
! Now generate the offset
PT3 _ .EQLPTR[EQLID]; ! Symbol table
PT2 _ .PT3[IDDIM]; ! Dimension table
%2271% IF FLAGANSI
%2271% THEN ! Compatibility checks
%2271% IF .PT2[DIMNUM] NEQ 1 ! Should be single dimension
%2271% THEN WARNERR(PT3[IDSYMBOL],.ISN,E274<0,0>);
%2414% ! Compute size of array, and check to see if the
%2414% ! subscript is within range.
%2414% ! The subscript is considered to be within range
%2414% ! if it is not less than the lower bound of the
%2414% ! first dimension, and not greater than the number
%2414% ! of elements offset by that first lower bound.
%2414% NUMELM=1; ! Will hold the computed number of elements
%2414% DECR I FROM .PT2[DIMNUM]-1 TO 0
%2414% DO
%2414% BEGIN ! Loop to compute number of elements
%2414% PTL=.PT2[DIMENL(.I)]; ! Lower bound
%2414% PTU=.PT2[DIMENU(.I)]; ! Upper bound
%2414% NUMELM=.NUMELM*(.PTU[CONST2]-.PTL[CONST2]+1);
%2414% END; ! Loop to compute number of elements
%2414% IF .PT1[CONST2] GTR (.NUMELM+.PTL[CONST2]-1) OR
%2414% .PT1[CONST2] LSS .PTL[CONST2]
%2414% THEN !Subscript out of range
%2414% WARNERR(PT3[IDSYMBOL],.ISN,E293<0,0>);
EQLPTR[EQLDISPL] _ - .PT1[CONST2] !CONSTANT VALUE
+ .PTL[CONST2]; !OFFSET
%1261% IF .PT3[VALTYPE] EQL CHARACTER ! MULTIPLY BY ELEMENT
%1261% THEN ! LENGTH IN CHARACTERS
%1261% EQLPTR[EQLDISPL] _ .EQLPTR[EQLDISPL] * .PT3[IDCHLEN]
%1261% ELSE
%1261% IF .PT3[DBLFLG]
%1261% THEN EQLPTR[EQLDISPL] _ .EQLPTR[EQLDISPL] * 2 * CHARSPERWORD
%1261% ELSE
%1261% EQLPTR[EQLDISPL] _ .EQLPTR[EQLDISPL] * CHARSPERWORD;
%2322% ! Check if the array reference is too large for
%2322% ! the amount of addressable memory on the
%2322% ! machine. /EXTEND allows larger arrays. If
%2322% ! too large, give a fatal error message.
%2322%
%2322% IF .EQLPTR[EQLDISPL] LEQ -(.VMSIZE * CHARSPERWORD)
%2322% OR .EQLPTR[EQLDISPL] GEQ (.VMSIZE * CHARSPERWORD)
%2322% THEN RETURN FATLERR(PT3[IDSYMBOL], .ISN, E103<0,0>);
END ! Single subscript
END; ! Has dimensions
ESYM _ .EQLPTR[EQLID]; !PTR TO SYMBOL TABLE
%1262% ! ADD IN SUBSTRING OFFSET FOR CHARACTER VARIABLES
%1262% IF .EQLPTR[EQLSSTRING] ! IF THIS LIST ELEMENT IS A SUBSTRING
%1262% THEN
%1262% IF .ESYM[VALTYPE] NEQ CHARACTER ! BASE IDENTIFIER MUST BE CHARACTER
%1262% THEN FATLERR(.ISN,E162<0,0>) ! "Substring of non-CHARACTER"
%1262% ELSE IF .EQLPTR[EQLLOWER] LSS 0 OR .EQLPTR[EQLLOWER] GEQ .ESYM[IDCHLEN]
%1262% THEN FATLERR(.ISN,E165<0,0>); ! Substring bound out of range
%1262% EQLPTR[EQLDISPL] _ .EQLPTR[EQLDISPL] - .EQLPTR[EQLLOWER];
%1261% ! IF EQUIVALENCED VARIABLE IS NUMERIC, THIS GROUP MUST BE WORD ALIGNED
%1261% IF .ESYM[VALTYPE] NEQ CHARACTER
%1261% THEN EQVCPTR[EQVALIGN] _ 1;
!NOW CHECK FOR NEW EQVLIMIT (R2) FOR THIS GROUP
!
%1261% EQSIZ _ SIZEINCHARS(.ESYM);
IF (.EQLPTR[EQLDISPL] + .EQSIZ) GTR .R2 %EQVLIMIT%
THEN R2 _ (.EQLPTR[EQLDISPL] +.EQSIZ);
!NOW CHECK FOR NEW MIN(R(I)) RELATIVE DISPLACEMENT
!
IF .EQLPTR[EQLDISPL] LSS .R1
THEN
BEGIN
R1 _ .EQLPTR[EQLDISPL]; ! New smallest displacement
LCLHD _ .EQLPTR[EQLID];
END;
IF .ECOMMPTR NEQ 0 THEN
IF .EQLPTR NEQ .ECOMMPTR
THEN
BEGIN
LOCAL BASE LINK:COM;
MAP BASE ECOMMHDR :ECOMMPTR;
LINK _ .EQLPTR[EQLID];
COM _ .ECOMMPTR[EQLID]; !PTR TO ITEM IN CO MMON
IF NOT .LINK[IDATTRIBUT(INCOM)]
THEN
BEGIN ! Not in common
LINK _ .ECOMMHDR[COMLAST];
ECOMMHDR[COMLAST] _ .EQLPTR[EQLID];
LINK _ LINK[IDCOLINK] _ .EQLPTR[EQLID]; !PTR TO SYMBOL TABLES NODE
%1511% ! Can't be in both SAVE and Common
%1511% IF .LINK[IDSAVVARIABLE]
%1511% THEN FATLERR(.LINK[IDSYMBOL],.ISN,E197<0,0>);
LINK[IDATTRIBUT(INCOM)] _ 1; !SET IN COMMON
LINK[IDCOMMON] _ .ECOMMHDR;
LINK[IDCOLINK] _ 0;
IF (LINK[IDADDR] _ (.EQLPTR[EQLDISPL] - .ECOMMPTR[EQLDISPL] + .COM[IDADDR]) ) LSS 0
THEN
BEGIN
FATLERR(ECOMMHDR[COMNAME],.ISN,E33<0,0>);
LEAVE LOOP2;
END;
IF .ECOMMHDR[COMSIZE] LSS (.LINK[IDADDR] + .EQSIZ)
THEN ECOMMHDR[COMSIZE] _ (.LINK[IDADDR] + .EQSIZ);
END ! Not in common
ELSE ! Checking the declarations for violating
! beginning of common block
IF (.COM[IDADDR]-.ECOMMPTR[EQLDISPL])
NEQ (.LINK[IDADDR]-.EQLPTR[EQLDISPL])
! If both the group and the element
! are in common, make sure it is the
! SAME common block! Otherwise an
! error.
OR (.COM[IDCOMMON] NEQ .LINK[IDCOMMON])
THEN
BEGIN
EQERRLIST(.EQVCPTR); ! List out vars
%2235% EQVCPTR[EQVAVAIL] = EQVERROR;
LEAVE LOOP2;
END;
END;
%2235% EQLPTR = .EQLPTR[EQLLINK] !Next list item
%2235% END; ! For each list in ECLASS
EQVCPTR[EQVADDR] _ .R1; !LOWEST RELATIVE DISPLACEMENT
EQVCPTR[EQVHEAD] _ .LCLHD; !PTR TO HED OF GROUP
EQVCPTR[EQVLIMIT] _ .R2; !SPAN OF GROUP RELATIVE TO 0
!
!REAL SPAN (#OF WORDS OCCUPIED BY ALL ELEMNTS OF GROUP)
!IS EQVLIMIT - EQVADDR
!
%1450% ! Check for EQUIVALENCE (A(1),A(2))
%1450% EQLPTR _ .EQVCPTR[EQVFIRST]; ! Step through all variables
%1450% WHILE .EQLPTR NEQ 0 DO ! in equivalence list
%1450% BEGIN
%1450% EQLPT2 _ .EQLPTR[EQLLINK]; ! Step through all subsequent
%1450% WHILE .EQLPT2 NEQ 0 DO ! variables in list
%1450% BEGIN ! Look for duplicates
%1450% IF .EQLPTR[EQLID] EQL .EQLPT2[EQLID] ! If variable is
%1450% THEN ! the same
%1450% IF .EQLPTR[EQLDISPL] NEQ .EQLPT2[EQLDISPL] ! displ must
%1450% THEN ! also be the same
%1450% BEGIN
%1450% EQERRLIST(.EQVCPTR); ! error, type message
%2235% EQVCPTR[EQVAVAIL] = EQVERROR;! mark group to prevent
%1450% ! further processing
%1450% END;
%1450% EQLPT2 _ .EQLPT2[EQLLINK];
%1450% END;
%1450% EQLPTR _ .EQLPTR[EQLLINK];
%1450% END;
%2235% EQVCPTR = .EQVCPTR[EQVLINK] !Next group
%2235% END; ! For each equivalence group
! Now start to make equivalence classes by combining groups if possible
EQVCPTR _ .EQVPTR<LEFT>; ! Start with first group
%2235% UNTIL .EQVCPTR EQL 0 DO
%2235% BEGIN ! Walk through each equivalence group
%2235% IF .EQVCPTR[EQVAVAIL] EQL EQVGROUP
THEN
BEGIN ! Group available for Class
ISN _ .EQVCPTR[EQVISN]; ! Set ISN in case of errors
%2235% EQVCPTR[EQVAVAIL] = EQVCLASS; ! Make Group a Class
EQLPTR _ .EQVCPTR; ! Begin search of other groups on current Group
DO
BEGIN ! Walk through all groups after EQVCPTR
%2235% IF .EQLPTR[EQVAVAIL] EQL EQVGROUP
THEN
BEGIN ! Ok to search this group
! Try to combine the groups into a single one.
IF (ELISTSRCH(.EQVCPTR,.EQLPTR)) GTR 0
THEN
BEGIN ! Groups were combined
%2235% EQLPTR[EQVAVAIL] = EQVIGNORE; ! Have searched
EQLPTR _ .EQVCPTR ; !SEE IF ANY OF THE REJECTS FIT NOW
END;
! If error occurred in ELSTSRCH then
%2235% ! EQLPTR[EQVAVAIL] will be set to EQVERROR
END; ! Ok to search this group
END ! Walk through all groups after EQVCPTR
WHILE (EQLPTR _ .EQLPTR[EQVLINK]) NEQ 0;
IF NOT .EQVCPTR[EQVINCOM]
%2235% THEN IF .EQVCPTR[EQVAVAIL] EQL EQVCLASS
%[735]% THEN
%[735]% BEGIN ! No error in searching, not in common
%[735]% IF .HDRFLG EQL 0
%2311% THEN
%2311% IF EXTENDED
%2311% THEN
%2311% LSTHDR(4,2,PLIT'?M?JEQUIVALENCED VARIABLES [ "!" VARIABLE STORED IN .LARG. ]?M?J?0')
%2311% ELSE
%[735]% LSTHDR(4,2,PLIT'?M?JEQUIVALENCED VARIABLES?M?J?0');
%[735]% EQCALLOC(.EQVCPTR); ! Allocate Class
%[735]% HDRFLG_1;
%[735]% END;
END; ! Group available for Class
%2235% EQVCPTR = .EQVCPTR[EQVLINK] !Next class or group
%2235% END; ! Walk through each equivalence group
FLGREG<BOUNDS> = .SAVEBOUNDSFLG; !RESTORE THE "BOUNDS" SWITCH
END; ! of PROCEQUIV
GLOBAL ROUTINE ALCCON=
BEGIN
! Allocate all the constants that have the flag CNTOBEALCFLG set.
! this flag is set by calls to ALOCONST.
%1232% ! Rewritten by TFV, 17-Jun-81
%1232% ! Fixup block structure and allocate hollerith and character constants
BIND HI=R1,LOW=R2;
MACHOP ADDI=#271,TLZE=#623,TLO=#661,LSH=#242,DFN=#131;
MACRO EXPON=27,8$;
REGISTER BASE CPTR;
%1733% ! The over/underflows that may occur in this routine are not associated
%1733% ! with any particular line, so set ISN to zero (which means no line
%1733% ! number is known). It is safe to do this because this routine is
%1733% ! called so late in the back end.
%1733% ISN = 0;
! Set CNTOBEALCFLG for all consts used in dimensioning arrays that will
! have bounds checking performed on them
ALODIMCONSTS();
INCR I FROM 0 TO CSIZ-1 DO ! Walk through hash table entries
BEGIN
CPTR_.CONTBL[.I]; ! Get next hash table entry
WHILE .CPTR NEQ 0 DO ! Walk down linked list for each hash
BEGIN
%1272% ! Convert real constants from DP to SP form, even if
%1272% ! the constant lives in a MOVEI.
IF .CPTR[CONST1] NEQ 0
THEN
BEGIN
! Convert real constants from DP to SP
! form, 0 is a special case
IF .CPTR[VALTYPE] EQL REAL
THEN
BEGIN
! When rounding to single
! precision, zero second word
CPTR[CONST1] _ KISNGL(.CPTR[CONST1],
.CPTR[CONST2]);
CPTR[CONST2]_0;
END;
END;
%1272% IF .CPTR[CNTOBEALCFLG] THEN
%1272% BEGIN
%1272% ! Constant to be allocated
%1526% CPTR[IDADDR]_.LOWLOC;
! Now put constant out in REL file.
! Remember that this routine is
! executed within a test for the .REL
! file generation
IF .CPTR[VALTP1] EQL INTEG1 ! Output first or only word of data
THEN RDATWD _ .CPTR[CONST2] ! Only word
ELSE RDATWD _ .CPTR[CONST1]; ! High order for double or complex
! Output to low seg with no relocation
IF .FLGREG<OBJECT>
%1526% THEN ZCODE(PSABS,PSDATA);
%1526% LOWLOC _ .LOWLOC + 1;
IF .CPTR[DBLFLG]
THEN
BEGIN
! Output low order word for double and complex
RDATWD _ .CPTR[CONST2];
! Output to low seg with no relocation
IF .FLGREG<OBJECT>
%1526% THEN ZCODE(PSABS,PSDATA);
%1526% LOWLOC _ .LOWLOC + 1
END
END; ! Constant to be allocated
CPTR_.CPTR[CLINK] ! Get next linked list item
END; ! Walk down linked list for each hash
END; ! Walk through hash table entries
! Output HOLLERITH and CHARACTER constants to lowseg. They
! are in writable storage since they can be actuals passed to
! dummy arrays and updated. FORTRAN 66 also allows reading
! into FORMAT specs. LINK will fixup character constant
! actuals passed to non-character dummy args by converting the
! character constant to hollerith. This is done by
! substituting a pointer to the actual constant for a pointer
! to the character descriptor. Because of this character
! constants must look the same as hollerith; they are blank
! filled to a full word and followed by a zero word (ASCIZ).
CPTR _ .LITPOINTER<LEFT>;
WHILE .CPTR NEQ 0 DO ! walk down linked list
BEGIN
IF .CPTR[CNTOBEALCFLG]
THEN
BEGIN
! Literal to be allocated
! LITADDR points to the literal in the lowseg.
! Character constants will have character
! descriptors generated in the high seg
! pointing to the low seg data and LITADDR
! will be modified to point to the descriptor.
%1526% CPTR[LITADDR] _ .LOWLOC;
IF .FLGREG<OBJECT>
THEN
BEGIN
INCR I FROM 0 TO .CPTR[LITSIZ] - 1 DO
BEGIN
! Output LITSIZ words
RDATWD _ .(CPTR[LIT1] + .I); ! Get next word
%1526% ZCODE(PSABS,PSDATA);
%1526% LOWLOC _ .LOWLOC + 1;
END
END
%1526% ELSE LOWLOC _ .LOWLOC + .CPTR[LITSIZ];
END; ! Literal to be allocated
CPTR _ .CPTR[LITLINK] ! Get next linked list item
END ! of walk down linked list
END; ! of ALCCON
GLOBAL ROUTINE HSLITD=
BEGIN
%1232% ! Written by TFV, 17-Jun-81
! Output hiseg descriptors for character constants. Called after
! hiseg is inited. Fixup IDADDR to point to descriptor. Descriptor
! points to lowseg character constant data.
REGISTER
BASE CPTR,
BP;
CPTR _ .LITPOINTER<LEFT>;
WHILE .CPTR NEQ 0 DO ! walk down linked list
BEGIN
IF .CPTR[CNTOBEALCFLG] AND .CPTR[LITOPER] EQL CHARCONST
THEN
BEGIN
! Character constant to be allocated
! LITADDR points to the character descriptor generated
! in the high seg which points to the low seg data.
%1406% BP = RDATWD = BPGEN(.CPTR[LITADDR]); ! Byte pointer to low seg data
CPTR[LITADDR] _ .HILOC; ! Pointer to descriptor
IF .FLGREG<OBJECT>
THEN
BEGIN ! .REL being generated
![2330] Output byte pointer to hiseg,
![2330] relocating address field to lowseg
%2330% Z30CODE(PSDATA,PSCODE);
HILOC _ .HILOC + 1;
RDATWD _ .CPTR[LITLEN]; ! Length of constant
![2330] Output length to hiseg without
![2330] relocation
%2330% Z30CODE(PSABS,PSCODE);
HILOC _ .HILOC + 1;
END ! of .REL being generated
ELSE HILOC _ .HILOC + 2;
! List symbol name, descriptor address, lowseg
! data position, and length
IF .FLGREG<LISTING> AND .FLGREG<MACROCODE>
THEN LISTCHD(.CPTR,.BP);
END; ! Literal to be allocated
CPTR _ .CPTR[LITLINK] ! Get next linked list item
END; ! Walk down linked list
END; ! of HSLITD
GLOBAL ROUTINE HSCHD=
BEGIN
REGISTER
BASE PTR,
%1434% BASE ENT,
%1434% BASE FUNC;
MAP
%1261% BASE R2;
%1232% ! Written by TFV, 17-Jun-81
! Generate hiseg descriptors for non-dummy character scalars and
! arrays. Called after the hiseg is inited. Only called if a
! character declaration or an implicit character declaration has been
! seen. Calls LISTCHD to list the character data name, descriptor
! location, start of character data, and length.
DECR I FROM SSIZ-1 TO 0 DO ! Walk through hash table entries
BEGIN
PTR = .SYMTBL[.I]; ! Entry for this hash
WHILE .PTR NEQ 0 DO ! Walk down linked list of symbols
BEGIN
%1422% ! Generate descriptors for character variables and for the
%1422% ! function name and entry points for this program unit, but
%1422% ! not for functions it calls. Generate descriptors for
%1422% ! character functions that are declared external. Generate
%1422% ! only one descriptor for multi-entry character functions.
IF .PTR[VALTYPE] EQL CHARACTER THEN
%1422% IF NOT .PTR[IDATTRIBUT(NOALLOC)] THEN
%1434% IF (.PTR[IDATTRIBUT(FENTRYNAME)] AND .PTR[IDSYMBOL] EQL .PROGNAME) OR
%1434% (.PTR[OPERSP] EQL FNNAME AND (.PTR[IDATTRIBUT(INEXTERN)] OR .PTR[IDATTRIBUT(SFN)])) OR
%1434% (NOT .PTR[IDATTRIBUT(FENTRYNAME)] AND .PTR[OPERSP] NEQ FNNAME)
THEN
BEGIN
IF NOT .PTR[IDATTRIBUT(DUMMY)]
THEN
BEGIN
! Non-dummy arg character scalars and
! arrays have a hiseg descriptor, so
! generate it. Point IDADDR to
! descriptor. Descriptor is in the
! .CODE. psect
PTR[IDADDR] = .HILOC;
PTR[IDPSECT] = PSCODE;
IF .FLGREG<OBJECT>
THEN
BEGIN ! .REL being generated
%1434% IF NOT .PTR[IDATTRIBUT(INEXTERN)]
%1434% THEN
%1434% BEGIN
! Byte pointer to low seg data
RDATWD = .PTR[IDCHBP];
%1261% IF .PTR[IDATTRIBUT(INCOM)]
%1261% THEN ! Output byte pointer with
%1261% ! a RH fixup request
%1261% BEGIN ! COMMON
! Output byte pointer,
! no relocation
%2330% Z30CODE(PSABS,PSCODE);
! Get pointer to
! COMMON block
%1261% R2 _ .PTR[IDCOMMON];
![2330] Output additive
![2330] fixup for
![2330] descriptor at
![2330] HILOC - use
![2330] EXTENDED flag
![2330] to decide on
![2330] 18 or 30 bit.
%2330% IF EXTENDED
%2330% THEN ZSYMBOL(
%2330% GLB30ADDFIX,
%2330% .R2[COMNAME],
%2330% .HILOC,
%2330% PSCODE)
%1512% ELSE ZSYMBOL(
%1512% GLB18ADDFIX,
%1512% .R2[COMNAME],
%1512% .HILOC,
%1512% PSCODE);
%1261% END ! COMMON
%2330% ELSE ! NOT INCOM
%2330% BEGIN ! NOT COMMON
![2330] Output BP to
![2330] high seg with
![2330] relocation
%2330% Z30CODE(
%1526% .PTR[IDPSCHARS],
%1526% PSCODE);
%2330% END ! NOT COMMON
%1434% END
%1434% ELSE
%1434% BEGIN ! function is declared external
![2330] Store address at HILOC
![2330] with additive fixup.
![2330] Use an IFIW under
![2330] /NOEXTEND to keep
![2330] things section
![2330] independant, in case
![2330] someone wants to
![2330] execute by mapping into
![2330] a non-zero section.
%2330% IF EXTENDED ! N sections?
%2330% THEN
%2330% BEGIN ! EXTENDED
%2330% RDATWD = 0; ! EFIW
%2330% Z30CODE(PSABS,PSCODE);
%2345% ZSYMBOL(GLB30ADDFIX,
%2330% .PTR[IDSYMBOL],
%2330% .HILOC,PSCODE);
%2330% END ! EXTENDED
%2330% ELSE ! One section, use IFIW
%2330% BEGIN ! NOT EXTENDED
%1434% RDATWD = 1^35; ! IFIW
%2330% Z30CODE(PSABS,PSCODE);
%2345% ZSYMBOL(GLB18ADDFIX,
%1512% .PTR[IDSYMBOL],
%1512% .HILOC,PSCODE);
%2330% END; ! NOT EXTENDED
%1434% END;
HILOC _ .HILOC + 1;
! Length of character scalar or array
RDATWD _ .PTR[IDCHLEN];
! Output length to high seg with no
! relocation
%2330% Z30CODE(PSABS,PSCODE);
HILOC _ .HILOC + 1
END ! of .REL being generated
ELSE HILOC _ .HILOC + 2
END; ! Non- dummy
! List symbol name, descriptor address, low seg data position, and length
IF .FLGREG<LISTING>
THEN LISTCHD(.PTR,.PTR[IDCHBP]);
%1522% ! Check for illegal length star declaration.
%1522% ! Length star is legal only for dummy arguments
%1522% ! and character parameters.
%1522% IF NOT .PTR[IDATTRIBUT(DUMMY)]
%1522% THEN IF .PTR[IDCHLEN] EQL LENSTAR
%1522% THEN FATLERR(.PTR[IDSYMBOL],0,E194<0,0>)
END; ! Character
PTR _ .PTR[CLINK]; ! Next linked list entry
END ! Walk down linked list
END; ! Walk through hash table entries
%1434% ! Now setup all character entry points to use the descriptor of
%1434% ! the main entry point
%1434% IF .FLGREG<PROGTYP> EQL FNPROG THEN
%1434% IF .MULENTRY NEQ 0
%1434% THEN
%1434% BEGIN
%1434% ENTRY = .PROGNAME; ! Lookup the symbol table entry
%1434% ! for the function name
%1434% NAME = IDTAB; ! It's an identifier
%1434% FUNC = TBLSEARCH(); ! Search for it
%1434% IF .FUNC[VALTYPE] EQL CHARACTER
%1434% THEN
%1434% BEGIN ! Multi-entry character function
%1434% ENT = .MULENTRY; ! Linked list of entry points
%1434% ! Copy IDADDR field of function name into IDADDR fields for the entry points
%1434% DO ENT[IDADDR] = .FUNC[IDADDR]
%1434% WHILE (ENT = .ENT[IDENTLNK]) NEQ 0;
%1434% END; ! Multi-entry character function
%1434% END;
END; ! of HSCHD
GLOBAL ROUTINE HSDDESC=
BEGIN
%1406% ! Written by TFV on 27-Oct-81
! Output .Dnnnn compile-time-constant character descriptors to the
! .REL file. Either one word (byte pointer only) or two words
! (byte pointer and length) are output based on the flag
! IDGENLENFLG. One word .Dnnnn variables are used for SUBSTRINGs
! with constant lower bounds and non-constant upper bounds. Fill
! in the IDADDR field with the address of the descriptor. Use
! LISTCHD to output the descriptor to the .LST file.
REGISTER BASE DPTR: SUBNODE;
MAP BASE R2;
DPTR = .DANCHOR; ! Start at first .Dnnnn variable
WHILE .DPTR NEQ 0 DO ! Walk down linked list
BEGIN
%1567% IF NOT .DPTR[IDATTRIBUT(NOALLOC)]
%1627% THEN IF .DPTR[IDADDR] NEQ 0 ! skip .D's allocated for function
%1627% ! return values where the function was
%1627% ! CHAR(constant) in a parameter stmt
%1567% THEN
%1567% BEGIN ! Do only if we want to allocate this .Dnnn
! Get the subnode for the data from either a .Qnnnn
! variable (function calls and concatenation) or a symbol
! table entry for a scalar (substring) or array (arrayref)
SUBNODE = .DPTR[IDADDR];
DPTR[IDPSECT] = PSCODE; ! Descriptor is in the hiseg
DPTR[IDPSCHARS] = .SUBNODE[IDPSCHARS]; ! Psect for the data
! Form the byte pointer from the byte pointer in the subnode
IF .DPTR[IDBPOFFSET] NEQ 0
%2216% THEN RDATWD = BPADD(.SUBNODE[IDCHBP],.DPTR[IDBPOFFSET])
ELSE RDATWD = .SUBNODE[IDCHBP];
DPTR[IDCHBP] = .RDATWD; ! Put byte pointer in IDCHBP
DPTR[IDADDR] = .HILOC; ! Location of the descriptor
! Output byte pointer
IF .FLGREG<OBJECT> THEN
%1451% BEGIN ! generating .REL file
%1451% IF .SUBNODE[IDATTRIBUT(INCOM)]
%1451% THEN ! If byte pointer is in common
%1451% BEGIN ! Output with RH fixup request
%2330% Z30CODE(PSABS,PSCODE); ! Output byte pointer,
%1451% ! no relocation
%1451% R2 _ .SUBNODE[IDCOMMON]; ! COMMON block name
! Output RH additive fixup request to LINK for word at HILOC
%2330% IF EXTENDED ! /EXTEND?
%2330% THEN ZSYMBOL(GLB30ADDFIX,.R2[COMNAME],
%2330% .HILOC,PSCODE)
%2330% ELSE ZSYMBOL(GLB18ADDFIX,.R2[COMNAME],
%1512% .HILOC,PSCODE);
%1451% END
%2330% ELSE Z30CODE(.DPTR[IDPSCHARS],PSCODE); ! Use RH relocation
%1451% END; ! generating .REL file
HILOC = .HILOC + 1;
IF .DPTR[IDGENLENFLG]
THEN
BEGIN ! Output length to hiseg with no relocation
! SUBSTRING nodes with a constant lower bound and
! non-constant upper bound only use the byte pointer
RDATWD = .DPTR[IDCHLEN];
IF .FLGREG<OBJECT>
%2330% THEN Z30CODE(PSABS,PSCODE);
HILOC = .HILOC + 1;
END; ! of outputting length
! List symbol name, descriptor address, lowseg data position,
! and length
IF .FLGREG<LISTING> AND .FLGREG<MACROCODE>
THEN LISTCHD(.DPTR,.DPTR[IDCHBP]);
%1522% ! Cause an internal compiler error if the .Dnnnn
%1522% ! variable has a length less than 1.
%1522% IF .DPTR[IDGENLENFLG] THEN
%1522% IF .DPTR[IDCHLEN] LEQ 0 THEN CGERR();
%1567% END; ! Want to allocate
DPTR = .DPTR[CLINK] ! Get next linked list entry
END ! Walk down linked list
END; ! of HSDDESC
GLOBAL ROUTINE HDRCHD=
BEGIN
%1232% ! Written by TFV, 17-Jun-81
! Output header to .LST file for character data section
%2311% IF EXTENDED
%2311% THEN
%2311% LSTHDR(7, 6, PLIT '?M?JCHARACTER DATA [ "*" NO EXPLICIT DEFINITION - "!" VARIABLE STORED IN .LARG. ]
?J NAME ?I?IDESCRIPTOR ADDRESS ?ISTART OF DATA ?ILENGTH
?J?I?I?I?I?IADDR(POSITION)?M?J?M?J?0')
%2311% ELSE
LSTHDR(7, 6, PLIT '?M?JCHARACTER DATA [ "*" NO EXPLICIT DEFINITION ]
?J NAME ?I?IDESCRIPTOR ADDRESS ?ISTART OF DATA ?ILENGTH
?J?I?I?I?I?IADDR(POSITION)?M?J?M?J?0');
END; ! of HDRCHD
GLOBAL ROUTINE TABOUT=
BEGIN
%1232% ! Written by TFV, 17-Jun-81
! Output a tab to the listing
CHR _ #11; ! TAB
LSTOUT();
END; ! of TABOUT
GLOBAL ROUTINE ZOUTBP(OBP)=
BEGIN
%1232% ! Written by TFV, 17-Jun-81
REGISTER BASE BP;
MAP
BASE R2,
BASE OBP;
! Output the start address of character data as addr(charpos)
%2330% IF NOT EXTENDED ! Local byte pointers?
%2216% THEN
! Convert #010700,,FOO-1 TO #440700,,FOO
IF .OBP<LEFT> EQL #010700
THEN BP = #440700 ^ 18 + .OBP<RIGHT> + 1
ELSE BP = .OBP
%2216% ELSE ! Convert #66ssss,,FOO-1 TO #61ssss,,FOO
%2216% IF .OBP<30,6> EQL #66
%2216% THEN BP = #61^30 + .OBP<0,30> + 1
%2216% ELSE BP = .OBP;
%2330% IF EXTENDED ! Global byte pointers?
%2311% THEN
%2311% BEGIN !/EXTEND
%2311% R2 _ .BP<0,30>; !GET LONG ADDR
%2311% ZOUTADDR(); !OUTPUT IT
%2311% END !/EXTEND
%2311% ELSE
%2311% BEGIN !NO /EXTEND
R2<LEFT> _ .BP<RIGHT>; ! Get the address of data
ZOUTOCT() ! Output it
%2311% END; !NO /EXTEND
CHAROUT("("); ! Output a (
%2344% IF .OBP NEQ 0 ! Was the BP good?
%2344% THEN
%2344% BEGIN ! Good BP
%2330% IF NOT EXTENDED ! Local byte pointers?
%2216% THEN ! Yes
%2216% BEGIN ! NOT EXTENDED
R1 _ .BP<30,6>; ! Get P field of byte pointer
R1 _ (43 - .R1) / 7; ! Compute charpos 1-5
%2216% END ! NOT EXTENDED
%2216% ELSE ! No, global byte pointers
%2216% BEGIN ! EXTENDED
%2216% R1 _ .OBP<30,6>; ! Get P&S field of byte pointer
%2311% R1 _ (.R1-#60); ! Compute charpos 1-5
%2216% END; ! EXTENDED
%2344% ZOUDECIMAL() ! Output byte offset
%2344% END ! Good BP
%2344% ELSE CHAROUT("??"); ! No, bad BP, be silly
CHAROUT(")"); ! Output a )
END; ! of ZOUTBP
GLOBAL ROUTINE LISTCHD(PTR,BP)=
BEGIN
%1232% ! Written by TFV, 17-Jun-81
! Output character data name, descriptor address, start of data, and length
MAP BASE PTR:R2;
IF .HDRFLG EQL 0 ! Output header if needed
THEN
BEGIN ! Output character data banner
HDRFLG_1;
HDRCHD();
END; ! Output character data banner
! Output variable name or TAB for constants
IF .PTR[OPERATOR] EQL CHARCONST
THEN
BEGIN ! Character constant
%1534% REGISTER COL,CC,C;
%1534% LOCAL CP;
! Output 'cccccc' to listing
%1534% CHAROUT("'"); ! start with '
%1534% COL = 2; ! we are now at col 2
%1534% CP = PTR[LITC1]; ! set character pointer
%1534% CC = .PTR[LITLEN]; ! and character count
%1534% WHILE (.CC GTR 0) AND (.COL LEQ 11) ! print up to 10 chars
%1534% DO
%1534% BEGIN
%1534% C = SCANI(CP); ! get char from string
%1534% IF .C EQL #177 THEN C = -1; ! print rubout as ^?
%1534% IF .C LSS #40 ! control char?
%1534% THEN (CHAROUT("^"); CHAROUT(.C+#100); COL = .COL + 1)
%1534% ELSE CHAROUT(.C); ! no, print normally
%1534% COL = .COL + 1; ! increment col count
%1534% CC = .CC - 1; ! decrement char count
%1534% END;
%1534%
%1534% CHAROUT("'"); ! print closing '
%1534% IF .CC GTR 0 THEN STRNGOUT(UPLIT ASCIZ '...');
%1534% ! print dots if whole
%1534% ! constant didn't get
%1534% ! printed
%1534% IF .COL LSS 8 THEN TABOUT(); ! print extra tab to
%1534% ! line up tab stops
END ! Character constant
ELSE
BEGIN ! Character variable
R2 _ .PTR[IDSYMBOL]; ! Name of variable
%2311% ! Output "!" if stored in .LARG. else,
! output "*" if not explicitly defined.
%2311% ! (IE; Large overrides not defined)
%2311% ! Information can be lost when a variable is
%2311% ! by IMPLICIT CHARACTER*<bignumber>.
%2311% IF .PTR[IDPSCHARS] EQL PSLARGE !IF LARGE CHARACTER DATA
%2311% THEN CHAROUT("!") ! FLAG FROM LARGE PSECT W/ A BANG!
%2311% ELSE
IF NOT .PTR[IDATTRIBUT(INTYPE)] AND .PTR[OPRSP1] NEQ ARRAYNM1
THEN
BEGIN ! Don't output "*" for .Dnnnn variables
IF .R2<30,6> NEQ SIXBIT "." THEN CHAROUT("*")
END ! Don't output "*" for .Dnnnn variables
ELSE CHAROUT(" ");
ZOUTSYM(); ! Output it
TABOUT(); ! Output a TAB
END; ! Character variable
TABOUT(); ! Output a TAB
! Output descriptor address
IF .PTR[OPERATOR] NEQ CHARCONST AND .PTR[IDPSECT] EQL PSDATA
THEN
BEGIN ! It's a lowseg address
R2<LEFT> _ .PTR[IDADDR]; ! Lowseg address
ZOUTOCT(); ! Output it to listing
TABOUT(); ! Output extra TAB
END ! It's a lowseg address
ELSE
BEGIN ! It's a hiseg address
STRNGOUT(UPLIT ASCIZ '.HSCHD'); ! Address of start of hiseg descriptors
R1 _ .PTR[IDADDR] - .CHDSTART; ! Offset from .HSCHD
ZOUOFFSET(); ! Output + offset
END; ! It's a hiseg address
TABOUT(); ! Output a TAB
TABOUT(); ! Output another TAB
! Output start of character data as addr(charpos)
! charpos is 1 for first char, 5 for last in word
%1434% IF .PTR[OPERATOR] NEQ CHARCONST
%1434% THEN
%1434% BEGIN
%1434% IF .PTR[IDATTRIBUT(DUMMY)]
THEN STRNGOUT(UPLIT ASCIZ '(argument)') ! Dummy argument
%1434% ELSE IF .PTR[IDATTRIBUT(INEXTERN)]
%1434% THEN STRNGOUT(UPLIT ASCIZ '(external)') ! External function
%1434% ELSE
BEGIN ! Output character constant data address
ZOUTBP(.BP); !OUTPUT BP
%2330% IF EXTENDED ! Global byte pointers?
%2311% THEN !IF /EXTENDED
%2311% (IF .BP<0,30> LSS #10000 !CHECK 30 BITS OF OWG
%2311% THEN TABOUT()) !OUTPUT TAB IF NEEDED
%2311% ELSE !IF /NOEXTEND
%2311% (IF .BP<RIGHT> LSS #10000 !CHECK 18 BITS
%2311% THEN TABOUT()); ! Output an extra TAB
END; ! Output character constant data address
%1434% END
%1434% ELSE
BEGIN ! Output character constant data address
ZOUTBP(.BP);
%2330% IF EXTENDED ! Global byte pointers?
%2311% THEN
%2311% (IF .BP<0,30> LSS #10000
%2311% THEN TABOUT())
%2311% ELSE
IF .BP<RIGHT> LSS #10000
THEN TABOUT(); ! Output an extra TAB
END; ! Output character constant data address
TABOUT(); ! Output a TAB
! Output the length
IF .PTR[OPERATOR] EQL CHARCONST
THEN R1 _ .PTR[LITLEN]
ELSE R1 _ .PTR[IDCHLEN];
IF .R1 EQL LENSTAR ! Is it length *
THEN STRNGOUT(UPLIT ASCIZ '(*)') ! Output a (*)
ELSE ZOUDECIMAL(); ! Output the length
CRLF; ! Output a CRLF
HEADCHK(); ! Check for bottom of listing page
END; ! of LISTCHD
%[735]% ROUTINE HDRTMP=
%[735]% LSTHDR(4,3,PLIT'?M?JTEMPORARIES?M?J?M?J?0');
GLOBAL ROUTINE ALCQVARS=
BEGIN
! Routine cleans up the allocation of .Qnnnn variables.
! These are the temps generated by the local register allocator
%2311% LOCAL HOWIDE; !NUMBER OF SYMBOLS / LISTING LINE
%1274% REGISTER LEN,BASE SYMPTR;
! Now (for either subprogram or main program, allocate and list
! the temps generated by local register allocation
%2311% IF .FLGREG<LISTING>
%2311% THEN
%2311% HOWIDE = IF EXTENDED THEN 3 !THIS MANY SYBOLS / LINE UNDER /EXTEND
%2311% ELSE 5; !OTHERWISE DO MORE
%1274% SYMPTR = .QANCHOR; ! Start at the beginning
%1274% WHILE .SYMPTR NEQ 0 DO
BEGIN
%1274% LEN = .SYMPTR[IDADDR]; ! Address in .Q space for this variable
%1274% SYMPTR[IDADDR] = .LOWLOC + .LEN; ! Actual address for this variable
%1406% SYMPTR[IDCHBP] = BPGEN(.SYMPTR[IDADDR]); ! Setup byte pointer
IF .FLGREG<LISTING>
%[735]% THEN
BEGIN
IF .HDRFLG EQL 0
THEN
BEGIN
HDRFLG = 1;
HDRTMP();
END;
%1274% LISTSYM(.SYMPTR);
TCNT = .TCNT + 1;
%2311% IF .TCNT GTR .HOWIDE
THEN
BEGIN
TCNT = 0;
CRLF;
HEADCHK();
END
END;
%1274% SYMPTR = .SYMPTR[CLINK]; ! Next .Q to allocate
END; ! WHILE .SYMPTR NEQ 0
%1274% LOWLOC = .LOWLOC + .QMAX; ! Set up lowloc to after end of .Q space
IF .FLGREG<LISTING>
THEN
BEGIN
CRLF;
HEADCHK();
END;
END; ! of ALCQVARS
GLOBAL ROUTINE HISEGBLK=
BEGIN
!ROUTINE GENERATES A HISEG BLOCK IN THE THE REL FILE
!WORD 1 OF THE HISEG BLOCK IS THE TWOSEG PSEUDO OP ID
!WORD 2 IS THE SIZE OF THE LOWSEG IN WORDS IN THE LEFT HALF
! AND ZERO IN THE RIGHT HALF
!WORD 2 IS ONLY USEFUL IF WE WISH TO LOAD EXECUTABLE CODE IN THE LOWSEG
! INSTEAD OF THE HISEG
%1526% CHDSTART = HILOC = 0; ! First free location in .CODE.
%1245% ! and start of character descriptors
%470% IF .LOWLOC LSS #400000-#1000 ! Will the lowseg overlap the hiseg ?
%1526% THEN HIORIGIN = #400000 ! No, start at halfway point
%1526% ELSE HIORIGIN = (.LOWLOC+#777+#1000) AND #777000; ! Yes, round up
IF .FLGREG<OBJECT>
THEN
BEGIN
%1525% IF EXTENDED ! Psected compilation ?
%1525% THEN DMPMAINRLBF() ! Yes, flush out lowseg constants
%1525% ELSE ! No, define segments
%1525% BEGIN
%1526% RDATWD = .HIORIGIN^18 + .HIORIGIN; ! In both halves
ZOUTBLOCK(RHISEG,RELRI);
RDATWD = .LOWLOC^18 + 0;
ZOUTBLOCK(RHISEG,RELN)
%1525% END;
%1245% ! Output symbol .HSCHD for character data listing section
%1512% ZSYMBOL(LOCSUPDEF,SIXBIT '.HSCHD',.CHDSTART,PSCODE)
END;
END; ! of HISEGBLK
GLOBAL ROUTINE RELINIT=
BEGIN
!++
!********************************************************
! Initializes .REL file, generating these LINK blocks
!
! 4 - ENTRY
! 6 - NAME
![2446] 1050 - PSECT HEADER
! 1131 - Segment redirection (/EXTEND only)
!
!********************************************************
!--
LOCAL
INDEX, ! last psect index
NAME[2]; ! Holds single word psect names
REGISTER
%1434% BASE ENT;
BIND
! Various bits for the name block
%1003% KSCPU = 1^33, ! KS10 cpu type
%1003% KLCPU = 1^32, ! KL10
%1666% FTNID = #10^18, ! FORTRAN compiler id
! Origins for the various segments
%2440% DATAORG = #1001000,
%2356% CODEORG = #1300000,
%1525% LARGEORG = #2000000;
INIRLBUFFS(); ! Initialize the .REL file buffers
! Initialize the entry block
%1434% R2 = .PROGNAME; ! First the program name
%1434% RDATWD = RADIX50();
%1434% ZOUTBLOCK(RENTRY,RELN);
%1434% ENT = .MULENTRY; ! Now any entry points
%1434% WHILE .ENT NEQ 0 DO
%1434% BEGIN
%1434% R2 = .ENT[IDSYMBOL]; ! Get the entry name
%1434% RDATWD = RADIX50();
%1434% ZOUTBLOCK(RENTRY,RELN);
%1434% ENT = .ENT[IDENTLNK];
%1434% END;
R2 = .PROGNAME;
RDATWD = RADIX50();
ZOUTBLOCK(RNAME,RELN); !NAME BLOCK
![1003] Output compiler type to .REL file.
%1666% RDATWD = FTNID;
%1703% ! To include a processor type into the rel file, include some
%1703% ! part(s) of the below lines to the assignment to RDATWD. We
%1703% ! are not specifying any processor, since V5A specified only KI,
%1703% ! and V7 will not run on a KI. If we tell the truth, then V7
%1703% ! users with a V5A library will get Link-time warnings.
%1703% ![1525] KS processors are non-extended and non-gfloating.
%1703% ! OR KLCPU OR
%1703% ! (IF NOT .GFLOAT AND NOT EXTENDED THEN KSCPU ELSE 0);
%1666% ZOUTBLOCK(RNAME,RELN); ! FORTRAN compiler id and CPU bits
%1525% IF EXTENDED
THEN
BEGIN ! /EXTEND switch given
! Define the psect names, attributes, indices and
! origins.
DMPMAINRLBF(); ! Make sure the type 4 blocks
! gets out first
! Note that LINK has a hidden restriction that you
! must define psects in increasing psect index order.
! If the values of PXCODE, PXDATA and PXLARGE change,
%2446% ! the following paragraphs should be changed.
%2446% NAME[0] = 1;
%2446% NAME[1] = SIXBIT '.LARG.';
%2446% TYPE1050(HINAME,PXCODE,PACODE,CODEORG);
%2446% TYPE1050(LONAME,PXDATA,PADATA,DATAORG);
%2446% TYPE1050(NAME,PXLARGE,PALARGE,LARGEORG);
%2446% INDEX = PXLARGE; ! last psect index
%2446% IF (.HINAME[0] NEQ 1) OR (.HINAME[1] NEQ SIXBIT ".CODE.")
%2446% THEN
%2446% BEGIN
%2446% NAME[1] = SIXBIT '.CODE.';
%2446% TYPE1050(NAME,INDEX=.INDEX+1,PACODE,CODEORG);
%2446% END;
%2446% IF (.LONAME[0] NEQ 1) OR (.LONAME[1] NEQ SIXBIT ".DATA.")
%2446% THEN
%2446% BEGIN
%2446% NAME[1] = SIXBIT '.DATA.';
%2446% TYPE1050(NAME,INDEX=.INDEX+1,PADATA,DATAORG);
%2446% END;
%2310% ! Output PSECT redirection information rel block
%2310%
%2310% PSREDIRECT();
%1525% END; ! /EXTEND switch given
END; ! of RELINIT
GLOBAL ROUTINE TYPE1050(NAME,INDEX,ATTRIB,ORIGIN)=
!++
! FUNCTIONAL DESCRIPTION:
!
! This routine puts out a type 1050 rel block
!
! FORMAL PARAMETERS:
!
! NAME word 0 = number of words in psect name
! word 1-12 = psect name
! INDEX psect index
! ATTRIB psect attributes
! ORIGIN psect origin
!
! IMPLICIT INPUTS:
!
! None
!
! IMPLICIT OUTPUTS:
!
! None
!
! ROUTINE VALUE:
!
! None
!
! SIDE EFFECTS:
!
! None
!
!--
! New [2446] MEM
BEGIN
STRUCTURE
PVECTOR[WD]= ! Structure for a pointer to a vector
(@.PVECTOR + .WD);
MAP
PVECTOR NAME;
LOCAL
MYRELBUF[17], ! Holds various REL block types
! 13 words are needed for the psect name and long count
! plus words for block type / long count, index,
! attributes, origin
NAMELEN, ! number of words in the psect name
ATTINDX; ! index into MYRELBLOCK of attributes
MYRELBUF[1] = .INDEX;
NAMELEN = .NAME[0]; ! number of words in psect name
IF .NAMELEN EQL 1
THEN
BEGIN
MYRELBUF[2] = .NAME[1];
MYRELBUF[3] = .ATTRIB;
MYRELBUF[4] = .ORIGIN;
! Don't specify an origin if it is not .DATA.,.CODE. or .LARG.
IF (.NAME[1] NEQ SIXBIT '.DATA.') AND
(.NAME[1] NEQ SIXBIT '.CODE.') AND
(.NAME[1] NEQ SIXBIT '.LARG.')
THEN
BEGIN
MYRELBUF[0] = RLONGPSECTHEAD^18 OR 3;
DMPRLBLOCK(MYRELBUF,4);
END
ELSE
BEGIN
MYRELBUF[0] = RLONGPSECTHEAD^18 OR 4;
DMPRLBLOCK(MYRELBUF,5);
END;
END
ELSE
BEGIN
MYRELBUF[2] = .NAMELEN;
INCR I FROM 1 TO .NAMELEN DO MYRELBUF[.I+2] = .NAME[.I];
ATTINDX = 3 + .NAMELEN;
MYRELBUF[.ATTINDX] = .ATTRIB;
MYRELBUF[0] = RLONGPSECTHEAD^18 OR
(.ATTINDX); ! type & count
DMPRLBLOCK(MYRELBUF,.ATTINDX+1);
END;
END;
GLOBAL ROUTINE PSREDIRECT= ![2310] New
!++
! FUNCTIONAL DESCRIPTION:
!
! Output a type 1131 PSECT redirection block for LINK when
! compiling /EXTEND. This will make all low segment code go into
! a specific PSECT and all high segment code go into another (the
! names can be given by the user). The caller decides if
! compilation is done /EXTEND.
!
! FORMAL PARAMETERS:
!
! None
!
! IMPLICIT INPUTS:
!
! DEFLON Default name of the low (data) PSECT. Word 0 is
! the count of the number of SIXBIT words in name.
!
! DEFHIN Default name of the high (code) PSECT. Word 0 is
! the count of the number of SIXBIT words in name.
!
! IMPLICIT OUTPUTS:
!
! None
!
! ROUTINE VALUE:
!
! None
!
! SIDE EFFECTS:
!
! Outputs a rel block.
!
!--
BEGIN
LOCAL HEADERWD;
! Make sure we've finished dumping out other rel blocks.
DMPMAINRLBF();
! Dump our block. Output 1 word at a time. The names and
! lengths of the PSECT's may vary, so we must use variables.
%2454% HEADERWD = RREDIRECT^18 OR (.DEFLON[0]+.DEFHIN[0]+2);
%2446% DMPRLBLOCK(HEADERWD, 1); ! Header; 1131,,count
%2454% DMPRLBLOCK(DEFLON, .DEFLON[0]+1); ! Count and Name of data psect
%2454% DMPRLBLOCK(DEFHIN, .DEFHIN[0]+1); ! Count and Name of code psect
END; ! of PSREDIRECT
ROUTINE CIMPLNONE= ! [2507] New
!++
! FUNCTIONAL DESCRIPTION:
!
! Walk the symbol table to check for any symbols that should be
! output for IMPLICIT NONE that haven't been yet. We primarily
! will catch the unallocated variables at this point.
!
! FORMAL PARAMETERS:
!
! None
!
! IMPLICIT INPUTS:
!
! E304 Warning for IMPLICIT NONE
!
! SYMTBL Hashed symbol table entries
!
! IMPLICIT OUTPUTS:
!
! None
!
! ROUTINE VALUE:
!
! None
!
! SIDE EFFECTS:
!
! None
!
!--
BEGIN
REGISTER BASE SYM; ! The symbol table entry
! Go through every symbol in the symbol table.
DECR CNT FROM SSIZ-1 TO 0
DO
BEGIN ! Walk each hash bucket in the symbol table
SYM = .SYMTBL[.CNT]; ! This hash entry
! If this isn't zero, then there's a symbol here. The
! entries are linked together within a hash bucket, so walk
! all of them in this bucket and check them.
WHILE (.SYM NEQ 0)
DO
BEGIN ! Contents of each bucket in the symbol table
! If IMPLICIT NONE is given, then we must insure that
! the variable is declared in a type statement,
! Unless:
! - The warning has already been given for
! this symbol
! - The symbol was in a type statement
! - The symbol is a Fortran temporary (has
! "." as first char)
! - The symbol is a NAMELIST name
! - The symbol is a COMMON block name, but not
! in a COMMON statement;
! COMMON /FOO/ A,FOO,B
! - The symbol is a subroutine name, and not
! also a variable name (can only happen in a
! subroutine program)
! - The symbol is a valid subroutine name
! (for the form of calling a function)
! - The symbol is a library function
! - The symbol is a function entry name and
! we're compiling a MAIN program (so the name
! is a main program name)
! - The symbol has a library function name
! (The symbol table reference for the
! original undotted name appears just like a
! variable)
! This is structured to not slow down the majority
! of cases, since the entire symbol table is
! walked. IF THEN's generate faster code than
! IF AND's.
IF NOT .SYM[IDIMPLNONE] ! Message already given
THEN IF NOT .SYM[IDATTRIBUT(INTYPE)] ! Declared
THEN IF .SYM[IDDOT] NEQ SIXBIT"." ! Dotted name
THEN IF NOT .SYM[IDATTRIBUT(NAMNAM)] ! NAMELIST
THEN IF NOT (.SYM[IDATTRIBUT(COMBL)] ! COMMON block
AND NOT .SYM[IDATTRIBUT(INCOM)])
THEN IF NOT (.SYM[IDSUBROUTINE] ! Subroutine
AND .SYM[IDATTRIBUT(NOALLOC)]) ! or var?
THEN IF NOT (.SYM[OPR1] EQL FNNAMFL ! External name
AND (.SYM[IDLIBFNFLG] ! library fn
OR .SYM[IDSUBROUTINE])) ! subroutine
THEN IF NOT (.FLGREG<PROGTYP> EQL MAPROG ! Main program
AND .SYM[IDATTRIBUT(FENTRYNAME)])
THEN IF SRCHLIB(.SYM) EQL -1 ! Not lib fn, undotted
! name would appear to
! be a variable
THEN
BEGIN ! Give a warning, this symbol must be declared!
FATLERR(.SYM[IDSYMBOL], 0, E304<0,0>);
SYM[IDIMPLNONE] = 1; ! Gave message
END; ! Give a warning, this symbol must be declared!
SYM = .SYM[CLINK]; ! Next linked symbol (or 0)
END; ! Contents of each bucket in the symbol table
END; ! Walk each hash bucket in the symbol table
END; ! of CIMPLNONE
END
ELUDOM