home *** CD-ROM | disk | FTP | other *** search
- (* TwoTreesRunning 15 Oct 85
-
- A few years ago, I offered the conjecture that in Modula-2 one could traverse
- two trees simultaneously (eg. merge them) with one procedure but two Modula-2
- coroutines. As an exercise for a course ("Modula-2 for FORTRAN Programmers",
- five days) I am giving next month, I had a chance to make good on my specu-
- lations and actually write the program.
-
- The example is brutal in that it makes no attempt to hide the type of the data
- values or other motherhoods. Though bad practice, I did not want to obscure
- the principal goal.
-
- Feel free to use it in your own work, but please credit the original author.
- Comments, improvements, and abuse should be direct to me.
-
- Thank you,
-
- Randy Bush
- Pacific Systems Group
- 601 South 12th Court
- Coos Bay, Oregon 97420
- Voice : (503) 267-6970
- Occasional : (503) 572-5391
- TeleMail : RBush/PSG
- Telex : 9103339158 PACIFIC SYS GR
- Fido 122/6 : (503) 269-5202
- CompuServe : 70265,757
- Usenet : decvax!decwrl!logitech!psg
-
- *)
-
- MODULE TwoTreesRunning; (* by RBush. Copyright 1985, Pacific *)
- IMPORT SYSTEM; (* Systems Group. All rights reserved.*)
- FROM Storage IMPORT ALLOCATE, DEALLOCATE;
-
- TYPE
- Node = POINTER TO NodeRec; (* one subtree of list elements *)
- NodeRec = RECORD (* one list element looks like this *)
- left : Node; (* val of these nodes is less *)
- right : Node; (* val of these nodes is greater *)
- i : CARDINAL (* example, any ordered type will do *)
- END;
- VAR
- t0, t1 : Node; (* two trees possibly full of data *)
- p : SYSTEM.PROCESS; (* the non-running process of the two *)
- other : Node; (* non-running process's current node *)
- parm : Node; (* root parameter to DoTree *)
- minNode : Node; (* fake node with min value for data *)
- stack : ARRAY [0..1953] OF (* stack space for the second process *)
- SYSTEM.WORD; (* type arbitrary, size system-dep *)
-
- PROCEDURE DoTree (); (* coroutine, so 'parm' in global *)
-
- PROCEDURE DoSubTree ( n : Node );
- BEGIN
- IF n^.left <> NIL THEN (* do the left subtree before node *)
- DoSubTree ( n^.left ) (* recurse down to lowest in subtree *)
- END;
- IF (other <> NIL) AND (n^.i > other^.i) THEN
- other := n; (* node(s) in other tree come first *)
- SYSTEM.TRANSFER ( p, p )
- END;
- (* Some.Process (n^) *) (* actually process the current node *)
- IF n^.right <> NIL THEN (* after node do entire right subtree *)
- DoSubTree ( n^.right )
- END
- END DoSubTree;
-
- BEGIN
- IF parm <> NIL THEN (* if the passed tree is not empty *)
- DoSubTree ( parm ) (* then processs it as a subtree *)
- END;
- IF other <> NIL THEN (* if not finished with other tree *)
- other := NIL; (* then let other coroutine finish *)
- SYSTEM.TRANSFER ( p, p )
- END
- END DoTree;
-
- BEGIN
- (* t0 := SomeHow.MakeTree (); *)
- parm := t0; (* couroutine will traverse tree t0 *)
- NEW ( minNode ); (* create phony t1 starting node *)
- minNode^.i := 0; (* with the minimum data value in it *)
- other := minNode; (* to force t0 traversal far left *)
- SYSTEM.NEWPROCESS ( DoTree, SYSTEM.ADR(stack), SYSTEM.SIZE(stack), p );
- SYSTEM.TRANSFER ( p, p ); (* start t0 traversal which *)
- DISPOSE ( minNode ); (* xfers back when at far left value *)
- (* t1 := SomeHow.MakeTree (); *)
- parm := t1; (* main coroutine does t1 traversal *)
- DoTree ()
- END TwoTreesRunning.