got initial lexer almost working

This commit is contained in:
Richard Harrington 2013-07-02 17:28:12 -04:00
parent 66172d0b28
commit 857e1d3d0f

View File

@ -1,58 +1,140 @@
(ns hs-robotwar.core) (ns hs-robotwar.core)
(defn add-column-metadata
[s n]
{:string s,
:column n})
(def registers (set (concat (map #(-> % char str) (range 65 91))
["AIM" "SHOT" "RADAR" "DAMAGE" "SPEEDX" "SPEEDY" "RANDOM" "INDEX"])))
(def error-type-map (def operators #{\= \< \> \# \+ \- \* \/})
{:parse-error "Parse Error"
:end-of-line-error "End of Line Error"})
(defn error (defn int-str?
[error-type error-string] [string]
(str (error-type-map error-type) ": " error-string)) (re-find #"^-?\d+$" string))
(defn valid-number-string (defn lex
[n] [initial-line]
(re-find #"^-?\d+\.?\d*$" n)) (loop
[line initial-line
(defn number-or-string partial-token ""
[x] pos 0
(if (valid-number-string x) result []]
(Float/parseFloat x) (let [conj-to-result (fn [s] (conj result (add-column-metadata s pos)))
x)) new-pos (fn [] (- (count initial-line) (count line)))
previous-token (last result)
parsing-token? (not (empty? partial-token))
first-char (first line)
rest-of-line (rest line)]
(cond
(or (empty? line) (= \; first-char)) (if parsing-token?
(conj-to-result partial-token)
result)
(#{\space \tab} first-char) (if parsing-token?
(recur rest-of-line "" pos (conj-to-result partial-token))
(recur rest-of-line "" pos result))
(= \- first-char) (when (and (int-str? (str (second line)))
(not (or (int-str? previous-token)
(registers previous-token))))
; if true => the minus sign is the beginning of a number
(recur rest-of-line (str first-char) (new-pos) result))
(operators first-char) (recur rest-of-line "" (new-pos) (conj-to-result (str first-char)))
:else (recur rest-of-line (str partial-token first-char) pos result)))))
(defn parse
"parses a line, by returning a map with the expression, and meta- ; (def prettyprint-tokens [token-seq]
information. Right now the value is just a number if it's supposed ; (map #(println (:column %) (:string %))))
to be a number, otherwise the original string." ; [{:string "IF", :column 0}
[line] ; {:string "DAMAGE", :column 0}
(reduce (fn [ast ])) ; {:string "#", :column 0}
(map (fn [word] ; {:string "D", :column 10}
{:column-number } ; {:string "GOTO", :column 10}
(number-or-string word)) ; {:string "MOVE", :column 10}]
(re-seq #"\S+" line)))
(defn validate-expr
"right now just checks to see whether it's a number.
will do a lot more things in the future."
[expr]
(if (number? expr)
[expr nil]
[expr (error :parse-error "Not a number")]))
(defn evaluate
"evaluates an ast (right now just prints it). ; (def error-type-map
Checks to see if it's a string because that's ; {:parse-error "Parse Error"
the way errors are passed. We'll change that." ; :end-of-line-error "End of Line Error"})
[ast]
(if (string? ast) ; (defn error
ast ; [error-type error-string]
(apply str (interpose " " ast)))) ; (str (error-type-map error-type) ": " error-string))
; (defn valid-number-string
; [n]
; (re-find #"^-?\d+\.?\d*$" n))
; (defn number-or-string
; [x]
; (if (valid-number-string x)
; (Float/parseFloat x)
; x))
; (defn string-with-idx
; [s, idx]
; (if (empty? s)
; nil
; {:string s
; :idx idx}))
; (defn tokens-with-column-numbers
; "splits a string and returns a sequence of hashmaps,
; with column-number metadata. separated just by spaces
; for now. In the future, tokens won't necessarily have
; spaces between them."
; [s]
; (let [len (count s)]
; (loop [s s
; idx 0
; partial-word ""
; result []]
; (let [first-s (subs s 0 1)
; rest-s (subs s 1)]
; (cond
; (empty? s) (if (empty? partial-word)
; result
; (conj result (str-with-idx partial-word idx))
; (re-find #"\s" first-s) (if (empty? partial-word)
; (recur rest-s idx "" result)
; (recur rest-s idx "" (conj result (str-with-idx
; partial-word idx))))
; :else (if (empty? partial-word)
; (recur rest-s (- len (count s)) first-s result)
; (recur rest-s idx (str partial-word first-s) result))))))))
; (defn validate-expr
; "right now just checks to see whether it's a number.
; will do a lot more things in the future."
; [expr]
; (if (number? expr)
; [expr nil]
; [expr (error :parse-error "Not a number")]))
(defn repl ; (defn evaluate
"make it so" ; "evaluates an ast (right now just prints it).
[] ; Checks to see if it's a string because that's
(loop [] ; the way errors are passed. We'll change that."
(println (evaluate (parse (lex (read-line))))) ; [ast]
(recur))) ; (if (string? ast)
; ast
; (apply str (interpose " " ast))))
; (defn repl
; "make it so"
; []
; (loop []
; (println (evaluate (parse (lex (read-line)))))
; (recur)))