home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / CALC.ZIP / CALC.PAS
Encoding:
Pascal/Delphi Source File  |  1985-12-28  |  11.6 KB  |  462 lines

  1. (**********************************************************
  2. *
  3. *        CALCULATOR PROGRAM
  4. *
  5. *    I gave this a quick check and it works.  It looks 
  6. *  like it has some extra things that I didn't check out so
  7. *  if someone does and would be so kind to send me a DOC, I
  8. *  will republish it.  Not everyone who Modified this pro-
  9. *  gram left their name but for those who did I left in.
  10. *
  11. *  Donated July, 1980
  12. *
  13. ************************************************************)
  14.  
  15. PROGRAM CALCULATOR;(*WRITTEN BY DALE ANDER JULY 8, 1977
  16.                       MODIFIED JULY 17, 1977*)
  17.  
  18. LABEL 999; (*PROGRAM EXIT POINT*)
  19. CONST IDLENGTH = 8;{---19/6/80---}
  20.       TABLESIZE = 35;  (*TABLESIZE IS MEMORYSIZE*)
  21.       IDBLANKS = '        '; {---8 blanks---}
  22.       LASTX = 'LASTX   ';
  23.  
  24. TYPE  TOKENKINDS = (CONSTV, EOFV, FUCIDENV, LINEV, LPARENV, MINUSV, PLUSV,
  25.                      RPARENV, SLASHV, STARV, UNRECIDV, UNRECSYMV, UPARROWV,
  26.                      VARIDENV, EQUALV,  LASTXV);
  27.     idkind = packed array[1..idlength] of char;
  28. (*---IDKIND = PACKED ARRAY[0..IDLENGTH] OF CHAR;---*)
  29.  
  30.     $STRING0 = STRING 0;
  31.     $STRING255 = STRING 255;
  32.     STRING80   = STRING 80; (*---80 IS THE DEFAULT LENGTH---*)
  33.  
  34. VAR
  35.   CH        : CHAR;
  36.   J,
  37.   TOTALIDS,
  38.   INDEX        : INTEGER;
  39.   OPERATORS,
  40.   ALPHA,
  41.   NUMERIC    : SET OF CHAR;
  42.   NUM,
  43.   ANSWER    : REAL;
  44.   SOURCE    : STRING80; (*---PASCAL/Z---*)
  45.   TOKENTYPE    : TOKENKINDS;
  46.   NAMETABLE    : ARRAY[0..TABLESIZE] OF
  47.                 RECORD
  48.                   NAME: IDKIND;
  49.                   CASE ISVAR: BOOLEAN OF
  50.                     TRUE: (VALUE: REAL)
  51.                 END;
  52.   TEMP        : REAL;
  53.   ITSOK,
  54.   GAVEERR    : BOOLEAN;
  55.  
  56. FUNCTION LENGTH(X: $STRING255): INTEGER; EXTERNAL;
  57. PROCEDURE SETLENGTH(VAR X: $STRING0; Y: INTEGER); EXTERNAL;
  58.  
  59. PROCEDURE GETCHAR;
  60. BEGIN
  61.   J:=J+1;  (*J IS INDEX INTO SOURCE*)
  62.   IF J<=LENGTH(SOURCE) THEN
  63.     CH:=SOURCE[J]
  64.   ELSE
  65.     CH:='#';  (*EOF SOURCE CHAR*)
  66.   IF (CH>='a') AND (CH<='z') THEN
  67.     CH := CHR(ORD(CH)-32) (*CHANGE TO UPPER CASE*)
  68. END (*OF GETCHAR*);
  69.  
  70. PROCEDURE SCANNER;
  71. VAR DONTEAT: BOOLEAN;
  72.  
  73. PROCEDURE GETCONSTANT;
  74.   (*Real number scanner    RJH 9 July 77*)
  75. VAR WHOLEPART:  REAL;
  76.     DODECIMAL:  BOOLEAN;
  77.  
  78.   FUNCTION NUMBER (FRACTION: BOOLEAN): REAL;
  79.   (*Returns number as whole or fraction*)
  80.   VAR SUM, COUNT: REAL;
  81.   BEGIN
  82.     COUNT:=1;
  83.     SUM:=0;
  84.     REPEAT
  85.       IF SUM < 0.9E37 (*MAXREAL*) THEN
  86.     BEGIN
  87.       SUM := 10*SUM + ORD(CH) - ORD('0');
  88.       COUNT:=10*COUNT
  89.     END;
  90.       GETCHAR
  91.     UNTIL NOT (CH IN NUMERIC);
  92.     IF FRACTION THEN
  93.        NUMBER:=SUM/COUNT
  94.     ELSE
  95.        NUMBER:=SUM
  96.   END (*NUMBER*);
  97.  
  98. BEGIN (*GETCONSTANT*)
  99.   TOKENTYPE:=CONSTV;
  100.   IF CH <> '.' THEN
  101.     BEGIN
  102.       WHOLEPART:=NUMBER(FALSE);
  103.       IF CH='.' THEN GETCHAR;
  104.       DODECIMAL:=(CH IN NUMERIC);
  105.     END
  106.   ELSE
  107.     BEGIN
  108.       WHOLEPART:=0;
  109.       GETCHAR;
  110.       DODECIMAL:=(CH IN NUMERIC);
  111.       IF NOT DODECIMAL THEN TOKENTYPE:=UNRECSYMV
  112.     END;
  113.   IF DODECIMAL THEN
  114.      NUM:=WHOLEPART + NUMBER(TRUE)
  115.   ELSE
  116.      NUM:=WHOLEPART;
  117.   DONTEAT:=CH<>' '; (*DONT EAT NEXT IF CH IS NONBLANK  DA 7/11/77*)
  118. END (*OF GETCONSTANT*);
  119.  
  120. PROCEDURE GETID;
  121. VAR ID: IDKIND;
  122.     I: INTEGER;
  123.  
  124.   FUNCTION LOOKUP(IDTEXT: IDKIND):INTEGER;
  125.   VAR I: INTEGER;
  126.  
  127.   BEGIN
  128.     I:=TOTALIDS;
  129.     NAMETABLE[0].NAME:=IDTEXT;(*DON'T CHANGE--THIS IS USED
  130.                                  INSIDE OF PRIMARY!!*)
  131.     WHILE NAMETABLE[I].NAME<>IDTEXT DO  I:=I-1;
  132.     LOOKUP:=I
  133.   END (*OF LOOKUP*);
  134.  
  135. BEGIN (*GETID*)
  136.   ID:=IDBLANKS;
  137.   I:=1;{---start at position #1 NOT position #0---}
  138.   REPEAT
  139.     IF I<=IDLENGTH THEN ID[I]:=CH;
  140.     I:=I+1;
  141.     GETCHAR
  142.   UNTIL NOT(CH IN ['A'..'Z','0'..'9']);
  143.   DONTEAT:=CH<>' '; (*DONT GET NEXT IF CH IS NONBLANK*)
  144.   IF ID=LASTX THEN
  145.     TOKENTYPE:=LASTXV
  146.   ELSE
  147.     BEGIN
  148.       INDEX:=LOOKUP(ID);
  149.       IF INDEX>0 THEN
  150.         IF NAMETABLE[INDEX].ISVAR THEN
  151.        TOKENTYPE:=VARIDENV
  152.         ELSE
  153.        TOKENTYPE:=FUCIDENV
  154.       ELSE
  155.     TOKENTYPE:=UNRECIDV
  156.     END
  157. END (*OF GETID*);
  158.  
  159. BEGIN (*SCANNER*)
  160.   DONTEAT:=FALSE;
  161.   IF CH IN ALPHA THEN GETID
  162.   ELSE
  163.     IF CH IN NUMERIC+['.'] THEN GETCONSTANT
  164.     ELSE
  165.       IF CH IN OPERATORS THEN
  166.         CASE CH OF
  167.       '+': TOKENTYPE:=PLUSV;
  168.       '-': TOKENTYPE:=MINUSV;
  169.       '*': TOKENTYPE:=STARV;
  170.       '/': TOKENTYPE:=SLASHV;
  171.       '\': TOKENTYPE:=LINEV;
  172.       '^': TOKENTYPE:=UPARROWV;
  173.       '(': TOKENTYPE:=LPARENV;
  174.       ')': TOKENTYPE:=RPARENV;
  175.       '=': TOKENTYPE:=EQUALV;
  176.       '#': BEGIN TOKENTYPE:=EOFV; DONTEAT:=TRUE END
  177.         END
  178.       ELSE TOKENTYPE:=UNRECSYMV;
  179.   IF NOT DONTEAT THEN REPEAT GETCHAR UNTIL CH<>' ' (*GETNONBLANK*)
  180. END (*OF SCANNER*);
  181.  
  182. FUNCTION EXPRESS(VAR ANS: REAL): BOOLEAN ;
  183. VAR OK, CHANGESIGN: BOOLEAN;
  184.     RSLT1, RSLT2: REAL;
  185.     SAVEOP: TOKENKIND;
  186.  
  187. FUNCTION TERM(VAR ANS: REAL): BOOLEAN ;
  188. VAR OK: BOOLEAN;
  189.     SAVEOP: TOKENKIND;
  190.     RSLT1, RSLT2: REAL;
  191.  
  192. FUNCTION FACTOR(VAR ANS: REAL): BOOLEAN ;
  193. VAR OK: BOOLEAN;
  194.     RSLT1, RSLT2: REAL;
  195.  
  196. FUNCTION PRIMARY(VAR ANS: REAL): BOOLEAN ;
  197. (*REWRITTEN BY RJH 12 JULY 77
  198.    REREWRITTEN BY DA 7/14/77*)
  199. VAR  FUCNUM, SAVEINDEX: INTEGER;
  200.      SAVEID: IDKIND;
  201.      SAVETOK: TOKENKINDS;
  202.  
  203. FUNCTION PARENEXPRESSION(VAR ANS: REAL): BOOLEAN ;
  204. BEGIN
  205.   PARENEXPRESSION:=FALSE;
  206.   IF TOKENTYPE=LPARENV THEN
  207.     BEGIN
  208.       SCANNER;
  209.       IF EXPRESS(ANS) THEN
  210.         IF TOKENTYPE=RPARENV THEN
  211.       BEGIN SCANNER; PARENEXPRESSION:=TRUE END
  212.         ELSE
  213.           IF TOKENTYPE<>EOFV THEN
  214.             BEGIN GAVEERR:=TRUE; WRITE ('")"  missing') END
  215.     END
  216.   ELSE
  217.     IF TOKENTYPE IN [UNRECIDV, UNRECSYMV] THEN
  218.       BEGIN GAVEERR:=TRUE; WRITE ('Illegal symbol') END
  219.     ELSE
  220.       IF TOKENTYPE<>EOFV THEN
  221.         BEGIN GAVEERR:=TRUE; WRITE ('"(" missing') END
  222. END (*OF PARENEXPRESSION*);
  223.  
  224. FUNCTION EVALU8 (VAR ANS: REAL): BOOLEAN;
  225. VAR ARG, TEMP: REAL;
  226.     I: INTEGER;
  227.  
  228.     Function LOG(x:real):real;
  229.     { Returns the LOG to base 10 }
  230.     begin
  231.       LOG := LN(10) / LN(x)
  232.     end;
  233.  
  234. BEGIN
  235.   EVALU8:=TRUE;
  236.   IF PARENEXPRESSION (ARG) THEN
  237.     CASE FUCNUM OF
  238.       1: ANS:=SIN(ARG);
  239.       2: ANS:=COS(ARG);
  240.       3: IF COS(ARG)=0 THEN
  241.         BEGIN WRITE('Undefined TAN'); GAVEERR:=TRUE END
  242.      ELSE
  243.         ANS:=SIN(ARG)/COS(ARG);
  244.       4: IF ARG<=0 THEN
  245.         BEGIN WRITE('Undefined LOG'); GAVEERR:=TRUE END
  246.      ELSE
  247.         ANS:=LOG(ARG);
  248.       5: IF ARG<=0 THEN
  249.         BEGIN WRITE('Undefined LN'); GAVEERR:=TRUE END
  250.      ELSE
  251.         ANS:=LN(ARG);
  252.       6: ANS:=ABS(ARG);
  253.       7: IF ARG<0 THEN
  254.         BEGIN WRITE('Undefined SQRT'); GAVEERR:=TRUE END
  255.      ELSE
  256.         ANS:=SQRT(ARG);
  257.       10: IF (ROUND(ARG)>33) OR (ROUND(ARG)<0) THEN
  258.             BEGIN
  259.           WRITE('Cannot calculate factorial GTR 33');
  260.           GAVEERR:=TRUE
  261.         END
  262.           ELSE
  263.             BEGIN
  264.               TEMP:=1;
  265.               FOR I:=2 TO ROUND(ARG) DO TEMP:=TEMP*I;
  266.               ANS:=TEMP
  267.             END
  268.     END (*OF CASE*)
  269.   ELSE EVALU8:=FALSE;
  270.   IF GAVEERR THEN EVALU8:=FALSE
  271. END (*OF EVALU8*);
  272.  
  273. BEGIN (*PRIMARY*)
  274.   PRIMARY:=FALSE;
  275.   IF TOKENTYPE=CONSTV THEN (*CONSTANT*)
  276.     BEGIN
  277.       ANS:=NUM; (*GLOBAL SET BY GETCONSTANT*)
  278.       PRIMARY:=TRUE;
  279.       SCANNER
  280.     END
  281.   ELSE
  282.     IF TOKENTYPE IN [VARIDENV, UNRECIDV] THEN
  283.       BEGIN
  284.         SAVETOK:=TOKENTYPE;
  285.         SAVEID:=NAMETABLE[0].NAME; (*PUT THERE BY LOOKUP IN GETID*)
  286.         SAVEINDEX:=INDEX; (*GLOBAL SET IN GETID*)
  287.         SCANNER;
  288.         IF TOKENTYPE=EQUALV THEN  (*MEMORY ASSIGNMENT*)
  289.           BEGIN
  290.             SCANNER;
  291.         IF EXPRESS(ANS) THEN
  292.           BEGIN
  293.         IF SAVETOK=UNRECIDV THEN
  294.           IF TOTALIDS+1<=TABLESIZE THEN
  295.             BEGIN
  296.               TOTALIDS:=TOTALIDS+1;
  297.               SAVEINDEX:=TOTALIDS;
  298.               WITH NAMETABLE[SAVEINDEX] DO
  299.             BEGIN ISVAR:=TRUE; NAME:=SAVEID END
  300.               END
  301.                   ELSE
  302.                     BEGIN WRITE('Table full. Not done'); GAVEERR:=TRUE END;
  303.         IF SAVEINDEX<>0 THEN
  304.           BEGIN NAMETABLE[SAVEINDEX].VALUE:=ANS; PRIMARY:=TRUE END
  305.           END
  306.       END
  307.     ELSE
  308.           IF SAVETOK=UNRECIDV THEN
  309.             BEGIN WRITE('Unrecognized ID'); GAVEERR:=TRUE END
  310.       ELSE
  311.             BEGIN PRIMARY:=TRUE; ANS:=NAMETABLE[SAVEINDEX].VALUE END
  312.       END
  313.     ELSE
  314.       IF TOKENTYPE=FUCIDENV THEN (*FUNCTION*)
  315.     BEGIN
  316.       FUCNUM:=INDEX; (*INDEX SET BY GETIDENT*)
  317.       SCANNER;
  318.       PRIMARY:=EVALU8 (ANS)
  319.     END
  320.       ELSE
  321.         IF TOKENTYPE=LASTXV THEN
  322.        BEGIN SCANNER; ANS:=ANSWER; PRIMARY:=TRUE END
  323.         ELSE PRIMARY:=PARENEXPRESSION (ANS)
  324. END (*OF PRIMARY*);
  325.  
  326. BEGIN (*FACTOR*)
  327.   OK:=TRUE;
  328.   IF PRIMARY(RSLT1) THEN
  329.     WHILE OK AND (TOKENTYPE=UPARROWV) DO
  330.       BEGIN
  331.     SCANNER;
  332.     IF PRIMARY(RSLT2) THEN
  333.           IF RSLT1<=0 THEN
  334.             BEGIN
  335.           WRITE('Cannot calculate power');
  336.           OK:=FALSE;
  337.           GAVEERR:=TRUE
  338.         END
  339.           ELSE
  340.         RSLT1:=EXP(RSLT2*LN(RSLT1))
  341.     ELSE
  342.       OK:=FALSE
  343.       END
  344.   ELSE
  345.     OK:=FALSE;
  346.   IF OK THEN ANS:=RSLT1;
  347.   FACTOR:=OK
  348. END (*OF FACTOR*);
  349.  
  350. BEGIN (*TERM*)
  351.   OK:=TRUE;
  352.   IF FACTOR(RSLT1) THEN
  353.     WHILE OK AND (TOKENTYPE IN [STARV, SLASHV, LINEV]) DO
  354.       BEGIN
  355.         SAVEOP:=TOKENTYPE;
  356.     SCANNER;
  357.     IF FACTOR(RSLT2) THEN
  358.       CASE SAVEOP OF
  359.         STARV:     RSLT1:=RSLT1*RSLT2;
  360.         SLASHV:     IF RSLT2=0 THEN
  361.                BEGIN
  362.                  OK:=FALSE;
  363.                 GAVEERR:=TRUE;
  364.                 WRITE('Division by zero')
  365.               END
  366.             ELSE RSLT1:=RSLT1/RSLT2;
  367.         LINEV:    IF ROUND(RSLT2)=0 THEN
  368.               BEGIN
  369.                 OK:=FALSE;
  370.                 GAVEERR:=TRUE;
  371.                 WRITE('MOD by zero')
  372.               END
  373.             ELSE
  374.                   RSLT1:=ROUND(RSLT1) MOD ROUND(RSLT2)
  375.       END (*CASE*)
  376.     ELSE OK:=FALSE
  377.       END
  378.   ELSE OK:=FALSE;
  379.   IF OK THEN ANS:=RSLT1;
  380.   TERM:=OK
  381. END (*TERM*);
  382.  
  383.  
  384. BEGIN (*EXPRESS*)
  385.   OK:=TRUE;
  386.   IF TOKENTYPE IN [PLUSV,MINUSV] THEN
  387.     BEGIN CHANGESIGN:=(TOKENTYPE=MINUSV); SCANNER END
  388.   ELSE CHANGESIGN:=FALSE;
  389.   IF TERM(RSLT1) THEN
  390.     BEGIN
  391.       IF CHANGESIGN THEN RSLT1:=-RSLT1;
  392.       WHILE OK AND (TOKENTYPE IN [PLUSV,MINUSV]) DO
  393.         BEGIN
  394.           SAVEOP:=TOKENTYPE;
  395.           SCANNER;
  396.         IF TERM(RSLT2) THEN
  397.           CASE SAVEOP OF
  398.             PLUSV:    RSLT1:=RSLT1+RSLT2;
  399.             MINUSV:    RSLT1:=RSLT1-RSLT2
  400.           END
  401.         ELSE OK:=FALSE
  402.         END
  403.     END
  404.   ELSE OK:=FALSE;
  405.   EXPRESS:=OK;
  406.   IF OK THEN ANS:=RSLT1
  407. END (*OF EXPRESS*);
  408.  
  409. PROCEDURE INITABLES;
  410. BEGIN
  411.   ALPHA:=['A'..'Z'];
  412.   NUMERIC:=['0'..'9'];
  413.   OPERATORS:=['+','=','*','-','/','\','^','(',')','#'];
  414.   WITH NAMETABLE[1] DO
  415.     BEGIN NAME:='SIN     '; ISVAR:=FALSE END;
  416.   WITH NAMETABLE[2] DO
  417.     BEGIN NAME:='COS     '; ISVAR:=FALSE END;
  418.   WITH NAMETABLE[3] DO
  419.     BEGIN NAME:='TAN     '; ISVAR:=FALSE END;
  420.   WITH NAMETABLE[4] DO
  421.     BEGIN NAME:='LOG     '; ISVAR:=FALSE END;
  422.   WITH NAMETABLE[5] DO
  423.     BEGIN NAME:='LN      '; ISVAR:=FALSE END;
  424.   WITH NAMETABLE[6] DO
  425.     BEGIN NAME:='ABS     '; ISVAR:=FALSE END;
  426.   WITH NAMETABLE[7] DO
  427.     BEGIN NAME:='SQRT    '; ISVAR:=FALSE END;
  428.   WITH NAMETABLE[8] DO
  429.     BEGIN NAME:='E       '; ISVAR:=TRUE; VALUE:=2.718282 END;
  430.   WITH NAMETABLE[9] DO
  431.     BEGIN NAME:='PI      '; ISVAR:=TRUE; VALUE:=3.141593 END;
  432.   WITH NAMETABLE[10] DO
  433.     BEGIN NAME:='FAC     '; ISVAR:=FALSE END;
  434.   TOTALIDS:=10 (*BUILD IN NUMBER OF FUNCS & VARS*)
  435. END (*INITABLES*);
  436.  
  437. BEGIN (*CALCULATOR*)
  438.   ANSWER:=0;
  439.   INITABLES;
  440.   REPEAT
  441.     SETLENGTH(SOURCE,0);{---PASCAL/Z---}
  442.     GAVEERR:=FALSE;
  443.     J:=0;
  444.     WRITE('->');
  445.     READLN(SOURCE);
  446.     IF LENGTH(SOURCE)=0 THEN{EXIT(PROGRAM)}goto 999;
  447.     REPEAT GETCHAR UNTIL CH<>' '; (*GETNONBLANK*)
  448.     SCANNER;
  449.     ITSOK:=EXPRESS(TEMP) AND (TOKENTYPE=EOFV);
  450.     IF NOT ITSOK THEN
  451.       BEGIN
  452.     IF (TOKENTYPE=EOFV) AND NOT GAVEERR THEN
  453.       WRITE ('Unexpected end of expression')
  454.         ELSE IF NOT GAVEERR THEN WRITE('Illegal Symbol');
  455.         WRITELN(': Try Again')
  456.       END
  457.     ELSE
  458.       BEGIN WRITELN('    ',TEMP); ANSWER:=TEMP END
  459.   UNTIL FALSE;
  460. 999:{EXIT PROGRAM HERE}
  461. END (*EXPRESSION*).
  462.