ec2-52-204-98-217.compute-1.amazonaws.com | ToothyWiki | RecentChanges | Login | Webcomic

I've had a poke around, looking at various of the generators, but is there a page explaining the syntax anywhere?  Is it possible to control how many times certain elements are listed?  (For example, with the worship leader generator, can one ensure that only two songs are used rather than 6, or with the recipe generator, that a sensible number of ingredients are included?).  Is one supposed to pick up the syntax by copying other peoples' generators?  I had a look at  MoonShadow/GeneratorGenerator, but I'm still in the dark. AR

See WikiPedia: Backus-Naur_form ;) The angle brackets are optional, and confusing if you're gonna be using HTML, so no-one puts them in. Basically, you give it a list of lines like this:

 thing ::= some possible text | some other possible text | even more possible text..

Think of "::=" as "is defined as", and "|" as "or".

The script looks at text from left to right. Every time the script finds thing in whatever text it's looking at, it'll randomly select one of the possibilities from the definition, substitute it in instead of thing and start again from just before where thing used to be (so it'll be examining the text it just substituted). It starts off by looking up the definition of "bnf". If it can't find a definition for something, it'll just display that thing verbatim. So for instance

 bnf ::= cat | dog

will make it randomly display "cat" or "dog";

 bnf ::= yellow animal tail
animal ::= cat | dog

will make it display "yellow" ('cos isn't defined further), then look up "animal" (which will randomly get substituted for "cat" or "dog", which is then looked up, not defined further, so displayed), then display "tail".

Because it looks up substituted text again, you can do things like this:

 bnf ::= list-of-animals
list-of-animals ::= animal | list-of-animals animal

..which means that when looking up list-of-animals, there is a chance that the result will still contain list-of-animals, and lots of animals might get produced.

There's a couple of extra options.
 option ::= include = someoneelses/generator
includes the code of someone else's generator there and then so you don't have to type all their stuff out again if you just want to change a couple of things.
 option ::= spaces = 0
turns off spaces between elements in the output
 option ::= debug = 1
turns on debugging (which makes it list all the rules it recognised, then list all the substitutions it made, in order, when it generated a phrase).

That's the entire syntax.

BNF is defined in some places.  And no, it only defines what is possible in a grammar - it isn't powerful enough to keep count and such.
(PeterTaylor) I think that's Vitenka's ForDummies? was of saying that the grammars supported by MoonShadow's generator are context-free. That means that the only counting you can do is along the lines of making sure brackets match.

You can do sensible recipies with something like:

ingredients ::= ingredient | twoingredient  | ingredient twoingredient | twoingredient twoingredient
twoingredient ::= ingredient ingredient

It's not pleasant, but it works.  And to be truly truly evil, you could have a BNF that generates a new BNF.  That gets you some variable handling (eg. if you have three ingredients there must also be three steps to the recipie) but it's not nice.  --Vitenka

Oh dear.  I clearly didn't stress the dummy part of this enough :-).

There isn't an explaining page, no, so here's a good place...

The Basics

 label ::= text
means, "Wherever you have 'label', substitute in 'text' instead."

 label ::= text1 text2
means, "Wherever you have 'label', substitute in 'text1', followed by 'text2'."

 option ::= one | two
means, "Wherever you have 'option', substitute in either 'one' or 'two', at random."

That's the basics, I think.  Everything else comes from that.

Fixed number of items

So, to fix the number of songs (for example), you could have:
 bnf ::= song song
song ::= title1 | title2 | title3 | title4
which would produce exactly two random selections from the "song" list.

Fixed range of items

If you want, say, 2, 3, or 4 items, but no other amount, you could use:
 bnf ::= song song | song song song | song song song song
song ::= title1 | title2 | title3 | title4


If you want "ping" to turn up most of the time, but "pong" once in a while, you can use:
 bnf ::= "ping" | "ping" | "ping" | "ping" | "ping" | "pong"


Note that there is no way to do open-ended numbering.  You can't have nx,ny,nz (some number of x's follwed by the SAME number of y's unless you are willing to write a seperate line in the grammar for every possible number of n.  You can fake it for a smaller number, or paiur matching though:
bnf ::= middle | before middle after
middle ::= | before after | before middle after

Terminals vs Nonterminals

A nonterminal is something you've defined. A terminal is stuff that goes into the output. The parser will assume anything you've not defined is a terminal. It will also assume anything in double quotes is a terminal, even if you've defined it. So

 bnf ::= animal
animal ::= dog

will produce "dog", whereas

 bnf ::= "animal"
animal ::= dog

will produce "animal".


Escape stuff using HTML entities. For instance to produce a quote, use &quot;. To protect itself, the parser will turn all instances of < and > into &lt; and &gt;, then selectively turn some of them back to allow certain HTML tags. (todo: degorify)

Variables / Reference Storing

resolves b *one* level, and assigns the result to a, producing no output.

 pick_animal ::= cat | dog
bnf ::= <animal::=pick_animal> My animal is better than your animal
will produce one of "My cat is better than your cat" or "My dog is better than your dog".

The stored value will still be looked up each time it's displayed, potentially producing different answers. So,
 pick_animal ::= cat | dog
bnf ::= <animal::=pick_animal> My animal is better than your animal
cat ::= Tiddles | Mrs C | Tiger | Garfield
dog ::= Barney | Rex | Rover | Lumpy
might get "My Rex is better than your Rover", or "My Tiddles is better than your Garfield". But it will always compare cats with cats or dogs with dogs, never cats with dogs.

Resolves b all the way down and assigns it to a (as above).
This is mostly useful when using a complex lookup that you want to display in precisely the same way each time it appears.
 pick_animal ::= cat | dog
bnf ::= <<animal::=pick_animal>> My animal is better than your animal
cat ::= Tiddles | Mrs C | Tiger | Garfield
dog ::= Barney | Rex | Rover | Lumpy
might get the result:  "My Rex is better than your Rex", or "My Tiger is better than your Tiger". The two mentions of "animal" will always be the same.

(Note that spaces are not permitted around the ::= when inside of < > or << >> tags, but are required outside of them)

resolves b one level, appends the result to a, separated with an underscore, and resolves the lot. Thus,
 pick_animal ::= cat | dog
bnf ::= <animal::=pick_animal> My animal is more latin##animal than your animal
latin_cat ::= feline
latin_dog ::= canine
will produce one of "My cat is more feline than your cat" or "My dog is more canine than your dog".

The operation is recursive, so a itself may contain a ##. So, for example,
might be a good way to look up things like
 verb_dog_happy ::= wag
verb_dog_angry ::= growl
verb_cat_happy ::= purr
verb_cat_angry ::= hiss


ec2-52-204-98-217.compute-1.amazonaws.com | ToothyWiki | RecentChanges | Login | Webcomic
Edit this page | View other revisions | Recently used referrers
Last edited March 23, 2006 12:58 pm (viewing revision 19, which is the newest) (diff)