diff options
author | bd <bdunahu@operationnull.com> | 2025-04-10 01:23:38 -0400 |
---|---|---|
committer | bd <bdunahu@operationnull.com> | 2025-04-10 01:23:38 -0400 |
commit | 3eeebe73826906b1c598d5e5d207bfee936ed315 (patch) | |
tree | 9b750918dcc606a4a228503201f870249303cc7c | |
parent | e50d44464db7eb8e1c20755c862466ac8f7419b0 (diff) |
Messy data section
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | src/main.lisp | 2 | ||||
-rw-r--r-- | src/package.lisp | 4 | ||||
-rw-r--r-- | src/parse.lisp | 86 | ||||
-rw-r--r-- | t/parse.lisp | 103 |
5 files changed, 117 insertions, 79 deletions
@@ -10,6 +10,7 @@ A common-lisp implementation (SBCL) and the following libraries are required to - ASDF (tested with v3.3.7) - fiveam (tested with v3.3.7) - clingon (tested with v0.5.0-1.f2a730f) +- esrap (tested with v0.18-4.d806138) ## To run diff --git a/src/main.lisp b/src/main.lisp index be9f69a..9692603 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -38,7 +38,7 @@ _/_/ _/_/ " (error "The file is not an asm source code file.~%")) (t (let ((str (uiop:read-file-string file))) (if str - (progn (pprint (esrap:parse 'parse:text (string-upcase str))) + (progn (pprint (esrap:parse 'parse:str->ast (string-upcase str))) (terpri) (maphash #'(lambda (k v) (format t "~A => ~A~%" k v)) util:label-table) (format t "---~%")) diff --git a/src/package.lisp b/src/package.lisp index efa617c..4bdd274 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -21,8 +21,8 @@ (defpackage #:parse (:use #:cl) - (:export ;; exported for testing only - #:text + (:export #:str->ast + ;; exported for testing only #:register #:instr )) diff --git a/src/parse.lisp b/src/parse.lisp index f9ede20..109205f 100644 --- a/src/parse.lisp +++ b/src/parse.lisp @@ -1,42 +1,50 @@ (in-package #:parse) -(defparameter line-number 0) +(defparameter line-number 0 + "The number of real instructions processed up until this point.") +(defparameter var-offset 0 + "The number of variables processed up until this point.") (esrap:defrule space (+ (or #\space #\tab)) (:constant nil)) -(esrap:defrule newline - (+ #\newline) +(esrap:defrule nl (+ #\newline) + (:constant nil)) + +(esrap:defrule nl-inc (+ #\newline) (:destructure (n) (declare (ignore n)) (incf line-number) nil)) +(esrap:defrule alpha (+ (alphanumericp character)) + (:text t)) + ;;; defines rules to parse an integer in various bases (defmacro define-number-rule ()) (esrap:defrule binary (and #\0 #\B (+ (or "0" "1"))) - (:lambda (list) (parse-integer (esrap:text (cddr list)) :radix 2))) + (:lambda (e) (parse-integer (esrap:text (cddr e)) :radix 2))) (esrap:defrule octal (and #\0 #\O (+ (or (esrap:character-ranges (#\0 #\7))))) - (:lambda (list) (parse-integer (esrap:text (cddr list)) :radix 8))) + (:lambda (e) (parse-integer (esrap:text (cddr e)) :radix 8))) (esrap:defrule decimal (+ (or (esrap:character-ranges (#\0 #\9)))) - (:lambda (list) (parse-integer (esrap:text list) :radix 10))) + (:lambda (e) (parse-integer (esrap:text e) :radix 10))) (esrap:defrule hex (and #\0 #\X (+ (or (esrap:character-ranges (#\0 #\9)) "A" "B" "C" "D" "E" "F"))) - (:lambda (list) (parse-integer (esrap:text (cddr list)) :radix 16))) + (:lambda (e) (parse-integer (esrap:text (cddr e)) :radix 16))) (esrap:defrule int (or binary octal hex decimal)) ;;; defines rules to parse an operand -(esrap:defrule register (and #\$ (or int reg-id)) +(esrap:defrule register (and #\$ int) (:function cadr) - (:lambda (id) (list 'rr id))) + (:lambda (e) (list 'rr e))) (esrap:defrule dereference (and (esrap:? (or #\+ #\-)) int #\( register #\)) (:destructure (s i1 w1 r w2) @@ -44,19 +52,17 @@ (list r (list 'imm (if (and s (string= s "-")) (- i1) i1))))) (esrap:defrule immediate int - (:lambda (i) (list 'imm i))) + (:lambda (e) (list 'imm e))) ;;; defines rules to parse labels -(esrap:defrule label (+ (alphanumericp character)) - (:lambda (list) (list 'l (esrap:text list)))) +(esrap:defrule label alpha + (:lambda (e) (list 'l e))) (esrap:defrule label-decl (and label #\:) (:function car) - (:lambda (l) - (util:add-label l line-number) - ;; this line isn't in the final program - (decf line-number) + (:lambda (e) + (util:add-label e line-number) nil)) ;;; defines rules to parse instruction types @@ -79,6 +85,7 @@ (generate-mnemonic 'i-type-3-m (reverse util:i-type)) (generate-mnemonic 'j-type-3-m (reverse util:j-type)) +;; TODO this is pretty gross (defmacro defrule-instr (name type-id order &rest destructure-pattern) "Defines the boilerplate for a common esrap instruction rule. NAME is the name of the non-terminal symbol. @@ -100,12 +107,12 @@ DESTRUCTURE-PATTERN is the list of non-terminals on the right side of the gramma (defrule-instr i-type-3 'i (0 1 2) register register immediate) (defrule-instr j-type-3 'j (1 0) label) -(esrap:defrule i-type-1 (and i-type-1-m space register space dereference) +(esrap:defrule i-type-1 (and i-type-1-m space register space (or dereference alpha)) (:destructure (m w1 s w2 di) (declare (ignore w1 w2)) `(i ,m ,s ,@di))) -(esrap:defrule i-type-2 (and i-type-2-m space register space dereference) +(esrap:defrule i-type-2 (and i-type-2-m space register space (or dereference alpha)) (:destructure (m w1 s w2 di) (declare (ignore w1 w2)) `(i ,m ,@(util:insert-in-middle di s)))) @@ -121,17 +128,46 @@ DESTRUCTURE-PATTERN is the list of non-terminals on the right side of the gramma `(j ,m ,r (imm 0)))) (esrap:defrule instr (or r-type-1 r-type-2 r-type-3 i-type-1 i-type-2 - i-type-3 j-type-1 j-type-2 j-type-3 label-decl)) + i-type-3 j-type-1 j-type-2 j-type-3)) ;;; defines rules to parse the .text segment -(esrap:defrule instr-clean (and (esrap:? space) instr newline) +(esrap:defrule instr-clean (and (esrap:? space) instr (esrap:? space) nl-inc) (:function cadr)) -(esrap:defrule text (and ".TEXT" newline - (* instr-clean)) - (:function caddr) - (:lambda (instr) - `(text ,@(remove nil instr)))) +(esrap:defrule label-clean (and label-decl (esrap:? space) nl) + (:function car)) + +(esrap:defrule text-line (or instr-clean label-clean)) + +(esrap:defrule text (and ".TEXT" (esrap:? space) nl (* text-line)) + (:function cadddr) + (:lambda (e) + `(t ,@(remove nil e)))) ;;; defines rules to parse the .data segment + +(esrap:defrule data-word (and (esrap:? space) int) + (:function cadr) + (:lambda (e) + (incf var-offset) + e)) + +(esrap:defrule var-decl alpha + (:lambda (e) + (util:add-variable e var-offset) + nil)) + +(esrap:defrule data-line (and (esrap:? space) var-decl (+ data-word) (esrap:? space) nl) + (:function caddr)) + +(esrap:defrule data (and ".DATA" (esrap:? space) nl (* data-line)) + (:function cadddr) + (:lambda (e) + (list 'd (apply #'append e)))) + +;;; defines rules to parse a program + +(esrap:defrule str->ast (* (or data text)) + (:lambda (e) + (list 'p (apply #'append e)))) diff --git a/t/parse.lisp b/t/parse.lisp index b32263a..5b23343 100644 --- a/t/parse.lisp +++ b/t/parse.lisp @@ -9,54 +9,55 @@ (in-suite parse-tests) -(test esrap-register-decimal-ten - (is (equal (list 'parse::rr 10) - (esrap:parse 'parse::register "$10")))) - -(test esrap-register-binary-ten - (is (equal (list 'parse::rr 10) - (esrap:parse 'parse::register "$0B1010")))) - -(test esrap-register-octal-ten - (is (equal (list 'parse::rr 10) - (esrap:parse 'parse::register "$0O12")))) - -(test esrap-register-hex-ten - (is (equal (list 'parse::rr 10) - (esrap:parse 'parse::register "$0XA")))) - -(test esrap-r-type-1 - (is (equal '(parse::r "ADD" (parse::rr 5) (parse::rr 8) (parse::rr 1)) - (esrap:parse 'parse:instr "ADD $1 $5 $8")))) - -(test esrap-r-type-2 - (is (equal '(parse::r "NOT" (parse::rr 5) (parse::rr 0) (parse::rr 1)) - (esrap:parse 'parse:instr "NOT $1 $5")))) - -(test esrap-r-type-3 - (is (equal '(parse::r "CMP" (parse::rr 1) (parse::rr 5) (parse::rr 0)) - (esrap:parse 'parse:instr "CMP $1 $5")))) - -(test esrap-i-type-1 - (is (equal '(parse::i "LOAD" (parse::rr 8) (parse::rr 9) (parse::imm 1)) - (esrap:parse 'parse:instr "LOAD $8 1($9)")))) - -(test esrap-i-type-2 - (is (equal '(parse::i "STORE" (parse::rr 3) (parse::rr 5) (parse::imm 3)) - (esrap:parse 'parse:instr "STORE $5 3($3)")))) - -(test esrap-i-type-3 - (is (equal '(parse::i "ORI" (parse::rr 5) (parse::rr 4) (parse::imm 2)) - (esrap:parse 'parse:instr "ORI $5 $4 2")))) - -(test esrap-j-type-1 - (is (equal '(parse::j "JMP" (parse::rr 3) (parse::imm 3)) - (esrap:parse 'parse:instr "JMP 3($3)")))) - -(test esrap-j-type-2 - (is (equal '(parse::j "JRL" (parse::rr 0) (parse::l "FOO")) - (esrap:parse 'parse:instr "JRL FOO")))) - -(test esrap-j-type-3 - (is (equal '(parse::j "PUSH" (parse::rr 1) (parse::imm 0)) - (esrap:parse 'parse:instr "PUSH $1")))) +(test esrap-register-bases + (is (equal '(parse::p + (parse::t + (parse::r "ADD" (parse::rr 10) (parse::rr 10) (parse::rr 10)))) + (esrap:parse 'parse::str->ast (format nil ".TEXT~%~tADD $0O012 $0B1010 $0XA~%"))))) + +(test esrap-instr-all-type-r + (is (equal + '(parse::p + (parse::t + (parse::r "ADDV" (parse::rr 1) (parse::rr 2) (parse::rr 3)) + (parse::r "NOT" (parse::rr 4) (parse::rr 0) (parse::rr 5)) + (parse::r "CMP" (parse::rr 6) (parse::rr 7) (parse::rr 0)))) + (esrap:parse 'parse::str->ast (format nil ".TEXT~%~tADDV $3 $1 $2 +~tNOT $5 $4~%~tCMP $6 $7~%"))))) + +(test esrap-instr-all-type-i + (is (equal + '(parse::p + (parse::t + (parse::i "LOADV" (parse::rr 8) (parse::rr 9) (parse::imm 1)) + (parse::i "STORE" (parse::rr 3) (parse::rr 5) (parse::imm 3)) + (parse::i "ADDI" (parse::rr 5) (parse::rr 4) (parse::imm 2)))) + (esrap:parse 'parse::str->ast (format nil ".TEXT~%~tLOADV $8 1($9) +~tSTORE $5 3($3)~%~tADDI $5 $4 2~%"))))) + +(test esrap-instr-type-all-type-j + (is (equal + '(parse::p + (parse::t + (parse::j "JMP" (parse::rr 3) (parse::imm 3)) + (parse::j "JRL" (parse::rr 0) (parse::l "FOO")) + (parse::j "PUSH" (parse::rr 5) (parse::imm 0)))) + (esrap:parse 'parse::str->ast (format nil ".TEXT~%~tJMP 3($3) +~tJRL FOO~%~tPUSH $5~%"))))) + +(test esrap-instr-type-all-lazy-spaces + (is (equal + '(parse::p + (parse::t + (parse::j "JMP" (parse::rr 3) (parse::imm 3)) + (parse::j "JRL" (parse::rr 0) (parse::l "FOO")) + (parse::j "PUSH" (parse::rr 5) (parse::imm 0)))) + (esrap:parse 'parse::str->ast (format nil "~t~%.TEXT~t~%JMP 3($3)~t +JRL FOO~t~%PUSH $5~%"))))) + +(test esrap-data-singleton + (is (equal + '(parse::p + (parse::d + 1))) + (esrap:parse 'parse:str->ast (format nil ".DATA~%~tA 1~%")))) |