// PLMaker1.bcpl
// utility routines for PLMaker
// edited by Wyatt, February 15, 1979 10:14 AM
external
[
// outgoing
Str; Chr; Cr; Dec; UDec; Oct; DNum; ONum; XNum; Char; RNumOver10; Begin; End;
SetPos; GetPos; IncPos; DoubleSub; MulDiv;
WordsForString; CopyString; StringMatch; AppendChar; AppendNum; AppendStr;
DefaultExtension; StripExtension;
// from PLMaker
outstream
lev
// from OS
Ws; Wo; Wns; Wss;
Gets; Puts; Endofs; Resets; Closes;
SetFilePos; FilePos;
DoubleAdd; MoveBlock; SetBlock; Usc;
];
manifest cr=$*n;
structure S: // BCPL string
[
length byte
body↑0,255 byte
];
let Str(string) be Wss(outstream, string);
and Chr(c) be Puts(outstream, c);
and Cr() be [ Puts(outstream, cr); for i=1 to lev do Puts(outstream, $*T) ]
and Dec(n) be Wns(outstream, n, 0, -10); // signed decimal
and UDec(n) be Wns(outstream, n, 0, 10); // unsigned decimal
and Oct(n) be Wns(outstream, n, 0, 8); // (unsigned) octal
and DNum(n) be [ Str(" D "); Dec(n)];
and ONum(n) be [ Str(" O "); Oct(n)];
and XNum(p) be [ Str(" X "); Dec(p!0); Chr($ ); UDec(p!1) ];
and Char(c) be
[
test ($0 le c & c le $9)
% ($A le c & c le $Z)
% ($a le c & c le $z)
ifso [ Str(" C "); Chr(c) ]
ifnot ONum(c);
];
and RNumOver10(n) be // n/10 as a real number
[
Str(" R ");
if n ls 0 do [ Chr($-); n=-n];
UDec(n/10); Chr($.); UDec(n rem 10)
];
and Begin() be [ Chr($(); lev=lev+1 ]
and End() be [ lev=lev-1; Chr($)); Cr() ];
// routines for dealing with file positions in words
and
SetPos(stream, fp) be
[
let fph, fpl=fp!0, fp!1; // don't disturb given fp
fph=(fph lshift 1)+(fpl ls 0?1,0)
fpl=fpl lshift 1
SetFilePos(stream, fph, fpl)
]
and
GetPos(stream, fp) be
[
FilePos(stream, fp)
fp!1=(fp!1 rshift 1)+((fp!0 & 1) eq 1?#100000,0);
fp!0=fp!0 rshift 1
]
and
IncPos(stream, nwords) be // increment file position by nwords
[
let fp=vec 1;
GetPos(stream, fp);
let t=vec 1;
t!0=nwords ls 0?-1,0;
t!1=nwords;
DoubleAdd(fp, t);
SetPos(stream, fp);
]
and
DoubleSub(a, b) be
[
// does a ← a - b
let minusb=vec 1;
minusb!0, minusb!1 = not b!0, not b!1;
DoubleAdd(minusb, table [ 0; 1 ]);
DoubleAdd(a, minusb);
];
and
MulDiv(a,b,c) = valof [
// Returns a*b/c using unsigned arithmetic.
MulDiv=table [
#55001 // STA 3,1,2
#155000 // MOV 2,3 save stack pointer
#111000 // MOV 0,2 a
#21403 // LDA 0,3,3
#101220 // MOVZR 0,0 c/2
#61020 // MUL
#31403 // LDA 2,3,3 c
#61021 // DIV
#101010 // MOV# 0,0
#121000 // MOV 1,0
#171000 // MOV 3,2
#35001 // LDA 3,1,2
#1401 // JMP 1,3
]
resultis MulDiv(a,b,c)
]
and
WordsForString(s) = valof
[
let b=s>>S.length+1; // number of bytes
resultis (b+1)/2; // number of words required
];
and
CopyString(dest, source) be
MoveBlock(dest, source, WordsForString(source));
and
StringMatch(s1,s2) = valof
[
let Uc(c) = (c ge $a & c le $z)?(c-($a-$A)),c;
let n=s1>>S.length;
if s2>>S.length ne n resultis false;
for i=0 to n-1 do
if Uc(s1>>S.body↑i) ne Uc(s2>>S.body↑i) resultis false;
resultis true;
];
and
AppendChar(s, c) be
[
let i=s>>S.length;
s>>S.body↑i=c;
s>>S.length=i+1;
];
and
AppendNum(s, n) be
[
// append the number n, in decimal, to string s
if n gr 9 do [ AppendNum(s, n/10); n=n rem 10 ];
AppendChar(s,$0+n);
];
and
AppendStr(s, s2) be
[
// append the string s2 to string s
let i=s>>S.length;
for j=0 to s2>>S.length-1 do [ s>>S.body↑i=s2>>S.body↑j; i=i+1 ];
s>>S.length=i;
];
and
DefaultExtension(name, ext) be
[
let n=name>>S.length;
for i=0 to n-1 do if name>>S.body↑i eq $. return;
AppendChar(name,$.);
AppendStr(name,ext);
];
and
StripExtension(s) be
[
for i=0 to s>>S.length-1 do
if s>>S.body↑i eq $. do [ s>>S.length=i; return ];
];