	SUBROUTINE CALC
C COPYRIGHT (C) 1983 GLENN EVERHART
C PERMISSION IS GIVEN TO ANYONE TO USE, DISTRIBUTE, OR COPY THIS
C PROGRAM FREELY BUT NOT TO SELL IT COMMERICALLY.
	INCLUDE 'VKLUGPRM.FTN'
C	PARAMETER RRW = 32
C	PARAMETER RCL = 32
C RRW=MAX REAL ROWS
C RCL=MAX REAL COLS
C RRW MUST BE 1 LARGER TO HANDLE 1ST 27 VARIABLES IN AVBLS
C VBLS AND TYPE DIMENSIONED RRW,RCL
C ***               CALC   MAINLINE                   ***
C
C THIS PROGRAM EVALUATES ARITHMETIC EXPRESSIONS INPUT TO IT
C AND ALLOWS VARIABLES TO BE ASSIGNED VALUES. IT FEATURES
C MULTIPLE PRECISION ARITHMETIC IN BASE 10, OCTAL, AND
C HEXADECIMAL. SEE CALC.MEM FOR A COMPLETE DESCRIPTION IN 
C THE FORM OF A USERS GUIDE. TYPE ? TO OBTAIN A LIST OF
C POSSIBLE COMMANDS.
C
C    CALC CALLS
C
C  ASSIGN    OPENS A FILE AND ASSIGNS IT TO A LOGICAL I/O UNIT.
C  CLOSE     CLOSES A FILE ASSOCIATED WITH A LOGICAL I/O UNIT.
C  CMND      DETERMINES WHAT CALC COMMAND IS REQUIRED.
C  ERRCX     CHECKS THE EXPRESSION IN AN INPUT LINE FOR SYNTAX ERRORS.
C  ERRMSG    PRINTS OUT ERROR MESSAGES.
C  EXIT      RETURNS TO OPERATING SYSTEM.
C  GETMCR    GETS THE COMMAND LINE USED TO INVOKE CALC. IF AN ARGUMENT
C            IS PRESENT, CALC EXITS AFTER THAT ONE COMMAND IS EXECUTED.
C  INPOST    CONVERTS AN INFIX EXPRESSION TO POSTFIX FORM.
C  LIST      LISTS THE LEGAL CALC COMMANDS.
C  POSTVL    CONVERTS AN EXPRESSION IN POSTFIX NOTATION ON STACK 1 TO
C            A VALUE.
C  SLEND     FINDS THE LAST NON-BLANK IN LINE(80).
C  VAROUT    PRINTS OUT THE VALUE OF A VARIABLE.
C  ZNEG      DETERMINES IF A VARIABLE IS POSITIVE IN VALUE
C
C
C
C   VARIABLE      USE
C
C  BASED        DEFAULT BASE WHEN CONSTANTS ARE ENTERED.
C  BLANK        ' '
C  DIGITS(16,3) HOLDS DECIMAL, OCTAL, AND HEXADECIMAL DIGITS. THE
C               SECOND SUBSCRIPT IS
C                     1 FOR DECIMAL
C                     2 FOR OCTAL
C                     3 FOR HEXADECIMAL
C  I,J          HOLD TEMPORARY VALUES.
C  ITCNTV(6)    INDEXED BY LEVEL. 0 INDICATES THAT NO ITERATION ON THE
C               INDIRECT COMMAND FILE IS TO TAKE PLACE. IF POSITIVE, IT
C               HOLDS THE INDEX INTO VBLS AND REPRESENTS THE VARIABLE
C               USED TO CONTROL ITERATION.
C		THIS VARIABLE IS GUARANTEED TO BE 1-27.
C  LEND         POINTS TO LAST NON-BLANK CHARACTER IN LINE(80)
C  LEVEL        HOLDS THE LOGICAL I/O UNIT WHERE THE NEXT CALC COMMAND
C               LINES COME FROM.
C  LINE(80)     COMMAND INPUT LINE.
C  NONBLK       POINTS TO LAST NON-BLANK FOUND IN LINE(80).
C  ONCE         HOLDS 1 IF ONLY ONE COMMAND LINE IS TO BE EXECUTED,
C               0 OTHERWISE.
C  STAR         '*'
C  VIEWSW           VIEW SWITCH
C                    0 = OUTPUT ERROR MESSAGES
C                    1 = OUTPUT ERROR MESSAGES AND FILE COMMAND LINES
C                    2 = OUTPUT ERROR MESSAGES AND VALUE OF EXPRESSIONS
C                        EVALUATED.
C                    3 = OUTPUT EVERYTHING
C  WHAT         '?' SIGNIFIES THAT A LIST OF POSSIBLE COMMANDS
C               SHOULD BE OUTPUT.
C
C	MODIFIED	REASON
C
C	18-MAY-1981	DELETED LINE THAT CAUSED DEFAULT BASE TO BE RESET
C			WHEN AN ERROR OCCURS (PB)
C
C	18-MAY-1981	ADDED CODE AT LINES 106 TO 108 TO CONVERT FROM LOWER
C			TO UPPER CASE  (PB)
C
C CHANGED TO SUBROUTINE GCE TO ALLOW EXTERNAL CONTROL OF CALCULATOR.
C
	INTEGER*2 LEVEL,NONBLK,LEND
	INTEGER*2 RETCD,VIEWSW,BASED
	INTEGER*2 ONCE
	INTEGER*2 ZNEG,ITCNTV(6)
C
	LOGICAL*1  LINE(80),WHAT,STAR,QUOTE
	LOGICAL*1 ALPHA(27),COMMA,BLANK,RPAR,LPAR,EQ
	LOGICAL*1 DIGITS(16,3)
	INTEGER*2 OSWIT,OCNTR,ILNFG,ILNCT
	LOGICAL*1 OARRY(100),ILINE(106)
	COMMON/OAR/OSWIT,OCNTR,OARRY
	COMMON/ILN/ILNFG,ILNCT,ILINE
C
	COMMON  LEVEL,LINE,NONBLK,LEND,VIEWSW,BASED
	COMMON/KLVL/KLVL
	COMMON  /CONS/ALPHA,COMMA,BLANK,RPAR,LPAR,EQ
	COMMON /DIGV/ DIGITS
	COMMON/ITERA/ITCNTV
C
	DATA  WHAT/'?'/, STAR/'*'/, QUOTE/''''/
	DATA ONCE/0/
C
C
C
C LOGICAL I/O UNIT 1 IS ASSIGNED TO THE INVOKING TERMINAL
C IF YOU DON'T WANT TO RISK THE BUILDER TASK BUILDING (LINKING)
C THE MODULES PROPERLY, PUT IN A
	IF(KLVL.EQ.1)LEVEL=KLVL
	ONCE=0
	IF(ILNFG.NE.0) GOTO 6000
	CALL ASSIGN (1,'TT:')
6000	CONTINUE
C CHANGE TI: TO TT: FOR VMS.
C THE ADVANTAGE OF NOT DOING THIS IS THAT YOU CAN CREATE AN OUTPUT
C TEST FILE TO DISK TO HELP VERIFY CORRECTNESS AFTER A CHANGE TO THE
C SOURCE HAS BEEN MADE.
C
C
C
C GET MCR COMMAND LINE (RSX11-M CALL)
	IF(ILNFG.EQ.0)GOTO 6010
	IF(ILNCT.GT.0)GOTO 6010
C INVALID INPUTS...NO LINE TO DO BUT FLAGGED TO DO. CLEAN UP.
	ILNFG=0
	RETURN
6010	CONTINUE
	IF(ILNFG.NE.0.AND.ILNCT.GT.0)GOTO 6001
C ++++++
C FOR DEC FORTRAN:
C	CALL GETMCR(LINE,LEND)
C	IF(LEND)20,20,5
C FOR NON-DEC FORTRAN:
	GOTO 20
C ++++++  END OF CHOICES...
5	CONTINUE
	GOTO 6003
6001	CONTINUE
	DO 6007 LENDX=1,80
6007	LINE(LENDX)=32
	IF(ILNFG.EQ.1)ONCE=1
	DO 6002 LENDX=1,ILNCT
	LINE(LENDX)=ILINE(LENDX)
	IF(LINE(LENDX).GT.0.AND.LINE(LENDX).LT.32)LINE(LENDX)=32
C LEAVE NAY EXISTING NULLS IN.
6002	CONTINUE
	LEND=ILNCT
CC NULL TERMINATE THE LINE TO ENSURE WE END SOMEWHERE.
C	ICCC=MIN0(80,(LEND+1))
C	LINE(ICCC)=0
	GOTO 103
6003	CONTINUE
	DO 6 NONBLK=1,7
	IF(LINE(NONBLK).EQ.BLANK)GO TO 7
	IF(LINE(NONBLK).EQ.13)GO TO 20
6	CONTINUE
	STOP 6
7	NONBLK=NONBLK+1
	ONCE=1
	GO TO 106
C
C  ERROR RESET
10	IF(LEVEL.LE.1) GO TO 12
	CALL CLOSE(LEVEL)
	LEVEL=LEVEL-1
	GO TO 10
12	CONTINUE
	VIEWSW=3
C
C
C  GET NEXT INPUT LINE
20	CONTINUE
	LINE(1)=0
	LINE(2)=0
	IF(ONCE.EQ.1.AND.LEVEL.LE.1) RETURN
C20	IF(ONCE.EQ.1.AND.LEVEL.EQ.1) CALL EXIT
C	IF (ILNFG.NE.0.AND.ILNCT.GT.0)GOTO 6004
	IF (LEVEL.LE.1.AND.ILNFG.NE.0.AND.ILNCT.GT.0)RETURN
	IF(LEVEL.LT.1)RETURN
	IF(ILNFG.EQ.0.AND.LEVEL.EQ.1)WRITE(1,22)
22	FORMAT(' CALC>',$)
C
C
	READ (LEVEL,24,END=900,ERR=1000) LINE
24	FORMAT (80A1)
C	GOTO 6005
C SECTION BELOW COMMENTED OUT BECAUSE IT SHOULD NEVER BE CALLED (GCE).
C6004	CONTINUE
C	DO 6006 LENDX=1,80
C6006	LINE(LENDX)=32
CC ABOVE BLANKS OUT LINE ARRAY
C	DO 6007 LENDX=1,ILNCT
C6007	LINE(LENDX)=ILINE(LENDX)
CC ABOVE COPIES INPUT FROM OUR CALLER...
C6005	CONTINUE
C
C
C
C FIND LAST NONBLANK, SAVE POSITION WITH VARIABLE 'LEND'
	CALL SLEND(RETCD)
	GO TO(30,20),RETCD
	STOP 30
30	CONTINUE
C
C
C
	IF(ILNFG.EQ.0.AND.ILNCT.GT.0)GOTO 103
C SHOW WHAT WAS READ FROM FILE
	IF(LEVEL.NE.1.AND.(VIEWSW.EQ.1.OR.VIEWSW.EQ.3))
     1 WRITE(1,40)LEVEL,(LINE(I),I=1,LEND)
40	FORMAT (' CALC<',I1,'>',80A1)
103	CONTINUE
C NULL TERMINATE THE LINE TO ENSURE WE END SOMEWHERE.
	ICCC=MIN0(80,(LEND+1))
	LINE(ICCC)=0
C
C  IDENTIFY FIRST NON-BLANK
	DO 104 NONBLK=1,LEND
	IF (LINE(NONBLK).NE.BLANK) GOTO 106
104	CONTINUE
	RETURN
C	STOP 104
C
C CONVERT LOWER CASE TO UPPER CASE
106	DO 108 I=NONBLK,LEND
	J=LINE(I)
	IF (I.EQ.NONBLK) GOTO 107
	IF (LINE(I-1).EQ.QUOTE) GOTO 108
107	IF(J.GE.97.AND.J.LE.122) LINE(I)=J-32
108	CONTINUE
C
C  SEE IF A LIST OF POSSIBLE COMMANDS SHOULD BE PRINTED
	IF (LINE(NONBLK).NE.WHAT) GOTO 110
	CALL LIST
	GOTO 20
C
C  SEE IF IT IS A COMMAND
110	IF (LINE(NONBLK).NE.STAR) GOTO 120
	CALL CMND (RETCD)
	GOTO (20,115,10,6120), RETCD
6120	RETURN
C	STOP 110
C
C
C A READ COMMAND WAS EXECUTED SO LINE HOLDS THE NEW COMMAND LINE.
115	CALL SLEND(RETCD)
	GO TO (103,20),RETCD
	RETURN
C	STOP 115
C
C  SEE IF ONLY ONE ALPHA CHARACTER
120	J=NONBLK+1
	IF (LEND.NE.NONBLK) GOTO 130
	DO 124 I=1,27
	IF (LINE (NONBLK).EQ.ALPHA(I)) GOTO 126
124	CONTINUE
C
C ALLOW FOR A SINGLE DIGIT TO BE ASSIGNED TO %
	DO 125 I=1,10
	IF(LINE(NONBLK).EQ.DIGITS(I,1))GO TO 130
125	CONTINUE
C
C
C ALLOW FOR ENTERING THE ASCII BLANK
	IF(LINE(NONBLK).EQ.QUOTE)GO TO 130
	I=1
	GOTO 1001
C
C  OUTPUT VALUE OF SINGLE VARIABLE
126	CALL VAROUT(I,1)
	GOTO 20
C
C
C CHECK INPUT FOR SYNTAX ERRORS
130	CALL ERRCX (RETCD)
	GOTO (140,10),RETCD
	RETURN
C	STOP 130
C
C  CHANGE FROM INFIX TO POSTFIX NOTATION
140	CALL INPOST (RETCD)
	GOTO (150,10), RETCD
C
C
C EVALUATE EXPRESSION
150	CONTINUE
	CALL POSTVL(RETCD)
	GOTO(20,10),RETCD
	RETURN
C	STOP 150
C
C
C  EXIT
900	CONTINUE
	IF (LEVEL.EQ.1) RETURN
C	IF (LEVEL.EQ.1) CALL EXIT
	IF(ITCNTV(LEVEL).EQ.0)GOTO 910
	IF(ZNEG(ITCNTV(LEVEL)).EQ.1)GO TO 910
C
C VALUE OF ITERATION VARIABLE IS POSITIVE SO REWIND FILE
C AND EXECUTE AGAIN.
	REWIND LEVEL
	GO TO 20
C
C
C EXIT FROM THIS LEVEL BY CLOSING THE FILE AND DECREASING VALUE
C OF LEVEL BY ONE.
910	CALL CLOSE(LEVEL)
	LEVEL=LEVEL-1
	GOTO 20
C
C
C
C *** ERROR PROCESSING ***
1000	I=27
1001	CALL ERRMSG(I)
	GO TO 10
	END
