home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1990 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 1, 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 "funcdef.h"
- #include "sysdef.h"
-
- #include "global.h"
- #include "eval.h"
- #include "cell.h"
-
- struct pr_node {
- int tightness;
- int len;
- char string[1];
- };
-
- char *backslash_a_string EXT2(char *, int);
-
- 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 */
- #ifdef A0_REFS
- #define F0 "@%s()"
- #define F1 "@%s(%s)"
- #define F2 "@%s(%s,%s)"
- #define F3 "@%s(%s,%s,%s)"
- #define F4 "@%s(%s,%s,%s,%s)"
- #define FN1 "@%s(%s"
- #else
- #define F0 "%s()"
- #define F1 "%s(%s)"
- #define F2 "%s(%s,%s)"
- #define F3 "%s(%s,%s,%s)"
- #define F4 "%s(%s,%s,%s,%s)"
- #define FN1 "%s(%s"
- #endif
-
- /* We decompile things with these wierd node-things. It's ugly, but it works.
- */
- static struct pr_node *
- n_alloc FUN3N(int, size, int, tightness, char *, fmt)
- {
- 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 FUN1(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;
- }
- #ifdef TEST
- else
- jumpto=0;
- #endif
- 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:
- {
- #ifndef A0_REFS
- int num1,num2;
- char *str;
- #endif
- CELLREF row,col;
-
- row=GET_ROW(expr);
- col=GET_COL(expr);
- expr+=EXP_ADD;
-
- #ifdef A0_REFS
- 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=f->fn_str;
- } else if(row==decomp_row) {
- str="rc%u";
- num1=num2=col;
- } else {
- str=f->fn_str;
- num2=col;
- }
- } else if(byte&COLREL) {
- num1=row;
- num2=col-decomp_col;
- if(col==decomp_col)
- str="r%uc";
- else
- str=f->fn_str;
- } else {
- str=f->fn_str;
- num1=row;
- num2=col;
- }
- new=n_alloc(30,1000,str,num1,num2);
- #endif
- new->len=strlen(new->string);
- }
- break;
-
- case C_RANGE:
- {
- #ifndef A0_REFS
- char tmprbuf[40];
- char tmpcbuf[40];
- #endif
- struct rng rng;
-
- GET_RNG(expr,&rng);
- expr+=EXP_ADD_RNG;
-
- #ifdef A0_REFS
- 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);
- #endif
- 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]) {
- 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 */
- char *
- decomp FUN3(CELLREF, r, CELLREF, c, CELL *, cell)
- {
- struct pr_node *ret;
- char *str;
- extern char *bname[];
- extern char *strdup EXT1(const char *);
- extern char *flt_to_str EXT1(double);
-
- 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;
- #ifdef TEST
- default:
- str=0;
- 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]);
- }
-
- void
- decomp_free FUN0()
- {
- #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. . .
- */
- char *
- backslash_a_string FUN2(char *,string, int,add_quote)
- {
- 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 FUN1(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-1),GET_COL(expr-1));
- 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:
- error_msg("Unknown decompile type %d",f->fn_comptype);
- }
- buf+=strlen(buf);
- }
- text_line(print_buf);
- }
-
- #endif
-