-- JaMMathImpl.mesa
-- Original version by John Warnock, February 27, 1979
-- Last changed by Bill Paxton, December 19, 1980  9:35 AM
-- Last changed by Doug Wyatt,  7-Nov-81 14:15:57

DIRECTORY
  JaMBasic USING [Object],
  JaMInternal USING [Frame],
  JaMOps USING [Bug, Compare, Error, Install, InstallReason, MakeName, Pop,
    PopBoolean, PopInteger, PopReal, Push, PushBoolean, PushInteger, PushReal,
    rangechk, RegisterExplicit, StringCompare, typechk],
  Inline USING [BITAND, BITNOT, BITOR, BITSHIFT, BITXOR, LongNumber],
  Real USING [FAdd, FDiv, Fix, Float, FMul, FSub, RealException],
  RealFns USING [ArcTanDeg, CosDeg, Log, Power, SinDeg, SqRt];

JaMMathImpl: PROGRAM
IMPORTS JaMOps, Inline, Real, RealFns = {
OPEN JaMOps, JaMInternal, JaMBasic;

-- Globals

overflow: name Object;

-- Math operations

Add: PUBLIC PROC[a,b: Object] RETURNS[Object] = {
  ENABLE Real.RealException => GOTO Overflow;
  WITH a:a SELECT FROM
    integer => WITH b:b SELECT FROM
      integer => { i,j,k: LONG INTEGER;
        i ← a.ivalue; j ← b.ivalue; k ← i + j;
	IF (i<0)#(j<0) OR (i<0)=(k<0) THEN RETURN[[L,integer[k]]]
	ELSE RETURN[[L,real[Real.FAdd[i,j]]]] };
      real => RETURN[[L,real[Real.FAdd[a.ivalue,b.rvalue]]]];
      ENDCASE;
    real => WITH b:b SELECT FROM
      integer => RETURN[[L,real[Real.FAdd[a.rvalue,b.ivalue]]]];
      real => RETURN[[L,real[Real.FAdd[a.rvalue,b.rvalue]]]];
      ENDCASE;
    ENDCASE;
  ERROR Error[typechk];
  EXITS Overflow => ERROR Error[overflow];
  };

Sub: PUBLIC PROC[a,b: Object] RETURNS[Object] = {
  ENABLE Real.RealException => GOTO Overflow;
  WITH a:a SELECT FROM
    integer => WITH b:b SELECT FROM
      integer => { i,j,k: LONG INTEGER;
        i ← a.ivalue; j ← b.ivalue; k ← i - j;
	IF (i<0)=(j<0) OR (i<0)=(k<0) THEN RETURN[[L,integer[k]]]
	ELSE RETURN[[L,real[Real.FSub[i,j]]]] };
      real => RETURN[[L,real[Real.FSub[a.ivalue,b.rvalue]]]];
      ENDCASE;
    real => WITH b:b SELECT FROM
      integer => RETURN[[L,real[Real.FSub[a.rvalue,b.ivalue]]]];
      real => RETURN[[L,real[Real.FSub[a.rvalue,b.rvalue]]]];
      ENDCASE;
    ENDCASE;
  ERROR Error[typechk];
  EXITS Overflow => ERROR Error[overflow];
  };

Mul: PUBLIC PROC[a,b: Object] RETURNS[Object] = {
  ENABLE Real.RealException => GOTO Overflow;
  WITH a:a SELECT FROM
    integer => WITH b:b SELECT FROM
      integer => { r: REAL ← Real.FMul[a.ivalue,b.ivalue];
        IF r IN[FIRST[LONG INTEGER]..LAST[LONG INTEGER]]
	THEN RETURN[[L,integer[Real.Fix[r]]]]
	ELSE RETURN[[L,real[r]]] };
      real => RETURN[[L,real[Real.FMul[a.ivalue,b.rvalue]]]];
      ENDCASE;
    real => WITH b:b SELECT FROM
      integer => RETURN[[L,real[Real.FMul[a.rvalue,b.ivalue]]]];
      real => RETURN[[L,real[Real.FMul[a.rvalue,b.rvalue]]]];
      ENDCASE;
    ENDCASE;
  ERROR Error[typechk];
  EXITS Overflow => ERROR Error[overflow];
  };

Div: PUBLIC PROC[a,b: Object] RETURNS[Object] = {
  ENABLE Real.RealException => GOTO Overflow;
  WITH a:a SELECT FROM
    integer => WITH b:b SELECT FROM
      integer => IF b.ivalue=0 THEN GOTO Overflow
        ELSE RETURN[[L,integer[a.ivalue/b.ivalue]]];
      real => RETURN[[L,real[Real.FDiv[a.ivalue,b.rvalue]]]];
      ENDCASE;
    real => WITH b:b SELECT FROM
      integer => RETURN[[L,real[Real.FDiv[a.rvalue,b.ivalue]]]];
      real => RETURN[[L,real[Real.FDiv[a.rvalue,b.rvalue]]]];
      ENDCASE;
    ENDCASE;
  ERROR Error[typechk];
  EXITS Overflow => ERROR Error[overflow];
  };

IDiv: PUBLIC PROC[a,b: Object] RETURNS[Object] = {
  WITH a:a SELECT FROM
    integer => WITH b:b SELECT FROM
      integer => IF b.ivalue=0 THEN ERROR Error[overflow]
        ELSE RETURN[[L,integer[a.ivalue/b.ivalue]]];
      ENDCASE;
    ENDCASE;
  ERROR Error[typechk];
  };

RDiv: PUBLIC PROC[a,b: Object] RETURNS[Object] = {
  ENABLE Real.RealException => GOTO Overflow;
  WITH a:a SELECT FROM
    integer => WITH b:b SELECT FROM
      integer => RETURN[[L,real[Real.FDiv[a.ivalue,b.ivalue]]]];
      real => RETURN[[L,real[Real.FDiv[a.ivalue,b.rvalue]]]];
      ENDCASE;
    real => WITH b:b SELECT FROM
      integer => RETURN[[L,real[Real.FDiv[a.rvalue,b.ivalue]]]];
      real => RETURN[[L,real[Real.FDiv[a.rvalue,b.rvalue]]]];
      ENDCASE;
    ENDCASE;
  ERROR Error[typechk];
  EXITS Overflow => ERROR Error[overflow];
  };

Neg: PUBLIC PROC[a: Object] RETURNS[Object] = {
  ENABLE Real.RealException => GOTO Overflow;
  WITH a:a SELECT FROM
    integer => IF a.ivalue#FIRST[LONG INTEGER]
      THEN RETURN[[L,integer[-a.ivalue]]]
      ELSE RETURN[[L,real[-Real.Float[a.ivalue]]]];
    real => RETURN[[L,real[-a.rvalue]]];
    ENDCASE;
  ERROR Error[typechk];
  EXITS Overflow => ERROR Error[overflow];
  };

Eq: PUBLIC PROC[a,b: Object] RETURNS[BOOLEAN] = {
  SELECT Compare[a,b] FROM
    F => RETURN[FALSE];
    T => RETURN[TRUE];
    nil => ERROR Error[typechk];
    ENDCASE => ERROR Bug;
  };

Lt: PUBLIC PROC[a,b: Object] RETURNS[BOOLEAN] = {
  WITH a:a SELECT FROM
    integer => WITH b:b SELECT FROM
      integer => RETURN[a.ivalue<b.ivalue];
      real => RETURN[a.ivalue<b.rvalue];
      ENDCASE;
    real => WITH b:b SELECT FROM
      integer => RETURN[a.rvalue<b.ivalue];
      real => RETURN[a.rvalue<b.rvalue];
      ENDCASE;
    string => WITH b:b SELECT FROM
      string => RETURN[StringCompare[a,b]<0];
      ENDCASE;
    ENDCASE;
  ERROR Error[typechk];
  };

Gt: PUBLIC PROC[a,b: Object] RETURNS[BOOLEAN] = {
  WITH a:a SELECT FROM
    integer => WITH b:b SELECT FROM
      integer => RETURN[a.ivalue>b.ivalue];
      real => RETURN[a.ivalue>b.rvalue];
      ENDCASE;
    real => WITH b:b SELECT FROM
      integer => RETURN[a.rvalue>b.ivalue];
      real => RETURN[a.rvalue>b.rvalue];
      ENDCASE;
    string => WITH b:b SELECT FROM
      string => RETURN[StringCompare[a,b]>0];
      ENDCASE;
    ENDCASE;
  ERROR Error[typechk];
  };

-- Intrinsics

JAdd: PUBLIC PROC[frame: Frame] = {
  b: Object ← Pop[frame.opstk];
  a: Object ← Pop[frame.opstk];
  Push[frame.opstk,Add[a,b]];
  };

JSub: PUBLIC PROC[frame: Frame] = {
  b: Object ← Pop[frame.opstk];
  a: Object ← Pop[frame.opstk];
  Push[frame.opstk,Sub[a,b]];
  };

JMul: PUBLIC PROC[frame: Frame] = {
  b: Object ← Pop[frame.opstk];
  a: Object ← Pop[frame.opstk];
  Push[frame.opstk,Mul[a,b]];
  };

JDiv: PUBLIC PROC[frame: Frame] = {
  b: Object ← Pop[frame.opstk];
  a: Object ← Pop[frame.opstk];
  Push[frame.opstk,Div[a,b]];
  };

JIDiv: PUBLIC PROC[frame: Frame] = {
  b: Object ← Pop[frame.opstk];
  a: Object ← Pop[frame.opstk];
  Push[frame.opstk,IDiv[a,b]];
  };

JRDiv: PUBLIC PROC[frame: Frame] = {
  b: Object ← Pop[frame.opstk];
  a: Object ← Pop[frame.opstk];
  Push[frame.opstk,RDiv[a,b]];
  };

JNeg: PUBLIC PROC[frame: Frame] = {
  a: Object ← Pop[frame.opstk];
  Push[frame.opstk,Neg[a]];
  };

JSin: PUBLIC PROC[frame: Frame] = {
  a: REAL ← PopReal[frame.opstk];
  PushReal[frame.opstk,RealFns.SinDeg[a]];
  };

JCos: PUBLIC PROC[frame: Frame] = {
  a: REAL ← PopReal[frame.opstk];
  PushReal[frame.opstk,RealFns.CosDeg[a]];
  };

JATan: PUBLIC PROC[frame: Frame] = {
  b: REAL ← PopReal[frame.opstk];
  a: REAL ← PopReal[frame.opstk];
  PushReal[frame.opstk,RealFns.ArcTanDeg[a,b]];
  };

JExp: PUBLIC PROC[frame: Frame] = {
  ENABLE Real.RealException => GOTO Overflow;
  b: REAL ← PopReal[frame.opstk];
  a: REAL ← PopReal[frame.opstk];
  PushReal[frame.opstk,RealFns.Power[a,b]];
  EXITS Overflow => ERROR Error[overflow];
  };

JLog: PUBLIC PROC[frame: Frame] = {
  b: REAL ← PopReal[frame.opstk];
  a: REAL ← PopReal[frame.opstk];
  IF a>0 AND b>0 THEN PushReal[frame.opstk,RealFns.Log[a,b]]
  ELSE ERROR Error[rangechk];
  };

JSqRt: PUBLIC PROC[frame: Frame] = {
  a: REAL ← PopReal[frame.opstk];
  IF a>=0 THEN PushReal[frame.opstk,RealFns.SqRt[a]]
  ELSE ERROR Error[rangechk];
  };

JEq: PUBLIC PROC[frame: Frame] = {
  b: Object ← Pop[frame.opstk];
  a: Object ← Pop[frame.opstk];
  PushBoolean[frame.opstk,Eq[a,b]];
  };

JLt: PUBLIC PROC[frame: Frame] = {
  b: Object ← Pop[frame.opstk];
  a: Object ← Pop[frame.opstk];
  PushBoolean[frame.opstk,Lt[a,b]];
  };

JGt: PUBLIC PROC[frame: Frame] = {
  b: Object ← Pop[frame.opstk];
  a: Object ← Pop[frame.opstk];
  PushBoolean[frame.opstk,Gt[a,b]];
  };

JNot: PUBLIC PROC[frame: Frame] = {
  a: BOOLEAN ← PopBoolean[frame.opstk];
  PushBoolean[frame.opstk,NOT a];
  };

JAnd: PUBLIC PROC[frame: Frame] = {
  b: BOOLEAN ← PopBoolean[frame.opstk];
  a: BOOLEAN ← PopBoolean[frame.opstk];
  PushBoolean[frame.opstk,a AND b];
  };

JOr: PUBLIC PROC[frame: Frame] = {
  b: BOOLEAN ← PopBoolean[frame.opstk];
  a: BOOLEAN ← PopBoolean[frame.opstk];
  PushBoolean[frame.opstk,a OR b];
  };

JXor: PUBLIC PROC[frame: Frame] = {
  b: BOOLEAN ← PopBoolean[frame.opstk];
  a: BOOLEAN ← PopBoolean[frame.opstk];
  PushBoolean[frame.opstk,a # b];
  };

JBitNot: PUBLIC PROC[frame: Frame] = {
  a,r: Inline.LongNumber;
  a.li ← PopInteger[frame.opstk];
  r.low ← Inline.BITNOT[a.low];
  r.high ← Inline.BITNOT[a.high];
  PushInteger[frame.opstk,r.li];
  };

JBitAnd: PUBLIC PROC[frame: Frame] = {
  a,b,r: Inline.LongNumber;
  b.li ← PopInteger[frame.opstk];
  a.li ← PopInteger[frame.opstk];
  r.low ← Inline.BITAND[a.low,b.low];
  r.high ← Inline.BITAND[a.high,b.high];
  PushInteger[frame.opstk,r.li];
  };

JBitOr: PUBLIC PROC[frame: Frame] = {
  a,b,r: Inline.LongNumber;
  b.li ← PopInteger[frame.opstk];
  a.li ← PopInteger[frame.opstk];
  r.low ← Inline.BITOR[a.low,b.low];
  r.high ← Inline.BITOR[a.high,b.high];
  PushInteger[frame.opstk,r.li];
  };

JBitXor: PUBLIC PROC[frame: Frame] = {
  a,b,r: Inline.LongNumber;
  b.li ← PopInteger[frame.opstk];
  a.li ← PopInteger[frame.opstk];
  r.low ← Inline.BITXOR[a.low,b.low];
  r.high ← Inline.BITXOR[a.high,b.high];
  PushInteger[frame.opstk,r.li];
  };

JBitShift: PUBLIC PROC[frame: Frame] = { OPEN Inline;
  a,b,r: LongNumber;
  shift: INTEGER;
  b.li ← PopInteger[frame.opstk];
  a.li ← PopInteger[frame.opstk];
  r.li ← 0; IF b.li IN[-31..32] THEN SELECT (shift ← b.low) FROM
    <-15 => { r.low ← BITSHIFT[a.high,shift+16] };
    <  0 => { r.high ← BITSHIFT[a.high,shift];
              r.low ← BITOR[BITSHIFT[a.low,shift],BITSHIFT[a.high,shift+16]] };
    < 16 => { r.low ← BITSHIFT[a.low,shift];
              r.high ← BITOR[BITSHIFT[a.high,shift],BITSHIFT[a.low,shift-16]] };
    ENDCASE => { r.high ← BITSHIFT[a.low,shift-16] };
  PushInteger[frame.opstk,r.li];
  };


-- Initialization

InstallMath: PROC[why: InstallReason, frame: Frame] = { SELECT why FROM
  register => {
    -- Error name
    overflow ← MakeName[".overflow"];
    -- Math commands
    RegisterExplicit[frame,".add"L,JAdd];
    RegisterExplicit[frame,".sub"L,JSub];
    RegisterExplicit[frame,".mul"L,JMul];
    RegisterExplicit[frame,".div"L,JDiv];
    RegisterExplicit[frame,".idiv"L,JIDiv];
    RegisterExplicit[frame,".rdiv"L,JRDiv];
    RegisterExplicit[frame,".neg"L,JNeg];
    RegisterExplicit[frame,".sin"L,JSin];
    RegisterExplicit[frame,".cos"L,JCos];
    RegisterExplicit[frame,".atan"L,JATan];
    RegisterExplicit[frame,".exp"L,JExp];
    RegisterExplicit[frame,".log"L,JLog];
    RegisterExplicit[frame,".sqrt"L,JSqRt];
    RegisterExplicit[frame,".eq"L,JEq];
    RegisterExplicit[frame,".lt"L,JLt];
    RegisterExplicit[frame,".gt"L,JGt];
    RegisterExplicit[frame,".not"L,JNot];
    RegisterExplicit[frame,".and"L,JAnd];
    RegisterExplicit[frame,".or"L,JOr];
    RegisterExplicit[frame,".xor"L,JXor];
    RegisterExplicit[frame,".bitnot"L,JBitNot];
    RegisterExplicit[frame,".bitand"L,JBitAnd];
    RegisterExplicit[frame,".bitor"L,JBitOr];
    RegisterExplicit[frame,".bitxor"L,JBitXor];
    RegisterExplicit[frame,".bitshift"L,JBitShift];
    };
  ENDCASE;
  };

Install[InstallMath];

}.

Wyatt	 7-Nov-81 14:14:30	change .div to do integer division for integer operands
				add .rdiv