Mercurial > repo
view src/ploki/expr.c @ 12515:df8f62801bed draft default tip
<int-e> learn The password of the month is twenty-six characters long
author | HackEso <hackeso@esolangs.org> |
---|---|
date | Tue, 01 Oct 2024 11:58:37 +0100 |
parents | ac0403686959 |
children |
line wrap: on
line source
#include "config.h" #include "Str.h" #include "expr.h" #include "hang.h" #include "list.h" #include "main_io.h" #include "main_label.h" #include "main_var.h" #include "mars.h" #include "match.h" #include "op.h" #include "pp.h" #include "random.h" #include "re.h" #include "run.h" #include "stack.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> #ifdef M_PI #define MY_PI M_PI #else #define MY_PI 3.1415926535897932384626433832795028841971693993751058209749445923 #endif #ifdef M_E #define MY_E M_E #else #define MY_E 2.71828182845904523536028747135266249775724709369995957496696762772 #endif typedef struct val *svalp; stack_declare(svalp, static) static void sv_init(svalp *x) { *x = v_undef(); } static void sv_end(svalp *x) { v_delete(*x); } static void sv_copy(svalp *dst, const svalp *src) { v_set(*dst, *src); } stack_define(svalp, static, sv_init, sv_end, sv_copy) static stack(svalp) Stack; static void con_nop(t_context *c) { (void)c; } ATTR_NORETURN static void con_error(const t_context *x, const t_context *y) { (void)x; (void)y; NOTREACHED; } stack_define(t_context, extern, con_nop, con_nop, con_error) stack(t_context) Context; void expr_init(void) { stack_func(svalp, init)(&Stack); stack_func(t_context, init)(&Context); } void expr_end(void) { stack_func(t_context, end)(&Context); stack_func(svalp, end)(&Stack); } void expr_pp(enum t_binop op, struct val *x, struct val *y) { switch (op) { case B_AMPERSAND: pp_and(x, y); return; case B_ANGLE: pp_lt_n(x, y); return; case B_BACKSPARK: pp_tobase(x, y); return; case B_BRACELET: pp_gt(x, y); return; case B_DOUBLE_OH_SEVEN: pp_mod(x, y); return; case B_EMBRACE: pp_lt(x, y); return; case B_FLATWORM: pp_concat(x, y); return; case B_HALF_MESH: pp_eq_n(x, y); return; case B_HYBRID: pp_ne(x, y); return; case B_INTERSECTION: pp_add(x, y); return; case B_RIGHT_ANGLE: pp_gt_n(x, y); return; case B_SHARK_FIN: pp_pow(x, y); return; case B_SLAT: pp_div(x, y); return; case B_SPARK: pp_frombase(x, y); return; case B_SPARK_SPOT: pp_ne_n(x, y); return; case B_SPIKE: pp_or(x, y); return; case B_SPLAT: pp_mult(x, y); return; case B_SPOT: pp_read(x, y); return; case B_SQIGGLE: pp_match(x, y); return; case B_TAIL: pp_comma(x, y); return; case B_TWO_SPOT: pp_eq(x, y); return; case B_U_TURN: pp_shift(x, y); return; case B_U_TURN_BACK: pp_pop(x, y); return; case B_WORM: pp_sub(x, y); return; case B_XMATCH: NOTREACHED; } } enum t_binop expr_binop(int c) { switch (c) { case '!': return B_SPARK_SPOT; case '%': return B_DOUBLE_OH_SEVEN; case '&': return B_AMPERSAND; case '\'': return B_SPARK; case '*': return B_SPLAT; case '+': return B_INTERSECTION; case ',': return B_TAIL; case '-': return B_WORM; case '.': return B_SPOT; case '/': return B_SLAT; case ':': return B_TWO_SPOT; case ';': return B_HYBRID; case '<': return B_ANGLE; case '=': return B_HALF_MESH; case '>': return B_RIGHT_ANGLE; case '[': return B_U_TURN; case ']': return B_U_TURN_BACK; case '^': return B_SHARK_FIN; case '_': return B_FLATWORM; case '`': return B_BACKSPARK; case '{': return B_EMBRACE; case '|': return B_SPIKE; case '}': return B_BRACELET; case '~': return B_SQIGGLE; } NOTREACHED; } void free_expr(struct expr *x) { if (!x) { return; } switch (x->type) { case literE: v_end(x->v.val); xfree(x->v.val); break; case varE: break; case varhashE: free_expr(x->right); break; case symbolE: switch (x->op) { case S_ARGV: free_expr(x->right); break; } break; case unopE: free_expr(x->right); if (x->op == F_MATCH) { re_free(x->left.rx); } break; case binopE: free_expr(x->left.expr); free_expr(x->right); break; case listE: free_expr(x->right); free_expr(x->left.expr); break; } xfree(x); } static struct expr *undef(void) { struct expr *e; e = xmalloc(1, sizeof *e); e->type = literE; e->left.expr = e->right = NULL; e->v.val = v_undef(); return e; } static void xv_delete(void *v) { v_delete(v); } struct expr *get_lval(struct op *op) { struct expr *x; int c; size_t n; St_shiftws(&op->txt); c = ST_FIRSTCHAR(&op->txt); if (!(c == '$' || isalpha(c))) { return NULL; } for (n = 1; (c = ST_INDEX(&op->txt, n)) == '$' || isalpha(c); ++n) ; x = xmalloc(1, sizeof *x); x->left.expr = x->right = NULL; if (ST_INDEX(&op->txt, n) != '(') { x->type = varE; if ((x->v.tent = vr_exists(Var_plain, St_ptr(&op->txt), n)) == VR_NO_COOKIE) { x->v.tent = vr_register(Var_plain, St_ptr(&op->txt), n, v_undef()); } St_del(&op->txt, 0, n); } else { x->type = varhashE; if ((x->v.tent = vr_exists(Var_hash, St_ptr(&op->txt), n)) == VR_NO_COOKIE) { x->v.tent = vr_register(Var_hash, St_ptr(&op->txt), n, sh_new(xv_delete)); } St_del(&op->txt, 0, n + 1); x->right = get_expr(op); if (ST_FIRSTCHAR(&op->txt) == ')') { St_shift(&op->txt); } } return x; } ATTR_CONST static int xval(int c) { switch (c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': case 'a': return 10; case 'B': case 'b': return 11; case 'C': case 'c': return 12; case 'D': case 'd': return 13; case 'E': case 'e': return 14; case 'F': case 'f': return 15; } NOTREACHED; } static struct expr *get_value(struct op *, int); static struct expr *get_list(struct op *op, int null) { struct expr *e; e = xmalloc(1, sizeof *e); e->type = listE; if ((e->right = get_value(op, 1))) { e->left.expr = get_list(op, 1); } else if (null) { xfree(e); return NULL; } else { e->right = e->left.expr = NULL; } return e; } static struct expr *get_value(struct op *op, int null) { struct expr *e; int c; St_shiftws(&op->txt); if (!St_len(&op->txt)) { return null ? NULL : undef(); } c = ST_FIRSTCHAR(&op->txt); if (c == '$' || isalpha(c)) { return get_lval(op); } if (isdigit(c) || (c == '.' && isdigit(ST_INDEX(&op->txt, 1)))) { char *tmp; e = undef(); tmp = St_ptr(&op->txt); v_set_n(e->v.val, strtod(tmp, &tmp)); tmp += tmp == St_ptr(&op->txt); St_del(&op->txt, 0, tmp - St_ptr(&op->txt)); return e; } if (OPERATOR_P(c)) { e = xmalloc(1, sizeof *e); e->type = binopE; e->op = expr_binop(c); St_shift(&op->txt); e->left.expr = undef(); e->right = get_value(op, 0); return e; } if (c == '?' && ST_INDEX(&op->txt, 1) == 'o' && ST_INDEX(&op->txt, 2) == '~') { e = xmalloc(1, sizeof *e); e->type = binopE; e->op = B_XMATCH; St_del(&op->txt, 0, 3); e->left.expr = undef(); e->right = get_value(op, 0); return e; } switch (c) { case '#': if (ST_INDEX(&op->txt, 1) != '<') { goto unrecog; } St_del(&op->txt, 0, 2); e = get_list(op, 0); St_shiftws(&op->txt); if (ST_FIRSTCHAR(&op->txt) == '#' && ST_INDEX(&op->txt, 1) == '>') { St_del(&op->txt, 0, 2); } break; case '(': St_shift(&op->txt); e = get_expr(op); St_shiftws(&op->txt); if (ST_FIRSTCHAR(&op->txt) == ')') { St_shift(&op->txt); } break; case '"': { struct val *v; St_shift(&op->txt); e = undef(); v = e->v.val; V_STR(v); for (; St_len(&op->txt) && (c = St_shift(&op->txt)) != '"'; ) { switch (c) { case '\\': if (St_len(&op->txt) == 0) { v_cat_c(v, c); break; } c = St_shift(&op->txt); if (c >= '0' && c <= '7') { int oct; oct = c - '0'; c = ST_FIRSTCHAR(&op->txt); if (c >= '0' && c <= '7') { oct *= 010; oct += c - '0'; St_shift(&op->txt); c = ST_FIRSTCHAR(&op->txt); if (c >= '0' && c <= '7') { oct *= 010; oct += c - '0'; St_shift(&op->txt); } } v_cat_c(v, oct); break; } switch (c) { case 'x': c = ST_FIRSTCHAR(&op->txt); if (isxdigit(c)) { int hex; hex = xval(c); St_shift(&op->txt); c = ST_FIRSTCHAR(&op->txt); if (isxdigit(c)) { hex *= 0x10; hex += xval(c); St_shift(&op->txt); } v_cat_c(v, hex); } else { v_cat_m(v, "\\x", 2); } break; case 'a': v_cat_c(v, '\a'); break; case 'b': v_cat_c(v, '\b'); break; case 'f': v_cat_c(v, '\f'); break; case 'n': v_cat_c(v, '\n'); break; case 'r': v_cat_c(v, '\r'); break; case 't': v_cat_c(v, '\t'); break; case 'v': v_cat_c(v, '\v'); break; case 'c': if (St_len(&op->txt)) { c = St_shift(&op->txt); v_cat_c(v, (toupper(c) + 64) % 128); } else { v_cat_m(v, "\\c", 2); } break; case 'V': { struct expr *tmp; tmp = e; e = xmalloc(1, sizeof *e); e->type = binopE; e->op = B_FLATWORM; e->left.expr = tmp; e->right = get_value(op, 0); tmp = e; e = xmalloc(1, sizeof *e); e->type = binopE; e->op = B_FLATWORM; e->left.expr = tmp; e->right = undef(); v = e->right->v.val; break; } default: v_cat_c(v, c); break; } break; default: v_cat_c(v, c); break; } } } break; case '\\': St_shift(&op->txt); e = xmalloc(1, sizeof *e); e->type = symbolE; e->right = NULL; e->left.expr = NULL; c = ST_FIRSTCHAR(&op->txt); if (isdigit(c)) { char *tmp = St_ptr(&op->txt); e->left.bonus = strtoul(tmp, &tmp, 10); St_del(&op->txt, 0, tmp - St_ptr(&op->txt)); e->op = S_MATCH; } else switch (c) { case '!': St_shift(&op->txt); e->op = S_ERR; break; case '?': St_shift(&op->txt); e->op = S_RAND; break; case '_': St_shift(&op->txt); e->op = S_RESULT; break; case '@': St_shift(&op->txt); e->op = S_ARG; break; case 'A': switch (ST_INDEX(&op->txt, 1)) { case 'R': if (ST_INDEX(&op->txt, 2) == 'G') { St_del(&op->txt, 0, 3); e->op = S_ARGC; if (ST_FIRSTCHAR(&op->txt) == ':') { St_shift(&op->txt); e->op = S_ARGV; e->right = get_value(op, 0); } break; } goto nullsym; case 'U': if (ST_INDEX(&op->txt, 2) == 'S' && ST_INDEX(&op->txt, 3) == 'G') { St_del(&op->txt, 0, 4); e->op = S_STDOUT; break; } goto nullsym; default: goto nullsym; } break; case 'E': switch (ST_INDEX(&op->txt, 1)) { case 'I': if ( ST_INDEX(&op->txt, 2) == 'N' && ST_INDEX(&op->txt, 3) == 'G' ) { St_del(&op->txt, 0, 4); e->op = S_STDIN; break; } if (0) case 'N': { if (ST_INDEX(&op->txt, 2) == 'V') { St_del(&op->txt, 0, 3); e->type = unopE; e->op = F_GETENV; e->right = get_value(op, 0); break; } } /*DURCHFALL*/ default: St_shift(&op->txt); e->op = S_EULER; break; } break; case 'F': if ( ST_INDEX(&op->txt, 1) == 'E' && ST_INDEX(&op->txt, 2) == 'H' && ST_INDEX(&op->txt, 3) == 'L' ) { St_del(&op->txt, 0, 4); e->op = S_STDERR; break; } goto nullsym; case 'L': e->op = F_LOWER; goto simplefunc; case 'Q': e->op = F_QUOTE; goto simplefunc; case 'R': e->op = F_RE_ESC; goto simplefunc; case 'U': e->op = F_UPPER; goto simplefunc; simplefunc: St_shift(&op->txt); e->type = unopE; e->right = get_value(op, 0); break; case 'P': if (ST_INDEX(&op->txt, 1) == 'I') { St_del(&op->txt, 0, 2); e->op = S_LUDOLF; break; } goto nullsym; nullsym: default: e->op = S_NUL; break; } break; case '@': #define CASE_DO_STUFF(n, o) \ if (1) { \ St_del(&op->txt, 0, (n)); \ e->op = (o); \ e->right = get_value(op, 0); \ break; \ } else ((void)0) #define CASE(i, w, n, o) \ case i: if (1) { \ if (St_len(&op->txt) < (n) || St_ncmp_m(&op->txt, w, n)) { \ goto usrfunc; \ } \ CASE_DO_STUFF(n, o); \ } else ((void)0) St_shift(&op->txt); e = xmalloc(1, sizeof *e); e->type = unopE; e->left.expr = NULL; switch (ST_FIRSTCHAR(&op->txt)) { case '+': CASE_DO_STUFF(1, F_MOEND); case '-': CASE_DO_STUFF(1, F_MOSTART); case 'A': switch (ST_INDEX(&op->txt, 1)) { CASE('B', "ABS", 3, F_ABS); CASE('C', "ACOS", 4, F_ACOS); CASE('P', "APERS", 5, F_OPEN); CASE('S', "ASIN", 4, F_ASIN); case 'T': if (St_len(&op->txt) >= 4) { if (St_ncmp_m(&op->txt, "ATAN2", 5) == 0) { CASE_DO_STUFF(5, F_ATAN2); } if (St_ncmp_m(&op->txt, "ATAN", 4) == 0) { CASE_DO_STUFF(4, F_ATAN); } } goto usrfunc; default: goto usrfunc; } break; case 'C': switch (ST_INDEX(&op->txt, 1)) { CASE('H', "CHR", 3, F_CHR); CASE('O', "COS", 3, F_COS); default: goto usrfunc; } break; CASE('D', "DEF-P", 5, F_DEFINED); case 'E': switch (ST_INDEX(&op->txt, 1)) { CASE('D', "EDD-P", 5, F_EOF); CASE('N', "ENV", 3, F_GETENV); CASE('R', "ERR-P", 5, F_ERROR); CASE('V', "EVAL", 4, F_CATCH); default: goto usrfunc; } break; CASE('G', "GET", 3, F_GETC); case 'I': switch (ST_INDEX(&op->txt, 1)) { CASE('N', "INT", 3, F_INT); CASE('O', "IO-P", 4, F_IO); default: goto usrfunc; } break; case 'L': switch (ST_INDEX(&op->txt, 1)) { CASE('A', "LAPERS", 6, F_OPENR); case 'E': switch (ST_INDEX(&op->txt, 2)) { CASE('G', "LEGS", 4, F_GETS); CASE('N', "LENGTH", 6, F_LENGTH); default: goto usrfunc; } break; CASE('G', "LG", 2, F_LOG10); CASE('N', "LN", 2, F_LOG); default: goto usrfunc; } break; case 'N': switch (ST_INDEX(&op->txt, 1)) { CASE('E', "NEG", 3, F_NEG); CASE('O', "NOT", 3, F_NOT); CASE('U', "NUM", 3, F_NUM); default: goto usrfunc; } break; case 'O': switch (ST_INDEX(&op->txt, 1)) { CASE('R', "ORD", 3, F_ORD); CASE('M', "OMFG", 4, F_FREEZE); default: goto usrfunc; } break; case 'R': if (ST_INDEX(&op->txt, 1) != 'E') { goto usrfunc; } switch (ST_INDEX(&op->txt, 2)) { CASE('M', "REMOVE", 6, F_REMOVE); CASE('N', "RENAEM", 6, F_RENAME); CASE('V', "REVERSE", 7, F_REVERSE); default: goto usrfunc; } break; case 'S': switch (ST_INDEX(&op->txt, 1)) { case 'A': switch (ST_INDEX(&op->txt, 2)) { CASE('G', "SAG", 3, F_TELL); CASE('P', "SAPERS", 6, F_OPENW); default: goto usrfunc; } break; CASE('I', "SIN", 3, F_SIN); CASE('Q', "SQRT", 4, F_SQRT); CASE('T', "STR", 3, F_STR); CASE('U', "SUCH", 4, F_SEEK); default: goto usrfunc; } break; case 'T': switch (ST_INDEX(&op->txt, 1)) { CASE('A', "TAN", 3, F_TAN); CASE('Y', "TYPE OF", 7, F_TYPEOF); default: goto usrfunc; } break; usrfunc: default: if ((e->left.op = ma_find(&Mars, &op->txt))) { e->op = F_CALL; } else { e->op = F_NUL; e->left.bonus = op->line; } e->right = get_value(op, 0); break; } #undef CASE_DO_STUFF #undef CASE break; unrecog: default: if (null) { e = NULL; } else { e = undef(); } break; } return e; } struct expr *get_iobj(struct op *op) { return get_value(op, 0); } struct expr *get_expr(struct op *op) { struct expr *a, *b; a = get_value(op, 0); for (St_shiftws(&op->txt); St_len(&op->txt); St_shiftws(&op->txt)) { struct expr *tmp; enum t_binop k; if (OPERATOR_P(ST_FIRSTCHAR(&op->txt))) { k = expr_binop(St_shift(&op->txt)); b = get_value(op, 0); } else if (St_ncmp_m(&op->txt, "?o~", 3) == 0) { k = B_XMATCH; St_del(&op->txt, 0, 3); b = get_value(op, 0); } else { if (!(b = get_value(op, 1))) { break; } k = B_SPOT; } tmp = a; a = xmalloc(1, sizeof *a); a->type = binopE; a->op = k; a->left.expr = tmp; a->right = b; } return a; } #define TOS (*stack_func(svalp, at)(&Stack, 0)) void eval_push(struct expr *ex) { const struct expr *const e = ex; switch (e->type) { case literE: case varE: stack_func(svalp, push)(&Stack, &e->v.val); return; case varhashE: { struct val *tmp, *tos; const char *ptr; size_t len; eval_push(e->right); tos = TOS; ptr = v_sptr(tos, &len); if ((tmp = sh_get(e->v.hash, ptr, len))) { v_set(tos, tmp); } else { v_set_undef(tos); } return; } case symbolE: switch (e->op) { case S_NUL: stack_func(svalp, pushnull)(&Stack); break; case S_ARG: { struct val *const tmp = &Interp.arg; stack_func(svalp, push)(&Stack, &tmp); break; } case S_ARGC: stack_func(svalp, pushnull)(&Stack); v_set_n(TOS, Interp.a.argc); break; case S_ARGV: { struct val *tos; size_t n; eval_push(e->right); tos = TOS; V_NUM(tos); n = RINT(tos->num); if (n < Interp.a.argc) { v_set(tos, &Interp.a.argv[n]); } else { v_set_undef(tos); } break; } case S_ERR: { struct val *tos; const char *const tmp = strerror(errno); stack_func(svalp, pushnull)(&Stack); tos = TOS; v_set_m(tos, tmp, strlen(tmp)); tos->num = errno; tos->type |= V_NUM_K; break; } case S_EULER: stack_func(svalp, pushnull)(&Stack); v_set_n(TOS, MY_E); break; case S_LUDOLF: stack_func(svalp, pushnull)(&Stack); v_set_n(TOS, MY_PI); break; case S_MATCH: stack_func(svalp, pushnull)(&Stack); if (e->left.bonus < Interp.match.length) { v_set(TOS, &Interp.match.matches[e->left.bonus]); } break; case S_RAND: stack_func(svalp, pushnull)(&Stack); v_set_n(TOS, randval()); break; case S_RESULT: { struct val *const tmp = &Interp.result; stack_func(svalp, push)(&Stack, &tmp); break; } case S_STDIN: stack_func(svalp, pushnull)(&Stack); v_set_io(TOS, In); break; case S_STDOUT: stack_func(svalp, pushnull)(&Stack); v_set_io(TOS, Out); break; case S_STDERR: stack_func(svalp, pushnull)(&Stack); v_set_io(TOS, Err); break; } return; case unopE: if (e->op == F_FREEZE) { struct sub *const tmp = sub_new(e->right); stack_func(svalp, pushnull)(&Stack); v_set_sub(TOS, tmp); sub_decr(tmp); return; } if (e->op == F_CATCH) { const size_t stackmark = stack_func(svalp, size)(&Stack); t_context *tos; stack_func(t_context, pushnull)(&Context); tos = stack_func(t_context, at)(&Context, 0); if (!setjmp(tos->buf)) { tos->depth = stack_func(save_pair, size)(&Saved); eval_push(e->right); assert(stack_func(svalp, size)(&Stack) - stackmark == 1u); stack_func(t_context, clear)(&Context, 1); } else { tos = stack_func(t_context, at)(&Context, 0); depth_restore(tos->depth); stack_func(t_context, clear)(&Context, 1); assert(stackmark <= stack_func(svalp, size)(&Stack)); stack_func(svalp, clear)(&Stack, stack_func(svalp, size)(&Stack) - stackmark); stack_func(svalp, pushnull)(&Stack); } return; } eval_push(e->right); switch (e->op) { case F_NUL: { struct op *op; struct val *const tos = TOS; TOLABEL(tos); if ((op = ve_findnext(&Venus, ko_str(tos->ko), e->left.bonus))) { struct val *tmp = v_undef(); v_set(tmp, tos); tmp = execute(op, tmp); v_set(TOS, tmp); v_delete(tmp); } else { hang(); } break; } case F_CALL: { struct val *tmp = v_undef(); v_set(tmp, TOS); tmp = execute(e->left.op, tmp); v_set(TOS, tmp); v_delete(tmp); break; } case F_MATCH: do_match(TOS, e->left.rx); break; case F_ABS: pp_abs(TOS); break; case F_ACOS: pp_acos(TOS); break; case F_ASIN: pp_asin(TOS); break; case F_ATAN: pp_atan(TOS); break; case F_ATAN2: pp_atan2(TOS); break; case F_CHR: pp_chr(TOS); break; case F_COS: pp_cos(TOS); break; case F_DEFINED: pp_defined(TOS); break; case F_EOF: pp_eof(TOS); break; case F_ERROR: pp_error(TOS); break; case F_GETC: pp_getc(TOS); break; case F_GETENV: pp_getenv(TOS); break; case F_GETS: pp_gets(TOS); break; case F_HANG: hang(); break; case F_INT: pp_int(TOS); break; case F_IO: pp_io(TOS); break; case F_LENGTH: pp_length(TOS); break; case F_LOG: pp_log(TOS); break; case F_LOG10: pp_log10(TOS); break; case F_LOWER: pp_lower(TOS); break; case F_MOEND: pp_moend(TOS); break; case F_MOSTART: pp_mostart(TOS); break; case F_NEG: pp_neg(TOS); break; case F_NOT: pp_not(TOS); break; case F_NUM: pp_num(TOS); break; case F_OPEN: pp_open(TOS); break; case F_OPENR: pp_openr(TOS); break; case F_OPENW: pp_openw(TOS); break; case F_ORD: pp_ord(TOS); break; case F_QUOTE: pp_quote(TOS); break; case F_RE_ESC: pp_escape(TOS); break; case F_REMOVE: pp_remove(TOS); break; case F_RENAME: pp_rename(TOS); break; case F_REVERSE: pp_reverse(TOS); break; case F_SEEK: pp_seek(TOS); break; case F_SIN: pp_sin(TOS); break; case F_SQRT: pp_sqrt(TOS); break; case F_STR: pp_str(TOS); break; case F_TAN: pp_tan(TOS); break; case F_TELL: pp_tell(TOS); break; case F_TYPEOF: pp_typeof(TOS); break; case F_UPPER: pp_upper(TOS); break; } return; case binopE: eval_push(e->left.expr); eval_push(e->right); if (e->op != B_XMATCH) { expr_pp(e->op, *stack_func(svalp, at)(&Stack, 1), TOS); stack_func(svalp, clear)(&Stack, 1); } else { t_regex *rx; struct val *const tos = TOS; V_STR(tos); rx = re_compile(ko_str(tos->ko)); stack_func(svalp, clear)(&Stack, 1); free_expr(ex->right); ex->right = ex->left.expr; ex->left.rx = rx; ex->op = F_MATCH; ex->type = unopE; do_match(TOS, rx); } return; case listE: { struct val *tos; stack_func(svalp, pushnull)(&Stack); tos = TOS; tos->magic.list = li_new(); tos->type = V_LIST_K; if (e->right) { struct val *tmp; eval_push(e->right); tmp = v_undef(); stack_func(svalp, pop)(&Stack, &tmp); li_push(tos->magic.list, tmp); if (e->left.expr) { eval_push(e->left.expr); assert(!!V_LIST_P(TOS)); li_append((*stack_func(svalp, at)(&Stack, 1))->magic.list, TOS->magic.list); stack_func(svalp, clear)(&Stack, 1); } } return; } } NOTREACHED; } void eval_into(struct expr *e, struct val *v) { DEBUG(const size_t oldsize = stack_func(svalp, size)(&Stack);) eval_push(e); assert(stack_func(svalp, size)(&Stack) - oldsize == 1u); stack_func(svalp, pop)(&Stack, &v); } struct val *eval_pop(void) { struct val *new = v_undef(); assert(stack_func(svalp, size)(&Stack) != 0); stack_func(svalp, pop)(&Stack, &new); return new; } struct val *eval_expr(struct expr *e) { eval_push(e); return eval_pop(); }