chris@mimsy.UUCP (Chris Torek) (03/21/88)
In article <1139@PT.CS.CMU.EDU> edw@IUS1.CS.CMU.EDU (Eddie Wyatt) writes: > But do you need coroutines to implimented generlized iteration. ... > void iterate_inorder(root,func) > TREE *root; > void (*func)(); > { > if (root != NULLPTR(TREE)) > { > iterate_inorder(root->left,func); > func(root->val); > iterate_inorder(root->right,func); > } > } > > I do see one problem though, which is dealing with variable > referenced inside the loop. They would have to become > global. This replaces coroutine iteration with stack recursion; I think the two are provably equivalent (but I am not going to [try to] prove it here). The variables need not be global; and indeed, I added a similar routine to Gosling Emacs in a situation in which I wanted the variables to be local. The code (real, working, code, in all its gory, I mean glory) is as follows: /* * Iterate over a table, calling the given function with each entry * and with the given pointer. The table is first sorted. */ TableIterate(t, f, a) register struct table *t; register int (*f)(); caddr_t a; /* this is a `generic pointer' */ { register int n; if (t->t_sorted <= 0) SortEntries(t); for (n = 0; n < t->t_size; n++) (*f)(t->t_ents[n], a); } [and in another file] /* * Apropos matching is carried out in a context consisting of a keyword, * the original buffer, and a flag that is set whenever a buffer specific * variable is matched. */ struct AproposContext { char *keyword; struct buffer *old; int AnyBufferSpecific; }; static AproposVarMatch(te, context) struct tentry *te; caddr_t context; { register struct AproposContext *c = (struct AproposContext *)context; struct Binding *b; int type; char buf[100]; /* ignore it if the name matches nowhere */ if (sindex(te->te_name, c->keyword) == 0) return; /* or if the variable is unbound */ if ((b = tetod(te, struct VariableName *)->v_binding) == NULL) return; /* footnote any variables that are buffer specific */ if (b->BufferSpecific || b->IsDefault || b->IsSystem && b->b.b_Default) { type = '*'; c->AnyBufferSpecific = 1; } else type = ' '; /* print name and (truncated to `reasonable' length) value */ (void) sprintfl(buf, sizeof buf, "%-30s%c = %s\n", te->te_name, type, CanonicalValue(b, c->old)); InsStr(buf); } [AproposMacMatch deleted; it is much the same] static DoApropos(context) caddr_t context; { register struct AproposContext *c = (struct AproposContext *)context; c->AnyBufferSpecific = 0; TableIterate(&MacTable, AproposMacMatch, c); TableIterate(&VarTable, AproposVarMatch, c); if (c->AnyBufferSpecific) InsCStr("\n*Buffer Specific\n", 18); } static Apropos() { struct AproposContext context; if ((context.keyword = getnbstr(": apropos keyword: ")) == NULL) return (0); context.old = bf_cur; ShowSomething("Help", (char *)NULL, DoApropos, (caddr_t)&context); return (0); } [Incidentally, ShowSomething itself uses another similar iterator. Perhaps the fanciest of all is in the routine that gives help for partial matches; when I rewrote it, I made it produce a column-sorted list of possible matches, where the columns are of the width deemed most appropriate given the length of the matching strings. But that one uses global variables.] -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris