xref: /plan9-contrib/sys/src/cmd/hoc/code.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "hoc.h"
5 #include "y.tab.h"
6 
7 #define	NSTACK	256
8 
9 static Datum stack[NSTACK];	/* the stack */
10 static Datum *stackp;		/* next free spot on stack */
11 
12 #define	NPROG	2000
13 Inst	prog[NPROG];	/* the machine */
14 Inst	*progp;		/* next free spot for code generation */
15 Inst	*pc;		/* program counter during execution */
16 Inst	*progbase = prog; /* start of current subprogram */
17 int	returning;	/* 1 if return stmt seen */
18 
19 typedef struct Frame {	/* proc/func call stack frame */
20 	Symbol	*sp;	/* symbol table entry */
21 	Inst	*retpc;	/* where to resume after return */
22 	Datum	*argn;	/* n-th argument on stack */
23 	int	nargs;	/* number of arguments */
24 } Frame;
25 #define	NFRAME	100
26 Frame	frame[NFRAME];
27 Frame	*fp;		/* frame pointer */
28 
29 void
30 initcode(void)
31 {
32 	progp = progbase;
33 	stackp = stack;
34 	fp = frame;
35 	returning = 0;
36 }
37 
38 void
39 push(Datum d)
40 {
41 	if (stackp >= &stack[NSTACK])
42 		execerror("stack too deep", 0);
43 	*stackp++ = d;
44 }
45 
46 Datum
47 pop(void)
48 {
49 	if (stackp == stack)
50 		execerror("stack underflow", 0);
51 	return *--stackp;
52 }
53 
54 void
55 xpop(void)	/* for when no value is wanted */
56 {
57 	if (stackp == stack)
58 		execerror("stack underflow", (char *)0);
59 	--stackp;
60 }
61 
62 void
63 constpush(void)
64 {
65 	Datum d;
66 	d.val = ((Symbol *)*pc++)->u.val;
67 	push(d);
68 }
69 
70 void
71 varpush(void)
72 {
73 	Datum d;
74 	d.sym = (Symbol *)(*pc++);
75 	push(d);
76 }
77 
78 void
79 whilecode(void)
80 {
81 	Datum d;
82 	Inst *savepc = pc;
83 
84 	execute(savepc+2);	/* condition */
85 	d = pop();
86 	while (d.val) {
87 		execute(*((Inst **)(savepc)));	/* body */
88 		if (returning)
89 			break;
90 		execute(savepc+2);	/* condition */
91 		d = pop();
92 	}
93 	if (!returning)
94 		pc = *((Inst **)(savepc+1)); /* next stmt */
95 }
96 
97 void
98 forcode(void)
99 {
100 	Datum d;
101 	Inst *savepc = pc;
102 
103 	execute(savepc+4);		/* precharge */
104 	pop();
105 	execute(*((Inst **)(savepc)));	/* condition */
106 	d = pop();
107 	while (d.val) {
108 		execute(*((Inst **)(savepc+2)));	/* body */
109 		if (returning)
110 			break;
111 		execute(*((Inst **)(savepc+1)));	/* post loop */
112 		pop();
113 		execute(*((Inst **)(savepc)));	/* condition */
114 		d = pop();
115 	}
116 	if (!returning)
117 		pc = *((Inst **)(savepc+3)); /* next stmt */
118 }
119 
120 void
121 ifcode(void)
122 {
123 	Datum d;
124 	Inst *savepc = pc;	/* then part */
125 
126 	execute(savepc+3);	/* condition */
127 	d = pop();
128 	if (d.val)
129 		execute(*((Inst **)(savepc)));
130 	else if (*((Inst **)(savepc+1))) /* else part? */
131 		execute(*((Inst **)(savepc+1)));
132 	if (!returning)
133 		pc = *((Inst **)(savepc+2)); /* next stmt */
134 }
135 
136 void
137 define(Symbol* sp)	/* put func/proc in symbol table */
138 {
139 	sp->u.defn = progbase;	/* start of code */
140 	progbase = progp;	/* next code starts here */
141 }
142 
143 void
144 call(void) 		/* call a function */
145 {
146 	Symbol *sp = (Symbol *)pc[0]; /* symbol table entry */
147 				      /* for function */
148 	if (fp++ >= &frame[NFRAME-1])
149 		execerror(sp->name, "call nested too deeply");
150 	fp->sp = sp;
151 	fp->nargs = (int)pc[1];
152 	fp->retpc = pc + 2;
153 	fp->argn = stackp - 1;	/* last argument */
154 	execute(sp->u.defn);
155 	returning = 0;
156 }
157 
158 static void
159 ret(void) 		/* common return from func or proc */
160 {
161 	int i;
162 	for (i = 0; i < fp->nargs; i++)
163 		pop();	/* pop arguments */
164 	pc = (Inst *)fp->retpc;
165 	--fp;
166 	returning = 1;
167 }
168 
169 void
170 funcret(void) 	/* return from a function */
171 {
172 	Datum d;
173 	if (fp->sp->type == PROCEDURE)
174 		execerror(fp->sp->name, "(proc) returns value");
175 	d = pop();	/* preserve function return value */
176 	ret();
177 	push(d);
178 }
179 
180 void
181 procret(void) 	/* return from a procedure */
182 {
183 	if (fp->sp->type == FUNCTION)
184 		execerror(fp->sp->name,
185 			"(func) returns no value");
186 	ret();
187 }
188 
189 double*
190 getarg(void) 	/* return pointer to argument */
191 {
192 	int nargs = (int) *pc++;
193 	if (nargs > fp->nargs)
194 	    execerror(fp->sp->name, "not enough arguments");
195 	return &fp->argn[nargs - fp->nargs].val;
196 }
197 
198 void
199 arg(void) 	/* push argument onto stack */
200 {
201 	Datum d;
202 	d.val = *getarg();
203 	push(d);
204 }
205 
206 void
207 argassign(void) 	/* store top of stack in argument */
208 {
209 	Datum d;
210 	d = pop();
211 	push(d);	/* leave value on stack */
212 	*getarg() = d.val;
213 }
214 
215 void
216 argaddeq(void) 	/* store top of stack in argument */
217 {
218 	Datum d;
219 	d = pop();
220 	d.val = *getarg() += d.val;
221 	push(d);	/* leave value on stack */
222 }
223 
224 void
225 argsubeq(void) 	/* store top of stack in argument */
226 {
227 	Datum d;
228 	d = pop();
229 	d.val = *getarg() -= d.val;
230 	push(d);	/* leave value on stack */
231 }
232 
233 void
234 argmuleq(void) 	/* store top of stack in argument */
235 {
236 	Datum d;
237 	d = pop();
238 	d.val = *getarg() *= d.val;
239 	push(d);	/* leave value on stack */
240 }
241 
242 void
243 argdiveq(void) 	/* store top of stack in argument */
244 {
245 	Datum d;
246 	d = pop();
247 	d.val = *getarg() /= d.val;
248 	push(d);	/* leave value on stack */
249 }
250 
251 void
252 argmodeq(void) 	/* store top of stack in argument */
253 {
254 	Datum d;
255 	double *x;
256 	long y;
257 	d = pop();
258 	/* d.val = *getarg() %= d.val; */
259 	x = getarg();
260 	y = *x;
261 	d.val = *x = y % (long) d.val;
262 	push(d);	/* leave value on stack */
263 }
264 
265 void
266 bltin(void)
267 {
268 
269 	Datum d;
270 	d = pop();
271 	d.val = (*(double (*)(double))*pc++)(d.val);
272 	push(d);
273 }
274 
275 void
276 add(void)
277 {
278 	Datum d1, d2;
279 	d2 = pop();
280 	d1 = pop();
281 	d1.val += d2.val;
282 	push(d1);
283 }
284 
285 void
286 sub(void)
287 {
288 	Datum d1, d2;
289 	d2 = pop();
290 	d1 = pop();
291 	d1.val -= d2.val;
292 	push(d1);
293 }
294 
295 void
296 mul(void)
297 {
298 	Datum d1, d2;
299 	d2 = pop();
300 	d1 = pop();
301 	d1.val *= d2.val;
302 	push(d1);
303 }
304 
305 void
306 div(void)
307 {
308 	Datum d1, d2;
309 	d2 = pop();
310 	if (d2.val == 0.0)
311 		execerror("division by zero", (char *)0);
312 	d1 = pop();
313 	d1.val /= d2.val;
314 	push(d1);
315 }
316 
317 void
318 mod(void)
319 {
320 	Datum d1, d2;
321 	long x;
322 	d2 = pop();
323 	if (d2.val == 0.0)
324 		execerror("division by zero", (char *)0);
325 	d1 = pop();
326 	/* d1.val %= d2.val; */
327 	x = d1.val;
328 	x %= (long) d2.val;
329 	d1.val = d2.val = x;
330 	push(d1);
331 }
332 
333 void
334 negate(void)
335 {
336 	Datum d;
337 	d = pop();
338 	d.val = -d.val;
339 	push(d);
340 }
341 
342 void
343 verify(Symbol* s)
344 {
345 	if (s->type != VAR && s->type != UNDEF)
346 		execerror("attempt to evaluate non-variable", s->name);
347 	if (s->type == UNDEF)
348 		execerror("undefined variable", s->name);
349 }
350 
351 void
352 eval(void)		/* evaluate variable on stack */
353 {
354 	Datum d;
355 	d = pop();
356 	verify(d.sym);
357 	d.val = d.sym->u.val;
358 	push(d);
359 }
360 
361 void
362 preinc(void)
363 {
364 	Datum d;
365 	d.sym = (Symbol *)(*pc++);
366 	verify(d.sym);
367 	d.val = d.sym->u.val += 1.0;
368 	push(d);
369 }
370 
371 void
372 predec(void)
373 {
374 	Datum d;
375 	d.sym = (Symbol *)(*pc++);
376 	verify(d.sym);
377 	d.val = d.sym->u.val -= 1.0;
378 	push(d);
379 }
380 
381 void
382 postinc(void)
383 {
384 	Datum d;
385 	double v;
386 	d.sym = (Symbol *)(*pc++);
387 	verify(d.sym);
388 	v = d.sym->u.val;
389 	d.sym->u.val += 1.0;
390 	d.val = v;
391 	push(d);
392 }
393 
394 void
395 postdec(void)
396 {
397 	Datum d;
398 	double v;
399 	d.sym = (Symbol *)(*pc++);
400 	verify(d.sym);
401 	v = d.sym->u.val;
402 	d.sym->u.val -= 1.0;
403 	d.val = v;
404 	push(d);
405 }
406 
407 void
408 gt(void)
409 {
410 	Datum d1, d2;
411 	d2 = pop();
412 	d1 = pop();
413 	d1.val = (double)(d1.val > d2.val);
414 	push(d1);
415 }
416 
417 void
418 lt(void)
419 {
420 	Datum d1, d2;
421 	d2 = pop();
422 	d1 = pop();
423 	d1.val = (double)(d1.val < d2.val);
424 	push(d1);
425 }
426 
427 void
428 ge(void)
429 {
430 	Datum d1, d2;
431 	d2 = pop();
432 	d1 = pop();
433 	d1.val = (double)(d1.val >= d2.val);
434 	push(d1);
435 }
436 
437 void
438 le(void)
439 {
440 	Datum d1, d2;
441 	d2 = pop();
442 	d1 = pop();
443 	d1.val = (double)(d1.val <= d2.val);
444 	push(d1);
445 }
446 
447 void
448 eq(void)
449 {
450 	Datum d1, d2;
451 	d2 = pop();
452 	d1 = pop();
453 	d1.val = (double)(d1.val == d2.val);
454 	push(d1);
455 }
456 
457 void
458 ne(void)
459 {
460 	Datum d1, d2;
461 	d2 = pop();
462 	d1 = pop();
463 	d1.val = (double)(d1.val != d2.val);
464 	push(d1);
465 }
466 
467 void
468 and(void)
469 {
470 	Datum d1, d2;
471 	d2 = pop();
472 	d1 = pop();
473 	d1.val = (double)(d1.val != 0.0 && d2.val != 0.0);
474 	push(d1);
475 }
476 
477 void
478 or(void)
479 {
480 	Datum d1, d2;
481 	d2 = pop();
482 	d1 = pop();
483 	d1.val = (double)(d1.val != 0.0 || d2.val != 0.0);
484 	push(d1);
485 }
486 
487 void
488 not(void)
489 {
490 	Datum d;
491 	d = pop();
492 	d.val = (double)(d.val == 0.0);
493 	push(d);
494 }
495 
496 void
497 power(void)
498 {
499 	Datum d1, d2;
500 	d2 = pop();
501 	d1 = pop();
502 	d1.val = Pow(d1.val, d2.val);
503 	push(d1);
504 }
505 
506 void
507 assign(void)
508 {
509 	Datum d1, d2;
510 	d1 = pop();
511 	d2 = pop();
512 	if (d1.sym->type != VAR && d1.sym->type != UNDEF)
513 		execerror("assignment to non-variable",
514 			d1.sym->name);
515 	d1.sym->u.val = d2.val;
516 	d1.sym->type = VAR;
517 	push(d2);
518 }
519 
520 void
521 addeq(void)
522 {
523 	Datum d1, d2;
524 	d1 = pop();
525 	d2 = pop();
526 	if (d1.sym->type != VAR && d1.sym->type != UNDEF)
527 		execerror("assignment to non-variable",
528 			d1.sym->name);
529 	d2.val = d1.sym->u.val += d2.val;
530 	d1.sym->type = VAR;
531 	push(d2);
532 }
533 
534 void
535 subeq(void)
536 {
537 	Datum d1, d2;
538 	d1 = pop();
539 	d2 = pop();
540 	if (d1.sym->type != VAR && d1.sym->type != UNDEF)
541 		execerror("assignment to non-variable",
542 			d1.sym->name);
543 	d2.val = d1.sym->u.val -= d2.val;
544 	d1.sym->type = VAR;
545 	push(d2);
546 }
547 
548 void
549 muleq(void)
550 {
551 	Datum d1, d2;
552 	d1 = pop();
553 	d2 = pop();
554 	if (d1.sym->type != VAR && d1.sym->type != UNDEF)
555 		execerror("assignment to non-variable",
556 			d1.sym->name);
557 	d2.val = d1.sym->u.val *= d2.val;
558 	d1.sym->type = VAR;
559 	push(d2);
560 }
561 
562 void
563 diveq(void)
564 {
565 	Datum d1, d2;
566 	d1 = pop();
567 	d2 = pop();
568 	if (d1.sym->type != VAR && d1.sym->type != UNDEF)
569 		execerror("assignment to non-variable",
570 			d1.sym->name);
571 	d2.val = d1.sym->u.val /= d2.val;
572 	d1.sym->type = VAR;
573 	push(d2);
574 }
575 
576 void
577 modeq(void)
578 {
579 	Datum d1, d2;
580 	long x;
581 	d1 = pop();
582 	d2 = pop();
583 	if (d1.sym->type != VAR && d1.sym->type != UNDEF)
584 		execerror("assignment to non-variable",
585 			d1.sym->name);
586 	/* d2.val = d1.sym->u.val %= d2.val; */
587 	x = d1.sym->u.val;
588 	x %= (long) d2.val;
589 	d2.val = d1.sym->u.val = x;
590 	d1.sym->type = VAR;
591 	push(d2);
592 }
593 
594 void
595 printtop(void)	/* pop top value from stack, print it */
596 {
597 	Datum d;
598 	static Symbol *s;	/* last value computed */
599 	if (s == 0)
600 		s = install("_", VAR, 0.0);
601 	d = pop();
602 	print("%.12g\n", d.val);
603 	s->u.val = d.val;
604 }
605 
606 void
607 prexpr(void)	/* print numeric value */
608 {
609 	Datum d;
610 	d = pop();
611 	print("%.12g ", d.val);
612 }
613 
614 void
615 prstr(void)		/* print string value */
616 {
617 	print("%s", (char *) *pc++);
618 }
619 
620 void
621 varread(void)	/* read into variable */
622 {
623 	Datum d;
624 	extern Biobuf *bin;
625 	Symbol *var = (Symbol *) *pc++;
626 	int c;
627 
628   Again:
629 	do
630 		c = Bgetc(bin);
631 	while(c==' ' || c=='\t');
632 	if(c == Beof){
633   Iseof:
634 		if(moreinput())
635 			goto Again;
636 		d.val = var->u.val = 0.0;
637 		goto Return;
638 	}
639 
640 	if(strchr("+-.0123456789", c) == 0)
641 		execerror("non-number read into", var->name);
642 	Bungetc(bin);
643 	if(Bgetd(bin, &var->u.val) == Beof)
644 		goto Iseof;
645 	else
646 		d.val = 1.0;
647   Return:
648 	var->type = VAR;
649 	push(d);
650 }
651 
652 Inst*
653 code(Inst f)	/* install one instruction or operand */
654 {
655 	Inst *oprogp = progp;
656 	if (progp >= &prog[NPROG])
657 		execerror("program too big", (char *)0);
658 	*progp++ = f;
659 	return oprogp;
660 }
661 
662 void
663 execute(Inst* p)
664 {
665 	for (pc = p; *pc != STOP && !returning; )
666 		(*((++pc)[-1]))();
667 }
668