// 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 ]; ];