diff options
Diffstat (limited to 'src/lex.lisp')
-rw-r--r-- | src/lex.lisp | 57 |
1 files changed, 46 insertions, 11 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) |