从读表中移除Racket默认的读取程序,针对字符|。

4

我正在尝试编写一种Racket读取器扩展过程,以禁用管道字符|的特殊处理。

我有两个文件:mylang/lang/reader.rkt用于���现语言读取器和mylang/testing.rkt用于尝试它。 我运行了raco pkg install --link来安装该语言包。

以下是reader.rkt

#lang s-exp syntax/module-reader
racket
#:read my-read
#:read-syntax my-read-syntax

(define (parse-pipe char in srcloc src linum colnum)
  #'\|)

(define my-readtable
  (make-readtable #f #\| 'terminating-macro parse-pipe))

(define (my-read-syntax src in)
  (parameterize ((current-readtable my-readtable))
    (read-syntax src in)))

(define (my-read in)
  (syntax->datum
   (my-read-syntax #f in)))

使用如下代码的 testing.rkt 文件:

#lang mylang
(define | 3)
(+ 3 2)

这段代码的第一个运行结果是5,和预期一致。但下面这个运行结果并不是:

#lang mylang
(define |+ 3)
(+ |+ 2)

抱怨 (define \| + 3) 存在"bad syntax (multiple expressions after identifier)",这是合理的,因为parse-pipe生成的是语法对象而不是字符串,所以它会过早地终止符号的读取。

我可以做的一件事是一直读到符号结尾,但这最多也只是一个hack,因为我将重新实现符号解析,并且这并不能解决符号中间包含管道字符或者|在字符串中等情况。

我想要做的是从读取表中删除管道符的默认读取程序,但我不知道如何做或是否可以这样做。

1个回答

6

好的,我找到了一种方法。有关make-readtable的文档说明如下:

char like-char readtable —— 将char解析为与readtable中like-char相同的方式,其中readtable可以是#f表示默认readtable。

因此,我可以通过以下方式使读取器像处理a字符一样处理|字符:

(define my-readtable
  (make-readtable #f #\| #\a #f))

它可以正常工作。

(define hawdy|+ "hello")    
(string-append hawdy|+ "|world")
; => "hello|world"

我+1了你的答案,因为它是有效的,但我无法想象为什么你要这样做(除非你正在为自定义的非Scheme语言实现阅读器)。在Scheme中,使用|作为符号的一种方式是“引用”符号,以便它可以包含任意字符(例如,|foo bar|被读取为对应于(string->symbol"foo bar")的符号);通过重新定义|,您剥夺了读取具有任意字符的符号的能力。 - C. K. Young
这是为了一种自定义语言。我非常乐意接受 racket 的现状 ;)。 - spelufo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接