xref: /inferno-os/appl/cmd/stackv.b (revision 99c84fef96ccd10bb6cabb823384c033090293e9)
137da2899SCharles.Forsythimplement Stackv;
237da2899SCharles.Forsyth
337da2899SCharles.Forsythinclude "sys.m";
437da2899SCharles.Forsyth	sys: Sys;
537da2899SCharles.Forsythinclude "draw.m";
637da2899SCharles.Forsythinclude "debug.m";
737da2899SCharles.Forsyth	debug: Debug;
837da2899SCharles.Forsyth	Prog, Module, Exp: import debug;
937da2899SCharles.Forsyth	Tadt, Tarray, Tbig, Tbyte, Treal,
1037da2899SCharles.Forsyth	Tfn, Tint, Tlist,
1137da2899SCharles.Forsyth	Tref, Tstring, Tslice: import Debug;
1237da2899SCharles.Forsythinclude "arg.m";
1337da2899SCharles.Forsythinclude "bufio.m";
1437da2899SCharles.Forsyth	bufio: Bufio;
1537da2899SCharles.Forsyth	Iobuf: import bufio;
1637da2899SCharles.Forsyth
1737da2899SCharles.Forsythstderr: ref Sys->FD;
1837da2899SCharles.Forsythstdout: ref Iobuf;
1966f5808bSforsyth
2066f5808bSforsythhasht := array[97] of (int, array of int);
2137da2899SCharles.Forsyth
2237da2899SCharles.ForsythStackv: module {
2337da2899SCharles.Forsyth	init: fn(ctxt: ref Draw->Context, argv: list of string);
2437da2899SCharles.Forsyth};
2537da2899SCharles.Forsyth
2637da2899SCharles.Forsythmaxrecur := 16r7ffffffe;
2737da2899SCharles.Forsyth
2837da2899SCharles.Forsythbadmodule(p: string)
2937da2899SCharles.Forsyth{
3037da2899SCharles.Forsyth	sys->fprint(stderr, "stackv: cannot load %q: %r\n", p);
3137da2899SCharles.Forsyth	raise "fail:bad module";
3237da2899SCharles.Forsyth}
3337da2899SCharles.Forsyth
3437da2899SCharles.Forsythcurrp: ref Prog;
3537da2899SCharles.Forsythshowtypes := 1;
3637da2899SCharles.Forsythshowsource := 0;
3766f5808bSforsythshowmodule := 0;
3837da2899SCharles.Forsyth
3937da2899SCharles.Forsythinit(nil: ref Draw->Context, argv: list of string)
4037da2899SCharles.Forsyth{
4137da2899SCharles.Forsyth
4237da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
4337da2899SCharles.Forsyth	stderr = sys->fildes(2);
4437da2899SCharles.Forsyth	debug = load Debug Debug->PATH;
4537da2899SCharles.Forsyth	if(debug == nil)
4637da2899SCharles.Forsyth		badmodule(Debug->PATH);
4737da2899SCharles.Forsyth	bufio = load Bufio Bufio->PATH;
4837da2899SCharles.Forsyth	if (bufio == nil)
4937da2899SCharles.Forsyth		badmodule(Bufio->PATH);
5037da2899SCharles.Forsyth	arg := load Arg Arg->PATH;
5137da2899SCharles.Forsyth	if (arg == nil)
5237da2899SCharles.Forsyth		badmodule(Arg->PATH);
5337da2899SCharles.Forsyth	stdout = bufio->fopen(sys->fildes(1), Sys->OWRITE);
5437da2899SCharles.Forsyth
5537da2899SCharles.Forsyth	arg->init(argv);
5666f5808bSforsyth	arg->setusage("stackv [-Tlm] [-r maxdepth] [-s dis sbl]... [pid[.sym]...] ...");
5737da2899SCharles.Forsyth	sblfile := "";
5837da2899SCharles.Forsyth	while((opt := arg->opt()) != 0){
5937da2899SCharles.Forsyth		case opt {
6037da2899SCharles.Forsyth		's' =>
6137da2899SCharles.Forsyth			arg->earg();	# XXX make it a list of maps from dis to sbl later
6237da2899SCharles.Forsyth			sblfile = arg->earg();
6337da2899SCharles.Forsyth		'l' =>
6437da2899SCharles.Forsyth			showsource = 1;
6566f5808bSforsyth		'm' =>
6666f5808bSforsyth			showmodule = 1;
6737da2899SCharles.Forsyth		'r' =>
6837da2899SCharles.Forsyth			maxrecur = int arg->earg();
6937da2899SCharles.Forsyth		'T' =>
7037da2899SCharles.Forsyth			showtypes = 0;
7137da2899SCharles.Forsyth		* =>
7237da2899SCharles.Forsyth			arg->usage();
7337da2899SCharles.Forsyth		}
7437da2899SCharles.Forsyth	}
7537da2899SCharles.Forsyth	debug->init();
7637da2899SCharles.Forsyth	argv = arg->argv();
7737da2899SCharles.Forsyth	printpids := len argv > 1;
7837da2899SCharles.Forsyth	if(printpids)
7937da2899SCharles.Forsyth		maxrecur++;
8037da2899SCharles.Forsyth	for(; argv != nil; argv = tl argv)
8137da2899SCharles.Forsyth		db(sys->tokenize(hd argv, ".").t1, printpids);
8237da2899SCharles.Forsyth}
8337da2899SCharles.Forsyth
8437da2899SCharles.Forsythdb(toks: list of string, printpid: int): int
8537da2899SCharles.Forsyth{
8637da2899SCharles.Forsyth	if(toks == nil){
8737da2899SCharles.Forsyth		sys->fprint(stderr, "stackv: bad pid\n");
8837da2899SCharles.Forsyth		return -1;
8937da2899SCharles.Forsyth	}
9037da2899SCharles.Forsyth	if((pid := int hd toks) <= 0){
9137da2899SCharles.Forsyth		sys->fprint(stderr, "stackv: bad pid %q\n", hd toks);
9237da2899SCharles.Forsyth		return -1;
9337da2899SCharles.Forsyth	}
9437da2899SCharles.Forsyth	err: string;
9537da2899SCharles.Forsyth	p: ref Prog;
9637da2899SCharles.Forsyth
9737da2899SCharles.Forsyth	# reuse process if possible
9837da2899SCharles.Forsyth	if(currp == nil || currp.id != pid){
9937da2899SCharles.Forsyth		(currp, err) = debug->prog(pid);
10037da2899SCharles.Forsyth		if(err != nil){
10137da2899SCharles.Forsyth			sys->fprint(stderr, "stackv: %s\n", err);
10237da2899SCharles.Forsyth			return -1;
10337da2899SCharles.Forsyth		}
10437da2899SCharles.Forsyth		if(currp == nil){
10537da2899SCharles.Forsyth			sys->fprint(stderr, "stackv: nil prog from pid %d\n", pid);
10637da2899SCharles.Forsyth			return -1;
10737da2899SCharles.Forsyth		}
10837da2899SCharles.Forsyth	}
10937da2899SCharles.Forsyth	p = currp;
11037da2899SCharles.Forsyth	stk: array of ref Exp;
11137da2899SCharles.Forsyth	(stk, err) = p.stack();
11237da2899SCharles.Forsyth	if(err != nil){
11337da2899SCharles.Forsyth		sys->fprint(stderr, "stackv: %s\n", err);
11437da2899SCharles.Forsyth		return -1;
11537da2899SCharles.Forsyth	}
11637da2899SCharles.Forsyth	for (i := 0; i < len stk; i++) {
11737da2899SCharles.Forsyth		stk[i].m.stdsym();
11837da2899SCharles.Forsyth		stk[i].findsym();
11937da2899SCharles.Forsyth	}
12037da2899SCharles.Forsyth	depth := 0;
12137da2899SCharles.Forsyth	if(printpid){
12237da2899SCharles.Forsyth		stdout.puts(sys->sprint("prog %d {\n", pid));	# }
12337da2899SCharles.Forsyth		depth++;
12437da2899SCharles.Forsyth	}
12537da2899SCharles.Forsyth	pexp(stk, tl toks, depth);
12637da2899SCharles.Forsyth	if(printpid)
12737da2899SCharles.Forsyth		stdout.puts("}\n");
12837da2899SCharles.Forsyth	stdout.flush();
12937da2899SCharles.Forsyth	return 0;
13037da2899SCharles.Forsyth}
13137da2899SCharles.Forsyth
13237da2899SCharles.Forsythpexp(stk: array of ref Exp, toks: list of string, depth: int)
13337da2899SCharles.Forsyth{
13437da2899SCharles.Forsyth	if(toks == nil){
13537da2899SCharles.Forsyth		for (i := 0; i < len stk; i++)
13637da2899SCharles.Forsyth			pfn(stk[i], depth);
13737da2899SCharles.Forsyth	}else{
13837da2899SCharles.Forsyth		exp := stackfindsym(stk, toks, depth);
13937da2899SCharles.Forsyth		if(exp == nil)
14037da2899SCharles.Forsyth			return;
14166f5808bSforsyth		pname(exp, depth, nil);
14237da2899SCharles.Forsyth		stdout.putc('\n');
14337da2899SCharles.Forsyth	}
14437da2899SCharles.Forsyth}
14537da2899SCharles.Forsyth
14637da2899SCharles.Forsythstackfindsym(stk: array of ref Exp, toks: list of string, depth: int): ref Exp
14737da2899SCharles.Forsyth{
14837da2899SCharles.Forsyth	fname := hd toks;
14937da2899SCharles.Forsyth	toks = tl toks;
15037da2899SCharles.Forsyth	for(i := 0; i < len stk; i++){
15137da2899SCharles.Forsyth		s := stk[i].name;
15237da2899SCharles.Forsyth		if(s == fname)
15337da2899SCharles.Forsyth			break;
15437da2899SCharles.Forsyth		if(hasdot(s) && toks != nil && s == fname+"."+hd toks){
15537da2899SCharles.Forsyth			fname += "."+hd toks;
15637da2899SCharles.Forsyth			toks = tl toks;
15737da2899SCharles.Forsyth			break;
15837da2899SCharles.Forsyth		}
15937da2899SCharles.Forsyth	}
16037da2899SCharles.Forsyth	if(i == len stk){
16137da2899SCharles.Forsyth		indent(depth);
16237da2899SCharles.Forsyth		stdout.puts("function not found\n");
16337da2899SCharles.Forsyth		return nil;
16437da2899SCharles.Forsyth	}
16537da2899SCharles.Forsyth	if(toks == nil)
16637da2899SCharles.Forsyth		return stk[i];
16737da2899SCharles.Forsyth	stk = stk[i].expand();
16837da2899SCharles.Forsyth	if(hd toks == "module"){
16937da2899SCharles.Forsyth		if((e := getname(stk, "module")) == nil){
17037da2899SCharles.Forsyth			indent(depth);
17137da2899SCharles.Forsyth			stdout.puts(sys->sprint("no module declarations in function %q\n", fname));
17237da2899SCharles.Forsyth		}else if((e = symfindsym(e, tl toks, depth)) != nil)
17337da2899SCharles.Forsyth			return e;
17437da2899SCharles.Forsyth		return nil;
17537da2899SCharles.Forsyth	}
17637da2899SCharles.Forsyth	for(t := "locals" :: "args" :: "module" :: nil; t != nil; t = tl t){
17737da2899SCharles.Forsyth		if((e := getname(stk, hd t)) == nil)
17837da2899SCharles.Forsyth			continue;
17937da2899SCharles.Forsyth		if((e = symfindsym(e, toks, depth)) != nil)
18037da2899SCharles.Forsyth			return e;
18137da2899SCharles.Forsyth	}
18237da2899SCharles.Forsyth	indent(depth);
18337da2899SCharles.Forsyth	stdout.puts(sys->sprint("symbol %q not found in function %q\n", hd toks, fname));
18437da2899SCharles.Forsyth	return nil;
18537da2899SCharles.Forsyth}
18637da2899SCharles.Forsyth
18737da2899SCharles.Forsythhasdot(s: string): int
18837da2899SCharles.Forsyth{
18937da2899SCharles.Forsyth	for(i := 0; i < len s; i++)
19037da2899SCharles.Forsyth		if(s[i] == '.')
19137da2899SCharles.Forsyth			return 1;
19237da2899SCharles.Forsyth	return 0;
19337da2899SCharles.Forsyth}
19437da2899SCharles.Forsyth
19537da2899SCharles.Forsythsymfindsym(e: ref Exp, toks: list of string, depth: int): ref Exp
19637da2899SCharles.Forsyth{
19737da2899SCharles.Forsyth	if(toks == nil)
19837da2899SCharles.Forsyth		return e;
19937da2899SCharles.Forsyth	exps := e.expand();
20037da2899SCharles.Forsyth	for(i := 0; i < len exps; i++)
20137da2899SCharles.Forsyth		if(exps[i].name == hd toks)
20237da2899SCharles.Forsyth			return symfindsym(exps[i], tl toks, depth);
20337da2899SCharles.Forsyth	return nil;
20437da2899SCharles.Forsyth}
20537da2899SCharles.Forsyth
20637da2899SCharles.Forsythpfn(exp: ref Exp, depth: int)
20737da2899SCharles.Forsyth{
20837da2899SCharles.Forsyth	(v, w) := exp.val();
20937da2899SCharles.Forsyth	if(!w || v == nil){
21037da2899SCharles.Forsyth		indent(depth);
21137da2899SCharles.Forsyth		stdout.puts(sys->sprint("no value for fn %q\n", exp.name));
21237da2899SCharles.Forsyth		return;
21337da2899SCharles.Forsyth	}
21437da2899SCharles.Forsyth	exps := exp.expand();
21537da2899SCharles.Forsyth	indent(depth);
21637da2899SCharles.Forsyth	stdout.puts("["+exp.srcstr()+"]\n");
21737da2899SCharles.Forsyth	indent(depth);
21837da2899SCharles.Forsyth	stdout.puts(symname(exp)+"(");
21937da2899SCharles.Forsyth	if((e := getname(exps, "args")) != nil){
22037da2899SCharles.Forsyth		args := e.expand();
22137da2899SCharles.Forsyth		for(i := 0; i < len args; i++){
22266f5808bSforsyth			pname(args[i], depth+1, nil);
22337da2899SCharles.Forsyth			if(i != len args - 1)
22437da2899SCharles.Forsyth				stdout.puts(", ");
22537da2899SCharles.Forsyth		}
22637da2899SCharles.Forsyth	}
22737da2899SCharles.Forsyth	stdout.puts(")\n");
22837da2899SCharles.Forsyth	indent(depth);
22937da2899SCharles.Forsyth	stdout.puts("{\n");	# }
23037da2899SCharles.Forsyth	if((e = getname(exps, "locals")) != nil){
23137da2899SCharles.Forsyth		locals := e.expand();
23237da2899SCharles.Forsyth		for(i := 0; i < len locals; i++){
23337da2899SCharles.Forsyth			indent(depth+1);
23466f5808bSforsyth			pname(locals[i], depth+1, nil);
23566f5808bSforsyth			stdout.puts("\n");
23666f5808bSforsyth		}
23766f5808bSforsyth	}
23866f5808bSforsyth	if(showmodule && (e = getname(exps, "module")) != nil){
23966f5808bSforsyth		mvars := e.expand();
24066f5808bSforsyth		for(i := 0; i < len mvars; i++){
24166f5808bSforsyth			indent(depth+1);
24266f5808bSforsyth			pname(mvars[i], depth+1, "module.");
24337da2899SCharles.Forsyth			stdout.puts("\n");
24437da2899SCharles.Forsyth		}
24537da2899SCharles.Forsyth	}
24637da2899SCharles.Forsyth	indent(depth);
24737da2899SCharles.Forsyth	stdout.puts("}\n");
24837da2899SCharles.Forsyth}
24937da2899SCharles.Forsyth
25037da2899SCharles.Forsythgetname(exps: array of ref Exp, name: string): ref Exp
25137da2899SCharles.Forsyth{
25237da2899SCharles.Forsyth	for(i := 0; i < len exps; i++)
25337da2899SCharles.Forsyth		if(exps[i].name == name)
25437da2899SCharles.Forsyth			return exps[i];
25537da2899SCharles.Forsyth	return nil;
25637da2899SCharles.Forsyth}
25737da2899SCharles.Forsyth
25837da2899SCharles.Forsythstrval(v: string): string
25937da2899SCharles.Forsyth{
26037da2899SCharles.Forsyth	for(i := 0; i < len v; i++)
26137da2899SCharles.Forsyth		if(v[i] == '"')
26237da2899SCharles.Forsyth			break;
26337da2899SCharles.Forsyth	if(i < len v)
26437da2899SCharles.Forsyth		v = v[i:];
26537da2899SCharles.Forsyth	return v;
26637da2899SCharles.Forsyth}
26737da2899SCharles.Forsyth
26866f5808bSforsythpname(exp: ref Exp, depth: int, prefix: string)
26937da2899SCharles.Forsyth{
27066f5808bSforsyth	name := prefix+symname(exp);
27137da2899SCharles.Forsyth	(v, w) := exp.val();
27237da2899SCharles.Forsyth	if (!w && v == nil) {
27337da2899SCharles.Forsyth		stdout.puts(sys->sprint("%s: %s = novalue", symname(exp), exp.typename()));
27437da2899SCharles.Forsyth		return;
27537da2899SCharles.Forsyth	}
27637da2899SCharles.Forsyth	case exp.kind() {
27737da2899SCharles.Forsyth	Tfn =>
27837da2899SCharles.Forsyth		pfn(exp, depth);
27937da2899SCharles.Forsyth	Tint =>
28066f5808bSforsyth		stdout.puts(sys->sprint("%s := %s", name, v));
28137da2899SCharles.Forsyth	Tstring =>
28266f5808bSforsyth		stdout.puts(sys->sprint("%s := %s", name, strval(v)));
28337da2899SCharles.Forsyth	Tbyte or
28437da2899SCharles.Forsyth	Tbig or
28537da2899SCharles.Forsyth	Treal =>
28666f5808bSforsyth		stdout.puts(sys->sprint("%s := %s %s", name, exp.typename(), v));
28737da2899SCharles.Forsyth	* =>
28837da2899SCharles.Forsyth		if(showtypes)
28966f5808bSforsyth			stdout.puts(sys->sprint("%s: %s = ", name, exp.typename()));
29037da2899SCharles.Forsyth		else
29166f5808bSforsyth			stdout.puts(sys->sprint("%s := ", name));
29237da2899SCharles.Forsyth		pval(exp, v, w, depth);
29337da2899SCharles.Forsyth	}
29437da2899SCharles.Forsyth}
29537da2899SCharles.Forsyth
29637da2899SCharles.Forsythsrcstr(src: ref Debug->Src): string
29737da2899SCharles.Forsyth{
29837da2899SCharles.Forsyth	if(src == nil)
29937da2899SCharles.Forsyth		return nil;
30037da2899SCharles.Forsyth	if(src.start.file != src.stop.file)
30137da2899SCharles.Forsyth		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);
30237da2899SCharles.Forsyth	if(src.start.line != src.stop.line)
30337da2899SCharles.Forsyth		return sys->sprint("%q:%d.%d,%d.%d", src.start.file, src.start.line, src.start.pos, src.stop.line, src.stop.pos);
30437da2899SCharles.Forsyth	return sys->sprint("%q:%d.%d,%d", src.start.file, src.start.line, src.start.pos, src.stop.pos);
30537da2899SCharles.Forsyth}
30637da2899SCharles.Forsyth
30737da2899SCharles.Forsythpval(exp: ref Exp, v: string, w: int, depth: int)
30837da2899SCharles.Forsyth{
30937da2899SCharles.Forsyth	if(depth >= maxrecur){
31037da2899SCharles.Forsyth		stdout.puts(v);
31137da2899SCharles.Forsyth		return;
31237da2899SCharles.Forsyth	}
31337da2899SCharles.Forsyth	case exp.kind() {
31437da2899SCharles.Forsyth	Tarray =>
31537da2899SCharles.Forsyth		if(pref(v)){
31637da2899SCharles.Forsyth			if(depth+1 >= maxrecur)
31737da2899SCharles.Forsyth				stdout.puts(v+"{...}");
31837da2899SCharles.Forsyth			else{
31937da2899SCharles.Forsyth				stdout.puts(v+"{\n");
32037da2899SCharles.Forsyth				indent(depth+1);
32137da2899SCharles.Forsyth				parray(exp, depth+1);
32237da2899SCharles.Forsyth				stdout.puts("\n");
32337da2899SCharles.Forsyth				indent(depth);
32437da2899SCharles.Forsyth				stdout.puts("}");
32537da2899SCharles.Forsyth			}
32637da2899SCharles.Forsyth		}
32737da2899SCharles.Forsyth	Tlist =>
32837da2899SCharles.Forsyth		if(v == "nil")
32937da2899SCharles.Forsyth			stdout.puts("nil");
33037da2899SCharles.Forsyth		else
33137da2899SCharles.Forsyth		if(depth+1 >= maxrecur)
33237da2899SCharles.Forsyth			stdout.puts(v+"{...}");
33337da2899SCharles.Forsyth		else{
33437da2899SCharles.Forsyth			stdout.puts("{\n");
33537da2899SCharles.Forsyth			indent(depth+1);
33637da2899SCharles.Forsyth			plist(exp, v, w, depth+1);
33737da2899SCharles.Forsyth			stdout.puts("\n");
33837da2899SCharles.Forsyth			indent(depth);
33937da2899SCharles.Forsyth			stdout.puts("}");
34037da2899SCharles.Forsyth		}
34137da2899SCharles.Forsyth	Tadt =>
34237da2899SCharles.Forsyth		pgenval(exp, nil, w, depth);
34337da2899SCharles.Forsyth	Tref =>
34437da2899SCharles.Forsyth		if(pref(v))
34537da2899SCharles.Forsyth			pgenval(exp, v, w, depth);
34637da2899SCharles.Forsyth	Tstring =>
34737da2899SCharles.Forsyth		stdout.puts(strval(v));
34837da2899SCharles.Forsyth	* =>
34937da2899SCharles.Forsyth		pgenval(exp, v, w, depth);
35037da2899SCharles.Forsyth	}
35137da2899SCharles.Forsyth}
35237da2899SCharles.Forsyth
35337da2899SCharles.Forsythparray(exp: ref Exp, depth: int)
35437da2899SCharles.Forsyth{
35537da2899SCharles.Forsyth	exps := exp.expand();
35637da2899SCharles.Forsyth	for(i := 0; i < len exps; i++){
35737da2899SCharles.Forsyth		e := exps[i];
35837da2899SCharles.Forsyth		(v, w) := e.val();
35937da2899SCharles.Forsyth		if(e.kind() == Tslice)
36037da2899SCharles.Forsyth			parray(e, depth);
36137da2899SCharles.Forsyth		else{
36237da2899SCharles.Forsyth			pval(e, v, w, depth);
36337da2899SCharles.Forsyth			stdout.puts(", ");
36437da2899SCharles.Forsyth		}
36537da2899SCharles.Forsyth	}
36637da2899SCharles.Forsyth}
36737da2899SCharles.Forsyth
36837da2899SCharles.Forsythplist(exp: ref Exp, v: string, w: int, depth: int)
36937da2899SCharles.Forsyth{
37037da2899SCharles.Forsyth	while(w && v != "nil"){
37137da2899SCharles.Forsyth		exps := exp.expand();
37237da2899SCharles.Forsyth		h := getname(exps, "hd");
3733f1f06c5SCharles.Forsyth		if(h == nil)
3743f1f06c5SCharles.Forsyth			break;
37537da2899SCharles.Forsyth		(hv, vw) := h.val();
37637da2899SCharles.Forsyth		if(pref(v) == 0)
37737da2899SCharles.Forsyth			return;
37837da2899SCharles.Forsyth		stdout.puts(v+"(");
37937da2899SCharles.Forsyth		pval(h, hv, vw, depth);
38037da2899SCharles.Forsyth		stdout.puts(") :: ");
38137da2899SCharles.Forsyth		h = nil;
38237da2899SCharles.Forsyth		exp = getname(exps, "tl");
38337da2899SCharles.Forsyth		(v, w) = exp.val();
38437da2899SCharles.Forsyth	}
38537da2899SCharles.Forsyth	stdout.puts("nil");
38637da2899SCharles.Forsyth}
38737da2899SCharles.Forsyth
38837da2899SCharles.Forsythpgenval(exp: ref Exp, v: string, w: int, depth: int)
38937da2899SCharles.Forsyth{
39037da2899SCharles.Forsyth	if(w){
39137da2899SCharles.Forsyth		exps := exp.expand();
39237da2899SCharles.Forsyth		if(len exps == 0)
39337da2899SCharles.Forsyth			stdout.puts(v);
39437da2899SCharles.Forsyth		else{
39537da2899SCharles.Forsyth			stdout.puts(v+"{\n");		# }
39637da2899SCharles.Forsyth			if (len exps > 0){
39737da2899SCharles.Forsyth				if(depth >= maxrecur){
39837da2899SCharles.Forsyth					indent(depth);
39937da2899SCharles.Forsyth					stdout.puts(sys->sprint("...[%d]\n", len exps));
40037da2899SCharles.Forsyth				}else{
40137da2899SCharles.Forsyth					for (i := 0; i < len exps; i++){
40237da2899SCharles.Forsyth						indent(depth+1);
40366f5808bSforsyth						pname(exps[i], depth+1, nil);
40437da2899SCharles.Forsyth						stdout.puts("\n");
40537da2899SCharles.Forsyth					}
40637da2899SCharles.Forsyth				}
40737da2899SCharles.Forsyth			}
40837da2899SCharles.Forsyth			indent(depth);		# {
40937da2899SCharles.Forsyth			stdout.puts("}");
41037da2899SCharles.Forsyth		}
41137da2899SCharles.Forsyth	}else
41237da2899SCharles.Forsyth		stdout.puts(v);
41337da2899SCharles.Forsyth}
41437da2899SCharles.Forsyth
41537da2899SCharles.Forsythsymname(exp: ref Exp): string
41637da2899SCharles.Forsyth{
41737da2899SCharles.Forsyth	if(showsource == 0)
41837da2899SCharles.Forsyth		return exp.name;
41937da2899SCharles.Forsyth	return exp.name+"["+srcstr(exp.src())+"]";
42037da2899SCharles.Forsyth}
42137da2899SCharles.Forsyth
42237da2899SCharles.Forsythindent(n: int)
42337da2899SCharles.Forsyth{
42437da2899SCharles.Forsyth	while(n-- > 0)
42566f5808bSforsyth		stdout.putc('\t');
42666f5808bSforsyth}
42766f5808bSforsyth
42866f5808bSforsythref2int(v: string): int
42966f5808bSforsyth{
43066f5808bSforsyth	if(v == nil)
43166f5808bSforsyth		error("bad empty value for ref");
43266f5808bSforsyth	i := 0;
43366f5808bSforsyth	n := len v;
43466f5808bSforsyth	if(v[0] == '@')
43566f5808bSforsyth		i = 1;
43666f5808bSforsyth	else{
43766f5808bSforsyth		# skip array bounds
43866f5808bSforsyth		if(v[0] == '['){
43966f5808bSforsyth			for(; i < n && v[i] != ']'; i++)
44066f5808bSforsyth				;
44166f5808bSforsyth			if(i >= n - 2 || v[i+1] != ' ' || v[i+2] != '@')
44266f5808bSforsyth				error("bad value for ref: "+v);
44366f5808bSforsyth			i += 3;
44466f5808bSforsyth		}
44566f5808bSforsyth	}
44666f5808bSforsyth	if(n - i > 8)
44766f5808bSforsyth		error("64-bit pointers?");
44866f5808bSforsyth	p := 0;
44966f5808bSforsyth	for(; i < n; i++){
45066f5808bSforsyth		c := v[i];
45166f5808bSforsyth		case c {
45266f5808bSforsyth		'0' to '9' =>
45366f5808bSforsyth			p = (p << 4) + (c - '0');
45466f5808bSforsyth		'a' to 'f' =>
45566f5808bSforsyth			p = (p << 4) + (c - 'a' + 10);
45666f5808bSforsyth		* =>
45766f5808bSforsyth			error("bad value for ref: "+v);
45866f5808bSforsyth		}
45966f5808bSforsyth	}
46066f5808bSforsyth	return p;
46137da2899SCharles.Forsyth}
46237da2899SCharles.Forsyth
46337da2899SCharles.Forsythpref(v: string): int
46437da2899SCharles.Forsyth{
46566f5808bSforsyth	if(v == "nil"){
46666f5808bSforsyth		stdout.puts("nil");
46766f5808bSforsyth		return 0;
46866f5808bSforsyth	}
46966f5808bSforsyth	if(addref(ref2int(v)) == 0){
47037da2899SCharles.Forsyth		stdout.puts(v);
47137da2899SCharles.Forsyth		stdout.puts("(qv)");
47237da2899SCharles.Forsyth		return 0;
47337da2899SCharles.Forsyth	}
47437da2899SCharles.Forsyth	return 1;
47537da2899SCharles.Forsyth}
47637da2899SCharles.Forsyth
47766f5808bSforsyth# hash table implementation that tries to be reasonably
47866f5808bSforsyth# parsimonious on memory usage.
47966f5808bSforsythaddref(v: int): int
48037da2899SCharles.Forsyth{
48166f5808bSforsyth	slot := (v & 16r7fffffff) % len hasht;
48266f5808bSforsyth	(n, a) := hasht[slot];
48366f5808bSforsyth	for(i := 0; i < n; i++)
48466f5808bSforsyth		if(a[i] == v)
48537da2899SCharles.Forsyth			return 0;
48666f5808bSforsyth	if(n == len a){
48766f5808bSforsyth		if(n == 0)
48866f5808bSforsyth			n = 3;
48966f5808bSforsyth		t := array[n*3/2] of int;
49066f5808bSforsyth		t[0:] = a;
49166f5808bSforsyth		hasht[slot].t1 = t;
492*99c84fefSforsyth		a = t;
49366f5808bSforsyth	}
49466f5808bSforsyth	a[hasht[slot].t0++] = v;
49537da2899SCharles.Forsyth	return 1;
49637da2899SCharles.Forsyth}
49737da2899SCharles.Forsyth
49866f5808bSforsytherror(e: string)
49937da2899SCharles.Forsyth{
50066f5808bSforsyth	sys->fprint(sys->fildes(2), "stackv: error: %s\n", e);
50166f5808bSforsyth	raise "fail:error";
50237da2899SCharles.Forsyth}
503