Source

lisp-random / rpn.lisp

(defparameter *stack-instructions*
  ;; op-string arity symbol
  '(("+"       2     +)
    ("-"       2     -)
    ("*"       2     *)
    ("/"       2     /)
    ("^"       2     expt)
    ("neg"     1     -)
    ("abs"     1     abs)
    )
  "List of the instructions that the RPN interpreter recognizes.")

(defun split (s ss)
  "Split a string SS by a delimiter S."
  (loop
     :for n := 0 :then (+ p (length s))
     :for p := (search s ss :start2 n)
     :if p :collect (subseq ss n p)
     :else :collect (subseq ss n)
     :while p))

(defun integer-literal (s)
  "Check that a string S is an integer literal, and if so, return
it. Junk is allowed on the end of the string."
  (parse-integer s :junk-allowed t))

(defun get-instr (x)
  "Get an instruction from the instruction list. If it doesn't exist,
return NIL."
  (assoc x *stack-instructions* :test #'string-equal))

(defmacro pop-n (n stk)
  "Pop N arguments off of STK and return them in a list."
  `(loop :repeat ,n :collecting (pop ,stk)))

(defun rpn (&optional (stack nil))
  "A little, naïve RPN interpreter."
  (loop
     ;; get le input
     :for u := (progn (format t "> ") (read-line))
     ;; check if the user is tired of this BS yet
     :until (string-equal (string-downcase u) "quit")
     ;; eval the stack
     :do (dolist (i (split " " u))
           (let ((int (integer-literal i))
                 (opr (get-instr i)))
             (cond
               ;; integer
               (int (push int stack))
               ;; operator name
               (opr (push (apply (third opr)
                                 (pop-n (second opr) stack))
                          stack))
               ;; pawp 'n' print
               ((string-equal i ".") (format t "~A~%" (pop stack)))
               ;; DAMNIT
               (t (warn "undefined func: ~S" i)))))
     ;; print le stack
     (format t "top: ~{~A ~};~%" stack)
     ;; return stack when we qvit
     :finally (return stack)))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.