@X @~
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H             BSC251
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL
~
~
                                                            ISSUE 11~
~V9 -1
~V9 -1
~P
~V9 1
~YBSC251
~S~M~OBASIC COMPILER IMPLEMENTATION DESCRIPTION
~S~M~OSection 25
~S~OSection 25 Run-time Support Procedures
~S~O1. General Description
~BThis section implements those numeric and string functions required
by the BASIC standard which are not implemented directly by the
MUSS system.
~S~O2. Interfaces
~S~O2.1 Section Interfaces Used
~
   Section 20   (Run-time configuration)~
   Section 21   (Program control)~
   Section 22   (INPUT)~
   Section 23   (OUTPUT)~
~S~O2.2 Section Interface
~
Exported Procedures:~
   BIO.CEIL~
   BIO.D.CEIL~
   BIO.DATE~
   BIO.TIME~
   BIO.INF~
   BIO.FP~
   BIO.D.FP~
   BIO.INT~
   BIO.D.INT~
   BIO.EPS~
   BIO.I16.REM~
   BIO.I32.REM~
   BIO.REM~
   BIO.D.REM~
   BIO.RND~
   BIO.ROUND~
   BIO.D.ROUND~
   BIO.TRUNCATE~
   BIO.D.TRUNCATE~
   BIO.L.CASE~
   BIO.U.CASE~
   BIO.L.TRIM~
   BIO.R.TRIM~
   BIO.ORD~
   BIO.POS~
   BIO.STR~
   BIO.D.STR~
   BIO.VAL~
   BIO.S.DATE~
   BIO.S.TIME~
~
Configuration Parameters:~
   R64.INF~
~S11) BIO.CEIL(X<RE32>)RES<RE32>
~BThis function returns the smaller integer not less than P1.
~S12) BIO.D.CEIL(X<RE62>)RES<RE63>
~BA double precision version of BIO.CEIL.
~S13) BIO.DATE()DATE<IN32>
~BThis function returns the current date in the decimal form YYDDD,
where YY are the last 2 digits of the year and DDD is the ordinal
number of the current day of the year.  E.g. on May 9 1983, BIO.DATE has
the value 83129.
~S14) BIO.TIME()TIME<IN32>
~BThis function returns the number of seconds elapsed since the
previous midnight.
~S15) BIO.INF()INF<RE64>
~BThis function returns the largest positive value representable
by the implementation.
~S16) BIO.FP(X<RE32>)<RE32>
~BThis function returns the fractional part of P1.
~S17) BIO.D.FP(X<RE64>)<RE64>
~BA double precision version of BIO.FP.
~S18) BIO.INT(X<RE32>)<RE32>
~BThis function returns the largest integer not greater than P1.
E.g. BIO.INT (1.3) = 1, and BIO.INT (-1.3) = -2.
~S19) BIO.D.INT(X<RE64>)<RE64>
~BA double precision version of BIO.INT.
~S110) BIO.EPS(X<RE32>)<RE64>
~BNot yet defined.
~S111) BIO.I16.REM(X<INT16>,(Y<IN16>)<IN16>
~BThis function returns a remainder REM such that REM = X-Y*IP (X/Y).
~S112) BIO.I32>REM(X<IN32>,Y<IN32>)<IN32>~
~G13) BIO.REM(X<RE32>,Y<RE32>)<RE32>~G~
~G14) BIO.D.REM(X<RE64>,Y<RE64>)<RE64>~G~
~BThe above three functions are corresponding versions of
BIO.I16.REM.
~S115) BIO.RND()<RE32>
~BThis function returns the next pseudo-random number, in an
implementation - defined sequence, lying in the range 0 <= RND <= 1.
~S116) BIO.ROUND(X<RE32>,Y<IN16>)<RE32>
~BThis function returns the value of X rounded to Y decimal digits.
~S117) BIO.D.ROUND(X<RE64>,Y<IN16>)<RE64>
~BA double precision version of BIO.ROUND.
~S118) BIO.TRUNCATE(X<RE32>,N<IN16>)<RE32>
~BThis function returns the value of P1 truncated to P2
decimal digits.
~S119) BIO.TRUNCATE(X<RE64>,N<IN16><RE64>
~BA double precision version of BIO.TRUNCATE.
~S120) BIO.L.CASE(STRING)
~BThis function replaces any upper case characters in the string
P1 with their corresponding lower case versions.
~S121) BIO.U.CASE(STRING)
~BThis function replaces any lower case characters in the string P1
with their corresponding upper case version.
~S122) BIO.L.TRIM(STRING)
~BThis function deletes all leading spaces in the string P1.
~S123) BIO.R.TRIM(STRING)
~BThis function deletes all trailing spaces in the string P1.
~S124) BIO.ORD(STRING)<IN16>
~BThis function returns the ordinal position of the standard ISO
collating sequence of the character defined by P1.  The acceptable
values for P1 are single characters, and two or three character
mnemonics, as defined by the BASIC standard.
~S125) BIO.POS(STRING.1,STRING.2,M<IN16>)<IN16>
~BThis function returns the character position, within P1 of the
first occurrence of P2, starting at the P3 th position in P1, as
defined by the BASIC standard.
~S126) BIO.STR(VALUE<RE32>,STRING)
~BThis function returns in P2 the string generated by the print
statement for P1, with leading and trailing spaces deleted.  E.g.
BIO.STR(123.5, 5) assigns "123.5" to 5.
~S127) BIO.D.STR(VALUE<RE64>,STRING)
~BA double precision version of BIO.STR.
~S128) BIO.VAL(STRING)<RE64>
~BThis function returns the value of the numeric constant associated
with P1, e.g. BIO.VAL("1.2") returns a value of 1.2.
~S129)BIO.S.DATE(STRING)
~BThis function returns in P1 the current date in the string representation
"YYYYMMDD".  E.g. for June 16th. 1983, this function returns "19830616".
~S130) BIO.S.TIME(STRING)
~BThis function returns in P1 the current time in the string representation
"HH:MM:SS".
~S~O3. Implementation Description
~S~O3.1 Outline of Operation
~BThe operation of this section is straightforward and is described
by the flowcharts.
~S~O3.2 Data Structures
~T# 11
~
VAL.FN~IAn exported variable used to indicate when BIO.VAL
has been called.  0 = not called, 1 = called.~
~
G.TIME~INumber of seconds since previous midnight.~
~
G.YEAR~IThe current year (0-99).~
~
G.MONTH~IThe current month (0-11).~
~
G.DAY~IThe current day, as the number of the day within the current
month (1-31).~
~S~O3.3 Special Notes
~BNone.
~Y
~V9 -1
~P
~D15
~HFLOWCHARTS
~
~
~H                BSC251
~V9 -1
~F
///12
@TITLE BSC25(1,11)
@COL 1S-2R-3R-4R-5F
@FLOW 1-2-3-4-5
@BOX 1.0
RUN-TIME SUPPORT PROCEDURES

@BOX 2.0
MODULE HEADING
@BOX 3.0
DECLARATIONS
@BOX 4.0
PROCEDURES IN MODULE:

   LIBRARY PROCS:
   BIO.CEIL  [25.1]     BIO.I16.REM  [25.13]
   BIO.D.CEIL  [25.2]   BIO.I32.REM  [25.214]
   BIO.DATE  [25.3]     BIO.REM  [25.15]
   BIO.TIME  [25.4]     BIO.D.REM  [25.16]
   BIO.INF   [25.5]     BIO.RND    [25.17]
   BIO.FP   [25.8]      BIO.ROUND  [25.18]
   BIO.D.FP  [25.9]     BIO.D.ROUND [25.19]
   BIO.INT    [25.10]
   BIO.D.INT  [25.11]
                         BIO.TRUNCATE [25.22]
                        BIO.D.TRUNCATE [25.23]

   BIO.LCASE  [BSC25.40]    BIO.STR  [BSC25.46]
   BIO.UCASE  [BSC25.41]    BIO.D.STR[BSC25.47]
   BIO.LTRIM  [BSC25.42]    BIO.VAL  [BSC25.48]
   BIO.RTRIM  [BSC25.43]    BIO.S.DATE[BSC25.49]
   BIO.ORD    [BSC25.44]    BIO.S.TIME[BSC25.50]
   BIO.POS    [BSC25.45]

   INTERNAL PROCS:
   EXP.10  [BSC25.30]
   GET.TD  [BSC25.31]
@BOX 5.0
END
@BOX 1.1
::RUN-TIME SUPPORT PROCEDURES
@BOX 2.1
#BSC25/1
MODULE(BIO.CEIL, BIO.D.CEIL, BIO.DATE, BIO.TIME, BIO.INF,
       BIO.FP, BIO.D.FP, BIO.INT, BIO.D.INT, BIO.I16.REM, BIO.I32.REM,
       BIO.REM, BIO.D.REM, BIO.RND, BIO.D.RND, BIO.ROUND, BIO.D.ROUND,
       BIO.TRUNCATE, BIO.D.TRUNCATE,VAL.FN,
       BIO.LCASE, BIO.UCASE, BIO.LTRIM, BIO.RTRIM, BIO.ORD,
       BIO.POS, BIO.STR, BIO.DSTR, BIO.VAL, BIO.S.DATE, BIO.S.TIME);
@BOX 3.1
*GLOBAL 2;
$LO8 VAL.FN;  ::SET TO 1 WHEN VAL FN IS CALLED
$IN32 G.TIME; ::NO OF SECS SINCE PREVIOUS MIDNIGHT
$IN G.YEAR;  ::00-99
$IN G.MONTH;  ::0-11
$IN G.DAY;  ::NO. OF DAY WITHIN MONTH
$LI / ADDR[$LO8] NIL =;
$LI / $RE64 R.ZERO = 0.0;
*GLOBAL 0;
@BOX 4.1
PSPEC GET.TD();
PSPEC EXP.10($IN)/$RE64;
LSPEC BIO.CEIL($RE32)/$RE32;
LSPEC BIO.D.CEIL($RE64)/$RE64;
LSPEC BIO.DATE()/$IN32;
LSPEC BIO.TIME()/$IN32;
LSPEC BIO.INF()/$RE64;
LSPEC BIO.FP($RE32)/$RE32;
LSPEC BIO.D.FP($RE64)/$RE64;
LSPEC BIO.INT($RE32)/$RE32;
LSPEC BIO.D.INT($RE64)/$RE64;
LSPEC BIO.I16.REM($IN16,$IN16)/$IN16;
LSPEC BIO.I32.REM($IN32,$IN32)/$IN32;
LSPEC BIO.REM($RE32,$RE32)/$RE32;
LSPEC BIO.D.REM($RE64,$RE64)/$RE64;
LSPEC BIO.RND()/$RE32;
LSPEC BIO.ROUND($RE32,$IN16)/$RE32;
LSPEC BIO.D.ROUND($RE64,$IN16)/$RE64;
LSPEC BIO.TRUNCATE($RE32,$IN16)/$RE32;
LSPEC BIO.D.TRUNCATE($RE64,$IN16)/$RE64;
LSPEC BIO.L.CASE(ADDR[$LO8]);
LSPEC BIO.U.CASE(ADDR[$LO8]);
LSPEC BIO.L.TRIM(ADDR[$LO8]);
LSPEC BIO.R.TRIM(ADDR[$LO8]);
LSPEC BIO.ORD(ADDR[$LO8])/$IN16;
LSPEC BIO.POS(ADDR[$LO8],ADDR[$LO8],$IN16)/$IN16;
LSPEC BIO.STR($RE32,ADDR[$LO8]);
LSPEC BIO.D.STR($RE64,ADDR[$LO8]);
LSPEC BIO.VAL(ADDR[$LO8])/$RE64;
LSPEC BIO.S.DATE(ADDR[$LO8]);
LSPEC BIO.S.TIME(ADDR[$LO8]);
#BSC25.1
#BSC25.2
#BSC25.3
#BSC25.4
#BSC25.5
#BSC25.8
#BSC25.9
#BSC25.10
#BSC25.11
#BSC25.13
#BSC25.14
#BSC25.15
#BSC25.16
#BSC25.17
#BSC25.18
#BSC25.19
#BSC25.22
#BSC25.23
#BSC25.30
#BSC25.31
#BSC25.40
#BSC25.41
#BSC25.42
#BSC25.43
#BSC25.44
#BSC25.45
#BSC25.46
#BSC25.47
#BSC25.48
#BSC25.49
#BSC25.50
@BOX 5.1
*END
@END
//18 18-AUG-83
@TITLE BSC25/1(1,11)
@COL 1S
@BOX 1.0
IMPORTS
@BOX 1.1
LSPEC DEFINE.STRING.IO($IN,ADDR[$LO8],$IN32)/$IN;
LSPEC O.POS()/$IN32;
LSPEC SELECT.OUTPUT($IN);
PSPEC R.IP($RE32)/$RE32;
PSPEC D.IP($RE64)/$RE64;
PSPEC BIO.EXCEPTION($IN16);
PSPEC EXCEPTION($IN,ADDR[$LO8],$IN);
PSPEC BIO.OUTPUT($IN16,$IN16);
PSPEC BIO.END.OUTPUT($IN16);
PSPEC BIO.PRINT.R32($RE32);
PSPEC BIO.PRINT.R64($RE64);
PSPEC BIO.READ(ADDR[$LO8],$LO16,$IN16);
PSPEC BIO.END.READ()/$LO16;
PSPEC BIO.IN.R64()/$RE64;
$LO64 PWW1, PWW2;
IMPORT LITERAL $LO64 R64.INF;
@END
///12
@TITLE BSC25.1(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.CEIL(X)RES
@BOX 2.0
COMPUTE SMALLEST INTEGER
NOT LESS THAN X
@BOX 3.0
END
@BOX 1.1
PROC BIO.CEIL(X);
@BOX 2.1
R.IP(X) => BIO.CEIL;
IF X > R.ZERO THEN
   1.0 +> BIO.CEIL;
FI
@BOX 3.1
END
@END
///12
@TITLE BSC25.2(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.D.CEIL(XX)RES
@BOX 2.0
COMPUTE SMALLEST INTEGER
NOT LESS THAN DOUBLE PRECISION XX
@BOX 3.0
END
@BOX 1.1
PROC BIO.D.CEIL(XX);
@BOX 2.1
D.IP(XX) => BIO.D.CEIL;
IF XX > R.ZERO THEN
   1.0 +> BIO.D.CEIL;
FI;
@BOX 3.1
END
@END
//12
@TITLE BSC25.3(1,11)
@COL 1S-2R-3R-4R-5R-6R-7F
@FLOW 1-2-3-4-5-6-7
@BOX 1.0
BIO.DATE()YYDDD
@BOX 2.0
GET TIME AND DATE
[BSC25.31]
@BOX 3.0
FORM YEAR PART OF RESULT
@BOX 4.0
GET ORDINAL NUMBER OF DAY
@BOX 5.0
INCREMENT DAY IF LEAP YEAR
@BOX 6.0
FOR DAY PART OF RESULT
@BOX 7.0
END
@BOX 1.1
PROC BIO.DATE;
$IN I;
DATAVEC MONTH.Z ($IN)
31 28 31 30 31 30 31 31 30 31 30 31
END
@BOX 2.1
GET.TD();
@BOX 3.1
G.YEAR * 1000 => BIO.DATE;
@BOX 4.1
FOR I < G.MONTH DO
   MONTH.Z[I] +> G.DAY
OD
@BOX 5.1
IF G.YEAR / 4 -: G.YEAR = 0 AND G.DAY > 59 THEN
   ::ADD EXTRA DAY FOR LEAP YEAR
   1 +> G.DAY
FI
@BOX 6.1
G.DAY +> BIO.DATE;
@BOX 7.1
END
@END
///12
@TITLE BSC25.4(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.TIME()RES
@BOX 2.0
GET TIME AND DATE [BSC25.31]
@BOX 3.0
END
@BOX 1.1
PROC BIO.TIME;
@BOX 2.1
GET.TD();
G.TIME => BIO.TIME;
@BOX 3.1
END
@END
///12
@TITLE BSC25.5(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.INF()RES
@BOX 2.0
RETURN LARGEST R64 VALUE
@BOX 3.0
END
@BOX 1.1
PROC BIO.INF;
@BOX 2.1
R64.INF => BIO.INF;
@BOX 3.1
END
@END
///12
///12
@TITLE BSC25.8(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.FP(X)RES
@BOX 2.0
RETURN FRACTIONAL PART OF X
@BOX 3.0
END
@BOX 1.1
PROC BIO.FP(X);
@BOX 2.1
X - R.IP(X) => BIO.FP;
@BOX 3.1
END
@END
///12
@TITLE BSC25.9(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.D.FP(XX);
@BOX 2.0
RETURN FRACTIONAL PART OF
DOUBLE PRECISION XX
@BOX 3.0
END
@BOX 1.1
PROC BIO.D.FP(XX);
@BOX 2.1
XX - D.IP(XX) => BIO.D.FP;
@BOX 3.1
END
@END
///12
@TITLE BSC25.10(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.INT(X)RES
@BOX 2.0
RETURN LARGEST INTEGER
NOT GREATER THAN X
@BOX 3.0
END
@BOX 1.1
PROC BIO.INT(X);
@BOX 2.1
R.IP(X) => BIO.INT;
IF X < R.ZERO THEN
   1.0 -> BIO.INT;
FI;
@BOX 3.1
END
@END
///12
@TITLE BSC25.11(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.D.INT(XX)RES
@BOX 2.0
RETURN LARGEST INTEGER
NOT GRATER THAN DOUBLE
PRECISION XX
@BOX 3.0
END
@BOX 1.1
PROC BIO.D.INT(XX);
@BOX 2.1
D.IP(XX) => BIO.D.INT;
IF XX < R.ZERO THEN
   1.0 -> BIO.D.INT;
FI;
@BOX 3.1
END
@END
///12
@TITLE BSC25.13(1,11)
@COL 1S-4T-2R-3F
@COL 5R
@ROW 2-5
@FLOW 1-4N-2-3
@FLOW 4Y-5-3
@BOX 1.0
BIO.I16.REM(P1,P2)REM
@BOX 2.0
RETURN I16 REMAINDER
OF P1/P2
@BOX 3.0
END
@BOX 4.0
IS P2 = 0 ?
@BOX 5.0
EXCEPTION
@BOX 1.1
PROC BIO.I16.REM(P1,P2);
@BOX 2.1
P1 / P2 * P2 -: P1 => BIO.I16.REM;
@BOX 3.1
END
@BOX 4.1
IF P2 = 0
@BOX 5.1
BIO.EXCEPTION(%42);
@END
///12
@TITLE BSC25.14(1,11)
@COL 1S-4T-2R-3F
@COL 5R
@ROW 2-5
@FLOW 1-4N-2-3
@FLOW 4Y-5-3
@BOX 1.0
BIO.I32.REM(P1,P2)REM
@BOX 2.0
RETURN I32 REMAINDER OF P1/P2
@BOX 3.0
END
@BOX 4.0
IS P2 = 0 ?
@BOX 5.0
EXCEPTION
@BOX 1.1
PROC BIO.I32.REM(P1,P2);
@BOX 2.1
P1 / P2 * P2 -: P1 => BIO.I32.REM;
@BOX 3.1
END
@BOX 4.1
IF P2 = 0
@BOX 5.1
BIO.EXCEPTION(%42);
@END
///12
@TITLE BSC25.15(1,11)
@COL 1S-4T-2R-3F
@COL 5R
@ROW 2-5
@FLOW 1-4N-2-3
@FLOW 4Y-5-3
@BOX 1.0
BIO.REM(P1,P2)REM
@BOX 2.0
RETURN REMAINDER OF P1/P2
@BOX 3.0
END
@BOX 4.0
IS P2 = 0 ?
@BOX 5.0
EXCEPTION
@BOX 1.1
PROC BIO.REM(P1,P2);
@BOX 2.1
R.IP(P1 / P2) * P2 -: P1 => BIO.REM;
@BOX 3.1
END
@BOX 4.1
IF P2 = R.ZERO
@BOX 5.1
BIO.EXCEPTION(%42);
@END
///12
@TITLE BSC25.16(1,11)
@COL 1S-4T-2R-3F
@COL 5R
@ROW 2-5
@FLOW 1-4N-2-3
@FLOW 4Y-5-3
@BOX 1.0
BIO.D.REM(P1,P2)REM
@BOX 2.0
RETURN REMAINDER OF
DOUBLE PRECISION P1/P2
@BOX 3.0
END
@BOX 4.0
IS P2 = 0 ?
@BOX 5.0
EXCEPTION
@BOX 1.1
PROC BIO.D.REM(P1,P2);
@BOX 2.1
D.IP(P1 / P2) * P2 -: P1 => BIO.D.REM;
@BOX 3.1
END
@BOX 4.1
IF P2 = R.ZERO
@BOX 5.1
BIO.EXCEPTION(%42);
@END
///12
@TITLE BSC25.17(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.RND()
@BOX 2.0
RETURN NEXT NUMBER IN
PSEUDO-RANDOM SEQUENCE
@BOX 3.0
END
@BOX 1.1
PROC BIO.RND;
@BOX 2.1
::TBC
@BOX 3.1
END
@END
///12
@TITLE BSC25.18(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.ROUND(X,N)RES
@BOX 2.0
RETURN X ROUNDED TO
N DIGITS
@BOX 3.0
END
@BOX 1.1
PROC BIO.ROUND(X,N);
$RE32 D;
@BOX 2.1
BIO.INT(EXP.10(N) => D * X + 0.5)/D => BIO.ROUND;
@BOX 3.1
END
@END
///12
@TITLE BSC25.19(1,11)
@COL 1S-2R-3F

@FLOW 1-2-3
@BOX 1.0
BIO.D.ROUND(XX,N)RES
@BOX 2.0
RETURN DOUBLE PRECISION XX
ROUNDED TO N DIGITS
@BOX 3.0
END
@BOX 1.1
PROC BIO.D.ROUND(XX,N);
$RE64 D;
@BOX 2.1
BIO.D.INT (EXP.10(N) => D * XX + 0.5)/D => BIO.D.ROUND;
@BOX 3.1
END
@END
///12
@TITLE BSC25.22(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.TRUNCATE(X,N)
@BOX 2.0
RETURN X TRUNCATED TO N DIGITS
@BOX 3.0
END
@BOX 1.1
PROC BIO.TRUNCATE(X,N);
$RE32 D;
@BOX 2.1
R.IP(EXP.10(N) => D * X) / D => BIO.TRUNCATE;
@BOX 3.1
END
@END
///12
@TITLE BSC25.23(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.D.TRUNCATE(XX,N)
@BOX 2.0
RETURN XX TRUNCATED TO N DIGITS
@BOX 3.0
END
@BOX 1.1
PROC BIO.D.TRUNCATE(XX,N);
$RE64 D;
@BOX 2.1
D.IP(EXP.10(N) => D * XX) / D => BIO.D.TRUNCATE;
@BOX 3.1
END
@END
///12
@TITLE BSC25.30(1,11)
@COL 1S-2T-3R-4F
@COL 5R
@ROW 3-5
@FLOW 1-2N-3-4
@FLOW 2Y-5-4
@BOX 1.0
EXP.10(N)RES
COMPUTES 10^N
@BOX 2.0
N OUT OF RANGE ?
@BOX 3.0
COMPUTE 10 ^ N
@BOX 4.0
END
@BOX 5.0
RETURN 1.0
@BOX 1.1
PROC EXP.10(N);
DATAVEC POWERS($RE64)
1.0@-16 1.0@-15 1.0@-14 1.0@-13 1.0@-12 1.0@-11 1.0@-10
1.0@-9  1.0@-8  1.0@-7  1.0@-6  1.0@-5  1.0@-4  1.0@-3
0.01  0.1   1.0    10.0  100.0  1000.0   10000.0
10@5   10@6   10@7   10@8   10@9   10@10  10@11
10@12  10@13  10@14  10@15  10@16
END
$RE64 P, D;
$IN I;
@BOX 2.1
IF N < -22 OR N > 37
@BOX 3.1
N + 16 => I;
IF I =< 32 AND I >= 0 THEN
   POWERS[I] => P;
ELSE
   IF N < 0 THEN POWERS[0 => I] => P; 0.1 => D; 0 -:> N;
   ELSE POWERS[32] => P; 10.0 => D; 16 => I;
   FI
   WHILE 1 +> I =< N DO D *> P OD;
FI
P => EXP.10;
@BOX 4.1
END
@BOX 5.1
IF N < 0 THEN 1@-16 => EXP.10
ELSE 10@16 => EXP.10
FI
@END
//12
@TITLE BSC25.31(1,11)
@COL 1S-2R-4R-3R-5F
@FLOW 1-2-4-3-5
@BOX 1.0
GET.TD
@BOX 2.0
GET NUMBER OF DAYS SINCE
JAN 1ST 1900
@BOX 3.0
GET MONTH NO. (0-11) => G.MONTH
GET YEAR.NO (0-99) => G.YEAR
GET DAY WITHIN MONTH => G.DAY
@BOX 4.0
GET NO. OF SECS SINCE MIDNIGHT => G.TIME;
@BOX 5.0
END
@BOX 1.1
PROC GET.TD;
$IN32 DAYS, SECS;
$IN TEMP, I;
@BOX 2.1
TIME.AND.DATE();
PWW1 => SECS ->> 7 / 675 => DAYS; ::SECS/60/60/24
@BOX 3.1
59 -> DAYS * 4 - 1 => DAYS;
DAYS / 1461 => G.YEAR;
G.YEAR * 1461 -: DAYS + 4 / 4 => G.DAY;
G.DAY * 5 - 3 => TEMP / 153 => G.MONTH;
G.MONTH * 153 -: TEMP + 5 / 5 => G.DAY;
IF 3 +> G.MONTH > 12 THEN
   12 -> G.MONTH;
   1 +> G.YEAR;
FI
1 -> G.MONTH;
@BOX 4.1
DAYS * 675 <<- 7 -: SECS => G.TIME;
@BOX 5.1
END
@END
///13
@TITLE BSC25.40(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.L.CASE(STR)
@BOX 2.0
CONVERT ANY UPPER CASE CHARS
TO LOWER CASE
@BOX 3.0
END
@BOX 1.1
PROC BIO.L.CASE(STR);
$IN I;
@BOX 2.1
FOR I < STR^[0] DO
   IF STR^[I+1] >= %41 =< %5A THEN
      %20 +> STR^[I+1]
   FI
OD
@BOX 3.1
END
@END
///13
@TITLE BSC25.41(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.U.CASE(STR)
@BOX 2.0
CONVERT ANY LOWER CASE CHARS
TO UPPER CASE
@BOX 3.0
END
@BOX 1.1
PROC BIO.U.CASE(STR);
$IN I;
@BOX 2.1
FOR I < STR^[0] DO
   IF STR^[I+1] >= %61 =< %7A THEN
      %20 -> STR^[I+1]
   FI
OD
@BOX 3.1
END
@END
///13
@TITLE BSC25.42(1,11)
@COL 1S-2R-3T-4T-5R-6F
@COL 7R
@ROW 5-7
@FLOW 1-2-3N-4N-5-6
@FLOW 3Y-7-6
@FLOW 4Y-6
@BOX 1.0
BIO.L.TRIM(STR)
@BOX 2.0
FIND FIRST NON-SPACE CHAR
@BOX 3.0
ALL SPACES ?
@BOX 4.0
NO SPACES ?
@BOX 5.0
DELETE LEADING SPACES
AND UPDATE BYTE COUNT
@BOX 6.0
END
@BOX 7.0
SET BYTE COUNT TO ZERO
@BOX 1.1
PROC BIO.L.TRIM(STR);
$IN I, J, SZ;
@BOX 2.1
STR^[0] => SZ;
0 => I;
WHILE 1 +> I =< SZ AND STR^[I] = %20 DO OD;
@BOX 3.1
IF I > SZ
@BOX 4.1
IF I = 1
@BOX 5.1
0 => J; I-1 -> STR^[0];
WHILE I =< SZ DO
   STR^[I] => STR^[1 +> J];
   1 +> I;
OD
@BOX 6.1
END
@BOX 7.1
0 => STR^[0];
@END
///13
@TITLE BSC25.43(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.R.TRIM(STR)
@BOX 2.0
DELETE ALL TRAILING SPACES FROM STR
@BOX 3.0
END
@BOX 1.1
PROC BIO.R.TRIM(STR);
$IN I;
@BOX 2.1
STR^[0] + 1 => I;
WHILE 1 -> I >= 1 AND STR^[I] = %20 DO OD;
I => STR^[0];
@BOX 3.1
END
@END
//17
@TITLE BSC25.44(1,11)
@COL 7R
@COL 1S-2T-10T-3T-5R-6F
@COL 8C
@COL 9R
@ROW 3-9
@ROW 7-5
@ROW 5-8
@FLOW 1-2N-10N-3N-5-6
@FLOW 2Y-9-6
@FLOW 3Y-7-6
@FLOW 10Y-8
@BOX 1.0
BIO.ORD(STR)
@BOX 2.0
SINGLE CHAR ?
@BOX 3.0
TWO CHAR MNEMONIC ?
@BOX 5.0
SEARCH CH3 VECTOR FOR MNEMONIC
@BOX 6.0
END
@BOX 7.0
SEARCH CH2 VECTOR FIR MNEMONIC
@BOX 8.0
EXCEPTION
@BOX 9.0
RETURN POS DIRECTLY
@BOX 10.0
ILLEGAL STRING SIZE ?
@BOX 1.1
PROC BIO.ORD(STR);
$LO8 C1,C2,C3,MATCH;
$IN I,SZ;
ADDR[$LO8]EX;
#BSC25.44.1
PART(STR,1,STR^[0]) => EX;
@BOX 2.1
IF STR^[0] => SZ = 1
@BOX 3.1
-2 => I; 0 => MATCH;
IF STR^[1] => C1 >=%61=<%7A THEN
  %20 -> C1;
FI
IF STR^[2] => C2 >=%61=<%7A THEN
  %20 -> C2;
FI
IF SZ = 2
@BOX 5.1
1 -> I;
IF STR^[3] => C3 >=%61=<%7A THEN
  %20 -> C3
FI;
WHILE MATCH=0 AND 3+>I < CH3.Z DO
   IF C1=CH.3[I] AND
    C2=CH.3[I+1] AND C3=CH.3[I+2] THEN
      1 => MATCH;
   FI
OD
3 /> I;
IF MATCH = 1 THEN
   IF I < 19 THEN CH.3P[I] => I
   ELSE 76 +> I FI;
   I => BIO.ORD;
ELSE
  EXCEPTION(%143,EX,0);
FI
@BOX 6.1
END
@BOX 7.1
WHILE MATCH=0 AND 2+>I < CH2.Z DO
   IF C1=CH.2[I] AND C2=CH.2[I+1] THEN
      1 => MATCH;
   FI;
OD
IF MATCH = 1 THEN
   CH2.P[I->>1] => BIO.ORD;
ELSE
   EXCEPTION(%143,EX,0);
FI;
@BOX 8.1
EXCEPTION(%143,EX,0);
@BOX 9.1
STR^[1] => BIO.ORD;
@BOX 10.1
IF SZ /= 2 /= 3
@END
///13
@TITLE BSC25.44.1(1,11)
@COL 1S-2R-3R
@FLOW 1-2-3
@BOX 1.0
CHARACTER CODE MNMONIC DATAVECS
@BOX 2.0
ORDINAL POSITION DATAVECS
@BOX 3.0
LITERALS
@BOX 1.1
DATAVEC CH2($LO8);
"BS"  "HT"  "LF"  "VT"  "FF"  "CR"  "SO"  "SI"
"EM"  "FS"  "GS"  "RS"  "US"  "SP"
END

DATAVEC CH3($LO8)
"NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL"
"DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB"
"CAN" "SUB" "ESC" "UND" "GRA" "LCA" "LCB" "LCC"
"LCD" "LCE" "LCF" "LCG" "LCH" "LCI" "LCJ" "LCK"
"LCL" "LCM" "LCN" "LCO" "LCP" "LCQ" "LCR" "LCS"
"LCT" "LCU" "LCV" "LCW" "LCX" "LCY" "LCZ" "LBR"
"VLN" "RBR" "TIL" "DEL"
END
@BOX 2.1
DATAVEC CH2.P($IN)
8  9  10 11 12 13 14 15 25
28 29 30 31 32
END

DATAVEC CH3.P($IN)
0  1  2  3  4  5  6  7
16 17 18 19 20 21 22 23
24 26 27
END
@BOX 3.1
LITERAL CH2.Z = 28, CH3.Z = 156;
@END
///13
@TITLE BSC25.45(1,11)
@COL 11R
@COL 1S-2R-3T-4T-5R-6R-7T-8T-9R-10F
@COL 12R
@ROW 11-8-12
@FLOW 1-2-3N-4N-5-6-7N-8N-9-10
@FLOW 3Y-11-10
@FLOW 4Y-12-10
@FLOW 7Y-11
@FLOW 8Y-6
@BOX 1.0
BIO.POS(S1,S2,M)
@BOX 2.0
GET SIZES OF S1,S2
@BOX 3.0
IS M > LEN(S1) ?
@BOX 4.0
IS S2 EMPTY ?
@BOX 5.0
SET START OF SEARCH TO M AND
GET LEADING CHAR OF S2 => L
@BOX 6.0
SCAN ALONG S1 UNTIL L FOUND
@BOX 7.0
NOT FOUND ?
@BOX 8.0
TRY AND MATCH S2
FAIL ?
@BOX 9.0
RETURN POS
@BOX 10.0
END
@BOX 11.0
RETURN ZERO
@BOX 12.0
RETURN MAX(M,1)
@BOX 1.1
PROC BIO.POS(S1,S2,M);
$IN SZ.1, SZ.2, I, P, J;
$LO8 L, MATCH;
@BOX 2.1
S1^[0] => SZ.1;
S2^[0] => SZ.2;
@BOX 3.1
IF M > SZ.1
@BOX 4.1
IF SZ.2 = 0
@BOX 5.1
M - 1 => P;
S2^[1] => L;
@BOX 6.1
P => I;
0 => MATCH;
WHILE MATCH=0 AND 1+>I =< SZ.1 DO
   IF S1^[I] = L THEN
      1 => MATCH;
   FI
OD;
@BOX 7.1
IF MATCH = 0 OR
   SZ.1 - I < SZ.2 - 1
@BOX 8.1
I => P;
1 => MATCH => J;
WHILE 1+>J =< SZ.2 AND MATCH = 1 DO
   IF S1^[1+>I] /= S2^[J] THEN
      0 => MATCH;
   FI
OD
IF MATCH = 0
@BOX 9.1
P => BIO.POS;
@BOX 10.1
END
@BOX 11.1
0 => BIO.POS;
@BOX 12.1
IF M > 1 THEN
   M => BIO.POS;
ELSE
  1 => BIO.POS;
FI
@END
///16
@TITLE BSC25.46(1,11)
@COL 1S-3R-4R-6R-7F
@FLOW 1-3-4-6-7
@BOX 1.0
BIO.STR(X,STR)
@BOX 3.0
DEFINE OUTPUT TO A TEMP
BYTE VECTOR
@BOX 4.0
CALL BIOOUTPUT SPECIFYING
SPECIAL CHANNEL FOR BIOSTR
CALL BIO.PRINT.R32
@BOX 6.0
COPY TEMP VECTOR TO RESULT,
DELETING LEADING AND TRAILING SPACES
@BOX 7.0
END
@BOX 1.1
PROC BIO.STR(X,STR);
$LO8[30]TEMP;
$IN V,I,J,K;
$LO8 CH;
@BOX 3.1
DEFINE.STRING.IO(-1,^TEMP,0) => V;
@BOX 4.1
BIO.OUTPUT(0,%200);
SELECT.OUTPUT(V);
BIO.PRINT.R32(X);
O.POS() + 1 => I;
END.OUTPUT(V,0);
BIO.END.OUTPUT(%4);
@BOX 6.1
0 => K;
FOR J < I DO
   IF TEMP[J] => CH /= %20 THEN
      CH => STR^[1+>K];
   FI
OD
K => STR^[0];
@BOX 7.1
END
@END
///16
@TITLE BSC25.47(1,11)
@COL 1S-3R-4R-6R-7F
@FLOW 1-3-4-6-7
@BOX 1.0
BIO.D.STR(XX,STR)
@BOX 3.0
DEFINE OUTPUT TO TEMP VEC
@BOX 4.0
CALL BIOOUTPUT SPECIFYING
SPECIAL CHANNEL FOT BIOSTR
CALL BIO.PRINT.R64
@BOX 6.0
COPY TEMP VECTOR TO RESULT,
DELETING LEADING AND TRAILING SPACES
@BOX 7.0
END
@BOX 1.1
PROC BIO.D.STR(XX,STR);
$LO8[30]TEMP;
$IN V,I,J,K;
$LO8 CH;
@BOX 3.1
DEFINE.STRING.IO(-1,^TEMP,0) => V;
@BOX 4.1
BIO.OUTPUT(0,%200);
SELECT.OUTPUT(V);
BIO.PRINT.R64(XX);
O.POS() + 1 => I;
END.OUTPUT(V,0);
BIO.END.OUTPUT(%4);
@BOX 6.1
0 => K;
FOR J < I DO
   IF TEMP[J] => CH /= %20 THEN
      CH => STR^[1+>K];
   FI
OD
K => STR^[0];
@BOX 7.1
END
@END
///16
@TITLE BSC25.48(1,11)
@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
BIO.VAL(STR)RES
@BOX 2.0
NOTE VAL FUNCTION CALL
CREATE TEMP VECTOR CONTAINING STRING
AND FINAL NEWLINE CHAR FOR USE BY
BIO.READ [BSC22]
@BOX 3.0
CALL BIO.IN.R64
@BOX 4.0
END
@BOX 1.1
PROC BIO.VAL(STR);
$LO8[20] V;
$IN I,J;
@BOX 2.1
1 => VAL.FN;
-1 => J;
FOR I < STR^[0] DO
   STR^[I+1] => V[1+>J];
OD
%0A => V[1+>J];
@BOX 3.1
BIO.READ(PART(^V,0,I),0,0);
BIO.IN.R64() => BIO.VAL;
BIO.END.READ();
@BOX 4.1
0 => VAL.FN;
END
@END
///13
@TITLE BSC25.49(1,11)
@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
BIO.S.DATE(STR)
@BOX 2.0
GET TIME AND DATE
[BSC25.31]
@BOX 3.0
STORE "19"&YEAR TO RESULT
@BOX 4.0
STORE MONTH TO RESULT
@BOX 5.0
STORE DAY TO RESULT
@BOX 6.0
END
@BOX 1.1
PROC BIO.S.DATE(STR);
$IN I;
PSPEC OUT.D.CH($IN);
PROC OUT.D.CH(D);
   D/10 + "0" => STR^[1+>I];
   D/10 * 10 -: D + "0" => STR^[1+>I];
END
@BOX 2.1
GET.TD();
@BOX 3.1
"1" => STR^[1]; "9" => STR^[2];
2 => I;
OUT.D.CH(G.YEAR);
@BOX 4.1
OUT.D.CH(G.MONTH+1);
@BOX 5.1
OUT.D.CH(G.DAY);
@BOX 6.1
8 => STR^[0];
END
@END
///13
@TITLE BSC25.50(1,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BIO.S.TIME(STR)
@BOX 2.0
RETURN TIME IN FORM HH:MM:SS
@BOX 3.0
END
@BOX 1.1
PROC BIO.S.TIME(STR);
$IN I, TEMP;
PSPEC OUT.TIM.I($IN);
PROC OUT.TIM.I(T);
   T/10 + "0" => STR^[1+>I];
   T/10*10 -: T + "0" => STR^[1+>I];
END
@BOX 2.1
0 => I;
GET.TD();
OUT.TIM.I(G.TIME / 3600 => TEMP);
":" => STR^[1+>I];
OUT.TIM.I(TEMP * 3600 -> G.TIME /60 => TEMP);
":" => STR^[1+>I];
OUT.TIM.I(TEMP * 60 -: G.TIME);
8 => STR^[0];
@BOX 3.1
END
@END
