!Graham Toal - latest development version of SKIMPE 23/01/80 18.58
%external %integer %array %spec a(1 : 500)

%external %integer %array %spec taglink(0 : 255)

%external %integer %array %spec tag(1 : 512)

%external %string (5) %array %spec display(0 : 15)

%external %integer %spec level, condflag, expropt
!-----------------------------------------------------------------------
%external %string (7) %fn %spec s(%integer i)
%external %string (255) %fn %spec strint(%integer n, p)
%external %string (8) %fn %spec strhex(%integer n)
%external %routine %spec fault(%string (63) s)
%external %string (255) %fn %spec name(%integer ident)
%external %routine %spec dump(%string (7) lab, op, reg, addr)
%external %integer %fn %spec getwork
%external %routine %spec returnwork(%integer work)
%external %routine %spec proc(%integer ap)
%external %routine %spec array(%integer ap)
%external %integer %fn %spec getcoti(%integer const)
!-----------------------------------------------------------------------
%const %integer proceedure = -1, arrayelement = -2, scalar = -3, unary = 11, %c
  complex = -2, terminal = 0, true = 1, load = 0, exp = 6, sub = 10, %c
  mult = 8, div = 7, shr = 2, shl = 1, cmp = 13
!------------------------------------------------------------------------
%external %integer %fn intstr(%string (6) val)
   %integer i, total
   total = 0
   %for i = 1, 1, length(val) %cycle
      total = total * 10 + charno(val, i) - '0'
   %repeat
   %result = total
%end
%external %routine expr(%integer exprp)
   %integer %fn %spec totree(%integer exprp)
   %routine %spec evaluate(%integer exprp)
   %routine %spec opn(%integer op, ptr)
   %integer %array tree(1 : 64)
   %integer treep, treenode, treenode1, treenode2, testp, expr1p, expr2p, compp, i, j, l
   %const %integer %array reversecomp(1 : 6) = 1, 2, 5, 6, 3, 4

   treep = 1
   %if condflag = 0 %then treenode = totree(exprp) %else %start
      condflag = 0
      testp = exprp
      ! for <test>=<expr><comp><expr>
      expr1p = a(testp + 1)
      compp = a(testp + 2)
      expr2p = a(testp + 3)
      treenode1 = totree(expr1p)
      treenode2 = totree(expr2p)
      tree(treep) = 13
      ! CMP
      %if tree(treenode1) = -4 %then %start
         a(compp) = reversecomp(a(compp))
         tree(treep + 1) = treenode2
         tree(treep + 2) = treenode1
      %finish %else %start
         tree(treep + 1) = treenode1
         tree(treep + 2) = treenode2
      %finish
      treenode = treep
   %finish
   %if expropt = 1 %then %start
      newline
      %if 0 < tree(treenode) <= 10 %then l = treenode + 2 %else l = treenode + 1
      j = 0
      %for i = 1, 1, l %cycle
         write(tree(i), 4)
         j = j + 5
         %if i = treenode %then printstring("*") %and j = j + 1
         %if tree(i) = -3 %then i = i + 1 %and printstring("  " . strhex(tree(i))) %and j = j + 10
         %if j > 70 %then newline %and j = 0
      %repeat
      newlines(2)
   %finish
   evaluate(treenode)
   %return
   !-----------------------------------------------------------------------
   %integer %fn totree(%integer exprp)
      ! create tree form of expression
      %routine %spec pseval(%integer type, datum)
      %integer %array os(1 : 4), ps(1 : 5)
      ! operator & pseudo-evaluation stacks
      %integer osp, psp, unaryp, operandp, exprrestp, opp, namep, actualp, ident, nametag
      %const %integer %array prec(1 : 12) = 3, 3, 2, 1, 1, 3, 2, 2, 1, 1, 1, 4

      ! <<,>>,&,!!,!,**,/,*,+,-,-(unary),\
      %integer %fn constop(%integer op, val1)
         %switch exec(1:10)
         %integer res
         -> exec(op)
exec(1): 
         ! <<
         res = tree(val1 + 1) << tree(val1 + 3)
         -> cont
exec(2): 
         ! >>
         res = tree(val1 + 1) >> tree(val1 + 3)
         -> cont
exec(3): 
         ! &
         res = tree(val1 + 1) & tree(val1 + 3)
         -> cont
exec(4): 
         ! !!
         res = tree(val1 + 1) !! tree(val1 + 3)
         -> cont
exec(5): 
         ! !
         res = tree(val1 + 1) ! tree(val1 + 3)
         -> cont
exec(6): 
         ! **
         res = tree(val1 + 1) \\ tree(val1 + 3)
         -> cont
exec(7): 
         ! /
         %if tree(val1 + 3) = 0 %then fault("DIVISION BY ZERO") %and res = 0 %and -> cont
         res = tree(val1 + 1) // tree(val1 + 3)
         -> cont
exec(8): 
         ! *
         res = tree(val1 + 1) * tree(val1 + 3)
         -> cont
exec(9): 
         ! +
         res = tree(val1 + 1) + tree(val1 + 3)
         -> cont
exec(10): 
         ! -
         res = tree(val1 + 1) - tree(val1 + 3)
cont: 
         %result = res
      %end
      unaryp = a(exprp + 1)
      operandp = a(exprp + 2)
      exprrestp = a(exprp + 3)
      %if a(unaryp) <= 2 %then os(1) = a(unaryp) + 10 %and osp = 1 %else osp = 0
      psp = 0
      %cycle 
         ! for each operand
         %if a(operandp) = 1 %then %start
            ! <name><actual>
            namep = a(operandp + 1)
            actualp = a(operandp + 2)
            ident = a(namep + 1)
            %if taglink(ident) = 0 %then %start
               !?        fault(name(ident)." NOT DECLARED")
               pseval(-3, -ident)
               ! pseval dummy tag
            %finish %else %start
               nametag = tag(taglink(ident))
               %if nametag >> 28 <= 1 %then %start
                  ! scalar variable
                  %if a(actualp) = 1 %then %start
                     fault("SCALAR " . name(ident) . " HAS PARAMETER")
                     pseval(-3, 0)
                  %finish %else pseval(-3, nametag)
               %finish %else %start
                  %if nametag >> 28 <= 3 %then pseval(-2, operandp) %else %start
                     %if nametag >> 24 & 16_F = 0 %then %start
                        fault("ROUTINE NAME " . name(ident) . " IN EXPRESSION")
                        pseval(-3, 0)
                     %finish %else pseval(-1, operandp)
                  %finish
               %finish
            %finish
         %finish %else %start
            %if a(operandp) = 2 %then pseval(-4, a(a(operandp + 1) + 1)) %c
            %else psp = psp + 1 %and ps(psp) = totree(a(operandp + 1))
         %finish
         %if a(exprrestp) = 2 %then %exit
         ! no more operands
         opp = a(exprrestp + 1)
         operandp = a(exprrestp + 2)
         exprrestp = a(exprrestp + 3)
         pseval(os(osp), 0) %and osp = osp - 1 %while osp > 0 %and prec(a(opp)) <= prec(os(osp))
         ! unstack while prec(new op)<=
         osp = osp + 1
         ! stack new operator
         os(osp) = a(opp)
      %repeat
      pseval(os(osp), 0) %and osp = osp - 1 %while osp > 0
      ! unstack rest
      %result = ps(1)
      !-----------------------------------------------------------------------
      %routine pseval(%integer type, datum)
         %routine %spec store(%integer t)
         %integer nodep, temp
         nodep = treep
         store(type)
         %if type > 0 %then %start
            ! operator
            %if type > 10 %then %start
               store(ps(psp))
            %finish %else %start
               %if tree(ps(psp - 1)) = -4 %and tree(ps(psp)) = -4 %c
                 %and ps(psp - 1) = treep - 5 %and ps(psp) = treep - 3 %start
                  temp = constop(type, treep - 5)
                  %if temp >= 0 %then %start
                     treep = ps(psp - 1) + 2
                     tree(ps(psp - 1) + 1) = temp
                     psp = psp - 1
                     ps(psp) = treep - 2
                     %return
                  %finish %else -> over
               %finish %else %start
over: 
                  store(ps(psp - 1))
                  store(ps(psp))
                  psp = psp - 1
               %finish
            %finish
         %finish %else store(datum) %and psp = psp + 1
         ps(psp) = nodep
         !-----------------------------------------------------------------------
         %routine store(%integer t)
            %if treep > 64 %then fault("EXPRESSION TOO LONG") %and %stop
            tree(treep) = t
            treep = treep + 1
         %end
      %end
   %end
   !-----------------------------------------------------------------------
   %const %string (3) %array strop(0 : 13) = "LD", "SHL", "SHR", "AND", "EOR", %c
     "OR", "EXP", "DIV", "MUL", "ADD", "SUB", "NEG", "COM", "CMP"

   %const %integer %array args(0 : 13) = 1, 0, 0, 1, 1, 1, 0, 0, -1, 1, 1, 1, 1, 1

   %const %integer %array commut(0 : 13) = 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1

   %routine doop(%integer op, %string (10) val)
      %string (6) const
      %integer value
      %switch clever(0:13)
      ! B op VAL
      %if args(op) # 1 %start
         %if val -> ("#") . const %then %start
            value = intstr(const)
            -> clever(op)
clever(mult): 
            %if value = 2 %or value = 4 %then %start
               dump("", "ASL", "B", "") %and value = value >> 1 %while value # 1
            %finish
            %return %if value = 1
            -> eval
clever(div): 
            %if value = 2 %or value = 4 %then %start
               dump("", "ASR", "B", "") %and value = value >> 1 %while value # 1
            %finish
            %return %if value = 1
            -> eval
clever(exp): 
            %if value = 2 %then %start
               dump("", "TFR", "", "B,A")
               dump("", "MUL", "", "")
               %return
            %finish %else -> eval
clever(shl): 
            %if 1 <= value <= 2 %then %start
               dump("", "LSL", "B", "") %and value = value - 1 %until value = 0
            %finish
            %return %unless 3 <= value <= 7
            -> eval
clever(shr): 
            %if 1 <= value <= 2 %then %start
               dump("", "LSR", "B", "") %and value = value - 1 %until value = 0
            %finish
            %return %unless 3 <= value <= 7
            -> eval
            clever(*):

eval: 
         %finish
         dump("", "LD", "A", val)
         %if args(op) < 0 %start
            dump("", "MUL", "", "")
         %finish %else %start
            dump("", "LBSR", "", strop(op))
         %finish
      %finish %else %start
         dump("", strop(op), "B", val)
      %finish
   %end
   %routine opn(%integer op, nodep)
      %integer type, basep, varp, disp
      %string (4) base
      type = tree(nodep)
      %if type > scalar %then fault("*BUG")
      varp = tree(nodep + 1)
      %if varp < 0 %then %start
         doop(op, name(-varp))
      %finish %else %start
         %if type = scalar %start
            basep = varp >> 16 & 16_F
            base = display(basep)
            base = ",Y" %if basep = level
            base = ",X" %if basep = 1
            disp = varp & 16_FFFF
            %if varp >> 28 = 1 %start
               %if basep = level # 1 %start
                  doop(op, "[" . "-" . s(disp) . base . "]")
               %finish %else %if basep # level # 1 %start
                  dump("", "PSH", "U", "A,B")
                  dump("", "LD", "D", base)
                  dump("", "ADD", "D", "#" . s(disp))
                  dump("", "ST", "D", "0,X")
                  dump("", "PUL", "U", "A,B")
                  doop(op, "[0,X]")
               %finish
               %return
            %finish
            %if basep = level %or basep = 1 %start
               doop(op, "-" . s(disp) . base)
            %finish %else %start
               dump("", "PSH", "U", "A,B")
               dump("", "LD", "D", base)
               dump("", "ADD", "D", "#" . s(disp))
               dump("", "ST", "D", "0,X")
               dump("", "PUL", "U", "A,B")
               doop(op, "[0,X]")
            %finish
         %finish %else %start
            doop(op, "#" . s(varp))
         %finish
      %finish
   %end
   %routine regop(%integer op, %string (7) r1, r2)
      ! R1 op R2
      %if args(op) # 1 %start
         %if args(op) < 0 %start
            dump("", "MUL", "", "")
         %finish %else %start
            dump("", "LBSR", "", strop(op))
         %finish
      %finish %else %start
         dump("", strop(op), r1, r2)
      %finish
   %end
   %routine loadb(%integer nodep)
      %integer type, datum
      type = tree(nodep)
      datum = tree(nodep + 1)
      %if type = proceedure %start
         proc(datum)
         %return
      %finish
      %if type = arrayelement %start
         array(datum)
         dump("", "LD", "B", "[0,X]")
         %return
      %finish
      opn(load, nodep)
   %end
   %routine evaluate(%integer nodep)
      %integer op, opd1p, opd2p
      %if tree(nodep) <= terminal %start
         loadb(nodep)
         %return
      %finish
      op = tree(nodep)
      opd1p = tree(nodep + 1)
      %if cmp > op >= unary %start
         !
         ! TEST FOR CONST NODE HERE
         !
         evaluate(opd1p)
         dump("", strop(op), "B", "")
         %return
      %finish
      opd2p = tree(nodep + 2)
      !
      ! TEST FOR BOTH NODES CONST HERE
      !
      %if tree(opd1p) >= complex %start
         %if tree(opd2p) >= complex %start
            evaluate(opd2p)
            dump("", "PSH", "U", "B")
            evaluate(opd1p)
            doop(op, ",U+")
         %finish %else %start
            evaluate(opd1p)
            opn(op, opd2p)
         %finish
      %finish %else %start
         %if tree(opd2p) >= complex %start
            evaluate(opd2p)
            %if commut(op) = true %start
               opn(op, opd1p)
               %return
            %finish
            %if args(op) <= 0 %start
               dump("", "TFR", "", "B,A")
               opn(load, opd1p)
               regop(op, "B", "A")
            %finish %else %start
               dump("", "PSH", "U", "B")
               opn(load, opd1p)
               doop(op, ",U+")
            %finish
         %finish %else %start
            opn(load, opd1p)
            opn(op, opd2p)
         %finish
      %finish
   %end
%end
%end %of %file
