aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Peter McGoron 2024-09-07 21:10:40 -0400
committerGravatar Peter McGoron 2024-09-07 21:10:40 -0400
commit6945841d1ce5edf53d823d6b5a9ddb5cbb531e61 (patch)
treee1d5afebea2c1252d8f583f77cd71271696afcde
parentreadtable: when adding sequences to the readtable, push the last (diff)
readtable: case folding
-rw-r--r--README.rst11
-rw-r--r--read.scm88
2 files changed, 62 insertions, 37 deletions
diff --git a/README.rst b/README.rst
index ebc68a0..7fa167d 100644
--- a/README.rst
+++ b/README.rst
@@ -19,12 +19,12 @@ designed to be used by a severely limited Scheme interpreter, which
* has fixnums only
* only uses immutable strings
* does not use "load" recursively
-* uses R3RS essental procedures only (with some exceptions)
+* uses R3RS essential procedures only (with some exceptions)
The goal is to have the compiler run under the MiniScheme in ``miniscm``
in DOS, and then run in GLLV to compile itself.
-A proper implementation must have
+A proper implementation must have, in addition to R3RS,
* ``open-input-port``, ``read-char``
* ``open-output-port``, ``write-char``
@@ -32,7 +32,6 @@ A proper implementation must have
* ``and``, ``or``
* ``error``
-If your system supports any macro system at all, ``cond-expand``,
-``and``, and ``or`` can be implemented. ``error`` can be implemented
-as in SRFI-23 : https://srfi.schemers.org/srfi-23/srfi-23.html .
-
+Hopefully your implementation has input and output ports (there's no other
+way to write a compiler). Everything else can be expressed in terms of
+macros or R3RS essential procedures.
diff --git a/read.scm b/read.scm
index 224a910..edea2b5 100644
--- a/read.scm
+++ b/read.scm
@@ -26,6 +26,7 @@
;;; ;;;;;;;;;;;;;;;;;;;;;;;;
;;; Port reader wrapper
+
;;; ;;;;;;;;;;;;;;;;;;;;;;;;
(define port->read-function
@@ -39,38 +40,50 @@
;;; (READ): Read the next character in the stream. Returns #F on EOF.
;;; (PUSH CHAR): Push CHAR such that it will be the next character read
;;; when (READ) is called.
+;;; (FOLD-CASE?): Returns a boolean if case folding is enabled.
+;;; (FOLD-CASE! BOOL): Sets the case folding to BOOL.
(define port->read
(lambda (read-function filename)
(let ((line-number 1)
(offset 0)
- (pushback-buffer '()))
- (let ((update-position
- (lambda (ch)
- (cond
- ((or (eof-object? ch) (not ch)) (set! ch #f))
- ((eqv? ch #\newline)
- (set! line-number (+ 1 line-number)) (set! offset 0))
- (offset (set! offset (+ 1 offset))))
- ch)))
- (lambda (op . args)
- (cond
- ((eq? op 'pos) (list filename line-number offset))
- ((eq? op 'read)
- (update-position
- (if (null? pushback-buffer)
- (read-function)
- (let ((ch (car pushback-buffer)))
- (set! pushback-buffer (cdr pushback-buffer))
- ch))))
- ((eq? op 'push)
- (let ((ch (car args)))
- (if (eqv? ch #\newline)
- (begin
- (set! line-number (- line-number 1))
- (set! offset #f))
- (set! offset (- offset 1)))
- (set! pushback-buffer (cons ch pushback-buffer))))
- (else (error "read->port: invalid" (cons op args)))))))))
+ (pushback-buffer '())
+ (fold-case? #f))
+ (letrec ((update-position!
+ (lambda (ch)
+ (cond
+ ((eqv? ch #\newline)
+ (set! line-number (+ 1 line-number)) (set! offset 0))
+ (offset (set! offset (+ 1 offset))))))
+ (process
+ (lambda (ch)
+ (update-position! ch)
+ (cond
+ ((or (eof-object? ch) (not ch)) ch)
+ (fold-case? (char-downcase ch))
+ (else ch))))
+ (port
+ (lambda (op . args)
+ (cond
+ ((eq? op 'pos) (list filename line-number offset))
+ ((eq? op 'read)
+ (process
+ (if (null? pushback-buffer)
+ (read-function)
+ (let ((ch (car pushback-buffer)))
+ (set! pushback-buffer (cdr pushback-buffer))
+ ch))))
+ ((eq? op 'push)
+ (let ((ch (car args)))
+ (if (eqv? ch #\newline)
+ (begin
+ (set! line-number (- line-number 1))
+ (set! offset #f))
+ (set! offset (- offset 1)))
+ (set! pushback-buffer (cons ch pushback-buffer))))
+ ((eq? op 'fold-case?) fold-case?)
+ ((eq? op 'fold-case!) (set! fold-case? (car args)))
+ (else (error "read->port: invalid" (cons op args)))))))
+ port))))
;;; ;;;;;;;;;;;;;;
;;; Character maps
@@ -315,10 +328,19 @@
(define readtable:top
(readtable:update-many-sequence
readtable:empty
+ (cons "#!fold-case"
+ (readtable:exec:new
+ (lambda (table char acc port)
+ (port 'fold-case! #t)
+ '())))
+ (cons "#!no-fold-case"
+ (readtable:exec:new
+ (lambda (table char acc port)
+ (port 'fold-case! #f)
+ '())))
(cons "#t" (readtable:return-value #t))
(cons "#f" (readtable:return-value #f))
- (cons "#true" (readtable:return-value #t))
- (cons "#trouble" (readtable:return-value 15))))
+ (cons "#true" (readtable:return-value #t))))
;;; ;;;;;;;;;;;
;;; Test reader
@@ -334,8 +356,12 @@
ch)))
"test")))
-(let ((true-reader (%list->read (string->list "#t#false#true"))))
+(let ((true-reader (%list->read (string->list "#!fold-case#TRUE#!no-fold-case#TRUE"))))
(display (list "first:" (readtable:top (true-reader 'read) #f true-reader)))
(newline)
(display (list "second: " (readtable:top (true-reader 'read) #f true-reader)))
+ (newline)
+ (display (list "third: " (readtable:top (true-reader 'read) #f true-reader)))
+ (newline)
+ (display (list "fourth: " (readtable:top (true-reader 'read) #f true-reader)))
(newline))