sources-request@munnari.UUCP (02/28/87)
Submitted by: Alan Kent <ajk@goanna.oz.au> Mod.sources: Volume 8, Issue 82 Archive-name: graph+/Part02 #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting test in a file # 3. Execute the file with /bin/sh (not csh) to create the files: # # abort.c # adjacent.c # appendtb.c # attrnode.c # average.c # count.c # cpyentry.c # cpytable.c # cumulate.c # dumpgrph.c # eval.c # evaltab.c # freetab.c # fundeclr.c # # Created by ajk on Wed Feb 25 09:24:11 EST 1987 # if test -f 'abort.c' then echo shar: will not over-write existing file "'abort.c'" else echo extracting "'abort.c'" sed 's/^X//' >abort.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X Xextern int linenum; Xextern char *infilename; Xextern int warnings; X X X Xabort ( mesg , parm ) Xchar *mesg , *parm; X{ X fprintf ( stderr , "%s: near line %d: " , infilename , linenum ); X fprintf ( stderr , mesg , parm ); X fprintf ( stderr , "\n" ); X while ( yyinput () > 0 ); /* read until EOF */ X exit ( 1 ); X} X X Xwarn ( mesg , parm ) Xchar *mesg , *parm; X{ X if ( warnings ) { X fprintf ( stderr , "%s: warning near line %d: " , infilename , linenum ); X fprintf ( stderr , mesg , parm ); X fprintf ( stderr , "\n" ); X } X} X SHAR_EOF if test 850 -ne "`wc -c < 'abort.c'`" then echo shar: error transmitting "'abort.c'" '(should have been 850 characters)' fi fi if test -f 'adjacent.c' then echo shar: will not over-write existing file "'adjacent.c'" else echo extracting "'adjacent.c'" sed 's/^X//' >adjacent.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include "graph.h" X X Xtable_st * Xadjacent ( tab1 , tab2 ) Xtable_st *tab1 , *tab2; X{ X table_st *p; X table_st *final; X X if ( tab1 == NULL ) { X final = tab2; X } X else if ( tab2 == NULL ) { X final = tab1; X } X else { X if ( tab1->size != tab2->size ) { X abort ( "ADJACENT: Cannot join tables of different length" ); X } X else { X for ( p = tab1; p->next != NULL; p = p->next ); X p->next = tab2; X final = tab1; X } X } X return ( final ); X} SHAR_EOF if test 785 -ne "`wc -c < 'adjacent.c'`" then echo shar: error transmitting "'adjacent.c'" '(should have been 785 characters)' fi fi if test -f 'appendtb.c' then echo shar: will not over-write existing file "'appendtb.c'" else echo extracting "'appendtb.c'" sed 's/^X//' >appendtb.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include "graph.h" X X Xextern table_st *new_table (); X X Xtable_st * Xappend_tables ( tab1 , tab2 ) Xtable_st *tab1 , *tab2; X{ X register table_st *p1 , *p2; X table_st *newtab; X int count; X int i; X X X if ( tab1 == NULL ) X return ( tab2 ); X if ( tab2 == NULL ) X return ( tab1 ); X p1 = tab1; X p2 = tab2; X count = 0; X while ( p1 != NULL && p2 != NULL ) { X p1 = p1->next; X p2 = p2->next; X count++; X } X if ( p1 != NULL || p2 != NULL ) X abort ( "Tables must be of same width to append them" ); X newtab = new_table ( count , tab1->size + tab2->size ); X for ( p1 = tab1, p2 = newtab; p1 != NULL; p1 = p1->next, p2 = p2->next ) X for ( i = 0; i < tab1->size; i++ ) X p2->data[i] = p1->data[i]; X for ( p1 = tab2, p2 = newtab; p1 != NULL; p1 = p1->next, p2 = p2->next ) X for ( i = 0; i < tab2->size; i++ ) X p2->data[i+tab1->size] = p1->data[i]; X free_table ( tab1 ); X free_table ( tab2 ); X return ( newtab ); X} X SHAR_EOF if test 1271 -ne "`wc -c < 'appendtb.c'`" then echo shar: error transmitting "'appendtb.c'" '(should have been 1271 characters)' fi fi if test -f 'attrnode.c' then echo shar: will not over-write existing file "'attrnode.c'" else echo extracting "'attrnode.c'" sed 's/^X//' >attrnode.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include "graph.h" X Xextern char *new (); X X/* create an attribute expression node */ X Xattr_st * Xattr_node ( node_type , value , left , right ) Xint node_type; Xdouble value; Xattr_st *left , *right; X{ X attr_st *p; X X p = (attr_st *) new ( sizeof ( attr_st ) ); X p->node_type = node_type; X p->value = value; X p->left = left; X p->right = right; X return ( p ); X} X SHAR_EOF if test 691 -ne "`wc -c < 'attrnode.c'`" then echo shar: error transmitting "'attrnode.c'" '(should have been 691 characters)' fi fi if test -f 'average.c' then echo shar: will not over-write existing file "'average.c'" else echo extracting "'average.c'" sed 's/^X//' >average.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include "graph.h" X X Xdouble Xaverage_fun ( table , from , to ) Xtable_st *table; Xint from , to; X{ X int i; X double val; X X if ( table == NULL ) X abort ( "AVERAGE requires at least a single column table" ); X if ( table->size < 1 ) { X warn ( "AVERAGE requires at least one value in table " ); X return ( 0.0 ); X } X if ( to >= table->size ) X to = table->size - 1; X val = 0.0; X for ( i = from; i <= to; i++ ) X val += table->data[i]; X return ( val / (double)( to - from + 1 ) ); X} X SHAR_EOF if test 813 -ne "`wc -c < 'average.c'`" then echo shar: error transmitting "'average.c'" '(should have been 813 characters)' fi fi if test -f 'count.c' then echo shar: will not over-write existing file "'count.c'" else echo extracting "'count.c'" sed 's/^X//' >count.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include "graph.h" X X Xdouble Xcount_fun ( table , from , to ) Xtable_st *table; X{ X if ( table == NULL ) X return ( 0.0 ); X if ( to >= table->size ) X to = table->size - 1; X if ( from > to ) X return ( 0.0 ); X return ( (double) to - from + 1 ); X} X SHAR_EOF if test 567 -ne "`wc -c < 'count.c'`" then echo shar: error transmitting "'count.c'" '(should have been 567 characters)' fi fi if test -f 'cpyentry.c' then echo shar: will not over-write existing file "'cpyentry.c'" else echo extracting "'cpyentry.c'" sed 's/^X//' >cpyentry.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include "graph.h" X Xcopy_entry ( table , to , from ) Xtable_st *table; Xint to , from; X{ X table_st *p; X X for ( p = table; p != NULL; p = p->next ) X p->data[to] = p->data[from]; X} X SHAR_EOF if test 498 -ne "`wc -c < 'cpyentry.c'`" then echo shar: error transmitting "'cpyentry.c'" '(should have been 498 characters)' fi fi if test -f 'cpytable.c' then echo shar: will not over-write existing file "'cpytable.c'" else echo extracting "'cpytable.c'" sed 's/^X//' >cpytable.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include "graph.h" X X Xextern table_st *new_table (); X X Xtable_st * Xcopy_of_table ( oldtab ) Xtable_st *oldtab; X{ X int i; X register table_st *table , *ftp , *ttp; X X if ( oldtab == NULL ) X return ( NULL ); X table = new_table ( num_cols ( oldtab ) , oldtab->size ); X ftp = oldtab; X ttp = table; X while ( ftp != NULL ) { X for ( i = 0; i < table->size; i++ ) X ttp->data[i] = ftp->data[i]; X ftp = ftp->next; X ttp = ttp->next; X } X return ( table ); X} SHAR_EOF if test 786 -ne "`wc -c < 'cpytable.c'`" then echo shar: error transmitting "'cpytable.c'" '(should have been 786 characters)' fi fi if test -f 'cumulate.c' then echo shar: will not over-write existing file "'cumulate.c'" else echo extracting "'cumulate.c'" sed 's/^X//' >cumulate.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include <math.h> X#include "graph.h" X#include "y.tab.h" X X X X Xtable_st * Xcumulate ( table , attr ) Xtable_st *table; Xint attr; X{ X double total; X double *data; X int i; X table_st *p; X X total = 0.0; X p = table; X if ( attr < 1 ) X abort ( "Cannot CUMULATE on column $0" ); X while ( --attr > 0 && p != NULL ) X p = p->next; X if ( p == NULL ) X abort ( "Illegal column to CUMULATE by" ); X data = p->data; X for ( i = 0; i < p->size; i++ ) { X total += data[i]; X data[i] = total; X } X return ( table ); X} X SHAR_EOF if test 845 -ne "`wc -c < 'cumulate.c'`" then echo shar: error transmitting "'cumulate.c'" '(should have been 845 characters)' fi fi if test -f 'dumpgrph.c' then echo shar: will not over-write existing file "'dumpgrph.c'" else echo extracting "'dumpgrph.c'" sed 's/^X//' >dumpgrph.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X/* X * WARNING: This file is extremely sensative to changes. X * Making one minor change may break other features. X * This file probably needs to be re-written. X */ X X#include <stdio.h> X#include <math.h> X#include "graph.h" X#include "y.tab.h" X X X#define DEBUG 0 X#define DEBUG_LOG 0 X X X/* this info is for trying to place the text nicely on the screen */ X/* however, unfortunately it is different for all the different plotters! */ X X#ifdef LASER X#define CHAR_WIDTH 48 X#define CHAR_HEIGHT 100 X#else X#define CHAR_WIDTH 80 X#define CHAR_HEIGHT 100 X#endif X X X#define XSPACE 4096 X#define YSPACE 4096 X#define XORIGIN (15*CHAR_WIDTH) X#define YORIGIN 650 X#define XRANGE (XSPACE-XORIGIN) X#define YRANGE (YSPACE-YORIGIN-3*CHAR_HEIGHT) X#define TICK_SIZE 50 X#define TEXT_GAP 400 X X#define TICK_TEXT_GAP 400 /* minimum gap between ticks for log */ X#define TICK_GAP 40 X X#define RAD (XSPACE/200) X X#define LEGEND_LINE_LENGTH 400 X X Xextern double min_fun (); Xextern double max_fun (); Xextern double ceil (); Xextern double pow (); Xextern double log10 (); X X Xextern graph_st graph[]; Xextern int num_graphs; Xextern char *graph_label; Xextern axis_st xaxis; Xextern axis_st yaxis; Xextern int horiz_legend; Xextern int vert_legend; X X X Xstatic double lastx_clip; /* buffered coordinate for clip function */ Xstatic double lasty_clip; X X Xdump_graphs () X{ X int i; X X if ( num_graphs < 1 ) { X fprintf ( stderr , "No graphs to print\n" ); X exit ( 0 ); X } X X if ( xaxis.linear == LOGRITHMIC ) { X for ( i = 0; i < num_graphs; i++ ) X log_tab ( graph[i].table , graph[i].table->next ); X } X X if ( yaxis.linear == LOGRITHMIC ) { X for ( i = 0; i < num_graphs; i++ ) X log_tab ( graph[i].table->next , graph[i].table ); X } X X /* plot(3x) routines */ X openpl (); X erase (); X space ( 0 , 0 , XSPACE , YSPACE ); X X if ( graph_label != NULL ) { X move ( XORIGIN + XRANGE / 2 - strlen ( graph_label ) * CHAR_WIDTH / 2 , X YSPACE - CHAR_HEIGHT ); X label ( graph_label ); X } X X determine_range ( XAXIS , &xaxis ); X determine_range ( YAXIS , &yaxis ); X X axes (); X X dump_legend (); X X for ( i = 0; i < num_graphs; i++ ) X draw_graph ( &graph[i] ); X X /* plot(3x) */ X move ( 0 , 0 ); X closepl (); X} X X X X/* discards values <= 0.0 */ X Xstatic Xlog_tab ( table , othercol ) Xtable_st *table , *othercol; X{ X int i , j; X int warn_count; X X warn_count = 0; X j = 0; X for ( i = 0; i < table->size; i++ ) { X if ( table->data[i] > 0.0 ) { X othercol->data[j] = othercol->data[i]; X table->data[j] = log10 ( table->data[i] ); X j++; X } X else if ( warn_count++ == 0 ) X warn ( "negative or zero data to be plotted logrithmically discarded" ); X } X table->size = j; X othercol->size = j; X} X X X Xstatic Xdraw_graph ( gptr ) Xgraph_st *gptr; X{ X int i , size; X int reseti; X int basex , basey; X double *xdata , *ydata; X double lastx , lasty; X double newx , newy; X X X /* necessary for clip function to work safely */ X X lasty_clip = -1; X lastx_clip = -1; X X /* no data to plot */ X X if ( gptr->table->size < 1 ) X return; X X xdata = gptr->table->data; X ydata = gptr->table->next->data; X size = gptr->table->size; X X /* draw the line (with clipping) */ X X if ( gptr->line_type != NO ) { X set_line ( gptr->line_type ); X lastx = xdata[0]; X lasty = ydata[0]; X /* start from 0 (not 1) so a single point will come out as a dot */ X for ( i = 0; i < size; i++ ) { X newx = xdata[i]; X newy = ydata[i]; X clip_line ( lastx , lasty , newx , newy ); X lastx = newx; X lasty = newy; X } X } X X /* Draw any points along the line */ X X if ( gptr->point_type != 0 ) { X set_line ( SOLID ); X for ( i = 0; i < size; i++ ) { X X basex = lxscale ( xdata[i] ); X basey = lyscale ( ydata[i] ); X X if ( basex >= XORIGIN && basex <= XORIGIN + XRANGE X && basey >= YORIGIN && basey <= YORIGIN + YRANGE ) X X draw_point ( gptr->point_type , basex , basey ); X } X } X X /* output the graph label */ X X set_line ( SOLID ); X if ( gptr->label != NULL ) { X move ( lxscale ( lastx_clip ) , lyscale ( lasty_clip ) ); X /*move ( lxscale ( xdata[size-1] ) , lyscale ( ydata[size-1] ) );*/ X label ( gptr->label ); X } X} X X X Xdraw_point ( point_type , basex , basey ) Xint point_type , basex , basey; X{ X if ( point_type & MSK_TRIANGLE ) { X move ( basex - RAD , basey - RAD * 2 / 3 ); X cont ( basex + RAD , basey - RAD * 2 / 3 ); X cont ( basex , basey + RAD * 4 / 3 ); X cont ( basex - RAD , basey - RAD * 2 / 3 ); X } X X if ( point_type & MSK_CROSS ) { X move ( basex - RAD , basey - RAD ); X cont ( basex + RAD , basey + RAD ); X move ( basex - RAD , basey + RAD ); X cont ( basex + RAD , basey - RAD ); X } X X if ( point_type & MSK_PLUS ) { X move ( basex - RAD , basey - RAD ); X cont ( basex + RAD , basey + RAD ); X move ( basex - RAD , basey + RAD ); X cont ( basex + RAD , basey - RAD ); X } X X if ( point_type & MSK_CIRCLE ) { X circle ( basex , basey , RAD ); X } X X if ( point_type & MSK_SQUARE ) { X /* *4/5 is just to make the shapes appear the same size */ X move ( basex - RAD * 4 / 5 , basey - RAD * 4 / 5 ); X cont ( basex + RAD * 4 / 5 , basey - RAD * 4 / 5 ); X cont ( basex + RAD * 4 / 5 , basey + RAD * 4 / 5 ); X cont ( basex - RAD * 4 / 5 , basey + RAD * 4 / 5 ); X cont ( basex - RAD * 4 / 5 , basey - RAD * 4 / 5 ); X } X} X X Xclip_line ( x1 , y1 , x2 , y2 ) Xdouble x1 , y1 , x2 , y2; X{ X double minx , miny , maxx , maxy; X int mx1 , my1 , mx2 , my2; X double xedge , yedge; X X X minx = xaxis.range.min; X miny = yaxis.range.min; X maxx = xaxis.range.max; X maxy = yaxis.range.max; X X /* determine which sector the end points are in */ X X mx1 = sector ( x1 , minx , maxx ); X my1 = sector ( y1 , miny , maxy ); X mx2 = sector ( x2 , minx , maxx ); X my2 = sector ( y2 , miny , maxy ); X X /* points must not be in same sector and off screen */ X X if ( mx1 * mx2 != 1 && my1 * my2 != 1 ) { X X if ( mx1 != 0 ) { X X /* move point 1 nearer the x-edge of the frame */ X X if ( mx1 == 1 ) X xedge = maxx; X else X xedge = minx; X y1 = y1 + ( y2 - y1 ) * ( xedge - x1 ) / ( x2 - x1 ); X x1 = xedge; X X /* recompute sector to see if point needs another shift */ X X my1 = sector ( y1 , miny , maxy ); X } X X if ( my1 != 0 ) { X X /* move point 1 nearer the y-edge of the frame */ X X if ( my1 == 1 ) X yedge = maxy; X else X yedge = miny; X x1 = x1 + ( x2 - x1 ) * ( yedge - y1 ) / ( y2 - y1 ); X y1 = yedge; X X } X X /* ok, now repeat the above for point 2 */ X X if ( mx2 != 0 ) { X X /* move point 2 nearer the x-edge of the frame */ X X if ( mx2 == 1 ) X xedge = maxx; X else X xedge = minx; X y2 = y2 + ( y1 - y2 ) * ( xedge - x2 ) / ( x1 - x2 ); X x2 = xedge; X X /* recompute sector to see if point needs another shift */ X X my2 = sector ( y2 , miny , maxy ); X } X X if ( my2 != 0 ) { X X /* move point 2 nearer the y-edge of the frame */ X X if ( my2 == 1 ) X yedge = maxy; X else X yedge = miny; X x2 = x2 + ( x1 - x2 ) * ( yedge - y2 ) / ( y1 - y2 ); X y2 = yedge; X X } X X if ( x1 >= minx && x1 <= maxx && x2 >= minx && x2 <= maxx X && y1 >= miny && y1 <= maxy && y2 >= miny && y2 <= maxy ) { X X /* use buffered move and cont calls where possible as some */ X /* plotters do dotted lines better if cont is used for continuous */ X /* lines. Using separate line() calls means the dotted lines */ X /* start again per line */ X X if ( x1 != lastx_clip || y1 != lasty_clip ) X move ( xscale ( x1 ) , yscale ( y1 ) ); X cont ( xscale ( x2 ) , yscale ( y2 ) ); X lastx_clip = x2; X lasty_clip = y2; X } X } X} X X Xstatic int Xsector ( val , min , max ) Xdouble val , min , max; X{ X if ( val < min ) return ( -1 ); X if ( val > max ) return ( 1 ); X return ( 0 ); X} X X Xstatic Xset_line ( type ) Xint type; X{ X switch ( type ) { X case DOTTED : linemod ( "dotted" ); break; X case DOTDASHED : linemod ( "dotdashed" ); break; X case SHORTDASHED : linemod ( "shortdashed" ); break; X case LONGDASHED : linemod ( "longdashed" ); break; X default : linemod ( "solid" ); break; X } X} X X Xstatic int Xxscale ( coord ) Xdouble coord; X{ X double xcoord; X X xcoord = ( ( coord - xaxis.range.min ) X / ( xaxis.range.max - xaxis.range.min ) ) * (double)XRANGE; X return ( (int)xcoord + XORIGIN ); X} X X Xstatic int Xyscale ( coord ) Xdouble coord; X{ X double ycoord; X X ycoord = ( ( coord - yaxis.range.min ) X / ( yaxis.range.max - yaxis.range.min ) ) * (double)YRANGE; X return ( (int)ycoord + YORIGIN ); X} X X Xstatic int Xlxscale ( coord ) Xdouble coord; X{ X int xcoord; X X xcoord = xscale ( coord ); X if ( xcoord < 0 ) X return ( 0 ); X if ( xcoord >= XSPACE ) X return ( XSPACE - 1 ); X return ( xcoord ); X} X X Xstatic int Xlyscale ( coord ) Xdouble coord; X{ X int ycoord; X X ycoord = yscale ( coord ); X if ( ycoord < 0 ) X return ( 0 ); X if ( ycoord >= YSPACE ) X return ( YSPACE - 1 ); X return ( ycoord ); X} X X Xchar * Xchoose_format ( paxis ) Xstruct axis_st *paxis; X{ X double first_log_tick (); X X if ( paxis->linear == LOGRITHMIC ) { X paxis->power_10 = floor ( paxis->range.min ); X paxis->format = "%.0f"; X /* STILL NOT RIGHT X if ( xscale ( first_log_tick ( xaxis.range.min ) ) >= XRANGE + XORIGIN ) X paxis->format = "%.2f"; X */ X } X else if ( paxis->auto_tick_size ) X calc_ticks ( paxis , &paxis->tick_size , &paxis->power_10 ); X X if ( paxis->scale == AUTO X /* && paxis->linear != LOGRITHMIC ???? special scaling ok for log too? */ X && paxis->auto_tick_size ) { X if ( paxis->power_10 == 1.0 X || paxis->power_10 == 2.0 ) { X paxis->format = "%.0f"; X paxis->scale = NO; X } X else if ( paxis->tick_size >= 10.0 ) X paxis->format = "%.0f"; X } X return ( ( paxis->user_format == NULL ) X ? paxis->format : paxis->user_format ); X} X X Xstatic Xaxes () X{ X int xscale (); X int yscale (); X int lxscale (); X int lyscale (); X double first_log_tick (); X double next_log_tick (); X double next_10_tick (); X X int base_x , base_y; X int tick_pos; X int last_tick_pos; X int last_text_pos; X int tick_num; X int loop_count; X int i; X double tick_value; X double base; X double xaxis_min , yaxis_min; X char buf[500]; X char small_buf[2]; X char *p , *beg; X int longest , length , num_lines , line_num; X int print_tick; X int best_log_ticks; X char *xformat , *yformat; X X X xformat = choose_format ( &xaxis ); X yformat = choose_format ( &yaxis ); X X base_x = lxscale ( xaxis.range.min ); X base_y = lyscale ( yaxis.range.min ); X base = 10.0; X set_line ( SOLID ); X X if ( xaxis.frame != NO ) { X X /* First the x-axis */ X X /* draw base line */ X X line ( base_x , base_y , base_x + XRANGE - 1 , base_y ); X X if ( xaxis.frame == OUTLINE ) X line ( base_x , base_y + YRANGE - 1 , base_x + XRANGE - 1 , base_y + YRANGE - 1 ); X X /* Label the axis */ X X if ( xaxis.label != NULL ) { X sprintf ( buf , X ( xaxis.scale != AUTO || xaxis.power_10 == 0.0 ) X ? "%s" : "%s x 10^%d" , X xaxis.label , X (int)xaxis.power_10 ); X move ( base_x + XRANGE / 2 - strlen ( buf ) * CHAR_WIDTH / 2 , X base_y - TEXT_GAP ); X label ( buf ); X/* fprintf(stderr,"xaxis label '%s'\n",buf);*/ X } X X /* Put ticks on the axis */ X X/*fprintf(stderr,"power_10 = %f\n",xaxis.power_10);*/ X tick_num = 0; X loop_count = 0; X last_tick_pos = 0; X last_text_pos = 0; X X if ( xaxis.linear == LOGRITHMIC ) { X xaxis_min = xaxis.range.min; X X#if DEBUG Xfprintf(stderr,"min = %f\n",xaxis.range.min); X#endif X X best_log_ticks = xscale ( first_log_tick ( xaxis.range.min ) ) X < XRANGE + XORIGIN; X best_log_ticks = 1; /* override for now */ X X#if DEBUG_LOG Xfprintf(stderr,"best = %d, xscale(min) = %d\n",best_log_ticks,xscale(first_log_tick(xaxis.range.min))); X#endif X X } X else { X X /* now, round the value off! If we dont do that, min */ X /* values that are strange fractions will cause misleading */ X /* values to be printed (%.1f will round fractions to one */ X /* decimal place which will be totally wrong for a tick size */ X /* of 0.1 */ X X xaxis_min = ceil ( xaxis.range.min X / ( xaxis.tick_size * pow ( base , xaxis.power_10 ) ) ) X * ( xaxis.tick_size * pow ( base , xaxis.power_10 ) ); X#if DEBUG Xfprintf(stderr,"x.min %f, x.tick_size %f, x.power_10 %f , xaxis_min %f\n", Xxaxis.range.min,xaxis.tick_size,xaxis.power_10,xaxis_min); X#endif X } X X while ( 1 ) { X X /* determine value to display next to tick */ X X if ( xaxis.linear == LOGRITHMIC ) { X if ( best_log_ticks ) { X if ( loop_count == 0 ) { X tick_value = first_log_tick ( xaxis.range.min ); X#if DEBUG_LOG Xfprintf(stderr,"min = %f, max = %f, tick = %f\n",xaxis.range.min,xaxis.range.max,tick_value); X#endif X } X else X tick_value = next_log_tick (); X } X else { X tick_value = pow ( 10.0 , xaxis.range.min ) X + (double)tick_num X * ( pow( 10.0 , xaxis.range.max ) X - pow ( 10.0 , xaxis.range.min ) ) / 5.0; X#if DEBUG_LOG Xfprintf(stderr,"tick value is %f\n",tick_value); X#endif X } X } X else { X tick_value = xaxis_min + (double)tick_num X * xaxis.tick_size * pow ( base , xaxis.power_10 ); X } X loop_count++; X X /* determine offset along axis to place tick */ X X if ( xaxis.linear == LOGRITHMIC ) X tick_pos = xscale ( log10 ( tick_value ) ); X else X tick_pos = xscale ( tick_value ); X X /* see if meant to auto scale value */ X X if ( xaxis.scale == AUTO ) X tick_value /= pow ( base , xaxis.power_10 ); X#if DEBUG_LOG Xfprintf(stderr,"scaled tickvalue to %f\n",tick_value); X#endif X X /* run out of axis? */ X X if ( tick_pos > XRANGE + XORIGIN ) X break; X X /* if logrithmic axis, must also check that ticks wont be */ X /* too close together */ X X if ( xaxis.linear == LOGRITHMIC X && tick_pos != xscale ( next_10_tick () - 1.0 ) ) { X /* is tick too close to last tick? */ X if ( tick_pos < last_tick_pos + TICK_GAP ) { X#if DEBUG_LOG Xfprintf(stderr,"tick %d (%d) too close to LAST position\n",tick_num,tick_pos); X#endif X continue; /* try next tick */ X } X /* is tick too close to next 1,10,100,1000 value? */ X if ( tick_pos + TICK_GAP > xscale ( next_10_tick () ) ) { X#if DEBUG_LOG Xfprintf(stderr,"tick %d (%d) too close to NEXT position\n",tick_num,tick_pos); Xfprintf(stderr,"next = %f, xscale(next) = %d\n",next_10_tick (),xscale(next_10_tick())); X#endif X continue; /* try next tick */ X } X last_tick_pos = tick_pos; X } X X /* draw the actual tick */ X X if ( xaxis.frame == GRID ) X line ( tick_pos , base_y + YRANGE - 1 , tick_pos , base_y ); X else X line ( tick_pos , base_y , tick_pos , base_y - TICK_SIZE ); X X /* print the tick value */ X X print_tick = 0; X if ( xaxis.linear != LOGRITHMIC ) X print_tick = 1; X else if ( tick_pos >= last_text_pos + TICK_TEXT_GAP ) { X if ( xscale ( 2.0 ) - xscale ( 1.0 ) <= TICK_TEXT_GAP ) { X if ( tick_pos == xscale ( next_10_tick () - 1.0 ) ) X print_tick = 1; X } X else { X if ( tick_pos + TICK_TEXT_GAP <= xscale ( next_10_tick () ) ) X print_tick = 1; X } X } X#if DEBUG|DEBUG_LOG Xfprintf(stderr,"tick_pos = %d, 2.0-1.0 = %d, print it %d\n", Xtick_pos,xscale(2.0)-xscale(1.0),print_tick); X#endif X X if ( print_tick ) { X sprintf ( buf , xformat , tick_value ); X move ( tick_pos - strlen ( buf ) * CHAR_WIDTH / 2 , X base_y - ( xaxis.frame == GRID ? 2 : 3 ) * TICK_SIZE ); X label ( buf ); X last_text_pos = tick_pos; X#if DEBUG|DEBUG_LOG Xfprintf(stderr,"TICK %d at %d: '%s'\n",tick_num,tick_pos,buf); X#endif X X } X X /* loop until tick position off axis */ X X tick_num++; X if ( tick_num > 100 ) X abort ( "axis tick algorithm failed!!" ); X } X } X X /* Second, the y-axis */ X X if ( yaxis.frame != NO ) { X X /* draw base line */ X X line ( base_x , base_y , base_x , base_y + YRANGE - 1 ); X X if ( yaxis.frame == OUTLINE ) X line ( base_x , base_y + YRANGE - 1 , base_x + XRANGE - 1 , base_y + YRANGE - 1 ); X X /* Label the axis by writing values DOWN the axis */ X X if ( yaxis.label != NULL ) { X sprintf ( buf , X ( yaxis.scale != AUTO || yaxis.power_10 == 0.0 ) X ? "%s" : "%s x~10^%d" , X yaxis.label , X (int)yaxis.power_10 ); X X#ifdef OLD_DOWN_AXIS X for ( i = 0; buf[i] != '\0'; i++ ) { X move ( base_x - TEXT_GAP - 2 * CHAR_WIDTH , base_y + YRANGE / 2 X + strlen ( buf ) * CHAR_HEIGHT / 2 - i * CHAR_HEIGHT ); X small_buf[0] = buf[i]; X small_buf[1] = '\0'; X label ( small_buf ); X } X#else X X /* split label into many lines, each line separated by a space. */ X /* to allow a space to be force, ~ is mapped to a space at the */ X /* last moment. to place the text, each line is centred and */ X /* placed so that the longest line touches the edge of the */ X /* graph. */ X X /* first find longest line and number of lines */ X X longest = 0; X num_lines = 0; X p = buf; X while ( *p != '\0' ) { X num_lines++; X length = 0; X while ( *p != ' ' && *p != '\0' ) { X p++; X length++; X } X if ( *p == ' ' ) X p++; X if ( length > longest ) X longest = length; X } X X /* now print yaxis label by replacing blanks with \0 and */ X /* ~ with blanks and output each line */ X X line_num = 0; X p = buf; X while ( *p != '\0' ) { X beg = p; X length = 0; X while ( *p != '\0' && *p != ' ' ) { X if ( *p == '~' ) X *p = ' '; X length++; X p++; X } X if ( *p == ' ' ) X *p++ = '\0'; X move ( ( longest * CHAR_WIDTH/2 ) - ( length * CHAR_WIDTH/2 ) , X base_y + YRANGE / 2 + num_lines * CHAR_HEIGHT X - line_num * CHAR_HEIGHT * 3 / 2 ); X label ( beg ); X line_num++; X } X X#endif X } X X /* Put ticks on the axis */ X X tick_num = 0; X last_tick_pos = 0; X last_text_pos = 0; X loop_count = 0; X X if ( yaxis.linear == LOGRITHMIC ) { X yaxis_min = yaxis.range.min; X } X else { X X /* now, round the value off! If we dont do that, min */ X /* values that are strange fractions will cause misleading */ X /* values to be printed (%.1f will round fractions to one */ X /* decimal place which will be totally wrong for a tick size */ X /* of 0.1 */ X X yaxis_min = ceil ( yaxis.range.min X / ( yaxis.tick_size * pow ( base , yaxis.power_10 ) ) ) X * ( yaxis.tick_size * pow ( base , yaxis.power_10 ) ); X } X X while ( 1 ) { X X /* determine value to display next to tick */ X X if ( yaxis.linear == LOGRITHMIC ) { X if ( loop_count == 0 ) X tick_value = first_log_tick ( yaxis.range.min ); X else X tick_value = next_log_tick (); X } X else { X tick_value = yaxis_min + (double)tick_num X * yaxis.tick_size * pow ( base , yaxis.power_10 ); X } X loop_count++; X X /* determine offset along axis to place tick */ X X if ( yaxis.linear == LOGRITHMIC ) X tick_pos = yscale ( log10 ( tick_value ) ); X else X tick_pos = yscale ( tick_value ); X X /* see if meant to auto scale value */ X X if ( yaxis.scale == AUTO ) X tick_value /= pow ( base , yaxis.power_10 ); X X /* run out of axis? */ X X if ( tick_pos > YRANGE + YORIGIN ) X break; X X /* if logrithmic axis, must also check that ticks wont be */ X /* too close together */ X X if ( yaxis.linear == LOGRITHMIC X && tick_pos != yscale ( next_10_tick () - 1.0 ) ) { X /* is tick too close to last tick? */ X if ( tick_pos < last_tick_pos + TICK_GAP ) X continue; /* try next tick */ X /* is tick too close to next 1,10,100,1000 value? */ X if ( tick_pos + TICK_GAP > yscale ( next_10_tick () ) ) X continue; /* try next tick */ X last_tick_pos = tick_pos; X } X X /* draw the actual tick */ X X if ( yaxis.frame == GRID ) X line ( base_x + XRANGE - 1 , tick_pos , base_x , tick_pos ); X else X line ( base_x , tick_pos , base_x - TICK_SIZE , tick_pos ); X X /* print the tick value */ X X print_tick = 0; X if ( yaxis.linear != LOGRITHMIC ) X print_tick = 1; X else if ( tick_pos >= last_text_pos + TICK_TEXT_GAP ) { X if ( yscale ( 2.0 ) - yscale ( 1.0 ) <= TICK_TEXT_GAP ) { X if ( tick_pos == yscale ( next_10_tick () - 1.0 ) ) X print_tick = 1; X } X else { X if ( tick_pos + TICK_TEXT_GAP <= yscale ( next_10_tick () ) ) X print_tick = 1; X } X } X X if ( print_tick ) { X sprintf ( buf , yformat , tick_value ); X move ( base_x - strlen ( buf ) * CHAR_WIDTH X - ( yaxis.frame == GRID ? 1 : 2 ) * TICK_SIZE , X tick_pos - CHAR_WIDTH / 2 ); X label ( buf ); X last_text_pos = tick_pos; X } X X /* loop until tick position off axis */ X X tick_num++; X if ( tick_num > 100 ) X abort ( "axis tick algorithm failed!!" ); X } X } X} X X Xstatic Xdetermine_range ( which , paxis ) Xint which; Xaxis_st *paxis; X{ X double floor () , log10 () , pow (); X int i; X double best_min , best_max; X double new_min , new_max; X double round_max; X table_st *table; X X X /* only automatically calculate range if no range has been specified */ X /* (This is indicated by the min value being greater than the max value) */ X X if ( paxis->range.min >= paxis->range.max ) { X X /* scan through all the graphs and determine the largest and */ X /* smallest value. */ X X if ( which == XAXIS ) X table = graph[0].table; X else X table = graph[0].table->next; X best_min = min_fun ( table , 0 , table->size - 1 ); X best_max = max_fun ( table , 0 , table->size - 1 ); X for ( i = 1; i < num_graphs; i++ ) { X if ( which == XAXIS ) X table = graph[i].table; X else X table = graph[i].table->next; X new_min = min_fun ( table , 0 , table->size - 1 ); X new_max = max_fun ( table , 0 , table->size - 1 ); X if ( new_min < best_min ) X best_min = new_min; X if ( new_max > best_max ) X best_max = new_max; X } X X /* check for zero height graph */ X X if ( best_min == best_max ) { X X /* give the graph some height */ X X if ( best_min == 0.0 ) { X best_min = -1.0; X best_max = 1.0; X } X else if ( best_min > 0.0 ) { X if ( paxis->linear == LOGRITHMIC ) X best_min = best_min / 2.0; X else X best_min = 0; X best_max = 2.0 * best_max; X } X else { X best_min = best_min * 0.9; X best_max = best_max * 1.1; X } X } X X /* make min a nice round value (eg: 4-1000 => 0-1000) */ X X if ( best_max > 0.0 ) { X round_max = pow ( (double)10.0 , floor ( log10 ( best_max / 3.0 ) ) ); X if ( round_max > 0.0 ) X best_min = floor ( best_min / round_max ) * round_max * 0.999; X } X /* X if ( paxis->linear != LOGRITHMIC ) { X if ( best_max > 0.0 ) { X round_max = pow ( (double)10.0 , floor ( log10 ( best_max ) ) ); X best_min = floor ( best_min / round_max ) * round_max; X } X } X else { X if ( best_max > 1.0 ) { X round_max = pow ( (double)10.0 , floor ( log10 ( best_max ) ) ); X best_min = floor ( best_min / round_max ) * round_max; X } X } X */ X#if 0 X /* to stop 0->infinity graphs from hanging the program */ X if ( paxis->linear == LOGRITHMIC ) { X if ( best_min < best_max / 5.0 ) X best_min = best_max / 5.0; X /* remember, this is 10^5.0 */ X } X#endif X paxis->range.min = best_min; X paxis->range.max = best_max; X } X else if ( paxis->linear == LOGRITHMIC ) { X X /* convert values to actual values */ X X if ( paxis->range.min <= 0.0 ) X abort ( "Minimum value for axis on log graph is <= 0" ); X paxis->range.min = log10 ( paxis->range.min ); X paxis->range.max = log10 ( paxis->range.max ); X } X} X X X Xstatic Xcalc_ticks ( paxis , tick , power ) Xaxis_st *paxis; Xdouble *tick , *power; X{ X double log10 (); X double base , delta; X int power_of_10; X double tick_size; X X base = 10.0; X delta = paxis->range.max - paxis->range.min; X power_of_10 = (int) floor ( log10 ( delta ) ); X tick_size = delta / pow ( base , (double)(power_of_10+1) ); X if ( tick_size <= 0.5 ) { X tick_size = ceil ( (double)( tick_size * 10.0 ) ) / (double)10.0; X } X else { X tick_size = 0.1; X power_of_10++; X } X X /* round tick size off to x10 ^3,6,9,12,.... which people understand */ X switch ( power_of_10 % 3 ) { X case 0 : /* already mult of 3 */ X break; X case 1 : /* its just too high (by one) */ X tick_size *= 10.0; X power_of_10--; X break; X case 2 : /* its just too low (by one) */ X /* X tick_size /= 10.0; X power_of_10++; X */ X tick_size *= 100.0; X power_of_10 -= 2; X break; X } X X *tick = tick_size; X *power = (double)power_of_10; X} X X X Xstatic int lt_value; Xstatic int lt_power; X X Xstatic double Xfirst_log_tick ( value ) Xdouble value; X{ X double actual; X double ret_val; X X actual = pow ( (double)10.0 , value ); X lt_power = (int) floor ( log10 ( actual ) ); X lt_value = (int) ceil ( actual / pow ( (double)10.0 , (double)lt_power ) ); X while ( lt_value >= 10 ) { X lt_value /= 10; X lt_power++; X } X ret_val = (double)lt_value * pow ( (double)10.0 , (double)lt_power ); X/*fprintf(stderr,"first_log_tick: lt_power = %d, lt_value = %d, ret_val = %f\n",lt_power,lt_value,ret_val);*/ X return ( ret_val ); X} X X Xstatic double Xnext_log_tick () X{ X lt_value++; X while ( lt_value >= 10 ) { X lt_value /= 10; X lt_power++; X } X return ( (double)lt_value * pow ( (double)10.0 , (double)lt_power ) ); X} X X Xstatic double Xnext_10_tick () X{ X return ( (double)( lt_power + 1 ) ); X} X X Xstatic Xdump_legend () X{ X int i; X int num_lines; X int longest; X int basex , basey; X X X /* first determine how much is going to be output, and what is the */ X /* longest string that is to be output */ X X num_lines = 0; X longest = 0; X for ( i = 0; i < num_graphs; i++ ) { X if ( graph[i].legend != NULL ) { X num_lines++; X if ( strlen ( graph[i].legend ) > longest ) X longest = strlen ( graph[i].legend ); X } X } X X /* ok, now we want to work out where to start outputing the legend */ X X switch ( horiz_legend ) { X X case LEFT : X basex = XORIGIN + CHAR_WIDTH * 3; X break; X X case CENTER : X basex = XORIGIN + XRANGE / 2 - ( longest * CHAR_WIDTH - LEGEND_LINE_LENGTH ) / 2; X break; X X case RIGHT : X basex = XORIGIN + XRANGE - longest * CHAR_WIDTH - 3 * CHAR_WIDTH - LEGEND_LINE_LENGTH - CHAR_WIDTH; X break; X } X X switch ( vert_legend ) { X X case TOP : X basey = YORIGIN + YRANGE - CHAR_HEIGHT * 2; X break; X X case MIDDLE : X basey = YORIGIN + YRANGE / 2 + num_lines * CHAR_HEIGHT / 2; X break; X X case BOTTOM : X basey = YORIGIN + CHAR_HEIGHT * 1 + num_lines * CHAR_HEIGHT; X break; X } X X /* ok, now loop through and acutally output the legend! */ X X for ( i = 0; i < num_graphs; i++ ) { X if ( graph[i].legend != NULL ) { X if ( graph[i].line_type != NO ) { X set_line ( graph[i].line_type ); X line ( basex , basey , basex + LEGEND_LINE_LENGTH , basey ); X } X set_line ( SOLID ); X draw_point ( graph[i].point_type , basex + LEGEND_LINE_LENGTH / 2 , basey ); X move ( basex + LEGEND_LINE_LENGTH + CHAR_WIDTH , basey - CHAR_HEIGHT / 3 ); X label ( graph[i].legend ); X basey -= CHAR_HEIGHT; X } X } X} SHAR_EOF if test 27046 -ne "`wc -c < 'dumpgrph.c'`" then echo shar: error transmitting "'dumpgrph.c'" '(should have been 27046 characters)' fi fi if test -f 'eval.c' then echo shar: will not over-write existing file "'eval.c'" else echo extracting "'eval.c'" sed 's/^X//' >eval.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include <math.h> X#include "graph.h" X#include "y.tab.h" X X Xextern double var_lookup (); Xextern double call_var_fun (); X X X/* evaluate an expression tree */ X Xdouble Xeval ( table , row , expr ) Xregister table_st *table; Xregister int row; Xregister attr_st *expr; X{ X register table_st *tp; X register int i; X int intval; X double value; X double val1 , val2; X X X if ( expr == NULL ) X return ( 0.0 ); X X switch ( expr->node_type ) { X X case PLUS : X value = eval ( table , row , expr->left ) X + eval ( table , row , expr->right ); X break; X X case MINUS : X value = ( eval ( table , row , expr->left ) X - eval ( table , row , expr->right ) ); X break; X X case MULTIPLY : X value = ( eval ( table , row , expr->left ) X * eval ( table , row , expr->right ) ); X break; X X case DIVIDE : X val1 = eval ( table , row , expr->left ); X val2 = eval ( table , row , expr->right ); X if ( val2 == 0.0 ) { X value = HUGE; X warn ( "division by zero error" ); X } X else X value = val1 / val2; X break; X X case MODULUS : X val1 = eval ( table , row , expr->left ); X val2 = eval ( table , row , expr->right ); X if ( val2 == 0.0 ) { X value = 0.0; X warn ( "modulus by zero error" ); X } X else { X while ( val1 > val2 ) /* % does not work with float's */ X val1 -= val2; X while ( val1 < 0.0 ) X val1 += val2; X value = val1; X } X break; X X case LE : X value = ( eval ( table , row , expr->left ) X <= eval ( table , row , expr->right ) ); X break; X X case LT : X value = ( eval ( table , row , expr->left ) X < eval ( table , row , expr->right ) ); X break; X X case GE : X value = ( eval ( table , row , expr->left ) X >= eval ( table , row , expr->right ) ); X break; X X case GT : X value = ( eval ( table , row , expr->left ) X > eval ( table , row , expr->right ) ); X break; X X case EQ : X value = ( eval ( table , row , expr->left ) X == eval ( table , row , expr->right ) ); X break; X X case NE : X value = ( eval ( table , row , expr->left ) X != eval ( table , row , expr->right ) ); X break; X X case QUEST : X value = ( eval ( table , row , expr->left ) != 0.0 ) X ? eval ( table , row , expr->right->left ) X : eval ( table , row , expr->right->right ); X break; X X case AND : X value = ( eval ( table , row , expr->left ) X && eval ( table , row , expr->right ) ); X break; X X case OR : X value = ( eval ( table , row , expr->left ) X || eval ( table , row , expr->right ) ); X break; X X case NOT : X value = ( eval ( table , row , expr->left ) == 0.0 ); X break; X X case NEG : X value = ( - eval ( table , row , expr->left ) ); X break; X X case FVAR_IDENT : X value = call_var_fun ( expr->ident , expr->parm_list , table , row ); X break; X X case VAR_IDENT : X value = var_lookup ( expr->ident ); X break; X X case NUMBER : X value = ( expr->value ); X break; X X case ATTR : X intval = (int) eval ( table , row , expr->left ); X if ( intval == 0 ) X value = row + 1.0; X else { X for ( i = 1 , tp = table; tp != NULL && i < intval; i++ , tp = tp->next ) X ; X if ( tp == NULL ) X abort ( "Illegal attribute number selected from table" ); X if ( row >= tp->size ) X abort ( "Internal error - accessing past end of array in eval()" ); X value = ( tp->data[row] ); X } X break; X X default : X value = 0.0; X abort ( "Unknown operator in eval() = %d" , expr->node_type ); X } X return ( value ); X} X SHAR_EOF if test 3653 -ne "`wc -c < 'eval.c'`" then echo shar: error transmitting "'eval.c'" '(should have been 3653 characters)' fi fi if test -f 'evaltab.c' then echo shar: will not over-write existing file "'evaltab.c'" else echo extracting "'evaltab.c'" sed 's/^X//' >evaltab.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include "graph.h" X#include "y.tab.h" X X Xextern table_st *append_tables (); Xextern table_st *adjacent (); Xextern table_st *project (); Xextern table_st *select (); Xextern table_st *sort (); Xextern table_st *join (); Xextern table_st *tab_lookup (); Xextern table_st *group (); Xextern table_st *cumulate (); Xextern table_st *generate (); Xextern table_st *call_tab_fun (); Xextern table_st *new_table (); Xextern table_st *copy_of_table (); Xextern double eval (); X X Xtable_st * Xeval_tab ( expr ) Xtnode_st *expr; X{ X trow_st *trp; X tcol_st *tcp; X int num_rows , num_cols , tmp_cols; X table_st *newtab , *tp; X int row; X X X switch ( expr->operator ) { X X case TABLE : X num_rows = 0; X num_cols = 0; X for ( trp = expr->const_table; trp != NULL; trp = trp->next ) { X tmp_cols = 0; X for ( tcp = trp->cols; tcp != NULL; tcp = tcp->next ) { X tmp_cols++; X } X if ( num_rows == 0 ) X num_cols = tmp_cols; X else X if ( num_cols != tmp_cols ) X abort ( "constant table has rows with different number of columns" ); X num_rows++; X } X newtab = new_table ( num_cols , num_rows ); X row = 0; X for ( trp = expr->const_table; trp != NULL; trp = trp->next ) { X for ( tcp = trp->cols, tp = newtab; tcp != NULL; tcp = tcp->next, tp = tp->next ) { X tp->data[ row ] = eval ( NULL , 0 , tcp->expr ); X } X row++; X } X return ( newtab ); X break; X X case TAB_CONST : X return ( copy_of_table ( expr->table ) ); X X case FTAB_IDENT : X return ( call_tab_fun ( expr->ident , expr->parm_list , NULL , 0 ) ); X X case APPEND : X return ( append_tables ( eval_tab ( expr->left ) , X eval_tab ( expr->right ) ) ); X X case ADJACENT : X return ( adjacent ( eval_tab ( expr->left ) , X eval_tab ( expr->right ) ) ); X X case PROJECT : X return ( project ( eval_tab ( expr->left ) , expr->expr_list ) ); X X case WHERE : X return ( select ( eval_tab ( expr->left ) , expr->expr ) ); X X case SORT : X return ( sort ( eval_tab ( expr->left ) , (int)eval ( NULL , 0 , expr->expr ) ) ); X X case JOIN : X return ( join ( eval_tab ( expr->left ) , eval_tab ( expr->right ) , X (int)eval ( NULL , 0 , expr->expr->left ) , X (int)eval ( NULL , 0 , expr->expr->right ) ) ); X X case CUMULATE : X return ( cumulate ( eval_tab ( expr->left ) , (int)eval ( NULL , 0 , expr->expr ) ) ); X X case GENERATE : X return ( generate ( expr->range , expr->interval ) ); X X case TAB_IDENT : X return ( tab_lookup ( expr->ident ) ); X X case GROUP : X return ( group ( eval_tab ( expr->left ) , expr->range , expr->interval , expr->ident ) ); X X default : X abort ( "unknown operator in eval_tab: %d" , expr->operator ); X X } X return ( NULL ); X} SHAR_EOF if test 2981 -ne "`wc -c < 'evaltab.c'`" then echo shar: error transmitting "'evaltab.c'" '(should have been 2981 characters)' fi fi if test -f 'freetab.c' then echo shar: will not over-write existing file "'freetab.c'" else echo extracting "'freetab.c'" sed 's/^X//' >freetab.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X X#include <stdio.h> X#include "graph.h" X X Xfree_table ( table ) Xtable_st *table; X{ X table_st *p; X X while ( table != NULL ) { X p = table->next; X release ( table->data ); X release ( table ); X table = p; X } X} X SHAR_EOF if test 509 -ne "`wc -c < 'freetab.c'`" then echo shar: error transmitting "'freetab.c'" '(should have been 509 characters)' fi fi if test -f 'fundeclr.c' then echo shar: will not over-write existing file "'fundeclr.c'" else echo extracting "'fundeclr.c'" sed 's/^X//' >fundeclr.c <<'SHAR_EOF' X/* X * Copyright (C) 1986 Alan Kent X * X * Permission is granted to freely distribute part or X * all of this code as long as it is not for profit X * and this message is retained in the code. X * X * No resposibility is taken for any damage or incorect X * results this program generates. X * X */ X X X#include <stdio.h> X#include "graph.h" X#include "y.tab.h" X#include "math.h" X X Xextern double eval (); Xextern table_st *eval_tab (); Xextern double min_fun (); Xextern double max_fun (); Xextern double sum_fun (); Xextern double count_fun (); Xextern double average_fun (); X X X#define MIN_FUN ((attr_st *)2) X#define MAX_FUN ((attr_st *)3) X#define SUM_FUN ((attr_st *)4) X#define COUNT_FUN ((attr_st *)5) X#define AVERAGE_FUN ((attr_st *)6) X#define LOG_FUN ((attr_st *)7) X#define LN_FUN ((attr_st *)8) X#define EXP_FUN ((attr_st *)9) X#define POWER_FUN ((attr_st *)10) X#define SQRT_FUN ((attr_st *)11) X#define FLOOR_FUN ((attr_st *)12) X#define CEIL_FUN ((attr_st *)13) X#define ABS_FUN ((attr_st *)14) X#define SIN_FUN ((attr_st *)15) X#define COS_FUN ((attr_st *)16) X#define ASIN_FUN ((attr_st *)17) X#define ACOS_FUN ((attr_st *)18) X#define ATAN_FUN ((attr_st *)19) X#define ATAN2_FUN ((attr_st *)20) X#define SINH_FUN ((attr_st *)21) X#define COSH_FUN ((attr_st *)22) X#define TANH_FUN ((attr_st *)23) X#define HYPOT_FUN ((attr_st *)24) X#define J0_FUN ((attr_st *)26) X#define J1_FUN ((attr_st *)27) X#define JN_FUN ((attr_st *)28) X#define Y0_FUN ((attr_st *)29) X#define Y1_FUN ((attr_st *)30) X#define YN_FUN ((attr_st *)31) X X X#define MAX_DEC 50 X X Xstatic struct declare_st { X char *name; X parm_st *parm_list; X attr_st *expr; X tnode_st *tab_expr; X} dec [ MAX_DEC ]; X Xstatic int num_dec; X X X Xpdef_fun () X{ X static parm_st ptab; X static parm_st pexpr1 , pexpr2; X X ptab.parm_type = TABLE; X ptab.ident = ""; X ptab.next = NULL; X X pexpr1.parm_type = VALUE; X pexpr1.ident = ""; X pexpr1.next = NULL; X X pexpr2.parm_type = VALUE; X pexpr2.ident = ""; X pexpr2.next = &pexpr1; X X fun_declare ( "min" , &ptab , MIN_FUN , NULL ); X fun_declare ( "max" , &ptab , MAX_FUN , NULL ); X fun_declare ( "sum" , &ptab , SUM_FUN , NULL ); X fun_declare ( "count" , &ptab , COUNT_FUN , NULL ); X fun_declare ( "average" , &ptab , AVERAGE_FUN , NULL ); X X fun_declare ( "sqrt" , &pexpr1 , SQRT_FUN , NULL ); X fun_declare ( "log" , &pexpr1 , LOG_FUN , NULL ); X fun_declare ( "ln" , &pexpr1 , LN_FUN , NULL ); X fun_declare ( "exp" , &pexpr1 , EXP_FUN , NULL ); X fun_declare ( "pow" , &pexpr2 , POWER_FUN , NULL ); X fun_declare ( "floor" , &pexpr1 , FLOOR_FUN , NULL ); X fun_declare ( "ceil" , &pexpr1 , CEIL_FUN , NULL ); X fun_declare ( "abs" , &pexpr1 , ABS_FUN , NULL ); X X fun_declare ( "sin" , &pexpr1 , SIN_FUN , NULL ); X fun_declare ( "cos" , &pexpr1 , COS_FUN , NULL ); X fun_declare ( "asin" , &pexpr1 , ASIN_FUN , NULL ); X fun_declare ( "acos" , &pexpr1 , ACOS_FUN , NULL ); X fun_declare ( "atan" , &pexpr1 , ATAN_FUN , NULL ); X fun_declare ( "atan2" , &pexpr2 , ATAN2_FUN , NULL ); X fun_declare ( "sinh" , &pexpr1 , SINH_FUN , NULL ); X fun_declare ( "cosh" , &pexpr1 , COSH_FUN , NULL ); X fun_declare ( "tanh" , &pexpr1 , TANH_FUN , NULL ); X X fun_declare ( "hypot" , &pexpr2 , HYPOT_FUN , NULL ); X X fun_declare ( "j0" , &pexpr1 , J0_FUN , NULL ); X fun_declare ( "j1" , &pexpr1 , J1_FUN , NULL ); X fun_declare ( "jn" , &pexpr2 , JN_FUN , NULL ); X fun_declare ( "y0" , &pexpr1 , Y0_FUN , NULL ); X fun_declare ( "y1" , &pexpr1 , Y1_FUN , NULL ); X fun_declare ( "yn" , &pexpr2 , YN_FUN , NULL ); X} X X Xfun_declare ( name , parm_list , expr , tab_expr ) Xchar *name; Xparm_st *parm_list; Xattr_st *expr; Xtnode_st *tab_expr; X{ X int i; X X for ( i = 0; i < num_dec; i++ ) { X if ( strcmp ( name , dec[i].name ) == 0 ) { X abort ( "cannot redeclare functions: '%s'" , name ); X return; X } X } X if ( num_dec >= MAX_DEC ) X abort ( "Internal array overflow - too many functions declared" ); X dec[num_dec].name = name; X dec[num_dec].parm_list = parm_list; X dec[num_dec].expr = expr; X dec[num_dec].tab_expr = tab_expr; X num_dec++; X} X X Xdouble Xcall_var_fun ( name , parm_list , table , row ) Xchar *name; Xparm_st *parm_list; Xtable_st *table; Xint row; X{ X int i; X double value; X parm_st *p1 , *p2; X#define MAX_TAB 3 X#define MAX_VAR 3 X table_st *tab_parm[ MAX_TAB ]; X double var_parm[ MAX_VAR ]; X int tab_num , var_num; X X for ( i = 0; i < num_dec; i++ ) { X if ( strcmp ( dec[i].name , name ) == 0 ) { X X if ( dec[i].expr == NULL ) X abort ( "value function with no expression found" ); X X p1 = parm_list; X p2 = dec[i].parm_list; X var_num = 0; X tab_num = 0; X while ( p1 != NULL && p2 != NULL ) { X X if ( p1->parm_type != p2->parm_type ) X abort ( "type mismatch for parameter to function '%s'" , name ); X X if ( p1->parm_type == TABLE ) { X tab_parm[ tab_num ] = eval_tab ( p1->tab_expr ); X tab_declare ( p2->ident , tab_parm[ tab_num ] ); X if ( tab_num + 1 < MAX_TAB ) X tab_num++; X } X else { X var_parm[ var_num ] = eval ( table , row , p1->expr ); X var_declare ( p2->ident , var_parm[ var_num ] ); X if ( var_num + 1 < MAX_VAR ) X var_num++; X } X p1 = p1->next; X p2 = p2->next; X } X if ( p1 != NULL || p2 != NULL ) X abort ( "illegal parameter list for function '%s'" , name ); X X switch ( dec[i].expr ) { X X case MIN_FUN : X value = min_fun ( tab_parm[0] , 0 , tab_parm[0]->size ); X break; X X case MAX_FUN : X value = max_fun ( tab_parm[0] , 0 , tab_parm[0]->size ); X break; X X case SUM_FUN : X value = sum_fun ( tab_parm[0] , 0 , tab_parm[0]->size ); X break; X X case COUNT_FUN : X value = count_fun ( tab_parm[0] , 0 , tab_parm[0]->size ); X break; X X case AVERAGE_FUN : X value = average_fun ( tab_parm[0] , 0 , tab_parm[0]->size ); X break; X X case LOG_FUN : X value = log10 ( var_parm[0] ); X break; X X case LN_FUN : X value = log ( var_parm[0] ); X break; X X case EXP_FUN : X value = exp ( var_parm[0] ); X break; X X case POWER_FUN : X value = pow ( var_parm[0] , var_parm[1] ); X break; X X case SQRT_FUN : X value = sqrt ( var_parm[0] ); X break; X X case FLOOR_FUN : X value = floor ( var_parm[0] ); X break; X X case CEIL_FUN : X value = ceil ( var_parm[0] ); X break; X X case ABS_FUN : X value = fabs ( var_parm[0] ); X break; X X case SIN_FUN : X value = sin ( var_parm[0] ); X break; X X case COS_FUN : X value = cos ( var_parm[0] ); X break; X X case ASIN_FUN : X value = asin ( var_parm[0] ); X break; X X case ACOS_FUN : X value = acos ( var_parm[0] ); X break; X X case ATAN_FUN : X value = atan ( var_parm[0] ); X break; X X case ATAN2_FUN : X value = atan2 ( var_parm[0] , var_parm[1] ); X break; X X case SINH_FUN : X value = sinh ( var_parm[0] ); X break; X X case COSH_FUN : X value = cosh ( var_parm[0] ); X break; X X case TANH_FUN : X value = tanh ( var_parm[0] ); X break; X X case HYPOT_FUN : X value = hypot ( var_parm[0] , var_parm[1] ); X break; X X case J0_FUN : X value = sin ( var_parm[0] ); X break; X X case J1_FUN : X value = j1 ( var_parm[0] ); X break; X X case JN_FUN : X value = jn ( var_parm[0] ); X break; X X case Y0_FUN : X value = y0 ( var_parm[0] ); X break; X X case Y1_FUN : X value = y1 ( var_parm[0] ); X break; X X case YN_FUN : X value = yn ( var_parm[0] ); X break; X X default : X value = eval ( table , row , dec[i].expr ); X break; X } X return ( value ); X } X } X abort ( "Undefined function '%s' referenced" , name ); X} X X Xtable_st * Xcall_tab_fun ( name , parm_list , table , row ) Xchar *name; Xparm_st *parm_list; Xtable_st *table; Xint row; X{ X int i; X table_st *newtab; X parm_st *p1 , *p2; X X for ( i = 0; i < num_dec; i++ ) { X if ( strcmp ( dec[i].name , name ) == 0 ) { X if ( dec[i].tab_expr == NULL ) X abort ( "table function with no expression found" ); X p1 = parm_list; X p2 = dec[i].parm_list; X while ( p1 != NULL && p2 != NULL ) { X if ( p1->parm_type != p2->parm_type ) X abort ( "type mismatch for parameter to function '%s'" , name ); X if ( p1->parm_type == TABLE ) X tab_declare ( p2->ident , eval_tab ( p1->tab_expr ) ); X else X var_declare ( p2->ident , eval ( table , row , p1->expr ) ); X p1 = p1->next; X p2 = p2->next; X } X if ( p1 != NULL || p2 != NULL ) X abort ( "illegal parameter list for function '%s'" , name ); X newtab = eval_tab ( dec[i].tab_expr ); X return ( newtab ); X } X } X abort ( "Undefined function '%s' referenced" , name ); X} X X X Xis_fvar_ident ( name ) Xchar *name; X{ X int i; X X for ( i = 0; i < num_dec; i++ ) { X if ( strcmp ( dec[i].name , name ) == 0 ) { X return ( dec[i].expr != NULL ); X } X } X return ( 0 ); X} X X X Xis_ftab_ident ( name ) Xchar *name; X{ X int i; X X for ( i = 0; i < num_dec; i++ ) { X if ( strcmp ( dec[i].name , name ) == 0 ) { X return ( dec[i].expr == NULL ); X } X } X return ( 0 ); X} X X X Xcheck_group_fun ( name ) Xchar *name; X{ X int i; X X for ( i = 0; i < num_dec; i++ ) { X if ( strcmp ( dec[i].name , name ) == 0 ) { X if ( dec[i].expr == NULL ) X abort ( "function '%s' must return a value" , name ); X if ( dec[i].parm_list == NULL X || dec[i].parm_list->next != NULL X || dec[i].parm_list->parm_type != TABLE ) X abort ( "function '%s' expects a single table as parameters" ); X return; X } X } X} SHAR_EOF if test 9436 -ne "`wc -c < 'fundeclr.c'`" then echo shar: error transmitting "'fundeclr.c'" '(should have been 9436 characters)' fi fi # end of shell archive exit 0