Grammar Files

By using the -lg grammar, you can specify your own grammar and have GENR8 do the drawing. The grammars used by GENR8 are expressed on Backus-Naur Form (BNF).The parser can handle all grammars that are generated from the following definition.


N = { RewriteRule, Predecessor, Successor, Modifier, Operator, Axiom, Condition, LSystem, Segment }



T = { +, -, &, ^, \, /, ~, [, ], <, >, Edge, -> }



S = { <LSystem> }



P = {



<LSystem>	::=	<Axiom> <RewriteRule> { <RewriteRule> }



<Axiom>		::=	<Segment> [ "~" ] "+" <Segment> [ "~" ] "+" <Segment> { [ "~" ] "+" <Segment> }



<RewriteRule>	::=	<Predecessor> "->" <Successor> [ <Condition>]



<Predecessor>	::=	<Segment> |

			<Segment> "<" <Segment> |

			<Segment> ">" <Segment> |

			<Segment> "<" <Segment> ">" <Segment>



<Successor>	::=	{ <Modifier> } <Segment>



<Condition>	::=	"If"



<Modifier>	::=	{ <Segment> } |

			"+" <Modifier> "-" |

			"-" <Modifier> "+" |

			"&" <Modifier> "^" |

			"^" <Modifier> "&" |

			"\" <Modifier> "/" |

			"/" <Modifier> "\" |

			"~" <Modifer> |

			"[" "[" "+" { <Operator> } <Segment> "]" "-" { <Operator> } <Segment> "]"



<Operator>	::=	"+"	|

			"-"	|

			"&"	|

			"^"	|

			"\"	|

			"/"	|

			"~"	|

Here is an example of a grammar file:
Edge0 + Edge1 + Edge2 + Edge3
// This is a comment, the parser ignores this text
Edge0 -> Edge3 [ + Edge0 ] Edge1
Edge1 -> Edge1
Edge2 -> Edge1 [ + Edge0 ] Edge1
Edge3 -> Edge2
// Another comment
Angle 90
Sync
BranchAngle 30
Before discussing what each symbol means it is necessary to emphasize that the parser is very primitive. Since the parser is very bad at handling errors, you should be careful and make sure that the syntax is correct. Each word should be separated by one space (' ') or tab (\t) and the lines should end with a return ('\n'). Unfortunately the comments must be on a separate line and you should not forget the white space after "//". Below is a list of the instructions and a brief explanation of how they are interpreted by the turtle.
EdgeXSegment type X.
<Left-sensitive context.
>Right-sensitive context.
+Turn right by Angle.
-Turn left by Angle.
&Pitch down by Angle.
^Pitch up by Angle.
\Roll left by Angle.
/Roll right by Angle.
~Switch direction.
[Push state on stack.
]Pop state from stack.

The first line contains the axiom. The axiom must be a regular polygon and may only contain '+', '~' and "EdgeX". The example specifies a square, where each side has a different type. By default the direction of the first segment is (1,0,0) and unfortunately, this can not be changed.

Next comes the rewrite rules, they have the format: predecessor -> successor A predecessor can have four formats:
EdgeX
EdgeY < EdgeX
EdgeX > EdgeZ
EdgeY < EdgeX > EdgeZ

When GENR8 looks for successors and predecessors, any segment that comes directly before the segment is considered.

The '[' and ']' symbols are used for placing branches. A branch may be preceded by any number of operators, but it can only consist of one segment.

The angle is given in degrees (0-360) and it is preceded by the word "Angle", it specifies how much to turn, pitch or roll.

Branches can be joined either after each rewrite-rule has been applied (asynchronous), or when all the rules have been applied (synchronous). You may get different results for the same grammar depending on which method you choose. Default is asynchronous, so if you want synchronous growth, you simply type "Sync".

If you like, you can specify the -ba flag in the grammar instead of in the command line.

Probabilistic RewriteRule

GENR8 can handle probalistic rewrite rules, for example

Edge0 + Edge1 + Edge0 + Edge1
Edge1 -> Edge0
      -> + Edge1 - - Edge1	Weight 2
Edge0 -> Edge1
      -> - Edge0 + + Edge0	Weight 2
Angle 45

The keyword Weight followed by an integer is used to control the relative weights of the possible successors when deciding which one to use. A Successor will get a Weight of 1 by default. Note that the parser can handle tabs as well as space when tokenizing. However, it is case-sensitive.