-- PLSupImpl.Mesa Last Modified by JHM -- Schmidt August 22, 1982 1:47 pm -- used to be Sup.Mesa DIRECTORY Inline: TYPE USING [LongCARDINAL], PL: TYPE USING [BlessLST, BlessString, GetSpecialNodes, Insert, LengthList, LSTNode, LSTNodeRecord, Map, NewNail, Node, NodeRecord, RErr, rLST, rSTR, Z], PString: TYPE USING [Item, NewStream, Stream], Rope: TYPE USING [Equal, ROPE], SafeStorage: TYPE USING [NewZone]; PLSupImpl: CEDAR PROGRAM IMPORTS P:PL, S: PString, SafeStorage, Rope EXPORTS PL = { OPEN P, Rope; -- N: ZONE = P.Z; PrefixedZone: ZONE; LSTNode: TYPE = PL.LSTNode; LSTNodeRecord: TYPE = PL.LSTNodeRecord; NodeRecord: TYPE = PL.NodeRecord; Node: TYPE = PL.Node; -- PBug: PUBLIC SIGNAL[ROPE] = CODE; SErr: PUBLIC SIGNAL[est: ROPE] = CODE; RErr: PUBLIC SIGNAL[est: ROPE] = CODE; EndDisplay: PUBLIC SIGNAL = CODE; Interrupt: PUBLIC SIGNAL = CODE; -- ListRecord: TYPE = RECORD[old: Node, new: ROPE, pref: LONG INTEGER, number: BOOLEAN]; List: REF L; L: TYPE = RECORD[e:SEQUENCE length: NAT OF ListRecord]; lin: CARDINAL; ascii: BOOLEAN; Nail: LSTNode; SortRoutine: PROC[input: Node] RETURNS[Node] = { ascii ← FALSE; WITH input SELECT FROM l: rLST => RETURN[sort[l]]; ENDCASE => ERROR P.RErr["sort requires a list"]; }; ASortRoutine: PROC[input: Node] RETURNS[Node] = { ascii ← TRUE; WITH input SELECT FROM l: rLST => RETURN[sort[l]]; ENDCASE => ERROR P.RErr["asort requires a list"]; }; sort: PROC[input: LSTNode] RETURNS[j:LSTNode] = { i,m: CARDINAL; j ← NIL; i ← P.LengthList[input]; IF i <= 1 THEN j ← input ELSE { List ← PrefixedZone.NEW[L[i]]; lin ← 0; FOR m IN [0..i) DO List[m].number ← FALSE; ENDLOOP; P.Map[input,SR]; -- setting up simple random number generaor TreeSort[lin]; -- sort the list j ← N.NEW[LSTNodeRecord←[TRUE,LST[List[lin-1].old,Nail]]]; IF lin > 1 THEN FOR i DECREASING IN [0.. (lin-2)] DO j ← N.NEW[LSTNodeRecord←[TRUE,LST[List[i].old,j]]]; ENDLOOP; }; RETURN[j]; }; SR: PROC[n: Node] = { ns: PString.Stream; List[lin].old ← n; WITH n SELECT FROM l: rLST => n ← l.listhead; t: rSTR => List[lin].new ← t.str; ENDCASE => P.RErr["sort expects a list of strings"]; ns ← S.NewStream[List[lin].new]; List[lin].number ← FALSE; IF ~ascii THEN { c: CHARACTER; neg: BOOLEAN ← FALSE; n: LONG INTEGER ← 0; [c,ns] ← S.Item[ns]; IF c = '- THEN { neg ← TRUE; [c, ns] ← S.Item[ns] }; IF c=0C THEN GOTO NotNum; UNTIL c=0C DO IF c NOT IN ['0..'9] THEN GOTO NotNum; n ← n*10+ (c-'0); [c, ns] ← S.Item[ns]; ENDLOOP; IF neg THEN n ← -n; List[lin].number ← TRUE; List[lin].pref ← n EXITS NotNum => NULL; }; IF ~List[lin].number THEN { -- this is just to get the first four characters into the long integer place so that they form a good hint FunnyINT: TYPE = PACKED ARRAY [0..4) OF CHARACTER; ns ← S.NewStream[List[lin].new]; [LOOPHOLE[List[lin].pref, FunnyINT][2], ns] ← S.Item[ns]; [LOOPHOLE[List[lin].pref, FunnyINT][3], ns] ← S.Item[ns]; [LOOPHOLE[List[lin].pref, FunnyINT][0], ns] ← S.Item[ns]; [LOOPHOLE[List[lin].pref, FunnyINT][1], ns] ← S.Item[ns]; }; lin ← lin + 1; }; TreeSort: PROC[N: INTEGER] = { t: ListRecord; siftUp: PROC[low, high: INTEGER] = { k, son: INTEGER; k ← low; DO IF 2*k>high THEN EXIT; IF 2*k+1>high OR LessThan[2*k+1-1, 2*k-1] THEN son ← 2*k ELSE son ← 2*k+1; IF LessThan[son-1, k-1] THEN EXIT; t ← List[son-1]; List[son-1] ← List[k-1]; List[k-1] ← t; k ← son; ENDLOOP; }; i: INTEGER; FOR i DECREASING IN [1..N/2] DO siftUp[i,N] ENDLOOP; FOR i DECREASING IN [1..N) DO t ← List[1-1]; List[1-1] ← List[i+1-1]; List[i+1-1] ← t; siftUp[1,i] ENDLOOP; }; LessThan: PROC[i,j: INTEGER] RETURNS[BOOLEAN] = { res: INTEGER; n1, n2: PString.Stream; c1,c2: CHARACTER; IF List[i].number AND List[j].number THEN { IF List[i].pref < List[j].pref THEN RETURN[TRUE] ELSE RETURN[FALSE]; }; IF ~List[i].number AND ~List[j].number THEN { res ← USC[List[i].pref,List[j].pref]; IF res ~= 0 THEN RETURN[res=-1]; }; n1 ← S.NewStream[List[i].new]; n2 ← S.NewStream[List[j].new]; DO [c1, n1] ← S.Item[n1]; [c2, n2] ← S.Item[n2]; IF c1 > c2 THEN { res ← 1; EXIT; }; IF c1 < c2 THEN { res ← -1; EXIT; }; IF c1 = 0C THEN { res ← 0; EXIT; }; ENDLOOP; RETURN[res=-1]; }; USC: PROC[a,b: LONG INTEGER] RETURNS[INTEGER] = { -- unsigned compare, treat a and b as LONG CARDINALS -- return -1 if a<b, 0 if a=b, 1 if a>b i: Inline.LongCARDINAL ← LOOPHOLE[a]; j: Inline.LongCARDINAL ← LOOPHOLE[b]; IF i>j THEN RETURN[1]; IF i<j THEN RETURN[-1]; RETURN[0]; }; USortRoutine: PROC[input: Node] RETURNS[ans:Node] = -- unary {n: LSTNode ← P.BlessLST[ASortRoutine[input]]; ans ← n; IF n.listhead#NIL THEN WHILE n.listtail.listhead # NIL DO IF Equal[P.BlessString[n.listhead],P.BlessString[n.listtail.listhead]] THEN { --n.listhead ← n.listtail.listhead; --n.listtail ← n.listtail.listtail; n↑ ← n.listtail↑ } ELSE n ← n.listtail ENDLOOP; }; FactorRoutine: PROC[ninput: Node] RETURNS[ans:Node] = { -- unary input: LSTNode = P.BlessLST[ninput]; Ch: PROC[n: Node] = {WITH n SELECT FROM l: rLST => WITH l.listhead SELECT FROM s: rSTR => RETURN; ENDCASE => P.RErr["Illegal input to factor"]; ENDCASE => P.RErr["Illegal input to factor"]}; ans ← NIL; P.Map[input,Ch]; {n: LSTNode ← sort[input]; m: LSTNode ← P.NewNail[]; ans ← m; UNTIL n.listhead=NIL DO key: Node ← P.BlessLST[n.listhead].listhead; target: LSTNode ← P.NewNail[]; m↑ ← [TRUE, LST[ N.NEW[NodeRecord←[TRUE,LST[key,target]]], P.NewNail[]]]; m ← m.listtail; WHILE n.listhead#NIL AND Equal[P.BlessString[key],P.BlessString[P.BlessLST[n.listhead].listhead]] DO target↑ ← [TRUE,LST[ P.BlessLST[n.listhead].listtail, P.NewNail[]]]; target ← target.listtail; n ← n.listtail ENDLOOP; ENDLOOP; }}; SupSetup: PUBLIC PROC = { [] ← P.Insert["sort",[,,ZARY[SortRoutine]]]; [] ← P.Insert["usort",[,,ZARY[USortRoutine]]]; [] ← P.Insert["asort",[,,ZARY[ASortRoutine]]]; [] ← P.Insert["factor",[,,ZARY[FactorRoutine]]]; }; PrefixedZone ← SafeStorage.NewZone[]; [,,Nail] ← P.GetSpecialNodes[]; }.