Mercurial > repo
view src/ploki/run.c @ 8123:9df4aeaac079
<moon_> ` med il 1 \'lol this is a test\' testcmd
author | HackBot |
---|---|
date | Wed, 25 May 2016 00:31:41 +0000 |
parents | ac0403686959 |
children |
line wrap: on
line source
#include "config.h" #include "IO.h" #include "Str.h" #include "atechit.h" #include "expr.h" #include "hang.h" #include "main.h" #include "main_io.h" #include "main_label.h" #include "main_opt.h" #include "run.h" #include "stack.h" #include "strhash.h" #include "text.h" #include "val.h" #include "venus.h" #include "xmalloc.h" #include "zz.h" #include <ctype.h> #include <errno.h> #include <math.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <setjmp.h> struct Interp Interp; static void my_x_end(void) { v_end(&Interp.arg); v_end(&Interp.result); while (Interp.a.argc) { --Interp.a.argc; v_end(&Interp.a.argv[Interp.a.argc]); } xfree(Interp.a.argv); while (Interp.match.length) { --Interp.match.length; v_end(&Interp.match.matches[Interp.match.length]); } xfree(Interp.match.matches); xfree(Interp.m_start.index); xfree(Interp.m_end.index); } static void sp_nop(save_pair *sp) { (void)sp; } static void sp_writeback(save_pair *sp) { v_set(sp->target, &sp->content); v_end(&sp->content); } ATTR_NORETURN static void sp_error(const save_pair *x, const save_pair *y) { (void)x; (void)y; NOTREACHED; } stack_define(save_pair, extern, sp_nop, sp_writeback, sp_error) stack(save_pair) Saved; void stack_store(struct val *target, const struct val *value) { save_pair *tos; stack_func(save_pair, pushnull)(&Saved); tos = stack_func(save_pair, at)(&Saved, 0); tos->target = target; v_iniset(&tos->content, target); v_set(target, value); } static void stack_store_del(struct val *target, struct val *value) { stack_store(target, value); v_delete(value); } size_t depth_get(void) { return stack_func(save_pair, size)(&Saved); } void depth_restore(size_t n) { assert(depth_get() >= n); stack_func(save_pair, clear)(&Saved, depth_get() - n); } struct val *execute(const struct op *op, struct val *arg) { struct val *v; const size_t curdepth = depth_get(); stack_store_del(&Interp.arg, arg); while (op) { if (Opt.debug & DBG_OPS) { fprintf(io_fp(Err), "op %d\n", op->type); } switch (op->type) { case OP_NOP: break; case OP_ASSIGN: if (!op->arh.expr) { eval_into(op->arg, &Interp.result); } else { switch (op->arh.expr->type) { case varE: eval_into(op->arg, op->arh.expr->v.val); break; case varhashE: { struct val *tmp; eval_push(op->arg); eval_push(op->arh.expr->right); tmp = eval_pop(); v = eval_pop(); V_STR(tmp); sh_put(op->arh.expr->v.hash, ko_ptr(tmp->ko), ko_length(tmp->ko), v); v_delete(tmp); break; } default: NOTREACHED; break; } } break; case OP_CALL: v = eval_expr(op->arg); v = execute(op->arh.op, v); v_set(&Interp.result, v); v_delete(v); break; case OP_CALL_BACK: { struct op *tmp; v = eval_expr(op->arh.expr); TOLABEL(v); if (!(tmp = ve_findprev(&Venus, ko_str(v->ko), op->line))) { v_delete(v); hang(); } v_delete(v); v = eval_expr(op->arg); v = execute(tmp, v); v_set(&Interp.result, v); v_delete(v); break; } case OP_CALL_DYN: { struct op *tmp; v = eval_expr(op->arg); TOLABEL(v); if (!(tmp = ve_findnext(&Venus, ko_str(v->ko), op->line))) { v_delete(v); hang(); } v_set_undef(v); v = execute(tmp, v); v_set(&Interp.result, v); v_delete(v); break; } case OP_CLOSE: v = eval_expr(op->arg); if (V_EXT_P(v)) { v_set_n(&Interp.result, io_close(v->magic.ext)); } else { v_set_n(&Interp.result, -1); #ifdef EBADF errno = EBADF; #endif } v_delete(v); break; case OP_EXIT: { int tmp; v = eval_expr(op->arg); V_NUM(v); tmp = v->num >= 0.0 ? v->num + .5 : EXIT_FAILURE; v_delete(v); exit(tmp); } case OP_FLUSH: v = eval_expr(op->arg); if (!V_EXT_P(v)) { v_delete(v); v_set_n(&Interp.result, EOF); #ifdef EBADF errno = EBADF; #endif break; } v_set_n(&Interp.result, io_flush(v->magic.ext)); v_delete(v); break; case OP_GOBACK: v = eval_expr(op->arg); TOLABEL(v); if ((op = ve_findprev(&Venus, ko_str(v->ko), op->line))) { v_delete(v); continue; } v_delete(v); hang(); break; case OP_GOTO: v = eval_expr(op->arg); TOLABEL(v); if ((op = ve_findnext(&Venus, ko_str(v->ko), op->line))) { v_delete(v); continue; } v_delete(v); hang(); break; case OP_ELSE: case OP_HANG: case OP_FI: hang(); break; case OP_IF: v = eval_expr(op->arg); if (v_true(v)) { v_delete(v); op = op->arh.op; continue; } v_delete(v); break; case OP_MODIFY: { struct val *tmp = eval_expr(op->arg); expr_pp(op->arh.expr->op, op->arh.expr->v.val, tmp); v_delete(tmp); break; } case OP_PRINT: { IO *fh; eval_push(op->arg); if (!op->arh.expr) { fh = io_incr(Out); } else { struct val *const tmp = eval_expr(op->arh.expr); if (V_EXT_P(tmp)) { fh = io_incr(tmp->magic.ext); } else { v_delete(tmp); v_delete(eval_pop()); v_set_n(&Interp.result, -1); #ifdef EBADF errno = EBADF; #endif break; } v_delete(tmp); } v = eval_pop(); V_STR(v); v_set_n(&Interp.result, io_write_m(fh, ko_ptr(v->ko), ko_length(v->ko)) + 1u - 1.); io_decr(fh); v_delete(v); break; } case OP_PUTC: { IO *fh; eval_push(op->arg); if (!op->arh.expr) { fh = io_incr(Out); } else { struct val *const tmp = eval_expr(op->arh.expr); if (V_EXT_P(tmp)) { fh = io_incr(tmp->magic.ext); } else { v_delete(tmp); v_delete(eval_pop()); v_set_n(&Interp.result, -1); #ifdef EBADF errno = EBADF; #endif break; } v_delete(tmp); } v = eval_pop(); V_NUM(v); v_set_n(&Interp.result, io_putc(fh, RINT(v->num))); io_decr(fh); v_delete(v); break; } case OP_RESET: v = eval_expr(op->arg); if (!V_EXT_P(v)) { v_delete(v); v_set_n(&Interp.result, EOF); #ifdef EBADF errno = EBADF; #endif break; } io_clearerr(v->magic.ext); v_delete(v); break; case OP_RETURN: if (op->arg->type == unopE && op->arg->op == F_CALL) { eval_into(op->arg->right, &Interp.arg); op = op->arg->left.op; continue; } v = eval_expr(op->arg); depth_restore(curdepth); return v; case OP_SET_VAL: switch (op->arh.expr->type) { case varE: v_set(op->arh.expr->v.val, op->arg->v.val); break; case varhashE: { struct val *const tmp = eval_expr(op->arh.expr->right); struct val *const val = v_undef(); V_STR(tmp); v_set(val, op->arg->v.val); sh_put(op->arh.expr->v.hash, ko_ptr(tmp->ko), ko_length(tmp->ko), val); v_delete(tmp); break; } default: NOTREACHED; break; } break; case OP_SYSTEM: v = eval_expr(op->arg); V_STR(v); v_set_n(&Interp.result, system(ko_szp(v->ko))); v_delete(v); break; case OP_TEMP: eval_push(op->arg); if (!op->arh.expr) { v_delete(eval_pop()); } else switch (op->arh.expr->type) { case varE: stack_store_del(op->arh.expr->v.val, eval_pop()); break; case varhashE: { struct val *addr; struct val *const tmp = eval_expr(op->arh.expr->right); v = eval_pop(); V_STR(tmp); if (!(addr = sh_get(op->arh.expr->v.hash, ko_ptr(tmp->ko), ko_length(tmp->ko)))) { sh_put(op->arh.expr->v.hash, ko_ptr(tmp->ko), ko_length(tmp->ko), addr = v_undef()); } v_delete(tmp); stack_store_del(addr, v); break; } default: NOTREACHED; } break; case OP_THROW: v = eval_expr(op->arg); if (!depth_get()) { V_STR(v); if (ko_at(v->ko, ko_length(v->ko) - 1u) == '\n') { io_write_m(Err, ko_ptr(v->ko), ko_length(v->ko)); } else { fprintf(io_fp(Err), "%s: uncaught exception: ", Prog); io_write_m(Err, ko_ptr(v->ko), ko_length(v->ko)); putc('\n', io_fp(Err)); } v_delete(v); exit(EXIT_FAILURE); } v_set(&Interp.result, v); v_delete(v); longjmp(stack_func(t_context, at)(&Context, 0)->buf, 1); break; } op = op->next; } exit(0); } static void cleanup(void) { stack_func(save_pair, end)(&Saved); } void run(const struct text *t, size_t argc, char **argv) { int status; struct val *result; v_init(&Interp.arg); v_init(&Interp.result); Interp.a.argv = xmalloc(argc, sizeof *Interp.a.argv); for (Interp.a.argc = 0; Interp.a.argc < argc; ++Interp.a.argc) { struct val *const tmp = &Interp.a.argv[Interp.a.argc]; v_init(tmp); v_set_m(tmp, argv[Interp.a.argc], strlen(argv[Interp.a.argc])); } Interp.match.matches = xmalloc(Interp.match.size = 2, sizeof *Interp.match.matches); Interp.match.length = 0; Interp.m_start.index = xmalloc(Interp.m_start.size = 0, sizeof *Interp.m_start.index); Interp.m_end.index = xmalloc(Interp.m_end.size = 0, sizeof *Interp.m_end.index); stack_func(save_pair, init)(&Saved); atechit(cleanup); atechit(my_x_end); result = execute(t->start[0], v_undef()); V_NUM(result); status = result->num >= 0.0 ? result->num + .5 : EXIT_FAILURE; v_delete(result); exit(status); }