#lang scheme
(require "peg.ss")
(define (convert-to-decimal n)
(if (= 0 n)
0
(/ n (expt 10 (ceiling (/ (log n) (log 10)))))))
(define calc
(peg
(start s)
(grammar
(s (((* line)) _))
(line (((bind c expr) w "\n")
(begin
(printf "~a\n" c)
c)))
(w (((* space-tab)) (void)))
(space-tab ((" ") _)
((" ") _))
(expr ((prec1) _))
(num (((bind d digit) (bind rest (* digit)) (bind decimal (? "." (* digit))))
(+ (string->number (apply string-append d rest))
(convert-to-decimal
(string->number (apply string-append "0" decimal))))))
(base (("(" w (bind e expr) w ")") e)
(((bind o op) w "(" w (bind e expr) w ")")
(o e))
(((bind o multi-op) w "(" w (bind e1 expr) (bind es (* w "," expr)) w ")")
(apply o e1 es))
(("pi") pi)
((num) _))
(multi-op (("gcd") gcd)
(("lcm") lcm)
(("max") max)
(("min") min))
(op (("sinh") sinh)
(("cosh") cosh)
(("random") random)
(("round") round)
(("floor") floor)
(("ceiling") ceiling)
(("truncate") truncate)
(("sin") sin)
(("cos") cos)
(("log") log))
(digit (("0") _)
(("1") _)
(("2") _)
(("3") _)
(("4") _)
(("5") _)
(("6") _)
(("7") _)
(("8") _)
(("9") _))
(prec-last ((base) _))
(prec1 (((bind n prec2) w "+" w (bind e prec1))
(+ n e))
(((bind n prec2) w "-" w (bind e prec1))
(- n e))
((prec2) _))
(prec2 (((bind n prec3) w "*" w (bind e prec2))
(* n e))
(((bind n prec3) w "/" w (bind e prec2))
(/ n e))
((prec3) _))
(prec3 (((bind n prec4) w "^" w (bind e prec3))
(expt n e))
((prec4) _))
(prec4 (("-" (bind n expr)) (- n))
((prec-last) _)))))
(printf "Type some arithmetic, then hit enter. Press enter on a blank line to end the calculator\n")
(calc (let ((input (make-hash)))
(lambda (i)
(hash-ref input i
(lambda ()
(let ((next (read-char)))
(hash-set! input i next)
next))))))