C++********************************************************************* 
C
C POLISH.F                    
C              CHANGED SOME ARRAYS FROM CHAR. TO INT FOR IBM JAN 2000 AL
C              READ(EXPR,FMTR LEAK                           AUG 2002 AL
C              SIMPLIFIED NUMBER INTERPRETATION              AUG 2002 AL
C              STACK LEVEL & LOWERCASE                       DEC 2005 AL
C
C **********************************************************************
C=* FROM: SPIDER - MODULAR IMAGE PROCESSING SYSTEM.   AUTHOR: J.FRANK  *
C=* Copyright (C) 1985-2005  Health Research Inc.                      *
C=*                                                                    *
C=* HEALTH RESEARCH INCORPORATED (HRI),                                *   
C=* ONE UNIVERSITY PLACE, RENSSELAER, NY 12144-3455.                   *
C=*                                                                    *
C=* Email:  spider@wadsworth.org                                       *
C=*                                                                    *
C=* This program is free software; you can redistribute it and/or      *
C=* modify it under the terms of the GNU General Public License as     *
C=* published by the Free Software Foundation; either version 2 of the *
C=* License, or (at your option) any later version.                    *
C=*                                                                    *
C=* This program is distributed in the hope that it will be useful,    *
C=* but WITHOUT ANY WARRANTY; without even the implied warranty of     *
C=* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  *
C=* General Public License for more details.                           *
C=*                                                                    *
C=* You should have received a copy of the GNU General Public License  *
C=* along with this program; if not, write to the                      *
C=* Free Software Foundation, Inc.,                                    *
C=* 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.      *
C=*                                                                    *
C **********************************************************************
C
C  POLISH(ILEVEL,EXPR,NLET,IPOLSH,NPOL,VAL,NVAL,IRTFLG)
C
C  PURPOSE: PARSE INFIX EXPESSION INTO POSTFIX EXPESSION
C
C  PARAMETERS:
C	ILEVEL     STACK LEVEL                                   (SENT)
C       EXPR       CHARACTER STRING CONTAINING EXPRESSION        (SENT)
C	NLET       LENGTH OF EXPR                                (SENT)
C	IPOLSH     INT ARRAY RETURNS POSTFIX EXPRESSION      (RETURNED)
C       NPOL       NO. OF ELEMENTS IN IPOLSH ARRAY           (RETURNED)
C       VAL        ARRAY STORES VALUES WHICH INDEX BY        (RETURNED)
C                        POLISH'S ELEMENTS
C       NVAL       NO. OF ELEMENTS USED IN VAL               (RETURNED)
C       IRTFLG     ERROR FLAG                                (RETURNED)
C
C FOR VAL INDEX
C ASCII(N) - ASCII(0) FOR N FROM 1 TO Z ON THE ASCII TABLE
C FOR MATH FUNCTION ARGUMENTS
C       PAD -> a       
C       SIN -> b
C       EXP -> c
C       LOG -> d
C       COS -> e
C       SQR -> f
C       LON -> g (NATURAL LOGARITHM)
C       INT -> h
C       ABS -> i
C       ATA -> j
C       ASI -> k
C       ACO -> l 
C       TAN -> m
C       RAN -> n   [0,1] uniform distribution
C       RNN -> o   (0,1) normal distribution
C       CHANGE THE SIGN -> p
C
C THE SUBROUTINE TRANSFORMS THE EXPRESSION FROM A TOKEN TO A SINGLE
C FOR EXAMPLE EXPRESSION 43+COS(6) -> 1+e(2)
C CONVERT FROM INFIX TO POSTFIX NOTATION
C  12E+	
C
C  NOTE:  TO ADD A NEW MATH FUNCTION:
C     1. CHOOSE A SEQUENTIAL LETTER FOR SUBSTITUTING A MATH FUNCTION
C
C **********************************************************************

	SUBROUTINE POLISH(ILEVEL,EXPR,NLET,IPOLSH,NPOL,
     &                        VAL,NVAL,IRTFLG)

        COMMON /UNITS/  LUNC,NIN,NOUT,NECHO,IFOUND,NPROC,NDAT

        CHARACTER(LEN=*)  :: EXPR

        INTEGER,PARAMETER :: IVALEN  = 40  ! RPN LENGTH LIMIT
        INTEGER,PARAMETER :: IRPNLEN = 80  ! RPN LENGTH LIMIT
        INTEGER,PARAMETER :: NFUNC  = 15   ! 

	INTEGER           :: IPOLSH(IRPNLEN),IEXPR1(IRPNLEN)
	INTEGER           :: ISTACK(IRPNLEN),ISTP(10)
        REAL              :: VAL(IVALEN)
	LOGICAL           :: FP,BGS,UNITARY,POWER

        CHARACTER *80   MSG
        CHARACTER *7    FRMT
        CHARACTER *3    TCHR
        CHARACTER *1    CTEMP,CNEXT,MINUS
	CHARACTER *3    FUNT(NFUNC)

	DATA  FUNT/
     &  'PAD','SIN','EXP','LOG','COS','SQR','LON','INT',
C         a     b     c     d     e     f     g     h
     &  'ABS','ATA','ASI','ACO','TAN','RAN','RNN'/
C         i     j     k     l     m     n     o
C       'p'  RESERVED FOR UNITARY OPERATIONS!
	DATA  MINUS/'p'/

C       SET ERROR RETURN
        IRTFLG = 1

        IEXPR1  = 0
        ISTACK  = 0
        IPOLSH  = 0

	K       = 1
	J       = 1
	I       = 0
	BGS     = .TRUE.
	UNITARY = .FALSE.

C       POSITION ON A STACK (ISTP) OF UNITARY OPERATIONS
	LISTP   = 0

C       PARANTHESIS NESTING LEVEL IS ON THE STACK
        POWER = .FALSE.
        LPOW  = 0

C       -------------- LOOP ----------------------------------------
C       LEXICAL ANALYSIS	
40	I = I + 1
	IF (I .GT. NLET) GOTO 41

        CTEMP = EXPR(I:I)

C       ALL THE SPACES ARE ASSUMED TO BE REMOVED

	IF (BGS) THEN
           IF (CTEMP.EQ. '+')  THEN
C             IGNORE UNITARY +
	      GOTO 41

           ELSEIF (CTEMP.EQ.'-')  THEN
C             UNITARY OPERATION   MINUS SIGN
              IEXPR1(K)   = ICHAR(MINUS)
              IEXPR1(K+1) = ICHAR('(')
              K = K + 2
C             HERE PUSH ON STACK
              LISTP = LISTP+1
              ISTP(LISTP) = 0
              UNITARY     = .TRUE.
              I           = I + 1
	      IF (I .GT. NLET)  THEN
                 CALL ERRT(101,' EXPRESSION CANNOT END WITH -',NE)
                 RETURN
              ENDIF
              CTEMP = EXPR(I:I)

           ELSE
              BGS = .FALSE.           
           ENDIF
	ENDIF

	IF (CTEMP .EQ. '(') THEN
C          LEFT PARENTHESIS
           IF (POWER) LPOW = LPOW+1
           IF (UNITARY) THEN
C             BEGIN NEW EXPRESSION
              ISTP(LISTP) = ISTP(LISTP)+1
              BGS = .TRUE.
           ELSE
              BGS = .TRUE.
           ENDIF
           IEXPR1(K) = ICHAR(CTEMP)
           K          = K + 1
           GOTO 41

	ELSEIF (CTEMP.EQ.')') THEN
C          RIGHT PARENTHESIS
           IEXPR1(K) = ICHAR(CTEMP)
           K          = K + 1
           IF (UNITARY)  THEN
              BGS = .FALSE.
C             POP FROM THE STACK, IF END OF STACK UNITARY=.FALSE.
              ISTP(LISTP) = ISTP(LISTP)-1
              IF (ISTP(LISTP) .EQ. 0)  THEN
                 LISTP = MAX(LISTP-1,0)
                 IF (LISTP .EQ. 0)  UNITARY = .FALSE.
C                SEE IF THE NEXT OPERATION IS '**', IF YES DO NOTHING
                 IF (I+2 .LE. NLET) THEN
                    IF (EXPR(I+1:I+2) .EQ. '**')  THEN
                       IF (POWER)  THEN
                          CALL ERRT(101,
     &                       'TOO MANY NESTED POWER OPERATORS',NE)
                          RETURN
                       ENDIF
                       POWER = .TRUE.
                       LPOW  = 0
                       GOTO 41
                    ENDIF
                 ENDIF
                 IEXPR1(K) = ICHAR(')')
                 K         = K + 1
              ENDIF
           ENDIF
           IF (POWER) THEN
              LPOW = LPOW-1
              IF (LPOW .EQ. 0)  THEN
                 POWER = .FALSE.
                 IEXPR1(K) = ICHAR(')')
                 K         = K + 1
              ENDIF
           ENDIF
           GOTO 41

        ELSEIF (I+1 .LE. NLET)  THEN
           IF (EXPR(I:I+1) .EQ. '**') THEN
              IEXPR1(K) = ICHAR('^')
              K         = K+1
              I         = I+1
              GOTO 41
           ENDIF
        ENDIF

        IF (CTEMP  .EQ. '[') THEN
C          [] IS RESERVED FOR REGISTERS (SYMBOLS ALREADY SUBSTTUTED OUT)

           CALL REG_GET_VAR(ILEVEL,EXPR(I:),.FALSE.,VALDUM,
     &                      IREG,IENDVAR,IER)
	   IF (IER .NE. 0)  THEN
C             ERRT CALLED IN REG_GET_VAR
              WRITE(NOUT,*)'  *** NO REGISTER VARIABLE: ',EXPR(I:)
              RETURN
           ENDIF

           I = I + IENDVAR - 1 

          VAL(J)     = IREG
          IEXPR1(K)  = (127+J)
          J          = J+1
          K          = K+1

          IF (UNITARY) THEN
             IF (BGS) THEN
                BGS = .FALSE.
C               POP FROM THE STACK, IF END OF STACK UNITARY= .FALSE.
                LISTP = MAX(LISTP-1,0)
                IF (LISTP .EQ. 0)  UNITARY= .FALSE.
C               SEE IF THE NEXT OPERATION IS '**', IF YES DO NOTHING
                IF (I+2 .LE. NLET) THEN
                   IF (EXPR(I+1:I+2) .EQ. '**')  THEN
                      IF (POWER)  THEN
                         CALL ERRT(101,
     &                   'TOO MANY NESTED POWER OPERATORS',NE)
                         RETURN
                      ENDIF
                      POWER = .TRUE.
                      LPOW  = 0
                      GOTO 41
                   ENDIF
                ENDIF
                IEXPR1(K) = ICHAR(')')
                K         = K + 1
             ENDIF
          ENDIF
          IF (POWER .AND. LPOW .EQ.0) THEN
             POWER = .FALSE.
             IEXPR1(K) = ICHAR(')')
             K         = K + 1
          ENDIF
	
        ELSEIF (CTEMP .GE. 'A') THEN

C          MATH FUNCTIONS PARSING BEGINS HERE
C          SUBSTITUTE LETTERS FOR MATH FUNCTIONS
	
           IF (I+2 .LE. NLET)  THEN
              TCHR = EXPR(I:I+2)
              CALL SSUPCAS(TCHR)  !COULD BE LOWERCASE
              DO  L=1,NFUNC
                 IF (TCHR .EQ. FUNT(L)) GOTO  51
              ENDDO
              GOTO 52

C             CODE FUNCTION BY A SMALL LETTER
51            IEXPR1(K) = (L - 1 + ICHAR('a'))
	      K = K+1
	      I = I+2
              GOTO 41

           ENDIF
52         IF (I+1 .LE. NLET)  THEN
              IF (EXPR(I:I+1) .EQ. 'P1' .OR. EXPR(I:I+1) .EQ. 'p1') THEN
C                PIXEL OPERATIONS FOR 'AR' USE
                 IF (J .GT. IVALEN)  THEN
                    CALL ERRT(101,'EXPRESSION TOO LONG',NE)
                    RETURN
                 ENDIF

C                RESERVE PLACE FOR PIXEL IN VAL ARRAY
                 VAL(J)    = 1.0
                 IEXPR1(K) = (200+J)
                 K = K+1
                 I = I+1
                 J = J+1
                 IF (UNITARY)  THEN
                    IF (BGS) THEN
                       BGS = .FALSE.
C                      POP FROM THE STACK, IF END OF STACK UNITARY= .FALSE.
                       LISTP = MAX(LISTP-1,0)
                       IF (LISTP .EQ. 0)  UNITARY = .FALSE.
C                      SEE IF THE NEXT OPERATION IS '**', 
C                      IF YES DO NOTHING
                       IF (I+2 .LE. NLET) THEN
                          IF (EXPR(I+1:I+2) .EQ. '**')  THEN
                             IF (POWER)  THEN
                                CALL ERRT(101,
     &                          'TOO MANY NESTED POWER OPERATORS',NE)
                                RETURN
                             ENDIF
                             POWER = .TRUE.
                             LPOW  = 0
                             GOTO 41
                          ENDIF
                       ENDIF
                       IEXPR1(K) = ICHAR(')')
                       K         = K + 1
                    ENDIF
                 ENDIF
                 IF (POWER .AND. LPOW .EQ. 0) THEN
                    POWER     = .FALSE.
                    IEXPR1(K) = ICHAR(')')
                    K         = K + 1
                 ENDIF
                 GOTO 41
              ENDIF
           ENDIF

       ELSEIF (CTEMP .EQ. '+' .OR. CTEMP .EQ. '-' .OR.
     &         CTEMP .EQ. '*' .OR. CTEMP .EQ. '/' .OR.
     &         CTEMP .EQ. '^') THEN
C         ARITHMETIC OPERATION +-*/
          IEXPR1(K) = ICHAR(EXPR(I:I))
          K         = K + 1

       ELSEIF (CTEMP .EQ.'.' .OR. (CTEMP.GE.'0'.AND.CTEMP.LE.'9')) THEN
C         A NUMBER IN EXPRESSION

          IGO  = I
          INOT = VERIFY(EXPR(IGO:NLET),'.Ee0123456789')
          I    = NLET
          IF (INOT .GT. 0) THEN
             I = IGO + INOT - 2
             IF (EXPR(I:I) .EQ. 'E' .OR. EXPR(I:I) .EQ. 'e') THEN
C               CAN HAVE INCLUDED '+" or '-'
                INOT  = VERIFY(EXPR(I+2:NLET),'.Ee0123456789')
                IF (INOT .GT. 0) THEN
                   I = I + INOT
                ELSE
                   I = NLET
                ENDIF
             ENDIF
          ENDIF

c          WRITE(NOUT,9009) INOT,IGO,I,EXPR(IGO:I)
c9009      FORMAT('inot: ',i2,'  EXPR(',i2,':',i2,') :'A)

C         EVALUATE THE NUMBER
          IF (J .GT. IVALEN)  THEN
              CALL ERRT(101,'EXPRESSION TOO LONG',NE)
              RETURN
          ENDIF
          IEXPR1(K) = (J+48)
          READ(EXPR(IGO:I),'(F20.0)',IOSTAT=IER) VAL(J)

	   IF (IER .NE. 0)  THEN
              WRITE(NOUT,*) 'IN EXPRESSION: ',EXPR(IGO:I)
              CALL ERRT(101,'READING NUMBER',NE)
              RETURN
           ENDIF

	   J = J + 1
	   K = K + 1

 30	   FORMAT(I1)
        
           IF (UNITARY)  THEN
              IF (BGS) THEN
                 BGS = .FALSE.
C                POP FROM STACK, IF END OF STACK UNITARY= .FALSE.
                 LISTP = MAX(LISTP-1,0)
                 IF (LISTP .EQ.0)  UNITARY= .FALSE.
C                SEE IF THE NEXT OPERATION IS '**', IF YES DO NOTHING
                 IF (I+2 .LE. NLET) THEN
                    IF (EXPR(I+1:I+2) .EQ. '**')  THEN
                       IF (POWER)  THEN
                          CALL ERRT(101,
     &                       'TOO MANY NESTED POWER OPERATORS',NE)
                          RETURN
                       ENDIF
                       POWER= .TRUE.
                       LPOW=0
                       GOTO 41
                    ENDIF
                 ENDIF
                 IEXPR1(K) = ICHAR(')')
                 K          = K + 1
              ENDIF
           ENDIF
           IF (POWER .AND. LPOW .EQ.0) THEN
              POWER= .FALSE.
              IEXPR1(K) = ICHAR(')')
              K          = K + 1
           ENDIF
        ELSE
C          UNEXPECTED CHARACTER IN THE EXPRESSION
           MSG = 'UNEXPECTED CHARACTER IN EXPRESSION: '//CTEMP//CHAR(0)
           NCHARE = lnblnkn(MSG)
           CALL ERRT(101,MSG(:NCHARE),NE)
           RETURN
        ENDIF

C       END OF NUMBER PROCESSING LOOP

41	IF (I .LT. NLET) GOTO 40

C       --------------------- END LOOP ------------------------

C       CONVERT FROM INFIX TO POSTFIX
C       SYNTAX ANALYSIS
        NVAL       = J-1
        IEXPR1(K)  = ICHAR(')')
	NCHAR2     = K+1
	IPNT       = 1
	ITOP       = 1
	ISTACK(1)  = ICHAR('(')
	IRANK      = 0
	I          = 0

4	NEXT = IEXPR1(IPNT)
	IPNT = IPNT+1
	IF (IPNT .GT. NCHAR2) THEN
C          ALL DONE, CAN RETURN NOW
	   IF (ITOP .NE.0) THEN
	      CALL ERRT(43,'POLISH',NE)
              RETURN
	   ENDIF
           J      = 1
           IRTFLG = 0
           NPOL   = I
           RETURN
        ENDIF

	IF (ITOP .LT. 1)  THEN
           WRITE(NOUT,*) ' *** INVALID EXPRESSION: ',EXPR
	   CALL ERRT(101,'INVALID ARITHMETIC EXPRESSION',NE)
           RETURN
	ENDIF

7       CONTINUE
        IF (NEXT .EQ. ICHAR('+') .OR. NEXT.EQ. ICHAR('-')) THEN
          NFQT = 1
        ELSEIF (NEXT .EQ. ICHAR('*') .OR. 
     &          NEXT .EQ. ICHAR('/')) THEN
          NFQT = 3
        ELSEIF (NEXT .EQ. ICHAR('^')) THEN
          NFQT = 6
        ELSEIF (NEXT .EQ. ICHAR('(')) THEN
          NFQT = 9
        ELSEIF (NEXT .EQ. ICHAR(')')) THEN
          NFQT = 0
        ELSE
          NFQT = 7
        ENDIF

        ITEMP = ISTACK(ITOP)
        IF (ITEMP .EQ. ICHAR('+') .OR. ITEMP .EQ. ICHAR('-')) THEN
           NGQT = 2
        ELSEIF (ITEMP .EQ. ICHAR('*') .OR. ITEMP .EQ. ICHAR('/')) THEN
            NGQT = 4
        ELSEIF (ITEMP .EQ. ICHAR('^')) THEN
            NGQT = 5
        ELSEIF (ITEMP .EQ. ICHAR('(')) THEN
            NGQT = 0
        ELSE
            NGQT = 8
        ENDIF

 	IF (NFQT .LE. NGQT) THEN
           IF (NFQT .NE. NGQT) THEN
              I          = I + 1
              IPOLSH(I)  = ITEMP
              NRQT       = 1
              IF (ITEMP .EQ. ICHAR('+') .OR. ITEMP .EQ. ICHAR('-') .OR.
     &            ITEMP .EQ. ICHAR('*') .OR. ITEMP .EQ. ICHAR('/') .OR.
     &            ITEMP .EQ. ICHAR('^')) NRQT = -1

              IRANK = IRANK + NRQT
              IF (IRANK .LE. 0)   THEN
		 CALL ERRT(43,'POLISH',NE)
                 RETURN	
	      ENDIF
              ITOP = ITOP - 1
              GOTO 7
           ENDIF
           ITOP = ITOP - 1
        ELSE
           ITOP         = ITOP+1
           ISTACK(ITOP) = NEXT
        ENDIF
	GOTO 4

	END

