home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
-
- This file is part of Oleo, the GNU Spreadsheet.
-
- Oleo 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 2, or (at your option)
- any later version.
-
- Oleo 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 Oleo; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "global.h"
- #include "decompile.h"
- #include "eval.h"
- #include "cell.h"
- #include "io-utils.h"
-
-
-
- struct pr_node
- {
- int tightness;
- int len;
- char string[1];
- };
-
-
- static VOIDSTAR save_decomp;
- static CELLREF decomp_row;
- static CELLREF decomp_col;
-
- /* These #defines are so that we don't have to duplicate code below */
- /* JF: now obsolete, and should be trashed. */
-
- #define F0 a0?"@%s()":"%s()"
- #define F1 a0?"@%s(%s)":"%s(%s)"
- #define F2 a0?"@%s(%s, %s)":"%s(%s, %s)"
- #define F3 a0?"@%s(%s, %s, %s)":"%s(%s, %s, %s)"
- #define F4 a0?"@%s(%s, %s, %s, %s)":"%s(%s, %s, %s, %s)"
- #define FN1 a0?"@%s(%s":"%s(%s"
-
- /* We decompile things with these wierd node-things. It's ugly, but it works.
- */
- #ifdef __STDC__
- static struct pr_node *
- n_alloc (int size, int tightness, char *fmt,...)
- #else
- static struct pr_node *
- n_alloc (size, tightness, fmt, va_alist)
- int size;
- int tightness;
- char *fmt;
- va_dcl
- #endif
- {
- struct pr_node *ret;
- va_list args;
-
- ret = ck_malloc (sizeof (struct pr_node) + size + 1);
- ret->len = size;
- ret->tightness = tightness;
- var_start (args, fmt);
- vsprintf (ret->string, fmt, args);
- va_end (args);
- return ret;
- }
-
- #define n_free(x) free(x)
-
- static struct pr_node *
- byte_decompile (expr)
- unsigned char *expr;
- {
- unsigned char byte;
- double tmp_flt;
- long tmp_lng;
- char *tmp_str;
- struct var *v;
- unsigned long_skp;
- unsigned char save_val;
- unsigned jumpto;
-
- struct pr_node *new = 0;
- int pri;
- int aso;
- char *chr;
-
- static struct pr_node **the_line;
- static int line_alloc;
-
- static struct pr_node **c_node;
- struct function *f;
-
- if (!the_line)
- {
- the_line = (struct pr_node **) ck_malloc (20 * sizeof (struct pr_node *));
- line_alloc = 20;
- c_node = the_line;
- }
-
- #ifdef TEST
- if (!expr)
- panic ("No expression to decompile");
- #endif
- next_byte:
- byte = *expr++;
- if (byte < USR1)
- f = &the_funs[byte];
- else if (byte < SKIP)
- {
- tmp_lng = *expr++;
- f = &usr_funs[byte - USR1][tmp_lng];
- }
- else
- f = &skip_funs[byte - SKIP];
-
- if (f->fn_argn & X_J)
- jumpto = *expr++;
- else if (f->fn_argn & X_JL)
- {
- jumpto = expr[0] + ((unsigned) (expr[1]) << 8);
- expr += 2;
- }
- else
- jumpto = 0;
-
- switch (GET_COMP (f->fn_comptype))
- {
- case C_IF:
- if (expr[jumpto - 2] != SKIP)
- {
- long_skp = 1;
- save_val = expr[jumpto - 3];
- expr[jumpto - 3] = 0;
- }
- else
- {
- long_skp = 0;
- save_val = expr[jumpto - 2];
- expr[jumpto - 2] = 0;
- }
- c_node[0] = byte_decompile (expr);
- c_node++;
-
- if (long_skp)
- {
- expr[jumpto - 3] = save_val;
- expr += jumpto;
- jumpto = expr[-2] + ((unsigned) (expr[-1]) << 8);
- }
- else
- {
- expr[jumpto - 2] = save_val;
- expr += jumpto;
- jumpto = expr[-1];
- }
- save_val = expr[jumpto];
- expr[jumpto] = 0;
- c_node[0] = byte_decompile (expr);
- c_node -= 2;
- expr[jumpto] = save_val;
- expr += jumpto;
- if (byte == IF || byte == IF_L)
- {
- if (c_node[0]->tightness <= 1)
- new = n_alloc (8 + c_node[0]->len + c_node[1]->len + c_node[2]->len,
- 1,
- "(%s) ? %s : %s", c_node[0]->string, c_node[1]->string, c_node[2]->string);
- else
- new = n_alloc (6 + c_node[0]->len + c_node[1]->len + c_node[2]->len,
- 1,
- "%s ? %s : %s", c_node[0]->string, c_node[1]->string, c_node[2]->string);
- }
- else
- new = n_alloc (6 + c_node[0]->len + c_node[1]->len + c_node[2]->len + strlen (f->fn_str),
- 1000,
- F3, f->fn_str, c_node[0]->string, c_node[1]->string, c_node[2]->string);
- n_free (c_node[0]);
- n_free (c_node[1]);
- n_free (c_node[2]);
- break;
-
- case C_ANDOR:
- save_val = expr[jumpto];
- expr[jumpto] = 0;
- c_node[0] = byte_decompile (expr);
- expr[jumpto] = save_val;
- expr += jumpto;
- c_node++;
- if (ISINFIX (f->fn_comptype))
- {
- pri = GET_IN (f->fn_comptype);
- aso = GET_ASO (f->fn_comptype);
- chr = f->fn_str;
- goto do_infix;
- }
- else
- goto do_fn2;
-
- case C_STR:
- tmp_str = backslash_a_string ((char *) expr + jumpto, 1);
- new = n_alloc (strlen (tmp_str) + 1,
- 1000,
- tmp_str);
- break;
-
- case C_CELL:
- {
- int num1, num2;
- char *str;
- CELLREF row, col;
-
- row = GET_ROW (expr);
- col = GET_COL (expr);
- expr += EXP_ADD;
-
- if (a0)
- {
- new = n_alloc (30, 1000, f->fn_str, col_to_str (col), row);
- }
- else
- {
- if (byte & ROWREL)
- {
- num1 = row - decomp_row;
- if (byte & COLREL)
- {
- num2 = col - decomp_col;
- if (row == decomp_row && col == decomp_col)
- str = "rc";
- else if (row == decomp_row)
- {
- str = "rc[%+d]";
- num1 = num2;
- }
- else if (col == decomp_col)
- str = "r[%+d]c";
- else
- str = "r[%+d]c[%+d]";
- }
- else if (row == decomp_row)
- {
- str = "rc%u";
- num1 = num2 = col;
- }
- else
- {
- str = "r[%+d]c%u";
- num2 = col;
- }
- }
- else if (byte & COLREL)
- {
- num1 = row;
- num2 = col - decomp_col;
- if (col == decomp_col)
- str = "r%uc";
- else
- str = "r%uc[%+d]";
- }
- else
- {
- str = "r%uc%u";
- num1 = row;
- num2 = col;
- }
- new = n_alloc (30, 1000, str, num1, num2);
- }
- new->len = strlen (new->string);
- }
- break;
-
- case C_RANGE:
- {
- char tmprbuf[40];
- char tmpcbuf[40];
- struct rng rng;
-
- GET_RNG (expr, &rng);
- expr += EXP_ADD_RNG;
-
- if (a0)
- new = n_alloc (40, 1000, f->fn_str, col_to_str (rng.lc), rng.lr, col_to_str (rng.hc), rng.hr);
- else
- {
- /* Check for special cases */
- if (rng.lr == rng.hr && ((byte & LRREL) ? 1 : 0) == ((byte & HRREL) ? 1 : 0))
- {
- if (byte & LRREL)
- {
- if (rng.lr == decomp_row)
- {
- tmprbuf[0] = 'r';
- tmprbuf[1] = '\0';
- }
- else
- (void) sprintf (tmprbuf, "r[%+d]", rng.lr - decomp_row);
- }
- else
- sprintf (tmprbuf, "r%u", rng.lr);
- }
- else if ((byte & LRREL) && (byte & HRREL))
- {
- int r1, r2, rtmp;
-
- r1 = rng.lr - decomp_row;
- r2 = rng.hr - decomp_row;
- if (r1 < r2)
- rtmp = r1, r1 = r2, r2 = rtmp;
- (void) sprintf (tmprbuf, "r[%+d:%+d]", r1, r2);
- }
- else if ((byte & LRREL))
- (void) sprintf (tmprbuf, "r[%+d]:%u", rng.lr - decomp_row, rng.hr);
- else if (byte & HRREL)
- (void) sprintf (tmprbuf, "r%u:[%+d]", rng.lr, rng.hr - decomp_row);
- else if (rng.lr < rng.hr)
- (void) sprintf (tmprbuf, "r%u:%u", rng.lr, rng.hr);
- else
- (void) sprintf (tmprbuf, "r%u:%u", rng.hr, rng.lr);
-
- if (rng.lc == rng.hc && ((byte & LCREL) ? 1 : 0) == ((byte & HCREL) ? 1 : 0))
- {
- if (byte & LCREL)
- {
- if (rng.lc == decomp_col)
- {
- tmpcbuf[0] = 'c';
- tmpcbuf[1] = '\0';
- }
- else
- sprintf (tmpcbuf, "c[%+d]", rng.lc - decomp_col);
- }
- else
- sprintf (tmpcbuf, "c%u", rng.lc);
- }
- else if ((byte & LCREL) && (byte & HCREL))
- {
- int c1, c2, ctmp;
-
- c1 = rng.lc - decomp_col;
- c2 = rng.hc - decomp_col;
- if (c1 < c2)
- ctmp = c1, c1 = c2, c2 = ctmp;
- (void) sprintf (tmpcbuf, "c[%+d:%+d]", c1, c2);
- }
- else if ((byte & LCREL))
- (void) sprintf (tmpcbuf, "c[%+d]:%u", rng.lc - decomp_col, rng.hc);
- else if (byte & HCREL)
- (void) sprintf (tmpcbuf, "c%u:[%+d]", rng.lc, rng.hc - decomp_col);
- else if (rng.lc < rng.hc)
- (void) sprintf (tmpcbuf, "c%u:%u", rng.lc, rng.hc);
- else
- (void) sprintf (tmpcbuf, "c%u:%u", rng.hc, rng.lc);
-
- new = n_alloc (40, 1000, "%s%s", tmprbuf, tmpcbuf);
- }
- new->len = strlen (new->string);
- }
- break;
-
- case C_CONST:
- new = n_alloc (strlen (f->fn_str) + 1, 1000, f->fn_str);
- break;
-
- case C_FN0:
- case C_FN0X:
- case C_FN0 | C_T:
- new = n_alloc (strlen (f->fn_str) + 3,
- 1000,
- F0,
- f->fn_str);
- break;
-
- case C_FN1:
- --c_node;
- new = n_alloc (c_node[0]->len + strlen (f->fn_str) + 3,
- 1000,
- F1, f->fn_str, c_node[0]->string);
- n_free (*c_node);
- break;
-
- case C_UNA:
- --c_node;
- if (c_node[0]->tightness < 9)
- {
- new = n_alloc (3 + c_node[0]->len,
- 9,
- "%s(%s)", f->fn_str, c_node[0]->string);
- }
- else
- {
- new = n_alloc (1 + c_node[0]->len,
- 9,
- "%s%s", f->fn_str, c_node[0]->string);
- }
- n_free (*c_node);
- break;
-
- case C_INF:
- pri = GET_IN (f->fn_comptype);
- aso = GET_ASO (f->fn_comptype);
- chr = f->fn_str;
-
- do_infix:
- c_node -= 2;
- if (c_node[0]->tightness < pri || (c_node[0]->tightness == pri && aso != 1))
- {
- if (c_node[1]->tightness < pri || (c_node[1]->tightness == pri && aso != -1))
- new = n_alloc (7 + c_node[0]->len + c_node[1]->len,
- pri,
- "(%s) %s (%s)", c_node[0]->string, chr, c_node[1]->string);
- else
- new = n_alloc (5 + c_node[0]->len + c_node[1]->len,
- pri,
- "(%s) %s %s", c_node[0]->string, chr, c_node[1]->string);
- }
- else if (c_node[1]->tightness < pri || (c_node[1]->tightness == pri && aso != -1))
- new = n_alloc (5 + c_node[0]->len + c_node[1]->len,
- pri,
- "%s %s (%s)", c_node[0]->string, chr, c_node[1]->string);
- else
- new = n_alloc (3 + c_node[0]->len + c_node[1]->len,
- pri,
- "%s %s %s", c_node[0]->string, chr, c_node[1]->string);
-
- n_free (c_node[0]);
- n_free (c_node[1]);
- break;
-
- case C_FN2:
- do_fn2:
- c_node -= 2;
- new = n_alloc (c_node[0]->len + c_node[1]->len + strlen (f->fn_str) + 5,
- 1000,
- F2, f->fn_str, c_node[0]->string, c_node[1]->string);
- n_free (c_node[0]);
- n_free (c_node[1]);
- break;
-
- case C_FN3:
- c_node -= 3;
- new = n_alloc (c_node[0]->len + c_node[1]->len + c_node[2]->len + strlen (f->fn_str) + 7,
- 1000,
- F3,
- f->fn_str,
- c_node[0]->string,
- c_node[1]->string,
- c_node[2]->string);
- n_free (c_node[0]);
- n_free (c_node[1]);
- n_free (c_node[2]);
- break;
-
- case C_FNN:
- aso = *expr++;
- c_node -= aso;
-
- if (aso == 1)
- new = n_alloc (3 + c_node[0]->len + strlen (f->fn_str),
- 1000,
- F1, f->fn_str, c_node[0]->string);
- else
- {
- new = n_alloc (2 + c_node[0]->len + strlen (f->fn_str),
- 1000,
- FN1, f->fn_str, c_node[0]->string);
- --aso;
- for (pri = 1; pri < aso; pri++)
- {
- n_free (c_node[0]);
- c_node[0] = new;
- new = n_alloc (2 + new->len + c_node[pri]->len,
- 1000,
- "%s, %s", new->string, c_node[pri]->string);
- }
- n_free (c_node[0]);
- c_node[0] = new;
- new = n_alloc (3 + new->len + c_node[aso]->len,
- 1000,
- "%s, %s)", new->string, c_node[aso]->string);
- }
- n_free (c_node[0]);
- break;
-
- case C_FN4:
- c_node -= 4;
- new = n_alloc (c_node[0]->len + c_node[1]->len + c_node[2]->len + c_node[3]->len + strlen (f->fn_str) + 6,
- 1000,
- F4,
- f->fn_str,
- c_node[0]->string,
- c_node[1]->string,
- c_node[2]->string,
- c_node[3]->string);
- n_free (c_node[0]);
- n_free (c_node[1]);
- n_free (c_node[2]);
- n_free (c_node[3]);
- break;
-
- case C_ERR:
- tmp_str = (char *) expr + jumpto;
- expr++;
- new = n_alloc (strlen (tmp_str) + 1, 1000, tmp_str);
- /* bcopy((VOIDSTAR)expr,(VOIDSTAR)&tmp_str,sizeof(char *));
- expr+=sizeof(char *);
- new=n_alloc(strlen(tmp_str)+1,1000,f->fn_str,tmp_str); */
- break;
-
- case C_FLT:
- bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_flt, sizeof (double));
- expr += sizeof (double);
- new = n_alloc (20, 1000, f->fn_str, tmp_flt);
- new->len = strlen (new->string);
- break;
-
- case C_INT:
- bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_lng, sizeof (long));
- expr += sizeof (long);
- new = n_alloc (20, 1000, f->fn_str, tmp_lng);
- new->len = strlen (new->string);
- break;
-
- case C_VAR:
- bcopy ((VOIDSTAR) expr, (VOIDSTAR) & v, sizeof (struct var *));
- expr += sizeof (struct var *);
- new = n_alloc (strlen (v->var_name) + 1,
- 1000,
- f->fn_str, v->var_name);
- break;
-
-
- default:
- panic ("Bad decompile %d", f->fn_comptype);
- }
- *c_node++ = new;
- if (c_node == &the_line[line_alloc])
- {
- line_alloc *= 2;
- the_line = ck_realloc (the_line, line_alloc * sizeof (struct pr_node *));
- c_node = &the_line[line_alloc / 2];
- }
-
- if (*expr)
- goto next_byte;
-
- /* if(c_node != &the_line[1]) {
- io_error_msg("%d values on decompile stack!",c_node - the_line);
- return the_line[0];
- } */
- new = *--c_node;
- /* free(the_line); */
- return new;
- }
-
- /* Actual entry points to this file */
- /* decomp(row, col, cell) returns a string that can be byte_compiled to create
- cell->formula decomp_free() frees up the allocated string */
- #if __STDC__
- char *
- decomp (CELLREF r, CELLREF c, CELL *cell)
- #else
- char *
- decomp (r, c, cell)
- CELLREF r;
- CELLREF c;
- CELL *cell;
- #endif
- {
- struct pr_node *ret;
- char *str;
- extern char *bname[];
-
- if (!cell)
- return "";
- decomp_row = r;
- decomp_col = c;
- if (cell->cell_formula == 0)
- {
- switch (GET_TYP (cell))
- {
- case 0:
- str = ck_malloc (1);
- str[0] = '\0';
- break;
- case TYP_FLT:
- str = strdup (flt_to_str (cell->cell_flt));
- break;
- case TYP_INT:
- str = ck_malloc (20);
- sprintf (str, "%ld", cell->cell_int);
- break;
- case TYP_STR:
- str = strdup (backslash_a_string (cell->cell_str, 1));
- break;
- case TYP_BOL:
- str = strdup (bname[cell->cell_bol]);
- break;
- case TYP_ERR:
- str = strdup (ename[cell->cell_bol]);
- break;
- default:
- str = 0;
- #ifdef TEST
- panic ("Unknown type %d in decomp", GET_TYP (cell));
- #endif
- }
- save_decomp = (VOIDSTAR) str;
- return str;
- }
- else
- ret = byte_decompile (cell->cell_formula);
- save_decomp = (VOIDSTAR) ret;
- return &(ret->string[0]);
- }
-
- #ifdef __STDC__
- void
- decomp_free (void)
- #else
- void
- decomp_free ()
- #endif
- {
- #ifdef TEST
- if (!save_decomp)
- panic ("No save decomp");
- n_free (save_decomp);
- save_decomp = (VOIDSTAR) 0;
- #else
- n_free (save_decomp);
- #endif
- }
-
- /* This takes a string and returns a backslashed form suitable for printing.
- Iff add_quote is true, it'll add "s at the beginning and end.
- Note that this returns a pointer to a static area that is overwritten with
- each call. . .
- */
- #ifdef __STDC__
- char *
- backslash_a_string (char *string, int add_quote)
- #else
- char *
- backslash_a_string (string, add_quote)
- char *string;
- int add_quote;
- #endif
- {
- char *pf;
- char *pt;
- int ch;
- int size;
- int len;
-
- static char *cbuf;
- static int s_cbuf;
-
- #define ALLOC_PT() \
- len=strlen(pf); \
- size=pf-string; \
- if(s_cbuf<3+size+4*len) { \
- s_cbuf=3+size+4*len; \
- cbuf= (cbuf) ? ck_realloc(cbuf,s_cbuf) : ck_malloc(s_cbuf); \
- } \
- if(size) \
- bcopy(string,cbuf,size); \
- pt=cbuf+size; \
-
-
- pt = 0;
- pf = string;
- if (add_quote)
- {
- ALLOC_PT ()
- * pt++ = '"';
- }
- for (; *pf; pf++)
- {
- ch = *pf;
- if (ch >= ' ' && ch <= '~' && ch != '\\' && (ch != '"' || !add_quote))
- {
- if (pt)
- *pt++ = ch;
- continue;
- }
-
- if (!pt)
- {
- ALLOC_PT ()
- }
- if (ch == '\\')
- {
- *pt++ = '\\';
- *pt++ = '\\';
- }
- else if (ch == '"')
- {
- *pt++ = '\\';
- *pt++ = ch;
- }
- else
- {
- *pt++ = '\\';
- *pt++ = ((ch >> 6) & 0x3) + '0';
- *pt++ = ((ch >> 3) & 0x7) + '0';
- *pt++ = (ch & 0x7) + '0';
- }
- }
- if (add_quote)
- *pt++ = '"';
- if (pt)
- {
- *pt++ = '\0';
- return cbuf;
- }
- return string;
- }
-
- #ifdef TEST
- void
- dbg_print_formula (expr)
- unsigned char *expr;
- {
- unsigned char byte;
- struct function *f;
- double tmp_flt;
- char *tmp_str;
- long tmp_int;
- struct var *v;
- struct rng rng;
- char *buf;
- unsigned jumpto;
- extern char print_buf[];
- extern char *strcpy ();
-
- if (!expr)
- return;
- strcpy (print_buf, "Formula: ");
- buf = print_buf + 9;
- while (*expr)
- {
- byte = *expr++;
-
- if (byte < USR1)
- f = &the_funs[byte];
- else if (byte < SKIP)
- {
- tmp_int = *expr++;
- f = &usr_funs[byte - USR1][tmp_int];
- }
- else
- f = &skip_funs[byte - SKIP];
-
- if (f->fn_argn & X_J)
- jumpto = *expr++;
- else if (f->fn_argn & X_JL)
- {
- jumpto = expr[0] + ((unsigned) (expr[1]) << 8);
- expr += 2;
- }
- else
- jumpto = 0;
-
- switch (GET_COMP (f->fn_comptype))
- {
- case C_IF:
- sprintf (buf, " if%d.%u", byte, jumpto);
- break;
- case C_ANDOR:
- sprintf (buf, " andor%d.%u", byte, jumpto);
- break;
- case C_ERR:
- tmp_str = (char *) (expr + jumpto);
- byte = *expr++;
- sprintf (buf, " err%d.%p(%s)", byte, tmp_str, tmp_str);
- break;
- case C_FLT:
- bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_flt, sizeof (double));
- expr += sizeof (double);
- sprintf (buf, " flt.%.15g", tmp_flt);
- break;
- case C_INT:
- bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_int, sizeof (long));
- expr += sizeof (long);
- sprintf (buf, " int.%ld", tmp_int);
- break;
- case C_STR:
- tmp_str = (char *) (expr + jumpto);
- sprintf (buf, " str.%p.%s", tmp_str, tmp_str);
- break;
- case C_VAR:
- bcopy ((VOIDSTAR) expr, (VOIDSTAR) & v, sizeof (struct var *));
- expr += sizeof (struct var *);
- sprintf (buf, " var.%p.%s", v, v->var_name);
- break;
- case C_CELL:
- sprintf (buf, " ref%d.%u.%u", byte, GET_ROW (expr), GET_COL (expr));
- expr += EXP_ADD;
- break;
- case C_RANGE:
- GET_RNG (expr, &rng);
- sprintf (buf, " rng%d.%u-%u,%u-%u", byte, rng.lr, rng.hr, rng.lc, rng.hc);
- expr += EXP_ADD_RNG;
- break;
- case C_FN0:
- case C_FN0X:
- case C_FN1:
- case C_FN2:
- case C_FN3:
- case C_FN4:
- case C_UNA:
- case C_INF:
- sprintf (buf, " fun%d.%s.%p", byte, f->fn_str, f->fn_fun);
- break;
-
- case C_FNN:
- sprintf (buf, " funn%d.%s.%p.%d", byte, f->fn_str, f->fn_fun, *expr++);
- break;
- case C_CONST:
- sprintf (buf, " const%s", f->fn_str);
- break;
- case C_SKIP:
- sprintf (buf, " skip.%d", jumpto);
- break;
- case 0:
- sprintf (buf, " ???%d", byte);
- break;
- default:
- io_error_msg ("Unknown decompile type %d", f->fn_comptype);
- }
- buf += strlen (buf);
- }
- io_text_line (print_buf);
- }
-
- #endif
-