<> <> <> <> <> <> DIRECTORY Ascii, Basics, CharDisplays, DisplayControllers, IO, RefText, Rope; DisplayControllersImpl: CEDAR PROGRAM IMPORTS Basics, CharDisplays, IO, RefText, Rope EXPORTS DisplayControllers = {OPEN DisplayControllers; neverMind: Action _ [proc: Naught, overrideable: TRUE]; print: Action _ [proc: Print, overrideable: TRUE]; displayDriverClass: ATOM = $TermEmDisplayController; displayDriverProcs: REF IO.StreamProcs _ IO.CreateStreamProcs[ variety: output, class: displayDriverClass, flush: FlushDisplay, putChar: ConsumeChar, putBlock: ConsumeChars ]; Create: PUBLIC PROC [cd: CharDisplay, cp: ControlProgram] RETURNS [dc: DisplayController] = { dc _ NEW [DisplayControllerRep _ [ cd: cd, cp: cp, cps: NEW [ControlProgramStateRep _ [ curVertex: cp.start, chars: RefText.New[10]]], toDisplay: NIL, fromDisplay: cd.fromDisplay ]]; IF cp.Init # NIL THEN cp.Init[dc]; dc.toDisplay _ IO.CreateStream[streamProcs: displayDriverProcs, streamData: dc]; }; SetDriver: PUBLIC PROC [dc: DisplayController, driver: IO.STREAM] = { dc.driver _ driver; }; FlushDisplay: PROC [self: IO.STREAM] = { dc: DisplayController = NARROW[self.streamData]; IF dc.cd.class.Destroyed[dc.cd] THEN ERROR IO.Error[StreamClosed, self]; IF dc.cd.class.Flush # NIL THEN dc.cd.class.Flush[dc.cd]; }; ConsumeChar: PROC [self: IO.STREAM, char: CHAR] = { dc: DisplayController _ NARROW[self.streamData]; consumed: BOOL _ FALSE; IF dc.cd.class.Destroyed[dc.cd] THEN ERROR IO.Error[StreamClosed, self]; SELECT dc.cp.bits FROM 7 => char _ VAL[Basics.BITAND[ORD[char], 127]]; 8 => NULL; ENDCASE => ERROR; IF dc.cps.curVertex = dc.cp.start THEN dc.cps.chars.length _ 0; WHILE dc.cps.chars.length >= dc.cps.chars.maxLength DO dc.cps.chars _ RefText.New[dc.cps.chars.maxLength*2] ENDLOOP; dc.cps.chars _ RefText.InlineAppendChar[dc.cps.chars, char]; DO ENABLE CharDisplays.DisplayDestroyed => ERROR IO.Error[StreamClosed, self]; Do: PROC [t: Transition] = INLINE { t.action.proc[dc: dc, clientData: t.action.clientData]; dc.cps.curVertex _ t.newVertex}; v: Vertex _ dc.cps.curVertex; SELECT v.repStyle FROM epsilon => Do[v.t]; list => { el: EdgeList _ NIL; IF consumed THEN EXIT; consumed _ TRUE; FOR el _ v.edgeList, el.rest WHILE el # NIL DO IF el.first.char = char THEN {Do[el.first.transition]; EXIT}; ENDLOOP; IF el = NIL THEN Do[v.t]; }; array => { IF consumed THEN EXIT; consumed _ TRUE; Do[v.edgeArray[char]]; }; ENDCASE => ERROR; ENDLOOP; <> {driver: IO.STREAM = dc.driver; flush: BOOL _ driver = NIL; IF NOT flush THEN flush _ driver.CharsAvail[!IO.Error => {flush _ TRUE; CONTINUE}] = 0; IF flush AND dc.cd.class.Flush # NIL THEN dc.cd.class.Flush[dc.cd]; }; }; ConsumeChars: PROC [self: IO.STREAM, block: REF READONLY TEXT, startIndex: NAT _ 0, count: NAT _ NAT.LAST] = { ENABLE CharDisplays.DisplayDestroyed => ERROR IO.Error[StreamClosed, self]; dc: DisplayController _ NARROW[self.streamData]; IF startIndex+count > block.maxLength THEN count _ block.length - startIndex; FOR i: INT IN [startIndex..startIndex+count) DO char: CHAR _ block[i]; consumed: BOOL _ FALSE; IF dc.cd.class.Destroyed[dc.cd] THEN ERROR IO.Error[StreamClosed, self]; SELECT dc.cp.bits FROM 7 => char _ VAL[Basics.BITAND[ORD[char], 127]]; 8 => NULL; ENDCASE => ERROR; IF dc.cps.curVertex = dc.cp.start THEN dc.cps.chars.length _ 0; WHILE dc.cps.chars.length >= dc.cps.chars.maxLength DO dc.cps.chars _ RefText.New[dc.cps.chars.maxLength*2] ENDLOOP; dc.cps.chars _ RefText.InlineAppendChar[dc.cps.chars, char]; DO Do: PROC [t: Transition] = INLINE { t.action.proc[dc: dc, clientData: t.action.clientData]; dc.cps.curVertex _ t.newVertex}; v: Vertex _ dc.cps.curVertex; SELECT v.repStyle FROM epsilon => Do[v.t]; list => { el: EdgeList _ NIL; IF consumed THEN EXIT; consumed _ TRUE; FOR el _ v.edgeList, el.rest WHILE el # NIL DO IF el.first.char = char THEN {Do[el.first.transition]; EXIT}; ENDLOOP; IF el = NIL THEN Do[v.t]; }; array => { IF consumed THEN EXIT; consumed _ TRUE; Do[v.edgeArray[char]]; }; ENDCASE => ERROR; ENDLOOP; ENDLOOP; -- Consider flushing IF dc.cd.class.Flush # NIL THEN { IF (dc.driver#NIL) AND (dc.driver.CharsAvail[!IO.Error=>CONTINUE] >0 ) THEN RETURN; dc.cd.class.Flush[dc.cd] } }; NewControlProgram: PUBLIC PROC [Init: PROC [dc: DisplayController] _ NIL, clientData: REF ANY _ NIL, bits: [7 .. 8] _ 8] RETURNS [cp: ControlProgram] = { sv: Vertex _ NEW [VertexRep _ [repStyle: array]]; sv.edgeArray _ NEW [TransitionArrayRep _ ALL[[print, sv]]]; cp _ NEW [ControlProgramRep _ [ start: sv, Init: Init, clientData: clientData, bits: bits]]; }; AddInstruction: PUBLIC PROC [cp: ControlProgram, steps: StepList, final: Action] = { v: Vertex _ cp.start; FOR steps _ steps, steps.rest WHILE steps # NIL DO lastStep: BOOL _ steps.rest = NIL; WITH steps.first SELECT FROM t: REFTEXT => { lastI: INT = t.length-1; FOR i: INT IN [0 .. lastI] DO IF lastStep AND i=lastI THEN v _ Merge[cp: cp, char: t[i], v: v, last: TRUE, a: final] ELSE v _ Merge[cp: cp, char: t[i], v: v, last: FALSE]; ENDLOOP; IF lastStep THEN final _ neverMind; }; r: ROPE => { lastI: INT = r.Length[]-1; FOR i: INT IN [0 .. lastI] DO IF lastStep AND i=lastI THEN v _ Merge[cp: cp, char: r.Fetch[i], v: v, last: TRUE, a: final] ELSE v _ Merge[cp: cp, char: r.Fetch[i], v: v, last: FALSE]; ENDLOOP; IF lastStep THEN final _ neverMind; }; d: Decode => { IF d.len = 0 THEN { dec0: Action _ DecodeAction[d, 0]; dec1: Action _ DecodeAction[d, 1]; IF lastStep THEN ERROR; v _ MergeDigits[d: d, cp: cp, last: FALSE, a: dec0, v: v]; IF v # MergeDigits[d: d, cp: cp, last: FALSE, to: v, a: dec1, v: v] THEN ERROR; } ELSE { FOR i: INT IN [0 .. d.len) DO dec: Action _ DecodeAction[d, i]; v _ MergeDigits[d: d, cp: cp, last: lastStep AND i=d.len-1 AND final=neverMind, a: dec, v: v]; ENDLOOP; }; }; ENDCASE => ERROR; IF (v = cp.start) # (lastStep AND final = neverMind) THEN ERROR; ENDLOOP; IF final # neverMind THEN { IF v = cp.start THEN ERROR; v _ Append[cp: cp, a: final, from: v, to: cp.start]}; IF v # cp.start THEN ERROR; }; Replaceable: PROC [cp: ControlProgram, t: Transition, from: Vertex, a: Action] RETURNS [boring: BOOL] = { boring _ t.action.overrideable OR ActionEqual[t.action, a]}; ActionEqual: PROC [a1, a2: Action] RETURNS [eq: BOOL] = { IF a1.proc # a2.proc THEN RETURN [FALSE]; IF a1.clientData = a1.clientData THEN RETURN [TRUE]; WITH a1.clientData SELECT FROM dd1: DecodeData => WITH a2.clientData SELECT FROM dd2: DecodeData => RETURN [dd1.i = dd2.i AND dd1.d^ = dd2.d^]; ENDCASE => RETURN [FALSE]; ENDCASE => RETURN [FALSE]; }; AddEpsilon: PROC [t: Transition, a: Action] RETURNS [u: Transition] = { u _ [ action: a, newVertex: NEW [VertexRep _ [epsilon, t]] ]}; MergeDigits: PROC [ d: Decode, cp: ControlProgram, last: BOOL, to: Vertex _ NIL, a: Action, v: Vertex] RETURNS [newV: Vertex] = { deltaMax: NAT _ MIN[(LAST[CHAR] - d.org), d.base-1]; newV _ to; FOR c: CHAR IN [d.org .. d.org + deltaMax] DO xc: CHAR _ 0C + XOR[c-0C, d.xor]; ans: Vertex _ Merge[cp: cp, last: last, char: xc, to: newV, a: a, v: v]; IF newV = NIL THEN newV _ ans ELSE IF newV # ans THEN ERROR; ENDLOOP; }; Append: PROC [cp: ControlProgram, a: Action, from, to: Vertex _ NIL] RETURNS [newV: Vertex] = { IF NOT (from.repStyle = list AND from.edgeList = NIL AND from.t = [print, cp.start]) THEN ERROR; from.repStyle _ epsilon; IF to # NIL THEN { IF to # from.t.newVertex THEN ERROR; from.t.action _ a; newV _ from.t.newVertex; } ELSE { newV _ NEW [VertexRep _ [repStyle: list, t: [print, cp.start]]]; from.t _ [a, newV]; }; }; Merge: PROC [ cp: ControlProgram, last: BOOL, char: CHAR, to: Vertex _ NIL, a: Action _ neverMind, v: Vertex] RETURNS [newV: Vertex] = { NextV: PROC RETURNS [v: Vertex] = { v _ IF to # NIL THEN to ELSE NEW [VertexRep _ [repStyle: list, t: DefaultEnd[cp]]]; }; Update: PROC [oldT: Transition] RETURNS [newT: Transition] = { oldNext: Vertex _ oldT.newVertex; rbl: BOOL _ Replaceable[cp, oldT, v, a]; IF oldNext # to THEN { IF to # NIL AND ((NOT rbl) OR oldNext # cp.start) THEN ERROR; IF to = NIL AND (NOT rbl) AND (oldNext = cp.start OR NOT a.overrideable) THEN ERROR; }; newT _ oldT; IF rbl THEN { IF oldNext = cp.start OR to # NIL THEN newT _ [a, NextV[]] ELSE newT.action _ a; } ELSE IF to # NIL AND NOT a.overrideable THEN newT _ AddEpsilon[newT, a]; }; IF last THEN { IF to = NIL THEN to _ cp.start ELSE IF to # cp.start THEN ERROR; IF a = neverMind THEN a _ print; }; SELECT v.repStyle FROM epsilon => ERROR; list => { el: EdgeList _ NIL; FOR el _ v.edgeList, el.rest WHILE el # NIL DO IF el.first.char = char THEN EXIT; ENDLOOP; IF el = NIL THEN v.edgeList _ el _ CONS[[char: char, transition: v.t], v.edgeList]; newV _ (el.first.transition _ Update[el.first.transition]).newVertex; }; array => { newV _ (v.edgeArray[char] _ Update[v.edgeArray[char]]).newVertex; }; ENDCASE => ERROR; DO SELECT newV.repStyle FROM epsilon => newV _ newV.t.newVertex; list, array => EXIT; ENDCASE => ERROR; ENDLOOP; IF last AND newV # cp.start THEN ERROR; }; DefaultEnd: PROC [cp: ControlProgram] RETURNS [t: Transition] = {t _ [action: print, newVertex: cp.start]}; ClearRegAction: PROC [d: Decode] RETURNS [a: Action] = {a _ [proc: ClearReg, clientData: d]}; ClearReg: PROC [dc: DisplayController, clientData: REF ANY] = { d: Decode _ NARROW[clientData]; dc.cps.regs[d.reg] _ d.offset}; DecodeData: TYPE = REF DecodeDataRep; DecodeDataRep: TYPE = RECORD [ d: Decode, i: NAT]; DecodeAction: PROC [d: Decode, i: NAT] RETURNS [a: Action] = {a _ [proc: DecodeReg, clientData: NEW [DecodeDataRep _ [d, i]]]}; DecodeReg: PROC [dc: DisplayController, clientData: REF ANY] = { dd: DecodeData _ NARROW[clientData]; c: CHAR _ dc.cps.chars[dc.cps.chars.length-1]; IF dd.i = 0 THEN dc.cps.regs[dd.d.reg] _ dd.d.offset; dc.cps.regs[dd.d.reg] _ (dc.cps.regs[dd.d.reg] - dd.d.offset) * dd.d.base + (XOR[c-0C, dd.d.xor] - (dd.d.org - 0C)) + dd.d.offset; }; XOR: PROC [i1, i2: INTEGER] RETURNS [i3: INTEGER] = TRUSTED {i3 _ Basics.BITXOR[i1, i2]}; Naught: PUBLIC PROC [dc: DisplayController, clientData: REF ANY] = {}; Print: PUBLIC PROC [dc: DisplayController, clientData: REF ANY] = { Do: PROC [c: CHAR] = INLINE {dc.cd.class.TakeChar[dc.cd, c, dc.cps.modes[insert]]}; FOR i: INT IN [0 .. dc.cps.chars.length) DO Do[dc.cps.chars[i]] ENDLOOP; }; }.