/* linked-list symbol table */ #include #include #include #include "ss.h" #include "parse.h" /*** default symbol format ***/ const char *symbol_format = "%g"; /*** head and tail of the symbol table ***/ static Symbol *chead = NULL, *head = NULL, *tail = NULL; /* chead -> constants -> ... (head) -> variables -> ... */ /*** internal functions: new_name, new_symbol ***/ /* create unique names for unnamed "" symbols */ static char *new_name( void) { static int n = 0; static char buf[32]; ++n; sprintf( buf, "$%d", n); return estrdup( buf); } /* allocate new symbol, exit if malloc fails */ static Symbol *new_symbol( const char *name, int constant, double val) { Symbol *e = malloc( sizeof( Symbol) ); if( e == NULL) { yyerror( "new_symbol: malloc failed"); exit(1); } e->name = *name ? name : new_name(); e->constant = constant; e->val = val; e->state = constant ? EVALUATED : UNEVALUATED; e->hide = 0; e->format = NULL; e->depend = NULL; e->n = NULL; e->next = NULL; return e; } /* install constant in symbol table */ void install_constant( const char *name, double val, const char *fmt) { Symbol *e = new_symbol( name, 1, val); e->format = fmt; if( chead == NULL) { chead = tail = e; } else { tail->next = e; tail = e; } } /* try to find name in symbol table */ Symbol *find_symbol( const char *name) { Symbol *e; for( e = chead; e; e = e->next) if( strcmp( e->name, name) == 0) return e; return NULL; } /* lookup name in symbol table, install if not found */ Symbol *lookup_symbol( const char *name) { Symbol *e; if( *name && (e = find_symbol( name)) ) return e; e = new_symbol( name, 0, 0.0); /* chead and tail are not NULL since constants were installed at startup */ tail->next = e; tail = e; if( head == NULL) head = tail; return e; } /* install formula in symbol table */ void install_symbol( Symbol *e, Node *n) { if( e->constant) { fprintf( out, "warning: can not change constant %s = ", e->name); fprintf( out, e->format ? e->format : symbol_format, e->val); fprintf( out, "\n"); return; } if( e->n) fprintf( out, "warning: overwriting symbol %s\n", e->name); if( n->type == NUMBER) { e->val = n->u.val; e->state = EVALUATED; e->n = NULL; } else { e->n = n; if( n->type == STRING) { e->state = EVALUATED; } else { install_tree( n, &cell_00, 1); e->state = UNEVALUATED; } } } /* evaluate the symbol table - called only from ss_eval() */ int eval_symbols( void) { Symbol *e; double oldval; int changed = 0; for( e = head; e; e = e->next) { if( debug) { fprintf( out, "eval_symbols: %s, state = %d", e->name, e->state); if( e->depend) fprintf( out, " - depends on %s", e->depend->name); else if( !e->n || e->n->type == STRING) fprintf( out, " - constant"); putc( '\n', out); } if( depend) { eval_symbol(e); // sets e->val if necessary } else if( e->n) { oldval = e->val; e->val = eval_tree( e->n, &cell_00); if( oldval != e->val) changed = 1; } } return changed; } /* set non-constant symbol states to UNEVALUATED */ void reset_symbols( void) { Symbol *e; for( e = head; e; e = e->next) if( e->depend || (e->n != NULL && e->n->type != STRING)) e->state = UNEVALUATED; } /* print one symbol */ static void print_symbol( const Symbol *e) { fprintf( out, " %s", e->name); if( e->n) { int t = func[e->n->type]->type; if( *e->name && (!t || !(t & SS_ASGN)) ) fprintf( out, " = "); print_tree( e->n, &cell_00, 0); } fprintf( out, " = "); fprintf( out, e->format ? e->format : symbol_format, e->val); fprintf( out, "\n"); } /* print the symbol table, except for constants */ void print_symbols( void) { Symbol *e; for( e = head; e; e = e->next) if( !e->hide) print_symbol( e); } /* print the symbol table constants */ void print_constants( void) { Symbol *e; fprintf( out, "Constants:\n"); for( e = chead; e != head; e = e->next) { if( !e->hide) { fprintf( out, " %s = ", e->name); fprintf( out, e->format ? e->format : symbol_format, e->val); fprintf( out, "\n"); } } } /* print the symbol table states */ void print_symbol_states( void) { fprintf( out, "States:\n"); for( Symbol *e = chead; e; e = e->next) { if( !e->hide) { if( e->depend) fprintf( out, " %d (%s) %s\n", e->state, e->depend->name, e->name); else fprintf( out, " %d %s\n", e->state, e->name); } } } /* print the symbol table formats */ void print_symbol_formats( void) { Symbol *e; fprintf( out, "Formats:\n"); for( e = chead; e; e = e->next) if( !e->hide) fprintf( out, " %s = %s\n", e->name, e->format ? e->format : symbol_format); } // install formats for a span list, and also free the list // void install_symbol_format( Span_list *sl, const char *fmt) { if( !sl) // install global symbol format { symbol_format = fmt; return; } Span *s = NULL, *t = sl->head; while( t) { switch( t->type) { case ID: t->u.s->format = fmt; break; default: /* shouldn't happen */ fprintf( out, "install_symbol_format: unknown type %d\n", t->type); break; } s = t; t = t->next; free( s); } free( sl); } // install hide/show values for a span list, and also free the list // void install_symbol_hide( Span_list *sl, int val) { if( !sl) // hide or show ALL { for( Symbol *e = chead; e; e = e->next) e->hide = val; return; } Span *s = NULL, *t = sl->head; while( t) { switch( t->type) { case ID: t->u.s->hide = val; break; default: /* shouldn't happen */ fprintf( out, "install_symbol_hide: unknown type %d\n", t->type); break; } s = t; t = t->next; free( s); } free( sl); }