<> <> <> DIRECTORY Basics USING [BYTE, HighHalf, LowHalf], IO USING [GetChar, PutChar, STREAM], IPXerox USING [EncodingValue, SequenceType, ShortEncodingValue, ShortNumber, Token]; IPXeroxImpl: CEDAR PROGRAM IMPORTS Basics, IO EXPORTS IPXerox ~ BEGIN OPEN IPXerox; STREAM: TYPE ~ IO.STREAM; BYTE: TYPE ~ Basics.BYTE; PutByte: PROC[stream: STREAM, byte: BYTE] ~ INLINE { IO.PutChar[stream, VAL[byte]] }; PutToken: PUBLIC PROC[stream: STREAM, token: Token] ~ { WITH token: token SELECT FROM shortNumber => { x: [0..77777B] ~ token.number-ShortNumber.FIRST; PutByte[stream, x/400B]; PutByte[stream, x MOD 400B]; }; shortOp => { PutByte[stream, 200B+ORD[token.op]]; }; longOp => { x: [0..17777B] ~ ORD[token.op]; PutByte[stream, 240B+x/400B]; PutByte[stream, x MOD 400B]; }; shortSequence => { PutByte[stream, 300B+ORD[token.type]]; PutByte[stream, token.length]; }; longSequence => { highByte: BYTE ~ Basics.HighHalf[token.length]; -- this does the bounds check lowWord: CARDINAL ~ Basics.LowHalf[token.length]; PutByte[stream, 340B+ORD[token.type]]; PutByte[stream, highByte]; PutByte[stream, lowWord/400B]; PutByte[stream, lowWord MOD 400B]; }; ENDCASE => ERROR; }; GetByte: PROC[stream: STREAM] RETURNS[BYTE] ~ INLINE { RETURN[ORD[CHAR[IO.GetChar[stream]]]] }; GetToken: PUBLIC PROC[stream: STREAM] RETURNS[Token] ~ { b: BYTE ~ GetByte[stream]; SELECT b FROM <200B => RETURN[[shortNumber[b*400B+GetByte[stream]+ShortNumber.FIRST]]]; <240B => RETURN[[shortOp[VAL[b MOD 40B]]]]; <300B => RETURN[[longOp[VAL[(b MOD 40B)*400B+GetByte[stream]]]]]; <340B => RETURN[[shortSequence[type: VAL[b MOD 40B], length: GetByte[stream]]]]; <400B => { length: INT _ GetByte[stream]; length _ length*400B+GetByte[stream]; length _ length*400B+GetByte[stream]; RETURN[[longSequence[type: VAL[b MOD 40B], length: length]]]; }; ENDCASE => ERROR; }; END.