Charles.Forsyth20060303a828770d19 years agoHistory
378 lines · 7.3 KB · Brainfuck
RawDownload
PPrint: adt{	ex:	ref Exec;	code:	ref Code;	stack:	array of string;	sp:	int;}; mkpprint(ex: ref Exec, code: ref Code): ref PPrint{	return ref PPrint(ex, code, array[4] of string, 0);} funcprint(ex: ref Exec, func: ref Ecmascript->Obj): string{	params := func.call.params;	(nil, name) := str->splitr(func.val.str, ".");	s := "function " + name + "(";	sep := "";	for(i := 0; i < len params; i++){		s += sep + params[i];		sep = ", ";	}	s += "){";	if(func.host != nil)		s += "[host code]";	else		s += "\n" + pprint(ex, func.call.code, "	");	s += "}";	return s;} pprint(ex: ref Exec, code: ref Code, indent: string): string{	pp := ref PPrint(ex, code, array[4] of string, 0);#for(i:=0; i < code.npc; i++) sys->print("%d: %d\n", i, int code.ops[i]);	s := pstmt(pp, 0, code.npc, indent); 	if(pp.sp != 0)		fatal(ex, "pprint stack not balanced"); 	return s;} pstmt(pp: ref PPrint, pc, epc: int, indent: string): string{	e, e1, e2: string;	c, apc: int; 	code := pp.code;	s := "";	while(pc < epc){		op := int code.ops[pc++];		while(op == Llabel){			(pc, c) = getconst(code.ops, pc);			s += code.strs[c] + ":\n";			op = int code.ops[pc++];		}		s += indent;		case op{		Lbreak or		Lcontinue or		Lreturn =>			s += tokname(op);			if(op == Lreturn){				(pc, e) = pexp(pp, pc, code.npc);				s += " " + e;			}			s += ";\n";		Lbreaklab or		Lcontinuelab =>			s += tokname(op);			(pc, c) = getconst(code.ops, pc);			s += " " + code.strs[c] + ";\n";		'{' =>			(pc, apc) = getjmp(code.ops, pc);			s += "{\n" + pstmt(pp, pc, apc, indent+"	") + indent + "}\n";			pc = apc;		Lif or		Lwith or		Lwhile =>			(pc, apc) = getjmp(code.ops, pc);			(pc, e) = pexp(pp, pc, apc);			(pc, apc) = getjmp(code.ops, pc);			s += tokname(op) + "(" + e + "){\n";			s += pstmt(pp, pc, apc, indent+"	");			if(op == Lif){				(pc, apc) = getjmp(code.ops, apc);				if(pc != apc)					s += indent + "}else{\n";				s += pstmt(pp, pc, apc, indent+"	");			}			s += indent + "}\n";			pc = apc;		Ldo =>			(pc, apc) = getjmp(code.ops, pc);			e = pstmt(pp, pc, apc, indent+"	");			(pc, apc) = getjmp(code.ops, apc);			(pc, e1) = pexp(pp, pc, apc);			s += "do{\n" + e + indent + "}(while(" + e1 + ");\n";			pc = apc;		Lfor or		Lforvar or		Lforin or		Lforvarin =>			(pc, apc) = getjmp(code.ops, pc);			(pc, e) = pexp(pp, pc, apc);			(pc, apc) = getjmp(code.ops, pc);			(pc, e1) = pexp(pp, pc, apc);			s += "for(";			if(op == Lforvar || op == Lforvarin)				s += "var ";			s += e;			if(op == Lfor || op == Lforvar){				(pc, apc) = getjmp(code.ops, pc);				(pc, e2) = pexp(pp, pc, apc);				s += "; " + e1 + "; " + e2;			}else				s += " in " + e1;			s += "){\n";			(pc, apc) = getjmp(code.ops, pc);			s += pstmt(pp, pc, apc, indent+"	");			s += indent + "}\n";			pc = apc;		';' =>			s += ";\n";		Lvar =>			(pc, apc) = getjmp(code.ops, pc);			(pc, e) = pexp(pp, pc, apc);			s += "var " + e + ";\n";		Lswitch =>			(pc, apc) = getjmp(code.ops, pc);			(pc, e) = pexp(pp, pc, apc);			s += "switch (" + e + ") {\n";			(pc, apc) = getjmp(code.ops, pc);			(pc, e) = pcaseblk(pp, pc, apc, indent);			s  += e + indent + "}\n";			pc = apc;		Lthrow =>			(pc, e) = pexp(pp, pc, code.npc);			s += "throw " + e + "\n";		Ltry =>			s += "try\n";			(pc, apc) = getjmp(code.ops, pc);			s += pstmt(pp, pc, apc, indent+"	");			(pc, apc) = getjmp(code.ops, apc);			if(pc != apc){				(pc, c) = getconst(code.ops, ++pc);				s += "catch(" + code.strs[c] + ")\n";				s += pstmt(pp, pc, apc, indent+"	");			}			(pc, apc) = getjmp(code.ops, apc);			if(pc != apc){				s += "finally\n";				s += pstmt(pp, pc, apc, indent+"	");			}			pc = apc;		* =>			(pc, e) = pexp(pp, pc-1, code.npc);			s += e + ";\n";		}	}	return s;} pexp(pp: ref PPrint, pc, epc: int): (int, string){	c, apc: int;	s, f, a, a1, a2: string; 	code := pp.code;	savesp := pp.sp;out:	while(pc < epc){		case op := int code.ops[pc++]{		Lthis =>			s = "this";		Lid or		Lnum or		Lstr or		Lregexp =>			(pc, c) = getconst(code.ops, pc);			if(op == Lnum)				s = string code.nums[c];			else{				s = code.strs[c];				if(op == Lstr)					s = "\""+escstr(code.strs[c])+"\"";			}		'*' or		'/' or		'%' or		'+' or		'-' or		Llsh or		Lrsh or		Lrshu or		'<' or		'>' or		Lleq or		Lgeq or		Lin or		Linstanceof or		Leq or		Lneq or		Lseq or		Lsne or		'&' or		'^' or		'|' or		'=' or		'.' or		',' or		'[' =>			a2 = ppop(pp);			a1 = ppop(pp);			s = tokname(op);			if(a1[0] == '='){				s += "=";				a1 = a1[1:];			}			if(op == '[')				s = a1 + "[" + a2 + "]";			else{				if(op != '.'){					if(op != ',')						s = " " + s;					s = s + " ";				}				s = a1 + s + a2;			}		Ltypeof or		Ldelete or		Lvoid or		Lnew or		Linc or		Ldec or		Lpreadd or		Lpresub or		'~' or		'!' or		Lpostinc or		Lpostdec =>			a = ppop(pp);			s = tokname(op);			if(op == Lpostinc || op == Lpostdec)				s = a + s;			else{				if(op == Ltypeof || op == Ldelete || op == Lvoid || op == Lnew)					s += " ";				s += a;			}		'(' =>			s = "(";		')' =>			s = ppop(pp);			if(ppop(pp) != "(")				fatal(pp.ex, "unbalanced () in pexp");			s = "(" + s + ")";		Lgetval or		Las =>			continue;		Lasop =>			s = "=" + ppop(pp);		Lcall or		Lnewcall =>			(pc, c) = getconst(code.ops, pc);			a = "";			sep := "";			for(sp := pp.sp-c; sp < pp.sp; sp++){				a += sep + pp.stack[sp];				sep = ", ";			}			pp.sp -= c;			f = ppop(pp);			if(op == Lnewcall)				f = "new " + f;			s = f + "(" + a + ")";		';' =>			break out;		Landand or		Loror or		'?' =>			s = ppop(pp);			(pc, apc) = getjmp(code.ops, pc);			(pc, a1) = pexp(pp, pc, apc);			s += " " + tokname(op) + " " + a1;			if(op == '?'){				(pc, apc) = getjmp(code.ops, pc);				(pc, a2) = pexp(pp, pc, apc);				s += " : "+ a2;			}		* =>			fatal(pp.ex, "pexp: unknown op " + tokname(op));		}		ppush(pp, s);	} 	if(savesp == pp.sp)		return (pc, ""); 	if(savesp != pp.sp-1)		fatal(pp.ex, "unbalanced stack in pexp");	return (pc, ppop(pp));} pcaseblk(pp: ref PPrint, pc, epc: int, indent: string): (int, string){	code := pp.code;	defpc, clausepc, nextpc, apc: int;	s, a: string; 	(pc, defpc) = getjmp(code.ops, pc);	clausepc = pc;	(pc, nextpc) = getjmp(code.ops, pc);	for (; pc < epc; (clausepc, (pc, nextpc)) = (nextpc, getjmp(code.ops, nextpc))) {		if (clausepc == defpc) {			s += indent + "default:\n";		} else {			(pc, apc) = getjmp(code.ops, pc);			(pc, a) = pexp(pp, pc, apc);			s += indent + "case " + a + ":\n";		}		s += pstmt(pp, pc, nextpc, indent+"\t");	}	return (epc, s);} ppush(pp: ref PPrint, s: string){	if(pp.sp >= len pp.stack){		st := array[2 * len pp.stack] of string;		st[:] = pp.stack;		pp.stack = st;	}	pp.stack[pp.sp++] = s;} ppop(pp: ref PPrint): string{	if(pp.sp == 0)		fatal(pp.ex, "popping too far off the pstack");	return pp.stack[--pp.sp];} unescmap :=	array[128] of {	'\'' =>		byte '\'',	'"' =>		byte '"',	'\\' =>		byte '\\',	'\b' =>		byte 'b',	'\u000c' =>	byte 'f',	'\n' =>		byte 'n',	'\r' =>		byte 'r',	'\t' =>		byte 't', 	* =>		byte 0}; escstr(s: string): string{	n := len s;	sb := "";	for(i := 0; i < n; i++){		c := s[i];		if(c < 128 && (e := int unescmap[c])){			sb[len sb] = '\\';			sb[len sb] = e;		}else if(c > 128 || c < 32){			sb += "\\u0000";			for(j := 1; j <= 4; j++){				sb[len sb - j] = "0123456789abcdef"[c & 16rf];				c >>= 4;			}		}else			sb[len sb] = c;	}	return sb;}