5 Angel Ortega <angel@triptico.com>
7 This is an experiment of a reverse-stack MPSL.
9 Also, the executor includes a maximum number of
10 milliseconds before yielding, with the capability
11 of restarting where it left in the subsequent call.
46 #define mpsl_is_true(v) mpdm_ival(v)
48 void rs_mpsl_reset_machine(mpdm_t machine
)
50 mpdm_hset_s(machine
, L
"stack", MPDM_A(0));
51 mpdm_hset_s(machine
, L
"c_stack", MPDM_A(0));
52 mpdm_hset_s(machine
, L
"pc", MPDM_I(0));
56 int rs_mpsl_exec1(mpdm_t prg
, mpdm_t stack
, mpdm_t c_stack
, int *ppc
)
65 opcode
= mpdm_ival(mpdm_aget(prg
, pc
++));
69 /* literal: next thing in pc is the literal */
70 mpdm_push(stack
, mpdm_clone(mpdm_aget(prg
, pc
++)));
78 double v2
= mpdm_rval(mpdm_pop(stack
));
79 double v1
= mpdm_rval(mpdm_pop(stack
));
83 case OP_ADD
: r
= v1
+ v2
; break;
84 case OP_SUB
: r
= v1
- v2
; break;
85 case OP_MUL
: r
= v1
* v2
; break;
86 case OP_DIV
: r
= v1
/ v2
; break;
89 mpdm_push(stack
, MPDM_R(r
));
101 double v2
= mpdm_rval(mpdm_pop(stack
));
102 double v1
= mpdm_rval(mpdm_pop(stack
));
106 case OP_EQ
: r
= v1
== v2
; break;
107 case OP_NEQ
: r
= v1
!= v2
; break;
108 case OP_LT
: r
= v1
< v2
; break;
109 case OP_LE
: r
= v1
<= v2
; break;
110 case OP_GT
: r
= v1
> v2
; break;
111 case OP_GE
: r
= v1
>= v2
; break;
114 mpdm_push(stack
, MPDM_I(r
));
120 /* push the program counter */
121 mpdm_push(stack
, MPDM_I(pc
));
125 /* call the value on the stack */
127 mpdm_t x
= mpdm_pop(stack
);
129 /* executable value? arguments are in the stack in an array */
130 if (MPDM_IS_EXEC(x
)) {
131 mpdm_t args
= mpdm_pop(stack
);
132 mpdm_push(stack
, mpdm_exec(x
, args
, NULL
));
135 /* "lightweight" call */
136 mpdm_push(c_stack
, MPDM_I(pc
));
145 mpdm_push(stack
, MPDM_I(pc
));
148 /* move beyond the appropriate return */
151 while (l
&& pc
< mpdm_size(prg
)) {
152 opcode
= mpdm_ival(mpdm_aget(prg
, pc
++));
154 if (opcode
== OP_PATH
)
156 if (opcode
== OP_RETURN
)
160 /* return not found? error */
168 /* if there is a return address, use it;
169 otherwise, trigger error */
170 if (mpdm_size(c_stack
))
171 pc
= mpdm_ival(mpdm_pop(c_stack
));
178 if (mpsl_is_true(mpdm_pop(stack
))) {
179 /* push return address and call */
180 mpdm_push(c_stack
, MPDM_I(pc
));
181 pc
= mpdm_ival(mpdm_pop(stack
));
184 mpdm_adel(stack
, -1);
189 /* always push return address */
190 mpdm_push(c_stack
, MPDM_I(pc
));
192 if (mpsl_is_true(mpdm_pop(stack
))) {
194 mpdm_adel(stack
, -1);
196 /* jump to true pc */
197 pc
= mpdm_ival(mpdm_pop(stack
));
200 /* jump to false pc */
201 pc
= mpdm_ival(mpdm_pop(stack
));
204 mpdm_adel(stack
, -1);
211 <body pc> <condition pc> <condition>
213 if (mpdm_ival(mpdm_pop(stack
))) {
214 /* set the return address to the cond. pc */
215 mpdm_push(c_stack
, mpdm_aget(stack
, -1));
217 /* jump to the body */
218 pc
= mpdm_ival(mpdm_aget(stack
, -2));
222 mpdm_adel(stack
, -1);
223 mpdm_adel(stack
, -1);
230 <body pc> <array> <iterator>
233 int i
= mpdm_ival(mpdm_pop(stack
));
236 if (mpdm_iterator(mpdm_aget(stack
, -1), &i
, &v
, NULL
)) {
237 /* another iteration */
239 /* push return value back over 'foreach' */
240 mpdm_push(c_stack
, MPDM_I(pc
- 1));
243 pc
= mpdm_ival(mpdm_aget(stack
, -2));
245 /* stack the iterator back */
246 mpdm_push(stack
, MPDM_I(i
));
248 /* stack the element (the body should pick it) */
253 mpdm_adel(stack
, -1);
254 mpdm_adel(stack
, -1);
261 /* prints the value in the stack */
262 mpdm_write_wcs(stdout
, mpdm_string(mpdm_pop(stack
)));
267 mpdm_t v
= mpdm_pop(stack
);
274 /* assign a value to a symbol */
276 mpdm_t s
= mpdm_pop(stack
);
277 mpdm_t v
= mpdm_pop(stack
);
278 mpdm_hset(mpdm_root(), s
, v
);
283 /* get symbol value */
284 mpdm_push(stack
, mpdm_hget(mpdm_root(), mpdm_pop(stack
)));
288 /* pushes a value into an array on the stack */
290 mpdm_t v
= mpdm_pop(stack
);
291 mpdm_push(mpdm_aget(stack
, -1), v
);
296 /* sets a hash's key/value pair */
298 mpdm_t v
= mpdm_pop(stack
);
299 mpdm_t k
= mpdm_pop(stack
);
300 mpdm_hset(mpdm_aget(stack
, -1), k
, v
);
306 /* got to the end? trigger exit */
307 if (pc
== mpdm_size(prg
))
315 int rs_mpsl_exec(mpdm_t machine
, int msecs
)
318 mpdm_t prg
= mpdm_hget_s(machine
, L
"prg");
319 mpdm_t stack
= mpdm_hget_s(machine
, L
"stack");
320 mpdm_t c_stack
= mpdm_hget_s(machine
, L
"c_stack");
321 int pc
= mpdm_ival(mpdm_hget_s(machine
, L
"pc"));
324 /* maximum running time */
325 max
= msecs
? (clock() + (msecs
* CLOCKS_PER_SEC
) / 1000) : 0x7fffffff;
328 pc
< mpdm_size(prg
) &&
329 (ret
= rs_mpsl_exec1(prg
, stack
, c_stack
, &pc
)) > 0 &&
333 mpdm_hset_s(machine
, L
"pc", MPDM_I(pc
));
339 static mpdm_t
add_arg(mpdm_t prg
, mpdm_t arg
)
341 return mpdm_push(prg
, arg
);
344 static mpdm_t
add_ins(mpdm_t prg
, mpsl_op_t opcode
)
346 return mpdm_push(prg
, MPDM_I((int) opcode
));
350 int main(int argc
, char *argv
[])
359 machine
= mpdm_ref(MPDM_H(0));
360 prg
= mpdm_hset_s(machine
, L
"prg", MPDM_A(0));
361 rs_mpsl_reset_machine(machine
);
363 add_ins(prg
, OP_LITERAL
);
364 add_arg(prg
, MPDM_I(1));
365 add_ins(prg
, OP_LITERAL
);
366 add_arg(prg
, MPDM_I(2));
368 add_ins(prg
, OP_PRINT
);
369 add_ins(prg
, OP_PATH
);
370 add_ins(prg
, OP_LITERAL
);
371 add_arg(prg
, MPDM_LS(L
"true\n"));
372 add_ins(prg
, OP_PRINT
);
373 add_ins(prg
, OP_RETURN
);
374 add_ins(prg
, OP_PATH
);
375 add_ins(prg
, OP_LITERAL
);
376 add_arg(prg
, MPDM_LS(L
"false\n"));
377 add_ins(prg
, OP_PRINT
);
378 add_ins(prg
, OP_RETURN
);
379 add_ins(prg
, OP_LITERAL
);
380 add_arg(prg
, MPDM_I(1));
381 add_ins(prg
, OP_IFELSE
);
382 add_ins(prg
, OP_LITERAL
);
383 add_arg(prg
, MPDM_I(2));
384 add_ins(prg
, OP_LITERAL
);
385 add_arg(prg
, MPDM_I(3));
386 add_ins(prg
, OP_ADD
);
387 add_ins(prg
, OP_PRINT
);
388 add_ins(prg
, OP_LITERAL
);
389 add_arg(prg
, MPDM_LS(L
"!!!\n"));
390 add_ins(prg
, OP_PRINT
);
391 add_ins(prg
, OP_LITERAL
);
392 add_arg(prg
, MPDM_LS(L
"content\n"));
393 add_ins(prg
, OP_LITERAL
);
394 add_arg(prg
, MPDM_LS(L
"VAR1"));
395 add_ins(prg
, OP_ASSIGN
);
396 add_ins(prg
, OP_LITERAL
);
397 add_arg(prg
, MPDM_LS(L
"VAR1"));
398 add_ins(prg
, OP_SYMVAL
);
399 add_ins(prg
, OP_PRINT
);
400 add_ins(prg
, OP_LITERAL
);
401 add_arg(prg
, MPDM_I(3));
402 add_ins(prg
, OP_LITERAL
);
403 add_arg(prg
, MPDM_I(4));
404 add_ins(prg
, OP_ADD
);
405 add_ins(prg
, OP_LITERAL
);
406 add_arg(prg
, MPDM_LS(L
"VAR1"));
407 add_ins(prg
, OP_ASSIGN
);
408 add_ins(prg
, OP_LITERAL
);
409 add_arg(prg
, MPDM_LS(L
"VAR1"));
410 add_ins(prg
, OP_SYMVAL
);
411 add_ins(prg
, OP_PRINT
);
413 /* VAR1 = VAR1 + 4 ; print VAR1 */
414 add_ins(prg
, OP_LITERAL
);
415 add_arg(prg
, MPDM_LS(L
"VAR1"));
416 add_ins(prg
, OP_SYMVAL
);
417 add_ins(prg
, OP_LITERAL
);
418 add_arg(prg
, MPDM_I(4));
419 add_ins(prg
, OP_ADD
);
420 add_ins(prg
, OP_LITERAL
);
421 add_arg(prg
, MPDM_LS(L
"VAR1"));
422 add_ins(prg
, OP_ASSIGN
);
423 add_ins(prg
, OP_LITERAL
);
424 add_arg(prg
, MPDM_LS(L
"VAR1"));
425 add_ins(prg
, OP_SYMVAL
);
426 add_ins(prg
, OP_PRINT
);
428 rs_mpsl_exec(machine
, 0);
430 prg
= mpdm_hset_s(machine
, L
"prg", MPDM_A(0));
431 rs_mpsl_reset_machine(machine
);
434 add_ins(prg
, OP_LITERAL
);
435 add_arg(prg
, MPDM_I(0));
436 add_ins(prg
, OP_LITERAL
);
437 add_arg(prg
, MPDM_LS(L
"VAR1"));
438 add_ins(prg
, OP_ASSIGN
);
440 /* { print VAR1; print "\n"; VAR1 = VAR1 + 1; } */
441 add_ins(prg
, OP_PATH
);
442 add_ins(prg
, OP_LITERAL
);
443 add_arg(prg
, MPDM_LS(L
"VAR1"));
444 add_ins(prg
, OP_SYMVAL
);
445 add_ins(prg
, OP_PRINT
);
446 add_ins(prg
, OP_LITERAL
);
447 add_arg(prg
, MPDM_LS(L
"\n"));
448 add_ins(prg
, OP_PRINT
);
449 add_ins(prg
, OP_LITERAL
);
450 add_arg(prg
, MPDM_LS(L
"VAR1"));
451 add_ins(prg
, OP_SYMVAL
);
452 add_ins(prg
, OP_LITERAL
);
453 add_arg(prg
, MPDM_I(1));
454 add_ins(prg
, OP_ADD
);
455 add_ins(prg
, OP_LITERAL
);
456 add_arg(prg
, MPDM_LS(L
"VAR1"));
457 add_ins(prg
, OP_ASSIGN
);
458 add_ins(prg
, OP_RETURN
);
460 /* | VAR1 < 10 while */
462 add_ins(prg
, OP_LITERAL
);
463 add_arg(prg
, MPDM_LS(L
"VAR1"));
464 add_ins(prg
, OP_SYMVAL
);
465 add_ins(prg
, OP_LITERAL
);
466 add_arg(prg
, MPDM_I(10));
468 add_ins(prg
, OP_WHILE
);
471 rs_mpsl_exec(machine
, 1);
473 rs_mpsl_exec(machine
, 0);
475 prg
= mpdm_hset_s(machine
, L
"prg", MPDM_A(0));
476 rs_mpsl_reset_machine(machine
);
478 add_ins(prg
, OP_LITERAL
);
479 add_arg(prg
, MPDM_A(0));
480 add_ins(prg
, OP_LITERAL
);
481 add_arg(prg
, MPDM_I(1));
482 add_ins(prg
, OP_APUSH
);
483 add_ins(prg
, OP_LITERAL
);
484 add_arg(prg
, MPDM_I(2));
485 add_ins(prg
, OP_APUSH
);
486 add_ins(prg
, OP_DUMP
);
488 rs_mpsl_exec(machine
, 0);
490 prg
= mpdm_hset_s(machine
, L
"prg", MPDM_A(0));
491 rs_mpsl_reset_machine(machine
);
493 add_ins(prg
, OP_LITERAL
);
494 add_arg(prg
, MPDM_H(0));
495 add_ins(prg
, OP_LITERAL
);
496 add_arg(prg
, MPDM_LS(L
"font_face"));
497 add_ins(prg
, OP_LITERAL
);
498 add_arg(prg
, MPDM_LS(L
"Courier"));
499 add_ins(prg
, OP_HSET
);
500 add_ins(prg
, OP_DUMP
);
502 rs_mpsl_exec(machine
, 0);
504 prg
= mpdm_hset_s(machine
, L
"prg", MPDM_A(0));
505 rs_mpsl_reset_machine(machine
);
507 /* { + 2 / } "avg" = */
508 add_ins(prg
, OP_PATH
);
509 add_ins(prg
, OP_ADD
);
510 add_ins(prg
, OP_LITERAL
);
511 add_arg(prg
, MPDM_I(2));
512 add_ins(prg
, OP_DIV
);
513 add_ins(prg
, OP_RETURN
);
514 add_ins(prg
, OP_LITERAL
);
515 add_arg(prg
, MPDM_LS(L
"avg"));
516 add_ins(prg
, OP_ASSIGN
);
518 /* 3 4 "avg" $ & ? */
519 add_ins(prg
, OP_LITERAL
);
520 add_arg(prg
, MPDM_I(3));
521 add_ins(prg
, OP_LITERAL
);
522 add_arg(prg
, MPDM_I(4));
523 add_ins(prg
, OP_LITERAL
);
524 add_arg(prg
, MPDM_LS(L
"avg"));
525 add_ins(prg
, OP_SYMVAL
);
526 add_ins(prg
, OP_CALL
);
527 add_ins(prg
, OP_PRINT
);
529 rs_mpsl_exec(machine
, 0);
531 prg
= mpdm_hset_s(machine
, L
"prg", MPDM_A(0));
532 rs_mpsl_reset_machine(machine
);
535 add_ins(prg
, OP_PATH
);
536 add_ins(prg
, OP_PRINT
);
537 add_ins(prg
, OP_RETURN
);
539 /* [1..10] 0 foreach */
540 add_ins(prg
, OP_LITERAL
);
543 for (n
= 10; n
< 20; n
++)
544 mpdm_push(v
, MPDM_I(n
));
549 add_ins(prg
, OP_LITERAL
);
550 add_arg(prg
, MPDM_I(0));
551 add_ins(prg
, OP_FOREACH
);
553 rs_mpsl_exec(machine
, 0);