/* PhysCalc - Main program - March 1989
Copyright (C) 1989, 1990 Marty White
This program 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 2
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include "compiler.h"
#ifdef __STDHEADERS__
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
/*#include <conio.h>*/
/*#include <dos.h>*/
/*#include <alloc.h>*/
#include <memory.h>
#endif
#include "physcalc.h"
#include "physdecl.h"
#ifdef __PROTOTYPES__
LOCAL void initvars(void);
#endif
EXPORT struct varstruct *var; /* initialized by initvars() */
EXPORT struct ufstruct *userfunc = NULL; /* Holds user functions */
EXPORT int echo=TRUE, error;
EXPORT char *errormsg;
#ifdef TRACE
EXPORT int trace=FALSE;
#endif
/** FUNCTIONS *********************************************************/
#ifndef __TURBOC__ /* Turbo has built in working function */
EXPORT void clrscr() /* Clear screen - compiler dependent */
{
puts("\33[2J"); /* ANSI code to clear screen */
}
#endif
EXPORT int pause_for_user()
{ /* Probably compiler/operating system dependent.
This is supposed to display a message, wait for a keypress,
not echo it, erase the current line and leave the cursor where
it started. */
int c;
printf("Press any key to continue ");
#ifdef __TURBOC__
c = getch(); /* should get 1 char, no echo */
if (!c)
getch();
#else
#ifdef __DESMETC__
c = ci();
if (!c)
ci();
#else
c = getchar(); /* Will NOT work right! */
#endif
#endif
printf("\r%30s\r","");
return c;
}
EXPORT void printerror()
{
static char *errors[7] = {
"Computational error",
"Unbalanced parenthesis",
"Syntax error",
"Unknown function",
"Unknown variable",
"Type mismatch",
"Out of memory"
};
if (echo) {
if (error>0 && error<8)
printf("%s.\n",errors[error-1]);
if (error<-1 || error>7)
printf("Unknown error #%d\n",error);
if (errormsg)
printf("%s.\n",errormsg);
}
}
EXPORT NODEP solve(s)
char const **s;
/* Take a string expression, return an evaluated node */
{
NODEP n,n2;
n = parse(s);
if (!error)
n2 = evaluate(n);
deallocnode(n);
if (error)
return NULL;
return n2;
}
LOCAL void initvars()
{ /* Create variable PREVIOUS */
static char previous[] = "PREVIOUS";
if ((var = malloc(sizeof(struct varstruct)))==NULL)
out_of_memory("initvars()");
var->next = NULL;
var->value = NULL;
var->name = previous; /* Create permament PREVIOUS variable */
var->rflag = FALSE;
}
void printmyaddress()
{
}
/***** Command functions *****/
LOCAL void help(s)
char const *s;
{
printf("You may type a command or an expression for immediate evaluation.\n");
printf("Operators are: + - * / ^ ! not and or mod ( )\n");
printf("Built in functions are: exp(), ln(), log(), sqrt(), fact(), sin(), cos(),\n");
printf(" tan(), arcsin(), arccos(), arctan(), and integrate(f,a,b[,p]).\n");
printf("Built in commands are: HELP, QUIT, INFO, LET, DEFINE, LIST, DELETE, FACTOR\n");
printf(" TRACE, FRACTION, BASE, DIMENSION, UNIT, SAVE, LOAD, and DOS.\n");
}
LOCAL void info(s) /* INFO cmd */
char const *s;
{
printf("PhysCalc Version %s by Marty White\n",VERSION);
/* Compiler dependent */
#ifdef __BORLANDC__
printf("Compiled on %s at %s with Borland C++ %d.\n",
__DATE__,__TIME__,__TURBOC__);
#else
#ifdef __TURBOC__
printf("Compiled on %s at %s with Turbo C %d.\n",
__DATE__,__TIME__,__TURBOC__);
#endif
#endif
#ifdef __DESMETC__
printf("Compiled with DeSmet C.\n");
#endif
printf("Maximum fundamental dimensions: %d\n",MAXDIM);
printf("There are currently %d nodes allocated.\n",nodecount);
#ifdef __TURBOC__
printf("At least %luK of memory is available.\n", (unsigned long) coreleft() / 1024);
#endif
}
LOCAL void do_let(s) /* Assigns an expresion to a variable */
char const *s;
{ /* TD: fix spacing allowances */
/* Syntax: LET variable = literal string
Uses direct substitution, variables & functions are not
calculated until needed.
LET variable := value
Evaluates immediately, saving time & memory */
int flag;
char buf[NAMELEN],answer[SMALLBUF];
NODEP n,n2;
struct varstruct *v,*v2;
static char msg[] =
"Error: missing '='. To use LET type:\n LET <variable name> = <expression>\nor\n LET <variable name> := <expression>\n";
strupr(s);
scan_symbol(&s,buf);
if (buf[0]=='\0') {
error = -1;
errormsg = msg;
return;
}
flag = FALSE;
skipspc(s);
if (*s==':') {
flag = TRUE; /* colon found */
s++;
}
if (!*s=='=') {
error = -1;
errormsg = msg;
return;
}
s++;
skipspc(s);
n = parse(&s); /* convert to a node tree */
if (error) {
deallocnode(n);
return;
}
if (flag) { /* evaluate expression NOW instead of later */
n2 = evaluate(n);
deallocnode(n);
if (error) {
deallocnode(n2);
return;
}
n = n2;
}
/* The 1st variable, "PREVIOUS", is not user alterable */
v = var;
while (v->next) { /* search for duplicate name or end of list */
v = v->next;
if (!strcmp(v->name,buf)) {
if (echo) {
printf("Replace %s = ",v->name);
printexpr(v->value);
printf(" ?");
fgets(answer, sizeof(answer), stdin);
printf("\n");
} else
answer[0] = 'Y';
if (toupper(answer[0])=='Y') {
deallocnode(v->value);
v->value = n;
if (echo) printf("Assigned.\n");
return;
}
}
}
if ((v2=malloc(sizeof(struct varstruct)))==NULL) {
error = MEMERR;
return;
}
if ((v2->name = strdup(buf))==NULL) {
error = MEMERR;
return;
}
v2->value = n;
v2->rflag = FALSE;
v2->next = NULL;
v->next = v2;
if (echo) printf("Assigned.\n");
}
LOCAL void define_uf(s) /* Define a function */
char const *s; /* text to parse */
{
char buf[NAMELEN],buf2[NAMELEN];
NODEP n,n2,n3;
struct ufstruct *u,*u2;
static char msg[] = "Bad function definition.\n";
strupr(s);
scan_symbol(&s,buf); /* Scan function name */
skipspc(s);
if (!buf[0] || *s!='(') {
error = -1;
errormsg = msg;
return;
}
n2 = alloclnode(LNODE);
do {
s++; /* Skip '(' or ',' */
scan_symbol(&s,buf2); /* Scan dummy var name */
n3 = allocsnode(buf2);
linknode(n2,n3);
skipspc(s);
} while (*s==',');
if (*s != ')') {
error = -1;
errormsg = msg;
deallocnode(n2);
return;
}
s++;
skipspc(s);
if (*s=='=')
s++;
n = parse(&s); /* parse function expression */
if (error) {
deallocnode(n);
deallocnode(n2);
return;
}
if (u = userfunc) {
do {
if (!strcmp(u->name,buf)) {
deallocnode(u->dummy);
deallocnode(u->value);
u->dummy = n2;
u->value = n;
if (echo) printf("Redefined.\n");
return;
}
} while (u->next && (u=u->next));
}
if ((u2 = malloc(sizeof(struct ufstruct)))==NULL) {
error = MEMERR;
return;
}
if (u)
u->next = u2;
else
userfunc = u2;
if ((u2->name = strdup(buf))==NULL) {
error = MEMERR;
return;
}
u2->value = n;
u2->dummy = n2;
u2->next = NULL;
if (echo) printf("Defined.\n");
}
EXPORT void output_list(fp,vars,funcs,verbose)
FILE *fp;
struct varstruct const *vars;
struct ufstruct const *funcs;
int verbose;
{ /* Output a list of all variables and/or user-functions. If
verbose is true, output in a format from which the original
expression can be reconstructed. */
int j;
while (vars) {
fprintf(fp,"%s%s = ", verbose?"LET ":"", vars->name);
fprintexpr(fp,vars->value);
fprintf(fp,"\n");
vars = vars->next;
}
while (funcs) {
fprintf(fp, "%s%s(", verbose?"DEFINE ":"", funcs->name);
j=0;
while (funcs->dummy->data->list[j]) {
fprintexpr(fp,funcs->dummy->data->list[j]);
if (funcs->dummy->data->list[++j])
fprintf(fp,",");
}
fprintf(fp,") = ");
fprintexpr(fp, funcs->value);
fprintf(fp,"\n");
funcs = funcs->next;
}
}
LOCAL void list(s)
char const *s;
{ /* output all variables and/or user-functions to console */
skipspc(s);
strupr(s);
output_list(stdout,
strncmp(s,"FUNC",4) ? var : NULL,
strncmp(s,"VAR",3) ? userfunc : NULL,
FALSE);
}
LOCAL void delete(s) /* erase a variable or user-function */
char const *s;
{ /* a function name must be followed by an open paren to distinguish from
a variable */
char name[NAMELEN];
int flag;
struct varstruct *v,*v2;
struct ufstruct *u,*u2;
strupr(s);
scan_symbol(&s,name);
if (name[0]=='\0') {
error = -1;
errormsg =
"To delete a variable type:\n DELETE <variable name>\nTo delete a function type:\n DELETE <function name>(\n";
return;
}
if (*s=='(') { /* delete a function */
u2 = NULL;
if (u = userfunc)
do {
if (!strcmp(u->name,name)) {
free(u->name);
deallocnode(u->value);
deallocnode(u->dummy);
if (u2)
u2->next = u->next;
free(u);
if (echo) printf("Function deleted.\n");
return;
}
u2 = u;
u = u->next;
} while (u);
if (echo) printf("No user-defined function '%s'.\n",name);
} else { /* delete a variable */
flag = FALSE;
v = var;
v2 = NULL;
do {
if (!strcmp(v->name,name)) {
free(v->name);
deallocnode(v->value);
if (v2)
v2->next = v->next;
free(v);
flag = TRUE;
} else
v2 = v;
v = v->next;
} while (v);
if (echo) {
if (flag)
printf("Variable Deleted.\n");
else
printf("No user-defined variable '%s'.\n",name);
}
}
}
LOCAL void quit(s)
char const *s;
{
exit(0);
}
#ifdef TRACE
LOCAL void trace_cmd(s) /* set expression tracing mode */
char const *s;
{
strupr(s);
trace = !!strcmp(s,"OFF");
printf("Tracing is o%s.\n",trace?"n":"ff");
}
#endif
LOCAL void base_cmd(s)
char const *s;
{
int b;
skipspc(s);
if (*s=='=')
s++;
skipspc(s);
if (!*s) {
printf("Default numeric base is %d.\n", defaultbase);
return;
}
b = atoi(s);
if (b>0 && b<37) {
printf("New default numeric base is %d.\n", b);
defaultbase = b;
} else
printf("Invalid base. Usage: BASE ['='] <base, in base 10>\n");
}
LOCAL void save_cmd(s)
char *s;
{ /* Save some or all variables, functions, dimensions, and units by
writing human-readable text to a file from which the original
expressions can be reconstructed. Only those expressions defined
since the original loading will be saved unless the qualifier
"ALL" is used. */
int saveall=FALSE;
if (!strncmp(s,"ALL ",4)) {
s+=4;
saveall = TRUE;
}
printf("Saving '%s'...\n",s);
save_data(s,saveall);
if (echo) printf("Done.\n");
}
LOCAL void load_cmd(s)
char *s;
{ /* Load definitions from a file */
#ifdef TRACE
if (trace) printf("Loading '%s'...\n",s);
#endif
load_data(s);
if (echo) printf("Done.\n");
}
LOCAL void do_system(s)
char *s;
{ /* Operating system escape */
#ifdef __DESMETC__
char shell[128],parms[128];
if (getenv("COMSPEC",shell)==0) {
error = -1;
errormsg = "Error: No COMSPEC environment variable.\n";
return;
}
strcpy(parms,"/c");
strncat(parms,s,124);
exec(shell, parms);
#else
if (system(s)) {
error = -1;
errormsg = "Error: Unable to run shell.\n";
}
/*
error = -1;
errormsg = "Shell is unavailable.\n";
return;
*/
#endif
}
EXPORT void do_cmd(buf)
char *buf;
{ /* This is the start of command processing. If the buffer starts
with a keyword, invoke that command, else assume it is an
expression to be evaluated. */
char *s;
int i,len;
NODEP n;
static struct {
char *name;
#ifndef __PROTOTYPES__
void (*cmdptr)();
#else
void (*cmdptr)(char const *s);
#endif
} commands[] = {
"DIMENSION",define_dimension,
"UNIT",define_unit,
"LET",do_let,
"DEFINE",define_uf,
"FRACTION",fraction_cmd,
"LIST",list,
"FACTOR",factor,
"DELETE",delete,
"SAVE",save_cmd,
"LOAD",load_cmd,
"INFO",info,
"HELP",help,
"?",querry,
"SYSTEM",do_system,
"QUIT",quit,
"EXIT",quit,
"BYE", quit,
"BASE",base_cmd,
#ifdef TRACE
"TRACE",trace_cmd,
#endif
"",NULL
};
error = 0; /* Initialize flags */
errormsg = NULL;
trimspc(buf); /* Compress/eliminate extra whitespace */
/*strupr(buf);*/
s = buf;
while (*s && !isspace(*s)) {
*s = toupper(*s);
++s;
}
if (*buf=='\0')
return;
s = buf;
for (i=0; commands[i].cmdptr; i++) { /* scan for keywords */
len = strlen(commands[i].name);
if (!strncmp(buf,commands[i].name,len)) {
s += len;
trimspc(s);
(*commands[i].cmdptr)( s );
if (error)
printerror();
return;
}
}
strupr(buf);
n = solve(&s); /* No keyword found, evaluate it */
if (error) {
printerror();
if (*s)
printf("--> %s\n",s);
return;
}
skipspc(s); /* Expression was successfully evaluated, */
if (*s) { /* so print out the answer in the desired units. */
if (*s=='=') {
/* printf("Automatically converting to '%s'...\n", s+1); */
printanswer(n,s+1);
} else {
error = SYNERR;
printerror();
printf("--> %s\n",s);
return;
}
} else
printanswer(n,NULL);
deallocnode(var->value);
var->value = n; /* save valid result in var PREVIOUS */
}
LOCAL char *GetStartupDir(argv0)
char *argv0;
{
int len = strlen(argv0);
char *s = strchr(argv0, '\0');
if (!len || !s)
return NULL;
while (len) {
if (*--s == '\\') {
char *path = malloc(len + 1);
strncpy(path, argv0, len);
path[len] = '\0';
return path;
}
len--;
}
return strdup(argv0);
}
void LegalCrap()
{
printf(
"\nPhysCalc\n"
"Copyright (C) 1990 Marty White\n\n"
"This program is free software; you can redistribute it and/or\n"
"modify it under the terms of the GNU General Public License\n"
"as published by the Free Software Foundation; either version 2\n"
"of the License, or (at your option) any later version.\n\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"
);
}
int main(argc, argv)
int argc;
char *argv[];
{ /* Main program: Init vars, load unit & help data, enter main loop */
static char buf[LARGEBUF];
int quick=FALSE, argi=1, cmdline=FALSE;
char datapath[65];
char *startpath = GetStartupDir(argv[0]);
buf[0]='\0';
initnodes();
initvars();
if (argc > 1) {
if (!stricmp(argv[1],"?") || !stricmp(argv[1],"/?") || !stricmp(argv[1],"-?")) {
printf("Usage: physcalc [/Q] [expression]\n\n");
return;
}
if (!stricmp(argv[1],"/q")) {
quick=TRUE;
argi++;
}
}
while (argi < argc) {
strcat(buf, argv[argi]);
strcat(buf," ");
argi++;
}
trimspc(buf);
if (buf[0]) {
quick=cmdline=TRUE;
}
if (!quick) {
LegalCrap();
/* pause_for_user(); */
printf("\nEnter HELP for a very brief summary of commands.\n");
}
/* printf("Loading unit conversion data...\n"); */
#ifndef __GNUC__
strcpy(datapath, startpath);
#else
datapath[0] = '\0';
#endif
strcat(datapath, "physcalc.phy");
load_data(datapath);
remember_old();
if (cmdline) {
do_cmd(buf);
} else
while (TRUE) {
printf(">");
fgets(buf, sizeof(buf), stdin);
do_cmd(buf);
}
}
syntax highlighted by Code2HTML, v. 0.9.1