diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-08-21 11:46:57 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-08-21 11:46:57 +0300 |
commit | a1718144344d2743713164adc1790ec1ac399d8c (patch) | |
tree | cd8b86e6b13f2877151eddcbf7fbb2f69260f0ca /mfd/prog.c | |
parent | e2f591b6cd344420023daa910c7435298fe376c9 (diff) | |
download | mailfromd-a1718144344d2743713164adc1790ec1ac399d8c.tar.gz mailfromd-a1718144344d2743713164adc1790ec1ac399d8c.tar.bz2 |
Rename mfd -> src
Diffstat (limited to 'mfd/prog.c')
-rw-r--r-- | mfd/prog.c | 2696 |
1 files changed, 0 insertions, 2696 deletions
diff --git a/mfd/prog.c b/mfd/prog.c deleted file mode 100644 index 150f04d8..00000000 --- a/mfd/prog.c +++ /dev/null @@ -1,2696 +0,0 @@ -/* This file is part of Mailfromd. - Copyright (C) 2006, 2007, 2008, 2009, 2010 Sergey Poznyakoff - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include <setjmp.h> -#include <stdarg.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <arpa/inet.h> -#include <assert.h> -#include <fnmatch.h> -#include <syslog.h> -#include "mailfromd.h" -#include "prog.h" -#include "msg.h" -#include "optab.h" -#include "builtin.h" - - -/* Code generation support */ -#define CODE_INITIAL 128 -#define CODE_INCREMENT 128 - -static prog_counter_t pc, pmax; -instr_t *prog; -size_t stack_size = 4096; -size_t stack_max_size = 0; -size_t stack_expand_incr = 4096; -enum stack_expand_policy stack_expand_policy = stack_expand_add; - -/* Data segment */ -STKVAL *dataseg; -size_t datasize; -size_t dvarsize; - -/* Table of relocatable entries in the data segment */ -size_t *dataseg_reloc; -size_t dataseg_reloc_count; - -/* Regular expressions */ -struct rt_regex *regtab; -size_t regcount; -struct obstack regstk; - -/* Exceptions */ -size_t exception_count = mf_exception_count; - - -void -code_init() -{ - pmax = CODE_INITIAL; - prog = calloc(pmax, sizeof prog[0]); - if (!prog) { - mu_error(_("not enough memory")); - exit(1); - } -} - -prog_counter_t -code_get_counter() -{ - return pc; -} - -prog_counter_t -code_reserve(size_t count) -{ - prog_counter_t ret = pc; - if (pc + count > pmax) { - size_t incr = (pc + count - pmax + CODE_INCREMENT - 1) - / CODE_INCREMENT; - pmax += incr * CODE_INCREMENT; - prog = realloc(prog, pmax*sizeof prog[0]); - if (!prog) { - mu_error(_("not enough memory")); - exit(1); - } - } - pc += count; - return ret; -} - -prog_counter_t -code_instr(const instr_t ptr) -{ - if (pc >= pmax) { - pmax += CODE_INCREMENT; - prog = realloc(prog, pmax*sizeof prog[0]); - if (!prog) { - mu_error(_("not enough memory")); - exit(1); - } - } - prog[pc] = ptr; - return pc++; -} - -prog_counter_t -code_op(unsigned code) -{ - return code_instr((instr_t)code); -} - -prog_counter_t -code_immediate(const void *ptr) -{ - return code_instr(ptr); -} - -prog_counter_t -code_exmask(struct exmask *exmask) -{ - return code_immediate((void*) exmask->off); -} - -void -code_put(prog_counter_t pos, void *ptr) -{ - assert(pos < pmax); - prog[pos] = (instr_t) ptr; -} - -instr_t -code_peek(prog_counter_t pos) -{ - assert(pos < pmax); - return prog[pos]; -} - - -/* Regexps*/ - -void -register_regex(struct sym_regex *rp) -{ - struct rt_regex r; - if (regcount == 0) - obstack_init(®stk); - r.compiled = 0; /* Will be compiled later */ - r.expr = rp->lit ? rp->lit->off : 0; - r.regflags = rp->regflags; - rp->index = regcount++; - obstack_grow(®stk, &r, sizeof r); -} - -void -finalize_regex() -{ - if (regcount) - regtab = obstack_finish(®stk); -} - - -#define PROG_TRACE_ENGINE (builtin_module_trace(BUILTIN_IDX_prog)) - -static void -set_prog_trace(const char *modlist, int val) -{ - while (1) { - size_t len = strcspn(modlist, ","); - if (len == 3 && memcmp(modlist, "all", 3) == 0) - builtin_set_all_module_trace(val); - else if (len == 4 && memcmp(modlist, "none", 4) == 0) - builtin_set_all_module_trace(!val); - else { - if (len > 3 && memcmp (modlist, "no-", 3) == 0) - builtin_set_module_trace(modlist+3, len-3, - !val); - else - builtin_set_module_trace(modlist, len, val); - } - modlist += len; - if (*modlist) - modlist++; - else - break; - } -} - -void -enable_prog_trace(const char *modlist) -{ - set_prog_trace(modlist, 1); -} - -void -disable_prog_trace(const char *modlist) -{ - set_prog_trace(modlist, 0); -} - -/* ======================================================================== - Drzewa w górę, rzeki w dół. - - Jacek Kaczmarski. - "Upadek Ikara" - ======================================================================== */ - -/* Run-time evaluation */ - -/* Max. number of C locals to save in struct eval_environ for eventual fixups. - See comment to env_fixup_autos, below. */ -#define MAX_AUTO_PTR 128 - -#define ENVF_MSGMOD 0x01 /* message modofication instruction has been used */ - -struct exception_context { - prog_counter_t pc; - prog_counter_t tos; - prog_counter_t base; -}; - -#define TOS_INVARIANT(env,t) (datasize + (env)->stack_size - (t)) - -struct eval_environ { - prog_counter_t pc; /* Program counter */ - - prog_counter_t tos; /* Top of stack: - toh <= tos < datasize + stack_size */ - prog_counter_t toh; /* Top of heap: - datasize <= toh <= tos */ - - prog_counter_t base; /* Base pointer */ - STKVAL reg; /* General purpose register */ - STKVAL *dataseg; /* Data space */ - size_t stack_size; /* Size of allocated stack + heap */ - - struct locus locus; /* Program locus corresponding to PC */ - - /* Temporary heap space */ - size_t temp_start; - size_t temp_size; - - STKVAL *auto_ptr[MAX_AUTO_PTR]; /* Pointers to C automatic variables - referring to dataseg. */ - size_t numautos; /* Number of entries in auto_ptr. */ - - /* Sendmail interaction data: */ - SMFICTX *ctx; /* Milter Context */ - void *data; /* MTA symbol table */ - /* methods to access the latter */ - const char *(*getsym)(void *data, const char *str); - int (*setreply)(void *data, char *code, char *xcode, char *message); - void (*msgmod)(void *data, struct msgmod_closure *c); - - int flags; - - /* Regular expression matching */ - regmatch_t *matches; /* Match map */ - size_t matchcount; /* Number of used entries in matches */ - size_t matchsize; /* Total number of entries in matches */ - char *string; /* Last matched string */ - - mu_stream_t stream; /* Capture stream */ - size_t line_count; /* Number of lines in stream */ - int reposition; /* When !0, stream must be repositioned to - its end before writing. */ - - /* Non-local exits */ - struct exception_context *defcatch_ctx; - struct exception_context *catch_ctx; - - /* Built-in private data */ - void **bi_priv_array; - - /* Exit information */ - sfsistat status; /* Program exit status */ - jmp_buf x_jmp; /* Return point for runtime errors */ - jmp_buf catch_jmp; /* Return point for throws */ -}; - -void -advance_pc(eval_environ_t env, long cnt) -{ - env->pc += cnt; -} - -void -adjust_stack(eval_environ_t env, unsigned cnt) -{ - env->tos += cnt; -} - -void -unroll_stack(eval_environ_t env, unsigned cnt) -{ - env->tos -= cnt; -} - -size_t -env_base(eval_environ_t env, size_t frame) -{ - size_t base = env->base; - for (; frame; frame--) - base = (size_t) env->dataseg[base + 1] + base + 1; - return base; -} - -char * -env_vaptr(eval_environ_t env, size_t off) -{ - return (char*)(env->dataseg + (size_t) env->dataseg[off]); -} - -void -env_var_inc(eval_environ_t env, size_t off) -{ - ++*env_data_ref(env, off); -} - -const struct locus * -env_get_locus(eval_environ_t env) -{ - return &env->locus; -} - -const char * -env_get_macro(eval_environ_t env, const char *symbol) -{ - return env->getsym(env->data, symbol); -} - -mu_stream_t -env_get_stream(eval_environ_t env) -{ - return env->stream; -} - -STKVAL -env_get_reg(eval_environ_t env) -{ - return env->reg; -} - -void -env_reposition(eval_environ_t env) -{ - env->reposition = 1; -} - - -/* A call to expand_dataseg (see below) invalidates any C variables that - pointed to the dataseg before the call. To avoid dereferencing invalid - memory pointers, addresses of such C variables are stored in env->auto_ptr - using env_register_auto (it is done by get_string_arg). When - expand_dataseg is called, it calls env_fixup_autos and passes it the - offset of the new dataseg from the old one. Env_fixup_autos adds this - value to every address in auto_ptr, thereby fixing them. - - The auto_ptr array is cleared (by calling env_unregister_autos) after - executing each instruction (see eval_environment). - */ -void -env_register_auto(eval_environ_t env, void *ptr) -{ - if (env->numautos == MAX_AUTO_PTR) - runtime_error(env, "INTERNAL ERROR at %s:%d, please report", - __FILE__, __LINE__); - env->auto_ptr[env->numautos++] = ptr; -} - -void -env_unregister_autos(eval_environ_t env) -{ - env->numautos = 0; -} - -void -env_fixup_autos(eval_environ_t env, ptrdiff_t offset) -{ - int i; - for (i = 0; i < env->numautos; i++) { - STKVAL *pptr = env->auto_ptr[i]; - *pptr += offset; - } -} - - -static int -expand_dataseg(eval_environ_t env, size_t count, const char *errtext) -{ - STKVAL *newds; - ptrdiff_t offset; - size_t new_stack_size; - size_t diff; - - switch (stack_expand_policy) { - case stack_expand_add: - diff = ((count + stack_expand_incr - 1) / stack_expand_incr) - * stack_expand_incr; - new_stack_size = env->stack_size + diff; - break; - - case stack_expand_twice: - new_stack_size = 2 * env->stack_size; - if (new_stack_size < env->stack_size) { - if (errtext) - runtime_error(env, errtext); - else - return 1; - } - diff = new_stack_size - env->stack_size; - if (diff < count) { - if (errtext) - runtime_error(env, errtext); - else - return 1; - } - } - - if ((stack_max_size && new_stack_size > stack_max_size) - || (newds = realloc(env->dataseg, - (new_stack_size + datasize) - * sizeof env->dataseg[0])) == NULL) { - if (errtext) - runtime_error(env, errtext); - else - return 1; - } - - offset = (char*)newds - (char*)env->dataseg; - env->dataseg = newds; - env->stack_size = new_stack_size; - env->tos += diff; - env->base += diff; - memmove(newds + env->tos, newds + env->tos - diff, - (datasize + env->stack_size - env->tos) - * sizeof newds[0]); - env_fixup_autos(env, offset); - mu_diag_output(MU_DIAG_WARNING, - _("stack segment expanded, new size=%lu"), - (unsigned long) env->stack_size); - return 0; -} - - -void -prog_trace(eval_environ_t env, const char *fmt, ...) -{ - char buf[512]; - va_list ap; - - va_start(ap, fmt); - vsnprintf(buf, sizeof buf, fmt, ap); - va_end(ap); - logmsg(LOG_DEBUG, "%4lu: %s:%lu: %s", - (unsigned long) env->pc, - env->locus.file, (unsigned long) env->locus.line, - buf); -} - -void instr_funcall(eval_environ_t env); -void instr_locus(eval_environ_t env); - -void -runtime_stack_trace(eval_environ_t env) -{ - size_t base; - - mu_error(_("stack trace:")); - for (base = env->base; base < datasize + env->stack_size - 4; - base = (size_t) env->dataseg[base + 1] + base + 1) { - int i; - prog_counter_t pc = (prog_counter_t)env->dataseg[base + 2] - 1; - char *name; - struct locus *ploc = NULL, loc; - - if (pc < 2) - break; /*FIXME*/ - if (prog[pc-2] == instr_funcall) { - name = (char*)(env->dataseg + (size_t) prog[pc-1]); - pc -= 2; - } else { - name = "(in catch)"; - pc -= 3; - } - - for (i = 0; i < 10; i++) { - if (pc > i + 3 - && prog[pc - i - 3] == instr_locus) { - loc.file = (char*)(env->dataseg - + (size_t) prog[pc - i - 2]); - loc.line = (size_t) prog[pc - i - 1]; - ploc = &loc; - break; - } - } - - if (ploc) - mu_error("%04lu: %s:%lu: %s", - (unsigned long) pc, - ploc->file, (unsigned long) ploc->line, - name); - else - mu_error("%04lu: %s", - (unsigned long) pc, - name); - } - mu_error(_("stack trace finishes")); -} - -void -runtime_warning(eval_environ_t env, const char *fmt, ...) -{ - va_list ap; - - mu_diag_printf(MU_DIAG_WARNING, - _("RUNTIME WARNING near %s:%lu: "), - env->locus.file, (unsigned long) env->locus.line); - va_start(ap, fmt); - mu_diag_output(MU_DIAG_WARNING, fmt, ap); - va_end(ap); -} - -void -runtime_error(eval_environ_t env, const char *fmt, ...) -{ - int n; - va_list ap; - char buf[512]; - - n = snprintf(buf, sizeof buf, _("RUNTIME ERROR near %s:%lu: "), - env->locus.file, (unsigned long) env->locus.line); - va_start(ap, fmt); - vsnprintf(buf + n, sizeof buf - n, fmt, ap); - va_end(ap); - mu_error(buf); - if (stack_trace_option) - runtime_stack_trace(env); - env->status = SMFIS_TEMPFAIL; /* FIXME */ - longjmp(env->x_jmp, 1); -} - -void * -get_immediate(eval_environ_t env, unsigned n) -{ - return prog[env->pc + n + 1]; -} - -void -get_literal(eval_environ_t env, unsigned n, const char **p) -{ - *p = (char*)(env->dataseg + (size_t) get_immediate(env, n)); - env_register_auto(env, p); -} - -STKVAL -get_arg(eval_environ_t env, unsigned n) -{ - return env->dataseg[env->tos + n + 1]; -} - -void -get_string_arg(eval_environ_t env, unsigned n, char **p) -{ - *p = (char*) (env->dataseg + (size_t) get_arg(env, n)); - env_register_auto(env, p); -} - -void -get_numeric_arg(eval_environ_t env, unsigned n, long *np) -{ - *np = (long) get_arg(env, n); -} - -void -get_pointer_arg(eval_environ_t env, unsigned n, void **p) -{ - *p = (void*) get_arg(env, n); -} - -void -push(eval_environ_t env, STKVAL val) -{ - if (env->tos < env->toh) - runtime_error(env, "INTERNAL ERROR at %s:%d, please report", - __FILE__, __LINE__); - if (env->tos == env->toh) { - debug(MF_SOURCE_PROG, 100, - ("tos=%lu, toh=%lu", - (unsigned long) env->tos, - (unsigned long) env->toh)); - expand_dataseg(env, 1, - _("out of stack space; increase #pragma stacksize")); - } - env->dataseg[env->tos--] = val; -} - -STKVAL -pop(eval_environ_t env) -{ - if (env->tos == datasize + env->stack_size - 1) - runtime_error(env, _("stack underflow")); - return env->dataseg[++env->tos]; -} - -size_t -heap_reserve_words(eval_environ_t env, size_t words) -{ - size_t off = env->toh; - if (env->toh + words > env->tos) - expand_dataseg(env, words, - _("heap overrun; increase #pragma stacksize")); - env->toh += words; - return off; -} - -size_t -heap_reserve(eval_environ_t env, size_t size) -{ - return heap_reserve_words(env, B2STACK(size)); -} - -STKVAL -heap_tempspace(eval_environ_t env, size_t size) -{ - size_t words = B2STACK(size); - - if (env->toh + words > env->tos) - expand_dataseg(env, words, - _("heap overrun; increase #pragma stacksize")); - return env->dataseg + env->toh; -} - -void -heap_obstack_begin(eval_environ_t env) -{ - env->temp_start = env->toh; - env->temp_size = 0; -} - -void -heap_obstack_cancel(eval_environ_t env) -{ - env->toh = env->temp_start; - env->temp_start = 0; - env->temp_size = 0; -} - -STKVAL -heap_obstack_finish(eval_environ_t env) -{ - size_t ret = env->temp_start; - env->temp_start = 0; - env->temp_size = 0; - return (STKVAL) ret; -} - -void * -heap_obstack_grow(eval_environ_t env, void *ptr, size_t size) -{ - size_t words = B2STACK(size); - char *ret; - - if (env->tos - env->toh < words + B2STACK(env->temp_size)) - expand_dataseg(env, words, - _("memory chunk too big to fit into heap")); - ret = (char*) env_data_ref(env, env->temp_start) + env->temp_size; - if (ptr) - memmove(ret, ptr, size); - env->temp_size += size; - env->toh += words; - return ret; -} - -void * -heap_obstack_base(eval_environ_t env) -{ - return (void*) env_data_ref(env, env->temp_start); -} - -STKVAL * -env_data_ref(eval_environ_t env, size_t off) -{ - return env->dataseg + off; -} - -void -pushs(eval_environ_t env, const char *s) -{ - size_t off = heap_reserve(env, strlen(s) + 1); - strcpy((char*) env_data_ref(env, off), s); - push(env, (STKVAL) off); -} - -/* Auxiliary instructions */ - -void -instr_locus(eval_environ_t env) -{ - env->locus.line = (size_t) get_immediate(env, 1); - get_literal(env, 0, &env->locus.file); - if (PROG_TRACE_ENGINE) - prog_trace(env, "LOCUS"); - advance_pc(env, 2); -} - -void -dump_locus(prog_counter_t i) -{ - printf("\"%s\" %lu", (char*) (dataseg + (size_t)prog[i]), - (unsigned long) (size_t) prog[i+1]); -} - -/* Stack manipulation instructions */ -void -instr_xchg(eval_environ_t env) -{ - prog_counter_t p = env->tos + 1; - STKVAL tmp = env->dataseg[p]; - env->dataseg[p] = env->dataseg[p + 1]; - env->dataseg[p + 1] = tmp; - if (PROG_TRACE_ENGINE) - prog_trace(env, "XCHG"); -} - -void -instr_dup(eval_environ_t env) -{ - if (PROG_TRACE_ENGINE) - prog_trace(env, "DUP"); - push(env, get_arg(env, 0)); -} - -void -instr_pop(eval_environ_t env) -{ - if (PROG_TRACE_ENGINE) - prog_trace(env, "POP"); - pop(env); -} - -void -instr_push(eval_environ_t env) -{ - if (PROG_TRACE_ENGINE) - prog_trace(env, "PUSH %x", get_immediate(env, 0)); - push(env, get_immediate(env, 0)); - advance_pc(env, 1); -} - -void -dump_push(prog_counter_t i) -{ - printf("%lx", (unsigned long) prog[i]); -} - -void -instr_memstk(eval_environ_t env) -{ - size_t frame = (size_t) get_immediate(env, 0); - long off = (long) get_immediate(env, 1); - size_t val = env_base(env, frame) + off; - - if (PROG_TRACE_ENGINE) - prog_trace(env, "MEMSTK %lu(%ld)=%lu", - (unsigned long) frame, off, - (unsigned long) val); - advance_pc(env, 2); - push(env, (STKVAL) val); -} - -void -dump_memstk(prog_counter_t i) -{ - printf("%lu(%ld)", (unsigned long) prog[i], (long) prog[i+1]); -} - -void -instr_xmemstk(eval_environ_t env) -{ - size_t frame = (size_t) get_arg(env, 1); - long off = (long) get_arg(env, 0); - size_t val = env_base(env, frame) + off; - - if (PROG_TRACE_ENGINE) - prog_trace(env, "XMEMSTK %lu(%ld)=%lu", - (unsigned long) frame, off, - (unsigned long) val); - adjust_stack(env, 2); - push(env, (STKVAL) val); -} - -void -instr_deref(eval_environ_t env) -{ - size_t off = (size_t) get_arg(env, 0); - STKVAL val = env->dataseg[off]; - - if (PROG_TRACE_ENGINE) - prog_trace(env, "DEREF %lu=%lu (%p)", - (unsigned long) off, - (unsigned long) val, val); - adjust_stack(env, 1); - push(env, val); -} - -void -instr_stkalloc(eval_environ_t env) -{ - unsigned n = (unsigned) get_immediate(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "STKALLOC %p", n); - if (env->tos - n < env->toh) { - debug(MF_SOURCE_PROG, 100, - ("tos=%lu, toh=%lu, delta=%u", - (unsigned long) env->tos, - (unsigned long) env->toh, - n)); - expand_dataseg(env, env->toh - (env->tos - n), - _("Out of stack space; increase #pragma stacksize")); - } - env->tos -= n; - advance_pc(env, 1); -} - -void -dump_stkalloc(prog_counter_t i) -{ - printf("%u", (unsigned)prog[i]); -} - -void -instr_backref(eval_environ_t env) -{ - unsigned n = (unsigned) get_immediate(env, 0); - size_t matchlen; - - if (PROG_TRACE_ENGINE) - prog_trace(env, "BACKREF %u", (unsigned)get_immediate(env, 0)); - advance_pc(env, 1); - - if (!env->matches || !env->string) { - /* FIXME: Try to throw exception first: - env_throw(env, mf_no_regex); - */ - runtime_error(env, _("no previous regular expression")); - } - if (n > env->matchcount) { - /* FIXME: See above */ - runtime_error(env, _("invalid back-reference number")); - } - - if (env->matches[n].rm_so == -1) { - push(env, 0); - } else { - char *s; - size_t off; - - matchlen = env->matches[n].rm_eo - env->matches[n].rm_so; - off = heap_reserve(env, matchlen + 1); - s = (char*) env_data_ref(env, off); - memcpy(s, env->string + env->matches[n].rm_so, matchlen); - s[matchlen] = 0; - push(env, (STKVAL) off); - } -} - -void -dump_backref(prog_counter_t i) -{ - printf("%u", (unsigned) prog[i]); -} - -/* Type conversion instructions */ -void -instr_ston(eval_environ_t env) -{ - char *s; - char *p; - long v; - - get_string_arg(env, 0, &s); - v = strtol(s, &p, 0); - - if (PROG_TRACE_ENGINE) - prog_trace(env, "STON %s", s); - adjust_stack(env, 1); - if (*p) - env_throw(env, mfe_ston_conv, - "Cannot convert stack value to number (stopped at %-.8s)", - p); - - push(env, (STKVAL) v); -} - -void -instr_ntos(eval_environ_t env) -{ - long v = (long) get_arg(env, 0); - char buf[NUMERIC_BUFSIZE_BOUND]; - - if (PROG_TRACE_ENGINE) - prog_trace(env, "NTOS %ld", v); - adjust_stack(env, 1); - - snprintf(buf, sizeof buf, "%ld", v); - pushs(env, buf); -} - -/* Evaluation instructions */ -void -instr_cmp(eval_environ_t env) -{ - long l = (long) get_arg(env, 1); - long r = (long) get_arg(env, 0); - - if (PROG_TRACE_ENGINE) - prog_trace(env, "CMP %ld %ld", l, r); - adjust_stack(env, 2); - push(env, (STKVAL) (l == r)); -} - -void -instr_symbol(eval_environ_t env) -{ - char *symbol; - const char *s; - - get_literal(env, 0, (const char **)&symbol); - s = env->getsym(env->data, symbol); - - if (PROG_TRACE_ENGINE) - prog_trace(env, "SYMBOL %s", symbol); - if (!s) - env_throw(env, mfe_macroundef, _("macro not defined: %s"), - symbol); - - if (PROG_TRACE_ENGINE) - prog_trace(env, "%s dereferenced to %s", symbol, s); - - advance_pc(env, 1); - - pushs(env, s); -} - -void -dump_symbol(prog_counter_t i) -{ - printf("%08lx %s", (unsigned long) prog[i], - (char *) (dataseg + (size_t) prog[i])); -} - -/* Comparation instructions */ -void -instr_eqn(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "EQN %ld %ld", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a == b)); -} - -void -instr_eqs(eval_environ_t env) -{ - char *a, *b; - get_string_arg(env, 1, &a); - get_string_arg(env, 0, &b); - if (PROG_TRACE_ENGINE) - prog_trace(env, "EQS %s %s", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (strcmp(a, b) == 0)); -} - -void -instr_nen(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "NEN %ld %ld", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a != b)); -} - -void -instr_nes(eval_environ_t env) -{ - char *a, *b; - - get_string_arg(env, 1, &a); - get_string_arg(env, 0, &b); - if (PROG_TRACE_ENGINE) - prog_trace(env, "NES %s %s", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) strcmp(a, b)); -} - -void -instr_ltn(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "LTN %ld %ld", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a < b)); -} - -void -instr_lts(eval_environ_t env) -{ - char *a, *b; - - get_string_arg(env, 1, &a); - get_string_arg(env, 0, &b); - if (PROG_TRACE_ENGINE) - prog_trace(env, "LTS %s %s", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (strcmp(a, b) < 0)); -} - -void -instr_len(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "LEN %ld %ld", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a <= b)); -} - -void -instr_les(eval_environ_t env) -{ - char *a, *b; - - get_string_arg(env, 1, &a); - get_string_arg(env, 0, &b); - if (PROG_TRACE_ENGINE) - prog_trace(env, "LES %s %s", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (strcmp(a, b) <= 0)); -} - -void -instr_gtn(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "GTN %ld %ld", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a > b)); -} - -void -instr_gts(eval_environ_t env) -{ - char *a, *b; - - get_string_arg(env, 1, &a); - get_string_arg(env, 0, &b); - if (PROG_TRACE_ENGINE) - prog_trace(env, "GTS %s %s", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (strcmp(a, b) > 0)); -} - -void -instr_gen(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "GEN %ld %ld", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a >= b)); -} - -void -instr_ges(eval_environ_t env) -{ - char *a, *b; - - get_string_arg(env, 1, &a); - get_string_arg(env, 0, &b); - if (PROG_TRACE_ENGINE) - prog_trace(env, "GES %s %s", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (strcmp(a, b) >= 0)); -} - -/* Jump instructions */ -void -instr_bz(eval_environ_t env) -{ - long v = (long) get_arg(env, 0); - long off = (long) get_immediate(env, 0); - - if (PROG_TRACE_ENGINE) - prog_trace(env, "BZ %ld (%ld)", off, v); - adjust_stack(env, 1); - if (v == 0) - advance_pc(env, off); - advance_pc(env, 1); -} - -void -dump_branch (prog_counter_t i) -{ - printf("%ld (%ld)", (long) prog[i], i + (long) prog[i] + 1); -} - -void -instr_bnz(eval_environ_t env) -{ - long v = (long) get_arg(env, 0); - long off = (long) get_immediate(env, 0); - - if (PROG_TRACE_ENGINE) - prog_trace(env, "BNZ %ld (%ld)", off, v); - adjust_stack(env, 1); - if (v != 0) - advance_pc(env, off); - advance_pc(env, 1); -} - -void -instr_jmp(eval_environ_t env) -{ - long off = (long) get_immediate(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "JMP %ld", off); - advance_pc(env, off+1); -} - -/* Boolean instructions */ -void -instr_not(eval_environ_t env) -{ - long v = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "NOT %ld", v); - adjust_stack(env, 1); - push(env, (STKVAL) !v); -} - -/* Bitwise arithmetics */ -void -instr_logand(eval_environ_t env) -{ - unsigned long a = (unsigned long) get_arg(env, 1); - unsigned long b = (unsigned long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "LOGAND %lu %lu", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a & b)); -} - -void -instr_logor(eval_environ_t env) -{ - unsigned long a = (unsigned long) get_arg(env, 1); - unsigned long b = (unsigned long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "LOGOR %lu %lu", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a | b)); -} - -void -instr_logxor(eval_environ_t env) -{ - unsigned long a = (unsigned long) get_arg(env, 1); - unsigned long b = (unsigned long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "LOGXOR %lu %lu", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a ^ b)); -} - -void -instr_lognot(eval_environ_t env) -{ - unsigned long v = (unsigned long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "LOGNOT %ld", v); - adjust_stack(env, 1); - push(env, (STKVAL) ~v); -} - -/* Arithmetic instructions */ -void -instr_add(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "ADD %ld %ld", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a + b)); -} - -void -instr_sub(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "SUB %ld %ld", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a - b)); -} - -void -instr_mul(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "MUL %ld %ld", a, b); - adjust_stack(env, 2); - push(env, (STKVAL) (a * b)); -} - -void -instr_div(eval_environ_t env) -{ - long a = (long) get_arg(env, 1); - long b = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "DIV %ld %ld", a, b); - adjust_stack(env, 2); - if (b == 0) - env_throw(env, mfe_divzero, - "Division by zero at %08x", (unsigned int) env->pc); - push(env, (STKVAL) (a / b)); -} - -void -instr_neg(eval_environ_t env) -{ - long v = (long) get_arg(env, 0); - if (PROG_TRACE_ENGINE) - prog_trace(env, "NEG %ld", v); - adjust_stack(env, 1); - push(env, (STKVAL) -v); -} - -/* Matching and Regular expression instructions */ - -/* REGEX: Basically it is useful only for debugging. Its effect is - the same as that of instr_push */ -void -instr_regex(eval_environ_t env) -{ - char buffer[REGEX_STRING_BUFSIZE]; - size_t index = (size_t) get_immediate(env, 0); - - if (PROG_TRACE_ENGINE) - prog_trace(env, "REGEX (%s) %s", - regex_flags_to_string(regtab[index].regflags, - buffer, - sizeof buffer), - (char*) env_data_ref(env, regtab[index].expr)); - advance_pc |