
 (*    COPYRIGHT (C) 1978, REGENTS OF THE        *)
 (*    UNIVERSITY OF CALIFORNIA, SAN DIEGO       *)

   PROCEDURE EXPRESSION(*FSYS: SETOFSYS*);
     LABEL 1;    (* STRING COMPARE KLUDGE *)
     VAR LATTR: ATTR; LOP: OPERATOR; TYPIND: INTEGER;
         LSIZE: ADDRRANGE; LSTRING,GSTRING: BOOLEAN;
         LMIN,LMAX: INTEGER;

     PROCEDURE FLOATIT(VAR FSP: STP; FORCEFLOAT: BOOLEAN);
     BEGIN
       IF (GATTR.TYPTR = REALPTR) OR (FSP = REALPTR) OR FORCEFLOAT THEN
         BEGIN
           IF GATTR.TYPTR = INTPTR THEN
             BEGIN GEN0(10(*FLT*)); GATTR.TYPTR := REALPTR END;
           IF FSP = INTPTR THEN
             BEGIN GEN0(9(*FLO*)); FSP := REALPTR END
         END
     END (*FLOATIT*) ;

     PROCEDURE STRETCHIT(VAR FSP: STP);

     BEGIN
       IF (FSP^.FORM = LONGINT) OR (GATTR.TYPTR^.FORM = LONGINT) THEN
         IF GATTR.TYPTR = INTPTR THEN
           BEGIN GENLDC(INTSIZE); GATTR.TYPTR := LONGINTPTR END
         ELSE
           IF FSP = INTPTR THEN
             BEGIN GENLDC(14(*DCV*)); GENNR(DECOPS); FSP := LONGINTPTR END
     END (*STRETCHIT*) ;

     PROCEDURE SIMPLEEXPRESSION(FSYS: SETOFSYS);
       VAR LATTR: ATTR; LOP: OPERATOR; SIGNED: BOOLEAN;

       PROCEDURE TERM(FSYS: SETOFSYS);
         VAR LATTR: ATTR; LSP: STP; LOP: OPERATOR;

         PROCEDURE FACTOR(FSYS: SETOFSYS);
           VAR LCP: CTP; LVP: CSP; VARPART,ALLCONST: BOOLEAN;
               LSP: STP; HIGHVAL,LOWVAL,LIC,LOP: INTEGER;
               CSTPART: SET OF 0..127;
         BEGIN
           IF NOT (SY IN FACBEGSYS) THEN
             BEGIN ERROR(58); SKIP(FSYS + FACBEGSYS);
               GATTR.TYPTR := NIL
             END;
           WHILE SY IN FACBEGSYS DO
             BEGIN
               CASE SY OF
         (*ID*)  IDENT:
                   BEGIN SEARCHID([KONST,FORMALVARS,ACTUALVARS,FIELD,FUNC],LCP);
                     INSYMBOL;
                     IF LCP^.KLASS = FUNC THEN
                       BEGIN CALL(FSYS,LCP); GATTR.KIND := EXPR END
                     ELSE
                       IF LCP^.KLASS = KONST THEN
                         WITH GATTR, LCP^ DO
                           BEGIN TYPTR := IDTYPE; KIND := CST;
                             CVAL := VALUES
                           END
                       ELSE SELECTOR(FSYS,LCP);
                     IF GATTR.TYPTR <> NIL THEN
                       WITH GATTR,TYPTR^ DO
                         IF FORM = SUBRANGE THEN TYPTR := RANGETYPE
                   END;
         (*CST*) INTCONST:
                   BEGIN
                     WITH GATTR DO
                       BEGIN TYPTR := INTPTR; KIND := CST;
                         CVAL := VAL
                       END;
                     INSYMBOL
                   END;
                 REALCONST:
                   BEGIN
                     WITH GATTR DO
                       BEGIN TYPTR := REALPTR; KIND := CST;
                         CVAL := VAL
                       END;
                     INSYMBOL
                   END;
                 STRINGCONST:
                   BEGIN
                     WITH GATTR DO
                       BEGIN
                         IF LGTH = 1 THEN TYPTR := CHARPTR
                         ELSE
                           BEGIN NEW(LSP,ARRAYS,TRUE,TRUE);
                             LSP^ := STRGPTR^;
                             LSP^.MAXLENG := LGTH;
                             TYPTR := LSP
                           END;
                         KIND := CST; CVAL := VAL
                       END;
                     INSYMBOL
                   END;
                 LONGCONST:
                   BEGIN
                     WITH GATTR DO
                       BEGIN NEW(LSP,LONGINT);
                         LSP^ := LONGINTPTR^;
                         LSP^.SIZE := DECSIZE(LGTH);
                         TYPTR := LSP; KIND := CST; CVAL := VAL
                       END;
                     INSYMBOL
                   END;
         (*(*)   LPARENT:
                   BEGIN INSYMBOL; EXPRESSION(FSYS + [RPARENT]);
                     IF SY = RPARENT THEN INSYMBOL ELSE ERROR(4)
                   END;
         (*NOT*) NOTSY:
                   WITH GATTR DO
                     BEGIN INSYMBOL; FACTOR(FSYS);
                       IF (KIND = CST) AND (TYPTR = BOOLPTR) THEN
                         CVAL.IVAL := ORD(NOT ODD(CVAL.IVAL))
                       ELSE
                       BEGIN LOAD; GEN0(19(*NOT*));
                         IF TYPTR <> NIL THEN
                           IF TYPTR <> BOOLPTR THEN
                             BEGIN ERROR(135); TYPTR := NIL END
                       END
                     END;
         (*[*)   LBRACK:
                   BEGIN INSYMBOL; CSTPART := [ ]; VARPART := FALSE;
                     NEW(LSP,POWER);
                     WITH LSP^ DO
                       BEGIN ELSET := NIL; SIZE := 0; FORM := POWER END;
                     IF SY = RBRACK THEN
                       BEGIN
                         WITH GATTR DO
                           BEGIN TYPTR := LSP; KIND := CST END;
                         INSYMBOL
                       END
                     ELSE
                       BEGIN
                         REPEAT EXPRESSION(FSYS + [COMMA,RBRACK,COLON]);
                           IF GATTR.TYPTR <> NIL THEN
                             IF GATTR.TYPTR^.FORM <> SCALAR THEN
                               BEGIN ERROR(136); GATTR.TYPTR := NIL END
                             ELSE
                               IF COMPTYPES(LSP^.ELSET,GATTR.TYPTR) THEN
                                 BEGIN ALLCONST := FALSE; LOP := 23(*SGS*);
                                   IF (GATTR.KIND = CST) AND
                                      (GATTR.CVAL.IVAL <= 127) THEN
                                     BEGIN ALLCONST := TRUE;
                                       LOWVAL := GATTR.CVAL.IVAL;
                                       HIGHVAL := LOWVAL
                                     END;
                                   LIC := IC; LOAD;
                                   IF SY = COLON THEN
                                     BEGIN INSYMBOL; LOP := 20(*SRS*);
                                       EXPRESSION(FSYS + [COMMA,RBRACK]);
                                       IF COMPTYPES(LSP^.ELSET,GATTR.TYPTR) THEN
                                       ELSE
                                         BEGIN ERROR(137); GATTR.TYPTR:=NIL END;
                                       IF ALLCONST THEN
                                         IF (GATTR.KIND = CST) AND
                                            (GATTR.CVAL.IVAL <= 127) THEN
                                             HIGHVAL := GATTR.CVAL.IVAL
                                         ELSE
                                           BEGIN LOAD; ALLCONST := FALSE END
                                       ELSE LOAD
                                     END;
                                   IF ALLCONST THEN
                                     BEGIN IC := LIC; (*FORGET FIRST CONST*)
                                       CSTPART := CSTPART + [LOWVAL..HIGHVAL]
                                     END
                                   ELSE
                                     BEGIN GEN0(LOP);
                                       IF VARPART THEN GEN0(28(*UNI*))
                                       ELSE VARPART := TRUE
                                     END;
                                   LSP^.ELSET := GATTR.TYPTR;
                                   GATTR.TYPTR := LSP
                                 END
                               ELSE ERROR(137);
                           TEST := SY <> COMMA;
                           IF NOT TEST THEN INSYMBOL
                         UNTIL TEST;
                         IF SY = RBRACK THEN INSYMBOL ELSE ERROR(12)
                       END;
                     IF VARPART THEN
                       BEGIN
                         IF CSTPART <> [ ] THEN
                           BEGIN
                             SCONST^.PVAL := CSTPART;
                             SCONST^.CCLASS := PSET;
                             GATTR.CVAL.VALP := SCONST;
                             GATTR.KIND := CST;
                             LOAD; GEN0(28(*UNI*))
                           END;
                         GATTR.KIND := EXPR
                       END
                     ELSE
                       BEGIN
                         SCONST^.PVAL := CSTPART;
                         SCONST^.CCLASS := PSET;
                         GATTR.CVAL.VALP := SCONST;
                         GATTR.KIND := CST
                       END
                   END
               END (*CASE*) ;
               IF NOT (SY IN FSYS) THEN
                 BEGIN ERROR(6); SKIP(FSYS + FACBEGSYS) END
             END (*WHILE*)
         END (*FACTOR*) ;

       BEGIN (*TERM*)
         FACTOR(FSYS + [MULOP]);
         WHILE SY = MULOP DO
           BEGIN LOAD; LATTR := GATTR; LOP := OP;
             INSYMBOL; FACTOR(FSYS + [MULOP]); LOAD;
             IF (LATTR.TYPTR <> NIL) AND (GATTR.TYPTR <> NIL) THEN
               CASE LOP OF
       (***)     MUL:  BEGIN FLOATIT(LATTR.TYPTR,FALSE); STRETCHIT(LATTR.TYPTR);
                         IF (LATTR.TYPTR = INTPTR) AND (GATTR.TYPTR = INTPTR)
                           THEN GEN0(15(*MPI*))
                         ELSE
                           IF (LATTR.TYPTR = REALPTR) AND
                              (GATTR.TYPTR = REALPTR) THEN GEN0(16(*MPR*))
                           ELSE
                             IF (GATTR.TYPTR^.FORM = LONGINT) AND
                                (LATTR.TYPTR^.FORM = LONGINT) THEN
                               BEGIN GENLDC(8(*DMP*)); GENNR(DECOPS) END
                             ELSE
                               IF (LATTR.TYPTR^.FORM = POWER)
                                   AND COMPTYPES(LATTR.TYPTR,GATTR.TYPTR) THEN
                                 GEN0(12(*INT*))
                               ELSE BEGIN ERROR(134); GATTR.TYPTR:=NIL END
                       END;
       (*/*)     RDIV: BEGIN FLOATIT(LATTR.TYPTR,TRUE);
                         IF (LATTR.TYPTR = REALPTR) AND
                            (GATTR.TYPTR = REALPTR) THEN GEN0(7(*DVR*))
                         ELSE BEGIN ERROR(134); GATTR.TYPTR := NIL END
                       END;
       (*DIV*)   IDIV: BEGIN STRETCHIT(LATTR.TYPTR);
                         IF (LATTR.TYPTR = INTPTR) AND
                            (GATTR.TYPTR = INTPTR) THEN GEN0(6(*DVI*))
                         ELSE
                           IF (LATTR.TYPTR^.FORM = LONGINT) AND
                              (GATTR.TYPTR^.FORM = LONGINT) THEN
                             BEGIN GENLDC(10(*DDV*)); GENNR(DECOPS) END
                           ELSE BEGIN ERROR(134); GATTR.TYPTR := NIL END
                       END;
       (*MOD*)   IMOD: IF (LATTR.TYPTR = INTPTR) AND
                          (GATTR.TYPTR = INTPTR) THEN GEN0(14(*MOD*))
                       ELSE BEGIN ERROR(134); GATTR.TYPTR := NIL END;
       (*AND*)   ANDOP:IF (LATTR.TYPTR = BOOLPTR) AND
                          (GATTR.TYPTR = BOOLPTR) THEN GEN0(4(*AND*))
                       ELSE BEGIN ERROR(134); GATTR.TYPTR := NIL END
               END (*CASE*)
             ELSE GATTR.TYPTR := NIL
           END (*WHILE*)
       END (*TERM*) ;

     BEGIN (*SIMPLEEXPRESSION*)
       SIGNED := FALSE;
       IF (SY = ADDOP) AND (OP IN [PLUS,MINUS]) THEN
         BEGIN SIGNED := OP = MINUS; INSYMBOL END;
       TERM(FSYS + [ADDOP]);
       IF SIGNED THEN
         BEGIN LOAD;
           IF GATTR.TYPTR = INTPTR THEN GEN0(17(*NGI*))
           ELSE
             IF GATTR.TYPTR = REALPTR THEN GEN0(18(*NGR*))
             ELSE
               IF GATTR.TYPTR^.FORM = LONGINT THEN
                 BEGIN GENLDC(6(*DNG*)); GENNR(DECOPS) END
               ELSE BEGIN ERROR(134); GATTR.TYPTR := NIL END
         END;
       WHILE SY = ADDOP DO
         BEGIN LOAD; LATTR := GATTR; LOP := OP;
           INSYMBOL; TERM(FSYS + [ADDOP]); LOAD;
           IF (LATTR.TYPTR <> NIL) AND (GATTR.TYPTR <> NIL) THEN
             CASE LOP OF
     (*+*)     PLUS:
                 BEGIN FLOATIT(LATTR.TYPTR,FALSE); STRETCHIT(LATTR.TYPTR);
                   IF (LATTR.TYPTR = INTPTR)AND(GATTR.TYPTR = INTPTR) THEN
                     GEN0(2(*ADI*))
                   ELSE
                     IF (LATTR.TYPTR = REALPTR)AND(GATTR.TYPTR = REALPTR) THEN
                       GEN0(3(*ADR*))
                     ELSE
                       IF (GATTR.TYPTR^.FORM = LONGINT) AND
                          (LATTR.TYPTR^.FORM = LONGINT) THEN
                         BEGIN GENLDC(2(*DAD*)); GENNR(DECOPS) END
                       ELSE
                         IF (LATTR.TYPTR^.FORM = POWER)
                            AND COMPTYPES(LATTR.TYPTR,GATTR.TYPTR) THEN
                           GEN0(28(*UNI*))
                         ELSE BEGIN ERROR(134); GATTR.TYPTR := NIL END
                 END;
     (*-*)     MINUS:
                 BEGIN FLOATIT(LATTR.TYPTR,FALSE); STRETCHIT(LATTR.TYPTR);
                   IF (LATTR.TYPTR = INTPTR) AND (GATTR.TYPTR = INTPTR) THEN
                     GEN0(21(*SBI*))
                   ELSE
                     IF (LATTR.TYPTR = REALPTR) AND (GATTR.TYPTR = REALPTR)
                       THEN GEN0(22(*SBR*))
                     ELSE
                       IF (GATTR.TYPTR^.FORM = LONGINT) AND
                          (LATTR.TYPTR^.FORM = LONGINT) THEN
                         BEGIN GENLDC(4(*DSB*)); GENNR(DECOPS) END
                       ELSE
                         IF (LATTR.TYPTR^.FORM = POWER)
                             AND COMPTYPES(LATTR.TYPTR,GATTR.TYPTR) THEN
                           GEN0(5(*DIF*))
                         ELSE BEGIN ERROR(134); GATTR.TYPTR := NIL END
                 END;
     (*OR*)    OROP:
                 IF (LATTR.TYPTR = BOOLPTR) AND (GATTR.TYPTR = BOOLPTR) THEN
                   GEN0(13(*IOR*))
                 ELSE BEGIN ERROR(134); GATTR.TYPTR := NIL END
             END (*CASE*)
           ELSE GATTR.TYPTR := NIL
         END (*WHILE*)
     END (*SIMPLEEXPRESSION*) ;

     PROCEDURE MAKEPA(VAR STRGFSP: STP; PAFSP: STP);
       VAR LMIN,LMAX: INTEGER;
     BEGIN
       IF PAFSP^.INXTYPE <> NIL THEN
         BEGIN GETBOUNDS(PAFSP^.INXTYPE,LMIN,LMAX);
           IF LMAX-LMIN+1 <> STRGFSP^.MAXLENG THEN ERROR(129)
         END;
       STRGFSP := PAFSP
     END (*MAKEPA*) ;

   BEGIN (*EXPRESSION*)
     SIMPLEEXPRESSION(FSYS + [RELOP]);
     IF SY = RELOP THEN
       BEGIN
         LSTRING := (GATTR.KIND = CST) AND
                 (STRGTYPE(GATTR.TYPTR) OR (GATTR.TYPTR = CHARPTR));
         IF GATTR.TYPTR <> NIL THEN
           IF GATTR.TYPTR^.FORM <= POWER THEN LOAD
           ELSE LOADADDRESS;
         LATTR := GATTR; LOP := OP;
         INSYMBOL; SIMPLEEXPRESSION(FSYS);
         GSTRING := (GATTR.KIND = CST) AND
                 (STRGTYPE(GATTR.TYPTR) OR (GATTR.TYPTR = CHARPTR));
         IF GATTR.TYPTR <> NIL THEN
           IF GATTR.TYPTR^.FORM <= POWER THEN LOAD
           ELSE LOADADDRESS;
         IF (LATTR.TYPTR <> NIL) AND (GATTR.TYPTR <> NIL) THEN
           IF LOP = INOP THEN
             IF GATTR.TYPTR^.FORM = POWER THEN
               IF COMPTYPES(LATTR.TYPTR,GATTR.TYPTR^.ELSET) THEN
                 GEN0(11(*INN*))
               ELSE BEGIN ERROR(129); GATTR.TYPTR := NIL END
             ELSE BEGIN ERROR(130); GATTR.TYPTR := NIL END
           ELSE
             BEGIN
               IF LATTR.TYPTR <> GATTR.TYPTR THEN
                 BEGIN FLOATIT(LATTR.TYPTR,FALSE); STRETCHIT(LATTR.TYPTR) END;
               IF LSTRING THEN
                 BEGIN
                   IF PAOFCHAR(GATTR.TYPTR) THEN
                     IF NOT GATTR.TYPTR^.AISSTRNG THEN
                       BEGIN GEN0(29(*S2P*));
                         MAKEPA(LATTR.TYPTR,GATTR.TYPTR)
                       END
                 END
               ELSE
                 IF GSTRING THEN
                   BEGIN
                     IF PAOFCHAR(LATTR.TYPTR) THEN
                       IF NOT LATTR.TYPTR^.AISSTRNG THEN
                         BEGIN GEN0(80(*S1P*));
                           MAKEPA(GATTR.TYPTR,LATTR.TYPTR)
                         END;
                   END;
               IF (LSTRING AND STRGTYPE(GATTR.TYPTR)) OR
                  (GSTRING AND STRGTYPE(LATTR.TYPTR)) THEN GOTO 1;
               IF COMPTYPES(LATTR.TYPTR,GATTR.TYPTR) THEN
                 BEGIN LSIZE := LATTR.TYPTR^.SIZE; (*INVALID FOR LONG INTEGERS*)
                   CASE LATTR.TYPTR^.FORM OF
                     SCALAR:
                       IF LATTR.TYPTR = REALPTR THEN TYPIND := 1
                       ELSE
                         IF LATTR.TYPTR = BOOLPTR THEN TYPIND := 3
                         ELSE TYPIND := 0;
                     POINTER:
                       BEGIN
                         IF LOP IN [LTOP,LEOP,GTOP,GEOP] THEN ERROR(131);
                         TYPIND := 0
                       END;
                     LONGINT: TYPIND := 7;
                     POWER:
                       BEGIN
                         IF LOP IN [LTOP,GTOP] THEN ERROR(132);
                         TYPIND := 4
                       END;
                     ARRAYS:
                       BEGIN
                         TYPIND := 6;
                         IF PAOFCHAR(LATTR.TYPTR) THEN
                           IF LATTR.TYPTR^.AISSTRNG THEN
                 1:          TYPIND := 2
                           ELSE
                             BEGIN TYPIND := 5;
                               IF LATTR.TYPTR^.INXTYPE <> NIL THEN
                                 BEGIN
                                   GETBOUNDS(LATTR.TYPTR^.INXTYPE,LMIN,LMAX);
                                   LSIZE := LMAX - LMIN + 1
                                 END
                             END
                         ELSE
                           IF LOP IN [LTOP,LEOP,GTOP,GEOP] THEN ERROR(131)
                       END;
                     RECORDS:
                       BEGIN
                         IF LOP IN [LTOP,LEOP,GTOP,GEOP] THEN ERROR(131);
                         TYPIND := 6
                       END;
                     FILES:
                       BEGIN ERROR(133); TYPIND := 0 END
                   END;
                   IF TYPIND = 7 THEN
                     BEGIN GENLDC(ORD(LOP)); GENLDC(16(*DCMP*));
                       GENNR(DECOPS)
                     END
                   ELSE
                     CASE LOP OF
                       LTOP: GEN2(53(*LES*),TYPIND,LSIZE);
                       LEOP: GEN2(52(*LEQ*),TYPIND,LSIZE);
                       GTOP: GEN2(49(*GRT*),TYPIND,LSIZE);
                       GEOP: GEN2(48(*GEQ*),TYPIND,LSIZE);
                       NEOP: GEN2(55(*NEQ*),TYPIND,LSIZE);
                       EQOP: GEN2(47(*EQU*),TYPIND,LSIZE)
                     END
                 END
               ELSE ERROR(129)
             END;
         GATTR.TYPTR := BOOLPTR; GATTR.KIND := EXPR
       END (*SY = RELOP*)
   END (*EXPRESSION*) ;
