xref: /inferno-os/appl/cmd/calc.b (revision 0d13e2d8f571afd10965c136375ea336c9f5d9f2)
1*0d13e2d8SCharles.Forsythimplement Calc;
2*0d13e2d8SCharles.Forsyth
3*0d13e2d8SCharles.Forsythinclude "sys.m";
4*0d13e2d8SCharles.Forsyth	sys: Sys;
5*0d13e2d8SCharles.Forsythinclude "draw.m";
6*0d13e2d8SCharles.Forsythinclude "arg.m";
7*0d13e2d8SCharles.Forsyth	arg: Arg;
8*0d13e2d8SCharles.Forsythinclude "bufio.m";
9*0d13e2d8SCharles.Forsyth	bufio: Bufio;
10*0d13e2d8SCharles.Forsyth	Iobuf: import bufio;
11*0d13e2d8SCharles.Forsythinclude "math.m";
12*0d13e2d8SCharles.Forsyth	maths: Math;
13*0d13e2d8SCharles.Forsythinclude "rand.m";
14*0d13e2d8SCharles.Forsyth	rand: Rand;
15*0d13e2d8SCharles.Forsythinclude "daytime.m";
16*0d13e2d8SCharles.Forsyth	daytime: Daytime;
17*0d13e2d8SCharles.Forsyth
18*0d13e2d8SCharles.ForsythCalc: module
19*0d13e2d8SCharles.Forsyth{
20*0d13e2d8SCharles.Forsyth	init: fn(nil: ref Draw->Context, argv: list of string);
21*0d13e2d8SCharles.Forsyth};
22*0d13e2d8SCharles.Forsyth
23*0d13e2d8SCharles.Forsythinit(nil: ref Draw->Context, args: list of string)
24*0d13e2d8SCharles.Forsyth{
25*0d13e2d8SCharles.Forsyth	sys = load Sys Sys->PATH;
26*0d13e2d8SCharles.Forsyth	arg = load Arg Arg->PATH;
27*0d13e2d8SCharles.Forsyth	bufio = load Bufio Bufio->PATH;
28*0d13e2d8SCharles.Forsyth	maths = load Math Math->PATH;
29*0d13e2d8SCharles.Forsyth	rand = load Rand Rand->PATH;
30*0d13e2d8SCharles.Forsyth	daytime = load Daytime Daytime->PATH;
31*0d13e2d8SCharles.Forsyth
32*0d13e2d8SCharles.Forsyth	maths->FPcontrol(0, Math->INVAL|Math->ZDIV|Math->OVFL|Math->UNFL|Math->INEX);
33*0d13e2d8SCharles.Forsyth
34*0d13e2d8SCharles.Forsyth	rand->init(daytime->now());
35*0d13e2d8SCharles.Forsyth	rand->init(rand->rand(Big)^rand->rand(Big));
36*0d13e2d8SCharles.Forsyth	daytime = nil;
37*0d13e2d8SCharles.Forsyth
38*0d13e2d8SCharles.Forsyth	arg->init(args);
39*0d13e2d8SCharles.Forsyth	while((c := arg->opt()) != 0){
40*0d13e2d8SCharles.Forsyth		case(c){
41*0d13e2d8SCharles.Forsyth		'b' =>
42*0d13e2d8SCharles.Forsyth			bits = 1;
43*0d13e2d8SCharles.Forsyth		'd' =>
44*0d13e2d8SCharles.Forsyth			debug = 1;
45*0d13e2d8SCharles.Forsyth		's' =>
46*0d13e2d8SCharles.Forsyth			strict = 1;
47*0d13e2d8SCharles.Forsyth		}
48*0d13e2d8SCharles.Forsyth	}
49*0d13e2d8SCharles.Forsyth	gargs = args = arg->argv();
50*0d13e2d8SCharles.Forsyth	if(args == nil){
51*0d13e2d8SCharles.Forsyth		stdin = 1;
52*0d13e2d8SCharles.Forsyth		bin = bufio->fopen(sys->fildes(0), Sys->OREAD);
53*0d13e2d8SCharles.Forsyth	}
54*0d13e2d8SCharles.Forsyth	else if(tl args == nil)
55*0d13e2d8SCharles.Forsyth		bin = bufio->open(hd args, Sys->OREAD);
56*0d13e2d8SCharles.Forsyth
57*0d13e2d8SCharles.Forsyth	syms = array[Hash] of ref Sym;
58*0d13e2d8SCharles.Forsyth
59*0d13e2d8SCharles.Forsyth	pushscope();
60*0d13e2d8SCharles.Forsyth	for(i := 0; keyw[i].t0 != nil; i++)
61*0d13e2d8SCharles.Forsyth		enter(keyw[i].t0, keyw[i].t1);
62*0d13e2d8SCharles.Forsyth	for(i = 0; conw[i].t0 != nil; i++)
63*0d13e2d8SCharles.Forsyth		adddec(conw[i].t0, Ocon, conw[i].t1, 0);
64*0d13e2d8SCharles.Forsyth	for(i = 0; varw[i].t0 != nil; i++)
65*0d13e2d8SCharles.Forsyth		adddec(varw[i].t0, Ovar, varw[i].t1, 0);
66*0d13e2d8SCharles.Forsyth	for(i = 0; funw[i].t0 != nil; i++)
67*0d13e2d8SCharles.Forsyth		adddec(funw[i].t0, Olfun, real funw[i].t1, funw[i].t2);
68*0d13e2d8SCharles.Forsyth
69*0d13e2d8SCharles.Forsyth	deg = lookup(Deg).dec;
70*0d13e2d8SCharles.Forsyth	pbase = lookup(Base).dec;
71*0d13e2d8SCharles.Forsyth	errdec = ref Dec;
72*0d13e2d8SCharles.Forsyth
73*0d13e2d8SCharles.Forsyth	pushscope();
74*0d13e2d8SCharles.Forsyth	for(;;){
75*0d13e2d8SCharles.Forsyth		e: ref Node;
76*0d13e2d8SCharles.Forsyth
77*0d13e2d8SCharles.Forsyth		{
78*0d13e2d8SCharles.Forsyth			t := lex();
79*0d13e2d8SCharles.Forsyth			if(t == Oeof)
80*0d13e2d8SCharles.Forsyth				break;
81*0d13e2d8SCharles.Forsyth			unlex(t);
82*0d13e2d8SCharles.Forsyth			ls := lexes;
83*0d13e2d8SCharles.Forsyth			e = stat(1);
84*0d13e2d8SCharles.Forsyth			ckstat(e, Onothing, 0);
85*0d13e2d8SCharles.Forsyth			if(ls == lexes){
86*0d13e2d8SCharles.Forsyth				t = lex();
87*0d13e2d8SCharles.Forsyth				error(nil, sys->sprint("syntax error near %s", opstring(t)));
88*0d13e2d8SCharles.Forsyth				unlex(t);
89*0d13e2d8SCharles.Forsyth			}
90*0d13e2d8SCharles.Forsyth			consume(Onl);
91*0d13e2d8SCharles.Forsyth		}
92*0d13e2d8SCharles.Forsyth		exception ex{
93*0d13e2d8SCharles.Forsyth			Eeof =>
94*0d13e2d8SCharles.Forsyth				e = nil;
95*0d13e2d8SCharles.Forsyth				err("premature eof");
96*0d13e2d8SCharles.Forsyth				skip();
97*0d13e2d8SCharles.Forsyth			"*" =>
98*0d13e2d8SCharles.Forsyth				e = nil;
99*0d13e2d8SCharles.Forsyth				err(ex);
100*0d13e2d8SCharles.Forsyth				skip();
101*0d13e2d8SCharles.Forsyth		}
102*0d13e2d8SCharles.Forsyth		if(0 && debug)
103*0d13e2d8SCharles.Forsyth			prtree(e, 0);
104*0d13e2d8SCharles.Forsyth		if(e != nil && e.op != Ofn){
105*0d13e2d8SCharles.Forsyth			(k, v) := (Onothing, 0.0);
106*0d13e2d8SCharles.Forsyth			{
107*0d13e2d8SCharles.Forsyth				(k, v) = estat(e);
108*0d13e2d8SCharles.Forsyth			}
109*0d13e2d8SCharles.Forsyth			exception ex{
110*0d13e2d8SCharles.Forsyth			"*" =>
111*0d13e2d8SCharles.Forsyth				e = nil;
112*0d13e2d8SCharles.Forsyth				err(ex);
113*0d13e2d8SCharles.Forsyth			}
114*0d13e2d8SCharles.Forsyth			if(pexp(e))
115*0d13e2d8SCharles.Forsyth				printnum(v, "\n");
116*0d13e2d8SCharles.Forsyth			if(k == Oexit)
117*0d13e2d8SCharles.Forsyth				exit;
118*0d13e2d8SCharles.Forsyth		}
119*0d13e2d8SCharles.Forsyth	}
120*0d13e2d8SCharles.Forsyth	popscope();
121*0d13e2d8SCharles.Forsyth	popscope();
122*0d13e2d8SCharles.Forsyth}
123*0d13e2d8SCharles.Forsyth
124*0d13e2d8SCharles.Forsythbits: int;
125*0d13e2d8SCharles.Forsythdebug: int;
126*0d13e2d8SCharles.Forsythstrict: int;
127*0d13e2d8SCharles.Forsyth
128*0d13e2d8SCharles.ForsythNone: con -2;
129*0d13e2d8SCharles.ForsythEof: con -1;
130*0d13e2d8SCharles.ForsythEeof: con "eof";
131*0d13e2d8SCharles.Forsyth
132*0d13e2d8SCharles.ForsythHash: con 16;
133*0d13e2d8SCharles.ForsythBig: con 1<<30;
134*0d13e2d8SCharles.ForsythMaxint: con 16r7FFFFFFF;
135*0d13e2d8SCharles.ForsythNan: con Math->NaN;
136*0d13e2d8SCharles.ForsythInfinity: con Math->Infinity;
137*0d13e2d8SCharles.ForsythPi: con Math->Pi;
138*0d13e2d8SCharles.ForsythEps: con 1E-10;
139*0d13e2d8SCharles.ForsythBigeps: con 1E-2;
140*0d13e2d8SCharles.ForsythLn2: con 0.6931471805599453;
141*0d13e2d8SCharles.ForsythLn10: con 2.302585092994046;
142*0d13e2d8SCharles.ForsythEuler: con 2.71828182845904523536;
143*0d13e2d8SCharles.ForsythGamma: con 0.57721566490153286060;
144*0d13e2d8SCharles.ForsythPhi: con 1.61803398874989484820;
145*0d13e2d8SCharles.Forsyth
146*0d13e2d8SCharles.ForsythOeof,
147*0d13e2d8SCharles.ForsythOstring, Onum, Oident, Ocon, Ovar, Ofun, Olfun,
148*0d13e2d8SCharles.ForsythOadd, Osub, Omul, Odiv, Omod, Oidiv, Oexp, Oand, Oor, Oxor, Olsh, Orsh,
149*0d13e2d8SCharles.ForsythOadde, Osube, Omule, Odive, Omode, Oidive, Oexpe, Oande, Oore, Oxore, Olshe, Orshe,
150*0d13e2d8SCharles.ForsythOeq, One, Ogt, Olt, Oge, Ole,
151*0d13e2d8SCharles.ForsythOinc, Opreinc, Opostinc, Odec, Opredec, Opostdec,
152*0d13e2d8SCharles.ForsythOandand, Ooror,
153*0d13e2d8SCharles.ForsythOexc, Onot, Ofact, Ocom,
154*0d13e2d8SCharles.ForsythOas, Odas,
155*0d13e2d8SCharles.ForsythOplus, Ominus, Oinv,
156*0d13e2d8SCharles.ForsythOcomma, Oscomma, Oquest, Ocolon,
157*0d13e2d8SCharles.ForsythOnand, Onor, Oimp, Oimpby, Oiff,
158*0d13e2d8SCharles.ForsythOlbr, Orbr, Olcbr, Orcbr,  Oscolon, Onl,
159*0d13e2d8SCharles.ForsythOnothing,
160*0d13e2d8SCharles.ForsythOprint, Oread,
161*0d13e2d8SCharles.ForsythOif, Oelse, Ofor, Owhile, Odo, Obreak, Ocont, Oexit, Oret, Ofn, Oinclude,
162*0d13e2d8SCharles.ForsythOsigma, Opi, Ocfrac, Oderiv, Ointeg, Osolve,
163*0d13e2d8SCharles.ForsythOlog, Olog10, Olog2, Ologb, Oexpf, Opow, Osqrt, Ocbrt, Ofloor, Oceil, Omin, Omax, Oabs, Ogamma, Osign, Oint, Ofrac, Oround, Oerf, Oatan2, Osin, Ocos, Otan, Oasin, Oacos, Oatan, Osinh, Ocosh, Otanh, Oasinh, Oacosh, Oatanh, Orand,
164*0d13e2d8SCharles.ForsythOlast: con iota;
165*0d13e2d8SCharles.Forsyth
166*0d13e2d8SCharles.ForsythBinary: con (1<<8);
167*0d13e2d8SCharles.ForsythPreunary:	con (1<<9);
168*0d13e2d8SCharles.ForsythPostunary: con (1<<10);
169*0d13e2d8SCharles.ForsythAssoc: con (1<<11);
170*0d13e2d8SCharles.ForsythRassoc: con (1<<12);
171*0d13e2d8SCharles.ForsythPrec: con Binary-1;
172*0d13e2d8SCharles.Forsyth
173*0d13e2d8SCharles.Forsythopss := array[Olast] of
174*0d13e2d8SCharles.Forsyth{
175*0d13e2d8SCharles.Forsyth	"eof",
176*0d13e2d8SCharles.Forsyth	"string",
177*0d13e2d8SCharles.Forsyth	"number",
178*0d13e2d8SCharles.Forsyth	"identifier",
179*0d13e2d8SCharles.Forsyth	"constant",
180*0d13e2d8SCharles.Forsyth	"variable",
181*0d13e2d8SCharles.Forsyth	"function",
182*0d13e2d8SCharles.Forsyth	"library function",
183*0d13e2d8SCharles.Forsyth	"+",
184*0d13e2d8SCharles.Forsyth	"-",
185*0d13e2d8SCharles.Forsyth	"*",
186*0d13e2d8SCharles.Forsyth	"/",
187*0d13e2d8SCharles.Forsyth	"%",
188*0d13e2d8SCharles.Forsyth	"//",
189*0d13e2d8SCharles.Forsyth	"&",
190*0d13e2d8SCharles.Forsyth	"|",
191*0d13e2d8SCharles.Forsyth	"^",
192*0d13e2d8SCharles.Forsyth	"<<",
193*0d13e2d8SCharles.Forsyth	">>",
194*0d13e2d8SCharles.Forsyth	"+=",
195*0d13e2d8SCharles.Forsyth	"-=",
196*0d13e2d8SCharles.Forsyth	"*=",
197*0d13e2d8SCharles.Forsyth	"/=",
198*0d13e2d8SCharles.Forsyth	"%=",
199*0d13e2d8SCharles.Forsyth	"//=",
200*0d13e2d8SCharles.Forsyth	"&=",
201*0d13e2d8SCharles.Forsyth	"|=",
202*0d13e2d8SCharles.Forsyth	"^=",
203*0d13e2d8SCharles.Forsyth	"<<=",
204*0d13e2d8SCharles.Forsyth	">>=",
205*0d13e2d8SCharles.Forsyth	"==",
206*0d13e2d8SCharles.Forsyth	"!=",
207*0d13e2d8SCharles.Forsyth	">",
208*0d13e2d8SCharles.Forsyth	"<",
209*0d13e2d8SCharles.Forsyth	">=",
210*0d13e2d8SCharles.Forsyth	"<=",
211*0d13e2d8SCharles.Forsyth	"++",
212*0d13e2d8SCharles.Forsyth	"++",
213*0d13e2d8SCharles.Forsyth	"++",
214*0d13e2d8SCharles.Forsyth	"--",
215*0d13e2d8SCharles.Forsyth	"--",
216*0d13e2d8SCharles.Forsyth	"--",
217*0d13e2d8SCharles.Forsyth	"**",
218*0d13e2d8SCharles.Forsyth	"&&",
219*0d13e2d8SCharles.Forsyth	"||",
220*0d13e2d8SCharles.Forsyth	"!",
221*0d13e2d8SCharles.Forsyth	"!",
222*0d13e2d8SCharles.Forsyth	"!",
223*0d13e2d8SCharles.Forsyth	"~",
224*0d13e2d8SCharles.Forsyth	"=",
225*0d13e2d8SCharles.Forsyth	":=",
226*0d13e2d8SCharles.Forsyth	"+",
227*0d13e2d8SCharles.Forsyth	"-",
228*0d13e2d8SCharles.Forsyth	"1/",
229*0d13e2d8SCharles.Forsyth	",",
230*0d13e2d8SCharles.Forsyth	",",
231*0d13e2d8SCharles.Forsyth	"?",
232*0d13e2d8SCharles.Forsyth	":",
233*0d13e2d8SCharles.Forsyth	"↑",
234*0d13e2d8SCharles.Forsyth	"↓",
235*0d13e2d8SCharles.Forsyth	"->",
236*0d13e2d8SCharles.Forsyth	"<-",
237*0d13e2d8SCharles.Forsyth	"<->",
238*0d13e2d8SCharles.Forsyth	"(",
239*0d13e2d8SCharles.Forsyth	")",
240*0d13e2d8SCharles.Forsyth	"{",
241*0d13e2d8SCharles.Forsyth	"}",
242*0d13e2d8SCharles.Forsyth	";",
243*0d13e2d8SCharles.Forsyth	"\n",
244*0d13e2d8SCharles.Forsyth	"",
245*0d13e2d8SCharles.Forsyth};
246*0d13e2d8SCharles.Forsyth
247*0d13e2d8SCharles.Forsythops := array[Olast] of
248*0d13e2d8SCharles.Forsyth{
249*0d13e2d8SCharles.Forsyth	Oeof =>	0,
250*0d13e2d8SCharles.Forsyth	Ostring =>	17,
251*0d13e2d8SCharles.Forsyth	Onum =>	17,
252*0d13e2d8SCharles.Forsyth	Oident =>	17,
253*0d13e2d8SCharles.Forsyth	Ocon =>	17,
254*0d13e2d8SCharles.Forsyth	Ovar =>	17,
255*0d13e2d8SCharles.Forsyth	Ofun =>	17,
256*0d13e2d8SCharles.Forsyth	Olfun =>	17,
257*0d13e2d8SCharles.Forsyth	Oadd =>	12|Binary|Assoc|Preunary,
258*0d13e2d8SCharles.Forsyth	Osub =>	12|Binary|Preunary,
259*0d13e2d8SCharles.Forsyth	Omul =>	13|Binary|Assoc,
260*0d13e2d8SCharles.Forsyth	Odiv =>	13|Binary,
261*0d13e2d8SCharles.Forsyth	Omod =>	13|Binary,
262*0d13e2d8SCharles.Forsyth	Oidiv =>	13|Binary,
263*0d13e2d8SCharles.Forsyth	Oexp =>	14|Binary|Rassoc,
264*0d13e2d8SCharles.Forsyth	Oand =>	8|Binary|Assoc,
265*0d13e2d8SCharles.Forsyth	Oor =>	6|Binary|Assoc,
266*0d13e2d8SCharles.Forsyth	Oxor =>	7|Binary|Assoc,
267*0d13e2d8SCharles.Forsyth	Olsh =>	11|Binary,
268*0d13e2d8SCharles.Forsyth	Orsh =>	11|Binary,
269*0d13e2d8SCharles.Forsyth	Oadde =>	2|Binary|Rassoc,
270*0d13e2d8SCharles.Forsyth	Osube =>	2|Binary|Rassoc,
271*0d13e2d8SCharles.Forsyth	Omule =>	2|Binary|Rassoc,
272*0d13e2d8SCharles.Forsyth	Odive =>	2|Binary|Rassoc,
273*0d13e2d8SCharles.Forsyth	Omode =>	2|Binary|Rassoc,
274*0d13e2d8SCharles.Forsyth	Oidive =>	2|Binary|Rassoc,
275*0d13e2d8SCharles.Forsyth	Oexpe =>	2|Binary|Rassoc,
276*0d13e2d8SCharles.Forsyth	Oande =>	2|Binary|Rassoc,
277*0d13e2d8SCharles.Forsyth	Oore =>	2|Binary|Rassoc,
278*0d13e2d8SCharles.Forsyth	Oxore =>	2|Binary|Rassoc,
279*0d13e2d8SCharles.Forsyth	Olshe =>	2|Binary|Rassoc,
280*0d13e2d8SCharles.Forsyth	Orshe =>	2|Binary|Rassoc,
281*0d13e2d8SCharles.Forsyth	Oeq =>	9|Binary,
282*0d13e2d8SCharles.Forsyth	One =>	9|Binary,
283*0d13e2d8SCharles.Forsyth	Ogt =>	10|Binary,
284*0d13e2d8SCharles.Forsyth	Olt =>	10|Binary,
285*0d13e2d8SCharles.Forsyth	Oge =>	10|Binary,
286*0d13e2d8SCharles.Forsyth	Ole =>	10|Binary,
287*0d13e2d8SCharles.Forsyth	Oinc =>	15|Rassoc|Preunary|Postunary,
288*0d13e2d8SCharles.Forsyth	Opreinc =>	15|Rassoc|Preunary,
289*0d13e2d8SCharles.Forsyth	Opostinc =>	15|Rassoc|Postunary,
290*0d13e2d8SCharles.Forsyth	Odec =>	15|Rassoc|Preunary|Postunary,
291*0d13e2d8SCharles.Forsyth	Opredec =>	15|Rassoc|Preunary,
292*0d13e2d8SCharles.Forsyth	Opostdec =>	15|Rassoc|Postunary,
293*0d13e2d8SCharles.Forsyth	Oandand =>	5|Binary|Assoc,
294*0d13e2d8SCharles.Forsyth	Ooror =>	4|Binary|Assoc,
295*0d13e2d8SCharles.Forsyth	Oexc =>	15|Rassoc|Preunary|Postunary,
296*0d13e2d8SCharles.Forsyth	Onot =>	15|Rassoc|Preunary,
297*0d13e2d8SCharles.Forsyth	Ofact =>	15|Rassoc|Postunary,
298*0d13e2d8SCharles.Forsyth	Ocom =>	15|Rassoc|Preunary,
299*0d13e2d8SCharles.Forsyth	Oas =>	2|Binary|Rassoc,
300*0d13e2d8SCharles.Forsyth	Odas =>	2|Binary|Rassoc,
301*0d13e2d8SCharles.Forsyth	Oplus =>	15|Rassoc|Preunary,
302*0d13e2d8SCharles.Forsyth	Ominus =>	15|Rassoc|Preunary,
303*0d13e2d8SCharles.Forsyth	Oinv =>	15|Rassoc|Postunary,
304*0d13e2d8SCharles.Forsyth	Ocomma =>	1|Binary|Assoc,
305*0d13e2d8SCharles.Forsyth	Oscomma =>	1|Binary|Assoc,
306*0d13e2d8SCharles.Forsyth	Oquest =>	3|Binary|Rassoc,
307*0d13e2d8SCharles.Forsyth	Ocolon =>	3|Binary|Rassoc,
308*0d13e2d8SCharles.Forsyth	Onand =>	8|Binary,
309*0d13e2d8SCharles.Forsyth	Onor =>	6|Binary,
310*0d13e2d8SCharles.Forsyth	Oimp =>	9|Binary,
311*0d13e2d8SCharles.Forsyth	Oimpby =>	9|Binary,
312*0d13e2d8SCharles.Forsyth	Oiff =>	10|Binary|Assoc,
313*0d13e2d8SCharles.Forsyth	Olbr =>	16,
314*0d13e2d8SCharles.Forsyth	Orbr =>	16,
315*0d13e2d8SCharles.Forsyth	Onothing =>	0,
316*0d13e2d8SCharles.Forsyth};
317*0d13e2d8SCharles.Forsyth
318*0d13e2d8SCharles.ForsythDeg: con "degrees";
319*0d13e2d8SCharles.ForsythBase: con "printbase";
320*0d13e2d8SCharles.ForsythLimit: con "solvelimit";
321*0d13e2d8SCharles.ForsythStep: con "solvestep";
322*0d13e2d8SCharles.Forsyth
323*0d13e2d8SCharles.Forsythkeyw := array[] of
324*0d13e2d8SCharles.Forsyth{
325*0d13e2d8SCharles.Forsyth	("include",	Oinclude),
326*0d13e2d8SCharles.Forsyth	("if",	Oif),
327*0d13e2d8SCharles.Forsyth	("else",	Oelse),
328*0d13e2d8SCharles.Forsyth	("for",	Ofor),
329*0d13e2d8SCharles.Forsyth	("while",	Owhile),
330*0d13e2d8SCharles.Forsyth	("do",	Odo),
331*0d13e2d8SCharles.Forsyth	("break",	Obreak),
332*0d13e2d8SCharles.Forsyth	("continue",	Ocont),
333*0d13e2d8SCharles.Forsyth	("exit",	Oexit),
334*0d13e2d8SCharles.Forsyth	("return",	Oret),
335*0d13e2d8SCharles.Forsyth	("print",	Oprint),
336*0d13e2d8SCharles.Forsyth	("read",	Oread),
337*0d13e2d8SCharles.Forsyth	("fn",	Ofn),
338*0d13e2d8SCharles.Forsyth	("",	0),
339*0d13e2d8SCharles.Forsyth};
340*0d13e2d8SCharles.Forsyth
341*0d13e2d8SCharles.Forsythconw := array[] of
342*0d13e2d8SCharles.Forsyth{
343*0d13e2d8SCharles.Forsyth	("π",	Pi),
344*0d13e2d8SCharles.Forsyth	("Pi", Pi),
345*0d13e2d8SCharles.Forsyth	("e",	Euler),
346*0d13e2d8SCharles.Forsyth	("γ",	Gamma),
347*0d13e2d8SCharles.Forsyth	("Gamma",	Gamma),
348*0d13e2d8SCharles.Forsyth	("φ",	Phi),
349*0d13e2d8SCharles.Forsyth	("Phi",	Phi),
350*0d13e2d8SCharles.Forsyth	("∞",	Infinity),
351*0d13e2d8SCharles.Forsyth	("Infinity",	Infinity),
352*0d13e2d8SCharles.Forsyth	("NaN",	Nan),
353*0d13e2d8SCharles.Forsyth	("Nan",	Nan),
354*0d13e2d8SCharles.Forsyth	("nan",	Nan),
355*0d13e2d8SCharles.Forsyth	("",	0.0),
356*0d13e2d8SCharles.Forsyth};
357*0d13e2d8SCharles.Forsyth
358*0d13e2d8SCharles.Forsythvarw := array[] of
359*0d13e2d8SCharles.Forsyth{
360*0d13e2d8SCharles.Forsyth	(Deg, 0.0),
361*0d13e2d8SCharles.Forsyth	(Base, 10.0),
362*0d13e2d8SCharles.Forsyth	(Limit, 100.0),
363*0d13e2d8SCharles.Forsyth	(Step, 1.0),
364*0d13e2d8SCharles.Forsyth	("", 0.0),
365*0d13e2d8SCharles.Forsyth};
366*0d13e2d8SCharles.Forsyth
367*0d13e2d8SCharles.Forsythfunw := array[] of
368*0d13e2d8SCharles.Forsyth{
369*0d13e2d8SCharles.Forsyth	("log",	Olog,	1),
370*0d13e2d8SCharles.Forsyth	("ln",		Olog,	1),
371*0d13e2d8SCharles.Forsyth	("log10",	Olog10,	1),
372*0d13e2d8SCharles.Forsyth	("log2",	Olog2,	1),
373*0d13e2d8SCharles.Forsyth	("logb",	Ologb,	2),
374*0d13e2d8SCharles.Forsyth	("exp",	Oexpf,	1),
375*0d13e2d8SCharles.Forsyth	("pow",	Opow,	2),
376*0d13e2d8SCharles.Forsyth	("sqrt",	Osqrt,	1),
377*0d13e2d8SCharles.Forsyth	("cbrt",	Ocbrt,	1),
378*0d13e2d8SCharles.Forsyth	("floor",	Ofloor,	1),
379*0d13e2d8SCharles.Forsyth	("ceiling",	Oceil,	1),
380*0d13e2d8SCharles.Forsyth	("min",	Omin,	2),
381*0d13e2d8SCharles.Forsyth	("max",	Omax,	2),
382*0d13e2d8SCharles.Forsyth	("abs",	Oabs,	1),
383*0d13e2d8SCharles.Forsyth	("Γ",	Ogamma,	1),
384*0d13e2d8SCharles.Forsyth	("gamma",	Ogamma,	1),
385*0d13e2d8SCharles.Forsyth	("sign",	Osign,	1),
386*0d13e2d8SCharles.Forsyth	("int",	Oint,	1),
387*0d13e2d8SCharles.Forsyth	("frac",	Ofrac,	1),
388*0d13e2d8SCharles.Forsyth	("round",	Oround,	1),
389*0d13e2d8SCharles.Forsyth	("erf",	Oerf,	1),
390*0d13e2d8SCharles.Forsyth	("atan2",	Oatan2,	2),
391*0d13e2d8SCharles.Forsyth	("sin",	Osin,	1),
392*0d13e2d8SCharles.Forsyth	("cos",	Ocos,	1),
393*0d13e2d8SCharles.Forsyth	("tan",	Otan,	1),
394*0d13e2d8SCharles.Forsyth	("asin",	Oasin,	1),
395*0d13e2d8SCharles.Forsyth	("acos",	Oacos,	1),
396*0d13e2d8SCharles.Forsyth	("atan",	Oatan,	1),
397*0d13e2d8SCharles.Forsyth	("sinh",	Osinh,	1),
398*0d13e2d8SCharles.Forsyth	("cosh",	Ocosh,	1),
399*0d13e2d8SCharles.Forsyth	("tanh",	Otanh,	1),
400*0d13e2d8SCharles.Forsyth	("asinh",	Oasinh,	1),
401*0d13e2d8SCharles.Forsyth	("acosh",	Oacosh,	1),
402*0d13e2d8SCharles.Forsyth	("atanh",	Oatanh,	1),
403*0d13e2d8SCharles.Forsyth	("rand",	Orand,	0),
404*0d13e2d8SCharles.Forsyth	("Σ",	Osigma,	3),
405*0d13e2d8SCharles.Forsyth	("sigma",	Osigma,	3),
406*0d13e2d8SCharles.Forsyth	("Π",	Opi,	3),
407*0d13e2d8SCharles.Forsyth	("pi",	Opi,	3),
408*0d13e2d8SCharles.Forsyth	("cfrac", Ocfrac,	3),
409*0d13e2d8SCharles.Forsyth	("Δ",	Oderiv,	2),
410*0d13e2d8SCharles.Forsyth	("differential",	Oderiv,	2),
411*0d13e2d8SCharles.Forsyth	("∫",	Ointeg,	3),
412*0d13e2d8SCharles.Forsyth	("integral",	Ointeg,	3),
413*0d13e2d8SCharles.Forsyth	("solve",	Osolve,	1),
414*0d13e2d8SCharles.Forsyth	("",	0,	0),
415*0d13e2d8SCharles.Forsyth};
416*0d13e2d8SCharles.Forsyth
417*0d13e2d8SCharles.Forsythstdin: int;
418*0d13e2d8SCharles.Forsythbin: ref Iobuf;
419*0d13e2d8SCharles.Forsythlineno: int = 1;
420*0d13e2d8SCharles.Forsythfile: string;
421*0d13e2d8SCharles.Forsythiostack: list of (int, int, int, string, ref Iobuf);
422*0d13e2d8SCharles.Forsythgeof: int;
423*0d13e2d8SCharles.Forsythgarg: string;
424*0d13e2d8SCharles.Forsythgargs: list of string;
425*0d13e2d8SCharles.Forsythbufc: int = None;
426*0d13e2d8SCharles.Forsythbuft: int = Olast;
427*0d13e2d8SCharles.Forsythlexes: int;
428*0d13e2d8SCharles.Forsythlexval: real;
429*0d13e2d8SCharles.Forsythlexstr: string;
430*0d13e2d8SCharles.Forsythlexsym: ref Sym;
431*0d13e2d8SCharles.Forsythsyms: array of ref Sym;
432*0d13e2d8SCharles.Forsythdeg: ref Dec;
433*0d13e2d8SCharles.Forsythpbase: ref Dec;
434*0d13e2d8SCharles.Forsytherrdec: ref Dec;
435*0d13e2d8SCharles.Forsythinloop: int;
436*0d13e2d8SCharles.Forsythinfn: int;
437*0d13e2d8SCharles.Forsyth
438*0d13e2d8SCharles.ForsythNode: adt
439*0d13e2d8SCharles.Forsyth{
440*0d13e2d8SCharles.Forsyth	op: int;
441*0d13e2d8SCharles.Forsyth	left: cyclic ref Node;
442*0d13e2d8SCharles.Forsyth	right: cyclic ref Node;
443*0d13e2d8SCharles.Forsyth	val: real;
444*0d13e2d8SCharles.Forsyth	str: string;
445*0d13e2d8SCharles.Forsyth	dec: cyclic ref Dec;
446*0d13e2d8SCharles.Forsyth	src: int;
447*0d13e2d8SCharles.Forsyth};
448*0d13e2d8SCharles.Forsyth
449*0d13e2d8SCharles.ForsythDec: adt
450*0d13e2d8SCharles.Forsyth{
451*0d13e2d8SCharles.Forsyth	kind: int;
452*0d13e2d8SCharles.Forsyth	scope: int;
453*0d13e2d8SCharles.Forsyth	sym: cyclic ref Sym;
454*0d13e2d8SCharles.Forsyth	val: real;
455*0d13e2d8SCharles.Forsyth	na: int;
456*0d13e2d8SCharles.Forsyth	code: cyclic ref Node;
457*0d13e2d8SCharles.Forsyth	old: cyclic ref Dec;
458*0d13e2d8SCharles.Forsyth	next: cyclic ref Dec;
459*0d13e2d8SCharles.Forsyth};
460*0d13e2d8SCharles.Forsyth
461*0d13e2d8SCharles.ForsythSym: adt
462*0d13e2d8SCharles.Forsyth{
463*0d13e2d8SCharles.Forsyth	name: string;
464*0d13e2d8SCharles.Forsyth	kind: int;
465*0d13e2d8SCharles.Forsyth	dec: cyclic ref Dec;
466*0d13e2d8SCharles.Forsyth	next: cyclic ref Sym;
467*0d13e2d8SCharles.Forsyth};
468*0d13e2d8SCharles.Forsyth
469*0d13e2d8SCharles.Forsythopstring(t: int): string
470*0d13e2d8SCharles.Forsyth{
471*0d13e2d8SCharles.Forsyth	s := opss[t];
472*0d13e2d8SCharles.Forsyth	if(s != nil)
473*0d13e2d8SCharles.Forsyth		return s;
474*0d13e2d8SCharles.Forsyth	for(i := 0; keyw[i].t0 != nil; i++)
475*0d13e2d8SCharles.Forsyth		if(t == keyw[i].t1)
476*0d13e2d8SCharles.Forsyth			return keyw[i].t0;
477*0d13e2d8SCharles.Forsyth	for(i = 0; funw[i].t0 != nil; i++)
478*0d13e2d8SCharles.Forsyth		if(t == funw[i].t1)
479*0d13e2d8SCharles.Forsyth			return funw[i].t0;
480*0d13e2d8SCharles.Forsyth	return s;
481*0d13e2d8SCharles.Forsyth}
482*0d13e2d8SCharles.Forsyth
483*0d13e2d8SCharles.Forsytherr(s: string)
484*0d13e2d8SCharles.Forsyth{
485*0d13e2d8SCharles.Forsyth	sys->print("error: %s\n", s);
486*0d13e2d8SCharles.Forsyth}
487*0d13e2d8SCharles.Forsyth
488*0d13e2d8SCharles.Forsytherror(n: ref Node, s: string)
489*0d13e2d8SCharles.Forsyth{
490*0d13e2d8SCharles.Forsyth	if(n != nil)
491*0d13e2d8SCharles.Forsyth		lno := n.src;
492*0d13e2d8SCharles.Forsyth	else
493*0d13e2d8SCharles.Forsyth		lno = lineno;
494*0d13e2d8SCharles.Forsyth	s = sys->sprint("line %d: %s", lno, s);
495*0d13e2d8SCharles.Forsyth	if(file != nil)
496*0d13e2d8SCharles.Forsyth		s = sys->sprint("file %s: %s", file, s);
497*0d13e2d8SCharles.Forsyth	raise s;
498*0d13e2d8SCharles.Forsyth}
499*0d13e2d8SCharles.Forsyth
500*0d13e2d8SCharles.Forsythfatal(s: string)
501*0d13e2d8SCharles.Forsyth{
502*0d13e2d8SCharles.Forsyth	sys->print("fatal: %s\n", s);
503*0d13e2d8SCharles.Forsyth	exit;
504*0d13e2d8SCharles.Forsyth}
505*0d13e2d8SCharles.Forsyth
506*0d13e2d8SCharles.Forsythstack(s: string, f: ref Iobuf)
507*0d13e2d8SCharles.Forsyth{
508*0d13e2d8SCharles.Forsyth	iostack = (bufc, buft, lineno, file, bin) :: iostack;
509*0d13e2d8SCharles.Forsyth	bufc = None;
510*0d13e2d8SCharles.Forsyth	buft = Olast;
511*0d13e2d8SCharles.Forsyth	lineno = 1;
512*0d13e2d8SCharles.Forsyth	file = s;
513*0d13e2d8SCharles.Forsyth	bin = f;
514*0d13e2d8SCharles.Forsyth}
515*0d13e2d8SCharles.Forsyth
516*0d13e2d8SCharles.Forsythunstack()
517*0d13e2d8SCharles.Forsyth{
518*0d13e2d8SCharles.Forsyth	(bufc, buft, lineno, file, bin) = hd iostack;
519*0d13e2d8SCharles.Forsyth	iostack = tl iostack;
520*0d13e2d8SCharles.Forsyth}
521*0d13e2d8SCharles.Forsyth
522*0d13e2d8SCharles.Forsythdoinclude(s: string)
523*0d13e2d8SCharles.Forsyth{
524*0d13e2d8SCharles.Forsyth	f := bufio->open(s, Sys->OREAD);
525*0d13e2d8SCharles.Forsyth	if(f == nil)
526*0d13e2d8SCharles.Forsyth		error(nil, sys->sprint("cannot open %s", s));
527*0d13e2d8SCharles.Forsyth	stack(s, f);
528*0d13e2d8SCharles.Forsyth}
529*0d13e2d8SCharles.Forsyth
530*0d13e2d8SCharles.Forsythgetc(): int
531*0d13e2d8SCharles.Forsyth{
532*0d13e2d8SCharles.Forsyth	if((c := bufc) != None)
533*0d13e2d8SCharles.Forsyth		bufc = None;
534*0d13e2d8SCharles.Forsyth	else if(bin != nil)
535*0d13e2d8SCharles.Forsyth		c = bin.getc();
536*0d13e2d8SCharles.Forsyth	else{
537*0d13e2d8SCharles.Forsyth		if(garg == nil){
538*0d13e2d8SCharles.Forsyth			if(gargs == nil){
539*0d13e2d8SCharles.Forsyth				if(geof == 0){
540*0d13e2d8SCharles.Forsyth					geof = 1;
541*0d13e2d8SCharles.Forsyth					c = '\n';
542*0d13e2d8SCharles.Forsyth				}
543*0d13e2d8SCharles.Forsyth				else
544*0d13e2d8SCharles.Forsyth					c = Eof;
545*0d13e2d8SCharles.Forsyth			}
546*0d13e2d8SCharles.Forsyth			else{
547*0d13e2d8SCharles.Forsyth				garg = hd gargs;
548*0d13e2d8SCharles.Forsyth				gargs = tl gargs;
549*0d13e2d8SCharles.Forsyth				c = ' ';
550*0d13e2d8SCharles.Forsyth			}
551*0d13e2d8SCharles.Forsyth		}
552*0d13e2d8SCharles.Forsyth		else{
553*0d13e2d8SCharles.Forsyth			c = garg[0];
554*0d13e2d8SCharles.Forsyth			garg = garg[1: ];
555*0d13e2d8SCharles.Forsyth		}
556*0d13e2d8SCharles.Forsyth	}
557*0d13e2d8SCharles.Forsyth	if(c == Eof && iostack != nil){
558*0d13e2d8SCharles.Forsyth		unstack();
559*0d13e2d8SCharles.Forsyth		return getc();
560*0d13e2d8SCharles.Forsyth	}
561*0d13e2d8SCharles.Forsyth	return c;
562*0d13e2d8SCharles.Forsyth}
563*0d13e2d8SCharles.Forsyth
564*0d13e2d8SCharles.Forsythungetc(c: int)
565*0d13e2d8SCharles.Forsyth{
566*0d13e2d8SCharles.Forsyth	bufc = c;
567*0d13e2d8SCharles.Forsyth}
568*0d13e2d8SCharles.Forsyth
569*0d13e2d8SCharles.Forsythslash(c: int): int
570*0d13e2d8SCharles.Forsyth{
571*0d13e2d8SCharles.Forsyth	if(c != '\\')
572*0d13e2d8SCharles.Forsyth		return c;
573*0d13e2d8SCharles.Forsyth	nc := getc();
574*0d13e2d8SCharles.Forsyth	case(nc){
575*0d13e2d8SCharles.Forsyth	'b' => return '\b';
576*0d13e2d8SCharles.Forsyth	'f' => return '\f';
577*0d13e2d8SCharles.Forsyth	'n' => return '\n';
578*0d13e2d8SCharles.Forsyth	'r' => return '\r';
579*0d13e2d8SCharles.Forsyth	't' => return '\t';
580*0d13e2d8SCharles.Forsyth	}
581*0d13e2d8SCharles.Forsyth	return nc;
582*0d13e2d8SCharles.Forsyth}
583*0d13e2d8SCharles.Forsyth
584*0d13e2d8SCharles.Forsythlexstring(): int
585*0d13e2d8SCharles.Forsyth{
586*0d13e2d8SCharles.Forsyth	sp := "";
587*0d13e2d8SCharles.Forsyth	while((c := getc()) != '"'){
588*0d13e2d8SCharles.Forsyth		if(c == Eof)
589*0d13e2d8SCharles.Forsyth			raise Eeof;
590*0d13e2d8SCharles.Forsyth		sp[len sp] = slash(c);
591*0d13e2d8SCharles.Forsyth	}
592*0d13e2d8SCharles.Forsyth	lexstr = sp;
593*0d13e2d8SCharles.Forsyth	return Ostring;
594*0d13e2d8SCharles.Forsyth}
595*0d13e2d8SCharles.Forsyth
596*0d13e2d8SCharles.Forsythlexchar(): int
597*0d13e2d8SCharles.Forsyth{
598*0d13e2d8SCharles.Forsyth	while((c := getc()) != '\''){
599*0d13e2d8SCharles.Forsyth		if(c == Eof)
600*0d13e2d8SCharles.Forsyth			raise Eeof;
601*0d13e2d8SCharles.Forsyth		lexval = real slash(c);
602*0d13e2d8SCharles.Forsyth	}
603*0d13e2d8SCharles.Forsyth	return Onum;
604*0d13e2d8SCharles.Forsyth}
605*0d13e2d8SCharles.Forsyth
606*0d13e2d8SCharles.Forsythbasev(c: int, base: int): int
607*0d13e2d8SCharles.Forsyth{
608*0d13e2d8SCharles.Forsyth	if(c >= 'a' && c <= 'z')
609*0d13e2d8SCharles.Forsyth		c += 10-'a';
610*0d13e2d8SCharles.Forsyth	else if(c >= 'A' && c <= 'Z')
611*0d13e2d8SCharles.Forsyth		c += 10-'A';
612*0d13e2d8SCharles.Forsyth	else if(c >= '0' && c <= '9')
613*0d13e2d8SCharles.Forsyth		c -= '0';
614*0d13e2d8SCharles.Forsyth	else
615*0d13e2d8SCharles.Forsyth		return -1;
616*0d13e2d8SCharles.Forsyth	if(c >= base)
617*0d13e2d8SCharles.Forsyth		error(nil, "bad digit");
618*0d13e2d8SCharles.Forsyth	return c;
619*0d13e2d8SCharles.Forsyth}
620*0d13e2d8SCharles.Forsyth
621*0d13e2d8SCharles.Forsythlexe(base: int): int
622*0d13e2d8SCharles.Forsyth{
623*0d13e2d8SCharles.Forsyth	neg := 0;
624*0d13e2d8SCharles.Forsyth	v := big 0;
625*0d13e2d8SCharles.Forsyth	c := getc();
626*0d13e2d8SCharles.Forsyth	if(c == '-')
627*0d13e2d8SCharles.Forsyth		neg = 1;
628*0d13e2d8SCharles.Forsyth	else
629*0d13e2d8SCharles.Forsyth		ungetc(c);
630*0d13e2d8SCharles.Forsyth	for(;;){
631*0d13e2d8SCharles.Forsyth		c = getc();
632*0d13e2d8SCharles.Forsyth		cc := basev(c, base);
633*0d13e2d8SCharles.Forsyth		if(cc < 0){
634*0d13e2d8SCharles.Forsyth			ungetc(c);
635*0d13e2d8SCharles.Forsyth			break;
636*0d13e2d8SCharles.Forsyth		}
637*0d13e2d8SCharles.Forsyth		v = big base*v+big cc;
638*0d13e2d8SCharles.Forsyth	}
639*0d13e2d8SCharles.Forsyth	if(neg)
640*0d13e2d8SCharles.Forsyth		v = -v;
641*0d13e2d8SCharles.Forsyth	return int v;
642*0d13e2d8SCharles.Forsyth}
643*0d13e2d8SCharles.Forsyth
644*0d13e2d8SCharles.Forsythlexnum(): int
645*0d13e2d8SCharles.Forsyth{
646*0d13e2d8SCharles.Forsyth	base := 10;
647*0d13e2d8SCharles.Forsyth	exp := 0;
648*0d13e2d8SCharles.Forsyth	r := f := e := 0;
649*0d13e2d8SCharles.Forsyth	v := big 0;
650*0d13e2d8SCharles.Forsyth	c := getc();
651*0d13e2d8SCharles.Forsyth	if(c == '0'){
652*0d13e2d8SCharles.Forsyth		base = 8;
653*0d13e2d8SCharles.Forsyth		c = getc();
654*0d13e2d8SCharles.Forsyth		if(c == '.'){
655*0d13e2d8SCharles.Forsyth			base = 10;
656*0d13e2d8SCharles.Forsyth			ungetc(c);
657*0d13e2d8SCharles.Forsyth		}
658*0d13e2d8SCharles.Forsyth		else if(c == 'x' || c == 'X')
659*0d13e2d8SCharles.Forsyth			base = 16;
660*0d13e2d8SCharles.Forsyth		else
661*0d13e2d8SCharles.Forsyth			ungetc(c);
662*0d13e2d8SCharles.Forsyth	}
663*0d13e2d8SCharles.Forsyth	else
664*0d13e2d8SCharles.Forsyth		ungetc(c);
665*0d13e2d8SCharles.Forsyth	for(;;){
666*0d13e2d8SCharles.Forsyth		c = getc();
667*0d13e2d8SCharles.Forsyth		if(!r && (c == 'r' || c == 'R')){
668*0d13e2d8SCharles.Forsyth			if(f || e)
669*0d13e2d8SCharles.Forsyth				error(nil, "bad base");
670*0d13e2d8SCharles.Forsyth			r = 1;
671*0d13e2d8SCharles.Forsyth			base = int v;
672*0d13e2d8SCharles.Forsyth			if(base < 2 || base > 36)
673*0d13e2d8SCharles.Forsyth				error(nil, "bad base");
674*0d13e2d8SCharles.Forsyth			v = big 0;
675*0d13e2d8SCharles.Forsyth			continue;
676*0d13e2d8SCharles.Forsyth		}
677*0d13e2d8SCharles.Forsyth		if(c == '.'){
678*0d13e2d8SCharles.Forsyth			if(f || e)
679*0d13e2d8SCharles.Forsyth				error(nil, "bad real");
680*0d13e2d8SCharles.Forsyth			f = 1;
681*0d13e2d8SCharles.Forsyth			continue;
682*0d13e2d8SCharles.Forsyth		}
683*0d13e2d8SCharles.Forsyth		if(base == 10 && (c == 'e' || c == 'E')){
684*0d13e2d8SCharles.Forsyth			if(e)
685*0d13e2d8SCharles.Forsyth				error(nil, "bad E part");
686*0d13e2d8SCharles.Forsyth			e = 1;
687*0d13e2d8SCharles.Forsyth			exp = lexe(base);
688*0d13e2d8SCharles.Forsyth			continue;
689*0d13e2d8SCharles.Forsyth		}
690*0d13e2d8SCharles.Forsyth		cc := basev(c, base);
691*0d13e2d8SCharles.Forsyth		if(cc < 0){
692*0d13e2d8SCharles.Forsyth			ungetc(c);
693*0d13e2d8SCharles.Forsyth			break;
694*0d13e2d8SCharles.Forsyth		}
695*0d13e2d8SCharles.Forsyth		v = big base*v+big cc;
696*0d13e2d8SCharles.Forsyth		if(f)
697*0d13e2d8SCharles.Forsyth			f++;
698*0d13e2d8SCharles.Forsyth	}
699*0d13e2d8SCharles.Forsyth	lexval = real v;
700*0d13e2d8SCharles.Forsyth	if(f)
701*0d13e2d8SCharles.Forsyth		lexval /= real base**(f-1);
702*0d13e2d8SCharles.Forsyth	if(exp){
703*0d13e2d8SCharles.Forsyth		if(exp > 0)
704*0d13e2d8SCharles.Forsyth			lexval *= real base**exp;
705*0d13e2d8SCharles.Forsyth		else
706*0d13e2d8SCharles.Forsyth			lexval *= maths->pow(real base, real exp);
707*0d13e2d8SCharles.Forsyth	}
708*0d13e2d8SCharles.Forsyth	return Onum;
709*0d13e2d8SCharles.Forsyth}
710*0d13e2d8SCharles.Forsyth
711*0d13e2d8SCharles.Forsythlexid(): int
712*0d13e2d8SCharles.Forsyth{
713*0d13e2d8SCharles.Forsyth	sp := "";
714*0d13e2d8SCharles.Forsyth	for(;;){
715*0d13e2d8SCharles.Forsyth		c := getc();
716*0d13e2d8SCharles.Forsyth		if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c >= 'α' && c <=  'ω' || c >= 'Α' && c <= 'Ω' || c == '_')
717*0d13e2d8SCharles.Forsyth			sp[len sp] = c;
718*0d13e2d8SCharles.Forsyth		else{
719*0d13e2d8SCharles.Forsyth			ungetc(c);
720*0d13e2d8SCharles.Forsyth			break;
721*0d13e2d8SCharles.Forsyth		}
722*0d13e2d8SCharles.Forsyth	}
723*0d13e2d8SCharles.Forsyth	lexsym = enter(sp, Oident);
724*0d13e2d8SCharles.Forsyth	return lexsym.kind;
725*0d13e2d8SCharles.Forsyth}
726*0d13e2d8SCharles.Forsyth
727*0d13e2d8SCharles.Forsythfollow(c: int, c1: int, c2: int): int
728*0d13e2d8SCharles.Forsyth{
729*0d13e2d8SCharles.Forsyth	nc := getc();
730*0d13e2d8SCharles.Forsyth	if(nc == c)
731*0d13e2d8SCharles.Forsyth		return c1;
732*0d13e2d8SCharles.Forsyth	ungetc(nc);
733*0d13e2d8SCharles.Forsyth	return c2;
734*0d13e2d8SCharles.Forsyth}
735*0d13e2d8SCharles.Forsyth
736*0d13e2d8SCharles.Forsythskip()
737*0d13e2d8SCharles.Forsyth{
738*0d13e2d8SCharles.Forsyth	if((t := buft) != Olast){
739*0d13e2d8SCharles.Forsyth		lex();
740*0d13e2d8SCharles.Forsyth		if(t == Onl)
741*0d13e2d8SCharles.Forsyth			return;
742*0d13e2d8SCharles.Forsyth	}
743*0d13e2d8SCharles.Forsyth	for(;;){
744*0d13e2d8SCharles.Forsyth		c := getc();
745*0d13e2d8SCharles.Forsyth		if(c == Eof){
746*0d13e2d8SCharles.Forsyth			ungetc(c);
747*0d13e2d8SCharles.Forsyth			return;
748*0d13e2d8SCharles.Forsyth		}
749*0d13e2d8SCharles.Forsyth		if(c == '\n'){
750*0d13e2d8SCharles.Forsyth			lineno++;
751*0d13e2d8SCharles.Forsyth			return;
752*0d13e2d8SCharles.Forsyth		}
753*0d13e2d8SCharles.Forsyth	}
754*0d13e2d8SCharles.Forsyth}
755*0d13e2d8SCharles.Forsyth
756*0d13e2d8SCharles.Forsythlex(): int
757*0d13e2d8SCharles.Forsyth{
758*0d13e2d8SCharles.Forsyth	lexes++;
759*0d13e2d8SCharles.Forsyth	if((t := buft) != Olast){
760*0d13e2d8SCharles.Forsyth		buft = Olast;
761*0d13e2d8SCharles.Forsyth		if(t == Onl)
762*0d13e2d8SCharles.Forsyth			lineno++;
763*0d13e2d8SCharles.Forsyth		return t;
764*0d13e2d8SCharles.Forsyth	}
765*0d13e2d8SCharles.Forsyth	for(;;){
766*0d13e2d8SCharles.Forsyth		case(c := getc()){
767*0d13e2d8SCharles.Forsyth		Eof =>
768*0d13e2d8SCharles.Forsyth			return Oeof;
769*0d13e2d8SCharles.Forsyth		'#' =>
770*0d13e2d8SCharles.Forsyth			while((c = getc()) != '\n'){
771*0d13e2d8SCharles.Forsyth				if(c == Eof)
772*0d13e2d8SCharles.Forsyth					raise Eeof;
773*0d13e2d8SCharles.Forsyth			}
774*0d13e2d8SCharles.Forsyth			lineno++;
775*0d13e2d8SCharles.Forsyth		'\n' =>
776*0d13e2d8SCharles.Forsyth			lineno++;
777*0d13e2d8SCharles.Forsyth			return Onl;
778*0d13e2d8SCharles.Forsyth		' ' or
779*0d13e2d8SCharles.Forsyth		'\t' or
780*0d13e2d8SCharles.Forsyth		'\r' or
781*0d13e2d8SCharles.Forsyth		'\v' =>
782*0d13e2d8SCharles.Forsyth			;
783*0d13e2d8SCharles.Forsyth		'"' =>
784*0d13e2d8SCharles.Forsyth			return lexstring();
785*0d13e2d8SCharles.Forsyth		'\'' =>
786*0d13e2d8SCharles.Forsyth			return lexchar();
787*0d13e2d8SCharles.Forsyth		'0' to '9' =>
788*0d13e2d8SCharles.Forsyth			ungetc(c);
789*0d13e2d8SCharles.Forsyth			return lexnum();
790*0d13e2d8SCharles.Forsyth		'a' to 'z' or
791*0d13e2d8SCharles.Forsyth		'A' to 'Z' or
792*0d13e2d8SCharles.Forsyth		'α' to 'ω' or
793*0d13e2d8SCharles.Forsyth		'Α' to 'Ω' or
794*0d13e2d8SCharles.Forsyth		'_' =>
795*0d13e2d8SCharles.Forsyth			ungetc(c);
796*0d13e2d8SCharles.Forsyth			return lexid();
797*0d13e2d8SCharles.Forsyth		'+' =>
798*0d13e2d8SCharles.Forsyth			c = getc();
799*0d13e2d8SCharles.Forsyth			if(c == '=')
800*0d13e2d8SCharles.Forsyth				return Oadde;
801*0d13e2d8SCharles.Forsyth			ungetc(c);
802*0d13e2d8SCharles.Forsyth			return follow('+', Oinc, Oadd);
803*0d13e2d8SCharles.Forsyth		'-' =>
804*0d13e2d8SCharles.Forsyth			c = getc();
805*0d13e2d8SCharles.Forsyth			if(c == '=')
806*0d13e2d8SCharles.Forsyth				return Osube;
807*0d13e2d8SCharles.Forsyth			if(c == '>')
808*0d13e2d8SCharles.Forsyth				return Oimp;
809*0d13e2d8SCharles.Forsyth			ungetc(c);
810*0d13e2d8SCharles.Forsyth			return follow('-', Odec, Osub);
811*0d13e2d8SCharles.Forsyth		'*' =>
812*0d13e2d8SCharles.Forsyth			c = getc();
813*0d13e2d8SCharles.Forsyth			if(c == '=')
814*0d13e2d8SCharles.Forsyth				return Omule;
815*0d13e2d8SCharles.Forsyth			if(c == '*')
816*0d13e2d8SCharles.Forsyth				return follow('=', Oexpe, Oexp);
817*0d13e2d8SCharles.Forsyth			ungetc(c);
818*0d13e2d8SCharles.Forsyth			return Omul;
819*0d13e2d8SCharles.Forsyth		'/' =>
820*0d13e2d8SCharles.Forsyth			c = getc();
821*0d13e2d8SCharles.Forsyth			if(c == '=')
822*0d13e2d8SCharles.Forsyth				return Odive;
823*0d13e2d8SCharles.Forsyth			if(c == '/')
824*0d13e2d8SCharles.Forsyth				return follow('=', Oidive, Oidiv);
825*0d13e2d8SCharles.Forsyth			ungetc(c);
826*0d13e2d8SCharles.Forsyth			return Odiv;
827*0d13e2d8SCharles.Forsyth		'%' =>
828*0d13e2d8SCharles.Forsyth			return follow('=', Omode, Omod);
829*0d13e2d8SCharles.Forsyth		'&' =>
830*0d13e2d8SCharles.Forsyth			c = getc();
831*0d13e2d8SCharles.Forsyth			if(c == '=')
832*0d13e2d8SCharles.Forsyth				return Oande;
833*0d13e2d8SCharles.Forsyth			ungetc(c);
834*0d13e2d8SCharles.Forsyth			return follow('&', Oandand, Oand);
835*0d13e2d8SCharles.Forsyth		'|' =>
836*0d13e2d8SCharles.Forsyth			c = getc();
837*0d13e2d8SCharles.Forsyth			if(c == '=')
838*0d13e2d8SCharles.Forsyth				return Oore;
839*0d13e2d8SCharles.Forsyth			ungetc(c);
840*0d13e2d8SCharles.Forsyth			return follow('|', Ooror, Oor);
841*0d13e2d8SCharles.Forsyth		'^' =>
842*0d13e2d8SCharles.Forsyth			return follow('=', Oxore, Oxor);
843*0d13e2d8SCharles.Forsyth		'=' =>
844*0d13e2d8SCharles.Forsyth			return follow('=', Oeq, Oas);
845*0d13e2d8SCharles.Forsyth		'!' =>
846*0d13e2d8SCharles.Forsyth			return follow('=', One, Oexc);
847*0d13e2d8SCharles.Forsyth		'>' =>
848*0d13e2d8SCharles.Forsyth			c = getc();
849*0d13e2d8SCharles.Forsyth			if(c == '=')
850*0d13e2d8SCharles.Forsyth				return Oge;
851*0d13e2d8SCharles.Forsyth			if(c == '>')
852*0d13e2d8SCharles.Forsyth				return follow('=', Orshe, Orsh);
853*0d13e2d8SCharles.Forsyth			ungetc(c);
854*0d13e2d8SCharles.Forsyth			return Ogt;
855*0d13e2d8SCharles.Forsyth		'<' =>
856*0d13e2d8SCharles.Forsyth			c = getc();
857*0d13e2d8SCharles.Forsyth			if(c == '=')
858*0d13e2d8SCharles.Forsyth				return Ole;
859*0d13e2d8SCharles.Forsyth			if(c == '<')
860*0d13e2d8SCharles.Forsyth				return follow('=', Olshe, Olsh);
861*0d13e2d8SCharles.Forsyth			if(c == '-')
862*0d13e2d8SCharles.Forsyth				return follow('>', Oiff, Oimpby);
863*0d13e2d8SCharles.Forsyth			ungetc(c);
864*0d13e2d8SCharles.Forsyth			return Olt;
865*0d13e2d8SCharles.Forsyth		'(' =>
866*0d13e2d8SCharles.Forsyth			return Olbr;
867*0d13e2d8SCharles.Forsyth		')' =>
868*0d13e2d8SCharles.Forsyth			return Orbr;
869*0d13e2d8SCharles.Forsyth		'{' =>
870*0d13e2d8SCharles.Forsyth			return Olcbr;
871*0d13e2d8SCharles.Forsyth		'}' =>
872*0d13e2d8SCharles.Forsyth			return Orcbr;
873*0d13e2d8SCharles.Forsyth		'~' =>
874*0d13e2d8SCharles.Forsyth			return Ocom;
875*0d13e2d8SCharles.Forsyth		'.' =>
876*0d13e2d8SCharles.Forsyth			ungetc(c);
877*0d13e2d8SCharles.Forsyth			return lexnum();
878*0d13e2d8SCharles.Forsyth		',' =>
879*0d13e2d8SCharles.Forsyth			return Ocomma;
880*0d13e2d8SCharles.Forsyth		'?' =>
881*0d13e2d8SCharles.Forsyth			return Oquest;
882*0d13e2d8SCharles.Forsyth		':' =>
883*0d13e2d8SCharles.Forsyth			return follow('=', Odas, Ocolon);
884*0d13e2d8SCharles.Forsyth		';' =>
885*0d13e2d8SCharles.Forsyth			return Oscolon;
886*0d13e2d8SCharles.Forsyth		'↑' =>
887*0d13e2d8SCharles.Forsyth			return Onand;
888*0d13e2d8SCharles.Forsyth		'↓' =>
889*0d13e2d8SCharles.Forsyth			return Onor;
890*0d13e2d8SCharles.Forsyth		'∞' =>
891*0d13e2d8SCharles.Forsyth			lexval = Infinity;
892*0d13e2d8SCharles.Forsyth			return Onum;
893*0d13e2d8SCharles.Forsyth		* =>
894*0d13e2d8SCharles.Forsyth			error(nil, sys->sprint("bad character %c", c));
895*0d13e2d8SCharles.Forsyth		}
896*0d13e2d8SCharles.Forsyth	}
897*0d13e2d8SCharles.Forsyth}
898*0d13e2d8SCharles.Forsyth
899*0d13e2d8SCharles.Forsythunlex(t: int)
900*0d13e2d8SCharles.Forsyth{
901*0d13e2d8SCharles.Forsyth	lexes--;
902*0d13e2d8SCharles.Forsyth	buft = t;
903*0d13e2d8SCharles.Forsyth	if(t == Onl)
904*0d13e2d8SCharles.Forsyth		lineno--;
905*0d13e2d8SCharles.Forsyth}
906*0d13e2d8SCharles.Forsyth
907*0d13e2d8SCharles.Forsythmustbe(t: int)
908*0d13e2d8SCharles.Forsyth{
909*0d13e2d8SCharles.Forsyth	nt := lex();
910*0d13e2d8SCharles.Forsyth	if(nt != t)
911*0d13e2d8SCharles.Forsyth		error(nil, sys->sprint("expected %s not %s", opstring(t), opstring(nt)));
912*0d13e2d8SCharles.Forsyth}
913*0d13e2d8SCharles.Forsyth
914*0d13e2d8SCharles.Forsythconsume(t: int)
915*0d13e2d8SCharles.Forsyth{
916*0d13e2d8SCharles.Forsyth	nt := lex();
917*0d13e2d8SCharles.Forsyth	if(nt != t)
918*0d13e2d8SCharles.Forsyth		unlex(nt);
919*0d13e2d8SCharles.Forsyth}
920*0d13e2d8SCharles.Forsyth
921*0d13e2d8SCharles.Forsythelex(): int
922*0d13e2d8SCharles.Forsyth{
923*0d13e2d8SCharles.Forsyth	t := lex();
924*0d13e2d8SCharles.Forsyth	if(binary(t))
925*0d13e2d8SCharles.Forsyth		return t;
926*0d13e2d8SCharles.Forsyth	if(hexp(t)){
927*0d13e2d8SCharles.Forsyth		unlex(t);
928*0d13e2d8SCharles.Forsyth		return Oscomma;
929*0d13e2d8SCharles.Forsyth	}
930*0d13e2d8SCharles.Forsyth	return t;
931*0d13e2d8SCharles.Forsyth}
932*0d13e2d8SCharles.Forsyth
933*0d13e2d8SCharles.Forsythhexp(o: int): int
934*0d13e2d8SCharles.Forsyth{
935*0d13e2d8SCharles.Forsyth	return preunary(o) || o == Olbr || atom(o);
936*0d13e2d8SCharles.Forsyth}
937*0d13e2d8SCharles.Forsyth
938*0d13e2d8SCharles.Forsythatom(o: int): int
939*0d13e2d8SCharles.Forsyth{
940*0d13e2d8SCharles.Forsyth	return o >= Ostring && o <= Olfun;
941*0d13e2d8SCharles.Forsyth}
942*0d13e2d8SCharles.Forsyth
943*0d13e2d8SCharles.Forsythasop(o: int): int
944*0d13e2d8SCharles.Forsyth{
945*0d13e2d8SCharles.Forsyth	return o == Oas || o == Odas || o >= Oadde && o <= Orshe || o >= Oinc && o <= Opostdec;
946*0d13e2d8SCharles.Forsyth}
947*0d13e2d8SCharles.Forsyth
948*0d13e2d8SCharles.Forsythpreunary(o: int): int
949*0d13e2d8SCharles.Forsyth{
950*0d13e2d8SCharles.Forsyth	return ops[o]&Preunary;
951*0d13e2d8SCharles.Forsyth}
952*0d13e2d8SCharles.Forsyth
953*0d13e2d8SCharles.Forsythpostunary(o: int): int
954*0d13e2d8SCharles.Forsyth{
955*0d13e2d8SCharles.Forsyth	return ops[o]&Postunary;
956*0d13e2d8SCharles.Forsyth}
957*0d13e2d8SCharles.Forsyth
958*0d13e2d8SCharles.Forsythbinary(o: int): int
959*0d13e2d8SCharles.Forsyth{
960*0d13e2d8SCharles.Forsyth	return ops[o]&Binary;
961*0d13e2d8SCharles.Forsyth}
962*0d13e2d8SCharles.Forsyth
963*0d13e2d8SCharles.Forsythprec(o: int): int
964*0d13e2d8SCharles.Forsyth{
965*0d13e2d8SCharles.Forsyth	return ops[o]&Prec;
966*0d13e2d8SCharles.Forsyth}
967*0d13e2d8SCharles.Forsyth
968*0d13e2d8SCharles.Forsythassoc(o: int): int
969*0d13e2d8SCharles.Forsyth{
970*0d13e2d8SCharles.Forsyth	return ops[o]&Assoc;
971*0d13e2d8SCharles.Forsyth}
972*0d13e2d8SCharles.Forsyth
973*0d13e2d8SCharles.Forsythrassoc(o: int): int
974*0d13e2d8SCharles.Forsyth{
975*0d13e2d8SCharles.Forsyth	return ops[o]&Rassoc;
976*0d13e2d8SCharles.Forsyth}
977*0d13e2d8SCharles.Forsyth
978*0d13e2d8SCharles.Forsythpreop(o: int): int
979*0d13e2d8SCharles.Forsyth{
980*0d13e2d8SCharles.Forsyth	case(o){
981*0d13e2d8SCharles.Forsyth	Oadd => return Oplus;
982*0d13e2d8SCharles.Forsyth	Osub => return Ominus;
983*0d13e2d8SCharles.Forsyth	Oinc => return Opreinc;
984*0d13e2d8SCharles.Forsyth	Odec => return Opredec;
985*0d13e2d8SCharles.Forsyth	Oexc => return Onot;
986*0d13e2d8SCharles.Forsyth	}
987*0d13e2d8SCharles.Forsyth	return o;
988*0d13e2d8SCharles.Forsyth}
989*0d13e2d8SCharles.Forsyth
990*0d13e2d8SCharles.Forsythpostop(o: int): int
991*0d13e2d8SCharles.Forsyth{
992*0d13e2d8SCharles.Forsyth	case(o){
993*0d13e2d8SCharles.Forsyth	Oinc => return Opostinc;
994*0d13e2d8SCharles.Forsyth	Odec => return Opostdec;
995*0d13e2d8SCharles.Forsyth	Oexc => return Ofact;
996*0d13e2d8SCharles.Forsyth	}
997*0d13e2d8SCharles.Forsyth	return o;
998*0d13e2d8SCharles.Forsyth}
999*0d13e2d8SCharles.Forsyth
1000*0d13e2d8SCharles.Forsythprtree(p: ref Node, in: int)
1001*0d13e2d8SCharles.Forsyth{
1002*0d13e2d8SCharles.Forsyth	if(p == nil)
1003*0d13e2d8SCharles.Forsyth		return;
1004*0d13e2d8SCharles.Forsyth	for(i := 0; i < in; i++)
1005*0d13e2d8SCharles.Forsyth		sys->print("    ");
1006*0d13e2d8SCharles.Forsyth	sys->print("%s ", opstring(p.op));
1007*0d13e2d8SCharles.Forsyth	case(p.op){
1008*0d13e2d8SCharles.Forsyth	Ostring =>
1009*0d13e2d8SCharles.Forsyth		sys->print("%s", p.str);
1010*0d13e2d8SCharles.Forsyth	Onum =>
1011*0d13e2d8SCharles.Forsyth		sys->print("%g", p.val);
1012*0d13e2d8SCharles.Forsyth	Ocon or
1013*0d13e2d8SCharles.Forsyth	Ovar =>
1014*0d13e2d8SCharles.Forsyth		sys->print("%s(%g)", p.dec.sym.name, p.dec.val);
1015*0d13e2d8SCharles.Forsyth	Ofun or
1016*0d13e2d8SCharles.Forsyth	Olfun =>
1017*0d13e2d8SCharles.Forsyth		sys->print("%s", p.dec.sym.name);
1018*0d13e2d8SCharles.Forsyth	}
1019*0d13e2d8SCharles.Forsyth	sys->print("\n");
1020*0d13e2d8SCharles.Forsyth	# sys->print(" - %d\n", p.src);
1021*0d13e2d8SCharles.Forsyth	prtree(p.left, in+1);
1022*0d13e2d8SCharles.Forsyth	prtree(p.right, in+1);
1023*0d13e2d8SCharles.Forsyth}
1024*0d13e2d8SCharles.Forsyth
1025*0d13e2d8SCharles.Forsythtree(o: int, l: ref Node, r: ref Node): ref Node
1026*0d13e2d8SCharles.Forsyth{
1027*0d13e2d8SCharles.Forsyth	p := ref Node;
1028*0d13e2d8SCharles.Forsyth	p.op = o;
1029*0d13e2d8SCharles.Forsyth	p.left = l;
1030*0d13e2d8SCharles.Forsyth	p.right = r;
1031*0d13e2d8SCharles.Forsyth	p.src = lineno;
1032*0d13e2d8SCharles.Forsyth	if(asop(o)){
1033*0d13e2d8SCharles.Forsyth		if(o >= Oadde && o <= Orshe){
1034*0d13e2d8SCharles.Forsyth			p = tree(Oas, l, p);
1035*0d13e2d8SCharles.Forsyth			p.right.op += Oadd-Oadde;
1036*0d13e2d8SCharles.Forsyth		}
1037*0d13e2d8SCharles.Forsyth	}
1038*0d13e2d8SCharles.Forsyth	return p;
1039*0d13e2d8SCharles.Forsyth}
1040*0d13e2d8SCharles.Forsyth
1041*0d13e2d8SCharles.Forsythitree(n: int): ref Node
1042*0d13e2d8SCharles.Forsyth{
1043*0d13e2d8SCharles.Forsyth	return vtree(real n);
1044*0d13e2d8SCharles.Forsyth}
1045*0d13e2d8SCharles.Forsyth
1046*0d13e2d8SCharles.Forsythvtree(v: real): ref Node
1047*0d13e2d8SCharles.Forsyth{
1048*0d13e2d8SCharles.Forsyth	n := tree(Onum, nil, nil);
1049*0d13e2d8SCharles.Forsyth	n.val = v;
1050*0d13e2d8SCharles.Forsyth	return n;
1051*0d13e2d8SCharles.Forsyth}
1052*0d13e2d8SCharles.Forsyth
1053*0d13e2d8SCharles.Forsythltree(s: string, a: ref Node): ref Node
1054*0d13e2d8SCharles.Forsyth{
1055*0d13e2d8SCharles.Forsyth	n := tree(Olfun, a, nil);
1056*0d13e2d8SCharles.Forsyth	n.dec = lookup(s).dec;
1057*0d13e2d8SCharles.Forsyth	return n;
1058*0d13e2d8SCharles.Forsyth}
1059*0d13e2d8SCharles.Forsyth
1060*0d13e2d8SCharles.Forsythptree(n: ref Node, p: real): ref Node
1061*0d13e2d8SCharles.Forsyth{
1062*0d13e2d8SCharles.Forsyth	if(isinteger(p)){
1063*0d13e2d8SCharles.Forsyth		i := int p;
1064*0d13e2d8SCharles.Forsyth		if(i == 0)
1065*0d13e2d8SCharles.Forsyth			return itree(1);
1066*0d13e2d8SCharles.Forsyth		if(i == 1)
1067*0d13e2d8SCharles.Forsyth			return n;
1068*0d13e2d8SCharles.Forsyth		if(i == -1)
1069*0d13e2d8SCharles.Forsyth			return tree(Oinv, n, nil);
1070*0d13e2d8SCharles.Forsyth		if(i < 0)
1071*0d13e2d8SCharles.Forsyth			return tree(Oinv, tree(Oexp, n, itree(-i)), nil);
1072*0d13e2d8SCharles.Forsyth	}
1073*0d13e2d8SCharles.Forsyth	return tree(Oexp, n, vtree(p));
1074*0d13e2d8SCharles.Forsyth}
1075*0d13e2d8SCharles.Forsyth
1076*0d13e2d8SCharles.Forsythiscon(n: ref Node): int
1077*0d13e2d8SCharles.Forsyth{
1078*0d13e2d8SCharles.Forsyth	return n.op == Onum || n.op == Ocon;
1079*0d13e2d8SCharles.Forsyth}
1080*0d13e2d8SCharles.Forsyth
1081*0d13e2d8SCharles.Forsythiszero(n: ref Node): int
1082*0d13e2d8SCharles.Forsyth{
1083*0d13e2d8SCharles.Forsyth	return iscon(n) && eval(n) == 0.0;
1084*0d13e2d8SCharles.Forsyth}
1085*0d13e2d8SCharles.Forsyth
1086*0d13e2d8SCharles.Forsythisone(n: ref Node): int
1087*0d13e2d8SCharles.Forsyth{
1088*0d13e2d8SCharles.Forsyth	return iscon(n) && eval(n) == 1.0;
1089*0d13e2d8SCharles.Forsyth}
1090*0d13e2d8SCharles.Forsyth
1091*0d13e2d8SCharles.Forsythisnan(n: ref Node): int
1092*0d13e2d8SCharles.Forsyth{
1093*0d13e2d8SCharles.Forsyth	return iscon(n) && maths->isnan(eval(n));
1094*0d13e2d8SCharles.Forsyth}
1095*0d13e2d8SCharles.Forsyth
1096*0d13e2d8SCharles.Forsythisinf(n: ref Node): int
1097*0d13e2d8SCharles.Forsyth{
1098*0d13e2d8SCharles.Forsyth	return iscon(n) && (v := eval(n)) == Infinity || v == -Infinity;
1099*0d13e2d8SCharles.Forsyth}
1100*0d13e2d8SCharles.Forsyth
1101*0d13e2d8SCharles.Forsythstat(scope: int): ref Node
1102*0d13e2d8SCharles.Forsyth{
1103*0d13e2d8SCharles.Forsyth	e1, e2, e3, e4: ref Node;
1104*0d13e2d8SCharles.Forsyth
1105*0d13e2d8SCharles.Forsyth	consume(Onl);
1106*0d13e2d8SCharles.Forsyth	t := lex();
1107*0d13e2d8SCharles.Forsyth	case(t){
1108*0d13e2d8SCharles.Forsyth	Olcbr =>
1109*0d13e2d8SCharles.Forsyth		if(scope)
1110*0d13e2d8SCharles.Forsyth			pushscope();
1111*0d13e2d8SCharles.Forsyth		for(;;){
1112*0d13e2d8SCharles.Forsyth			e2 = stat(1);
1113*0d13e2d8SCharles.Forsyth			if(e1 == nil)
1114*0d13e2d8SCharles.Forsyth				e1 = e2;
1115*0d13e2d8SCharles.Forsyth			else
1116*0d13e2d8SCharles.Forsyth				e1 = tree(Ocomma, e1, e2);
1117*0d13e2d8SCharles.Forsyth			consume(Onl);
1118*0d13e2d8SCharles.Forsyth			t = lex();
1119*0d13e2d8SCharles.Forsyth			if(t == Oeof)
1120*0d13e2d8SCharles.Forsyth				raise Eeof;
1121*0d13e2d8SCharles.Forsyth			if(t == Orcbr)
1122*0d13e2d8SCharles.Forsyth				break;
1123*0d13e2d8SCharles.Forsyth			unlex(t);
1124*0d13e2d8SCharles.Forsyth		}
1125*0d13e2d8SCharles.Forsyth		if(scope)
1126*0d13e2d8SCharles.Forsyth			popscope();
1127*0d13e2d8SCharles.Forsyth		return e1;
1128*0d13e2d8SCharles.Forsyth	Oprint or
1129*0d13e2d8SCharles.Forsyth	Oread or
1130*0d13e2d8SCharles.Forsyth	Oret =>
1131*0d13e2d8SCharles.Forsyth		if(t == Oret && !infn)
1132*0d13e2d8SCharles.Forsyth			error(nil, "return not in fn");
1133*0d13e2d8SCharles.Forsyth		e1= tree(t, expr(0, 1), nil);
1134*0d13e2d8SCharles.Forsyth		consume(Oscolon);
1135*0d13e2d8SCharles.Forsyth		if(t == Oread)
1136*0d13e2d8SCharles.Forsyth			allvar(e1.left);
1137*0d13e2d8SCharles.Forsyth		return e1;
1138*0d13e2d8SCharles.Forsyth	Oif =>
1139*0d13e2d8SCharles.Forsyth		# mustbe(Olbr);
1140*0d13e2d8SCharles.Forsyth		e1 = expr(0, 1);
1141*0d13e2d8SCharles.Forsyth		# mustbe(Orbr);
1142*0d13e2d8SCharles.Forsyth		e2 = stat(1);
1143*0d13e2d8SCharles.Forsyth		e3 = nil;
1144*0d13e2d8SCharles.Forsyth		consume(Onl);
1145*0d13e2d8SCharles.Forsyth		t = lex();
1146*0d13e2d8SCharles.Forsyth		if(t == Oelse)
1147*0d13e2d8SCharles.Forsyth			e3 = stat(1);
1148*0d13e2d8SCharles.Forsyth		else
1149*0d13e2d8SCharles.Forsyth			unlex(t);
1150*0d13e2d8SCharles.Forsyth		return tree(Oif, e1, tree(Ocomma, e2, e3));
1151*0d13e2d8SCharles.Forsyth	Ofor =>
1152*0d13e2d8SCharles.Forsyth		inloop++;
1153*0d13e2d8SCharles.Forsyth		mustbe(Olbr);
1154*0d13e2d8SCharles.Forsyth		e1 = expr(0, 1);
1155*0d13e2d8SCharles.Forsyth		mustbe(Oscolon);
1156*0d13e2d8SCharles.Forsyth		e2 = expr(0, 1);
1157*0d13e2d8SCharles.Forsyth		mustbe(Oscolon);
1158*0d13e2d8SCharles.Forsyth		e3 = expr(0, 1);
1159*0d13e2d8SCharles.Forsyth		mustbe(Orbr);
1160*0d13e2d8SCharles.Forsyth		e4 = stat(1);
1161*0d13e2d8SCharles.Forsyth		inloop--;
1162*0d13e2d8SCharles.Forsyth		return tree(Ocomma, e1, tree(Ofor, e2, tree(Ocomma, e4, e3)));
1163*0d13e2d8SCharles.Forsyth	Owhile =>
1164*0d13e2d8SCharles.Forsyth		inloop++;
1165*0d13e2d8SCharles.Forsyth		# mustbe(Olbr);
1166*0d13e2d8SCharles.Forsyth		e1 = expr(0, 1);
1167*0d13e2d8SCharles.Forsyth		# mustbe(Orbr);
1168*0d13e2d8SCharles.Forsyth		e2 = stat(1);
1169*0d13e2d8SCharles.Forsyth		inloop--;
1170*0d13e2d8SCharles.Forsyth		return tree(Ofor, e1, tree(Ocomma, e2, nil));
1171*0d13e2d8SCharles.Forsyth	Odo =>
1172*0d13e2d8SCharles.Forsyth		inloop++;
1173*0d13e2d8SCharles.Forsyth		e1 = stat(1);
1174*0d13e2d8SCharles.Forsyth		consume(Onl);
1175*0d13e2d8SCharles.Forsyth		mustbe(Owhile);
1176*0d13e2d8SCharles.Forsyth		# mustbe(Olbr);
1177*0d13e2d8SCharles.Forsyth		e2 = expr(0, 1);
1178*0d13e2d8SCharles.Forsyth		# mustbe(Orbr);
1179*0d13e2d8SCharles.Forsyth		consume(Oscolon);
1180*0d13e2d8SCharles.Forsyth		inloop--;
1181*0d13e2d8SCharles.Forsyth		return tree(Odo, e1, e2);
1182*0d13e2d8SCharles.Forsyth	Obreak or
1183*0d13e2d8SCharles.Forsyth	Ocont or
1184*0d13e2d8SCharles.Forsyth	Oexit =>
1185*0d13e2d8SCharles.Forsyth		if((t == Obreak || t == Ocont) && !inloop)
1186*0d13e2d8SCharles.Forsyth			error(nil, "break/continue not in loop");
1187*0d13e2d8SCharles.Forsyth		consume(Oscolon);
1188*0d13e2d8SCharles.Forsyth		return tree(t, nil, nil);
1189*0d13e2d8SCharles.Forsyth	Ofn =>
1190*0d13e2d8SCharles.Forsyth		if(infn)
1191*0d13e2d8SCharles.Forsyth			error(nil, "nested functions not allowed");
1192*0d13e2d8SCharles.Forsyth		infn++;
1193*0d13e2d8SCharles.Forsyth		mustbe(Oident);
1194*0d13e2d8SCharles.Forsyth		s := lexsym;
1195*0d13e2d8SCharles.Forsyth		d := mkdec(s, Ofun, 1);
1196*0d13e2d8SCharles.Forsyth		d.code = tree(Ofn, nil, nil);
1197*0d13e2d8SCharles.Forsyth		pushscope();
1198*0d13e2d8SCharles.Forsyth		(d.na, d.code.left) = args(0);
1199*0d13e2d8SCharles.Forsyth		allvar(d.code.left);
1200*0d13e2d8SCharles.Forsyth		pushparams(d.code.left);
1201*0d13e2d8SCharles.Forsyth		d.code.right = stat(0);
1202*0d13e2d8SCharles.Forsyth		popscope();
1203*0d13e2d8SCharles.Forsyth		infn--;
1204*0d13e2d8SCharles.Forsyth		return d.code;
1205*0d13e2d8SCharles.Forsyth	Oinclude =>
1206*0d13e2d8SCharles.Forsyth		e1 = expr(0, 0);
1207*0d13e2d8SCharles.Forsyth		if(e1.op != Ostring)
1208*0d13e2d8SCharles.Forsyth			error(nil, "bad include file");
1209*0d13e2d8SCharles.Forsyth		consume(Oscolon);
1210*0d13e2d8SCharles.Forsyth		doinclude(e1.str);
1211*0d13e2d8SCharles.Forsyth		return nil;
1212*0d13e2d8SCharles.Forsyth	* =>
1213*0d13e2d8SCharles.Forsyth		unlex(t);
1214*0d13e2d8SCharles.Forsyth		e1 = expr(0, 1);
1215*0d13e2d8SCharles.Forsyth		consume(Oscolon);
1216*0d13e2d8SCharles.Forsyth		if(debug)
1217*0d13e2d8SCharles.Forsyth			prnode(e1);
1218*0d13e2d8SCharles.Forsyth		return e1;
1219*0d13e2d8SCharles.Forsyth	}
1220*0d13e2d8SCharles.Forsyth	return nil;
1221*0d13e2d8SCharles.Forsyth}
1222*0d13e2d8SCharles.Forsyth
1223*0d13e2d8SCharles.Forsythckstat(n: ref Node, parop: int, pr: int)
1224*0d13e2d8SCharles.Forsyth{
1225*0d13e2d8SCharles.Forsyth	if(n == nil)
1226*0d13e2d8SCharles.Forsyth		return;
1227*0d13e2d8SCharles.Forsyth	pr |= n.op == Oprint;
1228*0d13e2d8SCharles.Forsyth	ckstat(n.left, n.op, pr);
1229*0d13e2d8SCharles.Forsyth	ckstat(n.right, n.op, pr);
1230*0d13e2d8SCharles.Forsyth	case(n.op){
1231*0d13e2d8SCharles.Forsyth	Ostring =>
1232*0d13e2d8SCharles.Forsyth		if(!pr || parop != Oprint && parop != Ocomma)
1233*0d13e2d8SCharles.Forsyth			error(n, "illegal string operation");
1234*0d13e2d8SCharles.Forsyth	}
1235*0d13e2d8SCharles.Forsyth}
1236*0d13e2d8SCharles.Forsyth
1237*0d13e2d8SCharles.Forsythpexp(e: ref Node): int
1238*0d13e2d8SCharles.Forsyth{
1239*0d13e2d8SCharles.Forsyth	if(e == nil)
1240*0d13e2d8SCharles.Forsyth		return 0;
1241*0d13e2d8SCharles.Forsyth	if(e.op == Ocomma)
1242*0d13e2d8SCharles.Forsyth		return pexp(e.right);
1243*0d13e2d8SCharles.Forsyth	return e.op >= Ostring && e.op <= Oiff && !asop(e.op);
1244*0d13e2d8SCharles.Forsyth}
1245*0d13e2d8SCharles.Forsyth
1246*0d13e2d8SCharles.Forsythexpr(p: int, zok: int): ref Node
1247*0d13e2d8SCharles.Forsyth{
1248*0d13e2d8SCharles.Forsyth	n := exp(p, zok);
1249*0d13e2d8SCharles.Forsyth	ckexp(n, Onothing);
1250*0d13e2d8SCharles.Forsyth	return n;
1251*0d13e2d8SCharles.Forsyth}
1252*0d13e2d8SCharles.Forsyth
1253*0d13e2d8SCharles.Forsythexp(p: int, zok: int): ref Node
1254*0d13e2d8SCharles.Forsyth{
1255*0d13e2d8SCharles.Forsyth	l := prim(zok);
1256*0d13e2d8SCharles.Forsyth	if(l == nil)
1257*0d13e2d8SCharles.Forsyth		return nil;
1258*0d13e2d8SCharles.Forsyth	while(binary(t := elex()) && (o := prec(t)) >= p){
1259*0d13e2d8SCharles.Forsyth		if(rassoc(t))
1260*0d13e2d8SCharles.Forsyth			r := exp(o, 0);
1261*0d13e2d8SCharles.Forsyth		else
1262*0d13e2d8SCharles.Forsyth			r = exp(o+1, 0);
1263*0d13e2d8SCharles.Forsyth		if(t == Oscomma)
1264*0d13e2d8SCharles.Forsyth			t = Ocomma;
1265*0d13e2d8SCharles.Forsyth		l = tree(t, l, r);
1266*0d13e2d8SCharles.Forsyth	}
1267*0d13e2d8SCharles.Forsyth	if(t != Oscomma)
1268*0d13e2d8SCharles.Forsyth		unlex(t);
1269*0d13e2d8SCharles.Forsyth	return l;
1270*0d13e2d8SCharles.Forsyth}
1271*0d13e2d8SCharles.Forsyth
1272*0d13e2d8SCharles.Forsythprim(zok: int): ref Node
1273*0d13e2d8SCharles.Forsyth{
1274*0d13e2d8SCharles.Forsyth	p: ref Node;
1275*0d13e2d8SCharles.Forsyth	na: int;
1276*0d13e2d8SCharles.Forsyth
1277*0d13e2d8SCharles.Forsyth	t := lex();
1278*0d13e2d8SCharles.Forsyth	if(preunary(t)){
1279*0d13e2d8SCharles.Forsyth		t = preop(t);
1280*0d13e2d8SCharles.Forsyth		return tree(t, exp(prec(t), 0), nil);
1281*0d13e2d8SCharles.Forsyth	}
1282*0d13e2d8SCharles.Forsyth	case(t){
1283*0d13e2d8SCharles.Forsyth	Olbr =>
1284*0d13e2d8SCharles.Forsyth		p = exp(0, zok);
1285*0d13e2d8SCharles.Forsyth		mustbe(Orbr);
1286*0d13e2d8SCharles.Forsyth	Ostring =>
1287*0d13e2d8SCharles.Forsyth		p = tree(t, nil, nil);
1288*0d13e2d8SCharles.Forsyth		p.str = lexstr;
1289*0d13e2d8SCharles.Forsyth	Onum =>
1290*0d13e2d8SCharles.Forsyth		p = tree(t, nil ,nil);
1291*0d13e2d8SCharles.Forsyth		p.val = lexval;
1292*0d13e2d8SCharles.Forsyth	Oident =>
1293*0d13e2d8SCharles.Forsyth		s := lexsym;
1294*0d13e2d8SCharles.Forsyth		d := s.dec;
1295*0d13e2d8SCharles.Forsyth		if(d == nil)
1296*0d13e2d8SCharles.Forsyth			d = mkdec(s, Ovar, 0);
1297*0d13e2d8SCharles.Forsyth		case(t = d.kind){
1298*0d13e2d8SCharles.Forsyth		Ocon or
1299*0d13e2d8SCharles.Forsyth		Ovar =>
1300*0d13e2d8SCharles.Forsyth			p = tree(t, nil, nil);
1301*0d13e2d8SCharles.Forsyth			p.dec = d;
1302*0d13e2d8SCharles.Forsyth		Ofun or
1303*0d13e2d8SCharles.Forsyth		Olfun =>
1304*0d13e2d8SCharles.Forsyth			p = tree(t, nil, nil);
1305*0d13e2d8SCharles.Forsyth			p.dec = d;
1306*0d13e2d8SCharles.Forsyth			(na, p.left) = args(prec(t));
1307*0d13e2d8SCharles.Forsyth			if(!(t == Olfun && d.val == real Osolve && na == 2))
1308*0d13e2d8SCharles.Forsyth			if(na != d.na)
1309*0d13e2d8SCharles.Forsyth				error(p, "wrong number of arguments");
1310*0d13e2d8SCharles.Forsyth			if(t == Olfun){
1311*0d13e2d8SCharles.Forsyth				case(int d.val){
1312*0d13e2d8SCharles.Forsyth				Osigma or
1313*0d13e2d8SCharles.Forsyth				Opi or
1314*0d13e2d8SCharles.Forsyth				Ocfrac or
1315*0d13e2d8SCharles.Forsyth				Ointeg =>
1316*0d13e2d8SCharles.Forsyth					if((op := p.left.left.left.op) != Oas && op != Odas)
1317*0d13e2d8SCharles.Forsyth						error(p.left, "expression not an assignment");
1318*0d13e2d8SCharles.Forsyth				Oderiv =>
1319*0d13e2d8SCharles.Forsyth					if((op := p.left.left.op) != Oas && op != Odas)
1320*0d13e2d8SCharles.Forsyth						error(p.left, "expression not an assignment");
1321*0d13e2d8SCharles.Forsyth				}
1322*0d13e2d8SCharles.Forsyth			}
1323*0d13e2d8SCharles.Forsyth		}
1324*0d13e2d8SCharles.Forsyth	* =>
1325*0d13e2d8SCharles.Forsyth		unlex(t);
1326*0d13e2d8SCharles.Forsyth		if(!zok)
1327*0d13e2d8SCharles.Forsyth			error(nil, "missing expression");
1328*0d13e2d8SCharles.Forsyth		return nil;
1329*0d13e2d8SCharles.Forsyth	}
1330*0d13e2d8SCharles.Forsyth	while(postunary(t = lex())){
1331*0d13e2d8SCharles.Forsyth		t = postop(t);
1332*0d13e2d8SCharles.Forsyth		p = tree(t, p, nil);
1333*0d13e2d8SCharles.Forsyth	}
1334*0d13e2d8SCharles.Forsyth	unlex(t);
1335*0d13e2d8SCharles.Forsyth	return p;
1336*0d13e2d8SCharles.Forsyth}
1337*0d13e2d8SCharles.Forsyth
1338*0d13e2d8SCharles.Forsythckexp(n: ref Node, parop: int)
1339*0d13e2d8SCharles.Forsyth{
1340*0d13e2d8SCharles.Forsyth	if(n == nil)
1341*0d13e2d8SCharles.Forsyth		return;
1342*0d13e2d8SCharles.Forsyth	o := n.op;
1343*0d13e2d8SCharles.Forsyth	l := n.left;
1344*0d13e2d8SCharles.Forsyth	r := n.right;
1345*0d13e2d8SCharles.Forsyth	if(asop(o))
1346*0d13e2d8SCharles.Forsyth		var(l);
1347*0d13e2d8SCharles.Forsyth	case(o){
1348*0d13e2d8SCharles.Forsyth	Ovar =>
1349*0d13e2d8SCharles.Forsyth		s := n.dec.sym;
1350*0d13e2d8SCharles.Forsyth		d := s.dec;
1351*0d13e2d8SCharles.Forsyth		if(d == nil){
1352*0d13e2d8SCharles.Forsyth			if(strict)
1353*0d13e2d8SCharles.Forsyth				error(n, sys->sprint("%s undefined", s.name));
1354*0d13e2d8SCharles.Forsyth			d = mkdec(s, Ovar, 1);
1355*0d13e2d8SCharles.Forsyth		}
1356*0d13e2d8SCharles.Forsyth		n.dec = d;
1357*0d13e2d8SCharles.Forsyth	Odas =>
1358*0d13e2d8SCharles.Forsyth		ckexp(r, o);
1359*0d13e2d8SCharles.Forsyth		l.dec = mkdec(l.dec.sym, Ovar, 1);
1360*0d13e2d8SCharles.Forsyth	* =>
1361*0d13e2d8SCharles.Forsyth		ckexp(l, o);
1362*0d13e2d8SCharles.Forsyth		ckexp(r, o);
1363*0d13e2d8SCharles.Forsyth		if(o == Oquest && r.op != Ocolon)
1364*0d13e2d8SCharles.Forsyth			error(n, "bad '?' operator");
1365*0d13e2d8SCharles.Forsyth		if(o == Ocolon && parop != Oquest)
1366*0d13e2d8SCharles.Forsyth			error(n, "bad ':' operator");
1367*0d13e2d8SCharles.Forsyth	}
1368*0d13e2d8SCharles.Forsyth}
1369*0d13e2d8SCharles.Forsyth
1370*0d13e2d8SCharles.Forsythcommas(n: ref Node): int
1371*0d13e2d8SCharles.Forsyth{
1372*0d13e2d8SCharles.Forsyth	if(n == nil || n.op == Ofun || n.op == Olfun)
1373*0d13e2d8SCharles.Forsyth		return 0;
1374*0d13e2d8SCharles.Forsyth	c := commas(n.left)+commas(n.right);
1375*0d13e2d8SCharles.Forsyth	if(n.op == Ocomma)
1376*0d13e2d8SCharles.Forsyth		c++;
1377*0d13e2d8SCharles.Forsyth	return c;
1378*0d13e2d8SCharles.Forsyth}
1379*0d13e2d8SCharles.Forsyth
1380*0d13e2d8SCharles.Forsythallvar(n: ref Node)
1381*0d13e2d8SCharles.Forsyth{
1382*0d13e2d8SCharles.Forsyth	if(n == nil)
1383*0d13e2d8SCharles.Forsyth		return;
1384*0d13e2d8SCharles.Forsyth	if(n.op == Ocomma){
1385*0d13e2d8SCharles.Forsyth		allvar(n.left);
1386*0d13e2d8SCharles.Forsyth		allvar(n.right);
1387*0d13e2d8SCharles.Forsyth		return;
1388*0d13e2d8SCharles.Forsyth	}
1389*0d13e2d8SCharles.Forsyth	var(n);
1390*0d13e2d8SCharles.Forsyth}
1391*0d13e2d8SCharles.Forsyth
1392*0d13e2d8SCharles.Forsythargs(p: int): (int, ref Node)
1393*0d13e2d8SCharles.Forsyth{
1394*0d13e2d8SCharles.Forsyth	if(!p)
1395*0d13e2d8SCharles.Forsyth		mustbe(Olbr);
1396*0d13e2d8SCharles.Forsyth	a := exp(p, 1);
1397*0d13e2d8SCharles.Forsyth	if(!p)
1398*0d13e2d8SCharles.Forsyth		mustbe(Orbr);
1399*0d13e2d8SCharles.Forsyth	na := 0;
1400*0d13e2d8SCharles.Forsyth	if(a != nil)
1401*0d13e2d8SCharles.Forsyth		na = commas(a)+1;
1402*0d13e2d8SCharles.Forsyth	return (na, a);
1403*0d13e2d8SCharles.Forsyth}
1404*0d13e2d8SCharles.Forsyth
1405*0d13e2d8SCharles.Forsythhash(s: string): int
1406*0d13e2d8SCharles.Forsyth{
1407*0d13e2d8SCharles.Forsyth	l := len s;
1408*0d13e2d8SCharles.Forsyth	h := 4104;
1409*0d13e2d8SCharles.Forsyth	for(i := 0; i < l; i++)
1410*0d13e2d8SCharles.Forsyth		h = 1729*h ^ s[i];
1411*0d13e2d8SCharles.Forsyth	if(h < 0)
1412*0d13e2d8SCharles.Forsyth		h = -h;
1413*0d13e2d8SCharles.Forsyth	return h&(Hash-1);
1414*0d13e2d8SCharles.Forsyth}
1415*0d13e2d8SCharles.Forsyth
1416*0d13e2d8SCharles.Forsythenter(sp: string, k: int): ref Sym
1417*0d13e2d8SCharles.Forsyth{
1418*0d13e2d8SCharles.Forsyth	for(s := syms[hash(sp)]; s != nil; s = s.next){
1419*0d13e2d8SCharles.Forsyth		if(sp == s.name)
1420*0d13e2d8SCharles.Forsyth			return s;
1421*0d13e2d8SCharles.Forsyth	}
1422*0d13e2d8SCharles.Forsyth	s = ref Sym;
1423*0d13e2d8SCharles.Forsyth	s.name = sp;
1424*0d13e2d8SCharles.Forsyth	s.kind = k;
1425*0d13e2d8SCharles.Forsyth	h := hash(sp);
1426*0d13e2d8SCharles.Forsyth	s.next = syms[h];
1427*0d13e2d8SCharles.Forsyth	syms[h] = s;
1428*0d13e2d8SCharles.Forsyth	return s;
1429*0d13e2d8SCharles.Forsyth}
1430*0d13e2d8SCharles.Forsyth
1431*0d13e2d8SCharles.Forsythlookup(sp: string): ref Sym
1432*0d13e2d8SCharles.Forsyth{
1433*0d13e2d8SCharles.Forsyth	return enter(sp, Oident);
1434*0d13e2d8SCharles.Forsyth}
1435*0d13e2d8SCharles.Forsyth
1436*0d13e2d8SCharles.Forsythmkdec(s: ref Sym, k: int, dec: int): ref Dec
1437*0d13e2d8SCharles.Forsyth{
1438*0d13e2d8SCharles.Forsyth	d := ref Dec;
1439*0d13e2d8SCharles.Forsyth	d.kind = k;
1440*0d13e2d8SCharles.Forsyth	d.val = 0.0;
1441*0d13e2d8SCharles.Forsyth	d.na = 0;
1442*0d13e2d8SCharles.Forsyth	d.sym = s;
1443*0d13e2d8SCharles.Forsyth	d.scope = 0;
1444*0d13e2d8SCharles.Forsyth	if(dec)
1445*0d13e2d8SCharles.Forsyth		pushdec(d);
1446*0d13e2d8SCharles.Forsyth	return d;
1447*0d13e2d8SCharles.Forsyth}
1448*0d13e2d8SCharles.Forsyth
1449*0d13e2d8SCharles.Forsythadddec(sp: string, k: int, v: real, n: int): ref Dec
1450*0d13e2d8SCharles.Forsyth{
1451*0d13e2d8SCharles.Forsyth	d := mkdec(enter(sp, Oident), k, 1);
1452*0d13e2d8SCharles.Forsyth	d.val = v;
1453*0d13e2d8SCharles.Forsyth	d.na = n;
1454*0d13e2d8SCharles.Forsyth	return d;
1455*0d13e2d8SCharles.Forsyth}
1456*0d13e2d8SCharles.Forsyth
1457*0d13e2d8SCharles.Forsythscope: int;
1458*0d13e2d8SCharles.Forsythcurscope: ref Dec;
1459*0d13e2d8SCharles.Forsythscopes: list of ref Dec;
1460*0d13e2d8SCharles.Forsyth
1461*0d13e2d8SCharles.Forsythpushscope()
1462*0d13e2d8SCharles.Forsyth{
1463*0d13e2d8SCharles.Forsyth	scope++;
1464*0d13e2d8SCharles.Forsyth	scopes = curscope :: scopes;
1465*0d13e2d8SCharles.Forsyth	curscope = nil;
1466*0d13e2d8SCharles.Forsyth}
1467*0d13e2d8SCharles.Forsyth
1468*0d13e2d8SCharles.Forsythpopscope()
1469*0d13e2d8SCharles.Forsyth{
1470*0d13e2d8SCharles.Forsyth	popdecs();
1471*0d13e2d8SCharles.Forsyth	curscope = hd scopes;
1472*0d13e2d8SCharles.Forsyth	scopes = tl scopes;
1473*0d13e2d8SCharles.Forsyth	scope--;
1474*0d13e2d8SCharles.Forsyth}
1475*0d13e2d8SCharles.Forsyth
1476*0d13e2d8SCharles.Forsythpushparams(n: ref Node)
1477*0d13e2d8SCharles.Forsyth{
1478*0d13e2d8SCharles.Forsyth	if(n == nil)
1479*0d13e2d8SCharles.Forsyth		return;
1480*0d13e2d8SCharles.Forsyth	if(n.op == Ocomma){
1481*0d13e2d8SCharles.Forsyth		pushparams(n.left);
1482*0d13e2d8SCharles.Forsyth		pushparams(n.right);
1483*0d13e2d8SCharles.Forsyth		return;
1484*0d13e2d8SCharles.Forsyth	}
1485*0d13e2d8SCharles.Forsyth	n.dec = mkdec(n.dec.sym, Ovar, 1);
1486*0d13e2d8SCharles.Forsyth}
1487*0d13e2d8SCharles.Forsyth
1488*0d13e2d8SCharles.Forsythpushdec(d: ref Dec)
1489*0d13e2d8SCharles.Forsyth{
1490*0d13e2d8SCharles.Forsyth	if(0 && debug)
1491*0d13e2d8SCharles.Forsyth		sys->print("dec %s scope %d\n", d.sym.name, scope);
1492*0d13e2d8SCharles.Forsyth	d.scope = scope;
1493*0d13e2d8SCharles.Forsyth	s := d.sym;
1494*0d13e2d8SCharles.Forsyth	if(s.dec != nil && s.dec.scope == scope)
1495*0d13e2d8SCharles.Forsyth		error(nil, sys->sprint("redeclaration of %s", s.name));
1496*0d13e2d8SCharles.Forsyth	d.old = s.dec;
1497*0d13e2d8SCharles.Forsyth	s.dec = d;
1498*0d13e2d8SCharles.Forsyth	d.next = curscope;
1499*0d13e2d8SCharles.Forsyth	curscope = d;
1500*0d13e2d8SCharles.Forsyth}
1501*0d13e2d8SCharles.Forsyth
1502*0d13e2d8SCharles.Forsythpopdecs()
1503*0d13e2d8SCharles.Forsyth{
1504*0d13e2d8SCharles.Forsyth	nd: ref Dec;
1505*0d13e2d8SCharles.Forsyth	for(d := curscope; d != nil; d = nd){
1506*0d13e2d8SCharles.Forsyth		d.sym.dec = d.old;
1507*0d13e2d8SCharles.Forsyth		d.old = nil;
1508*0d13e2d8SCharles.Forsyth		nd = d.next;
1509*0d13e2d8SCharles.Forsyth		d.next = nil;
1510*0d13e2d8SCharles.Forsyth	}
1511*0d13e2d8SCharles.Forsyth	curscope = nil;
1512*0d13e2d8SCharles.Forsyth}
1513*0d13e2d8SCharles.Forsyth
1514*0d13e2d8SCharles.Forsythestat(n: ref Node): (int, real)
1515*0d13e2d8SCharles.Forsyth{
1516*0d13e2d8SCharles.Forsyth	k: int;
1517*0d13e2d8SCharles.Forsyth	v: real;
1518*0d13e2d8SCharles.Forsyth
1519*0d13e2d8SCharles.Forsyth	if(n == nil)
1520*0d13e2d8SCharles.Forsyth		return (Onothing, 0.0);
1521*0d13e2d8SCharles.Forsyth	l := n.left;
1522*0d13e2d8SCharles.Forsyth	r := n.right;
1523*0d13e2d8SCharles.Forsyth	case(n.op){
1524*0d13e2d8SCharles.Forsyth	Ocomma =>
1525*0d13e2d8SCharles.Forsyth		(k, v) = estat(l);
1526*0d13e2d8SCharles.Forsyth		if(k == Oexit || k == Oret || k == Obreak || k == Ocont)
1527*0d13e2d8SCharles.Forsyth			return (k, v);
1528*0d13e2d8SCharles.Forsyth		return estat(r);
1529*0d13e2d8SCharles.Forsyth	Oprint =>
1530*0d13e2d8SCharles.Forsyth		v = print(l);
1531*0d13e2d8SCharles.Forsyth		return (Onothing, v);
1532*0d13e2d8SCharles.Forsyth	Oread =>
1533*0d13e2d8SCharles.Forsyth		v = read(l);
1534*0d13e2d8SCharles.Forsyth		return (Onothing, v);
1535*0d13e2d8SCharles.Forsyth	Obreak or
1536*0d13e2d8SCharles.Forsyth	Ocont or
1537*0d13e2d8SCharles.Forsyth	Oexit =>
1538*0d13e2d8SCharles.Forsyth		return (n.op, 0.0);
1539*0d13e2d8SCharles.Forsyth	Oret =>
1540*0d13e2d8SCharles.Forsyth		return (Oret, eval(l));
1541*0d13e2d8SCharles.Forsyth	Oif =>
1542*0d13e2d8SCharles.Forsyth		v = eval(l);
1543*0d13e2d8SCharles.Forsyth		if(int v)
1544*0d13e2d8SCharles.Forsyth			return estat(r.left);
1545*0d13e2d8SCharles.Forsyth		else if(r.right != nil)
1546*0d13e2d8SCharles.Forsyth			return estat(r.right);
1547*0d13e2d8SCharles.Forsyth		else
1548*0d13e2d8SCharles.Forsyth			return (Onothing, v);
1549*0d13e2d8SCharles.Forsyth	Ofor =>
1550*0d13e2d8SCharles.Forsyth		for(;;){
1551*0d13e2d8SCharles.Forsyth			v = eval(l);
1552*0d13e2d8SCharles.Forsyth			if(!int v)
1553*0d13e2d8SCharles.Forsyth				break;
1554*0d13e2d8SCharles.Forsyth			(k, v) = estat(r.left);
1555*0d13e2d8SCharles.Forsyth			if(k == Oexit || k == Oret)
1556*0d13e2d8SCharles.Forsyth				return (k, v);
1557*0d13e2d8SCharles.Forsyth			if(k == Obreak)
1558*0d13e2d8SCharles.Forsyth				break;
1559*0d13e2d8SCharles.Forsyth			if(r.right != nil)
1560*0d13e2d8SCharles.Forsyth				v = eval(r.right);
1561*0d13e2d8SCharles.Forsyth		}
1562*0d13e2d8SCharles.Forsyth		return (Onothing, v);
1563*0d13e2d8SCharles.Forsyth	Odo =>
1564*0d13e2d8SCharles.Forsyth		for(;;){
1565*0d13e2d8SCharles.Forsyth			(k, v) = estat(l);
1566*0d13e2d8SCharles.Forsyth			if(k == Oexit || k == Oret)
1567*0d13e2d8SCharles.Forsyth				return (k, v);
1568*0d13e2d8SCharles.Forsyth			if(k == Obreak)
1569*0d13e2d8SCharles.Forsyth				break;
1570*0d13e2d8SCharles.Forsyth			v = eval(r);
1571*0d13e2d8SCharles.Forsyth			if(!int v)
1572*0d13e2d8SCharles.Forsyth				break;
1573*0d13e2d8SCharles.Forsyth		}
1574*0d13e2d8SCharles.Forsyth		return (Onothing, v);
1575*0d13e2d8SCharles.Forsyth	* =>
1576*0d13e2d8SCharles.Forsyth		return (Onothing, eval(n));
1577*0d13e2d8SCharles.Forsyth	}
1578*0d13e2d8SCharles.Forsyth	return (Onothing, 0.0);
1579*0d13e2d8SCharles.Forsyth}
1580*0d13e2d8SCharles.Forsyth
1581*0d13e2d8SCharles.Forsytheval(e: ref Node): real
1582*0d13e2d8SCharles.Forsyth{
1583*0d13e2d8SCharles.Forsyth	lv, rv: real;
1584*0d13e2d8SCharles.Forsyth
1585*0d13e2d8SCharles.Forsyth	if(e == nil)
1586*0d13e2d8SCharles.Forsyth		return 1.0;
1587*0d13e2d8SCharles.Forsyth	o := e.op;
1588*0d13e2d8SCharles.Forsyth	l := e.left;
1589*0d13e2d8SCharles.Forsyth	r := e.right;
1590*0d13e2d8SCharles.Forsyth	if(o != Ofun && o != Olfun)
1591*0d13e2d8SCharles.Forsyth		lv = eval(l);
1592*0d13e2d8SCharles.Forsyth	if(o != Oandand && o != Ooror && o != Oquest)
1593*0d13e2d8SCharles.Forsyth		rv = eval(r);
1594*0d13e2d8SCharles.Forsyth	case(o){
1595*0d13e2d8SCharles.Forsyth	Ostring =>
1596*0d13e2d8SCharles.Forsyth		return 0.0;
1597*0d13e2d8SCharles.Forsyth	Onum =>
1598*0d13e2d8SCharles.Forsyth		return e.val;
1599*0d13e2d8SCharles.Forsyth	Ocon or
1600*0d13e2d8SCharles.Forsyth	Ovar =>
1601*0d13e2d8SCharles.Forsyth		return e.dec.val;
1602*0d13e2d8SCharles.Forsyth	Ofun =>
1603*0d13e2d8SCharles.Forsyth		return call(e.dec, l);
1604*0d13e2d8SCharles.Forsyth	Olfun =>
1605*0d13e2d8SCharles.Forsyth		return libfun(int e.dec.val, l);
1606*0d13e2d8SCharles.Forsyth	Oadd =>
1607*0d13e2d8SCharles.Forsyth		return lv+rv;
1608*0d13e2d8SCharles.Forsyth	Osub =>
1609*0d13e2d8SCharles.Forsyth		return lv-rv;
1610*0d13e2d8SCharles.Forsyth	Omul =>
1611*0d13e2d8SCharles.Forsyth		return lv*rv;
1612*0d13e2d8SCharles.Forsyth	Odiv =>
1613*0d13e2d8SCharles.Forsyth		return lv/rv;
1614*0d13e2d8SCharles.Forsyth	Omod =>
1615*0d13e2d8SCharles.Forsyth		return real (big lv%big rv);
1616*0d13e2d8SCharles.Forsyth	Oidiv =>
1617*0d13e2d8SCharles.Forsyth		return real (big lv/big rv);
1618*0d13e2d8SCharles.Forsyth	Oand =>
1619*0d13e2d8SCharles.Forsyth		return real (big lv&big rv);
1620*0d13e2d8SCharles.Forsyth	Oor =>
1621*0d13e2d8SCharles.Forsyth		return real (big lv|big rv);
1622*0d13e2d8SCharles.Forsyth	Oxor =>
1623*0d13e2d8SCharles.Forsyth		return real (big lv^big rv);
1624*0d13e2d8SCharles.Forsyth	Olsh =>
1625*0d13e2d8SCharles.Forsyth		return real (big lv<<int rv);
1626*0d13e2d8SCharles.Forsyth	Orsh =>
1627*0d13e2d8SCharles.Forsyth		return real (big lv>>int rv);
1628*0d13e2d8SCharles.Forsyth	Oeq =>
1629*0d13e2d8SCharles.Forsyth		return real (lv == rv);
1630*0d13e2d8SCharles.Forsyth	One =>
1631*0d13e2d8SCharles.Forsyth		return real (lv != rv);
1632*0d13e2d8SCharles.Forsyth	Ogt =>
1633*0d13e2d8SCharles.Forsyth		return real (lv > rv);
1634*0d13e2d8SCharles.Forsyth	Olt =>
1635*0d13e2d8SCharles.Forsyth		return real (lv < rv);
1636*0d13e2d8SCharles.Forsyth	Oge =>
1637*0d13e2d8SCharles.Forsyth		return real (lv >= rv);
1638*0d13e2d8SCharles.Forsyth	Ole =>
1639*0d13e2d8SCharles.Forsyth		return real (lv <= rv);
1640*0d13e2d8SCharles.Forsyth	Opreinc =>
1641*0d13e2d8SCharles.Forsyth		l.dec.val += 1.0;
1642*0d13e2d8SCharles.Forsyth		return l.dec.val;
1643*0d13e2d8SCharles.Forsyth	Opostinc =>
1644*0d13e2d8SCharles.Forsyth		l.dec.val += 1.0;
1645*0d13e2d8SCharles.Forsyth		return l.dec.val-1.0;
1646*0d13e2d8SCharles.Forsyth	Opredec =>
1647*0d13e2d8SCharles.Forsyth		l.dec.val -= 1.0;
1648*0d13e2d8SCharles.Forsyth		return l.dec.val;
1649*0d13e2d8SCharles.Forsyth	Opostdec =>
1650*0d13e2d8SCharles.Forsyth		l.dec.val -= 1.0;
1651*0d13e2d8SCharles.Forsyth		return l.dec.val+1.0;
1652*0d13e2d8SCharles.Forsyth	Oexp =>
1653*0d13e2d8SCharles.Forsyth		if(isinteger(rv) && rv >= 0.0)
1654*0d13e2d8SCharles.Forsyth			return lv**int rv;
1655*0d13e2d8SCharles.Forsyth		return maths->pow(lv, rv);
1656*0d13e2d8SCharles.Forsyth	Oandand =>
1657*0d13e2d8SCharles.Forsyth		if(!int lv)
1658*0d13e2d8SCharles.Forsyth			return lv;
1659*0d13e2d8SCharles.Forsyth		return eval(r);
1660*0d13e2d8SCharles.Forsyth	Ooror =>
1661*0d13e2d8SCharles.Forsyth		if(int lv)
1662*0d13e2d8SCharles.Forsyth			return lv;
1663*0d13e2d8SCharles.Forsyth		return eval(r);
1664*0d13e2d8SCharles.Forsyth	Onot =>
1665*0d13e2d8SCharles.Forsyth		return real !int lv;
1666*0d13e2d8SCharles.Forsyth	Ofact =>
1667*0d13e2d8SCharles.Forsyth		if(isinteger(lv) && lv >= 0.0){
1668*0d13e2d8SCharles.Forsyth			n := int lv;
1669*0d13e2d8SCharles.Forsyth			lv = 1.0;
1670*0d13e2d8SCharles.Forsyth			for(i := 2; i <= n; i++)
1671*0d13e2d8SCharles.Forsyth				lv *= real i;
1672*0d13e2d8SCharles.Forsyth			return lv;
1673*0d13e2d8SCharles.Forsyth		}
1674*0d13e2d8SCharles.Forsyth		return gamma(lv+1.0);
1675*0d13e2d8SCharles.Forsyth	Ocom =>
1676*0d13e2d8SCharles.Forsyth		return real ~big lv;
1677*0d13e2d8SCharles.Forsyth	Oas or
1678*0d13e2d8SCharles.Forsyth	Odas =>
1679*0d13e2d8SCharles.Forsyth		l.dec.val = rv;
1680*0d13e2d8SCharles.Forsyth		return rv;
1681*0d13e2d8SCharles.Forsyth	Oplus =>
1682*0d13e2d8SCharles.Forsyth		return lv;
1683*0d13e2d8SCharles.Forsyth	Ominus =>
1684*0d13e2d8SCharles.Forsyth		return -lv;
1685*0d13e2d8SCharles.Forsyth	Oinv =>
1686*0d13e2d8SCharles.Forsyth		return 1.0/lv;
1687*0d13e2d8SCharles.Forsyth	Ocomma =>
1688*0d13e2d8SCharles.Forsyth		return rv;
1689*0d13e2d8SCharles.Forsyth	Oquest =>
1690*0d13e2d8SCharles.Forsyth		if(int lv)
1691*0d13e2d8SCharles.Forsyth			return eval(r.left);
1692*0d13e2d8SCharles.Forsyth		else
1693*0d13e2d8SCharles.Forsyth			return eval(r.right);
1694*0d13e2d8SCharles.Forsyth	Onand =>
1695*0d13e2d8SCharles.Forsyth		return real !(int lv&int rv);
1696*0d13e2d8SCharles.Forsyth	Onor =>
1697*0d13e2d8SCharles.Forsyth		return real !(int lv|int rv);
1698*0d13e2d8SCharles.Forsyth	Oimp =>
1699*0d13e2d8SCharles.Forsyth		return real (!int lv|int rv);
1700*0d13e2d8SCharles.Forsyth	Oimpby =>
1701*0d13e2d8SCharles.Forsyth		return real (int lv|!int rv);
1702*0d13e2d8SCharles.Forsyth	Oiff =>
1703*0d13e2d8SCharles.Forsyth		return real !(int lv^int rv);
1704*0d13e2d8SCharles.Forsyth	* =>
1705*0d13e2d8SCharles.Forsyth		fatal(sys->sprint("case %s in eval", opstring(o)));
1706*0d13e2d8SCharles.Forsyth	}
1707*0d13e2d8SCharles.Forsyth	return 0.0;
1708*0d13e2d8SCharles.Forsyth}
1709*0d13e2d8SCharles.Forsyth
1710*0d13e2d8SCharles.Forsythvar(e: ref Node)
1711*0d13e2d8SCharles.Forsyth{
1712*0d13e2d8SCharles.Forsyth	if(e == nil || e.op != Ovar || e.dec.kind != Ovar)
1713*0d13e2d8SCharles.Forsyth		error(e, "expected a variable");
1714*0d13e2d8SCharles.Forsyth}
1715*0d13e2d8SCharles.Forsyth
1716*0d13e2d8SCharles.Forsythlibfun(o: int, a: ref Node): real
1717*0d13e2d8SCharles.Forsyth{
1718*0d13e2d8SCharles.Forsyth	a1, a2: real;
1719*0d13e2d8SCharles.Forsyth
1720*0d13e2d8SCharles.Forsyth	case(o){
1721*0d13e2d8SCharles.Forsyth	Osolve =>
1722*0d13e2d8SCharles.Forsyth		return solve(a);
1723*0d13e2d8SCharles.Forsyth	Osigma or
1724*0d13e2d8SCharles.Forsyth	Opi or
1725*0d13e2d8SCharles.Forsyth	Ocfrac =>
1726*0d13e2d8SCharles.Forsyth		return series(o, a);
1727*0d13e2d8SCharles.Forsyth	Oderiv =>
1728*0d13e2d8SCharles.Forsyth		return differential(a);
1729*0d13e2d8SCharles.Forsyth	Ointeg =>
1730*0d13e2d8SCharles.Forsyth		return integral(a);
1731*0d13e2d8SCharles.Forsyth	}
1732*0d13e2d8SCharles.Forsyth	v := 0.0;
1733*0d13e2d8SCharles.Forsyth	if(a != nil && a.op == Ocomma){
1734*0d13e2d8SCharles.Forsyth		a1 = eval(a.left);
1735*0d13e2d8SCharles.Forsyth		a2 = eval(a.right);
1736*0d13e2d8SCharles.Forsyth	}
1737*0d13e2d8SCharles.Forsyth	else
1738*0d13e2d8SCharles.Forsyth		a1 = eval(a);
1739*0d13e2d8SCharles.Forsyth	case(o){
1740*0d13e2d8SCharles.Forsyth	Olog =>
1741*0d13e2d8SCharles.Forsyth		v = maths->log(a1);
1742*0d13e2d8SCharles.Forsyth	Olog10 =>
1743*0d13e2d8SCharles.Forsyth		v = maths->log10(a1);
1744*0d13e2d8SCharles.Forsyth	Olog2 =>
1745*0d13e2d8SCharles.Forsyth		v = maths->log(a1)/maths->log(2.0);
1746*0d13e2d8SCharles.Forsyth	Ologb =>
1747*0d13e2d8SCharles.Forsyth		v = maths->log(a1)/maths->log(a2);
1748*0d13e2d8SCharles.Forsyth	Oexpf =>
1749*0d13e2d8SCharles.Forsyth		v = maths->exp(a1);
1750*0d13e2d8SCharles.Forsyth	Opow =>
1751*0d13e2d8SCharles.Forsyth		v = maths->pow(a1, a2);
1752*0d13e2d8SCharles.Forsyth	Osqrt =>
1753*0d13e2d8SCharles.Forsyth		v = maths->sqrt(a1);
1754*0d13e2d8SCharles.Forsyth	Ocbrt =>
1755*0d13e2d8SCharles.Forsyth		v = maths->cbrt(a1);
1756*0d13e2d8SCharles.Forsyth	Ofloor =>
1757*0d13e2d8SCharles.Forsyth		v = maths->floor(a1);
1758*0d13e2d8SCharles.Forsyth	Oceil =>
1759*0d13e2d8SCharles.Forsyth		v = maths->ceil(a1);
1760*0d13e2d8SCharles.Forsyth	Omin =>
1761*0d13e2d8SCharles.Forsyth		v = maths->fmin(a1, a2);
1762*0d13e2d8SCharles.Forsyth	Omax =>
1763*0d13e2d8SCharles.Forsyth		v = maths->fmax(a1, a2);
1764*0d13e2d8SCharles.Forsyth	Oabs =>
1765*0d13e2d8SCharles.Forsyth		v = maths->fabs(a1);
1766*0d13e2d8SCharles.Forsyth	Ogamma =>
1767*0d13e2d8SCharles.Forsyth		v = gamma(a1);
1768*0d13e2d8SCharles.Forsyth	Osign =>
1769*0d13e2d8SCharles.Forsyth		if(a1 > 0.0)
1770*0d13e2d8SCharles.Forsyth			v = 1.0;
1771*0d13e2d8SCharles.Forsyth		else if(a1 < 0.0)
1772*0d13e2d8SCharles.Forsyth			v = -1.0;
1773*0d13e2d8SCharles.Forsyth		else
1774*0d13e2d8SCharles.Forsyth			v = 0.0;
1775*0d13e2d8SCharles.Forsyth	Oint =>
1776*0d13e2d8SCharles.Forsyth		(vi, nil) := maths->modf(a1);
1777*0d13e2d8SCharles.Forsyth		v = real vi;
1778*0d13e2d8SCharles.Forsyth	Ofrac =>
1779*0d13e2d8SCharles.Forsyth		(nil, v) = maths->modf(a1);
1780*0d13e2d8SCharles.Forsyth	Oround =>
1781*0d13e2d8SCharles.Forsyth		v = maths->rint(a1);
1782*0d13e2d8SCharles.Forsyth	Oerf =>
1783*0d13e2d8SCharles.Forsyth		v = maths->erf(a1);
1784*0d13e2d8SCharles.Forsyth	Osin =>
1785*0d13e2d8SCharles.Forsyth		v = maths->sin(D2R(a1));
1786*0d13e2d8SCharles.Forsyth	Ocos =>
1787*0d13e2d8SCharles.Forsyth		v = maths->cos(D2R(a1));
1788*0d13e2d8SCharles.Forsyth	Otan =>
1789*0d13e2d8SCharles.Forsyth		v = maths->tan(D2R(a1));
1790*0d13e2d8SCharles.Forsyth	Oasin =>
1791*0d13e2d8SCharles.Forsyth		v = R2D(maths->asin(a1));
1792*0d13e2d8SCharles.Forsyth	Oacos =>
1793*0d13e2d8SCharles.Forsyth		v = R2D(maths->acos(a1));
1794*0d13e2d8SCharles.Forsyth	Oatan =>
1795*0d13e2d8SCharles.Forsyth		v = R2D(maths->atan(a1));
1796*0d13e2d8SCharles.Forsyth	Oatan2 =>
1797*0d13e2d8SCharles.Forsyth		v = R2D(maths->atan2(a1, a2));
1798*0d13e2d8SCharles.Forsyth	Osinh =>
1799*0d13e2d8SCharles.Forsyth		v = maths->sinh(a1);
1800*0d13e2d8SCharles.Forsyth	Ocosh =>
1801*0d13e2d8SCharles.Forsyth		v = maths->cosh(a1);
1802*0d13e2d8SCharles.Forsyth	Otanh =>
1803*0d13e2d8SCharles.Forsyth		v = maths->tanh(a1);
1804*0d13e2d8SCharles.Forsyth	Oasinh =>
1805*0d13e2d8SCharles.Forsyth		v = maths->asinh(a1);
1806*0d13e2d8SCharles.Forsyth	Oacosh =>
1807*0d13e2d8SCharles.Forsyth		v = maths->acosh(a1);
1808*0d13e2d8SCharles.Forsyth	Oatanh =>
1809*0d13e2d8SCharles.Forsyth		v = maths->atanh(a1);
1810*0d13e2d8SCharles.Forsyth	Orand =>
1811*0d13e2d8SCharles.Forsyth		v = real rand->rand(Big)/real Big;
1812*0d13e2d8SCharles.Forsyth	* =>
1813*0d13e2d8SCharles.Forsyth		fatal(sys->sprint("case %s in libfun", opstring(o)));
1814*0d13e2d8SCharles.Forsyth	}
1815*0d13e2d8SCharles.Forsyth	return v;
1816*0d13e2d8SCharles.Forsyth}
1817*0d13e2d8SCharles.Forsyth
1818*0d13e2d8SCharles.Forsythseries(o: int, a: ref Node): real
1819*0d13e2d8SCharles.Forsyth{
1820*0d13e2d8SCharles.Forsyth	p0, p1, q0, q1: real;
1821*0d13e2d8SCharles.Forsyth
1822*0d13e2d8SCharles.Forsyth	l := a.left;
1823*0d13e2d8SCharles.Forsyth	r := a.right;
1824*0d13e2d8SCharles.Forsyth	if(o == Osigma)
1825*0d13e2d8SCharles.Forsyth		v := 0.0;
1826*0d13e2d8SCharles.Forsyth	else if(o == Opi)
1827*0d13e2d8SCharles.Forsyth		v = 1.0;
1828*0d13e2d8SCharles.Forsyth	else{
1829*0d13e2d8SCharles.Forsyth		p0 = q1 = 0.0;
1830*0d13e2d8SCharles.Forsyth		p1 = q0 = 1.0;
1831*0d13e2d8SCharles.Forsyth		v = Infinity;
1832*0d13e2d8SCharles.Forsyth	}
1833*0d13e2d8SCharles.Forsyth	i := l.left.left.dec;
1834*0d13e2d8SCharles.Forsyth	ov := i.val;
1835*0d13e2d8SCharles.Forsyth	i.val = eval(l.left.right);
1836*0d13e2d8SCharles.Forsyth	eq := 0;
1837*0d13e2d8SCharles.Forsyth	for(;;){
1838*0d13e2d8SCharles.Forsyth		rv := eval(l.right);
1839*0d13e2d8SCharles.Forsyth		if(i.val > rv)
1840*0d13e2d8SCharles.Forsyth			break;
1841*0d13e2d8SCharles.Forsyth		lv := v;
1842*0d13e2d8SCharles.Forsyth		ev := eval(r);
1843*0d13e2d8SCharles.Forsyth		if(o == Osigma)
1844*0d13e2d8SCharles.Forsyth			v += ev;
1845*0d13e2d8SCharles.Forsyth		else if(o == Opi)
1846*0d13e2d8SCharles.Forsyth			v *= ev;
1847*0d13e2d8SCharles.Forsyth		else{
1848*0d13e2d8SCharles.Forsyth			t := ev*p1+p0;
1849*0d13e2d8SCharles.Forsyth			p0 = p1;
1850*0d13e2d8SCharles.Forsyth			p1 = t;
1851*0d13e2d8SCharles.Forsyth			t = ev*q1+q0;
1852*0d13e2d8SCharles.Forsyth			q0 = q1;
1853*0d13e2d8SCharles.Forsyth			q1 = t;
1854*0d13e2d8SCharles.Forsyth			v = p1/q1;
1855*0d13e2d8SCharles.Forsyth		}
1856*0d13e2d8SCharles.Forsyth		if(v == lv && rv == Infinity){
1857*0d13e2d8SCharles.Forsyth			eq++;
1858*0d13e2d8SCharles.Forsyth			if(eq > 100)
1859*0d13e2d8SCharles.Forsyth				break;
1860*0d13e2d8SCharles.Forsyth		}
1861*0d13e2d8SCharles.Forsyth		else
1862*0d13e2d8SCharles.Forsyth			eq = 0;
1863*0d13e2d8SCharles.Forsyth		i.val += 1.0;
1864*0d13e2d8SCharles.Forsyth	}
1865*0d13e2d8SCharles.Forsyth	i.val = ov;
1866*0d13e2d8SCharles.Forsyth	return v;
1867*0d13e2d8SCharles.Forsyth}
1868*0d13e2d8SCharles.Forsyth
1869*0d13e2d8SCharles.Forsythpushe(a: ref Node, l: list of real): list of real
1870*0d13e2d8SCharles.Forsyth{
1871*0d13e2d8SCharles.Forsyth	if(a == nil)
1872*0d13e2d8SCharles.Forsyth		return l;
1873*0d13e2d8SCharles.Forsyth	if(a.op == Ocomma){
1874*0d13e2d8SCharles.Forsyth		l = pushe(a.left, l);
1875*0d13e2d8SCharles.Forsyth		return pushe(a.right, l);
1876*0d13e2d8SCharles.Forsyth	}
1877*0d13e2d8SCharles.Forsyth	l = eval(a) :: l;
1878*0d13e2d8SCharles.Forsyth	return l;
1879*0d13e2d8SCharles.Forsyth}
1880*0d13e2d8SCharles.Forsyth
1881*0d13e2d8SCharles.Forsythpusha(f: ref Node, l: list of real, nl: list of real): (list of real, list of real)
1882*0d13e2d8SCharles.Forsyth{
1883*0d13e2d8SCharles.Forsyth	if(f == nil)
1884*0d13e2d8SCharles.Forsyth		return (l, nl);
1885*0d13e2d8SCharles.Forsyth	if(f.op == Ocomma){
1886*0d13e2d8SCharles.Forsyth		(l, nl) = pusha(f.left, l, nl);
1887*0d13e2d8SCharles.Forsyth		return pusha(f.right, l, nl);
1888*0d13e2d8SCharles.Forsyth	}
1889*0d13e2d8SCharles.Forsyth	l = f.dec.val :: l;
1890*0d13e2d8SCharles.Forsyth	f.dec.val = hd nl;
1891*0d13e2d8SCharles.Forsyth	return (l, tl nl);
1892*0d13e2d8SCharles.Forsyth}
1893*0d13e2d8SCharles.Forsyth
1894*0d13e2d8SCharles.Forsythpop(f: ref Node, l: list of real): list of real
1895*0d13e2d8SCharles.Forsyth{
1896*0d13e2d8SCharles.Forsyth	if(f == nil)
1897*0d13e2d8SCharles.Forsyth		return l;
1898*0d13e2d8SCharles.Forsyth	if(f.op == Ocomma){
1899*0d13e2d8SCharles.Forsyth		l = pop(f.left, l);
1900*0d13e2d8SCharles.Forsyth		return pop(f.right, l);
1901*0d13e2d8SCharles.Forsyth	}
1902*0d13e2d8SCharles.Forsyth	f.dec.val = hd l;
1903*0d13e2d8SCharles.Forsyth	return tl l;
1904*0d13e2d8SCharles.Forsyth}
1905*0d13e2d8SCharles.Forsyth
1906*0d13e2d8SCharles.Forsythrev(l: list of real): list of real
1907*0d13e2d8SCharles.Forsyth{
1908*0d13e2d8SCharles.Forsyth	nl: list of real;
1909*0d13e2d8SCharles.Forsyth
1910*0d13e2d8SCharles.Forsyth	for( ; l != nil; l = tl l)
1911*0d13e2d8SCharles.Forsyth		nl = hd l :: nl;
1912*0d13e2d8SCharles.Forsyth	return nl;
1913*0d13e2d8SCharles.Forsyth}
1914*0d13e2d8SCharles.Forsyth
1915*0d13e2d8SCharles.Forsythcall(d: ref Dec, a: ref Node): real
1916*0d13e2d8SCharles.Forsyth{
1917*0d13e2d8SCharles.Forsyth	l: list of real;
1918*0d13e2d8SCharles.Forsyth
1919*0d13e2d8SCharles.Forsyth	nl := rev(pushe(a, nil));
1920*0d13e2d8SCharles.Forsyth	(l, nil) = pusha(d.code.left, nil, nl);
1921*0d13e2d8SCharles.Forsyth	l = rev(l);
1922*0d13e2d8SCharles.Forsyth	(k, v) := estat(d.code.right);
1923*0d13e2d8SCharles.Forsyth	l = pop(d.code.left, l);
1924*0d13e2d8SCharles.Forsyth	if(k == Oexit)
1925*0d13e2d8SCharles.Forsyth		exit;
1926*0d13e2d8SCharles.Forsyth	return v;
1927*0d13e2d8SCharles.Forsyth}
1928*0d13e2d8SCharles.Forsyth
1929*0d13e2d8SCharles.Forsythprint(n: ref Node): real
1930*0d13e2d8SCharles.Forsyth{
1931*0d13e2d8SCharles.Forsyth	if(n == nil)
1932*0d13e2d8SCharles.Forsyth		return 0.0;
1933*0d13e2d8SCharles.Forsyth	if(n.op == Ocomma){
1934*0d13e2d8SCharles.Forsyth		print(n.left);
1935*0d13e2d8SCharles.Forsyth		return print(n.right);
1936*0d13e2d8SCharles.Forsyth	}
1937*0d13e2d8SCharles.Forsyth	if(n.op == Ostring){
1938*0d13e2d8SCharles.Forsyth		sys->print("%s", n.str);
1939*0d13e2d8SCharles.Forsyth		return 0.0;
1940*0d13e2d8SCharles.Forsyth	}
1941*0d13e2d8SCharles.Forsyth	v := eval(n);
1942*0d13e2d8SCharles.Forsyth	printnum(v, "");
1943*0d13e2d8SCharles.Forsyth	return v;
1944*0d13e2d8SCharles.Forsyth}
1945*0d13e2d8SCharles.Forsyth
1946*0d13e2d8SCharles.Forsythread(n: ref Node): real
1947*0d13e2d8SCharles.Forsyth{
1948*0d13e2d8SCharles.Forsyth	bio: ref Iobuf;
1949*0d13e2d8SCharles.Forsyth
1950*0d13e2d8SCharles.Forsyth	if(n == nil)
1951*0d13e2d8SCharles.Forsyth		return 0.0;
1952*0d13e2d8SCharles.Forsyth	if(n.op == Ocomma){
1953*0d13e2d8SCharles.Forsyth		read(n.left);
1954*0d13e2d8SCharles.Forsyth		return read(n.right);
1955*0d13e2d8SCharles.Forsyth	}
1956*0d13e2d8SCharles.Forsyth	sys->print("%s ? ", n.dec.sym.name);
1957*0d13e2d8SCharles.Forsyth	if(!stdin){
1958*0d13e2d8SCharles.Forsyth		bio = bufio->fopen(sys->fildes(0), Sys->OREAD);
1959*0d13e2d8SCharles.Forsyth		stack(nil, bio);
1960*0d13e2d8SCharles.Forsyth	}
1961*0d13e2d8SCharles.Forsyth	lexnum();
1962*0d13e2d8SCharles.Forsyth	consume(Onl);
1963*0d13e2d8SCharles.Forsyth	n.dec.val = lexval;
1964*0d13e2d8SCharles.Forsyth	if(!stdin && bin == bio)
1965*0d13e2d8SCharles.Forsyth		unstack();
1966*0d13e2d8SCharles.Forsyth	return n.dec.val;
1967*0d13e2d8SCharles.Forsyth}
1968*0d13e2d8SCharles.Forsyth
1969*0d13e2d8SCharles.Forsythisint(v: real): int
1970*0d13e2d8SCharles.Forsyth{
1971*0d13e2d8SCharles.Forsyth	return v >= -real Maxint && v <= real Maxint;
1972*0d13e2d8SCharles.Forsyth}
1973*0d13e2d8SCharles.Forsyth
1974*0d13e2d8SCharles.Forsythisinteger(v: real): int
1975*0d13e2d8SCharles.Forsyth{
1976*0d13e2d8SCharles.Forsyth	return v == real int v && isint(v);
1977*0d13e2d8SCharles.Forsyth}
1978*0d13e2d8SCharles.Forsyth
1979*0d13e2d8SCharles.Forsythsplit(v: real): (int, real)
1980*0d13e2d8SCharles.Forsyth{
1981*0d13e2d8SCharles.Forsyth	# v >= 0.0
1982*0d13e2d8SCharles.Forsyth	n := int v;
1983*0d13e2d8SCharles.Forsyth	if(real n > v)
1984*0d13e2d8SCharles.Forsyth		n--;
1985*0d13e2d8SCharles.Forsyth	return (n, v-real n);
1986*0d13e2d8SCharles.Forsyth}
1987*0d13e2d8SCharles.Forsyth
1988*0d13e2d8SCharles.Forsythn2c(n: int): int
1989*0d13e2d8SCharles.Forsyth{
1990*0d13e2d8SCharles.Forsyth	if(n < 10)
1991*0d13e2d8SCharles.Forsyth		return n+'0';
1992*0d13e2d8SCharles.Forsyth	return n-10+'a';
1993*0d13e2d8SCharles.Forsyth}
1994*0d13e2d8SCharles.Forsyth
1995*0d13e2d8SCharles.Forsythgamma(v: real): real
1996*0d13e2d8SCharles.Forsyth{
1997*0d13e2d8SCharles.Forsyth	(s, lg) := maths->lgamma(v);
1998*0d13e2d8SCharles.Forsyth	return real s*maths->exp(lg);
1999*0d13e2d8SCharles.Forsyth}
2000*0d13e2d8SCharles.Forsyth
2001*0d13e2d8SCharles.ForsythD2R(a: real): real
2002*0d13e2d8SCharles.Forsyth{
2003*0d13e2d8SCharles.Forsyth	if(deg.val != 0.0)
2004*0d13e2d8SCharles.Forsyth		a *= Pi/180.0;
2005*0d13e2d8SCharles.Forsyth	return a;
2006*0d13e2d8SCharles.Forsyth}
2007*0d13e2d8SCharles.Forsyth
2008*0d13e2d8SCharles.ForsythR2D(a: real): real
2009*0d13e2d8SCharles.Forsyth{
2010*0d13e2d8SCharles.Forsyth	if(deg.val != 0.0)
2011*0d13e2d8SCharles.Forsyth		a /= Pi/180.0;
2012*0d13e2d8SCharles.Forsyth	return a;
2013*0d13e2d8SCharles.Forsyth}
2014*0d13e2d8SCharles.Forsyth
2015*0d13e2d8SCharles.Forsythside(n: ref Node): int
2016*0d13e2d8SCharles.Forsyth{
2017*0d13e2d8SCharles.Forsyth	if(n == nil)
2018*0d13e2d8SCharles.Forsyth		return 0;
2019*0d13e2d8SCharles.Forsyth	if(asop(n.op) || n.op == Ofun)
2020*0d13e2d8SCharles.Forsyth		return 1;
2021*0d13e2d8SCharles.Forsyth	return side(n.left) || side(n.right);
2022*0d13e2d8SCharles.Forsyth}
2023*0d13e2d8SCharles.Forsyth
2024*0d13e2d8SCharles.Forsythsametree(n1: ref Node, n2: ref Node): int
2025*0d13e2d8SCharles.Forsyth{
2026*0d13e2d8SCharles.Forsyth	if(n1 == n2)
2027*0d13e2d8SCharles.Forsyth		return 1;
2028*0d13e2d8SCharles.Forsyth	if(n1 == nil || n2 == nil)
2029*0d13e2d8SCharles.Forsyth		return 0;
2030*0d13e2d8SCharles.Forsyth	if(n1.op != n2.op)
2031*0d13e2d8SCharles.Forsyth		return 0;
2032*0d13e2d8SCharles.Forsyth	case(n1.op){
2033*0d13e2d8SCharles.Forsyth	Ostring =>
2034*0d13e2d8SCharles.Forsyth		return n1.str == n2.str;
2035*0d13e2d8SCharles.Forsyth	Onum =>
2036*0d13e2d8SCharles.Forsyth		return n1.val == n2.val;
2037*0d13e2d8SCharles.Forsyth	Ocon or
2038*0d13e2d8SCharles.Forsyth	Ovar =>
2039*0d13e2d8SCharles.Forsyth		return n1.dec == n2.dec;
2040*0d13e2d8SCharles.Forsyth	Ofun or
2041*0d13e2d8SCharles.Forsyth	Olfun =>
2042*0d13e2d8SCharles.Forsyth		return n1.dec == n2.dec && sametree(n1.left, n2.left);
2043*0d13e2d8SCharles.Forsyth	* =>
2044*0d13e2d8SCharles.Forsyth		return sametree(n1.left, n2.left) && sametree(n1.right, n2.right);
2045*0d13e2d8SCharles.Forsyth	}
2046*0d13e2d8SCharles.Forsyth	return 0;
2047*0d13e2d8SCharles.Forsyth}
2048*0d13e2d8SCharles.Forsyth
2049*0d13e2d8SCharles.Forsythsimplify(n: ref Node): ref Node
2050*0d13e2d8SCharles.Forsyth{
2051*0d13e2d8SCharles.Forsyth	if(n == nil)
2052*0d13e2d8SCharles.Forsyth		return nil;
2053*0d13e2d8SCharles.Forsyth	op := n.op;
2054*0d13e2d8SCharles.Forsyth	l := n.left = simplify(n.left);
2055*0d13e2d8SCharles.Forsyth	r := n.right = simplify(n.right);
2056*0d13e2d8SCharles.Forsyth	if(l != nil && iscon(l) && (r == nil || iscon(r))){
2057*0d13e2d8SCharles.Forsyth		if(isnan(l))
2058*0d13e2d8SCharles.Forsyth			return l;
2059*0d13e2d8SCharles.Forsyth		if(r != nil && isnan(r))
2060*0d13e2d8SCharles.Forsyth			return r;
2061*0d13e2d8SCharles.Forsyth		return vtree(eval(n));
2062*0d13e2d8SCharles.Forsyth	}
2063*0d13e2d8SCharles.Forsyth	case(op){
2064*0d13e2d8SCharles.Forsyth		Onum or
2065*0d13e2d8SCharles.Forsyth		Ocon or
2066*0d13e2d8SCharles.Forsyth		Ovar or
2067*0d13e2d8SCharles.Forsyth		Olfun or
2068*0d13e2d8SCharles.Forsyth		Ocomma =>
2069*0d13e2d8SCharles.Forsyth			return n;
2070*0d13e2d8SCharles.Forsyth		Oplus =>
2071*0d13e2d8SCharles.Forsyth			return l;
2072*0d13e2d8SCharles.Forsyth		Ominus =>
2073*0d13e2d8SCharles.Forsyth			if(l.op == Ominus)
2074*0d13e2d8SCharles.Forsyth				return l.left;
2075*0d13e2d8SCharles.Forsyth		Oinv =>
2076*0d13e2d8SCharles.Forsyth			if(l.op == Oinv)
2077*0d13e2d8SCharles.Forsyth				return l.left;
2078*0d13e2d8SCharles.Forsyth		Oadd =>
2079*0d13e2d8SCharles.Forsyth			if(iszero(l))
2080*0d13e2d8SCharles.Forsyth				return r;
2081*0d13e2d8SCharles.Forsyth			if(iszero(r))
2082*0d13e2d8SCharles.Forsyth				return l;
2083*0d13e2d8SCharles.Forsyth			if(sametree(l, r))
2084*0d13e2d8SCharles.Forsyth				return tree(Omul, itree(2), l);
2085*0d13e2d8SCharles.Forsyth		Osub =>
2086*0d13e2d8SCharles.Forsyth			if(iszero(l))
2087*0d13e2d8SCharles.Forsyth				return simplify(tree(Ominus, r, nil));
2088*0d13e2d8SCharles.Forsyth			if(iszero(r))
2089*0d13e2d8SCharles.Forsyth				return l;
2090*0d13e2d8SCharles.Forsyth			if(sametree(l, r))
2091*0d13e2d8SCharles.Forsyth				return itree(0);
2092*0d13e2d8SCharles.Forsyth		Omul =>
2093*0d13e2d8SCharles.Forsyth			if(iszero(l))
2094*0d13e2d8SCharles.Forsyth				return l;
2095*0d13e2d8SCharles.Forsyth			if(iszero(r))
2096*0d13e2d8SCharles.Forsyth				return r;
2097*0d13e2d8SCharles.Forsyth			if(isone(l))
2098*0d13e2d8SCharles.Forsyth				return r;
2099*0d13e2d8SCharles.Forsyth			if(isone(r))
2100*0d13e2d8SCharles.Forsyth				return l;
2101*0d13e2d8SCharles.Forsyth			if(sametree(l, r))
2102*0d13e2d8SCharles.Forsyth				return tree(Oexp, l, itree(2));
2103*0d13e2d8SCharles.Forsyth		Odiv =>
2104*0d13e2d8SCharles.Forsyth			if(iszero(l))
2105*0d13e2d8SCharles.Forsyth				return l;
2106*0d13e2d8SCharles.Forsyth			if(iszero(r))
2107*0d13e2d8SCharles.Forsyth				return vtree(Infinity);
2108*0d13e2d8SCharles.Forsyth			if(isone(l))
2109*0d13e2d8SCharles.Forsyth				return ptree(r, -1.0);
2110*0d13e2d8SCharles.Forsyth			if(isone(r))
2111*0d13e2d8SCharles.Forsyth				return l;
2112*0d13e2d8SCharles.Forsyth			if(sametree(l, r))
2113*0d13e2d8SCharles.Forsyth				return itree(1);
2114*0d13e2d8SCharles.Forsyth		Oexp =>
2115*0d13e2d8SCharles.Forsyth			if(iszero(l))
2116*0d13e2d8SCharles.Forsyth				return l;
2117*0d13e2d8SCharles.Forsyth			if(iszero(r))
2118*0d13e2d8SCharles.Forsyth				return itree(1);
2119*0d13e2d8SCharles.Forsyth			if(isone(l))
2120*0d13e2d8SCharles.Forsyth				return l;
2121*0d13e2d8SCharles.Forsyth			if(isone(r))
2122*0d13e2d8SCharles.Forsyth				return l;
2123*0d13e2d8SCharles.Forsyth		* =>
2124*0d13e2d8SCharles.Forsyth			fatal(sys->sprint("case %s in simplify", opstring(op)));
2125*0d13e2d8SCharles.Forsyth	}
2126*0d13e2d8SCharles.Forsyth	return n;
2127*0d13e2d8SCharles.Forsyth}
2128*0d13e2d8SCharles.Forsyth
2129*0d13e2d8SCharles.Forsythderiv(n: ref Node, d: ref Dec): ref Node
2130*0d13e2d8SCharles.Forsyth{
2131*0d13e2d8SCharles.Forsyth	if(n == nil)
2132*0d13e2d8SCharles.Forsyth		return nil;
2133*0d13e2d8SCharles.Forsyth	op := n.op;
2134*0d13e2d8SCharles.Forsyth	l := n.left;
2135*0d13e2d8SCharles.Forsyth	r := n.right;
2136*0d13e2d8SCharles.Forsyth	case(op){
2137*0d13e2d8SCharles.Forsyth		Onum or
2138*0d13e2d8SCharles.Forsyth		Ocon =>
2139*0d13e2d8SCharles.Forsyth			n = itree(0);
2140*0d13e2d8SCharles.Forsyth		Ovar =>
2141*0d13e2d8SCharles.Forsyth			if(d == n.dec)
2142*0d13e2d8SCharles.Forsyth				n = itree(1);
2143*0d13e2d8SCharles.Forsyth			else
2144*0d13e2d8SCharles.Forsyth				n = itree(0);
2145*0d13e2d8SCharles.Forsyth		Olfun =>
2146*0d13e2d8SCharles.Forsyth			case(int n.dec.val){
2147*0d13e2d8SCharles.Forsyth				Olog =>
2148*0d13e2d8SCharles.Forsyth					n = ptree(l, -1.0);
2149*0d13e2d8SCharles.Forsyth				Olog10 =>
2150*0d13e2d8SCharles.Forsyth					n = ptree(tree(Omul, l, vtree(Ln10)), -1.0);
2151*0d13e2d8SCharles.Forsyth				Olog2 =>
2152*0d13e2d8SCharles.Forsyth					n = ptree(tree(Omul, l, vtree(Ln2)), -1.0);
2153*0d13e2d8SCharles.Forsyth				Oexpf =>
2154*0d13e2d8SCharles.Forsyth					n = n;
2155*0d13e2d8SCharles.Forsyth				Opow =>
2156*0d13e2d8SCharles.Forsyth					return deriv(tree(Oexp, l.left, l.right), d);
2157*0d13e2d8SCharles.Forsyth				Osqrt =>
2158*0d13e2d8SCharles.Forsyth					return deriv(tree(Oexp, l, vtree(0.5)), d);
2159*0d13e2d8SCharles.Forsyth				Ocbrt =>
2160*0d13e2d8SCharles.Forsyth					return deriv(tree(Oexp, l, vtree(1.0/3.0)), d);
2161*0d13e2d8SCharles.Forsyth				Osin =>
2162*0d13e2d8SCharles.Forsyth					n = ltree("cos", l);
2163*0d13e2d8SCharles.Forsyth				Ocos =>
2164*0d13e2d8SCharles.Forsyth					n = tree(Ominus, ltree("sin", l), nil);
2165*0d13e2d8SCharles.Forsyth				Otan =>
2166*0d13e2d8SCharles.Forsyth					n = ptree(ltree("cos", l), -2.0);
2167*0d13e2d8SCharles.Forsyth				Oasin =>
2168*0d13e2d8SCharles.Forsyth					n = ptree(tree(Osub, itree(1), ptree(l, 2.0)), -0.5);
2169*0d13e2d8SCharles.Forsyth				Oacos =>
2170*0d13e2d8SCharles.Forsyth					n = tree(Ominus, ptree(tree(Osub, itree(1), ptree(l, 2.0)), -0.5), nil);
2171*0d13e2d8SCharles.Forsyth				Oatan =>
2172*0d13e2d8SCharles.Forsyth					n = ptree(tree(Oadd, itree(1), ptree(l, 2.0)), -1.0);
2173*0d13e2d8SCharles.Forsyth				Osinh =>
2174*0d13e2d8SCharles.Forsyth					n = ltree("cosh", l);
2175*0d13e2d8SCharles.Forsyth				Ocosh =>
2176*0d13e2d8SCharles.Forsyth					n = ltree("sinh", l);
2177*0d13e2d8SCharles.Forsyth				Otanh =>
2178*0d13e2d8SCharles.Forsyth					n = ptree(ltree("cosh", l), -2.0);
2179*0d13e2d8SCharles.Forsyth				Oasinh =>
2180*0d13e2d8SCharles.Forsyth					n = ptree(tree(Oadd, itree(1), ptree(l, 2.0)), -0.5);
2181*0d13e2d8SCharles.Forsyth				Oacosh =>
2182*0d13e2d8SCharles.Forsyth					n = ptree(tree(Osub, ptree(l, 2.0), itree(1)), -0.5);
2183*0d13e2d8SCharles.Forsyth				Oatanh =>
2184*0d13e2d8SCharles.Forsyth					n = ptree(tree(Osub, itree(1), ptree(l, 2.0)), -1.0);
2185*0d13e2d8SCharles.Forsyth				* =>
2186*0d13e2d8SCharles.Forsyth					return vtree(Nan);
2187*0d13e2d8SCharles.Forsyth			}
2188*0d13e2d8SCharles.Forsyth			return tree(Omul, n, deriv(l, d));
2189*0d13e2d8SCharles.Forsyth		Oplus or
2190*0d13e2d8SCharles.Forsyth		Ominus =>
2191*0d13e2d8SCharles.Forsyth			n = tree(op, deriv(l, d), nil);
2192*0d13e2d8SCharles.Forsyth		Oinv =>
2193*0d13e2d8SCharles.Forsyth			n = tree(Omul, tree(Ominus, ptree(l, -2.0), nil), deriv(l, d));
2194*0d13e2d8SCharles.Forsyth		Oadd or
2195*0d13e2d8SCharles.Forsyth		Osub or
2196*0d13e2d8SCharles.Forsyth		Ocomma =>
2197*0d13e2d8SCharles.Forsyth			n = tree(op, deriv(l, d), deriv(r, d));
2198*0d13e2d8SCharles.Forsyth		Omul =>
2199*0d13e2d8SCharles.Forsyth			n = tree(Oadd, tree(Omul, deriv(l, d), r), tree(Omul, l, deriv(r, d)));
2200*0d13e2d8SCharles.Forsyth		Odiv =>
2201*0d13e2d8SCharles.Forsyth			n = tree(Osub, tree(Omul, deriv(l, d), r), tree(Omul, l, deriv(r, d)));
2202*0d13e2d8SCharles.Forsyth			n = tree(Odiv, n, ptree(r, 2.0));
2203*0d13e2d8SCharles.Forsyth		Oexp =>
2204*0d13e2d8SCharles.Forsyth			nn := tree(Oadd, tree(Omul, deriv(l, d), tree(Odiv, r, l)), tree(Omul, ltree("log", l), deriv(r, d)));
2205*0d13e2d8SCharles.Forsyth			n = tree(Omul, n, nn);
2206*0d13e2d8SCharles.Forsyth		* =>
2207*0d13e2d8SCharles.Forsyth			n = vtree(Nan);
2208*0d13e2d8SCharles.Forsyth	}
2209*0d13e2d8SCharles.Forsyth	return n;
2210*0d13e2d8SCharles.Forsyth}
2211*0d13e2d8SCharles.Forsyth
2212*0d13e2d8SCharles.Forsythderivative(n: ref Node, d: ref Dec): ref Node
2213*0d13e2d8SCharles.Forsyth{
2214*0d13e2d8SCharles.Forsyth	n = simplify(deriv(n, d));
2215*0d13e2d8SCharles.Forsyth	if(isnan(n))
2216*0d13e2d8SCharles.Forsyth		error(n, "no derivative");
2217*0d13e2d8SCharles.Forsyth	if(debug)
2218*0d13e2d8SCharles.Forsyth		prnode(n);
2219*0d13e2d8SCharles.Forsyth	return n;
2220*0d13e2d8SCharles.Forsyth}
2221*0d13e2d8SCharles.Forsyth
2222*0d13e2d8SCharles.Forsythnewton(f: ref Node, e: ref Node, d: ref Dec, v1: real, v2: real): (int, real)
2223*0d13e2d8SCharles.Forsyth{
2224*0d13e2d8SCharles.Forsyth	v := (v1+v2)/2.0;
2225*0d13e2d8SCharles.Forsyth	lv := 0.0;
2226*0d13e2d8SCharles.Forsyth	its := 0;
2227*0d13e2d8SCharles.Forsyth	for(;;){
2228*0d13e2d8SCharles.Forsyth		lv = v;
2229*0d13e2d8SCharles.Forsyth		d.val = v;
2230*0d13e2d8SCharles.Forsyth		v = eval(e);
2231*0d13e2d8SCharles.Forsyth		# if(v < v1 || v > v2)
2232*0d13e2d8SCharles.Forsyth		#	return (0, 0.0);
2233*0d13e2d8SCharles.Forsyth		if(maths->isnan(v))
2234*0d13e2d8SCharles.Forsyth			return (0, 0.0);
2235*0d13e2d8SCharles.Forsyth		if(its > 100 || fabs(v-lv) < Eps)
2236*0d13e2d8SCharles.Forsyth			break;
2237*0d13e2d8SCharles.Forsyth		its++;
2238*0d13e2d8SCharles.Forsyth	}
2239*0d13e2d8SCharles.Forsyth	if(fabs(v-lv) > Bigeps || fabs(eval(f)) > Bigeps)
2240*0d13e2d8SCharles.Forsyth		return (0, 0.0);
2241*0d13e2d8SCharles.Forsyth	return (1, v);
2242*0d13e2d8SCharles.Forsyth}
2243*0d13e2d8SCharles.Forsyth
2244*0d13e2d8SCharles.Forsythsolve(n: ref Node): real
2245*0d13e2d8SCharles.Forsyth{
2246*0d13e2d8SCharles.Forsyth	d: ref Dec;
2247*0d13e2d8SCharles.Forsyth
2248*0d13e2d8SCharles.Forsyth	if(n == nil)
2249*0d13e2d8SCharles.Forsyth		return Nan;
2250*0d13e2d8SCharles.Forsyth	if(n.op == Ocomma){	# solve(..., var)
2251*0d13e2d8SCharles.Forsyth		var(n.right);
2252*0d13e2d8SCharles.Forsyth		d = n.right.dec;
2253*0d13e2d8SCharles.Forsyth		n = n.left;
2254*0d13e2d8SCharles.Forsyth		if(!varmem(n, d))
2255*0d13e2d8SCharles.Forsyth			error(n, "variable not in equation");
2256*0d13e2d8SCharles.Forsyth	}
2257*0d13e2d8SCharles.Forsyth	else{
2258*0d13e2d8SCharles.Forsyth		d = findvar(n, nil);
2259*0d13e2d8SCharles.Forsyth		if(d == nil)
2260*0d13e2d8SCharles.Forsyth			error(n, "variable missing");
2261*0d13e2d8SCharles.Forsyth		if(d == errdec)
2262*0d13e2d8SCharles.Forsyth			error(n, "one variable only required");
2263*0d13e2d8SCharles.Forsyth	}
2264*0d13e2d8SCharles.Forsyth	if(n.op == Oeq)
2265*0d13e2d8SCharles.Forsyth		n.op = Osub;
2266*0d13e2d8SCharles.Forsyth	dn := derivative(n, d);
2267*0d13e2d8SCharles.Forsyth	var := tree(Ovar, nil, nil);
2268*0d13e2d8SCharles.Forsyth	var.dec = d;
2269*0d13e2d8SCharles.Forsyth	nr := tree(Osub, var, tree(Odiv, n, dn));
2270*0d13e2d8SCharles.Forsyth	ov := d.val;
2271*0d13e2d8SCharles.Forsyth	lim := lookup(Limit).dec.val;
2272*0d13e2d8SCharles.Forsyth	step := lookup(Step).dec.val;
2273*0d13e2d8SCharles.Forsyth	rval := Infinity;
2274*0d13e2d8SCharles.Forsyth	d.val = -lim-step;
2275*0d13e2d8SCharles.Forsyth	v1 := 0.0;
2276*0d13e2d8SCharles.Forsyth	v2 := eval(n);
2277*0d13e2d8SCharles.Forsyth	for(v := -lim; v <= lim; v += step){
2278*0d13e2d8SCharles.Forsyth		d.val = v;
2279*0d13e2d8SCharles.Forsyth		v1 = v2;
2280*0d13e2d8SCharles.Forsyth		v2 = eval(n);
2281*0d13e2d8SCharles.Forsyth		if(maths->isnan(v2))	# v == nan, v <= nan, v >= nan all give 1
2282*0d13e2d8SCharles.Forsyth			continue;
2283*0d13e2d8SCharles.Forsyth		if(fabs(v2) < Eps){
2284*0d13e2d8SCharles.Forsyth			if(v >= -lim && v <= lim && v != rval){
2285*0d13e2d8SCharles.Forsyth				printnum(v, " ");
2286*0d13e2d8SCharles.Forsyth				rval = v;
2287*0d13e2d8SCharles.Forsyth			}
2288*0d13e2d8SCharles.Forsyth		}
2289*0d13e2d8SCharles.Forsyth		else if(v1*v2 <= 0.0){
2290*0d13e2d8SCharles.Forsyth			(f, rv) := newton(n, nr, var.dec, v-step, v);
2291*0d13e2d8SCharles.Forsyth			if(f && rv >= -lim && rv <= lim && rv != rval){
2292*0d13e2d8SCharles.Forsyth				printnum(rv, " ");
2293*0d13e2d8SCharles.Forsyth				rval = rv;
2294*0d13e2d8SCharles.Forsyth			}
2295*0d13e2d8SCharles.Forsyth		}
2296*0d13e2d8SCharles.Forsyth	}
2297*0d13e2d8SCharles.Forsyth	d.val = ov;
2298*0d13e2d8SCharles.Forsyth	if(rval == Infinity)
2299*0d13e2d8SCharles.Forsyth		error(n, "no roots found");
2300*0d13e2d8SCharles.Forsyth	else
2301*0d13e2d8SCharles.Forsyth		sys->print("\n");
2302*0d13e2d8SCharles.Forsyth	return rval;
2303*0d13e2d8SCharles.Forsyth}
2304*0d13e2d8SCharles.Forsyth
2305*0d13e2d8SCharles.Forsythdifferential(n: ref Node): real
2306*0d13e2d8SCharles.Forsyth{
2307*0d13e2d8SCharles.Forsyth	x := n.left.left.dec;
2308*0d13e2d8SCharles.Forsyth	ov := x.val;
2309*0d13e2d8SCharles.Forsyth	v := evalx(derivative(n.right, x), x, eval(n.left.right));
2310*0d13e2d8SCharles.Forsyth	x.val = ov;
2311*0d13e2d8SCharles.Forsyth	return v;
2312*0d13e2d8SCharles.Forsyth}
2313*0d13e2d8SCharles.Forsyth
2314*0d13e2d8SCharles.Forsythintegral(n: ref Node): real
2315*0d13e2d8SCharles.Forsyth{
2316*0d13e2d8SCharles.Forsyth	l := n.left;
2317*0d13e2d8SCharles.Forsyth	r := n.right;
2318*0d13e2d8SCharles.Forsyth	x := l.left.left.dec;
2319*0d13e2d8SCharles.Forsyth	ov := x.val;
2320*0d13e2d8SCharles.Forsyth	a := eval(l.left.right);
2321*0d13e2d8SCharles.Forsyth	b := eval(l.right);
2322*0d13e2d8SCharles.Forsyth	h := b-a;
2323*0d13e2d8SCharles.Forsyth	end := evalx(r, x, a) + evalx(r, x, b);
2324*0d13e2d8SCharles.Forsyth	odd := even := 0.0;
2325*0d13e2d8SCharles.Forsyth	oldarea := 0.0;
2326*0d13e2d8SCharles.Forsyth	area := h*end/2.0;
2327*0d13e2d8SCharles.Forsyth	for(i := 1; i < 1<<16; i <<= 1){
2328*0d13e2d8SCharles.Forsyth		even += odd;
2329*0d13e2d8SCharles.Forsyth		odd = 0.0;
2330*0d13e2d8SCharles.Forsyth		xv := a+h/2.0;
2331*0d13e2d8SCharles.Forsyth		for(j := 0; j < i; j++){
2332*0d13e2d8SCharles.Forsyth			odd += evalx(r, x, xv);
2333*0d13e2d8SCharles.Forsyth			xv += h;
2334*0d13e2d8SCharles.Forsyth		}
2335*0d13e2d8SCharles.Forsyth		h /= 2.0;
2336*0d13e2d8SCharles.Forsyth		oldarea = area;
2337*0d13e2d8SCharles.Forsyth		area = h*(end+4.0*odd+2.0*even)/3.0;
2338*0d13e2d8SCharles.Forsyth		if(maths->isnan(area))
2339*0d13e2d8SCharles.Forsyth			error(n, "integral not found");
2340*0d13e2d8SCharles.Forsyth		if(fabs(area-oldarea) < Eps)
2341*0d13e2d8SCharles.Forsyth			break;
2342*0d13e2d8SCharles.Forsyth	}
2343*0d13e2d8SCharles.Forsyth	if(fabs(area-oldarea) > Bigeps)
2344*0d13e2d8SCharles.Forsyth		error(n, "integral not found");
2345*0d13e2d8SCharles.Forsyth	x.val = ov;
2346*0d13e2d8SCharles.Forsyth	return area;
2347*0d13e2d8SCharles.Forsyth}
2348*0d13e2d8SCharles.Forsyth
2349*0d13e2d8SCharles.Forsythevalx(n: ref Node, d: ref Dec, v: real): real
2350*0d13e2d8SCharles.Forsyth{
2351*0d13e2d8SCharles.Forsyth	d.val = v;
2352*0d13e2d8SCharles.Forsyth	return eval(n);
2353*0d13e2d8SCharles.Forsyth}
2354*0d13e2d8SCharles.Forsyth
2355*0d13e2d8SCharles.Forsythfindvar(n: ref Node, d: ref Dec): ref Dec
2356*0d13e2d8SCharles.Forsyth{
2357*0d13e2d8SCharles.Forsyth	if(n == nil)
2358*0d13e2d8SCharles.Forsyth		return d;
2359*0d13e2d8SCharles.Forsyth	d = findvar(n.left, d);
2360*0d13e2d8SCharles.Forsyth	d = findvar(n.right, d);
2361*0d13e2d8SCharles.Forsyth	if(n.op == Ovar){
2362*0d13e2d8SCharles.Forsyth		if(d == nil)
2363*0d13e2d8SCharles.Forsyth			d = n.dec;
2364*0d13e2d8SCharles.Forsyth		if(n.dec != d)
2365*0d13e2d8SCharles.Forsyth			d = errdec;
2366*0d13e2d8SCharles.Forsyth	}
2367*0d13e2d8SCharles.Forsyth	return d;
2368*0d13e2d8SCharles.Forsyth}
2369*0d13e2d8SCharles.Forsyth
2370*0d13e2d8SCharles.Forsythvarmem(n: ref Node, d: ref Dec): int
2371*0d13e2d8SCharles.Forsyth{
2372*0d13e2d8SCharles.Forsyth	if(n == nil)
2373*0d13e2d8SCharles.Forsyth		return 0;
2374*0d13e2d8SCharles.Forsyth	if(n.op == Ovar)
2375*0d13e2d8SCharles.Forsyth		return d == n.dec;
2376*0d13e2d8SCharles.Forsyth	return varmem(n.left, d) || varmem(n.right, d);
2377*0d13e2d8SCharles.Forsyth}
2378*0d13e2d8SCharles.Forsyth
2379*0d13e2d8SCharles.Forsythfabs(r: real): real
2380*0d13e2d8SCharles.Forsyth{
2381*0d13e2d8SCharles.Forsyth	if(r < 0.0)
2382*0d13e2d8SCharles.Forsyth		return -r;
2383*0d13e2d8SCharles.Forsyth	return r;
2384*0d13e2d8SCharles.Forsyth}
2385*0d13e2d8SCharles.Forsyth
2386*0d13e2d8SCharles.Forsythcvt(v: real, base: int): string
2387*0d13e2d8SCharles.Forsyth{
2388*0d13e2d8SCharles.Forsyth	if(base == 10)
2389*0d13e2d8SCharles.Forsyth		return sys->sprint("%g", v);
2390*0d13e2d8SCharles.Forsyth	neg := 0;
2391*0d13e2d8SCharles.Forsyth	if(v < 0.0){
2392*0d13e2d8SCharles.Forsyth		neg = 1;
2393*0d13e2d8SCharles.Forsyth		v = -v;
2394*0d13e2d8SCharles.Forsyth	}
2395*0d13e2d8SCharles.Forsyth	if(!isint(v)){
2396*0d13e2d8SCharles.Forsyth		n := 0;
2397*0d13e2d8SCharles.Forsyth		lg := maths->log(v)/maths->log(real base);
2398*0d13e2d8SCharles.Forsyth		if(lg < 0.0){
2399*0d13e2d8SCharles.Forsyth			(n, nil) = split(-lg);
2400*0d13e2d8SCharles.Forsyth			v *= real base**n;
2401*0d13e2d8SCharles.Forsyth			n = -n;
2402*0d13e2d8SCharles.Forsyth		}
2403*0d13e2d8SCharles.Forsyth		else{
2404*0d13e2d8SCharles.Forsyth			(n, nil) = split(lg);
2405*0d13e2d8SCharles.Forsyth			v /= real base**n;
2406*0d13e2d8SCharles.Forsyth		}
2407*0d13e2d8SCharles.Forsyth		s := cvt(v, base) + "E" + string n;
2408*0d13e2d8SCharles.Forsyth		if(neg)
2409*0d13e2d8SCharles.Forsyth			s = "-" + s;
2410*0d13e2d8SCharles.Forsyth		return s;
2411*0d13e2d8SCharles.Forsyth	}
2412*0d13e2d8SCharles.Forsyth	(n, f) := split(v);
2413*0d13e2d8SCharles.Forsyth	s := "";
2414*0d13e2d8SCharles.Forsyth	do{
2415*0d13e2d8SCharles.Forsyth		r := n%base;
2416*0d13e2d8SCharles.Forsyth		n /= base;
2417*0d13e2d8SCharles.Forsyth		s[len s] = n2c(r);
2418*0d13e2d8SCharles.Forsyth	}while(n != 0);
2419*0d13e2d8SCharles.Forsyth	ls := len s;
2420*0d13e2d8SCharles.Forsyth	for(i := 0; i < ls/2; i++){
2421*0d13e2d8SCharles.Forsyth		t := s[i];
2422*0d13e2d8SCharles.Forsyth		s[i] = s[ls-1-i];
2423*0d13e2d8SCharles.Forsyth		s[ls-1-i] = t;
2424*0d13e2d8SCharles.Forsyth	}
2425*0d13e2d8SCharles.Forsyth	if(f != 0.0){
2426*0d13e2d8SCharles.Forsyth		s[len s] = '.';
2427*0d13e2d8SCharles.Forsyth		for(i = 0; i < 16 && f != 0.0; i++){
2428*0d13e2d8SCharles.Forsyth			f *= real base;
2429*0d13e2d8SCharles.Forsyth			(n, f) = split(f);
2430*0d13e2d8SCharles.Forsyth			s[len s] = n2c(n);
2431*0d13e2d8SCharles.Forsyth		}
2432*0d13e2d8SCharles.Forsyth	}
2433*0d13e2d8SCharles.Forsyth	s = string base + "r" + s;
2434*0d13e2d8SCharles.Forsyth	if(neg)
2435*0d13e2d8SCharles.Forsyth		s = "-" + s;
2436*0d13e2d8SCharles.Forsyth	return s;
2437*0d13e2d8SCharles.Forsyth}
2438*0d13e2d8SCharles.Forsyth
2439*0d13e2d8SCharles.Forsythprintnum(v: real, s: string)
2440*0d13e2d8SCharles.Forsyth{
2441*0d13e2d8SCharles.Forsyth	base := int pbase.val;
2442*0d13e2d8SCharles.Forsyth	if(!isinteger(pbase.val) || base < 2 || base > 36)
2443*0d13e2d8SCharles.Forsyth		base = 10;
2444*0d13e2d8SCharles.Forsyth	sys->print("%s%s", cvt(v, base), s);
2445*0d13e2d8SCharles.Forsyth	if(bits){
2446*0d13e2d8SCharles.Forsyth		r := array[1] of real;
2447*0d13e2d8SCharles.Forsyth		b := array[8] of byte;
2448*0d13e2d8SCharles.Forsyth		r[0] = v;
2449*0d13e2d8SCharles.Forsyth		maths->export_real(b, r);
2450*0d13e2d8SCharles.Forsyth		for(i := 0; i < 8; i++)
2451*0d13e2d8SCharles.Forsyth			sys->print("%2.2x ", int b[i]);
2452*0d13e2d8SCharles.Forsyth		sys->print("\n");
2453*0d13e2d8SCharles.Forsyth	}
2454*0d13e2d8SCharles.Forsyth}
2455*0d13e2d8SCharles.Forsyth
2456*0d13e2d8SCharles.ForsythLeft, Right, Pre, Post: con 1<<iota;
2457*0d13e2d8SCharles.Forsyth
2458*0d13e2d8SCharles.Forsythlspace := array[] of { 0, 0, 2, 3, 4, 5, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0 };
2459*0d13e2d8SCharles.Forsythrspace := array[] of { 0, 1, 2, 3, 4, 5, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0 };
2460*0d13e2d8SCharles.Forsyth
2461*0d13e2d8SCharles.Forsythpreced(op1: int, op2: int, s: int): int
2462*0d13e2d8SCharles.Forsyth{
2463*0d13e2d8SCharles.Forsyth	br := 0;
2464*0d13e2d8SCharles.Forsyth	p1 := prec(op1);
2465*0d13e2d8SCharles.Forsyth	p2 := prec(op2);
2466*0d13e2d8SCharles.Forsyth	if(p1 > p2)
2467*0d13e2d8SCharles.Forsyth		br = 1;
2468*0d13e2d8SCharles.Forsyth	else if(p1 == p2){
2469*0d13e2d8SCharles.Forsyth		if(op1 == op2){
2470*0d13e2d8SCharles.Forsyth			if(rassoc(op1))
2471*0d13e2d8SCharles.Forsyth				br = s == Left;
2472*0d13e2d8SCharles.Forsyth			else
2473*0d13e2d8SCharles.Forsyth				br = s == Right && !assoc(op1);
2474*0d13e2d8SCharles.Forsyth		}
2475*0d13e2d8SCharles.Forsyth		else{
2476*0d13e2d8SCharles.Forsyth			if(rassoc(op1))
2477*0d13e2d8SCharles.Forsyth				br = s == Left;
2478*0d13e2d8SCharles.Forsyth			else
2479*0d13e2d8SCharles.Forsyth				br = s == Right && op1 != Oadd;
2480*0d13e2d8SCharles.Forsyth			if(postunary(op1) && preunary(op2))
2481*0d13e2d8SCharles.Forsyth				br = 1;
2482*0d13e2d8SCharles.Forsyth		}
2483*0d13e2d8SCharles.Forsyth	}
2484*0d13e2d8SCharles.Forsyth	return br;
2485*0d13e2d8SCharles.Forsyth}
2486*0d13e2d8SCharles.Forsyth
2487*0d13e2d8SCharles.Forsythprnode(n: ref Node)
2488*0d13e2d8SCharles.Forsyth{
2489*0d13e2d8SCharles.Forsyth	pnode(n, Onothing, Pre);
2490*0d13e2d8SCharles.Forsyth	sys->print("\n");
2491*0d13e2d8SCharles.Forsyth}
2492*0d13e2d8SCharles.Forsyth
2493*0d13e2d8SCharles.Forsythpnode(n: ref Node, opp: int, s: int)
2494*0d13e2d8SCharles.Forsyth{
2495*0d13e2d8SCharles.Forsyth	if(n == nil)
2496*0d13e2d8SCharles.Forsyth		return;
2497*0d13e2d8SCharles.Forsyth	op := n.op;
2498*0d13e2d8SCharles.Forsyth	if(br := preced(opp, op, s))
2499*0d13e2d8SCharles.Forsyth		sys->print("(");
2500*0d13e2d8SCharles.Forsyth	if(op == Oas && n.right.op >= Oadd && n.right.op <= Orsh && n.left == n.right.left){
2501*0d13e2d8SCharles.Forsyth		pnode(n.left, op, Left);
2502*0d13e2d8SCharles.Forsyth		sys->print(" %s ", opstring(n.right.op+Oadde-Oadd));
2503*0d13e2d8SCharles.Forsyth		pnode(n.right.right, op, Right);
2504*0d13e2d8SCharles.Forsyth	}
2505*0d13e2d8SCharles.Forsyth	else if(binary(op)){
2506*0d13e2d8SCharles.Forsyth		p := prec(op);
2507*0d13e2d8SCharles.Forsyth		pnode(n.left, op, Left);
2508*0d13e2d8SCharles.Forsyth		if(lspace[p])
2509*0d13e2d8SCharles.Forsyth			sys->print(" ");
2510*0d13e2d8SCharles.Forsyth		sys->print("%s", opstring(op));
2511*0d13e2d8SCharles.Forsyth		if(rspace[p])
2512*0d13e2d8SCharles.Forsyth			sys->print(" ");
2513*0d13e2d8SCharles.Forsyth		pnode(n.right, op, Right);
2514*0d13e2d8SCharles.Forsyth	}
2515*0d13e2d8SCharles.Forsyth	else if(op == Oinv){	# cannot print postunary -1
2516*0d13e2d8SCharles.Forsyth		sys->print("%s", opstring(op));
2517*0d13e2d8SCharles.Forsyth		pnode(n.left, Odiv, Right);
2518*0d13e2d8SCharles.Forsyth	}
2519*0d13e2d8SCharles.Forsyth	else if(preunary(op)){
2520*0d13e2d8SCharles.Forsyth		sys->print("%s", opstring(op));
2521*0d13e2d8SCharles.Forsyth		pnode(n.left, op, Pre);
2522*0d13e2d8SCharles.Forsyth	}
2523*0d13e2d8SCharles.Forsyth	else if(postunary(op)){
2524*0d13e2d8SCharles.Forsyth		pnode(n.left, op, Post);
2525*0d13e2d8SCharles.Forsyth		sys->print("%s", opstring(op));
2526*0d13e2d8SCharles.Forsyth	}
2527*0d13e2d8SCharles.Forsyth	else{
2528*0d13e2d8SCharles.Forsyth		case(op){
2529*0d13e2d8SCharles.Forsyth		Ostring =>
2530*0d13e2d8SCharles.Forsyth			sys->print("%s", n.str);
2531*0d13e2d8SCharles.Forsyth		Onum =>
2532*0d13e2d8SCharles.Forsyth			sys->print("%g", n.val);
2533*0d13e2d8SCharles.Forsyth		Ocon or
2534*0d13e2d8SCharles.Forsyth		Ovar =>
2535*0d13e2d8SCharles.Forsyth			sys->print("%s", n.dec.sym.name);
2536*0d13e2d8SCharles.Forsyth		Ofun or
2537*0d13e2d8SCharles.Forsyth		Olfun =>
2538*0d13e2d8SCharles.Forsyth			sys->print("%s(", n.dec.sym.name);
2539*0d13e2d8SCharles.Forsyth			pnode(n.left, Onothing, Pre);
2540*0d13e2d8SCharles.Forsyth			sys->print(")");
2541*0d13e2d8SCharles.Forsyth		* =>
2542*0d13e2d8SCharles.Forsyth			fatal(sys->sprint("bad op %s in pnode()", opstring(op)));
2543*0d13e2d8SCharles.Forsyth		}
2544*0d13e2d8SCharles.Forsyth	}
2545*0d13e2d8SCharles.Forsyth	if(br)
2546*0d13e2d8SCharles.Forsyth		sys->print(")");
2547*0d13e2d8SCharles.Forsyth}
2548