blob: 7b2f9ef2e0b93caf8626cab5167fde2010b27e9f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
(defpackage #:argot.examples.calc
(:use #:cl)
(:import-from #:argot #:deflanguage))
(in-package #:argot.examples.calc)
(deflanguage calc (:documentation "A calculator language")
(<calc> :-> (:or
(:seq <subexpr> (:eof))
(:seq <value> (:eof))
(:seq <unop> (:eof))
(:seq <binop> (:eof)))
:then car)
(<expr> :-> (:or <subexpr> <value> <unop> <binop>))
(<subexpr> :-> (:item)
:if listp
:then (argot:parse calc <subexpr>))
(<value> :-> (:item) :if numberp)
(<binop> :-> (:seq (:@ lhs <expr>)
(:@ rhs (:+ (:seq (:or= + - / * ^ %) <expr>))))
:then (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))))))
|