mirror of
https://github.com/richardharrington/robotwar.git
synced 2024-10-02 12:54:39 +00:00
got initial lexer almost working
This commit is contained in:
parent
66172d0b28
commit
857e1d3d0f
@ -1,58 +1,140 @@
|
||||
(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 operators #{\= \< \> \# \+ \- \* \/})
|
||||
|
||||
(defn int-str?
|
||||
[string]
|
||||
(re-find #"^-?\d+$" string))
|
||||
|
||||
(defn lex
|
||||
[initial-line]
|
||||
(loop
|
||||
[line initial-line
|
||||
partial-token ""
|
||||
pos 0
|
||||
result []]
|
||||
(let [conj-to-result (fn [s] (conj result (add-column-metadata s pos)))
|
||||
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)))))
|
||||
|
||||
|
||||
(def error-type-map
|
||||
{:parse-error "Parse Error"
|
||||
:end-of-line-error "End of Line Error"})
|
||||
|
||||
(defn error
|
||||
[error-type error-string]
|
||||
(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 parse
|
||||
"parses a line, by returning a map with the expression, and meta-
|
||||
information. Right now the value is just a number if it's supposed
|
||||
to be a number, otherwise the original string."
|
||||
[line]
|
||||
(reduce (fn [ast ]))
|
||||
(map (fn [word]
|
||||
{:column-number }
|
||||
(number-or-string word))
|
||||
(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")]))
|
||||
; (def prettyprint-tokens [token-seq]
|
||||
; (map #(println (:column %) (:string %))))
|
||||
; [{:string "IF", :column 0}
|
||||
; {:string "DAMAGE", :column 0}
|
||||
; {:string "#", :column 0}
|
||||
; {:string "D", :column 10}
|
||||
; {:string "GOTO", :column 10}
|
||||
; {:string "MOVE", :column 10}]
|
||||
|
||||
|
||||
(defn evaluate
|
||||
"evaluates an ast (right now just prints it).
|
||||
Checks to see if it's a string because that's
|
||||
the way errors are passed. We'll change that."
|
||||
[ast]
|
||||
(if (string? ast)
|
||||
ast
|
||||
(apply str (interpose " " ast))))
|
||||
|
||||
|
||||
(defn repl
|
||||
"make it so"
|
||||
[]
|
||||
(loop []
|
||||
(println (evaluate (parse (lex (read-line)))))
|
||||
(recur)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
; (def error-type-map
|
||||
; {:parse-error "Parse Error"
|
||||
; :end-of-line-error "End of Line Error"})
|
||||
|
||||
; (defn error
|
||||
; [error-type error-string]
|
||||
; (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 evaluate
|
||||
; "evaluates an ast (right now just prints it).
|
||||
; Checks to see if it's a string because that's
|
||||
; the way errors are passed. We'll change that."
|
||||
; [ast]
|
||||
; (if (string? ast)
|
||||
; ast
|
||||
; (apply str (interpose " " ast))))
|
||||
|
||||
|
||||
; (defn repl
|
||||
; "make it so"
|
||||
; []
|
||||
; (loop []
|
||||
; (println (evaluate (parse (lex (read-line)))))
|
||||
; (recur)))
|
||||
|
Loading…
Reference in New Issue
Block a user