From 6e338215192c26dfb16236398ca8e3762a8d4d0e Mon Sep 17 00:00:00 2001 From: bd Date: Thu, 20 Mar 2025 13:51:28 -0400 Subject: Add logic to open file, lex single character symbols, tests --- src/main.lisp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src/main.lisp') diff --git a/src/main.lisp b/src/main.lisp index c85e392..1f0afdd 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -35,14 +35,19 @@ _/_/ _/_/ " (defun driver (cmd) "Reads in a file and directs lexing, parsing, and binary emission." (print-splash) - (let ((args (clingon:command-arguments cmd)) - (parse? (not (clingon:getopt cmd :lex))) - (emit? (not (clingon:getopt cmd :parse)))) + (let* ((args (clingon:command-arguments cmd)) + (file (car args)) + (parse? (not (clingon:getopt cmd :lex))) + (emit? (not (clingon:getopt cmd :parse)))) (cond ;; complain about num arguments ((/= (length args) 1) (error "Wrong number of arguments.")) - ((not (util:asm-extension? (car args))) (error "The file is not an asm source code file.")))) - (error-cli "Nitimur in Vetitum")) + ((not (util:asm-extension? file)) + (error "The file is not an asm source code file, or it could not be opened.")) + (t (let ((tokens (lex:file->tokens file))) + (format t "~a" tokens) + (format t "Nitimur in Vetitum~%")))))) + (defun cli/command () "Returns a clingon command." -- cgit v1.2.3 From 5f010ed3f98ffb82fe94c1a31f3338485dd3fbb7 Mon Sep 17 00:00:00 2001 From: bd Date: Thu, 20 Mar 2025 13:55:28 -0400 Subject: Edit logic in main to error if passed file could not be opened. --- src/main.lisp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/main.lisp') diff --git a/src/main.lisp b/src/main.lisp index 1f0afdd..98176ec 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -43,9 +43,11 @@ _/_/ _/_/ " ;; complain about num arguments ((/= (length args) 1) (error "Wrong number of arguments.")) ((not (util:asm-extension? file)) - (error "The file is not an asm source code file, or it could not be opened.")) + (error "The file is not an asm source code file.")) (t (let ((tokens (lex:file->tokens file))) - (format t "~a" tokens) + (if tokens + (format t "~a" tokens) + (error "The file does not exist, or it could not be opened.")) (format t "Nitimur in Vetitum~%")))))) -- cgit v1.2.3 From 4d8ffb6a29285f12d9ebd788727d633550510d7f Mon Sep 17 00:00:00 2001 From: bd Date: Thu, 3 Apr 2025 01:07:13 -0400 Subject: Add lexing for immediates, keywords, and associated tests --- src/lex.lisp | 57 +++++++++++++++++++++++++++++++++++++++++++++----------- src/main.lisp | 9 +++++---- src/package.lisp | 3 ++- t/lex.lisp | 46 ++++++++++++++++++++++++++++++++++++--------- 4 files changed, 90 insertions(+), 25 deletions(-) (limited to 'src/main.lisp') 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)) diff --git a/t/lex.lisp b/t/lex.lisp index e210ecb..40698f9 100644 --- a/t/lex.lisp +++ b/t/lex.lisp @@ -14,6 +14,11 @@ (read-this "" (is (not (lex:read-token))))) +(test read-token-reads-nl + (read-this " +" + (is (eq (lex:read-token) 'lex::nl)))) + (test read-token-reads-left-paren (read-this "(" (is (eq (lex:read-token) 'lex::left-paren)))) @@ -22,6 +27,10 @@ (read-this ")" (is (eq (lex:read-token) 'lex::right-paren)))) +(test read-token-reads-left-paren + (read-this "$" + (is (eq (lex:read-token) 'lex::dollar)))) + (test read-token-ignores-space (read-this " (" (is (eq (lex:read-token) 'lex::left-paren)))) @@ -30,16 +39,35 @@ (read-this " (" (is (eq (lex:read-token) 'lex::left-paren)))) -(test read-token-ignores-newline - (read-this " -(" - (is (eq (lex:read-token) 'lex::left-paren)))) - (test read-token-ignores-comment (read-this "; this is a comment (" - (is (eq (lex:read-token) 'lex::left-paren)))) + (is (eq (lex:read-token) 'lex::nl)))) -(test read-token-ignores-comment-eof - (read-this ";" - (is (not (lex:read-token))))) +(test read-token-immediate-zero + (read-this "0" + (is (= (lex:read-token) 0)))) + +(test read-token-immediate-all-digits + (read-this "123456789" + (is (= (lex:read-token) 123456789)))) + +(test read-token-immediate-invalid-immediate + (handler-case + (progn (read-this "0v0" (lex:read-token)) + (fail)) + (lex:invalid-immediate-or-keyword ()))) + +(test read-token-keyword-single + (read-this "a" + (is (string= (lex:read-token) "a")))) + +(test read-token-keyword-add + (read-this "addi" + (is (string= (lex:read-token) "addi")))) + +(test read-token-immediate-invalid-keyword + (handler-case + (progn (read-this "sub0" (lex:read-token)) + (fail)) + (lex:invalid-immediate-or-keyword ()))) -- cgit v1.2.3