#include #include #include #include #include "ss.h" #include "parse.h" /* allocate new node, exit if malloc fails */ static Node *new_node( void) { Node *e = malloc( sizeof( Node) ); if( e == NULL) { yyerror( "new_node: malloc failed"); exit(1); } e->next = NULL; /* next only used in expr_list */ return e; } static void lval_type_error( int type) { char msg[100]; sprintf( msg, "lval type %d is not a cell or symbol", type); yyerror( msg); } /* adding new nodes */ Node *add_func( int op, Expr_list *r, Expr_list *e) { int acount, rcount; Node *n = new_node(); n->type = op; if( e) /* set arg count */ { acount = e->count; Right(n) = e->head; free(e); } else { acount = 0; Right(n) = NULL; } if( r) /* set result count */ { if( op == RF_STATS) listify_ranges( r); // stats is a special case rcount = r->count; Left(n) = r->head; free(r); } else { rcount = 0; Left(n) = NULL; } if( func[op]->nargs >= 0 && func[op]->nargs != acount) { char msg[100]; sprintf( msg, "%s takes %d argument%s", func[op]->name, func[op]->nargs, (func[op]->nargs != 1) ? "s" : ""); yyerror( msg); n->type = 0; } if( func[op]->rcount >= 0 && func[op]->rcount < rcount) { char msg[100]; sprintf( msg, "%s returns %d value%s", func[op]->name, func[op]->rcount, (func[op]->rcount != 1) ? "s" : ""); yyerror( msg); n->type = 0; } if( rcount == 0) // function call is NOT of the form: { results... } = func... return n; // function call IS of the form: { results... } = func... // // first let install_tree() fix result types RCCELL, RCRANGE, RCA0RANGE, etc. // Node *lval = Left(n); install_tree( lval, &cell_00, 1); // special case, install symbol or cell // if( rcount == 1 && lval->type != RANGE) { Left(n) = NULL; switch( lval->type) { case ID: install_symbol( lval->u.s, n); break; case CELL: install_cell( lval, n, 1, 1); break; default: /* should not happen */ lval_type_error( lval->type); break; } return n; } // rcount > 1 or lval is a RANGE, install formula in symbol table // Symbol *s = lookup_symbol(""); install_symbol( s, n); // set indirect dependencies // while( lval) { switch( lval->type) { case CELL: if( !check_cell( &lval->u.c)) { SS *cp = &ss[lval->u.c.row][lval->u.c.col]; if( cp->n || cp->depend) { yyerror( "cell already has formula or dependency"); fprintf( out, "add_func: cell "); print_cell( &lval->u.c, &cell_00); putc( '\n', out); } cp->depend = s; cp->used = 1; } break; case ID: if( lval->u.s->n || lval->u.s->depend) { yyerror( "symbol already has formula or dependency"); fprintf( out, "add_func: symbol %s\n", lval->u.s->name); } lval->u.s->depend = s; break; case RANGE: add_range_depend( lval, s); break; default: // should not happen lval_type_error( lval->type); break; } lval = lval->next; } return n; } Node *add_op( int op, Node *left, Node *right) { Node *e = NULL; switch( op) { case X_MM: case X_PP: e = left; break; case MM_X: case PP_X: e = right; break; } if( e && e->type != CELL && e->type != RCCELL && e->type != ID) { yyerror( "can only increment/decrement cell or symbol"); return e; } if( e && e->type == ID && e->u.s->constant) { yyerror( "can not change constant"); return e; } e = new_node(); e->type = op; Left(e) = left; Right(e) = right; return e; } /* ?: node, left contains condition, * right is additional node for middle/right choices */ Node *add_cond( Node *left, Node *middle, Node *right) { Node *e = new_node(); Node *f = new_node(); e->type = '?'; Left(e) = left; Right(e) = f; f->type = ':'; /* this type doesn't matter, it is not used */ Left(f) = middle; Right(f) = right; return e; } Node *add_string( const char *str) { Node *e = new_node(); e->type = STRING; e->u.str = str; return e; } Node *add_number( double val) { Node *e = new_node(); e->type = NUMBER; e->u.val = val; return e; } Node *add_empty( void) { Node *e = new_node(); e->type = EMPTY; return e; } Node *add_cell( const Cell *c, int type) { Node *e = new_node(); e->type = type; e->u.c = *c; return e; } Node *add_range( const Range *r, int type) { Node *e = new_node(); e->type = type; e->u.r = *r; return e; } Node *add_symbol( Symbol *s) { Node *e = new_node(); e->type = ID; e->u.s = s; return e; } Expr_list *new_expr_list( Node *n) { Expr_list *e = malloc( sizeof( Expr_list) ); if( e == NULL) { yyerror( "new_expr_list: malloc failed"); exit(1); } e->head = e->tail = n; e->count = 1; return e; } void append_expr_list( Expr_list *e, Node *n) { e->tail->next = n; e->tail = n; ++e->count; } /* print the parse tree fully parenthesized */ void print_tree( const Node *t, const Cell *ref_cell, int level) { char *lparen = (level > 0) ? "(" : ""; char *rparen = (level > 0) ? ")" : ""; if( t == NULL) return; switch( t->type) { case STRING: fprintf( out, "\"%s\"", t->u.str); break; case NUMBER: fprintf( out, "%g", t->u.val); break; case CELL: switch( print_Format) { case RC: print_cell_RC( &t->u.c); break; case CR: print_cell_CR( &t->u.c); break; default: print_cell( &t->u.c, ref_cell); break; } break; case RANGE: switch( print_Format) { case RC: print_range_RC( &t->u.r); break; case CR: print_range_CR( &t->u.r); break; default: print_range( &t->u.r, ref_cell); break; } break; case ID: fprintf( out, "%s", t->u.s->name); break; /* '?' is a special case */ case '?': fprintf( out, "%s", lparen); print_tree( Left(t), ref_cell, level+1); fprintf( out, " ? "); print_tree( Left(Right(t)), ref_cell, level+1); fprintf( out, " : ("); print_tree( Right(Right(t)), ref_cell, level+1); fprintf( out, ")%s", rparen); break; case EMPTY: /* should not happen */ fprintf( out, "EMPTY"); break; default: /* function */ { int type = func[t->type]->type; if( type & SS_OP) /* operator function */ { fprintf( out, "%s", lparen); if( !(type & SS_ASGN) ) print_tree( Left(t), ref_cell, level+1); fprintf( out, (type & SS_WORD) ? " %s " : "%s", func[t->type]->name); print_tree( Right(t), ref_cell, level+1); fprintf( out, "%s", rparen); } else /* numeric or range function */ { if( Left(t)) { fprintf( out, "{"); print_tree( Left(t), ref_cell, 0); fprintf( out, "} = "); } fprintf( out, "%s(", func[t->type]->name); print_tree( Right(t), ref_cell, level+1); fprintf( out, ")"); } break; } } if( t->next) /* expr list */ { putc( ',', out); print_tree( t->next, ref_cell, level+1); } } /* make cell reference relative */ static void mkrel_cell( Cell *c, const Cell *r) { if( !c->row_fixed) c->row -= r->row; if( !c->col_fixed) c->col -= r->col; } /* traverse tree and make cell references relative * * When invoked from install_range() for: range = { expr_list } * install_list will be 0 to prevent traversal of the expression list, * but subsequent recursive calls below set install_list = 1 so that * function argument lists will be processed. */ void install_tree( Node *t, const Cell *ref_cell, int install_list) { if( t == NULL) return; switch( t->type) { case STRING: case NUMBER: case ID: break; case RCCELL: /* already relative */ t->type = CELL; break; case CELL: check_cell( &t->u.c); mkrel_cell( &t->u.c, ref_cell); break; case RCRANGE: /* already relative */ t->type = RANGE; break; case A0RCRANGE: /* end is already relative */ t->type = RANGE; check_cell( &t->u.r.start); mkrel_cell( &t->u.r.start, ref_cell); break; case RCA0RANGE: /* start is already relative */ t->type = RANGE; check_cell( &t->u.r.end); mkrel_cell( &t->u.r.end, ref_cell); break; case RANGE: check_cell( &t->u.r.start); mkrel_cell( &t->u.r.start, ref_cell); check_cell( &t->u.r.end); mkrel_cell( &t->u.r.end, ref_cell); break; /* '?' is a special case */ case '?': install_tree( Left(t), ref_cell, 1); install_tree( Left(Right(t)), ref_cell, 1); install_tree( Right(Right(t)), ref_cell, 1); break; default: /* function */ if( func[t->type]->type & SS_OP) /* operator function */ { install_tree( Left(t), ref_cell, 1); install_tree( Right(t), ref_cell, 1); } else /* numeric or range function */ { install_tree( Right(t), ref_cell, 1); } break; } if( install_list) install_tree( t->next, ref_cell, 1); } /* dependency evaluation of a symbol */ double eval_symbol( Symbol *e) { double r = 0; if( debug) fprintf( out, "eval_symbol: %s", e->name); if( !depend) { if( debug) fprintf( out, " using current value\n"); r = e->val; } else if( e->state == EVALUATED) { if( debug) fprintf( out, " is EVALUATED\n"); r = e->val; } else if( e->state == INPROGRESS) { if( debug) fprintf( out, " is INPROGRESS\n"); fprintf( out, "eval_symbol: %s has a cyclic dependency\n", e->name); } else // UNEVALUATED { if( debug) fprintf( out, " is UNEVALUATED\n"); e->state = INPROGRESS; if( e->depend) { eval_symbol( e->depend); // indirectly sets e->val r = e->val; } else { r = e->val = eval_tree( e->n, &cell_00); } e->state = evaluated; // EVALUATED, or UNEVALUATED if called from rf/search.c } return r; } /* dependency evaluation of a cell */ double eval_cell( SS *cp, const Cell *c) { double r = 0; if( debug) { fprintf( out, "eval_cell: "); print_cell( c, &cell_00); } if( !depend) { if( debug) fprintf( out, " using current value\n"); r = cp->val; } else if( cp->state == EVALUATED) { if( debug) fprintf( out, " is EVALUATED\n"); r = cp->val; } else if( cp->state == INPROGRESS) { if( debug) fprintf( out, " is INPROGRESS\n"); fprintf( out, "eval_cell: "); print_cell( c, &cell_00); fprintf( out, " has a cyclic dependency\n"); } else // UNEVALUATED { if( debug) fprintf( out, " is UNEVALUATED\n"); cp->state = INPROGRESS; if( cp->depend) { eval_symbol( cp->depend); // indirectly sets cp->val r = cp->val; } else { r = cp->val = eval_tree( cp->n, c); } cp->state = evaluated; // EVALUATED, or UNEVALUATED if called from rf/search.c } return r; } /* evaluate tree */ double eval_tree( const Node *t, const Cell *ref_cell) { Cell c; double r = 0; if( t == NULL) return r; switch( t->type) { case STRING: break; case NUMBER: r = t->u.val; break; case ID: r = eval_symbol( t->u.s); break; case CELL: c = t->u.c; adjust_cell( &c, ref_cell); if( !check_cell( &c) ) { SS *cp = &ss[c.row][c.col]; r = eval_cell( cp, &c); } break; case RANGE: /* should not happen */ fprintf( out, "eval_tree: got RANGE! "); print_range( &t->u.r, ref_cell); putc( '\n', out); break; default: /* function */ r = func[t->type]->f( t, ref_cell); break; } return r; }