summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-04-10 01:23:38 -0400
committerbd <bdunahu@operationnull.com>2025-04-10 01:23:38 -0400
commit3eeebe73826906b1c598d5e5d207bfee936ed315 (patch)
tree9b750918dcc606a4a228503201f870249303cc7c
parente50d44464db7eb8e1c20755c862466ac8f7419b0 (diff)
Messy data section
-rw-r--r--README.md1
-rw-r--r--src/main.lisp2
-rw-r--r--src/package.lisp4
-rw-r--r--src/parse.lisp86
-rw-r--r--t/parse.lisp103
5 files changed, 117 insertions, 79 deletions
diff --git a/README.md b/README.md
index 4f2631d..d0f1a19 100644
--- a/README.md
+++ b/README.md
@@ -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~%"))))