The goal of bnf
is to parse grammar specifications in Backus–Naur
form (BNF) and
generate code from that grammar.
;
after each ruleInstall the development version from GitHub. This will also require installing minilexer which is used in parsing the original BNF grammar
# install.packages("devtools")
devtools::install_github("coolbutuseless/minilexer")
devtools::install_github("ropenscilabs/bnf")
eval()
this codelibrary(bnf)
cat(bnf:::simple_bnf)
#>
#> Expr ::= Term ('+' Term | '-' Term)* ;
#> Term ::= Number ('*' Number | '/' Number)* ;
#> Number ::= ('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9')+ ;
bnf_spec <- bnf::parse_bnf(bnf:::simple_bnf)
bnf_spec
Click here to show/hide the BNF spec as an R object (a deeply
nested list)
list(
Expr = list(
list(items = list("Term")),
list(
items = list(
list(items = list("+", "Term")),
list(items = list("-", "Term"))
),
N = "zero_or_more", type = "choice")
),
Term = list(
list(items = list("Number")),
list(
items = list(
list(items = list("*", "Number")),
list(items = list("/", "Number"))
),
N = "zero_or_more", type = "choice")
),
Number = list(
items = list(
list(items = list("0")),
list(items = list("1")),
list(items = list("2")),
list(items = list("3")),
list(items = list("4")),
list(items = list("5")),
list(items = list("6")),
list(items = list("7")),
list(items = list("8")),
list(items = list("9"))
),
N = "one_or_more", type = "choice")
)
set.seed(2)
(code <- bnf::generate_code(bnf_spec = bnf_spec))
#> [1] "5-81+25+12*6"
eval()
this codeeval(parse(text = code))
#> [1] 21
simple_bnf_with_trig <- "
Expr ::= Term ('+' Term | '-' Term)* ;
Term ::= Factor ('*' Factor | '/' Factor)* ;
Factor ::= (Number | Var | '(' Expr ')' | Call) ;
Call ::= ('cos(' Expr ')' | 'sin(' Expr ')') ;
Var ::= ('x' | 'y') ;
Number ::= ('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9')+ ;
"
bnf_spec <- bnf::parse_bnf(simple_bnf_with_trig)
Click to see R representation of this grammar
list(
Expr = list(
list(items = list("Term")),
list(
items = list(
list(items = list("+", "Term")),
list(items = list("-", "Term"))
),
N = "zero_or_more",
type = "choice"
)
),
Term = list(
list(items = list("Factor")),
list(
items = list(
list(items = list("*", "Factor")),
list(items = list("/", "Factor"))
),
N = "zero_or_more",
type = "choice"
)
),
Factor = list(
items = list(
list(items = list("Number")),
list(items = list("Var")),
list(items = list("(", "Expr", ")")),
list(items = list("Call"))
),
type = "choice"
),
Call = list(
items = list(
list(items = list("cos(", "Expr", ")")),
list(items = list("sin(", "Expr", ")"))
),
type = "choice"
),
Var = list(
items = list(
list(items = list("x")),
list(items = list("y"))
),
type = "choice"
),
Number = list(
items = list(
list(items = list("0")),
list(items = list("1")),
list(items = list("2")),
list(items = list("3")),
list(items = list("4")),
list(items = list("5")),
list(items = list("6")),
list(items = list("7")),
list(items = list("8")),
list(items = list("9"))
),
N = "one_or_more",
type = "choice"
)
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Generate some R code from this grammar
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
set.seed(18) # 8
code <- bnf::generate_code(bnf_spec = bnf_spec, lambda0p = 0.5, lambda1p = 0.5)
code
#> [1] "y/y/3-cos(y-45*cos((07)*sin(4/x+x))+0/y)"
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Evaluate this code in R at a single (x, y) location
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eval(parse(text = code), list(x = 1, y = 2))
#> [1] -0.01241846
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Evaluate this code at multiple points on a grid
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
plot_df <- bnf::eval_grid(code, xmin = 0, xmax = 1, xn = 40)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# plot it
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ggplot(plot_df, aes(x, y)) +
geom_tile(aes(fill = abs(log(z)))) +
theme_void() +
theme(legend.position = 'none') +
scale_fill_viridis_c(na.value = '#440154FF') +
coord_equal()
The package includes a shiny app to explore graphical representations of the generated code.
bnf::run_example()
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.