/*********************************************************************** | | Dimension Calculator | | A Postfix Calculator that deals | with units as well as numbers | | by David A Lyons | | Based on my Prime Pascal version of 6-Nov-86 | Last mod 10-Feb-89 DL | *********************************************************************/ #define Version 1.3 #define ModDate "30-Aug-89" #define Debug 0 #include #include #define is(X,Y) (!strcmp(X,Y)) #define false 0 #define true 1 #define MaxStringLen 200 #define MaxStackSize 100 #define MaxUnits 300 #define MaxVars 100 #define MaxDefs 100 #define SigDigs 11 #define MaxExpands 20 typedef char ShortString[20]; typedef char MyString[MaxStringLen]; typedef double ShapeType[10]; struct ValueType { double n; ShapeType sh; }; typedef struct { int size; struct ValueType el[MaxStackSize]; } StackType; typedef struct { ShortString name; /* ex: "yard" */ ShapeType sh; /* exponents for each dimension */ double scale; /* scale compared to standard unit */ } UnitType; typedef UnitType UnitListType[MaxUnits]; typedef struct { ShortString name; double scale; } MetricPfxType; MetricPfxType MetricPrefix[30]; typedef struct { ShortString Name; struct ValueType val; } VarType; typedef struct { int changed; int n; VarType v[MaxVars]; } VarListType; typedef struct { int changed; int n; struct { ShortString Name; MyString val; } d[MaxDefs]; } DefListType; enum ModeEnum { fix, sci, eng }; typedef struct { enum ModeEnum mode; int digits; double MaxV, MinV; } FmtType; int ScreenHeight, Finished; StackType S; MyString Line, UnitStr; UnitListType UnitList; int NumUnits, NumDims, NumPrefixes; ShortString DimName[11], StdUnit[11]; MyString W; int PerFlag, EqualFlag; ShapeType AngleVec, NoDimsVec; VarListType Vars; DefListType Defs; struct ValueType LastVal; FmtType fmt; void Literal(); /*----------------------------------------------------------------------*/ int Yes(str) char *str; { char s[80]; while(1) { printf("%s? (y/n) ", str); gets(s); if(s[0]=='y' || s[0]=='Y') return(1); if(s[0]=='n' || s[0]=='N') return(0); } } double myAbs(x) double x; { if(x<0.0) return(-x); else return(x); } void MyWrite(n) double n; { switch(fmt.mode) { case fix: if(n > fmt.MinV) { printf("%E", n); break; } case sci: printf("%E", n); break; case eng: printf("%E", n); break; } } char *myfgets(s,n,stream) char *s; int n; FILE *stream; { char *result; result=fgets(s,n,stream); if(s[strlen(s)-1]=='\n') s[strlen(s)-1]='\0'; return(result); } double sqr(n) double n; { return(n*n); } /*----------------------------------------------------------------------*/ void Welcome() { printf("\n"); printf("[DimCalc v%1.1f of %s] by David A Lyons\n", Version, ModDate); printf("\n"); printf("(Type \"help\" for help.)\n"); printf("\n"); } /*----------------------------------------------------------------------*/ double ReadInt(UnitsFile) FILE *UnitsFile; { double x; fscanf(UnitsFile,"%E\n",&x); return(x); } /*----------------------------------------------------------------------*/ void ReadUnits() { FILE *UnitsFile; int i; char dummy[80]; NumUnits = 0; UnitsFile = fopen("unit.data", "r"); printf("Reading units...\n"); fscanf(UnitsFile,"%d\n",&NumDims); for(i=1;i<=NumDims;i++) { fscanf(UnitsFile,"%s\n",DimName[i]); myfgets(StdUnit[i],10,UnitsFile); } printf("done reading dims\n"); /* read metric prefixes */ fscanf(UnitsFile,"%d\n", &NumPrefixes); for(i=1;i<=NumPrefixes;i++) { fscanf(UnitsFile,"%s\n",MetricPrefix[i].name); fscanf(UnitsFile,"%E\n",&(MetricPrefix[i].scale)); } printf("done reading prefixes\n"); /* now read the juicy stuff */ fgets(dummy,10,UnitsFile); /* dummy line */ while(!feof(UnitsFile)) { NumUnits++; myfgets(UnitList[NumUnits].name,20,UnitsFile); fscanf(UnitsFile, "%E\n", &UnitList[NumUnits].scale); for(i=1;i<=NumDims;i++) UnitList[NumUnits].sh[i] = ReadInt(UnitsFile); } fclose(UnitsFile); printf("\n"); } /*----------------------------------------------------------------------*/ int Alpha(S) char S; { return( ( (S>='a')&&(S<='z') ) || ( (S>='A')&&(S<='Z') ) || ( (S>='0')&&(S<='9') ) || (S=='-') || (S=='+') || (S=='.') || (S=='_') || (S=='$') || (S=='.') ); } TrimBlanks(s) char *s; { int i, j; for(i=strlen(s); i && s[i-1]==' '; i--) s[i-1]='\0'; for(i=0; s[i]==' '; i++) ; for(j=0; s[i]; j++, i++) s[j]=s[i]; s[j]='\0'; } /*----------------------------------------------------------------------*/ void ParseWord ( Word ) char *Word; { int Done=false; TrimBlanks(Line); Word[0] = '\0'; while(!Done) { if(!strlen(Line)) Done=true; else { int L=strlen(Word); Word[L+1]= '\0'; Word[L] = Line[0]; strcpy(Line, Line+1); if((strlen(Word)==1)&&(!Alpha(Word[0]))) Done = true; if((strlen(Word)>=1)&&(strlen(Line)>0)) if(!Alpha(Line[0])) Done=true; } } TrimBlanks(Word); #if Debug printf("Word=/%s/\n", Word); #endif } CopySh( Dest, Src ) ShapeType Dest, Src; { int i; for(i=1;i<=NumDims;i++) { Dest[i] = Src[i]; } } /* Stack operations */ void Push(X) struct ValueType X; { #if Debug printf("Push(%E)\n", X.n); #endif if(S.size==MaxStackSize) printf("*** stack is full\n"); else { S.el[S.size] = X; S.size++; } } void Pop(X) struct ValueType *X; { int i; if(S.size<=1) { printf("*** stack is empty\n"); X->n = 0.0; for(i=1;i<=NumDims;i++) X->sh[i]=0.0; } else { S.size--; *X = S.el[S.size]; } #if Debug printf("Pop() = %E\n", X->n); #endif } struct ValueType Extract(i) { return(S.el[i]); } int StackSize() { return(S.size-1); } int Empty() { return(S.size<=1); } void DoClear() { struct ValueType X; while(!Empty()) Pop(&X); } /*======================================================================*/ int IsDimLess(X) struct ValueType X; { int OK=true, i; for(i=1;i<=NumDims;i++) OK = OK && ( X.sh[i] == 0.0 ); return(OK); } int SameDims(X,Y) struct ValueType X,Y; { int Same=true, i; for(i=1;i<=NumDims;i++) Same = Same && (X.sh[i]==Y.sh[i]); return(Same); } int IsAngle(X) struct ValueType X; { int Same=true, i; for(i=1;i<=NumDims;i++) Same = Same && (X.sh[i]==AngleVec[i]); return(Same); } /*======================================================================*/ void DoHelp() { system("more dimcalc.help"); /* printf("Nope, no help yet.\n"); */ printf("\n"); } /*======================================================================*/ double GetPower(UnitString) char *UnitString; { int Temp; struct ValueType Pwr; double P = 0.0; ParseWord(W); if(is(W,"^")) { ParseWord(W); Temp = PerFlag; if(EqualFlag) { strcat(UnitString,"^"); strcat(UnitString,W); } Literal(); PerFlag = Temp; Pop(&Pwr); P = Pwr.n; ParseWord(W); } else P = 1.0; return(P); } int StripPrefix(S) char *S; { int ret; int P=1, Done; ret = -1; Done = (P>NumPrefixes); while(!Done) { if(strlen(S)==1) break; if(!strncmp(MetricPrefix[P].name,S,strlen(MetricPrefix[P].name))) { Done = true; ret=P; strcpy(S, S+strlen(MetricPrefix[P].name)); } else { P++; Done = (P>NumPrefixes); } } return(ret); } int LookupUnit(S) char *S; { char temp[40]; int i; for(i=1;i<=NumUnits;i++) { strcpy(temp,UnitList[i].name); if(is(temp,S)) return(i); strcat(temp,"s"); if(is(temp,S)) return(i); strcpy(temp,UnitList[i].name); strcat(temp,"es"); if(is(temp,S)) return(i); } return(-1); } void BuildUnit() { struct ValueType X; double Mult, Power; int Done; int U, P, i; MyString Unit, TheUnit; int Popped; /* did we pop something off the stack? */ strcpy(TheUnit,W); if(Empty()) { Popped = false; X.n = 1.0; CopySh(X.sh,NoDimsVec); } else { Pop(&X); Popped = true; } Mult = 1.0; Done = false; while(!Done) { U = LookupUnit ( W ); if(U!=-1) Done = true; else { P = StripPrefix ( W ); if(P!=-1) Mult = Mult * MetricPrefix[P].scale; else Done = true; } } strcpy(Unit,W); Power=GetPower(TheUnit); if(U==-1) printf("*** unknown unit: %s\n", Unit); else { if(!PerFlag) X.n = X.n * Mult; else X.n = X.n / Mult; if(PerFlag) Power = -Power; for(i=1;i<=NumDims;i++) X.sh[i] = X.sh[i] + (Power * UnitList[U].sh[i]); X.n = X.n / exp(Power * log(UnitList[U].scale)); } if(Popped||(U>0)) Push(X); if(U>0) { strcat(UnitStr," "); strcat(UnitStr,TheUnit); } } /*======================================================================*/ ShowPrefixes() { int i, Blanks; printf(" prefix value (%d prefixes)\n", NumPrefixes); printf(" ------ -----\n"); for(i=1;i<=NumPrefixes;i++) { printf( " %s", MetricPrefix[i].name ); for(Blanks=strlen(MetricPrefix[i].name);Blanks<16;Blanks++) printf(" "); printf( "10^%d\n", (int)(log(MetricPrefix[i].scale)/log(10.0)) ); } } /*======================================================================*/ ShowUnits() { int i=1, Blanks, dim, LineCount=5; double X; printf(" unit dimensions (%d units)\n", NumUnits); printf(" ---- ----------\n"); while(i<=NumUnits) { printf(" %s", UnitList[i].name ); for(Blanks=strlen(UnitList[i].name);Blanks<18;Blanks++) printf(" "); for(dim=1;dim<=NumDims;dim++) { X = UnitList[i].sh[dim]; if(UnitList[i].sh[dim]) { printf("%s",DimName[dim]); if(X!=1.0) printf("^%d", (int)(X)); printf(" "); } } printf("\n"); if(++LineCount>ScreenHeight) { LineCount = 3; if(!Yes("Continue")) i=NumUnits+1; } i++; } } /*======================================================================*/ OpSize() { struct ValueType X; X.n = StackSize(); CopySh(X.sh,NoDimsVec); Push(X); } OpSin() { struct ValueType X; Pop(&X); if(!IsAngle(X)) printf("*** argument to SIN must be an angle\n"); else { X.n = sin(X.n); CopySh(X.sh,NoDimsVec); Push(X); } } OpTan() { struct ValueType X; Pop(&X); if(!IsAngle(X)) printf("*** argument to TAN must be an angle\n"); else { X.n = sin(X.n)/cos(X.n); CopySh(X.sh,NoDimsVec); Push(X); } } OpCos() { struct ValueType X; Pop(&X); if(!IsAngle(X)) printf("*** argument to COS must be an angle\n"); else { X.n = cos(X.n); CopySh(X.sh,NoDimsVec); Push(X); } } OpASin() { struct ValueType X; Pop(&X); if(IsDimLess(X)) { if(myAbs(X.n) > 1.0) printf("*** operand for ASin must be -1..1\n"); else { if(myAbs(X.n) < 1.0) X.n = atan( (double)(X.n/sqrt(-sqr(X.n)+1.0)) ); else if(X.n == -1.0) X.n = -2.0 * atan(1.0); else if(X.n == 1.0) X.n = 2.0 * atan(1.0); CopySh(X.sh,AngleVec); Push(X); } } else printf("*** operand for ASin must be dimensionless\n"); } OpACos() { struct ValueType X; Pop(&X); if(IsDimLess(X)) { if(myAbs(X.n) > 1.0) printf("*** operand for ACos must be -1..1\n"); else { if(X.n == -1.0) X.n = 4*atan(1.0); /* pi */ else if(X.n==1.0) X.n = 0.0; else X.n = -atan( (double)(X.n/sqrt(-sqr(X.n)+1.0)) ) + 2.0*atan(1.0); CopySh(X.sh,AngleVec); Push(X); } } else printf("*** operand for ACos must be dimensionless\n"); } OpATan() { struct ValueType X; Pop(&X); if(IsDimLess(X)) { X.n = atan(X.n); CopySh(X.sh,AngleVec); Push(X); } else printf("*** operand for ATan must be dimensionless\n"); } OpNeg() { struct ValueType X; Pop(&X); X.n = -X.n; Push(X); } OpAbs() { struct ValueType X; Pop(&X); X.n = myAbs(X.n); Push(X); } OpAdd() { struct ValueType X,Y; Pop(&Y); Pop(&X); if(SameDims(X,Y)) { Y.n = Y.n + X.n; Push(Y); } else { printf("*** operands for \"+\" must have same dimensions\n"); Push(X); Push(Y); } } OpSub() { struct ValueType X,Y; Pop(&X); Pop(&Y); if(SameDims(X,Y)) { Y.n = Y.n - X.n; Push(Y); } else { printf("*** operands for \"-\" must have same dimensions\n"); Push(Y); Push(X); } } OpPwr() { struct ValueType X,Y; int i; Pop(&Y); Pop(&X); if(!IsDimLess(Y)) printf("*** second operand for pwr must be dimensionless\n"); else if(X.n < 0.0) printf("*** first operand for pwr must be positive\n"); else { if(X.n > 0.0) X.n = exp ( log(X.n) * Y.n ); for(i=1;i<=NumDims;i++) X.sh[i] = X.sh[i] * Y.n; Push(X); } } OpMult() { struct ValueType X,Y; int i; Pop(&Y); Pop(&X); Y.n = Y.n * X.n; for(i=1;i<=NumDims;i++) Y.sh[i] = Y.sh[i] + X.sh[i]; Push(Y); } OpDiv() { struct ValueType X,Y; int i; Pop(&Y); Pop(&X); if(Y.n==0.0) { printf("*** can't divide by zero\n"); Y.n = 0.0; } else Y.n = X.n / Y.n; for(i=1;i<=NumDims;i++) Y.sh[i] = X.sh[i] - Y.sh[i]; Push(Y); } OpSqrt() { struct ValueType X; int i; Pop(&X); if(X.n < 0.0) printf("*** operand for SQRT must not be negative\n"); else { X.n = sqrt(X.n); for(i=1;i<=NumDims;i++) X.sh[i] = X.sh[i] / 2.0; Push(X); } } OpDup() { struct ValueType X; Pop(&X); Push(X); Push(X); } OpDrop() { struct ValueType X; Pop(&X); } OpSqr() { OpDup(); OpMult(); } OpLog() { struct ValueType X; Pop(&X); if(IsDimLess(X)) { if(X.n<=0.0) printf("*** operand for Log must be positive\n"); else { X.n = log(X.n) / log(10.0); Push(X); } } else printf("*** operand for Log must be dimensionless\n"); } OpLn() { struct ValueType X; Pop(&X); if(IsDimLess(X)) { if(X.n <= 0.0) printf("*** operand for Ln must be positive\n"); else { X.n = log(X.n); Push(X); } } else printf("*** operand for Ln must be dimensionless\n"); } OpExp() { struct ValueType X; Pop(&X); if(!IsDimLess(X)) printf("*** operand for Exp must be dimensionless\n"); else { X.n = exp(X.n); Push(X); } } OpAlog() { struct ValueType X; Pop(&X); if(!IsDimLess(X)) printf("*** operand for Alog must be dimensionless\n"); else { X.n = exp( X.n * log(10.0) ); Push(X); } } /*----------------------------------------------------------------------*/ PrintStdUnits(X) struct ValueType X; { int i; for(i=1;i<=NumDims;i++) if(X.sh[i] != 0.0) { printf("%s",StdUnit[i]); if(X.sh[i] != 1.0) { printf("^"); if(X.sh[i]==(int)(X.sh[i])) printf("%d",(int)(X.sh[i])); else printf("%E",X.sh[i]); } printf(" "); } } OpPrint() { struct ValueType X, Conv; if(EqualFlag) /* units specified */ { Pop(&Conv); Pop(&X); } else /* units not specified */ { Pop(&X); Conv.n = 1.0; CopySh(Conv.sh,X.sh); } LastVal = X; if(!SameDims(X, Conv)) printf("*** dimensions do not match; unable to print\n"); else /* units OK */ { X.n = X.n / Conv.n; #if Debug printf("### X was %E; Conv is %E; X is %E\n", LastVal.n, Conv.n, X.n); #endif MyWrite( X.n ); printf(" "); if(EqualFlag) { if(strlen(UnitStr)) printf("%s",UnitStr); } else PrintStdUnits(X); printf("\n"); } EqualFlag = false; PerFlag = false; strcpy(UnitStr,""); } SetMode(W) ShortString W; /* Fix or Sci or Eng */ { struct ValueType X; int i; if(!IsDimLess(X)) printf("*** operand for fix/sci/eng must be dimensionless\n"); else if(X.n < 0.0) printf("*** operand for fix/sci/eng must not be negative\n"); else if(X.n > SigDigs) printf("*** operand for fix/sci/eng must not exceed %d", SigDigs ); else { if(is(W,"fix")) fmt.mode = fix; if(is(W,"sci")) fmt.mode = sci; if(is(W,"eng")) fmt.mode = eng; fmt.digits = (int)(X.n); fmt.MinV = 1.0; for(i=1;i<=fmt.digits;i++) fmt.MinV = fmt.MinV / 10.0; } } ShowStack() { int i; struct ValueType Temp, X; if(Empty()) printf("(stack is empty)\n"); else { Temp = LastVal; /* change by OpPrint; preserve */ printf("\n"); for(i=1;i<=StackSize();i++) { X = Extract(i); Push(X); OpPrint(); } LastVal = Temp; } } /*----------------------------------------------------------------------*/ OpSwap() { struct ValueType x, y; Pop(&x); Pop(&y); Push(x); Push(y); } OpWhat() { struct ValueType X; int i; Pop(&X); /* print dimensions of X */ for(i=1;i<=NumDims;i++) { if(X.sh[i] != 0.0) { printf("%s", DimName[i]); if(X.sh[i] != 1.0) { printf("^"); if(X.sh[i] == (int)(X.sh[i])) printf("%d", (int)(X.sh[i])); else printf("%E", X.sh[i]); } printf(" "); } } if(IsDimLess(X)) printf("dimensionless"); printf("\n"); } PerFound() { PerFlag = true; if(EqualFlag) strcat(UnitStr," per"); } EqualFound() { struct ValueType X; strcpy(UnitStr,""); if(EqualFlag) printf("*** something's fishy...second \"=\" found, but no \".\"\n"); EqualFlag = true; PerFlag = false; CopySh(X.sh,NoDimsVec); X.n = 1.0; Push(X); } int StrToInt ( W ) MyString W; { int Done, Neg, N, i; char ch; Done = false; N = 0; i = 0; ch = W[i]; Neg = (ch=='-'); if( (ch=='+') || (ch=='-') ) i++; ch = W[i]; while(!Done) if(i>=strlen(W)) Done=true; else if(ch>='0' && ch<='9') { i++; N = N * 10 + ( (int) ch - (int) '0'); ch = W[i]; } else Done = true; if(Neg) N = - N; return(N); } void Literal() { struct ValueType N; int Neg, Done, Ex, i; char ch; double PlaceVal; PerFlag = false; Neg = false; /* digits before decimal */ Done = false; N.n = 0.0; CopySh(N.sh,NoDimsVec); i = 0; if(W[i]=='-') { Neg = true; i++; } while(!Done) { if(i>strlen(W)) Done = true; else { ch = W[i]; if(ch>='0' && ch <='9') { N.n = (N.n * 10.0) + (double)(ch-'0'); i++; } else Done = true; } } /* after decimal point */ PlaceVal = 1.0; if(W[i]=='.') { Done = false; i++; } else Done = true; if(i>strlen(W)) Done = true; while(!Done) { PlaceVal = PlaceVal / 10.0; if(i>strlen(W)) Done = true; else { ch = W[i]; if(ch>='0' && ch<='9') { N.n = N.n + PlaceVal * (ch-'0'); i++; } else Done = true; } } /* do the Exponent */ if(i<=strlen(W)) { ch = W[i]; if(ch=='e' || ch=='E' || ch=='d' || ch=='D') { Ex = StrToInt ( W+i+1 ); if(Ex>0) for(i=1;i<=Ex;i++) { N.n = N.n * 10.0; } if(Ex<0) for(i=1;i<=-Ex;i++) { N.n = N.n / 10.0; } } } if(Neg) N.n = - N.n; Push(N); #if Debug printf("Literal() pushed %E\n", N.n); #endif } /*----------------------------------------------------------------------*/ /* Definitions stuff */ int FindDef( wrd ) MyString wrd; { int i, Done; i = 1; Done = false; while(!Done) if(i>Defs.n) Done = true; else if(is(Defs.d[i].Name,wrd)) Done = true; else i++; if(i>Defs.n) i = -1; return(i); } /* FindDef */ DoDefine() { MyString Def; int i; ParseWord(Def); if(!strlen(Def)) printf("*** definition name required\n"); else { i = FindDef( Def ); if(i==-1) { Defs.n++; i = Defs.n; } if(i>MaxDefs) printf("*** too many definitions\n"); else { strcpy(Defs.d[i].Name,Def); strcpy(Defs.d[i].val, Line); Defs.changed = true; } strcpy(Line,""); } } DoUndefine() { int i, J; MyString Def; ParseWord(Def); i = FindDef(Def); if(i==-1) printf("*** \"%s\" not defined\n", Def); else { for(J=i;J<=Defs.n-1;J++) { strcpy(Defs.d[J].Name, Defs.d[J+1].Name); strcpy(Defs.d[J].val, Defs.d[J+1].val); } Defs.n--; Defs.changed = true; } } DoDefs() { int i; if(!Defs.n) printf("There are no definitions.\n"); else { if(Defs.n==1) printf("There is 1 definition: "); else printf("There are %d definitions: ", Defs.n ); if(Defs.changed) printf("(not saved)\n"); else printf("\n"); for(i=1;i<=Defs.n;i++) printf("%15s = %s\n", Defs.d[i].Name, Defs.d[i].val ); } } DoShowDef() { int i; ParseWord(W); if(!strlen(W)) printf("*** definition name required\n"); else { i = FindDef(W); if(i==-1) printf("*** \"%s\" not defined\n", W ); else printf( "%15s = %s", Defs.d[i].Name, Defs.d[i].val ); } } DoStoreDefs() { int i; FILE *DefFile; DefFile = fopen("Calc.defs", "w"); for(i=1;i<=Defs.n;i++) { fputs(Defs.d[i].Name, DefFile); fputs("\n", DefFile); fputs(Defs.d[i].val , DefFile); fputs("\n", DefFile); } fclose(DefFile); Defs.changed = false; } DoReadDefs() { FILE *DefFile; char *line; Defs.n = 0; Defs.changed = false; DefFile = fopen("Calc.defs", "r"); if(DefFile==NULL) return; do { Defs.n++; line=myfgets(Defs.d[Defs.n].Name,80,DefFile); myfgets(Defs.d[Defs.n].val,80,DefFile); } while (line!=NULL); Defs.n--; fclose(DefFile); } /* returns TRUE if something is expanded */ int ExpandDef( Word, Line ) char *Word, *Line; { int i; MyString MyWord; MyString TempLine; int Result; strcpy(MyWord, Word); Result = false; i = FindDef(MyWord); if(i!=-1) { strcpy(TempLine, Line); strcpy(Line, Defs.d[i].val); strcat(Line, TempLine); Result = true; ParseWord(Word); } return(Result); } /* Variables stuff */ DoVars() { int i; struct ValueType Temp; /* list all defined variables */ if(!Vars.n) printf("No variables are defined.\n"); else { Temp = LastVal; /* OpPrint changes; preserve */ printf("%d variable", Vars.n); if(Vars.n!=1) printf("s are defined:"); else printf(" is defined:"); if(Vars.changed) printf(" (not saved)\n"); else printf("\n"); for(i=1;i<=Vars.n;i++) { printf(" %20s = ", Vars.v[i].Name); Push(Vars.v[i].val); OpPrint(); } LastVal = Temp; } } DoSetVar() { MyString Vname; int i, Done, Found; ParseWord(Vname); if(!strlen(Vname)) printf("*** variable name required\n"); else { i = 1; Done = false; Found = false; while(!Done && !Found) if(i>Vars.n) Done = true; else if(is(Vars.v[i].Name,Vname)) Found = true; else i++; Done = false; if(!Found) if(Vars.n >= MaxVars) { printf("*** too many variables\n"); Done = true; } else { Vars.n++; i = Vars.n; strcpy(Vars.v[i].Name,Vname); } Pop(&(Vars.v[i].val)); Vars.changed = true; } } DoGetVar() { int i, Done, Found; MyString Vname; ParseWord(Vname); if(!strlen(Vname)) printf("*** variable name required\n"); else { i = 1; Done = false; Found = false; while(!Done && !Found) if(i>Vars.n) Done = true; else if(is(Vars.v[i].Name, Vname)) Found = true; else i++; if(Found) Push(Vars.v[i].val); else printf("*** undefined variable: \"%s\"\n", Vname ); } PerFlag = false; } DoDelVar() { int I, J, Done, Found; MyString Vname; ParseWord(Vname); if(!strlen(Vname)) printf("*** variable name required\n"); else { I = 1; Done = false; Found = false; while(!Done && !Found) if(I>Vars.n) Done = true; else if(is(Vars.v[I].Name,Vname)) Found = true; else I++; if(!Found) printf("*** undefined variable: \"%s\"\n", Vname ); else { for(J=I;J<=Vars.n-1;J++) Vars.v[J] = Vars.v[J+1]; Vars.n--; Vars.changed = true; } } } DoReadVars() { FILE *VarFile; int j; Vars.n = 0; Vars.changed = false; VarFile = fopen ( "Calc.vars", "r" ); if(VarFile!=NULL) { do { Vars.n++; if(!myfgets(Vars.v[Vars.n].Name,80,VarFile)) { Vars.n--; break; } fscanf(VarFile,"%E\n",&Vars.v[Vars.n].val.n); for(j=1;j<=NumDims;j++) fscanf(VarFile,"%E\n",&Vars.v[Vars.n].val.sh[j]); } while(1); fclose(VarFile); } } DoStoreVars() { int I, j; FILE *VarFile = fopen("Calc.vars", "w"); if(VarFile==NULL) printf("Unable to write variables\n"); else { for(I=1;I<=Vars.n;I++) { fputs(Vars.v[I].Name,VarFile); fputs("\n", VarFile); fprintf(VarFile,"%E\n",Vars.v[I].val.n); for(j=1;j<=NumDims;j++) fprintf(VarFile,"%E\n",Vars.v[I].val.sh[j]); } fclose(VarFile); Vars.changed = false; } } /*----------------------------------------------------------------------*/ ProcessLine() { char Char1; int Count; PerFlag = false; ParseWord(W); Count = 0; do Count++; while(ExpandDef(W, Line) && (Count<=MaxExpands)); if(Count>MaxExpands) { printf("*** excessive expansion: aborted\n"); strcpy(W,""); strcpy(Line,""); } while(!Finished && strlen(W)) { Char1 = W[0]; if(is(W,"q") || is(W,"quit")) Finished = true; else if(is(W,"help")) { DoHelp(); ParseWord(W); } else if(is(W,"version") || is(W,"ver") ) { Welcome(); ParseWord(W); } else if(is(W,"#")) { Push(LastVal); PerFlag = false; ParseWord(W); } else if(is(W,"=")) { EqualFound(); ParseWord(W); } else if(is(W,".")) { OpPrint(); ParseWord(W); } else if(is(W,"size")) { OpSize(); ParseWord(W); } else if(is(W,"fix")||is(W,"sci")||is(W,"eng")) { SetMode(W); ParseWord(W); } else if(is(W,"per")) { PerFound(); ParseWord(W); } else if(is(W,"+")) { OpAdd(); ParseWord(W); } else if(is(W,"-")) { OpSub(); ParseWord(W); } else if(is(W,"*")) { OpMult(); ParseWord(W); } else if(is(W,"/")) { OpDiv(); ParseWord(W); } else if(is(W,"pwr")) { OpPwr(); ParseWord(W); } else if(is(W,"abs")) { OpAbs(); ParseWord(W); } else if(is(W,"neg")) { OpNeg(); ParseWord(W); } else if(is(W,"swap")) { OpSwap(); ParseWord(W); } else if(is(W,"what")) { OpWhat(); ParseWord(W); } else if(is(W,"sqr")) { OpSqr(); ParseWord(W); } else if(is(W,"sqrt")) { OpSqrt(); ParseWord(W); } else if(is(W,"dup")) { OpDup(); ParseWord(W); } else if(is(W,"drop")) { OpDrop(); ParseWord(W); } else if(is(W,"sin")) { OpSin(); ParseWord(W); } else if(is(W,"cos")) { OpCos(); ParseWord(W); } else if(is(W,"tan")) { OpTan(); ParseWord(W); } else if(is(W,"asin")||is(W,"arcsin")) { OpASin(); ParseWord(W); } else if(is(W,"acos")||is(W,"arccos")) { OpACos(); ParseWord(W); } else if(is(W,"atan")||is(W,"arctan")) { OpATan(); ParseWord(W); } else if(is(W,"log")) { OpLog(); ParseWord(W); } else if(is(W,"ln")) { OpLn(); ParseWord(W); } else if(is(W,"exp")) { OpExp(); ParseWord(W); } else if(is(W,"alog")) { OpAlog(); ParseWord(W); } else if(is(W,"def")||is(W,"define")) { DoDefine(); ParseWord(W); } else if(is(W,"show")) { DoShowDef(); ParseWord(W); } else if(is(W,"undef")||is(W,"undefine")||is(W,"deldef")) { DoUndefine(); ParseWord(W); } else if(is(W,"defs")||is(W,"definitions")) { DoDefs(); ParseWord(W); } else if(is(W,">")) { DoSetVar(); ParseWord(W); } else if(is(W,"<")||is(W,"@")) { DoGetVar(); ParseWord(W); } else if(is(W,"vars")) { DoVars(); ParseWord(W); } else if(is(W,"delvar")) { DoDelVar(); ParseWord(W); } else if( ((Char1>='0') && (Char1<='9')) || (Char1=='-') ) { Literal(); ParseWord(W); } else if(is(W,"prefixes")) { ShowPrefixes(); ParseWord(W); } else if(is(W,"units")) { ShowUnits(); ParseWord(W); } else if(is(W,"stack")) { ShowStack(); ParseWord(W); } else if(is(W,"clear")) { DoClear(); ParseWord(W); } else BuildUnit(); /* expand definitions */ Count = 0; do { Count++; } while(ExpandDef(W, Line) && (CountMaxExpands) { printf("*** excessive expansion: aborted\n"); strcpy(W,""); strcpy(Line,""); } /* done expanding definitions */ } } /* ProcessLine */ /*----------------------------------------------------------------------*/ ProcessDef( D ) char *D; { int I; I = FindDef(D); if(I!=-1) { strcpy(Line, Defs.d[I].val); ProcessLine(); } } /*----------------------------------------------------------------------*/ main() { int i; ScreenHeight = 24; /* should use system routines for this !!! */ Welcome(); Finished = false; S.size = 1; /* next free stack element is 1 */ ReadUnits(); /* read vars, read defs */ DoReadVars(); DoReadDefs(); for(i=1;i<=NumDims;i++) { NoDimsVec[i] = 0.0; if(is(DimName[i],"angle")) AngleVec[i] = 1.0; else AngleVec[i] = 0.0; } /* default to FIX 4 */ fmt.mode = fix; fmt.digits = 4; fmt.MinV = 0.0001; fmt.MaxV = 1000000000.0; LastVal.n = 0.0; CopySh(LastVal.sh,NoDimsVec); EqualFlag = false; strcpy(UnitStr,""); ProcessDef("_start"); do { ProcessDef("_prompt"); printf("DimCalc> "); gets(Line); if(Line[0]=='!') system(Line+1); /* printf("Shell escape not implemented.\n"); */ else ProcessLine(); } while(!Finished); if(Vars.changed) if(Yes("Variables changed; save them")) DoStoreVars(); if(Defs.changed) if(Yes("Definitions changed; save them")) DoStoreDefs(); printf("Bye!\n"); }