;; --- MiniJava compiler --- ;; I separated out the load / run utilities just because it makes it ;; easier to debug. For example, you can load stuff into the VM, ;; run until it crashes, manually fix the stack, redirect the output ;; to a file, ... all semi-interactively through Lisp. (defun print-java-asm (name) "Print the MiniJava bytecode") (defun run-java-asm (name &optional (stdout t) (stdin nil) (debug nil)) "Run the MiniJava bytecode") (defun load-java-asm (name) "Load MiniJava bytecode into a new VM") (defun compile-java (name) "Compile the named MiniJava program to bytecode") (defun mj-compile (ast) "Translate an MJ program from the AST") ;; --- Construct names for methods, labels --- ;; Hack number 1: the only purpose of having an mj-c-state is so that ;; I have a scratch pad to which everyone can add their own bits of ;; the code. Uses the accumulate-and-reverse idiom. (defstruct mj-c-state code) ; Code list (defun mj-c-vtable-name (class-name) "Create a symbol associated with this method") (defun mj-c-method-name (class-name method-name) "Create a symbol associated with this method") (defun mj-c-label-name () "Create a symbol associated with a stack variable or argument") (defun emit (cs code) "Emit code" (push code (mj-c-state-code cs))) ;; --- Lay out vtable index structure --- (defun setup-mj-vtables (env) "Construct a map from class -> vtable") (defun setup-mj-vtable (class-pair env) "Add to the vtable for a class") ;; --- Generate vtable code --- ;; The vtables are represented as tables of "jump" operations; the label ;; of the first such jump serves as the vtable pointer. (defun mj-c-vtables (env cs) "Generate vtable source") ;; --- Translate methods --- (defun mj-c-methods (env cs) "Translate all methods.") (defun mj-c-method (class-name method-name method env cs) "Translate one method.") ;; --- Compile variable setter/getter code --- (defun mj-c-get-var (var-name env cs) "Retrieve the variable.") (defun mj-c-set-var (var-name env cs) "Set the variable.") ;; --- Compile calls --- ;; To get the address of a call, I look up the vtable (index zero in ;; "this"), add an offset (the vtable index), and call. The vtable ;; instruction then immediately bounces control to the start of the function ;; I want. (defun mj-c-call (ast env cs) "Compile a method call.") ;; --- Compile statements and expressions --- ;; Nothing unusual here, except that if we make alloc initialize everything ;; to zeros, then the only thing we need to initialize in a new object is ;; the vtable pointer. Of course, we'd probably compile a constructor ;; function call if MJ object construction were not so simple. (defun mj-c-statements (statements env cs) "Compile a statement list.") (defun mj-c-statement (ast env cs) "Compile a MiniJava statement.") (defun mj-c-exp (ast env cs) "Translate a MiniJava expression")