home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / basic / compiler / asic / calc.asi < prev    next >
Text File  |  1994-03-01  |  21KB  |  648 lines

  1. rem CALC.ASI - A simple RPN Calculator written in ASIC
  2. rem Copyright 1993 by David A. Visti--All rights reserved
  3.  
  4. rem RPN stands for Reverse Polish Notation.  Calculators which use
  5. rem RPN are somewhat different than standard calculators which use algebraic
  6. rem notation, but some people, at least me, prefer RPN.  The difference
  7. rem between the two approaches is probably best illustrated with an example:
  8. rem with a standard calculator, to evaluate:   (1 + 2) * (5 + 6)
  9. rem you would have to decide how to enter the data.  In this case, you
  10. rem would perhaps enter the following key strokes:
  11. rem        <1> <+> <2> <=> <store-mem> <5> <+> <6> <=> <*> <recall-mem> <=>
  12. rem
  13. rem With an RPN calculator, you would enter:
  14. rem        <1> <enter> <2> <+> <5> <enter> <6> <+> <*>
  15. rem You simply keep entering numbers (the <enter> pushes the number to the
  16. rem stack) until you can evaluate an expression.  Thus after entering the
  17. rem operands 1 and 2, you can add them.  The RPN calculator will store the
  18. rem result back on the stack.  Next we enter the 5.  We can't multiply yet,
  19. rem so we push it to the stack (press <enter>) and then enter the next
  20. rem operand, 6.  At this point, we can add the 5 and 6, so we press <+>.
  21. rem Now both sub-results are on the stack and we can multiply them by
  22. rem pressing <*>.  This example is shown below with the stack contents shown
  23. rem at the right to better illustrate how this works.  For convenience in
  24. rem referencing the stack entries, they are named "X", "Y", "Z", and finally
  25. rem "A".
  26. rem                                                         STACK
  27. rem                                                         ┌────┐
  28. rem  At the start, the stack is initialized to            a │  0 │
  29. rem  zeros.                                               z │  0 │
  30. rem                                                       y │  0 │
  31. rem                                                       x │  0 │
  32. rem                                                         └────┘
  33. rem                                                         ┌────┐
  34. rem  First, we enter the <1> and press <enter>            a │  0 │
  35. rem                                                       z │  0 │
  36. rem                                                       y │  0 │
  37. rem                                                       x │  1 │
  38. rem                                                         └────┘
  39. rem                                                         ┌────┐
  40. rem  Next, we enter the <2> and press <enter>             a │  0 │
  41. rem                                                       z │  0 │
  42. rem                                                       y │  1 │
  43. rem                                                       x │  2 │
  44. rem                                                         └────┘
  45. rem                                                         ┌────┐
  46. rem  Next, we add 1+2 by pressing the <+> key.            a │  0 │
  47. rem  (Pressing <+> always adds the x and y stack          z │  0 │
  48. rem   entries.  This is also true of <*>, </> and         y │  0 │
  49. rem   <->)                                                x │  3 │
  50. rem                                                         └────┘
  51. rem                                                         ┌────┐
  52. rem  Next, we push the 5 to the stack                     a │  0 │
  53. rem  by typing <5> <enter>                                z │  0 │
  54. rem                                                       y │  3 │
  55. rem                                                       x │  5 │
  56. rem                                                         └────┘
  57. rem                                                         ┌────┐
  58. rem  Next, we push the 6 to the stack                     a │  0 │
  59. rem  by typing <6> <enter>                                z │  3 │
  60. rem                                                       y │  5 │
  61. rem                                                       x │  6 │
  62. rem                                                         └────┘
  63. rem                                                         ┌────┐
  64. rem  Next, we add 5+6 by pressing <+>                     a │  0 │
  65. rem                                                       z │  0 │
  66. rem                                                       y │  3 │
  67. rem                                                       x │ 11 │
  68. rem                                                         └────┘
  69. rem                                                         ┌────┐
  70. rem  Finally, we multiply the two sums together           a │  0 │
  71. rem  by pressing <*>                                      z │  0 │
  72. rem                                                       y │  0 │
  73. rem                                                       x │ 33 │
  74. rem                                                         └────┘
  75. rem
  76. rem In case you're counting, the RPN calculator saves 3 keystrokes
  77. rem in this example.  That's the end of my sales pitch.
  78.  
  79. rem Other functions included in this sample program are:
  80. rem "Clr"      Clear (set to 0) all stack entries (X, Y, Z, and A).
  81. rem "clX"      Clears the "X" stack entry.
  82. rem "xY"      Swaps the values of the "X" and "Y" stack entries
  83. rem "Pop"      Pops the X entry off the stack (discards it), moves the "Y"
  84. rem            stack entry into the "X" stack entry, moves the "Z" stack
  85. rem            entry into the "Y" stack entry, and moves the "A" stack entry
  86. rem            into the "Z" stack entry.
  87. rem "Sgn"      Changes the sign of the "X" stack entry.  If positive, changes
  88. rem            to negative.  If negative, changes to positive.
  89. rem "Quit"     Terminate the program and exit to DOS.
  90.  
  91. rem Note that all of the above functions are labeled on the calculator with
  92. rem one character capitalized.  If you are using the keyboard, press this
  93. rem letter to select the function.  For example, press "Q" to Quit.  If you
  94. rem are using the mouse, click on the calculator key with the left mouse
  95. rem button.
  96.  
  97.  
  98. dim stack@(3)
  99. rem following arrays are used to identify locations of key that was pressed
  100. rem keys--contains the ascii value of the hot key of each calculator key
  101. rem keysx--contains the x coordinate of the left-hand side of each key
  102. rem keysy--contains the y coordinate of the left-hand side of each key
  103. dim keys(22)
  104. dim keysx(22)
  105. dim keysy(22)
  106. rem   0  1  2  3  4  5  6  7  8  9  .  C  X  Y  S  P  Q <┘  +  -  *  /
  107. data 48,49,50,51,52,53,54,55,56,57,46,67,88,89,83,80,81,61,43,45,42,47
  108. rem data for x coords for each of the above keys
  109. data 26,26,32,38,26,32,38,26,32,38,32,26,26,32,32,38,44,38,44,44,44,44
  110. rem data for y coords for each of the above keys
  111. data 21,19,19,19,17,17,17,15,15,15,21,11,13,13,11,11,11,21,21,19,17,15
  112.  
  113. rem PROGRAM LOGIC BEGINS HERE
  114. cls
  115. gosub readdata:
  116. gosub chkscrn:
  117. gosub drawscrn:
  118. gosub detectmouse:
  119. gosub displaystack:
  120. gosub inloop:
  121.  
  122. readdata:
  123.  
  124.    for i=1 to 22
  125.        read keys(i)
  126.    next i
  127.  
  128.    for i=1 to 22
  129.        read keysx(i)
  130.    next i
  131.  
  132.    for i=1 to 22
  133.        read keysy(i)
  134.    next i
  135.    return
  136.  
  137. detectmouse:
  138.    rem detect/init mouse function is function 0
  139.    rem all mouse calls load a function into the AX register
  140.    ax=0
  141.    gosub mouse:
  142.    if ax=-1 then
  143.        rem when ax=-1, mouse was found
  144.        mousefound=1
  145.        rem make mouse visible
  146.        gosub showmouse:
  147.    else
  148.        rem no mouse was found
  149.        mousefound=0
  150.    endif
  151.  
  152.  
  153.  
  154. chkscrn:  rem determine display type and point to video memory
  155.    vidtype=zmode
  156.    if vidtype=1 then
  157.        defseg=&hexb800
  158.        color 14,1
  159.    else
  160.        defseg=&hexb000
  161.    endif
  162.    return
  163.  
  164. drawscrn:  rem draw calculator image on screen
  165.  
  166.    gosub movecursorright25:
  167.    print "┌───────────────────────┐"
  168.    gosub movecursorright25:
  169.    print "│              CALC.ASI │"
  170.    gosub movecursorright25:
  171.    print "├─┬─────────────────────┤"
  172.    gosub movecursorright25:
  173.    print "│a│                     │"
  174.    gosub movecursorright25:
  175.    print "├─┼─────────────────────┤"
  176.    gosub movecursorright25:
  177.    print "│z│                     │"
  178.    gosub movecursorright25:
  179.    print "├─┼─────────────────────┤"
  180.    gosub movecursorright25:
  181.    print "│y│                     │"
  182.    gosub movecursorright25:
  183.    print "├─┼─────────────────────┤"
  184.    gosub movecursorright25:
  185.    print "│x│                     │"
  186.    gosub movecursorright25:
  187.    print "├─┴───┬─────┬─────┬─────┤"
  188.    gosub movecursorright25:
  189.    print "│ Clr │ Sgn │ Pop │ Quit│"
  190.    gosub movecursorright25:
  191.    print "├─────┼─────┼─────┴─────┤"
  192.    gosub movecursorright25:
  193.    print "│ clX │ xY │           │"
  194.    gosub movecursorright25:
  195.    print "├─────┼─────┼─────┬─────┤"
  196.    gosub movecursorright25:
  197.    print "│  7  │  8  │  9  │  /  │"
  198.    gosub movecursorright25:
  199.    print "├─────┼─────┼─────┼─────┤"
  200.    gosub movecursorright25:
  201.    print "│  4  │  5  │  6  │  *  │"
  202.    gosub movecursorright25:
  203.    print "├─────┼─────┼─────┼─────┤"
  204.    gosub movecursorright25:
  205.    print "│  1  │  2  │  3  │  -  │"
  206.    gosub movecursorright25:
  207.    print "├─────┼─────┼─────┼─────┤"
  208.    gosub movecursorright25:
  209.    print "│  0  │  .  │ <─┘ │  +  │"
  210.    gosub movecursorright25:
  211.    print "└─────┴─────┴─────┴─────┘"
  212.    return
  213.  
  214. movecursorright25:  rem position cursor 25 spaces right on current line
  215.    x=pos(0)
  216.    y=csrlin
  217.    x=x+25
  218.    locate y,x
  219.    return
  220.  
  221.  
  222. inloop:    rem loop here until user quits
  223.    rem loop endlessly until user selects "Q"
  224.    while (x=x)
  225.       char$=inkey$
  226.       if mousefound=1 then
  227.            gosub readmouse:
  228.       endif
  229.       if char$="" then inloop:
  230.       char$=ucase$(char$)
  231.       gosub analyzechar:
  232.       if char$="Q" then
  233.           gosub flashkeyon:
  234.           gosub flashkeyoff:
  235.           gosub hidemouse:
  236.           rem Quit
  237.           cls
  238.           end
  239.       else
  240.           if char$="C" then
  241.               rem Clear Stack
  242.               inbuf$=""
  243.               for i=0 to 3
  244.                    stack@(i)=0.0
  245.               next i
  246.               gosub flashkeyon:
  247.               gosub displaystack:
  248.               gosub flashkeyoff:
  249.           else
  250.               if char$="S" then
  251.                   rem Change Sign of X entry of Stack
  252.                   gosub flashkeyon:
  253.                   if inbuf$="" then
  254.                       stack@(0)=stack@(0) * -1.0
  255.                       gosub displaystack:
  256.                   else
  257.                      x$=left$(inbuf$,1)
  258.                      if x$="-" then
  259.                          n=len(inbuf$)
  260.                          n=n-1
  261.                          inbuf$=right$(inbuf$,n)
  262.                      else
  263.                          inbuf$="-"+inbuf$
  264.                      endif
  265.                      gosub displayinbuf:
  266.                   endif
  267.                   gosub flashkeyoff:
  268.               else
  269.                   if chartype$="DIGIT" then
  270.                       gosub flashkeyon:
  271.                       rem Accumulate user input
  272.                       inbuf$=inbuf$+char$
  273.                       gosub displayinbuf:
  274.                       gosub flashkeyoff:
  275.                   else
  276.                       if chartype$="OPERATOR" then
  277.                           gosub operator:
  278.                       else
  279.                            if char$="Y" then
  280.                                rem swap x and y stack entry
  281.                                gosub flashkeyon:
  282.                                if inbuf$="" then
  283.                                   inbuf@=stack@(0)
  284.                                else
  285.                                   gosub convertnum:
  286.                                   inbuf$=""
  287.                                endif
  288.                                if ERROR=0 then
  289.                                   stack@(0)=stack@(1)
  290.                                   stack@(1)=inbuf@
  291.                                   gosub displaystack:
  292.                                   gosub flashkeyoff:
  293.                                endif
  294.                            else
  295.                                if char$="P" then
  296.                                    rem pop x entry off stack
  297.                                    gosub flashkeyon:
  298.                                    stack@(0)=stack@(1)
  299.                                    stack@(1)=stack@(2)
  300.                                    stack@(2)=stack@(3)
  301.                                    gosub displaystack:
  302.                                    gosub flashkeyoff:
  303.                                else
  304.                                    if char$="X" then
  305.                                        rem clear x entry on stack
  306.                                        gosub flashkeyon:
  307.                                        stack@(0)=0.0
  308.                                        inbuf$=""
  309.                                        gosub displaystack:
  310.                                        gosub flashkeyoff:
  311.                                    endif
  312.                                endif
  313.                            endif
  314.                       endif
  315.                   endif
  316.               endif
  317.           endif
  318.       endif
  319.    wend
  320.    return
  321.  
  322. analyzechar:   rem identify what user character is
  323.  
  324.    chartype$="UNKNOWN"
  325.    char=asc(char$)
  326.    if char$="." then
  327.        chartype$="DIGIT"
  328.    else
  329.        if char=13 then
  330.            rem <enter>
  331.            chartype$="OPERATOR"
  332.            char$="="
  333.        else
  334.            if char$="+" then
  335.                chartype$="OPERATOR"
  336.            else
  337.                if char$="-" then
  338.                    chartype$="OPERATOR"
  339.                else
  340.                    if char$="*" then
  341.                        chartype$="OPERATOR"
  342.                    else
  343.                        if char$="/" then
  344.                            chartype$="OPERATOR"
  345.                        else
  346.                            if char$="=" then
  347.                                rem allow "=" as a synonym for <enter>
  348.                                chartype$="OPERATOR"
  349.                            else
  350.                               if char$>"9" then
  351.                               else
  352.                                   if char$<"0" then
  353.                                   else
  354.                                       chartype$="DIGIT"
  355.                                   endif
  356.                               endif
  357.                            endif
  358.                        endif
  359.                    endif
  360.                endif
  361.            endif
  362.        endif
  363.    endif
  364.    return
  365.  
  366. displayinbuf:  rem display user input
  367.    z$=inbuf$
  368.    n=len(z$)
  369.    if n>19 then
  370.        z$=left$(z$,19)
  371.        n=19
  372.    endif
  373.    if n<19 then
  374.        n=19-n
  375.        x$=space$(n)
  376.        z$=x$+z$
  377.    endif
  378.    locate 9,29
  379.    rem if color display, display white on blue
  380.    if vidtype=1 then
  381.        color 15,1
  382.    endif
  383.    print z$;
  384.    return
  385.  
  386. displaystack:  rem display stack
  387.    y=3
  388.    n=3
  389.    for i=0 to 3
  390.        locate y,29
  391.        y=y+2
  392.        x$=str$(stack@(n))
  393.        n=n-1
  394.        if vidtype=1 then
  395.            if i<3 then
  396.                rem display first 3 entries with regular white on color systems
  397.                color 7,1
  398.            else
  399.                rem display x stack entry in bright white on color systems
  400.                color 15,1
  401.            endif
  402.        endif
  403.        print x$;
  404.    next i
  405.    return
  406. operator: rem user entered an operator + - * / = <enter>
  407.    if inbuf$>"" then
  408.       gosub convertnum:
  409.       if ERROR >0 then
  410.            return
  411.       endif
  412.    endif
  413.    if char$="/" then
  414.        gosub flashkeyon:
  415.        gosub pushifinput:
  416.        if (stack@(1)=0.0) then
  417.           inbuf$="Divide By Zero"
  418.           gosub displayinbuf:
  419.           inbuf$=""
  420.        else
  421.            stack@(0)=stack@(0)/stack@(1)
  422.            gosub drop:
  423.        endif
  424.        gosub flashkeyoff:
  425.    else
  426.        if char$="*" then
  427.            gosub flashkeyon:
  428.            gosub pushifinput:
  429.            stack@(0)=stack@(0)*stack@(1)
  430.            gosub drop:
  431.            gosub flashkeyoff:
  432.        else
  433.            if char$="+" then
  434.                gosub flashkeyon:
  435.                gosub pushifinput:
  436.                stack@(0)=stack@(0)+stack@(1)
  437.                gosub drop:
  438.                gosub flashkeyoff:
  439.            else
  440.                if char$="-" then
  441.                    gosub flashkeyon:
  442.                    gosub pushifinput:
  443.                    stack@(0)=stack@(0)-stack@(1)
  444.                    gosub drop:
  445.                    gosub flashkeyoff:
  446.                else
  447.                    if char$="=" then
  448.                        gosub flashkeyon:
  449.                        gosub push:
  450.                        gosub flashkeyoff:
  451.                    endif
  452.                endif
  453.            endif
  454.        endif
  455.    endif
  456.    return
  457.  
  458. push:  rem push current input to stack
  459.    stack@(3)=stack@(2)
  460.    stack@(2)=stack@(1)
  461.    stack@(1)=stack@(0)
  462.    if inbuf$>"" then
  463.        stack@(0)=inbuf@
  464.    endif
  465.    inbuf$=""
  466.    gosub displaystack:
  467.    return
  468.  
  469. pushifinput:   rem if user has entered some characters, then push to stk
  470.    if inbuf$>"" then
  471.        gosub push:
  472.    endif
  473.    return
  474.  
  475. drop:  rem clean up stack after math
  476.    stack@(1)=stack@(2)
  477.    stack@(2)=stack@(3)
  478.    gosub displaystack:
  479.    return
  480.  
  481. flashkeyon:    rem display calc key in reverse video when "pressed"
  482.                rem expects char$ to contain the key pressed
  483.  
  484.    gosub computexy:
  485.    rem check if both coords are 0, if so, not a valid key--don't flash it
  486.    z=x+y
  487.    if z=0 then
  488.        return
  489.    endif
  490.    gosub hidemouse:
  491.    rem timerval@ will be used by flashkeyoff: to delay reseting key
  492.    rem so reverse highlighting is visible
  493.    timerval@=timer
  494.    timerval@=abs(timerval@)
  495.    offset=y*160
  496.    x1=x*2
  497.    offset=offset+x1
  498.    offset=offset+1
  499.    if vidtype=1 then
  500.        rem dark yellow on blue background
  501.        vid=97
  502.    else
  503.        rem reverse video for monochrome systems
  504.        vid=112
  505.    endif
  506.    rem poke the attribute video bytes with new color to make key appear
  507.    rem to flash
  508.    for i=1 to 5
  509.       poke offset,vid
  510.       offset=offset+2
  511.    next i
  512.    gosub showmouse:
  513.    return
  514.  
  515. flashkeyoff:    rem restore normal video on key pressed
  516.                 rem expects char$ to contain key pressed
  517.    gosub computexy:
  518.    rem check if both coords are 0, if so, not a valid key--don't reset flash
  519.    z=x+y
  520.    if z=0 then
  521.        return
  522.    endif
  523. waitloop:
  524.    x@=timer
  525.    x@=abs(x@)
  526.    x@=x@-timerval@
  527.    x@=abs(x@)
  528.    if x@<2@ then waitloop:
  529.    gosub hidemouse:
  530.    offset=y*160
  531.    x1=x*2
  532.    offset=offset+x1
  533.    offset=offset+1
  534.    if vidtype=1 then
  535.        rem reset key to default colors
  536.        vid=30
  537.    else
  538.        rem reset monochrome system key to normal attribute
  539.        vid=07
  540.    endif
  541.    for i=1 to 5
  542.       poke offset,vid
  543.       offset=offset+2
  544.    next i
  545.    gosub showmouse:
  546.    return
  547.  
  548. mouse:  rem mouse interrupt caller (INT 33h)
  549.  
  550.    INT86(&HEX33,AX,BX,CX,DX,NA,NA,NA,NA,NA)
  551.    return
  552.  
  553. readmouse:  rem read mouse input and store in char$ to simulate keyboard
  554.  
  555.    rem check if user has pressed a key, if so, ignore mouse
  556.    if char$>"" then
  557.        return
  558.    endif
  559.  
  560.    rem get mouse button status and position
  561.    ax=3
  562.    gosub mouse:
  563.    mousex=cx
  564.    mousey=dx
  565.    if bx=1 then
  566.        rem left mouse button is being pressed, wait for release
  567.        buttondown=1
  568.        while (buttondown=1)
  569.            ax=3
  570.            gosub mouse:
  571.            newmousex=cx
  572.            newmousey=dx
  573.            if bx=0 then
  574.                buttondown=0
  575.            endif
  576.        wend
  577.        rem the reason we are checking to see if the mouse has moved
  578.        rem is to give the user a chance to "bail out".  If he pressed the
  579.        rem mouse button by mistake, he can move it and release it.  In this
  580.        rem case, we will cancel the button.  If he releases the button, but
  581.        rem hasn't moved the mouse, we assume the mouse click is good.
  582.        if mousex=newmousex then
  583.            if mousey=newmousey then
  584.                rem convert mouse coords to row/col
  585.                mousey=mousey/8
  586.                mousex=mousex/8
  587.                gosub interpretloc:
  588.            endif
  589.        endif
  590.    endif
  591.    return
  592.  
  593. interpretloc:  rem figure out if the mouse pointer was on a button when clicked 
  594.        rem expects mouse coords in: mousex, mousey
  595.  
  596.    for i=1 to 22
  597.        startx=keysx(i)
  598.        endx=startx+4
  599.        if mousex<startx then
  600.        else
  601.            if mousex>endx then
  602.            else
  603.                if mousey=keysy(i) then
  604.                    char$=chr$(keys(i))
  605.                    return
  606.                endif
  607.            endif
  608.        endif
  609.    next i
  610.    return
  611.  
  612. computexy:  rem try to find a key location match for character in "char$"
  613.  
  614.    x=0
  615.    y=0
  616.    char=asc(char$)
  617.    for i=1 to 22
  618.        if char=keys(i) then
  619.            rem matched
  620.            x=keysx(i)
  621.            y=keysy(i)
  622.            return
  623.        endif
  624.    next i
  625.    return
  626.  
  627. hidemouse: rem turn off mouse cursor
  628.  
  629.    ax=2
  630.    gosub mouse:
  631.    return
  632.  
  633. showmouse: rem turn on mouse cursor
  634.    ax=1
  635.    gosub mouse:
  636.    return
  637.  
  638. convertnum: rem convert inbuf$ string to decimal format in inbuf
  639.  
  640.    inbuf@=val(inbuf$)
  641.    if error>0 then
  642.        inbuf$="Input Error"
  643.        gosub displayinbuf:
  644.        inbuf$=""
  645.        inbuf@=0.0
  646.    endif
  647.    return
  648.