summaryrefslogtreecommitdiff
path: root/src/parse.lisp
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.lisp')
-rw-r--r--src/parse.lisp89
1 files changed, 54 insertions, 35 deletions
diff --git a/src/parse.lisp b/src/parse.lisp
index a92eae7..f9ede20 100644
--- a/src/parse.lisp
+++ b/src/parse.lisp
@@ -1,14 +1,22 @@
(in-package #:parse)
+(defparameter line-number 0)
+
(esrap:defrule space
(+ (or #\space #\tab))
(:constant nil))
(esrap:defrule newline
- (+ #\newline))
+ (+ #\newline)
+ (:destructure (n)
+ (declare (ignore n))
+ (incf line-number)
+ nil))
;;; 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)))
@@ -19,7 +27,7 @@
(:lambda (list) (parse-integer (esrap:text list) :radix 10)))
(esrap:defrule hex (and #\0 #\X (+ (or (esrap:character-ranges (#\0 #\9))
- "A" "B" "C" "D" "E" "F")))
+ "A" "B" "C" "D" "E" "F")))
(:lambda (list) (parse-integer (esrap:text (cddr list)) :radix 16)))
(esrap:defrule int (or binary octal hex decimal))
@@ -27,7 +35,8 @@
;;; defines rules to parse an operand
(esrap:defrule register (and #\$ (or int reg-id))
- (:lambda (list) (list 'rr (cadr list))))
+ (:function cadr)
+ (:lambda (id) (list 'rr id)))
(esrap:defrule dereference (and (esrap:? (or #\+ #\-)) int #\( register #\))
(:destructure (s i1 w1 r w2)
@@ -43,22 +52,32 @@
(:lambda (list) (list 'l (esrap:text list))))
(esrap:defrule label-decl (and label #\:)
- (:destructure (l w)
- (declare (ignore w))
- l))
+ (:function car)
+ (:lambda (l)
+ (util:add-label l line-number)
+ ;; this line isn't in the final program
+ (decf line-number)
+ nil))
;;; defines rules to parse instruction types
-(esrap:defrule r-type-1-m (or "ADDV" "SUBV" "MULV" "DIVV" "ADD" "SUB" "MUL"
- "QUOT" "REM" "SFTR" "SFTL" "AND" "OR" "NOT" "XOR" ))
-(esrap:defrule r-type-2-m "NOT")
-(esrap:defrule r-type-3-m (or "CMP" "CEV"))
-(esrap:defrule i-type-1-m (or "LOADV" "LOAD"))
-(esrap:defrule i-type-2-m (or "STOREV" "STORE"))
-(esrap:defrule i-type-3-m (or "ADDI" "SUBI" "SFTRI" "SFTLI" "ANDI" "ORI" "XORI"))
-(esrap:defrule j-type-1-m (or "JMP" "JAL"))
-(esrap:defrule j-type-2-m (or "JRL" "BEQ" "BGT" "BUF" "BOF"))
-(esrap:defrule j-type-3-m (or "PUSH" "POP"))
+(defun generate-mnemonic (name ops)
+ (let ((expr `(or ,@ops)))
+ (esrap:add-rule
+ name (make-instance 'esrap:rule :expression expr))))
+
+;; define special cases first
+(generate-mnemonic 'r-type-1-m '("NOT"))
+(generate-mnemonic 'r-type-2-m '("CMP" "CEV"))
+(generate-mnemonic 'i-type-1-m '("LOADV" "LOAD"))
+(generate-mnemonic 'i-type-2-m '("STOREV" "STORE"))
+(generate-mnemonic 'j-type-1-m '("JMP" "JAL"))
+(generate-mnemonic 'j-type-2-m '("PUSH" "POP"))
+
+;; we need to reverse to ensure rules like "ADDV" are matched before "ADD"
+(generate-mnemonic 'r-type-3-m (reverse util:r-type))
+(generate-mnemonic 'i-type-3-m (reverse util:i-type))
+(generate-mnemonic 'j-type-3-m (reverse util:j-type))
(defmacro defrule-instr (name type-id order &rest destructure-pattern)
"Defines the boilerplate for a common esrap instruction rule.
@@ -67,17 +86,19 @@ TYPE-ID is the symbol which appears as the first element of a successful parse.
ORDER is the order to place the parsed tokens in the resulting list.
DESTRUCTURE-PATTERN is the list of non-terminals on the right side of the grammar rule."
(let* ((pattern-size (length destructure-pattern))
- (spaces (mapcar (lambda (x) (read-from-string (format nil "w~A" x))) (util:iota pattern-size)))
- (vars (mapcar (lambda (x) (read-from-string (format nil "s~A" x))) (util:iota pattern-size))))
+ (spaces (mapcar (lambda (x) (read-from-string (format nil "w~A" x))) (util:iota pattern-size)))
+ (vars (mapcar (lambda (x) (read-from-string (format nil "s~A" x))) (util:iota pattern-size))))
`(esrap:defrule ,name
- (and ,(read-from-string (format nil "~A-m" name)) ,@(util:riffle (make-list pattern-size :initial-element 'space) destructure-pattern))
+ (and ,(read-from-string (format nil "~A-m" name)) ,@(util:riffle (make-list pattern-size :initial-element 'space) destructure-pattern))
(:destructure (m ,@(util:riffle spaces vars))
- (declare (ignore ,@spaces))
- (list ,type-id m ,@(mapcar (lambda (x) (or (nth x vars) ''(rr 0))) order))))))
+ (declare (ignore ,@spaces))
+ (list ,type-id m ,@(mapcar (lambda (x) (or (nth x vars) ''(rr 0))) order))))))
-(defrule-instr r-type-1 'r (1 2 0) register register register)
-(defrule-instr r-type-2 'r (1 2 0) register register)
-(defrule-instr r-type-3 'r (0 1 2) register register)
+(defrule-instr r-type-1 'r (1 2 0) register register)
+(defrule-instr r-type-2 'r (0 1 2) register register)
+(defrule-instr r-type-3 'r (1 2 0) register register register)
+(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)
(:destructure (m w1 s w2 di)
@@ -89,30 +110,28 @@ DESTRUCTURE-PATTERN is the list of non-terminals on the right side of the gramma
(declare (ignore w1 w2))
`(i ,m ,@(util:insert-in-middle di s))))
-(defrule-instr i-type-3 'i (0 1 2) register register immediate)
(esrap:defrule j-type-1 (and j-type-1-m space dereference)
(:destructure (m w di)
(declare (ignore w))
`(j ,m ,@di)))
-(defrule-instr j-type-2 'j (1 0) label)
-(esrap:defrule j-type-3 (and j-type-3-m space register)
+(esrap:defrule j-type-2 (and j-type-2-m space register)
(:destructure (m w r)
(declare (ignore w))
`(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 label-decl))
;;; defines rules to parse the .text segment
(esrap:defrule instr-clean (and (esrap:? space) instr newline)
- (:destructure (w1 i w2)
- (declare (ignore nl l))
- i))
+ (:function cadr))
(esrap:defrule text (and ".TEXT" newline
- (* instr-clean))
- (:destructure (txt nl is)
- (declare (ignore txt nl))
- (list 'text is)))
+ (* instr-clean))
+ (:function caddr)
+ (:lambda (instr)
+ `(text ,@(remove nil instr))))
+
+;;; defines rules to parse the .data segment