home *** CD-ROM | disk | FTP | other *** search
/ AMIGA PD 1 / AMIGA-PD-1.iso / Programme_zum_Heft / Programmieren / Kurztests / ACE / Prgs / ShellUtils / bc.b < prev    next >
Text File  |  1994-01-10  |  7KB  |  417 lines

  1. { ** bc ** 
  2.  
  3.   Unix-style basic calculator with extras.
  4.  
  5.   Legal operators: +,-,*,/,^,(,)
  6.         functions: sin(n),cos(n),tan(n),log(n),sqr(n),fix(n),int(n)
  7.  
  8.   Variables are supported.
  9.  
  10.   bc uses a recursive descent parser.
  11.  
  12.   usage: bc [?]
  13.  
  14.   Author: David Benn
  15.     Date: 21st,22nd March 1992,
  16.         26th January 1993 }
  17.  
  18. '..boolean constants
  19. const true=-1&
  20. const false=0&
  21.  
  22. '..stack 
  23. const maxstack=100
  24. dim stack(maxstack)
  25. shortint stacktop
  26. stacktop=1
  27.  
  28. '..functions
  29. const maxfunc=7
  30. dim funcs$(maxfunc)
  31.  
  32. for i%=1 to maxfunc
  33.   read funcs$(i%)
  34. next
  35.  
  36. data "SIN","COS","TAN","LOG","SQR","FIX","INT"
  37.  
  38. '..symbols
  39. const alpha=1
  40. const number=2
  41. const plus=3
  42. const minus=4
  43. const mult=5
  44. const div=6
  45. const pow=7
  46. const lparen=8
  47. const rparen=9
  48. const equal=10
  49. const eos=11
  50. const letsym=12
  51. const undef=13
  52.  
  53. const maxsym=13
  54. {dim sym.name$(maxsym)
  55. for i%=1 to maxsym
  56.  read sym.name$(i%)
  57. next
  58. data alpha,number,plus,minus,mult,div,pow
  59. data lparen,rparen,equal,eos,letsym,undef}
  60.  
  61. '..reserved words
  62. const maxword=1
  63. dim word$(1)
  64.  
  65. for i%=1 to maxword
  66.   read word$(i%)
  67. next
  68.  
  69. data "LET"
  70.  
  71. '..errors
  72. longint bad
  73. const DIVBYZERO=1
  74. const SYNTAX=2
  75. const STKOVFL=3
  76. const STKUFL=4
  77.  
  78. '..globals
  79. shortint n,length
  80. ch$=""
  81. equ$=""
  82. obj$=""
  83. sym=undef
  84.  
  85. '..variables
  86. dim var(25)
  87.  
  88. for i%=0 to 25
  89.  var(i%)=0
  90. next
  91.     
  92. '..forward references
  93. declare SUB expr   '...factor will call this
  94.  
  95. {SUB show.sym(n)
  96. shared sym.name$
  97.   print sym.name$(n)
  98. END SUB}
  99.  
  100. SUB er(n)
  101. shared bad
  102.   case
  103.     n=DIVBYZERO : print "division by zero"
  104.     n=SYNTAX    : print "syntax error"
  105.     n=STKOVFL    : print "stack overflow"
  106.     n=STKUFL    : print "stack underflow"
  107.   end case
  108.   bad=true
  109. END SUB
  110.  
  111. SUB nextch
  112. shared ch$,equ$,n,length
  113.  
  114.   if n<=length then
  115.     ch$=mid$(equ$,n,1)
  116.     ++n
  117.   else
  118.     ch$=""
  119.   end if 
  120. END SUB
  121.  
  122. SUB rsvd.wd%(x$)
  123. shared word$
  124. shortint n
  125.  
  126.  for i%=1 to maxword
  127.    if x$ = word$(i%) then n=i%
  128.  next
  129.  
  130.  if n=0 then rsvd.wd%=alpha else rsvd.wd%=n+eos
  131. END SUB
  132.  
  133. SUB insymbol
  134. shared ch$,sym,obj$
  135. shortint periods
  136.  
  137.  obj$=""
  138.  sym=undef
  139.  
  140.  '...skip whitespace
  141.  if ch$<=" " and ch$<>"" then
  142.    repeat
  143.      nextch
  144.    until ch$>" " or ch$=""
  145.  end if
  146.  
  147.  '..end of string?
  148.  if ch$="" then sym=eos:exit sub
  149.  
  150.  '...characters
  151.  if ch$>="A" and ch$<="Z" then
  152.    while ch$>="A" and ch$<="Z"
  153.      obj$=obj$+ch$   
  154.      nextch 
  155.    wend
  156.    sym=rsvd.wd%(obj$)
  157.  else  
  158.    '...unsigned numeric constant
  159.    if (ch$>="0" and ch$<="9") or ch$="." then
  160.      sym=number
  161.      while (ch$>="0" and ch$<="9") or ch$="."
  162.        if ch$="." then ++periods
  163.        obj$=obj$+ch$
  164.        nextch
  165.      wend
  166.      if periods > 1 then 
  167.        sym=undef
  168.        er(SYNTAX)
  169.      end if
  170.    else
  171.      '...single character
  172.      obj$=ch$
  173.      case
  174.        obj$="+" : sym=plus
  175.        obj$="-" : sym=minus
  176.        obj$="*" : sym=mult
  177.        obj$="/" : sym=div
  178.        obj$="^" : sym=pow
  179.        obj$="(" : sym=lparen
  180.        obj$=")" : sym=rparen
  181.        obj$="=" : sym=equal
  182.      end case
  183.      if sym=undef then call er(SYNTAX)
  184.      nextch
  185.    end if
  186.  end if
  187. END SUB
  188.  
  189. SUB push(x)
  190. shared stacktop,stack
  191.  
  192.   if stacktop>maxstack then 
  193.     er(STKOVFL)
  194.   else
  195.     stack(stacktop)=x
  196.     ++stacktop
  197.   end if
  198. END SUB
  199.  
  200. SUB pop
  201. shared stacktop,stack
  202.  
  203.   --stacktop
  204.   if stacktop<0 then 
  205.     er(STKUFL) 
  206.   else
  207.     pop=stack(stacktop)
  208.   end if
  209. END SUB
  210.  
  211. SUB func%
  212. shared funcs$,obj$,sym,bad
  213. longint found
  214. shortint funct
  215.  
  216.   funct=0
  217.  
  218.   found=false
  219.   i=1
  220.   while i<=maxfunc and not found
  221.     if funcs$(i) = obj$ then funct=i:found=true else ++i
  222.   wend
  223.  
  224.   if funct then 
  225.     '..function
  226.     fun$=funcs$(funct)
  227.   else
  228.     '..variable
  229.     func%=0
  230.     exit sub
  231.   end if
  232.  
  233.   '...push the argument
  234.   if funct then
  235.     insymbol
  236.     if bad then func%=0:exit sub
  237.     if sym<>lparen then 
  238.       er(SYNTAX)
  239.     else
  240.       insymbol
  241.       if bad then func%=0:exit sub
  242.       expr
  243.       if sym<>rparen then call er(SYNTAX):funct=0
  244.     end if
  245.   end if
  246.  
  247.   '...which function?
  248.   case
  249.     funct=1 : push(sin(pop))
  250.     funct=2 : push(cos(pop))
  251.     funct=3 : push(tan(pop))
  252.     funct=4 : push(log(pop))
  253.     funct=5 : push(sqr(pop))
  254.     funct=6 : push(fix(pop))
  255.     funct=7 : push(clng(pop))
  256.   end case
  257.  
  258.   func%=funct
  259. END SUB
  260.  
  261. SUB factor
  262. shared sym,obj$,bad,var
  263.   if sym=number then 
  264.     push(val(obj$))   '...number
  265.   else
  266.     if sym=lparen then
  267.       insymbol
  268.       if bad then exit sub
  269.       expr
  270.       if sym<>rparen then call er(SYNTAX)
  271.     else  
  272.       '..function or variable
  273.       if func%=0 then call push(var(asc(obj$)-asc("A")))
  274.     end if
  275.   end if
  276.   insymbol
  277. END SUB
  278.  
  279. SUB expterm
  280. shared sym,bad
  281.   factor
  282.   while sym=pow
  283.     insymbol
  284.     if bad then exit sub
  285.     factor
  286.     op2=pop
  287.     op1=pop
  288.     push(op1^op2)
  289.   wend
  290. END SUB
  291.  
  292. SUB negterm
  293. shared sym,bad
  294. longint negate
  295.   negate=false
  296.   if sym=minus then negate=true:insymbol:if bad then exit sub 
  297.   if sym=plus then call insymbol:if bad then exit sub
  298.   expterm
  299.   if negate then call push(-pop)  
  300. END SUB
  301.  
  302. SUB term
  303. shared sym,bad
  304. shortint op
  305.   negterm
  306.   while sym=mult or sym=div
  307.     op=sym
  308.     insymbol
  309.     if bad then exit sub
  310.     negterm
  311.     op2=pop
  312.     op1=pop
  313.     if op=mult then
  314.       push(op1*op2)
  315.     else
  316.       if op2<>0 then 
  317.         push(op1/op2) 
  318.       else 
  319.         er(DIVBYZERO)
  320.       end if
  321.     end if
  322.   wend
  323. END SUB
  324.  
  325. SUB expr
  326. shared sym,bad
  327.   term
  328.   while sym=plus or sym=minus
  329.     op=sym
  330.     insymbol
  331.     if bad then exit sub
  332.     term
  333.     op2=pop
  334.     op1=pop
  335.     if op=plus then
  336.       push(op1+op2)
  337.     else
  338.       push(op1-op2) 
  339.     end if
  340.   wend  
  341.   if sym=undef then call er(SYNTAX)
  342. END SUB
  343.  
  344. SUB assign_var
  345. shared sym,bad,obj$,var
  346.  
  347.  '..variable assignment
  348.  insymbol
  349.  if sym<>alpha then call er(SYNTAX):exit sub
  350.  variable$=obj$
  351.  insymbol
  352.  if sym=equal then
  353.    insymbol
  354.    expr
  355.    if bad then 
  356.      exit sub
  357.    else
  358.      var(asc(variable$)-asc("A"))=pop
  359.    end if
  360.  end if
  361. END SUB
  362.  
  363. SUB parse
  364. shared sym,bad
  365.   insymbol
  366.   if sym=eos then exit sub
  367.   if sym=letsym then 
  368.     assign_var
  369.   else
  370.     expr
  371.     if not bad then print pop
  372.   end if
  373. END SUB
  374.  
  375. SUB usage
  376.   print
  377.   print "Unix-style basic calculator with extras."
  378.   print
  379.   print "operators: + - * / ^ ( )" 
  380.   print "functions: sin(n) cos(n) tan(n) log(n) sqr(n) fix(n) int(n)"
  381.   print
  382.   print "Variables are also supported. There are 26 variables which"
  383.   print "correspond to the first letter of an identifier (ie: A is the"
  384.   print "same as ALTITUDE)."
  385.   print
  386.   print "bc ignores 'flotsam' at the end of a legal line."
  387.   print 
  388.   print "bc is not case sensitive."
  389.   print 
  390.   print "Examples"
  391.   print "--------"
  392.   print 
  393.   print "    (12+2)*3.5-log(7)"
  394.   print "     47.054088"
  395.   print "    let n=log(10)/log(2)"
  396.   print "    n*2.25"
  397.   print "     7.4743376"
  398.   stop
  399. END SUB
  400.  
  401. '...main
  402. print "* bc *"
  403. if argcount=1 and arg$(1)="?" then call usage
  404.  
  405. repeat
  406.   bad=false
  407.   stacktop=1
  408.   ch$=" " 
  409.   n=1
  410.   input ,equ$
  411.   equ$=ucase$(equ$)
  412.   if left$(equ$,1) <> "Q" then
  413.     length=len(equ$)
  414.     parse
  415.   end if
  416. until left$(equ$,1)="Q"
  417.