DIRECTORY Atom USING [MakeAtom], IO USING [PutChar, PutRope, STREAM], IPBasic USING [Any, ComposedOp, Identifier, Index, Integer, Marker, nullIndex, nullMarker, Number, Operator, OperatorRep, PrimitiveOp, SaveType, Vec, Vector, VectorShape], IPControl USING [], IPConvert USING [IntToNumber], IPEncoding USING [GetInt, GetToken, GetReal, GetRope, GetStartingIndex, OpenReader, Reader, Token], IPErrors USING [AppearanceError, AppearanceErrorType, AppearanceWarning, AppearanceWarningType, Bug, Error, MasterError, MasterErrorType, MasterWarning, MasterWarningType, RopeFromError], IPExec USING [], IPImagerOps USING [Init, Restore, Save], IPLimits USING [topFrameSize], IPPrimitive USING [Apply], IPStack USING [Count, Init, PopInteger, PopMark, PopToMark, PushIdentifier, PushInteger, PushNumber, PushReal, PushVector], IPState USING [Context, ContextRep, nullContextRep, Skeleton, SkeletonRep, State, StateRep], IPVector USING [CopyVec, NewVec, VectorToVec], IPWritten USING [RopeFromOp], Rope USING [ROPE, Translate]; IPExecImpl: CEDAR PROGRAM IMPORTS Atom, IO, IPConvert, IPEncoding, IPErrors, IPImagerOps, IPPrimitive, IPStack, IPVector, IPWritten, Rope EXPORTS IPExec, IPControl, IPBasic = BEGIN OPEN IPEncoding, IPState, IPBasic; ROPE: TYPE = Rope.ROPE; State: TYPE = IPState.State; StateRep: PUBLIC TYPE = IPState.StateRep; -- export to IPBasic Master: TYPE = IPEncoding.Reader; MarkRecovery: ERROR = CODE; Frame: PROC[self: State] RETURNS[Vec] = { f: Vec = self.context.frame; RETURN[IF f#NIL THEN IPVector.CopyVec[f] ELSE self.context.initialFrame] }; ReadonlyFrame: PROC[context: Context] RETURNS[Vec] = INLINE { RETURN[ IF context.frame#NIL THEN context.frame ELSE context.initialFrame] }; MutableFrame: PROC[context: Context] RETURNS[Vec] = INLINE { RETURN[ IF context.frame#NIL THEN context.frame ELSE context.frame _ IPVector.CopyVec[context.initialFrame]] }; FGet: PUBLIC PROC[self: State, n: Integer] RETURNS[Any] = { frame: Vec = ReadonlyFrame[self.context]; shape: VectorShape = frame.shape; IF n IN[shape.l..shape.l+shape.n) THEN RETURN[frame[n-shape.l]] ELSE ERROR IPErrors.MasterError[BoundsFault]; }; FSet: PUBLIC PROC[self: State, x: Any, n: Integer] = { frame: Vec = MutableFrame[self.context]; shape: VectorShape = frame.shape; IF n IN[shape.l..shape.l+shape.n) THEN frame[n-shape.l] _ x ELSE ERROR IPErrors.MasterError[BoundsFault]; }; MakeCO: PUBLIC PROC[self: State, f: Vector] RETURNS[Operator] = { frame: Vec = IPVector.VectorToVec[f]; index: Index = SkipBody[self]; RETURN[NEW[OperatorRep[composed] _ [composed[start: index, initialFrame: frame]]]]; }; MakeSimpleCO: PUBLIC PROC[self: State] RETURNS[Operator] = { frame: Vec = Frame[self]; -- copy the current frame index: Index = SkipBody[self]; RETURN[NEW[OperatorRep[composed] _ [composed[start: index, initialFrame: frame]]]]; }; Do: PUBLIC PROC[self: State, o: Operator, sv: SaveType _ nil] = { WITH o SELECT FROM op: ComposedOp => { caller: Context = self.context; savedPC: Index = self.pc; self.pc _ op.start; -- set the pc to the beginning of the operator's body [] _ CallBody[self, op.initialFrame, sv ! MarkRecovery => self.pc _ savedPC]; self.pc _ savedPC; -- restore caller's pc IF self.context#caller THEN ERROR IPErrors.Bug; }; ENDCASE => ERROR IPErrors.MasterError[Unimplemented]; }; DoBody: PUBLIC PROC[self: State, f: Vector, sv: SaveType _ nil] = { frame: Vec = IPVector.VectorToVec[f]; [] _ CallBody[self, frame, sv]; }; DoSimpleBody: PUBLIC PROC[self: State, sv: SaveType _ nil] = { frame: Vec = Frame[self]; [] _ CallBody[self, frame, sv]; }; If: PUBLIC PROC[self: State, b: BOOL] = { IF b THEN DoSimpleBody[self] ELSE [] _ SkipBody[self]; }; IfCopy: PUBLIC PROC[self: State, testCopy: Operator] = { ERROR IPErrors.MasterError[Unimplemented]; }; CopyNumberAndName: PUBLIC PROC[self: State] RETURNS[copyNumber: Number, copyName: Identifier] = { ERROR; }; NewMark: PROC[self: State] RETURNS[Marker] = { last: Marker = self.lastMark; IF last [] _ PopContext[self]; IF sv#nil THEN IPImagerOps.Save[self, sv=saveAll]; DO token: Token = master.GetToken[self.pc]; -- fetch the next token self.pc _ token.next; IF token.op=endBody THEN EXIT ELSE { DoToken[self, token ! IPErrors.MasterError => { LogError[self, [Me[type]], token]; self.pc _ token.index; GOTO Recover }; IPErrors.MasterWarning => { LogError[self, [Mw[type]], token]; RESUME }; IPErrors.AppearanceError => { LogError[self, [Ae[type]], token]; RESUME }; IPErrors.AppearanceWarning => { LogError[self, [Aw[type]], token]; RESUME }; MarkRecovery => GOTO Recover; ]; EXITS Recover => { marker: Marker = PopToMarkOnCallStack[self]; IF marker=self.context.mark THEN { IF SkipToUnmark0OrEndOfBody[self] THEN { -- press on -- } ELSE GOTO Exit; -- marked by this context, but unmark0 not found } ELSE { SkipToEndOfBody[self]; GOTO Exit }; -- not marked by this context }; }; REPEAT Exit => error _ TRUE; ENDLOOP; IF sv#nil THEN IPImagerOps.Restore[self]; }; finalFrame _ PopContext[self]; IF error THEN ERROR MarkRecovery; }; DoToken: PROC[self: State, token: Token] = { SELECT token.type FROM op => IPPrimitive.Apply[self, token.op]; number => IPStack.PushNumber[self, IPConvert.IntToNumber[token.number]]; int => IPStack.PushNumber[self, IPConvert.IntToNumber[self.master.GetInt[token]]]; rational, real => IPStack.PushReal[self, self.master.GetReal[token]]; identifier => IPStack.PushIdentifier[self, MakeID[self.master.GetRope[token]]]; string, largeVec => IPStack.PushVector[self, self.master.GetRope[token]]; comment => { }; ENDCASE => ERROR IPErrors.Bug; -- unexpected token type }; MakeID: PUBLIC PROC[rope: ROPE] RETURNS[Identifier] = { LowerCase: PROC[c: CHAR] RETURNS[CHAR] = { RETURN[IF c IN['A..'Z] THEN (c-'A)+'a ELSE c] }; RETURN[Atom.MakeAtom[Rope.Translate[base: rope, translator: LowerCase]]]; }; SetErrorLog: PUBLIC PROC[self: State, log: IO.STREAM] = { self.log _ log; }; LogError: PROC[self: State, error: IPErrors.Error, token: Token] = { log: IO.STREAM = self.log; rope: Rope.ROPE = IPErrors.RopeFromError[error]; IF log#NIL THEN { log.PutRope[rope]; IF token.op#nil THEN { log.PutRope[" -- "]; log.PutRope[IPWritten.RopeFromOp[token.op]]; }; log.PutChar['\n]; }; }; BeginBody: PROC[self: State] RETURNS[Index] = { token: Token = Fetch[self]; IF token.op=beginBody THEN RETURN[token.index] ELSE { self.pc _ token.index; ERROR IPErrors.MasterError[MissingBody] }; }; SkipBody: PROC[self: State] RETURNS[Index] = { index: Index = BeginBody[self]; SkipToEndOfBody[self]; RETURN[index]; }; SkipToEndOfBody: PROC[self: State] = { DO token: Token = Fetch[self]; SELECT token.op FROM beginBody => SkipToEndOfBody[self]; endBody => EXIT; ENDCASE; ENDLOOP; }; SkipToUnmark0OrEndOfBody: PROC[self: State] RETURNS[BOOL] = { DO token: Token = Fetch[self]; SELECT token.op FROM unmark0 => { self.pc _ token.index; RETURN[TRUE] }; beginBody => SkipToEndOfBody[self]; endBody => EXIT; ENDCASE; ENDLOOP; RETURN[FALSE]; }; initialTopFrame: Vec = IPVector.NewVec[[l: 0, n: IPLimits.topFrameSize]]; OpenMaster: PUBLIC PROC[name: ROPE] RETURNS[State] = { master: Master = OpenReader[name]; self: State = NEW[StateRep _ [master: NIL, skeleton: NIL, pc: 0, stack: NIL, topFrame: NIL, context: NIL, lastMark: nullMarker, imager: NIL]]; self.master _ master; self.pc _ master.GetStartingIndex[]; IPStack.Init[self, 1000]; IPImagerOps.Init[self]; self.skeleton _ GetSkeleton[self]; IF self.skeleton.size<2 THEN ERROR IPErrors.MasterError[MalformedSkeleton]; self.topFrame _ DoPreamble[self, initialTopFrame]; RETURN[self]; }; PageCount: PUBLIC PROC[self: State] RETURNS[NAT] = { RETURN[self.skeleton.size-1]; }; DoPreamble: PROC[self: State, frame: Vec] RETURNS[Vec] = { self.pc _ self.skeleton[0].body; -- beginning of the preamble RETURN[CallBody[self, frame, saveAll]]; }; DoPage: PUBLIC PROC[self: State, n: NAT] = { self.pc _ self.skeleton[n].body; -- beginning of the page body [] _ CallBody[self, self.topFrame, saveAll]; }; GetSkeleton: PROC[self: State] RETURNS[Skeleton] = { token: Token = Fetch[self]; SELECT token.op FROM beginBody => { IPStack.PushInteger[self, token.index]; -- instructions body SkipToEndOfBody[self]; IF Fetch[self].op=beginBlock THEN GetBlock[self] ELSE ERROR IPErrors.MasterError[MalformedSkeleton]; }; beginBlock => { IPStack.PushInteger[self, nullIndex]; -- no instructions GetBlock[self]; }; ENDCASE => ERROR IPErrors.MasterError[MalformedSkeleton]; { count: NAT = IPStack.Count[self]; size: NAT = count/2; skeleton: Skeleton = NEW[SkeletonRep[size]]; FOR i: NAT DECREASING IN[0..size) DO body: Index = IPStack.PopInteger[self]; instructions: Index = IPStack.PopInteger[self]; skeleton[i] _ [instructions: instructions, body: body]; ENDLOOP; RETURN[skeleton]; }; }; GetBlock: PROC[self: State] = { IPStack.PushInteger[self, SkipBody[self]]; -- preamble DO token: Token = Fetch[self]; SELECT token.op FROM endBlock => EXIT; pageInstructions => { IPStack.PushInteger[self, SkipBody[self]]; -- page instructions body IPStack.PushInteger[self, SkipBody[self]]; -- page body }; beginBody => { IPStack.PushInteger[self, nullIndex]; -- no page instructions IPStack.PushInteger[self, token.index]; -- page body SkipToEndOfBody[self]; }; ENDCASE => ERROR IPErrors.MasterError[MalformedSkeleton]; ENDLOOP; }; END. DIPExecImpl.mesa Last edited by: Doug Wyatt, July 7, 1983 3:36 pm Here is an excerpt from the Interpress 2.0 standard describing error recovery: 2.4.1 Errors If the value named ai doesn't have the type Ti, there is a master error; note that during execution of the master there are always marks on the stack which will prevent underflow (see ΆŸ3.1). The definition may specify further conditions which must be satisfied; if the current state does not satisfy these conditions there is also a master error. In case of a master error, unless the operator definition specifies otherwise, there is a mark recovery. A mark recovery also occurs whenever any attempt is made to pop a mark except by a matching UNMARK or COUNT (ΆŸ2.4.6); when this happens, the mark remains on the stack. On a mark recovery, (a) the stack is popped until a mark is on top; (b) if the context that placed the mark on the stack no longer exists, the mark is popped and there is another mark recovery; otherwise, composed operators in execution are exited until the one which placed the mark is executing; and (c) literals are skipped in this operator until an UNMARK0 literal is found. The UNMARK0 found in step (c) is executed, thus popping the mark from the stack, and execution proceeds from this point. Note that the rules for executing a master given in ΆŸ3.1 insure that step (c) will eventually succeed. In addition, master errors are logged as specified in ΆŸ5.3. Marks thus serve two major purposes: to protect the stack from damage by an operator, and to indicate possible error recovery points. End of excerpt. Κ ž˜headšœ™šœ™Jšœ ™ —J˜šΟk ˜ Jšœœ ˜Jšœœœ˜$Jšœœž˜«Jšœ œ˜Jšœ œ˜Jšœ œS˜cJšœ œ­˜»Jšœœ˜Jšœ œ˜(Jšœ œ˜Jšœ œ ˜Jšœœn˜{JšœœO˜\Jšœ œ ˜.Jšœ œ˜Jšœœœ ˜—J˜—šœ œ˜Jšœœ_˜oJšœ˜"Jšœœœ˜*J˜Jšœœœ˜J˜Jšœœ˜Jšœ œœΟc˜>Jšœœ˜!J˜Jšœœœ˜J˜šΟnœœœ ˜)J˜šœœœœ˜(Jšœ˜—J˜—J˜š Ÿ œœœœœ˜EJšœœœ˜'Jšœ˜—J˜š Ÿ œœœœœ˜DJšœœœ ˜'Jšœ;˜?—J˜šŸœœœœ ˜;Jšœ)˜)J˜!Jšœœœœ˜?Jšœœ$˜.J˜—J˜šŸœœœ%˜6Jšœ(˜(Jšœ!˜!Jšœœœ˜;Jšœœ$˜.J˜—J˜šŸœœœœ˜AJ˜%Jšœ˜JšœœI˜SJ˜—J˜šŸ œœœœ˜Jšœ˜Jšœ˜J˜—J˜šŸœœœœ˜)Jšœœœ˜6J˜—J˜šŸœœœ%˜8Jšœ%˜*J˜—J™šŸœœœ ˜+Jšœ.˜5Jšœ˜J˜—J˜J™šœN™NbodyšΟb ™ Lš œΟiΠdiœ‘’œ Οe œο£ œ™ΔLšœ\œœ=™¨Lšœαœœ’™˜L™…——J™J™J˜šŸœœœ ˜.Jšœ˜Jšœœ œœ˜8Jšœœ˜J˜—J˜šŸœœœœ˜Dšœ1œ œ˜HJšœœœœ˜'Jšœ˜—Jšœœ˜Jšœ˜—J˜šŸœœœ ˜;š˜Jšœ)˜)Jšœ!œœ˜6Jšœ˜Jšœ˜—Jšœ˜—J˜šŸ œœ$˜5Jšœœ˜4Jšœž˜5Jšœ$˜$Jšœ7ž˜HJ˜—J˜šŸ œœœ˜:J˜ Jšœž˜J˜,J˜—J˜šŸ œœœ˜4J˜šœ ˜šœ˜Jšœ(ž˜