diff --git a/scribble-doc/scribblings/scribble/bnf.scrbl b/scribble-doc/scribblings/scribble/bnf.scrbl index f1d51414..ce5de10f 100644 --- a/scribble-doc/scribblings/scribble/bnf.scrbl +++ b/scribble-doc/scribblings/scribble/bnf.scrbl @@ -1,6 +1,7 @@ #lang scribble/doc @(require scribble/manual "utils.rkt" scribble/bnf - (for-label scribble/bnf)) + ;; "utils.rkt" provides scribble/bnf for-label + ) @title[#:tag "bnf"]{BNF Grammars} @@ -43,44 +44,48 @@ produces the output See also @racket[racketgrammar]. -@defproc[(BNF [prod (cons element? (listof (or/c block? element?)))] ...) table?]{ +@defproc[(BNF [prod (cons/c (or/c block? content?) + (non-empty-listof (or/c block? content?)))] + ...) + table?]{ Typesets a grammar table. Each production starts with an element (typically constructed with @racket[nonterm]) for the non-terminal being defined, and then a list of possibilities (typically constructed with @racket[BNF-seq], etc.) to show on separate lines.} -@defproc[(nonterm (pre-content any/c) ...) element?]{ +@defproc[(nonterm [pre-content pre-content?] ...) element?]{ Typesets a non-terminal: italic in angle brackets.} -@defproc[(BNF-seq [elem element?] ...) element?]{ +@defproc[(BNF-seq [elem content?] ...) (or/c element? "")]{ Typesets a sequence.} -@defproc[(BNF-seq-lines [elems (listof element?)] ...) block?]{ +@defproc[(BNF-seq-lines [elems (listof content?)] ...) block?]{ Typesets a sequence that is broken into multiple lines, where each @racket[elems] is one line.} -@defproc[(BNF-group [pre-content any/c] ...) element?]{ +@defproc[(BNF-group [pre-content pre-content?] ...) element?]{ Typesets a group surrounded by curly braces (so the entire group can be repeated, for example).} -@defproc[(optional [pre-content any/c] ...) element?]{ +@defproc[(optional [pre-content pre-content?] ...) element?]{ Typesets an optional element: in square brackets.} -@defproc[(kleenestar [pre-content any/c] ...) element?]{ +@defproc[(kleenestar [pre-content pre-content?] ...) element?]{ Typesets a 0-or-more repetition.} -@defproc[(kleeneplus [pre-content any/c] ...) element?]{ +@defproc[(kleeneplus [pre-content pre-content?] ...) element?]{ Typesets a 1-or-more repetition.} -@defproc[(kleenerange [n any/c] [m any/c] [pre-content any/c] ...) element?]{ +@defproc[(kleenerange [n any/c] [m any/c] [pre-content pre-content?] ...) + element?]{ Typesets a @racket[n]-to-@racket[m] repetition. The @racket[n] and @racket[m] arguments are converted to a string using @racket[(format @@ -92,6 +97,14 @@ Typesets alternatives for a production's right-hand side to appear on a single line. The result is normally used as a single possibility in a production list for @racket[BNF].} -@defthing[BNF-etc string?]{ +@; BNF-alt/close is exported but undocumented. +@; It looks like it produces a more densely packed version of +@; BNF-alt, but I haven't confirmed this. + +@defthing[BNF-etc element?]{ + +An element to use for omitted productions or content. +Renders as: @BNF-etc +} + -A string to use for omitted productions or content.} diff --git a/scribble-lib/scribble/bnf.rkt b/scribble-lib/scribble/bnf.rkt index 91af03e6..a974716d 100644 --- a/scribble-lib/scribble/bnf.rkt +++ b/scribble-lib/scribble/bnf.rkt @@ -1,19 +1,45 @@ (module bnf racket - (require "struct.rkt" - "decode.rkt" - (only-in "core.rkt" + (require scribble/decode + (except-in scribble/struct + element?) + (only-in scribble/core + content? + element? 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) + ) + (provide (contract-out + [BNF (-> (cons/c (or/c block? content?) + (non-empty-listof (or/c block? content?))) + ... + table?)] + [BNF-etc element?] + ;; operate on content + [BNF-seq (-> content? ... + (or/c element? ""))] + [BNF-seq-lines (-> (listof content?) ... + block?)] + [BNF-alt (-> content? ... + element?)] + [BNF-alt/close (-> content? ... + element?)] + ;; operate on pre-content + [BNF-group (-> pre-content? ... + element?)] + [nonterm (-> pre-content? ... + element?)] + [optional (-> pre-content? ... + element?)] + [kleenestar (-> pre-content? ... + element?)] + [kleeneplus (-> pre-content? ... + element?)] + [kleenerange (-> any/c any/c pre-content? ... + element?)] + )) + + (define spacer (make-element 'hspace (list " "))) (define equals (make-element 'tt (list spacer "::=" spacer))) (define alt (make-element 'tt (list spacer spacer "|" spacer spacer))) @@ -33,14 +59,16 @@ (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)))) + (map (match-lambda + [(cons lhs (cons rhs0 more-rhs)) + (cons + (list (as-flow spacer) (as-flow lhs) (as-flow equals) (as-flow rhs0)) + (map (lambda (i) + (list (as-flow spacer) (as-flow " ") (as-flow alt) (as-flow i))) + more-rhs))]) defns)))) + ;; interleave : (listof content?) element? -> element? (define (interleave l spacer) (make-element #f (cons (car l) (apply append @@ -65,28 +93,28 @@ (define BNF-etc (make-element 'roman "...")) - (define/kw (nonterm #:body s) + (define (nonterm . s) (make-element 'roman (append (list 'lang) (list (make-element 'italic (decode-content s))) (list 'rang)))) - (define/kw (optional #:body s) + (define (optional . s) (make-element #f (append (list (make-element 'roman "[")) (decode-content s) (list (make-element 'roman "]"))))) - (define/kw (BNF-group #:body s) + (define (BNF-group . 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) + (define (kleenestar . s) (make-element #f (append (decode-content s) (list (make-element 'roman "*"))))) - (define/kw (kleeneplus #:body s) + (define (kleeneplus . s) (make-element #f (append (decode-content s) (list (make-element 'superscript (list "+")))))) - (define/kw (kleenerange a b #:body s) + (define (kleenerange a b . s) (make-element #f (append (decode-content s) (list (make-element 'roman (make-element 'superscript