3 ** EVAL.C A floating point expression evaluator.
6 ** Eval is a floating point expression evaluator.
7 ** This is version 1.12
8 ** Copyright (C) 1993 Will Menninger
10 ** To add a new constant to the Eval program
11 ** -----------------------------------------
12 ** 1. Update the size of MAXC in eval.h
13 ** 2. Add your constant to the clist[] array below. Please keep the
14 ** list in alphabetic order, and make sure that your contant's
15 ** name does not exceed MAXNAMELEN (from eval.h)
16 ** 3. If your constant is a physical constant with no indication
17 ** of units in the name, either make sure it is in SI units, or change
18 ** the print statement that claims all constants are in SI units.
19 ** 4. Recompile ALL source modules.
22 ** This program is free software; you can redistribute it and/or modify it
23 ** under the terms of the GNU General Public License as published by the
24 ** Free Software Foundation; either version 2 of the License, or any
27 ** This program is distributed in the hope that it will be useful, but
28 ** WITHOUT ANY WARRANTY; without even the implied warranty of
29 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 ** General Public License for more details.
32 ** You should have received a copy of the GNU General Public License along
33 ** with this program; if not, write to the Free Software Foundation, Inc.,
34 ** 675 Mass Ave, Cambridge, MA 02139, USA.
36 ** The author until 9/93 can be contacted at:
37 ** e-mail: willus@ilm.pfc.mit.edu
38 ** U.S. mail: Will Menninger, 45 River St., #2, Boston, MA 02108-1124
41 ** Originally written 5/89 in ANSI C
47 static char tempname
[80];
48 static char wdir
[100];
49 static char rpath
[200];
50 static FILE *tempfile
;
53 static VAR clist
[MAXC
]= {
54 {"_acres_per_sq_km",247.1},
55 {"_air_density",1.293},
56 {"_air_mol_mass",.02897},
57 {"_atm_per_psi",.06804},
58 {"_avagadro",6.0220e23
},
59 {"_boltzmann",1.3807e-23},
62 {"_coulomb_const",8.98755e9
},
63 {"_deg_per_rad",57.2958},
64 {"_earth_esc_spd",1.12e4
},
65 {"_earth_grav",9.80665},
66 {"_earth_mass",5.98e24
},
67 {"_earth_radius",6.37e6
},
68 {"_earth_to_moon",3.844e8
},
69 {"_earth_to_sun",1.496e11
},
70 {"_eps0",8.85419e-12},
71 {"_erg_per_joule",1e7
},
72 {"_eulers_const",.57721566490153286061},
73 {"_ft_per_m",3.280839895},
76 {"_gauss_per_tesla",1e4
},
77 {"_gm_per_oz",28.34952313},
78 {"_golden_ratio",1.6180339887498948482},
80 {"_hbar",1.05459e-34},
81 {"_joule_per_btu",1054.35},
82 {"_joule_per_cal",4.184},
83 {"_joule_per_ftlb",1.356},
84 {"_joule_per_kwh",3.6e6
},
85 {"_kg_per_slug",14.59},
86 {"_km_per_mi",1.609344},
87 {"_knots_per_mph",.86897624},
88 {"_lbs_per_kg",2.204622622},
89 {"_lit_per_gal",3.785411784},
93 {"_moon_mass",7.35e22
},
94 {"_moon_period",2360448.},
95 {"_moon_radius",1.738e6
},
99 {"_pasc_per_atm",101325.},
100 {"_pasc_per_psi",6895.},
101 {"_pasc_per_torr",133.32},
102 {"_pi",3.14159265358979323846},
104 {"_solar_const",1350.},
105 {"_speed_sound",331.},
106 {"_sun_mass",1.99e30
},
107 {"_sun_radius",6.96e8
},
108 {"_watts_per_hp",745.712},
109 {"_zero_deg_cels",273.15}
112 static char *license
=
113 "Eval, a floating point expression evaluator, version %s\n"
114 "Copyright (C) 1993 Will Menninger\n"
115 "This program is freely redistributable under certain restrictions.\n"
116 "It comes with absolutely no warranty.\n"
117 "Type '\x3f\x3f' for more information, or '?' for brief help.\n";
120 static int process_file(char *filename
,int bequiet
,VARPTR vlist
,VARPTR clist
);
121 static BOOLEAN
process_line(FILE *stream
,int showinp
,int showout
,VARPTR vlist
,
123 static void init_varlist(VARPTR vlist
);
124 static void var_copy(VARPTR dest
,VARPTR source
);
125 static int print_help(FILE *stream
,int extended
,int page
,char *s
);
126 static int more(char *text
,char *input
,int pause
);
127 static void print_oplist(void);
128 static int print_varlist(FILE *s
,char *input
,VARPTR list
,int max
);
129 static void print_stats(void);
130 static int nextline(char *s
,FILE *stream
);
131 static void close_temp(int showout
);
132 static int srchpath(char *name
);
133 static void cwdir(char *name
);
136 int main(int argc
,char *argv
[])
144 printf(license
,VERSION
);
157 strcpy(scriptfile
,argv
[1]);
160 if (scriptfile
[0]!=EOS
)
161 status
=process_file(scriptfile
,0,vlist
,clist
);
165 while (!process_line(stdin
,0,1,vlist
,clist
));
174 ** Sends all of the lines from file, filename, to Eval for processing.
176 ** Returns 1 if a quit was encountered in the file, 0 otherwise
180 static int process_file(char *filename
,int bequiet
,VARPTR vlist
,VARPTR clist
)
186 s
=fopen(filename
,"r");
189 printf("File %s not found.\n",filename
);
194 status
=process_line(s
,!bequiet
,!bequiet
,vlist
,clist
);
195 if (status
==1 || status
==2)
199 return(status
==1 ? 1 : 0);
206 ** Processes one line of input from stream.
207 ** If showinp is NZ, the input is printed to stdout.
208 ** If showout is NZ, all output is printed to stdout.
210 ** Returns: 1 if "quit" (or similar command) is read.
216 static BOOLEAN
process_line(FILE *stream
,int showinp
,int showout
,VARPTR vlist
,
221 char input
[MAXINPUT
+1];
222 int bequiet
,i
,m0
,m1
=0,m2
=0,n
=0,nargs
;
225 if (!nextline(input
,stream
))
233 for (i
=1;input
[i
]==' ' || input
[i
]=='\t';i
++);
240 if (input
[i
]!='<' && input
[i
]!='>' && tempfile
!=NULL
)
242 fprintf(tempfile
,"%s\n",&input
[i
]);
245 if (showinp
&& !bequiet
&& input
[i
]!=EOS
)
246 printf("%s%s\n",PROMPT
,input
);
247 if (!strcmp(&input
[i
],"stop") || !strcmp(&input
[i
],"quit") ||
248 !strcmp(&input
[i
],"exit") || !strcmp(&input
[i
],"end"))
252 if (!showinp
&& !bequiet
&& showout
)
253 printf("Type '?' or 'help' for help.\n");
256 if (!strncmp(&input
[i
],"help",4) &&
257 (input
[i
+4]==' ' || input
[i
+4]=='\t' || input
[i
+4]==EOS
))
263 if (showout
&& !bequiet
&& print_help(stream
,1,n
,input
))
268 if (input
[i
]=='<' || input
[i
]=='>')
271 for (i
++;input
[i
]==' ' || input
[i
]=='\t';i
++);
276 printf("Must specify a file name after <.\n");
279 strcpy(rname
,&input
[i
]);
280 if (!srchpath(rname
))
282 printf("Cannot find %s in read path.\n",rname
);
285 return(process_file(rname
,bequiet
|| !showout
,vlist
,clist
));
287 close_temp(showout
&& !bequiet
);
290 strcpy(tempname
,&input
[i
]);
292 tempfile
=fopen(tempname
,"w");
295 printf("Cannot open %s for output.\n",tempname
);
297 if (showout
&& !bequiet
)
298 printf("Script file %s begun.\n",tempname
);
304 showout
=(showout
&& !bequiet
);
307 for (;!isspace(input
[i
]) && input
[i
]!=EOS
;i
++);
312 for (;isspace(input
[i
]);i
++);
323 if (!strncmp(&input
[m0
],"rpath",m1
))
327 strcpy(rpath
,&input
[m2
]);
328 printf("Read path set to %s\n",rpath
);
333 printf("Read path cleared.\n");
337 if (!strncmp(&input
[m0
],"wdir",m1
))
341 strcpy(wdir
,&input
[m2
]);
342 printf("Write dir set to %s\n",wdir
);
347 printf("Write dir set to current dir.\n");
351 if (!strncmp(&input
[m0
],"obase",m1
) && nargs
==2 && n
>0)
355 printf("Output base must be between 2 and 36.\n");
360 printf("Output base set to %d.\n",n
);
363 if (!strncmp(&input
[m0
],"ibase",m1
) && nargs
==2 && n
>0)
367 printf("Input base must be between 2 and 36.\n");
372 printf("Input base set to %d.\n",n
);
375 if (!strncmp(&input
[m0
],"sci",m1
) && nargs
<2)
377 set_scinote(!get_scinote());
379 printf("Scientific notation %s.\n",get_scinote() ? "ON":"OFF");
382 if (!strncmp(&input
[m0
],"fix",m1
) && nargs
<2)
386 printf("Fixed precision %s.\n",get_fix() ? "ON":"OFF");
389 if (!strncmp(&input
[m0
],"sigfig",m1
) && nargs
==2)
392 printf("Significant figures limited to %d.\n",
399 printf("Significant figures = ");
408 if (!strncmp(&input
[m0
],"maxexp",m1
) && nargs
==2)
414 printf("Exponent limit turned off.\n");
416 printf("Exponent limit = %d\n",n
);
420 if (!strncmp(&input
[m0
],"dplace",m1
) && nargs
==2)
423 printf("Decimal place must be between -70 and 70.\n");
428 printf("Decimal place = %d\n",n
);
434 evaluate(&input
[m0
],showout
,vlist
,clist
);
437 if (!strcmp(&input
[m0
],"?")) {
438 if (showout
&& print_help(stream
,0,0,input
))
443 for (i
=m0
+1;isspace(input
[i
]);i
++);
450 if (showout
&& print_help(stream
,1,n
,input
))
455 switch (tolower((int)input
[i
]))
458 if (showout
&& print_varlist(stream
,input
,vlist
,MAXV
))
464 printf("All physical constants are in SI units unless the "
465 "name of the variable\nindicates otherwise.\n");
466 if (print_varlist(stream
,input
,clist
,MAXC
))
472 if (print_funclist(stream
,input
,tolower((int)input
[i
+1])=='l'))
484 printf("\"%s\" is an unknown query.\n",&input
[i
]);
494 ** insert_var(VARPTR new,VARPTR vlist)
496 ** Inserts a the new variable into the current list of variables.
497 ** Returns 1 if successful, 0 if list is full.
501 BOOLEAN
insert_var(VARPTR
new,VARPTR vlist
)
507 found
=search_varlist(new,vlist
,&i
,MAXV
);
508 if (!found
&& vlist
[MAXV
-1].name
[0]!=EOS
)
511 var_copy(&vlist
[i
],new);
514 for (j
=i
;j
<MAXV
-1 && vlist
[j
].name
[0]!=EOS
;j
++);
516 var_copy(&vlist
[k
],&vlist
[k
-1]);
517 var_copy(&vlist
[i
],new);
524 ** init_varlist(VARPTR vlist)
526 ** Sets all variable names to EOS, representing empty spaces
530 static void init_varlist(VARPTR vlist
)
536 vlist
[i
].name
[0]=EOS
;
540 ** var_copy(VARPTR dest,VARPTR source)
542 ** copies one variable to another
546 static void var_copy(VARPTR dest
,VARPTR source
)
549 strcpy(dest
->name
,source
->name
);
550 dest
->value
=source
->value
;
555 ** search_varlist(VARPTR var,VARPTR vlist,int *n,int max)
557 ** Searches through a variable list for the variable specified. If
558 ** found, returns 1 else returns 0. The position for insertion is
559 ** returned in (*n). The search is binary for fast response.
563 BOOLEAN
search_varlist(VARPTR var
,VARPTR vlist
,int *n
,int max
)
573 if (vlist
[(*n
)].name
[0]==EOS
)
580 if (!(c
=strcmp(var
->name
,vlist
[(*n
)].name
)))
584 if ((*n
)==max
-2 || vlist
[(*n
)+1].name
[0]==EOS
)
587 if (vlist
[(*n
)].name
[0]!=EOS
)
588 return(!strcmp(var
->name
,vlist
[(*n
)].name
));
595 if ((*n
)==0 || strcmp(var
->name
,vlist
[(*n
)-1].name
)>0)
606 ** Prints instructions on how to use the expression evaluator.
610 static int print_help(FILE *stream
,int extended
,int page
,char *s
)
618 for (i
=0,j
=0;ehelp
[j
]!=EOS
&& i
<page
-1;j
++)
625 return (more(extended
? &ehelp
[j
] : bhelp
,s
,stream
==stdin
));
629 static int more(char *text
,char *input
,int pause
)
639 for (nl
=0;nl
<NLINES
;nl
++)
641 for (in
++;text
[in
]!='\f' && text
[in
]!='\n' && text
[in
]!=EOS
;in
++);
642 if (text
[in
]==EOS
|| text
[in
]=='\f')
645 if (text
[in
]==EOS
|| text
[in
+1]==EOS
)
647 printf("%s\n",&text
[istart
]);
654 printf("%s\n",&text
[istart
]);
658 printf("Press <ENTER> for more...\n");
660 nextline(input
,stdin
);
673 ** print_oplist(void)
675 ** Prints list of operands
679 static void print_oplist(void)
682 static char *oplist
=
683 "\nUnary operators:\n"
686 " ~ bit-wise NOT\n\n"
687 "Binary operators: (in order of precedence)\n"
689 " * / % multiply, divide, modulo\n"
690 " + - add, subtract\n"
691 " << >> bit-shift left, right\n"
695 "* - different from C\n\n";
701 ** print_varlist(VARPTR list,int max)
703 ** Prints out a list of constants or variables and their values
707 static int print_varlist(FILE *s
,char *input
,VARPTR list
,int max
)
710 char bigbuf
[MAXOUTLEN
];
711 char bigline
[MAXOUTLEN
];
712 int i
,j
,k
,l
,n
,m1
,m2
,nc
,cw
,nr
,li
,c
;
714 for (m1
=m2
=0,i
=0;i
<max
&& list
[i
].name
[0]!=EOS
;i
++)
716 if ((l
=strlen(list
[i
].name
))>m1
)
718 baseconv(list
[i
].value
,bigbuf
);
719 if ((l
=strlen(bigbuf
))>m2
)
725 printf("There are no currently assigned variables.\n");
741 for (l
=0;(c
=list
[k
].name
[l
])!=EOS
;l
++)
745 baseconv(list
[k
].value
,bigbuf
);
749 for (l
=0;(c
=bigbuf
[l
])!=EOS
;l
++)
756 printf("%s\n",bigline
);
757 if (s
==stdin
&& i
!=nr
-1 && ((i
+3)%NLINES
)==0)
759 printf("\nPress <ENTER> for more...\n");
772 static void print_stats(void)
779 printf("\nExpression evaluator, version %s\n",VERSION
);
781 printf("Default input base: %d\n",ib
);
782 printf("Default output base: %d\n\n",ob
);
783 printf("Base %d accuracy: %d digits\n",ib
,precision(ib
));
785 printf("Base %d accuracy: %d digits\n",ob
,precision(ob
));
787 printf("Read path: %s\n",rpath
[0]==EOS
? "None" : rpath
);
788 printf("Write dir: %s\n",wdir
[0]==EOS
? "Current dir" : wdir
);
794 ** void fixup(char *s)
796 ** Removes white space from beginning and end of string. Also removes
797 ** \n from end of string, and converts entire string to lower case.
806 for (i
=0;isspace(s
[i
]);i
++);
807 for (j
=0;s
[i
]!='\n' && s
[i
]!=EOS
;j
++,i
++)
808 s
[j
]=tolower((int)s
[i
]);
809 for (j
--;j
>=0 && isspace(s
[j
]);j
--);
814 static int nextline(char *s
,FILE *stream
)
822 if (fgets(s
,MAXINPUT
,stream
)==NULL
)
832 static void close_temp(int showout
)
840 printf("%d lines written to %s.\n",linecount
,tempname
);
845 static int srchpath(char *name
)
858 for (j
=0;rpath
[i
]!=EOS
&& rpath
[i
]!=';';i
++,j
++)
861 if (checked
&& !j
&& rpath
[i
]==EOS
)
863 while (rpath
[i
]==';')
881 static void cwdir(char *name
)