-- 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