forsyth20121205-174063a80cc13 years agoHistory
502 lines · 9.7 KB · Brainfuck
RawDownload
implement Stackv; include "sys.m";	sys: Sys;include "draw.m";include "debug.m";	debug: Debug;	Prog, Module, Exp: import debug;	Tadt, Tarray, Tbig, Tbyte, Treal,	Tfn, Tint, Tlist,	Tref, Tstring, Tslice: import Debug;include "arg.m";include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; stderr: ref Sys->FD;stdout: ref Iobuf; hasht := array[97] of (int, array of int); Stackv: module {	init: fn(ctxt: ref Draw->Context, argv: list of string);}; maxrecur := 16r7ffffffe; badmodule(p: string){	sys->fprint(stderr, "stackv: cannot load %q: %r\n", p);	raise "fail:bad module";} currp: ref Prog;showtypes := 1;showsource := 0;showmodule := 0; init(nil: ref Draw->Context, argv: list of string){ 	sys = load Sys Sys->PATH;	stderr = sys->fildes(2);	debug = load Debug Debug->PATH;	if(debug == nil)		badmodule(Debug->PATH);	bufio = load Bufio Bufio->PATH;	if (bufio == nil)		badmodule(Bufio->PATH);	arg := load Arg Arg->PATH;	if (arg == nil)		badmodule(Arg->PATH);	stdout = bufio->fopen(sys->fildes(1), Sys->OWRITE); 	arg->init(argv);	arg->setusage("stackv [-Tlm] [-r maxdepth] [-s dis sbl]... [pid[.sym]...] ...");	sblfile := "";	while((opt := arg->opt()) != 0){		case opt {		's' =>			arg->earg();	# XXX make it a list of maps from dis to sbl later			sblfile = arg->earg();		'l' =>			showsource = 1;		'm' =>			showmodule = 1;		'r' =>			maxrecur = int arg->earg();		'T' =>			showtypes = 0;		* =>			arg->usage();		}	}	debug->init();	argv = arg->argv();	printpids := len argv > 1;	if(printpids)		maxrecur++;	for(; argv != nil; argv = tl argv)		db(sys->tokenize(hd argv, ".").t1, printpids);} db(toks: list of string, printpid: int): int{	if(toks == nil){		sys->fprint(stderr, "stackv: bad pid\n");		return -1;	}	if((pid := int hd toks) <= 0){		sys->fprint(stderr, "stackv: bad pid %q\n", hd toks);		return -1;	}	err: string;	p: ref Prog; 	# reuse process if possible	if(currp == nil || currp.id != pid){		(currp, err) = debug->prog(pid);		if(err != nil){			sys->fprint(stderr, "stackv: %s\n", err);			return -1;		}		if(currp == nil){			sys->fprint(stderr, "stackv: nil prog from pid %d\n", pid);			return -1;		}	}	p = currp;	stk: array of ref Exp;	(stk, err) = p.stack();	if(err != nil){		sys->fprint(stderr, "stackv: %s\n", err);		return -1;	}	for (i := 0; i < len stk; i++) {		stk[i].m.stdsym();		stk[i].findsym();	}	depth := 0;	if(printpid){		stdout.puts(sys->sprint("prog %d {\n", pid));	# }		depth++;	}	pexp(stk, tl toks, depth);	if(printpid)		stdout.puts("}\n");	stdout.flush();	return 0;} pexp(stk: array of ref Exp, toks: list of string, depth: int){	if(toks == nil){		for (i := 0; i < len stk; i++)			pfn(stk[i], depth);	}else{		exp := stackfindsym(stk, toks, depth);		if(exp == nil)			return;		pname(exp, depth, nil);		stdout.putc('\n');	}} stackfindsym(stk: array of ref Exp, toks: list of string, depth: int): ref Exp{	fname := hd toks;	toks = tl toks;	for(i := 0; i < len stk; i++){		s := stk[i].name;		if(s == fname)			break;		if(hasdot(s) && toks != nil && s == fname+"."+hd toks){			fname += "."+hd toks;			toks = tl toks;			break;		}	}	if(i == len stk){		indent(depth);		stdout.puts("function not found\n");		return nil;	}	if(toks == nil)		return stk[i];	stk = stk[i].expand();	if(hd toks == "module"){		if((e := getname(stk, "module")) == nil){			indent(depth);			stdout.puts(sys->sprint("no module declarations in function %q\n", fname));		}else if((e = symfindsym(e, tl toks, depth)) != nil)			return e;		return nil;	}	for(t := "locals" :: "args" :: "module" :: nil; t != nil; t = tl t){		if((e := getname(stk, hd t)) == nil)			continue;		if((e = symfindsym(e, toks, depth)) != nil)			return e;	}	indent(depth);	stdout.puts(sys->sprint("symbol %q not found in function %q\n", hd toks, fname));	return nil;} hasdot(s: string): int{	for(i := 0; i < len s; i++)		if(s[i] == '.')			return 1;	return 0;} symfindsym(e: ref Exp, toks: list of string, depth: int): ref Exp{	if(toks == nil)		return e;	exps := e.expand();	for(i := 0; i < len exps; i++)		if(exps[i].name == hd toks)			return symfindsym(exps[i], tl toks, depth);	return nil;} pfn(exp: ref Exp, depth: int){	(v, w) := exp.val();	if(!w || v == nil){		indent(depth);		stdout.puts(sys->sprint("no value for fn %q\n", exp.name));		return;	}	exps := exp.expand();	indent(depth);	stdout.puts("["+exp.srcstr()+"]\n");	indent(depth);	stdout.puts(symname(exp)+"(");	if((e := getname(exps, "args")) != nil){		args := e.expand();		for(i := 0; i < len args; i++){			pname(args[i], depth+1, nil);			if(i != len args - 1)				stdout.puts(", ");		}	}	stdout.puts(")\n");	indent(depth);	stdout.puts("{\n");	# }	if((e = getname(exps, "locals")) != nil){		locals := e.expand();		for(i := 0; i < len locals; i++){			indent(depth+1);			pname(locals[i], depth+1, nil);			stdout.puts("\n");		}	}	if(showmodule && (e = getname(exps, "module")) != nil){		mvars := e.expand();		for(i := 0; i < len mvars; i++){			indent(depth+1);			pname(mvars[i], depth+1, "module.");			stdout.puts("\n");		}	}	indent(depth);	stdout.puts("}\n");} getname(exps: array of ref Exp, name: string): ref Exp{	for(i := 0; i < len exps; i++)		if(exps[i].name == name)			return exps[i];	return nil;} strval(v: string): string{	for(i := 0; i < len v; i++)		if(v[i] == '"')			break;	if(i < len v)		v = v[i:];	return v;} pname(exp: ref Exp, depth: int, prefix: string){	name := prefix+symname(exp);	(v, w) := exp.val();	if (!w && v == nil) {		stdout.puts(sys->sprint("%s: %s = novalue", symname(exp), exp.typename()));		return;	}	case exp.kind() {	Tfn =>		pfn(exp, depth);	Tint =>		stdout.puts(sys->sprint("%s := %s", name, v));	Tstring =>		stdout.puts(sys->sprint("%s := %s", name, strval(v)));	Tbyte or	Tbig or	Treal =>		stdout.puts(sys->sprint("%s := %s %s", name, exp.typename(), v));	* =>		if(showtypes)			stdout.puts(sys->sprint("%s: %s = ", name, exp.typename()));		else			stdout.puts(sys->sprint("%s := ", name));		pval(exp, v, w, depth);	}} srcstr(src: ref Debug->Src): string{	if(src == nil)		return nil;	if(src.start.file != src.stop.file)		return sys->sprint("%q:%d.%d,%q:%d.%d", src.start.file, src.start.line, src.start.pos, src.stop.file, src.stop.line, src.stop.pos);	if(src.start.line != src.stop.line)		return sys->sprint("%q:%d.%d,%d.%d", src.start.file, src.start.line, src.start.pos, src.stop.line, src.stop.pos);	return sys->sprint("%q:%d.%d,%d", src.start.file, src.start.line, src.start.pos, src.stop.pos);} pval(exp: ref Exp, v: string, w: int, depth: int){	if(depth >= maxrecur){		stdout.puts(v);		return;	}	case exp.kind() {	Tarray =>		if(pref(v)){			if(depth+1 >= maxrecur)				stdout.puts(v+"{...}");			else{				stdout.puts(v+"{\n");				indent(depth+1);				parray(exp, depth+1);				stdout.puts("\n");				indent(depth);				stdout.puts("}");			}		}	Tlist =>		if(v == "nil")			stdout.puts("nil");		else		if(depth+1 >= maxrecur)			stdout.puts(v+"{...}");		else{			stdout.puts("{\n");			indent(depth+1);			plist(exp, v, w, depth+1);			stdout.puts("\n");			indent(depth);			stdout.puts("}");		}	Tadt =>		pgenval(exp, nil, w, depth);	Tref =>		if(pref(v))			pgenval(exp, v, w, depth);	Tstring =>		stdout.puts(strval(v));	* =>		pgenval(exp, v, w, depth);	}} parray(exp: ref Exp, depth: int){	exps := exp.expand();	for(i := 0; i < len exps; i++){		e := exps[i];		(v, w) := e.val();		if(e.kind() == Tslice)			parray(e, depth);		else{			pval(e, v, w, depth);			stdout.puts(", ");		}	}} plist(exp: ref Exp, v: string, w: int, depth: int){	while(w && v != "nil"){		exps := exp.expand();		h := getname(exps, "hd");		if(h == nil)			break;		(hv, vw) := h.val();		if(pref(v) == 0)			return;		stdout.puts(v+"(");		pval(h, hv, vw, depth);		stdout.puts(") :: ");		h = nil;		exp = getname(exps, "tl");		(v, w) = exp.val();	}	stdout.puts("nil");} pgenval(exp: ref Exp, v: string, w: int, depth: int){	if(w){		exps := exp.expand();		if(len exps == 0)			stdout.puts(v);		else{			stdout.puts(v+"{\n");		# }			if (len exps > 0){				if(depth >= maxrecur){					indent(depth);					stdout.puts(sys->sprint("...[%d]\n", len exps));				}else{					for (i := 0; i < len exps; i++){						indent(depth+1);						pname(exps[i], depth+1, nil);						stdout.puts("\n");					}				}			}			indent(depth);		# {			stdout.puts("}");		}	}else		stdout.puts(v);} symname(exp: ref Exp): string{	if(showsource == 0)		return exp.name;	return exp.name+"["+srcstr(exp.src())+"]";} indent(n: int){	while(n-- > 0)		stdout.putc('\t');} ref2int(v: string): int{	if(v == nil)		error("bad empty value for ref");	i := 0;	n := len v;	if(v[0] == '@')		i = 1;	else{		# skip array bounds		if(v[0] == '['){			for(; i < n && v[i] != ']'; i++)				;			if(i >= n - 2 || v[i+1] != ' ' || v[i+2] != '@')				error("bad value for ref: "+v);			i += 3;		}	}	if(n - i > 8)		error("64-bit pointers?");	p := 0;	for(; i < n; i++){		c := v[i];		case c {		'0' to '9' =>			p = (p << 4) + (c - '0');		'a' to 'f' =>			p = (p << 4) + (c - 'a' + 10);		* =>			error("bad value for ref: "+v);		}	}	return p;} pref(v: string): int{	if(v == "nil"){		stdout.puts("nil");		return 0;	}	if(addref(ref2int(v)) == 0){		stdout.puts(v);		stdout.puts("(qv)");		return 0;	}	return 1;} # hash table implementation that tries to be reasonably# parsimonious on memory usage.addref(v: int): int{	slot := (v & 16r7fffffff) % len hasht;	(n, a) := hasht[slot];	for(i := 0; i < n; i++)		if(a[i] == v)			return 0;	if(n == len a){		if(n == 0)			n = 3;		t := array[n*3/2] of int;		t[0:] = a;		hasht[slot].t1 = t;		a = t;	}	a[hasht[slot].t0++] = v;	return 1;} error(e: string){	sys->fprint(sys->fildes(2), "stackv: error: %s\n", e);

Lines 1–500 of 502.