Proof of concept compiler
Compiles hand-created nodes for subroutine calls, forward branching, and fixed-length looping into textual 6502 assembly code. Currently only outputs this code to standard output for inspection.
This commit is contained in:
parent
b3887a8e0d
commit
b22f043523
1 changed files with 83 additions and 0 deletions
83
wip-duuqnd/compiler.lisp
Normal file
83
wip-duuqnd/compiler.lisp
Normal file
|
@ -0,0 +1,83 @@
|
|||
(defpackage #:compiler
|
||||
(:use #:cl))
|
||||
|
||||
(in-package #:compiler)
|
||||
|
||||
(defvar *label-counter* 0)
|
||||
|
||||
(defun genlabel (&optional (prefix "L"))
|
||||
(format nil "~A~D" prefix (incf *label-counter*)))
|
||||
|
||||
(defmacro format-inst (destination control-string &rest format-arguments)
|
||||
`(format ,destination "~8@T~A~%" (format nil ,control-string ,@format-arguments)))
|
||||
|
||||
(defclass reference () ())
|
||||
|
||||
(defclass reference-constant (reference)
|
||||
((%value :accessor ref-value :initarg :value)))
|
||||
|
||||
(defmethod dereference ((ref reference-constant))
|
||||
(format-inst t "LDA #~D" (ref-value ref)))
|
||||
|
||||
(defclass reference-variable (reference)
|
||||
((%index :accessor ref-index :initarg :index)))
|
||||
|
||||
(defmethod dereference ((ref reference-variable))
|
||||
(format-inst t "LDY #~D" (ref-index ref))
|
||||
(format-inst t "LDA VARVEC,Y"))
|
||||
|
||||
(defclass node ()
|
||||
((%next :accessor next :accessor normal-next)))
|
||||
|
||||
(defclass node-call (node)
|
||||
((%callee :accessor callee :initarg :callee)
|
||||
(%arguments :accessor arguments :initarg :arguments)))
|
||||
|
||||
(defmethod generate-code ((node node-call))
|
||||
(loop :for ref :in (arguments node)
|
||||
:for index :from 0
|
||||
:do (dereference ref)
|
||||
:do (format-inst t "STA ARGVEC+~D" index))
|
||||
(format-inst t "JSR ~A" (callee node)))
|
||||
|
||||
(defclass node-branch (node)
|
||||
((%branch-next :accessor branch-next :initarg :branch-next)))
|
||||
|
||||
(defmethod generate-code ((node node-branch))
|
||||
(let ((else-label (genlabel "ELSE")))
|
||||
(format-inst t "LDA RESULT")
|
||||
(format-inst t "BNE ~A" else-label)
|
||||
;; THEN branch
|
||||
(generate-code (branch-next node))
|
||||
(format t "~%~A:~%" else-label)))
|
||||
|
||||
(defclass node-dotimes (node)
|
||||
((%spot-ref :accessor stop-ref :initarg :stop-ref
|
||||
:documentation "A reference giving a value of how many times to run the loop.")
|
||||
(%loopee-node :accessor loopee-node :initarg :loopee-node)))
|
||||
|
||||
(defmethod generate-code ((node node-dotimes))
|
||||
(format-inst t "TXA")
|
||||
(format-inst t "PHA")
|
||||
|
||||
(let ((loop-label (genlabel "LOOPBACK")))
|
||||
(dereference (stop-ref node))
|
||||
(format-inst t "TAX")
|
||||
(format t "~%~A:~%" loop-label)
|
||||
(generate-code (loopee-node node))
|
||||
(format-inst t "DEX")
|
||||
(format-inst t "BNE ~A" loop-label))
|
||||
|
||||
(format-inst t "PLA")
|
||||
(format-inst t "TAX"))
|
||||
|
||||
(defun make-call (callee args)
|
||||
(let ((arguments
|
||||
(loop :for (constp value) :in args
|
||||
:with index := -1
|
||||
:if constp
|
||||
:collect (make-instance 'reference-constant :value value)
|
||||
:else
|
||||
:collect (make-instance 'reference-variable :index (incf index)))))
|
||||
(make-instance 'node-call :callee callee
|
||||
:arguments arguments)))
|
Loading…
Add table
Reference in a new issue