Created
May 4, 2011 01:11
-
-
Save budu/954579 to your computer and use it in GitHub Desktop.
Recursive implementation of Shunting-yard algorithm (refactored)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns sy2 "based on: https://gist.github.com/953966") | |
(defmacro if-eof [true-f false-f] | |
`(try | |
~false-f | |
(catch Exception e# | |
(if (= (.getMessage e#) "EOF while reading") | |
~true-f | |
(throw e#))))) | |
(defprotocol parser-p | |
(pop-info [this key]) | |
(push-info [this key val]) | |
(lower? [this op]) | |
(->sexp [this op]) | |
(shift-op [this op]) | |
(step [this]) | |
(parse* [this])) | |
(defrecord Parser [tokenizer out-stack op-stack ops] | |
parser-p | |
(pop-info [this key] | |
[(peek (key this)) | |
(assoc this key (next (key this)))]) | |
(push-info [this key val] | |
(assoc this key (conj (key this) val))) | |
(lower? [this op] | |
(<= (or (ops op) 0) | |
(or (ops (peek op-stack)) 0))) | |
(->sexp [this op] | |
(let [[s parser] (pop-info this :out-stack) | |
[f parser] (pop-info parser :out-stack)] | |
(push-info parser :out-stack (list (resolve op) f s)))) | |
(shift-op [this op] | |
(if (lower? this op) | |
(let [[op2 parser] (pop-info this :op-stack)] | |
(if op2 | |
(-> (->sexp parser op2) | |
(shift-op op)) | |
parser)) | |
this)) | |
(step [this] | |
(let [token (tokenizer)] | |
(if (number? token) | |
(push-info this :out-stack token) | |
(-> this | |
(shift-op token) | |
(push-info :op-stack token))))) | |
(parse* [this] | |
(if-eof | |
(->> (iterate #(shift-op % nil) this) | |
(take (inc (count op-stack))) | |
last | |
:out-stack | |
first) | |
(parse* (step this))))) | |
(defn make-parser [tokenizer & [ops]] | |
(Parser. tokenizer '() '() (or ops {'= 1 '+ 2 '* 3}))) | |
(defn tokenizer [s] | |
(let [rdr (java.io.PushbackReader. | |
(java.io.StringReader. s))] | |
#(read rdr))) | |
(defn parse [s] | |
(parse* (make-parser (tokenizer s)))) | |
; (eval (parse "1 + 1 * 2 + 3 = 3 * 2")) => true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment