-- BasicCommand.mesa
-- edited by Brotz and Hilton, September 23, 1982 5:07 PM

DIRECTORY
BasicDefs,
BasicImpDefs,
BasicOps,
IODefs,
Storage,
String;

BasicCommand: PROGRAM
IMPORTS BasicImpDefs, IODefs, Storage, String
EXPORTS BasicImpDefs =

BEGIN
OPEN BasicDefs, BasicImpDefs;

nCommands: CARDINAL = 43;
CommandRecord: TYPE = RECORD [name: STRING, command: PROCEDURE];
commandTable: ARRAY [0 .. nCommands) OF CommandRecord ←
[["!"L, RemCommand],
["AUTO"L, AutoCommand],
["CLEAR"L, ClearCommand],
["CONT"L, ContCommand],
["CODELIST"L, CodeListCommand],
["DATA"L, DataCommand],
["DEF"L, DefFnCommand],
["DEG"L, DegreeMode],
["DEL"L, DeleteCommand],
["DIM"L, DimCommand],
["DISP"L, PrintCommand],
["END"L, EndCommand],
["FNEND"L, FnEndCommand],
["FOR"L, ForCommand],
["GOSUB"L, GoSubCommand],
["GOTO"L, GoToCommand],
["HELP"L, HelpCommand],
["IF"L, IfCommand],
["IMAGE"L, ImageCommand],
["INPUT"L, InputCommand],
["LET"L, LetCommand],
["LIST"L, ListCommand],
["LOAD"L, LoadCommand],
["NEXT"L, NextCommand],
["NORMAL"L, NormalCommand],
["ON"L, OnCommand],
["OPTIONBASE"L, OptionBaseCommand],
["PAUSE"L, PauseCommand],
["PRINT"L, PrintCommand],
["QUIT"L, QuitCommand],
["RAD"L, RadianMode],
["READ"L, ReadCommand],
["REM"L, RemCommand],
["RENUMBER"L, RenumberCommand],
["RESTORE"L, RestoreCommand],
["RETURN"L, ReturnCommand],
["RUN"L, RunCommand],
["STEP"L, NulCommand],
["STOP"L, PauseCommand],
["TAB"L, TabCommand],
["TO"L, NulCommand],
["THEN"L, NulCommand],
["USING"L, NulCommand]];


AutoCommand: PROCEDURE =
BEGIN
IF isProgramLine THEN ParseError["AUTO command illegal in a program."L];
IF GetToken[] THEN
BEGIN
Expression[];
IF haveToken THEN
SELECT TRUE FROM
token[0] # ’, => ParseError["Missing comma in AUTO command."L];
GetToken[] => Expression[];
ENDCASE => ParseError["Missing increment in AUTO command."L]
ELSE BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 10];
END;
END
ELSE BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 10];
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 10];
END;
AppendByte[lineCodeCm, BasicOps.Auto];
END; -- of AutoCommand --


ClearCommand: PROCEDURE =
BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 255];
AppendByte[lineCodeCm, BasicOps.Tab];
NextStatement[];
END; -- of ClearCommand --


CodeListCommand: PROCEDURE =
BEGIN
GenericListCommand[BasicOps.CodeList];
END; -- of CodeListCommand --


CommandCleanUp: PUBLIC PROCEDURE =
BEGIN
goSubPrevPtr: GoSubStackPtr;
goSubCurPtr: GoSubStackPtr ← goSubHead;
nextPrevPtr: NextStackPtr;
nextcurPtr: NextStackPtr ← nextStackHead;
UNTIL nextcurPtr = NIL DO
nextPrevPtr ← nextcurPtr;
nextcurPtr ← nextcurPtr.next;
Storage.Free[nextPrevPtr];
ENDLOOP;
UNTIL goSubCurPtr = NIL DO
goSubPrevPtr ← goSubCurPtr;
goSubCurPtr ← goSubCurPtr.next;
Storage.Free[goSubPrevPtr];
ENDLOOP;
END; -- of CommandCleanUp --


ContCommand: PROCEDURE =
BEGIN
AppendByte[lineCodeCm, BasicOps.Cont];
END; -- of ContCommand --


DataCommand: PROCEDURE =
BEGIN
value: BasicValue;
AppendByte[lineCodeCm, BasicOps.Data];
DO
IF ~GetToken[] THEN ParseError["Missing value in DATA statement!"L];
value ← ParseConstant[];
AppendPointer[lineCodeCm, AllocateConstant[value]];
IF value.type = string THEN Storage.FreeString[value.stringValue];
IF ~haveToken THEN EXIT;
IF token[0] # ’, THEN ParseError["Missing comma in DATA statement!"L];
ENDLOOP;
AppendPointer[lineCodeCm, LOOPHOLE[0]];
END; -- of DataCommand --


DefFnCommand: PROCEDURE =
BEGIN
fnVarPtr, argVarPtr: VariablePtr ← NIL;
singleLine: BOOLEAN ← FALSE;
IF ~isProgramLine THEN ParseError["DEF FN command illegal outside of a program!"L];
IF ~GetToken[] THEN ParseError["Missing function name!"L];
fnVarPtr ← LookUpVariable[token];
WITH v: fnVarPtr SELECT FROM
userFunction => NULL;
ENDCASE => ParseError["Illegal function name!"L];
AppendByte[lineCodeCm, BasicOps.DefFn];
IF GetToken[] THEN
SELECT token[0] FROM
’= => singleLine ← TRUE;
’( =>
BEGIN
IF ~GetToken[] THEN ParseError["Missing formal parameter name!"L];
argVarPtr ← LookUpVariable[token];
WITH v: argVarPtr SELECT FROM
numeric, string => NULL;
ENDCASE => ParseError["Illegal formal paramter name!"L];
IF ~GetToken[] THEN ParseError["Missing )!"L];
IF GetToken[] THEN
BEGIN
IF token[0] = ’= THEN singleLine ← TRUE
ELSE ParseError["Missing = in function definition!"L];
END;
END;
ENDCASE => ParseError["Illegal character after function name!"L];
AppendByte[lineCodeCm, IF singleLine THEN 1 ELSE 2];
AppendPointer[lineCodeCm, fnVarPtr];
AppendPointer[lineCodeCm, IF argVarPtr = NIL THEN LOOPHOLE[0] ELSE argVarPtr];
IF singleLine THEN
BEGIN
IF GetToken[] THEN
BEGIN
Expression[];
AppendByte[lineCodeCm, BasicOps.PopVal];
AppendPointer[lineCodeCm, fnVarPtr];
AppendByte[lineCodeCm, BasicOps.FnEnd];
END
ELSE ParseError["Missing expression in function definition!"L];
END;
END; -- of DefFnCommand --


DegreeMode: PROCEDURE =
BEGIN
trigMode ← degrees;
END; -- of DegreeMode --


DeleteCommand: PROCEDURE =
BEGIN
IF isProgramLine THEN ParseError["DELETE command illegal in a program."L];
IF GetToken[] THEN
BEGIN
Expression[];
IF haveToken THEN
SELECT TRUE FROM
token[0] # ’, => ParseError["Missing comma in DELETE command."L];
GetToken[] => Expression[];
ENDCASE => ParseError["Missing end line number in DELETE command."L]
ELSE BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 0];
END;
AppendByte[lineCodeCm, BasicOps.Delete];
END
ELSE ParseError["DELETE command requires a line number."L];
END; -- of DeleteCommand --


DimCommand: PROCEDURE =
BEGIN
varPtr: VariablePtr;
DO
IF GetToken[] THEN
BEGIN
varPtr ← LookUpVariable[token];
WITH v: varPtr SELECT FROM
string =>
BEGIN
IF ~GetToken[] OR ~String.EquivalentString[token, "["L] THEN
ParseError["Missing [."L];
IF GetToken[] THEN Expression[] ELSE ParseError["Missing string dimension!"L];
IF ~haveToken OR token[0] # ’] THEN ParseError["Missing ]."L];
AppendByte[lineCodeCm, BasicOps.DimStr];
END;
numeric =>
BEGIN
IF ~GetToken[] OR ~String.EquivalentString[token, "("L] THEN
ParseError["Missing (."L];
IF GetToken[] THEN Expression[] ELSE ParseError["Missing array dimension!"L];
SELECT TRUE FROM
~haveToken => ParseError["Missing comma or )."L];
token[0] = ’, =>
IF GetToken[] THEN Expression[] ELSE ParseError["Missing array dimension!"L];
ENDCASE =>
{AppendByte[lineCodeCm, BasicOps.PushI]; AppendByte[lineCodeCm, 0]};
IF ~haveToken OR token[0] # ’) THEN ParseError["Missing )."L];
AppendByte[lineCodeCm, BasicOps.Dim];
END;
ENDCASE => ParseError["Improper variable in DIM statement!"L];
AppendPointer[lineCodeCm, varPtr];
IF ~GetToken[] THEN EXIT;
IF token[0] # ’, THEN ParseError["Missing comma between itmes in DIM statement."L];
END
ELSE ParseError["Missing variable in DIM statement!"L];
ENDLOOP;
END; -- of DimCommand --


EndCommand: PROCEDURE =
BEGIN
AppendByte[lineCodeCm, BasicOps.End];
END; -- of EndCommand --


FnEndCommand: PROCEDURE =
BEGIN
AppendByte[lineCodeCm, BasicOps.FnEnd];
END; -- of FnEndCommand --


ForCommand: PROCEDURE =
BEGIN
varPtr: VariablePtr;
savedLength: CARDINAL ← inputLine.length;
index: CARDINAL;
IF ~isProgramLine THEN ParseError["FOR command illegal outside of a program"L];
CheckForVariable[];
varPtr ← LookUpVariable[token];
CheckForEqualSign[];
index ← FindInfixReservedWord["TO"L];
IF index = 0 THEN ParseError["Missing TO in FOR statement!"L];
inputLine.length ← index;
IF GetToken[] THEN Expression[]
ELSE ParseError["Missing initial value in FOR statement."L];
IF haveToken THEN ParseError["Extra token before TO in FOR statement!"L];
inputLine.length ← savedLength;
IF GetToken[] AND String.EquivalentString[token, "TO"L] THEN
BEGIN
index ← FindInfixReservedWord["STEP"L];
IF index # 0 THEN inputLine.length ← index;
IF GetToken[] THEN Expression[]
ELSE ParseError["Missing final value in FOR statement."L];
IF haveToken THEN ParseError["Extra token before STEP in FOR statement!"L];
inputLine.length ← savedLength;
IF GetToken[] AND String.EquivalentString[token, "STEP"L] THEN
BEGIN
IF GetToken[] THEN Expression[]
ELSE ParseError["Missing step value in FOR statement."L];
END
ELSE {AppendByte[lineCodeCm, BasicOps.PushI]; AppendByte[lineCodeCm, 1]};
END
ELSE ParseError["Missing TO in FOR statement."L];
AppendByte[lineCodeCm, BasicOps.For];
AppendPointer[lineCodeCm, varPtr];
END; -- of ForCommand --


GenericListCommand: PROCEDURE [opCode: BasicOps.Byte] =
BEGIN
IF isProgramLine THEN ParseError["LIST command illegal in a program."L];
IF GetToken[] THEN
BEGIN
Expression[];
IF haveToken THEN
SELECT TRUE FROM
token[0] # ’, => ParseError["Missing comma in LIST command."L];
GetToken[] => Expression[];
ENDCASE => ParseError["Missing end line number in LIST command."L]
ELSE BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 0];
END;
END
ELSE BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 0];
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 0];
END;
AppendByte[lineCodeCm, opCode];
END; -- of GenericListCommand --


GoSubCommand: PROCEDURE =
BEGIN
IF ~isProgramLine THEN ParseError["GOSUB command illegal outside of a program"L];
AppendByte[lineCodeCm, BasicOps.GoSub];
ParseLineNumber[];
END; -- of GoSubCommand --


GoToCommand: PROCEDURE =
BEGIN
IF ~isProgramLine THEN ParseError["GO TO command illegal outside of a program"L];
AppendByte[lineCodeCm, BasicOps.GoTo];
ParseLineNumber[];
END; -- of GoToCommand --


ParseLineNumber: PROCEDURE =
BEGIN
lineNumber: INTEGER;
IF GetToken[] THEN
BEGIN
lineNumber ← String.StringToDecimal[token ! String.InvalidNumber => GO TO bad];
IF lineNumber ~IN [0 .. 9999] THEN GO TO bad;
AppendPointer[lineCodeCm, LOOPHOLE[lineNumber]];
END
ELSE ParseError["Missing statement number!"L];
EXITS
bad => ParseError["Illegal statement number!"L];
END; -- of ParseLineNumber --


HelpCommand: PROCEDURE =
BEGIN
IF isProgramLine THEN ParseError["Help command illegal in a program."L];
AppendByte[lineCodeCm, BasicOps.Help];
END; -- of HelpCommand --


IfCommand: PROCEDURE =
BEGIN
savedLength: CARDINAL ← inputLine.length;
index: CARDINAL;
IF ~isProgramLine THEN ParseError["IF command illegal outside of a program"L];
index ← FindInfixReservedWord["THEN"L];
IF index = 0 THEN index ← FindInfixReservedWord["GOSUB"L];
IF index = 0 THEN index ← FindInfixReservedWord["GOTO"L];
IF index = 0 THEN index ← FindInfixReservedWord["LET"L];
IF index = 0 THEN ParseError["Missing THEN, GOTO, GOSUB, or LET in IF statement!"L];
inputLine.length ← index;
IF GetToken[] THEN Expression[]
ELSE ParseError["Missing relation in IF command!"L];
IF haveToken THEN
ParseError["Extra token before THEN, GOTO, GOSUB, or LET in IF statement!"L];
inputLine.length ← savedLength;
IF ~GetToken[] THEN ParseError["Missing second part of IF command!"L];
AppendByte[lineCodeCm, BasicOps.IfZeroDone];
SELECT TRUE FROM
String.EquivalentString[token, "GOSUB"L] => GoSubCommand[];
String.EquivalentString[token, "THEN"L],
String.EquivalentString[token, "GOTO"L] => GoToCommand[];
String.EquivalentString[token, "LET"L] => LetCommand[];
ENDCASE => ParseError["Unrecognized second part of IF comand!"L];
END; -- of IfCommand --


ImageCommand: PROCEDURE =
BEGIN
AppendByte[lineCodeCm, BasicOps.Image];
END; -- of ImageCommand --


InputCommand: PROCEDURE =
BEGIN
varPtr: VariablePtr;
firstTime: BOOLEAN ← TRUE;
savedIndex, nIndices: CARDINAL;
DO
CheckForVariable[];
varPtr ← LookUpVariable[token];
AppendByte
[lineCodeCm, IF varPtr.type = string THEN BasicOps.InputStr ELSE BasicOps.InputNum];
AppendByte[lineCodeCm, IF firstTime THEN 0 ELSE 1];
nIndices ← 0;
WITH v: varPtr SELECT FROM
builtInFunction => ParseError["Unrecognized keyword!"L];
numeric =>
BEGIN
savedIndex ← inputLineIndex;
IF GetToken[] AND token[0] = ’( THEN nIndices ← ParseSubscripts[]
ELSE inputLineIndex ← savedIndex;
END;
string =>
BEGIN
savedIndex ← inputLineIndex;
IF GetToken[] AND token[0] = ’[ THEN nIndices ← ParseSubscripts[]
ELSE inputLineIndex ← savedIndex;
END;
ENDCASE;
SELECT nIndices FROM
0 => AppendByte[lineCodeCm, BasicOps.PopVal];
1 => AppendByte[lineCodeCm, WITH varPtr SELECT FROM
string => BasicOps.Str1Pop, ENDCASE => BasicOps.Arr1Pop];
2 => AppendByte[lineCodeCm, WITH varPtr SELECT FROM
string => BasicOps.Str2Pop, ENDCASE => BasicOps.Arr2Pop];
ENDCASE => ParseError["Can’t happen."L];
AppendPointer[lineCodeCm, varPtr];
IF ~GetToken[] THEN EXIT;
IF token[0] # ’, THEN ParseError["Missing comma in READ statement!"L];
ENDLOOP;
END; -- of InputCommand --


IsReservedWord: PUBLIC PROCEDURE [s: STRING] RETURNS [BOOLEAN] =
BEGIN
FOR i: CARDINAL IN [0 .. nCommands) DO
IF String.EquivalentString[s, commandTable[i].name] THEN
RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
END; -- of IsReservedWord --


ParseStatement: PUBLIC PROCEDURE [savedIndex: CARDINAL] =
BEGIN
FOR i: CARDINAL IN [0 .. nCommands) DO
IF String.EquivalentString[token, commandTable[i].name] THEN
{commandTable[i].command[]; RETURN};
ENDLOOP;
-- reset scanner so GetToken gets left side of bare LET statement.
inputLineIndex ← savedIndex;
LetCommand[];
END; -- of ParseStatement --


LetCommand: PROCEDURE =
BEGIN
varPtr: VariablePtr;
savedIndex, nIndices: CARDINAL ← 0;
CheckForVariable[];
varPtr ← LookUpVariable[token];
WITH v: varPtr SELECT FROM
builtInFunction => ParseError["Unrecognized keyword!"L];
numeric =>
BEGIN
savedIndex ← inputLineIndex;
IF GetToken[] AND token[0] = ’( THEN nIndices ← ParseSubscripts[]
ELSE inputLineIndex ← savedIndex;
END;
string =>
BEGIN
savedIndex ← inputLineIndex;
IF GetToken[] AND token[0] = ’[ THEN nIndices ← ParseSubscripts[]
ELSE inputLineIndex ← savedIndex;
END;
ENDCASE;
CheckForEqualSign[];
IF GetToken[] THEN
BEGIN
Expression[];
IF ~haveToken THEN
BEGIN
SELECT nIndices FROM
0 => AppendByte[lineCodeCm, BasicOps.PopVal];
1 => AppendByte[lineCodeCm, WITH varPtr SELECT FROM
string => BasicOps.Str1Pop, ENDCASE => BasicOps.Arr1Pop];
2 => AppendByte[lineCodeCm, WITH varPtr SELECT FROM
string => BasicOps.Str2Pop, ENDCASE => BasicOps.Arr2Pop];
ENDCASE => ParseError["Can’t happen."L];
AppendPointer[lineCodeCm, varPtr];
END
ELSE ParseError["Illegal expression within LET statemtent."L];
END
ELSE ParseError["Missing assignment value within the LET statement."L]; NextStatement[];
END; -- of LetCommand --


ListCommand: PROCEDURE =
-- Lists the program in numerical order
BEGIN
GenericListCommand[BasicOps.List];
END; -- of ListCommand --


LoadCommand: PROCEDURE =
BEGIN
bv: BasicValue;
constPtr: VariablePtr;
IF ~GetToken[] THEN
ParseError["Missing module name in LOAD command."L];
bv ← BasicValue[type: string, varPart: string[stringValue: token]];
constPtr ← AllocateConstant[bv];
AppendByte[lineCodeCm, BasicOps.PushVal];
AppendPointer[lineCodeCm, constPtr];
AppendByte[lineCodeCm, BasicOps.Load];
END; -- of LoadCommand --


NextCommand: PROCEDURE =
BEGIN
IF ~isProgramLine THEN ParseError["NEXT command illegal outside of a program"L];
CheckForVariable[];
AppendByte[lineCodeCm, BasicOps.Next];
AppendPointer[lineCodeCm, LookUpVariable[token]];
END; -- of NextCommand --


NormalCommand: PROCEDURE =
BEGIN
AppendByte[lineCodeCm, BasicOps.Normal];
END; -- of NormalCommand --


NulCommand: PROCEDURE =
BEGIN
-- This procedure is used as a procedure place holder within the
-- command table. This enables reserved words to be put into the
-- command table without actually having to execute code.
END; -- of NulCommand --


OnCommand: PROCEDURE =
BEGIN
savedLength: CARDINAL ← inputLine.length;
index: CARDINAL;
IF ~isProgramLine THEN
ParseError["ON GOTO/GOSUB command illegal outside of a program"L];
index ← FindInfixReservedWord["GOTO"L];
IF index = 0 THEN index ← FindInfixReservedWord["GOSUB"L];
IF index = 0 THEN ParseError["Missing GOTO or GOSUB in ON statement!"L];
inputLine.length ← index;
IF GetToken[] THEN Expression[]
ELSE ParseError["Missing expression in ON command!"L];
IF haveToken THEN ParseError["Extra token before GOTO or GOSUB in ON statement!"L];
inputLine.length ← savedLength;
IF GetToken[] THEN
SELECT TRUE FROM
String.EquivalentString[token, "GOTO"L] => AppendByte[lineCodeCm, BasicOps.OnGoTo];
String.EquivalentString[token, "GOSUB"L] =>
AppendByte[lineCodeCm, BasicOps.OnGoSub];
ENDCASE => ParseError["Unrecognized word in ON command!"L]
ELSE ParseError["Missing GOTO or GOSUB in ON command!"L];
DO
ParseLineNumber[];
IF ~GetToken[] THEN EXIT;
IF token[0] # ’, THEN ParseError["Missing comma in ON command!"L];
ENDLOOP;
AppendPointer[lineCodeCm, LOOPHOLE[0]];
END; -- of OnCommand --


OptionBaseCommand: PROCEDURE =
BEGIN
-- newOptionBase: CARDINAL;
-- IF GetToken[] AND token[0] = ’0 OR token [0] = ’1 THEN
-- BEGIN
-- newOptionBase ← String.StringToDecimal[token];
-- IF ~optionBaseCalled THEN
-- {optionBaseCalled ← TRUE;
-- optionBase ← newOptionBase;}
-- ELSE IF optionBaseCalled AND optionBase # newOptionBase THEN
-- IODefs.WriteLine["OPTION BASE has already been set."L];
-- END
-- ELSE IF ~haveToken THEN ErrorCode["Missing OPTION BASE number."L]
-- ELSE ErrorCode["OPTION BASE must be 0 or 1."L];
END; -- of OptionBaseCommand --


PauseCommand: PROCEDURE =
BEGIN
IF ~isProgramLine THEN ParseError["STOP command illegal outside of a program"L];
AppendByte[lineCodeCm, BasicOps.Stop];
END; -- of StopCommand --


PrintCommand: PROCEDURE =
BEGIN
realString: STRING ← [40];
quoteString: STRING ← [60];
printBlankLine: BOOLEAN ← TRUE;
DO
IF GetToken[] THEN
BEGIN
printBlankLine ← FALSE;
SELECT TRUE FROM
String.EquivalentString[token, "USING"L] => UsingCommand[];
String.EquivalentString[token, "TAB"L] => TabCommand[];
charTablePtr[token[0]] = statementSeparator => EXIT;
ENDCASE => {Expression[]; AppendByte[lineCodeCm, BasicOps.Print]};
SELECT TRUE FROM
inputLineIndex = inputLine.length OR ~haveToken =>
BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 255];
AppendByte[lineCodeCm, BasicOps.Tab];
EXIT;
END;
token[0] = ’, =>
BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 254];
AppendByte[lineCodeCm, BasicOps.Tab];
END;
token[0] = ’; => NULL;
ENDCASE => ParseError["Illegal PRINT command."L];
END
ELSE
IF printBlankLine THEN
BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 255];
AppendByte[lineCodeCm, BasicOps.Tab];
EXIT;
END
ELSE
IF inputLineIndex = inputLine.length OR token[0] = statementSeparatorChar THEN EXIT;
ENDLOOP;
NextStatement[];
END; -- of PrintCommand --



QuitCommand: PROCEDURE =
BEGIN
AppendByte[lineCodeCm, BasicOps.Quit];
END; -- of QuitCommand --


QuitSignal: PUBLIC SIGNAL = CODE;


RadianMode: PROCEDURE =
BEGIN
trigMode ← radians;
END; -- of RadianMode --


ReadCommand: PROCEDURE =
BEGIN
varPtr: VariablePtr;
savedIndex, nIndices: CARDINAL;
DO
CheckForVariable[];
varPtr ← LookUpVariable[token];
AppendByte[lineCodeCm, BasicOps.Read];
nIndices ← 0;
WITH v: varPtr SELECT FROM
builtInFunction => ParseError["Unrecognized keyword!"L];
numeric =>
BEGIN
savedIndex ← inputLineIndex;
IF GetToken[] AND token[0] = ’( THEN nIndices ← ParseSubscripts[]
ELSE inputLineIndex ← savedIndex;
END;
string =>
BEGIN
savedIndex ← inputLineIndex;
IF GetToken[] AND token[0] = ’[ THEN nIndices ← ParseSubscripts[]
ELSE inputLineIndex ← savedIndex;
END;
ENDCASE;
SELECT nIndices FROM
0 => AppendByte[lineCodeCm, BasicOps.PopVal];
1 => AppendByte[lineCodeCm, WITH varPtr SELECT FROM
string => BasicOps.Str1Pop, ENDCASE => BasicOps.Arr1Pop];
2 => AppendByte[lineCodeCm, WITH varPtr SELECT FROM
string => BasicOps.Str2Pop, ENDCASE => BasicOps.Arr2Pop];
ENDCASE => ParseError["Can’t happen."L];
AppendPointer[lineCodeCm, varPtr];
IF ~GetToken[] THEN EXIT;
IF token[0] # ’, THEN ParseError["Missing comma in READ statement!"L];
ENDLOOP;
END; -- of ReadCommand --


RemCommand: PROCEDURE =
BEGIN
END; -- of RemCommand --


RenumberCommand: PROCEDURE =
-- This procedure has not been updated --
BEGIN
textStartIndex: CARDINAL ← inputLineIndex;
i: CARDINAL;
previousPtr: ProgramLineDescPtr ← NIL;
currentPtr: ProgramLineDescPtr ← programLineDescHead;
numberCount: CARDINAL ← 0;
firstNumber, bumpNumber: CARDINAL ← 10;
startNumber, endNumber, thisNumber: CARDINAL;
numberString: STRING ← [10];

FOR i ← textStartIndex, i + 1
UNTIL i = inputLine.length OR inputLine[i] IN [’0..’9] DO ENDLOOP;
UNTIL i = inputLine.length DO
UNTIL i = inputLine.length OR inputLine[i] ~IN [’0..’9] DO
String.AppendChar[numberString, inputLine[i]];
i ← i + 1;
ENDLOOP;
thisNumber ← String.StringToDecimal[numberString];
numberCount ← numberCount + 1;
SELECT numberCount FROM
1 => firstNumber ← thisNumber;
2 => bumpNumber ← thisNumber;
3 => startNumber ← thisNumber;
4 => endNumber ← thisNumber;
ENDCASE =>BEGIN
IODefs.WriteLine["Your RENUMBER command contains too many numbers!"];
RETURN;
END;
FOR i ← i, i + 1
UNTIL i = inputLine.length OR inputLine[i] IN [’0..’9] DO ENDLOOP;
ENDLOOP;

IF numberCount = 3 OR numberCount = 4 THEN
UNTIL currentPtr = NIL OR currentPtr.lineNumber = startNumber DO
previousPtr ← currentPtr;
currentPtr ← currentPtr.next;
ENDLOOP;
IF currentPtr = NIL THEN
BEGIN
IODefs.WriteString["Your program does not contain line number "];
IODefs.WriteDecimal[startNumber];
IODefs.WriteLine[""];
RETURN;
END
ELSE --Renumber currentPtr.lineNumbers
BEGIN
currentPtr.lineNumber ← firstNumber;
previousPtr ← currentPtr;
currentPtr ← currentPtr.next;
UNTIL currentPtr = NIL OR currentPtr.lineNumber = endNumber DO
currentPtr.lineNumber ← previousPtr.lineNumber + bumpNumber;
previousPtr ← currentPtr;
currentPtr ← currentPtr.next;
ENDLOOP;
END;
NextStatement[];
END; -- of RenumberCommand --


RestoreCommand: PROCEDURE =
BEGIN
AppendByte[lineCodeCm, BasicOps.Restore];
END; -- of RestoreCommand --


ReturnCommand: PROCEDURE =
BEGIN
AppendByte[lineCodeCm, BasicOps.Return];
END; -- ReturnCommand --


RunCommand: PROCEDURE =
BEGIN
IF GetToken[] THEN Expression[]
ELSE BEGIN
AppendByte[lineCodeCm, BasicOps.PushI];
AppendByte[lineCodeCm, 0];
END;
AppendByte[lineCodeCm, BasicOps.Run];
END; -- of RunCommand --


TabCommand: PROCEDURE =
BEGIN
IF GetToken[] AND token[0] = ’( THEN
BEGIN
Expression[];
-- token should now be a comma or semicolon --
IF token[0] # ’, AND token[0] # ’; THEN
BEGIN
inputLineIndex ← inputLine.length;
ParseError["TAB statement missing a comma (,) or a semicolon (;)"L];
END;
AppendByte[lineCodeCm, BasicOps.Tab];
END
ELSE ParseError["TAB statement missing left parenthesis."L];
END; -- of TabCommand --


UsingCommand: PROCEDURE =
BEGIN
IF ~GetToken[] THEN ParseError["Missing USING line number!"L];
IF token[0] = ’" THEN Storage.FreeString[ScanQuotedString[]];
[] ← GetToken[];
END; -- of UsingCommand --


END. -- of BasicCommand --