(********************************************************** * * CALCULATOR PROGRAM * * I gave this a quick check and it works. It looks * like it has some extra things that I didn't check out so * if someone does and would be so kind to send me a DOC, I * will republish it. Not everyone who Modified this pro- * gram left their name but for those who did I left in. * * Donated July, 1980 * ************************************************************) PROGRAM CALCULATOR;(*WRITTEN BY DALE ANDER JULY 8, 1977 MODIFIED JULY 17, 1977*) LABEL 999; (*PROGRAM EXIT POINT*) CONST IDLENGTH = 8;{---19/6/80---} TABLESIZE = 35; (*TABLESIZE IS MEMORYSIZE*) IDBLANKS = ' '; {---8 blanks---} LASTX = 'LASTX '; TYPE TOKENKINDS = (CONSTV, EOFV, FUCIDENV, LINEV, LPARENV, MINUSV, PLUSV, RPARENV, SLASHV, STARV, UNRECIDV, UNRECSYMV, UPARROWV, VARIDENV, EQUALV, LASTXV); idkind = packed array[1..idlength] of char; (*---IDKIND = PACKED ARRAY[0..IDLENGTH] OF CHAR;---*) $STRING0 = STRING 0; $STRING255 = STRING 255; STRING80 = STRING 80; (*---80 IS THE DEFAULT LENGTH---*) VAR CH : CHAR; J, TOTALIDS, INDEX : INTEGER; OPERATORS, ALPHA, NUMERIC : SET OF CHAR; NUM, ANSWER : REAL; SOURCE : STRING80; (*---PASCAL/Z---*) TOKENTYPE : TOKENKINDS; NAMETABLE : ARRAY[0..TABLESIZE] OF RECORD NAME: IDKIND; CASE ISVAR: BOOLEAN OF TRUE: (VALUE: REAL) END; TEMP : REAL; ITSOK, GAVEERR : BOOLEAN; FUNCTION LENGTH(X: $STRING255): INTEGER; EXTERNAL; PROCEDURE SETLENGTH(VAR X: $STRING0; Y: INTEGER); EXTERNAL; PROCEDURE GETCHAR; BEGIN J:=J+1; (*J IS INDEX INTO SOURCE*) IF J<=LENGTH(SOURCE) THEN CH:=SOURCE[J] ELSE CH:='#'; (*EOF SOURCE CHAR*) IF (CH>='a') AND (CH<='z') THEN CH := CHR(ORD(CH)-32) (*CHANGE TO UPPER CASE*) END (*OF GETCHAR*); PROCEDURE SCANNER; VAR DONTEAT: BOOLEAN; PROCEDURE GETCONSTANT; (*Real number scanner RJH 9 July 77*) VAR WHOLEPART: REAL; DODECIMAL: BOOLEAN; FUNCTION NUMBER (FRACTION: BOOLEAN): REAL; (*Returns number as whole or fraction*) VAR SUM, COUNT: REAL; BEGIN COUNT:=1; SUM:=0; REPEAT IF SUM < 0.9E37 (*MAXREAL*) THEN BEGIN SUM := 10*SUM + ORD(CH) - ORD('0'); COUNT:=10*COUNT END; GETCHAR UNTIL NOT (CH IN NUMERIC); IF FRACTION THEN NUMBER:=SUM/COUNT ELSE NUMBER:=SUM END (*NUMBER*); BEGIN (*GETCONSTANT*) TOKENTYPE:=CONSTV; IF CH <> '.' THEN BEGIN WHOLEPART:=NUMBER(FALSE); IF CH='.' THEN GETCHAR; DODECIMAL:=(CH IN NUMERIC); END ELSE BEGIN WHOLEPART:=0; GETCHAR; DODECIMAL:=(CH IN NUMERIC); IF NOT DODECIMAL THEN TOKENTYPE:=UNRECSYMV END; IF DODECIMAL THEN NUM:=WHOLEPART + NUMBER(TRUE) ELSE NUM:=WHOLEPART; DONTEAT:=CH<>' '; (*DONT EAT NEXT IF CH IS NONBLANK DA 7/11/77*) END (*OF GETCONSTANT*); PROCEDURE GETID; VAR ID: IDKIND; I: INTEGER; FUNCTION LOOKUP(IDTEXT: IDKIND):INTEGER; VAR I: INTEGER; BEGIN I:=TOTALIDS; NAMETABLE[0].NAME:=IDTEXT;(*DON'T CHANGE--THIS IS USED INSIDE OF PRIMARY!!*) WHILE NAMETABLE[I].NAME<>IDTEXT DO I:=I-1; LOOKUP:=I END (*OF LOOKUP*); BEGIN (*GETID*) ID:=IDBLANKS; I:=1;{---start at position #1 NOT position #0---} REPEAT IF I<=IDLENGTH THEN ID[I]:=CH; I:=I+1; GETCHAR UNTIL NOT(CH IN ['A'..'Z','0'..'9']); DONTEAT:=CH<>' '; (*DONT GET NEXT IF CH IS NONBLANK*) IF ID=LASTX THEN TOKENTYPE:=LASTXV ELSE BEGIN INDEX:=LOOKUP(ID); IF INDEX>0 THEN IF NAMETABLE[INDEX].ISVAR THEN TOKENTYPE:=VARIDENV ELSE TOKENTYPE:=FUCIDENV ELSE TOKENTYPE:=UNRECIDV END END (*OF GETID*); BEGIN (*SCANNER*) DONTEAT:=FALSE; IF CH IN ALPHA THEN GETID ELSE IF CH IN NUMERIC+['.'] THEN GETCONSTANT ELSE IF CH IN OPERATORS THEN CASE CH OF '+': TOKENTYPE:=PLUSV; '-': TOKENTYPE:=MINUSV; '*': TOKENTYPE:=STARV; '/': TOKENTYPE:=SLASHV; '\': TOKENTYPE:=LINEV; '^': TOKENTYPE:=UPARROWV; '(': TOKENTYPE:=LPARENV; ')': TOKENTYPE:=RPARENV; '=': TOKENTYPE:=EQUALV; '#': BEGIN TOKENTYPE:=EOFV; DONTEAT:=TRUE END END ELSE TOKENTYPE:=UNRECSYMV; IF NOT DONTEAT THEN REPEAT GETCHAR UNTIL CH<>' ' (*GETNONBLANK*) END (*OF SCANNER*); FUNCTION EXPRESS(VAR ANS: REAL): BOOLEAN ; VAR OK, CHANGESIGN: BOOLEAN; RSLT1, RSLT2: REAL; SAVEOP: TOKENKIND; FUNCTION TERM(VAR ANS: REAL): BOOLEAN ; VAR OK: BOOLEAN; SAVEOP: TOKENKIND; RSLT1, RSLT2: REAL; FUNCTION FACTOR(VAR ANS: REAL): BOOLEAN ; VAR OK: BOOLEAN; RSLT1, RSLT2: REAL; FUNCTION PRIMARY(VAR ANS: REAL): BOOLEAN ; (*REWRITTEN BY RJH 12 JULY 77 REREWRITTEN BY DA 7/14/77*) VAR FUCNUM, SAVEINDEX: INTEGER; SAVEID: IDKIND; SAVETOK: TOKENKINDS; FUNCTION PARENEXPRESSION(VAR ANS: REAL): BOOLEAN ; BEGIN PARENEXPRESSION:=FALSE; IF TOKENTYPE=LPARENV THEN BEGIN SCANNER; IF EXPRESS(ANS) THEN IF TOKENTYPE=RPARENV THEN BEGIN SCANNER; PARENEXPRESSION:=TRUE END ELSE IF TOKENTYPE<>EOFV THEN BEGIN GAVEERR:=TRUE; WRITE ('")" missing') END END ELSE IF TOKENTYPE IN [UNRECIDV, UNRECSYMV] THEN BEGIN GAVEERR:=TRUE; WRITE ('Illegal symbol') END ELSE IF TOKENTYPE<>EOFV THEN BEGIN GAVEERR:=TRUE; WRITE ('"(" missing') END END (*OF PARENEXPRESSION*); FUNCTION EVALU8 (VAR ANS: REAL): BOOLEAN; VAR ARG, TEMP: REAL; I: INTEGER; Function LOG(x:real):real; { Returns the LOG to base 10 } begin LOG := LN(10) / LN(x) end; BEGIN EVALU8:=TRUE; IF PARENEXPRESSION (ARG) THEN CASE FUCNUM OF 1: ANS:=SIN(ARG); 2: ANS:=COS(ARG); 3: IF COS(ARG)=0 THEN BEGIN WRITE('Undefined TAN'); GAVEERR:=TRUE END ELSE ANS:=SIN(ARG)/COS(ARG); 4: IF ARG<=0 THEN BEGIN WRITE('Undefined LOG'); GAVEERR:=TRUE END ELSE ANS:=LOG(ARG); 5: IF ARG<=0 THEN BEGIN WRITE('Undefined LN'); GAVEERR:=TRUE END ELSE ANS:=LN(ARG); 6: ANS:=ABS(ARG); 7: IF ARG<0 THEN BEGIN WRITE('Undefined SQRT'); GAVEERR:=TRUE END ELSE ANS:=SQRT(ARG); 10: IF (ROUND(ARG)>33) OR (ROUND(ARG)<0) THEN BEGIN WRITE('Cannot calculate factorial GTR 33'); GAVEERR:=TRUE END ELSE BEGIN TEMP:=1; FOR I:=2 TO ROUND(ARG) DO TEMP:=TEMP*I; ANS:=TEMP END END (*OF CASE*) ELSE EVALU8:=FALSE; IF GAVEERR THEN EVALU8:=FALSE END (*OF EVALU8*); BEGIN (*PRIMARY*) PRIMARY:=FALSE; IF TOKENTYPE=CONSTV THEN (*CONSTANT*) BEGIN ANS:=NUM; (*GLOBAL SET BY GETCONSTANT*) PRIMARY:=TRUE; SCANNER END ELSE IF TOKENTYPE IN [VARIDENV, UNRECIDV] THEN BEGIN SAVETOK:=TOKENTYPE; SAVEID:=NAMETABLE[0].NAME; (*PUT THERE BY LOOKUP IN GETID*) SAVEINDEX:=INDEX; (*GLOBAL SET IN GETID*) SCANNER; IF TOKENTYPE=EQUALV THEN (*MEMORY ASSIGNMENT*) BEGIN SCANNER; IF EXPRESS(ANS) THEN BEGIN IF SAVETOK=UNRECIDV THEN IF TOTALIDS+1<=TABLESIZE THEN BEGIN TOTALIDS:=TOTALIDS+1; SAVEINDEX:=TOTALIDS; WITH NAMETABLE[SAVEINDEX] DO BEGIN ISVAR:=TRUE; NAME:=SAVEID END END ELSE BEGIN WRITE('Table full. Not done'); GAVEERR:=TRUE END; IF SAVEINDEX<>0 THEN BEGIN NAMETABLE[SAVEINDEX].VALUE:=ANS; PRIMARY:=TRUE END END END ELSE IF SAVETOK=UNRECIDV THEN BEGIN WRITE('Unrecognized ID'); GAVEERR:=TRUE END ELSE BEGIN PRIMARY:=TRUE; ANS:=NAMETABLE[SAVEINDEX].VALUE END END ELSE IF TOKENTYPE=FUCIDENV THEN (*FUNCTION*) BEGIN FUCNUM:=INDEX; (*INDEX SET BY GETIDENT*) SCANNER; PRIMARY:=EVALU8 (ANS) END ELSE IF TOKENTYPE=LASTXV THEN BEGIN SCANNER; ANS:=ANSWER; PRIMARY:=TRUE END ELSE PRIMARY:=PARENEXPRESSION (ANS) END (*OF PRIMARY*); BEGIN (*FACTOR*) OK:=TRUE; IF PRIMARY(RSLT1) THEN WHILE OK AND (TOKENTYPE=UPARROWV) DO BEGIN SCANNER; IF PRIMARY(RSLT2) THEN IF RSLT1<=0 THEN BEGIN WRITE('Cannot calculate power'); OK:=FALSE; GAVEERR:=TRUE END ELSE RSLT1:=EXP(RSLT2*LN(RSLT1)) ELSE OK:=FALSE END ELSE OK:=FALSE; IF OK THEN ANS:=RSLT1; FACTOR:=OK END (*OF FACTOR*); BEGIN (*TERM*) OK:=TRUE; IF FACTOR(RSLT1) THEN WHILE OK AND (TOKENTYPE IN [STARV, SLASHV, LINEV]) DO BEGIN SAVEOP:=TOKENTYPE; SCANNER; IF FACTOR(RSLT2) THEN CASE SAVEOP OF STARV: RSLT1:=RSLT1*RSLT2; SLASHV: IF RSLT2=0 THEN BEGIN OK:=FALSE; GAVEERR:=TRUE; WRITE('Division by zero') END ELSE RSLT1:=RSLT1/RSLT2; LINEV: IF ROUND(RSLT2)=0 THEN BEGIN OK:=FALSE; GAVEERR:=TRUE; WRITE('MOD by zero') END ELSE RSLT1:=ROUND(RSLT1) MOD ROUND(RSLT2) END (*CASE*) ELSE OK:=FALSE END ELSE OK:=FALSE; IF OK THEN ANS:=RSLT1; TERM:=OK END (*TERM*); BEGIN (*EXPRESS*) OK:=TRUE; IF TOKENTYPE IN [PLUSV,MINUSV] THEN BEGIN CHANGESIGN:=(TOKENTYPE=MINUSV); SCANNER END ELSE CHANGESIGN:=FALSE; IF TERM(RSLT1) THEN BEGIN IF CHANGESIGN THEN RSLT1:=-RSLT1; WHILE OK AND (TOKENTYPE IN [PLUSV,MINUSV]) DO BEGIN SAVEOP:=TOKENTYPE; SCANNER; IF TERM(RSLT2) THEN CASE SAVEOP OF PLUSV: RSLT1:=RSLT1+RSLT2; MINUSV: RSLT1:=RSLT1-RSLT2 END ELSE OK:=FALSE END END ELSE OK:=FALSE; EXPRESS:=OK; IF OK THEN ANS:=RSLT1 END (*OF EXPRESS*); PROCEDURE INITABLES; BEGIN ALPHA:=['A'..'Z']; NUMERIC:=['0'..'9']; OPERATORS:=['+','=','*','-','/','\','^','(',')','#']; WITH NAMETABLE[1] DO BEGIN NAME:='SIN '; ISVAR:=FALSE END; WITH NAMETABLE[2] DO BEGIN NAME:='COS '; ISVAR:=FALSE END; WITH NAMETABLE[3] DO BEGIN NAME:='TAN '; ISVAR:=FALSE END; WITH NAMETABLE[4] DO BEGIN NAME:='LOG '; ISVAR:=FALSE END; WITH NAMETABLE[5] DO BEGIN NAME:='LN '; ISVAR:=FALSE END; WITH NAMETABLE[6] DO BEGIN NAME:='ABS '; ISVAR:=FALSE END; WITH NAMETABLE[7] DO BEGIN NAME:='SQRT '; ISVAR:=FALSE END; WITH NAMETABLE[8] DO BEGIN NAME:='E '; ISVAR:=TRUE; VALUE:=2.718282 END; WITH NAMETABLE[9] DO BEGIN NAME:='PI '; ISVAR:=TRUE; VALUE:=3.141593 END; WITH NAMETABLE[10] DO BEGIN NAME:='FAC '; ISVAR:=FALSE END; TOTALIDS:=10 (*BUILD IN NUMBER OF FUNCS & VARS*) END (*INITABLES*); BEGIN (*CALCULATOR*) ANSWER:=0; INITABLES; REPEAT SETLENGTH(SOURCE,0);{---PASCAL/Z---} GAVEERR:=FALSE; J:=0; WRITE('->'); READLN(SOURCE); IF LENGTH(SOURCE)=0 THEN{EXIT(PROGRAM)}goto 999; REPEAT GETCHAR UNTIL CH<>' '; (*GETNONBLANK*) SCANNER; ITSOK:=EXPRESS(TEMP) AND (TOKENTYPE=EOFV); IF NOT ITSOK THEN BEGIN IF (TOKENTYPE=EOFV) AND NOT GAVEERR THEN WRITE ('Unexpected end of expression') ELSE IF NOT GAVEERR THEN WRITE('Illegal Symbol'); WRITELN(': Try Again') END ELSE BEGIN WRITELN(' ',TEMP); ANSWER:=TEMP END UNTIL FALSE; 999:{EXIT PROGRAM HERE} END (*EXPRESSION*). .