方案/球拍:如何添加关键字以定义语法分析器

问题描述 投票:0回答:2

我可以这样定义for循环的语法:

(require syntax/parse/define)
(define-syntax-parser myfor
  [(_ Binding Form1 ...)
   #'(for (Binding) Form1 ...)]
)

(myfor (I (range 0 10))
  (displayln I)
)

它有效,但是当我向其中添加关键字时,它不符合#:break关键字中的条件:

(require syntax/parse/define)
(define-syntax-parser myfor
  [(_ Binding #:break Break Form1 ...)
   #'(for (Binding) Form1 ...)]
)

(myfor (I (range 0 10))
  #:break (= I 5)
  (displayln I)
)

如何以正确的方式向define-syntax-parser添加关键字?

parsing syntax scheme racket keyword
2个回答
1
投票

有两个部分:

  1. 在输入中接受#:break作为可选关键字
  2. 必要时在输出中产生#:break

有三种方法:多分支,可选和语法类。

多分支

最简单的解决方法是在语法分析器中具有两个分支。一个分支带有关键字,另一个分支没有关键字。

两个分支意味着两个模式要在输入上匹配,两个模板要产生输出。

(define-syntax-parser myfor
  [(_ Binding #:break Break Form1 ...)
   #'(for (Binding #:break Break) Form1 ...)]
  [(_ Binding Form1 ...)
   #'(for (Binding) Form1 ...)])

这非常简单明了,但缺点是您要重复自己,为每个分支多次指定forBindingForm1 ...,如果添加更多关键字,它将变得更加冗长。] >

可选和~?

另一种方法是在模式中使用~optional~seq来匹配输入,而在模板中使用~?~@来产生输出。

(define-syntax-parser myfor
  [(_ Binding {~optional {~seq #:break Break}} Form1 ...)
   #'(for (Binding {~? {~@ #:break Break}}) Form1 ...)])

注意模板中的~?在图案中是~optional的位置,而模板中的~@在图案中是~seq的位置。

当输入模式和输出模板之间存在明显的对称性时,此策略是最佳选择。

语法类
(begin-for-syntax
  (define-splicing-syntax-class maybe-break-clause
    [pattern {~seq} #:with (out ...) '()]
    [pattern {~seq #:break Break} #:with (out ...) #'(#:break Break)]))

(define-syntax-parser myfor
  [(_ Binding mbc:maybe-break-clause Form1 ...)
   #'(for (Binding mbc.out ...) Form1 ...)])

在这种情况下,对于#:break,此策略是过大的,但是如果关键字的行为比简单地传递关键字(如果存在)更为复杂,则可能有必要。


0
投票

我发现了,我需要在语法中添加〜optional和〜seq:

© www.soinside.com 2019 - 2024. All rights reserved.