-- BasicInterpB.mesa
-- edited by Brotz and Hilton, September 23, 1982 2:33 PM

DIRECTORY
Ascii,
BasicDefs,
BasicImpDefs,
BasicOps,
BcdDefs,
BcdOps,
ControlDefs,
FrameDefs,
FrameOps,
IODefs,
LoaderOps,
Real,
SegmentDefs,
Storage,
String,
vmD: FROM "VirtualMgrDefs";

BasicInterpB: PROGRAM
IMPORTS BasicImpDefs, BasicOps, FrameDefs, FrameOps, IODefs, LoaderOps, Real,
SegmentDefs, Storage, String, vmD
EXPORTS BasicOps, BasicImpDefs =

BEGIN
OPEN BasicDefs, BasicImpDefs;


LEOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
PushInteger[IF PopAndCompare[] <= 0 THEN 1 ELSE 0];
RETURN[FALSE, pc];
END; -- of LEOp --


LesserOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
PushInteger[IF PopAndCompare[] = -1 THEN 1 ELSE 0];
RETURN[FALSE, pc];
END; -- of LesserOp --


ListCodeLine: PROCEDURE [line: ProgramLineDescPtr] =
BEGIN
op, byte: BasicOps.Byte;
var: VariablePtr;
pc: vmD.CharIndex ← line.codeStart;

PrintVariable: PROCEDURE [var: VariablePtr] =
BEGIN
IF var.name # NIL THEN IODefs.WriteString[var.name]
ELSE BEGIN
IODefs.WriteString["Constant: "L];
SELECT var.value.type FROM
integer => WriteLongDecimal[var.value.integerValue];
real => BEGIN
realString: STRING ← [40];
Real.AppendReal[realString, var.value.realValue];
IODefs.WriteString[realString];
END;
string => IODefs.WriteString[var.value.stringValue];
ENDCASE;
END;
END; -- of PrintVariable --

UNTIL pc >= line.codeEnd DO
[op, pc] ← FetchByte[codeCm, pc];
IF op ~IN [1 .. BasicOps.nOps) THEN {IODefs.WriteLine["Smash!!"L]; RETURN};
IODefs.WriteString[BasicOps.opCode[op].name];
SELECT BasicOps.opCode[op].type FROM
loner => NULL;
byte => BEGIN
IODefs.WriteChar[Ascii.TAB];
[byte, pc] ← FetchByte[codeCm, pc];
IODefs.WriteDecimal[byte];
END;
var => BEGIN
IODefs.WriteChar[Ascii.TAB];
[var, pc] ← FetchPointer[codeCm, pc];
PrintVariable[var];
END;
varList => BEGIN
IODefs.WriteChar[Ascii.TAB];
DO
[var, pc] ← FetchPointer[codeCm, pc];
IF var = LOOPHOLE[0] THEN EXIT;
PrintVariable[var];
IODefs.WriteChar[Ascii.TAB];
ENDLOOP;
END;
label => BEGIN
IODefs.WriteChar[Ascii.TAB];
[var, pc] ← FetchPointer[codeCm, pc];
IODefs.WriteDecimal[LOOPHOLE[var]];
END;
labelList => BEGIN
IODefs.WriteChar[Ascii.TAB];
DO
[var, pc] ← FetchPointer[codeCm, pc];
IF var = LOOPHOLE[0] THEN EXIT;
IODefs.WriteDecimal[LOOPHOLE[var]];
IODefs.WriteChar[Ascii.TAB];
ENDLOOP;
END;
defFn => BEGIN
IODefs.WriteChar[Ascii.TAB];
[byte, pc] ← FetchByte[codeCm, pc];
IODefs.WriteString[IF byte = 1 THEN "single"L ELSE "multi"L];
IODefs.WriteChar[Ascii.TAB];
[var, pc] ← FetchPointer[codeCm, pc];
IODefs.WriteString[var.name];
IODefs.WriteChar[Ascii.TAB];
[var, pc] ← FetchPointer[codeCm, pc];
IODefs.WriteString[var.name];
END;
ENDCASE;
IODefs.WriteLine[""L];
ENDLOOP;
END; -- of ListCodeLine --


ListOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
ListOperation[ListSourceLine];
RETURN[FALSE, pc];
END; -- of ListOp --


ListOperation: PUBLIC PROCEDURE [proc: PROC [ProgramLineDescPtr]] =
BEGIN
bv: BasicValue;
line: ProgramLineDescPtr;
start, end: CARDINAL;
bv ← Pop[];
end ← ConvertToCardinal[@bv];
bv ← Pop[];
start ← ConvertToCardinal[@bv];
FOR line ← programLineDescHead, line.next UNTIL line = NIL OR line.lineNumber >= start DO
ENDLOOP;
IF line = NIL THEN RunTimeError["Initial LIST line number does not exist."L];
UNTIL line = NIL OR (end # 0 AND line.lineNumber > end) DO
proc[line];
line ← line.next;
ENDLOOP;
END; -- of ListOperation --


ListSourceAndCodeLine: PUBLIC PROCEDURE [line: ProgramLineDescPtr] =
BEGIN
ListSourceLine[line];
ListCodeLine[line];
END; -- of ListSourceAndCodeLine --


ListSourceLine: PROCEDURE [line: ProgramLineDescPtr] =
BEGIN
IODefs.WriteDecimal[line.lineNumber];
IODefs.WriteChar[Ascii.SP];
FOR index: vmD.CharIndex IN [line.start .. line.end) DO
IODefs.WriteChar[vmD.GetMessageChar[cM, index]];
ENDLOOP;
IODefs.WriteLine[""L];
END; -- of ListSourceLine --


LoadOp: PUBLIC BasicOps.OpCodeProc =
BEGIN OPEN SegmentDefs;
s: STRING ← [40];
extended: BOOLEAN ← FALSE;
bcdFile: FileHandle ← NIL;
ctrlmod: ControlDefs.ControlModule ← ControlDefs.NullControl;
bcd: BcdOps.BcdBase;
bcdseg: FileSegmentHandle;
oldLoadedConfigs: LoadedConfigRecPtr;

OurLoad: PROCEDURE RETURNS [worked: BOOLEAN] =
-- This is derived from AltoLoader.Load and incorporates some bug
-- fixes and some optimizations.
BEGIN
pages: CARDINAL;
worked ← FALSE;
bcdseg ← NewFileSegment[bcdFile, 1, 1, Read];
MakeSwappedIn[bcdseg, DefaultMDSBase, HardUp ! SegmentFault => GO TO bogus];
bcd ← FileSegmentAddress[bcdseg];
IF bcd.versionIdent # BcdDefs.VersionID OR bcd.definitions THEN
{Unlock[bcdseg]; GO TO bogus}
ELSE IF (pages ← bcd.nPages) > 1 THEN
BEGIN
Unlock[bcdseg];
MoveFileSegment[bcdseg, 1, pages];
MakeSwappedIn[bcdseg, DefaultMDSBase, HardUp];
bcd ← FileSegmentAddress[bcdseg];
END;
worked ← TRUE;
EXITS
bogus => DeleteFileSegment[bcdseg];
END; -- of OurLoad --

OurUnload: PROCEDURE =
BEGIN
Unlock[bcdseg];
DeleteFileSegment[bcdseg];
END; -- of OurUnload --

BEGIN
s: STRING ← [60];
bv: BasicValue ← Pop[];
IF bv.type # string THEN RunTimeError["No string for LOAD command"L];
String.AppendString[s, bv.stringValue];
Storage.FreeString[bv.stringValue];
String.AppendString[s, ".bcd"L];
bcdFile ← NewFile[s, Read, OldFileOnly ! FileNameError => GOTO BadName];
LockFile[bcdFile];
IF ~OurLoad[ ! InsufficientVM => GO TO out] THEN GO TO cantExecute;
ctrlmod ← LoaderOps.New[bcd, TRUE, FALSE
! LoaderOps.BadCode => GO TO cantExecute;
LoaderOps.InvalidFile,
LoaderOps.VersionMismatch => GO TO BadVersion;
String.StringBoundsFault,
LoaderOps.FileNotFound => GO TO out;
InsufficientVM => {OurUnload[]; GO TO out} ];
IF ctrlmod = ControlDefs.NullControl THEN GO TO cantExecute;
FrameOps.Start[ctrlmod ! UNWIND => FrameDefs.UnNewConfig[ctrlmod.frame]];
oldLoadedConfigs ← loadedConfigs;
loadedConfigs ← Storage.Node[SIZE[LoadedConfigRec]];
loadedConfigs↑ ← LoadedConfigRec[oldLoadedConfigs, ctrlmod, bcdFile];
EXITS
BadName => RunTimeError["Bad name in LOAD command."L];
BadVersion => RunTimeError["Mismatched version in loaded module."L];
cantExecute, out => IF bcdFile ~= NIL THEN
{SegmentDefs.UnlockFile[bcdFile]; SegmentDefs.ReleaseFile[bcdFile]};
END;
RETURN[FALSE, pc];
END; -- of LoadOp --


MulOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
RETURN[BasicOps.ArithmeticOp[mul], pc];
END; -- of MulOp --


NEOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
PushInteger[IF PopAndCompare[] # 0 THEN 1 ELSE 0];
RETURN[FALSE, pc];
END; -- of NEOp --


NextOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
varPtr: VariablePtr;
node: NextStackPtr;
[varPtr, newPc] ← FetchPointer[cm, pc];
IF nextStackHead = NIL OR nextStackHead.varPtr # varPtr THEN
RunTimeError["Unmatched NEXT statement!"L];
Push[nextStackHead.varPtr.value];
Push[nextStackHead.stepValue];
[] ← BasicOps.ArithmeticOp[add];
nextStackHead.varPtr.value ← Pop[];
IF nextStackHead.stepDirection
= Compare[@nextStackHead.varPtr.value, @nextStackHead.finalValue] THEN
BEGIN
node ← nextStackHead;
nextStackHead ← node.next;
Storage.Free[node];
currentProgLine ← currentProgLine.next;
END
ELSE currentProgLine ← nextStackHead.progLine.next;
RETURN[TRUE, newPc];
END; -- of NextOp --


NormalOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
autoOn ← FALSE;
RETURN[FALSE, pc];
END; -- of NormalOp --


NotOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
bv: BasicValue;
i: CARDINAL;
bv ← Pop[];
i ← ConvertToCardinal[@bv];
PushInteger[IF i = 1 THEN 0 ELSE 1];
RETURN[FALSE, pc];
END; -- of NotOp --


OnGoToOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
BasicOps.GoToGuts[ChooseLineNumber[cm, pc]];
RETURN[TRUE, pc];
END; -- of OnGoToOp --


OnGoSubOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
BasicOps.GoSubGuts[ChooseLineNumber[cm, pc]];
RETURN[TRUE, pc];
END; -- of OnGoSubOp --


OrOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
bv1, bv2: BasicValue;
i1, i2: CARDINAL;
bv2 ← Pop[];
bv1 ← Pop[];
i1 ← ConvertToCardinal[@bv1];
i2 ← ConvertToCardinal[@bv1];
PushInteger[IF i1 = 1 OR i2 = 1 THEN 1 ELSE 0];
RETURN[FALSE, pc];
END; -- of OrOp --


Pop: PUBLIC PROCEDURE RETURNS [bv: BasicValue] =
BEGIN
IF stackPointer = 0 THEN ERROR;
bv ← stack[stackPointer];
stackPointer ← stackPointer - 1;
END; -- of Pop --


PopAndCompare: PUBLIC PROCEDURE RETURNS [result: INTEGER] =
BEGIN
bv1, bv2: BasicValue;
bv2 ← Pop[];
bv1 ← Pop[];
RETURN[Compare[@bv1, @bv2]];
END; -- of PopAndCompare --


PopOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
varPtr: VariablePtr;
bv: BasicValue;
[varPtr, newPc] ← FetchPointer[cm, pc];
bv ← Pop[];
IF (bv.type = string) # (varPtr.value.type = string) THEN
RunTimeError["Assignment between numeric and string!"L];
IF bv.type = string THEN
BEGIN
target: STRING ← varPtr.value.stringValue;
target.length ← MIN[bv.stringValue.length, target.maxlength];
FOR i: CARDINAL IN [0 .. target.length) DO
target[i] ← bv.stringValue[i];
ENDLOOP;
Storage.FreeString[bv.stringValue];
END
ELSE varPtr.value ← bv;
RETURN[FALSE, newPc];
END; -- of PopOp --


PrintOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
bv: BasicValue;
realString: STRING ← [40];
bv ← Pop[];
SELECT bv.type FROM
integer => WriteLongDecimal[bv.integerValue];
real => {Real.AppendReal[realString, bv.realValue]; IODefs.WriteString[realString]};
string => {IODefs.WriteString[bv.stringValue]; Storage.FreeString[bv.stringValue]};
ENDCASE;
RETURN[FALSE, pc];
END; -- of PrintOp --


Push: PUBLIC PROCEDURE [vp: BasicValue] =
BEGIN
stackPointer ← stackPointer + 1;
IF stackPointer >= stackLimit THEN ERROR;
IF vp.type = string THEN vp.stringValue ← Storage.CopyString[vp.stringValue];
stack[stackPointer] ← vp;
END; -- of Push --


PushInteger: PUBLIC PROCEDURE [i: INTEGER] =
BEGIN
bv: BasicValue ← BasicValue[integer, integer[integerValue: i]];
Push[bv];
END; -- of PushInteger --


PushIOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
bv: BasicValue;
byte: BasicOps.Byte;
[byte, newPc] ← FetchByte[cm, pc];
bv ← BasicValue[integer, integer[integerValue: byte]];
Push[bv];
RETURN[FALSE, newPc];
END; -- of PushIOp --


PushOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
varPtr: VariablePtr;
[varPtr, newPc] ← FetchPointer[cm, pc];
Push[varPtr.value];
RETURN[FALSE, newPc];
END; -- of PushOp --


QuitOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
UNTIL loadedConfigs = NIL DO
UnNewLastConfig[];
ENDLOOP;
ERROR QuitSignal;
END; -- of QuitOp --


ReadOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
varPtr: VariablePtr;
DO
IF noMoreData THEN RunTimeError["No more data!"L];
IF dataLinePc = NIL THEN
BEGIN
dataLinePc ← SearchForOpCodeByLines[cm, programLineDescHead, BasicOps.Data];
IF dataLinePc = NIL THEN noMoreData ← TRUE ELSE dataItem ← 0;
LOOP;
END;
[varPtr, ] ← FetchPointer[cm, dataLinePc.codeStart + 1 + dataItem * 2];
IF varPtr = LOOPHOLE[0] THEN
BEGIN
dataLinePc ← SearchForOpCodeByLines[cm, dataLinePc.next, BasicOps.Data];
IF dataLinePc = NIL THEN noMoreData ← TRUE ELSE dataItem ← 0;
LOOP;
END;
Push[varPtr.value];
dataItem ← dataItem + 1;
EXIT;
ENDLOOP;
RETURN[FALSE, pc];
END; -- of ReadOp --


RenumberOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
END; -- of RenumberOp --


RestoreOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
dataItem ← 0;
dataLinePc ← NIL;
noMoreData ← FALSE;
RETURN[FALSE, pc];
END; -- of RestoreOp --


ReturnOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
gssp: GoSubStackPtr ← goSubHead;
IF gssp = NIL THEN RunTimeError["Unmatched RETURN statement!"L];
currentProgLine ← gssp.returnPc.next;
goSubHead ← gssp.next;
Storage.Free[gssp];
RETURN[TRUE, newPc];
END; -- of ReturnOp --


RunOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
bv: BasicValue ← Pop[];
startLine: CARDINAL ← ConvertToCardinal[@bv];
startPc: ProgramLineDescPtr ← programLineDescHead;
IF startLine # 0 THEN
UNTIL startPc = NIL OR startPc.lineNumber = startLine DO
startPc ← startPc.next;
ENDLOOP;
IF startPc = NIL THEN RunTimeError["Can’t find line number to start RUN."L];
currentProgLine ← startPc;
optionBaseCalled ← FALSE;
optionBase ← 0;
noMoreInput ← FALSE;
[ , ] ← RestoreOp[cm, pc];
UNTIL currentProgLine = NIL DO
InterpretCode[codeCm, currentProgLine.codeStart ! RunTimeErrorSignal => EXIT];
ENDLOOP;
currentProgLine ← NIL;
RETURN[TRUE, pc];
END; -- of RunOp --


SearchForOpCodeByLines: PUBLIC
PROCEDURE [cm: vmD.VirtualMessagePtr, pc: ProgramLineDescPtr, opcode: BasicOps.Byte]
RETURNS [newPc: ProgramLineDescPtr] =
-- Looks for a line whose first compiled opcode is "opcode". The search begins with "pc".
-- If not found, then returns NIL.
BEGIN
FOR newPc ← pc, newPc.next UNTIL newPc = NIL DO
IF vmD.GetMessageChar[cm, newPc.codeStart] = LOOPHOLE[opcode] THEN EXIT;
ENDLOOP;
END; -- of SearchForOpCodeByLines --


StopOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
contPc ← currentProgLine.next;
currentProgLine ← NIL;
RETURN[TRUE, pc];
END; -- of StopOp --


Str1PopOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
varPtr: VariablePtr;
bvString: BasicValue ← Pop[];
string: STRING ← bvString.stringValue;
target: STRING;
bv: BasicValue ← Pop[];
index: CARDINAL ← ConvertToCardinal[@bv];
length, maxLength: CARDINAL;
index ← index - 1;
IF bvString.type # string THEN RunTimeError["Assignment of numeric to substring!"L];
[varPtr, newPc] ← FetchPointer[cm, pc];
IF varPtr.value.type # string THEN RunTimeError["Substring operation on numeric value!"L];
target ← varPtr.value.stringValue;
maxLength ← target.maxlength;
IF index ~IN [0 .. maxLength) THEN RunTimeError["Substring index out of bounds!"L];
length ← MIN[maxLength - index, string.length];
FOR i: CARDINAL IN [target.length .. index) DO
target[i] ← Ascii.SP;
ENDLOOP;
target.length ← index + length;
FOR i: CARDINAL IN [0 .. length) DO
target[index + i] ← string[i];
ENDLOOP;
Storage.FreeString[string];
RETURN[FALSE, newPc];
END; -- of Str1PopOp --


Str1PushOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
varPtr: VariablePtr;
string: STRING;
bv: BasicValue ← Pop[];
index: CARDINAL ← ConvertToCardinal[@bv];
length, maxLength: CARDINAL;
index ← index - 1;
[varPtr, newPc] ← FetchPointer[cm, pc];
IF varPtr.value.type # string THEN RunTimeError["Substring operation on numeric value!"L];
maxLength ← varPtr.value.stringValue.maxlength;
IF index ~IN [0 .. maxLength) THEN RunTimeError["Substring index out of bounds!"L];
length ← IF varPtr.value.stringValue.length > index THEN
varPtr.value.stringValue.length - index ELSE 0;
string ← Storage.String[length];
string.length ← length;
FOR i: CARDINAL IN [0 .. length) DO
string[i] ← varPtr.value.stringValue[index + i];
ENDLOOP;
bv ← BasicValue[type: string, varPart: string[stringValue: string]];
Push[bv];
RETURN[FALSE, newPc];
END; -- of Str1PushOp --


Str2PopOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
varPtr: VariablePtr;
bvString: BasicValue ← Pop[];
string: STRING ← bvString.stringValue;
bv2: BasicValue ← Pop[];
bv1: BasicValue ← Pop[];
index1: CARDINAL ← ConvertToCardinal[@bv1];
index2: CARDINAL ← ConvertToCardinal[@bv2];
target: STRING;
length, maxLength: CARDINAL;
index1 ← index1 - 1;
IF bvString.type # string THEN RunTimeError["Assignment of numeric to substring!"L];
[varPtr, newPc] ← FetchPointer[cm, pc];
IF varPtr.value.type # string THEN RunTimeError["Substring operation on numeric value!"L];
target ← varPtr.value.stringValue;
maxLength ← target.maxlength;
IF index1 ~IN [0 .. maxLength) OR index2 ~IN [0 .. maxLength] THEN
RunTimeError["Substring index out of bounds!"L];
length ← IF index2 > index1 THEN index2 - index1 ELSE 0;
FOR i: CARDINAL IN [target.length .. index1) DO
target[i] ← Ascii.SP;
ENDLOOP;
target.length ← MAX[target.length, index1 + length];
FOR i: CARDINAL IN [0 .. MIN[length, string.length]) DO
target[index1 + i] ← string[i];
ENDLOOP;
FOR i: CARDINAL IN [MIN[length, string.length] .. length) DO
target[index1 + i] ← Ascii.SP;
ENDLOOP;
Storage.FreeString[string];
RETURN[FALSE, newPc];
END; -- of Str2PopOp --


Str2PushOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
varPtr: VariablePtr;
string: STRING;
bv2: BasicValue ← Pop[];
bv1: BasicValue ← Pop[];
index1: CARDINAL ← ConvertToCardinal[@bv1];
index2: CARDINAL ← ConvertToCardinal[@bv2];
length, goodLength, maxLength: CARDINAL;
index1 ← index1 - 1;
[varPtr, newPc] ← FetchPointer[cm, pc];
IF varPtr.value.type # string THEN RunTimeError["Substring operation on numeric value!"L];
maxLength ← varPtr.value.stringValue.maxlength;
IF index1 ~IN [0 .. maxLength) OR index2 ~IN [0 .. maxLength] THEN
RunTimeError["Substring index out of bounds!"L];
length ← index2 - index1;
string ← Storage.String[length];
string.length ← length;
goodLength ← IF varPtr.value.stringValue.length <= index1 THEN 0
ELSE IF varPtr.value.stringValue.length <= index2
THEN varPtr.value.stringValue.length - index1 ELSE length;
FOR i: CARDINAL IN [0 .. goodLength) DO
string[i] ← varPtr.value.stringValue[index1 + i];
ENDLOOP;
FOR i: CARDINAL IN [goodLength .. length) DO
string[i] ← Ascii.SP;
ENDLOOP;
bv1 ← BasicValue[type: string, varPart: string[stringValue: string]];
Push[bv1];
RETURN[FALSE, newPc];
END; -- of Str2PushOp --


SubOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
RETURN[BasicOps.ArithmeticOp[sub], pc];
END; -- of SubOp --


TabOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
arg: CARDINAL;
bv: BasicValue;
bv ← Pop[];
arg ← ConvertToCardinal[@bv];
SELECT arg FROM
255 => IODefs.WriteLine[""L];
254 => IODefs.WriteString[" "L];
ENDCASE => THROUGH [1 .. arg] DO IODefs.WriteChar[Ascii.SP] ENDLOOP;
RETURN[FALSE, pc];
END; -- of TabOp --


UnaryMinusOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
bv: BasicValue ← Pop[];
SELECT bv.type FROM
real => bv.realValue ← -bv.realValue;
integer => bv.integerValue ← -bv.integerValue;
ENDCASE => RunTimeError["Unary minus of non-numeric value"L];
Push[bv];
RETURN[FALSE, pc];
END; -- of UnaryMinusOp --


UnNewLastConfig: PROCEDURE =
BEGIN
newLoadedConfigs: LoadedConfigRecPtr;
IF loadedConfigs = NIL THEN RETURN;
newLoadedConfigs ← loadedConfigs.next;
FrameDefs.UnNewConfig[loadedConfigs.cm.frame];
IF loadedConfigs.bcdFile ~= NIL THEN
{SegmentDefs.UnlockFile[loadedConfigs.bcdFile];
SegmentDefs.ReleaseFile[loadedConfigs.bcdFile]};
Storage.Free[loadedConfigs];
loadedConfigs ← newLoadedConfigs;
END; -- of UnNewLastConfig --


UsingOp: PUBLIC BasicOps.OpCodeProc =
BEGIN
[ , newPc] ← FetchPointer[cm, pc];
RETURN[FALSE, newPc];
END; -- of UsingOp --


WriteLongDecimal: PROCEDURE [n: Numeric] =
BEGIN
s: STRING ← [20];
String.AppendLongDecimal[s, n];
IODefs.WriteString[s];
END; -- of WriteLongDecimal --


END. -- of BasicInterpB --