aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/calc.lisp44
1 files changed, 44 insertions, 0 deletions
diff --git a/examples/calc.lisp b/examples/calc.lisp
new file mode 100644
index 0000000..14b03e5
--- /dev/null
+++ b/examples/calc.lisp
@@ -0,0 +1,44 @@
+
+(defpackage #:argot.examples.calc
+ (:use #:cl)
+ (:import-from #:argot #:deflanguage))
+
+(in-package #:argot.examples.calc)
+
+(deflanguage calc (:documentation "A calculator language")
+ (<calc> :-> (:or
+ (:seq <value> (:eof))
+ (:seq <unop> (:eof))
+ (:seq <binop> (:eof)))
+ :=> car)
+ (<expr> :-> (:or <value> <unop> <binop>))
+ (<value> :-> (:item) :?? numberp)
+ (<binop> :-> (:seq (:@ lhs <expr>)
+ (:@ rhs (:+ (:seq (:or= + - / * ^ %) <expr>))))
+ :=> (expand-binop lhs rhs))
+ (<unop> :-> (:seq (:or= sin cos tan -) <expr>)))
+
+
+(defun lassoc? (op)
+ (member op '(+ -)))
+
+(defparameter +op-table+
+ '((+ . +)
+ (- . -)
+ (^ . expt)
+ (% . mod)
+ (* . *)
+ (/ . /)))
+
+(defun symb->op (op)
+ (cdr (assoc op +op-table+)))
+
+(defun expand-binop (lhs rhs)
+ (let ((op (symb->op (caar rhs))))
+ (if (lassoc? op)
+ `(,(caar rhs) ,lhs ,(if (cdr rhs)
+ (expand-binop (cadar rhs) (cdr rhs))
+ (cadar rhs)))
+ (if (cdr rhs)
+ (expand-binop `(,op ,lhs ,(cadar rhs)) (cdr rhs))
+ `(,op ,lhs ,(cadar rhs))))))