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