xref: /inferno-os/appl/cmd/fc.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Fc;
2*37da2899SCharles.Forsythinclude "sys.m";
3*37da2899SCharles.Forsyth	sys: Sys;
4*37da2899SCharles.Forsythinclude "draw.m";
5*37da2899SCharles.Forsythinclude "math.m";
6*37da2899SCharles.Forsyth	math: Math;
7*37da2899SCharles.Forsythinclude "string.m";
8*37da2899SCharles.Forsyth	str: String;
9*37da2899SCharles.Forsythinclude "regex.m";
10*37da2899SCharles.Forsyth	regex: Regex;
11*37da2899SCharles.Forsyth
12*37da2899SCharles.ForsythFc: module {
13*37da2899SCharles.Forsyth	init: fn(nil: ref Draw->Context, argv: list of string);
14*37da2899SCharles.Forsyth};
15*37da2899SCharles.Forsyth
16*37da2899SCharles.Forsyth
17*37da2899SCharles.ForsythUNARY, BINARY, SPECIAL: con iota;
18*37da2899SCharles.Forsyth
19*37da2899SCharles.ForsythoSWAP, oDUP, oREP, oSUM, oPRNUM, oMULT,
20*37da2899SCharles.ForsythoPLUS, oMINUS, oDIV, oDIVIDE, oMOD, oSHIFTL, oSHIFTR,
21*37da2899SCharles.ForsythoAND, oOR, oXOR, oNOT, oUMINUS, oFACTORIAL,
22*37da2899SCharles.ForsythoPOW, oHYPOT, oATAN2, oJN, oYN, oSCALBN, oCOPYSIGN,
23*37da2899SCharles.ForsythoFDIM, oFMIN, oFMAX, oNEXTAFTER, oREMAINDER, oFMOD,
24*37da2899SCharles.ForsythoPOW10, oSQRT, oEXP, oEXPM1, oLOG, oLOG10, oLOG1P,
25*37da2899SCharles.ForsythoCOS, oCOSH, oSIN, oSINH, oTAN, oTANH, oACOS, oASIN, oACOSH,
26*37da2899SCharles.ForsythoASINH, oATAN, oATANH, oERF, oERFC,
27*37da2899SCharles.ForsythoJ0, oJ1, oY0, oY1, oILOGB, oFABS, oCEIL,
28*37da2899SCharles.ForsythoFLOOR, oFINITE, oISNAN, oRINT, oLGAMMA, oMODF,
29*37da2899SCharles.ForsythoDEG, oRAD: con iota;
30*37da2899SCharles.ForsythOp: adt {
31*37da2899SCharles.Forsyth	name: string;
32*37da2899SCharles.Forsyth	kind:	int;
33*37da2899SCharles.Forsyth	op: int;
34*37da2899SCharles.Forsyth};
35*37da2899SCharles.Forsyth
36*37da2899SCharles.Forsythops := array[] of {
37*37da2899SCharles.ForsythOp
38*37da2899SCharles.Forsyth("swap",	SPECIAL, oSWAP),
39*37da2899SCharles.Forsyth("dup",		SPECIAL, oDUP),
40*37da2899SCharles.Forsyth("rep",		SPECIAL, oREP),
41*37da2899SCharles.Forsyth("sum",		SPECIAL, oSUM),
42*37da2899SCharles.Forsyth("p",			SPECIAL, oPRNUM),
43*37da2899SCharles.Forsyth("x",			BINARY, oMULT),
44*37da2899SCharles.Forsyth("×",			BINARY, oMULT),
45*37da2899SCharles.Forsyth("pow",		BINARY, oPOW),
46*37da2899SCharles.Forsyth("xx",		BINARY, oPOW),
47*37da2899SCharles.Forsyth("+",			BINARY, oPLUS),
48*37da2899SCharles.Forsyth("-",			BINARY, oMINUS),
49*37da2899SCharles.Forsyth("/",			BINARY, oDIVIDE),
50*37da2899SCharles.Forsyth("div",		BINARY, oDIV),
51*37da2899SCharles.Forsyth("%",			BINARY, oMOD),
52*37da2899SCharles.Forsyth("shl",		BINARY, oSHIFTL),
53*37da2899SCharles.Forsyth("shr",		BINARY, oSHIFTR),
54*37da2899SCharles.Forsyth("and",		BINARY, oAND),
55*37da2899SCharles.Forsyth("or",		BINARY, oOR),
56*37da2899SCharles.Forsyth("⋀",			BINARY, oAND),
57*37da2899SCharles.Forsyth("⋁",			BINARY, oOR),
58*37da2899SCharles.Forsyth("xor",		BINARY, oXOR),
59*37da2899SCharles.Forsyth("not",		UNARY, oNOT),
60*37da2899SCharles.Forsyth("_",			UNARY, oUMINUS),
61*37da2899SCharles.Forsyth("factorial",	UNARY, oFACTORIAL),
62*37da2899SCharles.Forsyth("!",			UNARY, oFACTORIAL),
63*37da2899SCharles.Forsyth("pow",		BINARY, oPOW),
64*37da2899SCharles.Forsyth("hypot",		BINARY, oHYPOT),
65*37da2899SCharles.Forsyth("atan2",		BINARY, oATAN2),
66*37da2899SCharles.Forsyth("jn",			BINARY, oJN),
67*37da2899SCharles.Forsyth("yn",		BINARY, oYN),
68*37da2899SCharles.Forsyth("scalbn",		BINARY, oSCALBN),
69*37da2899SCharles.Forsyth("copysign",	BINARY, oCOPYSIGN),
70*37da2899SCharles.Forsyth("fdim",		BINARY, oFDIM),
71*37da2899SCharles.Forsyth("fmin",		BINARY, oFMIN),
72*37da2899SCharles.Forsyth("fmax",		BINARY, oFMAX),
73*37da2899SCharles.Forsyth("nextafter",	BINARY, oNEXTAFTER),
74*37da2899SCharles.Forsyth("remainder",	BINARY, oREMAINDER),
75*37da2899SCharles.Forsyth("fmod",		BINARY, oFMOD),
76*37da2899SCharles.Forsyth("pow10",		UNARY, oPOW10),
77*37da2899SCharles.Forsyth("sqrt",		UNARY, oSQRT),
78*37da2899SCharles.Forsyth("exp",		UNARY, oEXP),
79*37da2899SCharles.Forsyth("expm1",		UNARY, oEXPM1),
80*37da2899SCharles.Forsyth("log",		UNARY, oLOG),
81*37da2899SCharles.Forsyth("log10",		UNARY, oLOG10),
82*37da2899SCharles.Forsyth("log1p",		UNARY, oLOG1P),
83*37da2899SCharles.Forsyth("cos",		UNARY, oCOS),
84*37da2899SCharles.Forsyth("cosh",		UNARY, oCOSH),
85*37da2899SCharles.Forsyth("sin",		UNARY, oSIN),
86*37da2899SCharles.Forsyth("sinh",		UNARY, oSINH),
87*37da2899SCharles.Forsyth("tan",		UNARY, oTAN),
88*37da2899SCharles.Forsyth("tanh",		UNARY, oTANH),
89*37da2899SCharles.Forsyth("acos",		UNARY, oACOS),
90*37da2899SCharles.Forsyth("asin",		UNARY, oASIN),
91*37da2899SCharles.Forsyth("acosh",		UNARY, oACOSH),
92*37da2899SCharles.Forsyth("asinh",		UNARY, oASINH),
93*37da2899SCharles.Forsyth("atan",		UNARY, oATAN),
94*37da2899SCharles.Forsyth("atanh",		UNARY, oATANH),
95*37da2899SCharles.Forsyth("erf",		UNARY, oERF),
96*37da2899SCharles.Forsyth("erfc",		UNARY, oERFC),
97*37da2899SCharles.Forsyth("j0",			UNARY, oJ0),
98*37da2899SCharles.Forsyth("j1",			UNARY, oJ1),
99*37da2899SCharles.Forsyth("y0",		UNARY, oY0),
100*37da2899SCharles.Forsyth("y1",		UNARY, oY1),
101*37da2899SCharles.Forsyth("ilogb",		UNARY, oILOGB),
102*37da2899SCharles.Forsyth("fabs",		UNARY, oFABS),
103*37da2899SCharles.Forsyth("ceil",		UNARY, oCEIL),
104*37da2899SCharles.Forsyth("floor",		UNARY, oFLOOR),
105*37da2899SCharles.Forsyth("finite",		UNARY, oFINITE),
106*37da2899SCharles.Forsyth("isnan",		UNARY, oISNAN),
107*37da2899SCharles.Forsyth("rint",		UNARY, oRINT),
108*37da2899SCharles.Forsyth("rad",		UNARY, oRAD),
109*37da2899SCharles.Forsyth("deg",		UNARY, oDEG),
110*37da2899SCharles.Forsyth("lgamma",	SPECIAL, oLGAMMA),
111*37da2899SCharles.Forsyth("modf",		SPECIAL, oMODF),
112*37da2899SCharles.Forsyth};
113*37da2899SCharles.Forsyth
114*37da2899SCharles.ForsythnHEX, nBINARY, nOCTAL, nRADIX1, nRADIX2, nREAL, nCHAR: con iota;
115*37da2899SCharles.Forsythpats0 := array[] of {
116*37da2899SCharles.ForsythnHEX => "-?0[xX][0-9a-fA-F]+",
117*37da2899SCharles.ForsythnBINARY => "-?0[bB][01]+",
118*37da2899SCharles.ForsythnOCTAL => "-?0[0-7]+",
119*37da2899SCharles.ForsythnRADIX1 => "-?[0-9][rR][0-8]+",
120*37da2899SCharles.ForsythnRADIX2 => "-?[0-3][0-9][rR][0-9a-zA-Z]+",
121*37da2899SCharles.ForsythnREAL => "-?(([0-9]+(\\.[0-9]+)?)|([0-9]*(\\.[0-9]+)))([eE]-?[0-9]+)?",
122*37da2899SCharles.ForsythnCHAR => "@.",
123*37da2899SCharles.Forsyth};
124*37da2899SCharles.ForsythRADIX, ANNOTATE, CHAR: con 1 << (iota + 10);
125*37da2899SCharles.Forsyth
126*37da2899SCharles.Forsythoutbase := 10;
127*37da2899SCharles.Forsythpats: array of Regex->Re;
128*37da2899SCharles.Forsythstack: list of real;
129*37da2899SCharles.Forsythlast_op: Op;
130*37da2899SCharles.Forsythstderr: ref Sys->FD;
131*37da2899SCharles.Forsyth
132*37da2899SCharles.Forsythusage()
133*37da2899SCharles.Forsyth{
134*37da2899SCharles.Forsyth	sys->fprint(stderr,
135*37da2899SCharles.Forsyth		"usage: fc [-xdbB] [-r radix] <postfix expression>\n" +
136*37da2899SCharles.Forsyth		"option specifies output format:\n" +
137*37da2899SCharles.Forsyth		"\t-d decimal (default)\n" +
138*37da2899SCharles.Forsyth		"\t-x hex\n" +
139*37da2899SCharles.Forsyth		"\t-o octal\n" +
140*37da2899SCharles.Forsyth		"\t-b binary\n" +
141*37da2899SCharles.Forsyth		"\t-B annotated binary\n" +
142*37da2899SCharles.Forsyth		"\t-c character\n" +
143*37da2899SCharles.Forsyth		"\t-r <radix> specified base in Limbo 99r9999 format\n" +
144*37da2899SCharles.Forsyth		"operands are decimal(default), hex(0x), octal(0), binary(0b), radix(99r)\n");
145*37da2899SCharles.Forsyth	sys->fprint(stderr, "operators are:\n");
146*37da2899SCharles.Forsyth	for (i := 0; i < len ops; i++)
147*37da2899SCharles.Forsyth		sys->fprint(stderr, "%s ", ops[i].name);
148*37da2899SCharles.Forsyth	sys->fprint(stderr, "\n");
149*37da2899SCharles.Forsyth	raise "fail:usage";
150*37da2899SCharles.Forsyth}
151*37da2899SCharles.Forsyth
152*37da2899SCharles.Forsythinit(nil: ref Draw->Context, argv: list of string)
153*37da2899SCharles.Forsyth{
154*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
155*37da2899SCharles.Forsyth	stderr = sys->fildes(2);
156*37da2899SCharles.Forsyth	math = load Math Math->PATH;
157*37da2899SCharles.Forsyth	regex = load Regex Regex->PATH;
158*37da2899SCharles.Forsyth	if (regex == nil) {
159*37da2899SCharles.Forsyth		sys->fprint(stderr, "fc: cannot load %s: %r\n", Regex->PATH);
160*37da2899SCharles.Forsyth		raise "fail:error";
161*37da2899SCharles.Forsyth	}
162*37da2899SCharles.Forsyth
163*37da2899SCharles.Forsyth	initpats();
164*37da2899SCharles.Forsyth
165*37da2899SCharles.Forsyth	if (argv == nil || tl argv == nil)
166*37da2899SCharles.Forsyth		return;
167*37da2899SCharles.Forsyth	argv = tl argv;
168*37da2899SCharles.Forsyth	a := hd argv;
169*37da2899SCharles.Forsyth	if (len a > 1 && a[0] == '-' && number(a).t0 == 0) {
170*37da2899SCharles.Forsyth		case a[1] {
171*37da2899SCharles.Forsyth		'd' =>
172*37da2899SCharles.Forsyth			outbase = 10;
173*37da2899SCharles.Forsyth		'x' =>
174*37da2899SCharles.Forsyth			outbase = 16;
175*37da2899SCharles.Forsyth		'o' =>
176*37da2899SCharles.Forsyth			outbase = 8;
177*37da2899SCharles.Forsyth		'b' =>
178*37da2899SCharles.Forsyth			outbase = 2;
179*37da2899SCharles.Forsyth		'c' =>
180*37da2899SCharles.Forsyth			outbase = CHAR;
181*37da2899SCharles.Forsyth		'r' =>
182*37da2899SCharles.Forsyth			r := 0;
183*37da2899SCharles.Forsyth			if (len a > 2)
184*37da2899SCharles.Forsyth				r = int a[2:];
185*37da2899SCharles.Forsyth			else if (tl argv == nil)
186*37da2899SCharles.Forsyth				usage();
187*37da2899SCharles.Forsyth			else {
188*37da2899SCharles.Forsyth				argv = tl argv;
189*37da2899SCharles.Forsyth				r = int hd argv;
190*37da2899SCharles.Forsyth			}
191*37da2899SCharles.Forsyth			if (r < 2 || r > 36)
192*37da2899SCharles.Forsyth				usage();
193*37da2899SCharles.Forsyth			outbase = r | RADIX;
194*37da2899SCharles.Forsyth		'B' =>
195*37da2899SCharles.Forsyth			outbase = 2 | ANNOTATE;
196*37da2899SCharles.Forsyth		* =>
197*37da2899SCharles.Forsyth			sys->fprint(stderr, "fc: unknown option -%c\n", a[1]);
198*37da2899SCharles.Forsyth			usage();
199*37da2899SCharles.Forsyth		}
200*37da2899SCharles.Forsyth		argv = tl argv;
201*37da2899SCharles.Forsyth	}
202*37da2899SCharles.Forsyth
203*37da2899SCharles.Forsyth	math->FPcontrol(0, Math->INVAL|Math->ZDIV|Math->OVFL|Math->UNFL|Math->INEX);
204*37da2899SCharles.Forsyth
205*37da2899SCharles.Forsyth	for (; argv != nil; argv = tl argv) {
206*37da2899SCharles.Forsyth		(ok, x) := number(hd argv);
207*37da2899SCharles.Forsyth		if (ok)
208*37da2899SCharles.Forsyth			stack = x :: stack;
209*37da2899SCharles.Forsyth		else {
210*37da2899SCharles.Forsyth			op := find(hd argv);
211*37da2899SCharles.Forsyth			exec(op);
212*37da2899SCharles.Forsyth			last_op = op;
213*37da2899SCharles.Forsyth		}
214*37da2899SCharles.Forsyth	}
215*37da2899SCharles.Forsyth
216*37da2899SCharles.Forsyth	sp: list of real;
217*37da2899SCharles.Forsyth	for (; stack != nil; stack = tl stack)
218*37da2899SCharles.Forsyth		sp = hd stack :: sp;
219*37da2899SCharles.Forsyth
220*37da2899SCharles.Forsyth	# print stack bottom first
221*37da2899SCharles.Forsyth	for (; sp != nil; sp = tl sp)
222*37da2899SCharles.Forsyth		printnum(hd sp);
223*37da2899SCharles.Forsyth}
224*37da2899SCharles.Forsyth
225*37da2899SCharles.Forsythprintnum(n: real)
226*37da2899SCharles.Forsyth{
227*37da2899SCharles.Forsyth	case outbase {
228*37da2899SCharles.Forsyth	CHAR =>
229*37da2899SCharles.Forsyth		sys->print("@%c\n", int n);
230*37da2899SCharles.Forsyth	2 =>
231*37da2899SCharles.Forsyth		sys->print("%s\n", binary(big n));
232*37da2899SCharles.Forsyth	2 | ANNOTATE =>
233*37da2899SCharles.Forsyth		sys->print("%s\n", annotatebinary(big n));
234*37da2899SCharles.Forsyth	8 =>
235*37da2899SCharles.Forsyth		sys->print("%#bo\n", big n);
236*37da2899SCharles.Forsyth	10 =>
237*37da2899SCharles.Forsyth		sys->print("%g\n", n);
238*37da2899SCharles.Forsyth	16 =>
239*37da2899SCharles.Forsyth		sys->print("%#bx\n", big n);
240*37da2899SCharles.Forsyth	* =>
241*37da2899SCharles.Forsyth		if ((outbase & RADIX) == 0)
242*37da2899SCharles.Forsyth			error("unknown output base " + string outbase);
243*37da2899SCharles.Forsyth		sys->print("%s\n", big2string(big n, outbase & ~RADIX));
244*37da2899SCharles.Forsyth	}
245*37da2899SCharles.Forsyth}
246*37da2899SCharles.Forsyth
247*37da2899SCharles.Forsyth# convert to binary string, keeping multiples of 8 digits.
248*37da2899SCharles.Forsythbinary(n: big): string
249*37da2899SCharles.Forsyth{
250*37da2899SCharles.Forsyth	s := "0b";
251*37da2899SCharles.Forsyth	for (j := 7; j > 0; j--)
252*37da2899SCharles.Forsyth		if ((n & (big 16rff << (j * 8))) != big 0)
253*37da2899SCharles.Forsyth			break;
254*37da2899SCharles.Forsyth	for (i := 63; i >= 0; i--)
255*37da2899SCharles.Forsyth		if (i / 8 <= j)
256*37da2899SCharles.Forsyth			s[len s] = (int (n >> i) & 1) + '0';
257*37da2899SCharles.Forsyth	return s;
258*37da2899SCharles.Forsyth}
259*37da2899SCharles.Forsyth
260*37da2899SCharles.Forsythannotatebinary(n: big): string
261*37da2899SCharles.Forsyth{
262*37da2899SCharles.Forsyth	s := binary(n);
263*37da2899SCharles.Forsyth	a := s + "\n  ";
264*37da2899SCharles.Forsyth	ndig := len s - 2;
265*37da2899SCharles.Forsyth	for (i := ndig - 1; i >= 0; i--)
266*37da2899SCharles.Forsyth		a[len a] = (i % 10) + '0';
267*37da2899SCharles.Forsyth	if (ndig < 10)
268*37da2899SCharles.Forsyth		return a;
269*37da2899SCharles.Forsyth	a += "\n  ";
270*37da2899SCharles.Forsyth	for (i = ndig - 1; i >= 10; i--) {
271*37da2899SCharles.Forsyth		if (i % 10 == 0)
272*37da2899SCharles.Forsyth			a[len a] = (i / 10) + '0';
273*37da2899SCharles.Forsyth		else
274*37da2899SCharles.Forsyth			a[len a] = ' ';
275*37da2899SCharles.Forsyth	}
276*37da2899SCharles.Forsyth	return a;
277*37da2899SCharles.Forsyth}
278*37da2899SCharles.Forsyth
279*37da2899SCharles.Forsythfind(name: string): Op
280*37da2899SCharles.Forsyth{
281*37da2899SCharles.Forsyth	# XXX could do binary search here if we weren't a lousy performer anyway
282*37da2899SCharles.Forsyth	for (i := 0; i < len ops; i++)
283*37da2899SCharles.Forsyth		if (name == ops[i].name)
284*37da2899SCharles.Forsyth			break;
285*37da2899SCharles.Forsyth	if (i == len ops)
286*37da2899SCharles.Forsyth		error("invalid operator '" + name + "'");
287*37da2899SCharles.Forsyth	return ops[i];
288*37da2899SCharles.Forsyth}
289*37da2899SCharles.Forsyth
290*37da2899SCharles.Forsythexec(op: Op)
291*37da2899SCharles.Forsyth{
292*37da2899SCharles.Forsyth	case op.kind {
293*37da2899SCharles.Forsyth	UNARY =>
294*37da2899SCharles.Forsyth		unaryop(op.name, op.op);
295*37da2899SCharles.Forsyth	BINARY =>
296*37da2899SCharles.Forsyth		binaryop(op.name, op.op);
297*37da2899SCharles.Forsyth	SPECIAL =>
298*37da2899SCharles.Forsyth		specialop(op.name, op.op);
299*37da2899SCharles.Forsyth	}
300*37da2899SCharles.Forsyth}
301*37da2899SCharles.Forsyth
302*37da2899SCharles.Forsythunaryop(name: string, op: int)
303*37da2899SCharles.Forsyth{
304*37da2899SCharles.Forsyth	assure(1, name);
305*37da2899SCharles.Forsyth	v := hd stack;
306*37da2899SCharles.Forsyth	case op {
307*37da2899SCharles.Forsyth	oNOT =>
308*37da2899SCharles.Forsyth		v = real !(int v);
309*37da2899SCharles.Forsyth	oUMINUS =>
310*37da2899SCharles.Forsyth		v = -v;
311*37da2899SCharles.Forsyth	oFACTORIAL =>
312*37da2899SCharles.Forsyth		n := int v;
313*37da2899SCharles.Forsyth		v = 1.0;
314*37da2899SCharles.Forsyth		while (n > 0)
315*37da2899SCharles.Forsyth			v *= real n--;
316*37da2899SCharles.Forsyth	oPOW10 =>
317*37da2899SCharles.Forsyth		v = math->pow10(int v);
318*37da2899SCharles.Forsyth	oSQRT =>
319*37da2899SCharles.Forsyth		v = math->sqrt(v);
320*37da2899SCharles.Forsyth	oEXP =>
321*37da2899SCharles.Forsyth		v = math->exp(v);
322*37da2899SCharles.Forsyth	oEXPM1 =>
323*37da2899SCharles.Forsyth		v = math->expm1(v);
324*37da2899SCharles.Forsyth	oLOG =>
325*37da2899SCharles.Forsyth		v = math->log(v);
326*37da2899SCharles.Forsyth	oLOG10 =>
327*37da2899SCharles.Forsyth		v = math->log10(v);
328*37da2899SCharles.Forsyth	oLOG1P =>
329*37da2899SCharles.Forsyth		v = math->log1p(v);
330*37da2899SCharles.Forsyth	oCOS =>
331*37da2899SCharles.Forsyth		v = math->cos(v);
332*37da2899SCharles.Forsyth	oCOSH =>
333*37da2899SCharles.Forsyth		v = math->cosh(v);
334*37da2899SCharles.Forsyth	oSIN =>
335*37da2899SCharles.Forsyth		v = math->sin(v);
336*37da2899SCharles.Forsyth	oSINH =>
337*37da2899SCharles.Forsyth		v = math->sinh(v);
338*37da2899SCharles.Forsyth	oTAN =>
339*37da2899SCharles.Forsyth		v = math->tan(v);
340*37da2899SCharles.Forsyth	oTANH =>
341*37da2899SCharles.Forsyth		v = math->tanh(v);
342*37da2899SCharles.Forsyth	oACOS =>
343*37da2899SCharles.Forsyth		v = math->acos(v);
344*37da2899SCharles.Forsyth	oASIN =>
345*37da2899SCharles.Forsyth		v = math->asin(v);
346*37da2899SCharles.Forsyth	oACOSH =>
347*37da2899SCharles.Forsyth		v = math->acosh(v);
348*37da2899SCharles.Forsyth	oASINH =>
349*37da2899SCharles.Forsyth		v = math->asinh(v);
350*37da2899SCharles.Forsyth	oATAN =>
351*37da2899SCharles.Forsyth		v = math->atan(v);
352*37da2899SCharles.Forsyth	oATANH =>
353*37da2899SCharles.Forsyth		v = math->atanh(v);
354*37da2899SCharles.Forsyth	oERF =>
355*37da2899SCharles.Forsyth		v = math->erf(v);
356*37da2899SCharles.Forsyth	oERFC =>
357*37da2899SCharles.Forsyth		v = math->erfc(v);
358*37da2899SCharles.Forsyth	oJ0 =>
359*37da2899SCharles.Forsyth		v = math->j0(v);
360*37da2899SCharles.Forsyth	oJ1 =>
361*37da2899SCharles.Forsyth		v = math->j1(v);
362*37da2899SCharles.Forsyth	oY0 =>
363*37da2899SCharles.Forsyth		v = math->y0(v);
364*37da2899SCharles.Forsyth	oY1 =>
365*37da2899SCharles.Forsyth		v = math->y1(v);
366*37da2899SCharles.Forsyth	oILOGB =>
367*37da2899SCharles.Forsyth		v = real math->ilogb(v);
368*37da2899SCharles.Forsyth	oFABS =>
369*37da2899SCharles.Forsyth		v = math->fabs(v);
370*37da2899SCharles.Forsyth	oCEIL =>
371*37da2899SCharles.Forsyth		v = math->ceil(v);
372*37da2899SCharles.Forsyth	oFLOOR =>
373*37da2899SCharles.Forsyth		v = math->floor(v);
374*37da2899SCharles.Forsyth	oFINITE =>
375*37da2899SCharles.Forsyth		v = real math->finite(v);
376*37da2899SCharles.Forsyth	oISNAN =>
377*37da2899SCharles.Forsyth		v = real math->isnan(v);
378*37da2899SCharles.Forsyth	oRINT =>
379*37da2899SCharles.Forsyth		v = math->rint(v);
380*37da2899SCharles.Forsyth	oRAD =>
381*37da2899SCharles.Forsyth		v = (v / 360.0) * 2.0 * Math->Pi;
382*37da2899SCharles.Forsyth	oDEG =>
383*37da2899SCharles.Forsyth		v = v / (2.0 * Math->Pi) * 360.0;
384*37da2899SCharles.Forsyth	* =>
385*37da2899SCharles.Forsyth		error("unknown unary operator '" + name + "'");
386*37da2899SCharles.Forsyth	}
387*37da2899SCharles.Forsyth	stack = v :: tl stack;
388*37da2899SCharles.Forsyth}
389*37da2899SCharles.Forsyth
390*37da2899SCharles.Forsythbinaryop(name: string, op: int)
391*37da2899SCharles.Forsyth{
392*37da2899SCharles.Forsyth	assure(2, name);
393*37da2899SCharles.Forsyth	v1 := hd stack;
394*37da2899SCharles.Forsyth	v0 := hd tl stack;
395*37da2899SCharles.Forsyth	case op {
396*37da2899SCharles.Forsyth	oMULT =>
397*37da2899SCharles.Forsyth		v0 = v0 * v1;
398*37da2899SCharles.Forsyth	oPLUS =>
399*37da2899SCharles.Forsyth		v0 = v0 + v1;
400*37da2899SCharles.Forsyth	oMINUS =>
401*37da2899SCharles.Forsyth		v0 = v0 - v1;
402*37da2899SCharles.Forsyth	oDIVIDE =>
403*37da2899SCharles.Forsyth		v0 = v0 / v1;
404*37da2899SCharles.Forsyth	oDIV =>
405*37da2899SCharles.Forsyth		v0 = real (big v0 / big v1);
406*37da2899SCharles.Forsyth	oMOD =>
407*37da2899SCharles.Forsyth		v0 = real (big v0 % big v1);
408*37da2899SCharles.Forsyth	oSHIFTL =>
409*37da2899SCharles.Forsyth		v0 = real (big v0 << int v1);
410*37da2899SCharles.Forsyth	oSHIFTR =>
411*37da2899SCharles.Forsyth		v0 = real (big v0 >> int v1);
412*37da2899SCharles.Forsyth	oAND =>
413*37da2899SCharles.Forsyth		v0 = real (big v0 & big v1);
414*37da2899SCharles.Forsyth	oOR =>
415*37da2899SCharles.Forsyth		v0 = real (big v0 | big v1);
416*37da2899SCharles.Forsyth	oXOR =>
417*37da2899SCharles.Forsyth		v0 = real (big v0 ^ big v1);
418*37da2899SCharles.Forsyth	oPOW =>
419*37da2899SCharles.Forsyth		v0 = math->pow(v0, v1);
420*37da2899SCharles.Forsyth	oHYPOT =>
421*37da2899SCharles.Forsyth		v0 = math->hypot(v0, v1);
422*37da2899SCharles.Forsyth	oATAN2 =>
423*37da2899SCharles.Forsyth		v0 = math->atan2(v0, v1);
424*37da2899SCharles.Forsyth	oJN =>
425*37da2899SCharles.Forsyth		v0 = math->jn(int v0, v1);
426*37da2899SCharles.Forsyth	oYN =>
427*37da2899SCharles.Forsyth		v0 = math->yn(int v0, v1);
428*37da2899SCharles.Forsyth	oSCALBN =>
429*37da2899SCharles.Forsyth		v0 = math->scalbn(v0, int v1);
430*37da2899SCharles.Forsyth	oCOPYSIGN =>
431*37da2899SCharles.Forsyth		v0 = math->copysign(v0, v1);
432*37da2899SCharles.Forsyth	oFDIM =>
433*37da2899SCharles.Forsyth		v0 = math->fdim(v0, v1);
434*37da2899SCharles.Forsyth	oFMIN =>
435*37da2899SCharles.Forsyth		v0 = math->fmin(v0, v1);
436*37da2899SCharles.Forsyth	oFMAX =>
437*37da2899SCharles.Forsyth		v0 = math->fmax(v0, v1);
438*37da2899SCharles.Forsyth	oNEXTAFTER =>
439*37da2899SCharles.Forsyth		v0 = math->nextafter(v0, v1);
440*37da2899SCharles.Forsyth	oREMAINDER =>
441*37da2899SCharles.Forsyth		v0 = math->remainder(v0, v1);
442*37da2899SCharles.Forsyth	oFMOD =>
443*37da2899SCharles.Forsyth		v0 = math->fmod(v0, v1);
444*37da2899SCharles.Forsyth	* =>
445*37da2899SCharles.Forsyth		error("unknown binary operator '" + name + "'");
446*37da2899SCharles.Forsyth	}
447*37da2899SCharles.Forsyth	stack = v0 :: tl tl stack;
448*37da2899SCharles.Forsyth}
449*37da2899SCharles.Forsyth
450*37da2899SCharles.Forsythspecialop(name: string, op: int)
451*37da2899SCharles.Forsyth{
452*37da2899SCharles.Forsyth	case op {
453*37da2899SCharles.Forsyth	oSWAP =>
454*37da2899SCharles.Forsyth		assure(2, name);
455*37da2899SCharles.Forsyth		stack = hd tl stack :: hd stack :: tl tl stack;
456*37da2899SCharles.Forsyth	oDUP =>
457*37da2899SCharles.Forsyth		assure(1, name);
458*37da2899SCharles.Forsyth		stack = hd stack :: stack;
459*37da2899SCharles.Forsyth	oREP =>
460*37da2899SCharles.Forsyth		if (last_op.kind != BINARY)
461*37da2899SCharles.Forsyth			error("invalid operator '" + last_op.name + "' for rep");
462*37da2899SCharles.Forsyth		while (stack != nil && tl stack != nil)
463*37da2899SCharles.Forsyth			exec(last_op);
464*37da2899SCharles.Forsyth	oSUM =>
465*37da2899SCharles.Forsyth		for (sum := 0.0; stack != nil; stack = tl stack)
466*37da2899SCharles.Forsyth			sum += hd stack;
467*37da2899SCharles.Forsyth		stack = sum :: nil;
468*37da2899SCharles.Forsyth	oPRNUM =>
469*37da2899SCharles.Forsyth		assure(1, name);
470*37da2899SCharles.Forsyth		printnum(hd stack);
471*37da2899SCharles.Forsyth		stack = tl stack;
472*37da2899SCharles.Forsyth	oLGAMMA =>
473*37da2899SCharles.Forsyth		assure(1, name);
474*37da2899SCharles.Forsyth		(s, lg) := math->lgamma(hd stack);
475*37da2899SCharles.Forsyth		stack = lg :: real s :: tl stack;
476*37da2899SCharles.Forsyth	oMODF =>
477*37da2899SCharles.Forsyth		assure(1, name);
478*37da2899SCharles.Forsyth		(i, r) := math->modf(hd stack);
479*37da2899SCharles.Forsyth		stack = r :: real i :: tl stack;
480*37da2899SCharles.Forsyth	* =>
481*37da2899SCharles.Forsyth		error("unknown operator '" + name + "'");
482*37da2899SCharles.Forsyth	}
483*37da2899SCharles.Forsyth}
484*37da2899SCharles.Forsyth
485*37da2899SCharles.Forsythinitpats()
486*37da2899SCharles.Forsyth{
487*37da2899SCharles.Forsyth	pats = array[len pats0] of Regex->Re;
488*37da2899SCharles.Forsyth	for (i := 0; i < len pats0; i++) {
489*37da2899SCharles.Forsyth		(re, e) := regex->compile("^" + pats0[i] + "$", 0);
490*37da2899SCharles.Forsyth		if (re == nil) {
491*37da2899SCharles.Forsyth			sys->fprint(stderr, "fc: bad number pattern '^%s$': %s\n", pats0[i], e);
492*37da2899SCharles.Forsyth			raise "fail:error";
493*37da2899SCharles.Forsyth		}
494*37da2899SCharles.Forsyth		pats[i] = re;
495*37da2899SCharles.Forsyth	}
496*37da2899SCharles.Forsyth}
497*37da2899SCharles.Forsyth
498*37da2899SCharles.Forsythnumber(s: string): (int, real)
499*37da2899SCharles.Forsyth{
500*37da2899SCharles.Forsyth	case s {
501*37da2899SCharles.Forsyth	"pi" or
502*37da2899SCharles.Forsyth	"π" =>
503*37da2899SCharles.Forsyth		return (1, Math->Pi);
504*37da2899SCharles.Forsyth	"e" =>
505*37da2899SCharles.Forsyth		return (1, 2.71828182845904509);
506*37da2899SCharles.Forsyth	"nan" or
507*37da2899SCharles.Forsyth	"NaN" =>
508*37da2899SCharles.Forsyth		return (1, Math->NaN);
509*37da2899SCharles.Forsyth	"-nan" or
510*37da2899SCharles.Forsyth	"-NaN" =>
511*37da2899SCharles.Forsyth		return (1, -Math->NaN);
512*37da2899SCharles.Forsyth	"infinity" or
513*37da2899SCharles.Forsyth	"Infinity" or
514*37da2899SCharles.Forsyth	"∞" =>
515*37da2899SCharles.Forsyth		return (1, Math->Infinity);
516*37da2899SCharles.Forsyth	"-infinity" or
517*37da2899SCharles.Forsyth	"-Infinity" or
518*37da2899SCharles.Forsyth	"-∞" =>
519*37da2899SCharles.Forsyth		return (1, -Math->Infinity);
520*37da2899SCharles.Forsyth	"eps" or
521*37da2899SCharles.Forsyth	"macheps" =>
522*37da2899SCharles.Forsyth		return (1, Math->MachEps);
523*37da2899SCharles.Forsyth	}
524*37da2899SCharles.Forsyth	for (i := 0; i < len pats; i++) {
525*37da2899SCharles.Forsyth		if (regex->execute(pats[i], s) != nil)
526*37da2899SCharles.Forsyth			break;
527*37da2899SCharles.Forsyth	}
528*37da2899SCharles.Forsyth	case i {
529*37da2899SCharles.Forsyth	nHEX =>
530*37da2899SCharles.Forsyth		return base(s, 2, 16);
531*37da2899SCharles.Forsyth	nBINARY =>
532*37da2899SCharles.Forsyth		return base(s, 2, 2);
533*37da2899SCharles.Forsyth	nOCTAL =>
534*37da2899SCharles.Forsyth		return base(s, 1, 8);
535*37da2899SCharles.Forsyth	nRADIX1 =>
536*37da2899SCharles.Forsyth		return base(s, 2, int s);
537*37da2899SCharles.Forsyth	nRADIX2 =>
538*37da2899SCharles.Forsyth		return base(s, 3, int s);
539*37da2899SCharles.Forsyth	nREAL =>
540*37da2899SCharles.Forsyth		return (1, real s);
541*37da2899SCharles.Forsyth	nCHAR =>
542*37da2899SCharles.Forsyth		return (1, real s[1]);
543*37da2899SCharles.Forsyth	}
544*37da2899SCharles.Forsyth	return (0, Math->NaN);
545*37da2899SCharles.Forsyth}
546*37da2899SCharles.Forsyth
547*37da2899SCharles.Forsythbase(s: string, i: int, radix: int): (int, real)
548*37da2899SCharles.Forsyth{
549*37da2899SCharles.Forsyth	neg := s[0] == '-';
550*37da2899SCharles.Forsyth	if (neg)
551*37da2899SCharles.Forsyth		i++;
552*37da2899SCharles.Forsyth	n := big 0;
553*37da2899SCharles.Forsyth	if (radix == 10)
554*37da2899SCharles.Forsyth		n = big s[i:];
555*37da2899SCharles.Forsyth	else if (radix == 0 || radix > 36)
556*37da2899SCharles.Forsyth		return (0, Math->NaN);
557*37da2899SCharles.Forsyth	else {
558*37da2899SCharles.Forsyth		for (; i < len s; i++) {
559*37da2899SCharles.Forsyth			c := s[i];
560*37da2899SCharles.Forsyth			if ('0' <= c && c <= '9')
561*37da2899SCharles.Forsyth				n = (n * big radix) + big(c - '0');
562*37da2899SCharles.Forsyth			else if ('a' <= c && c < 'a' + radix - 10)
563*37da2899SCharles.Forsyth				n = (n * big radix) + big(c - 'a' + 10);
564*37da2899SCharles.Forsyth			else if ('A' <= c && c  < 'A' + radix - 10)
565*37da2899SCharles.Forsyth				n = (n * big radix) + big(c - 'A' + 10);
566*37da2899SCharles.Forsyth			else
567*37da2899SCharles.Forsyth				return (0, Math->NaN);
568*37da2899SCharles.Forsyth		}
569*37da2899SCharles.Forsyth	}
570*37da2899SCharles.Forsyth	if (neg)
571*37da2899SCharles.Forsyth		n = -n;
572*37da2899SCharles.Forsyth	return (1, real n);
573*37da2899SCharles.Forsyth}
574*37da2899SCharles.Forsyth
575*37da2899SCharles.Forsyth# stolen from /appl/cmd/sh/expr.b
576*37da2899SCharles.Forsythbig2string(n: big, radix: int): string
577*37da2899SCharles.Forsyth{
578*37da2899SCharles.Forsyth	if (neg := n < big 0) {
579*37da2899SCharles.Forsyth		n = -n;
580*37da2899SCharles.Forsyth	}
581*37da2899SCharles.Forsyth	s := "";
582*37da2899SCharles.Forsyth	do {
583*37da2899SCharles.Forsyth		c: int;
584*37da2899SCharles.Forsyth		d := int (n % big radix);
585*37da2899SCharles.Forsyth		if (d < 10)
586*37da2899SCharles.Forsyth			c = '0' + d;
587*37da2899SCharles.Forsyth		else
588*37da2899SCharles.Forsyth			c = 'a' + d - 10;
589*37da2899SCharles.Forsyth		s[len s] = c;
590*37da2899SCharles.Forsyth		n /= big radix;
591*37da2899SCharles.Forsyth	} while (n > big 0);
592*37da2899SCharles.Forsyth	t := s;
593*37da2899SCharles.Forsyth	for (i := len s - 1; i >= 0; i--)
594*37da2899SCharles.Forsyth		t[len s - 1 - i] = s[i];
595*37da2899SCharles.Forsyth	if (radix != 10)
596*37da2899SCharles.Forsyth		t = string radix + "r" + t;
597*37da2899SCharles.Forsyth	if (neg)
598*37da2899SCharles.Forsyth		return "-" + t;
599*37da2899SCharles.Forsyth	return t;
600*37da2899SCharles.Forsyth}
601*37da2899SCharles.Forsyth
602*37da2899SCharles.Forsytherror(e: string)
603*37da2899SCharles.Forsyth{
604*37da2899SCharles.Forsyth	sys->fprint(stderr, "fc: %s\n", e);
605*37da2899SCharles.Forsyth	raise "fail:error";
606*37da2899SCharles.Forsyth}
607*37da2899SCharles.Forsyth
608*37da2899SCharles.Forsythassure(n: int, opname: string)
609*37da2899SCharles.Forsyth{
610*37da2899SCharles.Forsyth	if (len stack < n)
611*37da2899SCharles.Forsyth		error("stack too small for op '" + opname + "'");
612*37da2899SCharles.Forsyth}
613