Mercurial > repo
diff src/ploki/deparse.c @ 4223:ac0403686959
<oerjan> rm -rf src/ploki; mv ploki src
author | HackBot |
---|---|
date | Fri, 20 Dec 2013 22:18:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ploki/deparse.c Fri Dec 20 22:18:50 2013 +0000 @@ -0,0 +1,688 @@ +#include "config.h" +#include "Str.h" +#include "deparse.h" +#include "expr.h" +#include "main_io.h" +#include "main_label.h" +#include "text.h" +#include "val.h" +#include "venus.h" +#include "xmalloc.h" +#include "zz.h" + +#include <ctype.h> +#include <stdio.h> +#include <assert.h> + +#if HAVE_VSNPRINTF_P +#define MAKE_LABEL(s, c) \ +do { \ + static unsigned long seq__; \ + St_init(s); \ + St_xprintf(s, "%c%lu", c, seq__++); \ +} while (0) +#else +#define MAKE_LABEL(s, c) \ +do { \ + static unsigned long seq__; \ + St_init(s); \ + St_num(s, seq__++); \ + St_tac_c(s, c); \ +} while (0) +#endif + +ATTR_CONST +static int display(enum t_binop b) { + switch (b) { + case B_SPARK_SPOT: return '!'; + case B_DOUBLE_OH_SEVEN: return '%'; + case B_AMPERSAND: return '&'; + case B_SPARK: return '\''; + case B_SPLAT: return '*'; + case B_INTERSECTION: return '+'; + case B_TAIL: return ','; + case B_WORM: return '-'; + case B_SPOT: return '.'; + case B_SLAT: return '/'; + case B_TWO_SPOT: return ':'; + case B_HYBRID: return ';'; + case B_ANGLE: return '<'; + case B_HALF_MESH: return '='; + case B_RIGHT_ANGLE: return '>'; + case B_U_TURN: return '['; + case B_U_TURN_BACK: return ']'; + case B_SHARK_FIN: return '^'; + case B_FLATWORM: return '_'; + case B_BACKSPARK: return '`'; + case B_EMBRACE: return '{'; + case B_SPIKE: return '|'; + case B_BRACELET: return '}'; + case B_SQIGGLE: return '~'; + default: break; + } + NOTREACHED; +} + +static void dump_str(const String *s) { + size_t i; + + io_write_m(Out, "\"", 1); + for (i = 0; i < St_len(s); ++i) { + const unsigned char c = ST_INDEX(s, i); + if (c != '\\' && c != '"' && isprint(c)) { + io_write_m(Out, &c, 1); + } else { + io_write_m(Out, "\\", 1); + switch (c) { + case '"': + case '\\': io_write_m(Out, &c , 1); break; + case '\a': io_write_m(Out, "a", 1); break; + case '\b': io_write_m(Out, "b", 1); break; + case '\f': io_write_m(Out, "f", 1); break; + case '\n': io_write_m(Out, "n", 1); break; + case '\r': io_write_m(Out, "r", 1); break; + case '\t': io_write_m(Out, "t", 1); break; + case '\v': io_write_m(Out, "v", 1); break; + default: fprintf(io_fp(Out), "%03o", c); break; + } + } + } + io_write_m(Out, "\"", 1); +} + +static void dump_ko(const struct kork *k) { + String tmp; + St_fake(&tmp, (char *)ko_ptr(k), ko_length(k)); + dump_str(&tmp); +} + +static void to_id(struct kork *k, size_t n) { + static char id[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "$" + ; + const size_t base = sizeof id - 1; + do { + ko_cat_c(k, id[n % base]); + n /= base; + } while (n); +} + +static void make_var(struct val *v) { + static size_t seq; + + ko_decouple(v->ko); + to_id(v->ko, seq++); + v->type = V_STR_K; +} + +static void dump_expr(const struct expr *e, int inlist) { + assert(e != NULL); + + switch (e->type) { + case literE: + if (V_EXT_P(e->v.val)) { + fprintf(io_fp(Out), "?%s?", io_name(e->v.val->magic.ext, NULL)); + } else if (V_SUB_P(e->v.val)) { + fprintf(io_fp(Out), "?CODE(%p)?", (void *)e->v.val->magic.sub); + } else if (V_STR_P(e->v.val)) { + dump_ko(e->v.val->ko); + } else if (V_NUM_P(e->v.val)) { + if (e->v.val->num < 0.0) { + fprintf(io_fp(Out), "@NEG %g", -e->v.val->num); + } else { + fprintf(io_fp(Out), "%g", e->v.val->num); + } + } else { + #if 0 + io_write_m(Out, "()", 2); + #endif + } + break; + + case varE: + if (!V_STR_P(e->v.val)) { + assert(e->v.val->type == V_UNDEF); + make_var(e->v.val); + } + io_write_m(Out, ko_ptr(e->v.val->ko), ko_length(e->v.val->ko)); + break; + + case varhashE: { + struct val *tmp; + if (!(tmp = sh_get(e->v.hash, "name", 4))) { + tmp = v_undef(); + make_var(tmp); + sh_put(e->v.hash, "name", 4, tmp); + } + io_write_m(Out, ko_ptr(tmp->ko), ko_length(tmp->ko)); + io_write_m(Out, "(", 1); + dump_expr(e->right, 0); + io_write_m(Out, ")", 1); + break; + } + + case symbolE: + io_write_m(Out, "\\", 1); + switch (e->op) { + case S_NUL: break; + case S_ARG: io_write_m(Out, "@", 1); break; + case S_ARGC: io_write_m(Out, "ARG", 3); break; + + case S_ARGV: + io_write_m(Out, "ARG:", 4); + if (e->right->type == binopE) { + io_write_m(Out, "(", 1); + dump_expr(e->right, 0); + io_write_m(Out, ")", 1); + } else { + dump_expr(e->right, 0); + } + break; + + case S_ERR: io_write_m(Out, "!", 1); break; + case S_EULER: io_write_m(Out, "E", 1); break; + case S_LUDOLF: io_write_m(Out, "PI", 2); break; + case S_MATCH: + fprintf(io_fp(Out), "%lu", (unsigned long)e->left.bonus); + break; + case S_RAND: io_write_m(Out, "?", 1); break; + case S_RESULT: io_write_m(Out, "_", 1); break; + case S_STDIN: io_write_m(Out, "EING", 4); break; + case S_STDOUT: io_write_m(Out, "AUSG", 4); break; + case S_STDERR: io_write_m(Out, "FEHL", 4); break; + + default: NOTREACHED; break; + } + break; + + case unopE: + switch (e->op) { + case F_EXP: io_write_m(Out, "\\E^", 3); break; + case F_LOWER: io_write_m(Out, "\\L" , 2); break; + case F_QUOTE: io_write_m(Out, "\\Q" , 2); break; + case F_RE_ESC: io_write_m(Out, "\\R" , 2); break; + case F_UPPER: io_write_m(Out, "\\U" , 2); break; + case F_MATCH: { + String tmp; + io_write_m(Out, "(", 1); + dump_expr(e->right, 0); + io_write_m(Out, " ~ ", 3); + St_init(&tmp); + re_decompile(e->left.rx, &tmp); + dump_str(&tmp); + St_clear(&tmp); + io_write_m(Out, ")", 1); + return; + } + + default: + io_write_m(Out, "@", 1); + switch (e->op) { + case F_CALL: io_write(Out, &e->left.op->txt); + case F_NUL: break; + case F_ABS: io_write_m(Out, "ABS", 3); break; + case F_ACOS: io_write_m(Out, "ACOS", 4); break; + case F_ASIN: io_write_m(Out, "ASIN", 4); break; + case F_ATAN: io_write_m(Out, "ATAN", 4); break; + case F_ATAN2: io_write_m(Out, "ATAN2", 5); break; + case F_CATCH: io_write_m(Out, "EVAL", 4); break; + case F_CHR: io_write_m(Out, "CHR", 3); break; + case F_COS: io_write_m(Out, "COS", 3); break; + case F_DEFINED: io_write_m(Out, "DEF-P", 5); break; + case F_EOF: io_write_m(Out, "EDD-P", 5); break; + case F_ERROR: io_write_m(Out, "ERR-P", 5); break; + case F_FREEZE: io_write_m(Out, "OMFG", 4); break; + case F_GETC: io_write_m(Out, "GET", 3); break; + case F_GETENV: io_write_m(Out, "ENV", 3); break; + case F_GETS: io_write_m(Out, "LEGS", 4); break; + case F_HANG: { + size_t i; + String tmp; + + St_init(&tmp); + for (St_num(&tmp, i = 1); + ve_findnext(&Venus, &tmp, 0); + St_num(&tmp, ++i)) + ; + fprintf(io_fp(Out), "(%s)", St_ptr(&tmp)); + St_clear(&tmp); + break; + } + case F_INT: io_write_m(Out, "INT", 3); break; + case F_IO: io_write_m(Out, "IO-P", 4); break; + case F_LENGTH: io_write_m(Out, "LENGTH", 6); break; + case F_LOG10: io_write_m(Out, "LG", 2); break; + case F_LOG: io_write_m(Out, "LN", 2); break; + case F_MOEND: io_write_m(Out, "+", 1); break; + case F_MOSTART: io_write_m(Out, "-", 1); break; + case F_NEG: io_write_m(Out, "NEG", 3); break; + case F_NOT: io_write_m(Out, "NOT", 3); break; + case F_NUM: io_write_m(Out, "NUM", 3); break; + case F_OPEN: io_write_m(Out, "APERS", 5); break; + case F_OPENR: io_write_m(Out, "LAPERS", 6); break; + case F_OPENW: io_write_m(Out, "SAPERS", 6); break; + case F_ORD: io_write_m(Out, "ORD", 3); break; + case F_REMOVE: io_write_m(Out, "REMOVE", 6); break; + case F_RENAME: io_write_m(Out, "RENAEM", 6); break; + case F_REVERSE: io_write_m(Out, "REVERSE", 7); break; + case F_SEEK: io_write_m(Out, "SUCH", 4); break; + case F_SIN: io_write_m(Out, "SIN", 3); break; + case F_SQRT: io_write_m(Out, "SPQR", 4); break; + case F_STR: io_write_m(Out, "STR", 3); break; + case F_TAN: io_write_m(Out, "TAN", 3); break; + case F_TELL: io_write_m(Out, "SAG", 3); break; + case F_TYPEOF: io_write_m(Out, "TYPE OF", 7); break; + default: + NOTREACHED; + break; + } + break; + } + if (e->right->type != unopE || e->op == F_NUL) { + io_write_m(Out, "(", 1); + dump_expr(e->right, 0); + io_write_m(Out, ")", 1); + } else { + io_write_m(Out, " ", 1); + dump_expr(e->right, 0); + } + break; + + case binopE: + dump_expr(e->left.expr, 0); + + if (e->op == B_XMATCH) { + io_write_m(Out, " ?o~ ", 5); + } else { + fprintf(io_fp(Out), "%s%c ", &" "[e->op == B_TAIL], display(e->op)); + } + + if (e->right->type == binopE) { + io_write_m(Out, "(", 1); + dump_expr(e->right, 0); + io_write_m(Out, ")", 1); + } else { + dump_expr(e->right, 0); + } + break; + + case listE: + if (!inlist) { + io_write_m(Out, "#<", 2); + } + if (e->right) { + io_write_m(Out, "(", 1); + dump_expr(e->right, 0); + io_write_m(Out, ")", 1); + if (e->left.expr) { + io_write_m(Out, " ", 1); + dump_expr(e->left.expr, 1); + } + } + if (!inlist) { + io_write_m(Out, "#>", 2); + } + break; + + } +} + +static void dump_op(struct op *op) { + switch (op->type) { + case OP_NOP: + io_write_m(Out, "REM", 3); + break; + + case OP_SET_VAL: + case OP_ASSIGN: + io_write_m(Out, "LET ", 4); + if (op->arh.expr) { + dump_expr(op->arh.expr, 0); + io_write_m(Out, " ", 1); + dump_expr(op->arg, 0); + } else { + io_write_m(Out, "(", 1); + dump_expr(op->arg, 0); + io_write_m(Out, ")", 1); + } + break; + + case OP_CALL: + if (op->arh.op) { + fprintf(io_fp(Out), "%s ", St_ptr(&op->arh.op->txt)); + dump_expr(op->arg, 0); + } else { + io_write_m(Out, "LET () ", 7); + dump_expr(op->arg, 0); + if (op->next) { + io_write_m(Out, "\nEND", 4); + } + } + break; + + case OP_CALL_BACK: + io_write_m(Out, "ABRUF (", 7); + dump_expr(op->arh.expr, 0); + io_write_m(Out, ") ", 2); + dump_expr(op->arg, 0); + break; + + case OP_CALL_DYN: + io_write_m(Out, "ANRUF ", 6); + dump_expr(op->arg, 0); + break; + + case OP_CLOSE: + io_write_m(Out, "CLAUDS ", 7); + dump_expr(op->arg, 0); + break; + + case OP_ELSE: + NOTREACHED; + break; + + case OP_EXIT: + if (op->arg->type == literE && !op->arg->v.val->type) { + io_write_m(Out, "END", 3); + } else { + io_write_m(Out, "END ", 4); + dump_expr(op->arg, 0); + } + break; + + case OP_FI: + NOTREACHED; + break; + + case OP_FLUSH: + io_write_m(Out, "FLUSH ", 6); + dump_expr(op->arg, 0); + break; + + case OP_GOBACK: + io_write_m(Out, "GOFOR ", 6); + dump_expr(op->arg, 0); + break; + + case OP_GOTO: + io_write_m(Out, "GOTO ", 5); + dump_expr(op->arg, 0); + break; + + case OP_HANG: + if (St_ptr(&op->txt)) { + fprintf(io_fp(Out), "NEXT %s", St_ptr(&op->txt)); + } else { + String tmp; + MAKE_LABEL(&tmp, '*'); + fprintf(io_fp(Out), "FOR %s NEXT %s", St_ptr(&tmp), St_ptr(&tmp)); + St_clear(&tmp); + } + break; + + case OP_IF: + if (op->arg->type == unopE && op->arg->op == F_NOT) { + io_write_m(Out, "IF ", 3); + dump_expr(op->arg->right, 0); + } else { + io_write_m(Out, "IF @NOT ", 8); + if (op->arg->type == binopE) { + io_write_m(Out, "(", 1); + dump_expr(op->arg, 0); + io_write_m(Out, ")", 1); + } else { + dump_expr(op->arg, 0); + } + } + + if (op->next) { + fprintf(io_fp(Out), "\n NEXT %s\nFI", St_ptr(&op->next->txt)); + } else { + io_write_m(Out, "\n END\nFI", 9); + } + break; + + case OP_MODIFY: + io_write_m(Out, "LET ", 4); + dump_expr(op->arh.expr, 0); + if (op->arh.expr->op == B_XMATCH) { + io_write_m(Out, " ?o~= ", 6); + } else { + fprintf(io_fp(Out), " %c= ", display(op->arh.expr->op)); + } + dump_expr(op->arg, 0); + break; + + case OP_PRINT: + io_write_m(Out, "WUNT ", 5); + if (op->arh.expr) { + dump_expr(op->arh.expr, 0); + io_write_m(Out, " ", 1); + dump_expr(op->arg, 0); + } else if (op->arg->type != binopE) { + dump_expr(op->arg, 0); + } else { + io_write_m(Out, "(", 1); + dump_expr(op->arg, 0); + io_write_m(Out, ")", 1); + } + break; + + case OP_PUTC: + io_write_m(Out, "SET ", 4); + dump_expr(op->arg, 0); + break; + + case OP_RESET: + io_write_m(Out, "RESET ", 6); + dump_expr(op->arg, 0); + break; + + case OP_RETURN: + io_write_m(Out, "KTHX ", 5); + dump_expr(op->arg, 0); + break; + + case OP_SYSTEM: + io_write_m(Out, "# ", 2); + dump_expr(op->arg, 0); + break; + + case OP_TEMP: + io_write_m(Out, "LEET ", 5); + dump_expr(op->arh.expr, 0); + io_write_m(Out, " ", 1); + dump_expr(op->arg, 0); + break; + + case OP_THROW: + io_write_m(Out, "IACS ", 5); + dump_expr(op->arg, 0); + break; + + default: + NOTREACHED; + break; + } +} + +static struct { + size_t length; + size_t size; + struct op **ops; +} seen; + +#define PUSH_SEEN(p) do { \ + if (seen.length >= seen.size) { \ + seen.ops = xrealloc(seen.ops, seen.size *= 2); \ + } \ + seen.ops[seen.length++] = (p); \ +} while (0) + +static int walk(const struct expr *e) { + for (;;) { + switch (e->type) { + case literE: + case symbolE: + return 0; + + case varE: + return 0; + + case varhashE: + e = e->right; + continue; + + case unopE: + if (e->op == F_NUL) { + return 1; + } else if (e->op == F_CALL && !St_ptr(&e->left.op->txt)) { + MAKE_LABEL(&e->left.op->txt, 'f'); + PUSH_SEEN(e->left.op); + } + e = e->right; + continue; + + case binopE: + return walk(e->left.expr) | walk(e->right); + + case listE: + return e->right && (walk(e->right) | (e->left.expr && walk(e->left.expr))); + } + } +} + +static void do_stuff(struct op *op) { + for (; op && !op->line; op = op->next) { + op->line = 1; + + if (St_ptr(&op->txt)) { + fprintf(io_fp(Out), "FOR %s ", St_ptr(&op->txt)); + if (op->type != OP_NOP) { + dump_op(op); + } else { + io_write_m(Out, "REM", 4); + } + io_write_m(Out, "\n", 1); + } else { + dump_op(op); + #if 0 + if (op->type != OP_NOP) + #endif + io_write_m(Out, "\n", 1); + } + + if (op->type == OP_IF) { + if (op->arh.op) { + if (op->arh.op->line) { + fprintf(io_fp(Out), "NEXT %s\n", St_ptr(&op->arh.op->txt)); + } else { + do_stuff(op->arh.op); + } + } + } else if (op->type == OP_CALL) { + if (op->arh.op && !op->arh.op->line) { + PUSH_SEEN(op->arh.op); + } + } else if (op->type == OP_HANG) { + return; + } + + if (op->next) { + if (op->next->line && op->type != OP_IF && op->type != OP_RETURN) { + fprintf(io_fp(Out), "NEXT %s\n", St_ptr(&op->next->txt)); + } + } else if ( + op->type != OP_EXIT && + op->type != OP_CALL && + op->type != OP_CALL_BACK && + op->type != OP_CALL_DYN && + op->type != OP_HANG && + op->type != OP_RETURN + ) { + io_write_m(Out, "END\n", 4); + } + } +} + +enum {MAGIC = 23}; +void deparse(const struct text *t) { + size_t i; + int computed_jumps; + + computed_jumps = 0; + seen.ops = xmalloc(seen.size = MAGIC, sizeof *seen.ops); + seen.length = 0; + + for (i = 0; i < t->length; ++i) { + struct op *op = t->start[i]; + + op->line = 0; + + if ( + op->type == OP_GOBACK || + op->type == OP_GOTO || + op->type == OP_CALL_DYN + ) { + walk(op->arg); + computed_jumps |= 1; + } else if (op->type == OP_CALL_BACK) { + walk(op->arh.expr); + walk(op->arg); + computed_jumps |= 1; + } else if (OP_1ARG_P(op->type)) { + computed_jumps |= walk(op->arg); + if (op->type == OP_CALL && op->arh.op) { + if (!St_ptr(&op->arh.op->txt)) { + MAKE_LABEL(&op->arh.op->txt, 'c'); + } + } + } else if (OP_2ARG_P(op->type)) { + if (op->arh.expr) { + computed_jumps |= walk(op->arh.expr); + } + computed_jumps |= walk(op->arg); + } + + if ( + op->next && + (op->next != t->start[i + 1] || op->type == OP_CALL) && + !St_ptr(&op->next->txt) + ) { + MAKE_LABEL(&op->next->txt, 'x'); + } + } + + if (!computed_jumps) { + do_stuff(t->start[0]); + for (i = 0; i < seen.length; ++i) { + do_stuff(seen.ops[i]); + } + } else { + for (i = 0; i < t->length; ++i) { + struct op *op = t->start[i]; + const String *tmp; + + if ((tmp = ve_label(&Venus, op))) { + if (St_ptr(&op->txt)) { + fprintf(io_fp(Out), " FOR %s\n", St_ptr(&op->txt)); + } + fprintf(io_fp(Out), "%s%s", St_ptr(tmp), &" "[!St_len(tmp)]); + } else { + if (St_ptr(&op->txt)) { + fprintf(io_fp(Out), "FOR %s ", St_ptr(&op->txt)); + } + } + + dump_op(op); + io_write_m(Out, "\n", 1); + + if (op->next && op->next != t->start[i + 1] && op->type != OP_IF) { + fprintf(io_fp(Out), "NEXT %s\n", St_ptr(&op->next->txt)); + } + } + } + xfree(seen.ops); +}