(defpackage #:argot.examples.calc (:use #:cl) (:import-from #:argot #:deflanguage)) (in-package #:argot.examples.calc) (deflanguage calc (:documentation "A calculator language") ( :-> (:or (:seq (:eof)) (:seq (:eof)) (:seq (:eof)) (:seq (:eof))) :=> car) ( :-> (:or )) ( :-> (:item) :?? listp :=> (argot:parse calc )) ( :-> (:item) :?? numberp) ( :-> (:seq (:@ lhs ) (:@ rhs (:+ (:seq (:or= + - / * ^ %) )))) :=> (expand-binop lhs rhs)) ( :-> (:seq (:or= sin cos tan -) ))) (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))))))