//MIOC.BCPL -- TV to DVec and DVec to stream routines, also Wns // PutField, and MoveLongField. // Last edited: 1 November 1979 get "mdecl.d" external [ // OS DefaultArgs; Puts; Zero; Min; DoubleAdd // MINIT0 @MBlock // MIDAS MidasSwat // MASM ErrorProtect; RepPuts; GetField; PutField; MoveLongField; DoubleNeg // MSYM EvalAText; ChkToken // Machine dependent DefRadix // Defined here DWns; Wns; DataToStream; GenlTexttoDVec; SimpleTexttoDVec ] //Convert an arbitrary sequence of numbers and address symbols separated //by "+" and "-" into a DVec of size le 32 bits (mandatory use of Form //feature for items bigger than 32 bits). The radix is initialized to //DefRadix, overruled by inserting "#" for octal, "!" for decimal, or "%" //for hexadecimal before any item. let SimpleTexttoDVec(TV,NBits,DVec,Radix,HNum,LNum; numargs NA) = valof [ if NBits > 32 then MidasSwat(NBitsG32) if NA < 4 then Radix = DefRadix let W = (NBits+15) rshift 4; Zero(DVec,W) let CurrentResult = vec 1; Zero(CurrentResult,2) let Size,X,Negative = nil,1,false [ let Token = ChkToken(TV,lv X,lv Size) if Token eq LimitToken then break test Token eq SignToken ifso if TV!X eq $- then Negative = true ifnot [ if Token ge MarkedOct then Radix = Token < MarkedDec ? 8,(Token < MarkedHex ? 10,16) Token = Token & (MarkedOct-1) //Strip radix marks let EvalToken = selecton Radix into [ case 8: OctToken*2 case 10: DecToken*2 case 16: HexToken*2 default: 0 ] if EvalToken eq 0 then MidasSwat(BadRadix) test (Token ge EvalToken) % (Token < OctToken) ifso //Character sequence is non-numeric--evaluate using EvalAText [ let AVal = vec size AVal/16 if not EvalAText(TV,lv X,AVal,true) then resultis false if AVal>>AVal.TypeStorage ne MemTypeStorage then resultis false MBlock(lv HNum,lv AVal>>AVal.Addr,2) ] ifnot //Have a sequence of valid number constituents [ HNum,LNum = 0,0 for I = X to X+Size-1 do [ let N = TV!I if (N eq $!) % (N eq $%) % (N eq $#) then loop (table [ //mul multiplies unsigned integers in 1 and 2 generating a 32-bit product; //low order result added to 0 left in 1; high order result in 0 #55001 //sta 3 1 2 #155000 //mov 2 3 Preserve 2 #31407 //lda 2 7 3 Radix #61020 //mul 0/ ovf of LNum*Radix + digit #45411 //sta 1 11 3 1/ new LNum #25410 //lda 1 10 3 HNum #61020 //mul 0/ ovf of HNum*Radix + low ovf #45410 //sta 1 10 3 1/ new HNum #171000 //mov 3 2 #35001 //lda 3 1 2 #1401 //jmp 1 3 ] )((N ge $A ? N-$A+10,N-$0),LNum) ] ] if Negative then [ DoubleNeg(lv HNum); Negative = false ] DoubleAdd(CurrentResult,lv HNum) ] X = X+Size ] repeat MoveLongField(CurrentResult,32-NBits,NBits,DVec,0) resultis true ] //DVec must be of size ge ValSize and GenlTexttoDVec(TV,Form,DVec,Radix) = valof [ let X,PV,PVptr = 1,vec 40,0 let CDVec = vec ValSize // Parse the groups of characters separated by blanks //PV!i = ptr to 1st char of group, PV!(i+1) = nchars in group while X le TV!0 do [ if TV!X eq $ then [ X = X+1; loop ] PV!PVptr = X //Mark pos. of 1st non-blank in group while (X le TV!0) & (TV!X ne $ ) do X = X+1 PV!(PVptr+1) = X-PV!PVptr; PVptr = PVptr+2 ] let Ngrps = Min(PVptr rshift 1,Form!0) // Zero initial missing groups let Field = vec ValSize let FormX = ((Form!0-Ngrps) lshift 1)+1 Zero(Field,ValSize); Zero(CDVec,ValSize) // Evaluate and store groups with text let TempTV = vec 80 PVptr = PVptr-(Ngrps lshift 1) for I = Form!0-Ngrps+1 to Form!0 do [ let Size = PV!(PVptr+1) TempTV!0 = Size MBlock(TempTV+1,TV+PV!PVptr,Size) unless SimpleTexttoDVec(TempTV,Form!(FormX+1),Field,Radix) do resultis false MoveLongField(Field,0,Form!(FormX+1),CDVec,Form!FormX) FormX = FormX+2; PVptr = PVptr+2 ] MBlock(DVec,CDVec,ValSize); resultis true ] //DataToStream(..) outputs register and memory values to a stream using //a format table from REGFORMS or MEMFORMS. If Form is 0, then a //left-justified octal string is printed. If non-0, it points at a format //table (see D1Tables.asm for description). //Note: Leading blanks must be suppressed for mmprgn.bcpl and DataToStream(S,Form,Width,DVec,Radix; numargs NA) be [ if NA < 5 then Radix = DefRadix test Form eq 0 ifso DWns(S,DVec,Width,0,Radix) ifnot [ let flush0,Foo = 0,Form!0+Form!0-1 for FormX = 1 to Foo by 2 do [ let NBits = Form!(FormX+1) let Width = nil test flush0 eq 0 ifso Width = (FormX eq Foo) & 1 ifnot [ Width = selecton Radix into [ case 16: (NBits+3)/4 case 8: (NBits+2)/3 case 10: table [ //***Just approximate 1; 1; 1; 2; 2; 2; 3; 3 3; 4; 4; 4; 4; 5; 5; 5 6; 6; 6; 7; 7; 7; 7; 8 8; 8; 9; 9; 9; 10; 10; 10 ] ! NBits ] Puts(S,$ ) ] flush0 = DWns(S,DVec,NBits,Form!FormX,Radix,Width,flush0) ] ] ] //DWns prints NBits from DVec starting at DBit1. //Negative radix means print as a signed number. //flush0 is $ for leading blanks or $0 for leading zeroes or 0 for //no leading fill and no-print on 0. If the Width argument is provided, //at least that many characters will be printed. Resultis the original //flush0 if number is 0, 60B if non-0. and DWns(S,DVec,NBits,DBit1,Radix,Width,flush0; numargs NA) = valof [ let HNum,LNum,I = 0,0,nil DefaultArgs(lv NA,2,32,0,DefRadix,1,$*s) if NBits > 32 then MidasSwat(NBitsG32) let V,Sign = vec 32,0 //Setup double-precision number in HNum,LNum if Radix < 0 then if GetField(DBit1,1,DVec) ne 0 then [ HNum,LNum = -1,-1 ] MoveLongField(DVec,DBit1,NBits,lv HNum,32-NBits) if Radix < 0 do [ Radix,Width,Sign = -Radix,Width-1,$+ if HNum < 0 do [ DoubleNeg(lv HNum); Sign = $- ] ] let Result = flush0 if flush0 eq 0 then test (HNum ne 0) % (LNum ne 0) ifso Result = 60B ifnot unless Width > 0 then resultis 0 //Radix is at 10,2; HNum,LNum,I at 14,2 15,2 and 16,2 I = V (table [ //First loop until HNum < Radix #55001 //sta 3 1 2 #155000 //mov 2 3 #31410 //lda 2 10 3 Radix #25414 //lda 1 14 3 HNum #132032 //adcz# 1 2 szc Skip if HNum ge Radix unsigned #414 //jmp .+14 #102400 //sub 0 0 #61021 //div 0←rem, 1←quo #77400 //swat if nodiv #45414 //sta 1 14 3 HNum←quotient #25415 //lda 1 15 3 LNum #61021 //div #77400 //swat #45415 //sta 1 15 3 LNum←quotient #43416 //sta 0 @16 3 rv I = rem #11416 //isz 16 3 I = I+1 #763 //jmp .-15 //Second loop until LNum eq 0 #21414 //lda 0 14 3 HNum #25415 //lda 1 15 3 LNum #61021 //div #77400 //Swat #43416 //sta 0 @16 3 #11416 //isz 16 3 #102400 //sub 0 0 #125014 //mov# 1 1 szr Skip if quotient is 0 #772 //jmp .-6 #171000 //mov 3 2 #35001 //lda 3 1 2 #1401 //jmp 1 3 ] )() I = I-V RepPuts(S,flush0,Width-I) if Sign ne 0 then Puts(S,Sign) while I ne 0 do [ I = I-1; Puts (S,(V!I > 9 ? $A-10,$0)+V!I) ] resultis Result ] // Do numeric output to stream. // Suppresses leading spaces if you tell it to, even if the radix is 8. // Default Width=1, Radix=10, signed and Wns(S,Num,Width,Radix; numargs NA) be [ DefaultArgs(lv NA,-2,1,-10) DWns(S,lv Num,16,0,Radix,Width) ]