-- File: [Cherry]<Thyme>System>C03>spExpressions.mesa
-- Last editted:
-- by Barth, July 11, 1983  11:04 AM.
-- SChen April 19, 1983  1:00 PM.
-- Wilhelm March 23, 1982  3:41 PM, reformated by Barth and stored under
--   [Cherry]<Barth>Thyme>1.97> .
-- Details at end of file.
DIRECTORY spGlobals, AltoDefs, Real, RealFns;
spExpressions:  PROGRAM
  IMPORTS spGlobals, Real, RealFns
  EXPORTS spGlobals =
  BEGIN
    OPEN spGlobals;

    Types:  TYPE = {real, name};
    type:   Types;

    factor:  PROCEDURE RETURNS[f:  expressionPtr] =
      BEGIN
        n: namePtr;

        SELECT item FROM
          leftP =>
            BEGIN
              next[];
              f ← expression[];
              IF item = rightP THEN next[] ELSE error[211]
            END;
          name =>
            BEGIN
              f ← makeExpr[];
              n ← variable[NIL];
              type ← IF n # NIL THEN
                       IF n↑.nType = parmName THEN real ELSE name
                     ELSE real;
              f↑.operands ← load[n, NIL]
            END;
          number =>
            BEGIN
              type ← real;
              f ← makeExpr[];
              f↑.operands ← num[value];
              next[]
            END;
          string =>
            BEGIN
              type ← real;
              f ← makeExpr[];
              f↑.operands ← num[LOOPHOLE[newString, REAL]];
              next[]
            END
        ENDCASE => error[209]
      END;

    unaryExpr:  PROCEDURE RETURNS[u:  expressionPtr] =
      BEGIN
        oldItem:  itemType;

        SELECT item FROM
          minus, atSign, upArrow, backSlash, slash, squiggle, vertical =>
            BEGIN
              oldItem ← item;
              next[];
              u ← makeExpr[];
              SELECT oldItem FROM
                minus      => u↑.operands ← neg[unaryExpr[]];
                atSign     => u↑.operands ← abs[unaryExpr[]];
                slash      => u↑.operands ← sqrt[unaryExpr[]];
                squiggle   => u↑.operands ← not[unaryExpr[]];
                backSlash  => u↑.operands ← log[unaryExpr[]];
                upArrow    => u↑.operands ← exp[unaryExpr[]];
                vertical   => u↑.operands ← int[unaryExpr[]]
              ENDCASE;
              IF type > real THEN error[270]
            END
        ENDCASE => u ← factor[]
      END;

    powerExpr:  PROCEDURE RETURNS[p:  expressionPtr] =
      BEGIN
        p2:  expressionPtr;

        p ← unaryExpr[];
        IF item = upArrow THEN
          BEGIN
            IF type > real THEN error[270];
            next[];
            p2 ← makeExpr[];
            p2↑.operands ← power[p, unaryExpr[]];
            IF type > real THEN error[270];
            p ← p2
          END
      END;

    term:  PROCEDURE RETURNS[t:  expressionPtr] =
      BEGIN
        mulOp:  BOOLEAN;
        t2:  expressionPtr;

        t ← powerExpr[];
        IF item = star OR item = slash THEN
          IF type > real THEN error[270];
        WHILE item = star OR item = slash DO
          mulOp ← item = star;
          next[];
          t2 ← makeExpr[];
          IF mulOp THEN t2↑.operands ← mul[t, powerExpr[]]
          ELSE t2↑.operands ← div[t, powerExpr[]];
          IF type > real THEN error[270];
          t ← t2
        ENDLOOP
      END;

    arithExpr:  PROCEDURE RETURNS[e:  expressionPtr] =
      BEGIN
        e2:  expressionPtr;

        e ← term[];
        IF (item = plus OR item = minus) OR
          (item = maximum OR item = minimum) THEN
          IF type > real THEN error[270];
        WHILE (item = plus OR item = minus) OR 
          (item = maximum OR item = minimum) DO
          oldItem: itemType← item;
          next[];
          e2 ← makeExpr[];
          SELECT oldItem FROM
            plus    => e2↑.operands← add[e, term[]];
            minus   => e2↑.operands← sub[e, term[]];
            maximum => e2↑.operands← max[e, term[]];
            ENDCASE => e2↑.operands← min[e, term[]];
          IF type > real THEN error[270];
          e ← e2
        ENDLOOP
      END;

    relExpr:  PROCEDURE RETURNS[r:  expressionPtr] =
      BEGIN
        r2:  expressionPtr;
        oldItem:  itemType;
        nodeOK:   BOOLEAN;

        r ← arithExpr[];
        SELECT item FROM
          greater, less, equal, pound, greatEqual, lessEqual =>
            BEGIN
              oldItem ← item;
              next[];
              r2 ← makeExpr[];
              nodeOK ← oldItem = equal OR oldItem = pound;
              IF type > real AND ~nodeOK THEN error[270];
              SELECT oldItem FROM
                greater =>    r2↑.operands ← grt[r, arithExpr[]];
                greatEqual => r2↑.operands ← geq[r, arithExpr[]];
                less =>       r2↑.operands ← les[r, arithExpr[]];
                lessEqual =>  r2↑.operands ← leq[r, arithExpr[]];
                equal =>      r2↑.operands ← eq[r, arithExpr[]];
                pound =>      r2↑.operands ← neq[r, arithExpr[]]
              ENDCASE;
              IF type > real AND ~nodeOK THEN error[270];
              type ← real;
              r ← r2
            END
        ENDCASE
      END;

    andExpr:  PROCEDURE RETURNS[e:  expressionPtr] =
      BEGIN
        e2:  expressionPtr;

        e ← relExpr[];
        IF item = amperesand THEN
          IF type > real THEN error[270];
        WHILE item = amperesand DO
          next[];
          e2 ← makeExpr[];
          e2↑.operands ← and[e, relExpr[]];
          IF type > real THEN error[270];
          e ← e2
        ENDLOOP
      END;

    expression:  PUBLIC PROCEDURE RETURNS[e:  expressionPtr] =
      BEGIN
        e2:  expressionPtr;

        e ← andExpr[];
        IF item = vertical THEN
          IF type > real THEN error[270];
        WHILE item = vertical DO
          next[];
          e2 ← makeExpr[];
          e2↑.operands ← or[e, andExpr[]];
          IF type > real THEN error[270];
          e ← e2
        ENDLOOP
      END;

    assignExpr:  PUBLIC PROCEDURE[leftContext:  circuitNamePtr]
                          RETURNS[a:  expressionPtr] =
      BEGIN
        v:  namePtr;

        a ← makeExpr[];
        v ← variable[leftContext];
        IF v#NIL THEN IF v↑.nType # parmName THEN error[271];
        IF item = leftArrow THEN next[] ELSE error[210];
        a↑.operands ← store[v, expression[]];
        IF type > real THEN error[270]
      END;

    eval:  PUBLIC PROCEDURE[exp:  expressionPtr] RETURNS[v:  REAL] =
      BEGIN
        ENABLE
          Real.RealException =>
            BEGIN
              errorCode:  CARDINAL;

              errorCode ← SELECT TRUE FROM
                            flags[divisionByZero] => 901,
                            flags[overflow]       => 902,
                            flags[underflow]      => 903,
                            flags[fixOverflow]    => 904,
                          ENDCASE => 900;
              ErrorSignal[errorCode, "?"]
            END;
        v ← ev[exp]
      END;

    ev:  PROCEDURE[exp:  expressionPtr] RETURNS[v:  REAL] =
      BEGIN
        OPEN Real, RealFns;

        x, y:  REAL;

        IF exp # NIL THEN
          WITH e:  exp↑ SELECT FROM
            max   => v ← MAX[ev[e.leftOp], ev[e.rightOp]];
            min   => v ← MIN[ev[e.leftOp], ev[e.rightOp]];
            add   => v ← ev[e.leftOp] + ev[e.rightOp];
            sub   => v ← ev[e.leftOp] - ev[e.rightOp];
            mul   => v ← ev[e.leftOp] * ev[e.rightOp];
            div   => v ← ev[e.leftOp] / ev[e.rightOp];
            eq    => v ← IF LOOPHOLE[ev[e.leftOp], LONG CARDINAL] =
                            LOOPHOLE[ev[e.rightOp], LONG CARDINAL]
                         THEN 1.0
                         ELSE 0.0;
            neq   => v ← IF LOOPHOLE[ev[e.leftOp], LONG CARDINAL] #
                            LOOPHOLE[ev[e.rightOp], LONG CARDINAL]
                         THEN 1.0
                         ELSE 0.0;
            grt   => v ← IF ev[e.leftOp] > ev[e.rightOp] THEN 1.0
                         ELSE 0.0;
            les   => v ← IF ev[e.leftOp] < ev[e.rightOp] THEN 1.0
                         ELSE 0.0;
            geq   => v ← IF ev[e.leftOp] >= ev[e.rightOp] THEN 1.0
                         ELSE 0.0;
            leq   => v ← IF ev[e.leftOp] <= ev[e.rightOp] THEN 1.0
                         ELSE 0.0;
            and   => v ← IF ev[e.leftOp]*ev[e.rightOp] # 0.0 THEN 1.0
                         ELSE 0.0;
            or    => v ← IF ev[e.leftOp] # 0.0 OR
                            ev[e.rightOp] # 0.0 THEN 1.0
                         ELSE 0.0;
            power =>
              BEGIN
                x ← ev[e.leftOp];
                y ← ev[e.rightOp];
                IF ABS[y] < 100.0 AND y = FixI[y] THEN
                  BEGIN
                    v ← 1.0;
                    THROUGH[1..ABS[FixI[y]]] DO
                      v ← v*x
                    ENDLOOP;
                    IF y < 0.0 THEN v ← 1.0/v
                  END
                ELSE v ← Power[ev[e.leftOp], ev[e.rightOp]]
              END;
            int   => v ← Real.RoundLI[ev[e.unaryOp]];
            abs   => v ← ABS[ev[e.unaryOp]];
            exp   => v ← Exp[ev[e.unaryOp]];
            log   => v ← Ln[ev[e.unaryOp]];
            sqrt  => v ← SqRt[ev[e.unaryOp]];
            neg   => v ← -ev[e.unaryOp];
            not   => v ← IF ev[e.unaryOp] # 0.0 THEN 0.0 ELSE 1.0;
            load  => v ← getParmValue[e.var];
            store => putParmValue[e.var, ev[e.expr]];
            num   => v ← e.v
          ENDCASE  => v ← 0.0
        ELSE v ← 0.0
      END;
  END.
  
4/19/83:-
  original: [Cherry]<Barth>Thyme>1.97>spExpressions.mesa
  changes:
  1. arithExpr - modified to allow item = minimum or maximum.
  2. ev - added MAX and MIN operations.
July 11, 1983  11:04 AM, by Barth
checked for v=NIL in assignExpr