EXTERNAL
function.
Use your editor to view the file
PRODSLD:UCHKTAG.PREPMORT
" This is a Comment "
" This is a comment that extends over two lines "
DELTAG = -1;
DIAG = SQRT( (XVALUE1 - XVALUE2)**2 + (YVALUE1 - YVALUE2) **2 + (ZVALUE1 - ZVALUE2) **2 );
UCHKTAG
file is everything
up to but not including:
"&COMMON/JAZELL/"Many lines in the header section are enclosed in Prepmort comment characters. However, some of these comment lines are actually used by the Prepmort compiler and the DUCS code distribution software. So do not assume that these lines can be left out.
Many of these comment lines are read by DUCS when the file is installed for use by the rest of the SLD collaboration. The lines contain information that DUCS turns into a help file. Thus every routine that contains a properly written header will automatically generate a help file when it is installed into DUCS.
$SLD_INTEGER_FUNCTION
.
The declaration includes the name and type of all of the routine's arguments.
In the current example, the integer function definition extends over four
lines.
KEYWORDS
line is another special comment line used
by the automatic help system. The applications that were meant to use
these keywords were never implemented, so you can actually put whatever you
want on this line. Just put in a few relevant words that people searching
through files might use to find this particular file.
When the file is installed into DUCS, a help file is generated. The help can be read by issuing the help command from DCL with the appropriate library specified. Separate help libraries are maintained for each DUCS section.
Since the file UCHKTAG.PREPMORT
lives in section SLD,
you can view it with the command:
HELP/LIBRARY=DUCSSLD:SLDAs another example, you could view the help library for section MFIT:
HELP/LIBRARY=DUCSMFIT:MFIT
UCHKTAG
file is everything from
"&COMMON/JAZELL/"through
LOGICAL FIRST / .TRUE. /;This part of the file declares what external code is to be included, what variables are to be used and what initial values these variables are to have.
"&
can not have spaces before them.
F_MA_BEL
and P_MA_BEL
are both declared to
be pointers to the Jazelle family MA_BEL
.
The comma in this statement allows you to declare more than one pointer
with a single statement.
The same pointers could have been set up with a pair of statements:
POINTER F_MA_BEL --> MA_BEL; POINTER P_MA_BEL --> MA_BEL;As was mentioned earlier, any statement can stretch over multiple lines. The end of the statement is determined by the semicolon. The spaces have no significane; they are only there to make the code easy to read. A statement can stretch over up to 19 lines.
UCHKTAG
routine.
How you do this declaration depends on what kind of routine will be called.
Some examples are as follows:
$SLD_INTEGER_FUNCTION
,
declare it with an INTEGER
statement.
Most SLD offline routines are of this type.
For example:
INTEGER JZBLOC;
$SLD_REAL_FUNCTION
,
declare it with a REAL
statement.
For example:
REAL ULMASS;
$SLD_DOUBLE PRECISION_FUNCTION
,
declare it with a REAL
statement.
For example:
REAL*8 JZS8;
$SLD_CHARACTER*(*)_FUNCTION
,
declare it with a CHARACTER
statement.
The CHARACTER
statement requires an additional number
to tell how long the string will be. Examples are:
CHARACTER*8 JZC8; CHARACTER*80 JZC;
INTEGER PREVTAG; INTEGER SEVTAG; INTEGER SAVCTRAC(10); INTEGER SAVCTRIB(10); INTEGER I;Or it could be written:
INTEGER PREVTAG, SEVTAG, SAVCTRAC(10), SAVCTRIB(10), I;Or they could have been grouped many other ways. You get the idea.
There is no real reason that this integer statement could not be joined
to the one that declared the routine JZBLOC
.
That might have looked as follows:
INTEGER JZBLOC, PREVTAG, SEVTAG, SAVCTRAC(10), SAVCTRIB(10), I;In general, it keeps things more clear if you separate the function declarations from the variable declarations. But this is not required.
The arrays like SEVCTRAC(10)
contain elements indexed from
SEVCTRAC(1)
to SEVCTRAC(10)
.
You also have the option of specifying your start and end indexes.
For example, if you want the elements of SEVCTRAC
to be indexed from SEVCTRAC(0)
to SEVCTRAC(9)
:
INTEGER SAVCTRAC(0:9);
Be careful. If no initial value is declared, the variable will initially contain whatever value happens to be in the piece of memory that the computer allocates to that variable. This could make your routine behave differently depending on what order code is loaded in or on what order you run other unrelated functions.
To repeat: the offline sortware system will not initialize the variable unless you tell it to.
REAL*4
,
REAL
(same as REAL*4
),
CHARACTER*8
,
CHARACTER*
some other string size.
Here are some other examples of variable declarations:
REAL MCST(0:7), "cos(theta) from hits" Integer Nmc, Nktag, I, Nhits, Iktag, IdKtag, Imc, Imcs, IdMc, IdMc0, Layer, McId, Adc, Igain(0:7)/1,1,2,2,2,2,3,3/; CHARACTER*9 VALSTRG / 'VALUATOR=' /; REAL XARRAY(8), YARRAY(8); Real*4 bPos(3)/0.,0.,0./ ;
UCHKTAG
example starts with a very common construction
called the "If First Block."
This construction works together with the last declarations statement.
Together, they create a section of code that will only be executed the first
time the routine is called:
LOGICAL FIRST / .TRUE. /; IF FIRST [ $CALL JZBLOC( 'MA_BEL', F_MA_BEL ) ERROR RETURN; FIRST = .FALSE.; ]
$CALL
.
We will talk about this particular called routine, JZBLOC
a little later when we talk about calling Jazelle from Prepmort.
The $CALL
, the parentheses and the ERROR RETURN
are required for all calls to other Prepmort routines.
The Prepmort pre-compiler turns this construction into a standard
Fortran call plus some extra code that allows informational and error
messages to be handled in a sophisiticated way.
We will talk about this message handling later when we discuss the
Signal system.
Inside the parentheses are the arguments.
JZBLOC
is a routine that finds the pointer to the head
of a Jazelle family.
'MA_BEL'
. Note how strings are delimited by single quotes.
F_MA_BEL
.
This pointer was declared in the declarations section of this routine
to be a pointer to a MA_BEL
bank.
JZBLOC
sets this pointer to point to the zero
MA_BEL
bank, the head of the family.
IF INIT .EQ. 1. [ PREVTAG = 0; DO I = 1, 10 [ SAVTAG(I) = 0; ] ]
IF
statements allow a large number of operators.
In general there are at least two ways to write any operator.
In the following chart, operators on the same line do the same thing:
.GT. > .GE. >= .EQ. = .LE. <= .LT. < .NE. <> ^= .AND. & .OR. | .NOT. ^
DO
statements are self-explanatory. And, unlike IDA,
you can use the loop index outside of the loop.
Thus, after the DO
statement in the example,
you can expect I
to be 10.
MA_BEL
bank. It does this by setting P_MA_BEL
to be one bank forward
from F_MA_BEL
.
P_MA_BEL = F_MA_BEL%(JB$FORPT);In Jazelle, each bank contains the pointer to the next bank in its family.
F_MA_BEL%(JB$FORPT)
is this pointer (the FORPT comes from
FORwards PoinTer).
This construction may look complicated, but there are actually very few such constructions that you will need to learn. For users who are already familiar with other pointer-based languages, such as C, this construction is nothing special.
Instead of using this IF FIRST
construction and the
JB$FORPT
pointer, we could have obtained the pointer to the
first bank directly by calling a different Jazelle routine,
$CALL JZBFND( 'MA_BEL', P_MA_BEL ) ERROR RETURN;This would mean that every time the routine
UCHKTAG
is called,
it has to make a call to the routine JZBFND
.
Since UCHKTAG
might get called a very large number of times,
we chose to use the faster method.
We only call to a Jazelle routine, JZBLOC
, the first time
that UCHKTAG
is called.
Every other time, we get away with a single assignment statement.
MA_BEL
bank in
P_MA_BEL
, we can get the variable TAG
by the
expression
P_MA_BEL%(TAG)The expression starts with the pointer, then has a percent sign, then has the variable name within parentheses.
Here are some examples of other Jazelle variables:
P_MA_BEL%(CONTRACT) P_DSPWIND%(INTERLEV) P_KDGHIT%(HITS(J),TOWERID) PHPSUM%(X(3)) PHCHRG%(HLXPAR(1))
IF...ELSE
structure a little bit later.
IF P_MA_BEL%(TAG) .EQ. SAVTAG(I) [ IF P_MA_BEL%(CONTRACT) .EQ. SAVCTRAC(I) .AND. P_MA_BEL%(CONTRIBU) .EQ. SAVCTRIB(I) [ DUPLICAT = 1; EXIT; ] ELSE [ SPLIT = 1; EXIT; ] ]There is no
THEN
statement in Prepmort.
The block structure defined by the square brackets makes this unnecessary.
EXIT
statement exists the nearest loop.
$RETURN; END;The
$RETURN
is used along with the top line,
$SLD_INTEGER_FUNCTION
, to tie this routine to the other routines
that call it.
The Prepmort pre-compiler turns the $RETURN
into a standard
Fortran RETURN
statement plus some sophisticated error handling
code.
Fortran fans, note that there is no STOP
in the routine.
The STOP
does not belong in any user routines.
DATA
statement can be used to assign an initial value
to a variable. This has the same affect as the method we saw earlier in
which the data was just appended to the end of the variable declaration
statement.
So you could replace:
LOGICAL FIRST / .TRUE. /; INTEGER COUNT / 10. /;with the following:
LOGICAL FIRST; INTEGER COUNT; DATA FIRST / .TRUE. /, COUNT / 10. /;
PARAMETER
statement is like a DATA
statement
except that the variable becomes an unchangeable parameter.
The value can never be changed in the routine.
The syntax is a little different from DATA
.
INTEGER MAXEVT; PARAMETER (MAXEVT=50);Note that the variable must have been declared before the parameter statement.
A parameter can be used in later parts of the declaration section of the
routine.
For example, the routine VXWRCCD PREPMORT
uses a parameter this
way:
integer i,j,k, "counters" bankid, hiloop, ndead; parameter (ndead = 38); integer dead(ndead) /53, 65,66,67,68,69,70,71,72, 105,106,107,108,109,110,111,112, 166, 201,202,203,204,205,206,207,208, 285,286, 316, 353,354,355,356,357,358,359,360, 365/; real effic(ndead) /95., 50.,50.,50.,50.,50.,50.,50.,50., 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, 0.0, 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, 0.0,75., 20., 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, 0.0/;
GOTO
, NEXT
and EXIT
statements.
With proper use of square brackets and ELSE
statements,
you will not need statement labels very often.
But here is how they work.
Any statement can have a label.
Put the label at the beginning of the statement
(as always with Prepmort, exact column position does not matter).
The label can be any set of up to eight characters with colons on either side.
For example, :TRACK:
.
Then put this label name after GOTO
, NEXT
or EXIT
.
For example:
:TRACK: DO I = 1, NTRACKS [ DO J = 1, NHITS [ ... ... IF BAD [ NEXT :TRACK:; ] ] ]
Code that is enclosed by the lines
GENVAX
and ENDVAX
will only be run on DEC VMS systems
(the VM version of the Prepmort compiler comments this code out).
Code that is enclosed by the lines
GENIBM
and ENDIBM
will only be run on IBM VM systems
(the VMS version of the Prepmort compiler comments this code out).
Edit the file PRODUTIL:UGTIME:PREPMORT
to see how the
routine that gets the current time uses this construction.