-- BasicProgram.mesa -- edited by Brotz and Hilton, July 20, 1982 3:15 PM DIRECTORY Ascii, BasicImpDefs, FrameDefs, IODefs, Real, Storage, StreamDefs, String, vmD: FROM "VirtualMgrDefs"; BasicProgram: PROGRAM IMPORTS BasicImpDefs, FrameDefs, IODefs, Real, Storage, String, vmD EXPORTS BasicImpDefs = BEGIN OPEN BasicImpDefs; programLineDescHead: PUBLIC ProgramLineDescPtr _ NIL; cM: PUBLIC vmD.ComposedMessagePtr; codeCm: PUBLIC vmD.ComposedMessagePtr; lineCodeCm: PUBLIC vmD.ComposedMessagePtr; AllocateAndInsert: PUBLIC PROCEDURE [programLineNumber, textStartIndex: CARDINAL] = -- Inserts (or replaces) a program line descriptor at the appropriate place in -- the line descriptor chain according to programLineNumber. Calls -- InsertMessage to insert the program text in cM. BEGIN cur: ProgramLineDescPtr; prev: ProgramLineDescPtr _ NIL; new: ProgramLineDescPtr _ Storage.Node[SIZE[ProgramLineDesc]]; new^ _ [ , programLineNumber, 0, 0, 0, 0]; FOR cur _ programLineDescHead, cur.next DO IF cur = NIL OR cur.lineNumber >= new.lineNumber THEN BEGIN --insert the new line between prev and cur. IF prev = NIL THEN programLineDescHead _ new ELSE {prev.next _ new; new.start _ prev.end; new.codeStart _ prev.codeEnd}; IF cur = NIL OR cur.lineNumber > new.lineNumber THEN BEGIN -- insert a new line. -- new.next _ cur; InsertMessage[textStartIndex, new, NIL]; END ELSE BEGIN -- replace an existing line. new.next _ cur.next; vmD.DeleteRangeInMessage[[cur.start, cur.end, cM]]; vmD.DeleteRangeInMessage[[cur.codeStart, cur.codeEnd, codeCm]]; InsertMessage[textStartIndex, new, cur]; Storage.Free[cur]; IF new.start = new.end THEN BEGIN IF prev = NIL THEN programLineDescHead _ new.next ELSE prev.next _ new.next; Storage.Free[new]; END; END; EXIT; END; prev _ cur; ENDLOOP; END; -- of AllocateAndInsert -- FindLineNumber: PUBLIC PROCEDURE [lineNumber: CARDINAL] RETURNS[tempPc: ProgramLineDescPtr] = BEGIN tempPc _ programLineDescHead; UNTIL tempPc = NIL OR tempPc.lineNumber = lineNumber DO tempPc _ tempPc.next; ENDLOOP; IF tempPc = NIL THEN RunTimeError["Target line number does not exist."L]; RETURN[tempPc]; END; -- of FindLineNumber -- InsertMessage: PROCEDURE [textStartIndex: CARDINAL, new, old: ProgramLineDescPtr] = -- Inserts the characters from inputLine (global) starting at -- inputLine[textStartIndex] through the last character in inputLine into -- cM. Indices for succeeding lines are updated to account for the new -- characters added (and possibly deletedChars deleted.) BEGIN cur: ProgramLineDescPtr; textLength: CARDINAL _ inputLine.length - textStartIndex; codeLength: CARDINAL _ vmD.GetMessageSize[lineCodeCm]; deletedChars: CARDINAL _ IF old = NIL THEN 0 ELSE old.end - old.start; deletedCode: CARDINAL _ IF old = NIL THEN 0 ELSE old.codeEnd - old.codeStart; vmD.StartMessageInsertion[cM, new.start]; vmD.InsertSubstringInMessage[cM, inputLine, textStartIndex, textLength ! vmD.MessageOverflow => GO TO overflow]; vmD.StopMessageInsertion[cM]; IF textLength = 0 THEN codeLength _ 0 -- don't insert code for text line that will go away.-- ELSE vmD.InsertRangeInMessage[new.codeStart, codeCm, [0, codeLength, lineCodeCm]]; new.end _ new.start + textLength; new.codeEnd _ new.codeStart + codeLength; FOR cur _ new.next, cur.next UNTIL cur = NIL DO --correct succeeding start and end indices cur.start _ cur.start + textLength - deletedChars; cur.end _ cur.end + textLength - deletedChars; cur.codeStart _ cur.codeStart + codeLength - deletedCode; cur.codeEnd _ cur.codeEnd + codeLength - deletedCode; ENDLOOP; EXITS overflow => BEGIN vmD.StopMessageInsertion[cM]; ParseError["Message overflow: your program is too long. Life is hard."L]; END; END; -- of InsertMessage -- NextStatement: PUBLIC PROCEDURE = BEGIN savedIndex: CARDINAL; UNTIL endOfLine OR charTablePtr[token[0]] = statementSeparator DO b: BOOLEAN _ GetToken[]; ENDLOOP; IF token[0] = statementSeparatorChar THEN BEGIN savedIndex _ inputLineIndex; IF GetToken[] THEN ParseStatement[savedIndex] ELSE ParseError["Statement missing after colon."L]; END; END; -- of NextStatement -- OutputAutoLineNumber: PUBLIC PROCEDURE = BEGIN numberString: STRING _ [7]; keyBoard: StreamDefs.StreamHandle _ IODefs.GetInputStream[]; keyBoard.putback[keyBoard, Ascii.SP]; numberString.length _ 0; autoStart _ autoStart + autoIncrement; String.AppendDecimal[numberString, autoStart]; FOR i: CARDINAL DECREASING IN [0..numberString.length] UNTIL i = 0 DO keyBoard.putback[keyBoard, numberString[i - 1]]; ENDLOOP; autoStart _ String.StringToDecimal[numberString]; END; -- of OutputAutoLineNumber -- ParseError: PUBLIC PROCEDURE [s: STRING] = BEGIN IODefs.WriteLine["Parse error:"L]; IODefs.WriteLine[s]; ERROR ParseErrorSignal; END; -- of ParseError -- ParseErrorSignal: PUBLIC ERROR = CODE; ProgramCleanUp: PUBLIC PROCEDURE = BEGIN previousPtr: ProgramLineDescPtr; currentPtr: ProgramLineDescPtr _ programLineDescHead; UNTIL currentPtr = NIL DO previousPtr _ currentPtr; currentPtr _ currentPtr.next; Storage.Free[previousPtr]; ENDLOOP; vmD.FreeVirtualMessageObject[cM]; vmD.FreeVirtualMessageObject[codeCm]; vmD.FreeVirtualMessageObject[lineCodeCm]; THROUGH [1..2] DO FrameDefs.UnlockCode[Real.InitReals]; ENDLOOP; END; -- of ProgramCleanUp -- RunTimeError: PUBLIC PROCEDURE [s: STRING] = BEGIN IODefs.WriteString["Run time error in line "L]; IF currentProgLine # NIL THEN IODefs.WriteDecimal[currentProgLine.lineNumber]; IODefs.WriteLine["."L]; IODefs.WriteLine[s]; ClearStack[]; ERROR RunTimeErrorSignal; END; -- of RunTimeError -- RunTimeErrorSignal: PUBLIC ERROR = CODE; TokenIsLineNumber: PUBLIC PROCEDURE RETURNS[b: BOOLEAN, programLineNumber: CARDINAL] = -- Determines whether or not the first token of each string is a number. -- If so, it is a program line. BEGIN i : CARDINAL _ 0; IF token[i] IN ['0..'9] THEN RETURN [b : TRUE, programLineNumber : String.StringToDecimal[token]] ELSE RETURN [b : FALSE, programLineNumber : 0]; END; -- of TokenIsLineNumber -- -- Initialization cM _ vmD.AllocateComposedMessageObject[]; vmD.InitComposedMessage[cM, ""L]; codeCm _ vmD.AllocateComposedMessageObject[]; vmD.InitComposedMessage[codeCm, ""L]; lineCodeCm _ vmD.AllocateComposedMessageObject[]; vmD.InitComposedMessage[lineCodeCm, ""L]; END. -- of BasicProgram -- (635)\f1