[go: up one dir, main page]

Skip to content

Commit

Permalink
added comments and changed interpreter to stack machine
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack You committed Jun 28, 2018
1 parent bb6f082 commit 2b364d6
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .lein-repl-history
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,8 @@ f 3
(interpreter/interpret (parser/parse (slurp "resources/count.c")))
(interpreter/interpret (parser/parse (slurp "resources/helloworld.ws")))
(parser/parse (slurp "resources/helloworld.ws"))
(interpreter/interpret (parser/parse (slurp "resources/helloworld.ws")))
(parser/parse (slurp "resources/helloworld.ws"))
(interpreter/interpret (parser/parse (slurp "resources/helloworld.ws")))
(interpreter/interpret (parser/parse (slurp "resources/fib.ws")))
(parser/parse (slurp "resources/fib.ws"))
4 changes: 2 additions & 2 deletions src/clj_whitespace/core.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns clj-whitespace.core
(:require [clj-whitespace.parser :as parser]
[clj-whitespace.interpreter :as interpreter]
[clj-whitespace.stackmachine :as stack-machine]
[clojure.string :as string]
[clojure.tools.cli :refer [parse-opts]]
[instaparse.core :as insta]
Expand Down Expand Up @@ -46,4 +46,4 @@
(System/exit (if ok? 0 1)))
(case action
:generate-intermediate (clojure.pprint/pprint(parser/parse (slurp file)))
:execute-source (interpreter/interpret (parser/parse (slurp file)))))))
:execute-source (stack-machine/interpret (parser/parse (slurp file)))))))
23 changes: 17 additions & 6 deletions src/clj_whitespace/parser.clj
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
(ns clj-whitespace.parser

(:require [clojure.core.match :refer [match]])
(:require [instaparse.core :as insta :refer [defparser]])
(:gen-class))

(def whitespacer
(def whitespacer
"This is a formal ebnf grammar specified from
https://hackage.haskell.org/package/whitespace-0.4/src/docs/tutorial.html"
(insta/parser
"
<S> = imp+ ;
Expand Down Expand Up @@ -53,25 +54,35 @@
<lf> = \"\n\" ;
" :start :S))

(defn tokenize [s] (apply str (re-seq #"[ \t\n]" s)))
(defn tokenize
"The tokenize function filters all non-accepted characters
from the input string as a prequesite for parsing."
[s]
(apply str (re-seq #"[ \t\n]" s)))

(defn parse [s]
(defn parse
"An input string `s` is tokenzied and parsed through the instaparse grammar.
Then the symbolic Whitespace numbers are transformed into appropriate integers.
Finally, any integer designating a location in the program is verified to be unique."
[s]
(->>
(insta/parse
whitespacer
(tokenize s)
:total true)
(tokenize s))
;; convert whitespace numbers to integers and generalize jump instruction.
(insta/transform
{:number (fn [x & xs] (* (if (= x "\t") (- 1) 1) (Integer/parseUnsignedInt (apply str (replace {"\t" "1" " " "0"} xs)) 2)))
:label (fn [x & xs] (Integer/parseUnsignedInt (apply str (replace {"\t" "1" " " "0"} (cons x xs))) 2))
:jz (fn [x] [:jump :eq x])
:jn (fn [x] [:jump :ne x])
:jmp (fn [x] [:jump :un x])
})
;; assert all labels are distinct
((fn [xs]
(if (distinct? (filter (fn [x] (match [x] [[:location l]] true :else false)) xs))
xs
(throw (Exception. "duplicate labels present")))))
;; flatten the vector
(map (fn [x]
(match [x]
[[y]] y
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
(ns clj-whitespace.interpreter
(ns clj-whitespace.stackmachine
(:require [clojure.core.match :refer [match]])
(:gen-class))


(defn interpret [prgm]
(defn interpret
"This function initiates a clean state for the stack machine and
executes the program denoted by `prgm`, a vector of instruction keywords and
their corresponding arguments."
[prgm]
(let
[
;; machine state variables
stack (atom '())
call-stack (atom '())
heap (atom {})
pc (atom 0)
state (atom :continue)
jump-table (atom {})

;; custom pop and return function
consume (fn [] (let [top-item (peek @stack)] (swap! stack pop) top-item))

;; FIXME: this should be a macro
;; generic binary operation function
binary-op (fn [op]
(let [a (consume) b (consume)]
(swap! stack conj (op b a))))


;; execute (1) instruction with side effects on the
;; state of the machine.
exec (fn [cmd]
(match [cmd]
[[:push val]]
Expand Down Expand Up @@ -57,20 +67,26 @@
[:read-char]
(let [keyint (.read System/in) addr (consume)]
(swap! heap conj {addr keyint}))
;; TODO: add read-int
[[:location loc]]
(reset! state :continue)
[[:call addr]]
(do
(swap! call-stack conj (inc pc))
(reset! pc addr))
;; generic jump instruction
[[:jump condition label]]
(let
;; decide if a jump should occur
[b (case condition
:eq (if (== (consume) 0) true false)
:ne (if (< (consume) 0) true false)
:un true)]
(when b
(reset! state :jump)
;; if this is the 1st time jumping to a label,
;; cache the corresponding address in the jump table, otherwise fetch
;; the address from the jump table
(if (contains? @jump-table label)
(reset! pc (@jump-table label))
(let
Expand All @@ -84,6 +100,7 @@
[:end] (reset! state :halt)
))
]
;; infinite loop breaking on the halt state.
(loop []
(do
(exec (prgm @pc))
Expand Down

0 comments on commit 2b364d6

Please sign in to comment.