basic error reporting to character and string literals

This commit is contained in:
2024-08-24 00:43:43 +03:00
parent 3fc13bcddd
commit 0f953a0a2f
2 changed files with 94 additions and 30 deletions

View File

@@ -14,12 +14,20 @@
(car token)) (car token))
;;; LEXER ;;; LEXER
(defun read-string (stream) (defun read-string (stream line-num line col)
;; TODO: Handle unmatched " and give proper error message "This function is called when a #\" (double quote) is read from the STREAM."
(let ((i 0))
(values
(with-output-to-string (str) (with-output-to-string (str)
(iter (for ch = (read-char stream)) (iter (for ch = (read-char stream nil 'eof))
(cond ((char= ch #\") (cond ((eq 'eof ch)
(finish)) (error (cond-string-not-closed
line-num line col
(get-output-stream-string str))))
((char= ch #\")
(if (> i 0)
(finish)
(error (cond-empty-string line-num line col))))
((char= ch #\\) ((char= ch #\\)
(case (peek-char nil stream) (case (peek-char nil stream)
(#\n (write-char #\Newline str)) (#\n (write-char #\Newline str))
@@ -27,19 +35,30 @@
(#\\ (write-char #\\ str)) (#\\ (write-char #\\ str))
(#\" (write-char #\" str))) (#\" (write-char #\" str)))
(read-char stream)) (read-char stream))
(t (write-char ch str)))))) (t (write-char ch str)))
(incf i)))
i)))
(defun read-character (stream line-num line col) (defun read-character (stream line-num line col)
(let ((ch? (read-char stream))) "This function is called when a #\' (single quote) is read from the STREAM."
(if (not (char-equal ch? #\\)) (let ((ch? (read-char stream nil 'eof)))
(if (char-equal #\' (peek-char nil stream)) (cond ((eq 'eof ch?)
(progn (read-char stream) ch?) (error (cond-char-not-closed line-num line col 'yok)))
(error (handle-char-not-closed line-num line col))) ((char-equal ch? #\\)
(progn (case (read-char stream) (let ((escaped-ch (read-char stream nil 'eof)))
(#\n (setf ch? #\Newline))) (case escaped-ch
(if (char-equal #\' (peek-char nil stream)) (eof (error (cond-char-not-closed line-num line col 'yok)))
(progn (read-char stream) ch?) (#\n (setf ch? #\Newline))
(error (handle-char-not-closed line-num line col))))))) (#\0 (setf ch? (code-char 0)))
(otherwise (setf ch? escaped-ch)))))
((char-equal ch? #\')
(error (cond-empty-char line-num line col)))
(t nil))
(let ((closing-ch (read-char stream nil 'eof)))
(if (or (eq 'eof closing-ch)
(not (char-equal #\' closing-ch)))
(error (cond-char-not-closed line-num line col ch?))
ch?))))
(defun lex-line (line &optional (line-num 0)) (defun lex-line (line &optional (line-num 0))
(let ((*package* (find-package "KEYWORD"))) (let ((*package* (find-package "KEYWORD")))
@@ -61,7 +80,8 @@
(finish)) (finish))
((char= #\" next-char) ((char= #\" next-char)
(read-char line-stream) (read-char line-stream)
(collect (make-token (read-string line-stream) (collect (make-token (read-string
line-stream line-num line col)
line-num col :string) line-num col :string)
into tokens)) into tokens))
((char= #\' next-char) ((char= #\' next-char)

View File

@@ -8,16 +8,60 @@
(write-char #\Space stream)) (write-char #\Space stream))
(format stream "^~%")) (format stream "^~%"))
(define-condition char-not-closed () (defun char-num-pair (ch?)
(if (characterp ch?)
(list ch? (char-code ch?))
ch?))
(define-condition char-error ()
((line :initarg :line :reader line) ((line :initarg :line :reader line)
(col :initarg :col :reader col) (col :initarg :col :reader col)
(line-num :initarg :line-num :reader line-num)) (line-num :initarg :line-num :reader line-num)
(ch :initarg :ch :reader ch :initform 'yok)))
(define-condition char-not-closed (char-error) ()
(:report (lambda (condition stream) (:report (lambda (condition stream)
(format stream "Karakterin kapanış sembolü ' eksik.~%") (format stream "Karakterin kapanış sembolü ' (tek tırnak) eksik.~%Okunan karakter: ~s~%" (char-num-pair (ch condition)))
(report-line (line-num condition) (line condition) (col condition) stream)))) (report-line (line-num condition) (line condition) (col condition) stream))))
(defun handle-char-not-closed (line-num line token-or-col) (define-condition empty-char (char-error) ()
(make-condition 'char-not-closed :line-num line-num :line line :col token-or-col)) (:report (lambda (condition stream)
(format stream "Boş karakter oluşturulamaz.~%")
(report-line (line-num condition) (line condition) (col condition) stream))))
(defun cond-char-not-closed (line-num line token-or-col ch)
(make-condition 'char-not-closed :line-num line-num :line line :col token-or-col :ch ch))
(defun cond-empty-char (line-num line token-or-col)
(make-condition 'empty-char :line-num line-num :line line :col token-or-col))
(define-condition string-error ()
((line :initarg :line :reader line)
(col :initarg :col :reader col)
(line-num :initarg :line-num :reader line-num)
(content :initarg :content :reader content :initform 'yok)))
(define-condition string-not-closed (string-error) ()
(:report (lambda (condition stream)
(format stream "Metnin kapanış sembolü \" (çift tırnak) eksik.~%Okunan metin: ~s~%"
(list (content condition) (length (content condition))))
(report-line (line-num condition) (line condition) (col condition) stream))))
(defun cond-string-not-closed (line-num line token-or-col &optional (content 'yok))
(make-condition 'string-not-closed :line-num line-num :line line
:col token-or-col :content content))
(define-condition empty-string (string-error) ()
(:report (lambda (condition stream)
(format stream "Boş metin oluşturulamaz.~%")
(report-line (line-num condition) (line condition) (col condition) stream))))
(defun cond-empty-string (line-num line token-or-col)
(make-condition 'empty-string :line-num line-num :line line :col token-or-col))
;; (define-condition op-not-implemented (style-warning) ;; (define-condition op-not-implemented (style-warning)
;; ((undef-ops :initarg :ops :reader undef-ops)) ;; ((undef-ops :initarg :ops :reader undef-ops))