forsyth20121205-174063a80cc13 years agoHistory
612 lines · 11.9 KB · Brainfuck
RawDownload
implement Fc;include "sys.m";	sys: Sys;include "draw.m";include "math.m";	math: Math;include "string.m";	str: String;include "regex.m";	regex: Regex; Fc: module {	init: fn(nil: ref Draw->Context, argv: list of string);};  UNARY, BINARY, SPECIAL: con iota; oSWAP, oDUP, oREP, oSUM, oPRNUM, oMULT,oPLUS, oMINUS, oDIV, oDIVIDE, oMOD, oSHIFTL, oSHIFTR,oAND, oOR, oXOR, oNOT, oUMINUS, oFACTORIAL,oPOW, oHYPOT, oATAN2, oJN, oYN, oSCALBN, oCOPYSIGN,oFDIM, oFMIN, oFMAX, oNEXTAFTER, oREMAINDER, oFMOD,oPOW10, oSQRT, oEXP, oEXPM1, oLOG, oLOG10, oLOG1P,oCOS, oCOSH, oSIN, oSINH, oTAN, oTANH, oACOS, oASIN, oACOSH,oASINH, oATAN, oATANH, oERF, oERFC,oJ0, oJ1, oY0, oY1, oILOGB, oFABS, oCEIL,oFLOOR, oFINITE, oISNAN, oRINT, oLGAMMA, oMODF,oDEG, oRAD: con iota;Op: adt {	name: string;	kind:	int;	op: int;}; ops := array[] of {Op("swap",	SPECIAL, oSWAP),("dup",		SPECIAL, oDUP),("rep",		SPECIAL, oREP),("sum",		SPECIAL, oSUM),("p",			SPECIAL, oPRNUM),("x",			BINARY, oMULT),("×",			BINARY, oMULT),("pow",		BINARY, oPOW),("xx",		BINARY, oPOW),("+",			BINARY, oPLUS),("-",			BINARY, oMINUS),("/",			BINARY, oDIVIDE),("div",		BINARY, oDIV),("%",			BINARY, oMOD),("shl",		BINARY, oSHIFTL),("shr",		BINARY, oSHIFTR),("and",		BINARY, oAND),("or",		BINARY, oOR),("⋀",			BINARY, oAND),("⋁",			BINARY, oOR),("xor",		BINARY, oXOR),("not",		UNARY, oNOT),("_",			UNARY, oUMINUS),("factorial",	UNARY, oFACTORIAL),("!",			UNARY, oFACTORIAL),("pow",		BINARY, oPOW),("hypot",		BINARY, oHYPOT),("atan2",		BINARY, oATAN2),("jn",			BINARY, oJN),("yn",		BINARY, oYN),("scalbn",		BINARY, oSCALBN),("copysign",	BINARY, oCOPYSIGN),("fdim",		BINARY, oFDIM),("fmin",		BINARY, oFMIN),("fmax",		BINARY, oFMAX),("nextafter",	BINARY, oNEXTAFTER),("remainder",	BINARY, oREMAINDER),("fmod",		BINARY, oFMOD),("pow10",		UNARY, oPOW10),("sqrt",		UNARY, oSQRT),("exp",		UNARY, oEXP),("expm1",		UNARY, oEXPM1),("log",		UNARY, oLOG),("log10",		UNARY, oLOG10),("log1p",		UNARY, oLOG1P),("cos",		UNARY, oCOS),("cosh",		UNARY, oCOSH),("sin",		UNARY, oSIN),("sinh",		UNARY, oSINH),("tan",		UNARY, oTAN),("tanh",		UNARY, oTANH),("acos",		UNARY, oACOS),("asin",		UNARY, oASIN),("acosh",		UNARY, oACOSH),("asinh",		UNARY, oASINH),("atan",		UNARY, oATAN),("atanh",		UNARY, oATANH),("erf",		UNARY, oERF),("erfc",		UNARY, oERFC),("j0",			UNARY, oJ0),("j1",			UNARY, oJ1),("y0",		UNARY, oY0),("y1",		UNARY, oY1),("ilogb",		UNARY, oILOGB),("fabs",		UNARY, oFABS),("ceil",		UNARY, oCEIL),("floor",		UNARY, oFLOOR),("finite",		UNARY, oFINITE),("isnan",		UNARY, oISNAN),("rint",		UNARY, oRINT),("rad",		UNARY, oRAD),("deg",		UNARY, oDEG),("lgamma",	SPECIAL, oLGAMMA),("modf",		SPECIAL, oMODF),}; nHEX, nBINARY, nOCTAL, nRADIX1, nRADIX2, nREAL, nCHAR: con iota;pats0 := array[] of {nHEX => "-?0[xX][0-9a-fA-F]+",nBINARY => "-?0[bB][01]+",nOCTAL => "-?0[0-7]+",nRADIX1 => "-?[0-9][rR][0-8]+",nRADIX2 => "-?[0-3][0-9][rR][0-9a-zA-Z]+",nREAL => "-?(([0-9]+(\\.[0-9]+)?)|([0-9]*(\\.[0-9]+)))([eE]-?[0-9]+)?",nCHAR => "@.",};RADIX, ANNOTATE, CHAR: con 1 << (iota + 10); outbase := 10;pats: array of Regex->Re;stack: list of real;last_op: Op;stderr: ref Sys->FD; usage(){	sys->fprint(stderr,		"usage: fc [-xdbB] [-r radix] <postfix expression>\n" +		"option specifies output format:\n" +		"\t-d decimal (default)\n" +		"\t-x hex\n" +		"\t-o octal\n" +		"\t-b binary\n" +		"\t-B annotated binary\n" +		"\t-c character\n" +		"\t-r <radix> specified base in Limbo 99r9999 format\n" +		"operands are decimal(default), hex(0x), octal(0), binary(0b), radix(99r)\n");	sys->fprint(stderr, "operators are:\n");	for (i := 0; i < len ops; i++)		sys->fprint(stderr, "%s ", ops[i].name);	sys->fprint(stderr, "\n");	raise "fail:usage";} init(nil: ref Draw->Context, argv: list of string){	sys = load Sys Sys->PATH;	stderr = sys->fildes(2);	math = load Math Math->PATH;	regex = load Regex Regex->PATH;	if (regex == nil) {		sys->fprint(stderr, "fc: cannot load %s: %r\n", Regex->PATH);		raise "fail:error";	} 	initpats(); 	if (argv == nil || tl argv == nil)		return;	argv = tl argv;	a := hd argv;	if (len a > 1 && a[0] == '-' && number(a).t0 == 0) {		case a[1] {		'd' =>			outbase = 10;		'x' =>			outbase = 16;		'o' =>			outbase = 8;		'b' =>			outbase = 2;		'c' =>			outbase = CHAR;		'r' =>			r := 0;			if (len a > 2)				r = int a[2:];			else if (tl argv == nil)				usage();			else {				argv = tl argv;				r = int hd argv;			}			if (r < 2 || r > 36)				usage();			outbase = r | RADIX;		'B' =>			outbase = 2 | ANNOTATE;		* =>			sys->fprint(stderr, "fc: unknown option -%c\n", a[1]);			usage();		}		argv = tl argv;	} 	math->FPcontrol(0, Math->INVAL|Math->ZDIV|Math->OVFL|Math->UNFL|Math->INEX); 	for (; argv != nil; argv = tl argv) {		(ok, x) := number(hd argv);		if (ok)			stack = x :: stack;		else {			op := find(hd argv);			exec(op);			last_op = op;		}	} 	sp: list of real;	for (; stack != nil; stack = tl stack)		sp = hd stack :: sp; 	# print stack bottom first	for (; sp != nil; sp = tl sp)		printnum(hd sp);} printnum(n: real){	case outbase {	CHAR =>		sys->print("@%c\n", int n);	2 =>		sys->print("%s\n", binary(big n));	2 | ANNOTATE =>		sys->print("%s\n", annotatebinary(big n));	8 =>		sys->print("%#bo\n", big n);	10 =>		sys->print("%g\n", n);	16 =>		sys->print("%#bx\n", big n);	* =>		if ((outbase & RADIX) == 0)			error("unknown output base " + string outbase);		sys->print("%s\n", big2string(big n, outbase & ~RADIX));	}} # convert to binary string, keeping multiples of 8 digits.binary(n: big): string{	s := "0b";	for (j := 7; j > 0; j--)		if ((n & (big 16rff << (j * 8))) != big 0)			break;	for (i := 63; i >= 0; i--)		if (i / 8 <= j)			s[len s] = (int (n >> i) & 1) + '0';	return s;} annotatebinary(n: big): string{	s := binary(n);	a := s + "\n  ";	ndig := len s - 2;	for (i := ndig - 1; i >= 0; i--)		a[len a] = (i % 10) + '0';	if (ndig < 10)		return a;	a += "\n  ";	for (i = ndig - 1; i >= 10; i--) {		if (i % 10 == 0)			a[len a] = (i / 10) + '0';		else			a[len a] = ' ';	}	return a;} find(name: string): Op{	# XXX could do binary search here if we weren't a lousy performer anyway	for (i := 0; i < len ops; i++)		if (name == ops[i].name)			break;	if (i == len ops)		error("invalid operator '" + name + "'");	return ops[i];} exec(op: Op){	case op.kind {	UNARY =>		unaryop(op.name, op.op);	BINARY =>		binaryop(op.name, op.op);	SPECIAL =>		specialop(op.name, op.op);	}} unaryop(name: string, op: int){	assure(1, name);	v := hd stack;	case op {	oNOT =>		v = real !(int v);	oUMINUS =>		v = -v;	oFACTORIAL =>		n := int v;		v = 1.0;		while (n > 0)			v *= real n--;	oPOW10 =>		v = math->pow10(int v);	oSQRT =>		v = math->sqrt(v);	oEXP =>		v = math->exp(v);	oEXPM1 =>		v = math->expm1(v);	oLOG =>		v = math->log(v);	oLOG10 =>		v = math->log10(v);	oLOG1P =>		v = math->log1p(v);	oCOS =>		v = math->cos(v);	oCOSH =>		v = math->cosh(v);	oSIN =>		v = math->sin(v);	oSINH =>		v = math->sinh(v);	oTAN =>		v = math->tan(v);	oTANH =>		v = math->tanh(v);	oACOS =>		v = math->acos(v);	oASIN =>		v = math->asin(v);	oACOSH =>		v = math->acosh(v);	oASINH =>		v = math->asinh(v);	oATAN =>		v = math->atan(v);	oATANH =>		v = math->atanh(v);	oERF =>		v = math->erf(v);	oERFC =>		v = math->erfc(v);	oJ0 =>		v = math->j0(v);	oJ1 =>		v = math->j1(v);	oY0 =>		v = math->y0(v);	oY1 =>		v = math->y1(v);	oILOGB =>		v = real math->ilogb(v);	oFABS =>		v = math->fabs(v);	oCEIL =>		v = math->ceil(v);	oFLOOR =>		v = math->floor(v);	oFINITE =>		v = real math->finite(v);	oISNAN =>		v = real math->isnan(v);	oRINT =>		v = math->rint(v);	oRAD =>		v = (v / 360.0) * 2.0 * Math->Pi;	oDEG =>		v = v / (2.0 * Math->Pi) * 360.0;	* =>		error("unknown unary operator '" + name + "'");	}	stack = v :: tl stack;} binaryop(name: string, op: int){	assure(2, name);	v1 := hd stack;	v0 := hd tl stack;	case op {	oMULT =>		v0 = v0 * v1;	oPLUS =>		v0 = v0 + v1;	oMINUS =>		v0 = v0 - v1;	oDIVIDE =>		v0 = v0 / v1;	oDIV =>		v0 = real (big v0 / big v1);	oMOD =>		v0 = real (big v0 % big v1);	oSHIFTL =>		v0 = real (big v0 << int v1);	oSHIFTR =>		v0 = real (big v0 >> int v1);	oAND =>		v0 = real (big v0 & big v1);	oOR =>		v0 = real (big v0 | big v1);	oXOR =>		v0 = real (big v0 ^ big v1);	oPOW =>		v0 = math->pow(v0, v1);	oHYPOT =>		v0 = math->hypot(v0, v1);	oATAN2 =>		v0 = math->atan2(v0, v1);	oJN =>		v0 = math->jn(int v0, v1);	oYN =>		v0 = math->yn(int v0, v1);	oSCALBN =>		v0 = math->scalbn(v0, int v1);	oCOPYSIGN =>		v0 = math->copysign(v0, v1);	oFDIM =>		v0 = math->fdim(v0, v1);	oFMIN =>		v0 = math->fmin(v0, v1);	oFMAX =>		v0 = math->fmax(v0, v1);	oNEXTAFTER =>		v0 = math->nextafter(v0, v1);	oREMAINDER =>		v0 = math->remainder(v0, v1);	oFMOD =>		v0 = math->fmod(v0, v1);	* =>		error("unknown binary operator '" + name + "'");	}	stack = v0 :: tl tl stack;} specialop(name: string, op: int){	case op {	oSWAP =>		assure(2, name);		stack = hd tl stack :: hd stack :: tl tl stack;	oDUP =>		assure(1, name);		stack = hd stack :: stack;	oREP =>		if (last_op.kind != BINARY)			error("invalid operator '" + last_op.name + "' for rep");		while (stack != nil && tl stack != nil)			exec(last_op);	oSUM =>		for (sum := 0.0; stack != nil; stack = tl stack)			sum += hd stack;		stack = sum :: nil;	oPRNUM =>		assure(1, name);		printnum(hd stack);		stack = tl stack;	oLGAMMA =>		assure(1, name);		(s, lg) := math->lgamma(hd stack);		stack = lg :: real s :: tl stack;	oMODF =>		assure(1, name);		(i, r) := math->modf(hd stack);		stack = r :: real i :: tl stack;	* =>		error("unknown operator '" + name + "'");	}} initpats(){	pats = array[len pats0] of Regex->Re;	for (i := 0; i < len pats0; i++) {		(re, e) := regex->compile("^" + pats0[i] + "$", 0);		if (re == nil) {			sys->fprint(stderr, "fc: bad number pattern '^%s$': %s\n", pats0[i], e);			raise "fail:error";		}		pats[i] = re;	}} number(s: string): (int, real){	case s {

Lines 1–500 of 612.