diff options
author | mRnea <akannemre@gmail.com> | 2024-07-27 11:58:41 +0300 |
---|---|---|
committer | mRnea <akannemre@gmail.com> | 2024-07-27 11:58:41 +0300 |
commit | 2d94db09901c346d1ac7f5787f89609b6ecf38dd (patch) | |
tree | c0b267150ed6da4855b6d3cbbbf3a5bf3f698968 | |
parent | 025c958e2f8b1499f23a5ae1c1be23452572b326 (diff) |
changed . to dump, extended defop syntax, added while loops
-rw-r--r-- | assembly.lisp | 86 | ||||
-rw-r--r-- | cl-forth.lisp | 85 |
2 files changed, 120 insertions, 51 deletions
diff --git a/assembly.lisp b/assembly.lisp index bdee15c..1522643 100644 --- a/assembly.lisp +++ b/assembly.lisp @@ -3,23 +3,38 @@ (defparameter *operations* (make-hash-table)) (eval-always - (defun normalize-op-list (lst) + (defun normalize-op-list (asm-list) (cons 'list (mapcar (lambda (el) (cond ((stringp el) el) ((listp el) `(format nil ,@el)))) - lst)))) + asm-list))) -(defmacro defop (op-name (&key (indent 4) args) &body asm-strings) - `(setf (gethash ',op-name *operations*) - (lambda (out-stream ,@args) - (format out-stream - ,(format nil "~~{~a~~a~~%~~}" - (make-string indent :initial-element - #\Space)) - ,(normalize-op-list asm-strings))))) + (defun defop-format (str space-num asm-list) + (format str + (format nil "~~{~a~~a~~%~~}" + (make-string space-num :initial-element #\Space)) + asm-list)) + (defun replace-write (out-stream indent forms) + (if (consp forms) + (if (eq :write (car forms)) + `(defop-format ,out-stream ,indent + ,(normalize-op-list (cdr forms))) + (cons (replace-write out-stream indent (car forms)) + (replace-write out-stream indent (cdr forms)))) + forms))) -(defop push (:args (a)) +(defmacro defop (op-name+args (&key (indent 4)) &body body) + (with-gensyms (out-stream) + (destructuring-bind (op-name . args) (mklist op-name+args) + `(setf (gethash ',op-name *operations*) + (lambda (,out-stream ,@args) + ,(if (or (stringp (car body)) (stringp (caar body))) + `(defop-format ,out-stream ,indent + ,(normalize-op-list body)) + (replace-write out-stream indent (car body)))))))) + +(defop (push a) () ("push ~d" a)) (defop + () @@ -34,7 +49,7 @@ "sub rbx, rax" "push rbx") -(defop |.| () +(defop dump () "pop rdi" "call dump") @@ -47,23 +62,60 @@ "cmove rcx, rdx" "push rcx") -(defop exit (:args (exit-code)) +(defop (exit code) () "mov rax, 60" - ("mov rdi, ~a" exit-code) + ("mov rdi, ~a" code) "syscall") -(defop ise (:args (label-num)) +(defop (ise label-num) () "pop rax" "test rax, rax" ("jz et_~a" label-num)) -(defop yoksa (:args (yap-num ise-num) :indent 0) +(defop (yoksa yap-num ise-num) (:indent 0) (" jmp et_~a" yap-num) ("et_~a:" ise-num)) -(defop yap (:args (label-num) :indent 0) +(defop (yap label-num &optional döngü-num) (:indent 0) + (if (null döngü-num) + (:write ("et_~a:" label-num)) + (:write (" jmp et_~a" döngü-num) + ("et_~a:" label-num)))) + +(defop eş () + "pop rax" + "push rax" + "push rax") + +(defop düş () + "pop rax") + +(defop (iken label-num) () + "pop rax" + "test rax, rax" + ("jz et_~a" label-num)) + +(defop (döngü label-num) (:indent 0) ("et_~a:" label-num)) +(defop < () + "mov rcx, 0" + "mov rdx, 1" + "pop rbx" + "pop rax" + "cmp rax, rbx" + "cmovl rcx, rdx" + "push rcx") + +(defop > () + "mov rcx, 0" + "mov rdx, 1" + "pop rbx" + "pop rax" + "cmp rax, rbx" + "cmovg rcx, rdx" + "push rcx") + (defun gen-code (op str) (let ((op-fn (gethash (car op) *operations*))) (if (null op-fn) diff --git a/cl-forth.lisp b/cl-forth.lisp index f7ea66e..a87d0eb 100644 --- a/cl-forth.lisp +++ b/cl-forth.lisp @@ -2,7 +2,7 @@ (eval-always (defparameter *identifiers* - '(+ - |.| = ise yoksa yap eş push değiş üst rot düş)) + '(+ - dump = ise yoksa yap eş push değiş üst rot düş döngü iken < >)) (defun is-identifier (sym) (find sym *identifiers*))) @@ -14,6 +14,7 @@ (defun token-op (token) (car token)) +;;; LEXER (defun lex-line (line &optional (line-num 0)) (iter (with line-stream = (make-string-input-stream line)) (with col = 0) @@ -21,13 +22,13 @@ (for next-char = (peek-char nil line-stream nil nil)) (until (null next-char)) (let ((flag t)) - (cond ((char= #\. next-char) - (collect (make-token '|.| line-num col) into tokens) - (read-char line-stream)) - ((char= #\Space next-char) (read-char line-stream)) - ((char= #\; next-char) ;; and not in string - (finish)) - (t (setf flag nil))) + (cond ;; ((char= #\. next-char) + ;; (collect (make-token '|.| line-num col) into tokens) + ;; (read-char line-stream)) + ((char= #\Space next-char) (read-char line-stream)) + ((char= #\; next-char) ;; and not in string + (finish)) + (t (setf flag nil))) (when flag (incf col) (next-iteration))) @@ -64,34 +65,42 @@ (appending tokens)))) has-error))) -;; (defun prog-from-tokens (tokens) -;; (iter (for token in tokens) -;; (let ((op (token-op token))) -;; (cond ((numberp op) -;; (collect `(push ,op) result-type 'vector)) -;; (t (collect (list op) result-type 'vector)))))) - +;;; PARSER (defun parse-tokens (tokens) (iter (with ops = (make-array (length tokens) :fill-pointer 0 :adjustable t)) - (with if-stack = ()) + (with stack = ()) (for i from 0) (for token in tokens) (let ((op (token-op token))) (cond ((numberp op) (vector-push-extend `(push ,op) ops)) ((eq 'ise op) - (push i if-stack) + (push (list 'ise i) stack) (vector-push-extend (list 'ise nil) ops)) ((eq 'yoksa op) - (let ((current (pop if-stack))) - (setf (second (aref ops current)) i) - (push i if-stack) + (let ((top (pop stack))) + (assert (eq 'ise (car top))) + (setf (second (aref ops (cadr top))) i) + (push (list 'yoksa i) stack) (vector-push-extend (list 'yoksa nil i) ops))) ((eq 'yap op) - (let ((current (pop if-stack))) - (setf (second (aref ops current)) i) - (vector-push-extend (list 'yap i) ops))) + (let ((top (pop stack))) + (cond ((find (car top) (list 'yoksa 'ise)) + (setf (second (aref ops (cadr top))) i) + (vector-push-extend (list 'yap i) ops)) + ((eq 'iken (car top)) + (setf (second (aref ops (cadr top))) i) + (vector-push-extend (list 'yap i (third top)) ops)) + (t (error "yap cannot reference: ~a" (car top)))))) + ((eq 'döngü op) + (push (list 'döngü i) stack) + (vector-push-extend (list 'döngü i) ops)) + ((eq 'iken op) + (let ((top (pop stack))) + (assert (eq 'döngü (car top))) + (push (list 'iken i (cadr top)) stack) + (vector-push-extend (list 'iken nil) ops))) (t (vector-push-extend (list op) ops)))) (finally (return ops)))) @@ -102,17 +111,19 @@ (error "Can't generate program due to error during lexing")) (parse-tokens tokens))) -;; (defun *ops* '(push pop minus dump)) -(define-condition op-not-implemented (style-warning) - ((undef-ops :initarg :ops :reader undef-ops)) - (:report (lambda (condition stream) - (format stream "These ops are not defined in op-case: ~s" - (undef-ops condition))))) -(defun identifier-coverage (defined-ops) - (let ((undef-ops (set-difference *identifiers* defined-ops))) - (unless (null undef-ops) - (warn (make-condition 'op-not-implemented :ops undef-ops))))) +;;; INTERPRETER +(eval-always + (define-condition op-not-implemented (style-warning) + ((undef-ops :initarg :ops :reader undef-ops)) + (:report (lambda (condition stream) + (format stream "These ops are not defined in op-case: ~s" + (undef-ops condition))))) + + (defun identifier-coverage (defined-ops) + (let ((undef-ops (set-difference *identifiers* defined-ops))) + (unless (null undef-ops) + (warn (make-condition 'op-not-implemented :ops undef-ops)))))) (defmacro op-case (case-form &body body) (iter (for (op-id) in body) @@ -178,6 +189,9 @@ ;; rot, rot ;; drop, düşür + + +;;; COMPILER (defun gen-header (op str) (format str " ;; -- ~s --~%" op)) @@ -203,5 +217,8 @@ (defun compile-program (path) (generate-program (make-program path) :compile t)) - +(defun assembly-undefined-ops () + (iter (for (k) in-hashtable *operations*) + (collect k into defops) + (finally (return (set-difference *identifiers* defops))))) |