Last active
August 29, 2015 14:07
-
-
Save wgb/7431a00f2ac1f96b595e to your computer and use it in GitHub Desktop.
Expression Parser
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
(require '[clojure.string :as str]) | |
;; In this use case, a valid expression won't have an even number of lexemes | |
(defn valid-length? [lexemes] | |
(odd? (count lexemes))) | |
(defn valid-paren-count? [lexemes] | |
(let [opens (filter #(= "(" %) lexemes) | |
closes (filter #(= ")" %) lexemes)] | |
(= (count opens) (count closes)))) | |
(defn pre-validate [lexemes] | |
(and (valid-length? lexemes) | |
(valid-paren-count? lexemes))) | |
(def valid-sequences | |
{:term [:factor :expr-begin] | |
:factor [:term :expr-end] | |
:expr-begin [:factor] | |
:expr-end [:term]}) | |
(defn term? [lexeme] | |
(= lexeme "+")) | |
(defn factor? [lexeme] | |
(or (not (clojure.string/blank? (re-matches #"[A-Z]" check))) | |
(not (clojure.string/blank? (re-matches #"[0-9]" check))))) | |
(defn expr-begin? [lexeme] | |
(= lexeme "(")) | |
(defn expr-end? [lexeme] | |
(= lexeme ")")) | |
(defn lexeme-type [lexeme] | |
(cond | |
(term? lexeme) :term | |
(factor? lexeme) :factor | |
(expr-begin? lexeme) :expr-begin | |
(expr-end? lexeme) :expr-end | |
:else nil)) | |
(defn valid? [prev curr] | |
(when (and prev curr) | |
(let [valid-continuances (prev valid-sequences)] | |
(contains? valid-continuances curr)))) | |
(defn validate-expression [lexemes] | |
(if (pre-validate lexemes) | |
(not-any? false? (reduce (fn [a lexeme] | |
(if (empty? a) | |
(if-not (factor? lexeme) | |
(conj a false) | |
(conj a lexeme)) | |
(let [prev (lexeme-type (last a)) | |
curr (lexeme-type lexeme)] | |
(if (valid? prev curr) | |
(conj a lexeme) | |
(conj a false))))) | |
[] | |
lexemes)) | |
false)) | |
(defn validate-expressions [expressions] | |
(doseq [lexemes expressions] | |
(if (validate-expression lexemes) | |
(println "Accept") | |
(println "Reject")))) | |
(defn split-line [line] | |
"Splits a line of text into a sequence of strings" | |
(str/split line #" ")) | |
(defn read-lines [filename] | |
"Reads a file and returns a sequence made up of a vector for each line" | |
(with-open [reader (clojure.java.io/reader filename)] | |
(for [line (doall (line-seq reader))] | |
(split-line line)))) | |
(defn parse-all [filename] | |
(let [lines (read-lines filename)] | |
(validate-expressions lines))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment