IOPrintImpl.mesa
TO DO:
Implement time zones in AppendTime.
Implement AppendReal here, eliminating ConvertReal and IeeeIOB.
Last edited by
Schmidt on 31-Aug-81 21:39:19
Stewart on 20-Jan-82 19:15:39
Teitelman on January 21, 1983 5:31 pm
Andrew Birrell on June 22, 1983 9:44 am
Paul Rovner on May 26, 1983 3:56 pm
Levin on August 8, 1983 6:09 pm
MBrown on September 19, 1983 10:34 pm
DIRECTORY
Ascii USING [Lower],
BasicTime USING [earliestGMT, GMT, Update],
Convert,
IO,
IOUtils,
RefText,
Real USING [RealException],
RealOps USING [RoundLI],
Rope;
IOPrintImpl: CEDAR MONITOR
IMPORTS Ascii, BasicTime, Convert, IO, IOUtils, RefText, Real, RealOps, Rope
EXPORTS IO, IOUtils
= BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
Value: TYPE = IO.Value;
Format: TYPE = IOUtils.Format;
PFCodeProc: TYPE = IOUtils.PFCodeProc;
PFErrorProc: TYPE = IOUtils.PFErrorProc;
Put
PutRope: PUBLIC PROC [self: STREAM, r: ROPE] = {
WITH r SELECT FROM
t: Rope.Text => self.PutBlock[RefText.TrustTextRopeAsText[t]];
ENDCASE => {
Put: PROC [char: CHAR] RETURNS [BOOL] = {
self.PutChar[char];
RETURN[FALSE]
};
[] ← Rope.Map[base: r, action: Put];
};
};
Put: PUBLIC PROC [stream: STREAM, v1, v2, v3: Value] = {
scratch: REF TEXT = RefText.ObtainScratch[100];
Put1[stream, v1, scratch];
Put1[stream, v2, scratch];
Put1[stream, v3, scratch];
RefText.ReleaseScratch[scratch];
};
PutR: PUBLIC PROC [v1, v2, v3: Value] RETURNS [ROPE] = {
stream: STREAM = IO.ROS[];
scratch: REF TEXT = RefText.ObtainScratch[100];
Put1[stream, v1, scratch];
Put1[stream, v2, scratch];
Put1[stream, v3, scratch];
RefText.ReleaseScratch[scratch];
RETURN[stream.RopeFromROS[]];
};
PutL: PUBLIC PROC [stream: STREAM, list: LIST OF Value] = {
scratch: REF TEXT = RefText.ObtainScratch[100];
FOR l: LIST OF READONLY Value ← list, l.rest UNTIL l = NIL DO
Put1[stream, l.first, scratch];
ENDLOOP;
RefText.ReleaseScratch[scratch];
};
PutLR: PUBLIC PROC [list: LIST OF Value] RETURNS [ROPE] = {
stream: STREAM = IO.ROS[];
scratch: REF TEXT = RefText.ObtainScratch[100];
FOR l: LIST OF READONLY Value ← list, l.rest UNTIL l = NIL DO
Put1[stream, l.first, scratch];
ENDLOOP;
RefText.ReleaseScratch[scratch];
RETURN[stream.RopeFromROS[]];
};
Put1: PROC [stream: STREAM, v: Value, scratch: REF TEXT] = {
scratch.length ← 0;
WITH v SELECT FROM
null: Value.null => NULL;
atom: Value.atom => stream.PutRope[Convert.RopeFromAtom[
from: atom.value, quote: FALSE]];
bool: Value.boolean =>
stream.PutBlock[RefText.TrustTextRopeAsText[Convert.RopeFromBool[bool.value]]];
char: Value.character => stream.PutChar[char.value];
card: Value.cardinal => stream.PutBlock[Convert.AppendCard[scratch, card.value]];
int: Value.integer => stream.PutBlock[Convert.AppendInt[scratch, int.value]];
real: Value.real => stream.PutBlock[Convert.AppendReal[scratch, real.value]];
refAny: Value.refAny => PrintRef[stream, scratch, refAny.value];
rope: Value.rope => stream.PutRope[rope.value];
text: Value.text => stream.PutBlock[text.value];
time: Value.time => stream.PutBlock[Convert.AppendTime[scratch, time.value]];
ENDCASE => ERROR;
};
PrintRefAny
globalPrintRefAny: IOUtils.PrintRefAnyProc ← NIL;
RegisterPrintRefAny: PUBLIC ENTRY PROC [printRefAnyProc: IOUtils.PrintRefAnyProc] = {
globalPrintRefAny ← printRefAnyProc;
};
GetPrintRefAny: ENTRY PROC [] RETURNS [IOUtils.PrintRefAnyProc] = {
RETURN [globalPrintRefAny]
};
PrintRef: PROC [stream: STREAM, scratch: REF TEXT, ref: REF READONLY ANY] = {
printRefAnyProc: IOUtils.PrintRefAnyProc = GetPrintRefAny[];
IF printRefAnyProc = NIL THEN {
scratch ← RefText.AppendTextRope[scratch, "[REF: "];
scratch ← Convert.AppendCard[
to: scratch, from: LOOPHOLE[ref, LONG CARDINAL], base: 8, showRadix: TRUE];
scratch ← RefText.AppendChar[scratch, ']];
stream.PutBlock[scratch];
}
ELSE {
printRefAnyProc[stream, ref, 4, 32, FALSE];
}
};
PFProcs
PFProcs: TYPE = REF PFProcsRecord;
PFProcsRecord: PUBLIC TYPE = RECORD [
procArray: ARRAY CHAR ['a..'z] OF PFCodeProc ← ALL[NIL],
errorProc: PFErrorProc ← NIL
];
globalPFProcs: PFProcs ← NIL;
GetDefaultPFProcs: ENTRY PROC [] RETURNS [PFProcs] = INLINE {
RETURN [globalPFProcs];
};
GetPFProcs: PROC [stream: STREAM] RETURNS [pfProcs: PFProcs] = INLINE {
pfProcs ← NARROW[IOUtils.LookupData[stream, $SetPFCode]];
IF pfProcs = NIL THEN pfProcs ← GetDefaultPFProcs[];
};
SetDefaultPFCodeProc: PUBLIC ENTRY PROC [char: CHAR, codeProc: PFCodeProc]
RETURNS [previous: PFCodeProc] = {
char ← Ascii.Lower[char];
IF char NOT IN ['a..'z] THEN ERROR IO.Error[PFInvalidCode, NIL];
previous ← globalPFProcs.procArray[char];
globalPFProcs.procArray[char] ← codeProc;
};
SetDefaultPFErrorProc: PUBLIC ENTRY PROC [errorProc: PFErrorProc]
RETURNS [previous: PFErrorProc] = {
previous ← globalPFProcs.errorProc;
globalPFProcs.errorProc ← errorProc;
};
CopyPFProcs: PUBLIC PROC [stream: STREAM] RETURNS [new: PFProcs] = {
pfProcs: PFProcs ←
IF stream = NIL THEN NIL ELSE NARROW[IOUtils.LookupData[stream, $SetPFCode]];
IF pfProcs = NIL THEN pfProcs ← GetDefaultPFProcs[];
RETURN [NEW[PFProcsRecord ← pfProcs^]];
};
SetPFProcs: PUBLIC PROC [stream: STREAM, pfProcs: PFProcs] RETURNS [previous: PFProcs] = {
previous ← NARROW[IOUtils.LookupData[stream, $SetPFCode]];
IOUtils.StoreData[stream, $SetPFCode, pfProcs];
};
SetPFCodeProc: PUBLIC PROC [pfProcs: PFProcs, char: CHAR, codeProc: PFCodeProc]
RETURNS [previous: PFCodeProc] = {
IF pfProcs = NIL THEN ERROR IO.Error[PFInvalidPFProcs, NIL];
char ← Ascii.Lower[char];
IF char NOT IN ['a..'z] THEN ERROR IO.Error[PFInvalidCode, NIL];
previous ← pfProcs.procArray[char];
pfProcs.procArray[char] ← codeProc;
};
SetPFErrorProc: PUBLIC PROC [pfProcs: PFProcs, errorProc: PFErrorProc]
RETURNS [previous: PFErrorProc] = {
IF pfProcs = NIL THEN ERROR IO.Error[PFInvalidPFProcs, NIL];
previous ← pfProcs.errorProc;
pfProcs.errorProc ← errorProc;
};
PutF, PutFR, PutFL, PutFLR
PutF: PUBLIC PROC [stream: STREAM, format: ROPE, v1, v2, v3, v4, v5: Value] = {
pfProcs: PFProcs = GetPFProcs[stream];
fp: INT ← 0;
IF v1.type#null THEN fp ← PFInternal[stream, format, fp, v1, pfProcs];
IF v2.type#null THEN fp ← PFInternal[stream, format, fp, v2, pfProcs];
IF v3.type#null THEN fp ← PFInternal[stream, format, fp, v3, pfProcs];
IF v4.type#null THEN fp ← PFInternal[stream, format, fp, v4, pfProcs];
IF v5.type#null THEN fp ← PFInternal[stream, format, fp, v5, pfProcs];
[] ← PFInternal[stream, format, fp, [null[]], pfProcs];
};
PutFR: PUBLIC PROC [format: ROPE, v1, v2, v3, v4, v5: Value]
RETURNS [ROPE] = {
stream: STREAM = IO.ROS[];
PutF[stream, format, v1, v2, v3, v4, v5];
RETURN [stream.RopeFromROS[]];
};
PutFL: PUBLIC PROC [stream: STREAM, format: ROPE, list: LIST OF Value] = {
pfProcs: PFProcs = GetPFProcs[stream];
fp: INT ← 0;
FOR l: LIST OF READONLY Value ← list, l.rest UNTIL l = NIL DO
fp ← PFInternal[stream, format, fp, l.first, pfProcs];
ENDLOOP;
[] ← PFInternal[stream, format, fp, [null[]], pfProcs];
};
PutFLR: PUBLIC PROC [format: ROPE, list: LIST OF Value] RETURNS [ROPE] = {
stream: STREAM = IO.ROS[];
PutFL[stream, format, list];
RETURN [stream.RopeFromROS[]];
};
PFInternal (scan format and print one Value)
PFInternal: PROC [
stream: STREAM, format: ROPE, formatPtr: INT, arg: Value, pfProcs: PFProcs]
RETURNS [--advancedFormatPtr--INT] = {
Scans format, starting at formatPtr, until reaching end or reaching a conversion specification (e.g., "%05d"). If format is a null rope, treats it as if it were the rope "%g", and as if formatPtr = 0. If conversion specification is found and arg is not null, prints it; if conversion specification is not found and arg is null, ok; otherwise error. Returns index of first byte of format not scanned.
error: IO.ErrorCode ← $Null;
c: CHAR;
GetNextFromFormat: PROC[] = INLINE {
c ← format.InlineFetch[formatPtr]; formatPtr ← formatPtr.SUCC;
};
formatSize: INT ← format.InlineLength[];
IF formatSize = 0 THEN {
IF arg.type = null THEN GOTO Done
ELSE {
format ← "%g"; formatSize ← 2; formatPtr ← 0 }
};
DO { -- EXITS PutC, HandleError
IF formatPtr >= formatSize THEN {
IF arg.type = null THEN GOTO Done
ELSE { --ran out of format while looking for '%
error ← PFFormatSyntaxError; GOTO HandleError
}
};
GetNextFromFormat[];
IF c # '% THEN GOTO PutC;
{
savedFormatPointer: INT = formatPtr;
DO {
IF formatPtr >= formatSize THEN { --ran out of format while looking for code
error ← PFFormatSyntaxError; GOTO HandleError
};
GetNextFromFormat[];
IF c IN ['a..'z] OR c IN ['A..'Z] THEN GOTO FoundCode;
IF c = '% THEN GOTO FoundPercent;
EXITS
FoundCode => EXIT;
FoundPercent => { --found '% while looking for code
IF formatPtr = savedFormatPointer.SUCC THEN GOTO PutC;
error ← PFFormatSyntaxError; GOTO HandleError
};
} ENDLOOP;
IF arg.type = null THEN { --no Value corresponding to '% in format
error ← PFFormatSyntaxError; GOTO HandleError
};
c ← Ascii.Lower[c];
{
c is a conversion code; conversion string is the stuff between % and c.
Now either print arg or generate error.
If arg has type refAny, narrow it to a more specific type if possible.
Can't update of arg in checked code, even though arg is local!
val: Value = WITH arg SELECT FROM
ref: Value.refAny =>
WITH ref.value SELECT FROM
refBool: REF READONLY BOOL => IO.bool[refBool^],
refChar: REF READONLY CHAR => IO.char[refChar^],
refCard: REF READONLY CARDINAL => IO.card[refCard^],
refLongCard: REF READONLY LONG CARDINAL => IO.card[refLongCard^],
refInteger: REF READONLY INTEGER => IO.int[refInteger^],
refInt: REF READONLY INT => IO.int[refInt^],
refNat: REF READONLY NAT => IO.int[refNat^],
refReal: REF READONLY REAL => IO.real[refReal^],
refText: REF READONLY TEXT => IO.text[refText],
atom: ATOM => IO.atom[atom],
rope: ROPE => IO.rope[rope],
Not possible now because of Compiler bug?
pi: REF READONLY BasicTime.GMT => time[pi^],
Not possible now because GMT is opaque
ENDCASE => arg
ENDCASE => arg;
p: PFCodeProc ← pfProcs.procArray[c];
IF p = NIL THEN {
error ← PFCantBindConversionProc; GOTO HandleError
};
p[stream, val, [format, savedFormatPointer], c ! IO.Error =>
IF ec IN [PFCantBindConversionProc .. PFUnprintableValue] THEN {
error ← ec; GOTO HandleError }];
GOTO Done;
}
}
EXITS
PutC => stream.PutChar[c];
HandleError => {
ep: PFErrorProc ← pfProcs.errorProc;
IF ep = NIL THEN ep ← PFErrorPrintPounds;
ep[error, stream];
GOTO Done;
};
} ENDLOOP;
EXITS
Done => RETURN [formatPtr];
};
PFErrorPrintPounds: PUBLIC PROC [error: IO.ErrorCode, stream: STREAM] = {
stream.PutRope["#####"];
};
PFErrorNoop: PUBLIC PROC [error: IO.ErrorCode, stream: STREAM] = {
};
PFErrorError: PUBLIC PROC [error: IO.ErrorCode, stream: STREAM] = {
ERROR IO.Error[error, stream];
};
PFCodeProcs
StringRoutine: PROC [stream: STREAM, val: Value, format: Format, char: CHAR] = TRUSTED {
TRUSTED because of WITH v: val SELECT ... compiler problem
Value: any
Format: standard
char: 'h: causes ^<char> for ctrl-char.
Converts fixnums to decimal, flonums to F-format decimal. Converts bools to "TRUE" | "FALSE". Converts date to standard format. Prints resulting string.
r: REF TEXT ← NIL;
rp: ROPE ← NIL;
WITH v: val SELECT FROM
atom => rp ← Convert.RopeFromAtom[from: v.value, quote: FALSE];
boolean => rp ← Convert.RopeFromBool[v.value];
character => {
r ← RefText.ObtainScratch[1];
r[0] ← v.value;
r.length ← 1;
};
cardinal => r ← Convert.AppendCard[RefText.ObtainScratch[12], v.value];
integer => r ← Convert.AppendInt[RefText.ObtainScratch[12], v.value];
real => r ← Convert.AppendReal[RefText.ObtainScratch[24], v.value];
refAny => {
stream: STREAM = IO.ROS[];
stream.Put[val];
rp ← stream.RopeFromROS[];
};
rope => rp ← v.value;
text => rp ← RefText.TrustTextAsRope[v.value];
time => r ← Convert.AppendTime[RefText.ObtainScratch[24], v.value];
ENDCASE => ERROR;
PrintText[r, rp, format, stream, IF char = 'h THEN TRUE ELSE FALSE];
};
FixnumRoutine: PROC [stream: STREAM, val: Value, format: Format, char: CHAR] = TRUSTED {
TRUSTED because of WITH v: val SELECT ... compiler problem
Value: bool, char, card, int, real
Format: standard
char: 'b: forces base 8; 'x: forces base 16
Converts numbers to decimal unless other base specified by char. Converts bools to 1 | 0. Converts char to numeric code. Rounds real to nearest INT. Prints resulting string.
base: Convert.Base ← SELECT char FROM 'b => 8, 'x => 16, ENDCASE => 10;
r: REF TEXT = WITH v: val SELECT FROM
boolean => Convert.AppendCard[RefText.ObtainScratch[1], IF v.value THEN 1 ELSE 0, base],
cardinal => Convert.AppendCard[RefText.ObtainScratch[12], v.value, base],
integer => Convert.AppendInt[RefText.ObtainScratch[12], v.value, base],
real => Convert.AppendInt[RefText.ObtainScratch[24], RealOps.RoundLI[v.value !
Real.RealException => ERROR IO.Error[PFUnprintableValue, stream]], base],
ENDCASE => ERROR IO.Error[PFTypeMismatch, stream];
PrintText[r, NIL, format, stream, FALSE];
};
FlonumRoutine: PROC [stream: STREAM, val: Value, format: Format, char: CHAR] = {
Value: card, int, real
Format: standard (does NOT notice precision control)
char: 'e: forces E format floating point
Converts card and int to real; prints real in an unspectacular manner.
realValue: REAL;
WITH val SELECT FROM
cardVal: Value.cardinal => realValue ← cardVal.value;
intVal: Value.integer => realValue ← intVal.value;
realVal: Value.real => realValue ← realVal.value
ENDCASE => ERROR IO.Error[PFTypeMismatch, stream];
PrintText[
Convert.AppendReal[to: RefText.ObtainScratch[24], from: realValue, useE: char = 'e],
NIL, format, stream, FALSE];
};
LooksRoutine: PROC [stream: STREAM, val: Value, format: Format, char: CHAR] = {
Value: rope
Format: ignored
char: ignored
Noop here; for Viewer streams, performs font changes
WITH val SELECT FROM
ropeVal: Value.rope => NULL;
ENDCASE => ERROR IO.Error[PFTypeMismatch, stream];
};
RopeLiteralRoutine: PROC [stream: STREAM, val: Value, format: Format, char: CHAR] = {
Value: rope
Format: ignored
char: ignored
Prints rope with \-notation for control codes, \, and "
PutEscape: PROC [c: CHAR] RETURNS [BOOL] = {
Print c to stream with \-notation
IF c IN [40C .. 177C] THEN {
IF c = '\\ OR c = '\" THEN stream.PutChar['\\];
stream.PutChar[c];
}
ELSE {
stream.PutChar['\\];
SELECT c FROM
'\n => stream.PutChar['n];
'\t => stream.PutChar['t];
'\b => stream.PutChar['b];
'\f => stream.PutChar['f];
'\l => stream.PutChar['l];
ENDCASE => {
stream.PutChar['0 + (c - 0C) / 64];
stream.PutChar['0 + (c - 0C) MOD 64 / 8];
stream.PutChar['0 + (c - 0C) MOD 8]
} ;
};
RETURN [FALSE];
};
WITH val SELECT FROM
ropeVal: Value.rope => [] ← Rope.Map[base: ropeVal.value, action: PutEscape];
ENDCASE => ERROR IO.Error[PFTypeMismatch, stream];
};
TimeIntervalRoutine: PROC [stream: STREAM, val: Value, format: Format, char: CHAR] = TRUSTED {
Value: card, int, real
Format: standard
char: ignored
Rounds real to nearest INT. Prints number as hh:mm:ss (hh may be more than two digits, but not fewer).
et, hours1, minutes, seconds: LONG CARDINAL;
li: INT;
r: REF TEXT;
han: STREAM;
WITH v: val SELECT FROM
cardinal => et ← v.value;
integer => et ← LOOPHOLE[v.value];
real => TRUSTED {
li ← RealOps.RoundLI[v.value ! Real.RealException =>
ERROR IO.Error[PFUnprintableValue, stream]];
IF li < 0 THEN ERROR IO.Error[PFUnprintableValue, stream];
et ← li;
};
ENDCASE => ERROR IO.Error[PFTypeMismatch, stream];
seconds ← et MOD 60;
et ← et/60;
minutes ← et MOD 60;
et ← et/60;
hours1 ← et MOD 100;
et ← et/100;
r ← RefText.ObtainScratch[50];
han ← IO.TOS[r];
IO.PutF[han, "%g%02g:%02g:%02g",
IF et # 0 THEN IO.int[et] ELSE IO.rope[NIL],
IO.card[hours1],
IO.card[minutes],
IO.card[seconds]];
r ← han.TextFromTOS[];
han.Close[];
PrintText[r, NIL, format, stream, FALSE];
};
TimeRoutine: PROC [stream: STREAM, val: Value, format: Format, char: CHAR] = TRUSTED {
Value: int, card, real, time
Format: standard
char: ignored
Prints a date using AppendTime. Interprets int, card, and real as seconds since "beginning of time"
t: BasicTime.GMT;
li: INT;
WITH v: val SELECT FROM
integer => t ← BasicTime.Update[base: BasicTime.earliestGMT, period: v.value];
cardinal => t ← BasicTime.Update[base: BasicTime.earliestGMT, period: v.value];
real => {
li ← RealOps.RoundLI[v.value ! Real.RealException =>
ERROR IO.Error[PFUnprintableValue, stream]];
IF li < 0 THEN ERROR IO.Error[PFUnprintableValue, stream];
t ← BasicTime.Update[base: BasicTime.earliestGMT, period: li];
};
time => t ← v.value;
ENDCASE => ERROR IO.Error[PFTypeMismatch, stream];
PrintText[Convert.AppendTime[RefText.ObtainScratch[100], t], NIL, format, stream, FALSE];
};
Field justification and filling
PrintText: PROC [
text: REF TEXT, rp: ROPE, format: Format, stream: STREAM, visiblecc: BOOL] = {
Prints text or rp to stream, while enforcing simple format specifications: field width, left or right justification, zero-filling. Format has syntax [0|-|][num.num]. Used by conversion routines that first buffer full output in text, then format it here. Our policy is to print all of text, even if the format specifies a smaller width.
If text is non-NIL, releases to scratch pool after call.
MyPut: PROC [c: CHAR] RETURNS [BOOL] = { stream.PutChar[c]; RETURN[FALSE] };
ladj, fill0: BOOLFALSE;
w, k, tlength: CARDINAL; -- w is field width, k is # chars to fill
c: CHAR;
formatPtr: INT ← format.first;
GetNextFromFormat: PROC[] = INLINE {
c ← format.form.InlineFetch[formatPtr]; formatPtr ← formatPtr.SUCC };
IF text#NIL THEN tlength ← text.length ELSE tlength ← rp.InlineLength[];
GetNextFromFormat[];
SELECT c FROM
'0 => { fill0 ← TRUE; GetNextFromFormat[] };
'- => { ladj ← TRUE; GetNextFromFormat[] };
ENDCASE;
w ← 0;
DO
SELECT c FROM
IN ['0 .. '9] => { w ← w*10 + (c - '0); GetNextFromFormat[] };
ENDCASE => EXIT;
ENDLOOP;
SELECT Ascii.Lower[c] FROM
'., IN ['a .. 'z] => NULL;
ENDCASE => IO.Error[PFFormatSyntaxError, stream];
IF w < tlength THEN { w ← tlength; k ← 0} ELSE { k ← w - tlength };
IF NOT ladj THEN THROUGH [1..k] DO stream.PutChar[IF fill0 THEN '0 ELSE ' ] ENDLOOP;
IF visiblecc THEN FOR j: NAT IN [0..tlength) DO
c ← IF text#NIL THEN text[j] ELSE rp.Fetch[j];
IF c < 40C THEN {stream.PutChar['^]; stream.PutChar[c + LOOPHOLE['@, CARDINAL]]; }
ELSE stream.PutChar[c];
ENDLOOP
ELSE {
IF text#NIL THEN stream.PutBlock[text]
ELSE [] ← Rope.Map[base: rp, action: MyPut];
};
IF ladj THEN THROUGH [1..k] DO stream.PutChar[' ] ENDLOOP;
IF text#NIL THEN RefText.ReleaseScratch[text];
};
Initialization
Create: ENTRY PROC [] = {
globalPFProcs ← NEW[PFProcsRecord ← []];
globalPFProcs.errorProc ← PFErrorPrintPounds;
globalPFProcs.procArray['a] ← StringRoutine;
globalPFProcs.procArray['b] ← FixnumRoutine;
globalPFProcs.procArray['c] ← StringRoutine;
globalPFProcs.procArray['d] ← FixnumRoutine;
globalPFProcs.procArray['e] ← FlonumRoutine;
globalPFProcs.procArray['f] ← FlonumRoutine;
globalPFProcs.procArray['g] ← StringRoutine;
globalPFProcs.procArray['h] ← StringRoutine;
globalPFProcs.procArray['l] ← LooksRoutine;
globalPFProcs.procArray['q] ← RopeLiteralRoutine;
globalPFProcs.procArray['r] ← TimeIntervalRoutine;
globalPFProcs.procArray['s] ← StringRoutine;
globalPFProcs.procArray['t] ← TimeRoutine;
globalPFProcs.procArray['x] ← FixnumRoutine;
};
Create[];
END.