rename `br/ragg` as `brag`

dev-elider
Matthew Butterick 8 years ago
parent 09ac200d0d
commit b55d290fe9

@ -36,7 +36,7 @@ script:
# don't rely on package server # don't rely on package server
- travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket-lib - travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket-lib
- raco test -p beautiful-racket-lib - raco test -p beautiful-racket-lib
- travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket-ragg - travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=brag
- raco test -p beautiful-racket-ragg - raco test -p brag
- travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket - travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket
- raco test -p beautiful-racket - raco test -p beautiful-racket

@ -4,12 +4,15 @@ beautiful-racket [![Build Status](https://travis-ci.org/mbutterick/beautiful-rac
Resources for the upcoming “Beautiful Racket” book, including: Resources for the upcoming “Beautiful Racket” book, including:
* `#lang br` teaching language * `#lang br` teaching language
* `#lang brag` parser generator language (a fork of Danny Yoo's [ragg](http://github.com/jbclements/ragg))
* supporting modules * supporting modules
* sample languages * sample languages
Installation: Installation:
`raco pkg install beautiful-racket` `raco pkg install beautiful-racket`

@ -1,5 +0,0 @@
#lang racket/base
(module+ reader
(require "ragg/codegen/reader.rkt")
(provide (all-from-out "ragg/codegen/reader.rkt")))

@ -1,4 +0,0 @@
#lang br/ragg/examples/simple-line-drawing
3 9 X;
6 3 b 3 X 3 b;
3 9 X;

@ -1,10 +0,0 @@
#lang setup/infotab
(define name "ragg")
(define categories '(devtools))
(define can-be-loaded-with 'all)
(define version "1.0")
(define repositories '("4.x"))
(define scribblings '(("br-ragg.scrbl")))
(define blurb '("ragg: a Racket AST Generator Generator. A design goal is to be easy for beginners to use. Given a grammar in EBNF, ragg produces a parser that generates Racket's native syntax objects with full source location."))
(define release-notes '((p "First release.")))
(define deps (list))

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; recursive rules destucture easily in the expander ;; recursive rules destucture easily in the expander
program : [CR]* [line [CR line]*] [CR]* program : [CR]* [line [CR line]*] [CR]*

@ -1,6 +1,6 @@
#lang br #lang br
(require parser-tools/lex parser-tools/lex-sre (require parser-tools/lex parser-tools/lex-sre
br/ragg/support brag/support
racket/string) racket/string)
(provide tokenize) (provide tokenize)

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
bf-program : (op | loop)* bf-program : (op | loop)*
op : ">" | "<" | "+" | "-" | "." | "," op : ">" | "<" | "+" | "-" | "." | ","
loop : "[" (op | loop)* "]" loop : "[" (op | loop)* "]"

@ -1,5 +1,5 @@
#lang br #lang br
(require parser-tools/lex br/ragg/support) (require parser-tools/lex brag/support)
(define (tokenize input-port) (define (tokenize input-port)
(define (next-token) (define (next-token)
(define get-token (define get-token

@ -1,5 +1,5 @@
#lang br #lang br
(require parser-tools/lex br/ragg/support) (require parser-tools/lex brag/support)
(define+provide (tokenize ip) (define+provide (tokenize ip)
(define get-token (define get-token

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
tst-program : header-expr test-expr* tst-program : header-expr test-expr*

@ -1,6 +1,6 @@
#lang br #lang br
(require parser-tools/lex parser-tools/lex-sre (require parser-tools/lex parser-tools/lex-sre
br/ragg/support brag/support
racket/string) racket/string)
(provide tokenize) (provide tokenize)

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; rule of thumb: use [optional] bits judiciously as they multiply the cases needed for a production rule ;; rule of thumb: use [optional] bits judiciously as they multiply the cases needed for a production rule
;; rule of thumb: for a set of related IDs, put each into the same grammar entity ;; rule of thumb: for a set of related IDs, put each into the same grammar entity

@ -1,6 +1,6 @@
#lang br #lang br
(require parser-tools/lex parser-tools/lex-sre (require parser-tools/lex parser-tools/lex-sre
br/ragg/support brag/support
racket/string) racket/string)
(provide tokenize) (provide tokenize)

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
txtadv-program : verb-section everywhere-section things-section places-section start-section txtadv-program : verb-section everywhere-section things-section places-section start-section

@ -1,6 +1,6 @@
#lang br #lang br
(require parser-tools/lex parser-tools/lex-sre (require parser-tools/lex parser-tools/lex-sre
br/ragg/support brag/support
racket/string) racket/string)
(provide tokenize) (provide tokenize)

@ -2,5 +2,5 @@
(define collection 'multi) (define collection 'multi)
(define version "0.01") (define version "0.01")
(define deps '("base" "sugar" "beautiful-racket-lib" "rackunit-lib" "beautiful-racket-ragg" "parser-tools-lib")) (define deps '("base" "sugar" "beautiful-racket-lib" "rackunit-lib" "brag" "parser-tools-lib"))
(define build-deps '("racket-doc")) (define build-deps '("racket-doc"))

@ -3,8 +3,8 @@
racket/date racket/date
file/md5 file/md5
(for-label racket (for-label racket
br/ragg/support brag/support
br/ragg/examples/nested-word-list brag/examples/nested-word-list
(only-in parser-tools/lex lexer-src-pos) (only-in parser-tools/lex lexer-src-pos)
(only-in syntax/parse syntax-parse ~literal))) (only-in syntax/parse syntax-parse ~literal)))
@ -26,14 +26,15 @@
@title{ragg: a Racket AST Generator Generator} @title{brag: the Beautiful Racket AST Generator}
@author+email["Danny Yoo" "dyoo@hashcollision.org"] @author["Danny Yoo" "Matthew Butterick"]
@defmodulelang[brag]
@section{Informal quickstart} @section{Informal quickstart}
@(define my-eval (make-base-eval)) @(define my-eval (make-base-eval))
@(my-eval '(require br/ragg/examples/nested-word-list @(my-eval '(require brag/examples/nested-word-list
racket/list racket/list
racket/match)) racket/match))
@ -66,11 +67,9 @@ or more repetitions of the previous thing, and we treat the uppercased
@racket[LEFT-PAREN], @racket[RIGHT-PAREN], and @racket[WORD] as placeholders @racket[LEFT-PAREN], @racket[RIGHT-PAREN], and @racket[WORD] as placeholders
for atomic @emph{tokens}. for atomic @emph{tokens}.
@margin-note{See @secref{install-ragg} for instructions on installing
@tt{ragg.}}
Here are a few examples of tokens: Here are a few examples of tokens:
@interaction[#:eval my-eval @interaction[#:eval my-eval
(require br/ragg/support) (require brag/support)
(token 'LEFT-PAREN) (token 'LEFT-PAREN)
(token 'WORD "crunchy" #:span 7) (token 'WORD "crunchy" #:span 7)
(token 'RIGHT-PAREN)] (token 'RIGHT-PAREN)]
@ -82,12 +81,12 @@ use it to make structures out of a sequence of tokens.
It's clear that we don't yet have a program because there's no @litchar{#lang} It's clear that we don't yet have a program because there's no @litchar{#lang}
line. We should add one. Put @litchar{#lang br/ragg} at the top of the BNF line. We should add one. Put @litchar{#lang brag} at the top of the BNF
description, and save it as a file called @filepath{nested-word-list.rkt}. description, and save it as a file called @filepath{nested-word-list.rkt}.
@filebox["nested-word-list.rkt"]{ @filebox["nested-word-list.rkt"]{
@verbatim{ @verbatim{
#lang br/ragg #lang brag
nested-word-list: WORD nested-word-list: WORD
| LEFT-PAREN nested-word-list* RIGHT-PAREN | LEFT-PAREN nested-word-list* RIGHT-PAREN
}} }}
@ -135,12 +134,11 @@ What happens if we pass it a more substantial source of tokens?
(token 'WORD str)]))) (token 'WORD str)])))
@code:comment{For example:} @code:comment{For example:}
(define token-source (tokenize "(welcome (to (((ragg)) ())))"))
(define v (parse token-source)) (define v (parse token-source))
(syntax->datum v) (syntax->datum v)
] ]
Welcome to @tt{ragg}. Welcome to @tt{brag}.
@ -153,12 +151,12 @@ Welcome to @tt{ragg}.
@section{Introduction} @section{Introduction}
@tt{ragg} is a parsing framework for Racket with the design goal to be easy @tt{brag} is a parsing framework for Racket with the design goal to be easy
to use. It includes the following features: to use. It includes the following features:
@itemize[ @itemize[
@item{It provides a @litchar{#lang} for writing extended BNF grammars. @item{It provides a @litchar{#lang} for writing extended BNF grammars.
A module written in @litchar{#lang br/ragg} automatically generates a A module written in @litchar{#lang brag} automatically generates a
parser. The output of this parser tries to follow parser. The output of this parser tries to follow
@link["http://en.wikipedia.org/wiki/How_to_Design_Programs"]{HTDP} @link["http://en.wikipedia.org/wiki/How_to_Design_Programs"]{HTDP}
doctrine; the structure of the grammar informs the structure of the doctrine; the structure of the grammar informs the structure of the
@ -170,7 +168,7 @@ starting production. Identifiers in uppercase are assumed to represent
terminal tokens, and are otherwise the names of nonterminals.} terminal tokens, and are otherwise the names of nonterminals.}
@item{Tokenizers can be developed completely independently of parsers. @item{Tokenizers can be developed completely independently of parsers.
@tt{ragg} takes a liberal view on tokens: they can be strings, @tt{brag} takes a liberal view on tokens: they can be strings,
symbols, or instances constructed with @racket[token]. Furthermore, symbols, or instances constructed with @racket[token]. Furthermore,
tokens can optionally provide location: if tokens provide location, the tokens can optionally provide location: if tokens provide location, the
generated syntax objects will as well.} generated syntax objects will as well.}
@ -182,38 +180,13 @@ generated syntax objects will as well.}
] ]
@subsection[#:tag "install-ragg"]{Installation}
@itemize[
@item{@margin-note{At the time of this writing, Racket 5.3.2 is in
@link["http://pre.racket-lang.org/"]{pre-release}.} If you are using a version
of Racket > 5.3.1, then follow the instructions on the
@link["https://plt-etc.byu.edu:9004/info/ragg"]{PLaneT2 page}.}
@item{For those who are using Racket <= 5.3.1, you can download the following PLT package:
@nested[#:style 'inset]{@link["ragg.plt"]{ragg.plt} [md5sum: @compute-md5sum["ragg.plt" "ab79038b40e510a5cf13363825c4aef4"]]
Last updated: @lookup-date["ragg.plt" "Wednesday, January 16th, 2013"]
}
Once downloaded, either use DrRacket's package installation features
(@link["http://docs.racket-lang.org/drracket/Menus.html#(idx._(gentag._57._(lib._scribblings/drracket/drracket..scrbl)))"]{Install
PLT File...} under DrRacket's File menu), or use the command line:
@nested[#:style 'inset]{@tt{raco setup -A ragg.plt}}}
]
@subsection{Example: a small DSL for ASCII diagrams} @subsection{Example: a small DSL for ASCII diagrams}
@margin-note{This is a @margin-note{This is a
@link["http://stackoverflow.com/questions/12345647/rewrite-this-script-by-designing-an-interpreter-in-racket"]{restatement @link["http://stackoverflow.com/questions/12345647/rewrite-this-script-by-designing-an-interpreter-in-racket"]{restatement
of a question on Stack Overflow}.} To motivate @tt{ragg}'s design, let's look of a question on Stack Overflow}.} To motivate @tt{brag}'s design, let's look
at the following toy problem: we'd like to define a language for at the following toy problem: we'd like to define a language for
drawing simple ASCII diagrams. We'd like to be able write something like this: drawing simple ASCII diagrams. We'd like to be able write something like this:
@ -276,7 +249,7 @@ programs.
@subsection{Parsing the concrete syntax} @subsection{Parsing the concrete syntax}
@filebox["simple-line-drawing.rkt"]{ @filebox["simple-line-drawing.rkt"]{
@verbatim|{ @verbatim|{
#lang br/ragg #lang brag
drawing: rows* drawing: rows*
rows: repeat chunk+ ";" rows: repeat chunk+ ";"
repeat: INTEGER repeat: INTEGER
@ -284,21 +257,21 @@ chunk: INTEGER STRING
}| }|
} }
@margin-note{@secref{ragg-syntax} describes @tt{ragg}'s syntax in more detail.} @margin-note{@secref{brag-syntax} describes @tt{brag}'s syntax in more detail.}
We write a @tt{ragg} program as an extended BNF grammar, where patterns can be: We write a @tt{brag} program as an extended BNF grammar, where patterns can be:
@itemize[ @itemize[
@item{the names of other rules (e.g. @racket[chunk])} @item{the names of other rules (e.g. @racket[chunk])}
@item{literal and symbolic token names (e.g. @racket[";"], @racket[INTEGER])} @item{literal and symbolic token names (e.g. @racket[";"], @racket[INTEGER])}
@item{quantified patterns (e.g. @litchar{+} to represent one-or-more repetitions)} @item{quantified patterns (e.g. @litchar{+} to represent one-or-more repetitions)}
] ]
The result of a @tt{ragg} program is a module with a @racket[parse] function The result of a @tt{brag} program is a module with a @racket[parse] function
that can parse tokens and produce a syntax object as a result. that can parse tokens and produce a syntax object as a result.
Let's exercise this function: Let's exercise this function:
@interaction[#:eval my-eval @interaction[#:eval my-eval
(require br/ragg/support) (require brag/support)
@eval:alts[(require "simple-line-drawing.rkt") @eval:alts[(require "simple-line-drawing.rkt")
(require br/ragg/examples/simple-line-drawing)] (require brag/examples/simple-line-drawing)]
(define stx (define stx
(parse (list (token 'INTEGER 6) (parse (list (token 'INTEGER 6)
(token 'INTEGER 2) (token 'INTEGER 2)
@ -553,7 +526,7 @@ Let's add one.
@filebox["letter-i.rkt"]{ @filebox["letter-i.rkt"]{
@verbatim|{ @verbatim|{
#lang br/ragg/examples/simple-line-drawing #lang brag/examples/simple-line-drawing
3 9 X; 3 9 X;
6 3 b 3 X 3 b; 6 3 b 3 X 3 b;
3 9 X; 3 9 X;
@ -569,9 +542,9 @@ how to compile programs labeled with this @litchar{#lang} line. We'll do two
things: things:
@itemize[ @itemize[
@item{Tell Racket to use the @tt{ragg}-generated parser and lexer we defined @item{Tell Racket to use the @tt{brag}-generated parser and lexer we defined
earlier whenever it sees a program written with earlier whenever it sees a program written with
@litchar{#lang br/ragg/examples/simple-line-drawing}.} @litchar{#lang brag/examples/simple-line-drawing}.}
@item{Define transformation rules for @racket[drawing], @racket[rows], and @item{Define transformation rules for @racket[drawing], @racket[rows], and
@racket[chunk] to rewrite these into standard Racket forms.} @racket[chunk] to rewrite these into standard Racket forms.}
@ -591,18 +564,18 @@ reader} tells Racket how to parse and compile a file. Whenever Racket sees a
@filepath{<name>/lang/reader}. @filepath{<name>/lang/reader}.
Here's the definition for Here's the definition for
@filepath{br/ragg/examples/simple-line-drawing/lang/reader.rkt}: @filepath{brag/examples/simple-line-drawing/lang/reader.rkt}:
@filebox["br/ragg/examples/simple-line-drawing/lang/reader.rkt"]{ @filebox["brag/examples/simple-line-drawing/lang/reader.rkt"]{
@codeblock|{ @codeblock|{
#lang s-exp syntax/module-reader #lang s-exp syntax/module-reader
br/ragg/examples/simple-line-drawing/semantics brag/examples/simple-line-drawing/semantics
#:read my-read #:read my-read
#:read-syntax my-read-syntax #:read-syntax my-read-syntax
#:whole-body-readers? #t #:whole-body-readers? #t
(require br/ragg/examples/simple-line-drawing/lexer (require brag/examples/simple-line-drawing/lexer
br/ragg/examples/simple-line-drawing/grammar) brag/examples/simple-line-drawing/grammar)
(define (my-read in) (define (my-read in)
(syntax->datum (my-read-syntax #f in))) (syntax->datum (my-read-syntax #f in)))
@ -614,11 +587,7 @@ br/ragg/examples/simple-line-drawing/semantics
We use a helper module @racketmodname[syntax/module-reader], which provides We use a helper module @racketmodname[syntax/module-reader], which provides
utilities for creating a module reader. It uses the lexer and utilities for creating a module reader. It uses the lexer and
@tt{ragg}-generated parser we defined earlier (saved into @tt{brag}-generated parser we defined earlier, and also tells Racket that it should compile the forms in the syntax
@link["http://hashcollision.org/ragg/examples/simple-line-drawing/lexer.rkt"]{lexer.rkt}
and
@link["http://hashcollision.org/ragg/examples/simple-line-drawing/grammar.rkt"]{grammar.rkt}
modules), and also tells Racket that it should compile the forms in the syntax
object using a module called @filepath{semantics.rkt}. object using a module called @filepath{semantics.rkt}.
@margin-note{For a systematic treatment on capturing the semantics of @margin-note{For a systematic treatment on capturing the semantics of
@ -627,7 +596,7 @@ Interpretation}.}
Let's look into @filepath{semantics.rkt} and see what's involved in Let's look into @filepath{semantics.rkt} and see what's involved in
compilation: compilation:
@filebox["br/ragg/examples/simple-line-drawing/semantics.rkt"]{ @filebox["brag/examples/simple-line-drawing/semantics.rkt"]{
@codeblock|{ @codeblock|{
#lang racket/base #lang racket/base
(require (for-syntax racket/base syntax/parse)) (require (for-syntax racket/base syntax/parse))
@ -692,7 +661,7 @@ There are a few things to note:
@itemize[ @itemize[
@item{@tt{ragg}'s native data structure is the syntax object because the @item{@tt{brag}'s native data structure is the syntax object because the
majority of Racket's language-processing infrastructure knows how to read and majority of Racket's language-processing infrastructure knows how to read and
write this structured value.} write this structured value.}
@ -718,12 +687,12 @@ the macro expansion system to do this:
] ]
Altogether, @tt{ragg}'s intent is to be a parser generator generator for Racket Altogether, @tt{brag}'s intent is to be a parser generator generator for Racket
that's easy and fun to use. It's meant to fit naturally with the other tools that's easy and fun to use. It's meant to fit naturally with the other tools
in the Racket language toolchain. Hopefully, it will reduce the friction in in the Racket language toolchain. Hopefully, it will reduce the friction in
making new languages with alternative concrete syntaxes. making new languages with alternative concrete syntaxes.
The rest of this document describes the @tt{ragg} language and the parsers it The rest of this document describes the @tt{brag} language and the parsers it
generates. generates.
@ -732,9 +701,9 @@ generates.
@section{The language} @section{The language}
@subsection[#:tag "ragg-syntax"]{Syntax and terminology} @subsection[#:tag "brag-syntax"]{Syntax and terminology}
A program in the @tt{ragg} language consists of the language line A program in the @tt{brag} language consists of the language line
@litchar{#lang br/ragg}, followed by a collection of @tech{rule}s and @litchar{#lang brag}, followed by a collection of @tech{rule}s and
@tech{line comment}s. @tech{line comment}s.
A @deftech{rule} is a sequence consisting of: a @tech{rule identifier}, a colon A @deftech{rule} is a sequence consisting of: a @tech{rule identifier}, a colon
@ -767,7 +736,7 @@ continues till the end of the line.
For example, in the following program: For example, in the following program:
@nested[#:style 'inset @nested[#:style 'inset
@verbatim|{ @verbatim|{
#lang br/ragg #lang brag
;; A parser for a silly language ;; A parser for a silly language
sentence: verb optional-adjective object sentence: verb optional-adjective object
verb: greeting verb: greeting
@ -787,20 +756,20 @@ More examples:
@itemize[ @itemize[
@item{A @item{A
@link["http://hashcollision.org/ragg/examples/01-equal.rkt"]{BNF} for binary BNF for binary
strings that contain an equal number of zeros and ones. strings that contain an equal number of zeros and ones.
@verbatim|{ @verbatim|{
#lang br/ragg #lang brag
equal: [zero one | one zero] ;; equal number of "0"s and "1"s. equal: [zero one | one zero] ;; equal number of "0"s and "1"s.
zero: "0" equal | equal "0" ;; has an extra "0" in it. zero: "0" equal | equal "0" ;; has an extra "0" in it.
one: "1" equal | equal "1" ;; has an extra "1" in it. one: "1" equal | equal "1" ;; has an extra "1" in it.
}| }|
} }
@item{A @link["http://hashcollision.org/ragg/examples/baby-json.rkt"]{BNF} for @item{A BNF for
@link["http://www.json.org/"]{JSON}-like structures. @link["http://www.json.org/"]{JSON}-like structures.
@verbatim|{ @verbatim|{
#lang br/ragg #lang brag
json: number | string json: number | string
| array | object | array | object
number: NUMBER number: NUMBER
@ -812,20 +781,16 @@ kvpair: ID ":" json
} }
] ]
The @link["https://github.com/dyoo/ragg"]{ragg github source repository}
includes
@link["https://github.com/dyoo/ragg/tree/master/ragg/examples"]{several more
examples}.
@subsection{Syntax errors} @subsection{Syntax errors}
Besides the basic syntax errors that can occur with a malformed grammar, there Besides the basic syntax errors that can occur with a malformed grammar, there
are a few other classes of situations that @litchar{#lang br/ragg} will consider are a few other classes of situations that @litchar{#lang brag} will consider
as syntax errors. as syntax errors.
@tt{ragg} will raise a syntax error if the grammar: @tt{brag} will raise a syntax error if the grammar:
@itemize[ @itemize[
@item{doesn't have any rules.} @item{doesn't have any rules.}
@ -835,7 +800,7 @@ as syntax errors.
following program: following program:
@nested[#:style 'code-inset @nested[#:style 'code-inset
@verbatim|{ @verbatim|{
#lang br/ragg #lang brag
foo: [bar] foo: [bar]
}| }|
] ]
@ -844,14 +809,14 @@ should raise an error because @tt{bar} has not been defined, even though
@item{uses the token name @racket[EOF]; the end-of-file token type is reserved @item{uses the token name @racket[EOF]; the end-of-file token type is reserved
for internal use by @tt{ragg}.} for internal use by @tt{brag}.}
@item{contains a rule that has no finite derivation. e.g. the following @item{contains a rule that has no finite derivation. e.g. the following
program: program:
@nested[#:style 'code-inset @nested[#:style 'code-inset
@verbatim|{ @verbatim|{
#lang br/ragg #lang brag
infinite-a: "a" infinite-a infinite-a: "a" infinite-a
}| }|
] ]
@ -860,13 +825,13 @@ should raise an error because no finite sequence of tokens will satisfy
] ]
Otherwise, @tt{ragg} should be fairly tolerant and permit even ambiguous Otherwise, @tt{brag} should be fairly tolerant and permit even ambiguous
grammars. grammars.
@subsection{Semantics} @subsection{Semantics}
@declare-exporting[br/ragg/examples/nested-word-list] @declare-exporting[brag/examples/nested-word-list]
A program written in @litchar{#lang br/ragg} produces a module that provides a few A program written in @litchar{#lang brag} produces a module that provides a few
bindings. The most important of these is @racket[parse]: bindings. The most important of these is @racket[parse]:
@defproc[(parse [source any/c #f] @defproc[(parse [source any/c #f]
@ -881,7 +846,7 @@ first rule as the start production. The parse must completely consume
The @deftech{token source} can either be a sequence, or a 0-arity function that The @deftech{token source} can either be a sequence, or a 0-arity function that
produces @tech{tokens}. produces @tech{tokens}.
A @deftech{token} in @tt{ragg} can be any of the following values: A @deftech{token} in @tt{brag} can be any of the following values:
@itemize[ @itemize[
@item{a string} @item{a string}
@item{a symbol} @item{a symbol}
@ -916,7 +881,7 @@ pattern that informs the parser to introduces nested structure into the syntax
object. object.
If the grammar has ambiguity, @tt{ragg} will choose and return a parse, though If the grammar has ambiguity, @tt{brag} will choose and return a parse, though
it does not guarantee which one it chooses. it does not guarantee which one it chooses.
@ -927,7 +892,7 @@ If the parse cannot be performed successfully, or if a token in the
It's often convenient to extract a parser for other non-terminal rules in the It's often convenient to extract a parser for other non-terminal rules in the
grammar, and not just for the first rule. A @tt{ragg}-generated module also grammar, and not just for the first rule. A @tt{brag}-generated module also
provides a form called @racket[make-rule-parser] to extract a parser for the provides a form called @racket[make-rule-parser] to extract a parser for the
other non-terminals: other non-terminals:
@ -936,11 +901,11 @@ other non-terminals:
Constructs a parser for the @racket[name] of one of the non-terminals Constructs a parser for the @racket[name] of one of the non-terminals
in the grammar. in the grammar.
For example, given the @tt{ragg} program For example, given the @tt{brag} program
@filepath{simple-arithmetic-grammar.rkt}: @filepath{simple-arithmetic-grammar.rkt}:
@filebox["simple-arithmetic-grammar.rkt"]{ @filebox["simple-arithmetic-grammar.rkt"]{
@verbatim|{ @verbatim|{
#lang br/ragg #lang brag
expr : term ('+' term)* expr : term ('+' term)*
term : factor ('*' factor)* term : factor ('*' factor)*
factor : INT factor : INT
@ -949,7 +914,7 @@ factor : INT
the following interaction shows how to extract a parser for @racket[term]s. the following interaction shows how to extract a parser for @racket[term]s.
@interaction[#:eval my-eval @interaction[#:eval my-eval
@eval:alts[(require "simple-arithmetic-grammar.rkt") @eval:alts[(require "simple-arithmetic-grammar.rkt")
(require br/ragg/examples/simple-arithmetic-grammar)] (require brag/examples/simple-arithmetic-grammar)]
(define term-parse (make-rule-parser term)) (define term-parse (make-rule-parser term))
(define tokens (list (token 'INT 3) (define tokens (list (token 'INT 3)
"*" "*"
@ -977,7 +942,7 @@ A set of all the token types used in a grammar.
For example: For example:
@interaction[#:eval my-eval @interaction[#:eval my-eval
@eval:alts[(require "simple-arithmetic-grammar.rkt") @eval:alts[(require "simple-arithmetic-grammar.rkt")
(require br/ragg/examples/simple-arithmetic-grammar)] (require brag/examples/simple-arithmetic-grammar)]
all-token-types all-token-types
] ]
@ -989,10 +954,10 @@ all-token-types
@section{Support API} @section{Support API}
@defmodule[br/ragg/support] @defmodule[brag/support]
The @racketmodname[br/ragg/support] module provides functions to interact with The @racketmodname[brag/support] module provides functions to interact with
@tt{ragg} programs. The most useful is the @racket[token] function, which @tt{brag} programs. The most useful is the @racket[token] function, which
produces tokens to be parsed. produces tokens to be parsed.
@defproc[(token [type (or/c string? symbol?)] @defproc[(token [type (or/c string? symbol?)]
@ -1043,65 +1008,4 @@ DrRacket should highlight the offending locations in the source.}
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@section{Caveats and things to do}
Here are a few caveats and future aims for @tt{ragg}.
@itemize[
@item{@tt{ragg} doesn't currently have a good story about operator precedence.
Future versions of @tt{ragg} will support the specification of operator
precedence to deal with grammar ambiguity, probably by extending the BNF
grammar rules in @litchar{#lang br/ragg} with keyword arguments.}
@item{I currently depend on the lexer framework provided by
@racketmodname[parser-tools/lex], which has a steeper learning curve than I'd
like. A future version of @tt{ragg} will probably try to provide a nicer set
of tools for defining lexers.}
@item{The underlying parsing engine (an Earley-style parser) has not been fully
optimized, so it may exhibit degenerate parse times. A future version of
@tt{ragg} will guarantee @math{O(n^3)} time bounds so that at the very least,
parses will be polynomial-time.}
@item{@tt{ragg} doesn't yet have a good story on dealing with parser error
recovery. If a parse fails, it tries to provide the source location, but does
little else.}
@item{@tt{ragg} is slightly misnamed: what it really builds is a concrete
syntax tree rather than an abstract syntax tree. A future version of @tt{ragg}
will probably support annotations on patterns so that they can be omitted or
transformed in the parser output.}
]
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@section{Miscellaneous and thanks}
Thanks to Matthew Flatt for pointing me to @racket[cfg-parser] from the
@racket[cfg-parser] library. Joe Politz gave me good advice and
feedback. Also, he suggested the name ``ragg''. Other alternatives I'd been
considering were ``autogrammar'' or ``chompy''. Thankfully, he is a better
Namer than me. Daniel Patterson provided feedback that led to
@racket[make-rule-parser]. Robby Findler and Guillaume Marceau provided
steadfast suggestions to look into other parsing frameworks like
@link["http://en.wikipedia.org/wiki/Syntax_Definition_Formalism"]{SDF} and
@link["http://sablecc.org/"]{SableCC}. Special thanks to Shriram
Krishnamurthi, who convinced me that other people might find this package
useful.
@close-eval[my-eval] @close-eval[my-eval]

@ -5,11 +5,11 @@
racket/set racket/set
racket/syntax racket/syntax
syntax/srcloc syntax/srcloc
br/ragg/rules/stx-types brag/rules/stx-types
"flatten.rkt" "flatten.rkt"
syntax/id-table syntax/id-table
(prefix-in sat: "satisfaction.rkt") (prefix-in sat: "satisfaction.rkt")
(prefix-in support: br/ragg/support) (prefix-in support: brag/support)
(prefix-in stxparse: syntax/parse)) (prefix-in stxparse: syntax/parse))
(provide rules-codegen) (provide rules-codegen)
@ -104,9 +104,9 @@
(begin (begin
(require parser-tools/lex (require parser-tools/lex
parser-module parser-module
br/ragg/codegen/runtime brag/codegen/runtime
br/ragg/support brag/support
br/ragg/private/internal-support brag/private/internal-support
racket/set racket/set
(for-syntax syntax/parse racket/base)) (for-syntax syntax/parse racket/base))

@ -1,5 +1,5 @@
#lang br #lang br
(require br/ragg/rules/stx-types (require brag/rules/stx-types
(for-syntax racket/base)) (for-syntax racket/base))
(provide flatten-rule (provide flatten-rule

@ -1,14 +1,14 @@
#lang s-exp syntax/module-reader #lang s-exp syntax/module-reader
br/ragg/codegen/sexp-based-lang brag/codegen/sexp-based-lang
#:read my-read #:read my-read
#:read-syntax my-read-syntax #:read-syntax my-read-syntax
#:info my-get-info #:info my-get-info
#:whole-body-readers? #t #:whole-body-readers? #t
(require br/ragg/rules/parser (require brag/rules/parser
br/ragg/rules/lexer brag/rules/lexer
br/ragg/rules/stx brag/rules/stx
br/ragg/rules/rule-structs) brag/rules/rule-structs)
(define (my-read in) (define (my-read in)
(syntax->datum (my-read-syntax #f in))) (syntax->datum (my-read-syntax #f in)))

@ -4,8 +4,8 @@
racket/list racket/list
racket/generator racket/generator
(prefix-in lex: parser-tools/lex) (prefix-in lex: parser-tools/lex)
br/ragg/support brag/support
br/ragg/private/internal-support) brag/private/internal-support)
(provide THE-ERROR-HANDLER (provide THE-ERROR-HANDLER

@ -11,7 +11,7 @@
;; The intended use of this language is as follows: ;; The intended use of this language is as follows:
;; ;;
;;;;; s-exp-grammar.rkt ;;;;;;;;; ;;;;; s-exp-grammar.rkt ;;;;;;;;;
;; #lang br/ragg ;; #lang brag
;; s-exp : "(" s-exp* ")" | ATOM ;; s-exp : "(" s-exp* ")" | ATOM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -91,6 +91,6 @@
#%top-interaction) #%top-interaction)
(define-syntax (rules stx) (define-syntax (rules stx)
(rules-codegen #:parser-provider-module 'br/ragg/cfg-parser/cfg-parser ;; 'parser-tools/yacc (rules-codegen #:parser-provider-module 'brag/cfg-parser/cfg-parser ;; 'parser-tools/yacc
#:parser-provider-form 'cfg-parser ;; 'parser #:parser-provider-form 'cfg-parser ;; 'parser
stx)) stx))

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; Simple baby example of JSON structure ;; Simple baby example of JSON structure
json: ID <":"> ID json: ID <":"> ID

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; Simple baby example of JSON structure ;; Simple baby example of JSON structure
json: number json: number

@ -1,6 +1,6 @@
#lang br #lang br
(require "json-elider.rkt" (require "json-elider.rkt"
br/ragg/support brag/support
rackunit) rackunit)
(check-equal? (check-equal?

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
## Equal numbers of 0 and 1s in a string. ## Equal numbers of 0 and 1s in a string.
## ##

@ -1,3 +1,3 @@
#lang br/ragg #lang brag
rule: "0"* "1" rule: "0"* "1"

@ -1,3 +1,3 @@
#lang br/ragg #lang brag
rule-0n1n: ["0" rule-0n1n "1"] rule-0n1n: ["0" rule-0n1n "1"]

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; Simple baby example of JSON structure ;; Simple baby example of JSON structure
json: number | string json: number | string

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; Lua parser, adapted from: ;; Lua parser, adapted from:
;; http://www.lua.org/manual/5.1/manual.html#8 ;; http://www.lua.org/manual/5.1/manual.html#8

@ -1,3 +1,3 @@
#lang br/ragg #lang brag
nested-word-list: WORD nested-word-list: WORD
| LEFT-PAREN nested-word-list* RIGHT-PAREN | LEFT-PAREN nested-word-list* RIGHT-PAREN

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
# Grammar for Python # Grammar for Python

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
expr : term ('+' term)* expr : term ('+' term)*
term : factor ('*' factor)* term : factor ('*' factor)*

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; ;;
;; See: http://stackoverflow.com/questions/12345647/rewrite-this-script-by-designing-an-interpreter-in-racket ;; See: http://stackoverflow.com/questions/12345647/rewrite-this-script-by-designing-an-interpreter-in-racket

@ -0,0 +1,4 @@
#lang brag/examples/simple-line-drawing
3 9 X;
6 3 b 3 X 3 b;
3 9 X;

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; ;;
;; See: http://stackoverflow.com/questions/12345647/rewrite-this-script-by-designing-an-interpreter-in-racket ;; See: http://stackoverflow.com/questions/12345647/rewrite-this-script-by-designing-an-interpreter-in-racket

@ -1,12 +1,12 @@
#lang s-exp syntax/module-reader #lang s-exp syntax/module-reader
br/ragg/examples/simple-line-drawing/semantics brag/examples/simple-line-drawing/semantics
#:read my-read #:read my-read
#:read-syntax my-read-syntax #:read-syntax my-read-syntax
#:info my-get-info #:info my-get-info
#:whole-body-readers? #t #:whole-body-readers? #t
(require br/ragg/examples/simple-line-drawing/lexer (require brag/examples/simple-line-drawing/lexer
br/ragg/examples/simple-line-drawing/grammar) brag/examples/simple-line-drawing/grammar)
(define (my-read in) (define (my-read in)
(syntax->datum (my-read-syntax #f in))) (syntax->datum (my-read-syntax #f in)))

@ -3,7 +3,7 @@
(provide tokenize) (provide tokenize)
;; A simple lexer for simple-line-drawing. ;; A simple lexer for simple-line-drawing.
(require br/ragg/support (require brag/support
parser-tools/lex) parser-tools/lex)
(define (tokenize ip) (define (tokenize ip)

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
## Statlist grammar ## Statlist grammar

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; A parser for a silly language ;; A parser for a silly language
sentence: verb optional-adjective object sentence: verb optional-adjective object
verb: greeting verb: greeting

@ -0,0 +1,6 @@
#lang setup/infotab
(define name "brag")
(define version "1.0")
(define scribblings '(("brag.scrbl")))
(define blurb '("brag: the Beautiful Racket AST Generator. A fork o fDanny Yoo's ragg. A design goal is to be easy for beginners to use. Given a grammar in EBNF, ragg produces a parser that generates Racket's native syntax objects with full source location."))
(define deps (list))

@ -0,0 +1,5 @@
#lang racket/base
(module+ reader
(require "codegen/reader.rkt")
(provide (all-from-out "codegen/reader.rkt")))

@ -1,6 +1,6 @@
#lang racket/base #lang racket/base
(require br/ragg/support) (require brag/support)
(provide current-source (provide current-source
current-parser-error-handler current-parser-error-handler

@ -1,6 +1,6 @@
#lang racket #lang racket
(require br/ragg/examples/python-grammar (require brag/examples/python-grammar
br/ragg/support brag/support
python-tokenizer python-tokenizer
racket/generator racket/generator
parser-tools/lex parser-tools/lex

@ -1,6 +1,6 @@
#lang racket/base #lang racket/base
(require br/ragg/examples/01-equal (require brag/examples/01-equal
rackunit) rackunit)
(check-equal? (syntax->datum (parse "")) (check-equal? (syntax->datum (parse ""))

@ -1,7 +1,7 @@
#lang racket/base #lang racket/base
(require br/ragg/examples/0n1 (require brag/examples/0n1
br/ragg/support brag/support
rackunit) rackunit)
(define (lex ip) (define (lex ip)

@ -1,6 +1,6 @@
#lang racket/base #lang racket/base
(require br/ragg/examples/0n1n (require brag/examples/0n1n
br/ragg/support brag/support
rackunit) rackunit)
(define (lex ip) (define (lex ip)

@ -15,4 +15,4 @@
"test-errors.rkt" "test-errors.rkt"
"test-old-token.rkt" "test-old-token.rkt"
"test-weird-grammar.rkt" "test-weird-grammar.rkt"
(submod br/ragg/codegen/satisfaction test)) (submod brag/codegen/satisfaction test))

@ -1,6 +1,6 @@
#lang racket/base #lang racket/base
(require br/ragg/examples/baby-json (require brag/examples/baby-json
br/ragg/support brag/support
rackunit) rackunit)
(check-equal? (check-equal?

@ -36,50 +36,50 @@
;; errors with position are sensitive to length of lang line ;; errors with position are sensitive to length of lang line
(define lang-line "#lang br/ragg") (define lang-line "#lang brag")
(check-compile-error (format "~a" lang-line) (check-compile-error (format "~a" lang-line)
"The grammar does not appear to have any rules") "The grammar does not appear to have any rules")
(check-compile-error (format "~a\nfoo" lang-line) (check-compile-error (format "~a\nfoo" lang-line)
"Error while parsing grammar near: foo [line=2, column=0, position=15]") "Error while parsing grammar near: foo [line=2, column=0, position=12]")
(check-compile-error (format "~a\nnumber : 42" lang-line) (check-compile-error (format "~a\nnumber : 42" lang-line)
"Error while parsing grammar near: 42 [line=2, column=9, position=24]") "Error while parsing grammar near: 42 [line=2, column=9, position=21]")
(check-compile-error (format "~a\nnumber : 1" lang-line) (check-compile-error (format "~a\nnumber : 1" lang-line)
"Error while parsing grammar near: 1 [line=2, column=9, position=24]") "Error while parsing grammar near: 1 [line=2, column=9, position=21]")
(check-compile-error "#lang br/ragg\n x: NUMBER\nx:STRING" (check-compile-error "#lang brag\n x: NUMBER\nx:STRING"
"Rule x has a duplicate definition") "Rule x has a duplicate definition")
;; Check to see that missing definitions for rules also raise good syntax ;; Check to see that missing definitions for rules also raise good syntax
;; errors: ;; errors:
(check-compile-error "#lang br/ragg\nx:y" (check-compile-error "#lang brag\nx:y"
"Rule y has no definition") "Rule y has no definition")
(check-compile-error "#lang br/ragg\nnumber : 1flarbl" (check-compile-error "#lang brag\nnumber : 1flarbl"
"Rule 1flarbl has no definition") "Rule 1flarbl has no definition")
(check-compile-error "#lang br/ragg\nprogram: EOF" (check-compile-error "#lang brag\nprogram: EOF"
"Token EOF is reserved and can not be used in a grammar") "Token EOF is reserved and can not be used in a grammar")
;; Nontermination checks: ;; Nontermination checks:
(check-compile-error "#lang br/ragg\nx : x" (check-compile-error "#lang brag\nx : x"
"Rule x has no finite derivation") "Rule x has no finite derivation")
(check-compile-error #<<EOF (check-compile-error #<<EOF
#lang br/ragg #lang brag
x : x y x : x y
y : "y" y : "y"
EOF EOF
@ -90,7 +90,7 @@ EOF
; This should be illegal too: ; This should be illegal too:
(check-compile-error #<<EOF (check-compile-error #<<EOF
#lang br/ragg #lang brag
a : "a" b a : "a" b
b : a | b b : a | b
EOF EOF
@ -100,7 +100,7 @@ EOF
(check-compile-error #<<EOF (check-compile-error #<<EOF
#lang br/ragg #lang brag
a : [b] a : [b]
b : [c] b : [c]
c : c c : c
@ -109,7 +109,7 @@ EOF
(check-compile-error #<<EOF (check-compile-error #<<EOF
#lang br/ragg #lang brag
a : [b] a : [b]
b : c b : c
c : c c : c
@ -118,7 +118,7 @@ EOF
(check-compile-error #<<EOF (check-compile-error #<<EOF
#lang br/ragg #lang brag
a : [a] a : [a]
b : [b] b : [b]
c : c c : c
@ -130,7 +130,7 @@ EOF
(check-compile-error #<<EOF (check-compile-error #<<EOF
#lang racket/base #lang racket/base
(require br/ragg/examples/simple-line-drawing) (require brag/examples/simple-line-drawing)
(define bad-parser (make-rule-parser crunchy)) (define bad-parser (make-rule-parser crunchy))
EOF EOF
"Rule crunchy is not defined in the grammar" "Rule crunchy is not defined in the grammar"

@ -1,6 +1,6 @@
#lang racket/base #lang racket/base
(require br/ragg/rules/stx-types (require brag/rules/stx-types
br/ragg/codegen/flatten brag/codegen/flatten
rackunit) rackunit)

@ -1,5 +1,5 @@
#lang racket/base #lang racket/base
(require br/ragg/rules/lexer (require brag/rules/lexer
rackunit rackunit
parser-tools/lex) parser-tools/lex)

@ -2,8 +2,8 @@
;; Make sure the old token type also works fine. ;; Make sure the old token type also works fine.
(require br/ragg/examples/simple-line-drawing (require brag/examples/simple-line-drawing
br/ragg/support brag/support
racket/list racket/list
parser-tools/lex parser-tools/lex
(prefix-in : parser-tools/lex-sre) (prefix-in : parser-tools/lex-sre)

@ -3,9 +3,9 @@
(require rackunit (require rackunit
parser-tools/lex parser-tools/lex
br/ragg/rules/parser brag/rules/parser
br/ragg/rules/lexer brag/rules/lexer
br/ragg/rules/rule-structs) brag/rules/rule-structs)
;; quick-and-dirty helper for pos construction. ;; quick-and-dirty helper for pos construction.

@ -1,6 +1,6 @@
#lang racket/base #lang racket/base
(require br/ragg/examples/simple-arithmetic-grammar (require brag/examples/simple-arithmetic-grammar
br/ragg/support brag/support
racket/set racket/set
parser-tools/lex parser-tools/lex
racket/list racket/list

@ -1,7 +1,7 @@
#lang racket/base #lang racket/base
(require br/ragg/examples/simple-line-drawing (require brag/examples/simple-line-drawing
br/ragg/support brag/support
racket/list racket/list
parser-tools/lex parser-tools/lex
(prefix-in : parser-tools/lex-sre) (prefix-in : parser-tools/lex-sre)

@ -1,6 +1,6 @@
#lang racket/base #lang racket/base
(require br/ragg/examples/wordy (require brag/examples/wordy
br/ragg/support brag/support
rackunit) rackunit)
(check-equal? (check-equal?

@ -1,4 +1,4 @@
#lang br/ragg #lang brag
;; This used to fail when we had the yacc-based backend, but ;; This used to fail when we had the yacc-based backend, but
;; cfg-parser seems to be ok with it. ;; cfg-parser seems to be ok with it.
Loading…
Cancel
Save