summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormRnea <akannemre@gmail.com>2024-07-31 14:53:18 +0300
committermRnea <akannemre@gmail.com>2024-07-31 14:53:18 +0300
commite4419034ceb01bc58a5cbe228ff8be7439e8defd (patch)
treeee1705cda4b33acb4ff1fd347f33424c9514f95d
parent7f6bb99e08f135fcf067ef71da9f11c872ab7993 (diff)
massive overhaul to defop, temporarily disable interpretation
-rw-r--r--assembly.lisp288
-rw-r--r--cl-forth.lisp153
2 files changed, 232 insertions, 209 deletions
diff --git a/assembly.lisp b/assembly.lisp
index e4582de..13623c7 100644
--- a/assembly.lisp
+++ b/assembly.lisp
@@ -2,6 +2,18 @@
(defparameter *operations* (make-hash-table :test 'equal))
+(defparameter *psuedo-identifiers*
+ '(syscall-1 syscall-2 syscall-3 syscall-4 syscall-5 syscall-6)
+ "These do not map to operations directly, but are valid to lexer")
+
+(defparameter *identifiers* ())
+;; '(+ - dump = ise yoksa yap eş push değiş üst rot düş döngü iken < >
+;; bel oku yaz >> << & "|")
+
+(defun is-identifier (sym)
+ (or (find sym *identifiers* :test #'string=)
+ (find sym *psuedo-identifiers* :test #'string=)))
+
(eval-always
(defun normalize-op-list (asm-list)
(cons 'list
@@ -22,55 +34,175 @@
,(normalize-op-list (cdr forms)))
(cons (replace-write out-stream indent (car forms))
(replace-write out-stream indent (cdr forms))))
- forms)))
-
-(defmacro defop (op-name+args (&key (indent 4)) &body body)
+ forms))
+
+ (defun add-indent (indent fmt-string)
+ (format nil "~a~a"
+ (make-string indent :initial-element #\Space)
+ fmt-string))
+
+ (defun split-stack (stack)
+ (let ((split-num (position '-- stack)))
+ (values (butlast stack (- (length stack) split-num))
+ (nthcdr (+ 1 split-num) stack))))
+
+ (defun op->string (asm-instruction &key (push? t))
+ "asm-instruction is something like (:add rax rbx)"
+ (destructuring-bind (op arg1 arg2) asm-instruction
+ (let ((*print-case* :downcase))
+ (if (null push?)
+ (format nil (format nil "~a ~a, ~a" op arg1 arg2))
+ (list (format nil "~a ~a, ~a" op arg1 arg2)
+ (format nil "push ~a" arg1))))))
+
+ (defun stack->string (stack)
+ (multiple-value-bind (prev next)
+ (split-stack stack)
+ (let ((*print-case* :downcase))
+ (append (iter (for sym in (reverse prev))
+ (collect (format nil "pop ~a" sym)))
+ (iter (for form in next)
+ (cond ((symbolp form)
+ (appending (list (format nil "push ~a" form))))
+ ((listp form)
+ (appending (op->string form)))))))))
+
+ (defun syntax-of (form)
+ (cond ((or (stringp form)
+ (and (consp form) (stringp (car form))))
+ :string)
+ ((and (listp form) (find '-- form))
+ :stack)
+ ((and (listp form) (keywordp (car form)))
+ :op)
+ (t :general)))
+
+ (defun group-by-syntax (forms &optional (syntax nil) (cur ()) (acc ()))
+ (when (null forms)
+ (return-from group-by-syntax
+ (cdr (reverse (append (list (cons (syntax-of (car cur))
+ (reverse cur)))
+ acc)))))
+ (let* ((form (car forms))
+ (form-syntax (syntax-of form)))
+ (cond ((eq syntax form-syntax)
+ (group-by-syntax (cdr forms) syntax
+ (cons form cur) acc))
+ (t (group-by-syntax (cdr forms) form-syntax
+ (list form) (append (list (cons syntax
+ (reverse cur)))
+ acc))))))
+
+ (defun expand-group (group out-stream &key (indent 4))
+ (destructuring-bind (syntax-type . forms) group
+ (case syntax-type
+ (:stack `(defop-format ,out-stream ,indent
+ ,(cons 'list (mapcan (lambda (form) (stack->string form))
+ forms))))
+ (:op `(defop-format ,out-stream ,indent
+ ,(cons 'list (mapcar (lambda (form) (op->string form :push? nil))
+ forms))))
+ (:string `(defop-format ,out-stream ,indent
+ ,(normalize-op-list forms)))
+ (:general `(progn ,@(mapcar (lambda (form) (replace-write out-stream indent
+ form))
+ forms)))))))
+
+(defmacro defop (op-name+args (&key (indent 4) (lex t)) &body body)
(with-gensyms (out-stream)
(destructuring-bind (op-name . args) (mklist op-name+args)
- `(setf (gethash ,(string 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))))))))
+ `(progn
+ ,@(append
+ (unless (null lex)
+ `((push ',op-name *identifiers*)))
+ `((setf (gethash ,(string op-name) *operations*)
+ (lambda (,out-stream ,@args)
+ ,@(mapcar #'(lambda (group) (expand-group group out-stream
+ :indent indent))
+ (group-by-syntax body))))))))))
;;; TODO: Turn stack operation comments to DEFOP option,
;;; which then can be used by the user as a documentation
;;; TODO: Better yet, generate the asm code directly from
;;; the stack op documentation (this seems easily doable)
+;;; Hopefully these two are done, need testing...
;; ( -- a)
-(defop (push a) ()
+(defop (push a) (:lex nil)
("push ~d" a))
-;; (rbx rax -- (rbx + rax))
(defop + ()
- "pop rax"
- "pop rbx"
- "add rax, rbx"
- "push rax")
+ (rbx rax -- (:add rax rbx)))
-;; (rbx rax -- (rbx - rax))
(defop - ()
- "pop rax"
- "pop rbx"
- "sub rbx, rax"
- "push rbx")
+ (rbx rax -- (:sub rbx rax)))
+
+(defop = ()
+ (:mov rcx 0)
+ (:mov rdx 1)
+ (rbx rax -- )
+ (:cmp rax rbx)
+ ( -- (:cmove rcx rdx)))
+
+(defop eş ()
+ (rax -- rax rax))
+
+(defop düş ()
+ (rax -- ))
+
+(defop < ()
+ (:mov rcx 0)
+ (:mov rdx 1)
+ (rax rbx -- )
+ (:cmp rax rbx)
+ ( -- (:cmovl rcx rdx)))
+
+(defop > ()
+ (:mov rcx 0)
+ (:mov rdx 1)
+ (rax rbx -- )
+ (:cmp rax rbx)
+ ( -- (:cmovg rcx rdx)))
+
+(defop bel ()
+ ( -- bel))
+
+(defop oku ()
+ (rax -- )
+ (:xor rbx rbx)
+ (:mov bl [rax])
+ ( -- rbx))
+
+(defop yaz ()
+ (rax rbx -- )
+ (:mov [rax] bl))
+
+(defop üst ()
+ (rbx rax -- rbx rax rbx))
+
+(defop rot ()
+ (rcx rbx rax -- rbx rax rcx))
+
+(defop değiş ()
+ (rbx rax -- rax rbx))
+
+(defop << ()
+ (rbx rcx -- (:shl rbx cl)))
+
+(defop >> ()
+ (rbx rcx -- (:shr rbx cl)))
+
+(defop "|" ()
+ (rbx rcx -- (:or rbx cl)))
+
+(defop & ()
+ (rbx rcx -- (:and rbx cl)))
(defop dump ()
"pop rdi"
"call dump")
-(defop = ()
- "mov rcx, 0"
- "mov rdx, 1"
- "pop rax"
- "pop rbx"
- "cmp rax, rbx"
- "cmove rcx, rdx"
- "push rcx")
-
-(defop (exit code) ()
+(defop (exit code) (:lex nil)
"mov rax, 60"
("mov rdi, ~a" code)
"syscall")
@@ -90,16 +222,6 @@
(:write (" jmp et_~a" döngü-num)
("et_~a:" label-num))))
-;; (rax -- rax rax)
-(defop eş ()
- "pop rax"
- "push rax"
- "push rax")
-
-;; (rax -- )
-(defop düş ()
- "pop rax")
-
(defop (iken label-num) ()
"pop rax"
"test rax, rax"
@@ -108,97 +230,13 @@
(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")
-
-(defop bel ()
- "push bel")
-
-(defop oku ()
- "pop rax"
- "xor rbx, rbx"
- "mov bl, [rax]"
- "push rbx")
-
-(defop yaz ()
- "pop rbx"
- "pop rax"
- "mov [rax], bl")
-
-(defop (syscall num) ()
+(defop (syscall num) (:lex nil)
(iter (with call-regs = #("rdi" "rsi" "rdx" "r10" "r8" "r9"))
(initially (:write "pop rax"))
(for i from (- num 1) downto 0)
(:write ("pop ~a" (aref call-regs i)))
(finally (:write "syscall"))))
-;;; (rbx rax -- rbx rax rbx)
-(defop üst ()
- "pop rax"
- "pop rbx"
- "push rbx"
- "push rax"
- "push rbx")
-
-;;; (rcx rbx rax -- rbx rax rcx)
-(defop rot ()
- "pop rax"
- "pop rbx"
- "pop rcx"
- "push rbx"
- "push rax"
- "push rcx")
-
-;;; (rbx rax -- rax rbx)
-(defop değiş ()
- "pop rax"
- "pop rbx"
- "push rax"
- "push rbx")
-
-;;; (rbx rcx -- (:shl rbx cl))
-(defop << ()
- "pop rcx"
- "pop rbx"
- "shl rbx, cl"
- "push rbx")
-
-;;; (rbx rcx -- (:shr rbx cl))
-(defop >> ()
- "pop rcx"
- "pop rbx"
- "shr rbx, cl"
- "push rbx")
-
-;;; (rbx rcx -- (:or rbx cl))
-(defop "|" ()
- "pop rax"
- "pop rbx"
- "or rbx, rax"
- "push rbx")
-
-;;; (rbx rcx -- (:and rbx cl))
-(defop & ()
- "pop rax"
- "pop rbx"
- "and rbx, rax"
- "push rbx")
-
(defun gen-header (op str)
(format str " ;; -- ~s --~%" op))
diff --git a/cl-forth.lisp b/cl-forth.lisp
index ab2da73..a22bb32 100644
--- a/cl-forth.lisp
+++ b/cl-forth.lisp
@@ -1,13 +1,5 @@
(in-package :cl-forth)
-(eval-always
- (defparameter *identifiers*
- '(+ - dump = ise yoksa yap eş push değiş üst rot düş döngü iken < >
- syscall-1 syscall-2 syscall-3 syscall-4 syscall-5 syscall-6
- bel oku yaz >> << & "|"))
- (defun is-identifier (sym)
- (find sym *identifiers* :test #'string=)))
-
(defun assembly-undefined-ops ()
(iter (for (k) in-hashtable *operations*)
(collect k into defops)
@@ -150,83 +142,76 @@
;;; 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)))))
+;; (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)
- (when (not (is-identifier op-id))
- (error "op-case: ~a is not an identifier" op-id))
- (collect op-id into defined-ops)
- (finally (identifier-coverage defined-ops)))
- (let ((case-sym (gensym)))
- `(let ((,case-sym ,case-form))
- (case ,case-sym
- ,@body
- (otherwise (if (is-identifier (first ,case-sym))
- (error "op: ~a -- Not implemented yet"
- (first ,case-sym))
- (error "op: ~a -- Does not exist"
- (first ,case-sym))))))))
-
-(defun interpret-program (program)
- (iter (with stack = (make-array 100 :fill-pointer 0 :adjustable t))
- ;; (for op in-sequence program)
- (for i from 0 below (length program))
- (let ((op (aref program i)))
- (op-case (first op)
- (push (vector-push-extend (second op) stack))
- (+ (vector-push-extend (+ (vector-pop stack)
- (vector-pop stack))
- stack))
- (- (vector-push-extend (let ((top (vector-pop stack)))
- (- (vector-pop stack) top))
- stack))
- (dump (print (vector-pop stack)))
- (= (vector-push-extend (if (= (vector-pop stack)
- (vector-pop stack))
- 1 0)
- stack))
- (yap (next-iteration))
- (yoksa (setf i (second op)))
- (ise (if (= (vector-pop stack) 1)
- nil
- (setf i (second op))))
- (eş (let ((top (vector-pop stack)))
- (vector-push-extend top stack)
- (vector-push-extend top stack)))
- (değiş (let* ((fst (vector-pop stack))
- (snd (vector-pop stack)))
- (vector-push-extend fst stack)
- (vector-push-extend snd stack)))
- (düş (vector-pop stack))
- (üst (let* ((fst (vector-pop stack))
- (snd (vector-pop stack)))
- (vector-push-extend snd stack)
- (vector-push-extend fst stack)
- (vector-push-extend snd stack)))
- (rot (let* ((fst (vector-pop stack))
- (snd (vector-pop stack))
- (trd (vector-pop stack)))
- (vector-push-extend snd stack)
- (vector-push-extend fst stack)
- (vector-push-extend trd stack)))))))
-;; swap, değiş
-;; dup, eş
-;; over, üst
-;; rot, rot
-;; drop, düşür
-
-
+;; (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)
+;; (when (not (is-identifier op-id))
+;; (error "op-case: ~a is not an identifier" op-id))
+;; (collect op-id into defined-ops)
+;; (finally (identifier-coverage defined-ops)))
+;; (let ((case-sym (gensym)))
+;; `(let ((,case-sym ,case-form))
+;; (case ,case-sym
+;; ,@body
+;; (otherwise (if (is-identifier (first ,case-sym))
+;; (error "op: ~a -- Not implemented yet"
+;; (first ,case-sym))
+;; (error "op: ~a -- Does not exist"
+;; (first ,case-sym))))))))
+
+;; (defun interpret-program (program)
+;; (iter (with stack = (make-array 100 :fill-pointer 0 :adjustable t))
+;; ;; (for op in-sequence program)
+;; (for i from 0 below (length program))
+;; (let ((op (aref program i)))
+;; (op-case (first op)
+;; (push (vector-push-extend (second op) stack))
+;; (+ (vector-push-extend (+ (vector-pop stack)
+;; (vector-pop stack))
+;; stack))
+;; (- (vector-push-extend (let ((top (vector-pop stack)))
+;; (- (vector-pop stack) top))
+;; stack))
+;; (dump (print (vector-pop stack)))
+;; (= (vector-push-extend (if (= (vector-pop stack)
+;; (vector-pop stack))
+;; 1 0)
+;; stack))
+;; (yap (next-iteration))
+;; (yoksa (setf i (second op)))
+;; (ise (if (= (vector-pop stack) 1)
+;; nil
+;; (setf i (second op))))
+;; (eş (let ((top (vector-pop stack)))
+;; (vector-push-extend top stack)
+;; (vector-push-extend top stack)))
+;; (değiş (let* ((fst (vector-pop stack))
+;; (snd (vector-pop stack)))
+;; (vector-push-extend fst stack)
+;; (vector-push-extend snd stack)))
+;; (düş (vector-pop stack))
+;; (üst (let* ((fst (vector-pop stack))
+;; (snd (vector-pop stack)))
+;; (vector-push-extend snd stack)
+;; (vector-push-extend fst stack)
+;; (vector-push-extend snd stack)))
+;; (rot (let* ((fst (vector-pop stack))
+;; (snd (vector-pop stack))
+;; (trd (vector-pop stack)))
+;; (vector-push-extend snd stack)
+;; (vector-push-extend fst stack)
+;; (vector-push-extend trd stack)))))))
;;; COMPILER
(defun write-program (program out &key (mem-cap 640000))