@define mkchaser(fn) { @local seen; seen = mktab(); return @lambda(p){ if(p) work(domof(p), [p], fn, seen); return nil; }; } @define chasetype(t) { if(istypedef(t)) return chasetype(typedeftype(t)); return t; } @define chaseable(t) { t = chasetype(t); if(!isptr(t)) return 0; if(!issu(chasetype(subtype(t)))) return 0; return 1; } @define work(dom, wk, fn, seen) { @local x, y, m, ls, i; while(length(wk) > 0){ x = pop(wk); if(seen[x] != nil) continue; ls = links(x); seen[x] = 1; fn(x, ls); m = length(ls); for(i = 0; i < m; i++){ y = pop(ls); if(y && ismapped(y)) append(wk, y); } } } @define links(p) { @local t, l; @local loop, f, fs, m, pft, q, i, n; l = []; @define loop(p) { t = chasetype(@typeof(*p)); if (isptr(t)) append(l, *p); else if(isstruct(t)){ p = (void*)p; foreach(@lambda(f){ pft = mkctype_ptr(fieldtype(f)); q = {pft}(p+fieldoff(f)); loop(q); }, fields(t)); }else if(isarray(t)){ n = arraynelm(t); q = *p; for(i = 0; i < n; i++) loop(&q[i]); } } loop(p); return l; } @define fmtnode(p) { return sprintfa("(%t)0x%p", p, p); } @define chasecb(p, ls) { printf("%s:\n", fmtnode(p)); foreach(@lambda(p) { printf("\t%s\n", fmtnode(p)); }, ls); } @define testchase() { @local ns, as, dom, p, q, i, j; ns = @names c32le { struct X { @0x00 struct X *x1; @0x10 struct Y y; @0x20 struct X *x[10]; // @0x20 struct X x[10]; @0x100; }; struct Y { @0x00 struct X *x2; @0x10; }; @0x0 struct X root; }; as = mkzas(10240); dom = mkdom(ns, as); q = p = (struct X*){dom}0; for(i = 0; i < 10; i++){ p->x1 = p+1; p->y.x2 = p+2; for(j = 0; j < 9; j++) p->x[j] = &q[j]; p++; } chase = mkchaser(chasecb); chase(q+1); return nil; }