shithub: purgatorio

ref: 3efb5bbb4061056e523858b134c555949591efe2
dir: /appl/cmd/limbo/sbl.b/

View raw version

sbltname := array[Tend] of
{
	Tnone =>	byte 'n',
	Tadt =>		byte 'a',
	Tadtpick =>	byte 'a',
	Tarray =>	byte 'A',
	Tbig =>		byte 'B',
	Tbyte =>	byte 'b',
	Tchan =>	byte 'C',
	Treal =>	byte 'f',
	Tfn =>		byte 'F',
	Tint =>		byte 'i',
	Tlist =>	byte 'L',
	Tmodule =>	byte 'm',
	Tref =>		byte 'R',
	Tstring =>	byte 's',
	Ttuple =>	byte 't',
	Texception => byte 't',
	Tfix => byte 'i',
	Tpoly => byte 'P',

	Tainit =>	byte '?',
	Talt =>		byte '?',
	Tany =>		byte 'N',
	Tarrow =>	byte '?',
	Tcase =>	byte '?',
	Tcasel =>	byte '?',
	Tcasec =>	byte '?',
	Tdot =>		byte '?',
	Terror =>	byte '?',
	Tgoto =>	byte '?',
	Tid =>		byte '?',
	Tiface =>	byte '?',
	Texcept => byte '?',
	Tinst => byte '?',
};
sbltadtpick:	con byte 'p';

sfiles:		ref Sym;
ftail:		ref Sym;
nsfiles:	int;
blockid:	int;
lastf:		int;
lastline:	int;

MAXSBLINT:	con 12;
MAXSBLSRC:	con 6*(MAXSBLINT+1);

sblmod(m: ref Decl)
{
	bsym.puts("limbo .sbl 2.1\n");
	bsym.puts(m.sym.name);
	bsym.putb(byte '\n');

	blockid = 0;
	nsfiles = 0;
	sfiles = ftail = nil;
	lastf = 0;
	lastline = 0;
}

sblfile(name: string): int
{
	i := 0;
	for(s := sfiles; s != nil; s = s.next){
		if(s.name == name)
			return i;
		i++;
	}
	s = ref Sym;
	s.name = name;
	s.next = nil;
	if(sfiles == nil)
		sfiles = s;
	else
		ftail.next = s;
	ftail = s;
	nsfiles = i + 1;
	return i;
}

filename(s: string): string
{
	(nil, file) := str->splitr(s, "/ \\");
	return file;
}

sblfiles()
{
	for(i := 0; i < nfiles; i++)
		files[i].sbl = sblfile(files[i].name);
	bsym.puts(string nsfiles);
	bsym.putb(byte '\n');
	for(s := sfiles; s != nil; s = s.next){
		bsym.puts(filename(s.name));
		bsym.putb(byte '\n');
	}
}

sblint(buf: array of byte, off, v: int): int
{
	if(v == 0){
		buf[off++] = byte '0';
		return off;
	}
	stop := off + MAXSBLINT;
	if(v < 0){
		buf[off++] = byte '-';
		v = -v;
	}
	n := stop;
	while(v > 0){
		buf[n -= 1] = byte(v % 10 + '0');
		v = v / 10;
	}
	while(n < stop)
		buf[off++] = buf[n++];
	return off;
}

sblsrcconvb(buf: array of byte, off: int, src: Src): int
{
	(startf, startl) := fline(src.start >> PosBits);
	(stopf, stopl) := fline(src.stop >> PosBits);
	if(lastf != startf.sbl){
		off = sblint(buf, off, startf.sbl);
		buf[off++] = byte ':';
	}
	if(lastline != startl){
		off = sblint(buf, off, startl);
		buf[off++] = byte '.';
	}
	off = sblint(buf, off, (src.start & PosMask));
	buf[off++] = byte ',';
	if(startf.sbl != stopf.sbl){
		off = sblint(buf, off, stopf.sbl);
		buf[off++] = byte ':';
	}
	if(startl != stopl){
		off = sblint(buf, off, stopl);
		buf[off++] = byte '.';
	}
	off = sblint(buf, off, (src.stop & PosMask));
	buf[off++] = byte ' ';
	lastf = stopf.sbl;
	lastline = stopl;
	return off;
}

sblsrcconv(src: Src): string
{
	s := "";
	(startf, startl) := fline(src.start >> PosBits);
	(stopf, stopl) := fline(src.stop >> PosBits);
	if(lastf != startf.sbl){
		s += string startf.sbl;
		s[len s] = ':';
	}
	if(lastline != startl){
		s += string startl;
		s[len s] = '.';
	}
	s += string (src.start & PosMask);
	s[len s] = ',';
	if(startf.sbl != stopf.sbl){
		s += string stopf.sbl;
		s[len s] = ':';
	}
	if(startl != stopl){
		s += string stopl;
		s[len s] = '.';
	}
	s += string (src.stop & PosMask);
	s[len s] = ' ';
	lastf = stopf.sbl;
	lastline = stopl;
	return s;
}

isnilsrc(s: Src): int
{
	return s.start == 0 && s.stop == 0;
}

isnilstopsrc(s: Src): int
{
	return s.stop == 0;
}

sblinst(in: ref Inst, ninst: int)
{
	src: Src;

	MAXSBL:	con 8*1024;
	buf := array[MAXSBL] of byte;
	n := 0;
	bsym.puts(string ninst);
	bsym.putb(byte '\n');
	sblblocks := array[nblocks] of {* => -1};
	for(; in != nil; in = in.next){
		if(in.op == INOOP)
			continue;
		if(in.src.start < 0)
			fatal("no file specified for "+instconv(in));
		if(n >= (MAXSBL - MAXSBLSRC - MAXSBLINT - 1)){
			bsym.write(buf, n);
			n = 0;
		}
		if(isnilsrc(in.src))
			in.src = src;
		else if(isnilstopsrc(in.src)){	# how does this happen ?
			in.src.stop = in.src.start;
			in.src.stop++;
		}
		n = sblsrcconvb(buf, n, in.src);
		src = in.src;
		b := sblblocks[in.block];
		if(b < 0)
			sblblocks[in.block] = b = blockid++;
		n = sblint(buf, n, b);
		buf[n++] = byte '\n';
	}
	if(n > 0)
		bsym.write(buf, n);
}

sblty(tys: array of ref Decl, ntys: int)
{
	bsym.puts(string ntys);
	bsym.putb(byte '\n');
	for(i := 0; i < ntys; i++){
		d := tys[i];
		d.ty.sbl = i;
	}
	for(i = 0; i < ntys; i++){
		d := tys[i];
		sbltype(d.ty, 1);
	}
}

sblfn(fns: array of ref Decl, nfns: int)
{
	bsym.puts(string nfns);
	bsym.putb(byte '\n');
	for(i := 0; i < nfns; i++){
		f := fns[i];
		if(ispoly(f))
			rmfnptrs(f);
		bsym.puts(string f.pc.pc);
		bsym.putb(byte ':');
		if(f.dot != nil && f.dot.ty.kind == Tadt){
			bsym.puts(f.dot.sym.name);
			bsym.putb(byte '.');
		}
		bsym.puts(f.sym.name);
		bsym.putb(byte '\n');
		sbldecl(f.ty.ids, Darg);
		sbldecl(f.locals, Dlocal);
		sbltype(f.ty.tof, 0);
	}
}

sblvar(vars: ref Decl)
{
	sbldecl(vars, Dglobal);
}

isvis(id: ref Decl): int
{
	if(!tattr[id.ty.kind].vis
	|| id.sym == nil
	|| id.sym.name == ""
	|| id.sym.name[0] == '.')
		return 0;
	if(id.ty == tstring && id.init != nil && id.init.op == Oconst)
		return 0;
	if(id.src.start < 0 || id.src.stop < 0)
		return 0;
	return 1;
}

sbldecl(ids: ref Decl, store: int)
{
	n := 0;
	for(id := ids; id != nil; id = id.next){
		if(id.store != store || !isvis(id))
			continue;
		n++;
	}
	bsym.puts(string n);
	bsym.putb(byte '\n');
	for(id = ids; id != nil; id = id.next){
		if(id.store != store || !isvis(id))
			continue;
		bsym.puts(string id.offset);
		bsym.putb(byte ':');
		bsym.puts(id.sym.name);
		bsym.putb(byte ':');
		bsym.puts(sblsrcconv(id.src));
		sbltype(id.ty, 0);
		bsym.putb(byte '\n');
	}
}

sbltype(t: ref Type, force: int)
{
	if(t.kind == Tadtpick)
		t = t.decl.dot.ty;

	d := t.decl;
	if(!force && d != nil && d.ty.sbl >= 0){
		bsym.putb(byte '@');
		bsym.puts(string d.ty.sbl);
		bsym.putb(byte '\n');
		return;
	}

	if(t.rec != byte 0)
		fatal("recursive sbl type: "+typeconv(t));

	t.rec = byte 1;
	case t.kind{
	* =>
		fatal("bad type in sbltype: "+typeconv(t));
	Tnone or
	Tany or
	Tint or
	Tbig or
	Tbyte or
	Treal or
	Tstring or
	Tfix or
	Tpoly =>
		bsym.putb(sbltname[t.kind]);
	Tfn =>
		bsym.putb(sbltname[t.kind]);
		sbldecl(t.ids, Darg);
		sbltype(t.tof, 0);
	Tarray or
	Tlist or
	Tchan or
	Tref =>
		bsym.putb(sbltname[t.kind]);
		if(t.kind == Tref && t.tof.kind == Tfn){
			tattr[Tany].vis = 1;
			sbltype(tfnptr, 0);
			tattr[Tany].vis = 0;
		}
		else
			sbltype(t.tof, 0);
	Ttuple or
	Texception =>
		bsym.putb(sbltname[t.kind]);
		bsym.puts(string t.size);
		bsym.putb(byte '.');
		sbldecl(t.ids, Dfield);
	Tadt =>
		if(t.tags != nil)
			bsym.putb(sbltadtpick);
		else
			bsym.putb(sbltname[t.kind]);
		if(d.dot != nil && !isimpmod(d.dot.sym))
			bsym.puts(d.dot.sym.name + "->");
		bsym.puts(d.sym.name);
		bsym.putb(byte ' ');
		bsym.puts(sblsrcconv(d.src));
		bsym.puts(string d.ty.size);
		bsym.putb(byte '\n');
		sbldecl(t.ids, Dfield);
		if(t.tags != nil){
			bsym.puts(string t.decl.tag);
			bsym.putb(byte '\n');
			lastt : ref Type = nil;
			for(tg := t.tags; tg != nil; tg = tg.next){
				bsym.puts(tg.sym.name);
				bsym.putb(byte ':');
				bsym.puts(sblsrcconv(tg.src));
				if(lastt == tg.ty){
					bsym.putb(byte '\n');
				}else{
					bsym.puts(string tg.ty.size);
					bsym.putb(byte '\n');
					sbldecl(tg.ty.ids, Dfield);
				}
				lastt = tg.ty;
			}
		}
	Tmodule =>
		bsym.putb(sbltname[t.kind]);
		bsym.puts(d.sym.name);
		bsym.putb(byte '\n');
		bsym.puts(sblsrcconv(d.src));
		sbldecl(t.ids, Dglobal);
	}
	t.rec = byte 0;
}