TargetConversionsImpl.mesa
Copyright Ó 1986, 1988, 1991 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) July 26, 1988 1:20:35 am PDT
Willie-s, September 24, 1991 4:50 pm PDT
DIRECTORY
Basics,
Basics16,
OSMiscOps USING [Copy],
Rope USING [Fetch, Length, ROPE, Text, TextRep],
SafeStorage USING [GetSystemZone],
TargetConversions,
TargetConversionsPrivate;
TargetConversionsImpl: CEDAR PROGRAM
IMPORTS Basics, Basics16, OSMiscOps, Rope, SafeStorage
EXPORTS TargetConversions
SHARES Rope
= BEGIN OPEN TargetConversions, TargetConversionsPrivate;
This implementation is customized to Dragon, although I hope to have shown where other machines can be plugged in.
In the external implementation more significant bytes are put out before less significant bytes for multi-byte numbers.
This implementation assumes that in the declaration PACKED ARRAY Index OF BOOL the more significant bits have lower indexes than the less significant bits. We also assume that the representations for packed arrays that occupy bitsPerWord bits can be freely overlaid EXCEPT for packed arrays where the element size is bitsPerWord bits.
Types & constants
ByteSequence: TYPE = Rope.ROPE;
Temporary
Reader: TYPE = REF ReaderRep;
ReaderRep: PUBLIC TYPE = TargetConversionsPrivate.ReaderRep;
Writer: TYPE = REF WriterRep;
WriterRep: PUBLIC TYPE = TargetConversionsPrivate.WriterRep;
Word: TYPE = Bits32;
nullWord: Word = LOOPHOLE[LONG[0]];
bytesPerWord: NAT = LAST[ByteLength];
Global variables
z: ZONE ¬ SafeStorage.GetSystemZone[];
The zone for all allocations in the intermediate code phase. In the non-Cedar world this becomes an UNCOUNTED ZONE.
Exceptions
InsufficientBits: PUBLIC ERROR = CODE;
Raised when a Get& operation is called and not enough bits remain in the reader to deliver the value.
InvalidArgument: PUBLIC ERROR = CODE;
Raised when an argument is illegal.
NotImplemented: PUBLIC ERROR = CODE;
Raised when an operation calls for a translation not supported by the implementation (as in use of Real when the kind is not real32).
NotAligned: PUBLIC ERROR = CODE;
Raised when an operation needs at least byte alignment and the stream is not byte aligned.
Internal Conversions
Card32ToBits32: PROC [c: Card32] RETURNS [Bits32] = INLINE {
RETURN [LOOPHOLE[Basics.FFromCard32[c]]];
};
CharToBits32: PROC [c: CHAR] RETURNS [Bits32] = INLINE {
RETURN [LOOPHOLE[Bytes[0, 0, 0, c.ORD]]];
};
Int32ToBits32: PROC [i: Int32] RETURNS [Bits32] = INLINE {
RETURN [LOOPHOLE[Basics.FFromInt32[i]]];
};
Real32ToBits32: PROC [r: Real32] RETURNS [Bits32] = INLINE {
RETURN [LOOPHOLE[Basics.FFromInt32[LOOPHOLE[r]]]];
};
BytesToBits32: PROC [bytes: Bytes] RETURNS [Bits32] = INLINE {
RETURN [LOOPHOLE[bytes]];
};
Bits32ToCard32: PROC [b: Bits32] RETURNS [Card32] = INLINE {
RETURN [Basics.Card32FromF[LOOPHOLE[b]]];
};
Bits32ToChar: PROC [b: Bits32] RETURNS [CHAR] = INLINE {
bytes: Bytes = LOOPHOLE[b];
RETURN [VAL[bytes[0]]];
};
Bits32ToInt32: PROC [b: Bits32] RETURNS [Int32] = INLINE {
RETURN [Basics.Int32FromF[LOOPHOLE[b]]];
};
Bits32ToReal32: PROC [b: Bits32] RETURNS [Real32] = INLINE {
RETURN [LOOPHOLE[Basics.Int32FromF[LOOPHOLE[b]]]];
};
Bits32ToBytes: PROC [b: Bits32] RETURNS [Bytes] = INLINE {
RETURN [LOOPHOLE[b]];
};
CharToByte: PROC [c: CHAR] RETURNS [BYTE] = INLINE {
RETURN [ORD[c]];
};
ByteToChar: PROC [b: BYTE] RETURNS [CHAR] = INLINE {
RETURN [VAL[b]];
};
Utilities
bank: CARD = 65536;
bigEndianOrder: Bytes = LOOPHOLE[(1*bank)+(2*256+3)];
littleEndianOrder: Bytes = LOOPHOLE[(3*256*bank+2*bank)+(1*256)];
princOpsOrder: Bytes = LOOPHOLE[(2*256*bank+3*bank)+(1)];
byteOrder: Bytes = [0, 1, 2, 3];
Useful for fixing up byte order
Half: TYPE = PACKED ARRAY [0..bitsPerHalf) OF [0..1];
bitsPerHalf: NAT = bitsPerWord/2;
nullHalf: Half = LOOPHOLE[0];
onesHalf: Half = LOOPHOLE[177777B];
Halves: TYPE = PACKED ARRAY [0..1] OF Half;
HalfShift: PROC [x: Half, len: INTEGER] RETURNS [Half] = INLINE {
RETURN [LOOPHOLE[Basics16.BITSHIFT[LOOPHOLE[x], len]]];
};
HalfAnd: PROC [x,y: Half] RETURNS [Half] = INLINE {
RETURN [LOOPHOLE[Basics16.BITAND[LOOPHOLE[x], LOOPHOLE[y]]]];
};
HalfOr: PROC [x,y: Half] RETURNS [Half] = INLINE {
RETURN [LOOPHOLE[Basics16.BITOR[LOOPHOLE[x], LOOPHOLE[y]]]];
};
WordAnd: PROC [x,y: Word] RETURNS [Word] = INLINE {
RETURN [LOOPHOLE[Basics.BITAND[LOOPHOLE[x], LOOPHOLE[y]]]];
};
WordOr: PROC [x,y: Word] RETURNS [Word] = INLINE {
RETURN [LOOPHOLE[Basics.BITOR[LOOPHOLE[x], LOOPHOLE[y]]]];
};
BitOffsetInByte: PROC [bits: INT] RETURNS [[0..7]] = INLINE {
RETURN [Basics16.BITAND[7, Basics.LowHalf[LOOPHOLE[bits]]]];
};
BitOffsetInWord: PROC [bits: INT] RETURNS [BitIndex] = INLINE {
RETURN [Basics16.BITAND[LAST[BitIndex], Basics.LowHalf[LOOPHOLE[bits]]]];
};
ShiftBitsLeft: PROC [word: Word, shift: BitLength] RETURNS [Word] = --INLINE-- {
halves: Halves ¬ LOOPHOLE[word, Halves];
halves[0] ¬ HalfOr[HalfShift[halves[0], shift], HalfShift[halves[1], shift-bitsPerHalf]];
halves[1] ¬ HalfShift[halves[1], shift];
RETURN [LOOPHOLE[halves]];
};
ShiftBitsRight: PROC [word: Word, shift: BitLength] RETURNS [Word] = --INLINE-- {
halves: Halves ¬ LOOPHOLE[word, Halves];
halves[1] ¬ HalfOr[HalfShift[halves[1], -shift], HalfShift[halves[0], bitsPerHalf-shift]];
halves[0] ¬ HalfShift[halves[0], -shift];
RETURN [LOOPHOLE[halves]];
};
MaskBitsLeft: PROC [bits32: Word, leftBits: BitLength] RETURNS [Word] = --INLINE-- {
halves: Halves ¬ LOOPHOLE[bits32, Halves];
SELECT leftBits FROM
<= bitsPerHalf => {
halves[0] ¬ HalfAnd[halves[0], HalfShift[onesHalf, bitsPerHalf-leftBits]];
halves[1] ¬ nullHalf;
};
< bitsPerWord =>
halves[1] ¬ HalfAnd[halves[1], HalfShift[onesHalf, bitsPerWord-leftBits]];
ENDCASE;
RETURN [LOOPHOLE[halves]];
};
BitsToBytes: PROC [bits: CARD] RETURNS [CARD] = INLINE {
RETURN [Basics.BITRSHIFT[bits, 3]];
};
SignCheck: PROC [int: Int32, rightBits: BitLength] = {
SELECT rightBits FROM
0 => ERROR InvalidArgument;
< bitsPerWord => {
limit: Int32 = Bits32ToInt32[ShiftBitsLeft[Int32ToBits32[1], rightBits-1]];
IF int NOT IN [-limit..limit) THEN ERROR InvalidArgument;
};
ENDCASE;
};
SignExtend: PROC [int: Int32, rightBits: BitLength] RETURNS [Int32] = {
Sign extension, with the assumption that the left bits (bitsPerWord-rightBits) are all zeros.
bits32: Bits32 ¬ Int32ToBits32[int];
SELECT rightBits FROM
0 => ERROR InvalidArgument;
< bitsPerWord => {
signBitOn: Bits32 ¬ nullBits32;
signIndex: BitIndex ¬ bitsPerWord-rightBits;
signBitOn[signIndex] ¬ 1;
bits32[signIndex] ¬ ORD[NOT VAL[bits32[signIndex]]];
int ¬ Bits32ToInt32[Card32ToBits32[Bits32ToCard32[bits32]-Bits32ToCard32[signBitOn]]];
};
ENDCASE;
RETURN [int];
};
EnsureBytes: PROC [writer: Writer, bytes: NAT] RETURNS [REF TEXT] = {
buffer: REF TEXT ¬ writer.buffer;
bufLen: NAT ¬ bytes;
IF bytes > buffer.maxLength THEN TRUSTED {
oldLen: NAT ¬ buffer.length;
newLen: NAT ¬ IF bytes > LAST[NAT]/2 THEN bytes+256 ELSE bytes*2;
new: REF TEXT ¬ z.NEW[TEXT[newLen]];
new.length ¬ bytes;
OSMiscOps.Copy[
from: LOOPHOLE[buffer, LONG POINTER] + SIZE[TEXT[0]],
nwords: WORDS[TEXT[oldLen]] - WORDS[TEXT[0]],
to: LOOPHOLE[new, LONG POINTER] + SIZE[TEXT[0]]];
writer.buffer ¬ buffer ¬ new;
};
RETURN [buffer];
};
FlushWriterWord: PROC [writer: Writer] = {
IF writer.dirty THEN {
word: Bits32 = writer.partialWord;
buffer: REF TEXT;
bytes: Bytes ¬ Bits32ToBytes[word];
bits: INT ¬ writer.bitPos;
offset: BitIndex = BitOffsetInWord[bits];
bPos: CARDINAL;
IF offset # 0 THEN bits ¬ bits - offset;
bPos ¬ BitsToBytes[bits];
buffer ¬ EnsureBytes[writer, bPos+bytesPerWord];
TRUSTED {
OSMiscOps.Copy[
from: @bytes,
nwords: WORDS[Bytes],
to: LOOPHOLE[buffer, LONG POINTER] + SIZE[TEXT[bPos]]];
};
writer.dirty ¬ FALSE;
};
};
AdvanceWriterPos: PROC [writer: Writer, new: INT] = {
newOffset: BitIndex ¬ BitOffsetInWord[new];
old: INT ¬ writer.bitPos;
oldOffset: BitIndex ¬ BitOffsetInWord[old];
buffer: REF TEXT ¬ writer.buffer;
IF new > writer.bitsWritten THEN writer.bitsWritten ¬ new;
IF (new-newOffset) # (old-oldOffset) THEN {
The old partial word is no longer valid
IF writer.dirty THEN FlushWriterWord[writer];
IF new >= writer.bitsWritten
THEN {
Writing to extend the length
bPos: INT ¬ BitsToBytes[new+(bitsPerWord-1)];
buffer ¬ EnsureBytes[writer, bPos];
writer.partialWord ¬ nullWord;
buffer.length ¬ bPos;
}
ELSE {
We need to get a new partial word from the buffer
bPos: NAT ¬ BitsToBytes[new-newOffset];
bytes: Bytes ¬ nullBytes;
TRUSTED {
OSMiscOps.Copy[
from: LOOPHOLE[buffer, LONG POINTER] + SIZE[TEXT[bPos]],
nwords: WORDS[Bytes],
to: @bytes];
};
writer.partialWord ¬ BytesToBits32[bytes];
};
};
writer.bitPos ¬ new;
};
PutBits32: PROC [writer: Writer, bits32: Bits32, start: BitIndex, bits: BitLength, mask: BOOL ¬ FALSE] = {
Puts out the given unsigned number using the low-order BitLength bits.
IF bits # 0 THEN {
pos: INT ¬ writer.bitPos;
offset: BitIndex ¬ BitOffsetInWord[pos];
rem: NAT ¬ (bitsPerWord-offset);
IF start+bits > bitsPerWord THEN ERROR InvalidArgument;
IF start # 0 THEN bits32 ¬ ShiftBitsLeft[bits32, start];
IF mask THEN bits32 ¬ MaskBitsLeft[bits32, bits];
IF offset # 0 THEN {
There are already bits in the output buffer
writer.partialWord ¬ WordOr[writer.partialWord, ShiftBitsRight[bits32, offset]];
writer.dirty ¬ TRUE;
bits32 ¬ ShiftBitsLeft[bits32, rem];
IF bits < rem THEN {
No need yet to force out a complete word.
new: INT ¬ writer.bitPos ¬ pos + bits;
IF new > writer.bitsWritten THEN writer.bitsWritten ¬ new;
RETURN;
};
AdvanceWriterPos[writer, pos ¬ pos + rem];
bits ¬ bits - rem;
};
IF bits # 0 THEN {
Aligned and stuff to move into the partial word.
writer.partialWord ¬ bits32;
writer.dirty ¬ TRUE;
AdvanceWriterPos[writer, pos ¬ pos + bits];
};
};
};
GetBits32: PROC [reader: Reader, start: BitIndex, len: BitLength]
RETURNS [bits32: Bits32 ¬ nullBits32] = {
IF len # 0 THEN {
offset: BitIndex ¬ BitOffsetInWord[reader.bitsRead];
rem: NAT = bitsPerWord - offset;
bitsAvail: INT = reader.bitsLength-reader.bitsRead;
index: INT ¬ reader.bytesRead;
lastByteIndex: INT ¬ reader.lastByteIndex;
IF bitsAvail < len THEN ERROR InsufficientBits;
IF start+len > bitsPerWord THEN ERROR InvalidArgument;
bits32 ¬ MaskBitsLeft[ShiftBitsLeft[reader.partialWord, offset], len];
The valid bits are all left-justified, other bits are 0s
IF len > rem THEN {
We must read some more to get enough
ReadAhead[reader];
bits32 ¬ WordOr[bits32, ShiftBitsRight[reader.partialWord, len-rem]];
IF start+len # bitsPerWord THEN bits32 ¬ MaskBitsLeft[bits32, len];
};
At this point bits32 is left-justified, and right-padded with 0s.
IF start # 0 THEN bits32 ¬ ShiftBitsRight[bits32, start];
reader.bitsRead ¬ reader.bitsRead + len;
IF BitOffsetInWord[reader.bitsRead] = 0 THEN ReadAhead[reader];
We exhausted the bits in the partial word, so we need some more
};
};
ReadAhead: PROC [reader: Reader] = {
index: INT ¬ reader.bytesRead;
lastByteIndex: INT ¬ reader.lastByteIndex;
bytes: Bytes ¬ nullBytes;
FOR i: ByteIndex IN ByteIndex DO
x: INT ¬ index+i;
IF x > lastByteIndex THEN EXIT;
bytes[i] ¬ CharToByte[Rope.Fetch[reader.buffer, x]];
reader.bytesRead ¬ x+1;
ENDLOOP;
reader.partialWord ¬ BytesToBits32[bytes];
};
Bits32ToByteSequence: PROC
[bits32: Bits32, start: BitIndex, len: BitLength, mask: BOOL ¬ FALSE]
RETURNS [ByteSequence ¬ NIL] = {
IF start # 0 THEN bits32 ¬ ShiftBitsLeft[bits32, start];
IF mask THEN bits32 ¬ MaskBitsLeft[bits32, len];
IF len # 0 THEN {
bytes: Bytes = Bits32ToBytes[bits32];
byteLen: ByteLength = (len+7)/8;
new: Rope.Text ¬ z.NEW[Rope.TextRep[byteLen]];
new.length ¬ byteLen;
FOR i: NAT IN [0..byteLen) DO new[i] ¬ ByteToChar[bytes[i]]; ENDLOOP;
RETURN [new];
};
};
ByteSequenceToBits32: PROC [seq: ByteSequence, start: BitIndex, len: BitLength]
RETURNS [bits32: Bits32 ¬ nullBits32] = {
bytes: Bytes ¬ nullBytes;
byteLen: ByteLength = (len+7)/8;
IF byteLen > Rope.Length[seq] THEN ERROR InvalidArgument;
FOR i: NAT IN [0..byteLen) DO
bytes[i] ¬ CharToByte[Rope.Fetch[seq, i]];
ENDLOOP;
bits32 ¬ BytesToBits32[bytes];
SELECT start+len FROM
> bitsPerWord => ERROR InvalidArgument;
< bitsPerWord => IF len MOD 8 # 0 THEN bits32 ¬ MaskBitsLeft[bits32, len];
ENDCASE;
IF start # 0 THEN bits32 ¬ ShiftBitsRight[bits32, start];
};
Bit Stream Writers
NewWriter: PUBLIC PROC RETURNS [Writer] = {
Returns a new bit stream writer with no bits.
RETURN [NEW[WriterRep ¬ [bitsWritten: 0, partialWord: nullWord, dirty: FALSE, buffer: z.NEW[TEXT[16]]]]];
};
ResetWriter: PUBLIC PROC [writer: Writer] = {
Resets the writer to ground zero, but retains intermediate storage for the sake of efficiency.
writer.bitsWritten ¬ writer.bitPos ¬ 0;
writer.partialWord ¬ nullWord;
writer.buffer.length ¬ 0;
writer.dirty ¬ FALSE;
};
WriterContents: PUBLIC PROC [writer: Writer] RETURNS [ByteSequence ¬ NIL] = {
Returns the byte sequence corresponding to the currently written contents of the given writer. NIL will be returned if there are no bits in the stream.
nB: NAT = BitsToBytes[writer.bitsWritten+7];
IF writer.dirty THEN FlushWriterWord[writer]; -- force out the partial word
IF nB # 0 THEN TRUSTED {
overhead: NAT = SIZE[TEXT[0]];
contents: Rope.Text ¬ z.NEW[Rope.TextRep[nB]];
contents.length ¬ nB;
OSMiscOps.Copy[
from: LOOPHOLE[writer.buffer, LONG POINTER] + overhead,
nwords: WORDS[TEXT[nB]] - WORDS[TEXT[0]],
to: LOOPHOLE[contents, LONG POINTER] + overhead];
RETURN [contents];
};
};
BitsWritten: PUBLIC PROC [writer: Writer] RETURNS [INT] = {
Returns the number of bits currently written to the stream. Useful for hairy alignment problems not covered by PutAlignment.
RETURN [writer.bitsWritten];
};
PutBool: PUBLIC PROC [writer: Writer, bool: Bool] = {
Puts out the given 1-bit boolean value.
PutBits32[writer, Card32ToBits32[ORD[bool]], bitsPerWord-1, 1];
};
PutByteSeq: PUBLIC PROC [writer: Writer, seq: ByteSequence, len: INT] = {
Puts out the first len bytes of the given byte sequence.
IF len > 0 THEN {
buffer: REF TEXT = EnsureBytes[writer, len];
offset: BitIndex = BitOffsetInWord[writer.bitsWritten];
IF offset # 0 THEN ERROR NotAligned;
FOR i: INT IN [0..len) DO
PutBits32[writer, CharToBits32[Rope.Fetch[seq, i]], bitsPerWord-8, 8];
ENDLOOP;
};
};
PutCard: PUBLIC PROC [writer: Writer, card: Card32, bits: BitLength] = {
Puts out the given unsigned number using the low-order BitLength bits.
IF bits # 0 THEN PutBits32[writer, Card32ToBits32[card], bitsPerWord-bits, bits];
};
PutCard32: PUBLIC PROC [writer: Writer, card: Card32] = {
Puts out the given bitsPerWord-bit unsigned number. PutCard32[w, c] is the same as (but faster than) PutCard[w, c, bitsPerWord].
PutBits32[writer, Card32ToBits32[card], 0, bitsPerWord];
};
PutChar: PUBLIC PROC [writer: Writer, char: Char] = {
Puts out the given character.
PutBits32[writer, CharToBits32[char], bitsPerWord-8, 8];
};
PutInt: PUBLIC PROC [writer: Writer, int: Int32, bits: BitLength] = {
Puts out the given signed number using the low-order bits of int. The given Int32 number must have correct sign extension (not currently checked for).
SignCheck[int, bits];
PutBits32[writer, Int32ToBits32[int], bitsPerWord-bits, bits];
};
PutInt32: PUBLIC PROC [writer: Writer, int: Int32] = {
Puts out the given bitsPerWord-bit signed number. PutInt32[w, i] is the same as (but faster than) PutInt[w, i, bitsPerWord].
PutBits32[writer, Int32ToBits32[int], 0, bitsPerWord];
};
PutPadBits: PUBLIC PROC [writer: Writer, bits: BitLength] = {
Puts out the requested number of padding bits.
PutBits32[writer, nullBits32, 0, bits];
};
PutReal: PUBLIC PROC [writer: Writer, real: Real] = {
Puts out the given Real.
WITH real SELECT FROM
real32: real32 Real => PutBits32[writer, Real32ToBits32[real32.real32], 0, bitsPerWord];
ENDCASE => ERROR NotImplemented;
};
SetOutputIndex: PUBLIC PROC [writer: Writer, bits: INT] = {
Sets the bit position in the writer.
SELECT TRUE FROM
bits < 0 => ERROR InvalidArgument;
BitsToBytes[bits] > (LAST[NAT]-20) => ERROR InvalidArgument;
ENDCASE;
AdvanceWriterPos[writer, bits];
};
GetOutputIndex: PUBLIC PROC [writer: Writer] RETURNS [INT] = {
Returns the bit position in the writer.
RETURN [writer.bitPos];
};
Bit Stream Readers
NewReader: PUBLIC PROC [seq: ByteSequence, start: INT ¬ 0, len: INT ¬ LAST[INT]] RETURNS [reader: Reader] = {
Returns a new bit stream Reader with initial contents given by the ByteSequence.
reader ¬ z.NEW[ReaderRep];
InitReader[reader, seq, start, len];
};
InitReader: PUBLIC PROC [reader: Reader, seq: ByteSequence, start: INT ¬ 0, len: INT ¬ LAST[INT]] = {
Initializes an existing Reader with contents given by the ByteSequence.
lim: INT = Rope.Length[seq];
IF start < 0 OR start > lim THEN ERROR InvalidArgument;
IF len < 0 THEN len ¬ 0 ELSE len ¬ MIN[len, lim-start];
reader­ ¬ [
bitsRead: 0,
bytesRead: start,
lastByteIndex: start+len-1,
bitsLength: len*8,
partialWord: nullWord,
buffer: seq];
IF reader.bitsLength # 0 THEN ReadAhead[reader];
};
RemainingBits: PUBLIC PROC [reader: Reader] RETURNS [INT] = {
Returns the number of remaining bits in the reader.
RETURN [reader.bitsLength-reader.bitsRead];
};
BitsRead: PUBLIC PROC [reader: Reader] RETURNS [INT] = {
Returns the number of remaining bits read from the reader.
RETURN [reader.bitsRead];
};
GetBool: PUBLIC PROC [reader: Reader] RETURNS [Bool] = {
Reads a 1-bit boolean value.
bits32: Bits32 = GetBits32[reader, 0, 1];
RETURN [VAL[bits32[0]]];
};
GetByteSequence: PUBLIC PROC [reader: Reader, len: INT] RETURNS [ByteSequence] = {
Reads a sequence of bytes, len gives the number of bytes.
offset: BitIndex ¬ BitOffsetInWord[reader.bitsRead];
IF offset # 0 THEN ERROR NotAligned;
IF len > 0 THEN {
lim: NAT ¬ len;
new: Rope.Text ¬ z.NEW[Rope.TextRep[lim]];
FOR pos: NAT IN [0..lim) DO
new[pos] ¬ ByteToChar[Bits32ToBytes[GetBits32[reader, 0, 8]][0]];
ENDLOOP;
RETURN [new];
};
RETURN [NIL];
};
GetCard: PUBLIC PROC [reader: Reader, bits: BitLength] RETURNS [Card32 ¬ 0] = {
Reads an unsigned number, # of bits given by BitLength.
IF bits # 0 THEN {
bits32: Bits32 = GetBits32[reader, bitsPerWord-bits, bits];
RETURN [Bits32ToCard32[bits32]];
};
};
GetCard32: PUBLIC PROC [reader: Reader] RETURNS [Card32] = {
Reads a bitsPerWord-bit unsigned number.
RETURN [Bits32ToCard32[GetBits32[reader, 0, bitsPerWord]]];
};
GetChar: PUBLIC PROC [reader: Reader] RETURNS [Char] = {
Reads an 8-bit character.
RETURN [Bits32ToChar[GetBits32[reader, bitsPerWord-8, 8]]];
};
GetInt: PUBLIC PROC [reader: Reader, bits: BitLength] RETURNS [Int32 ¬ 0] = {
Reads a signed number, # of bits given by BitLength, and properly extends the sign (if necessary).
IF bits = 0 THEN ERROR InvalidArgument;
RETURN [SignExtend[Bits32ToInt32[GetBits32[reader, bitsPerWord-bits, bits]], bits]];
};
GetInt32: PUBLIC PROC [reader: Reader] RETURNS [Int32] = {
Reads a bitsPerWord-bit signed number.
RETURN [Bits32ToInt32[GetBits32[reader, 0, bitsPerWord]]];
};
SkipPadBits: PUBLIC PROC [reader: Reader, bits: BitLength] = {
Skips a given number of padding bits.
[] ¬ GetBits32[reader, 0, bits];
};
GetReal: PUBLIC PROC [reader: Reader, kind: RealKind ¬ real32] RETURNS [Real] = {
Reads an IEEE floating-point number with the specified number of bits.
IF kind # real32 THEN ERROR NotImplemented;
RETURN [[real32[Bits32ToReal32[GetBits32[reader, 0, bitsPerWord]]]]];
};
SetInputIndex: PUBLIC PROC [reader: Reader, bits: INT] = {
Sets the bit position in the reader.
offset: BitIndex;
SELECT bits FROM
< 0, > reader.bitsLength => ERROR InvalidArgument;
ENDCASE;
offset ¬ BitOffsetInWord[bits];
IF offset # 0 THEN bits ¬ bits - offset;
reader.bytesRead ¬ BitsToBytes[bits];
ReadAhead[reader];
IF offset # 0 THEN [] ¬ GetBits32[reader, 0, offset];
};
Simple Types to Byte Sequences
These operations are present for efficiency. An operation of the form &ToByteSeq[&&] has the same behavior (more or less) as:
{w: Writer ← NewWriter[]; Put&[w, &&]; RESULT[BitStreamToByteSeq[w]]};
BoolToByteSeq: PUBLIC PROC [bool: Bool] RETURNS [ByteSequence] = {
bits32: Bits32 ¬ nullBits32;
bits32[0] ¬ ORD[bool];
RETURN [Bits32ToByteSequence[bits32, 0, 1]];
};
CardToByteSeq: PUBLIC PROC [card: Card32, bits: BitLength] RETURNS [ByteSequence] = {
RETURN [Bits32ToByteSequence[Card32ToBits32[card], bitsPerWord-bits, bits]];
};
Card32ToByteSeq: PUBLIC PROC [card: Card32] RETURNS [ByteSequence] = {
RETURN [Bits32ToByteSequence[Card32ToBits32[card], 0, bitsPerWord]];
};
CharToByteSeq: PUBLIC PROC [char: Char] RETURNS [ByteSequence] = {
bytes: Bytes ¬ nullBytes;
bytes[0] ¬ CharToByte[char];
RETURN [Bits32ToByteSequence[BytesToBits32[bytes], 0, 8]];
};
IntToByteSeq: PUBLIC PROC [int: Int32, bits: BitLength] RETURNS [ByteSequence] = {
SignCheck[int, bits];
RETURN [Bits32ToByteSequence[Int32ToBits32[int], bitsPerWord-bits, bits]];
};
Int32ToByteSeq: PUBLIC PROC [int: Int32] RETURNS [ByteSequence] = {
RETURN [Bits32ToByteSequence[Int32ToBits32[int], 0, bitsPerWord]];
};
RealToByteSeq: PUBLIC PROC [real: Real] RETURNS [ByteSequence] = {
WITH real SELECT FROM
real32: real32 Real =>
RETURN [Bits32ToByteSequence[Real32ToBits32[real32.real32], 0, bitsPerWord]];
ENDCASE => ERROR NotImplemented;
};
Byte Sequences to Simple Types
These operations are present for efficiency. An operation of the form val ← ByteSeqTo&[&&] has the same behavior (more or less) as:
val ← Get&[NewReader[&&]];
ByteSeqToBool: PUBLIC PROC [seq: ByteSequence] RETURNS [Bool] = {
RETURN [VAL[ByteSequenceToBits32[seq, 0, 1][0]]];
};
ByteSeqToCard: PUBLIC PROC [seq: ByteSequence, bits: BitLength] RETURNS [Card32] = {
IF bits = 0 THEN ERROR InvalidArgument;
RETURN [Bits32ToCard32[ByteSequenceToBits32[seq, bitsPerWord-bits, bits]]];
};
ByteSeqToCard32: PUBLIC PROC [seq: ByteSequence] RETURNS [Card32] = {
RETURN [Bits32ToCard32[ByteSequenceToBits32[seq, 0, bitsPerWord]]];
};
ByteSeqToChar: PUBLIC PROC [seq: ByteSequence] RETURNS [Char] = {
RETURN [Bits32ToChar[ByteSequenceToBits32[seq, bitsPerWord-8, 8]]];
};
ByteSeqToInt: PUBLIC PROC [seq: ByteSequence, bits: BitLength] RETURNS [Int32] = {
IF bits = 0 THEN ERROR InvalidArgument;
RETURN [SignExtend[Bits32ToInt32[ByteSequenceToBits32[seq, bitsPerWord-bits, bits]], bits]];
};
ByteSeqToInt32: PUBLIC PROC [seq: ByteSequence] RETURNS [Int32] = {
RETURN [Bits32ToInt32[ByteSequenceToBits32[seq, 0, bitsPerWord]]];
};
ByteSeqToReal: PUBLIC PROC [seq: ByteSequence, kind: RealKind ¬ real32] RETURNS [Real] = {
IF kind # real32 THEN ERROR NotImplemented;
RETURN [[real32[Bits32ToReal32[ByteSequenceToBits32[seq, 0, bitsPerWord]]]]];
};
END.