/* Build a human readable string from an expression */ #include "evalint.h" #include #include "support.h" #include #undef strlen /* When to add brackets */ /* It goes thus: in an expression of the form (a op0 b) op (c op1 d) bracket[op][op0] is TRUE if the brackets are necessary round the left expression bracket[op][op1] is TRUE if " " " " " " right " */ static char bracket[opsize][opsize][2] = { { { FALSE, FALSE }, /* a + b */ { FALSE, FALSE }, { FALSE, FALSE }, { FALSE, FALSE }, { FALSE, FALSE } }, { { FALSE, TRUE }, /* a - b */ { FALSE, TRUE }, { FALSE, FALSE }, { FALSE, FALSE }, { FALSE, TRUE } }, { { TRUE, TRUE }, /* a * b */ { TRUE, TRUE }, { FALSE, FALSE }, { FALSE, FALSE }, { FALSE, FALSE } }, { { TRUE, TRUE }, /* a / b */ { TRUE, TRUE }, { FALSE, TRUE }, { FALSE, TRUE }, { FALSE, FALSE } }, { { TRUE, TRUE }, /* a ^ b */ { TRUE, TRUE }, { TRUE, TRUE }, { TRUE, TRUE }, { FALSE, TRUE } } }; static char *namefunc(func) FUNCTION func; { onefunc *f = locate(func); if (f) return(f->functext); else return(NULL); } /* decompile expr into str. len is the length of str */ /* If there is not enough place return 0, otherwise the number of chars used */ static int _decompile(expr, str, len) register value expr; char *str; int len; { switch (expr->type) { case cste: { register int l; char buf[30]; l = strlen(gcvt(expr->cte, 4, buf)); if (l >= len) return(0); strcpy(str, buf); return(l); } case fonc: { char *tmp; register int l, nl; /* Special treatment for -(expression) */ if (expr->fn.func == neg) { int brackets; /* brackets necessary for -(-x) and -(a op b) if necessary for 0 - (a op b) */ brackets = expr->fn.arg->type == fonc && expr->fn.arg->fn.func == neg || expr->fn.arg->type == op && bracket[minus][expr->fn.arg->opr.op][1]; len -= 1 + 2 * brackets; if (len <= 0) return(0); *(str++) = '-'; if (brackets) *(str++) = '('; nl = _decompile(expr->fn.arg, str, len); if (nl == 0) return(0); str += nl; if (brackets) *(str++) = ')'; *str = '\0'; return(nl + 1 + 2 * brackets); } else { tmp = namefunc(expr->fn.func); if (!tmp) return(0); l = strlen(tmp); if (l >= len - 2) return(0); /* no place */ strcpy(str, tmp); *(str += l) = '('; nl = _decompile(expr->fn.arg, ++str, len - l - 2); if (nl == 0) return(0); *(str += nl) = ')'; *++str = '\0'; return(l + nl + 2); } } case var: { register int l; l = strlen(expr->vr.name); if (l >= len) return(0); strcpy(str, expr->vr.name); return(l); } case op: { e_op e_op; register int bracket1, bracket2; register int l1, l2; /* Check for brackets */ e_op = expr->opr.op; bracket1 = expr->opr.arg1->type == op && bracket[e_op][expr->opr.arg1->opr.op][0]; bracket2 = expr->opr.arg2->type == op && bracket[e_op][expr->opr.arg2->opr.op][1]; len -= 2 * bracket1 + 2 * bracket2 + 1; if (len <= 0) return(0); if (bracket1) *str++ = '('; l1 = _decompile(expr->opr.arg1, str, len); if (l1 == 0) return(0); str += l1; len -= l1; if (bracket1) *str++ = ')'; *str++ = "+-*/^"[e_op]; if (bracket2) *str++ = '('; l2 = _decompile(expr->opr.arg2, str, len); if (l2 == 0) return(0); str += l2; if (bracket2) { *str++ = ')'; *str = '\0'; } return(2 * bracket1 + l1 + 1 + 2 * bracket2 + l2); } } } char *decompile(expr, str, len) value expr; char *str; int len; { if (_decompile(expr, str, len) == 0) return(NULL); else return(str); }