scribble-enhanced/scribble-lib/scribble/bnf.rkt
2014-12-02 00:54:52 -05:00

94 lines
3.2 KiB
Racket

(module bnf racket
(require "struct.rkt"
"decode.rkt"
(only-in "core.rkt"
make-style
make-table-columns)
mzlib/kw)
(provide BNF
nonterm
BNF-seq BNF-seq-lines
BNF-alt BNF-alt/close ; single-line alternatives
BNF-etc
BNF-group
optional kleenestar kleeneplus kleenerange)
(define spacer (make-element 'hspace (list " ")))
(define equals (make-element 'tt (list spacer "::=" spacer)))
(define alt (make-element 'tt (list spacer spacer "|" spacer spacer)))
(define (as-flow i) (make-flow (list (if (block? i)
i
(make-paragraph (list i))))))
(define baseline (make-style #f '(baseline)))
(define (BNF . defns)
(make-table
(make-style #f
(list
(make-table-columns
(list baseline baseline baseline baseline))))
(apply
append
(map (lambda (defn)
(cons
(list (as-flow spacer) (as-flow (car defn)) (as-flow equals) (as-flow (cadr defn)))
(map (lambda (i)
(list (as-flow spacer) (as-flow " ") (as-flow alt) (as-flow i)))
(cddr defn))))
defns))))
(define (interleave l spacer)
(make-element #f (cons (car l)
(apply append
(map (lambda (i)
(list spacer i))
(cdr l))))))
(define (BNF-seq . l)
(if (null? l)
""
(interleave l spacer)))
(define (BNF-seq-lines . l)
(make-table #f (map (lambda (row) (list (as-flow (apply BNF-seq row))))
l)))
(define (BNF-alt . l)
(interleave l alt))
(define (BNF-alt/close . l)
(interleave l (make-element 'roman " | ")))
(define BNF-etc (make-element 'roman "..."))
(define/kw (nonterm #:body s)
(make-element 'roman (append (list 'lang)
(list (make-element 'italic (decode-content s)))
(list 'rang))))
(define/kw (optional #:body s)
(make-element #f (append (list (make-element 'roman "["))
(decode-content s)
(list (make-element 'roman "]")))))
(define/kw (BNF-group #:body s)
(make-element #f (append (list (make-element 'roman "{"))
(list (apply BNF-seq (decode-content s)))
(list (make-element 'roman "}")))))
(define/kw (kleenestar #:body s)
(make-element #f (append (decode-content s) (list (make-element 'roman "*")))))
(define/kw (kleeneplus #:body s)
(make-element #f (append (decode-content s) (list (make-element 'superscript (list "+"))))))
(define/kw (kleenerange a b #:body s)
(make-element #f (append (decode-content s)
(list (make-element 'roman
(make-element 'superscript
(list (format "{~a,~a}" a b)))))))))