Commit 2ccdb77c authored by Dmitry.Shahtanov's avatar Dmitry.Shahtanov Committed by Alexander.Trofimov

Добавлен генератор парсеров, грамматика Excel-формул, визуализатор грамматик.

git-svn-id: svn://192.168.3.15/activex/AVS/Sources/TeamlabOffice/trunk/OfficeWeb@59496 954022d7-b5bf-4e40-9824-e11837661b57
parent 118ec71c
logic = "TRUE" | "FALSE".
numConst = DecimalIntegerLiteral "." {decDig} {ExponentPart} | "." decDig {ExponentPart} | DecimalIntegerLiteral {ExponentPart}.
DecimalIntegerLiteral = "0" | NonZeroDigit {decDig}.
NonZeroDigit = {[+-]}[1-9].
ExponentPart = "e"i SignedInteger.
SignedInteger = {[+-]}decDig.
digSeq = decDig {decDig}.
decDig = [0-9].
Java = ["package" Name ";"]
{"import" Name ["." "*"] ";"}
{ClassDecl | InterfaceDecl | ";"}.
ClassDecl = {Modifyer} "class" ident
["extends" Name]
["implements" Name {"," Name} ]
"{" { FieldDecl
| MethodDecl
| ConstructorDecl
| "static" Block
}
"}".
InterfaceDecl = {Modifyer} "interface" ident
["extends" Name {"," Name} ]
"{" { FieldDecl
| MethodHeader ";"
}
"}".
FieldDecl = {Modifyer} Type Var {"," Var} ";".
Var = ident {"[" "]"} ["=" VarInit].
VarInit = Expr | ArrayInit.
ArrayInit = "{" VarInit {"," VarInit} "}".
MethodDecl = MethodHeader (Block | ";").
MethodHeader = {Modifyer} (Type | "void") ident "(" [FormPars] ")"
{"[" "]"}
["throws" Name {"," Name} ].
FormPars = FormPar {"," FormPar}.
FormPar = Type ident {"[" "]"}.
ConstructorDecl = {Modifyer} ident "(" [FormPars] ")"
["throws" Name {"," Name} ]
"{" [ConstructorCall] {BlockStatement} "}".
ConstructorCall = ("this" | "super") "(" [ActPars] ")".
Modifyer = "public" | "protected" | "private"
| "static"
| "abstract" | "final" | "native" | "synchronized" |
"transient" | "volatile".
Block = "{" {BlockStatement} "}".
BlockStatement = Type Var {"," Var} ";"
| Statement.
Statement = {ident ":"}
( Block
| [StatExpr] ";"
| "if" "(" Expr ")" Statement ["else" Statement]
| "while" "(" Expr ")" Statement
| "for" "(" [ForInit] ";" [Expr] ";" [ForUpdate] ")"
Statement
| "do" Statement "while" "(" Expr ")" ";"
| "switch" "(" Expr ")" "{" {SwitchGroup}
{SwitchLabel} "}"
| "break" [ident] ";"
| "continue" [ident] ";"
| "return" [Expr] ";"
| "synchronized" "(" Expr ")" Block
| "throw" Expr ";"
| "try" Block {CatchClause} ["finally" Block]
).
StatExpr = Assignment
| Designator "(" [ActPars] ")"
| Expr.
SwitchGroup = SwitchLabel {SwitchLabel} BlockStatement
{BlockStatement}.
SwitchLabel = "case" ConstExpr ":" | "default" ":".
ForInit = StatExpr {"," StatExpr}
| Type Var {"," Var} ";".
ForUpdate = StatExpr {"," StatExpr}.
CatchClause = "catch" "(" FormPar ")" Block.
ConstExpr = Expr.
Expr = CondExpr | Assignment.
CondExpr = CondOrExpr ["?" Expr ":" CondExpr].
CondOrExpr = CondAndExpr {"||" CondAndExpr}.
CondAndExpr = OrExpr {"&&" OrExpr}.
OrExpr = XorExpr {"|" XorExpr}.
XorExpr = AndExpr {"^" AndExpr}.
AndExpr = EqualExpr {"&" EqualExpr}.
EqualExpr = RelExpr {("==" | "!=") RelExpr}.
RelExpr = ShiftExpr {("<" | ">" | "<=" | ">=") ShiftExpr}
| ShiftExpr "instanceof" RefType.
ShiftExpr = AddExpr {("<<" | ">>" | ">>>") AddExpr}.
AddExpr = MulExpr {("+" | "-") MulExpr}.
MulExpr = Unary {("*" | "/" | "%") Unary}.
Unary = {"+" | "-" | "++" | "--" | "!" | "~"} Primary {"++" | "--"}.
Primary =
( Literal
| ident
| "this"
| "super"
| "(" Expr ")"
| "(" Type ")" Primary
| "new" ( PrimitiveType "[" Expr "]"
| Name ( "[" Expr "]" |
"(" [ActPars] ")" )
)
)
{ "." ident
| "[" [Expr] "]"
| "(" [ActPars] ")"
}.
ActPars = Expr {"," Expr}.
Assignment = Designator AssignOp Expr.
Designator = (ident | "this" | "super") {"." ident | "[" Expr "]"}.
AssignOp = "=" | "*=" | "/=" | "+=" | "-=" | "<<=" | ">>=" |
">>>="
| "&=" | "^=" | "|=".
Type = (PrimitiveType | Name) {"[" "]"}.
PrimitiveType = "byte " | "short" | "int" | "long" | "char"
| "float"| "double"
| "boolean".
RefType = Name {"[" "]"}
| PrimitiveType "[" "]" {"[" "]"}.
Name = {ident "."} ident.
Literal = number | string | char.
\ No newline at end of file
Ident = letter { letter | digit } .
QualIdent = { Ident "." } Ident .
Number = Integer | Real .
Integer = DecInteger | OctInteger | HexInteger .
DecInteger = digit { digit } .
OctInteger = ( "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" )
{ "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" } "B" .
HexInteger = digit { digit | "A" | "B" | "C" | "D" | "E" | "F" } "H" .
Real = digit { digit } "." { digit }
[ "E" [ "+" | "-" ] digit { digit } ] .
String = "'" { character } "'" | '"' { character } '"' | OctChar .
OctChar = ( "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" )
{ "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" } "C" .
ProgramModule = "MODULE" Ident [ Priority ] ";"
{ Import } Block "END" Ident "." .
Block = { Declaration } [ BEGIN StatementSequence ] .
Declaration = CONST { ConstDeclaration }
| TYPE { TypeDeclaration }
| VAR { VariableDeclaration }
| ProcedureDeclaration
| ModuleDeclaration .
StatementSequence = Statement { ";" Statement } .
Enumeration = "(" Ident { "," Ident } ")" .
Subrange = [ QualIdent ] "[" ConstExpr ".." ConstExpr "]" .
SetType = SET OF SimpleType .
SimpleType = QualIdent | Enumeration | Subrange .
ArrayType = ARRAY SimpleType { "," SimpleType } OF Type .
RecordType = "RECORD" FieldList { ";" FieldList } "END" .
FieldList = [ Ident { "," Ident } ":" Type
| VariantFieldList ] .
VariantFieldList = CASE [ Ident ] ":" QualIdent OF
( Variant { "|" Variant }
[ ELSE FieldList { ";" FieldList } ] END ) .
Variant = [ CaseLabelList ":" FieldList { ";" FieldList } ] .
CaseLabelList = ConstExpr [ ".." ConstExpr ]
{ "," ConstExpr [ ".." ConstExpr ] } .
PointerType = "POINTER" "TO" Type .
ConstantDeclaration = Ident "=" ConstExpr ";" .
ConstExpr = Expression .
TypeDeclaration = Ident "=" type .
Type = SetType | SimpleType | ArrayType | RecordType
| PointerType | ProcedureType .
VariableDeclaration = Ident { "," Ident } ":" Type ";" .
Designator = QualIdent { "^" | "." ident
| "[" Expression {"," Expression } "]" } .
Expression = SimpleExpression [ Relation SimpleExpression ] .
Relation = "="|"<>"|"#"|"<"|"<="|">"|">="|"IN".
SimpleExpression = [ "+" | "-" ] Term { ( "+" | "-" | "OR" ) Term } .
Term = Factor { MulOperator Factor } .
MulOperator = "*" | "/" | "DIV" | "MOD" | "AND" | "&" .
Factor = Designator [ "(" [ Expression { "," Expression } ] ")" ]
| Number
| String
| Set
| "(" expression ")"
| ( "NOT" | "~" ) Factor.
Set = [ QualIdent ] "{" [ Element { "," Element } ] "}" .
Element = Expression [ ".." Expression ] .
Statement = [ Assignment | IfStatement | CaseStatement |
WhileStatement | RepeatStatement | ForStatement | LoopStatement |
ExitStatement | WithStatement | ProcedureCall | ReturnStatement ] .
Assignment = Designator ":=" Expression .
IfStatement = "IF" Expression "THEN" StatementSequence
{ "ELSIF" Expression "THEN" StatementSequence }
[ "ELSE" StatementSequence ] "END" .
CaseStatement = "CASE" expression "OF"
[ CaseLabelList ":" StatementSequence ]
{ "|" [CaseLabelList ":" StatementSequence ] }
[ "ELSE" StatementSequence ] "END" .
WhileStatement = "WHILE" Expression "DO" StatementSequence "END" .
RepeatStatement = "REPEAT" StatementSequence "UNTIL" Expression .
ForStatement = "FOR" Ident ":=" Expression "TO" Expression
[ "BY" ConstExpression]
( "DO" StatementSequence "END" ) .
LoopStatement = "LOOP" StatementSequence "END" .
ExitStatement = "EXIT".
WithStatement = "WITH" Designator "DO" StatementSequence "END" .
ProcedureDeclaration = ProcedureHeading Block END Ident ";" .
ProcedureHeading = "PROCEDURE" ident [ FormalParameters ] ";" .
FormalParameters = "(" [ ParamSection { ";" ParamSection } ] ")"
[ ":" QualIdent ] .
ParamSection = [ "VAR" ] Ident { "," Ident } ":" FormalType .
FormalType = [ "ARRAY" "OF" ] QualIdent .
ProcedureCall = Designator [ "(" [ Expression {"," Expression} ] ")" ] .
ReturnStatement = RETURN [ Expression ] .
ProcedureType = "PROCEDURE" [ FormalTypeList ].
FormalTypeList = "(" [ [ "VAR" ] FormalType
{ "," [ "VAR" ] FormalType } ] ")" [ ":" QualIdent ] .
ModuleDeclaration = "MODULE" Ident [ Priority ] ";"
( { Import } [ Export ] )
Block "END" Ident ";" .
Import = [ "FROM" ident ] "IMPORT" Ident { "," Ident } ";" .
Export = "EXPORT" [ "QUALIFIED" ] Ident { "," Ident } ";" .
DefinitionModule = "DEFINITION" "MODULE" Ident ";"
{ Import } { Definition } "END" Ident "." .
Definition = "CONST" { ConstantDeclaration }
| "TYPE" { TypeDefinition }
| "VAR" { VariableDeclaration }
| ProcedureHeading.
TypeDefinition = Ident [ "=" Type ] ";" .
ImplementationModule = "IMPLEMENTATION" ProgramModule .
TypeTransfer = QualIdent "(" Expression ")" .
Priority = "[" ConstExpression "]" .
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>EBNF-Visualizer - Manual</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Pragma" content="no-cache">
<meta content="EBNF, GIF, Visualizer, Grafik, Syntax, Diagramm" name="keywords">
</head>
<body>
<h1>EBNF Visualizer - Manual</h1>
<h2>Content</h2>
<a href="#Introduction"> Introduction </a><br>
<a href="#Simple"> Simple example </a><br>
<a href="#EBNF"> EBNF - Extended Backus Naur Form</a><br>
<a href="#Writing"> Writing an .ebnf-file </a><br>
<a href="#Menu"> Menu </a><br>
<a href="#Functions"> Functions </a><br>
<a href="#License"> License & Copyright </a><br>
<a href="#Contact"> Contact </a><br>
<h2><a name="Introduction">Introduction</a></h2>
This program visualizes EBNF (Extended Backus Naur Form). Therefore an .ebnf File is required, which contains rules written in EBNF. The program parses the rules, visualizes them in form of syntax diagrams and is able to generate .gif files for further use. Furthermore the program allows to manipulate the look of the generated syntax diagrams.
<h2><a name="Simple">Simple example</a></h2>
<h3>Step 1:</h3>
Create a .ebnf file with a rule just like “A= a [b] c.”. A .ebnf file is just a simple .txt file, just change the ending of the file.
<h3>Step 2:</h3>
Start the program and open the .ebnf file via the menu entry “Load Grammar…”. The program parses it. If there exist errors in the .ebnf file, it would be reported in the log window. Otherwise the rule menu will be activated.<p><img src="open.JPG" alt="Open a .ebnf file">
<h3>Step 3:</h3>
Choose a rule from the loaded grammar in the rule menu. The chosen rule will be drawn.
<p><img src="choose.JPG" alt="Chose a rule">
<h3>Step 4 (optional):</h3>
Change the look of the syntax diagram in the menu File/Settings.
<p><img src="settings.JPG" alt="Settings">
<h3>Step 5 (optional):</h3>
Save the syntax diagram or just copy/paste it.
<h2><a name="EBNF">EBNF - Extended Backus Naur Form</a></h2>
EBNF is used to define the grammar of programming languages.
<br>Therefore a set of rules is specified. These are known as production rules.
They define the patterns or sequences of symbols allowed in the language. Each production rule defines the pattern that represents a named structured part of the language, such as an expression or a statement.
The name of such a part is called a non-terminal symbol in the language. The basic building blocks of the language are symbols which stand for themselves.
These can be individual characters or combinations such as keywords and arithmetic operators. These basic elements of the language are called terminal symbols.
<h2><a name="Writing">Writing an .ebnf-file</a></h2>
The following description is informal but will allow you to write EBNF that works with this program.<p>
A grammar consists of a set of rules. A rule consist of an identifier, followed by “=”, a sequence of meta, terminal and nonterminal symbols and ends with “.” (e.g. “A= a b [c].”)
<h3>Terminal symbol:</h3>
A terminal symbol can be any string. They are separated by space characters. <br>For example in the rule “A = a b [c].” a, b and c are terminal symbols.
<p><img src="terminal.GIF" alt="Simple example"><p>
It is also possible to put a terminal symbol under quotes (“) or apostrophes (‘) which is required in some cases.
(eg. Quote = "'" a "'".)<p>
<img src="Quote.GIF" alt="Simple example"><p>It’s also needed for numbers, because identifiers must begin with a character.
<h3>Nonterminal symbol:</h3>
A nonterminal symbol can’t be created in an explicit way.<br>If a terminal symbol matches the string of an rule identifier, it is automatically considered as a nonterminal symbol.<br>
For example, in the rule “A = a A | b.” A is a nonterminal symbol.
<p><img src="nonterminal.GIF" alt="Simple example">
<h3>Meta symbols:</h3>
<h4>- option “[“ “]”</h4>
The sequence of symbols within these brackets are optional.<br>
(e.g. Rule1 = “begin [optional things] end.”)
<p><img src="Rule1.GIF" alt="Simple example">
<h4>-iteration “{“ “}”</h4>
The sequence of symbols within these brackets can occur from zero to infinite times.<br>
(e.g. Rule2 = “begin {and again} end.”)
<p><img src="Rule2.GIF" alt="Simple example">
<h4>-alternative “|”</h4>
It allows to choose a sequence of symbols.<br>
(e.g. Rule3 = “I am a (good | bad) programmer.”)
<p><img src="Rule3.GIF" alt="Simple example">
<h4>-grouping “(“ “)”</h4>
These brackets are used to group sequences of symbols in a mathematical way.
<h3>Special symbol – Line break:</h3>
This program allows to make explicit line breaks within a syntax diagram. To do this, use “\n” in the outer structure of the rule. That means, it will be ignored within an option, iteration or alternative.<br>
(e.g. “Linebreak = First line \n Second line \n End.”)
<p><img src="Linebreak.GIF" alt="Simple example">
<h2><a name="Menu">Menu</a></h2>
<p><img src="open.JPG" alt="Menu">
<h3>File:</h3>
<h4>Load Grammar… :</h4>
Allows to load a grammar file (*.ebnf).
<h4>Save As… :</h4>
The current rule can be stored as .GIF file.
<h4>Copy:</h4>
The current rule is copied to the clipboard as a picture. It is possible to paste it into any program which allows to paste from the clipboard.
<h4>Settings… :</h4>
<p><img src="settings.JPG" alt="Settings"><br>
In the menu settings the look of the syntax diagrams can be changed.
<h5>Font</h5>
Change the font of terminal and nonterminal symbols.
<h5>Line</h5>
Change the thickness and the color of the line. It is also possible to increase or decrease the size of the arrows.
<h5>Dimensions</h5>
It is possible to increase or decrease the horizontal and vertical gap between the symbols.
The look of the terminal and nonterminal symbols can be changed by increasing or decreasing the gap between the line of the symbol and its name.
<h5>Optimizations</h5>
If the checkbox "Enable optimizations" is activated, the syntaxgraph will be optimized. Any change of this option requires to reload the actual grammar.
<h2><a name="Functions">Functions</a></h2>
<h3>Optimizations:</h3>
This happens implicitly. It is possible to disable them in the settings menu.<br>
If the syntax graph is optimized, redundant und needless productions within a rule are deleted. That means empty nodes, iterations, options and alternatives are removed. If there is an empty alternative, it is moved to the first position. Already existing alternatives are removed.
Furthermore some productions are visualized in a more elegant way,
<br> for example “A = ab {ab}.”
<p><img src="optimize1not.GIF" alt="Optimize"><img src="optimize1.GIF" alt="Optimize"><p>
or “B = ab { cd ab}.”
<p><img src="optimize2not.GIF" alt="Optimize"><img src="optimize2.GIF" alt="Optimize"><p>
<h2><a name="License">License & Copyright</a></h2>
EBNF Visualizer<br>
Copyright (c) 2005 Stefan Schoergenhumer, Markus Dopler<br>
supported by Hanspeter Moessenboeck, University of Linz<br>
<p>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
<p>
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
<p>
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<h2><a name="Contact">Contact</a></h2>
For further questions, please write an Email to:<p>
Markus Dopler, k0156207@students.jku.at or<br>
Stefan Schörgenhumer, k0155531@students.jku.at
</body>
</html>
COMPILER EBNF
CHARACTERS
letter = 'A'..'Z' + 'a'..'z' + '_'.
digit = '0'..'9'.
importantascii = ' '..'~' .
noquote = importantascii - '"'.
noapostrophe = importantascii - '\''.
TOKENS
ident = letter {letter | digit}.
terminal = '"' {noquote} '"' | '\'' {noapostrophe} '\''.
wrap = '\\' 'n'.
IGNORE '\t' + '\r' + '\n'
PRODUCTIONS
EBNF
= Rule
{Rule}.
Rule
= ident (. Node n;
Symbol s=Symbol.Find(t.val); //look if already known
if(s==null) n=new Node(new Symbol(Node.nt,t.val));
else {
if(s.typ==Node.nt) {
String message="ERROR: Nonterminal symbol "+t.val+" has been defined multiple times.";
EbnfForm.WriteLine(message);
n=new Node(new Symbol(0,"BUG"));
} else { //if only considered as terminal symbol until now
s.typ=Node.nt;
Symbol.terminalToNt(s.name);
Symbol.terminalToNt(s.name);
Node.terminalToNt(s.name);
n=Node.Find(s.name);
}
}
.)
"="
Expr <out n.sym.graph>
"."
(. Graph.Finish(n.sym.graph); .)
.
Expr <out Graph g>
= (. Graph g1; .)
Alt <out g>
(. bool first = true; .)
{ '|'
Alt <out g1>
(. if (first) { Graph.MakeFirstAlt(g); first = false; }
Graph.MakeAlternative(g, g1);
.)
}
.
Alt <out Graph g>
=
(. Graph g1; g=new Graph(); .)
{Sym <out g1>
(. Graph.MakeSequence(g, g1); .)
}
(. if(g.l==null && g.r==null)
g=new Graph(new Node(Node.eps,null));
.)
.
Sym <out Graph g>
(. Graph g1;g=new Graph(); .)
=
ident (. Symbol s=Symbol.Find(t.val);
Node n;
if(s!=null) n= new Node(s);
else n=new Node(new Symbol(Node.t,t.val)); //type could be nt, but not known yet
g=new Graph(n);
.)
| terminal (.
char[] trim=new char[1];
trim[0]=t.val[0];
String temp=t.val.Trim(trim);
Node n =new Node(new Symbol(Node.t,temp));
g=new Graph(n);
.)
| wrap (.
Node n =new Node(Node.wrap,null);
g=new Graph(n);
.)
| '(' Expr <out g1>')'
(. g=g1; .)
| '[' Expr <out g1>']'
(. Graph.MakeOption(g1);
g=g1;
.)
| '{' Expr <out g1>'}'
(. Graph.MakeIteration(g1);
g=g1;
.)
.
END EBNF.
Scanner.cs and Parser.cs have been generated by the Compiler Generator Coco/R.
The file EBNF.ATG contains the attributed grammar for the Coco.
See: http://www.ssw.uni-linz.ac.at/Research/Projects/Coco/
\ No newline at end of file
/*-------------------------------------------------------------------------
EBNF Visualizer
Copyright (c) 2005 Stefan Schoergenhumer, Markus Dopler
supported by Hanspeter Moessenboeck, University of Linz
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-------------------------------------------------------------------------*/
using System;
using System.IO;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Drawing.Imaging;
public class EbnfForm : System.Windows.Forms.Form {
private MainMenu mainMenu = new MainMenu();
private MenuItem menuItemFile = new MenuItem();
private MenuItem menuItemRules = new MenuItem();
private MenuItem menuItemHelp = new MenuItem();
private MenuItem menuItemLoad = new MenuItem();
private MenuItem menuItemSave = new MenuItem();
private MenuItem menuItemCopy = new MenuItem();
private MenuItem menuItemSettings = new MenuItem();
private MenuItem menuItemExit = new MenuItem();
private MenuItem menuItemHelpLink = new MenuItem();
private MenuItem menuItemAbout = new MenuItem();
private Label labelEbnf = new Label();
private static TextBox textBoxOutput = new TextBox();
private static Bitmap DrawArea = new Bitmap(1,1,System.Drawing.Imaging.PixelFormat.Format24bppRgb); // make a persistent drawing area
private Symbol currentSymbol = null;
public static Graphics BitmapGraphics {
get {
return Graphics.FromImage(DrawArea);
}
}
public static Bitmap Drawarea {
set {
DrawArea=value;
InitializeDrawArea();
}
}
public EbnfForm() {
InitializeComponent();
}
///////////////////////////////////////////////////////////////////////////////
//-----------Init main form and menu-------------------------------------------
///////////////////////////////////////////////////////////////////////////////
private void InitializeComponent() {
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(800, 600);
this.StartPosition = FormStartPosition.CenterScreen;
this.Text = "EBNF Visualizer";
this.Name = "EBNF Visualizer";
this.Paint += new PaintEventHandler(component_paint);
this.BackColor=Color.White;
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form_MouseDown);
menuItemFile.Text = "File";
menuItemRules.Text = "Rules";
menuItemHelp.Text = "Help";
menuItemLoad.Text = "Load Grammar...";
menuItemSave.Text = "Save as...";
menuItemCopy.Text = "Copy";
menuItemSettings.Text = "Settings...";
menuItemExit.Text = "Exit";
menuItemHelpLink.Text = "Help...";
menuItemAbout.Text = "About...";
menuItemSave.Enabled=false;
menuItemCopy.Enabled=false;
menuItemRules.Enabled=false;
menuItemCopy.Shortcut=Shortcut.CtrlC;
menuItemFile.MenuItems.Add(menuItemLoad);
menuItemFile.MenuItems.Add(menuItemSave);
menuItemFile.MenuItems.Add(menuItemCopy);
menuItemFile.MenuItems.Add(new MenuItem("-"));
menuItemFile.MenuItems.Add(menuItemSettings);
menuItemFile.MenuItems.Add(new MenuItem("-"));
menuItemFile.MenuItems.Add(menuItemExit);
menuItemHelp.MenuItems.Add(menuItemHelpLink);
menuItemHelp.MenuItems.Add(new MenuItem("-"));
menuItemHelp.MenuItems.Add(menuItemAbout);
mainMenu.MenuItems.Add(menuItemFile);
mainMenu.MenuItems.Add(menuItemRules);
mainMenu.MenuItems.Add(menuItemHelp);
textBoxOutput.ScrollBars = ScrollBars.Vertical;
textBoxOutput.Size=new Size(ClientSize.Width,100);
textBoxOutput.Multiline=true;
textBoxOutput.Location=new Point(0,ClientSize.Height-100);
this.Controls.Add(textBoxOutput);
menuItemLoad.Click+= new System.EventHandler(this.menuItemLoad_Click);
menuItemExit.Click+= new System.EventHandler(this.menuItemExit_Click);
menuItemSettings.Click+= new System.EventHandler(this.menuItemSettings_Click);
menuItemAbout.Click+= new System.EventHandler(this.menuItemAbout_Click);
menuItemSave.Click+= new System.EventHandler(this.menuItemSave_Click);
menuItemCopy.Click+= new System.EventHandler(this.menuItemCopy_Click);
SizeChanged+= new System.EventHandler(this.size_Changed);
menuItemHelpLink.Click+=new System.EventHandler(this.menuItemHelpLink_Click);
this.Menu = mainMenu;
}
///////////////////////////////////////////////////////////////////////////////
//-----------Main Form and Menu Event Handler----------------------------------
///////////////////////////////////////////////////////////////////////////////
private void size_Changed(object sender, System.EventArgs e) {
textBoxOutput.Size=new Size(ClientSize.Width,100);
textBoxOutput.Location=new Point(0,ClientSize.Height-100);
this.drawGrammar();
}
private void menuItemLoad_Click(object sender, System.EventArgs e) {
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Ebnf files (*.ebnf)|*.ebnf" ;
ofd.FilterIndex = 1;
ofd.RestoreDirectory = true;
if(ofd.ShowDialog() == DialogResult.OK) {
this.LoadFile(ofd.FileName);
menuItemSave.Enabled=false;
menuItemCopy.Enabled=false;
}
}
private void menuItemHelpLink_Click(object sender, System.EventArgs e) {
try {
System.Diagnostics.Process.Start("manual.html");
} catch {
EbnfForm.WriteLine("Help named manual.html was not found!");
}
}
private void menuItemSettings_Click(object sender, System.EventArgs e) {
this.CreateMySettingsForm();
}
private void menuItemAbout_Click(object sender, System.EventArgs e) {
this.CreateMyAboutForm();
}
private void menuItemExit_Click(object sender, System.EventArgs e) {
this.Close();
}
private void shortload_Click(object sender, System.EventArgs e) {
MenuItem temp=(MenuItem) sender;
LoadGrammar(temp.Text);
}
// save drawing in bitmap DrawArea as a jpeg file
private void menuItemSave_Click(object sender, System.EventArgs e) {
ImageFormat format = ImageFormat.Gif;
SaveFileDialog sfd = new SaveFileDialog();
if(currentSymbol!=null)
sfd.FileName=currentSymbol.name;
sfd.Filter = "GIF Files(*.GIF)|*.GIF|Windows Metafile (*.EMF)|*.EMF";
if (sfd.ShowDialog() == DialogResult.OK) {
if(sfd.FileName.EndsWith(".EMF")) {
saveEmf(sfd.FileName);
} else {
DrawArea.Save(sfd.FileName, format );
}
EbnfForm.WriteLine("Rule " + currentSymbol.name + " saved to "+sfd.FileName+".");
}
sfd.Dispose();
}
private void saveEmf(String path) {
FileStream fs = new FileStream(path,FileMode.Create );
Graphics g = CreateGraphics();
IntPtr hDC = g.GetHdc();
Metafile m = new Metafile( fs, hDC );
g.ReleaseHdc( hDC );
g.Dispose();
Graphics vg= Graphics.FromImage(m);
Node.drawComponent(currentSymbol, vg);
vg.Dispose();
m.Dispose();
fs.Close();
}
// copy current symbol picture to clipboard
private void menuItemCopy_Click(object sender, System.EventArgs e) {
EbnfForm.WriteLine("Rule " + currentSymbol.name + " copied to clipboard.");
Clipboard.SetDataObject(DrawArea,true);
}
///////////////////////////////////////////////////////////////////////////////
//-----------Settings menu form + eventhandler---------------------------------
///////////////////////////////////////////////////////////////////////////////
private Form form1 = new Form();
private Button buttonOk ;
private Button buttonCancel ;
private Button buttonChangeFont ;
private Button buttonApply ;
private Button buttonLineColor ;
private Button buttonLineMore ;
private Button buttonLineLess ;
private Button buttonArrowMore ;
private Button buttonArrowLess ;
private Button buttonHorizontalMore ;
private Button buttonHorizontalLess ;
private Button buttonVerticalMore ;
private Button buttonVerticalLess ;
private Button buttonSymbolSizeMore ;
private Button buttonSymbolSizeLess ;
private Button buttonRestoreDefault ;
private Label labelFont ;
private Label labelLineColor ;
private Label labelGapHeight ;
private Label labelGapWidth ;
private Label labelLineThickness ;
private Label labelArrowSize ;
private Label labelSymbolSize ;
private FontDialog fontDialog1 ;
private ColorDialog colorDialog1 ;
private TabPage tabPageFont ;
private TabPage tabPageLine ;
private TabPage tabPageDimensions ;
private TabPage tabPageOptimization ;
private TabControl tabControl ;
private GroupBox groupBoxTandNT ;
private GroupBox groupBoxThickness ;
private GroupBox groupBoxArrow ;
private GroupBox groupBoxLineColor ;
private GroupBox groupBoxHorizontal ;
private GroupBox groupBoxVertical ;
private GroupBox groupBoxSymbolSize ;
private GroupBox groupBoxOptimization ;
private CheckBox checkBoxOptimization ;
public void CreateMySettingsForm() {
buttonOk = new Button();
buttonCancel = new Button();
buttonChangeFont = new Button();
buttonApply = new Button();
buttonLineColor = new Button();
buttonLineMore = new Button();
buttonLineLess = new Button();
buttonArrowMore = new Button();
buttonArrowLess = new Button();
buttonHorizontalMore = new Button();
buttonHorizontalLess = new Button();
buttonVerticalMore = new Button();
buttonVerticalLess = new Button();
buttonSymbolSizeLess = new Button();
buttonSymbolSizeMore = new Button();
buttonRestoreDefault = new Button();
labelFont = new Label();
labelLineColor = new Label();
labelGapHeight = new Label();
labelGapWidth = new Label();
labelLineThickness = new Label();
labelArrowSize = new Label();
labelSymbolSize = new Label();
fontDialog1 = new FontDialog();
colorDialog1 = new ColorDialog();
tabPageFont = new TabPage();
tabPageLine = new TabPage();
tabPageDimensions = new TabPage();
tabPageOptimization = new TabPage();
tabControl = new TabControl();
groupBoxTandNT = new GroupBox();
groupBoxThickness = new GroupBox();
groupBoxArrow = new GroupBox();
groupBoxLineColor = new GroupBox();
groupBoxHorizontal = new GroupBox();
groupBoxVertical = new GroupBox();
groupBoxSymbolSize = new GroupBox();
groupBoxOptimization = new GroupBox();
checkBoxOptimization = new CheckBox();
form1.Text = "Settings";
form1.FormBorderStyle = FormBorderStyle.FixedDialog;
form1.MaximizeBox = false;
form1.MinimizeBox = false;
form1.AcceptButton = buttonOk;
form1.CancelButton = buttonCancel;
form1.StartPosition = FormStartPosition.CenterScreen;
checkBoxOptimization.Checked = Node.OptimizeGraph;
buttonCancel.Text = "Cancel";
buttonOk.Text = "OK";
buttonChangeFont.Text = "Change font...";
buttonApply.Text = "Apply";
buttonLineMore.Text = ">";
buttonLineLess.Text = "<";
buttonArrowMore.Text = ">";
buttonArrowLess.Text = "<";
buttonHorizontalMore.Text= ">";
buttonHorizontalLess.Text= "<";
buttonVerticalMore.Text = ">";
buttonVerticalLess.Text = "<";
buttonSymbolSizeMore.Text= ">";
buttonSymbolSizeLess.Text= "<";
buttonLineColor.Text = "Change color...";
buttonRestoreDefault.Text= "Restore default settings";
labelFont.Text = Node.CharFont.Name;
labelGapHeight.Text = Convert.ToString(Node.ComponentGapHeight);
labelGapWidth.Text = Convert.ToString(Node.ComponentGapWidth-26);
tabPageFont.Text = "Font";
tabPageLine.Text = "Line";
tabPageDimensions.Text = "Dimensions";
tabPageOptimization.Text = "Optimizations";
groupBoxTandNT.Text = "Terminal and nonterminal symbols";
groupBoxThickness.Text = "Thickness";
groupBoxArrow.Text = "Size of Arrow";
groupBoxLineColor.Text = "Color";
groupBoxHorizontal.Text = "Horizontal";
groupBoxVertical.Text = "Vertical";
groupBoxSymbolSize.Text = "Gap between symbolline and font (vertical)";
groupBoxOptimization.Text= "Optimization";
labelLineThickness.Text = Convert.ToString(Node.LinePen.Width);
labelArrowSize.Text = Convert.ToString(Node.ArrowSize);
labelSymbolSize.Text = Convert.ToString(Node.SymbolGapHeight);
checkBoxOptimization.Text= "Enable optimizations (reload required)";
labelFont.Font = Node.CharFont;
labelFont.ForeColor = Node.CharColor;
labelFont.BackColor = Color.White;
labelFont.TextAlign = ContentAlignment.MiddleCenter;
if(Node.LinePen.Width<=1) buttonLineLess.Enabled = false;
if(Node.SymbolGapHeight<=0) buttonSymbolSizeLess.Enabled = false;
if(Node.ArrowSize<=1) buttonArrowLess.Enabled = false;
if(Node.ComponentGapHeight<=0) buttonVerticalLess.Enabled = false;
if(Node.ComponentGapWidth<=26) buttonHorizontalLess.Enabled = false;
labelLineThickness.Font = new Font("Times",12);
labelLineThickness.TextAlign = ContentAlignment.MiddleCenter;
labelArrowSize.Font = new Font("Times",12);
labelArrowSize.TextAlign = ContentAlignment.MiddleCenter;
labelGapHeight.Font = new Font("Times",12);
labelGapHeight.TextAlign = ContentAlignment.MiddleCenter;
labelGapWidth.Font = new Font("Times",12);
labelGapWidth.TextAlign = ContentAlignment.MiddleCenter;
labelSymbolSize.Font = new Font("Times",12);
labelSymbolSize.TextAlign = ContentAlignment.MiddleCenter;
labelLineColor.BackColor=Node.LinePen.Color;
buttonLineColor.Size = new Size(100,20);
buttonLineMore.Size = new Size(20,20);
buttonLineLess.Size = new Size(20,20);
buttonArrowMore.Size = new Size(20,20);
buttonArrowLess.Size = new Size(20,20);
buttonHorizontalMore.Size= new Size(20,20);
buttonHorizontalLess.Size= new Size(20,20);
buttonVerticalMore.Size = new Size(20,20);
buttonVerticalLess.Size = new Size(20,20);
buttonSymbolSizeMore.Size= new Size(20,20);
buttonSymbolSizeLess.Size= new Size(20,20);
buttonChangeFont.Size = new Size(90,20);
buttonRestoreDefault.Size= new Size(150,20);
tabControl.Size = new Size(form1.Size.Width-15, form1.Size.Height-150);
groupBoxTandNT.Size = new Size(tabControl.Size.Width-30, groupBoxTandNT.Size.Height);
groupBoxThickness.Size = new Size(100, 50);
groupBoxArrow.Size = new Size(100, 50);
groupBoxHorizontal.Size = new Size(100, 50);
groupBoxVertical.Size = new Size(100, 50);
groupBoxOptimization.Size= new Size(tabControl.Size.Width-30, 50);
groupBoxLineColor.Size = new Size(155, 50);
groupBoxSymbolSize.Size = new Size(tabControl.Size.Width-30, 50);
labelLineColor.Size = new Size(20,20);
labelFont.Size = new Size(groupBoxTandNT.Size.Width-20,40);
checkBoxOptimization.Size= new Size(220, 20);
groupBoxTandNT.Location = new Point (10,10);
groupBoxThickness.Location = new Point (10,10);
groupBoxArrow.Location = new Point (10,groupBoxThickness.Height+10);
groupBoxLineColor.Location = new Point (110,10);
groupBoxHorizontal.Location = new Point (10,10);
groupBoxVertical.Location = new Point (110,10);
groupBoxOptimization.Location = new Point (10,10);
groupBoxSymbolSize.Location = new Point (10,groupBoxVertical.Height+10);
labelFont.Location = new Point (10,20);
buttonOk.Location = new Point (20, 220);
buttonApply.Location = new Point (buttonOk.Left+buttonOk.Width+10, 220);
buttonCancel.Location = new Point (buttonApply.Left+buttonApply.Width+20, 220);
tabControl.Location = new Point (5,5);
buttonChangeFont.Location = new Point (tabControl.Right-buttonChangeFont.Size.Width-45,labelFont.Top+labelFont.Height+10);
buttonLineLess.Location = new Point (10,20);
buttonLineMore.Location = new Point (buttonLineLess.Right+40, buttonLineLess.Top);
buttonArrowLess.Location = new Point (10,20);
buttonArrowMore.Location = new Point (buttonLineLess.Right+40, buttonLineLess.Top);
buttonHorizontalLess.Location = new Point (10,20);
buttonHorizontalMore.Location = new Point (buttonHorizontalLess.Right+40, buttonHorizontalLess.Top);
buttonVerticalLess.Location = new Point (10,20);
buttonVerticalMore.Location = new Point (buttonVerticalLess.Right+40, buttonVerticalLess.Top);
buttonSymbolSizeLess.Location = new Point (10,20);
buttonSymbolSizeMore.Location = new Point (buttonSymbolSizeLess.Right+40, buttonSymbolSizeLess.Top);
buttonRestoreDefault.Location = new Point ((tabControl.Size.Width-buttonRestoreDefault.Size.Width)/2, tabControl.Bottom+20);
labelLineThickness.Location = new Point (buttonLineLess.Right,buttonLineLess.Top);
labelArrowSize.Location = new Point (buttonArrowLess.Right,buttonArrowLess.Top);
labelGapHeight.Location = new Point (buttonHorizontalLess.Right,buttonHorizontalLess.Top);
labelGapWidth.Location = new Point (buttonVerticalLess.Right,buttonVerticalLess.Top);
labelSymbolSize.Location = new Point (buttonSymbolSizeLess.Right,buttonSymbolSizeLess.Top);
labelLineColor.Location = new Point (10,20);
buttonLineColor.Location = new Point (labelLineColor.Right+10,20);
checkBoxOptimization.Location = new Point (10,20);
labelLineThickness.Size = new Size (buttonLineMore.Left-buttonLineLess.Right,buttonLineLess.Height);
labelArrowSize.Size = new Size (buttonArrowMore.Left-buttonArrowLess.Right,buttonArrowLess.Height);
labelGapHeight.Size = new Size (buttonHorizontalMore.Left-buttonHorizontalLess.Right,buttonHorizontalLess.Height);
labelGapWidth.Size = new Size (buttonVerticalMore.Left-buttonVerticalLess.Right,buttonVerticalLess.Height);
labelSymbolSize.Size = new Size (buttonSymbolSizeMore.Left-buttonSymbolSizeLess.Right,buttonSymbolSizeLess.Height);
groupBoxTandNT.Controls.Add(buttonChangeFont);
groupBoxTandNT.Controls.Add(labelFont);
groupBoxHorizontal.Controls.Add(labelGapWidth);
groupBoxVertical.Controls.Add(labelGapHeight);
groupBoxThickness.Controls.Add(buttonLineMore);
groupBoxThickness.Controls.Add(buttonLineLess);
groupBoxThickness.Controls.Add(labelLineThickness);
groupBoxLineColor.Controls.Add(buttonLineColor);
groupBoxLineColor.Controls.Add(labelLineColor);
groupBoxArrow.Controls.Add(buttonArrowMore);
groupBoxArrow.Controls.Add(buttonArrowLess);
groupBoxArrow.Controls.Add(labelArrowSize);
groupBoxHorizontal.Controls.Add(buttonHorizontalLess);
groupBoxHorizontal.Controls.Add(buttonHorizontalMore);
groupBoxVertical.Controls.Add(buttonVerticalLess);
groupBoxVertical.Controls.Add(buttonVerticalMore);
groupBoxSymbolSize.Controls.Add(buttonSymbolSizeMore);
groupBoxSymbolSize.Controls.Add(buttonSymbolSizeLess);
groupBoxSymbolSize.Controls.Add(labelSymbolSize);
groupBoxOptimization.Controls.Add(checkBoxOptimization);
tabPageFont.Controls.Add(groupBoxTandNT);
tabPageLine.Controls.Add(groupBoxThickness);
tabPageLine.Controls.Add(groupBoxLineColor);
tabPageLine.Controls.Add(groupBoxArrow);
tabPageDimensions.Controls.Add(groupBoxSymbolSize);
tabPageDimensions.Controls.Add(groupBoxHorizontal);
tabPageDimensions.Controls.Add(groupBoxVertical);
tabPageOptimization.Controls.Add(groupBoxOptimization);
tabControl.Controls.Add(this.tabPageFont);
tabControl.Controls.Add(this.tabPageLine);
tabControl.Controls.Add(this.tabPageDimensions);
tabControl.Controls.Add(this.tabPageOptimization);
form1.Controls.Add(this.tabControl);
form1.Controls.Add(buttonOk);
form1.Controls.Add(buttonCancel);
form1.Controls.Add(buttonApply);
form1.Controls.Add(buttonRestoreDefault);
buttonOk.Click += new System.EventHandler(this.buttonOk_Click);
buttonChangeFont.Click += new System.EventHandler(this.buttonChangeFont_Click);
buttonApply.Click += new System.EventHandler(this.buttonApply_Click);
buttonLineColor.Click += new System.EventHandler(this.buttonLineColor_Click);
buttonLineMore.Click += new System.EventHandler(this.buttonLineMore_Click);
buttonLineLess.Click += new System.EventHandler(this.buttonLineLess_Click);
buttonArrowMore.Click += new System.EventHandler(this.buttonArrowMore_Click);
buttonArrowLess.Click += new System.EventHandler(this.buttonArrowLess_Click);
buttonHorizontalMore.Click += new System.EventHandler(this.buttonHorizontalMore_Click);
buttonHorizontalLess.Click += new System.EventHandler(this.buttonHorizontalLess_Click);
buttonVerticalMore.Click += new System.EventHandler(this.buttonVerticalMore_Click);
buttonVerticalLess.Click += new System.EventHandler(this.buttonVerticalLess_Click);
buttonSymbolSizeMore.Click += new System.EventHandler(this.buttonSymbolSizeMore_Click);
buttonSymbolSizeLess.Click += new System.EventHandler(this.buttonSymbolSizeLess_Click);
buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click);
buttonRestoreDefault.Click += new System.EventHandler(this.buttonRestoreDefault_Click);
form1.ShowDialog();
}
// change the color of the line
private void buttonLineColor_Click(object sender, System.EventArgs e) {
colorDialog1.Color = Node.LinePen.Color;
if(colorDialog1.ShowDialog() != DialogResult.Cancel ) {
labelLineColor.BackColor = colorDialog1.Color ;
}
}
// increase the size of the line
private void buttonLineMore_Click(object sender, System.EventArgs e) {
Node.LinePen.Width+=2;
labelLineThickness.Text = Convert.ToString(Node.LinePen.Width);
buttonLineLess.Enabled = true;
}
// decrease the size of the line
private void buttonLineLess_Click(object sender, System.EventArgs e) {
if(Node.LinePen.Width-2>0)
Node.LinePen.Width-=2;
if(Node.LinePen.Width==1)
buttonLineLess.Enabled = false;
labelLineThickness.Text = Convert.ToString(Node.LinePen.Width);
}
// increase the horizontal dimension
private void buttonHorizontalMore_Click(object sender, System.EventArgs e) {
Node.ComponentGapWidth+=2;
labelGapWidth.Text = Convert.ToString(Node.ComponentGapWidth-26);
buttonHorizontalLess.Enabled = true;
}
// decrease the horizonal dimension
private void buttonHorizontalLess_Click(object sender, System.EventArgs e) {
if(Node.ComponentGapWidth-2>=0)
Node.ComponentGapWidth-=2;
if(Node.ComponentGapWidth<27)
buttonHorizontalLess.Enabled = false;
labelGapWidth.Text = Convert.ToString(Node.ComponentGapWidth-26);
}
// increase the gap between the symbolline and the font
private void buttonSymbolSizeMore_Click(object sender, System.EventArgs e) {
Node.SymbolGapHeight+=1;
labelSymbolSize.Text = Convert.ToString(Node.SymbolGapHeight);
buttonSymbolSizeLess.Enabled = true;
}
// decrease the gap between the symbolline and the font
private void buttonSymbolSizeLess_Click(object sender, System.EventArgs e) {
if(Node.SymbolGapHeight-1>=0)
Node.SymbolGapHeight-=1;
if(Node.SymbolGapHeight<=0)
buttonSymbolSizeLess.Enabled = false;
labelSymbolSize.Text = Convert.ToString(Node.SymbolGapHeight);
}
// increase the vertical dimension
private void buttonVerticalMore_Click(object sender, System.EventArgs e) {
Node.ComponentGapHeight+=2;
labelGapHeight.Text = Convert.ToString(Node.ComponentGapHeight);
buttonVerticalLess.Enabled = true;
}
// decrease the vertical dimension
private void buttonVerticalLess_Click(object sender, System.EventArgs e) {
if(Node.ComponentGapHeight-2>=0)
Node.ComponentGapHeight-=2;
if(Node.ComponentGapHeight<1)
buttonVerticalLess.Enabled = false;
labelGapHeight.Text = Convert.ToString(Node.ComponentGapHeight);
}
// increase the arrowsize
private void buttonArrowMore_Click(object sender, System.EventArgs e) {
Node.ArrowSize+=1;
labelArrowSize.Text = Convert.ToString(Node.ArrowSize);
buttonArrowLess.Enabled = true;
}
// decrease the arrowsize
private void buttonArrowLess_Click(object sender, System.EventArgs e) {
if(Node.ArrowSize-1>0)
Node.ArrowSize-=1;
if(Node.ArrowSize==1)
buttonArrowLess.Enabled = false;
labelArrowSize.Text = Convert.ToString(Node.ArrowSize);
}
// change the font of t and nt symbols
private void buttonChangeFont_Click(object sender, System.EventArgs e) {
fontDialog1.ShowColor = true;
fontDialog1.Font = labelFont.Font;
fontDialog1.Color = labelFont.ForeColor;
if(fontDialog1.ShowDialog() != DialogResult.Cancel ) {
labelFont.Font = fontDialog1.Font ;
labelFont.ForeColor = fontDialog1.Color;
labelFont.Text = fontDialog1.Font.Name;
}
}
// use the default settings
private void buttonRestoreDefault_Click(object sender, System.EventArgs e) {
Node.restoreDefaultSettings();
labelFont.Text = Node.CharFont.Name;
labelFont.Font = Node.CharFont;
labelFont.ForeColor = Node.CharColor;
labelLineColor.BackColor = Node.LinePen.Color;
labelGapHeight.Text = Convert.ToString(Node.ComponentGapHeight);
labelGapWidth.Text = Convert.ToString(Node.ComponentGapWidth-26);
labelLineThickness.Text = Convert.ToString(Node.LinePen.Width);
labelArrowSize.Text = Convert.ToString(Node.ArrowSize);
labelSymbolSize.Text = Convert.ToString(Node.SymbolGapHeight);
checkBoxOptimization.Checked= true;
if(Node.LinePen.Width<=1) buttonLineLess.Enabled = false; else buttonLineLess.Enabled = true;
if(Node.SymbolGapHeight<=0) buttonSymbolSizeLess.Enabled = false; else buttonSymbolSizeLess.Enabled = true;
if(Node.ArrowSize<=1) buttonArrowLess.Enabled = false; else buttonArrowLess.Enabled = true;
if(Node.ComponentGapHeight<=0) buttonVerticalLess.Enabled = false; else buttonVerticalLess.Enabled = true;
if(Node.ComponentGapWidth<=26) buttonHorizontalLess.Enabled = false; else buttonHorizontalLess.Enabled = true;
this.drawGrammar();
}
// accept the settings and close the settingsform
private void buttonOk_Click(object sender, System.EventArgs e) {
Node.CharFont = labelFont.Font;
Node.CharColor = labelFont.ForeColor;
Node.ComponentGapHeight = Convert.ToInt16(labelGapHeight.Text);
Node.ComponentGapWidth = Convert.ToInt16(labelGapWidth.Text)+26;
Node.LinePen.Width = Convert.ToInt16(labelLineThickness.Text);
Node.LinePen.Color = labelLineColor.BackColor;
Node.OptimizeGraph = checkBoxOptimization.Checked;
this.drawGrammar();
form1.Close();
form1.Dispose();
form1=new Form();
}
// discard the settings and close the form
private void buttonCancel_Click(object sender, System.EventArgs e) {
this.drawGrammar();
form1.Close();
form1.Dispose();
form1=new Form();
}
// accept the settings but the settingsform isn't closed
private void buttonApply_Click(object sender, System.EventArgs e) {
Node.CharFont = labelFont.Font;
Node.CharColor = labelFont.ForeColor;
Node.ComponentGapHeight = Convert.ToInt16(labelGapHeight.Text);
Node.ComponentGapWidth = Convert.ToInt16(labelGapWidth.Text)+26;
Node.LinePen.Width = Convert.ToInt16(labelLineThickness.Text);
Node.LinePen.Color = labelLineColor.BackColor;
Node.OptimizeGraph = checkBoxOptimization.Checked;
this.drawGrammar();
}
///////////////////////////////////////////////////////////////////////////////
//-----------About menu form + eventhandler------------------------------------
///////////////////////////////////////////////////////////////////////////////
private Form about = new Form();
private GroupBox gp = new GroupBox();
private Label info = new Label();
private Button aboutOk = new Button();
public void CreateMyAboutForm() {
about.Text = "About";
about.FormBorderStyle = FormBorderStyle.FixedDialog;
about.MaximizeBox = false;
about.MinimizeBox = false;
about.AcceptButton = aboutOk;
about.StartPosition = FormStartPosition.CenterScreen;
about.Size = new Size(250,250);
aboutOk.Text = "OK";
aboutOk.Location = new Point (about.Width/2-aboutOk.Width/2-3, about.Height-70);
gp.Size = new Size(about.Width-37,about.Height-100);
gp.Location = new Point (15,10);
info.Text = "EBNF Visualizer 1.1\n\nCopyright (c) 2005 Stefan Schoergenhumer, Markus Dopler \n\nSupported by Hanspeter Moessenboeck, University of Linz\n\nThis program is licensed under GPL. For further information see license.txt.";
info.Location = new Point(5,10);
info.Size = new Size(gp.Width-10,gp.Height-20);
gp.Controls.Add(info);
about.Controls.Add(aboutOk);
about.Controls.Add(gp);
aboutOk.Click+= new System.EventHandler(aboutOK_Click);
about.ShowDialog();
}
private void aboutOK_Click(object sender, System.EventArgs e) {
about.Close();
}
///////////////////////////////////////////////////////////////////////////////
//-----------Methods for initialising and organising the draw area-------------
///////////////////////////////////////////////////////////////////////////////
private void component_paint(object sender,PaintEventArgs e) {
Node.drawComponent(currentSymbol);
Graphics xGraph;
xGraph = e.Graphics;
xGraph.DrawImage(DrawArea,0,0,DrawArea.Width,DrawArea.Height);
}
private void drawGrammar() {
InitializeDrawArea();
Node.calcDrawing();
this.Refresh();
}
private static void InitializeDrawArea(){
Graphics xGraph;
xGraph = Graphics.FromImage(DrawArea);
xGraph.Clear(Color.White); // clear the drawing area to background color
}
private void SetCurrentSymbol(object sender, System.EventArgs e) {
rulehistory.Clear();
foreach(MenuItem mi in menuItemRules.MenuItems) {
mi.Checked=false;
}
MenuItem temp=(MenuItem) sender;
temp.Checked=true;
menuItemSave.Enabled=true;
menuItemCopy.Enabled=true;
currentSymbol=Symbol.Find(temp.Text);
rulehistory.Push(currentSymbol);
this.drawGrammar();
EbnfForm.WriteLine("Switched to rule: "+currentSymbol.name+".");
}
///////////////////////////////////////////////////////////////////////////////
//-----------Load functionality - Loading Grammar, creating short paths--------
///////////////////////////////////////////////////////////////////////////////
private bool short_path_existing=false;
private void LoadFile(String path) {
if(!short_path_existing) {
MenuItem line=new MenuItem("-");
menuItemFile.MenuItems.Add(6,line);
short_path_existing=true;
}
bool existing=false;
foreach(MenuItem mi in menuItemFile.MenuItems) {
if(mi.Text==path) existing=true;
mi.Checked=false;
}
if(!existing){
MenuItem grammar=new MenuItem(path);
menuItemFile.MenuItems.Add(6,grammar);
grammar.Click+=new System.EventHandler(this.shortload_Click);
}
LoadGrammar(path);
}
private void LoadGrammar(String path) {
//put shortcut in menu to top position
foreach(MenuItem mi in menuItemFile.MenuItems) {
mi.Checked=false;
if(mi.Text==path) {
mi.Index=6;
mi.Checked=true;
break;
}
}
// Clear the existing nodes and symbols
Symbol.nonterminals=new ArrayList();
Symbol.terminals=new ArrayList();
Node.nodes=new ArrayList();
currentSymbol=null;
menuItemRules.MenuItems.Clear();
rulehistory.Clear();
Scanner.Init(path);
Parser.Parse();
Node.Optimize();
int i;
bool insert;
foreach (Symbol s in Symbol.nonterminals) {
MenuItem m=new MenuItem(s.name);
i=0;
insert=false;
foreach (MenuItem mi in menuItemRules.MenuItems) {
if(m.Text.CompareTo(mi.Text)>0) {
i++;
} else {
menuItemRules.MenuItems.Add(i,m);
insert=true;
break;
}
}
if(i>0 && !insert) menuItemRules.MenuItems.Add(i,m);
if(menuItemRules.MenuItems.Count==0) {
menuItemRules.MenuItems.Add(m);
}
m.Click+= new System.EventHandler(this.SetCurrentSymbol);
}
menuItemRules.Enabled=true;
this.drawGrammar();
EbnfForm.WriteLine("New grammar loaded from file " +path+".");
}
///////////////////////////////////////////////////////////////////////////////
//-----------Mousecontrol + Nonterminalsearch for cruise on click--------------
///////////////////////////////////////////////////////////////////////////////
private static Stack rulehistory = new Stack();
private void Form_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
// Update the mouse path with the mouse information
if(currentSymbol==null) return;
Node nt=null;
if(e.Button==MouseButtons.Left) nt=FindNT(currentSymbol.graph.l,new PointF(e.X, e.Y));
if(e.Button==MouseButtons.Right && rulehistory.Count>1) {
rulehistory.Pop();
Symbol s=(Symbol) rulehistory.Peek();
SwitchToRule(s);
}
}
private void SwitchToRule(Symbol s) {
currentSymbol=s;
drawGrammar();
EbnfForm.WriteLine("Switched to rule: "+s.name+".");
foreach(MenuItem mi in menuItemRules.MenuItems) {
mi.Checked=false;
if(mi.Text==s.name) mi.Checked=true;
}
}
private Node FindNT(Node n,PointF p) {
bool samelevel=true;
while(n!=null && samelevel) {
if(n.typ==Node.nt) {
if(p.X >= n.posBegin.X && p.X <= n.posEnd.X && p.Y >= n.posBegin.Y && p.Y <= n.posEnd.Y) {
SwitchToRule(n.sym);
rulehistory.Push(n.sym);
}
}
else if(n.typ==Node.opt|| n.typ==Node.iter || n.typ==Node.rerun) {
Node i=FindNT(n.sub,p);
if(i!=null) return i;
if(n.typ==Node.rerun && n.itergraph!=null) FindNT(n.itergraph,p);
}
else if(n.typ==Node.alt) {
Node a=n;
while(a!=null) {
Node i=FindNT(a.sub,p);
if(i!=null) return i;
a=a.down;
}
}
if(n.up) {
samelevel=false;
}
n=n.next;
}
return null;
}
///////////////////////////////////////////////////////////////////////////////
//-----------Utils-------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
public static void WriteLine(String s) {
textBoxOutput.AppendText(DateTime.Now.ToString().Substring(11) + ": " +s+"\r\n");
}
///////////////////////////////////////////////////////////////////////////////
//-----------Main-------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
public static void Main(string[] arg) {
if (arg.Length==1) {
if(arg[0]=="-trace") {
Node.trace=true;
} else {
Console.WriteLine("Optional parameter:\n" +
"-trace ...print graph");
}
}
Application.Run(new EbnfForm());
}
}
/*-------------------------------------------------------------------------
EBNF Visualizer
Copyright (c) 2005 Stefan Schoergenhumer, Markus Dopler
supported by Hanspeter Moessenboeck, University of Linz
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-------------------------------------------------------------------------*/
using System;
using System.Collections;
using System.Drawing;
public class Symbol {
public static ArrayList terminals = new ArrayList();
public static ArrayList nonterminals = new ArrayList();
public int typ; // t, nt
public string name; // symbol name
public Graph graph; // nt: to first node of syntax graph
public Symbol(int typ, string name) {
if (name.Length == 2 && name[0] == '"') {
Console.WriteLine("empty token not allowed"); name = "???";
}
this.typ = typ; this.name = name;
switch (typ) {
case Node.t: terminals.Add(this); break;
case Node.nt: nonterminals.Add(this); break;
}
}
public static Symbol Find(string name) {
foreach (Symbol s in terminals)
if (s.name == name) return s;
foreach (Symbol s in nonterminals)
if (s.name == name) return s;
return null;
}
public static void terminalToNt(string name) {
foreach (Symbol s in terminals) {
if (s.name == name) {
nonterminals.Add(s);
terminals.Remove(s);
break;
}
}
}
}
//---------------------------------------------------------------------
// Syntax graph (class Node, class Graph)
//---------------------------------------------------------------------
public class Node {
public static ArrayList nodes = new ArrayList();
public static string[] nTyp =
{" ", "t ", "nt ", "eps ", "alt ", "iter", "opt ","reru"};
// constants for node kinds
public const int t = 1; // terminal symbol
public const int nt = 2; // nonterminal symbol
public const int eps = 3; // empty
public const int alt = 4; // alternative: |
public const int iter = 5; // iteration: { }
public const int opt = 6; // option: [ ]
public const int rerun = 7; // the optimization of: a {a} or a {b a}
public const int wrap = 8; // forces line break if found in the outer structure
public int n; // node number
public int typ; // t, nt, eps, alt, iter, opt, rerun
public Node next; // to successor node
public Node down; // alt: to next alternative
public Node sub; // alt, iter, opt: to first node of substructure
public bool up; // true: "next" leads to successor in enclosing structure
public Symbol sym; // nt, t: symbol represented by this node
public Node itergraph; // rerun: points to the b in "a {b a}", null if "a {a}"
public bool firstLevel; // true if the Node is in the first Level
public static bool trace=false;
public Node(Symbol sym) {
this.typ = sym.typ; this.sym = sym;
n = nodes.Count;
nodes.Add(this);
}
public Node(int typ, Node sub) {
this.typ = typ;
n = nodes.Count;
nodes.Add(this);
this.sub = sub;
}
//only for searching nt/t nodes
public static Node Find(string name) {
foreach (Node n in nodes)
if (n.sym!=null && n.sym.name == name) return n;
return null;
}
//can change the type of node from t to nt later on
public static void terminalToNt(string name) {
foreach (Node n in nodes) {
if (n.sym!=null && n.sym.name == name) {
n.typ=Node.nt;
}
}
}
//----------------- for printing ----------------------
static int Ptr(Node p, bool up) {
if (p == null) return 0;
else if (up) return -p.n;
else return p.n;
}
public static void PrintNodes() {
Console.WriteLine("Graph nodes:");
Console.WriteLine("(S...Starting nodes)");
Console.WriteLine("--------------------------------------------");
Console.WriteLine("S n type name next down sub ");
Console.WriteLine("--------------------------------------------");
foreach (Node p in nodes) {
bool nt=false;
foreach (Symbol s in Symbol.nonterminals) {
if (s.graph.l.n == p.n) {
Console.Write("*");
nt=true;
}
}
if(!nt) Console.Write(" ");
Console.Write("{0,4} {1} ", p.n, nTyp[p.typ]);
if (p.sym != null) Console.Write("{0,12} ", p.sym.name);
else Console.Write(" ");
Console.Write("{0,5} ", Ptr(p.next, p.up));
switch (p.typ) {
case alt: case iter: case opt: case rerun:
Console.Write("{0,5} {1,5}", Ptr(p.down, false), Ptr(p.sub, false)); break;
case eps:
Console.Write(" "); break;
}
Console.WriteLine();
}
Console.WriteLine();
}
//----------------- for drawing ----------------------
/**************default Settings**********************/
private static bool showBorders = false; // show the rectangles around the components
private static int defaultComponentArcSize = 16;
private static int defaultComponentGapWidth = 32;
private static int defaultComponentGapHeight = 10;
private static Font defaultCharFont = new Font("Times",12);
private static int defaultArrowSize = 3;
private static Pen defaultLinePen = new Pen(Color.Black,1);
private static int defaultSymbolGapHeight = 0;
private static Color defaultCharColor = Color.Black;
/**********initialize variables with default settings***********/
private static int componentArcSize = defaultComponentArcSize; // size of the arcs
private static int componentGapWidth = defaultComponentGapWidth; // gap between subcomponent size and actual size
private static int componentGapHeight = defaultComponentGapHeight; // gap between subcomponent size and actual size
private static Font charFont = defaultCharFont; // font of the t and nt symbols
private static int arrowSize = defaultArrowSize; // size of the arrows
private static Pen linePen = defaultLinePen; // color and thickness of the line
private static int symbolGapHeight = defaultSymbolGapHeight; // gap between the line of the symbol and the font
private static Color charColor = defaultCharColor; // fontColor of the T and NT symbols
private static int fontHeight = (int)defaultCharFont.Height; // needed to make the gap between the symbol and and the font possible
private static bool optimizeGraph = true; // enable optimizations?
/*****************other variables needed for the drawing********/
public Size size = new Size(0,0); // the required size to draw the node
public Size altSize = new Size(0,0); // the required size to draw a construct of alts or the size of the firstcomponent in the special rerun-node (itergraph!=null)
public Size iterSize = new Size(0,0); // the size of the second component in the special rerun Node (itergraph!=null)
public PointF posBegin = new PointF(0,0); // the point in the left above corner of the component
public PointF posLine = new PointF(0,0); // the point of the line of the component
public PointF posEnd = new PointF(0,0); // the point in the left down corner of the component
private static Size symbolSize = new Size(1,1); // the total size of the current Rule
private static int beginningXCoordinate = 50; // where the drawing starts (X)
private static int beginningYCoordinate = 40; // where the drawing starts (Y)
private static Graphics g = EbnfForm.BitmapGraphics; // the graphics object from the EBNFForm on witch the drawing takes place
public static Font CharFont {
set {
charFont=value;
fontHeight=(int)charFont.Height+symbolGapHeight;
}
get {
return charFont;
}
}
public static Color CharColor {
set {
charColor=value;
}
get {
return charColor;
}
}
public static int ArrowSize {
set {
arrowSize=value;
}
get {
return arrowSize;
}
}
public static bool OptimizeGraph {
set {
optimizeGraph=value;
}
get {
return optimizeGraph;
}
}
public static int SymbolGapHeight {
set {
symbolGapHeight=value;
}
get {
return symbolGapHeight;
}
}
public static int ComponentGapHeight {
set {
componentGapHeight=value;
if(componentGapHeight/2+fontHeight/2<defaultComponentArcSize)
componentArcSize=(componentGapHeight+fontHeight)/2;
else
componentArcSize=defaultComponentArcSize;
if(componentArcSize%2!=0) componentArcSize-=1;
}
get {
return componentGapHeight;
}
}
public static int ComponentGapWidth {
set {
componentGapWidth=value;
}
get {
return componentGapWidth;
}
}
public static Pen LinePen {
set {
linePen=value;
}
get {
return linePen;
}
}
public static Size SymbolSize {
get {
return symbolSize;
}
}
public static void restoreDefaultSettings() {
componentArcSize = defaultComponentArcSize; // size of the arcs
componentGapWidth = defaultComponentGapWidth; // gap between subcomponent size and actual size
ComponentGapHeight = defaultComponentGapHeight; // gap between subcomponent size and actual size
charFont = defaultCharFont; // font of the t and nt symbols
arrowSize = defaultArrowSize; // size of the arrows
linePen = new Pen(Color.Black,1); // color and thickness of the line
symbolGapHeight = defaultSymbolGapHeight; // gap between the line of the symbol and the font
charColor = defaultCharColor; // fontColor of the T and NT symbols
fontHeight = (int)defaultCharFont.Height; // needed to make the gap between the symbol and and the font possible
optimizeGraph = true;
}
public static void calcDrawing() {
foreach(Symbol s in Symbol.nonterminals) {
s.graph.graphSize=s.graph.l.calcSize();
s.graph.l.setWrapSize();
s.graph.l.calcPos(beginningYCoordinate);
if(Node.trace) {
PrintNodes();
Console.WriteLine("\n\n"+s.graph.graphSize.ToString());
}
}
}
// calculates the size if there are wraps in the rule
public void setWrapSize() {
Node n=this;
int maxH=0;
while(n!=null) {
n.firstLevel=true;
if(n.typ==Node.wrap) {
n.size.Height=maxH;
maxH=0;
}
else {
if(n.typ==Node.iter) {
if(maxH<n.size.Height+(fontHeight+componentGapHeight)/2)
maxH=n.size.Height+(fontHeight+componentGapHeight)/2;
}
else if(maxH<n.size.Height || maxH<n.altSize.Height) {
if(n.altSize.Height!=0)
maxH=n.altSize.Height;
else
maxH=n.size.Height;
}
}
n=n.next;
}
}
// calculates the size of each symbol
public Size calcSize() {
Node n=this; //current node in the level
Size s=new Size(); //alt,iter,opt: size of current construct
int iterCompensation=0;
bool samelevel=true; //next node in same level?
int realHeight=n.calcHeight();
Size maxTotalSize=new Size(0,0);
while(n!=null && samelevel) {
if(n.typ==Node.t || n.typ==Node.nt) {
n.size.Height =fontHeight+componentGapHeight;
n.size.Width = (int)g.MeasureString(n.sym.name,charFont).Width+fontHeight/3;
if(!n.up && n.next!=null && n.next.typ==Node.wrap && n.next.size.Height==0) {
if(!n.next.up && n.next.next!=null && (n.next.next.typ==Node.t || n.next.next.typ==Node.nt)) {
s.Width+=componentGapWidth/2;
}
}
if(!n.up && n.next!=null && (n.next.typ==Node.t || n.next.typ==Node.nt)) {
s.Width+=componentGapWidth/2;
}
}
else if(n.typ==Node.eps) {
n.size.Height = fontHeight+componentGapHeight;
n.size.Width = componentGapWidth;
}
else if(n.typ==Node.opt) {
n.size=n.sub.calcSize();
n.size.Width += componentGapWidth*2;
n.size.Height += componentGapHeight/2;
}
else if(n.typ==Node.iter) {
n.size=n.sub.calcSize();
n.size.Width += componentGapWidth*2;
}
else if(n.typ==Node.wrap) {
maxTotalSize.Height+=s.Height-componentGapHeight/2;
if(maxTotalSize.Width<s.Width)
maxTotalSize.Width=s.Width;
s.Height=0;
s.Width=0;
}
else if(n.typ==Node.rerun) {
n.size=n.sub.calcSize();
if(n.itergraph!=null) {
n.altSize=n.size;
if(n.size.Width<n.itergraph.calcSize().Width)
n.size.Width=n.itergraph.calcSize().Width;
n.size.Height+=n.itergraph.calcSize().Height;
n.iterSize=n.itergraph.calcSize();
}
else
n.size.Height += componentGapHeight/2;
n.size.Width += componentGapWidth*2;
}
else if(n.typ==Node.alt) {
Node a=n;int maxH= -componentGapHeight, maxW=0;
while(a!=null) {
a.size=a.sub.calcSize();
maxH += a.size.Height;
if(a.size.Width>maxW) maxW=a.size.Width;
a=a.down;
}
if(n.sub.typ==iter && realHeight!=0) maxH+=(fontHeight+componentGapHeight)/2;
maxW += 2*componentGapWidth;
maxH += componentGapHeight;
n.altSize.Height=maxH;
n.altSize.Width=maxW;
}
if(n.typ==Node.iter&&realHeight!=0) {
iterCompensation=(fontHeight+componentGapHeight)/2;
}
if(n.typ==Node.alt) {
if(s.Height<n.altSize.Height) s.Height=n.altSize.Height;
s.Width += n.altSize.Width;
} else {
if(s.Height<n.size.Height) s.Height=n.size.Height;
s.Width += n.size.Width;
}
if(n.typ==Node.iter) {
if(s.Height<n.size.Height+iterCompensation) s.Height=n.size.Height+iterCompensation;
}
if(n.up) {
samelevel=false;
}
n=n.next;
}
if(maxTotalSize.Width!=0) {
maxTotalSize.Height+=s.Height-componentGapHeight/2;
if(maxTotalSize.Width<s.Width)
maxTotalSize.Width=s.Width;
return maxTotalSize;
}
else
return s;
}
// calculates the total height of all symbols wich are in the same horizontal level
public int calcHeight() {
Node n=this; //current node in the level
int realHeight=0;
bool samelevel=true; //next node in same level?
while(n!=null && samelevel) {
if(n.typ==Node.nt|| n.typ==Node.t) {
if(realHeight<n.size.Height)
realHeight=n.size.Height;
}
else if(n.typ==Node.iter) {
int tmpHeight=0;
if(realHeight<tmpHeight)
realHeight=tmpHeight;
}
else if(n.typ==Node.opt||n.typ==Node.rerun ) {
int tmpHeight=n.sub.calcHeight();
if(realHeight<tmpHeight){}
realHeight=tmpHeight;
}
else if(n.typ==Node.alt ) {
int tmpHeight=n.sub.calcHeight();
if(realHeight<tmpHeight){}
realHeight=tmpHeight;
}
else if(n.typ==Node.eps) {
if(realHeight<fontHeight*3/2)
realHeight=fontHeight+componentGapHeight;
}
if(n.up) {
samelevel=false;
}
n=n.next;
}
return realHeight;
}
// calcualtes the horizontal position of the symbols
public void calcPos(float posBegin) {
Node n=this; //current node in the level
int realHeight=calcHeight();
bool samelevel=true; //next node in same level?
while(n!=null && samelevel) {
if(n.typ==Node.nt||n.typ==Node.t) {
n.posLine.Y=posBegin+realHeight/2;
n.posBegin.Y=n.posLine.Y-(n.size.Height-componentGapHeight)/2;
n.posEnd.Y=n.posLine.Y+(n.size.Height-componentGapHeight)/2;
}
else if(n.typ==Node.eps) {
n.posLine.Y=posBegin+n.size.Height/2;
n.posBegin.Y=posBegin;
n.posEnd.Y=posBegin+n.size.Height;
}
else if(n.typ==Node.opt) {
n.posLine.Y=posBegin+realHeight/2;
n.posBegin.Y=posBegin;
n.posEnd.Y=posBegin+n.size.Height;
n.sub.calcPos(n.posBegin.Y);
}
else if(n.typ==Node.rerun) {
n.posLine.Y=posBegin+realHeight/2;
n.posBegin.Y=posBegin;
n.posEnd.Y=posBegin+n.size.Height;
if(n.itergraph!=null) {
n.itergraph.calcPos(posBegin+n.altSize.Height);
}
n.sub.calcPos(n.posBegin.Y);
}
else if(n.typ==Node.iter) {
if(realHeight==0) {
n.posLine.Y=posBegin+realHeight/2;
n.posBegin.Y=posBegin;
n.posEnd.Y=posBegin+n.size.Height;
}
else {
n.posLine.Y=posBegin+realHeight/2;
n.posBegin.Y=posBegin+(fontHeight+componentGapHeight)/2;
n.posEnd.Y=n.posBegin.Y+n.size.Height;
}
n.sub.calcPos(n.posLine.Y);
}
else if(n.typ==Node.wrap && firstLevel) {
n.posLine.Y=posBegin+realHeight/2;
n.posEnd.Y=posBegin+n.size.Height;
posBegin=posBegin+n.size.Height;
}
else if(n.typ==Node.alt) {
n.posLine.Y=posBegin+realHeight/2;
n.posBegin.Y=posBegin;
n.posEnd.Y=posBegin+n.altSize.Height;
if(n.sub.typ==iter && n.calcHeight()!=0 &&n.altSize.Height!=0)
posBegin+=(fontHeight+componentGapHeight)/2;
n.sub.calcPos(posBegin);
if(n.down!=null) {
n.down.calcPos(posBegin+n.size.Height);
}
if(n.sub.typ==iter && n.calcHeight()!=0 &&n.altSize.Height!=0)
posBegin-=(fontHeight+componentGapHeight)/2;
}
if(n.up) {
samelevel=false;
}
n=n.next;
}
}
public static void drawComponent(Symbol s) {
drawComponent(s,null);
}
// starts to draw the rule at the given symbol s
public static void drawComponent(Symbol s, Graphics vg) {
if(s!=null) {
symbolSize=new Size(s.graph.graphSize.Width+beginningXCoordinate+componentGapWidth*2,s.graph.graphSize.Height+beginningYCoordinate+componentGapHeight*2+5);
EbnfForm.Drawarea=new Bitmap(Node.SymbolSize.Width,Node.SymbolSize.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//decide either draw on visualized bitmap or record a metafile
if(vg!=null) {
g=vg;
g.FillRectangle(new SolidBrush(Color.White),0,0,symbolSize.Width,symbolSize.Height);
}
else g=EbnfForm.BitmapGraphics;
PointF p=new PointF(beginningXCoordinate,beginningYCoordinate-30);
g.DrawString(s.name,new Font("Times New Roman",14),new SolidBrush(Color.Black),p.X-20,p.Y);
//g.DrawRectangle(new Pen(Color.Orange,2),p.X,p.Y+30,s.graph.graphSize.Width,s.graph.graphSize.Height);
g.DrawLine(linePen ,beginningXCoordinate-componentGapWidth/4-componentArcSize/2 , s.graph.l.posLine.Y , beginningXCoordinate , s.graph.l.posLine.Y );
s.graph.l.drawComponents(p,s.graph.graphSize);
}
}
// draws arrows for different directions
public void drawArrow(Pen pen,float x, float y, float x1, float y1, String direction) {
g.DrawLine(pen,x,y,x1,y1);
PointF arrowHead = new PointF(x1,y1);
PointF arrowLeft;
PointF arrowRight;
if(direction=="right") {
arrowLeft = new PointF(x1-arrowSize*2,y1-arrowSize);
arrowRight = new PointF(x1-arrowSize*2,y1+arrowSize);
PointF[] curvePoints = {arrowHead,arrowLeft,arrowRight};
g.FillPolygon(pen.Brush, curvePoints);
}else if(direction=="up") {
arrowLeft = new PointF(x1-arrowSize,y1+arrowSize*2);
arrowRight = new PointF(x1+arrowSize,y1+arrowSize*2);
PointF[] curvePoints = {arrowHead,arrowLeft,arrowRight};
g.FillPolygon(pen.Brush, curvePoints);
}else if(direction=="left") {
arrowLeft = new PointF(x1+arrowSize*2,y1+arrowSize);
arrowRight = new PointF(x1+arrowSize*2,y1-arrowSize);
PointF[] curvePoints = {arrowHead,arrowLeft,arrowRight};
g.FillPolygon(pen.Brush, curvePoints);
}else if(direction=="down") {
arrowLeft = new PointF(x1-arrowSize,y1-arrowSize*2);
arrowRight = new PointF(x1+arrowSize,y1-arrowSize*2);
PointF[] curvePoints = {arrowHead,arrowLeft,arrowRight};
g.FillPolygon(pen.Brush, curvePoints);
}
}
/*
* Draws the components from left to right.
* Rekursive procedure. Therefore also the drawComponentsInverse procedure is used.
* Each component paints itself and then they give their coordinates to its innercomponents.
*/
public void drawComponents(PointF p,Size s) {
Node n=this; // current node in the level
bool samelevel=true; // next node in same level?
PointF p1=new Point(0,0); // needed for calculating the X-Coordinate for the recursion
while(n!=null && samelevel) {
if(n.typ==Node.t || n.typ==Node.nt) {
if(showBorders) g.DrawRectangle(new Pen(Color.PaleGreen,1),p.X,n.posBegin.Y-componentGapHeight/2,n.size.Width,n.size.Height);
if(n.typ==Node.t) {
// the quarter Arcs
g.DrawArc( linePen , p.X , n.posBegin.Y , (n.size.Height-componentGapHeight)/2 , (n.size.Height-componentGapHeight)/2 , 180 , 90);
g.DrawArc( linePen , p.X , n.posLine.Y , (n.size.Height-componentGapHeight)/2 , (n.size.Height-componentGapHeight)/2 , 90 , 90);
g.DrawArc( linePen , p.X+n.size.Width-(n.size.Height-componentGapHeight)/2 , n.posBegin.Y , (n.size.Height-componentGapHeight)/2 , (n.size.Height-componentGapHeight)/2 , 270 , 90);
g.DrawArc( linePen , p.X+n.size.Width-(n.size.Height-componentGapHeight)/2 , n.posLine.Y , (n.size.Height-componentGapHeight)/2 , (n.size.Height-componentGapHeight)/2 , 0 , 90);
// the short vertical and horizontal lines between the quarter Arcs
g.DrawLine(linePen , p.X+(n.size.Height-componentGapHeight)/4-1 , n.posBegin.Y , p.X+n.size.Width-(n.size.Height-componentGapHeight)/4+1 , n.posBegin.Y );
g.DrawLine(linePen , p.X+(n.size.Height-componentGapHeight)/4-1 , n.posEnd.Y , p.X+n.size.Width-(n.size.Height-componentGapHeight)/4+1 , n.posEnd.Y );
g.DrawLine(linePen , p.X , n.posLine.Y+(n.size.Height-componentGapHeight)/4+1 , p.X , n.posLine.Y-(n.size.Height-componentGapHeight)/4-1);
g.DrawLine(linePen , p.X+n.size.Width , n.posLine.Y+(n.size.Height-componentGapHeight)/4+1 , p.X+n.size.Width , n.posLine.Y-(n.size.Height-componentGapHeight)/4-1);
}
else {
n.posBegin.X=p.X;
n.posEnd.X=p.X+n.size.Width;
g.DrawRectangle(linePen , n.posBegin.X , n.posBegin.Y , n.size.Width , (n.size.Height-componentGapHeight));
}
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Center;
drawFormat.LineAlignment = StringAlignment.Center;
g.DrawString(n.sym.name , charFont , new SolidBrush(charColor) , new Rectangle((int)p.X,(int)n.posBegin.Y,n.size.Width,n.size.Height-componentGapHeight-2),drawFormat);
drawArrow(linePen , p.X , n.posLine.Y , p.X , n.posLine.Y , "right");
p.X+=n.size.Width;
// draw lines between t and nt nodes
if(!n.up && n.next!=null && (n.next.typ==Node.t || n.next.typ==Node.nt)) {
drawArrow(linePen , p.X , n.posLine.Y , p.X+componentGapWidth/2 , n.posLine.Y , "right");
p.X+=componentGapWidth/2;
}
if(!n.up && n.next!=null && n.next.typ==Node.wrap && n.next.size.Height==0) {
drawArrow(linePen , p.X , n.posLine.Y , p.X+componentGapWidth/2 , n.posLine.Y , "right");
p.X+=componentGapWidth/2;
}
}
else if(n.typ==Node.eps) {
if(showBorders) g.DrawRectangle(new Pen(Color.DarkKhaki,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
g.DrawLine(linePen , p.X , n.posLine.Y , p.X+n.size.Width , n.posLine.Y);
}
else if(n.typ==Node.opt) {
if(showBorders) g.DrawRectangle(new Pen(Color.DarkKhaki,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
// the two short lines at the beginning and the end
g.DrawLine(linePen , p.X , n.posLine.Y , p.X +componentGapWidth , n.posLine.Y);
g.DrawLine(linePen , p.X +n.size.Width , n.posLine.Y , p.X+n.size.Width-componentGapWidth , n.posLine.Y);
// the quarter Arcs
g.DrawArc( linePen , p.X + componentGapWidth/4 - componentArcSize/2 , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
g.DrawArc( linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posEnd.Y-componentArcSize-componentGapHeight/2 , componentArcSize , componentArcSize , 90 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 - componentArcSize*3/2 + n.size.Width , n.posEnd.Y-componentArcSize-componentGapHeight/2 , componentArcSize , componentArcSize , 0 , 90);
// the short vertical lines between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posLine.Y+componentArcSize/2 , p.X + componentGapWidth/4 + componentArcSize/2 , n.posEnd.Y-componentArcSize/2-componentGapHeight/2+1);
g.DrawLine(linePen , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.posLine.Y+componentArcSize/2 , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.posEnd.Y-componentArcSize/2-componentGapHeight/2+1);
// the the long horizontal line between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize , n.posEnd.Y-componentGapHeight/2 , p.X - componentGapWidth/4 - componentArcSize + n.size.Width+1 , n.posEnd.Y-componentGapHeight/2 );
p1.X=p.X+componentGapWidth;
n.sub.drawComponents(p1,n.size);
p.X+=n.size.Width;
}
else if(n.typ==Node.rerun&&n.itergraph==null) {
if(showBorders) g.DrawRectangle(new Pen(Color.Green,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
// the two short lines at the beginning and the end
g.DrawLine(linePen , p.X , n.posLine.Y , p.X +componentGapWidth , n.posLine.Y);
g.DrawLine(linePen , p.X +n.size.Width , n.posLine.Y , p.X+n.size.Width -componentGapWidth , n.posLine.Y);
// the quarter Arcs
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.posEnd.Y-componentGapHeight/2-componentArcSize , componentArcSize , componentArcSize , 90 , 90);
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.posEnd.Y-componentGapHeight/2-componentArcSize , componentArcSize , componentArcSize , 0 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
// the short vertical lines between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posLine.Y+componentArcSize/2 , p.X + componentGapWidth/4 + componentArcSize/2 , n.posEnd.Y-componentGapHeight/2-componentArcSize/2+1 );
g.DrawLine(linePen , p.X - componentGapWidth/4 - componentArcSize/2+n.size.Width , n.posLine.Y+componentArcSize/2 , p.X - componentGapWidth/4 - componentArcSize/2+ n.size.Width , n.posEnd.Y-componentGapHeight/2-componentArcSize/2+1 );
// the the long horizontal line between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize-1 , n.posEnd.Y-componentGapHeight/2 , p.X - componentGapWidth/4 - componentArcSize + n.size.Width+1 , n.posEnd.Y-componentGapHeight/2);
p1.X=p.X+componentGapWidth;
n.sub.drawComponents(p1,n.size);
p.X+=n.size.Width;
}
else if(n.typ==Node.rerun&&n.itergraph!=null) {
if(showBorders) g.DrawRectangle(new Pen(Color.Fuchsia,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
// the two short lines at the beginning and the end of the first component
g.DrawLine(linePen , p.X , n.posLine.Y , p.X + n.size.Width/2-n.altSize.Width/2-1 , n.posLine.Y);
g.DrawLine(linePen , p.X + n.size.Width/2+n.altSize.Width/2+1 , n.posLine.Y , p.X + n.size.Width , n.posLine.Y);
// the quarter Arcs
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.itergraph.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 90 , 90);
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.itergraph.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 0 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
// the short vertical lines between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posLine.Y+componentArcSize/2 , p.X + componentGapWidth/4 + componentArcSize/2 , n.itergraph.posLine.Y-componentArcSize/2+1 );
g.DrawLine(linePen , p.X - componentGapWidth/4 - componentArcSize/2+n.size.Width , n.posLine.Y+componentArcSize/2 , p.X - componentGapWidth/4 - componentArcSize/2+ n.size.Width , n.itergraph.posLine.Y-componentArcSize/2+1 );
// the two short lines at the beginning and the end of the second component
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize , n.itergraph.posLine.Y , p.X + n.size.Width/2-n.iterSize.Width/2-1 , n.itergraph.posLine.Y );
g.DrawLine(linePen , p.X + n.size.Width/2+n.iterSize.Width/2+1 , n.itergraph.posLine.Y , p.X - componentGapWidth/4 - componentArcSize + n.size.Width+1 , n.itergraph.posLine.Y );
n.itergraph.drawComponentsInverse(new PointF(p.X + n.size.Width/2+n.iterSize.Width/2 , n.posEnd.Y) , n.size);
n.sub.drawComponents( new PointF(p.X + n.size.Width/2-n.altSize.Width /2 , n.posEnd.Y) , n.size);
p.X+=n.size.Width;
}
else if(n.typ==Node.iter) {
if(showBorders) g.DrawRectangle(new Pen(Color.DarkViolet,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
// the quarter Arcs
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.sub.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 90 , 90);
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.sub.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 0 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
// the short vertical lines between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posLine.Y+componentArcSize/2 , p.X + componentGapWidth/4 + componentArcSize/2 , n.sub.posLine.Y-componentArcSize/2+1 );
g.DrawLine(linePen , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.posLine.Y+componentArcSize/2 , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.sub.posLine.Y-componentArcSize/2+1 );
// the two short horizontal lines between the quater Arcs and the components
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize-1 , n.sub.posLine.Y , p.X + componentGapWidth , n.sub.posLine.Y );
g.DrawLine(linePen , p.X - componentGapWidth + n.size.Width , n.sub.posLine.Y , p.X + n.size.Width-componentGapWidth/4 - componentArcSize+1 , n.sub.posLine.Y );
// the long horizontal line in the middle
g.DrawLine(linePen , p.X , n.posLine.Y , p.X + n.size.Width , n.posLine.Y);
p1.X=p.X-componentGapWidth+n.size.Width;
n.sub.drawComponentsInverse(p1,n.size);
p.X+=n.size.Width;
}
else if(n.typ==Node.wrap && n.size.Height!=0 && n.next!=null) {
// the short horizontal line after the first component
g.DrawLine(linePen , p.X , n.posLine.Y , p.X + componentGapWidth/4+1 , n.posLine.Y );
// the short horizontal line at the beginning of the second component
g.DrawLine(linePen , beginningXCoordinate , n.next.posLine.Y , beginningXCoordinate-componentGapWidth/4 , n.next.posLine.Y );
// the quarter Arcs
g.DrawArc( linePen , p.X + componentGapWidth/4-componentArcSize/2 , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
g.DrawArc( linePen , p.X + componentGapWidth/4-componentArcSize/2 , n.posEnd.Y-componentArcSize , componentArcSize , componentArcSize , 0 , 90);
g.DrawArc( linePen , beginningXCoordinate-componentGapWidth/4-componentArcSize/2 , n.posEnd.Y , componentArcSize , componentArcSize , 180 , 90);
g.DrawArc( linePen , beginningXCoordinate-componentGapWidth/4-componentArcSize/2 , n.next.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 90 , 90);
// the short vertical lines between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4+componentArcSize/2 , n.posLine.Y+componentArcSize/2 , p.X + componentGapWidth/4+componentArcSize/2 , n.posEnd.Y-componentArcSize/2 +1 );
g.DrawLine(linePen , beginningXCoordinate-componentGapWidth/4-componentArcSize/2 , n.posEnd.Y+componentArcSize/2 , beginningXCoordinate-componentGapWidth/4-componentArcSize/2 , n.next.posLine.Y-componentArcSize/2 +1 );
// the long horizontal line in the middle oft the two components
g.DrawLine(linePen , p.X + componentGapWidth/4+1 , n.posEnd.Y , beginningXCoordinate-componentGapWidth/4 , n.posEnd.Y );
p.X=beginningXCoordinate;
}
else if(n.typ==Node.alt) {
if(showBorders) g.DrawRectangle(new Pen(Color.Red,1),p.X,n.posBegin.Y,n.altSize.Width,n.altSize.Height);
// the two short lines at the beginning and the end of the altcomponent
g.DrawLine( linePen , p.X , n.posLine.Y , p.X +componentArcSize*3/2 , n.posLine.Y );
g.DrawLine( linePen , p.X+n.altSize.Width , n.posLine.Y , p.X+n.altSize.Width -+componentArcSize*3/2 , n.posLine.Y );
Node a=n;
bool first=true;
while(a!=null) {
// the horizontal lines at the beginning and the end
g.DrawLine( linePen , p.X +componentArcSize*3/2 , a.sub.posLine.Y , p.X +(n.altSize.Width-a.size.Width)/2 , a.sub.posLine.Y);
g.DrawLine( linePen , p.X -componentArcSize*3/2 + n.altSize.Width+1 , a.sub.posLine.Y , p.X +(n.altSize.Width-a.size.Width)/2 + a.size.Width , a.sub.posLine.Y);
// the first alternative draws different arcs
if(first) {
g.DrawArc ( linePen , p.X , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
g.DrawArc ( linePen , p.X +n.altSize.Width-componentArcSize , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
first=false;
}
// else draw other arcs and vertical lines
else {
g.DrawArc ( linePen , p.X + componentArcSize , a.sub.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 90 , 90);
g.DrawLine( linePen , p.X + componentArcSize , n.posLine.Y +componentArcSize/2 , p.X + componentArcSize , a.posLine.Y-componentArcSize/2+1);
g.DrawArc ( linePen , p.X - componentArcSize*2 + n.altSize.Width , a.sub.posLine.Y - componentArcSize , componentArcSize , componentArcSize , 0 , 90);
g.DrawLine( linePen , p.X - componentArcSize + n.altSize.Width , n.posLine.Y +componentArcSize/2 , p.X - componentArcSize + n.altSize.Width , a.posLine.Y-componentArcSize/2+1);
}
a.sub.drawComponents(new PointF(p.X+(n.altSize.Width-a.size.Width)/2 , a.posEnd.Y) , a.size);
a=a.down;
}
p.X+=n.altSize.Width;
}
if(n.up)
samelevel=false;
if(n.next==null && firstLevel) {
g.DrawLine( linePen , p.X , n.posLine.Y , p.X+componentGapWidth/4 , n.posLine.Y );
drawArrow( linePen , p.X+componentGapWidth/4+arrowSize , n.posLine.Y , p.X+componentGapWidth/4+arrowSize , n.posLine.Y , "right");
}
n=n.next;
}
}
/*
* Draw the components from right to left.
* Needed if for example in an iter-node.
*/
public void drawComponentsInverse(PointF p,Size s) {
Node n=this; //current node in the level
bool samelevel=true; //next node in same level?
PointF p1=new Point(0,0);
while(n!=null && samelevel) {
p.X-=n.size.Width;
if(n.typ==Node.t || n.typ==Node.nt) {
if(showBorders) g.DrawRectangle(new Pen(Color.PaleGreen,1),p.X,n.posBegin.Y-componentGapHeight/2,n.size.Width,n.size.Height);
if(n.typ==Node.t) {
// the quarter Arcs
g.DrawArc( linePen , p.X , n.posBegin.Y , (n.size.Height-componentGapHeight)/2 , (n.size.Height-componentGapHeight)/2 , 180 , 90);
g.DrawArc( linePen , p.X , n.posLine.Y , (n.size.Height-componentGapHeight)/2 , (n.size.Height-componentGapHeight)/2 , 90 , 90);
g.DrawArc( linePen , p.X+n.size.Width-(n.size.Height-componentGapHeight)/2 , n.posBegin.Y , (n.size.Height-componentGapHeight)/2 , (n.size.Height-componentGapHeight)/2 , 270 , 90);
g.DrawArc( linePen , p.X+n.size.Width-(n.size.Height-componentGapHeight)/2 , n.posLine.Y , (n.size.Height-componentGapHeight)/2 , (n.size.Height-componentGapHeight)/2 , 0 , 90);
// the short vertical and horizontal lines between the quarter Arcs
g.DrawLine(linePen , p.X+(n.size.Height-componentGapHeight)/4-1 , n.posBegin.Y , p.X+n.size.Width-(n.size.Height-componentGapHeight)/4+1 , n.posBegin.Y );
g.DrawLine(linePen , p.X+(n.size.Height-componentGapHeight)/4-1 , n.posEnd.Y , p.X+n.size.Width-(n.size.Height-componentGapHeight)/4+1 , n.posEnd.Y );
g.DrawLine(linePen , p.X , n.posLine.Y+(n.size.Height-componentGapHeight)/4+1 , p.X , n.posLine.Y-(n.size.Height-componentGapHeight)/4-1);
g.DrawLine(linePen , p.X+n.size.Width , n.posLine.Y+(n.size.Height-componentGapHeight)/4+1 , p.X+n.size.Width , n.posLine.Y-(n.size.Height-componentGapHeight)/4-1);
}
else {
n.posBegin.X=p.X;
n.posEnd.X=p.X+n.size.Width;
g.DrawRectangle(linePen , n.posBegin.X,n.posBegin.Y , n.size.Width , (n.size.Height-componentGapHeight));
}
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Center;
drawFormat.LineAlignment = StringAlignment.Center;
g.DrawString(n.sym.name , charFont , new SolidBrush(charColor) , new Rectangle((int)p.X,(int)n.posBegin.Y,n.size.Width,n.size.Height-componentGapHeight-2),drawFormat);
drawArrow(linePen , p.X+n.size.Width , n.posLine.Y , p.X+n.size.Width , n.posLine.Y , "left");
if(!n.up && n.next!=null && (n.next.typ==Node.t || n.next.typ==Node.nt)) {
drawArrow(linePen , p.X , n.posLine.Y , p.X-componentGapWidth/2 , n.posLine.Y , "left");
p.X-=componentGapWidth/2;
}
if(!n.up && n.next!=null && n.next.typ==Node.wrap && n.next.size.Height==0) {
if(!n.next.up && n.next.next!=null && (n.next.next.typ==Node.t || n.next.next.typ==Node.nt)) {
drawArrow(linePen , p.X , n.posLine.Y , p.X-componentGapWidth/2 , n.posLine.Y , "left");
p.X-=componentGapWidth/2;
}
}
}
else if(n.typ==Node.eps) {
if(showBorders) g.DrawRectangle(new Pen(Color.DarkKhaki,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
g.DrawLine(linePen , p.X , n.posLine.Y , p.X + n.size.Width , n.posLine.Y);
}
else if(n.typ==Node.opt) {
if(showBorders) g.DrawRectangle(new Pen(Color.DarkKhaki,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
// the two short lines at the beginning and the end
g.DrawLine(linePen , p.X , n.posLine.Y , p.X +componentGapWidth , n.posLine.Y);
g.DrawLine(linePen , p.X +n.size.Width , n.posLine.Y , p.X+n.size.Width-componentGapWidth , n.posLine.Y);
// the quarter Arcs
g.DrawArc( linePen , p.X + componentGapWidth/4 - componentArcSize/2 , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
g.DrawArc( linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posEnd.Y-componentArcSize-componentGapHeight/2 , componentArcSize , componentArcSize , 90 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 - componentArcSize*3/2 + n.size.Width , n.posEnd.Y-componentArcSize-componentGapHeight/2 , componentArcSize , componentArcSize , 0 , 90);
// the short vertical lines between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posLine.Y+componentArcSize/2 , p.X + componentGapWidth/4 + componentArcSize/2 , n.posEnd.Y-componentArcSize/2-componentGapHeight/2+1);
g.DrawLine(linePen , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.posLine.Y+componentArcSize/2 , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.posEnd.Y-componentArcSize/2-componentGapHeight/2+1);
// the the long horizontal line between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize , n.posEnd.Y-componentGapHeight/2 , p.X - componentGapWidth/4 - componentArcSize + n.size.Width+1 , n.posEnd.Y-componentGapHeight/2 );
p1.X=p.X+n.size.Width-componentGapWidth;
n.sub.drawComponentsInverse(p1,n.size);
}
else if(n.typ==Node.rerun && n.itergraph==null) {
if(showBorders) g.DrawRectangle(new Pen(Color.Green,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
// the two short lines at the beginning and the end
g.DrawLine(linePen , p.X , n.posLine.Y , p.X +componentGapWidth , n.posLine.Y);
g.DrawLine(linePen , p.X +n.size.Width , n.posLine.Y , p.X+n.size.Width -componentGapWidth , n.posLine.Y);
// the quarter Arcs
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.posEnd.Y-componentGapHeight/2-componentArcSize , componentArcSize , componentArcSize , 90 , 90);
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.posEnd.Y-componentGapHeight/2-componentArcSize , componentArcSize , componentArcSize , 0 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
// the short vertical lines between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posLine.Y+componentArcSize/2 , p.X + componentGapWidth/4 + componentArcSize/2 , n.posEnd.Y-componentGapHeight/2-componentArcSize/2+1 );
g.DrawLine(linePen , p.X - componentGapWidth/4 - componentArcSize/2+n.size.Width , n.posLine.Y+componentArcSize/2 , p.X - componentGapWidth/4 - componentArcSize/2+ n.size.Width , n.posEnd.Y-componentGapHeight/2-componentArcSize/2+1 );
// the the long horizontal line between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize-1 , n.posEnd.Y-componentGapHeight/2 , p.X - componentGapWidth/4 - componentArcSize + n.size.Width+1 , n.posEnd.Y-componentGapHeight/2);
p1.X=p.X+n.size.Width-componentGapWidth;
n.sub.drawComponentsInverse(p1,n.size);
}
else if(n.typ==Node.rerun&&n.itergraph!=null) {
if(showBorders) g.DrawRectangle(new Pen(Color.Fuchsia,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
// the two short lines at the beginning and the end of the first component
g.DrawLine(linePen , p.X , n.posLine.Y , p.X + n.size.Width/2-n.altSize.Width/2-1, n.posLine.Y);
g.DrawLine(linePen , p.X + n.size.Width/2+n.altSize.Width/2+1 , n.posLine.Y , p.X + n.size.Width , n.posLine.Y);
// the quarter Arcs
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.itergraph.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 90 , 90);
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.itergraph.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 0 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
// the short vertical lines between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posLine.Y+componentArcSize/2 , p.X + componentGapWidth/4 + componentArcSize/2 , n.itergraph.posLine.Y-componentArcSize/2+1 );
g.DrawLine(linePen , p.X - componentGapWidth/4 - componentArcSize/2+n.size.Width , n.posLine.Y+componentArcSize/2 , p.X - componentGapWidth/4 - componentArcSize/2+ n.size.Width , n.itergraph.posLine.Y-componentArcSize/2+1 );
// the two short lines at the beginning and the end of the second component
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize , n.itergraph.posLine.Y , p.X + n.size.Width/2-n.iterSize.Width/2-1 , n.itergraph.posLine.Y );
g.DrawLine(linePen , p.X + n.size.Width/2+n.iterSize.Width/2+1 , n.itergraph.posLine.Y , p.X - componentGapWidth/4 - componentArcSize + n.size.Width+1 , n.itergraph.posLine.Y );
n.sub.drawComponentsInverse(new PointF(p.X+n.size.Width/2+n.altSize.Width/2 , n.posEnd.Y),n.size);
n.itergraph.drawComponents( new PointF(p.X+n.size.Width/2-n.iterSize.Width/2 , n.posEnd.Y),n.size);
}
else if(n.typ==Node.iter) {
if(showBorders) g.DrawRectangle(new Pen(Color.DarkViolet,1),p.X,n.posBegin.Y,n.size.Width,n.size.Height);
// the quarter Arcs
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.sub.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 90 , 90);
g.DrawArc( linePen , p.X + componentGapWidth/4 +componentArcSize/2 , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.sub.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 0 , 90);
g.DrawArc( linePen , p.X - componentGapWidth/4 -componentArcSize*3/2 + n.size.Width , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
// the short vertical lines between the quarter Arcs
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize/2 , n.posLine.Y+componentArcSize/2 , p.X + componentGapWidth/4 + componentArcSize/2 , n.sub.posLine.Y-componentArcSize/2+1 );
g.DrawLine(linePen , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.posLine.Y+componentArcSize/2 , p.X - componentGapWidth/4 - componentArcSize/2 + n.size.Width , n.sub.posLine.Y-componentArcSize/2+1 );
// the two short horizontal lines between the quater Arcs and the components
g.DrawLine(linePen , p.X + componentGapWidth/4 + componentArcSize-1 , n.sub.posLine.Y , p.X + componentGapWidth , n.sub.posLine.Y );
g.DrawLine(linePen , p.X - componentGapWidth + n.size.Width , n.sub.posLine.Y , p.X + n.size.Width-componentGapWidth/4 - componentArcSize+1 , n.sub.posLine.Y );
// the long horizontal line in the middle
g.DrawLine(linePen , p.X , n.posLine.Y , p.X + n.size.Width , n.posLine.Y);
p1.X=p.X+componentGapWidth;
n.sub.drawComponents(p1,n.size);
}
else if(n.typ==Node.alt) {
p.X-=n.altSize.Width-n.size.Width;
if(showBorders) g.DrawRectangle(new Pen(Color.Red,1),p.X,n.posBegin.Y,n.altSize.Width,n.altSize.Height);
// the two short lines at the beginning and the end of the altcomponent
g.DrawLine( linePen , p.X , n.posLine.Y , p.X +componentArcSize*3/2 , n.posLine.Y );
g.DrawLine( linePen , p.X+n.altSize.Width , n.posLine.Y , p.X+n.altSize.Width -componentArcSize*3/2 , n.posLine.Y );
p1.X=p.X+2*componentGapWidth;
p1.Y=p1.Y+componentGapHeight;
Node a=n;
bool first=true;
while(a!=null) {
// the horizontal lines at the beginning and the end
g.DrawLine( linePen , p.X +componentArcSize*3/2 , a.sub.posLine.Y , p.X +(n.altSize.Width-a.size.Width)/2 , a.sub.posLine.Y);
g.DrawLine( linePen , p.X -componentArcSize*3/2 + n.altSize.Width+1 , a.sub.posLine.Y , p.X +(n.altSize.Width-a.size.Width)/2 + a.size.Width , a.sub.posLine.Y);
// if the first Alternative draw differnt Arcs
if(first) {
g.DrawArc ( linePen , p.X , n.posLine.Y , componentArcSize , componentArcSize , 270 , 90);
g.DrawArc ( linePen , p.X +n.altSize.Width-componentArcSize , n.posLine.Y , componentArcSize , componentArcSize , 180 , 90);
first=false;
}
// else draw other Arcs and vertical lines
else {
g.DrawArc ( linePen , p.X + componentArcSize , a.sub.posLine.Y-componentArcSize , componentArcSize , componentArcSize , 90 , 90);
g.DrawLine( linePen , p.X + componentArcSize , n.posLine.Y +componentArcSize/2 , p.X + componentArcSize , a.posLine.Y-componentArcSize/2+1);
g.DrawArc ( linePen , p.X - componentArcSize*2 + n.altSize.Width , a.sub.posLine.Y - componentArcSize , componentArcSize , componentArcSize , 0 , 90);
g.DrawLine( linePen , p.X - componentArcSize + n.altSize.Width , n.posLine.Y +componentArcSize/2 , p.X - componentArcSize + n.altSize.Width , a.posLine.Y-componentArcSize/2+1);
}
PointF pf=new PointF(p.X+(n.altSize.Width+a.size.Width)/2,p1.Y);
a.sub.drawComponentsInverse(pf,a.size);
a=a.down;
}
}
if(n.up)
samelevel=false;
n=n.next;
}
}
//----------------- for optimizing ----------------------
//compare two nodes on the basis of structure and value
public static bool Compare(Node n1, Node n2) {
if(n1.typ==n2.typ) {
if(n1.typ==Node.nt || n1.typ==Node.t) {
if(n1.sym.name!=n2.sym.name) return false;
}
return true;
}
return false;
}
/*
* compare two graphs on the basis of structure and value
* if untilIter is set, n1 and n2 are treated in a different way:
* the graph n1 to the iter node is compared to the iter subnode
* params: n1 must be the node before iter if untilIter==true
* params: n2 must be the first subnode of iter if untilIter==true
*/
public static bool DeepCompare(Node n1, Node n2, bool untilIter) {
bool samelevel=true;
Node identifier=n2; //helps to identify the relevant iter node
while(n1!=null && samelevel) {
//just compare nodes until the iter node
if(untilIter) {
if(n1.typ==Node.iter && n1.sub==identifier) {
if(n1==n2) { //last iter node's next points to the iter
if(Node.trace) Console.WriteLine("true: iter node reached, graphs match");
return true;
} else {
if(Node.trace) Console.WriteLine("false: iter node reached, graphs do not match");
return false;
}
}
}
if(n2==null) {
if(Node.trace) Console.WriteLine("false: second enclosing substructure ended before first");
return false;
}
if(!Compare(n1,n2)) {
if(Node.trace) Console.WriteLine("false: node not same type/content");
return false;
}
//--> t,nt,eps is ok, go to next
if(n1.typ==Node.opt|| n1.typ==Node.iter || n1.typ==Node.rerun) {
if(!DeepCompare(n1.sub, n2.sub,false)) {
if(Node.trace) Console.WriteLine("false: false in subelem of iter,opt or rerun");
return false;
}
if(n1.typ==Node.rerun && !DeepCompare(n1.itergraph, n2.itergraph, false)) {
if(Node.trace) Console.WriteLine("false: itergraph of rerun doesn't match");
return false;
}
}
else if(n1.typ==Node.alt) {
Node a1=n1,a2=n2;
while(a1!=null) {
if(a2==null) {
if(Node.trace) Console.WriteLine("false: false in subalt, second node null");
return false;
}
if(!DeepCompare(a1.sub,a2.sub,false)) {
if(Node.trace) Console.WriteLine("false: false in subelem of subalt");
return false;
}
a1=a1.down;
a2=a2.down;
}
if(a2!=null) {
if(Node.trace) Console.WriteLine("false: second alt has more alternatives");
return false;
}
}
if(n1.up) {
if(!n2.up) {
if(Node.trace) Console.WriteLine("false: second has not finished enclosing structure");
return false;
}
samelevel=false;
}
n1=n1.next;
n2=n2.next;
}
if(n1==null && n2!=null) {
if(Node.trace) Console.WriteLine("false: first enclosing substructure ended before second");
return false;
}
return true;
}
//calls all methods which optimize the graphs
public static void Optimize() {
foreach(Symbol s in Symbol.nonterminals) {
Node.RemoveWrongLinebreaks(s.graph.l,null,s);
if(optimizeGraph) Node.RemoveRedundancy(s.graph.l,null,s); //remove redundant iter/opts
if(optimizeGraph) Node.RemoveEps(s.graph.l,null,s); //remove eps nodes and redundant eps nodes in alternatives
if(optimizeGraph) Node.OptimizeIter(s.graph.l,null,s);
}
}
//removes all unnecessary and wrong linebreaks (wrap-nodes) from the graph
public static void RemoveWrongLinebreaks(Node n,Node parent, Symbol s) {
bool samelevel=true;
Node i=n;
while(i!=null && samelevel) {
if(i.typ==Node.wrap) {
//if in outer structure, just remove multiple wraps
if(parent==null) {
while(i.next!=null && i.next.typ==Node.wrap) {
i.next=i.next.next;
}
} //if in inner structure remove it
else {
//if \n is first element of substructure
if(n==i) {
//parent==null doesn't occur
//if \n is the only subelement
if(i.up ||i.next==null) {
Node eps=new Node(Node.eps, null);
parent.sub=eps;
eps.up=i.up;
eps.next=i.next;
n=eps;
} else {
parent.sub=i.next;
n=parent.sub;
}
} else { //if within substructure
Node j=n;
while(j.next!=i) j=j.next;
j.next=i.next;
j.up=i.up;
}
}
}
else if(i.typ==Node.opt || i.typ==Node.iter || i.typ==Node.rerun)
RemoveWrongLinebreaks(i.sub,i,s);
else if(i.typ==Node.alt) {
Node a=i;
while(a!=null) {
RemoveWrongLinebreaks(a.sub,a,s);
a=a.down;
}
}
if(i.up) {
samelevel=false;
}
i=i.next;
}
}
private static void RemoveRedundancy(Node n, Node parent, Symbol s) {
bool samelevel=true; //next node in same level?
Node begin=n;
while(n!=null && samelevel) {
if(n.typ==Node.alt) {
Node a=n;
while(a!=null) {
RemoveRedundancy(a.sub,a,s);
a=a.down;
}
}
else if(n.typ==Node.iter) {
while((n.sub.typ==Node.iter || n.sub.typ==Node.opt) && n.sub.up) {
//EbnfForm.WriteLine("Rendundant "+Node.nTyp[n.sub.typ]+" Node removed (iter).");
n.sub=n.sub.sub;
Node i=n.sub;
while(!i.up) {
i=i.next;
}
i.next=n;
}
RemoveRedundancy(n.sub,n,s);
} else if(n.typ==Node.opt) {
bool containsIter=false;
while((n.sub.typ==Node.opt && (n.sub.up || n.sub.next==null)) || (n.sub.typ==Node.iter && (n.sub.up || n.sub.next==null))) {
//if(n.sub.typ==Node.opt || containsIter) EbnfForm.WriteLine("Rendundant "+Node.nTyp[n.sub.typ]+" Node removed (opt).");
if(n.sub.typ==Node.iter) containsIter=true;
n.sub=n.sub.sub;
}
if(containsIter) {
Node iter=new Node(Node.iter,n.sub);
iter.next=n.next;
if(n==begin) {
if(parent==null) {
s.graph.l=iter;
} else {
parent.sub=iter;
}
} else {
Node j=begin;
while(j.next!=n) {
j=j.next;
}
j.next=iter;
}
n=iter;
//set correct next pointer of last subelement of new iter
Node i=iter.sub;
while(i.next!=null && !i.up) i=i.next;
i.next=iter;
}
RemoveRedundancy(n.sub,n,s);
}
if(n.up) samelevel=false;
n=n.next;
}
}
private static void RemoveEps(Node n, Node parent, Symbol s) {
bool samelevel=true; //next node in same level?
Node begin=n;
while(n!=null && samelevel) {
if(n.typ==Node.eps) {
if(n==begin) {
if(parent==null) {
//if the graph only consists of an eps, let it live
if(n.next!=null) {
s.graph.l=n.next;
begin=n.next;
}
} //else: at beginning of substructure not required (iter/opt/alt subnodes were already handled)
} else {
Node i=begin;
while(i.next!=n) {
i=i.next;
}
i.next=n.next;
i.up=n.up;
}
}
else if(n.typ==Node.iter || n.typ==Node.opt) {
if(n.sub.typ==Node.eps && (n.sub.next==null || n.sub.up)) {
if(n==begin) {
if(parent==null) { //beginning of graph
//if graph only consists of this iter/opt, then replace it with an eps node
if(n.next==null) {
Node eps=new Node(Node.eps, null);
s.graph.l=eps;
s.graph.r=eps;
} else { //remove that node
s.graph.l=n.next;
begin=n.next;
}
} //else: at beginning of substructure not required (iter/opt/alt subnodes were already handled)
} else { //within substructure
Node i=begin;
while(i.next!=n) {
i=i.next;
}
if(n.up) i.up=true;
i.next=n.next;
}
} else RemoveEps(n.sub,n,s);
}
else if(n.typ==Node.alt) {
Node a=n;
//count number of eps
int numOfEps=0;
while(a!=null) {
//CheckSubAlts(a);
if(a.sub.typ==Node.eps && (a.sub.next==null || a.sub.up)) numOfEps++;
a=a.down;
}
a=n;
while(numOfEps>1) {
if(n!=a && a.sub.typ==Node.eps && (a.sub.next==null || a.sub.up)) {
Node i=n;
while(i.down!=a) {
i=i.down;
}
i.down=a.down;
numOfEps--;
}
a=a.down;
}
RemoveSameAlts(n);
PutEpsAtBeginningOfAlt(begin,n,parent,s);
//optimize subcomponents
a=n;
while(a!=null) {
//if not the left eps node
if(!(a.sub.typ==Node.eps && (a.sub.next==null || a.sub.up))) RemoveEps(a.sub,a,s);
a=a.down;
}
}
if(n.up) samelevel=false;
n=n.next;
}
}
//removes all empty iter/opt nodes in alternatives, as well as multiple eps nodes at the beginning:
//they would bug a condition in RemoveEps
private static void CheckSubAlts(Node alt) {
//remove all empty iter/opts
//make sure, that at least one eps Node will exist
Node eps=new Node(Node.eps,null);
eps.next=alt.sub;
alt.sub=eps;
Node i=alt.sub;
bool samelevel=true;
while(i!=null && samelevel) {
//if empty iter/opt
if((i.typ==Node.iter || i.typ==Node.opt) && i.sub.typ==Node.eps && (i.sub.next==null || i.sub.up)) {
//case i==alt.sub not possible
Node a=alt.sub;
while(a.next!=i) a=a.next;
a.next=i.next;
}
if(i.up) samelevel=false;
i=i.next;
}
i=alt.sub;
//remove multiple eps nodes at the beginning
if(i.typ==Node.eps) {
while(i.next!=null && !i.next.up && i.next.typ==Node.eps) {
i.next=i.next.next;
}
}
}
private static void RemoveSameAlts(Node alt) {
Node a=alt;
while(a!=null) {
Node i=a.down;
while(i!=null) {
if(DeepCompare(a.sub,i.sub,false)) {
Node n=a;
while(n.down!=i) n=n.down;
n.down=i.down;
}
i=i.down;
}
a=a.down;
}
}
private static void PutEpsAtBeginningOfAlt(Node n,Node alt,Node parent, Symbol s) {
Node a=alt;
bool containsEps=false;
//determine if eps is contained
while(a!=null) {
//if eps node
if(a.sub.typ==Node.eps && (a.sub.next==null || a.sub.up)) containsEps=true;
a=a.down;
}
if(containsEps) {
//remove eps node
a=alt;
while(a!=null) {
//if eps node
if(a.sub.typ==Node.eps && (a.sub.next==null || a.sub.up)) {
//remove eps only if within alternatives
if(a!=alt) {
Node i=alt;
while(i.down!=a) i=i.down;
i.down=a.down;
}
break; //there can be only one eps in the alts because same nodes have already been removed
}
a=a.down;
}
//insert eps, if first alt isn't eps
if(!(alt.sub.typ==Node.eps && (alt.sub.next==null || alt.sub.up))) {
Node eps=new Node(Node.eps,null);
eps.next=alt.next;
eps.up=true;
Node a1= new Node(Node.alt,eps);
a1.down=alt;
if(alt==n) {
if(parent==null) s.graph.l=a1;
else parent.sub=a1;
} else {
Node i=n;
while (i.next!=alt) i=i.next;
i.next=a1;
}
a1.next=alt.next;
a1.up=alt.up;
alt.next=null;
}
}
}
//optimizes enclosing structures and recursively its substructures
private static void OptimizeIter(Node n, Node parent, Symbol s) {
bool samelevel=true; //next node in same level?
Node i=n;
while(i!=null && samelevel) {
if(i.typ==Node.opt) OptimizeIter(i.sub,i,s);
else if(i.typ==Node.alt) {
Node a=i;
while(a!=null) {
OptimizeIter(a.sub,a,s);
a=a.down;
}
}
else if(i.typ==Node.iter) {
//first optimize the iter substructure
OptimizeIter(i.sub,i,s);
//while loop to DeepCompare from every node until the iter node
Node j=n;
bool matchFound=false;
while(j!=i && !matchFound) {
Node k=i.sub;
bool samelevel2=true;
while(k!=null && samelevel2 && !matchFound) {
if(DeepCompare(j,k,true)) {
//EbnfForm.WriteLine("Iter node optimized.");
matchFound=true;
//replace the iter node and the nodes before by the rerun node
Node re= new Node(Node.rerun, k);
if(j==n) {
if(parent==null) {
s.graph.l=re;
n=re;
}
else {
parent.sub=re;
n=re;
}
} else {
Node l=n;
while(l.next!=j) l=l.next;
l.next=re;
}
//if a {b a} isolate b
if(k!=i.sub) {
re.itergraph=i.sub;
Node temp=re.itergraph;
while(temp.next!=k) temp=temp.next;
temp.next=null;
}
re.next=i.next;
re.up=i.up;
i=re;
}
if(k.up) samelevel2=false;
k=k.next;
}
j=j.next;
}
}
if(i.up) samelevel=false;
i=i.next;
}
}
}
public class Graph {
public Node l; // left end of graph = head
public Node r; // right end of graph = list of nodes to be linked to successor graph
public Size graphSize;
public Graph() {
l = null; r = null;
}
public Graph(Node left, Node right) {
l = left; r = right;
}
public Graph(Node p) {
l = p; r = p;
}
public static void MakeFirstAlt(Graph g) {
g.l = new Node(Node.alt, g.l);
g.l.next = g.r;
g.r = g.l;
}
public static void MakeAlternative(Graph g1, Graph g2) {
g2.l = new Node(Node.alt, g2.l);
Node p = g1.l; while (p.down != null) p = p.down;
p.down = g2.l;
p = g1.r; while (p.next != null) p = p.next;
p.next = g2.r;
}
public static void MakeSequence(Graph g1, Graph g2) {
if(g1.l==null && g1.r==null) {/*case: g1 is empty */
g1.l=g2.l;g1.r=g2.r;
} else {
Node p = g1.r.next; g1.r.next = g2.l; // link head node
while (p != null) { // link substructure
Node q = p.next; p.next = g2.l; p.up = true;
p = q;
}
g1.r = g2.r;
}
}
public static void MakeIteration(Graph g) {
g.l = new Node(Node.iter, g.l);
Node p = g.r;
g.r = g.l;
while (p != null) {
Node q = p.next; p.next = g.l; p.up = true;
p = q;
}
}
public static void MakeOption(Graph g) {
g.l = new Node(Node.opt, g.l);
g.l.next = g.r;
g.r = g.l;
}
public static void Finish(Graph g) {
Node p = g.r;
while (p != null) {
Node q = p.next; p.next = null; p = q;
}
}
}
/*-------------------------------------------------------------------------
EBNF Visualizer
Copyright (c) 2005 Stefan Schoergenhumer, Markus Dopler
supported by Hanspeter Moessenboeck, University of Linz
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
This class has been generated by the Compiler Generator Coco/R.
See: http://www.ssw.uni-linz.ac.at/Research/Projects/Coco/
-------------------------------------------------------------------------*/
using System;
public class Parser {
const int _EOF = 0;
const int _ident = 1;
const int _terminal = 2;
const int _wrap = 3;
const int maxT = 13;
const bool T = true;
const bool x = false;
const int minErrDist = 2;
public static Token t; // last recognized token
public static Token la; // lookahead token
static int errDist = minErrDist;
static void SynErr (int n) {
if (errDist >= minErrDist) Errors.SynErr(la.line, la.col, n);
errDist = 0;
}
public static void SemErr (string msg) {
if (errDist >= minErrDist) Errors.Error(t.line, t.col, msg);
errDist = 0;
}
static void Get () {
for (;;) {
t = la;
la = Scanner.Scan();
if (la.kind <= maxT) { ++errDist; break; }
la = t;
}
}
static void Expect (int n) {
if (la.kind==n) Get(); else { SynErr(n); }
}
static bool StartOf (int s) {
return set[s, la.kind];
}
static void ExpectWeak (int n, int follow) {
if (la.kind == n) Get();
else {
SynErr(n);
while (!StartOf(follow)) Get();
}
}
static bool WeakSeparator (int n, int syFol, int repFol) {
bool[] s = new bool[maxT+1];
if (la.kind == n) { Get(); return true; }
else if (StartOf(repFol)) return false;
else {
for (int i=0; i <= maxT; i++) {
s[i] = set[syFol, i] || set[repFol, i] || set[0, i];
}
SynErr(n);
while (!s[la.kind]) Get();
return StartOf(syFol);
}
}
static void EBNF() {
Rule();
while (la.kind == 1) {
Rule();
}
}
static void Rule() {
Expect(1);
Node n;
Symbol s=Symbol.Find(t.val); //look if already known
if(s==null) n=new Node(new Symbol(Node.nt,t.val));
else {
if(s.typ==Node.nt) {
String message="ERROR: Nonterminal symbol "+t.val+" has been defined multiple times.";
EbnfForm.WriteLine(message);
n=new Node(new Symbol(0,"BUG"));
} else { //if only considered as terminal symbol until now
s.typ=Node.nt;
Symbol.terminalToNt(s.name);
Symbol.terminalToNt(s.name);
Node.terminalToNt(s.name);
n=Node.Find(s.name);
}
}
Expect(4);
Expr(out n.sym.graph);
Expect(5);
Graph.Finish(n.sym.graph);
}
static void Expr(out Graph g) {
Graph g1;
Alt(out g);
bool first = true;
while (la.kind == 6) {
Get();
Alt(out g1);
if (first) { Graph.MakeFirstAlt(g); first = false; }
Graph.MakeAlternative(g, g1);
}
}
static void Alt(out Graph g) {
Graph g1; g=new Graph();
while (StartOf(1)) {
Sym(out g1);
Graph.MakeSequence(g, g1);
}
if(g.l==null && g.r==null)
g=new Graph(new Node(Node.eps,null));
}
static void Sym(out Graph g) {
Graph g1;g=new Graph();
switch (la.kind) {
case 1: {
Get();
Symbol s=Symbol.Find(t.val);
Node n;
if(s!=null) n= new Node(s);
else n=new Node(new Symbol(Node.t,t.val)); //type could be nt, but not known yet
g=new Graph(n);
break;
}
case 2: {
Get();
char[] trim=new char[1];
trim[0]=t.val[0];
String temp=t.val.Trim(trim);
Node n =new Node(new Symbol(Node.t,temp));
g=new Graph(n);
break;
}
case 3: {
Get();
Node n =new Node(Node.wrap,null);
g=new Graph(n);
break;
}
case 7: {
Get();
Expr(out g1);
Expect(8);
g=g1;
break;
}
case 9: {
Get();
Expr(out g1);
Expect(10);
Graph.MakeOption(g1);
g=g1;
break;
}
case 11: {
Get();
Expr(out g1);
Expect(12);
Graph.MakeIteration(g1);
g=g1;
break;
}
default: SynErr(14); break;
}
}
public static void Parse() {
la = new Token();
la.val = "";
Get();
EBNF();
Expect(0);
}
static bool[,] set = {
{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{x,T,T,T, x,x,x,T, x,T,x,T, x,x,x}
};
} // end Parser
public class Errors {
public static int count = 0; // number of errors detected
public static string errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text
public static void SynErr (int line, int col, int n) {
string s;
switch (n) {
case 0: s = "EOF expected"; break;
case 1: s = "ident expected"; break;
case 2: s = "terminal expected"; break;
case 3: s = "wrap expected"; break;
case 4: s = "\"=\" expected"; break;
case 5: s = "\".\" expected"; break;
case 6: s = "\"|\" expected"; break;
case 7: s = "\"(\" expected"; break;
case 8: s = "\")\" expected"; break;
case 9: s = "\"[\" expected"; break;
case 10: s = "\"]\" expected"; break;
case 11: s = "\"{\" expected"; break;
case 12: s = "\"}\" expected"; break;
case 13: s = "??? expected"; break;
case 14: s = "invalid Sym"; break;
default: s = "error " + n; break;
}
Console.WriteLine(Errors.errMsgFormat, line, col, s);
EbnfForm.WriteLine("ERROR: Line: "+line+" Col: "+ col+": "+ s);
count++;
}
public static void SemErr (int line, int col, int n) {
Console.WriteLine(errMsgFormat, line, col, ("error " + n));
count++;
}
public static void Error (int line, int col, string s) {
Console.WriteLine(errMsgFormat, line, col, s);
count++;
}
public static void Exception (string s) {
Console.WriteLine(s);
System.Environment.Exit(1);
}
} // Errors
/*-------------------------------------------------------------------------
EBNF Visualizer
Copyright (c) 2005 Stefan Schoergenhumer, Markus Dopler
supported by Hanspeter Moessenboeck, University of Linz
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
This class has been generated by the Compiler Generator Coco/R.
See: http://www.ssw.uni-linz.ac.at/Research/Projects/Coco/
-------------------------------------------------------------------------*/
using System;
using System.IO;
using System.Collections;
using System.Text;
public class Token {
public int kind; // token kind
public int pos; // token position in the source text (starting at 0)
public int col; // token column (starting at 0)
public int line; // token line (starting at 1)
public string val; // token value
public Token next; // AW 2003-03-07 Tokens are kept in linked list
}
public class Buffer {
public const char EOF = (char)256;
static byte[] buf;
static int bufLen;
static int pos;
public static void Fill (Stream s) {
bufLen = (int) s.Length;
buf = new byte[bufLen];
s.Read(buf, 0, bufLen);
pos = 0;
}
public static int Read () {
if (pos < bufLen) return buf[pos++];
else return EOF; /* pdt */
}
public static int Peek () {
if (pos < bufLen) return buf[pos];
else return EOF; /* pdt */
}
/* AW 2003-03-10 moved this from ParserGen.cs */
public static string GetString (int beg, int end) {
StringBuilder s = new StringBuilder(64);
int oldPos = Buffer.Pos;
Buffer.Pos = beg;
while (beg < end) { s.Append((char)Buffer.Read()); beg++; }
Buffer.Pos = oldPos;
return s.ToString();
}
public static int Pos {
get { return pos; }
set {
if (value < 0) pos = 0;
else if (value >= bufLen) pos = bufLen;
else pos = value;
}
}
}
public class Scanner {
const char EOL = '\n';
const int eofSym = 0; /* pdt */
const int charSetSize = 256;
const int maxT = 13;
const int noSym = 13;
static short[] start = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 0, 0, 3, 10, 11, 0, 0, 0, 0, 8, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, 5, 13, 0, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 9, 15, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-1};
static Token t; // current token
static char ch; // current input character
static int pos; // column number of current character
static int line; // line number of current character
static int lineStart; // start position of current line
static int oldEols; // EOLs that appeared in a comment;
static BitArray ignore; // set of characters to be ignored by the scanner
static Token tokens; // the complete input token stream
static Token pt; // current peek token
public static void Init (string fileName) {
FileStream s = null;
try {
s = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
Init(s);
} catch (IOException) {
EbnfForm.WriteLine("--- Cannot open file "+ fileName);
//System.Environment.Exit(1);
} finally {
if (s != null) s.Close();
}
}
public static void Init (Stream s) {
Buffer.Fill(s);
pos = -1; line = 1; lineStart = 0;
oldEols = 0;
NextCh();
ignore = new BitArray(charSetSize+1);
ignore[' '] = true; // blanks are always white space
ignore[9] = true; ignore[10] = true; ignore[13] = true;
//--- AW: fill token list
tokens = new Token(); // first token is a dummy
Token node = tokens;
do {
node.next = NextToken();
node = node.next;
} while (node.kind != eofSym);
node.next = node;
node.val = "EOF";
t = pt = tokens;
}
static void NextCh() {
if (oldEols > 0) { ch = EOL; oldEols--; }
else {
ch = (char)Buffer.Read(); pos++;
// replace isolated '\r' by '\n' in order to make
// eol handling uniform across Windows, Unix and Mac
if (ch == '\r' && Buffer.Peek() != '\n') ch = EOL;
if (ch == EOL) { line++; lineStart = pos + 1; }
}
}
static void CheckLiteral() {
switch (t.val) {
default: break;
}
}
/* AW Scan() renamed to NextToken() */
static Token NextToken() {
while (ignore[ch]) NextCh();
t = new Token();
t.pos = pos; t.col = pos - lineStart + 1; t.line = line;
int state = start[ch];
StringBuilder buf = new StringBuilder(16);
buf.Append(ch); NextCh();
switch (state) {
case -1: { t.kind = eofSym; goto done; } // NextCh already done /* pdt */
case 0: { t.kind = noSym; goto done; } // NextCh already done
case 1:
if ((ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z')) {buf.Append(ch); NextCh(); goto case 1;}
else {t.kind = 1; goto done;}
case 2:
if ((ch >= ' ' && ch <= '!' || ch >= '#' && ch <= '~')) {buf.Append(ch); NextCh(); goto case 2;}
else if (ch == '"') {buf.Append(ch); NextCh(); goto case 4;}
else {t.kind = noSym; goto done;}
case 3:
if ((ch >= ' ' && ch <= '&' || ch >= '(' && ch <= '~')) {buf.Append(ch); NextCh(); goto case 3;}
else if (ch == 39) {buf.Append(ch); NextCh(); goto case 4;}
else {t.kind = noSym; goto done;}
case 4:
{t.kind = 2; goto done;}
case 5:
if (ch == 'n') {buf.Append(ch); NextCh(); goto case 6;}
else {t.kind = noSym; goto done;}
case 6:
{t.kind = 3; goto done;}
case 7:
{t.kind = 4; goto done;}
case 8:
{t.kind = 5; goto done;}
case 9:
{t.kind = 6; goto done;}
case 10:
{t.kind = 7; goto done;}
case 11:
{t.kind = 8; goto done;}
case 12:
{t.kind = 9; goto done;}
case 13:
{t.kind = 10; goto done;}
case 14:
{t.kind = 11; goto done;}
case 15:
{t.kind = 12; goto done;}
}
done:
t.val = buf.ToString();
return t;
}
/* AW 2003-03-07 get the next token, move on and synch peek token with current */
public static Token Scan () {
t = pt = t.next;
return t;
}
/* AW 2003-03-07 get the next token, ignore pragmas */
public static Token Peek () {
do { // skip pragmas while peeking
pt = pt.next;
} while (pt.kind > maxT);
return pt;
}
/* AW 2003-03-11 to make sure peek start at current scan position */
public static void ResetPeek () { pt = t; }
} // end Scanner
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>EBNF-Visualizer - Manual</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Pragma" content="no-cache">
<meta content="EBNF, GIF, Visualizer, Grafik, Syntax, Diagramm" name="keywords">
</head>
<body>
<h1>EBNF Visualizer - Manual</h1>
<h2>Content</h2>
<a href="#Introduction"> Introduction </a><br>
<a href="#Simple"> Simple example </a><br>
<a href="#EBNF"> EBNF - Extended Backus Naur Form</a><br>
<a href="#Writing"> Writing an .ebnf-file </a><br>
<a href="#Menu"> Menu </a><br>
<a href="#Functions"> Functions </a><br>
<a href="#License"> License & Copyright </a><br>
<a href="#Contact"> Contact </a><br>
<h2><a name="Introduction">Introduction</a></h2>
This program visualizes EBNF (Extended Backus Naur Form). Therefore an .ebnf File is required, which contains rules written in EBNF. The program parses the rules, visualizes them in form of syntax diagrams and is able to generate .gif files for further use. Furthermore the program allows to manipulate the look of the generated syntax diagrams.
<h2><a name="Simple">Simple example</a></h2>
<h3>Step 1:</h3>
Create a .ebnf file with a rule just like “A= a [b] c.”. A .ebnf file is just a simple .txt file, just change the ending of the file.
<h3>Step 2:</h3>
Start the program and open the .ebnf file via the menu entry “Load Grammar…”. The program parses it. If there exist errors in the .ebnf file, it would be reported in the log window. Otherwise the rule menu will be activated.<p><img src="Manual\open.JPG" alt="Open a .ebnf file">
<h3>Step 3:</h3>
Choose a rule from the loaded grammar in the rule menu. The chosen rule will be drawn.
<p><img src="Manual\choose.JPG" alt="Chose a rule">
<h3>Step 4 (optional):</h3>
Change the look of the syntax diagram in the menu File/Settings.
<p><img src="Manual\settings.JPG" alt="Settings">
<h3>Step 5 (optional):</h3>
Save the syntax diagram or just copy/paste it.
<h2><a name="EBNF">EBNF - Extended Backus Naur Form</a></h2>
EBNF is used to define the grammar of programming languages.
<br>Therefore a set of rules is specified. These are known as production rules.
They define the patterns or sequences of symbols allowed in the language. Each production rule defines the pattern that represents a named structured part of the language, such as an expression or a statement.
The name of such a part is called a non-terminal symbol in the language. The basic building blocks of the language are symbols which stand for themselves.
These can be individual characters or combinations such as keywords and arithmetic operators. These basic elements of the language are called terminal symbols.
<h2><a name="Writing">Writing an .ebnf-file</a></h2>
The following description is informal but will allow you to write EBNF that works with this program.<p>
A grammar consists of a set of rules. A rule consist of an identifier, followed by “=”, a sequence of meta, terminal and nonterminal symbols and ends with “.” (e.g. “A= a b [c].”)
<h3>Terminal symbol:</h3>
A terminal symbol can be any string. They are separated by space characters. <br>For example in the rule “A = a b [c].” a, b and c are terminal symbols.
<p><img src="Manual\terminal.GIF" alt="Simple example"><p>
It is also possible to put a terminal symbol under quotes (“) or apostrophes (‘) which is required in some cases.
(eg. Quote = "'" a "'".)<p>
<img src="Manual\Quote.GIF" alt="Simple example"><p>It’s also needed for numbers, because identifiers must begin with a character.
<h3>Nonterminal symbol:</h3>
A nonterminal symbol can’t be created in an explicit way.<br>If a terminal symbol matches the string of an rule identifier, it is automatically considered as a nonterminal symbol.<br>
For example, in the rule “A = a A | b.” A is a nonterminal symbol.
<p><img src="Manual\nonterminal.GIF" alt="Simple example">
<h3>Meta symbols:</h3>
<h4>- option “[“ “]”</h4>
The sequence of symbols within these brackets are optional.<br>
(e.g. Rule1 = “begin [optional things] end.”)
<p><img src="Manual\Rule1.GIF" alt="Simple example">
<h4>-iteration “{“ “}”</h4>
The sequence of symbols within these brackets can occur from zero to infinite times.<br>
(e.g. Rule2 = “begin {and again} end.”)
<p><img src="Manual\Rule2.GIF" alt="Simple example">
<h4>-alternative “|”</h4>
It allows to choose a sequence of symbols.<br>
(e.g. Rule3 = “I am a (good | bad) programmer.”)
<p><img src="Manual\Rule3.GIF" alt="Simple example">
<h4>-grouping “(“ “)”</h4>
These brackets are used to group sequences of symbols in a mathematical way.
<h3>Special symbol – Line break:</h3>
This program allows to make explicit line breaks within a syntax diagram. To do this, use “\n” in the outer structure of the rule. That means, it will be ignored within an option, iteration or alternative.<br>
(e.g. “Linebreak = First line \n Second line \n End.”)
<p><img src="Manual\Linebreak.GIF" alt="Simple example">
<h2><a name="Menu">Menu</a></h2>
<p><img src="Manual\open.JPG" alt="Menu">
<h3>File:</h3>
<h4>Load Grammar… :</h4>
Allows to load a grammar file (*.ebnf).
<h4>Save As… :</h4>
The current rule can be stored as .GIF file or as .EMF file.
The Windows Enhanced Metafile Format .EMF is based on vectorgraphics and
therefore better suitable for printing or zooming.
<h4>Copy:</h4>
The current rule is copied to the clipboard as a picture. It is possible to paste it into any program which allows to paste from the clipboard.
<h4>Settings… :</h4>
<p><img src="Manual\settings.JPG" alt="Settings"><br>
In the menu settings the look of the syntax diagrams can be changed.
<h5>Font</h5>
Change the font of terminal and nonterminal symbols.
<h5>Line</h5>
Change the thickness and the color of the line. It is also possible to increase or decrease the size of the arrows.
<h5>Dimensions</h5>
It is possible to increase or decrease the horizontal and vertical gap between the symbols.
The look of the terminal and nonterminal symbols can be changed by increasing or decreasing the gap between the line of the symbol and its name.
<h5>Optimizations</h5>
If the checkbox "Enable optimizations" is activated, the syntaxgraph will be optimized. Any change of this option requires to reload the actual grammar.
<h2><a name="Functions">Functions</a></h2>
<h3>Optimizations:</h3>
This happens implicitly. It is possible to disable them in the settings menu.<br>
If the syntax graph is optimized, redundant und needless productions within a rule are deleted. That means empty nodes, iterations, options and alternatives are removed. If there is an empty alternative, it is moved to the first position. Already existing alternatives are removed.
Furthermore some productions are visualized in a more elegant way,
<br> for example “A = ab {ab}.”
<p><img src="Manual\optimize1not.GIF" alt="Optimize"><img src="Manual\optimize1.GIF" alt="Optimize"><p>
or “B = ab { cd ab}.”
<p><img src="Manual\optimize2not.GIF" alt="Optimize"><img src="Manual\optimize2.GIF" alt="Optimize"><p>
<h3>Navigation:</h3>
It is possible to navigate through an grammar by left-clicking on nonterminal symbols. Right-clicking allows to go back.
<h2><a name="License">License & Copyright</a></h2>
EBNF Visualizer<br>
Copyright (c) 2005 Stefan Schoergenhumer, Markus Dopler<br>
supported by Hanspeter Moessenboeck, University of Linz<br>
<p>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
<p>
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
<p>
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<h2><a name="Contact">Contact</a></h2>
For further questions, please write an Email to:<p>
Markus Dopler, k0156207@students.jku.at or<br>
Stefan Schörgenhumer, k0155531@students.jku.at
</body>
</html>
......@@ -567,10 +567,18 @@ cArea.prototype.tocBool = function () {
return this.getValue()[0].tocBool();
};
cArea.prototype.toString = function () {
var _c;
if( this.getRange() ){
return this.getRange().getName();
_c = this.getRange().getName();
}
return this._cells;
else{
_c = this._cells;
}
if( _c.indexOf(":") < 0 ){
_c = _c + ":" + _c;
}
return _c;
};
cArea.prototype.setRange = function ( cell ) {
this._cells = this.value = cell;
......@@ -712,8 +720,6 @@ cArea.prototype.index = function ( r, c, n ) {
return new cError( cErrorType.bad_reference );
}
};
/** @constructor */
......@@ -4585,7 +4591,7 @@ function gaussinv( x ) {
return z;
}
function lcl_getLanczosSum( fZ ) {
function getLanczosSum( fZ ) {
var num = [
23531376880.41075968857200767445163675473,
42919803642.64909876895789904700198885093,
......@@ -4645,8 +4651,8 @@ function lcl_getLanczosSum( fZ ) {
}
/** You must ensure fZ>0; fZ>171.624376956302 will overflow. */
function lcl_GetGammaHelper( fZ ) {
var gamma = lcl_getLanczosSum( fZ ),
function getGammaHelper( fZ ) {
var gamma = getLanczosSum( fZ ),
fg = 6.024680040776729583740234375,
zgHelp = fZ + fg - 0.5;
// avoid intermediate overflow
......@@ -4660,17 +4666,17 @@ function lcl_GetGammaHelper( fZ ) {
}
/** You must ensure fZ>0 */
function lcl_GetLogGammaHelper( fZ ) {
function getLogGammaHelper( fZ ) {
var _fg = 6.024680040776729583740234375, zgHelp = fZ + _fg - 0.5;
return Math.log( lcl_getLanczosSum( fZ ) ) + (fZ - 0.5) * Math.log( zgHelp ) - zgHelp;
return Math.log( getLanczosSum( fZ ) ) + (fZ - 0.5) * Math.log( zgHelp ) - zgHelp;
}
function getLogGamma( fZ ) {
if ( fZ >= maxGammaArgument )
return lcl_GetLogGammaHelper( fZ );
return getLogGammaHelper( fZ );
if ( fZ >= 0 )
return Math.log( lcl_GetGammaHelper( fZ ) );
return Math.log( getGammaHelper( fZ ) );
if ( fZ >= 0.5 )
return Math.log( lcl_GetGammaHelper( fZ + 1 ) / fZ );
return lcl_GetLogGammaHelper( fZ + 2 ) - Math.log( fZ + 1 ) - Math.log( fZ );
return Math.log( getGammaHelper( fZ + 1 ) / fZ );
return getLogGammaHelper( fZ + 2 ) - Math.log( fZ + 1 ) - Math.log( fZ );
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* PEG.js 0.8.0
*
* http://pegjs.majda.cz/
*
* Copyright (c) 2010-2013 David Majda
* Licensed under the MIT license.
*/
var PEG=function(undefined){var modules={define:function(e,t){function n(e){for(var t=r+e,n=/[^\/]+\/\.\.\/|\.\//;n.test(t);)t=t.replace(n,"");return modules[t]}var r=e.replace(/(^|\/)[^/]+$/,"$1"),s={exports:{}};t(s,n),this[e]=s.exports}};return modules.define("utils",function(e){var t={range:function(e,t){t===undefined&&(t=e,e=0);for(var n=new Array(Math.max(0,t-e)),r=0,s=e;t>s;r++,s++)n[r]=s;return n},find:function(e,t){for(var n=e.length,r=0;n>r;r++)if(t(e[r]))return e[r]},indexOf:function(e,t){for(var n=e.length,r=0;n>r;r++)if(t(e[r]))return r;return-1},contains:function(e,t){for(var n=e.length,r=0;n>r;r++)if(e[r]===t)return!0;return!1},each:function(e,t){for(var n=e.length,r=0;n>r;r++)t(e[r],r)},map:function(e,t){for(var n=[],r=e.length,s=0;r>s;s++)n[s]=t(e[s],s);return n},pluck:function(e,n){return t.map(e,function(e){return e[n]})},keys:function(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(n);return t},values:function(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(e[n]);return t},clone:function(e){var t={};for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t},defaults:function(e,t){for(var n in t)t.hasOwnProperty(n)&&(n in e||(e[n]=t[n]))},subclass:function(e,t){function n(){this.constructor=e}n.prototype=t.prototype,e.prototype=new n},padLeft:function(e,t,n){for(var r=e,s=n-e.length,i=0;s>i;i++)r=t+r;return r},escape:function(e){var n,r,s=e.charCodeAt(0);return 255>=s?(n="x",r=2):(n="u",r=4),"\\"+n+t.padLeft(s.toString(16).toUpperCase(),"0",r)},quote:function(e){return'"'+e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\x08/g,"\\b").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g,t.escape)+'"'},quoteForRegexpClass:function(e){return e.replace(/\\/g,"\\\\").replace(/\//g,"\\/").replace(/\]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\v/g,"\\x0B").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x01-\x08\x0E-\x1F\x80-\uFFFF]/g,t.escape)},buildNodeVisitor:function(e){return function(t){return e[t.type].apply(null,arguments)}},findRuleByName:function(e,n){return t.find(e.rules,function(e){return e.name===n})},indexOfRuleByName:function(e,n){return t.indexOf(e.rules,function(e){return e.name===n})}};e.exports=t}),modules.define("grammar-error",function(e,t){var n=t("./utils");e.exports=function(e){this.name="GrammarError",this.message=e},n.subclass(e.exports,Error)}),modules.define("parser",function(e,t){e.exports=function(){function e(e,t){function n(){this.constructor=e}n.prototype=t.prototype,e.prototype=new n}function n(e,t,n,r,s,i){this.message=e,this.expected=t,this.found=n,this.offset=r,this.line=s,this.column=i,this.name="SyntaxError"}function r(e){function r(e){throw o(e,null,Qr)}function s(t){function n(t,n,r){var s,i;for(s=n;r>s;s++)i=e.charAt(s),"\n"===i?(t.seenCR||t.line++,t.column=1,t.seenCR=!1):"\r"===i||"\u2028"===i||"\u2029"===i?(t.line++,t.column=1,t.seenCR=!0):(t.column++,t.seenCR=!1)}return es!==t&&(es>t&&(es=0,ts={line:1,column:1,seenCR:!1}),n(ts,es,t),es=t),ts}function i(e){ns>Kr||(Kr>ns&&(ns=Kr,rs=[]),rs.push(e))}function o(t,r,i){function o(e){var t=1;for(e.sort(function(e,t){return e.description<t.description?-1:e.description>t.description?1:0});t<e.length;)e[t-1]===e[t]?e.splice(t,1):t++}function a(e,t){function n(e){function t(e){return e.charCodeAt(0).toString(16).toUpperCase()}return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\x08/g,"\\b").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x00-\x07\x0B\x0E\x0F]/g,function(e){return"\\x0"+t(e)}).replace(/[\x10-\x1F\x80-\xFF]/g,function(e){return"\\x"+t(e)}).replace(/[\u0180-\u0FFF]/g,function(e){return"\\u0"+t(e)}).replace(/[\u1080-\uFFFF]/g,function(e){return"\\u"+t(e)})}var r,s,i,o=new Array(e.length);for(i=0;i<e.length;i++)o[i]=e[i].description;return r=e.length>1?o.slice(0,-1).join(", ")+" or "+o[e.length-1]:o[0],s=t?'"'+n(t)+'"':"end of input","Expected "+r+" but "+s+" found."}var p=s(i),c=i<e.length?e.charAt(i):null;return null!==r&&o(r),new n(null!==t?t:a(r,c),r,c,i,p.line,p.column)}function a(){var e,t,n,r,s;if(e=Kr,t=rt(),t!==ft)if(n=p(),n===ft&&(n=mt),n!==ft){if(r=[],s=c(),s!==ft)for(;s!==ft;)r.push(s),s=c();else r=gt;r!==ft?(Qr=e,t=vt(n,r),e=t):(Kr=e,e=gt)}else Kr=e,e=gt;else Kr=e,e=gt;return e}function p(){var e,t,n;return e=Kr,t=m(),t!==ft?(n=_(),n===ft&&(n=mt),n!==ft?(Qr=e,t=xt(t),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e}function c(){var e,t,n,r,s,i;return e=Kr,t=T(),t!==ft?(n=L(),n===ft&&(n=mt),n!==ft?(r=R(),r!==ft?(s=u(),s!==ft?(i=_(),i===ft&&(i=mt),i!==ft?(Qr=e,t=Pt(t,n,s),e=t):(Kr=e,e=gt)):(Kr=e,e=gt)):(Kr=e,e=gt)):(Kr=e,e=gt)):(Kr=e,e=gt),e}function u(){var e,t,n,r,s,i;if(e=Kr,t=l(),t!==ft){for(n=[],r=Kr,s=A(),s!==ft?(i=l(),i!==ft?(s=[s,i],r=s):(Kr=r,r=gt)):(Kr=r,r=gt);r!==ft;)n.push(r),r=Kr,s=A(),s!==ft?(i=l(),i!==ft?(s=[s,i],r=s):(Kr=r,r=gt)):(Kr=r,r=gt);n!==ft?(Qr=e,t=Rt(t,n),e=t):(Kr=e,e=gt)}else Kr=e,e=gt;return e}function l(){var e,t,n;for(e=Kr,t=[],n=f();n!==ft;)t.push(n),n=f();if(t!==ft?(n=m(),n!==ft?(Qr=e,t=bt(t,n),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft){for(e=Kr,t=[],n=f();n!==ft;)t.push(n),n=f();t!==ft&&(Qr=e,t=_t(t)),e=t}return e}function f(){var e,t,n,r;return e=Kr,t=T(),t!==ft?(n=b(),n!==ft?(r=d(),r!==ft?(Qr=e,t=At(t,r),e=t):(Kr=e,e=gt)):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=d()),e}function d(){var e,t,n;return e=Kr,t=y(),t!==ft?(n=h(),n!==ft?(Qr=e,t=Ct(n),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=Kr,t=C(),t!==ft?(n=m(),n!==ft?(Qr=e,t=$t(n),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=Kr,t=C(),t!==ft?(n=h(),n!==ft?(Qr=e,t=yt(n),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=Kr,t=$(),t!==ft?(n=m(),n!==ft?(Qr=e,t=Ft(n),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=Kr,t=$(),t!==ft?(n=h(),n!==ft?(Qr=e,t=Et(n),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=h()))))),e}function h(){var e,t,n;return e=Kr,t=g(),t!==ft?(n=F(),n!==ft?(Qr=e,t=kt(t),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=Kr,t=g(),t!==ft?(n=E(),n!==ft?(Qr=e,t=Ot(t),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=Kr,t=g(),t!==ft?(n=k(),n!==ft?(Qr=e,t=It(t),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=g()))),e}function g(){var e,t,n,r,s,i;return e=Kr,t=T(),t!==ft?(n=Kr,ss++,r=Kr,s=L(),s===ft&&(s=mt),s!==ft?(i=R(),i!==ft?(s=[s,i],r=s):(Kr=r,r=gt)):(Kr=r,r=gt),ss--,r===ft?n=St:(Kr=n,n=gt),n!==ft?(Qr=e,t=Tt(t),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),e===ft&&(e=N(),e===ft&&(e=z(),e===ft&&(e=Kr,t=S(),t!==ft&&(Qr=e,t=Nt()),e=t,e===ft&&(e=Kr,t=O(),t!==ft?(n=u(),n!==ft?(r=I(),r!==ft?(Qr=e,t=Lt(n),e=t):(Kr=e,e=gt)):(Kr=e,e=gt)):(Kr=e,e=gt))))),e}function m(){var e,t,n;return ss++,e=Kr,t=v(),t!==ft?(n=rt(),n!==ft?(Qr=e,t=jt(t),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),ss--,e===ft&&(t=ft,0===ss&&i(wt)),e}function v(){var t,n,r,s,o;if(t=Kr,n=Kr,123===e.charCodeAt(Kr)?(r=Dt,Kr++):(r=ft,0===ss&&i(Ut)),r!==ft){for(s=[],o=v(),o===ft&&(o=x());o!==ft;)s.push(o),o=v(),o===ft&&(o=x());s!==ft?(125===e.charCodeAt(Kr)?(o=Ht,Kr++):(o=ft,0===ss&&i(qt)),o!==ft?(r=[r,s,o],n=r):(Kr=n,n=gt)):(Kr=n,n=gt)}else Kr=n,n=gt;return n!==ft&&(n=e.substring(t,Kr)),t=n}function x(){var e,t;if(e=[],t=P(),t!==ft)for(;t!==ft;)e.push(t),t=P();else e=gt;return e}function P(){var t;return zt.test(e.charAt(Kr))?(t=e.charAt(Kr),Kr++):(t=ft,0===ss&&i(Gt)),t}function R(){var t,n,r;return t=Kr,61===e.charCodeAt(Kr)?(n=Mt,Kr++):(n=ft,0===ss&&i(Bt)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=Vt(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function b(){var t,n,r;return t=Kr,58===e.charCodeAt(Kr)?(n=Wt,Kr++):(n=ft,0===ss&&i(Xt)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=Yt(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function _(){var t,n,r;return t=Kr,59===e.charCodeAt(Kr)?(n=Zt,Kr++):(n=ft,0===ss&&i(Jt)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=Kt(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function A(){var t,n,r;return t=Kr,47===e.charCodeAt(Kr)?(n=Qt,Kr++):(n=ft,0===ss&&i(en)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=tn(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function C(){var t,n,r;return t=Kr,38===e.charCodeAt(Kr)?(n=nn,Kr++):(n=ft,0===ss&&i(rn)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=sn(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function $(){var t,n,r;return t=Kr,33===e.charCodeAt(Kr)?(n=on,Kr++):(n=ft,0===ss&&i(an)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=pn(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function y(){var t,n,r;return t=Kr,36===e.charCodeAt(Kr)?(n=cn,Kr++):(n=ft,0===ss&&i(un)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=ln(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function F(){var t,n,r;return t=Kr,63===e.charCodeAt(Kr)?(n=fn,Kr++):(n=ft,0===ss&&i(dn)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=hn(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function E(){var t,n,r;return t=Kr,42===e.charCodeAt(Kr)?(n=gn,Kr++):(n=ft,0===ss&&i(mn)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=vn(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function k(){var t,n,r;return t=Kr,43===e.charCodeAt(Kr)?(n=xn,Kr++):(n=ft,0===ss&&i(Pn)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=Rn(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function O(){var t,n,r;return t=Kr,40===e.charCodeAt(Kr)?(n=bn,Kr++):(n=ft,0===ss&&i(_n)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=An(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function I(){var t,n,r;return t=Kr,41===e.charCodeAt(Kr)?(n=Cn,Kr++):(n=ft,0===ss&&i($n)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=yn(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function S(){var t,n,r;return t=Kr,46===e.charCodeAt(Kr)?(n=Fn,Kr++):(n=ft,0===ss&&i(En)),n!==ft?(r=rt(),r!==ft?(Qr=t,n=kn(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function T(){var t,n,r,s,o,a;if(ss++,t=Kr,n=Kr,r=Kr,s=et(),s===ft&&(95===e.charCodeAt(Kr)?(s=In,Kr++):(s=ft,0===ss&&i(Sn))),s!==ft){for(o=[],a=et(),a===ft&&(a=K(),a===ft&&(95===e.charCodeAt(Kr)?(a=In,Kr++):(a=ft,0===ss&&i(Sn))));a!==ft;)o.push(a),a=et(),a===ft&&(a=K(),a===ft&&(95===e.charCodeAt(Kr)?(a=In,Kr++):(a=ft,0===ss&&i(Sn))));o!==ft?(s=[s,o],r=s):(Kr=r,r=gt)}else Kr=r,r=gt;return r!==ft&&(r=e.substring(n,Kr)),n=r,n!==ft?(r=rt(),r!==ft?(Qr=t,n=Tn(n),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),ss--,t===ft&&(n=ft,0===ss&&i(On)),t}function N(){var t,n,r,s;return ss++,t=Kr,n=w(),n===ft&&(n=U()),n!==ft?(105===e.charCodeAt(Kr)?(r=Ln,Kr++):(r=ft,0===ss&&i(wn)),r===ft&&(r=mt),r!==ft?(s=rt(),s!==ft?(Qr=t,n=jn(n,r),t=n):(Kr=t,t=gt)):(Kr=t,t=gt)):(Kr=t,t=gt),ss--,t===ft&&(n=ft,0===ss&&i(Nn)),t}function L(){var e,t,n;return ss++,e=Kr,t=w(),t===ft&&(t=U()),t!==ft?(n=rt(),n!==ft?(Qr=e,t=Un(t),e=t):(Kr=e,e=gt)):(Kr=e,e=gt),ss--,e===ft&&(t=ft,0===ss&&i(Dn)),e}function w(){var t,n,r,s;if(t=Kr,34===e.charCodeAt(Kr)?(n=Hn,Kr++):(n=ft,0===ss&&i(qn)),n!==ft){for(r=[],s=j();s!==ft;)r.push(s),s=j();r!==ft?(34===e.charCodeAt(Kr)?(s=Hn,Kr++):(s=ft,0===ss&&i(qn)),s!==ft?(Qr=t,n=zn(r),t=n):(Kr=t,t=gt)):(Kr=t,t=gt)}else Kr=t,t=gt;return t}function j(){var e;return e=D(),e===ft&&(e=W(),e===ft&&(e=X(),e===ft&&(e=Y(),e===ft&&(e=Z(),e===ft&&(e=J()))))),e}function D(){var t,n,r;return t=Kr,n=Kr,ss++,34===e.charCodeAt(Kr)?(r=Hn,Kr++):(r=ft,0===ss&&i(qn)),r===ft&&(92===e.charCodeAt(Kr)?(r=Gn,Kr++):(r=ft,0===ss&&i(Mn)),r===ft&&(r=pt())),ss--,r===ft?n=St:(Kr=n,n=gt),n!==ft?(e.length>Kr?(r=e.charAt(Kr),Kr++):(r=ft,0===ss&&i(Bn)),r!==ft?(Qr=t,n=Vn(r),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function U(){var t,n,r,s;if(t=Kr,39===e.charCodeAt(Kr)?(n=Wn,Kr++):(n=ft,0===ss&&i(Xn)),n!==ft){for(r=[],s=H();s!==ft;)r.push(s),s=H();r!==ft?(39===e.charCodeAt(Kr)?(s=Wn,Kr++):(s=ft,0===ss&&i(Xn)),s!==ft?(Qr=t,n=zn(r),t=n):(Kr=t,t=gt)):(Kr=t,t=gt)}else Kr=t,t=gt;return t}function H(){var e;return e=q(),e===ft&&(e=W(),e===ft&&(e=X(),e===ft&&(e=Y(),e===ft&&(e=Z(),e===ft&&(e=J()))))),e}function q(){var t,n,r;return t=Kr,n=Kr,ss++,39===e.charCodeAt(Kr)?(r=Wn,Kr++):(r=ft,0===ss&&i(Xn)),r===ft&&(92===e.charCodeAt(Kr)?(r=Gn,Kr++):(r=ft,0===ss&&i(Mn)),r===ft&&(r=pt())),ss--,r===ft?n=St:(Kr=n,n=gt),n!==ft?(e.length>Kr?(r=e.charAt(Kr),Kr++):(r=ft,0===ss&&i(Bn)),r!==ft?(Qr=t,n=Vn(r),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function z(){var t,n,r,s,o,a,p;if(ss++,t=Kr,91===e.charCodeAt(Kr)?(n=Zn,Kr++):(n=ft,0===ss&&i(Jn)),n!==ft)if(94===e.charCodeAt(Kr)?(r=Kn,Kr++):(r=ft,0===ss&&i(Qn)),r===ft&&(r=mt),r!==ft){for(s=[],o=G(),o===ft&&(o=M());o!==ft;)s.push(o),o=G(),o===ft&&(o=M());s!==ft?(93===e.charCodeAt(Kr)?(o=er,Kr++):(o=ft,0===ss&&i(tr)),o!==ft?(105===e.charCodeAt(Kr)?(a=Ln,Kr++):(a=ft,0===ss&&i(wn)),a===ft&&(a=mt),a!==ft?(p=rt(),p!==ft?(Qr=t,n=nr(r,s,a),t=n):(Kr=t,t=gt)):(Kr=t,t=gt)):(Kr=t,t=gt)):(Kr=t,t=gt)}else Kr=t,t=gt;else Kr=t,t=gt;return ss--,t===ft&&(n=ft,0===ss&&i(Yn)),t}function G(){var t,n,r,s;return t=Kr,n=M(),n!==ft?(45===e.charCodeAt(Kr)?(r=rr,Kr++):(r=ft,0===ss&&i(sr)),r!==ft?(s=M(),s!==ft?(Qr=t,n=ir(n,s),t=n):(Kr=t,t=gt)):(Kr=t,t=gt)):(Kr=t,t=gt),t}function M(){var e,t;return e=Kr,t=B(),t!==ft&&(Qr=e,t=or(t)),e=t}function B(){var e;return e=V(),e===ft&&(e=W(),e===ft&&(e=X(),e===ft&&(e=Y(),e===ft&&(e=Z(),e===ft&&(e=J()))))),e}function V(){var t,n,r;return t=Kr,n=Kr,ss++,93===e.charCodeAt(Kr)?(r=er,Kr++):(r=ft,0===ss&&i(tr)),r===ft&&(92===e.charCodeAt(Kr)?(r=Gn,Kr++):(r=ft,0===ss&&i(Mn)),r===ft&&(r=pt())),ss--,r===ft?n=St:(Kr=n,n=gt),n!==ft?(e.length>Kr?(r=e.charAt(Kr),Kr++):(r=ft,0===ss&&i(Bn)),r!==ft?(Qr=t,n=Vn(r),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function W(){var t,n,r,s;return t=Kr,92===e.charCodeAt(Kr)?(n=Gn,Kr++):(n=ft,0===ss&&i(Mn)),n!==ft?(r=Kr,ss++,s=K(),s===ft&&(120===e.charCodeAt(Kr)?(s=ar,Kr++):(s=ft,0===ss&&i(pr)),s===ft&&(117===e.charCodeAt(Kr)?(s=cr,Kr++):(s=ft,0===ss&&i(ur)),s===ft&&(s=pt()))),ss--,s===ft?r=St:(Kr=r,r=gt),r!==ft?(e.length>Kr?(s=e.charAt(Kr),Kr++):(s=ft,0===ss&&i(Bn)),s!==ft?(Qr=t,n=lr(s),t=n):(Kr=t,t=gt)):(Kr=t,t=gt)):(Kr=t,t=gt),t}function X(){var t,n,r,s;return t=Kr,e.substr(Kr,2)===fr?(n=fr,Kr+=2):(n=ft,0===ss&&i(dr)),n!==ft?(r=Kr,ss++,s=K(),ss--,s===ft?r=St:(Kr=r,r=gt),r!==ft?(Qr=t,n=hr(),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function Y(){var t,n,r,s,o,a;return t=Kr,e.substr(Kr,2)===gr?(n=gr,Kr+=2):(n=ft,0===ss&&i(mr)),n!==ft?(r=Kr,s=Kr,o=Q(),o!==ft?(a=Q(),a!==ft?(o=[o,a],s=o):(Kr=s,s=gt)):(Kr=s,s=gt),s!==ft&&(s=e.substring(r,Kr)),r=s,r!==ft?(Qr=t,n=vr(r),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function Z(){var t,n,r,s,o,a,p,c;return t=Kr,e.substr(Kr,2)===xr?(n=xr,Kr+=2):(n=ft,0===ss&&i(Pr)),n!==ft?(r=Kr,s=Kr,o=Q(),o!==ft?(a=Q(),a!==ft?(p=Q(),p!==ft?(c=Q(),c!==ft?(o=[o,a,p,c],s=o):(Kr=s,s=gt)):(Kr=s,s=gt)):(Kr=s,s=gt)):(Kr=s,s=gt),s!==ft&&(s=e.substring(r,Kr)),r=s,r!==ft?(Qr=t,n=vr(r),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function J(){var t,n,r;return t=Kr,92===e.charCodeAt(Kr)?(n=Gn,Kr++):(n=ft,0===ss&&i(Mn)),n!==ft?(r=at(),r!==ft?(Qr=t,n=Rr(r),t=n):(Kr=t,t=gt)):(Kr=t,t=gt),t}function K(){var t;return br.test(e.charAt(Kr))?(t=e.charAt(Kr),Kr++):(t=ft,0===ss&&i(_r)),t}function Q(){var t;return Ar.test(e.charAt(Kr))?(t=e.charAt(Kr),Kr++):(t=ft,0===ss&&i(Cr)),t}function et(){var e;return e=tt(),e===ft&&(e=nt()),e}function tt(){var t;return $r.test(e.charAt(Kr))?(t=e.charAt(Kr),Kr++):(t=ft,0===ss&&i(yr)),t}function nt(){var t;return Fr.test(e.charAt(Kr))?(t=e.charAt(Kr),Kr++):(t=ft,0===ss&&i(Er)),t}function rt(){var e,t;for(e=[],t=ct(),t===ft&&(t=at(),t===ft&&(t=st()));t!==ft;)e.push(t),t=ct(),t===ft&&(t=at(),t===ft&&(t=st()));return e}function st(){var e,t;return ss++,e=it(),e===ft&&(e=ot()),ss--,e===ft&&(t=ft,0===ss&&i(kr)),e}function it(){var t,n,r,s,o,a;if(t=Kr,e.substr(Kr,2)===Or?(n=Or,Kr+=2):(n=ft,0===ss&&i(Ir)),n!==ft){for(r=[],s=Kr,o=Kr,ss++,a=pt(),ss--,a===ft?o=St:(Kr=o,o=gt),o!==ft?(e.length>Kr?(a=e.charAt(Kr),Kr++):(a=ft,0===ss&&i(Bn)),a!==ft?(o=[o,a],s=o):(Kr=s,s=gt)):(Kr=s,s=gt);s!==ft;)r.push(s),s=Kr,o=Kr,ss++,a=pt(),ss--,a===ft?o=St:(Kr=o,o=gt),o!==ft?(e.length>Kr?(a=e.charAt(Kr),Kr++):(a=ft,0===ss&&i(Bn)),a!==ft?(o=[o,a],s=o):(Kr=s,s=gt)):(Kr=s,s=gt);r!==ft?(n=[n,r],t=n):(Kr=t,t=gt)}else Kr=t,t=gt;return t}function ot(){var t,n,r,s,o,a;if(t=Kr,e.substr(Kr,2)===Sr?(n=Sr,Kr+=2):(n=ft,0===ss&&i(Tr)),n!==ft){for(r=[],s=Kr,o=Kr,ss++,e.substr(Kr,2)===Nr?(a=Nr,Kr+=2):(a=ft,0===ss&&i(Lr)),ss--,a===ft?o=St:(Kr=o,o=gt),o!==ft?(e.length>Kr?(a=e.charAt(Kr),Kr++):(a=ft,0===ss&&i(Bn)),a!==ft?(o=[o,a],s=o):(Kr=s,s=gt)):(Kr=s,s=gt);s!==ft;)r.push(s),s=Kr,o=Kr,ss++,e.substr(Kr,2)===Nr?(a=Nr,Kr+=2):(a=ft,0===ss&&i(Lr)),ss--,a===ft?o=St:(Kr=o,o=gt),o!==ft?(e.length>Kr?(a=e.charAt(Kr),Kr++):(a=ft,0===ss&&i(Bn)),a!==ft?(o=[o,a],s=o):(Kr=s,s=gt)):(Kr=s,s=gt);r!==ft?(e.substr(Kr,2)===Nr?(s=Nr,Kr+=2):(s=ft,0===ss&&i(Lr)),s!==ft?(n=[n,r,s],t=n):(Kr=t,t=gt)):(Kr=t,t=gt)}else Kr=t,t=gt;return t}function at(){var t,n;return ss++,10===e.charCodeAt(Kr)?(t=jr,Kr++):(t=ft,0===ss&&i(Dr)),t===ft&&(e.substr(Kr,2)===Ur?(t=Ur,Kr+=2):(t=ft,0===ss&&i(Hr)),t===ft&&(13===e.charCodeAt(Kr)?(t=qr,Kr++):(t=ft,0===ss&&i(zr)),t===ft&&(8232===e.charCodeAt(Kr)?(t=Gr,Kr++):(t=ft,0===ss&&i(Mr)),t===ft&&(8233===e.charCodeAt(Kr)?(t=Br,Kr++):(t=ft,0===ss&&i(Vr)))))),ss--,t===ft&&(n=ft,0===ss&&i(wr)),t}function pt(){var t;return Wr.test(e.charAt(Kr))?(t=e.charAt(Kr),Kr++):(t=ft,0===ss&&i(Xr)),t}function ct(){var t,n;return ss++,Zr.test(e.charAt(Kr))?(t=e.charAt(Kr),Kr++):(t=ft,0===ss&&i(Jr)),ss--,t===ft&&(n=ft,0===ss&&i(Yr)),t}var ut,lt=arguments.length>1?arguments[1]:{},ft={},dt={grammar:a},ht=a,gt=ft,mt=null,vt=function(e,t){return{type:"grammar",initializer:e,rules:t}},xt=function(e){return{type:"initializer",code:e}},Pt=function(e,t,n){return{type:"rule",name:e,expression:null!==t?{type:"named",name:t,expression:n}:n}},Rt=function(e,t){if(t.length>0){var n=[e].concat(is.map(t,function(e){return e[1]}));return{type:"choice",alternatives:n}}return e},bt=function(e,t){var n=1!==e.length?{type:"sequence",elements:e}:e[0];return{type:"action",expression:n,code:t}},_t=function(e){return 1!==e.length?{type:"sequence",elements:e}:e[0]},At=function(e,t){return{type:"labeled",label:e,expression:t}},Ct=function(e){return{type:"text",expression:e}},$t=function(e){return{type:"semantic_and",code:e}},yt=function(e){return{type:"simple_and",expression:e}},Ft=function(e){return{type:"semantic_not",code:e}},Et=function(e){return{type:"simple_not",expression:e}},kt=function(e){return{type:"optional",expression:e}},Ot=function(e){return{type:"zero_or_more",expression:e}},It=function(e){return{type:"one_or_more",expression:e}},St=void 0,Tt=function(e){return{type:"rule_ref",name:e}},Nt=function(){return{type:"any"}},Lt=function(e){return e},wt={type:"other",description:"action"},jt=function(e){return e.substr(1,e.length-2)},Dt="{",Ut={type:"literal",value:"{",description:'"{"'},Ht="}",qt={type:"literal",value:"}",description:'"}"'},zt=/^[^{}]/,Gt={type:"class",value:"[^{}]",description:"[^{}]"},Mt="=",Bt={type:"literal",value:"=",description:'"="'},Vt=function(){return"="},Wt=":",Xt={type:"literal",value:":",description:'":"'},Yt=function(){return":"},Zt=";",Jt={type:"literal",value:";",description:'";"'},Kt=function(){return";"},Qt="/",en={type:"literal",value:"/",description:'"/"'},tn=function(){return"/"},nn="&",rn={type:"literal",value:"&",description:'"&"'},sn=function(){return"&"},on="!",an={type:"literal",value:"!",description:'"!"'},pn=function(){return"!"},cn="$",un={type:"literal",value:"$",description:'"$"'},ln=function(){return"$"},fn="?",dn={type:"literal",value:"?",description:'"?"'},hn=function(){return"?"},gn="*",mn={type:"literal",value:"*",description:'"*"'},vn=function(){return"*"},xn="+",Pn={type:"literal",value:"+",description:'"+"'},Rn=function(){return"+"},bn="(",_n={type:"literal",value:"(",description:'"("'},An=function(){return"("},Cn=")",$n={type:"literal",value:")",description:'")"'},yn=function(){return")"},Fn=".",En={type:"literal",value:".",description:'"."'},kn=function(){return"."},On={type:"other",description:"identifier"},In="_",Sn={type:"literal",value:"_",description:'"_"'},Tn=function(e){return e},Nn={type:"other",description:"literal"},Ln="i",wn={type:"literal",value:"i",description:'"i"'},jn=function(e,t){return{type:"literal",value:e,ignoreCase:"i"===t}},Dn={type:"other",description:"string"},Un=function(e){return e},Hn='"',qn={type:"literal",value:'"',description:'"\\""'},zn=function(e){return e.join("")},Gn="\\",Mn={type:"literal",value:"\\",description:'"\\\\"'},Bn={type:"any",description:"any character"},Vn=function(e){return e},Wn="'",Xn={type:"literal",value:"'",description:'"\'"'},Yn={type:"other",description:"character class"},Zn="[",Jn={type:"literal",value:"[",description:'"["'},Kn="^",Qn={type:"literal",value:"^",description:'"^"'},er="]",tr={type:"literal",value:"]",description:'"]"'},nr=function(e,t,n){var r=is.map(t,function(e){return e.data}),s="["+(null!==e?e:"")+is.map(t,function(e){return e.rawText}).join("")+"]"+(null!==n?n:"");return{type:"class",parts:r,rawText:s,inverted:"^"===e,ignoreCase:"i"===n}},rr="-",sr={type:"literal",value:"-",description:'"-"'},ir=function(e,t){return e.data.charCodeAt(0)>t.data.charCodeAt(0)&&r("Invalid character range: "+e.rawText+"-"+t.rawText+"."),{data:[e.data,t.data],rawText:e.rawText+"-"+t.rawText}},or=function(e){return{data:e,rawText:is.quoteForRegexpClass(e)}},ar="x",pr={type:"literal",value:"x",description:'"x"'},cr="u",ur={type:"literal",value:"u",description:'"u"'},lr=function(e){return e.replace("b","\b").replace("f","\f").replace("n","\n").replace("r","\r").replace("t"," ").replace("v"," ")},fr="\\0",dr={type:"literal",value:"\\0",description:'"\\\\0"'},hr=function(){return"\x00"},gr="\\x",mr={type:"literal",value:"\\x",description:'"\\\\x"'},vr=function(e){return String.fromCharCode(parseInt(e,16))},xr="\\u",Pr={type:"literal",value:"\\u",description:'"\\\\u"'},Rr=function(e){return e},br=/^[0-9]/,_r={type:"class",value:"[0-9]",description:"[0-9]"},Ar=/^[0-9a-fA-F]/,Cr={type:"class",value:"[0-9a-fA-F]",description:"[0-9a-fA-F]"},$r=/^[a-z]/,yr={type:"class",value:"[a-z]",description:"[a-z]"},Fr=/^[A-Z]/,Er={type:"class",value:"[A-Z]",description:"[A-Z]"},kr={type:"other",description:"comment"},Or="//",Ir={type:"literal",value:"//",description:'"//"'},Sr="/*",Tr={type:"literal",value:"/*",description:'"/*"'},Nr="*/",Lr={type:"literal",value:"*/",description:'"*/"'},wr={type:"other",description:"end of line"},jr="\n",Dr={type:"literal",value:"\n",description:'"\\n"'},Ur="\r\n",Hr={type:"literal",value:"\r\n",description:'"\\r\\n"'},qr="\r",zr={type:"literal",value:"\r",description:'"\\r"'},Gr="\u2028",Mr={type:"literal",value:"\u2028",description:'"\\u2028"'},Br="\u2029",Vr={type:"literal",value:"\u2029",description:'"\\u2029"'},Wr=/^[\n\r\u2028\u2029]/,Xr={type:"class",value:"[\\n\\r\\u2028\\u2029]",description:"[\\n\\r\\u2028\\u2029]"},Yr={type:"other",description:"whitespace"},Zr=/^[ \t\x0B\f\xA0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]/,Jr={type:"class",value:"[ \\t\\x0B\\f\\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]",description:"[ \\t\\x0B\\f\\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]"},Kr=0,Qr=0,es=0,ts={line:1,column:1,seenCR:!1},ns=0,rs=[],ss=0;if("startRule"in lt){if(!(lt.startRule in dt))throw new Error("Can't start parsing from rule \""+lt.startRule+'".');ht=dt[lt.startRule]}var is=t("./utils");if(ut=ht(),ut!==ft&&Kr===e.length)return ut;throw ut!==ft&&Kr<e.length&&i({type:"end",description:"end of input"}),o(null,rs,ns)}return e(n,Error),{SyntaxError:n,parse:r}}()}),modules.define("compiler/opcodes",function(e){e.exports={PUSH:0,PUSH_CURR_POS:1,POP:2,POP_CURR_POS:3,POP_N:4,NIP:5,APPEND:6,WRAP:7,TEXT:8,IF:9,IF_ERROR:10,IF_NOT_ERROR:11,WHILE_NOT_ERROR:12,MATCH_ANY:13,MATCH_STRING:14,MATCH_STRING_IC:15,MATCH_REGEXP:16,ACCEPT_N:17,ACCEPT_STRING:18,FAIL:19,REPORT_SAVED_POS:20,REPORT_CURR_POS:21,CALL:22,RULE:23,SILENT_FAILS_ON:24,SILENT_FAILS_OFF:25}}),modules.define("compiler/passes/generate-bytecode",function(e,t){var n=t("../../utils"),r=t("../opcodes");e.exports=function(e){function t(e){var t=n.indexOf(f,function(t){return t===e});return-1===t?f.push(e)-1:t}function s(e,n){return t("function("+e.join(", ")+") {"+n+"}")}function i(){return Array.prototype.concat.apply([],arguments)}function o(e,t,n){return e.concat([t.length,n.length],t,n)}function a(e,t){return e.concat([t.length],t)}function p(e,t,s,i){var o=n.map(n.values(s),function(e){return i-e});return[r.CALL,e,t,o.length].concat(o)}function c(e,n,s){var a=t("void 0"),p=t("peg$FAILED");return i([r.PUSH_CURR_POS],[r.SILENT_FAILS_ON],d(e,{sp:s.sp+1,env:{},action:null}),[r.SILENT_FAILS_OFF],o([n?r.IF_ERROR:r.IF_NOT_ERROR],i([r.POP],[n?r.POP:r.POP_CURR_POS],[r.PUSH,a]),i([r.POP],[n?r.POP_CURR_POS:r.POP],[r.PUSH,p])))}function u(e,a,c){var u=s(n.keys(c.env),e),l=t("void 0"),f=t("peg$FAILED");return i([r.REPORT_CURR_POS],p(u,0,c.env,c.sp),o([r.IF],i([r.POP],[r.PUSH,a?f:l]),i([r.POP],[r.PUSH,a?l:f])))}function l(e){return a([r.WHILE_NOT_ERROR],i([r.APPEND],e))}var f=[],d=n.buildNodeVisitor({grammar:function(e){n.each(e.rules,d),e.consts=f},rule:function(e){e.bytecode=d(e.expression,{sp:-1,env:{},action:null})},named:function(e,s){var a=t('{ type: "other", description: '+n.quote(e.name)+" }");return i([r.SILENT_FAILS_ON],d(e.expression,s),[r.SILENT_FAILS_OFF],o([r.IF_ERROR],[r.FAIL,a],[]))},choice:function(e,t){function n(e,t){return i(d(e[0],{sp:t.sp,env:{},action:null}),e.length>1?o([r.IF_ERROR],i([r.POP],n(e.slice(1),t)),[]):[])}return n(e.alternatives,t)},action:function(e,t){var a={},c="sequence"!==e.expression.type||0===e.expression.elements.length,u=d(e.expression,{sp:t.sp+(c?1:0),env:a,action:e}),l=s(n.keys(a),e.code);return c?i([r.PUSH_CURR_POS],u,o([r.IF_NOT_ERROR],i([r.REPORT_SAVED_POS,1],p(l,1,a,t.sp+2)),[]),[r.NIP]):u},sequence:function(e,a){function c(t,a){var u,l;return t.length>0?(u=e.elements.length-t.slice(1).length,i(d(t[0],{sp:a.sp,env:a.env,action:null}),o([r.IF_NOT_ERROR],c(t.slice(1),{sp:a.sp+1,env:a.env,action:a.action}),i(u>1?[r.POP_N,u]:[r.POP],[r.POP_CURR_POS],[r.PUSH,failedIndex])))):a.action?(l=s(n.keys(a.env),a.action.code),i([r.REPORT_SAVED_POS,e.elements.length],p(l,e.elements.length,a.env,a.sp),[r.NIP])):i([r.WRAP,e.elements.length],[r.NIP])}var u;return e.elements.length>0?(failedIndex=t("peg$FAILED"),i([r.PUSH_CURR_POS],c(e.elements,{sp:a.sp+1,env:a.env,action:a.action}))):(u=t("[]"),[r.PUSH,u])},labeled:function(e,t){return t.env[e.label]=t.sp+1,d(e.expression,{sp:t.sp,env:{},action:null})},text:function(e,t){return i([r.PUSH_CURR_POS],d(e.expression,{sp:t.sp+1,env:{},action:null}),o([r.IF_NOT_ERROR],[r.TEXT],[]),[r.NIP])},simple_and:function(e,t){return c(e.expression,!1,t)},simple_not:function(e,t){return c(e.expression,!0,t)},semantic_and:function(e,t){return u(e.code,!1,t)},semantic_not:function(e,t){return u(e.code,!0,t)},optional:function(e,n){var s=t("null");return i(d(e.expression,{sp:n.sp,env:{},action:null}),o([r.IF_ERROR],i([r.POP],[r.PUSH,s]),[]))},zero_or_more:function(e,n){var s=t("[]");return expressionCode=d(e.expression,{sp:n.sp+1,env:{},action:null}),i([r.PUSH,s],expressionCode,l(expressionCode),[r.POP])},one_or_more:function(e,n){var s=t("[]");return failedIndex=t("peg$FAILED"),expressionCode=d(e.expression,{sp:n.sp+1,env:{},action:null}),i([r.PUSH,s],expressionCode,o([r.IF_NOT_ERROR],i(l(expressionCode),[r.POP]),i([r.POP],[r.POP],[r.PUSH,failedIndex])))},rule_ref:function(t){return[r.RULE,n.indexOfRuleByName(e,t.name)]},literal:function(e){var s,i;return e.value.length>0?(s=t(e.ignoreCase?n.quote(e.value.toLowerCase()):n.quote(e.value)),i=t(["{",'type: "literal",',"value: "+n.quote(e.value)+",","description: "+n.quote(n.quote(e.value)),"}"].join(" ")),o(e.ignoreCase?[r.MATCH_STRING_IC,s]:[r.MATCH_STRING,s],e.ignoreCase?[r.ACCEPT_N,e.value.length]:[r.ACCEPT_STRING,s],[r.FAIL,i])):(s=t('""'),[r.PUSH,s])},"class":function(e){var s,i,a;return s=e.parts.length>0?"/^["+(e.inverted?"^":"")+n.map(e.parts,function(e){return e instanceof Array?n.quoteForRegexpClass(e[0])+"-"+n.quoteForRegexpClass(e[1]):n.quoteForRegexpClass(e)}).join("")+"]/"+(e.ignoreCase?"i":""):e.inverted?"/^[\\S\\s]/":"/^(?!)/",i=t(s),a=t(["{",'type: "class",',"value: "+n.quote(e.rawText)+",","description: "+n.quote(e.rawText),"}"].join(" ")),o([r.MATCH_REGEXP,i],[r.ACCEPT_N,1],[r.FAIL,a])},any:function(){var e=t('{ type: "any", description: "any character" }');return o([r.MATCH_ANY],[r.ACCEPT_N,1],[r.FAIL,e])}});d(e)}}),modules.define("compiler/passes/generate-javascript",function(module,require){var utils=require("../../utils"),op=require("../opcodes");module.exports=function(ast,options){function indent2(e){return e.replace(/^(.+)$/gm," $1")}function indent4(e){return e.replace(/^(.+)$/gm," $1")}function indent8(e){return e.replace(/^(.+)$/gm," $1")}function indent10(e){return e.replace(/^(.+)$/gm," $1")}function generateTables(){return"size"===options.optimize?["peg$consts = [",indent2(ast.consts.join(",\n")),"],","","peg$bytecode = [",indent2(utils.map(ast.rules,function(e){return"peg$decode("+utils.quote(utils.map(e.bytecode,function(e){return String.fromCharCode(e+32)}).join(""))+")"}).join(",\n")),"],"].join("\n"):utils.map(ast.consts,function(e,t){return"peg$c"+t+" = "+e+","}).join("\n")}function generateCacheHeader(e){return["var key = peg$currPos * "+ast.rules.length+" + "+e+","," cached = peg$cache[key];","","if (cached) {"," peg$currPos = cached.nextPos;"," return cached.result;","}",""].join("\n")}function generateCacheFooter(e){return["","peg$cache[key] = { nextPos: peg$currPos, result: "+e+" };"].join("\n")}function generateInterpreter(){function e(e,t){var n=t+3,r="bc[ip + "+(n-2)+"]",s="bc[ip + "+(n-1)+"]";return["ends.push(end);","ips.push(ip + "+n+" + "+r+" + "+s+");","","if ("+e+") {"," end = ip + "+n+" + "+r+";"," ip += "+n+";","} else {"," end = ip + "+n+" + "+r+" + "+s+";"," ip += "+n+" + "+r+";","}","","break;"].join("\n")}function t(e){var t=2,n="bc[ip + "+(t-1)+"]";return["if ("+e+") {"," ends.push(end);"," ips.push(ip);",""," end = ip + "+t+" + "+n+";"," ip += "+t+";","} else {"," ip += "+t+" + "+n+";","}","","break;"].join("\n")}function n(){var e=4,t="bc[ip + "+(e-1)+"]";return["params = bc.slice(ip + "+e+", ip + "+e+" + "+t+");","for (i = 0; i < "+t+"; i++) {"," params[i] = stack[stack.length - 1 - params[i]];","}","","stack.splice("," stack.length - bc[ip + 2],"," bc[ip + 2],"," peg$consts[bc[ip + 1]].apply(null, params)",");","","ip += "+e+" + "+t+";","break;"].join("\n")}var r=[];return r.push(["function peg$decode(s) {"," var bc = new Array(s.length), i;",""," for (i = 0; i < s.length; i++) {"," bc[i] = s.charCodeAt(i) - 32;"," }",""," return bc;","}","","function peg$parseRule(index) {"," var bc = peg$bytecode[index],"," ip = 0,"," ips = [],"," end = bc.length,"," ends = [],"," stack = [],"," params, i;",""].join("\n")),options.cache&&r.push(indent2(generateCacheHeader("index"))),r.push([" function protect(object) {",' return Object.prototype.toString.apply(object) === "[object Array]" ? [] : object;'," }",""," while (true) {"," while (ip < end) {"," switch (bc[ip]) {"," case "+op.PUSH+":"," stack.push(protect(peg$consts[bc[ip + 1]]));"," ip += 2;"," break;",""," case "+op.PUSH_CURR_POS+":"," stack.push(peg$currPos);"," ip++;"," break;",""," case "+op.POP+":"," stack.pop();"," ip++;"," break;",""," case "+op.POP_CURR_POS+":"," peg$currPos = stack.pop();"," ip++;"," break;",""," case "+op.POP_N+":"," stack.length -= bc[ip + 1];"," ip += 2;"," break;",""," case "+op.NIP+":"," stack.splice(-2, 1);"," ip++;"," break;",""," case "+op.APPEND+":"," stack[stack.length - 2].push(stack.pop());"," ip++;"," break;",""," case "+op.WRAP+":"," stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1]));"," ip += 2;"," break;",""," case "+op.TEXT+":"," stack.pop();"," stack.push(input.substring(stack[stack.length - 1], peg$currPos));"," ip++;"," break;",""," case "+op.IF+":",indent10(e("stack[stack.length - 1]",0)),""," case "+op.IF_ERROR+":",indent10(e("stack[stack.length - 1] === peg$FAILED",0)),""," case "+op.IF_NOT_ERROR+":",indent10(e("stack[stack.length - 1] !== peg$FAILED",0)),""," case "+op.WHILE_NOT_ERROR+":",indent10(t("stack[stack.length - 1] !== peg$FAILED")),""," case "+op.MATCH_ANY+":",indent10(e("input.length > peg$currPos",0)),""," case "+op.MATCH_STRING+":",indent10(e("input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]",1)),""," case "+op.MATCH_STRING_IC+":",indent10(e("input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]",1)),""," case "+op.MATCH_REGEXP+":",indent10(e("peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))",1)),""," case "+op.ACCEPT_N+":"," stack.push(input.substr(peg$currPos, bc[ip + 1]));"," peg$currPos += bc[ip + 1];"," ip += 2;"," break;",""," case "+op.ACCEPT_STRING+":"," stack.push(peg$consts[bc[ip + 1]]);"," peg$currPos += peg$consts[bc[ip + 1]].length;"," ip += 2;"," break;",""," case "+op.FAIL+":"," stack.push(peg$FAILED);"," if (peg$silentFails === 0) {"," peg$fail(peg$consts[bc[ip + 1]]);"," }"," ip += 2;"," break;",""," case "+op.REPORT_SAVED_POS+":"," peg$reportedPos = stack[stack.length - 1 - bc[ip + 1]];"," ip += 2;"," break;",""," case "+op.REPORT_CURR_POS+":"," peg$reportedPos = peg$currPos;"," ip++;"," break;",""," case "+op.CALL+":",indent10(n()),""," case "+op.RULE+":"," stack.push(peg$parseRule(bc[ip + 1]));"," ip += 2;"," break;",""," case "+op.SILENT_FAILS_ON+":"," peg$silentFails++;"," ip++;"," break;",""," case "+op.SILENT_FAILS_OFF+":"," peg$silentFails--;"," ip++;"," break;",""," default:",' throw new Error("Invalid opcode: " + bc[ip] + ".");'," }"," }",""," if (ends.length > 0) {"," end = ends.pop();"," ip = ips.pop();"," } else {"," break;"," }"," }"].join("\n")),options.cache&&r.push(indent2(generateCacheFooter("stack[0]"))),r.push([""," return stack[0];","}"].join("\n")),r.join("\n")
}function generateRuleFunction(rule){function c(e){return"peg$c"+e}function s(e){return"s"+e}function compile(bc){function compileCondition(e,t){var n,r,s,i,o=t+3,a=bc[ip+o-2],p=bc[ip+o-1],c=stack.sp;if(ip+=o,n=compile(bc.slice(ip,ip+a)),s=stack.sp,ip+=a,p>0&&(stack.sp=c,r=compile(bc.slice(ip,ip+p)),i=stack.sp,ip+=p,s!==i))throw new Error("Branches of a condition must move the stack pointer in the same way.");parts.push("if ("+e+") {"),parts.push(indent2(n)),p>0&&(parts.push("} else {"),parts.push(indent2(r))),parts.push("}")}function compileLoop(e){var t,n,r=2,s=bc[ip+r-1],i=stack.sp;if(ip+=r,t=compile(bc.slice(ip,ip+s)),n=stack.sp,ip+=s,n!==i)throw new Error("Body of a loop can't move the stack pointer.");parts.push("while ("+e+") {"),parts.push(indent2(t)),parts.push("}")}function compileCall(){var e=4,t=bc[ip+e-1],n=c(bc[ip+1])+"("+utils.map(bc.slice(ip+e,ip+e+t),stackIndex).join(", ")+")";stack.pop(bc[ip+2]),parts.push(stack.push(n)),ip+=e+t}function stackIndex(e){return stack.index(e)}for(var ip=0,end=bc.length,parts=[],value;end>ip;)switch(bc[ip]){case op.PUSH:parts.push(stack.push("[]"===ast.consts[bc[ip+1]]?"[]":c(bc[ip+1]))),ip+=2;break;case op.PUSH_CURR_POS:parts.push(stack.push("peg$currPos")),ip++;break;case op.POP:stack.pop(),ip++;break;case op.POP_CURR_POS:parts.push("peg$currPos = "+stack.pop()+";"),ip++;break;case op.POP_N:stack.pop(bc[ip+1]),ip+=2;break;case op.NIP:value=stack.pop(),stack.pop(),parts.push(stack.push(value)),ip++;break;case op.APPEND:value=stack.pop(),parts.push(stack.top()+".push("+value+");"),ip++;break;case op.WRAP:parts.push(stack.push("["+stack.pop(bc[ip+1]).join(", ")+"]")),ip+=2;break;case op.TEXT:stack.pop(),parts.push(stack.push("input.substring("+stack.top()+", peg$currPos)")),ip++;break;case op.IF:compileCondition(stack.top(),0);break;case op.IF_ERROR:compileCondition(stack.top()+" === peg$FAILED",0);break;case op.IF_NOT_ERROR:compileCondition(stack.top()+" !== peg$FAILED",0);break;case op.WHILE_NOT_ERROR:compileLoop(stack.top()+" !== peg$FAILED",0);break;case op.MATCH_ANY:compileCondition("input.length > peg$currPos",0);break;case op.MATCH_STRING:compileCondition(eval(ast.consts[bc[ip+1]]).length>1?"input.substr(peg$currPos, "+eval(ast.consts[bc[ip+1]]).length+") === "+c(bc[ip+1]):"input.charCodeAt(peg$currPos) === "+eval(ast.consts[bc[ip+1]]).charCodeAt(0),1);break;case op.MATCH_STRING_IC:compileCondition("input.substr(peg$currPos, "+eval(ast.consts[bc[ip+1]]).length+").toLowerCase() === "+c(bc[ip+1]),1);break;case op.MATCH_REGEXP:compileCondition(c(bc[ip+1])+".test(input.charAt(peg$currPos))",1);break;case op.ACCEPT_N:parts.push(stack.push(bc[ip+1]>1?"input.substr(peg$currPos, "+bc[ip+1]+")":"input.charAt(peg$currPos)")),parts.push(bc[ip+1]>1?"peg$currPos += "+bc[ip+1]+";":"peg$currPos++;"),ip+=2;break;case op.ACCEPT_STRING:parts.push(stack.push(c(bc[ip+1]))),parts.push(eval(ast.consts[bc[ip+1]]).length>1?"peg$currPos += "+eval(ast.consts[bc[ip+1]]).length+";":"peg$currPos++;"),ip+=2;break;case op.FAIL:parts.push(stack.push("peg$FAILED")),parts.push("if (peg$silentFails === 0) { peg$fail("+c(bc[ip+1])+"); }"),ip+=2;break;case op.REPORT_SAVED_POS:parts.push("peg$reportedPos = "+stack.index(bc[ip+1])+";"),ip+=2;break;case op.REPORT_CURR_POS:parts.push("peg$reportedPos = peg$currPos;"),ip++;break;case op.CALL:compileCall();break;case op.RULE:parts.push(stack.push("peg$parse"+ast.rules[bc[ip+1]].name+"()")),ip+=2;break;case op.SILENT_FAILS_ON:parts.push("peg$silentFails++;"),ip++;break;case op.SILENT_FAILS_OFF:parts.push("peg$silentFails--;"),ip++;break;default:throw new Error("Invalid opcode: "+bc[ip]+".")}return parts.join("\n")}var parts=[],code,stack={sp:-1,maxSp:-1,push:function(e){var t=s(++this.sp)+" = "+e+";";return this.sp>this.maxSp&&(this.maxSp=this.sp),t},pop:function(){var e,t;return 0===arguments.length?s(this.sp--):(e=arguments[0],t=utils.map(utils.range(this.sp-e+1,this.sp+1),s),this.sp-=e,t)},top:function(){return s(this.sp)},index:function(e){return s(this.sp-e)}};return code=compile(rule.bytecode),parts.push(["function peg$parse"+rule.name+"() {"," var "+utils.map(utils.range(0,stack.maxSp+1),s).join(", ")+";",""].join("\n")),options.cache&&parts.push(indent2(generateCacheHeader(utils.indexOfRuleByName(ast,rule.name)))),parts.push(indent2(code)),options.cache&&parts.push(indent2(generateCacheFooter(s(0)))),parts.push([""," return "+s(0)+";","}"].join("\n")),parts.join("\n")}var parts=[],startRuleIndices,startRuleIndex,startRuleFunctions,startRuleFunction;parts.push(["(function() {"," /*"," * Generated by PEG.js 0.8.0."," *"," * http://pegjs.majda.cz/"," */",""," function peg$subclass(child, parent) {"," function ctor() { this.constructor = child; }"," ctor.prototype = parent.prototype;"," child.prototype = new ctor();"," }",""," function SyntaxError(message, expected, found, offset, line, column) {"," this.message = message;"," this.expected = expected;"," this.found = found;"," this.offset = offset;"," this.line = line;"," this.column = column;","",' this.name = "SyntaxError";'," }",""," peg$subclass(SyntaxError, Error);",""," function parse(input) {"," var options = arguments.length > 1 ? arguments[1] : {},",""," peg$FAILED = {},",""].join("\n")),"size"===options.optimize?(startRuleIndices="{ "+utils.map(options.allowedStartRules,function(e){return e+": "+utils.indexOfRuleByName(ast,e)}).join(", ")+" }",startRuleIndex=utils.indexOfRuleByName(ast,options.allowedStartRules[0]),parts.push([" peg$startRuleIndices = "+startRuleIndices+","," peg$startRuleIndex = "+startRuleIndex+","].join("\n"))):(startRuleFunctions="{ "+utils.map(options.allowedStartRules,function(e){return e+": peg$parse"+e}).join(", ")+" }",startRuleFunction="peg$parse"+options.allowedStartRules[0],parts.push([" peg$startRuleFunctions = "+startRuleFunctions+","," peg$startRuleFunction = "+startRuleFunction+","].join("\n"))),parts.push(""),parts.push(indent8(generateTables())),parts.push([""," peg$currPos = 0,"," peg$reportedPos = 0,"," peg$cachedPos = 0,"," peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },"," peg$maxFailPos = 0,"," peg$maxFailExpected = [],"," peg$silentFails = 0,",""].join("\n")),options.cache&&parts.push(" peg$cache = {},"),parts.push([" peg$result;",""].join("\n")),"size"===options.optimize?parts.push([' if ("startRule" in options) {'," if (!(options.startRule in peg$startRuleIndices)) {",' throw new Error("Can\'t start parsing from rule \\"" + options.startRule + "\\".");'," }",""," peg$startRuleIndex = peg$startRuleIndices[options.startRule];"," }"].join("\n")):parts.push([' if ("startRule" in options) {'," if (!(options.startRule in peg$startRuleFunctions)) {",' throw new Error("Can\'t start parsing from rule \\"" + options.startRule + "\\".");'," }",""," peg$startRuleFunction = peg$startRuleFunctions[options.startRule];"," }"].join("\n")),parts.push([""," function text() {"," return input.substring(peg$reportedPos, peg$currPos);"," }",""," function offset() {"," return peg$reportedPos;"," }",""," function line() {"," return peg$computePosDetails(peg$reportedPos).line;"," }",""," function column() {"," return peg$computePosDetails(peg$reportedPos).column;"," }",""," function expected(description) {"," throw peg$buildException("," null,",' [{ type: "other", description: description }],'," peg$reportedPos"," );"," }",""," function error(message) {"," throw peg$buildException(message, null, peg$reportedPos);"," }",""," function peg$computePosDetails(pos) {"," function advance(details, startPos, endPos) {"," var p, ch;",""," for (p = startPos; p < endPos; p++) {"," ch = input.charAt(p);",' if (ch === "\\n") {'," if (!details.seenCR) { details.line++; }"," details.column = 1;"," details.seenCR = false;",' } else if (ch === "\\r" || ch === "\\u2028" || ch === "\\u2029") {'," details.line++;"," details.column = 1;"," details.seenCR = true;"," } else {"," details.column++;"," details.seenCR = false;"," }"," }"," }",""," if (peg$cachedPos !== pos) {"," if (peg$cachedPos > pos) {"," peg$cachedPos = 0;"," peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };"," }"," advance(peg$cachedPosDetails, peg$cachedPos, pos);"," peg$cachedPos = pos;"," }",""," return peg$cachedPosDetails;"," }",""," function peg$fail(expected) {"," if (peg$currPos < peg$maxFailPos) { return; }",""," if (peg$currPos > peg$maxFailPos) {"," peg$maxFailPos = peg$currPos;"," peg$maxFailExpected = [];"," }",""," peg$maxFailExpected.push(expected);"," }",""," function peg$buildException(message, expected, pos) {"," function cleanupExpected(expected) {"," var i = 1;",""," expected.sort(function(a, b) {"," if (a.description < b.description) {"," return -1;"," } else if (a.description > b.description) {"," return 1;"," } else {"," return 0;"," }"," });",""," while (i < expected.length) {"," if (expected[i - 1] === expected[i]) {"," expected.splice(i, 1);"," } else {"," i++;"," }"," }"," }",""," function buildMessage(expected, found) {"," function stringEscape(s) {"," function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }",""," return s"," .replace(/\\\\/g, '\\\\\\\\')"," .replace(/\"/g, '\\\\\"')"," .replace(/\\x08/g, '\\\\b')"," .replace(/\\t/g, '\\\\t')"," .replace(/\\n/g, '\\\\n')"," .replace(/\\f/g, '\\\\f')"," .replace(/\\r/g, '\\\\r')"," .replace(/[\\x00-\\x07\\x0B\\x0E\\x0F]/g, function(ch) { return '\\\\x0' + hex(ch); })"," .replace(/[\\x10-\\x1F\\x80-\\xFF]/g, function(ch) { return '\\\\x' + hex(ch); })"," .replace(/[\\u0180-\\u0FFF]/g, function(ch) { return '\\\\u0' + hex(ch); })"," .replace(/[\\u1080-\\uFFFF]/g, function(ch) { return '\\\\u' + hex(ch); });"," }",""," var expectedDescs = new Array(expected.length),"," expectedDesc, foundDesc, i;",""," for (i = 0; i < expected.length; i++) {"," expectedDescs[i] = expected[i].description;"," }",""," expectedDesc = expected.length > 1",' ? expectedDescs.slice(0, -1).join(", ")',' + " or "'," + expectedDescs[expected.length - 1]"," : expectedDescs[0];","",' foundDesc = found ? "\\"" + stringEscape(found) + "\\"" : "end of input";',"",' return "Expected " + expectedDesc + " but " + foundDesc + " found.";'," }",""," var posDetails = peg$computePosDetails(pos),"," found = pos < input.length ? input.charAt(pos) : null;",""," if (expected !== null) {"," cleanupExpected(expected);"," }",""," return new SyntaxError("," message !== null ? message : buildMessage(expected, found),"," expected,"," found,"," pos,"," posDetails.line,"," posDetails.column"," );"," }",""].join("\n")),"size"===options.optimize?(parts.push(indent4(generateInterpreter())),parts.push("")):utils.each(ast.rules,function(e){parts.push(indent4(generateRuleFunction(e))),parts.push("")}),ast.initializer&&(parts.push(indent4(ast.initializer.code)),parts.push("")),"size"===options.optimize?parts.push(" peg$result = peg$parseRule(peg$startRuleIndex);"):parts.push(" peg$result = peg$startRuleFunction();"),parts.push([""," if (peg$result !== peg$FAILED && peg$currPos === input.length) {"," return peg$result;"," } else {"," if (peg$result !== peg$FAILED && peg$currPos < input.length) {",' peg$fail({ type: "end", description: "end of input" });'," }",""," throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);"," }"," }",""," return {"," SyntaxError: SyntaxError,"," parse: parse"," };","})()"].join("\n")),ast.code=parts.join("\n")}}),modules.define("compiler/passes/remove-proxy-rules",function(e,t){var n=t("../../utils");e.exports=function(e,t){function r(e){return"rule"===e.type&&"rule_ref"===e.expression.type}function s(e,t,r){function s(){}function i(e,t,n){a(e.expression,t,n)}function o(e){return function(t,r,s){n.each(t[e],function(e){a(e,r,s)})}}var a=n.buildNodeVisitor({grammar:o("rules"),rule:i,named:i,choice:o("alternatives"),sequence:o("elements"),labeled:i,text:i,simple_and:i,simple_not:i,semantic_and:s,semantic_not:s,optional:i,zero_or_more:i,one_or_more:i,action:i,rule_ref:function(e,t,n){e.name===t&&(e.name=n)},literal:s,"class":s,any:s});a(e,t,r)}var i=[];n.each(e.rules,function(o,a){r(o)&&(s(e,o.name,o.expression.name),n.contains(t.allowedStartRules,o.name)||i.push(a))}),i.reverse(),n.each(i,function(t){e.rules.splice(t,1)})}}),modules.define("compiler/passes/report-left-recursion",function(e,t){var n=t("../../utils"),r=t("../../grammar-error");e.exports=function(e){function t(){}function s(e,t){o(e.expression,t)}function i(e){return function(t,r){n.each(t[e],function(e){o(e,r)})}}var o=n.buildNodeVisitor({grammar:i("rules"),rule:function(e,t){o(e.expression,t.concat(e.name))},named:s,choice:i("alternatives"),action:s,sequence:function(e,t){e.elements.length>0&&o(e.elements[0],t)},labeled:s,text:s,simple_and:s,simple_not:s,semantic_and:t,semantic_not:t,optional:s,zero_or_more:s,one_or_more:s,rule_ref:function(t,s){if(n.contains(s,t.name))throw new r('Left recursion detected for rule "'+t.name+'".');o(n.findRuleByName(e,t.name),s)},literal:t,"class":t,any:t});o(e,[])}}),modules.define("compiler/passes/report-missing-rules",function(e,t){var n=t("../../utils"),r=t("../../grammar-error");e.exports=function(e){function t(){}function s(e){o(e.expression)}function i(e){return function(t){n.each(t[e],o)}}var o=n.buildNodeVisitor({grammar:i("rules"),rule:s,named:s,choice:i("alternatives"),action:s,sequence:i("elements"),labeled:s,text:s,simple_and:s,simple_not:s,semantic_and:t,semantic_not:t,optional:s,zero_or_more:s,one_or_more:s,rule_ref:function(t){if(!n.findRuleByName(e,t.name))throw new r('Referenced rule "'+t.name+'" does not exist.')},literal:t,"class":t,any:t});o(e)}}),modules.define("compiler",function(module,require){var utils=require("./utils");module.exports={passes:{check:{reportMissingRules:require("./compiler/passes/report-missing-rules"),reportLeftRecursion:require("./compiler/passes/report-left-recursion")},transform:{removeProxyRules:require("./compiler/passes/remove-proxy-rules")},generate:{generateBytecode:require("./compiler/passes/generate-bytecode"),generateJavascript:require("./compiler/passes/generate-javascript")}},compile:function(ast,passes){function runPass(e){e(ast,options)}var options=arguments.length>2?utils.clone(arguments[2]):{},stage;utils.defaults(options,{allowedStartRules:[ast.rules[0].name],cache:!1,optimize:"speed",output:"parser"});for(stage in passes)passes.hasOwnProperty(stage)&&utils.each(passes[stage],runPass);switch(options.output){case"parser":return eval(ast.code);case"source":return ast.code}}}}),modules.define("peg",function(e,t){var n=t("./utils");e.exports={VERSION:"0.8.0",GrammarError:t("./grammar-error"),parser:t("./parser"),compiler:t("./compiler"),buildParser:function(e){function t(e){var t,r={};for(t in e)e.hasOwnProperty(t)&&(r[t]=n.values(e[t]));return r}var r=arguments.length>1?n.clone(arguments[1]):{},s="plugins"in r?r.plugins:[],i={parser:this.parser,passes:t(this.compiler.passes)};return n.each(s,function(e){e.use(i,r)}),this.compiler.compile(i.parser.parse(e),i.passes,r)}}}),modules.peg}();
\ No newline at end of file
formula = "="? space* ex:expression {return ex;}
expression = fC:functionCall e1:E1 {return [].concat(fC).concat(e1);}
/ "(" e:expression ")" e1:E1 {return ["("].concat(e).concat(")").concat(e1);}
/ prOp:prefOper e:expression e1:E1 {return [].concat(prOp).concat(e).concat(e1);}
/ con:const e1:E1 {return [].concat(con).concat(e1);}
/ cR:cellRef e1:E1 {return [].concat(cR).concat(e1);}
/ functionCall
/ "(" expression ")"
/ const
/ cellRef
/ prOp:prefOper e:expression {return [].concat(prOp).concat(e);}
E1 = inOp:infOper e:expression e1:E1{return [].concat(inOp).concat(e).concat(e1);}
/ pOp:postOper e1:E1{return [].concat(pOp).concat(e1);}
/ infOper expression
/ postOper
functionCall = space* fC:(functionName "(" (aL:(arg:argumentList?{return arg;}) {console.log(aL ? aL.length : 0);return aL;} )")"){return fC;} /*{return [fC,"("].concat(aL).concat([")"]);}*/
functionName = (letter (udn)*){return text();}
udn = letter / decDig / fullStop
argumentList = a1:argument a2:(delim:(comma / semicolon) arg:argument?{console.log(arg);return arg === null ? "cEmpty" : arg;})* {return [].concat(a1).concat(a2);}
argument = space* exp:expression space* {return exp;}
cellRef = ((wSP:workSheetPrefix? ((A1ref ":" A1ref) / A1ref)){return text();/*return cellA1Ref*/} / name) {return text()+"_";/*cellRef do somethink*/}
A1ref = ((A1c ":" A1c) / (A1r ":" A1r) / (A1c A1r)){return text();}
A1c = A1rc / ("$" A1rc)
A1rc = [a-z]i+ {return text();}
A1r = A1rr / ("$" A1rr)
A1rr = digSeq
workSheetPrefix = ( workSheetPrefixSpecial / sheetName sheetNameCellRefDelim / sheetName ":" sheetName sheetNameCellRefDelim){return text();}
workSheetPrefixSpecial = apostrophe sheetNameSpecial apostrophe sheetNameCellRefDelim / apostrophe sheetNameSpecial ":" sheetNameSpecial apostrophe sheetNameCellRefDelim
sheetNameSpecial = sheetNameStartCharacterSpecial sheetNameCharactersSpecial? sheetNameEndCharacterSpecial?
sheetNameStartCharacterSpecial = [^'\*\][\\:\?\/]
sheetNameEndCharacterSpecial = sheetNameStartCharacterSpecial
sheetNameCharactersSpecial = sheetNameCharacterSpecial*
sheetNameCharacterSpecial = ((apostrophe apostrophe) / [^'\*\][\\:\?\/])
sheetNameCellRefDelim = "!"
apostrophe = "'"
sheetName = sheetNameCharacter+{return text();}
/*sheetNameCharacter = [^'\[\]\\?:,*^\+\-&=<>%!]*/
sheetNameCharacter = [A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0345\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05B0-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0657\u0659-\u065F\u066E-\u06D3\u06D5-\u06DC\u06E1-\u06E8\u06ED-\u06EF\u06FA-\u06FC\u06FF\u0710-\u073F\u074D-\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0817\u081A-\u082C\u0840-\u0858\u08A0\u08A2-\u08AC\u08E4-\u08E9\u08F0-\u08FE\u0900-\u093B\u093D-\u094C\u094E-\u0950\u0955-\u0963\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD-\u09C4\u09C7\u09C8\u09CB\u09CC\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09F0\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A42\u0A47\u0A48\u0A4B\u0A4C\u0A51\u0A59-\u0A5C\u0A5E\u0A70-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD-\u0AC5\u0AC7-\u0AC9\u0ACB\u0ACC\u0AD0\u0AE0-\u0AE3\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D-\u0B44\u0B47\u0B48\u0B4B\u0B4C\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0BD0\u0BD7\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4C\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCC\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4C\u0D4E\u0D57\u0D60-\u0D63\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E46\u0E4D\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0ECD\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F71-\u0F81\u0F88-\u0F97\u0F99-\u0FBC\u1000-\u1036\u1038\u103B-\u103F\u1050-\u1062\u1065-\u1068\u106E-\u1086\u108E\u109C\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1713\u1720-\u1733\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17B3\u17B6-\u17C8\u17D7\u17DC\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u1938\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A1B\u1A20-\u1A5E\u1A61-\u1A74\u1AA7\u1B00-\u1B33\u1B35-\u1B43\u1B45-\u1B4B\u1B80-\u1BA9\u1BAC-\u1BAF\u1BBA-\u1BE5\u1BE7-\u1BF1\u1C00-\u1C35\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u24B6-\u24E9\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA674-\uA67B\uA67F-\uA697\uA69F-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA827\uA840-\uA873\uA880-\uA8C3\uA8F2-\uA8F7\uA8FB\uA90A-\uA92A\uA930-\uA952\uA960-\uA97C\uA980-\uA9B2\uA9B4-\uA9BF\uA9CF\uAA00-\uAA36\uAA40-\uAA4D\uAA60-\uAA76\uAA7A\uAA80-\uAABE\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF5\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]
name = (nameStartChar nameChars?){return text();}
nameStartChar = letter / underscore / backslash
nameChars = nameChar+{return text();}
nameChar = letter / decDig / underscore / fullStop
const = space* cnst:(errConst / logConst / strConst / numConst / arrConst) space* {return cnst;}
errConst = ("#DIV/0!" / "#N/A" / "#NAME?" / "#NULL!" / "#NUM!" / "#REF!" / "#VALUE!" / "#GETTING_DATA"){return text();/*erroconst do somethink*/}
logConst = "TRUE"i / "FALSE"i {return text(); /*logconst do somethink*/}
strConst = d1:dblQuote sc:strChars? d2:dblQuote {return text();/*strconst do somethink*/}
dblQuote = "\""
strChars = ([\u0009\u000A\u000D\u0020\u0021\u0023-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF] / "\"\"")+ {return text();}
numConst = (DecimalIntegerLiteral "." decDig* ExponentPart?
/ "." decDig+ ExponentPart?
/ DecimalIntegerLiteral ExponentPart?) {return text();/*numconst do somethink*/}
DecimalIntegerLiteral = "0" / NonZeroDigit decDig*
NonZeroDigit = [+-]?[1-9]
ExponentPart = "e"i SignedInteger
SignedInteger = [+-]?decDig+
decDig = [0-9]
digSeq = decDig+ {return text();}
fullStop = "\."
ws = space?
arrConst = "{" constListRows+ "}"
constListRows = constListRow ( semicolon arg:constListRow? )*
semicolon = ";"
constListRow = const (comma c:const?{return c === null ? "cEmpty" : c;})*
operator = space* op:(":" / comma / space / "^" / "*" / "\/" / "+" / "-" / "&" / "=" / "<>" / "<" / "<=" / ">" / ">=" / "%") space* {return op;}
infOper = space* op:(":" / comma / space / "^" / "*" / "\/" / "+" / "-" / "&" / "=" / "<>" / "<" / "<=" / ">" / ">=") space* {return op;}
postOper = space* op:"%" space* {return op;}
prefOper = space* op:("-" / "+") space* {return op;}
comma = ","
space = " "
underscore = "_"
backslash = "\\"
leftParentheses = "("
rigthParentheses = ")"
letters = letter+ {return text();}
letter = [A-Za-z\u005F\u0080-\u0081\u0083\u0085-\u0087\u0089-\u008A\u008C-\u0091\u0093-\u0094\u0096-\u0097\u0099-\u009A\u009C-\u009F\u00A1-\u00A5\u00A7-\u00A8\u00AA\u00AD\u00AF-\u00BA\u00BC-\u02B8\u02BB-\u02C1\u02C7\u02C9-\u02CB\u02CD\u02D0-\u02D1\u02D8-\u02DB\u02DD\u02E0-\u02E4\u02EE\u0370-\u0373\u0376-\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0523\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0621-\u064A\u066E-\u066F\u0671-\u06D3\u06D5\u06E5-\u06E6\u06EE-\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4-\u07F5\u07FA\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0972\u097B-\u097F\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0-\u0AE1\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B35-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58-\u0C59\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3D\u0D60-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E3A\u0E40-\u0E4E\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDD\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8B\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065-\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10D0-\u10FA\u10FC\u1100-\u1159\u115F-\u11A2\u11A8-\u11F9\u1200-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u1676\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19A9\u19C1-\u19C7\u1A00-\u1A16\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE-\u1BAF\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2010\u2013-\u2016\u2018\u201C-\u201D\u2020-\u2021\u2025-\u2027\u2030\u2032-\u2033\u2035\u203B\u2071\u2074\u207F\u2081-\u2084\u2090-\u2094\u2102-\u2103\u2105\u2107\u2109-\u2113\u2115-\u2116\u2119-\u211D\u2121-\u2122\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2153-\u2154\u215B-\u215E\u2160-\u2188\u2190-\u2199\u21D2\u21D4\u2200\u2202-\u2203\u2207-\u2208\u220B\u220F\u2211\u2215\u221A\u221D-\u2220\u2223\u2225\u2227-\u222C\u222E\u2234-\u2237\u223C-\u223D\u2248\u224C\u2252\u2260-\u2261\u2264-\u2267\u226A-\u226B\u226E-\u226F\u2282-\u2283\u2286-\u2287\u2295\u2299\u22A5\u22BF\u2312\u2460-\u24B5\u24D0-\u24E9\u2500-\u254B\u2550-\u2574\u2581-\u258F\u2592-\u2595\u25A0-\u25A1\u25A3-\u25A9\u25B2-\u25B3\u25B6-\u25B7\u25BC-\u25BD\u25C0-\u25C1\u25C6-\u25C8\u25CB\u25CE-\u25D1\u25E2-\u25E5\u25EF\u2605-\u2606\u2609\u260E-\u260F\u261C\u261E\u2640\u2642\u2660-\u2661\u2663-\u2665\u2667-\u266A\u266C-\u266D\u266F\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2C6F\u2C71-\u2C7D\u2C80-\u2CE4\u2D00-\u2D25\u2D30-\u2D65\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3000-\u3003\u3005-\u3017\u301D-\u301F\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31B7\u31F0-\u321C\u3220-\u3229\u3231-\u3232\u3239\u3260-\u327B\u327F\u32A3-\u32A8\u3303\u330D\u3314\u3318\u3322-\u3323\u3326-\u3327\u332B\u3336\u333B\u3349-\u334A\u334D\u3351\u3357\u337B-\u337E\u3380-\u3384\u3388-\u33CA\u33CD-\u33D3\u33D5-\u33D6\u33D8\u33DB-\u33DD\u3400-\u4DB5\u4E00-\u9FC3\uA000-\uA48C\uA500-\uA60C\uA610-\uA61F\uA62A-\uA62B\uA640-\uA65F\uA662-\uA66E\uA680-\uA697\uA722-\uA787\uA78B-\uA78C\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA90A-\uA925\uA930-\uA946\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAC00-\uD7A3\uE000-\uF848\uF900-\uFA2D\uFA30-\uFA6A\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40-\uFB41\uFB43-\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE30-\uFE31\uFE33-\uFE44\uFE49-\uFE52\uFE54-\uFE57\uFE59-\uFE66\uFE68-\uFE6B\uFE70-\uFE74\uFE76-\uFEFC\uFF01-\uFF5E\uFF61-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC\uFFE0-\uFFE6]i
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment