	SUBROUTINE CALBIN(RETCD)
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
C *******************************************************
C *                                                     *
C *             SUBROUTINE  CALBIN                      *
C *                                                     *
C *******************************************************
C
C  SUBROUTINE CALBIN PERFORMS A BINARY OPERATION ON TWO CONSTANTS.
C
C
C
C  UPON ENTRANCE TO ROUTINE:
C	OPERAND1 IS IN STACK1  (ST1PT-1)
C	OPERAND2 IS ON TOP OF STACK2  (ST2PT-1)
C	OPERATOR IS BELOW OPERAND2  (ST2PT-2)
C  UPON EXIT:
C	RESULT IS IN STACK1
C	STACK2 HAS BEEN CLEANED UP
C
C  RETURN CODE	MEANING
C	1	NORMAL RETURN
C	2	OPERATION COMPLETE (RESULT HAS BEEN OUTPUT)
C	3	ERROR RETURN
C
C
C
C  MODIFICATION CLASSES: M3, M4, AND M8
C
C
C
C  CALBIN CALLS
C
C  CONTYP   CONVERTS CONSTANTS TO DIFFERENT DATA TYPES
C  ERRMSG   PRINTS OUT ERROR MESSAGES
C  MULADD   PERFORMS MULTIPLE PRECISION ADDITION
C  MULDIV   PERFORMS MULTIPLE PRECISION DIVISION
C  MULMUL   PERFORMS MULTIPLE PRECISION MULTIPLICATION
C  
C
C
C CALBIN IS CALLED BY POSTVL WHICH EVALUATES A POSTFIX EXPRESSION
C
C
C
C
C   VARIABLE     USE
C
C  EIGHT(8)      PICKS OUT A REAL CONSTANT FROM STACK.
C  FOUR(4)       PICKS OUT AN INTEGER CONSTANT FROM STACK.
C  I,J           HOLD TEMPORARY VALUES.
C  IA            FIRST BYTE OF OPERAND 1. THIS HOLDS THE INDEX INTO
C                VBLS OF A VARIABLE IF THE OPERATOR IS AN = SIGN.
C  ID            USED TO CONVERT DECISION TABLE LOGICAL*1 VALUE TO
C                AN InTEgeR*4 VALUE THAT CAN BE USED AS AN ARGUMENT
C                IN A CALL TO CONTYP.
C  INT,IHOLD     HOLD INTEGER*4 VALUES.
C  IOP           HOLDS THE BINARY OPERATOR.
C  IOP2          USED TO INDEX A COMPUTED GO.
C  ISW           HOLDS BASE FOR MULTIPLE PRECISION EXPONENTIATION
C  MINUS         VALUE IN THE 100TH BYTE OF A MULTIPLE PRECISION
C                NUMBER THAT IS USED TO INDICATE A NEGATIVE.
C  OP1TYP        TYPE OF OPERAND 1.
C  OP2TYP        TYPE OF OPERAND 2.
C  PLUS          VALUE IN THE 100TH BYTE OF A MULTIPLE PRECISION
C                NUMBER THAT IS USED TO INDICATE POSITIVE.
C  PT1,PT2       POINT TO ELEMENTS ON TOP OF STACKS 1 AND 2.
C  REAL,RHOLD    HOLD TEMPORARY REAL*8 VALUES.
C  RETCD         ERROR RETURN:  1 = O.K.   2 = RESULT WAS OUTPUT
C                3 = ERROR
C
C
C
C
C
C
C
C
C
C	SUBROUTINE CALBIN(RETCD)
	REAL*8 REAL,RHOLD,DFLOAT
C
	INTEGER*4 INT,IHOLD
C
	InTEgeR*4 LEVEL,NONBLK,LEND
	InTEgeR*4 VLEN(9)
	InTEgeR*4 IOP,IA,ID,IOP2,ISW
	InTEgeR*4 PLUS,MINUS
	InTEgeR*4 OLDTYP,VIEWSW,BASED
	InTEgeR*4 TYPE(RRWP,RCLP)
	InTEgeR*4 RETCD,RETCD2
	InTEgeR*4 OP1TYP,OP2TYP
	InTEgeR*4 ST1PT,ST2PT,ST1TYP(40),ST2TYP(40),ST1LIM,ST2LIM
	InTEgeR*4 PT1,PT2
C
	LOGICAL*1 STACK1(20,40),STACK2(20,40)
	InTEgeR*2 STK12(10,40)
	REAL*8 XVBLK
	EQUIVALENCE(STK12(1,1),STACK1(1,1))
	LOGICAL*1 AVBLS(20,27), DTBL1(9,9,8)
	LOGICAL*1 VBLS(8,RRWP,RCLP)
	EQUIVALENCE (XVBLK,VBLS(1,1,1))
	LOGICAL*1 EIGHT(8),FOUR(4)
	LOGICAL*1 LINE(80)
C
	EQUIVALENCE (EIGHT,REAL), (FOUR,INT)
C
	COMMON LEVEL,LINE,NONBLK,LEND,VIEWSW,BASED
	COMMON/V/ TYPE,AVBLS,VBLS,VLEN
	COMMON /STACK/STACK1,STACK2,ST1PT,ST2PT,ST1TYP,ST2TYP,
     ;         ST1LIM,ST2LIM
	COMMON /DECIDE/DTBL1
C
C
	DATA PLUS/0/,MINUS/1/
C
C
C
C
C
	RETCD=1
	PT1=ST1PT-1
	PT2=ST2PT-1
C
C
	IOP=ST2TYP(ST2PT-2)
	OP1TYP=ST1TYP(PT1)
	OP2TYP=ST2TYP(PT2)
C NOTE THAT IA IS UNUSED HERE... SAVE BIG DIMENSIONS
	IA=STACK1(1,PT1)
C Following logic requires that row and column numbers fit in
C 16 bits, though their product may be larger. Allow this,
C since larger sizes seem excessive for an interpreter anyhow.
	ID1=STK12(1,PT1)
	ID2=STK12(2,PT1)
C	CALL GETDM(STACK1(1,PT1),ID1,ID2)
C ****&&&& ABOVE GETS LOCS IN 2 DIM ARRAY OF VARIABLES
	IF (IOP.NE.200) GOTO 100
C
C
C
C AN = SIGN IS THE OPERATOR. THIS IS A SPECIAL CASE.
	IF(OP1TYP.GE.0) GO TO 5
C
C
C
C VARIABLE TO THE LEFT OF = SIGN HAS A DATA TYPE BUT NO VALUE
	OP1TYP=-OP1TYP
	ST1TYP(PT1)=OP1TYP
C
C
C
C OPERAND 2 COPIED INTO OLD OPERAND'S POSITION IN CASE MORE
C THAN 1 = SIGN IS PRESENT FOR EXPRESSIONS LIKE  I=J=2
5	J=VLEN(OP2TYP)
C	TYPE(IA)=OP1TYP
	CALL TYPSET(ID1,ID2,OP1TYP)
C	TYPE(ID1,ID2)=OP1TYP
C *&*****&&&&& NOTE TYPE ARRAY AND VBLS ARRAY NOW ARE HUGE
C  NOTE FURTHER THAT AVBLS IS OLD VBLS ARRAY. SWITCHED ON IF
C ID1 =< 27 AND ID2=1.
	DO 10 I=1,J
10	STACK1(I,PT1)=STACK2(I,PT2)
	CALL CONTYP (STACK1,PT1,OP2TYP,OP1TYP,RETCD2)
	GOTO (20,9999), RETCD2
	STOP 20
C
C
C THE SPECIFIED VARIABLE GETS NEW VALUE.
C ***&&&& HERE'S WHERE WE STORE A VALUE INTO A VARIABLE...
20	J=VLEN(OP1TYP)
	DO 30 I=1,J
C	VBLS(I,IA)=STACK1(I,PT1)
	IF(ID1.LE.27.AND.ID2.EQ.1) GOTO 22
C REPLACE VBLSET CALL WITH XVBLST CALL ON LAST PASS TO AVOID
C MULTIPLE REPLACEMENT OF STORAGE FOR EVERY PASS.
	VBLS(I,1,1)=STACK1(I,PT1)
	IF(I.EQ.J)CALL XVBLST(ID1,ID2,XVBLK)
C	CALL VBLSET(I,ID1,ID2,STACK1(I,PT1))
C	VBLS(I,ID1,ID2)=STACK1(I,PT1)
	GOTO 30
22	AVBLS(I,ID1)=STACK1(I,PT1)
C *****&&&&&
30	CONTINUE
	GOTO 10000
C
C
C  IOP2 VALUES 1="**"  2="*"   3="/"   4="+"   5="-"
100	IOP2=IOP-111
	GOTO (1000,2000,2000,2000,2000),IOP2
C
C
C    ********************************************
C    ***********  EXPONENTIATION  ***************
C    ********************************************
C
C
C  FIRST CONVERT TO PROPER TYPE
1000	ID=DTBL1(OP2TYP,OP1TYP,5)
	CALL CONTYP(STACK1,PT1,OP1TYP,ID,RETCD2)
	IF (RETCD2.EQ.2) GOTO 9999
	ID=DTBL1(OP2TYP,OP1TYP,6)
	CALL CONTYP (STACK2,PT2,OP2TYP,ID,RETCD2)
	IF (RETCD2.EQ.2) GOTO 9999
C
C
C  GOTO APPROPRIATE PLACE TO PERFORM OPERATION
	ID=DTBL1(OP2TYP,OP1TYP,8)
	GOTO (1100,1200,1300,1400,1500,1600,1700),ID
	STOP 1000
C
C
C  REAL**REAL
1100	DO 1104 I=1,8
1104	EIGHT(I)=STACK1(I,PT1)
	RHOLD=REAL
	DO 1108 I=1,8
1108	EIGHT(I)=STACK2(I,PT2)
	REAL=RHOLD**REAL
C
C
C  USED BY REAL**I
1109	DO 1110 I=1,8
1110	STACK1(I,PT1)=EIGHT(I)
C
C
C  USED BY I**REAL,I**I
1114	ST1TYP(PT1)=DTBL1(OP2TYP,OP1TYP,7)
	GOTO 10000
C
C
C
C  REAL**I
1200	DO 1204 I=1,8
1204	EIGHT(I)=STACK1(I,PT1)
	DO 1208 I=1,4
1208	FOUR(I)=STACK2(I,PT2)
	REAL=REAL**INT
	GOTO 1109
C
C
C
C  I**REAL (PARTS USED BY I**I)
1300	DO 1304 I=1,4
1304	FOUR(I)=STACK1(I,PT1)
	DO 1308 I=1,8
1308	EIGHT(I)=STACK2(I,PT2)
C
C DIFFERENT VERSIONS OF FORTRAN TREAT THE RESULT IN DIFFERENT WAYS.
C IF YOU WANT THE RESULT TO BE REAL, YOU MUST ALSO CHANGE DTBL1.
C
	INT=DFLOAT(INT)**REAL
1310	DO 1314 I=1,4
1314	STACK1(I,PT1)=FOUR(I)
	GOTO 1114
C
C
C
C  I**I
1400	DO 1404 I=1,4
1404	FOUR(I)=STACK1(I,PT1)
	IHOLD=INT
	DO 1408 I=1,4
1408	FOUR(I)=STACK2(I,PT2)
	INT=IHOLD**INT
	GOTO 1310
C
C
C
C  M8**I    (PARTS USED BY M10**I, M16**I)
1500	ISW=8
1501	IF(ST2PT.LE.ST2LIM)GO TO 1502
C
C
C STACK OVERFLOW
	CALL ERRMSG(9)
	GO TO 9999
C
C
C GET EXPONENT AS AN INTEGER
1502	DO 1504 I=1,4
1504	FOUR(I)=STACK2(I,PT2)
	IF (INT.GE.0) GOTO 1520
C
C
C EXPONENT NOT POSITIVE OR 0
	CALL ERRMSG (15)
	GOTO 9999
1520	IF (INT.GT.0) GOTO 1530
C
C
C I**0 = 1
	STACK1(20,PT1)=PLUS
	DO 1522 I=2,19
1522	STACK1(I,PT1)=0
	STACK1(1,PT1)=1
	GOTO 10000
C
C
C EXPONENT IS > 0
1530	INT=INT-1
C
C
C IF EXPONENT = 1 WE ARE DONE
	IF(INT.EQ.0)GO TO 10000
C
C
C EXPONENT IS > 1. COPY TO STACK 2 WHERE MULMUL EXPECTS THE OTHER
C FACTOR.
	DO 1534 I=1,20
1534	STACK2(I,ST2PT)=STACK1(I,PT1)
	ST2TYP(ST2PT)=ST1TYP(PT1)
C
C
C
C
1549	DO 1550 I=1,INT
	CALL MULMUL(PT1,ST2PT,RETCD2,ISW)
	IF(RETCD2.GE.2)GO TO 9999
1550	CONTINUE
	GOTO 10000
C
C  M10**I
1600	ISW=10
	GOTO 1501
C
C
C
C  M16**I
1700	ISW=16
	GOTO 1501
C
C
C
C
C
C
C
C  *****************************************
C  * MAKE CONVERSIONS APPROPRIATE FOR */+- *
C  *****************************************
2000	CONTINUE
	ID=DTBL1(OP2TYP,OP1TYP,1)
	CALL CONTYP (STACK1,PT1,OP1TYP,ID,RETCD2)
	IF (RETCD2.EQ.2) GOTO 9999
	IF(ID.EQ.0)GO TO 2010
	ST1TYP(PT1)=ID
	OP1TYP=ID
2010	ID=DTBL1(OP2TYP,OP1TYP,2)
	CALL CONTYP (STACK2,PT2,OP2TYP,ID,RETCD2)
	IF (RETCD2.EQ.2) GOTO 9999
	IF(ID.EQ.0)GOTO 2020
	ST2TYP(PT2)=ID
	OP2TYP=ID
C
2020	CONTINUE
C
C
C  GOTO SECTION ACCORDING TO OPERATION *=3000, /=4000,+=5000,-=6000
	GOTO (2100,3000,4000,5000,6000),IOP2
2100	STOP 2100
C
C
C
C
C
C
C  **********************************************
C  ***********  MULTIPLICATION  *****************
C  **********************************************
3000	ID=DTBL1(OP2TYP,OP1TYP,4)
	GOTO (3100,3200,3300,3300,3500,3600,3700,3300,3200),ID
	STOP 3000
C
C
C  ASCII (ALSO SUBTRACTION, MULTIPLICATION AND DIVISION)
3100	CALL ERRMSG (12)
	GOTO 9999
C
C
C  DECIMAL, REAL
3200	DO 3204 I=1,8
3204	EIGHT(I)=STACK1(I,PT1)
	RHOLD=REAL
	DO 3208 I=1,8
3208	EIGHT(I)=STACK2(I,PT2)
	REAL=RHOLD*REAL
3209	DO 3210 I=1,8
3210	STACK1(I,PT1)=EIGHT(I)
C
C
C  FOLLOWING USED BY OTHER SECTIONS
3220	ST1TYP(PT1)=DTBL1(OP2TYP,OP1TYP,3)
	GOTO 10000
C
C
C
C  HEX,INTEGER,OCTAL
3300	DO 3304 I=1,4
3304	FOUR(I)=STACK1(I,PT1)
	IHOLD=INT
	DO 3308 I=1,4
3308	FOUR(I)=STACK2(I,PT2)
	INT=IHOLD*INT
3309	DO 3310 I=1,4
3310	STACK1(I,PT1)=FOUR(I)
	GOTO 3220
C
C
C
C  M10
3500	CALL MULMUL (PT1,PT2,RETCD2,10)
C
C
C  FOLLOWING USED BY OTHER SECTIONS
3510	IF (RETCD2.EQ.2) GOTO 9999
	GOTO 3220
C
C
C
C  M8
3600	CALL MULMUL (PT1,PT2,RETCD2,8)
	GOTO 3510
C
C
C
C  M16
3700	CALL MULMUL (PT1,PT2,RETCD2,16)
	GOTO 3510
C
C
C
C
C
C
C  **************************************************
C  ******************  DIVISION  ********************
C  **************************************************
4000	ID=DTBL1(OP2TYP,OP1TYP,4)
	GOTO (3100,4200,4300,4300,4500,4600,4700,4300,4200),ID
	STOP 4000
C
C
C  DECIMAL,REAL
4200	DO 4204 I=1,8
4204	EIGHT(I)=STACK1(I,PT1)
	RHOLD=REAL
	DO 4208 I=1,8
4208	EIGHT(I)=STACK2(I,PT2)
	IF(REAL.NE.0.D0)GO TO 4210
	CALL ERRMSG(23)
	GO TO 9999
4210	REAL=RHOLD/REAL
	GOTO 3209
C
C
C  HEX,INTEGER,OCTAL
4300	DO 4304 I=1,4
4304	FOUR(I)=STACK1(I,PT1)
	IHOLD=INT
	DO 4308 I=1,4
4308	FOUR(I)=STACK2(I,PT2)
	IF(INT.NE.0)GO TO 4310
	CALL ERRMSG(23)
	GO TO 9999
4310	INT=IHOLD/INT
	GOTO 3309
C
C
C  M10
4500	CALL MULDIV (PT1,PT2,RETCD2,10)
	GOTO 3510
C
C
C  M8
4600	CALL MULDIV (PT1,PT2,RETCD2,8)
	GOTO 3510
C
C
C  M16
4700	CALL MULDIV (PT1,PT2,RETCD2,16)
	GOTO 3510
C
C
C
C
C
C **************************************************
C *****************  ADDITION  *********************
C **************************************************
C
5000	ID=DTBL1(OP2TYP,OP1TYP,4)
	GOTO (3100,5200,5300,5300,5500,5600,5700,5300,5200),ID
	STOP 5000
C
C
C  DECIMAL, REAL
5200	DO 5204 I=1,8
5204	EIGHT(I)=STACK1(I,PT1)
	RHOLD=REAL
	DO 5208 I=1,8
5208	EIGHT(I)=STACK2(I,PT2)
	REAL=RHOLD+REAL
	GOTO 3209
C
C
C  HEX,INTEGER,OCTAL
5300	DO 5304 I=1,4
5304	FOUR(I)=STACK1(I,PT1)
	IHOLD=INT
	DO 5308 I=1,4
5308	FOUR(I)=STACK2(I,PT2)
	INT=IHOLD+INT
	GOTO 3309
C
C
C  M10
5500	CALL MULADD (PT1,PT2,RETCD2,1)
	GOTO 3510
C
C
C  M8
5600	CALL MULADD (PT1,PT2,RETCD2,2)
	GOTO 3510
C
C
C  M16
5700	CALL MULADD(PT1,PT2,RETCD2,3)
	GOTO 3510
C
C
C
C
C
C
C  ***************************************************
C  ******************  SUBTRACTION  ******************
C  ***************************************************
C
6000	ID=DTBL1(OP2TYP,OP1TYP,4)
	GOTO (3100,6200,6300,6300,6500,6600,6700,6300,6200),ID
	STOP 6000
C
C
C  DECIMAL,REAL
6200	DO 6204 I=1,8
6204	EIGHT(I)=STACK1(I,PT1)
	RHOLD=REAL
	DO 6208 I=1,8
6208	EIGHT(I)=STACK2(I,PT2)
	REAL=RHOLD-REAL
	GOTO 3209
C
C
C  HEX,INTEGER,OCTAL
6300	DO 6304 I=1,4
6304	FOUR(I)=STACK1(I,PT1)
	IHOLD=INT
	DO 6308 I=1,4
6308	FOUR(I)=STACK2(I,PT2)
	INT=IHOLD-INT
	GOTO 3309
C
C
C  M10
6500	CALL MULADD (PT1,PT2,RETCD2,4)
	GOTO 3510
C
C
C  M8
6600	CALL MULADD (PT1,PT2,RETCD2,5)
	GOTO 3510
C
C
C  M16
6700	CALL MULADD (PT1,PT2,RETCD2,6)
	GOTO 3510
C
C
C
C
C
C	EXIT
9999	RETCD=3
C
C
C
10000	ST2PT=ST2PT-2
	RETURN
	END
