summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-04-03 01:07:13 -0400
committerbd <bdunahu@operationnull.com>2025-04-03 01:07:13 -0400
commit4d8ffb6a29285f12d9ebd788727d633550510d7f (patch)
treece6e4a79d7c9e4fb093517ebdceb2fecd64a6a9d /src
parentca8d176ac7745986c4e3a92ed7cea277e344262d (diff)
Add lexing for immediates, keywords, and associated tests
Diffstat (limited to 'src')
-rw-r--r--src/lex.lisp57
-rw-r--r--src/main.lisp9
-rw-r--r--src/package.lisp3
3 files changed, 53 insertions, 16 deletions
diff --git a/src/lex.lisp b/src/lex.lisp
index ad386ba..c6e9cf7 100644
--- a/src/lex.lisp
+++ b/src/lex.lisp
@@ -1,19 +1,34 @@
(in-package #:lex)
+(define-condition invalid-immediate-or-keyword (error)
+ ((chr :initarg :chr
+ :initform nil
+ :reader chr)
+ (instance :initarg :instance
+ :initform nil
+ :reader instance))
+ (:report (lambda (condition stream)
+ (format stream
+ "Lex failed--encountered ~a while reading ~a."
+ (chr condition) (instance condition))))
+ (:documentation "Dedicated error for immediates/keywords which contain
+invalid characters."))
+
(defun file->tokens (file)
"Opens FILE and parses returns a list of tokens, or
NIL if the file could not be opened."
- (defun read-tokens (tokens-so-far)
- "Collects tokens in FILE into TOKENS-SO-FAR."
+ (defun read-instr (lst tokens-so-far)
+ "Collects tokens in FILE into TOKENS-SO-FAR, splitting on a newline."
(let ((token (read-token)))
- (if token
- (read-tokens (cons token tokens-so-far))
- (reverse tokens-so-far))))
+ (cond ((null token) (reverse tokens-so-far))
+ ((eq token 'nl)
+ (cons (reverse tokens-so-far) (read-instr nil nil)))
+ (t (read-instr lst (cons token tokens-so-far))))))
(and (probe-file file)
(with-open-file (*standard-input* file :direction :input)
- (read-tokens '()))))
+ (remove nil (read-instr '() '())))))
(defun read-token ()
"Reads *STANDARD-INPUT* and returns a token, or nil if the end
@@ -23,29 +38,49 @@ Comments start with a semi-colon ';' and all tokens after are ignored."
(let ((chr (read-char *standard-input* nil)))
(cond
((null chr) chr)
+
+ ((char= chr #\linefeed) 'nl)
+
((whitespace-char-p chr)
(read-token))
((char= chr #\;)
(progn (read-line *standard-input* nil)
- (read-token)))
+ 'nl))
((char= chr #\() 'left-paren)
((char= chr #\)) 'right-paren)
+ ((char= chr #\:) 'colon)
+ ((char= chr #\$) 'dollar)
+
((digit-char-p chr)
(read-immediate chr))
((alpha-char-p chr)
- (read-identifier chr))
+ (read-keyword chr))
(t (error (format nil "~a is not a valid lexical symbol.~%" chr))))))
(defun read-immediate (chr)
- 'immediate)
+ (defun read-immediate-helper (chrs-so-far)
+ (let ((chr (peek-char nil *standard-input* nil)))
+ (cond ((and (not (null chr)) (digit-char-p chr))
+ (read-immediate-helper (cons (read-char *standard-input* nil) chrs-so-far)))
+ ((and (not (null chr)) (alpha-char-p chr))
+ (error 'invalid-immediate-or-keyword :chr chr :instance "immediate"))
+ (t (reverse chrs-so-far)))))
+ (parse-integer (coerce (read-immediate-helper (list chr)) 'string)))
-(defun read-identifier (chr)
- 'id)
+(defun read-keyword (chr)
+ (defun read-keyword-helper (chrs-so-far)
+ (let ((chr (peek-char nil *standard-input* nil)))
+ (cond ((and (not (null chr)) (alpha-char-p chr))
+ (read-keyword-helper (cons (read-char *standard-input* nil) chrs-so-far)))
+ ((and (not (null chr)) (digit-char-p chr))
+ (error 'invalid-immediate-or-keyword :chr chr :instance "keyword"))
+ (t (reverse chrs-so-far)))))
+ (coerce (read-keyword-helper (list chr)) 'string))
(defun whitespace-char-p (x)
(or (char= #\space x)
diff --git a/src/main.lisp b/src/main.lisp
index 98176ec..f6e5754 100644
--- a/src/main.lisp
+++ b/src/main.lisp
@@ -41,13 +41,14 @@ _/_/ _/_/ "
(emit? (not (clingon:getopt cmd :parse))))
(cond
;; complain about num arguments
- ((/= (length args) 1) (error "Wrong number of arguments."))
+ ((/= (length args) 1) (error "Wrong number of arguments.~%"))
((not (util:asm-extension? file))
- (error "The file is not an asm source code file."))
+ (error "The file is not an asm source code file.~%"))
(t (let ((tokens (lex:file->tokens file)))
(if tokens
- (format t "~a" tokens)
- (error "The file does not exist, or it could not be opened."))
+ (progn (pprint tokens)
+ (terpri))
+ (error "The file does not exist, or it could not be opened.~%"))
(format t "Nitimur in Vetitum~%"))))))
diff --git a/src/package.lisp b/src/package.lisp
index 44399cb..670ed02 100644
--- a/src/package.lisp
+++ b/src/package.lisp
@@ -10,4 +10,5 @@
(:use #:cl)
(:export #:file->tokens
;; exported for testing only
- #:read-token))
+ #:read-token
+ #:invalid-immediate-or-keyword))